mfi.c revision 242681
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 242681 2012-11-06 23:25:06Z ambrisko $");
55157114Sscottl
56233711Sambrisko#include "opt_compat.h"
57157114Sscottl#include "opt_mfi.h"
58157114Sscottl
59157114Sscottl#include <sys/param.h>
60157114Sscottl#include <sys/systm.h>
61162118Sambrisko#include <sys/sysctl.h>
62157114Sscottl#include <sys/malloc.h>
63157114Sscottl#include <sys/kernel.h>
64158737Sambrisko#include <sys/poll.h>
65158737Sambrisko#include <sys/selinfo.h>
66157114Sscottl#include <sys/bus.h>
67157114Sscottl#include <sys/conf.h>
68157114Sscottl#include <sys/eventhandler.h>
69157114Sscottl#include <sys/rman.h>
70157114Sscottl#include <sys/bus_dma.h>
71157114Sscottl#include <sys/bio.h>
72157114Sscottl#include <sys/ioccom.h>
73158737Sambrisko#include <sys/uio.h>
74158737Sambrisko#include <sys/proc.h>
75163398Sscottl#include <sys/signalvar.h>
76238077Sjhb#include <sys/sysent.h>
77233711Sambrisko#include <sys/taskqueue.h>
78157114Sscottl
79157114Sscottl#include <machine/bus.h>
80157114Sscottl#include <machine/resource.h>
81157114Sscottl
82157114Sscottl#include <dev/mfi/mfireg.h>
83157114Sscottl#include <dev/mfi/mfi_ioctl.h>
84157114Sscottl#include <dev/mfi/mfivar.h>
85233711Sambrisko#include <sys/interrupt.h>
86233711Sambrisko#include <sys/priority.h>
87157114Sscottl
88157114Sscottlstatic int	mfi_alloc_commands(struct mfi_softc *);
89157114Sscottlstatic int	mfi_comms_init(struct mfi_softc *);
90157114Sscottlstatic int	mfi_get_controller_info(struct mfi_softc *);
91158737Sambriskostatic int	mfi_get_log_state(struct mfi_softc *,
92159806Sps		    struct mfi_evt_log_state **);
93180037Sjhbstatic int	mfi_parse_entries(struct mfi_softc *, int, int);
94157114Sscottlstatic void	mfi_data_cb(void *, bus_dma_segment_t *, int, int);
95157114Sscottlstatic void	mfi_startup(void *arg);
96157114Sscottlstatic void	mfi_intr(void *arg);
97159811Spsstatic void	mfi_ldprobe(struct mfi_softc *sc);
98233711Sambriskostatic void	mfi_syspdprobe(struct mfi_softc *sc);
99233711Sambriskostatic void	mfi_handle_evt(void *context, int pending);
100158737Sambriskostatic int	mfi_aen_register(struct mfi_softc *sc, int seq, int locale);
101158737Sambriskostatic void	mfi_aen_complete(struct mfi_command *);
102159811Spsstatic int	mfi_add_ld(struct mfi_softc *sc, int);
103159811Spsstatic void	mfi_add_ld_complete(struct mfi_command *);
104233711Sambriskostatic int	mfi_add_sys_pd(struct mfi_softc *sc, int);
105233711Sambriskostatic void	mfi_add_sys_pd_complete(struct mfi_command *);
106157114Sscottlstatic struct mfi_command * mfi_bio_command(struct mfi_softc *);
107157114Sscottlstatic void	mfi_bio_complete(struct mfi_command *);
108233711Sambriskostatic struct mfi_command *mfi_build_ldio(struct mfi_softc *,struct bio*);
109233711Sambriskostatic struct mfi_command *mfi_build_syspdio(struct mfi_softc *,struct bio*);
110157114Sscottlstatic int	mfi_send_frame(struct mfi_softc *, struct mfi_command *);
111242681Sambriskostatic int	mfi_abort(struct mfi_softc *, struct mfi_command **);
112192450Simpstatic int	mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int, struct thread *);
113162619Sscottlstatic void	mfi_timeout(void *);
114178968Sscottlstatic int	mfi_user_command(struct mfi_softc *,
115178968Sscottl		    struct mfi_ioc_passthru *);
116233711Sambriskostatic void	mfi_enable_intr_xscale(struct mfi_softc *sc);
117233711Sambriskostatic void	mfi_enable_intr_ppc(struct mfi_softc *sc);
118233711Sambriskostatic int32_t	mfi_read_fw_status_xscale(struct mfi_softc *sc);
119233711Sambriskostatic int32_t	mfi_read_fw_status_ppc(struct mfi_softc *sc);
120233711Sambriskostatic int	mfi_check_clear_intr_xscale(struct mfi_softc *sc);
121233711Sambriskostatic int	mfi_check_clear_intr_ppc(struct mfi_softc *sc);
122233711Sambriskostatic void 	mfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add,
123233711Sambrisko		    uint32_t frame_cnt);
124233711Sambriskostatic void 	mfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add,
125233711Sambrisko		    uint32_t frame_cnt);
126233711Sambriskostatic int mfi_config_lock(struct mfi_softc *sc, uint32_t opcode);
127233711Sambriskostatic void mfi_config_unlock(struct mfi_softc *sc, int locked);
128233711Sambriskostatic int mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm);
129233711Sambriskostatic void mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm);
130233711Sambriskostatic int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm);
131157114Sscottl
132227562SjhbSYSCTL_NODE(_hw, OID_AUTO, mfi, CTLFLAG_RD, 0, "MFI driver parameters");
133162118Sambriskostatic int	mfi_event_locale = MFI_EVT_LOCALE_ALL;
134162473SambriskoTUNABLE_INT("hw.mfi.event_locale", &mfi_event_locale);
135162118SambriskoSYSCTL_INT(_hw_mfi, OID_AUTO, event_locale, CTLFLAG_RW, &mfi_event_locale,
136162118Sambrisko            0, "event message locale");
137162473Sambrisko
138165852Sscottlstatic int	mfi_event_class = MFI_EVT_CLASS_INFO;
139162473SambriskoTUNABLE_INT("hw.mfi.event_class", &mfi_event_class);
140162118SambriskoSYSCTL_INT(_hw_mfi, OID_AUTO, event_class, CTLFLAG_RW, &mfi_event_class,
141162118Sambrisko          0, "event message class");
142162118Sambrisko
143178968Sscottlstatic int	mfi_max_cmds = 128;
144178968SscottlTUNABLE_INT("hw.mfi.max_cmds", &mfi_max_cmds);
145178968SscottlSYSCTL_INT(_hw_mfi, OID_AUTO, max_cmds, CTLFLAG_RD, &mfi_max_cmds,
146178968Sscottl	   0, "Max commands");
147178968Sscottl
148233711Sambriskostatic int	mfi_detect_jbod_change = 1;
149233711SambriskoTUNABLE_INT("hw.mfi.detect_jbod_change", &mfi_detect_jbod_change);
150233711SambriskoSYSCTL_INT(_hw_mfi, OID_AUTO, detect_jbod_change, CTLFLAG_RW,
151233711Sambrisko	   &mfi_detect_jbod_change, 0, "Detect a change to a JBOD");
152233711Sambrisko
153157114Sscottl/* Management interface */
154157114Sscottlstatic d_open_t		mfi_open;
155157114Sscottlstatic d_close_t	mfi_close;
156157114Sscottlstatic d_ioctl_t	mfi_ioctl;
157158737Sambriskostatic d_poll_t		mfi_poll;
158157114Sscottl
159157114Sscottlstatic struct cdevsw mfi_cdevsw = {
160157114Sscottl	.d_version = 	D_VERSION,
161157114Sscottl	.d_flags =	0,
162157114Sscottl	.d_open = 	mfi_open,
163157114Sscottl	.d_close =	mfi_close,
164157114Sscottl	.d_ioctl =	mfi_ioctl,
165158737Sambrisko	.d_poll =	mfi_poll,
166157114Sscottl	.d_name =	"mfi",
167157114Sscottl};
168157114Sscottl
169157114SscottlMALLOC_DEFINE(M_MFIBUF, "mfibuf", "Buffers for the MFI driver");
170157114Sscottl
171158737Sambrisko#define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH
172233711Sambriskostruct mfi_skinny_dma_info mfi_skinny;
173157114Sscottl
174171980Sscottlstatic void
175171980Sscottlmfi_enable_intr_xscale(struct mfi_softc *sc)
176171980Sscottl{
177171980Sscottl	MFI_WRITE4(sc, MFI_OMSK, 0x01);
178171980Sscottl}
179171980Sscottl
180171980Sscottlstatic void
181171980Sscottlmfi_enable_intr_ppc(struct mfi_softc *sc)
182171980Sscottl{
183184897Sambrisko	if (sc->mfi_flags & MFI_FLAGS_1078) {
184233711Sambrisko		MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
185184897Sambrisko		MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM);
186233711Sambrisko	}
187233711Sambrisko	else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
188233711Sambrisko		MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
189184897Sambrisko		MFI_WRITE4(sc, MFI_OMSK, ~MFI_GEN2_EIM);
190184897Sambrisko	}
191233711Sambrisko	else if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
192233711Sambrisko		MFI_WRITE4(sc, MFI_OMSK, ~0x00000001);
193233711Sambrisko	}
194171980Sscottl}
195171980Sscottl
196171980Sscottlstatic int32_t
197171980Sscottlmfi_read_fw_status_xscale(struct mfi_softc *sc)
198171980Sscottl{
199171980Sscottl	return MFI_READ4(sc, MFI_OMSG0);
200171980Sscottl}
201184897Sambrisko
202171980Sscottlstatic int32_t
203171980Sscottlmfi_read_fw_status_ppc(struct mfi_softc *sc)
204171980Sscottl{
205171980Sscottl	return MFI_READ4(sc, MFI_OSP0);
206171980Sscottl}
207171980Sscottl
208184897Sambriskostatic int
209171980Sscottlmfi_check_clear_intr_xscale(struct mfi_softc *sc)
210171980Sscottl{
211171980Sscottl	int32_t status;
212171980Sscottl
213171980Sscottl	status = MFI_READ4(sc, MFI_OSTS);
214171980Sscottl	if ((status & MFI_OSTS_INTR_VALID) == 0)
215171980Sscottl		return 1;
216171980Sscottl
217171980Sscottl	MFI_WRITE4(sc, MFI_OSTS, status);
218171980Sscottl	return 0;
219182085Simp}
220171980Sscottl
221184897Sambriskostatic int
222171980Sscottlmfi_check_clear_intr_ppc(struct mfi_softc *sc)
223171980Sscottl{
224171980Sscottl	int32_t status;
225171980Sscottl
226171980Sscottl	status = MFI_READ4(sc, MFI_OSTS);
227184897Sambrisko	if (sc->mfi_flags & MFI_FLAGS_1078) {
228184897Sambrisko		if (!(status & MFI_1078_RM)) {
229184897Sambrisko			return 1;
230184897Sambrisko		}
231233711Sambrisko	}
232233711Sambrisko	else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
233184897Sambrisko		if (!(status & MFI_GEN2_RM)) {
234184897Sambrisko			return 1;
235184897Sambrisko		}
236184897Sambrisko	}
237233711Sambrisko	else if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
238233711Sambrisko		if (!(status & MFI_SKINNY_RM)) {
239233711Sambrisko			return 1;
240233711Sambrisko		}
241233711Sambrisko	}
242233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
243233711Sambrisko		MFI_WRITE4(sc, MFI_OSTS, status);
244233711Sambrisko	else
245233711Sambrisko		MFI_WRITE4(sc, MFI_ODCR0, status);
246171980Sscottl	return 0;
247182085Simp}
248171980Sscottl
249184897Sambriskostatic void
250233711Sambriskomfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt)
251171980Sscottl{
252171980Sscottl	MFI_WRITE4(sc, MFI_IQP,(bus_add >>3)|frame_cnt);
253171980Sscottl}
254184897Sambrisko
255184897Sambriskostatic void
256233711Sambriskomfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt)
257171980Sscottl{
258233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
259233711Sambrisko	    MFI_WRITE4(sc, MFI_IQPL, (bus_add | frame_cnt <<1)|1 );
260233711Sambrisko	    MFI_WRITE4(sc, MFI_IQPH, 0x00000000);
261233711Sambrisko	} else {
262233711Sambrisko	    MFI_WRITE4(sc, MFI_IQP, (bus_add | frame_cnt <<1)|1 );
263233711Sambrisko	}
264171980Sscottl}
265171980Sscottl
266233711Sambriskoint
267157114Sscottlmfi_transition_firmware(struct mfi_softc *sc)
268157114Sscottl{
269194851Sscottl	uint32_t fw_state, cur_state;
270157114Sscottl	int max_wait, i;
271233711Sambrisko	uint32_t cur_abs_reg_val = 0;
272233711Sambrisko	uint32_t prev_abs_reg_val = 0;
273157114Sscottl
274233711Sambrisko	cur_abs_reg_val = sc->mfi_read_fw_status(sc);
275233711Sambrisko	fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK;
276157114Sscottl	while (fw_state != MFI_FWSTATE_READY) {
277157114Sscottl		if (bootverbose)
278157114Sscottl			device_printf(sc->mfi_dev, "Waiting for firmware to "
279171980Sscottl			"become ready\n");
280157114Sscottl		cur_state = fw_state;
281157114Sscottl		switch (fw_state) {
282157114Sscottl		case MFI_FWSTATE_FAULT:
283157114Sscottl			device_printf(sc->mfi_dev, "Firmware fault\n");
284157114Sscottl			return (ENXIO);
285157114Sscottl		case MFI_FWSTATE_WAIT_HANDSHAKE:
286233711Sambrisko			if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
287233711Sambrisko			    MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
288233711Sambrisko			else
289233711Sambrisko			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
290233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
291157114Sscottl			break;
292157114Sscottl		case MFI_FWSTATE_OPERATIONAL:
293233711Sambrisko			if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
294233711Sambrisko			    MFI_WRITE4(sc, MFI_SKINNY_IDB, 7);
295233711Sambrisko			else
296233711Sambrisko			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY);
297233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
298157114Sscottl			break;
299157114Sscottl		case MFI_FWSTATE_UNDEFINED:
300157114Sscottl		case MFI_FWSTATE_BB_INIT:
301233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
302157114Sscottl			break;
303233711Sambrisko		case MFI_FWSTATE_FW_INIT_2:
304233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
305233711Sambrisko			break;
306157114Sscottl		case MFI_FWSTATE_FW_INIT:
307157114Sscottl		case MFI_FWSTATE_FLUSH_CACHE:
308233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
309157114Sscottl			break;
310233711Sambrisko		case MFI_FWSTATE_DEVICE_SCAN:
311233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME; /* wait for 180 seconds */
312233711Sambrisko			prev_abs_reg_val = cur_abs_reg_val;
313233711Sambrisko			break;
314224041Sjhb		case MFI_FWSTATE_BOOT_MESSAGE_PENDING:
315233711Sambrisko			if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
316233711Sambrisko			    MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_HOTPLUG);
317233711Sambrisko			else
318233711Sambrisko			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG);
319233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
320224041Sjhb			break;
321157114Sscottl		default:
322233711Sambrisko			device_printf(sc->mfi_dev, "Unknown firmware state %#x\n",
323157114Sscottl			    fw_state);
324157114Sscottl			return (ENXIO);
325157114Sscottl		}
326157114Sscottl		for (i = 0; i < (max_wait * 10); i++) {
327233711Sambrisko			cur_abs_reg_val = sc->mfi_read_fw_status(sc);
328233711Sambrisko			fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK;
329157114Sscottl			if (fw_state == cur_state)
330157114Sscottl				DELAY(100000);
331157114Sscottl			else
332157114Sscottl				break;
333157114Sscottl		}
334233711Sambrisko		if (fw_state == MFI_FWSTATE_DEVICE_SCAN) {
335233711Sambrisko			/* Check the device scanning progress */
336233711Sambrisko			if (prev_abs_reg_val != cur_abs_reg_val) {
337233711Sambrisko				continue;
338233711Sambrisko			}
339233711Sambrisko		}
340157114Sscottl		if (fw_state == cur_state) {
341224041Sjhb			device_printf(sc->mfi_dev, "Firmware stuck in state "
342157114Sscottl			    "%#x\n", fw_state);
343157114Sscottl			return (ENXIO);
344157114Sscottl		}
345157114Sscottl	}
346157114Sscottl	return (0);
347157114Sscottl}
348157114Sscottl
349157114Sscottlstatic void
350233711Sambriskomfi_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
351157114Sscottl{
352233711Sambrisko	bus_addr_t *addr;
353157114Sscottl
354157114Sscottl	addr = arg;
355157114Sscottl	*addr = segs[0].ds_addr;
356157114Sscottl}
357157114Sscottl
358233711Sambrisko
359157114Sscottlint
360157114Sscottlmfi_attach(struct mfi_softc *sc)
361157114Sscottl{
362157114Sscottl	uint32_t status;
363157114Sscottl	int error, commsz, framessz, sensesz;
364162458Sscottl	int frames, unit, max_fw_sge;
365233711Sambrisko	uint32_t tb_mem_size = 0;
366157114Sscottl
367233711Sambrisko	if (sc == NULL)
368233711Sambrisko		return EINVAL;
369186132Sambrisko
370233711Sambrisko	device_printf(sc->mfi_dev, "Megaraid SAS driver Ver %s \n",
371233711Sambrisko	    MEGASAS_VERSION);
372233711Sambrisko
373157114Sscottl	mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF);
374171821Sjhb	sx_init(&sc->mfi_config_lock, "MFI config");
375157114Sscottl	TAILQ_INIT(&sc->mfi_ld_tqh);
376233711Sambrisko	TAILQ_INIT(&sc->mfi_syspd_tqh);
377242681Sambrisko	TAILQ_INIT(&sc->mfi_ld_pend_tqh);
378242681Sambrisko	TAILQ_INIT(&sc->mfi_syspd_pend_tqh);
379233711Sambrisko	TAILQ_INIT(&sc->mfi_evt_queue);
380233711Sambrisko	TASK_INIT(&sc->mfi_evt_task, 0, mfi_handle_evt, sc);
381235014Sambrisko	TASK_INIT(&sc->mfi_map_sync_task, 0, mfi_handle_map_sync, sc);
382158737Sambrisko	TAILQ_INIT(&sc->mfi_aen_pids);
383169611Sscottl	TAILQ_INIT(&sc->mfi_cam_ccbq);
384157114Sscottl
385157114Sscottl	mfi_initq_free(sc);
386157114Sscottl	mfi_initq_ready(sc);
387157114Sscottl	mfi_initq_busy(sc);
388157114Sscottl	mfi_initq_bio(sc);
389157114Sscottl
390233711Sambrisko	sc->adpreset = 0;
391233711Sambrisko	sc->last_seq_num = 0;
392233711Sambrisko	sc->disableOnlineCtrlReset = 1;
393233711Sambrisko	sc->issuepend_done = 1;
394233711Sambrisko	sc->hw_crit_error = 0;
395233711Sambrisko
396171980Sscottl	if (sc->mfi_flags & MFI_FLAGS_1064R) {
397171980Sscottl		sc->mfi_enable_intr = mfi_enable_intr_xscale;
398171980Sscottl		sc->mfi_read_fw_status = mfi_read_fw_status_xscale;
399171980Sscottl		sc->mfi_check_clear_intr = mfi_check_clear_intr_xscale;
400171980Sscottl		sc->mfi_issue_cmd = mfi_issue_cmd_xscale;
401233711Sambrisko	} else if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
402233711Sambrisko		sc->mfi_enable_intr = mfi_tbolt_enable_intr_ppc;
403233711Sambrisko		sc->mfi_disable_intr = mfi_tbolt_disable_intr_ppc;
404233711Sambrisko		sc->mfi_read_fw_status = mfi_tbolt_read_fw_status_ppc;
405233711Sambrisko		sc->mfi_check_clear_intr = mfi_tbolt_check_clear_intr_ppc;
406233711Sambrisko		sc->mfi_issue_cmd = mfi_tbolt_issue_cmd_ppc;
407233711Sambrisko		sc->mfi_adp_reset = mfi_tbolt_adp_reset;
408233711Sambrisko		sc->mfi_tbolt = 1;
409233711Sambrisko		TAILQ_INIT(&sc->mfi_cmd_tbolt_tqh);
410233711Sambrisko	} else {
411171980Sscottl		sc->mfi_enable_intr =  mfi_enable_intr_ppc;
412233711Sambrisko		sc->mfi_read_fw_status = mfi_read_fw_status_ppc;
413171980Sscottl		sc->mfi_check_clear_intr = mfi_check_clear_intr_ppc;
414171980Sscottl		sc->mfi_issue_cmd = mfi_issue_cmd_ppc;
415171980Sscottl	}
416171980Sscottl
417171980Sscottl
418157114Sscottl	/* Before we get too far, see if the firmware is working */
419157114Sscottl	if ((error = mfi_transition_firmware(sc)) != 0) {
420157114Sscottl		device_printf(sc->mfi_dev, "Firmware not in READY state, "
421157114Sscottl		    "error %d\n", error);
422157114Sscottl		return (ENXIO);
423157114Sscottl	}
424157114Sscottl
425233711Sambrisko	/* Start: LSIP200113393 */
426233711Sambrisko	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
427233711Sambrisko				1, 0,			/* algnmnt, boundary */
428233711Sambrisko				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
429233711Sambrisko				BUS_SPACE_MAXADDR,	/* highaddr */
430233711Sambrisko				NULL, NULL,		/* filter, filterarg */
431233711Sambrisko				MEGASAS_MAX_NAME*sizeof(bus_addr_t),			/* maxsize */
432233711Sambrisko				1,			/* msegments */
433233711Sambrisko				MEGASAS_MAX_NAME*sizeof(bus_addr_t),			/* maxsegsize */
434233711Sambrisko				0,			/* flags */
435233711Sambrisko				NULL, NULL,		/* lockfunc, lockarg */
436233711Sambrisko				&sc->verbuf_h_dmat)) {
437233711Sambrisko		device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmat DMA tag\n");
438233711Sambrisko		return (ENOMEM);
439233711Sambrisko	}
440233711Sambrisko	if (bus_dmamem_alloc(sc->verbuf_h_dmat, (void **)&sc->verbuf,
441233711Sambrisko	    BUS_DMA_NOWAIT, &sc->verbuf_h_dmamap)) {
442233711Sambrisko		device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmamap memory\n");
443233711Sambrisko		return (ENOMEM);
444233711Sambrisko	}
445233711Sambrisko	bzero(sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t));
446233711Sambrisko	bus_dmamap_load(sc->verbuf_h_dmat, sc->verbuf_h_dmamap,
447233711Sambrisko	    sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t),
448233711Sambrisko	    mfi_addr_cb, &sc->verbuf_h_busaddr, 0);
449233711Sambrisko	/* End: LSIP200113393 */
450233711Sambrisko
451157114Sscottl	/*
452157114Sscottl	 * Get information needed for sizing the contiguous memory for the
453157114Sscottl	 * frame pool.  Size down the sgl parameter since we know that
454157114Sscottl	 * we will never need more than what's required for MAXPHYS.
455157114Sscottl	 * It would be nice if these constants were available at runtime
456157114Sscottl	 * instead of compile time.
457157114Sscottl	 */
458171980Sscottl	status = sc->mfi_read_fw_status(sc);
459157114Sscottl	sc->mfi_max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK;
460162458Sscottl	max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16;
461195534Sscottl	sc->mfi_max_sge = min(max_fw_sge, ((MFI_MAXPHYS / PAGE_SIZE) + 1));
462157114Sscottl
463233711Sambrisko	/* ThunderBolt Support get the contiguous memory */
464233711Sambrisko
465233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
466233711Sambrisko		mfi_tbolt_init_globals(sc);
467233711Sambrisko		device_printf(sc->mfi_dev, "MaxCmd = %x MaxSgl = %x state = %x \n",
468233711Sambrisko		    sc->mfi_max_fw_cmds, sc->mfi_max_sge, status);
469233711Sambrisko		tb_mem_size = mfi_tbolt_get_memory_requirement(sc);
470233711Sambrisko
471233711Sambrisko		if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
472233711Sambrisko				1, 0,			/* algnmnt, boundary */
473233711Sambrisko				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
474233711Sambrisko				BUS_SPACE_MAXADDR,	/* highaddr */
475233711Sambrisko				NULL, NULL,		/* filter, filterarg */
476233711Sambrisko				tb_mem_size,		/* maxsize */
477233711Sambrisko				1,			/* msegments */
478233711Sambrisko				tb_mem_size,		/* maxsegsize */
479233711Sambrisko				0,			/* flags */
480233711Sambrisko				NULL, NULL,		/* lockfunc, lockarg */
481233711Sambrisko				&sc->mfi_tb_dmat)) {
482233711Sambrisko			device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
483233711Sambrisko			return (ENOMEM);
484233711Sambrisko		}
485233711Sambrisko		if (bus_dmamem_alloc(sc->mfi_tb_dmat, (void **)&sc->request_message_pool,
486233711Sambrisko		BUS_DMA_NOWAIT, &sc->mfi_tb_dmamap)) {
487233711Sambrisko			device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
488233711Sambrisko			return (ENOMEM);
489233711Sambrisko		}
490233711Sambrisko		bzero(sc->request_message_pool, tb_mem_size);
491233711Sambrisko		bus_dmamap_load(sc->mfi_tb_dmat, sc->mfi_tb_dmamap,
492233711Sambrisko		sc->request_message_pool, tb_mem_size, mfi_addr_cb, &sc->mfi_tb_busaddr, 0);
493233711Sambrisko
494233711Sambrisko		/* For ThunderBolt memory init */
495233711Sambrisko		if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
496233711Sambrisko				0x100, 0,		/* alignmnt, boundary */
497233711Sambrisko				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
498233711Sambrisko				BUS_SPACE_MAXADDR,	/* highaddr */
499233711Sambrisko				NULL, NULL,		/* filter, filterarg */
500233711Sambrisko				MFI_FRAME_SIZE,		/* maxsize */
501233711Sambrisko				1,			/* msegments */
502233711Sambrisko				MFI_FRAME_SIZE,		/* maxsegsize */
503233711Sambrisko				0,			/* flags */
504233711Sambrisko				NULL, NULL,		/* lockfunc, lockarg */
505233711Sambrisko				&sc->mfi_tb_init_dmat)) {
506233711Sambrisko		device_printf(sc->mfi_dev, "Cannot allocate init DMA tag\n");
507233711Sambrisko		return (ENOMEM);
508233711Sambrisko		}
509233711Sambrisko		if (bus_dmamem_alloc(sc->mfi_tb_init_dmat, (void **)&sc->mfi_tb_init,
510233711Sambrisko		    BUS_DMA_NOWAIT, &sc->mfi_tb_init_dmamap)) {
511233711Sambrisko			device_printf(sc->mfi_dev, "Cannot allocate init memory\n");
512233711Sambrisko			return (ENOMEM);
513233711Sambrisko		}
514233711Sambrisko		bzero(sc->mfi_tb_init, MFI_FRAME_SIZE);
515233711Sambrisko		bus_dmamap_load(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap,
516233711Sambrisko		sc->mfi_tb_init, MFI_FRAME_SIZE, mfi_addr_cb,
517233711Sambrisko		    &sc->mfi_tb_init_busaddr, 0);
518233711Sambrisko		if (mfi_tbolt_init_desc_pool(sc, sc->request_message_pool,
519233711Sambrisko		    tb_mem_size)) {
520233711Sambrisko			device_printf(sc->mfi_dev,
521233711Sambrisko			    "Thunderbolt pool preparation error\n");
522233711Sambrisko			return 0;
523233711Sambrisko		}
524233711Sambrisko
525233711Sambrisko		/*
526233711Sambrisko		  Allocate DMA memory mapping for MPI2 IOC Init descriptor,
527233711Sambrisko		  we are taking it diffrent from what we have allocated for Request
528233711Sambrisko		  and reply descriptors to avoid confusion later
529233711Sambrisko		*/
530233711Sambrisko		tb_mem_size = sizeof(struct MPI2_IOC_INIT_REQUEST);
531233711Sambrisko		if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
532233711Sambrisko				1, 0,			/* algnmnt, boundary */
533233711Sambrisko				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
534233711Sambrisko				BUS_SPACE_MAXADDR,	/* highaddr */
535233711Sambrisko				NULL, NULL,		/* filter, filterarg */
536233711Sambrisko				tb_mem_size,		/* maxsize */
537233711Sambrisko				1,			/* msegments */
538233711Sambrisko				tb_mem_size,		/* maxsegsize */
539233711Sambrisko				0,			/* flags */
540233711Sambrisko				NULL, NULL,		/* lockfunc, lockarg */
541233711Sambrisko				&sc->mfi_tb_ioc_init_dmat)) {
542233711Sambrisko			device_printf(sc->mfi_dev,
543233711Sambrisko			    "Cannot allocate comms DMA tag\n");
544233711Sambrisko			return (ENOMEM);
545233711Sambrisko		}
546233711Sambrisko		if (bus_dmamem_alloc(sc->mfi_tb_ioc_init_dmat,
547233711Sambrisko		    (void **)&sc->mfi_tb_ioc_init_desc,
548233711Sambrisko		    BUS_DMA_NOWAIT, &sc->mfi_tb_ioc_init_dmamap)) {
549233711Sambrisko			device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
550233711Sambrisko			return (ENOMEM);
551233711Sambrisko		}
552233711Sambrisko		bzero(sc->mfi_tb_ioc_init_desc, tb_mem_size);
553233711Sambrisko		bus_dmamap_load(sc->mfi_tb_ioc_init_dmat, sc->mfi_tb_ioc_init_dmamap,
554233711Sambrisko		sc->mfi_tb_ioc_init_desc, tb_mem_size, mfi_addr_cb,
555233711Sambrisko		    &sc->mfi_tb_ioc_init_busaddr, 0);
556233711Sambrisko	}
557157114Sscottl	/*
558157114Sscottl	 * Create the dma tag for data buffers.  Used both for block I/O
559157114Sscottl	 * and for various internal data queries.
560157114Sscottl	 */
561157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
562157114Sscottl				1, 0,			/* algnmnt, boundary */
563157114Sscottl				BUS_SPACE_MAXADDR,	/* lowaddr */
564157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
565157114Sscottl				NULL, NULL,		/* filter, filterarg */
566157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
567162458Sscottl				sc->mfi_max_sge,	/* nsegments */
568157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
569157114Sscottl				BUS_DMA_ALLOCNOW,	/* flags */
570157114Sscottl				busdma_lock_mutex,	/* lockfunc */
571157114Sscottl				&sc->mfi_io_lock,	/* lockfuncarg */
572157114Sscottl				&sc->mfi_buffer_dmat)) {
573157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate buffer DMA tag\n");
574157114Sscottl		return (ENOMEM);
575157114Sscottl	}
576157114Sscottl
577157114Sscottl	/*
578157114Sscottl	 * Allocate DMA memory for the comms queues.  Keep it under 4GB for
579157114Sscottl	 * efficiency.  The mfi_hwcomms struct includes space for 1 reply queue
580157114Sscottl	 * entry, so the calculated size here will be will be 1 more than
581157114Sscottl	 * mfi_max_fw_cmds.  This is apparently a requirement of the hardware.
582157114Sscottl	 */
583157114Sscottl	commsz = (sizeof(uint32_t) * sc->mfi_max_fw_cmds) +
584157114Sscottl	    sizeof(struct mfi_hwcomms);
585157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
586157114Sscottl				1, 0,			/* algnmnt, boundary */
587157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
588157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
589157114Sscottl				NULL, NULL,		/* filter, filterarg */
590157114Sscottl				commsz,			/* maxsize */
591157114Sscottl				1,			/* msegments */
592157114Sscottl				commsz,			/* maxsegsize */
593157114Sscottl				0,			/* flags */
594157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
595157114Sscottl				&sc->mfi_comms_dmat)) {
596157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
597157114Sscottl		return (ENOMEM);
598157114Sscottl	}
599157114Sscottl	if (bus_dmamem_alloc(sc->mfi_comms_dmat, (void **)&sc->mfi_comms,
600157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_comms_dmamap)) {
601157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
602157114Sscottl		return (ENOMEM);
603157114Sscottl	}
604157114Sscottl	bzero(sc->mfi_comms, commsz);
605157114Sscottl	bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap,
606233711Sambrisko	    sc->mfi_comms, commsz, mfi_addr_cb, &sc->mfi_comms_busaddr, 0);
607157114Sscottl	/*
608157114Sscottl	 * Allocate DMA memory for the command frames.  Keep them in the
609162458Sscottl	 * lower 4GB for efficiency.  Calculate the size of the commands at
610162458Sscottl	 * the same time; each command is one 64 byte frame plus a set of
611162458Sscottl         * additional frames for holding sg lists or other data.
612157114Sscottl	 * The assumption here is that the SG list will start at the second
613162458Sscottl	 * frame and not use the unused bytes in the first frame.  While this
614162458Sscottl	 * isn't technically correct, it simplifies the calculation and allows
615162458Sscottl	 * for command frames that might be larger than an mfi_io_frame.
616157114Sscottl	 */
617157114Sscottl	if (sizeof(bus_addr_t) == 8) {
618162458Sscottl		sc->mfi_sge_size = sizeof(struct mfi_sg64);
619157114Sscottl		sc->mfi_flags |= MFI_FLAGS_SG64;
620157114Sscottl	} else {
621162458Sscottl		sc->mfi_sge_size = sizeof(struct mfi_sg32);
622157114Sscottl	}
623233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
624233711Sambrisko		sc->mfi_sge_size = sizeof(struct mfi_sg_skinny);
625162458Sscottl	frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2;
626162458Sscottl	sc->mfi_cmd_size = frames * MFI_FRAME_SIZE;
627162458Sscottl	framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds;
628157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
629157114Sscottl				64, 0,			/* algnmnt, boundary */
630157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
631157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
632157114Sscottl				NULL, NULL,		/* filter, filterarg */
633157114Sscottl				framessz,		/* maxsize */
634157114Sscottl				1,			/* nsegments */
635157114Sscottl				framessz,		/* maxsegsize */
636157114Sscottl				0,			/* flags */
637157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
638157114Sscottl				&sc->mfi_frames_dmat)) {
639157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frame DMA tag\n");
640157114Sscottl		return (ENOMEM);
641157114Sscottl	}
642157114Sscottl	if (bus_dmamem_alloc(sc->mfi_frames_dmat, (void **)&sc->mfi_frames,
643157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_frames_dmamap)) {
644157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frames memory\n");
645157114Sscottl		return (ENOMEM);
646157114Sscottl	}
647157114Sscottl	bzero(sc->mfi_frames, framessz);
648157114Sscottl	bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap,
649233711Sambrisko	    sc->mfi_frames, framessz, mfi_addr_cb, &sc->mfi_frames_busaddr,0);
650157114Sscottl	/*
651157114Sscottl	 * Allocate DMA memory for the frame sense data.  Keep them in the
652157114Sscottl	 * lower 4GB for efficiency
653157114Sscottl	 */
654157114Sscottl	sensesz = sc->mfi_max_fw_cmds * MFI_SENSE_LEN;
655157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
656157114Sscottl				4, 0,			/* algnmnt, boundary */
657157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
658157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
659157114Sscottl				NULL, NULL,		/* filter, filterarg */
660157114Sscottl				sensesz,		/* maxsize */
661157114Sscottl				1,			/* nsegments */
662157114Sscottl				sensesz,		/* maxsegsize */
663157114Sscottl				0,			/* flags */
664157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
665157114Sscottl				&sc->mfi_sense_dmat)) {
666157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense DMA tag\n");
667157114Sscottl		return (ENOMEM);
668157114Sscottl	}
669157114Sscottl	if (bus_dmamem_alloc(sc->mfi_sense_dmat, (void **)&sc->mfi_sense,
670157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_sense_dmamap)) {
671157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense memory\n");
672157114Sscottl		return (ENOMEM);
673157114Sscottl	}
674157114Sscottl	bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap,
675233711Sambrisko	    sc->mfi_sense, sensesz, mfi_addr_cb, &sc->mfi_sense_busaddr, 0);
676157114Sscottl	if ((error = mfi_alloc_commands(sc)) != 0)
677157114Sscottl		return (error);
678157114Sscottl
679233711Sambrisko	/* Before moving the FW to operational state, check whether
680233711Sambrisko	 * hostmemory is required by the FW or not
681233711Sambrisko	 */
682157114Sscottl
683233711Sambrisko	/* ThunderBolt MFI_IOC2 INIT */
684233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
685233711Sambrisko		sc->mfi_disable_intr(sc);
686233711Sambrisko		if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0) {
687233711Sambrisko			device_printf(sc->mfi_dev,
688233711Sambrisko			    "TB Init has failed with error %d\n",error);
689233711Sambrisko			return error;
690233711Sambrisko		}
691157114Sscottl
692233711Sambrisko		if ((error = mfi_tbolt_alloc_cmd(sc)) != 0)
693233711Sambrisko			return error;
694233711Sambrisko		if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq,
695233711Sambrisko		    INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr_tbolt, sc,
696233711Sambrisko		    &sc->mfi_intr)) {
697233711Sambrisko			device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
698233711Sambrisko			return (EINVAL);
699233711Sambrisko		}
700242681Sambrisko		sc->mfi_intr_ptr = mfi_intr_tbolt;
701233711Sambrisko		sc->mfi_enable_intr(sc);
702233711Sambrisko	} else {
703233711Sambrisko		if ((error = mfi_comms_init(sc)) != 0)
704233711Sambrisko			return (error);
705157114Sscottl
706233711Sambrisko		if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq,
707233711Sambrisko		    INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr, sc, &sc->mfi_intr)) {
708233711Sambrisko			device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
709233711Sambrisko			return (EINVAL);
710233711Sambrisko		}
711242681Sambrisko		sc->mfi_intr_ptr = mfi_intr;
712233711Sambrisko		sc->mfi_enable_intr(sc);
713157114Sscottl	}
714233711Sambrisko	if ((error = mfi_get_controller_info(sc)) != 0)
715233711Sambrisko		return (error);
716233711Sambrisko	sc->disableOnlineCtrlReset = 0;
717157114Sscottl
718157114Sscottl	/* Register a config hook to probe the bus for arrays */
719157114Sscottl	sc->mfi_ich.ich_func = mfi_startup;
720157114Sscottl	sc->mfi_ich.ich_arg = sc;
721157114Sscottl	if (config_intrhook_establish(&sc->mfi_ich) != 0) {
722157114Sscottl		device_printf(sc->mfi_dev, "Cannot establish configuration "
723157114Sscottl		    "hook\n");
724157114Sscottl		return (EINVAL);
725157114Sscottl	}
726233711Sambrisko	if ((error = mfi_aen_setup(sc, 0), 0) != 0) {
727233711Sambrisko		mtx_unlock(&sc->mfi_io_lock);
728233711Sambrisko		return (error);
729233711Sambrisko	}
730157114Sscottl
731157114Sscottl	/*
732157114Sscottl	 * Register a shutdown handler.
733157114Sscottl	 */
734157114Sscottl	if ((sc->mfi_eh = EVENTHANDLER_REGISTER(shutdown_final, mfi_shutdown,
735157114Sscottl	    sc, SHUTDOWN_PRI_DEFAULT)) == NULL) {
736157114Sscottl		device_printf(sc->mfi_dev, "Warning: shutdown event "
737157114Sscottl		    "registration failed\n");
738157114Sscottl	}
739157114Sscottl
740157114Sscottl	/*
741157114Sscottl	 * Create the control device for doing management
742157114Sscottl	 */
743157114Sscottl	unit = device_get_unit(sc->mfi_dev);
744157114Sscottl	sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR,
745157114Sscottl	    0640, "mfi%d", unit);
746158737Sambrisko	if (unit == 0)
747158737Sambrisko		make_dev_alias(sc->mfi_cdev, "megaraid_sas_ioctl_node");
748157114Sscottl	if (sc->mfi_cdev != NULL)
749157114Sscottl		sc->mfi_cdev->si_drv1 = sc;
750171821Sjhb	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
751171821Sjhb	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
752171821Sjhb	    OID_AUTO, "delete_busy_volumes", CTLFLAG_RW,
753171821Sjhb	    &sc->mfi_delete_busy_volumes, 0, "Allow removal of busy volumes");
754171821Sjhb	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
755171821Sjhb	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
756171821Sjhb	    OID_AUTO, "keep_deleted_volumes", CTLFLAG_RW,
757171821Sjhb	    &sc->mfi_keep_deleted_volumes, 0,
758171821Sjhb	    "Don't detach the mfid device for a busy volume that is deleted");
759157114Sscottl
760169611Sscottl	device_add_child(sc->mfi_dev, "mfip", -1);
761169611Sscottl	bus_generic_attach(sc->mfi_dev);
762169611Sscottl
763162619Sscottl	/* Start the timeout watchdog */
764178250Skris	callout_init(&sc->mfi_watchdog_callout, CALLOUT_MPSAFE);
765162619Sscottl	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
766162619Sscottl	    mfi_timeout, sc);
767162619Sscottl
768235014Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
769235014Sambrisko		mfi_tbolt_sync_map_info(sc);
770235014Sambrisko	}
771235014Sambrisko
772157114Sscottl	return (0);
773157114Sscottl}
774157114Sscottl
775157114Sscottlstatic int
776157114Sscottlmfi_alloc_commands(struct mfi_softc *sc)
777157114Sscottl{
778157114Sscottl	struct mfi_command *cm;
779157114Sscottl	int i, ncmds;
780157114Sscottl
781157114Sscottl	/*
782157114Sscottl	 * XXX Should we allocate all the commands up front, or allocate on
783157114Sscottl	 * demand later like 'aac' does?
784157114Sscottl	 */
785178968Sscottl	ncmds = MIN(mfi_max_cmds, sc->mfi_max_fw_cmds);
786178968Sscottl	if (bootverbose)
787178968Sscottl		device_printf(sc->mfi_dev, "Max fw cmds= %d, sizing driver "
788178968Sscottl		   "pool to %d\n", sc->mfi_max_fw_cmds, ncmds);
789178968Sscottl
790157114Sscottl	sc->mfi_commands = malloc(sizeof(struct mfi_command) * ncmds, M_MFIBUF,
791157114Sscottl	    M_WAITOK | M_ZERO);
792157114Sscottl
793157114Sscottl	for (i = 0; i < ncmds; i++) {
794157114Sscottl		cm = &sc->mfi_commands[i];
795158737Sambrisko		cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames +
796162458Sscottl		    sc->mfi_cmd_size * i);
797157114Sscottl		cm->cm_frame_busaddr = sc->mfi_frames_busaddr +
798162458Sscottl		    sc->mfi_cmd_size * i;
799157114Sscottl		cm->cm_frame->header.context = i;
800157114Sscottl		cm->cm_sense = &sc->mfi_sense[i];
801157114Sscottl		cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i;
802157114Sscottl		cm->cm_sc = sc;
803162619Sscottl		cm->cm_index = i;
804157114Sscottl		if (bus_dmamap_create(sc->mfi_buffer_dmat, 0,
805233711Sambrisko		    &cm->cm_dmamap) == 0) {
806233711Sambrisko			mtx_lock(&sc->mfi_io_lock);
807157114Sscottl			mfi_release_command(cm);
808233711Sambrisko			mtx_unlock(&sc->mfi_io_lock);
809233711Sambrisko		}
810157114Sscottl		else
811157114Sscottl			break;
812157114Sscottl		sc->mfi_total_cmds++;
813157114Sscottl	}
814157114Sscottl
815157114Sscottl	return (0);
816157114Sscottl}
817157114Sscottl
818169611Sscottlvoid
819157114Sscottlmfi_release_command(struct mfi_command *cm)
820157114Sscottl{
821163398Sscottl	struct mfi_frame_header *hdr;
822157114Sscottl	uint32_t *hdr_data;
823157114Sscottl
824233711Sambrisko	mtx_assert(&cm->cm_sc->mfi_io_lock, MA_OWNED);
825233711Sambrisko
826157114Sscottl	/*
827157114Sscottl	 * Zero out the important fields of the frame, but make sure the
828165727Sscottl	 * context field is preserved.  For efficiency, handle the fields
829165727Sscottl	 * as 32 bit words.  Clear out the first S/G entry too for safety.
830157114Sscottl	 */
831163398Sscottl	hdr = &cm->cm_frame->header;
832175897Sambrisko	if (cm->cm_data != NULL && hdr->sg_count) {
833163398Sscottl		cm->cm_sg->sg32[0].len = 0;
834163398Sscottl		cm->cm_sg->sg32[0].addr = 0;
835163398Sscottl	}
836165727Sscottl
837165727Sscottl	hdr_data = (uint32_t *)cm->cm_frame;
838165727Sscottl	hdr_data[0] = 0;	/* cmd, sense_len, cmd_status, scsi_status */
839165727Sscottl	hdr_data[1] = 0;	/* target_id, lun_id, cdb_len, sg_count */
840165727Sscottl	hdr_data[4] = 0;	/* flags, timeout */
841165727Sscottl	hdr_data[5] = 0;	/* data_len */
842165727Sscottl
843157114Sscottl	cm->cm_extra_frames = 0;
844157114Sscottl	cm->cm_flags = 0;
845157114Sscottl	cm->cm_complete = NULL;
846157114Sscottl	cm->cm_private = NULL;
847169611Sscottl	cm->cm_data = NULL;
848157114Sscottl	cm->cm_sg = 0;
849157114Sscottl	cm->cm_total_frame_size = 0;
850233711Sambrisko	cm->retry_for_fw_reset = 0;
851163398Sscottl
852157114Sscottl	mfi_enqueue_free(cm);
853157114Sscottl}
854157114Sscottl
855235014Sambriskoint
856233711Sambriskomfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp,
857233711Sambrisko    uint32_t opcode, void **bufp, size_t bufsize)
858159806Sps{
859159806Sps	struct mfi_command *cm;
860159806Sps	struct mfi_dcmd_frame *dcmd;
861159806Sps	void *buf = NULL;
862233711Sambrisko	uint32_t context = 0;
863233711Sambrisko
864159806Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
865233711Sambrisko
866159806Sps	cm = mfi_dequeue_free(sc);
867159806Sps	if (cm == NULL)
868159806Sps		return (EBUSY);
869159806Sps
870233711Sambrisko	/* Zero out the MFI frame */
871233711Sambrisko	context = cm->cm_frame->header.context;
872233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
873233711Sambrisko	cm->cm_frame->header.context = context;
874233711Sambrisko
875159806Sps	if ((bufsize > 0) && (bufp != NULL)) {
876159806Sps		if (*bufp == NULL) {
877159806Sps			buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO);
878159806Sps			if (buf == NULL) {
879159806Sps				mfi_release_command(cm);
880159806Sps				return (ENOMEM);
881159806Sps			}
882159806Sps			*bufp = buf;
883159806Sps		} else {
884159806Sps			buf = *bufp;
885159806Sps		}
886159806Sps	}
887159806Sps
888159806Sps	dcmd =  &cm->cm_frame->dcmd;
889159806Sps	bzero(dcmd->mbox, MFI_MBOX_SIZE);
890159806Sps	dcmd->header.cmd = MFI_CMD_DCMD;
891159806Sps	dcmd->header.timeout = 0;
892159806Sps	dcmd->header.flags = 0;
893159806Sps	dcmd->header.data_len = bufsize;
894233711Sambrisko	dcmd->header.scsi_status = 0;
895159806Sps	dcmd->opcode = opcode;
896159806Sps	cm->cm_sg = &dcmd->sgl;
897159806Sps	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
898159806Sps	cm->cm_flags = 0;
899159806Sps	cm->cm_data = buf;
900159806Sps	cm->cm_private = buf;
901159806Sps	cm->cm_len = bufsize;
902159806Sps
903159806Sps	*cmp = cm;
904159806Sps	if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL))
905159806Sps		*bufp = buf;
906159806Sps	return (0);
907159806Sps}
908159806Sps
909159806Spsstatic int
910157114Sscottlmfi_comms_init(struct mfi_softc *sc)
911157114Sscottl{
912157114Sscottl	struct mfi_command *cm;
913157114Sscottl	struct mfi_init_frame *init;
914157114Sscottl	struct mfi_init_qinfo *qinfo;
915157114Sscottl	int error;
916233711Sambrisko	uint32_t context = 0;
917157114Sscottl
918163398Sscottl	mtx_lock(&sc->mfi_io_lock);
919157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
920157114Sscottl		return (EBUSY);
921157114Sscottl
922233711Sambrisko	/* Zero out the MFI frame */
923233711Sambrisko	context = cm->cm_frame->header.context;
924233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
925233711Sambrisko	cm->cm_frame->header.context = context;
926233711Sambrisko
927157114Sscottl	/*
928157114Sscottl	 * Abuse the SG list area of the frame to hold the init_qinfo
929157114Sscottl	 * object;
930157114Sscottl	 */
931157114Sscottl	init = &cm->cm_frame->init;
932157114Sscottl	qinfo = (struct mfi_init_qinfo *)((uintptr_t)init + MFI_FRAME_SIZE);
933157114Sscottl
934157114Sscottl	bzero(qinfo, sizeof(struct mfi_init_qinfo));
935157114Sscottl	qinfo->rq_entries = sc->mfi_max_fw_cmds + 1;
936157114Sscottl	qinfo->rq_addr_lo = sc->mfi_comms_busaddr +
937157114Sscottl	    offsetof(struct mfi_hwcomms, hw_reply_q);
938157114Sscottl	qinfo->pi_addr_lo = sc->mfi_comms_busaddr +
939157114Sscottl	    offsetof(struct mfi_hwcomms, hw_pi);
940157114Sscottl	qinfo->ci_addr_lo = sc->mfi_comms_busaddr +
941157114Sscottl	    offsetof(struct mfi_hwcomms, hw_ci);
942157114Sscottl
943157114Sscottl	init->header.cmd = MFI_CMD_INIT;
944157114Sscottl	init->header.data_len = sizeof(struct mfi_init_qinfo);
945157114Sscottl	init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE;
946164375Sscottl	cm->cm_data = NULL;
947164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
948157114Sscottl
949164375Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
950157114Sscottl		device_printf(sc->mfi_dev, "failed to send init command\n");
951163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
952157114Sscottl		return (error);
953157114Sscottl	}
954157114Sscottl	mfi_release_command(cm);
955163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
956157114Sscottl
957157114Sscottl	return (0);
958157114Sscottl}
959157114Sscottl
960157114Sscottlstatic int
961157114Sscottlmfi_get_controller_info(struct mfi_softc *sc)
962157114Sscottl{
963159806Sps	struct mfi_command *cm = NULL;
964159806Sps	struct mfi_ctrl_info *ci = NULL;
965157114Sscottl	uint32_t max_sectors_1, max_sectors_2;
966157114Sscottl	int error;
967157114Sscottl
968159806Sps	mtx_lock(&sc->mfi_io_lock);
969159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO,
970159806Sps	    (void **)&ci, sizeof(*ci));
971159806Sps	if (error)
972159806Sps		goto out;
973157114Sscottl	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
974157114Sscottl
975157114Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
976157114Sscottl		device_printf(sc->mfi_dev, "Failed to get controller info\n");
977162458Sscottl		sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE /
978157114Sscottl		    MFI_SECTOR_LEN;
979159806Sps		error = 0;
980159806Sps		goto out;
981157114Sscottl	}
982157114Sscottl
983157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
984157114Sscottl	    BUS_DMASYNC_POSTREAD);
985157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
986157114Sscottl
987233711Sambrisko	max_sectors_1 = (1 << ci->stripe_sz_ops.max) * ci->max_strips_per_io;
988157114Sscottl	max_sectors_2 = ci->max_request_size;
989157114Sscottl	sc->mfi_max_io = min(max_sectors_1, max_sectors_2);
990233711Sambrisko	sc->disableOnlineCtrlReset =
991233711Sambrisko	    ci->properties.OnOffProperties.disableOnlineCtrlReset;
992157114Sscottl
993159806Spsout:
994159806Sps	if (ci)
995159806Sps		free(ci, M_MFIBUF);
996159806Sps	if (cm)
997159806Sps		mfi_release_command(cm);
998159806Sps	mtx_unlock(&sc->mfi_io_lock);
999157114Sscottl	return (error);
1000157114Sscottl}
1001157114Sscottl
1002157114Sscottlstatic int
1003159806Spsmfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state)
1004158737Sambrisko{
1005159812Sps	struct mfi_command *cm = NULL;
1006158737Sambrisko	int error;
1007158737Sambrisko
1008233711Sambrisko	mtx_lock(&sc->mfi_io_lock);
1009159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO,
1010159806Sps	    (void **)log_state, sizeof(**log_state));
1011159806Sps	if (error)
1012159806Sps		goto out;
1013159810Sps	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1014158737Sambrisko
1015158737Sambrisko	if ((error = mfi_mapcmd(sc, cm)) != 0) {
1016159802Sps		device_printf(sc->mfi_dev, "Failed to get log state\n");
1017159806Sps		goto out;
1018158737Sambrisko	}
1019158737Sambrisko
1020158737Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1021158737Sambrisko	    BUS_DMASYNC_POSTREAD);
1022158737Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1023158737Sambrisko
1024159806Spsout:
1025159812Sps	if (cm)
1026159812Sps		mfi_release_command(cm);
1027233711Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1028158737Sambrisko
1029158737Sambrisko	return (error);
1030158737Sambrisko}
1031158737Sambrisko
1032233711Sambriskoint
1033158737Sambriskomfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
1034158737Sambrisko{
1035159806Sps	struct mfi_evt_log_state *log_state = NULL;
1036158737Sambrisko	union mfi_evt class_locale;
1037158737Sambrisko	int error = 0;
1038158737Sambrisko	uint32_t seq;
1039158737Sambrisko
1040158737Sambrisko	class_locale.members.reserved = 0;
1041162118Sambrisko	class_locale.members.locale = mfi_event_locale;
1042222589Semaste	class_locale.members.evt_class  = mfi_event_class;
1043158737Sambrisko
1044158737Sambrisko	if (seq_start == 0) {
1045158737Sambrisko		error = mfi_get_log_state(sc, &log_state);
1046233711Sambrisko		sc->mfi_boot_seq_num = log_state->boot_seq_num;
1047159806Sps		if (error) {
1048159806Sps			if (log_state)
1049159806Sps				free(log_state, M_MFIBUF);
1050158737Sambrisko			return (error);
1051159806Sps		}
1052180037Sjhb
1053180037Sjhb		/*
1054180037Sjhb		 * Walk through any events that fired since the last
1055180037Sjhb		 * shutdown.
1056180037Sjhb		 */
1057180037Sjhb		mfi_parse_entries(sc, log_state->shutdown_seq_num,
1058180037Sjhb		    log_state->newest_seq_num);
1059180037Sjhb		seq = log_state->newest_seq_num;
1060158737Sambrisko	} else
1061158737Sambrisko		seq = seq_start;
1062158737Sambrisko	mfi_aen_register(sc, seq, class_locale.word);
1063159806Sps	free(log_state, M_MFIBUF);
1064158737Sambrisko
1065158737Sambrisko	return 0;
1066158737Sambrisko}
1067158737Sambrisko
1068233711Sambriskoint
1069159811Spsmfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm)
1070159811Sps{
1071159811Sps
1072159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1073159811Sps	cm->cm_complete = NULL;
1074159811Sps
1075170284Sambrisko
1076170284Sambrisko	/*
1077170284Sambrisko	 * MegaCli can issue a DCMD of 0.  In this case do nothing
1078170284Sambrisko	 * and return 0 to it as status
1079170284Sambrisko	 */
1080170284Sambrisko	if (cm->cm_frame->dcmd.opcode == 0) {
1081170284Sambrisko		cm->cm_frame->header.cmd_status = MFI_STAT_OK;
1082170284Sambrisko		cm->cm_error = 0;
1083170284Sambrisko		return (cm->cm_error);
1084170284Sambrisko	}
1085159811Sps	mfi_enqueue_ready(cm);
1086159811Sps	mfi_startio(sc);
1087170284Sambrisko	if ((cm->cm_flags & MFI_CMD_COMPLETED) == 0)
1088170284Sambrisko		msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0);
1089170284Sambrisko	return (cm->cm_error);
1090159811Sps}
1091159811Sps
1092157114Sscottlvoid
1093157114Sscottlmfi_free(struct mfi_softc *sc)
1094157114Sscottl{
1095157114Sscottl	struct mfi_command *cm;
1096157114Sscottl	int i;
1097157114Sscottl
1098162619Sscottl	callout_drain(&sc->mfi_watchdog_callout);
1099162619Sscottl
1100157114Sscottl	if (sc->mfi_cdev != NULL)
1101157114Sscottl		destroy_dev(sc->mfi_cdev);
1102157114Sscottl
1103157114Sscottl	if (sc->mfi_total_cmds != 0) {
1104157114Sscottl		for (i = 0; i < sc->mfi_total_cmds; i++) {
1105157114Sscottl			cm = &sc->mfi_commands[i];
1106157114Sscottl			bus_dmamap_destroy(sc->mfi_buffer_dmat, cm->cm_dmamap);
1107157114Sscottl		}
1108157114Sscottl		free(sc->mfi_commands, M_MFIBUF);
1109157114Sscottl	}
1110157114Sscottl
1111157114Sscottl	if (sc->mfi_intr)
1112157114Sscottl		bus_teardown_intr(sc->mfi_dev, sc->mfi_irq, sc->mfi_intr);
1113157114Sscottl	if (sc->mfi_irq != NULL)
1114157114Sscottl		bus_release_resource(sc->mfi_dev, SYS_RES_IRQ, sc->mfi_irq_rid,
1115157114Sscottl		    sc->mfi_irq);
1116157114Sscottl
1117157114Sscottl	if (sc->mfi_sense_busaddr != 0)
1118157114Sscottl		bus_dmamap_unload(sc->mfi_sense_dmat, sc->mfi_sense_dmamap);
1119157114Sscottl	if (sc->mfi_sense != NULL)
1120157114Sscottl		bus_dmamem_free(sc->mfi_sense_dmat, sc->mfi_sense,
1121157114Sscottl		    sc->mfi_sense_dmamap);
1122157114Sscottl	if (sc->mfi_sense_dmat != NULL)
1123157114Sscottl		bus_dma_tag_destroy(sc->mfi_sense_dmat);
1124157114Sscottl
1125157114Sscottl	if (sc->mfi_frames_busaddr != 0)
1126157114Sscottl		bus_dmamap_unload(sc->mfi_frames_dmat, sc->mfi_frames_dmamap);
1127157114Sscottl	if (sc->mfi_frames != NULL)
1128157114Sscottl		bus_dmamem_free(sc->mfi_frames_dmat, sc->mfi_frames,
1129157114Sscottl		    sc->mfi_frames_dmamap);
1130157114Sscottl	if (sc->mfi_frames_dmat != NULL)
1131157114Sscottl		bus_dma_tag_destroy(sc->mfi_frames_dmat);
1132157114Sscottl
1133157114Sscottl	if (sc->mfi_comms_busaddr != 0)
1134157114Sscottl		bus_dmamap_unload(sc->mfi_comms_dmat, sc->mfi_comms_dmamap);
1135157114Sscottl	if (sc->mfi_comms != NULL)
1136157114Sscottl		bus_dmamem_free(sc->mfi_comms_dmat, sc->mfi_comms,
1137157114Sscottl		    sc->mfi_comms_dmamap);
1138157114Sscottl	if (sc->mfi_comms_dmat != NULL)
1139157114Sscottl		bus_dma_tag_destroy(sc->mfi_comms_dmat);
1140157114Sscottl
1141233711Sambrisko	/* ThunderBolt contiguous memory free here */
1142233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
1143233711Sambrisko		if (sc->mfi_tb_busaddr != 0)
1144233711Sambrisko			bus_dmamap_unload(sc->mfi_tb_dmat, sc->mfi_tb_dmamap);
1145233711Sambrisko		if (sc->request_message_pool != NULL)
1146233711Sambrisko			bus_dmamem_free(sc->mfi_tb_dmat, sc->request_message_pool,
1147233711Sambrisko			    sc->mfi_tb_dmamap);
1148233711Sambrisko		if (sc->mfi_tb_dmat != NULL)
1149233711Sambrisko			bus_dma_tag_destroy(sc->mfi_tb_dmat);
1150233711Sambrisko
1151233711Sambrisko		/* Version buffer memory free */
1152233711Sambrisko		/* Start LSIP200113393 */
1153233711Sambrisko		if (sc->verbuf_h_busaddr != 0)
1154233711Sambrisko			bus_dmamap_unload(sc->verbuf_h_dmat, sc->verbuf_h_dmamap);
1155233711Sambrisko		if (sc->verbuf != NULL)
1156233711Sambrisko			bus_dmamem_free(sc->verbuf_h_dmat, sc->verbuf,
1157233711Sambrisko			    sc->verbuf_h_dmamap);
1158233711Sambrisko		if (sc->verbuf_h_dmat != NULL)
1159233711Sambrisko			bus_dma_tag_destroy(sc->verbuf_h_dmat);
1160233711Sambrisko
1161233711Sambrisko		/* End LSIP200113393 */
1162233711Sambrisko		/* ThunderBolt INIT packet memory Free */
1163233711Sambrisko		if (sc->mfi_tb_init_busaddr != 0)
1164233711Sambrisko			bus_dmamap_unload(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap);
1165233711Sambrisko		if (sc->mfi_tb_init != NULL)
1166233711Sambrisko			bus_dmamem_free(sc->mfi_tb_init_dmat, sc->mfi_tb_init,
1167233711Sambrisko			    sc->mfi_tb_init_dmamap);
1168233711Sambrisko		if (sc->mfi_tb_init_dmat != NULL)
1169233711Sambrisko			bus_dma_tag_destroy(sc->mfi_tb_init_dmat);
1170233711Sambrisko
1171233711Sambrisko		/* ThunderBolt IOC Init Desc memory free here */
1172233711Sambrisko		if (sc->mfi_tb_ioc_init_busaddr != 0)
1173233711Sambrisko			bus_dmamap_unload(sc->mfi_tb_ioc_init_dmat,
1174233711Sambrisko			    sc->mfi_tb_ioc_init_dmamap);
1175233711Sambrisko		if (sc->mfi_tb_ioc_init_desc != NULL)
1176233711Sambrisko			bus_dmamem_free(sc->mfi_tb_ioc_init_dmat,
1177233711Sambrisko			    sc->mfi_tb_ioc_init_desc,
1178233711Sambrisko			    sc->mfi_tb_ioc_init_dmamap);
1179233711Sambrisko		if (sc->mfi_tb_ioc_init_dmat != NULL)
1180233711Sambrisko			bus_dma_tag_destroy(sc->mfi_tb_ioc_init_dmat);
1181233711Sambrisko		for (int i = 0; i < sc->mfi_max_fw_cmds; i++) {
1182233711Sambrisko			if (sc->mfi_cmd_pool_tbolt != NULL) {
1183233711Sambrisko				if (sc->mfi_cmd_pool_tbolt[i] != NULL) {
1184233711Sambrisko					free(sc->mfi_cmd_pool_tbolt[i],
1185233711Sambrisko					    M_MFIBUF);
1186233711Sambrisko					sc->mfi_cmd_pool_tbolt[i] = NULL;
1187233711Sambrisko				}
1188233711Sambrisko			}
1189233711Sambrisko		}
1190233711Sambrisko		if (sc->mfi_cmd_pool_tbolt != NULL) {
1191233711Sambrisko			free(sc->mfi_cmd_pool_tbolt, M_MFIBUF);
1192233711Sambrisko			sc->mfi_cmd_pool_tbolt = NULL;
1193233711Sambrisko		}
1194233711Sambrisko		if (sc->request_desc_pool != NULL) {
1195233711Sambrisko			free(sc->request_desc_pool, M_MFIBUF);
1196233711Sambrisko			sc->request_desc_pool = NULL;
1197233711Sambrisko		}
1198233711Sambrisko	}
1199157114Sscottl	if (sc->mfi_buffer_dmat != NULL)
1200157114Sscottl		bus_dma_tag_destroy(sc->mfi_buffer_dmat);
1201157114Sscottl	if (sc->mfi_parent_dmat != NULL)
1202157114Sscottl		bus_dma_tag_destroy(sc->mfi_parent_dmat);
1203157114Sscottl
1204171821Sjhb	if (mtx_initialized(&sc->mfi_io_lock)) {
1205157114Sscottl		mtx_destroy(&sc->mfi_io_lock);
1206171821Sjhb		sx_destroy(&sc->mfi_config_lock);
1207171821Sjhb	}
1208157114Sscottl
1209157114Sscottl	return;
1210157114Sscottl}
1211157114Sscottl
1212157114Sscottlstatic void
1213157114Sscottlmfi_startup(void *arg)
1214157114Sscottl{
1215157114Sscottl	struct mfi_softc *sc;
1216157114Sscottl
1217157114Sscottl	sc = (struct mfi_softc *)arg;
1218157114Sscottl
1219157114Sscottl	config_intrhook_disestablish(&sc->mfi_ich);
1220157114Sscottl
1221171980Sscottl	sc->mfi_enable_intr(sc);
1222171821Sjhb	sx_xlock(&sc->mfi_config_lock);
1223163398Sscottl	mtx_lock(&sc->mfi_io_lock);
1224159811Sps	mfi_ldprobe(sc);
1225233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
1226233711Sambrisko	    mfi_syspdprobe(sc);
1227163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1228171821Sjhb	sx_xunlock(&sc->mfi_config_lock);
1229157114Sscottl}
1230157114Sscottl
1231157114Sscottlstatic void
1232157114Sscottlmfi_intr(void *arg)
1233157114Sscottl{
1234157114Sscottl	struct mfi_softc *sc;
1235157114Sscottl	struct mfi_command *cm;
1236171980Sscottl	uint32_t pi, ci, context;
1237157114Sscottl
1238157114Sscottl	sc = (struct mfi_softc *)arg;
1239157114Sscottl
1240171980Sscottl	if (sc->mfi_check_clear_intr(sc))
1241157114Sscottl		return;
1242163398Sscottl
1243233711Sambriskorestart:
1244157114Sscottl	pi = sc->mfi_comms->hw_pi;
1245157114Sscottl	ci = sc->mfi_comms->hw_ci;
1246157114Sscottl	mtx_lock(&sc->mfi_io_lock);
1247157114Sscottl	while (ci != pi) {
1248157114Sscottl		context = sc->mfi_comms->hw_reply_q[ci];
1249170284Sambrisko		if (context < sc->mfi_max_fw_cmds) {
1250170284Sambrisko			cm = &sc->mfi_commands[context];
1251170284Sambrisko			mfi_remove_busy(cm);
1252170284Sambrisko			cm->cm_error = 0;
1253170284Sambrisko			mfi_complete(sc, cm);
1254170284Sambrisko		}
1255162099Sscottl		if (++ci == (sc->mfi_max_fw_cmds + 1)) {
1256157114Sscottl			ci = 0;
1257157114Sscottl		}
1258157114Sscottl	}
1259157114Sscottl
1260157114Sscottl	sc->mfi_comms->hw_ci = ci;
1261157114Sscottl
1262163398Sscottl	/* Give defered I/O a chance to run */
1263163398Sscottl	if (sc->mfi_flags & MFI_FLAGS_QFRZN)
1264163398Sscottl		sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
1265163398Sscottl	mfi_startio(sc);
1266163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1267163398Sscottl
1268233711Sambrisko	/*
1269233711Sambrisko	 * Dummy read to flush the bus; this ensures that the indexes are up
1270233711Sambrisko	 * to date.  Restart processing if more commands have come it.
1271233711Sambrisko	 */
1272233711Sambrisko	(void)sc->mfi_read_fw_status(sc);
1273233711Sambrisko	if (pi != sc->mfi_comms->hw_pi)
1274233711Sambrisko		goto restart;
1275233711Sambrisko
1276157114Sscottl	return;
1277157114Sscottl}
1278157114Sscottl
1279157114Sscottlint
1280157114Sscottlmfi_shutdown(struct mfi_softc *sc)
1281157114Sscottl{
1282157114Sscottl	struct mfi_dcmd_frame *dcmd;
1283157114Sscottl	struct mfi_command *cm;
1284157114Sscottl	int error;
1285157114Sscottl
1286242681Sambrisko
1287242681Sambrisko	if (sc->mfi_aen_cm)
1288242681Sambrisko		sc->cm_aen_abort = 1;
1289242681Sambrisko	if (sc->mfi_aen_cm != NULL)
1290242681Sambrisko		mfi_abort(sc, &sc->mfi_aen_cm);
1291242681Sambrisko
1292242681Sambrisko	if (sc->mfi_map_sync_cm)
1293242681Sambrisko		sc->cm_map_abort = 1;
1294242681Sambrisko	if (sc->mfi_map_sync_cm != NULL)
1295242681Sambrisko		mfi_abort(sc, &sc->mfi_map_sync_cm);
1296242681Sambrisko
1297159806Sps	mtx_lock(&sc->mfi_io_lock);
1298159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0);
1299163398Sscottl	if (error) {
1300163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
1301159806Sps		return (error);
1302163398Sscottl	}
1303157114Sscottl
1304157114Sscottl	dcmd = &cm->cm_frame->dcmd;
1305157114Sscottl	dcmd->header.flags = MFI_FRAME_DIR_NONE;
1306164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
1307164375Sscottl	cm->cm_data = NULL;
1308157114Sscottl
1309164375Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
1310157114Sscottl		device_printf(sc->mfi_dev, "Failed to shutdown controller\n");
1311157114Sscottl	}
1312157114Sscottl
1313159812Sps	mfi_release_command(cm);
1314163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1315157114Sscottl	return (error);
1316157114Sscottl}
1317157114Sscottl
1318157114Sscottlstatic void
1319233711Sambriskomfi_syspdprobe(struct mfi_softc *sc)
1320233711Sambrisko{
1321233711Sambrisko	struct mfi_frame_header *hdr;
1322233711Sambrisko	struct mfi_command *cm = NULL;
1323233711Sambrisko	struct mfi_pd_list *pdlist = NULL;
1324233711Sambrisko	struct mfi_system_pd *syspd, *tmp;
1325242681Sambrisko	struct mfi_system_pending *syspd_pend;
1326233711Sambrisko	int error, i, found;
1327233711Sambrisko
1328233711Sambrisko	sx_assert(&sc->mfi_config_lock, SA_XLOCKED);
1329233711Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1330233711Sambrisko	/* Add SYSTEM PD's */
1331233711Sambrisko	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_LIST_QUERY,
1332233711Sambrisko	    (void **)&pdlist, sizeof(*pdlist));
1333235016Sambrisko	if (error) {
1334233711Sambrisko		device_printf(sc->mfi_dev,
1335233711Sambrisko		    "Error while forming SYSTEM PD list\n");
1336233711Sambrisko		goto out;
1337233711Sambrisko	}
1338233711Sambrisko
1339233711Sambrisko	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1340233711Sambrisko	cm->cm_frame->dcmd.mbox[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
1341233711Sambrisko	cm->cm_frame->dcmd.mbox[1] = 0;
1342233711Sambrisko	if (mfi_mapcmd(sc, cm) != 0) {
1343233711Sambrisko		device_printf(sc->mfi_dev,
1344233711Sambrisko		    "Failed to get syspd device listing\n");
1345233711Sambrisko		goto out;
1346233711Sambrisko	}
1347233711Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat,cm->cm_dmamap,
1348233711Sambrisko	    BUS_DMASYNC_POSTREAD);
1349233711Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1350233711Sambrisko	hdr = &cm->cm_frame->header;
1351233711Sambrisko	if (hdr->cmd_status != MFI_STAT_OK) {
1352233711Sambrisko		device_printf(sc->mfi_dev,
1353233711Sambrisko		    "MFI_DCMD_PD_LIST_QUERY failed %x\n", hdr->cmd_status);
1354233711Sambrisko		goto out;
1355233711Sambrisko	}
1356233711Sambrisko	/* Get each PD and add it to the system */
1357233711Sambrisko	for (i = 0; i < pdlist->count; i++) {
1358233711Sambrisko		if (pdlist->addr[i].device_id ==
1359233711Sambrisko		    pdlist->addr[i].encl_device_id)
1360233711Sambrisko			continue;
1361233711Sambrisko		found = 0;
1362233711Sambrisko		TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) {
1363233711Sambrisko			if (syspd->pd_id == pdlist->addr[i].device_id)
1364233711Sambrisko				found = 1;
1365233711Sambrisko		}
1366242681Sambrisko		TAILQ_FOREACH(syspd_pend, &sc->mfi_syspd_pend_tqh, pd_link) {
1367242681Sambrisko			if (syspd_pend->pd_id == pdlist->addr[i].device_id)
1368242681Sambrisko				found = 1;
1369242681Sambrisko		}
1370233711Sambrisko		if (found == 0)
1371233711Sambrisko			mfi_add_sys_pd(sc, pdlist->addr[i].device_id);
1372233711Sambrisko	}
1373233711Sambrisko	/* Delete SYSPD's whose state has been changed */
1374233711Sambrisko	TAILQ_FOREACH_SAFE(syspd, &sc->mfi_syspd_tqh, pd_link, tmp) {
1375233711Sambrisko		found = 0;
1376233711Sambrisko		for (i = 0; i < pdlist->count; i++) {
1377233711Sambrisko			if (syspd->pd_id == pdlist->addr[i].device_id)
1378233711Sambrisko				found = 1;
1379233711Sambrisko		}
1380233711Sambrisko		if (found == 0) {
1381233711Sambrisko			printf("DELETE\n");
1382233711Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1383233711Sambrisko			mtx_lock(&Giant);
1384233711Sambrisko			device_delete_child(sc->mfi_dev, syspd->pd_dev);
1385233711Sambrisko			mtx_unlock(&Giant);
1386233711Sambrisko			mtx_lock(&sc->mfi_io_lock);
1387233711Sambrisko		}
1388233711Sambrisko	}
1389233711Sambriskoout:
1390233711Sambrisko	if (pdlist)
1391233711Sambrisko	    free(pdlist, M_MFIBUF);
1392233711Sambrisko	if (cm)
1393233711Sambrisko	    mfi_release_command(cm);
1394233711Sambrisko
1395233711Sambrisko	return;
1396233711Sambrisko}
1397233711Sambrisko
1398233711Sambriskostatic void
1399159811Spsmfi_ldprobe(struct mfi_softc *sc)
1400157114Sscottl{
1401159811Sps	struct mfi_frame_header *hdr;
1402159811Sps	struct mfi_command *cm = NULL;
1403159811Sps	struct mfi_ld_list *list = NULL;
1404171821Sjhb	struct mfi_disk *ld;
1405242681Sambrisko	struct mfi_disk_pending *ld_pend;
1406159811Sps	int error, i;
1407157114Sscottl
1408171821Sjhb	sx_assert(&sc->mfi_config_lock, SA_XLOCKED);
1409163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1410163398Sscottl
1411159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
1412159811Sps	    (void **)&list, sizeof(*list));
1413159811Sps	if (error)
1414159811Sps		goto out;
1415159811Sps
1416159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
1417159811Sps	if (mfi_wait_command(sc, cm) != 0) {
1418159811Sps		device_printf(sc->mfi_dev, "Failed to get device listing\n");
1419159811Sps		goto out;
1420157114Sscottl	}
1421157114Sscottl
1422157114Sscottl	hdr = &cm->cm_frame->header;
1423159811Sps	if (hdr->cmd_status != MFI_STAT_OK) {
1424159811Sps		device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n",
1425159811Sps		    hdr->cmd_status);
1426159811Sps		goto out;
1427157114Sscottl	}
1428157114Sscottl
1429171821Sjhb	for (i = 0; i < list->ld_count; i++) {
1430171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1431171821Sjhb			if (ld->ld_id == list->ld_list[i].ld.v.target_id)
1432171821Sjhb				goto skip_add;
1433171821Sjhb		}
1434242681Sambrisko		TAILQ_FOREACH(ld_pend, &sc->mfi_ld_pend_tqh, ld_link) {
1435242681Sambrisko			if (ld_pend->ld_id == list->ld_list[i].ld.v.target_id)
1436242681Sambrisko				goto skip_add;
1437242681Sambrisko		}
1438163398Sscottl		mfi_add_ld(sc, list->ld_list[i].ld.v.target_id);
1439171821Sjhb	skip_add:;
1440171821Sjhb	}
1441159811Spsout:
1442159811Sps	if (list)
1443159811Sps		free(list, M_MFIBUF);
1444159811Sps	if (cm)
1445157114Sscottl		mfi_release_command(cm);
1446163398Sscottl
1447159811Sps	return;
1448157114Sscottl}
1449157114Sscottl
1450180038Sjhb/*
1451180038Sjhb * The timestamp is the number of seconds since 00:00 Jan 1, 2000.  If
1452180038Sjhb * the bits in 24-31 are all set, then it is the number of seconds since
1453180038Sjhb * boot.
1454180038Sjhb */
1455180038Sjhbstatic const char *
1456180038Sjhbformat_timestamp(uint32_t timestamp)
1457158737Sambrisko{
1458180038Sjhb	static char buffer[32];
1459180038Sjhb
1460180038Sjhb	if ((timestamp & 0xff000000) == 0xff000000)
1461180038Sjhb		snprintf(buffer, sizeof(buffer), "boot + %us", timestamp &
1462180038Sjhb		    0x00ffffff);
1463180038Sjhb	else
1464180038Sjhb		snprintf(buffer, sizeof(buffer), "%us", timestamp);
1465180038Sjhb	return (buffer);
1466180038Sjhb}
1467180038Sjhb
1468180038Sjhbstatic const char *
1469180038Sjhbformat_class(int8_t class)
1470180038Sjhb{
1471180038Sjhb	static char buffer[6];
1472180038Sjhb
1473180038Sjhb	switch (class) {
1474180038Sjhb	case MFI_EVT_CLASS_DEBUG:
1475180038Sjhb		return ("debug");
1476180038Sjhb	case MFI_EVT_CLASS_PROGRESS:
1477180038Sjhb		return ("progress");
1478180038Sjhb	case MFI_EVT_CLASS_INFO:
1479180038Sjhb		return ("info");
1480180038Sjhb	case MFI_EVT_CLASS_WARNING:
1481180038Sjhb		return ("WARN");
1482180038Sjhb	case MFI_EVT_CLASS_CRITICAL:
1483180038Sjhb		return ("CRIT");
1484180038Sjhb	case MFI_EVT_CLASS_FATAL:
1485180038Sjhb		return ("FATAL");
1486180038Sjhb	case MFI_EVT_CLASS_DEAD:
1487180038Sjhb		return ("DEAD");
1488158737Sambrisko	default:
1489180038Sjhb		snprintf(buffer, sizeof(buffer), "%d", class);
1490180038Sjhb		return (buffer);
1491158737Sambrisko	}
1492158737Sambrisko}
1493158737Sambrisko
1494180038Sjhbstatic void
1495180038Sjhbmfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
1496180038Sjhb{
1497233711Sambrisko	struct mfi_system_pd *syspd = NULL;
1498180038Sjhb
1499200238Sjkim	device_printf(sc->mfi_dev, "%d (%s/0x%04x/%s) - %s\n", detail->seq,
1500222589Semaste	    format_timestamp(detail->time), detail->evt_class.members.locale,
1501233711Sambrisko	    format_class(detail->evt_class.members.evt_class),
1502233711Sambrisko	    detail->description);
1503233711Sambrisko
1504233711Sambrisko        /* Don't act on old AEN's or while shutting down */
1505233711Sambrisko        if (detail->seq < sc->mfi_boot_seq_num || sc->mfi_detaching)
1506233711Sambrisko                return;
1507233711Sambrisko
1508233711Sambrisko	switch (detail->arg_type) {
1509233711Sambrisko	case MR_EVT_ARGS_NONE:
1510233711Sambrisko		if (detail->code == MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED) {
1511233711Sambrisko		    device_printf(sc->mfi_dev, "HostBus scan raised\n");
1512233711Sambrisko			if (mfi_detect_jbod_change) {
1513233711Sambrisko				/*
1514233711Sambrisko				 * Probe for new SYSPD's and Delete
1515233711Sambrisko				 * invalid SYSPD's
1516233711Sambrisko				 */
1517233711Sambrisko				sx_xlock(&sc->mfi_config_lock);
1518233711Sambrisko				mtx_lock(&sc->mfi_io_lock);
1519233711Sambrisko				mfi_syspdprobe(sc);
1520233711Sambrisko				mtx_unlock(&sc->mfi_io_lock);
1521233711Sambrisko				sx_xunlock(&sc->mfi_config_lock);
1522233711Sambrisko			}
1523233711Sambrisko		}
1524233711Sambrisko		break;
1525233711Sambrisko	case MR_EVT_ARGS_LD_STATE:
1526233711Sambrisko		/* During load time driver reads all the events starting
1527233711Sambrisko		 * from the one that has been logged after shutdown. Avoid
1528233711Sambrisko		 * these old events.
1529233711Sambrisko		 */
1530233711Sambrisko		if (detail->args.ld_state.new_state == MFI_LD_STATE_OFFLINE ) {
1531233711Sambrisko			/* Remove the LD */
1532233711Sambrisko			struct mfi_disk *ld;
1533233711Sambrisko			TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1534233711Sambrisko				if (ld->ld_id ==
1535233711Sambrisko				    detail->args.ld_state.ld.target_id)
1536233711Sambrisko					break;
1537233711Sambrisko			}
1538233711Sambrisko			/*
1539233711Sambrisko			Fix: for kernel panics when SSCD is removed
1540233711Sambrisko			KASSERT(ld != NULL, ("volume dissappeared"));
1541233711Sambrisko			*/
1542233711Sambrisko			if (ld != NULL) {
1543233711Sambrisko				mtx_lock(&Giant);
1544233711Sambrisko				device_delete_child(sc->mfi_dev, ld->ld_dev);
1545233711Sambrisko				mtx_unlock(&Giant);
1546233711Sambrisko			}
1547233711Sambrisko		}
1548233711Sambrisko		break;
1549233711Sambrisko	case MR_EVT_ARGS_PD:
1550233711Sambrisko		if (detail->code == MR_EVT_PD_REMOVED) {
1551233711Sambrisko			if (mfi_detect_jbod_change) {
1552233711Sambrisko				/*
1553233711Sambrisko				 * If the removed device is a SYSPD then
1554233711Sambrisko				 * delete it
1555233711Sambrisko				 */
1556233711Sambrisko				TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,
1557233711Sambrisko				    pd_link) {
1558233711Sambrisko					if (syspd->pd_id ==
1559233711Sambrisko					    detail->args.pd.device_id) {
1560233711Sambrisko						mtx_lock(&Giant);
1561233711Sambrisko						device_delete_child(
1562233711Sambrisko						    sc->mfi_dev,
1563233711Sambrisko						    syspd->pd_dev);
1564233711Sambrisko						mtx_unlock(&Giant);
1565233711Sambrisko						break;
1566233711Sambrisko					}
1567233711Sambrisko				}
1568233711Sambrisko			}
1569233711Sambrisko		}
1570233711Sambrisko		if (detail->code == MR_EVT_PD_INSERTED) {
1571233711Sambrisko			if (mfi_detect_jbod_change) {
1572233711Sambrisko				/* Probe for new SYSPD's */
1573233711Sambrisko				sx_xlock(&sc->mfi_config_lock);
1574233711Sambrisko				mtx_lock(&sc->mfi_io_lock);
1575233711Sambrisko				mfi_syspdprobe(sc);
1576233711Sambrisko				mtx_unlock(&sc->mfi_io_lock);
1577233711Sambrisko				sx_xunlock(&sc->mfi_config_lock);
1578233711Sambrisko			}
1579233711Sambrisko		}
1580233711Sambrisko		break;
1581233711Sambrisko	}
1582180038Sjhb}
1583180038Sjhb
1584233711Sambriskostatic void
1585233711Sambriskomfi_queue_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
1586233711Sambrisko{
1587233711Sambrisko	struct mfi_evt_queue_elm *elm;
1588233711Sambrisko
1589233711Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1590233711Sambrisko	elm = malloc(sizeof(*elm), M_MFIBUF, M_NOWAIT|M_ZERO);
1591233711Sambrisko	if (elm == NULL)
1592233711Sambrisko		return;
1593233711Sambrisko	memcpy(&elm->detail, detail, sizeof(*detail));
1594233711Sambrisko	TAILQ_INSERT_TAIL(&sc->mfi_evt_queue, elm, link);
1595233711Sambrisko	taskqueue_enqueue(taskqueue_swi, &sc->mfi_evt_task);
1596233711Sambrisko}
1597233711Sambrisko
1598233711Sambriskostatic void
1599233711Sambriskomfi_handle_evt(void *context, int pending)
1600233711Sambrisko{
1601233711Sambrisko	TAILQ_HEAD(,mfi_evt_queue_elm) queue;
1602233711Sambrisko	struct mfi_softc *sc;
1603233711Sambrisko	struct mfi_evt_queue_elm *elm;
1604233711Sambrisko
1605233711Sambrisko	sc = context;
1606233711Sambrisko	TAILQ_INIT(&queue);
1607233711Sambrisko	mtx_lock(&sc->mfi_io_lock);
1608233711Sambrisko	TAILQ_CONCAT(&queue, &sc->mfi_evt_queue, link);
1609233711Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1610233711Sambrisko	while ((elm = TAILQ_FIRST(&queue)) != NULL) {
1611233711Sambrisko		TAILQ_REMOVE(&queue, elm, link);
1612233711Sambrisko		mfi_decode_evt(sc, &elm->detail);
1613233711Sambrisko		free(elm, M_MFIBUF);
1614233711Sambrisko	}
1615233711Sambrisko}
1616233711Sambrisko
1617157114Sscottlstatic int
1618158737Sambriskomfi_aen_register(struct mfi_softc *sc, int seq, int locale)
1619158737Sambrisko{
1620158737Sambrisko	struct mfi_command *cm;
1621158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1622158737Sambrisko	union mfi_evt current_aen, prior_aen;
1623159806Sps	struct mfi_evt_detail *ed = NULL;
1624163398Sscottl	int error = 0;
1625158737Sambrisko
1626158737Sambrisko	current_aen.word = locale;
1627158737Sambrisko	if (sc->mfi_aen_cm != NULL) {
1628158737Sambrisko		prior_aen.word =
1629158737Sambrisko		    ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1];
1630222589Semaste		if (prior_aen.members.evt_class <= current_aen.members.evt_class &&
1631158737Sambrisko		    !((prior_aen.members.locale & current_aen.members.locale)
1632158737Sambrisko		    ^current_aen.members.locale)) {
1633158737Sambrisko			return (0);
1634158737Sambrisko		} else {
1635158737Sambrisko			prior_aen.members.locale |= current_aen.members.locale;
1636222589Semaste			if (prior_aen.members.evt_class
1637222589Semaste			    < current_aen.members.evt_class)
1638222589Semaste				current_aen.members.evt_class =
1639222589Semaste				    prior_aen.members.evt_class;
1640242681Sambrisko			mfi_abort(sc, &sc->mfi_aen_cm);
1641158737Sambrisko		}
1642158737Sambrisko	}
1643158737Sambrisko
1644233711Sambrisko	mtx_lock(&sc->mfi_io_lock);
1645159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT,
1646159806Sps	    (void **)&ed, sizeof(*ed));
1647233711Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1648163398Sscottl	if (error) {
1649163398Sscottl		goto out;
1650163398Sscottl	}
1651158737Sambrisko
1652158737Sambrisko	dcmd = &cm->cm_frame->dcmd;
1653158737Sambrisko	((uint32_t *)&dcmd->mbox)[0] = seq;
1654158737Sambrisko	((uint32_t *)&dcmd->mbox)[1] = locale;
1655158737Sambrisko	cm->cm_flags = MFI_CMD_DATAIN;
1656158737Sambrisko	cm->cm_complete = mfi_aen_complete;
1657158737Sambrisko
1658233711Sambrisko	sc->last_seq_num = seq;
1659158737Sambrisko	sc->mfi_aen_cm = cm;
1660158737Sambrisko
1661233711Sambrisko	mtx_lock(&sc->mfi_io_lock);
1662158737Sambrisko	mfi_enqueue_ready(cm);
1663158737Sambrisko	mfi_startio(sc);
1664233711Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1665158737Sambrisko
1666163398Sscottlout:
1667163398Sscottl	return (error);
1668158737Sambrisko}
1669158737Sambrisko
1670158737Sambriskostatic void
1671158737Sambriskomfi_aen_complete(struct mfi_command *cm)
1672158737Sambrisko{
1673158737Sambrisko	struct mfi_frame_header *hdr;
1674158737Sambrisko	struct mfi_softc *sc;
1675158737Sambrisko	struct mfi_evt_detail *detail;
1676163398Sscottl	struct mfi_aen *mfi_aen_entry, *tmp;
1677158737Sambrisko	int seq = 0, aborted = 0;
1678158737Sambrisko
1679158737Sambrisko	sc = cm->cm_sc;
1680233711Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1681233711Sambrisko
1682158737Sambrisko	hdr = &cm->cm_frame->header;
1683158737Sambrisko
1684158737Sambrisko	if (sc->mfi_aen_cm == NULL)
1685158737Sambrisko		return;
1686158737Sambrisko
1687235014Sambrisko	if (sc->cm_aen_abort ||
1688224039Sjhb	    hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
1689235014Sambrisko		sc->cm_aen_abort = 0;
1690158737Sambrisko		aborted = 1;
1691158737Sambrisko	} else {
1692158737Sambrisko		sc->mfi_aen_triggered = 1;
1693163398Sscottl		if (sc->mfi_poll_waiting) {
1694163398Sscottl			sc->mfi_poll_waiting = 0;
1695158737Sambrisko			selwakeup(&sc->mfi_select);
1696163398Sscottl		}
1697158737Sambrisko		detail = cm->cm_data;
1698233711Sambrisko		mfi_queue_evt(sc, detail);
1699158737Sambrisko		seq = detail->seq + 1;
1700233711Sambrisko		TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link,
1701233711Sambrisko		    tmp) {
1702158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
1703158737Sambrisko			    aen_link);
1704163398Sscottl			PROC_LOCK(mfi_aen_entry->p);
1705225617Skmacy			kern_psignal(mfi_aen_entry->p, SIGIO);
1706163398Sscottl			PROC_UNLOCK(mfi_aen_entry->p);
1707158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
1708158737Sambrisko		}
1709158737Sambrisko	}
1710158737Sambrisko
1711158737Sambrisko	free(cm->cm_data, M_MFIBUF);
1712158737Sambrisko	sc->mfi_aen_cm = NULL;
1713158737Sambrisko	wakeup(&sc->mfi_aen_cm);
1714158737Sambrisko	mfi_release_command(cm);
1715158737Sambrisko
1716158737Sambrisko	/* set it up again so the driver can catch more events */
1717158737Sambrisko	if (!aborted) {
1718233711Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1719158737Sambrisko		mfi_aen_setup(sc, seq);
1720233711Sambrisko		mtx_lock(&sc->mfi_io_lock);
1721158737Sambrisko	}
1722158737Sambrisko}
1723158737Sambrisko
1724180037Sjhb#define MAX_EVENTS 15
1725180037Sjhb
1726158737Sambriskostatic int
1727180037Sjhbmfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq)
1728158737Sambrisko{
1729158737Sambrisko	struct mfi_command *cm;
1730158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1731162118Sambrisko	struct mfi_evt_list *el;
1732180037Sjhb	union mfi_evt class_locale;
1733180037Sjhb	int error, i, seq, size;
1734158737Sambrisko
1735180037Sjhb	class_locale.members.reserved = 0;
1736180037Sjhb	class_locale.members.locale = mfi_event_locale;
1737222589Semaste	class_locale.members.evt_class  = mfi_event_class;
1738158737Sambrisko
1739162118Sambrisko	size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail)
1740162118Sambrisko		* (MAX_EVENTS - 1);
1741162118Sambrisko	el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO);
1742180037Sjhb	if (el == NULL)
1743158737Sambrisko		return (ENOMEM);
1744158737Sambrisko
1745180037Sjhb	for (seq = start_seq;;) {
1746233711Sambrisko		mtx_lock(&sc->mfi_io_lock);
1747180037Sjhb		if ((cm = mfi_dequeue_free(sc)) == NULL) {
1748180037Sjhb			free(el, M_MFIBUF);
1749233711Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1750180037Sjhb			return (EBUSY);
1751180037Sjhb		}
1752233711Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1753158737Sambrisko
1754180037Sjhb		dcmd = &cm->cm_frame->dcmd;
1755180037Sjhb		bzero(dcmd->mbox, MFI_MBOX_SIZE);
1756180037Sjhb		dcmd->header.cmd = MFI_CMD_DCMD;
1757180037Sjhb		dcmd->header.timeout = 0;
1758180037Sjhb		dcmd->header.data_len = size;
1759180037Sjhb		dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET;
1760180037Sjhb		((uint32_t *)&dcmd->mbox)[0] = seq;
1761180037Sjhb		((uint32_t *)&dcmd->mbox)[1] = class_locale.word;
1762180037Sjhb		cm->cm_sg = &dcmd->sgl;
1763180037Sjhb		cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
1764180037Sjhb		cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1765180037Sjhb		cm->cm_data = el;
1766180037Sjhb		cm->cm_len = size;
1767180037Sjhb
1768233711Sambrisko		mtx_lock(&sc->mfi_io_lock);
1769180037Sjhb		if ((error = mfi_mapcmd(sc, cm)) != 0) {
1770180037Sjhb			device_printf(sc->mfi_dev,
1771180037Sjhb			    "Failed to get controller entries\n");
1772180037Sjhb			mfi_release_command(cm);
1773233711Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1774180037Sjhb			break;
1775180037Sjhb		}
1776180037Sjhb
1777233711Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1778180037Sjhb		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1779180037Sjhb		    BUS_DMASYNC_POSTREAD);
1780180037Sjhb		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1781180037Sjhb
1782180037Sjhb		if (dcmd->header.cmd_status == MFI_STAT_NOT_FOUND) {
1783233711Sambrisko			mtx_lock(&sc->mfi_io_lock);
1784180037Sjhb			mfi_release_command(cm);
1785233711Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1786180037Sjhb			break;
1787180037Sjhb		}
1788180037Sjhb		if (dcmd->header.cmd_status != MFI_STAT_OK) {
1789180037Sjhb			device_printf(sc->mfi_dev,
1790180037Sjhb			    "Error %d fetching controller entries\n",
1791180037Sjhb			    dcmd->header.cmd_status);
1792233711Sambrisko			mtx_lock(&sc->mfi_io_lock);
1793180037Sjhb			mfi_release_command(cm);
1794233711Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1795180037Sjhb			break;
1796180037Sjhb		}
1797233711Sambrisko		mtx_lock(&sc->mfi_io_lock);
1798158737Sambrisko		mfi_release_command(cm);
1799233711Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1800158737Sambrisko
1801162473Sambrisko		for (i = 0; i < el->count; i++) {
1802180037Sjhb			/*
1803180037Sjhb			 * If this event is newer than 'stop_seq' then
1804180037Sjhb			 * break out of the loop.  Note that the log
1805180037Sjhb			 * is a circular buffer so we have to handle
1806180037Sjhb			 * the case that our stop point is earlier in
1807180037Sjhb			 * the buffer than our start point.
1808180037Sjhb			 */
1809180037Sjhb			if (el->event[i].seq >= stop_seq) {
1810180037Sjhb				if (start_seq <= stop_seq)
1811180037Sjhb					break;
1812180037Sjhb				else if (el->event[i].seq < start_seq)
1813180037Sjhb					break;
1814180037Sjhb			}
1815233711Sambrisko			mtx_lock(&sc->mfi_io_lock);
1816233711Sambrisko			mfi_queue_evt(sc, &el->event[i]);
1817233711Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1818162473Sambrisko		}
1819180037Sjhb		seq = el->event[el->count - 1].seq + 1;
1820162118Sambrisko	}
1821158737Sambrisko
1822180037Sjhb	free(el, M_MFIBUF);
1823158737Sambrisko	return (0);
1824158737Sambrisko}
1825158737Sambrisko
1826158737Sambriskostatic int
1827159811Spsmfi_add_ld(struct mfi_softc *sc, int id)
1828157114Sscottl{
1829157114Sscottl	struct mfi_command *cm;
1830159811Sps	struct mfi_dcmd_frame *dcmd = NULL;
1831159811Sps	struct mfi_ld_info *ld_info = NULL;
1832242681Sambrisko	struct mfi_disk_pending *ld_pend;
1833159811Sps	int error;
1834157114Sscottl
1835159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1836159811Sps
1837242681Sambrisko	ld_pend = malloc(sizeof(*ld_pend), M_MFIBUF, M_NOWAIT | M_ZERO);
1838242681Sambrisko	if (ld_pend != NULL) {
1839242681Sambrisko		ld_pend->ld_id = id;
1840242681Sambrisko		TAILQ_INSERT_TAIL(&sc->mfi_ld_pend_tqh, ld_pend, ld_link);
1841242681Sambrisko	}
1842242681Sambrisko
1843159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO,
1844159811Sps	    (void **)&ld_info, sizeof(*ld_info));
1845159811Sps	if (error) {
1846159811Sps		device_printf(sc->mfi_dev,
1847159811Sps		    "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error);
1848159811Sps		if (ld_info)
1849159811Sps			free(ld_info, M_MFIBUF);
1850159811Sps		return (error);
1851157624Sscottl	}
1852159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
1853159811Sps	dcmd = &cm->cm_frame->dcmd;
1854159811Sps	dcmd->mbox[0] = id;
1855160052Sambrisko	if (mfi_wait_command(sc, cm) != 0) {
1856160052Sambrisko		device_printf(sc->mfi_dev,
1857160052Sambrisko		    "Failed to get logical drive: %d\n", id);
1858160052Sambrisko		free(ld_info, M_MFIBUF);
1859160052Sambrisko		return (0);
1860160052Sambrisko	}
1861233711Sambrisko	if (ld_info->ld_config.params.isSSCD != 1)
1862233711Sambrisko		mfi_add_ld_complete(cm);
1863233711Sambrisko	else {
1864233711Sambrisko		mfi_release_command(cm);
1865233711Sambrisko		if (ld_info)		/* SSCD drives ld_info free here */
1866233711Sambrisko			free(ld_info, M_MFIBUF);
1867233711Sambrisko	}
1868157114Sscottl	return (0);
1869157114Sscottl}
1870157114Sscottl
1871157114Sscottlstatic void
1872159811Spsmfi_add_ld_complete(struct mfi_command *cm)
1873157114Sscottl{
1874157114Sscottl	struct mfi_frame_header *hdr;
1875159811Sps	struct mfi_ld_info *ld_info;
1876157114Sscottl	struct mfi_softc *sc;
1877159811Sps	device_t child;
1878157114Sscottl
1879157114Sscottl	sc = cm->cm_sc;
1880157114Sscottl	hdr = &cm->cm_frame->header;
1881159811Sps	ld_info = cm->cm_private;
1882157114Sscottl
1883242681Sambrisko	if (sc->cm_map_abort || hdr->cmd_status != MFI_STAT_OK) {
1884159811Sps		free(ld_info, M_MFIBUF);
1885242681Sambrisko		wakeup(&sc->mfi_map_sync_cm);
1886157114Sscottl		mfi_release_command(cm);
1887157114Sscottl		return;
1888157114Sscottl	}
1889242681Sambrisko	wakeup(&sc->mfi_map_sync_cm);
1890157114Sscottl	mfi_release_command(cm);
1891157114Sscottl
1892169611Sscottl	mtx_unlock(&sc->mfi_io_lock);
1893196403Sjhb	mtx_lock(&Giant);
1894157114Sscottl	if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) {
1895157114Sscottl		device_printf(sc->mfi_dev, "Failed to add logical disk\n");
1896159811Sps		free(ld_info, M_MFIBUF);
1897196403Sjhb		mtx_unlock(&Giant);
1898169611Sscottl		mtx_lock(&sc->mfi_io_lock);
1899159811Sps		return;
1900157114Sscottl	}
1901157114Sscottl
1902169451Sscottl	device_set_ivars(child, ld_info);
1903157114Sscottl	device_set_desc(child, "MFI Logical Disk");
1904157114Sscottl	bus_generic_attach(sc->mfi_dev);
1905196403Sjhb	mtx_unlock(&Giant);
1906157114Sscottl	mtx_lock(&sc->mfi_io_lock);
1907157114Sscottl}
1908163399Sscottl
1909233711Sambriskostatic int mfi_add_sys_pd(struct mfi_softc *sc, int id)
1910233711Sambrisko{
1911233711Sambrisko	struct mfi_command *cm;
1912233711Sambrisko	struct mfi_dcmd_frame *dcmd = NULL;
1913233711Sambrisko	struct mfi_pd_info *pd_info = NULL;
1914242681Sambrisko	struct mfi_system_pending *syspd_pend;
1915233711Sambrisko	int error;
1916233711Sambrisko
1917233711Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1918233711Sambrisko
1919242681Sambrisko	syspd_pend = malloc(sizeof(*syspd_pend), M_MFIBUF, M_NOWAIT | M_ZERO);
1920242681Sambrisko	if (syspd_pend != NULL) {
1921242681Sambrisko		syspd_pend->pd_id = id;
1922242681Sambrisko		TAILQ_INSERT_TAIL(&sc->mfi_syspd_pend_tqh, syspd_pend, pd_link);
1923242681Sambrisko	}
1924242681Sambrisko
1925233711Sambrisko	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_GET_INFO,
1926233711Sambrisko		(void **)&pd_info, sizeof(*pd_info));
1927233711Sambrisko	if (error) {
1928233711Sambrisko		device_printf(sc->mfi_dev,
1929233711Sambrisko		    "Failed to allocated for MFI_DCMD_PD_GET_INFO %d\n",
1930233711Sambrisko		    error);
1931233711Sambrisko		if (pd_info)
1932233711Sambrisko			free(pd_info, M_MFIBUF);
1933233711Sambrisko		return (error);
1934233711Sambrisko	}
1935233711Sambrisko	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1936233711Sambrisko	dcmd = &cm->cm_frame->dcmd;
1937233711Sambrisko	dcmd->mbox[0]=id;
1938233711Sambrisko	dcmd->header.scsi_status = 0;
1939233711Sambrisko	dcmd->header.pad0 = 0;
1940233711Sambrisko	if (mfi_mapcmd(sc, cm) != 0) {
1941233711Sambrisko		device_printf(sc->mfi_dev,
1942233711Sambrisko		    "Failed to get physical drive info %d\n", id);
1943233711Sambrisko		free(pd_info, M_MFIBUF);
1944233711Sambrisko		return (0);
1945233711Sambrisko	}
1946233711Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1947233711Sambrisko	    BUS_DMASYNC_POSTREAD);
1948233711Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1949233711Sambrisko	mfi_add_sys_pd_complete(cm);
1950233711Sambrisko	return (0);
1951233711Sambrisko}
1952233711Sambrisko
1953233711Sambriskostatic void
1954233711Sambriskomfi_add_sys_pd_complete(struct mfi_command *cm)
1955233711Sambrisko{
1956233711Sambrisko	struct mfi_frame_header *hdr;
1957233711Sambrisko	struct mfi_pd_info *pd_info;
1958233711Sambrisko	struct mfi_softc *sc;
1959233711Sambrisko	device_t child;
1960233711Sambrisko
1961233711Sambrisko	sc = cm->cm_sc;
1962233711Sambrisko	hdr = &cm->cm_frame->header;
1963233711Sambrisko	pd_info = cm->cm_private;
1964233711Sambrisko
1965233711Sambrisko	if (hdr->cmd_status != MFI_STAT_OK) {
1966233711Sambrisko		free(pd_info, M_MFIBUF);
1967233711Sambrisko		mfi_release_command(cm);
1968233711Sambrisko		return;
1969233711Sambrisko	}
1970233711Sambrisko	if (pd_info->fw_state != MFI_PD_STATE_SYSTEM) {
1971233711Sambrisko		device_printf(sc->mfi_dev, "PD=%x is not SYSTEM PD\n",
1972233711Sambrisko		    pd_info->ref.v.device_id);
1973233711Sambrisko		free(pd_info, M_MFIBUF);
1974233711Sambrisko		mfi_release_command(cm);
1975233711Sambrisko		return;
1976233711Sambrisko	}
1977233711Sambrisko	mfi_release_command(cm);
1978233711Sambrisko
1979233711Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1980233711Sambrisko	mtx_lock(&Giant);
1981233711Sambrisko	if ((child = device_add_child(sc->mfi_dev, "mfisyspd", -1)) == NULL) {
1982233711Sambrisko		device_printf(sc->mfi_dev, "Failed to add system pd\n");
1983233711Sambrisko		free(pd_info, M_MFIBUF);
1984233711Sambrisko		mtx_unlock(&Giant);
1985233711Sambrisko		mtx_lock(&sc->mfi_io_lock);
1986233711Sambrisko		return;
1987233711Sambrisko	}
1988233711Sambrisko
1989233711Sambrisko	device_set_ivars(child, pd_info);
1990233711Sambrisko	device_set_desc(child, "MFI System PD");
1991233711Sambrisko	bus_generic_attach(sc->mfi_dev);
1992233711Sambrisko	mtx_unlock(&Giant);
1993233711Sambrisko	mtx_lock(&sc->mfi_io_lock);
1994233711Sambrisko}
1995235016Sambrisko
1996157114Sscottlstatic struct mfi_command *
1997157114Sscottlmfi_bio_command(struct mfi_softc *sc)
1998157114Sscottl{
1999157114Sscottl	struct bio *bio;
2000233711Sambrisko	struct mfi_command *cm = NULL;
2001157114Sscottl
2002233711Sambrisko	/*reserving two commands to avoid starvation for IOCTL*/
2003235016Sambrisko	if (sc->mfi_qstat[MFIQ_FREE].q_length < 2) {
2004157114Sscottl		return (NULL);
2005233711Sambrisko	}
2006157114Sscottl	if ((bio = mfi_dequeue_bio(sc)) == NULL) {
2007157114Sscottl		return (NULL);
2008157114Sscottl	}
2009233711Sambrisko	if ((uintptr_t)bio->bio_driver2 == MFI_LD_IO) {
2010233711Sambrisko		cm = mfi_build_ldio(sc, bio);
2011233711Sambrisko	} else if ((uintptr_t) bio->bio_driver2 == MFI_SYS_PD_IO) {
2012233711Sambrisko		cm = mfi_build_syspdio(sc, bio);
2013233711Sambrisko	}
2014233711Sambrisko	if (!cm)
2015233711Sambrisko	    mfi_enqueue_bio(sc, bio);
2016233711Sambrisko	return cm;
2017233711Sambrisko}
2018242497Sdelphij
2019242681Sambrisko/*
2020242681Sambrisko * mostly copied from cam/scsi/scsi_all.c:scsi_read_write
2021242681Sambrisko */
2022242681Sambrisko
2023242681Sambriskoint
2024242681Sambriskomfi_build_cdb(int readop, uint8_t byte2, u_int64_t lba, u_int32_t block_count, uint8_t *cdb)
2025242497Sdelphij{
2026242497Sdelphij	int cdb_len;
2027242497Sdelphij
2028242497Sdelphij	if (((lba & 0x1fffff) == lba)
2029242497Sdelphij         && ((block_count & 0xff) == block_count)
2030242497Sdelphij         && (byte2 == 0)) {
2031242497Sdelphij		/* We can fit in a 6 byte cdb */
2032242497Sdelphij		struct scsi_rw_6 *scsi_cmd;
2033242497Sdelphij
2034242681Sambrisko		scsi_cmd = (struct scsi_rw_6 *)cdb;
2035242497Sdelphij		scsi_cmd->opcode = readop ? READ_6 : WRITE_6;
2036242497Sdelphij		scsi_ulto3b(lba, scsi_cmd->addr);
2037242497Sdelphij		scsi_cmd->length = block_count & 0xff;
2038242497Sdelphij		scsi_cmd->control = 0;
2039242497Sdelphij		cdb_len = sizeof(*scsi_cmd);
2040242497Sdelphij	} else if (((block_count & 0xffff) == block_count) && ((lba & 0xffffffff) == lba)) {
2041242497Sdelphij		/* Need a 10 byte CDB */
2042242497Sdelphij		struct scsi_rw_10 *scsi_cmd;
2043242497Sdelphij
2044242681Sambrisko		scsi_cmd = (struct scsi_rw_10 *)cdb;
2045242497Sdelphij		scsi_cmd->opcode = readop ? READ_10 : WRITE_10;
2046242497Sdelphij		scsi_cmd->byte2 = byte2;
2047242497Sdelphij		scsi_ulto4b(lba, scsi_cmd->addr);
2048242497Sdelphij		scsi_cmd->reserved = 0;
2049242497Sdelphij		scsi_ulto2b(block_count, scsi_cmd->length);
2050242497Sdelphij		scsi_cmd->control = 0;
2051242497Sdelphij		cdb_len = sizeof(*scsi_cmd);
2052242497Sdelphij	} else if (((block_count & 0xffffffff) == block_count) &&
2053242497Sdelphij	    ((lba & 0xffffffff) == lba)) {
2054242497Sdelphij		/* Block count is too big for 10 byte CDB use a 12 byte CDB */
2055242497Sdelphij		struct scsi_rw_12 *scsi_cmd;
2056242497Sdelphij
2057242681Sambrisko		scsi_cmd = (struct scsi_rw_12 *)cdb;
2058242497Sdelphij		scsi_cmd->opcode = readop ? READ_12 : WRITE_12;
2059242497Sdelphij		scsi_cmd->byte2 = byte2;
2060242497Sdelphij		scsi_ulto4b(lba, scsi_cmd->addr);
2061242497Sdelphij		scsi_cmd->reserved = 0;
2062242497Sdelphij		scsi_ulto4b(block_count, scsi_cmd->length);
2063242497Sdelphij		scsi_cmd->control = 0;
2064242497Sdelphij		cdb_len = sizeof(*scsi_cmd);
2065242497Sdelphij	} else {
2066242497Sdelphij		/*
2067242497Sdelphij		 * 16 byte CDB.  We'll only get here if the LBA is larger
2068242497Sdelphij		 * than 2^32
2069242497Sdelphij		 */
2070242497Sdelphij		struct scsi_rw_16 *scsi_cmd;
2071242497Sdelphij
2072242681Sambrisko		scsi_cmd = (struct scsi_rw_16 *)cdb;
2073242497Sdelphij		scsi_cmd->opcode = readop ? READ_16 : WRITE_16;
2074242497Sdelphij		scsi_cmd->byte2 = byte2;
2075242497Sdelphij		scsi_u64to8b(lba, scsi_cmd->addr);
2076242497Sdelphij		scsi_cmd->reserved = 0;
2077242497Sdelphij		scsi_ulto4b(block_count, scsi_cmd->length);
2078242497Sdelphij		scsi_cmd->control = 0;
2079242497Sdelphij		cdb_len = sizeof(*scsi_cmd);
2080242497Sdelphij	}
2081242497Sdelphij
2082242497Sdelphij	return cdb_len;
2083242497Sdelphij}
2084242497Sdelphij
2085233711Sambriskostatic struct mfi_command *
2086233711Sambriskomfi_build_syspdio(struct mfi_softc *sc, struct bio *bio)
2087233711Sambrisko{
2088233711Sambrisko	struct mfi_command *cm;
2089233711Sambrisko	struct mfi_pass_frame *pass;
2090242681Sambrisko	uint32_t context = 0;
2091242681Sambrisko	int flags = 0, blkcount = 0, readop;
2092242497Sdelphij	uint8_t cdb_len;
2093157114Sscottl
2094233711Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL)
2095233711Sambrisko	    return (NULL);
2096233711Sambrisko
2097233711Sambrisko	/* Zero out the MFI frame */
2098242681Sambrisko	context = cm->cm_frame->header.context;
2099233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
2100233711Sambrisko	cm->cm_frame->header.context = context;
2101233711Sambrisko	pass = &cm->cm_frame->pass;
2102233711Sambrisko	bzero(pass->cdb, 16);
2103233711Sambrisko	pass->header.cmd = MFI_CMD_PD_SCSI_IO;
2104233711Sambrisko	switch (bio->bio_cmd & 0x03) {
2105233711Sambrisko	case BIO_READ:
2106233711Sambrisko		flags = MFI_CMD_DATAIN;
2107242681Sambrisko		readop = 1;
2108233711Sambrisko		break;
2109233711Sambrisko	case BIO_WRITE:
2110233711Sambrisko		flags = MFI_CMD_DATAOUT;
2111242681Sambrisko		readop = 0;
2112233711Sambrisko		break;
2113233711Sambrisko	default:
2114242497Sdelphij		/* TODO: what about BIO_DELETE??? */
2115242681Sambrisko		panic("Unsupported bio command %x\n", bio->bio_cmd);
2116233711Sambrisko	}
2117233711Sambrisko
2118233711Sambrisko	/* Cheat with the sector length to avoid a non-constant division */
2119242681Sambrisko	blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2120233711Sambrisko	/* Fill the LBA and Transfer length in CDB */
2121242681Sambrisko	cdb_len = mfi_build_cdb(readop, 0, bio->bio_pblkno, blkcount,
2122242681Sambrisko	    pass->cdb);
2123233711Sambrisko	pass->header.target_id = (uintptr_t)bio->bio_driver1;
2124242681Sambrisko	pass->header.lun_id = 0;
2125233711Sambrisko	pass->header.timeout = 0;
2126233711Sambrisko	pass->header.flags = 0;
2127233711Sambrisko	pass->header.scsi_status = 0;
2128233711Sambrisko	pass->header.sense_len = MFI_SENSE_LEN;
2129233711Sambrisko	pass->header.data_len = bio->bio_bcount;
2130242497Sdelphij	pass->header.cdb_len = cdb_len;
2131233711Sambrisko	pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2132233711Sambrisko	pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2133233711Sambrisko	cm->cm_complete = mfi_bio_complete;
2134233711Sambrisko	cm->cm_private = bio;
2135233711Sambrisko	cm->cm_data = bio->bio_data;
2136233711Sambrisko	cm->cm_len = bio->bio_bcount;
2137233711Sambrisko	cm->cm_sg = &pass->sgl;
2138233711Sambrisko	cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
2139233711Sambrisko	cm->cm_flags = flags;
2140233711Sambrisko	return (cm);
2141233711Sambrisko}
2142233711Sambrisko
2143233711Sambriskostatic struct mfi_command *
2144233711Sambriskomfi_build_ldio(struct mfi_softc *sc, struct bio *bio)
2145233711Sambrisko{
2146233711Sambrisko	struct mfi_io_frame *io;
2147233711Sambrisko	struct mfi_command *cm;
2148242497Sdelphij	int flags;
2149242497Sdelphij	uint32_t blkcount;
2150233711Sambrisko	uint32_t context = 0;
2151233711Sambrisko
2152233711Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL)
2153233711Sambrisko	    return (NULL);
2154233711Sambrisko
2155233711Sambrisko	/* Zero out the MFI frame */
2156233711Sambrisko	context = cm->cm_frame->header.context;
2157233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
2158233711Sambrisko	cm->cm_frame->header.context = context;
2159157114Sscottl	io = &cm->cm_frame->io;
2160157114Sscottl	switch (bio->bio_cmd & 0x03) {
2161157114Sscottl	case BIO_READ:
2162157114Sscottl		io->header.cmd = MFI_CMD_LD_READ;
2163157114Sscottl		flags = MFI_CMD_DATAIN;
2164157114Sscottl		break;
2165157114Sscottl	case BIO_WRITE:
2166157114Sscottl		io->header.cmd = MFI_CMD_LD_WRITE;
2167157114Sscottl		flags = MFI_CMD_DATAOUT;
2168157114Sscottl		break;
2169157114Sscottl	default:
2170242497Sdelphij		/* TODO: what about BIO_DELETE??? */
2171242681Sambrisko		panic("Unsupported bio command %x\n", bio->bio_cmd);
2172157114Sscottl	}
2173157114Sscottl
2174157114Sscottl	/* Cheat with the sector length to avoid a non-constant division */
2175157114Sscottl	blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2176157114Sscottl	io->header.target_id = (uintptr_t)bio->bio_driver1;
2177157114Sscottl	io->header.timeout = 0;
2178157114Sscottl	io->header.flags = 0;
2179233711Sambrisko	io->header.scsi_status = 0;
2180157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
2181157114Sscottl	io->header.data_len = blkcount;
2182233711Sambrisko	io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2183233711Sambrisko	io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2184157114Sscottl	io->lba_hi = (bio->bio_pblkno & 0xffffffff00000000) >> 32;
2185157114Sscottl	io->lba_lo = bio->bio_pblkno & 0xffffffff;
2186157114Sscottl	cm->cm_complete = mfi_bio_complete;
2187157114Sscottl	cm->cm_private = bio;
2188157114Sscottl	cm->cm_data = bio->bio_data;
2189157114Sscottl	cm->cm_len = bio->bio_bcount;
2190157114Sscottl	cm->cm_sg = &io->sgl;
2191157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
2192157114Sscottl	cm->cm_flags = flags;
2193157114Sscottl	return (cm);
2194157114Sscottl}
2195157114Sscottl
2196157114Sscottlstatic void
2197157114Sscottlmfi_bio_complete(struct mfi_command *cm)
2198157114Sscottl{
2199157114Sscottl	struct bio *bio;
2200157114Sscottl	struct mfi_frame_header *hdr;
2201157114Sscottl	struct mfi_softc *sc;
2202157114Sscottl
2203157114Sscottl	bio = cm->cm_private;
2204157114Sscottl	hdr = &cm->cm_frame->header;
2205157114Sscottl	sc = cm->cm_sc;
2206157114Sscottl
2207224039Sjhb	if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0)) {
2208157114Sscottl		bio->bio_flags |= BIO_ERROR;
2209157114Sscottl		bio->bio_error = EIO;
2210157114Sscottl		device_printf(sc->mfi_dev, "I/O error, status= %d "
2211157114Sscottl		    "scsi_status= %d\n", hdr->cmd_status, hdr->scsi_status);
2212157114Sscottl		mfi_print_sense(cm->cm_sc, cm->cm_sense);
2213184897Sambrisko	} else if (cm->cm_error != 0) {
2214184897Sambrisko		bio->bio_flags |= BIO_ERROR;
2215157114Sscottl	}
2216157114Sscottl
2217157114Sscottl	mfi_release_command(cm);
2218157114Sscottl	mfi_disk_complete(bio);
2219157114Sscottl}
2220157114Sscottl
2221157114Sscottlvoid
2222157114Sscottlmfi_startio(struct mfi_softc *sc)
2223157114Sscottl{
2224157114Sscottl	struct mfi_command *cm;
2225169611Sscottl	struct ccb_hdr *ccbh;
2226157114Sscottl
2227157114Sscottl	for (;;) {
2228157114Sscottl		/* Don't bother if we're short on resources */
2229157114Sscottl		if (sc->mfi_flags & MFI_FLAGS_QFRZN)
2230157114Sscottl			break;
2231157114Sscottl
2232157114Sscottl		/* Try a command that has already been prepared */
2233157114Sscottl		cm = mfi_dequeue_ready(sc);
2234157114Sscottl
2235169611Sscottl		if (cm == NULL) {
2236169611Sscottl			if ((ccbh = TAILQ_FIRST(&sc->mfi_cam_ccbq)) != NULL)
2237169611Sscottl				cm = sc->mfi_cam_start(ccbh);
2238169611Sscottl		}
2239169611Sscottl
2240157114Sscottl		/* Nope, so look for work on the bioq */
2241157114Sscottl		if (cm == NULL)
2242157114Sscottl			cm = mfi_bio_command(sc);
2243157114Sscottl
2244157114Sscottl		/* No work available, so exit */
2245157114Sscottl		if (cm == NULL)
2246157114Sscottl			break;
2247157114Sscottl
2248157114Sscottl		/* Send the command to the controller */
2249157114Sscottl		if (mfi_mapcmd(sc, cm) != 0) {
2250157114Sscottl			mfi_requeue_ready(cm);
2251157114Sscottl			break;
2252157114Sscottl		}
2253157114Sscottl	}
2254157114Sscottl}
2255157114Sscottl
2256233711Sambriskoint
2257157114Sscottlmfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm)
2258157114Sscottl{
2259157114Sscottl	int error, polled;
2260157114Sscottl
2261163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2262163398Sscottl
2263233711Sambrisko	if ((cm->cm_data != NULL) && (cm->cm_frame->header.cmd != MFI_CMD_STP )) {
2264157114Sscottl		polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0;
2265157114Sscottl		error = bus_dmamap_load(sc->mfi_buffer_dmat, cm->cm_dmamap,
2266157114Sscottl		    cm->cm_data, cm->cm_len, mfi_data_cb, cm, polled);
2267157114Sscottl		if (error == EINPROGRESS) {
2268157114Sscottl			sc->mfi_flags |= MFI_FLAGS_QFRZN;
2269157114Sscottl			return (0);
2270157114Sscottl		}
2271157114Sscottl	} else {
2272233711Sambrisko		if (sc->MFA_enabled)
2273233711Sambrisko			error = mfi_tbolt_send_frame(sc, cm);
2274233711Sambrisko		else
2275233711Sambrisko			error = mfi_send_frame(sc, cm);
2276157114Sscottl	}
2277157114Sscottl
2278157114Sscottl	return (error);
2279157114Sscottl}
2280157114Sscottl
2281157114Sscottlstatic void
2282157114Sscottlmfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
2283157114Sscottl{
2284157114Sscottl	struct mfi_frame_header *hdr;
2285157114Sscottl	struct mfi_command *cm;
2286157237Sscottl	union mfi_sgl *sgl;
2287157114Sscottl	struct mfi_softc *sc;
2288225869Smav	int i, j, first, dir;
2289233711Sambrisko	int sge_size;
2290157114Sscottl
2291157114Sscottl	cm = (struct mfi_command *)arg;
2292157114Sscottl	sc = cm->cm_sc;
2293157237Sscottl	hdr = &cm->cm_frame->header;
2294157237Sscottl	sgl = cm->cm_sg;
2295157114Sscottl
2296170284Sambrisko	if (error) {
2297170284Sambrisko		printf("error %d in callback\n", error);
2298170284Sambrisko		cm->cm_error = error;
2299170284Sambrisko		mfi_complete(sc, cm);
2300170284Sambrisko		return;
2301170284Sambrisko	}
2302233711Sambrisko	/* Use IEEE sgl only for IO's on a SKINNY controller
2303233711Sambrisko	 * For other commands on a SKINNY controller use either
2304233711Sambrisko	 * sg32 or sg64 based on the sizeof(bus_addr_t).
2305233711Sambrisko	 * Also calculate the total frame size based on the type
2306233711Sambrisko	 * of SGL used.
2307233711Sambrisko	 */
2308233711Sambrisko	if (((cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) ||
2309233711Sambrisko	    (cm->cm_frame->header.cmd == MFI_CMD_LD_READ) ||
2310233711Sambrisko	    (cm->cm_frame->header.cmd == MFI_CMD_LD_WRITE)) &&
2311233711Sambrisko	    (sc->mfi_flags & MFI_FLAGS_SKINNY)) {
2312157237Sscottl		for (i = 0; i < nsegs; i++) {
2313233711Sambrisko			sgl->sg_skinny[i].addr = segs[i].ds_addr;
2314233711Sambrisko			sgl->sg_skinny[i].len = segs[i].ds_len;
2315233711Sambrisko			sgl->sg_skinny[i].flag = 0;
2316157114Sscottl		}
2317233711Sambrisko		hdr->flags |= MFI_FRAME_IEEE_SGL | MFI_FRAME_SGL64;
2318233711Sambrisko		sge_size = sizeof(struct mfi_sg_skinny);
2319233711Sambrisko		hdr->sg_count = nsegs;
2320157237Sscottl	} else {
2321233711Sambrisko		j = 0;
2322233711Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
2323233711Sambrisko			first = cm->cm_stp_len;
2324233711Sambrisko			if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
2325233711Sambrisko				sgl->sg32[j].addr = segs[0].ds_addr;
2326233711Sambrisko				sgl->sg32[j++].len = first;
2327233711Sambrisko			} else {
2328233711Sambrisko				sgl->sg64[j].addr = segs[0].ds_addr;
2329233711Sambrisko				sgl->sg64[j++].len = first;
2330233711Sambrisko			}
2331233711Sambrisko		} else
2332225869Smav			first = 0;
2333233711Sambrisko		if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
2334233711Sambrisko			for (i = 0; i < nsegs; i++) {
2335233711Sambrisko				sgl->sg32[j].addr = segs[i].ds_addr + first;
2336233711Sambrisko				sgl->sg32[j++].len = segs[i].ds_len - first;
2337233711Sambrisko				first = 0;
2338233711Sambrisko			}
2339233711Sambrisko		} else {
2340233711Sambrisko			for (i = 0; i < nsegs; i++) {
2341233711Sambrisko				sgl->sg64[j].addr = segs[i].ds_addr + first;
2342233711Sambrisko				sgl->sg64[j++].len = segs[i].ds_len - first;
2343233711Sambrisko				first = 0;
2344233711Sambrisko			}
2345233711Sambrisko			hdr->flags |= MFI_FRAME_SGL64;
2346157237Sscottl		}
2347233711Sambrisko		hdr->sg_count = j;
2348233711Sambrisko		sge_size = sc->mfi_sge_size;
2349157114Sscottl	}
2350157114Sscottl
2351157114Sscottl	dir = 0;
2352157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAIN) {
2353157114Sscottl		dir |= BUS_DMASYNC_PREREAD;
2354157114Sscottl		hdr->flags |= MFI_FRAME_DIR_READ;
2355157114Sscottl	}
2356157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAOUT) {
2357157114Sscottl		dir |= BUS_DMASYNC_PREWRITE;
2358157114Sscottl		hdr->flags |= MFI_FRAME_DIR_WRITE;
2359157114Sscottl	}
2360157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
2361157114Sscottl	cm->cm_flags |= MFI_CMD_MAPPED;
2362157114Sscottl
2363157114Sscottl	/*
2364157114Sscottl	 * Instead of calculating the total number of frames in the
2365157114Sscottl	 * compound frame, it's already assumed that there will be at
2366157114Sscottl	 * least 1 frame, so don't compensate for the modulo of the
2367157114Sscottl	 * following division.
2368157114Sscottl	 */
2369162458Sscottl	cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs);
2370157114Sscottl	cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
2371157114Sscottl
2372233711Sambrisko	if (sc->MFA_enabled)
2373233711Sambrisko			mfi_tbolt_send_frame(sc, cm);
2374233711Sambrisko	else
2375233711Sambrisko		mfi_send_frame(sc, cm);
2376157114Sscottl
2377157114Sscottl	return;
2378157114Sscottl}
2379157114Sscottl
2380157114Sscottlstatic int
2381157114Sscottlmfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
2382157114Sscottl{
2383164375Sscottl	struct mfi_frame_header *hdr;
2384165225Sambrisko	int tm = MFI_POLL_TIMEOUT_SECS * 1000;
2385157114Sscottl
2386164375Sscottl	hdr = &cm->cm_frame->header;
2387164375Sscottl
2388164375Sscottl	if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
2389164375Sscottl		cm->cm_timestamp = time_uptime;
2390164375Sscottl		mfi_enqueue_busy(cm);
2391164375Sscottl	} else {
2392224039Sjhb		hdr->cmd_status = MFI_STAT_INVALID_STATUS;
2393164375Sscottl		hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
2394164375Sscottl	}
2395164375Sscottl
2396157114Sscottl	/*
2397157114Sscottl	 * The bus address of the command is aligned on a 64 byte boundary,
2398157114Sscottl	 * leaving the least 6 bits as zero.  For whatever reason, the
2399157114Sscottl	 * hardware wants the address shifted right by three, leaving just
2400162458Sscottl	 * 3 zero bits.  These three bits are then used as a prefetching
2401162458Sscottl	 * hint for the hardware to predict how many frames need to be
2402162458Sscottl	 * fetched across the bus.  If a command has more than 8 frames
2403162458Sscottl	 * then the 3 bits are set to 0x7 and the firmware uses other
2404162458Sscottl	 * information in the command to determine the total amount to fetch.
2405162458Sscottl	 * However, FreeBSD doesn't support I/O larger than 128K, so 8 frames
2406162458Sscottl	 * is enough for both 32bit and 64bit systems.
2407157114Sscottl	 */
2408162458Sscottl	if (cm->cm_extra_frames > 7)
2409162458Sscottl		cm->cm_extra_frames = 7;
2410162458Sscottl
2411233711Sambrisko	sc->mfi_issue_cmd(sc, cm->cm_frame_busaddr, cm->cm_extra_frames);
2412164375Sscottl
2413164375Sscottl	if ((cm->cm_flags & MFI_CMD_POLLED) == 0)
2414164375Sscottl		return (0);
2415164375Sscottl
2416164375Sscottl	/* This is a polled command, so busy-wait for it to complete. */
2417224039Sjhb	while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
2418164375Sscottl		DELAY(1000);
2419165225Sambrisko		tm -= 1;
2420164375Sscottl		if (tm <= 0)
2421164375Sscottl			break;
2422164375Sscottl	}
2423164375Sscottl
2424224039Sjhb	if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
2425165225Sambrisko		device_printf(sc->mfi_dev, "Frame %p timed out "
2426233711Sambrisko		    "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
2427164375Sscottl		return (ETIMEDOUT);
2428164375Sscottl	}
2429164375Sscottl
2430157114Sscottl	return (0);
2431157114Sscottl}
2432157114Sscottl
2433233711Sambrisko
2434233711Sambriskovoid
2435157114Sscottlmfi_complete(struct mfi_softc *sc, struct mfi_command *cm)
2436157114Sscottl{
2437157114Sscottl	int dir;
2438157114Sscottl
2439157114Sscottl	if ((cm->cm_flags & MFI_CMD_MAPPED) != 0) {
2440157114Sscottl		dir = 0;
2441225869Smav		if ((cm->cm_flags & MFI_CMD_DATAIN) ||
2442225869Smav		    (cm->cm_frame->header.cmd == MFI_CMD_STP))
2443157114Sscottl			dir |= BUS_DMASYNC_POSTREAD;
2444157114Sscottl		if (cm->cm_flags & MFI_CMD_DATAOUT)
2445157114Sscottl			dir |= BUS_DMASYNC_POSTWRITE;
2446157114Sscottl
2447157114Sscottl		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
2448157114Sscottl		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
2449157114Sscottl		cm->cm_flags &= ~MFI_CMD_MAPPED;
2450157114Sscottl	}
2451157114Sscottl
2452170284Sambrisko	cm->cm_flags |= MFI_CMD_COMPLETED;
2453170284Sambrisko
2454157114Sscottl	if (cm->cm_complete != NULL)
2455157114Sscottl		cm->cm_complete(cm);
2456159811Sps	else
2457159811Sps		wakeup(cm);
2458157114Sscottl}
2459157114Sscottl
2460158737Sambriskostatic int
2461242681Sambriskomfi_abort(struct mfi_softc *sc, struct mfi_command **cm_abort)
2462158737Sambrisko{
2463158737Sambrisko	struct mfi_command *cm;
2464158737Sambrisko	struct mfi_abort_frame *abort;
2465165225Sambrisko	int i = 0;
2466233711Sambrisko	uint32_t context = 0;
2467158737Sambrisko
2468242681Sambrisko	mtx_lock(&sc->mfi_io_lock);
2469158737Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL) {
2470158737Sambrisko		return (EBUSY);
2471158737Sambrisko	}
2472158737Sambrisko
2473233711Sambrisko	/* Zero out the MFI frame */
2474233711Sambrisko	context = cm->cm_frame->header.context;
2475233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
2476233711Sambrisko	cm->cm_frame->header.context = context;
2477233711Sambrisko
2478158737Sambrisko	abort = &cm->cm_frame->abort;
2479158737Sambrisko	abort->header.cmd = MFI_CMD_ABORT;
2480158737Sambrisko	abort->header.flags = 0;
2481233711Sambrisko	abort->header.scsi_status = 0;
2482242681Sambrisko	abort->abort_context = (*cm_abort)->cm_frame->header.context;
2483242681Sambrisko	abort->abort_mfi_addr_lo = (uint32_t)(*cm_abort)->cm_frame_busaddr;
2484233711Sambrisko	abort->abort_mfi_addr_hi =
2485242681Sambrisko		(uint32_t)((uint64_t)(*cm_abort)->cm_frame_busaddr >> 32);
2486158737Sambrisko	cm->cm_data = NULL;
2487164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
2488158737Sambrisko
2489158737Sambrisko	mfi_mapcmd(sc, cm);
2490158737Sambrisko	mfi_release_command(cm);
2491158737Sambrisko
2492242681Sambrisko	mtx_unlock(&sc->mfi_io_lock);
2493242681Sambrisko	while (i < 5 && *cm_abort != NULL) {
2494242681Sambrisko		tsleep(cm_abort, 0, "mfiabort",
2495233711Sambrisko		    5 * hz);
2496165225Sambrisko		i++;
2497158737Sambrisko	}
2498242681Sambrisko	if (*cm_abort != NULL) {
2499242681Sambrisko		/* Force a complete if command didn't abort */
2500242681Sambrisko		mtx_lock(&sc->mfi_io_lock);
2501242681Sambrisko		(*cm_abort)->cm_complete(*cm_abort);
2502242681Sambrisko		mtx_unlock(&sc->mfi_io_lock);
2503235014Sambrisko	}
2504158737Sambrisko
2505158737Sambrisko	return (0);
2506158737Sambrisko}
2507158737Sambrisko
2508157114Sscottlint
2509233711Sambriskomfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt,
2510233711Sambrisko     int len)
2511157114Sscottl{
2512157114Sscottl	struct mfi_command *cm;
2513157114Sscottl	struct mfi_io_frame *io;
2514157114Sscottl	int error;
2515233711Sambrisko	uint32_t context = 0;
2516157114Sscottl
2517157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
2518157114Sscottl		return (EBUSY);
2519157114Sscottl
2520233711Sambrisko	/* Zero out the MFI frame */
2521233711Sambrisko	context = cm->cm_frame->header.context;
2522233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
2523233711Sambrisko	cm->cm_frame->header.context = context;
2524233711Sambrisko
2525157114Sscottl	io = &cm->cm_frame->io;
2526157114Sscottl	io->header.cmd = MFI_CMD_LD_WRITE;
2527157114Sscottl	io->header.target_id = id;
2528157114Sscottl	io->header.timeout = 0;
2529157114Sscottl	io->header.flags = 0;
2530233711Sambrisko	io->header.scsi_status = 0;
2531157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
2532157114Sscottl	io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2533233711Sambrisko	io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2534233711Sambrisko	io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2535157114Sscottl	io->lba_hi = (lba & 0xffffffff00000000) >> 32;
2536157114Sscottl	io->lba_lo = lba & 0xffffffff;
2537157114Sscottl	cm->cm_data = virt;
2538157114Sscottl	cm->cm_len = len;
2539157114Sscottl	cm->cm_sg = &io->sgl;
2540157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
2541157114Sscottl	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT;
2542157114Sscottl
2543164375Sscottl	error = mfi_mapcmd(sc, cm);
2544157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
2545157114Sscottl	    BUS_DMASYNC_POSTWRITE);
2546157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
2547157114Sscottl	mfi_release_command(cm);
2548157114Sscottl
2549157114Sscottl	return (error);
2550157114Sscottl}
2551157114Sscottl
2552233711Sambriskoint
2553233711Sambriskomfi_dump_syspd_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt,
2554233711Sambrisko    int len)
2555233711Sambrisko{
2556233711Sambrisko	struct mfi_command *cm;
2557233711Sambrisko	struct mfi_pass_frame *pass;
2558242681Sambrisko	int error, readop, cdb_len;
2559242497Sdelphij	uint32_t blkcount;
2560233711Sambrisko
2561233711Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL)
2562233711Sambrisko		return (EBUSY);
2563233711Sambrisko
2564233711Sambrisko	pass = &cm->cm_frame->pass;
2565233711Sambrisko	bzero(pass->cdb, 16);
2566233711Sambrisko	pass->header.cmd = MFI_CMD_PD_SCSI_IO;
2567242681Sambrisko
2568242681Sambrisko	readop = 0;
2569233711Sambrisko	blkcount = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2570242681Sambrisko	cdb_len = mfi_build_cdb(readop, 0, lba, blkcount, pass->cdb);
2571233711Sambrisko	pass->header.target_id = id;
2572233711Sambrisko	pass->header.timeout = 0;
2573233711Sambrisko	pass->header.flags = 0;
2574233711Sambrisko	pass->header.scsi_status = 0;
2575233711Sambrisko	pass->header.sense_len = MFI_SENSE_LEN;
2576233711Sambrisko	pass->header.data_len = len;
2577242681Sambrisko	pass->header.cdb_len = cdb_len;
2578233711Sambrisko	pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2579233711Sambrisko	pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2580233711Sambrisko	cm->cm_data = virt;
2581233711Sambrisko	cm->cm_len = len;
2582233711Sambrisko	cm->cm_sg = &pass->sgl;
2583233711Sambrisko	cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
2584242681Sambrisko	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT | MFI_CMD_SCSI;
2585233711Sambrisko
2586233711Sambrisko	error = mfi_mapcmd(sc, cm);
2587233711Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
2588233711Sambrisko	    BUS_DMASYNC_POSTWRITE);
2589233711Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
2590233711Sambrisko	mfi_release_command(cm);
2591233711Sambrisko
2592233711Sambrisko	return (error);
2593233711Sambrisko}
2594233711Sambrisko
2595157114Sscottlstatic int
2596192450Simpmfi_open(struct cdev *dev, int flags, int fmt, struct thread *td)
2597157114Sscottl{
2598157114Sscottl	struct mfi_softc *sc;
2599171822Sjhb	int error;
2600157114Sscottl
2601157114Sscottl	sc = dev->si_drv1;
2602163398Sscottl
2603163398Sscottl	mtx_lock(&sc->mfi_io_lock);
2604171822Sjhb	if (sc->mfi_detaching)
2605171822Sjhb		error = ENXIO;
2606171822Sjhb	else {
2607171822Sjhb		sc->mfi_flags |= MFI_FLAGS_OPEN;
2608171822Sjhb		error = 0;
2609171822Sjhb	}
2610163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
2611157114Sscottl
2612171822Sjhb	return (error);
2613157114Sscottl}
2614157114Sscottl
2615157114Sscottlstatic int
2616192450Simpmfi_close(struct cdev *dev, int flags, int fmt, struct thread *td)
2617157114Sscottl{
2618157114Sscottl	struct mfi_softc *sc;
2619163398Sscottl	struct mfi_aen *mfi_aen_entry, *tmp;
2620157114Sscottl
2621157114Sscottl	sc = dev->si_drv1;
2622163398Sscottl
2623163398Sscottl	mtx_lock(&sc->mfi_io_lock);
2624157114Sscottl	sc->mfi_flags &= ~MFI_FLAGS_OPEN;
2625157114Sscottl
2626163398Sscottl	TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
2627158737Sambrisko		if (mfi_aen_entry->p == curproc) {
2628158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
2629158737Sambrisko			    aen_link);
2630158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
2631158737Sambrisko		}
2632158737Sambrisko	}
2633163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
2634157114Sscottl	return (0);
2635157114Sscottl}
2636157114Sscottl
2637157114Sscottlstatic int
2638171821Sjhbmfi_config_lock(struct mfi_softc *sc, uint32_t opcode)
2639171821Sjhb{
2640171821Sjhb
2641171821Sjhb	switch (opcode) {
2642171821Sjhb	case MFI_DCMD_LD_DELETE:
2643171821Sjhb	case MFI_DCMD_CFG_ADD:
2644171821Sjhb	case MFI_DCMD_CFG_CLEAR:
2645240962Sjhb	case MFI_DCMD_CFG_FOREIGN_IMPORT:
2646171821Sjhb		sx_xlock(&sc->mfi_config_lock);
2647171821Sjhb		return (1);
2648171821Sjhb	default:
2649171821Sjhb		return (0);
2650171821Sjhb	}
2651171821Sjhb}
2652171821Sjhb
2653171821Sjhbstatic void
2654171821Sjhbmfi_config_unlock(struct mfi_softc *sc, int locked)
2655171821Sjhb{
2656171821Sjhb
2657171821Sjhb	if (locked)
2658171821Sjhb		sx_xunlock(&sc->mfi_config_lock);
2659171821Sjhb}
2660171821Sjhb
2661233711Sambrisko/*
2662233711Sambrisko * Perform pre-issue checks on commands from userland and possibly veto
2663233711Sambrisko * them.
2664233711Sambrisko */
2665171821Sjhbstatic int
2666171821Sjhbmfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm)
2667171821Sjhb{
2668171821Sjhb	struct mfi_disk *ld, *ld2;
2669171821Sjhb	int error;
2670233711Sambrisko	struct mfi_system_pd *syspd = NULL;
2671233711Sambrisko	uint16_t syspd_id;
2672233711Sambrisko	uint16_t *mbox;
2673171821Sjhb
2674171821Sjhb	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2675171821Sjhb	error = 0;
2676171821Sjhb	switch (cm->cm_frame->dcmd.opcode) {
2677171821Sjhb	case MFI_DCMD_LD_DELETE:
2678171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
2679171821Sjhb			if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
2680171821Sjhb				break;
2681171821Sjhb		}
2682171821Sjhb		if (ld == NULL)
2683171821Sjhb			error = ENOENT;
2684171821Sjhb		else
2685171821Sjhb			error = mfi_disk_disable(ld);
2686171821Sjhb		break;
2687171821Sjhb	case MFI_DCMD_CFG_CLEAR:
2688171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
2689171821Sjhb			error = mfi_disk_disable(ld);
2690171821Sjhb			if (error)
2691171821Sjhb				break;
2692171821Sjhb		}
2693171821Sjhb		if (error) {
2694171821Sjhb			TAILQ_FOREACH(ld2, &sc->mfi_ld_tqh, ld_link) {
2695171821Sjhb				if (ld2 == ld)
2696171821Sjhb					break;
2697171821Sjhb				mfi_disk_enable(ld2);
2698171821Sjhb			}
2699171821Sjhb		}
2700171821Sjhb		break;
2701233711Sambrisko	case MFI_DCMD_PD_STATE_SET:
2702233711Sambrisko		mbox = (uint16_t *) cm->cm_frame->dcmd.mbox;
2703233711Sambrisko		syspd_id = mbox[0];
2704233711Sambrisko		if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) {
2705233711Sambrisko			TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) {
2706233711Sambrisko				if (syspd->pd_id == syspd_id)
2707233711Sambrisko					break;
2708233711Sambrisko			}
2709233711Sambrisko		}
2710233711Sambrisko		else
2711233711Sambrisko			break;
2712233711Sambrisko		if (syspd)
2713233711Sambrisko			error = mfi_syspd_disable(syspd);
2714233711Sambrisko		break;
2715171821Sjhb	default:
2716171821Sjhb		break;
2717171821Sjhb	}
2718171821Sjhb	return (error);
2719171821Sjhb}
2720171821Sjhb
2721171821Sjhb/* Perform post-issue checks on commands from userland. */
2722171821Sjhbstatic void
2723171821Sjhbmfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm)
2724171821Sjhb{
2725171821Sjhb	struct mfi_disk *ld, *ldn;
2726233711Sambrisko	struct mfi_system_pd *syspd = NULL;
2727233711Sambrisko	uint16_t syspd_id;
2728233711Sambrisko	uint16_t *mbox;
2729171821Sjhb
2730171821Sjhb	switch (cm->cm_frame->dcmd.opcode) {
2731171821Sjhb	case MFI_DCMD_LD_DELETE:
2732171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
2733171821Sjhb			if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
2734171821Sjhb				break;
2735171821Sjhb		}
2736171821Sjhb		KASSERT(ld != NULL, ("volume dissappeared"));
2737171821Sjhb		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
2738171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
2739196403Sjhb			mtx_lock(&Giant);
2740171821Sjhb			device_delete_child(sc->mfi_dev, ld->ld_dev);
2741196403Sjhb			mtx_unlock(&Giant);
2742171821Sjhb			mtx_lock(&sc->mfi_io_lock);
2743171821Sjhb		} else
2744171821Sjhb			mfi_disk_enable(ld);
2745171821Sjhb		break;
2746171821Sjhb	case MFI_DCMD_CFG_CLEAR:
2747171821Sjhb		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
2748171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
2749196403Sjhb			mtx_lock(&Giant);
2750171821Sjhb			TAILQ_FOREACH_SAFE(ld, &sc->mfi_ld_tqh, ld_link, ldn) {
2751171821Sjhb				device_delete_child(sc->mfi_dev, ld->ld_dev);
2752171821Sjhb			}
2753196403Sjhb			mtx_unlock(&Giant);
2754171821Sjhb			mtx_lock(&sc->mfi_io_lock);
2755171821Sjhb		} else {
2756171821Sjhb			TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link)
2757171821Sjhb				mfi_disk_enable(ld);
2758171821Sjhb		}
2759171821Sjhb		break;
2760171821Sjhb	case MFI_DCMD_CFG_ADD:
2761171821Sjhb		mfi_ldprobe(sc);
2762171821Sjhb		break;
2763184897Sambrisko	case MFI_DCMD_CFG_FOREIGN_IMPORT:
2764184897Sambrisko		mfi_ldprobe(sc);
2765184897Sambrisko		break;
2766233711Sambrisko	case MFI_DCMD_PD_STATE_SET:
2767233711Sambrisko		mbox = (uint16_t *) cm->cm_frame->dcmd.mbox;
2768233711Sambrisko		syspd_id = mbox[0];
2769233711Sambrisko		if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) {
2770233711Sambrisko			TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) {
2771233711Sambrisko				if (syspd->pd_id == syspd_id)
2772233711Sambrisko					break;
2773233711Sambrisko			}
2774233711Sambrisko		}
2775233711Sambrisko		else
2776233711Sambrisko			break;
2777233711Sambrisko		/* If the transition fails then enable the syspd again */
2778233711Sambrisko		if (syspd && cm->cm_frame->header.cmd_status != MFI_STAT_OK)
2779233711Sambrisko			mfi_syspd_enable(syspd);
2780233711Sambrisko		break;
2781171821Sjhb	}
2782171821Sjhb}
2783171821Sjhb
2784242681Sambriskostatic int
2785242681Sambriskomfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm)
2786233711Sambrisko{
2787242681Sambrisko	struct mfi_config_data *conf_data;
2788233711Sambrisko	struct mfi_command *ld_cm = NULL;
2789233711Sambrisko	struct mfi_ld_info *ld_info = NULL;
2790242681Sambrisko	struct mfi_ld_config *ld;
2791242681Sambrisko	char *p;
2792233711Sambrisko	int error = 0;
2793233711Sambrisko
2794242681Sambrisko	conf_data = (struct mfi_config_data *)cm->cm_data;
2795242681Sambrisko
2796242681Sambrisko	if (cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) {
2797242681Sambrisko		p = (char *)conf_data->array;
2798242681Sambrisko		p += conf_data->array_size * conf_data->array_count;
2799242681Sambrisko		ld = (struct mfi_ld_config *)p;
2800242681Sambrisko		if (ld->params.isSSCD == 1)
2801242681Sambrisko			error = 1;
2802233711Sambrisko	} else if (cm->cm_frame->dcmd.opcode == MFI_DCMD_LD_DELETE) {
2803233711Sambrisko		error = mfi_dcmd_command (sc, &ld_cm, MFI_DCMD_LD_GET_INFO,
2804233711Sambrisko		    (void **)&ld_info, sizeof(*ld_info));
2805235016Sambrisko		if (error) {
2806233711Sambrisko			device_printf(sc->mfi_dev, "Failed to allocate"
2807233711Sambrisko			    "MFI_DCMD_LD_GET_INFO %d", error);
2808233711Sambrisko			if (ld_info)
2809233711Sambrisko				free(ld_info, M_MFIBUF);
2810233711Sambrisko			return 0;
2811233711Sambrisko		}
2812233711Sambrisko		ld_cm->cm_flags = MFI_CMD_DATAIN;
2813233711Sambrisko		ld_cm->cm_frame->dcmd.mbox[0]= cm->cm_frame->dcmd.mbox[0];
2814233711Sambrisko		ld_cm->cm_frame->header.target_id = cm->cm_frame->dcmd.mbox[0];
2815235016Sambrisko		if (mfi_wait_command(sc, ld_cm) != 0) {
2816233711Sambrisko			device_printf(sc->mfi_dev, "failed to get log drv\n");
2817233711Sambrisko			mfi_release_command(ld_cm);
2818233711Sambrisko			free(ld_info, M_MFIBUF);
2819233711Sambrisko			return 0;
2820233711Sambrisko		}
2821233711Sambrisko
2822233711Sambrisko		if (ld_cm->cm_frame->header.cmd_status != MFI_STAT_OK) {
2823233711Sambrisko			free(ld_info, M_MFIBUF);
2824233711Sambrisko			mfi_release_command(ld_cm);
2825233711Sambrisko			return 0;
2826233711Sambrisko		}
2827233711Sambrisko		else
2828233711Sambrisko			ld_info = (struct mfi_ld_info *)ld_cm->cm_private;
2829233711Sambrisko
2830233711Sambrisko		if (ld_info->ld_config.params.isSSCD == 1)
2831233711Sambrisko			error = 1;
2832233711Sambrisko
2833233711Sambrisko		mfi_release_command(ld_cm);
2834233711Sambrisko		free(ld_info, M_MFIBUF);
2835233711Sambrisko
2836233711Sambrisko	}
2837233711Sambrisko	return error;
2838233711Sambrisko}
2839233711Sambrisko
2840171821Sjhbstatic int
2841233711Sambriskomfi_stp_cmd(struct mfi_softc *sc, struct mfi_command *cm,caddr_t arg)
2842233711Sambrisko{
2843233711Sambrisko	uint8_t i;
2844233711Sambrisko	struct mfi_ioc_packet *ioc;
2845233711Sambrisko	ioc = (struct mfi_ioc_packet *)arg;
2846233711Sambrisko	int sge_size, error;
2847233711Sambrisko	struct megasas_sge *kern_sge;
2848233711Sambrisko
2849233711Sambrisko	memset(sc->kbuff_arr, 0, sizeof(sc->kbuff_arr));
2850233711Sambrisko	kern_sge =(struct megasas_sge *) ((uintptr_t)cm->cm_frame + ioc->mfi_sgl_off);
2851233711Sambrisko	cm->cm_frame->header.sg_count = ioc->mfi_sge_count;
2852233711Sambrisko
2853233711Sambrisko	if (sizeof(bus_addr_t) == 8) {
2854233711Sambrisko		cm->cm_frame->header.flags |= MFI_FRAME_SGL64;
2855233711Sambrisko		cm->cm_extra_frames = 2;
2856233711Sambrisko		sge_size = sizeof(struct mfi_sg64);
2857233711Sambrisko	} else {
2858233711Sambrisko		cm->cm_extra_frames =  (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
2859233711Sambrisko		sge_size = sizeof(struct mfi_sg32);
2860233711Sambrisko	}
2861233711Sambrisko
2862233711Sambrisko	cm->cm_total_frame_size += (sge_size * ioc->mfi_sge_count);
2863233711Sambrisko	for (i = 0; i < ioc->mfi_sge_count; i++) {
2864233711Sambrisko			if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
2865233711Sambrisko			1, 0,			/* algnmnt, boundary */
2866233711Sambrisko			BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
2867233711Sambrisko			BUS_SPACE_MAXADDR,	/* highaddr */
2868233711Sambrisko			NULL, NULL,		/* filter, filterarg */
2869233711Sambrisko			ioc->mfi_sgl[i].iov_len,/* maxsize */
2870233711Sambrisko			2,			/* nsegments */
2871233711Sambrisko			ioc->mfi_sgl[i].iov_len,/* maxsegsize */
2872233711Sambrisko			BUS_DMA_ALLOCNOW,	/* flags */
2873233711Sambrisko			NULL, NULL,		/* lockfunc, lockarg */
2874233711Sambrisko			&sc->mfi_kbuff_arr_dmat[i])) {
2875233711Sambrisko			device_printf(sc->mfi_dev,
2876233711Sambrisko			    "Cannot allocate mfi_kbuff_arr_dmat tag\n");
2877233711Sambrisko			return (ENOMEM);
2878233711Sambrisko		}
2879233711Sambrisko
2880233711Sambrisko		if (bus_dmamem_alloc(sc->mfi_kbuff_arr_dmat[i],
2881233711Sambrisko		    (void **)&sc->kbuff_arr[i], BUS_DMA_NOWAIT,
2882233711Sambrisko		    &sc->mfi_kbuff_arr_dmamap[i])) {
2883233711Sambrisko			device_printf(sc->mfi_dev,
2884233711Sambrisko			    "Cannot allocate mfi_kbuff_arr_dmamap memory\n");
2885233711Sambrisko			return (ENOMEM);
2886233711Sambrisko		}
2887233711Sambrisko
2888233711Sambrisko		bus_dmamap_load(sc->mfi_kbuff_arr_dmat[i],
2889233711Sambrisko		    sc->mfi_kbuff_arr_dmamap[i], sc->kbuff_arr[i],
2890233711Sambrisko		    ioc->mfi_sgl[i].iov_len, mfi_addr_cb,
2891233711Sambrisko		    &sc->mfi_kbuff_arr_busaddr[i], 0);
2892233711Sambrisko
2893233711Sambrisko		if (!sc->kbuff_arr[i]) {
2894233711Sambrisko			device_printf(sc->mfi_dev,
2895233711Sambrisko			    "Could not allocate memory for kbuff_arr info\n");
2896233711Sambrisko			return -1;
2897233711Sambrisko		}
2898233711Sambrisko		kern_sge[i].phys_addr = sc->mfi_kbuff_arr_busaddr[i];
2899233711Sambrisko		kern_sge[i].length = ioc->mfi_sgl[i].iov_len;
2900233711Sambrisko
2901233711Sambrisko		if (sizeof(bus_addr_t) == 8) {
2902233711Sambrisko			cm->cm_frame->stp.sgl.sg64[i].addr =
2903233711Sambrisko			    kern_sge[i].phys_addr;
2904233711Sambrisko			cm->cm_frame->stp.sgl.sg64[i].len =
2905233711Sambrisko			    ioc->mfi_sgl[i].iov_len;
2906233711Sambrisko		} else {
2907233711Sambrisko			cm->cm_frame->stp.sgl.sg32[i].len =
2908233711Sambrisko			    kern_sge[i].phys_addr;
2909233711Sambrisko			cm->cm_frame->stp.sgl.sg32[i].len =
2910233711Sambrisko			    ioc->mfi_sgl[i].iov_len;
2911233711Sambrisko		}
2912233711Sambrisko
2913233711Sambrisko		error = copyin(ioc->mfi_sgl[i].iov_base,
2914233711Sambrisko		    sc->kbuff_arr[i],
2915233711Sambrisko		    ioc->mfi_sgl[i].iov_len);
2916233711Sambrisko		if (error != 0) {
2917233711Sambrisko			device_printf(sc->mfi_dev, "Copy in failed\n");
2918233711Sambrisko			return error;
2919233711Sambrisko		}
2920233711Sambrisko	}
2921233711Sambrisko
2922233711Sambrisko	cm->cm_flags |=MFI_CMD_MAPPED;
2923233711Sambrisko	return 0;
2924233711Sambrisko}
2925233711Sambrisko
2926233711Sambriskostatic int
2927178968Sscottlmfi_user_command(struct mfi_softc *sc, struct mfi_ioc_passthru *ioc)
2928178968Sscottl{
2929178968Sscottl	struct mfi_command *cm;
2930178968Sscottl	struct mfi_dcmd_frame *dcmd;
2931178968Sscottl	void *ioc_buf = NULL;
2932178968Sscottl	uint32_t context;
2933178968Sscottl	int error = 0, locked;
2934178968Sscottl
2935178968Sscottl
2936178968Sscottl	if (ioc->buf_size > 0) {
2937238077Sjhb		if (ioc->buf_size > 1024 * 1024)
2938238077Sjhb			return (ENOMEM);
2939178968Sscottl		ioc_buf = malloc(ioc->buf_size, M_MFIBUF, M_WAITOK);
2940178968Sscottl		error = copyin(ioc->buf, ioc_buf, ioc->buf_size);
2941178968Sscottl		if (error) {
2942178968Sscottl			device_printf(sc->mfi_dev, "failed to copyin\n");
2943178968Sscottl			free(ioc_buf, M_MFIBUF);
2944178968Sscottl			return (error);
2945178968Sscottl		}
2946178968Sscottl	}
2947178968Sscottl
2948178968Sscottl	locked = mfi_config_lock(sc, ioc->ioc_frame.opcode);
2949178968Sscottl
2950178968Sscottl	mtx_lock(&sc->mfi_io_lock);
2951178968Sscottl	while ((cm = mfi_dequeue_free(sc)) == NULL)
2952178968Sscottl		msleep(mfi_user_command, &sc->mfi_io_lock, 0, "mfiioc", hz);
2953178968Sscottl
2954178968Sscottl	/* Save context for later */
2955178968Sscottl	context = cm->cm_frame->header.context;
2956178968Sscottl
2957178968Sscottl	dcmd = &cm->cm_frame->dcmd;
2958178968Sscottl	bcopy(&ioc->ioc_frame, dcmd, sizeof(struct mfi_dcmd_frame));
2959178968Sscottl
2960178968Sscottl	cm->cm_sg = &dcmd->sgl;
2961178968Sscottl	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
2962178968Sscottl	cm->cm_data = ioc_buf;
2963178968Sscottl	cm->cm_len = ioc->buf_size;
2964178968Sscottl
2965178968Sscottl	/* restore context */
2966178968Sscottl	cm->cm_frame->header.context = context;
2967178968Sscottl
2968178968Sscottl	/* Cheat since we don't know if we're writing or reading */
2969178968Sscottl	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
2970178968Sscottl
2971178968Sscottl	error = mfi_check_command_pre(sc, cm);
2972178968Sscottl	if (error)
2973178968Sscottl		goto out;
2974178968Sscottl
2975178968Sscottl	error = mfi_wait_command(sc, cm);
2976178968Sscottl	if (error) {
2977178968Sscottl		device_printf(sc->mfi_dev, "ioctl failed %d\n", error);
2978178968Sscottl		goto out;
2979178968Sscottl	}
2980178968Sscottl	bcopy(dcmd, &ioc->ioc_frame, sizeof(struct mfi_dcmd_frame));
2981178968Sscottl	mfi_check_command_post(sc, cm);
2982178968Sscottlout:
2983178968Sscottl	mfi_release_command(cm);
2984178968Sscottl	mtx_unlock(&sc->mfi_io_lock);
2985178968Sscottl	mfi_config_unlock(sc, locked);
2986178968Sscottl	if (ioc->buf_size > 0)
2987178968Sscottl		error = copyout(ioc_buf, ioc->buf, ioc->buf_size);
2988178968Sscottl	if (ioc_buf)
2989178968Sscottl		free(ioc_buf, M_MFIBUF);
2990178968Sscottl	return (error);
2991178968Sscottl}
2992178968Sscottl
2993178968Sscottl#define	PTRIN(p)		((void *)(uintptr_t)(p))
2994178968Sscottl
2995178968Sscottlstatic int
2996192450Simpmfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
2997157114Sscottl{
2998157114Sscottl	struct mfi_softc *sc;
2999157114Sscottl	union mfi_statrequest *ms;
3000164281Sambrisko	struct mfi_ioc_packet *ioc;
3001233711Sambrisko#ifdef COMPAT_FREEBSD32
3002179392Sambrisko	struct mfi_ioc_packet32 *ioc32;
3003179392Sambrisko#endif
3004164281Sambrisko	struct mfi_ioc_aen *aen;
3005164281Sambrisko	struct mfi_command *cm = NULL;
3006233711Sambrisko	uint32_t context = 0;
3007184897Sambrisko	union mfi_sense_ptr sense_ptr;
3008233711Sambrisko	uint8_t *data = NULL, *temp, *addr, skip_pre_post = 0;
3009225869Smav	size_t len;
3010233711Sambrisko	int i, res;
3011178968Sscottl	struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg;
3012233711Sambrisko#ifdef COMPAT_FREEBSD32
3013178968Sscottl	struct mfi_ioc_passthru32 *iop32 = (struct mfi_ioc_passthru32 *)arg;
3014178968Sscottl	struct mfi_ioc_passthru iop_swab;
3015178968Sscottl#endif
3016171821Sjhb	int error, locked;
3017233711Sambrisko	union mfi_sgl *sgl;
3018157114Sscottl	sc = dev->si_drv1;
3019157114Sscottl	error = 0;
3020157114Sscottl
3021233711Sambrisko	if (sc->adpreset)
3022233711Sambrisko		return EBUSY;
3023233711Sambrisko
3024233711Sambrisko	if (sc->hw_crit_error)
3025233711Sambrisko		return EBUSY;
3026233711Sambrisko
3027233711Sambrisko	if (sc->issuepend_done == 0)
3028233711Sambrisko		return EBUSY;
3029233711Sambrisko
3030157114Sscottl	switch (cmd) {
3031157114Sscottl	case MFIIO_STATS:
3032157114Sscottl		ms = (union mfi_statrequest *)arg;
3033157114Sscottl		switch (ms->ms_item) {
3034157114Sscottl		case MFIQ_FREE:
3035157114Sscottl		case MFIQ_BIO:
3036157114Sscottl		case MFIQ_READY:
3037157114Sscottl		case MFIQ_BUSY:
3038157114Sscottl			bcopy(&sc->mfi_qstat[ms->ms_item], &ms->ms_qstat,
3039157114Sscottl			    sizeof(struct mfi_qstat));
3040157114Sscottl			break;
3041157114Sscottl		default:
3042158737Sambrisko			error = ENOIOCTL;
3043157114Sscottl			break;
3044157114Sscottl		}
3045157114Sscottl		break;
3046169451Sscottl	case MFIIO_QUERY_DISK:
3047169451Sscottl	{
3048169451Sscottl		struct mfi_query_disk *qd;
3049169451Sscottl		struct mfi_disk *ld;
3050169451Sscottl
3051169451Sscottl		qd = (struct mfi_query_disk *)arg;
3052169451Sscottl		mtx_lock(&sc->mfi_io_lock);
3053169451Sscottl		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
3054169451Sscottl			if (ld->ld_id == qd->array_id)
3055169451Sscottl				break;
3056169451Sscottl		}
3057169451Sscottl		if (ld == NULL) {
3058169451Sscottl			qd->present = 0;
3059169451Sscottl			mtx_unlock(&sc->mfi_io_lock);
3060169451Sscottl			return (0);
3061169451Sscottl		}
3062169451Sscottl		qd->present = 1;
3063169451Sscottl		if (ld->ld_flags & MFI_DISK_FLAGS_OPEN)
3064169451Sscottl			qd->open = 1;
3065169451Sscottl		bzero(qd->devname, SPECNAMELEN + 1);
3066169451Sscottl		snprintf(qd->devname, SPECNAMELEN, "mfid%d", ld->ld_unit);
3067169451Sscottl		mtx_unlock(&sc->mfi_io_lock);
3068169451Sscottl		break;
3069169451Sscottl	}
3070164281Sambrisko	case MFI_CMD:
3071233711Sambrisko#ifdef COMPAT_FREEBSD32
3072179392Sambrisko	case MFI_CMD32:
3073179392Sambrisko#endif
3074177489Sambrisko		{
3075177489Sambrisko		devclass_t devclass;
3076164281Sambrisko		ioc = (struct mfi_ioc_packet *)arg;
3077177489Sambrisko		int adapter;
3078164281Sambrisko
3079177489Sambrisko		adapter = ioc->mfi_adapter_no;
3080177489Sambrisko		if (device_get_unit(sc->mfi_dev) == 0 && adapter != 0) {
3081177489Sambrisko			devclass = devclass_find("mfi");
3082177489Sambrisko			sc = devclass_get_softc(devclass, adapter);
3083177489Sambrisko		}
3084164281Sambrisko		mtx_lock(&sc->mfi_io_lock);
3085164281Sambrisko		if ((cm = mfi_dequeue_free(sc)) == NULL) {
3086164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3087164281Sambrisko			return (EBUSY);
3088164281Sambrisko		}
3089164281Sambrisko		mtx_unlock(&sc->mfi_io_lock);
3090171821Sjhb		locked = 0;
3091164281Sambrisko
3092164281Sambrisko		/*
3093164281Sambrisko		 * save off original context since copying from user
3094164281Sambrisko		 * will clobber some data
3095164281Sambrisko		 */
3096164281Sambrisko		context = cm->cm_frame->header.context;
3097233711Sambrisko		cm->cm_frame->header.context = cm->cm_index;
3098164281Sambrisko
3099165225Sambrisko		bcopy(ioc->mfi_frame.raw, cm->cm_frame,
3100233711Sambrisko		    2 * MEGAMFI_FRAME_SIZE);
3101184897Sambrisko		cm->cm_total_frame_size = (sizeof(union mfi_sgl)
3102184897Sambrisko		    * ioc->mfi_sge_count) + ioc->mfi_sgl_off;
3103233711Sambrisko		cm->cm_frame->header.scsi_status = 0;
3104233711Sambrisko		cm->cm_frame->header.pad0 = 0;
3105175897Sambrisko		if (ioc->mfi_sge_count) {
3106175897Sambrisko			cm->cm_sg =
3107175897Sambrisko			    (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off];
3108175897Sambrisko		}
3109233711Sambrisko		sgl = cm->cm_sg;
3110175897Sambrisko		cm->cm_flags = 0;
3111175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
3112175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN;
3113175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
3114175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAOUT;
3115175897Sambrisko		/* Legacy app shim */
3116175897Sambrisko		if (cm->cm_flags == 0)
3117175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
3118164281Sambrisko		cm->cm_len = cm->cm_frame->header.data_len;
3119225869Smav		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
3120233711Sambrisko#ifdef COMPAT_FREEBSD32
3121225869Smav			if (cmd == MFI_CMD) {
3122225869Smav#endif
3123225869Smav				/* Native */
3124225869Smav				cm->cm_stp_len = ioc->mfi_sgl[0].iov_len;
3125233711Sambrisko#ifdef COMPAT_FREEBSD32
3126225869Smav			} else {
3127225869Smav				/* 32bit on 64bit */
3128225869Smav				ioc32 = (struct mfi_ioc_packet32 *)ioc;
3129225869Smav				cm->cm_stp_len = ioc32->mfi_sgl[0].iov_len;
3130225869Smav			}
3131225869Smav#endif
3132225869Smav			cm->cm_len += cm->cm_stp_len;
3133225869Smav		}
3134184897Sambrisko		if (cm->cm_len &&
3135184897Sambrisko		    (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
3136175897Sambrisko			cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
3137175897Sambrisko			    M_WAITOK | M_ZERO);
3138175897Sambrisko			if (cm->cm_data == NULL) {
3139175897Sambrisko				device_printf(sc->mfi_dev, "Malloc failed\n");
3140175897Sambrisko				goto out;
3141175897Sambrisko			}
3142175897Sambrisko		} else {
3143175897Sambrisko			cm->cm_data = 0;
3144165225Sambrisko		}
3145164281Sambrisko
3146164281Sambrisko		/* restore header context */
3147164281Sambrisko		cm->cm_frame->header.context = context;
3148164281Sambrisko
3149233711Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
3150233711Sambrisko			res = mfi_stp_cmd(sc, cm, arg);
3151233711Sambrisko			if (res != 0)
3152233711Sambrisko				goto out;
3153233711Sambrisko		} else {
3154233711Sambrisko			temp = data;
3155233711Sambrisko			if ((cm->cm_flags & MFI_CMD_DATAOUT) ||
3156233711Sambrisko			    (cm->cm_frame->header.cmd == MFI_CMD_STP)) {
3157233711Sambrisko				for (i = 0; i < ioc->mfi_sge_count; i++) {
3158233711Sambrisko#ifdef COMPAT_FREEBSD32
3159233711Sambrisko					if (cmd == MFI_CMD) {
3160225869Smav#endif
3161233711Sambrisko						/* Native */
3162233711Sambrisko						addr = ioc->mfi_sgl[i].iov_base;
3163233711Sambrisko						len = ioc->mfi_sgl[i].iov_len;
3164233711Sambrisko#ifdef COMPAT_FREEBSD32
3165233711Sambrisko					} else {
3166233711Sambrisko						/* 32bit on 64bit */
3167233711Sambrisko						ioc32 = (struct mfi_ioc_packet32 *)ioc;
3168233711Sambrisko						addr = PTRIN(ioc32->mfi_sgl[i].iov_base);
3169233711Sambrisko						len = ioc32->mfi_sgl[i].iov_len;
3170233711Sambrisko					}
3171179392Sambrisko#endif
3172233711Sambrisko					error = copyin(addr, temp, len);
3173233711Sambrisko					if (error != 0) {
3174233711Sambrisko						device_printf(sc->mfi_dev,
3175233711Sambrisko						    "Copy in failed\n");
3176233711Sambrisko						goto out;
3177233711Sambrisko					}
3178233711Sambrisko					temp = &temp[len];
3179175897Sambrisko				}
3180164281Sambrisko			}
3181164281Sambrisko		}
3182164281Sambrisko
3183171821Sjhb		if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
3184233711Sambrisko			locked = mfi_config_lock(sc,
3185233711Sambrisko			     cm->cm_frame->dcmd.opcode);
3186171821Sjhb
3187184933Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
3188233711Sambrisko			cm->cm_frame->pass.sense_addr_lo =
3189233711Sambrisko			    (uint32_t)cm->cm_sense_busaddr;
3190233711Sambrisko			cm->cm_frame->pass.sense_addr_hi =
3191233711Sambrisko			    (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
3192184933Sambrisko		}
3193164281Sambrisko		mtx_lock(&sc->mfi_io_lock);
3194233711Sambrisko		skip_pre_post = mfi_check_for_sscd (sc, cm);
3195233711Sambrisko		if (!skip_pre_post) {
3196233711Sambrisko			error = mfi_check_command_pre(sc, cm);
3197233711Sambrisko			if (error) {
3198233711Sambrisko				mtx_unlock(&sc->mfi_io_lock);
3199233711Sambrisko				goto out;
3200233711Sambrisko			}
3201171821Sjhb		}
3202170284Sambrisko		if ((error = mfi_wait_command(sc, cm)) != 0) {
3203164281Sambrisko			device_printf(sc->mfi_dev,
3204165225Sambrisko			    "Controller polled failed\n");
3205164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3206164281Sambrisko			goto out;
3207164281Sambrisko		}
3208233711Sambrisko		if (!skip_pre_post) {
3209233711Sambrisko			mfi_check_command_post(sc, cm);
3210233711Sambrisko		}
3211164281Sambrisko		mtx_unlock(&sc->mfi_io_lock);
3212164281Sambrisko
3213233711Sambrisko		if (cm->cm_frame->header.cmd != MFI_CMD_STP) {
3214233711Sambrisko			temp = data;
3215233711Sambrisko			if ((cm->cm_flags & MFI_CMD_DATAIN) ||
3216233711Sambrisko			    (cm->cm_frame->header.cmd == MFI_CMD_STP)) {
3217233711Sambrisko				for (i = 0; i < ioc->mfi_sge_count; i++) {
3218233711Sambrisko#ifdef COMPAT_FREEBSD32
3219233711Sambrisko					if (cmd == MFI_CMD) {
3220225869Smav#endif
3221233711Sambrisko						/* Native */
3222233711Sambrisko						addr = ioc->mfi_sgl[i].iov_base;
3223233711Sambrisko						len = ioc->mfi_sgl[i].iov_len;
3224233711Sambrisko#ifdef COMPAT_FREEBSD32
3225233711Sambrisko					} else {
3226233711Sambrisko						/* 32bit on 64bit */
3227233711Sambrisko						ioc32 = (struct mfi_ioc_packet32 *)ioc;
3228233711Sambrisko						addr = PTRIN(ioc32->mfi_sgl[i].iov_base);
3229233711Sambrisko						len = ioc32->mfi_sgl[i].iov_len;
3230233711Sambrisko					}
3231179392Sambrisko#endif
3232233711Sambrisko					error = copyout(temp, addr, len);
3233233711Sambrisko					if (error != 0) {
3234233711Sambrisko						device_printf(sc->mfi_dev,
3235233711Sambrisko						    "Copy out failed\n");
3236233711Sambrisko						goto out;
3237233711Sambrisko					}
3238233711Sambrisko					temp = &temp[len];
3239175897Sambrisko				}
3240164281Sambrisko			}
3241164281Sambrisko		}
3242164281Sambrisko
3243165225Sambrisko		if (ioc->mfi_sense_len) {
3244184897Sambrisko			/* get user-space sense ptr then copy out sense */
3245225428Sbz			bcopy(&ioc->mfi_frame.raw[ioc->mfi_sense_off],
3246184897Sambrisko			    &sense_ptr.sense_ptr_data[0],
3247184897Sambrisko			    sizeof(sense_ptr.sense_ptr_data));
3248233711Sambrisko#ifdef COMPAT_FREEBSD32
3249184974Sambrisko			if (cmd != MFI_CMD) {
3250184974Sambrisko				/*
3251184974Sambrisko				 * not 64bit native so zero out any address
3252184974Sambrisko				 * over 32bit */
3253184975Sambrisko				sense_ptr.addr.high = 0;
3254184974Sambrisko			}
3255184974Sambrisko#endif
3256184897Sambrisko			error = copyout(cm->cm_sense, sense_ptr.user_space,
3257165225Sambrisko			    ioc->mfi_sense_len);
3258164281Sambrisko			if (error != 0) {
3259164281Sambrisko				device_printf(sc->mfi_dev,
3260165225Sambrisko				    "Copy out failed\n");
3261164281Sambrisko				goto out;
3262164281Sambrisko			}
3263164281Sambrisko		}
3264164281Sambrisko
3265165225Sambrisko		ioc->mfi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status;
3266164281Sambriskoout:
3267171821Sjhb		mfi_config_unlock(sc, locked);
3268164281Sambrisko		if (data)
3269164281Sambrisko			free(data, M_MFIBUF);
3270233711Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
3271233711Sambrisko			for (i = 0; i < 2; i++) {
3272233711Sambrisko				if (sc->kbuff_arr[i]) {
3273233711Sambrisko					if (sc->mfi_kbuff_arr_busaddr != 0)
3274233711Sambrisko						bus_dmamap_unload(
3275233711Sambrisko						    sc->mfi_kbuff_arr_dmat[i],
3276233711Sambrisko						    sc->mfi_kbuff_arr_dmamap[i]
3277233711Sambrisko						    );
3278233711Sambrisko					if (sc->kbuff_arr[i] != NULL)
3279233711Sambrisko						bus_dmamem_free(
3280233711Sambrisko						    sc->mfi_kbuff_arr_dmat[i],
3281233711Sambrisko						    sc->kbuff_arr[i],
3282233711Sambrisko						    sc->mfi_kbuff_arr_dmamap[i]
3283233711Sambrisko						    );
3284233711Sambrisko					if (sc->mfi_kbuff_arr_dmat[i] != NULL)
3285233711Sambrisko						bus_dma_tag_destroy(
3286233711Sambrisko						    sc->mfi_kbuff_arr_dmat[i]);
3287233711Sambrisko				}
3288233711Sambrisko			}
3289233711Sambrisko		}
3290164281Sambrisko		if (cm) {
3291164281Sambrisko			mtx_lock(&sc->mfi_io_lock);
3292164281Sambrisko			mfi_release_command(cm);
3293164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3294164281Sambrisko		}
3295164281Sambrisko
3296164281Sambrisko		break;
3297177489Sambrisko		}
3298164281Sambrisko	case MFI_SET_AEN:
3299164281Sambrisko		aen = (struct mfi_ioc_aen *)arg;
3300164281Sambrisko		error = mfi_aen_register(sc, aen->aen_seq_num,
3301164281Sambrisko		    aen->aen_class_locale);
3302164281Sambrisko
3303164281Sambrisko		break;
3304164281Sambrisko	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
3305158737Sambrisko		{
3306158737Sambrisko			devclass_t devclass;
3307158737Sambrisko			struct mfi_linux_ioc_packet l_ioc;
3308158737Sambrisko			int adapter;
3309158737Sambrisko
3310158737Sambrisko			devclass = devclass_find("mfi");
3311158737Sambrisko			if (devclass == NULL)
3312158737Sambrisko				return (ENOENT);
3313158737Sambrisko
3314158737Sambrisko			error = copyin(arg, &l_ioc, sizeof(l_ioc));
3315158737Sambrisko			if (error)
3316158737Sambrisko				return (error);
3317158737Sambrisko			adapter = l_ioc.lioc_adapter_no;
3318158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
3319158737Sambrisko			if (sc == NULL)
3320158737Sambrisko				return (ENOENT);
3321158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
3322158737Sambrisko			    cmd, arg, flag, td));
3323158737Sambrisko			break;
3324158737Sambrisko		}
3325164281Sambrisko	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
3326158737Sambrisko		{
3327158737Sambrisko			devclass_t devclass;
3328158737Sambrisko			struct mfi_linux_ioc_aen l_aen;
3329158737Sambrisko			int adapter;
3330158737Sambrisko
3331158737Sambrisko			devclass = devclass_find("mfi");
3332158737Sambrisko			if (devclass == NULL)
3333158737Sambrisko				return (ENOENT);
3334158737Sambrisko
3335158737Sambrisko			error = copyin(arg, &l_aen, sizeof(l_aen));
3336158737Sambrisko			if (error)
3337158737Sambrisko				return (error);
3338158737Sambrisko			adapter = l_aen.laen_adapter_no;
3339158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
3340158737Sambrisko			if (sc == NULL)
3341158737Sambrisko				return (ENOENT);
3342158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
3343158737Sambrisko			    cmd, arg, flag, td));
3344158737Sambrisko			break;
3345158737Sambrisko		}
3346233711Sambrisko#ifdef COMPAT_FREEBSD32
3347178968Sscottl	case MFIIO_PASSTHRU32:
3348238077Sjhb		if (!SV_CURPROC_FLAG(SV_ILP32)) {
3349238077Sjhb			error = ENOTTY;
3350238077Sjhb			break;
3351238077Sjhb		}
3352178968Sscottl		iop_swab.ioc_frame	= iop32->ioc_frame;
3353178968Sscottl		iop_swab.buf_size	= iop32->buf_size;
3354178968Sscottl		iop_swab.buf		= PTRIN(iop32->buf);
3355178968Sscottl		iop			= &iop_swab;
3356178968Sscottl		/* FALLTHROUGH */
3357178968Sscottl#endif
3358178968Sscottl	case MFIIO_PASSTHRU:
3359178968Sscottl		error = mfi_user_command(sc, iop);
3360233711Sambrisko#ifdef COMPAT_FREEBSD32
3361178968Sscottl		if (cmd == MFIIO_PASSTHRU32)
3362178968Sscottl			iop32->ioc_frame = iop_swab.ioc_frame;
3363178968Sscottl#endif
3364178968Sscottl		break;
3365157114Sscottl	default:
3366163398Sscottl		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
3367238077Sjhb		error = ENOTTY;
3368157114Sscottl		break;
3369157114Sscottl	}
3370157114Sscottl
3371157114Sscottl	return (error);
3372157114Sscottl}
3373158737Sambrisko
3374158737Sambriskostatic int
3375192450Simpmfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
3376158737Sambrisko{
3377158737Sambrisko	struct mfi_softc *sc;
3378158737Sambrisko	struct mfi_linux_ioc_packet l_ioc;
3379158737Sambrisko	struct mfi_linux_ioc_aen l_aen;
3380158737Sambrisko	struct mfi_command *cm = NULL;
3381158737Sambrisko	struct mfi_aen *mfi_aen_entry;
3382184897Sambrisko	union mfi_sense_ptr sense_ptr;
3383233711Sambrisko	uint32_t context = 0;
3384158737Sambrisko	uint8_t *data = NULL, *temp;
3385158737Sambrisko	int i;
3386171821Sjhb	int error, locked;
3387158737Sambrisko
3388158737Sambrisko	sc = dev->si_drv1;
3389158737Sambrisko	error = 0;
3390158737Sambrisko	switch (cmd) {
3391164281Sambrisko	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
3392158737Sambrisko		error = copyin(arg, &l_ioc, sizeof(l_ioc));
3393158737Sambrisko		if (error != 0)
3394158737Sambrisko			return (error);
3395158737Sambrisko
3396158737Sambrisko		if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) {
3397158737Sambrisko			return (EINVAL);
3398158737Sambrisko		}
3399158737Sambrisko
3400158737Sambrisko		mtx_lock(&sc->mfi_io_lock);
3401158737Sambrisko		if ((cm = mfi_dequeue_free(sc)) == NULL) {
3402158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3403158737Sambrisko			return (EBUSY);
3404158737Sambrisko		}
3405158737Sambrisko		mtx_unlock(&sc->mfi_io_lock);
3406171821Sjhb		locked = 0;
3407158737Sambrisko
3408158737Sambrisko		/*
3409158737Sambrisko		 * save off original context since copying from user
3410158737Sambrisko		 * will clobber some data
3411158737Sambrisko		 */
3412158737Sambrisko		context = cm->cm_frame->header.context;
3413158737Sambrisko
3414158737Sambrisko		bcopy(l_ioc.lioc_frame.raw, cm->cm_frame,
3415175897Sambrisko		      2 * MFI_DCMD_FRAME_SIZE);	/* this isn't quite right */
3416184897Sambrisko		cm->cm_total_frame_size = (sizeof(union mfi_sgl)
3417184897Sambrisko		      * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off;
3418233711Sambrisko		cm->cm_frame->header.scsi_status = 0;
3419233711Sambrisko		cm->cm_frame->header.pad0 = 0;
3420175897Sambrisko		if (l_ioc.lioc_sge_count)
3421175897Sambrisko			cm->cm_sg =
3422175897Sambrisko			    (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
3423175897Sambrisko		cm->cm_flags = 0;
3424175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
3425175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN;
3426175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
3427175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAOUT;
3428158737Sambrisko		cm->cm_len = cm->cm_frame->header.data_len;
3429184897Sambrisko		if (cm->cm_len &&
3430184897Sambrisko		      (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
3431175897Sambrisko			cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
3432175897Sambrisko			    M_WAITOK | M_ZERO);
3433175897Sambrisko			if (cm->cm_data == NULL) {
3434175897Sambrisko				device_printf(sc->mfi_dev, "Malloc failed\n");
3435175897Sambrisko				goto out;
3436175897Sambrisko			}
3437175897Sambrisko		} else {
3438175897Sambrisko			cm->cm_data = 0;
3439175897Sambrisko		}
3440158737Sambrisko
3441158737Sambrisko		/* restore header context */
3442158737Sambrisko		cm->cm_frame->header.context = context;
3443158737Sambrisko
3444158737Sambrisko		temp = data;
3445175897Sambrisko		if (cm->cm_flags & MFI_CMD_DATAOUT) {
3446175897Sambrisko			for (i = 0; i < l_ioc.lioc_sge_count; i++) {
3447178968Sscottl				error = copyin(PTRIN(l_ioc.lioc_sgl[i].iov_base),
3448175897Sambrisko				       temp,
3449175897Sambrisko				       l_ioc.lioc_sgl[i].iov_len);
3450175897Sambrisko				if (error != 0) {
3451175897Sambrisko					device_printf(sc->mfi_dev,
3452175897Sambrisko					    "Copy in failed\n");
3453175897Sambrisko					goto out;
3454175897Sambrisko				}
3455175897Sambrisko				temp = &temp[l_ioc.lioc_sgl[i].iov_len];
3456158737Sambrisko			}
3457158737Sambrisko		}
3458158737Sambrisko
3459171821Sjhb		if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
3460171821Sjhb			locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
3461171821Sjhb
3462184933Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
3463233711Sambrisko			cm->cm_frame->pass.sense_addr_lo =
3464233711Sambrisko			    (uint32_t)cm->cm_sense_busaddr;
3465233711Sambrisko			cm->cm_frame->pass.sense_addr_hi =
3466233711Sambrisko			    (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
3467184933Sambrisko		}
3468184933Sambrisko
3469163398Sscottl		mtx_lock(&sc->mfi_io_lock);
3470171821Sjhb		error = mfi_check_command_pre(sc, cm);
3471171821Sjhb		if (error) {
3472171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
3473171821Sjhb			goto out;
3474171821Sjhb		}
3475171821Sjhb
3476170284Sambrisko		if ((error = mfi_wait_command(sc, cm)) != 0) {
3477158737Sambrisko			device_printf(sc->mfi_dev,
3478165225Sambrisko			    "Controller polled failed\n");
3479163398Sscottl			mtx_unlock(&sc->mfi_io_lock);
3480158737Sambrisko			goto out;
3481158737Sambrisko		}
3482158737Sambrisko
3483171821Sjhb		mfi_check_command_post(sc, cm);
3484163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
3485158737Sambrisko
3486158737Sambrisko		temp = data;
3487175897Sambrisko		if (cm->cm_flags & MFI_CMD_DATAIN) {
3488175897Sambrisko			for (i = 0; i < l_ioc.lioc_sge_count; i++) {
3489175897Sambrisko				error = copyout(temp,
3490178968Sscottl					PTRIN(l_ioc.lioc_sgl[i].iov_base),
3491175897Sambrisko					l_ioc.lioc_sgl[i].iov_len);
3492175897Sambrisko				if (error != 0) {
3493175897Sambrisko					device_printf(sc->mfi_dev,
3494175897Sambrisko					    "Copy out failed\n");
3495175897Sambrisko					goto out;
3496175897Sambrisko				}
3497175897Sambrisko				temp = &temp[l_ioc.lioc_sgl[i].iov_len];
3498158737Sambrisko			}
3499158737Sambrisko		}
3500158737Sambrisko
3501158737Sambrisko		if (l_ioc.lioc_sense_len) {
3502184897Sambrisko			/* get user-space sense ptr then copy out sense */
3503184897Sambrisko			bcopy(&((struct mfi_linux_ioc_packet*)arg)
3504184897Sambrisko                            ->lioc_frame.raw[l_ioc.lioc_sense_off],
3505184897Sambrisko			    &sense_ptr.sense_ptr_data[0],
3506184897Sambrisko			    sizeof(sense_ptr.sense_ptr_data));
3507184974Sambrisko#ifdef __amd64__
3508184974Sambrisko			/*
3509184974Sambrisko			 * only 32bit Linux support so zero out any
3510184974Sambrisko			 * address over 32bit
3511184974Sambrisko			 */
3512184975Sambrisko			sense_ptr.addr.high = 0;
3513184974Sambrisko#endif
3514184897Sambrisko			error = copyout(cm->cm_sense, sense_ptr.user_space,
3515158737Sambrisko			    l_ioc.lioc_sense_len);
3516158737Sambrisko			if (error != 0) {
3517158737Sambrisko				device_printf(sc->mfi_dev,
3518165225Sambrisko				    "Copy out failed\n");
3519158737Sambrisko				goto out;
3520158737Sambrisko			}
3521158737Sambrisko		}
3522158737Sambrisko
3523158737Sambrisko		error = copyout(&cm->cm_frame->header.cmd_status,
3524158737Sambrisko			&((struct mfi_linux_ioc_packet*)arg)
3525158737Sambrisko			->lioc_frame.hdr.cmd_status,
3526158737Sambrisko			1);
3527158737Sambrisko		if (error != 0) {
3528158737Sambrisko			device_printf(sc->mfi_dev,
3529165225Sambrisko				      "Copy out failed\n");
3530158737Sambrisko			goto out;
3531158737Sambrisko		}
3532158737Sambrisko
3533158737Sambriskoout:
3534171821Sjhb		mfi_config_unlock(sc, locked);
3535158737Sambrisko		if (data)
3536158737Sambrisko			free(data, M_MFIBUF);
3537158737Sambrisko		if (cm) {
3538158737Sambrisko			mtx_lock(&sc->mfi_io_lock);
3539158737Sambrisko			mfi_release_command(cm);
3540158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3541158737Sambrisko		}
3542158737Sambrisko
3543158737Sambrisko		return (error);
3544164281Sambrisko	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
3545158737Sambrisko		error = copyin(arg, &l_aen, sizeof(l_aen));
3546158737Sambrisko		if (error != 0)
3547158737Sambrisko			return (error);
3548158737Sambrisko		printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid);
3549158737Sambrisko		mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF,
3550158737Sambrisko		    M_WAITOK);
3551163398Sscottl		mtx_lock(&sc->mfi_io_lock);
3552158737Sambrisko		if (mfi_aen_entry != NULL) {
3553158737Sambrisko			mfi_aen_entry->p = curproc;
3554158737Sambrisko			TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry,
3555158737Sambrisko			    aen_link);
3556158737Sambrisko		}
3557158737Sambrisko		error = mfi_aen_register(sc, l_aen.laen_seq_num,
3558158737Sambrisko		    l_aen.laen_class_locale);
3559158737Sambrisko
3560158737Sambrisko		if (error != 0) {
3561158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
3562158737Sambrisko			    aen_link);
3563158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
3564158737Sambrisko		}
3565163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
3566158737Sambrisko
3567158737Sambrisko		return (error);
3568158737Sambrisko	default:
3569158737Sambrisko		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
3570158737Sambrisko		error = ENOENT;
3571158737Sambrisko		break;
3572158737Sambrisko	}
3573158737Sambrisko
3574158737Sambrisko	return (error);
3575158737Sambrisko}
3576158737Sambrisko
3577158737Sambriskostatic int
3578158737Sambriskomfi_poll(struct cdev *dev, int poll_events, struct thread *td)
3579158737Sambrisko{
3580158737Sambrisko	struct mfi_softc *sc;
3581158737Sambrisko	int revents = 0;
3582158737Sambrisko
3583158737Sambrisko	sc = dev->si_drv1;
3584158737Sambrisko
3585158737Sambrisko	if (poll_events & (POLLIN | POLLRDNORM)) {
3586163398Sscottl		if (sc->mfi_aen_triggered != 0) {
3587158737Sambrisko			revents |= poll_events & (POLLIN | POLLRDNORM);
3588163398Sscottl			sc->mfi_aen_triggered = 0;
3589163398Sscottl		}
3590158737Sambrisko		if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) {
3591158737Sambrisko			revents |= POLLERR;
3592158737Sambrisko		}
3593158737Sambrisko	}
3594158737Sambrisko
3595158737Sambrisko	if (revents == 0) {
3596158737Sambrisko		if (poll_events & (POLLIN | POLLRDNORM)) {
3597158737Sambrisko			sc->mfi_poll_waiting = 1;
3598158737Sambrisko			selrecord(td, &sc->mfi_select);
3599158737Sambrisko		}
3600158737Sambrisko	}
3601158737Sambrisko
3602158737Sambrisko	return revents;
3603158737Sambrisko}
3604162619Sscottl
3605162619Sscottlstatic void
3606163398Sscottlmfi_dump_all(void)
3607163398Sscottl{
3608163398Sscottl	struct mfi_softc *sc;
3609163398Sscottl	struct mfi_command *cm;
3610163398Sscottl	devclass_t dc;
3611163398Sscottl	time_t deadline;
3612163398Sscottl	int timedout;
3613163398Sscottl	int i;
3614163398Sscottl
3615163398Sscottl	dc = devclass_find("mfi");
3616163398Sscottl	if (dc == NULL) {
3617163398Sscottl		printf("No mfi dev class\n");
3618163398Sscottl		return;
3619163398Sscottl	}
3620163398Sscottl
3621163398Sscottl	for (i = 0; ; i++) {
3622163398Sscottl		sc = devclass_get_softc(dc, i);
3623163398Sscottl		if (sc == NULL)
3624163398Sscottl			break;
3625163398Sscottl		device_printf(sc->mfi_dev, "Dumping\n\n");
3626163398Sscottl		timedout = 0;
3627163398Sscottl		deadline = time_uptime - MFI_CMD_TIMEOUT;
3628163398Sscottl		mtx_lock(&sc->mfi_io_lock);
3629163398Sscottl		TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
3630163398Sscottl			if (cm->cm_timestamp < deadline) {
3631163398Sscottl				device_printf(sc->mfi_dev,
3632233711Sambrisko				    "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
3633233711Sambrisko				    cm, (int)(time_uptime - cm->cm_timestamp));
3634163398Sscottl				MFI_PRINT_CMD(cm);
3635163398Sscottl				timedout++;
3636163398Sscottl			}
3637163398Sscottl		}
3638163398Sscottl
3639163398Sscottl#if 0
3640163398Sscottl		if (timedout)
3641163398Sscottl			MFI_DUMP_CMDS(SC);
3642163398Sscottl#endif
3643163398Sscottl
3644163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
3645163398Sscottl	}
3646163398Sscottl
3647163398Sscottl	return;
3648163398Sscottl}
3649163398Sscottl
3650163398Sscottlstatic void
3651162619Sscottlmfi_timeout(void *data)
3652162619Sscottl{
3653162619Sscottl	struct mfi_softc *sc = (struct mfi_softc *)data;
3654162619Sscottl	struct mfi_command *cm;
3655162619Sscottl	time_t deadline;
3656162619Sscottl	int timedout = 0;
3657162619Sscottl
3658162619Sscottl	deadline = time_uptime - MFI_CMD_TIMEOUT;
3659233711Sambrisko	if (sc->adpreset == 0) {
3660233711Sambrisko		if (!mfi_tbolt_reset(sc)) {
3661233711Sambrisko			callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz, mfi_timeout, sc);
3662233711Sambrisko			return;
3663233711Sambrisko		}
3664233711Sambrisko	}
3665162619Sscottl	mtx_lock(&sc->mfi_io_lock);
3666162619Sscottl	TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
3667235014Sambrisko		if (sc->mfi_aen_cm == cm || sc->mfi_map_sync_cm == cm)
3668162688Sscottl			continue;
3669235014Sambrisko		if (cm->cm_timestamp < deadline) {
3670233711Sambrisko			if (sc->adpreset != 0 && sc->issuepend_done == 0) {
3671233711Sambrisko				cm->cm_timestamp = time_uptime;
3672233711Sambrisko			} else {
3673233711Sambrisko				device_printf(sc->mfi_dev,
3674233711Sambrisko				    "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
3675233711Sambrisko				     cm, (int)(time_uptime - cm->cm_timestamp)
3676233711Sambrisko				     );
3677233711Sambrisko				MFI_PRINT_CMD(cm);
3678233711Sambrisko				MFI_VALIDATE_CMD(sc, cm);
3679233711Sambrisko				timedout++;
3680233711Sambrisko			}
3681162619Sscottl		}
3682162619Sscottl	}
3683162619Sscottl
3684162619Sscottl#if 0
3685162619Sscottl	if (timedout)
3686162619Sscottl		MFI_DUMP_CMDS(SC);
3687162619Sscottl#endif
3688162619Sscottl
3689162619Sscottl	mtx_unlock(&sc->mfi_io_lock);
3690162619Sscottl
3691162619Sscottl	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
3692162619Sscottl	    mfi_timeout, sc);
3693162619Sscottl
3694163398Sscottl	if (0)
3695163398Sscottl		mfi_dump_all();
3696162619Sscottl	return;
3697162619Sscottl}
3698