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$");
55157114Sscottl
56234429Sambrisko#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>
76239866Sjhb#include <sys/sysent.h>
77234429Sambrisko#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>
85234429Sambrisko#include <sys/interrupt.h>
86234429Sambrisko#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);
98234429Sambriskostatic void	mfi_syspdprobe(struct mfi_softc *sc);
99234429Sambriskostatic 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 *);
104234429Sambriskostatic int	mfi_add_sys_pd(struct mfi_softc *sc, int);
105234429Sambriskostatic 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 *);
108234429Sambriskostatic struct mfi_command *mfi_build_ldio(struct mfi_softc *,struct bio*);
109234429Sambriskostatic struct mfi_command *mfi_build_syspdio(struct mfi_softc *,struct bio*);
110157114Sscottlstatic int	mfi_send_frame(struct mfi_softc *, struct mfi_command *);
111250496Ssmhstatic int	mfi_std_send_frame(struct mfi_softc *, struct mfi_command *);
112243824Sdelphijstatic int	mfi_abort(struct mfi_softc *, struct mfi_command **);
113192450Simpstatic int	mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int, struct thread *);
114162619Sscottlstatic void	mfi_timeout(void *);
115178968Sscottlstatic int	mfi_user_command(struct mfi_softc *,
116178968Sscottl		    struct mfi_ioc_passthru *);
117234429Sambriskostatic void	mfi_enable_intr_xscale(struct mfi_softc *sc);
118234429Sambriskostatic void	mfi_enable_intr_ppc(struct mfi_softc *sc);
119234429Sambriskostatic int32_t	mfi_read_fw_status_xscale(struct mfi_softc *sc);
120234429Sambriskostatic int32_t	mfi_read_fw_status_ppc(struct mfi_softc *sc);
121234429Sambriskostatic int	mfi_check_clear_intr_xscale(struct mfi_softc *sc);
122234429Sambriskostatic int	mfi_check_clear_intr_ppc(struct mfi_softc *sc);
123234429Sambriskostatic void 	mfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add,
124234429Sambrisko		    uint32_t frame_cnt);
125234429Sambriskostatic void 	mfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add,
126234429Sambrisko		    uint32_t frame_cnt);
127234429Sambriskostatic int mfi_config_lock(struct mfi_softc *sc, uint32_t opcode);
128234429Sambriskostatic void mfi_config_unlock(struct mfi_softc *sc, int locked);
129234429Sambriskostatic int mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm);
130234429Sambriskostatic void mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm);
131234429Sambriskostatic int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm);
132157114Sscottl
133162118SambriskoSYSCTL_NODE(_hw, OID_AUTO, mfi, CTLFLAG_RD, 0, "MFI driver parameters");
134162118Sambriskostatic int	mfi_event_locale = MFI_EVT_LOCALE_ALL;
135162473SambriskoTUNABLE_INT("hw.mfi.event_locale", &mfi_event_locale);
136250496SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, event_locale, CTLFLAG_RWTUN, &mfi_event_locale,
137250496Ssmh           0, "event message locale");
138162473Sambrisko
139165852Sscottlstatic int	mfi_event_class = MFI_EVT_CLASS_INFO;
140162473SambriskoTUNABLE_INT("hw.mfi.event_class", &mfi_event_class);
141250496SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, event_class, CTLFLAG_RWTUN, &mfi_event_class,
142250496Ssmh           0, "event message class");
143162118Sambrisko
144178968Sscottlstatic int	mfi_max_cmds = 128;
145178968SscottlTUNABLE_INT("hw.mfi.max_cmds", &mfi_max_cmds);
146250496SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, max_cmds, CTLFLAG_RDTUN, &mfi_max_cmds,
147250496Ssmh	   0, "Max commands limit (-1 = controller limit)");
148178968Sscottl
149234429Sambriskostatic int	mfi_detect_jbod_change = 1;
150234429SambriskoTUNABLE_INT("hw.mfi.detect_jbod_change", &mfi_detect_jbod_change);
151250496SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, detect_jbod_change, CTLFLAG_RWTUN,
152234429Sambrisko	   &mfi_detect_jbod_change, 0, "Detect a change to a JBOD");
153234429Sambrisko
154250496Ssmhint		mfi_polled_cmd_timeout = MFI_POLL_TIMEOUT_SECS;
155250496SsmhTUNABLE_INT("hw.mfi.polled_cmd_timeout", &mfi_polled_cmd_timeout);
156250496SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, polled_cmd_timeout, CTLFLAG_RWTUN,
157250496Ssmh	   &mfi_polled_cmd_timeout, 0,
158250496Ssmh	   "Polled command timeout - used for firmware flash etc (in seconds)");
159250496Ssmh
160251406Ssmhstatic int	mfi_cmd_timeout = MFI_CMD_TIMEOUT;
161251406SsmhTUNABLE_INT("hw.mfi.cmd_timeout", &mfi_cmd_timeout);
162251406SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, cmd_timeout, CTLFLAG_RWTUN, &mfi_cmd_timeout,
163251406Ssmh	   0, "Command timeout (in seconds)");
164251406Ssmh
165157114Sscottl/* Management interface */
166157114Sscottlstatic d_open_t		mfi_open;
167157114Sscottlstatic d_close_t	mfi_close;
168157114Sscottlstatic d_ioctl_t	mfi_ioctl;
169158737Sambriskostatic d_poll_t		mfi_poll;
170157114Sscottl
171157114Sscottlstatic struct cdevsw mfi_cdevsw = {
172157114Sscottl	.d_version = 	D_VERSION,
173157114Sscottl	.d_flags =	0,
174157114Sscottl	.d_open = 	mfi_open,
175157114Sscottl	.d_close =	mfi_close,
176157114Sscottl	.d_ioctl =	mfi_ioctl,
177158737Sambrisko	.d_poll =	mfi_poll,
178157114Sscottl	.d_name =	"mfi",
179157114Sscottl};
180157114Sscottl
181157114SscottlMALLOC_DEFINE(M_MFIBUF, "mfibuf", "Buffers for the MFI driver");
182157114Sscottl
183158737Sambrisko#define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH
184234429Sambriskostruct mfi_skinny_dma_info mfi_skinny;
185157114Sscottl
186171980Sscottlstatic void
187171980Sscottlmfi_enable_intr_xscale(struct mfi_softc *sc)
188171980Sscottl{
189171980Sscottl	MFI_WRITE4(sc, MFI_OMSK, 0x01);
190171980Sscottl}
191171980Sscottl
192171980Sscottlstatic void
193171980Sscottlmfi_enable_intr_ppc(struct mfi_softc *sc)
194171980Sscottl{
195184897Sambrisko	if (sc->mfi_flags & MFI_FLAGS_1078) {
196234429Sambrisko		MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
197184897Sambrisko		MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM);
198234429Sambrisko	}
199234429Sambrisko	else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
200234429Sambrisko		MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
201184897Sambrisko		MFI_WRITE4(sc, MFI_OMSK, ~MFI_GEN2_EIM);
202184897Sambrisko	}
203234429Sambrisko	else if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
204234429Sambrisko		MFI_WRITE4(sc, MFI_OMSK, ~0x00000001);
205234429Sambrisko	}
206171980Sscottl}
207171980Sscottl
208171980Sscottlstatic int32_t
209171980Sscottlmfi_read_fw_status_xscale(struct mfi_softc *sc)
210171980Sscottl{
211171980Sscottl	return MFI_READ4(sc, MFI_OMSG0);
212171980Sscottl}
213184897Sambrisko
214171980Sscottlstatic int32_t
215171980Sscottlmfi_read_fw_status_ppc(struct mfi_softc *sc)
216171980Sscottl{
217171980Sscottl	return MFI_READ4(sc, MFI_OSP0);
218171980Sscottl}
219171980Sscottl
220184897Sambriskostatic int
221171980Sscottlmfi_check_clear_intr_xscale(struct mfi_softc *sc)
222171980Sscottl{
223171980Sscottl	int32_t status;
224171980Sscottl
225171980Sscottl	status = MFI_READ4(sc, MFI_OSTS);
226171980Sscottl	if ((status & MFI_OSTS_INTR_VALID) == 0)
227171980Sscottl		return 1;
228171980Sscottl
229171980Sscottl	MFI_WRITE4(sc, MFI_OSTS, status);
230171980Sscottl	return 0;
231182085Simp}
232171980Sscottl
233184897Sambriskostatic int
234171980Sscottlmfi_check_clear_intr_ppc(struct mfi_softc *sc)
235171980Sscottl{
236171980Sscottl	int32_t status;
237171980Sscottl
238171980Sscottl	status = MFI_READ4(sc, MFI_OSTS);
239184897Sambrisko	if (sc->mfi_flags & MFI_FLAGS_1078) {
240184897Sambrisko		if (!(status & MFI_1078_RM)) {
241184897Sambrisko			return 1;
242184897Sambrisko		}
243234429Sambrisko	}
244234429Sambrisko	else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
245184897Sambrisko		if (!(status & MFI_GEN2_RM)) {
246184897Sambrisko			return 1;
247184897Sambrisko		}
248184897Sambrisko	}
249234429Sambrisko	else if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
250234429Sambrisko		if (!(status & MFI_SKINNY_RM)) {
251234429Sambrisko			return 1;
252234429Sambrisko		}
253234429Sambrisko	}
254234429Sambrisko	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
255234429Sambrisko		MFI_WRITE4(sc, MFI_OSTS, status);
256234429Sambrisko	else
257234429Sambrisko		MFI_WRITE4(sc, MFI_ODCR0, status);
258171980Sscottl	return 0;
259182085Simp}
260171980Sscottl
261184897Sambriskostatic void
262234429Sambriskomfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt)
263171980Sscottl{
264171980Sscottl	MFI_WRITE4(sc, MFI_IQP,(bus_add >>3)|frame_cnt);
265171980Sscottl}
266184897Sambrisko
267184897Sambriskostatic void
268234429Sambriskomfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt)
269171980Sscottl{
270234429Sambrisko	if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
271234429Sambrisko	    MFI_WRITE4(sc, MFI_IQPL, (bus_add | frame_cnt <<1)|1 );
272234429Sambrisko	    MFI_WRITE4(sc, MFI_IQPH, 0x00000000);
273234429Sambrisko	} else {
274234429Sambrisko	    MFI_WRITE4(sc, MFI_IQP, (bus_add | frame_cnt <<1)|1 );
275234429Sambrisko	}
276171980Sscottl}
277171980Sscottl
278234429Sambriskoint
279157114Sscottlmfi_transition_firmware(struct mfi_softc *sc)
280157114Sscottl{
281194851Sscottl	uint32_t fw_state, cur_state;
282157114Sscottl	int max_wait, i;
283234429Sambrisko	uint32_t cur_abs_reg_val = 0;
284234429Sambrisko	uint32_t prev_abs_reg_val = 0;
285157114Sscottl
286234429Sambrisko	cur_abs_reg_val = sc->mfi_read_fw_status(sc);
287234429Sambrisko	fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK;
288157114Sscottl	while (fw_state != MFI_FWSTATE_READY) {
289157114Sscottl		if (bootverbose)
290157114Sscottl			device_printf(sc->mfi_dev, "Waiting for firmware to "
291171980Sscottl			"become ready\n");
292157114Sscottl		cur_state = fw_state;
293157114Sscottl		switch (fw_state) {
294157114Sscottl		case MFI_FWSTATE_FAULT:
295157114Sscottl			device_printf(sc->mfi_dev, "Firmware fault\n");
296157114Sscottl			return (ENXIO);
297157114Sscottl		case MFI_FWSTATE_WAIT_HANDSHAKE:
298234429Sambrisko			if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
299234429Sambrisko			    MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
300234429Sambrisko			else
301234429Sambrisko			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
302234429Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
303157114Sscottl			break;
304157114Sscottl		case MFI_FWSTATE_OPERATIONAL:
305234429Sambrisko			if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
306234429Sambrisko			    MFI_WRITE4(sc, MFI_SKINNY_IDB, 7);
307234429Sambrisko			else
308234429Sambrisko			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY);
309234429Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
310157114Sscottl			break;
311157114Sscottl		case MFI_FWSTATE_UNDEFINED:
312157114Sscottl		case MFI_FWSTATE_BB_INIT:
313234429Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
314157114Sscottl			break;
315234429Sambrisko		case MFI_FWSTATE_FW_INIT_2:
316234429Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
317234429Sambrisko			break;
318157114Sscottl		case MFI_FWSTATE_FW_INIT:
319157114Sscottl		case MFI_FWSTATE_FLUSH_CACHE:
320234429Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
321157114Sscottl			break;
322234429Sambrisko		case MFI_FWSTATE_DEVICE_SCAN:
323234429Sambrisko			max_wait = MFI_RESET_WAIT_TIME; /* wait for 180 seconds */
324234429Sambrisko			prev_abs_reg_val = cur_abs_reg_val;
325234429Sambrisko			break;
326224041Sjhb		case MFI_FWSTATE_BOOT_MESSAGE_PENDING:
327234429Sambrisko			if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
328234429Sambrisko			    MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_HOTPLUG);
329234429Sambrisko			else
330234429Sambrisko			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG);
331234429Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
332224041Sjhb			break;
333157114Sscottl		default:
334234429Sambrisko			device_printf(sc->mfi_dev, "Unknown firmware state %#x\n",
335157114Sscottl			    fw_state);
336157114Sscottl			return (ENXIO);
337157114Sscottl		}
338157114Sscottl		for (i = 0; i < (max_wait * 10); i++) {
339234429Sambrisko			cur_abs_reg_val = sc->mfi_read_fw_status(sc);
340234429Sambrisko			fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK;
341157114Sscottl			if (fw_state == cur_state)
342157114Sscottl				DELAY(100000);
343157114Sscottl			else
344157114Sscottl				break;
345157114Sscottl		}
346234429Sambrisko		if (fw_state == MFI_FWSTATE_DEVICE_SCAN) {
347234429Sambrisko			/* Check the device scanning progress */
348234429Sambrisko			if (prev_abs_reg_val != cur_abs_reg_val) {
349234429Sambrisko				continue;
350234429Sambrisko			}
351234429Sambrisko		}
352157114Sscottl		if (fw_state == cur_state) {
353224041Sjhb			device_printf(sc->mfi_dev, "Firmware stuck in state "
354157114Sscottl			    "%#x\n", fw_state);
355157114Sscottl			return (ENXIO);
356157114Sscottl		}
357157114Sscottl	}
358157114Sscottl	return (0);
359157114Sscottl}
360157114Sscottl
361157114Sscottlstatic void
362234429Sambriskomfi_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
363157114Sscottl{
364234429Sambrisko	bus_addr_t *addr;
365157114Sscottl
366157114Sscottl	addr = arg;
367157114Sscottl	*addr = segs[0].ds_addr;
368157114Sscottl}
369157114Sscottl
370234429Sambrisko
371157114Sscottlint
372157114Sscottlmfi_attach(struct mfi_softc *sc)
373157114Sscottl{
374157114Sscottl	uint32_t status;
375157114Sscottl	int error, commsz, framessz, sensesz;
376250496Ssmh	int frames, unit, max_fw_sge, max_fw_cmds;
377234429Sambrisko	uint32_t tb_mem_size = 0;
378157114Sscottl
379234429Sambrisko	if (sc == NULL)
380234429Sambrisko		return EINVAL;
381186132Sambrisko
382234429Sambrisko	device_printf(sc->mfi_dev, "Megaraid SAS driver Ver %s \n",
383234429Sambrisko	    MEGASAS_VERSION);
384234429Sambrisko
385157114Sscottl	mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF);
386171821Sjhb	sx_init(&sc->mfi_config_lock, "MFI config");
387157114Sscottl	TAILQ_INIT(&sc->mfi_ld_tqh);
388234429Sambrisko	TAILQ_INIT(&sc->mfi_syspd_tqh);
389243824Sdelphij	TAILQ_INIT(&sc->mfi_ld_pend_tqh);
390243824Sdelphij	TAILQ_INIT(&sc->mfi_syspd_pend_tqh);
391234429Sambrisko	TAILQ_INIT(&sc->mfi_evt_queue);
392234429Sambrisko	TASK_INIT(&sc->mfi_evt_task, 0, mfi_handle_evt, sc);
393235135Sambrisko	TASK_INIT(&sc->mfi_map_sync_task, 0, mfi_handle_map_sync, sc);
394158737Sambrisko	TAILQ_INIT(&sc->mfi_aen_pids);
395169611Sscottl	TAILQ_INIT(&sc->mfi_cam_ccbq);
396157114Sscottl
397157114Sscottl	mfi_initq_free(sc);
398157114Sscottl	mfi_initq_ready(sc);
399157114Sscottl	mfi_initq_busy(sc);
400157114Sscottl	mfi_initq_bio(sc);
401157114Sscottl
402234429Sambrisko	sc->adpreset = 0;
403234429Sambrisko	sc->last_seq_num = 0;
404234429Sambrisko	sc->disableOnlineCtrlReset = 1;
405234429Sambrisko	sc->issuepend_done = 1;
406234429Sambrisko	sc->hw_crit_error = 0;
407234429Sambrisko
408171980Sscottl	if (sc->mfi_flags & MFI_FLAGS_1064R) {
409171980Sscottl		sc->mfi_enable_intr = mfi_enable_intr_xscale;
410171980Sscottl		sc->mfi_read_fw_status = mfi_read_fw_status_xscale;
411171980Sscottl		sc->mfi_check_clear_intr = mfi_check_clear_intr_xscale;
412171980Sscottl		sc->mfi_issue_cmd = mfi_issue_cmd_xscale;
413234429Sambrisko	} else if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
414234429Sambrisko		sc->mfi_enable_intr = mfi_tbolt_enable_intr_ppc;
415234429Sambrisko		sc->mfi_disable_intr = mfi_tbolt_disable_intr_ppc;
416234429Sambrisko		sc->mfi_read_fw_status = mfi_tbolt_read_fw_status_ppc;
417234429Sambrisko		sc->mfi_check_clear_intr = mfi_tbolt_check_clear_intr_ppc;
418234429Sambrisko		sc->mfi_issue_cmd = mfi_tbolt_issue_cmd_ppc;
419234429Sambrisko		sc->mfi_adp_reset = mfi_tbolt_adp_reset;
420234429Sambrisko		sc->mfi_tbolt = 1;
421234429Sambrisko		TAILQ_INIT(&sc->mfi_cmd_tbolt_tqh);
422234429Sambrisko	} else {
423171980Sscottl		sc->mfi_enable_intr =  mfi_enable_intr_ppc;
424234429Sambrisko		sc->mfi_read_fw_status = mfi_read_fw_status_ppc;
425171980Sscottl		sc->mfi_check_clear_intr = mfi_check_clear_intr_ppc;
426171980Sscottl		sc->mfi_issue_cmd = mfi_issue_cmd_ppc;
427171980Sscottl	}
428171980Sscottl
429171980Sscottl
430157114Sscottl	/* Before we get too far, see if the firmware is working */
431157114Sscottl	if ((error = mfi_transition_firmware(sc)) != 0) {
432157114Sscottl		device_printf(sc->mfi_dev, "Firmware not in READY state, "
433157114Sscottl		    "error %d\n", error);
434157114Sscottl		return (ENXIO);
435157114Sscottl	}
436157114Sscottl
437234429Sambrisko	/* Start: LSIP200113393 */
438234429Sambrisko	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
439234429Sambrisko				1, 0,			/* algnmnt, boundary */
440234429Sambrisko				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
441234429Sambrisko				BUS_SPACE_MAXADDR,	/* highaddr */
442234429Sambrisko				NULL, NULL,		/* filter, filterarg */
443234429Sambrisko				MEGASAS_MAX_NAME*sizeof(bus_addr_t),			/* maxsize */
444234429Sambrisko				1,			/* msegments */
445234429Sambrisko				MEGASAS_MAX_NAME*sizeof(bus_addr_t),			/* maxsegsize */
446234429Sambrisko				0,			/* flags */
447234429Sambrisko				NULL, NULL,		/* lockfunc, lockarg */
448234429Sambrisko				&sc->verbuf_h_dmat)) {
449234429Sambrisko		device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmat DMA tag\n");
450234429Sambrisko		return (ENOMEM);
451234429Sambrisko	}
452234429Sambrisko	if (bus_dmamem_alloc(sc->verbuf_h_dmat, (void **)&sc->verbuf,
453234429Sambrisko	    BUS_DMA_NOWAIT, &sc->verbuf_h_dmamap)) {
454234429Sambrisko		device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmamap memory\n");
455234429Sambrisko		return (ENOMEM);
456234429Sambrisko	}
457234429Sambrisko	bzero(sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t));
458234429Sambrisko	bus_dmamap_load(sc->verbuf_h_dmat, sc->verbuf_h_dmamap,
459234429Sambrisko	    sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t),
460234429Sambrisko	    mfi_addr_cb, &sc->verbuf_h_busaddr, 0);
461234429Sambrisko	/* End: LSIP200113393 */
462234429Sambrisko
463157114Sscottl	/*
464157114Sscottl	 * Get information needed for sizing the contiguous memory for the
465157114Sscottl	 * frame pool.  Size down the sgl parameter since we know that
466157114Sscottl	 * we will never need more than what's required for MAXPHYS.
467157114Sscottl	 * It would be nice if these constants were available at runtime
468157114Sscottl	 * instead of compile time.
469157114Sscottl	 */
470171980Sscottl	status = sc->mfi_read_fw_status(sc);
471250496Ssmh	max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK;
472250496Ssmh	if (mfi_max_cmds > 0 && mfi_max_cmds < max_fw_cmds) {
473250496Ssmh		device_printf(sc->mfi_dev, "FW MaxCmds = %d, limiting to %d\n",
474250496Ssmh		    max_fw_cmds, mfi_max_cmds);
475250496Ssmh		sc->mfi_max_fw_cmds = mfi_max_cmds;
476250496Ssmh	} else {
477250496Ssmh		sc->mfi_max_fw_cmds = max_fw_cmds;
478250496Ssmh	}
479162458Sscottl	max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16;
480195534Sscottl	sc->mfi_max_sge = min(max_fw_sge, ((MFI_MAXPHYS / PAGE_SIZE) + 1));
481157114Sscottl
482234429Sambrisko	/* ThunderBolt Support get the contiguous memory */
483234429Sambrisko
484234429Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
485234429Sambrisko		mfi_tbolt_init_globals(sc);
486250496Ssmh		device_printf(sc->mfi_dev, "MaxCmd = %d, Drv MaxCmd = %d, "
487250496Ssmh		    "MaxSgl = %d, state = %#x\n", max_fw_cmds,
488234429Sambrisko		    sc->mfi_max_fw_cmds, sc->mfi_max_sge, status);
489234429Sambrisko		tb_mem_size = mfi_tbolt_get_memory_requirement(sc);
490234429Sambrisko
491234429Sambrisko		if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
492234429Sambrisko				1, 0,			/* algnmnt, boundary */
493234429Sambrisko				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
494234429Sambrisko				BUS_SPACE_MAXADDR,	/* highaddr */
495234429Sambrisko				NULL, NULL,		/* filter, filterarg */
496234429Sambrisko				tb_mem_size,		/* maxsize */
497234429Sambrisko				1,			/* msegments */
498234429Sambrisko				tb_mem_size,		/* maxsegsize */
499234429Sambrisko				0,			/* flags */
500234429Sambrisko				NULL, NULL,		/* lockfunc, lockarg */
501234429Sambrisko				&sc->mfi_tb_dmat)) {
502234429Sambrisko			device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
503234429Sambrisko			return (ENOMEM);
504234429Sambrisko		}
505234429Sambrisko		if (bus_dmamem_alloc(sc->mfi_tb_dmat, (void **)&sc->request_message_pool,
506234429Sambrisko		BUS_DMA_NOWAIT, &sc->mfi_tb_dmamap)) {
507234429Sambrisko			device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
508234429Sambrisko			return (ENOMEM);
509234429Sambrisko		}
510234429Sambrisko		bzero(sc->request_message_pool, tb_mem_size);
511234429Sambrisko		bus_dmamap_load(sc->mfi_tb_dmat, sc->mfi_tb_dmamap,
512234429Sambrisko		sc->request_message_pool, tb_mem_size, mfi_addr_cb, &sc->mfi_tb_busaddr, 0);
513234429Sambrisko
514234429Sambrisko		/* For ThunderBolt memory init */
515234429Sambrisko		if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
516234429Sambrisko				0x100, 0,		/* alignmnt, boundary */
517234429Sambrisko				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
518234429Sambrisko				BUS_SPACE_MAXADDR,	/* highaddr */
519234429Sambrisko				NULL, NULL,		/* filter, filterarg */
520234429Sambrisko				MFI_FRAME_SIZE,		/* maxsize */
521234429Sambrisko				1,			/* msegments */
522234429Sambrisko				MFI_FRAME_SIZE,		/* maxsegsize */
523234429Sambrisko				0,			/* flags */
524234429Sambrisko				NULL, NULL,		/* lockfunc, lockarg */
525234429Sambrisko				&sc->mfi_tb_init_dmat)) {
526250496Ssmh			device_printf(sc->mfi_dev, "Cannot allocate init DMA tag\n");
527250496Ssmh			return (ENOMEM);
528234429Sambrisko		}
529234429Sambrisko		if (bus_dmamem_alloc(sc->mfi_tb_init_dmat, (void **)&sc->mfi_tb_init,
530234429Sambrisko		    BUS_DMA_NOWAIT, &sc->mfi_tb_init_dmamap)) {
531234429Sambrisko			device_printf(sc->mfi_dev, "Cannot allocate init memory\n");
532234429Sambrisko			return (ENOMEM);
533234429Sambrisko		}
534234429Sambrisko		bzero(sc->mfi_tb_init, MFI_FRAME_SIZE);
535234429Sambrisko		bus_dmamap_load(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap,
536234429Sambrisko		sc->mfi_tb_init, MFI_FRAME_SIZE, mfi_addr_cb,
537234429Sambrisko		    &sc->mfi_tb_init_busaddr, 0);
538234429Sambrisko		if (mfi_tbolt_init_desc_pool(sc, sc->request_message_pool,
539234429Sambrisko		    tb_mem_size)) {
540234429Sambrisko			device_printf(sc->mfi_dev,
541234429Sambrisko			    "Thunderbolt pool preparation error\n");
542234429Sambrisko			return 0;
543234429Sambrisko		}
544234429Sambrisko
545234429Sambrisko		/*
546234429Sambrisko		  Allocate DMA memory mapping for MPI2 IOC Init descriptor,
547234429Sambrisko		  we are taking it diffrent from what we have allocated for Request
548234429Sambrisko		  and reply descriptors to avoid confusion later
549234429Sambrisko		*/
550234429Sambrisko		tb_mem_size = sizeof(struct MPI2_IOC_INIT_REQUEST);
551234429Sambrisko		if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
552234429Sambrisko				1, 0,			/* algnmnt, boundary */
553234429Sambrisko				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
554234429Sambrisko				BUS_SPACE_MAXADDR,	/* highaddr */
555234429Sambrisko				NULL, NULL,		/* filter, filterarg */
556234429Sambrisko				tb_mem_size,		/* maxsize */
557234429Sambrisko				1,			/* msegments */
558234429Sambrisko				tb_mem_size,		/* maxsegsize */
559234429Sambrisko				0,			/* flags */
560234429Sambrisko				NULL, NULL,		/* lockfunc, lockarg */
561234429Sambrisko				&sc->mfi_tb_ioc_init_dmat)) {
562234429Sambrisko			device_printf(sc->mfi_dev,
563234429Sambrisko			    "Cannot allocate comms DMA tag\n");
564234429Sambrisko			return (ENOMEM);
565234429Sambrisko		}
566234429Sambrisko		if (bus_dmamem_alloc(sc->mfi_tb_ioc_init_dmat,
567234429Sambrisko		    (void **)&sc->mfi_tb_ioc_init_desc,
568234429Sambrisko		    BUS_DMA_NOWAIT, &sc->mfi_tb_ioc_init_dmamap)) {
569234429Sambrisko			device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
570234429Sambrisko			return (ENOMEM);
571234429Sambrisko		}
572234429Sambrisko		bzero(sc->mfi_tb_ioc_init_desc, tb_mem_size);
573234429Sambrisko		bus_dmamap_load(sc->mfi_tb_ioc_init_dmat, sc->mfi_tb_ioc_init_dmamap,
574234429Sambrisko		sc->mfi_tb_ioc_init_desc, tb_mem_size, mfi_addr_cb,
575234429Sambrisko		    &sc->mfi_tb_ioc_init_busaddr, 0);
576234429Sambrisko	}
577157114Sscottl	/*
578157114Sscottl	 * Create the dma tag for data buffers.  Used both for block I/O
579157114Sscottl	 * and for various internal data queries.
580157114Sscottl	 */
581157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
582157114Sscottl				1, 0,			/* algnmnt, boundary */
583157114Sscottl				BUS_SPACE_MAXADDR,	/* lowaddr */
584157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
585157114Sscottl				NULL, NULL,		/* filter, filterarg */
586157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
587162458Sscottl				sc->mfi_max_sge,	/* nsegments */
588157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
589157114Sscottl				BUS_DMA_ALLOCNOW,	/* flags */
590157114Sscottl				busdma_lock_mutex,	/* lockfunc */
591157114Sscottl				&sc->mfi_io_lock,	/* lockfuncarg */
592157114Sscottl				&sc->mfi_buffer_dmat)) {
593157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate buffer DMA tag\n");
594157114Sscottl		return (ENOMEM);
595157114Sscottl	}
596157114Sscottl
597157114Sscottl	/*
598157114Sscottl	 * Allocate DMA memory for the comms queues.  Keep it under 4GB for
599157114Sscottl	 * efficiency.  The mfi_hwcomms struct includes space for 1 reply queue
600157114Sscottl	 * entry, so the calculated size here will be will be 1 more than
601157114Sscottl	 * mfi_max_fw_cmds.  This is apparently a requirement of the hardware.
602157114Sscottl	 */
603157114Sscottl	commsz = (sizeof(uint32_t) * sc->mfi_max_fw_cmds) +
604157114Sscottl	    sizeof(struct mfi_hwcomms);
605157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
606157114Sscottl				1, 0,			/* algnmnt, boundary */
607157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
608157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
609157114Sscottl				NULL, NULL,		/* filter, filterarg */
610157114Sscottl				commsz,			/* maxsize */
611157114Sscottl				1,			/* msegments */
612157114Sscottl				commsz,			/* maxsegsize */
613157114Sscottl				0,			/* flags */
614157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
615157114Sscottl				&sc->mfi_comms_dmat)) {
616157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
617157114Sscottl		return (ENOMEM);
618157114Sscottl	}
619157114Sscottl	if (bus_dmamem_alloc(sc->mfi_comms_dmat, (void **)&sc->mfi_comms,
620157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_comms_dmamap)) {
621157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
622157114Sscottl		return (ENOMEM);
623157114Sscottl	}
624157114Sscottl	bzero(sc->mfi_comms, commsz);
625157114Sscottl	bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap,
626234429Sambrisko	    sc->mfi_comms, commsz, mfi_addr_cb, &sc->mfi_comms_busaddr, 0);
627157114Sscottl	/*
628157114Sscottl	 * Allocate DMA memory for the command frames.  Keep them in the
629162458Sscottl	 * lower 4GB for efficiency.  Calculate the size of the commands at
630162458Sscottl	 * the same time; each command is one 64 byte frame plus a set of
631162458Sscottl         * additional frames for holding sg lists or other data.
632157114Sscottl	 * The assumption here is that the SG list will start at the second
633162458Sscottl	 * frame and not use the unused bytes in the first frame.  While this
634162458Sscottl	 * isn't technically correct, it simplifies the calculation and allows
635162458Sscottl	 * for command frames that might be larger than an mfi_io_frame.
636157114Sscottl	 */
637157114Sscottl	if (sizeof(bus_addr_t) == 8) {
638162458Sscottl		sc->mfi_sge_size = sizeof(struct mfi_sg64);
639157114Sscottl		sc->mfi_flags |= MFI_FLAGS_SG64;
640157114Sscottl	} else {
641162458Sscottl		sc->mfi_sge_size = sizeof(struct mfi_sg32);
642157114Sscottl	}
643234429Sambrisko	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
644234429Sambrisko		sc->mfi_sge_size = sizeof(struct mfi_sg_skinny);
645162458Sscottl	frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2;
646162458Sscottl	sc->mfi_cmd_size = frames * MFI_FRAME_SIZE;
647162458Sscottl	framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds;
648157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
649157114Sscottl				64, 0,			/* algnmnt, boundary */
650157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
651157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
652157114Sscottl				NULL, NULL,		/* filter, filterarg */
653157114Sscottl				framessz,		/* maxsize */
654157114Sscottl				1,			/* nsegments */
655157114Sscottl				framessz,		/* maxsegsize */
656157114Sscottl				0,			/* flags */
657157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
658157114Sscottl				&sc->mfi_frames_dmat)) {
659157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frame DMA tag\n");
660157114Sscottl		return (ENOMEM);
661157114Sscottl	}
662157114Sscottl	if (bus_dmamem_alloc(sc->mfi_frames_dmat, (void **)&sc->mfi_frames,
663157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_frames_dmamap)) {
664157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frames memory\n");
665157114Sscottl		return (ENOMEM);
666157114Sscottl	}
667157114Sscottl	bzero(sc->mfi_frames, framessz);
668157114Sscottl	bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap,
669234429Sambrisko	    sc->mfi_frames, framessz, mfi_addr_cb, &sc->mfi_frames_busaddr,0);
670157114Sscottl	/*
671157114Sscottl	 * Allocate DMA memory for the frame sense data.  Keep them in the
672157114Sscottl	 * lower 4GB for efficiency
673157114Sscottl	 */
674157114Sscottl	sensesz = sc->mfi_max_fw_cmds * MFI_SENSE_LEN;
675157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
676157114Sscottl				4, 0,			/* algnmnt, boundary */
677157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
678157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
679157114Sscottl				NULL, NULL,		/* filter, filterarg */
680157114Sscottl				sensesz,		/* maxsize */
681157114Sscottl				1,			/* nsegments */
682157114Sscottl				sensesz,		/* maxsegsize */
683157114Sscottl				0,			/* flags */
684157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
685157114Sscottl				&sc->mfi_sense_dmat)) {
686157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense DMA tag\n");
687157114Sscottl		return (ENOMEM);
688157114Sscottl	}
689157114Sscottl	if (bus_dmamem_alloc(sc->mfi_sense_dmat, (void **)&sc->mfi_sense,
690157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_sense_dmamap)) {
691157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense memory\n");
692157114Sscottl		return (ENOMEM);
693157114Sscottl	}
694157114Sscottl	bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap,
695234429Sambrisko	    sc->mfi_sense, sensesz, mfi_addr_cb, &sc->mfi_sense_busaddr, 0);
696157114Sscottl	if ((error = mfi_alloc_commands(sc)) != 0)
697157114Sscottl		return (error);
698157114Sscottl
699234429Sambrisko	/* Before moving the FW to operational state, check whether
700234429Sambrisko	 * hostmemory is required by the FW or not
701234429Sambrisko	 */
702157114Sscottl
703234429Sambrisko	/* ThunderBolt MFI_IOC2 INIT */
704234429Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
705234429Sambrisko		sc->mfi_disable_intr(sc);
706250496Ssmh		mtx_lock(&sc->mfi_io_lock);
707234429Sambrisko		if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0) {
708234429Sambrisko			device_printf(sc->mfi_dev,
709234429Sambrisko			    "TB Init has failed with error %d\n",error);
710250496Ssmh			mtx_unlock(&sc->mfi_io_lock);
711234429Sambrisko			return error;
712234429Sambrisko		}
713250496Ssmh		mtx_unlock(&sc->mfi_io_lock);
714157114Sscottl
715234429Sambrisko		if ((error = mfi_tbolt_alloc_cmd(sc)) != 0)
716234429Sambrisko			return error;
717234429Sambrisko		if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq,
718234429Sambrisko		    INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr_tbolt, sc,
719234429Sambrisko		    &sc->mfi_intr)) {
720234429Sambrisko			device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
721234429Sambrisko			return (EINVAL);
722234429Sambrisko		}
723243824Sdelphij		sc->mfi_intr_ptr = mfi_intr_tbolt;
724234429Sambrisko		sc->mfi_enable_intr(sc);
725234429Sambrisko	} else {
726234429Sambrisko		if ((error = mfi_comms_init(sc)) != 0)
727234429Sambrisko			return (error);
728157114Sscottl
729234429Sambrisko		if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq,
730234429Sambrisko		    INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr, sc, &sc->mfi_intr)) {
731234429Sambrisko			device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
732234429Sambrisko			return (EINVAL);
733234429Sambrisko		}
734243824Sdelphij		sc->mfi_intr_ptr = mfi_intr;
735234429Sambrisko		sc->mfi_enable_intr(sc);
736157114Sscottl	}
737234429Sambrisko	if ((error = mfi_get_controller_info(sc)) != 0)
738234429Sambrisko		return (error);
739234429Sambrisko	sc->disableOnlineCtrlReset = 0;
740157114Sscottl
741157114Sscottl	/* Register a config hook to probe the bus for arrays */
742157114Sscottl	sc->mfi_ich.ich_func = mfi_startup;
743157114Sscottl	sc->mfi_ich.ich_arg = sc;
744157114Sscottl	if (config_intrhook_establish(&sc->mfi_ich) != 0) {
745157114Sscottl		device_printf(sc->mfi_dev, "Cannot establish configuration "
746157114Sscottl		    "hook\n");
747157114Sscottl		return (EINVAL);
748157114Sscottl	}
749250496Ssmh	mtx_lock(&sc->mfi_io_lock);
750234429Sambrisko	if ((error = mfi_aen_setup(sc, 0), 0) != 0) {
751234429Sambrisko		mtx_unlock(&sc->mfi_io_lock);
752234429Sambrisko		return (error);
753234429Sambrisko	}
754250496Ssmh	mtx_unlock(&sc->mfi_io_lock);
755157114Sscottl
756157114Sscottl	/*
757157114Sscottl	 * Register a shutdown handler.
758157114Sscottl	 */
759157114Sscottl	if ((sc->mfi_eh = EVENTHANDLER_REGISTER(shutdown_final, mfi_shutdown,
760157114Sscottl	    sc, SHUTDOWN_PRI_DEFAULT)) == NULL) {
761157114Sscottl		device_printf(sc->mfi_dev, "Warning: shutdown event "
762157114Sscottl		    "registration failed\n");
763157114Sscottl	}
764157114Sscottl
765157114Sscottl	/*
766157114Sscottl	 * Create the control device for doing management
767157114Sscottl	 */
768157114Sscottl	unit = device_get_unit(sc->mfi_dev);
769157114Sscottl	sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR,
770157114Sscottl	    0640, "mfi%d", unit);
771158737Sambrisko	if (unit == 0)
772158737Sambrisko		make_dev_alias(sc->mfi_cdev, "megaraid_sas_ioctl_node");
773157114Sscottl	if (sc->mfi_cdev != NULL)
774157114Sscottl		sc->mfi_cdev->si_drv1 = sc;
775171821Sjhb	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
776171821Sjhb	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
777171821Sjhb	    OID_AUTO, "delete_busy_volumes", CTLFLAG_RW,
778171821Sjhb	    &sc->mfi_delete_busy_volumes, 0, "Allow removal of busy volumes");
779171821Sjhb	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
780171821Sjhb	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
781171821Sjhb	    OID_AUTO, "keep_deleted_volumes", CTLFLAG_RW,
782171821Sjhb	    &sc->mfi_keep_deleted_volumes, 0,
783171821Sjhb	    "Don't detach the mfid device for a busy volume that is deleted");
784157114Sscottl
785169611Sscottl	device_add_child(sc->mfi_dev, "mfip", -1);
786169611Sscottl	bus_generic_attach(sc->mfi_dev);
787169611Sscottl
788162619Sscottl	/* Start the timeout watchdog */
789178250Skris	callout_init(&sc->mfi_watchdog_callout, CALLOUT_MPSAFE);
790251406Ssmh	callout_reset(&sc->mfi_watchdog_callout, mfi_cmd_timeout * hz,
791162619Sscottl	    mfi_timeout, sc);
792162619Sscottl
793235135Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
794250496Ssmh		mtx_lock(&sc->mfi_io_lock);
795235135Sambrisko		mfi_tbolt_sync_map_info(sc);
796250496Ssmh		mtx_unlock(&sc->mfi_io_lock);
797235135Sambrisko	}
798235135Sambrisko
799157114Sscottl	return (0);
800157114Sscottl}
801157114Sscottl
802157114Sscottlstatic int
803157114Sscottlmfi_alloc_commands(struct mfi_softc *sc)
804157114Sscottl{
805157114Sscottl	struct mfi_command *cm;
806250496Ssmh	int i, j;
807157114Sscottl
808157114Sscottl	/*
809157114Sscottl	 * XXX Should we allocate all the commands up front, or allocate on
810157114Sscottl	 * demand later like 'aac' does?
811157114Sscottl	 */
812250496Ssmh	sc->mfi_commands = malloc(sizeof(sc->mfi_commands[0]) *
813250496Ssmh	    sc->mfi_max_fw_cmds, M_MFIBUF, M_WAITOK | M_ZERO);
814178968Sscottl
815250496Ssmh	for (i = 0; i < sc->mfi_max_fw_cmds; i++) {
816157114Sscottl		cm = &sc->mfi_commands[i];
817158737Sambrisko		cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames +
818162458Sscottl		    sc->mfi_cmd_size * i);
819157114Sscottl		cm->cm_frame_busaddr = sc->mfi_frames_busaddr +
820162458Sscottl		    sc->mfi_cmd_size * i;
821157114Sscottl		cm->cm_frame->header.context = i;
822157114Sscottl		cm->cm_sense = &sc->mfi_sense[i];
823157114Sscottl		cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i;
824157114Sscottl		cm->cm_sc = sc;
825162619Sscottl		cm->cm_index = i;
826157114Sscottl		if (bus_dmamap_create(sc->mfi_buffer_dmat, 0,
827234429Sambrisko		    &cm->cm_dmamap) == 0) {
828234429Sambrisko			mtx_lock(&sc->mfi_io_lock);
829157114Sscottl			mfi_release_command(cm);
830234429Sambrisko			mtx_unlock(&sc->mfi_io_lock);
831250496Ssmh		} else {
832250496Ssmh			device_printf(sc->mfi_dev, "Failed to allocate %d "
833250496Ssmh			   "command blocks, only allocated %d\n",
834250496Ssmh			    sc->mfi_max_fw_cmds, i - 1);
835250496Ssmh			for (j = 0; j < i; j++) {
836250496Ssmh				cm = &sc->mfi_commands[i];
837250496Ssmh				bus_dmamap_destroy(sc->mfi_buffer_dmat,
838250496Ssmh				    cm->cm_dmamap);
839250496Ssmh			}
840250496Ssmh			free(sc->mfi_commands, M_MFIBUF);
841250496Ssmh			sc->mfi_commands = NULL;
842250496Ssmh
843250496Ssmh			return (ENOMEM);
844234429Sambrisko		}
845157114Sscottl	}
846157114Sscottl
847157114Sscottl	return (0);
848157114Sscottl}
849157114Sscottl
850169611Sscottlvoid
851157114Sscottlmfi_release_command(struct mfi_command *cm)
852157114Sscottl{
853163398Sscottl	struct mfi_frame_header *hdr;
854157114Sscottl	uint32_t *hdr_data;
855157114Sscottl
856234429Sambrisko	mtx_assert(&cm->cm_sc->mfi_io_lock, MA_OWNED);
857234429Sambrisko
858157114Sscottl	/*
859157114Sscottl	 * Zero out the important fields of the frame, but make sure the
860165727Sscottl	 * context field is preserved.  For efficiency, handle the fields
861165727Sscottl	 * as 32 bit words.  Clear out the first S/G entry too for safety.
862157114Sscottl	 */
863163398Sscottl	hdr = &cm->cm_frame->header;
864175897Sambrisko	if (cm->cm_data != NULL && hdr->sg_count) {
865163398Sscottl		cm->cm_sg->sg32[0].len = 0;
866163398Sscottl		cm->cm_sg->sg32[0].addr = 0;
867163398Sscottl	}
868165727Sscottl
869250496Ssmh	/*
870250496Ssmh	 * Command may be on other queues e.g. busy queue depending on the
871250496Ssmh	 * flow of a previous call to mfi_mapcmd, so ensure its dequeued
872250496Ssmh	 * properly
873250496Ssmh	 */
874250496Ssmh	if ((cm->cm_flags & MFI_ON_MFIQ_BUSY) != 0)
875250496Ssmh		mfi_remove_busy(cm);
876250496Ssmh	if ((cm->cm_flags & MFI_ON_MFIQ_READY) != 0)
877250496Ssmh		mfi_remove_ready(cm);
878250496Ssmh
879250496Ssmh	/* We're not expecting it to be on any other queue but check */
880250496Ssmh	if ((cm->cm_flags & MFI_ON_MFIQ_MASK) != 0) {
881250496Ssmh		panic("Command %p is still on another queue, flags = %#x",
882250496Ssmh		    cm, cm->cm_flags);
883250496Ssmh	}
884250496Ssmh
885250496Ssmh	/* tbolt cleanup */
886250496Ssmh	if ((cm->cm_flags & MFI_CMD_TBOLT) != 0) {
887250496Ssmh		mfi_tbolt_return_cmd(cm->cm_sc,
888250496Ssmh		    cm->cm_sc->mfi_cmd_pool_tbolt[cm->cm_extra_frames - 1],
889250496Ssmh		    cm);
890250496Ssmh	}
891250496Ssmh
892165727Sscottl	hdr_data = (uint32_t *)cm->cm_frame;
893165727Sscottl	hdr_data[0] = 0;	/* cmd, sense_len, cmd_status, scsi_status */
894165727Sscottl	hdr_data[1] = 0;	/* target_id, lun_id, cdb_len, sg_count */
895165727Sscottl	hdr_data[4] = 0;	/* flags, timeout */
896165727Sscottl	hdr_data[5] = 0;	/* data_len */
897165727Sscottl
898157114Sscottl	cm->cm_extra_frames = 0;
899157114Sscottl	cm->cm_flags = 0;
900157114Sscottl	cm->cm_complete = NULL;
901157114Sscottl	cm->cm_private = NULL;
902169611Sscottl	cm->cm_data = NULL;
903157114Sscottl	cm->cm_sg = 0;
904157114Sscottl	cm->cm_total_frame_size = 0;
905234429Sambrisko	cm->retry_for_fw_reset = 0;
906163398Sscottl
907157114Sscottl	mfi_enqueue_free(cm);
908157114Sscottl}
909157114Sscottl
910235135Sambriskoint
911234429Sambriskomfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp,
912234429Sambrisko    uint32_t opcode, void **bufp, size_t bufsize)
913159806Sps{
914159806Sps	struct mfi_command *cm;
915159806Sps	struct mfi_dcmd_frame *dcmd;
916159806Sps	void *buf = NULL;
917234429Sambrisko	uint32_t context = 0;
918234429Sambrisko
919159806Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
920234429Sambrisko
921159806Sps	cm = mfi_dequeue_free(sc);
922159806Sps	if (cm == NULL)
923159806Sps		return (EBUSY);
924159806Sps
925234429Sambrisko	/* Zero out the MFI frame */
926234429Sambrisko	context = cm->cm_frame->header.context;
927234429Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
928234429Sambrisko	cm->cm_frame->header.context = context;
929234429Sambrisko
930159806Sps	if ((bufsize > 0) && (bufp != NULL)) {
931159806Sps		if (*bufp == NULL) {
932159806Sps			buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO);
933159806Sps			if (buf == NULL) {
934159806Sps				mfi_release_command(cm);
935159806Sps				return (ENOMEM);
936159806Sps			}
937159806Sps			*bufp = buf;
938159806Sps		} else {
939159806Sps			buf = *bufp;
940159806Sps		}
941159806Sps	}
942159806Sps
943159806Sps	dcmd =  &cm->cm_frame->dcmd;
944159806Sps	bzero(dcmd->mbox, MFI_MBOX_SIZE);
945159806Sps	dcmd->header.cmd = MFI_CMD_DCMD;
946159806Sps	dcmd->header.timeout = 0;
947159806Sps	dcmd->header.flags = 0;
948159806Sps	dcmd->header.data_len = bufsize;
949234429Sambrisko	dcmd->header.scsi_status = 0;
950159806Sps	dcmd->opcode = opcode;
951159806Sps	cm->cm_sg = &dcmd->sgl;
952159806Sps	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
953159806Sps	cm->cm_flags = 0;
954159806Sps	cm->cm_data = buf;
955159806Sps	cm->cm_private = buf;
956159806Sps	cm->cm_len = bufsize;
957159806Sps
958159806Sps	*cmp = cm;
959159806Sps	if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL))
960159806Sps		*bufp = buf;
961159806Sps	return (0);
962159806Sps}
963159806Sps
964159806Spsstatic int
965157114Sscottlmfi_comms_init(struct mfi_softc *sc)
966157114Sscottl{
967157114Sscottl	struct mfi_command *cm;
968157114Sscottl	struct mfi_init_frame *init;
969157114Sscottl	struct mfi_init_qinfo *qinfo;
970157114Sscottl	int error;
971234429Sambrisko	uint32_t context = 0;
972157114Sscottl
973163398Sscottl	mtx_lock(&sc->mfi_io_lock);
974250496Ssmh	if ((cm = mfi_dequeue_free(sc)) == NULL) {
975250496Ssmh		mtx_unlock(&sc->mfi_io_lock);
976157114Sscottl		return (EBUSY);
977250496Ssmh	}
978157114Sscottl
979234429Sambrisko	/* Zero out the MFI frame */
980234429Sambrisko	context = cm->cm_frame->header.context;
981234429Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
982234429Sambrisko	cm->cm_frame->header.context = context;
983234429Sambrisko
984157114Sscottl	/*
985157114Sscottl	 * Abuse the SG list area of the frame to hold the init_qinfo
986157114Sscottl	 * object;
987157114Sscottl	 */
988157114Sscottl	init = &cm->cm_frame->init;
989157114Sscottl	qinfo = (struct mfi_init_qinfo *)((uintptr_t)init + MFI_FRAME_SIZE);
990157114Sscottl
991157114Sscottl	bzero(qinfo, sizeof(struct mfi_init_qinfo));
992157114Sscottl	qinfo->rq_entries = sc->mfi_max_fw_cmds + 1;
993157114Sscottl	qinfo->rq_addr_lo = sc->mfi_comms_busaddr +
994157114Sscottl	    offsetof(struct mfi_hwcomms, hw_reply_q);
995157114Sscottl	qinfo->pi_addr_lo = sc->mfi_comms_busaddr +
996157114Sscottl	    offsetof(struct mfi_hwcomms, hw_pi);
997157114Sscottl	qinfo->ci_addr_lo = sc->mfi_comms_busaddr +
998157114Sscottl	    offsetof(struct mfi_hwcomms, hw_ci);
999157114Sscottl
1000157114Sscottl	init->header.cmd = MFI_CMD_INIT;
1001157114Sscottl	init->header.data_len = sizeof(struct mfi_init_qinfo);
1002157114Sscottl	init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE;
1003164375Sscottl	cm->cm_data = NULL;
1004164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
1005157114Sscottl
1006250496Ssmh	if ((error = mfi_mapcmd(sc, cm)) != 0)
1007157114Sscottl		device_printf(sc->mfi_dev, "failed to send init command\n");
1008157114Sscottl	mfi_release_command(cm);
1009163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1010157114Sscottl
1011250496Ssmh	return (error);
1012157114Sscottl}
1013157114Sscottl
1014157114Sscottlstatic int
1015157114Sscottlmfi_get_controller_info(struct mfi_softc *sc)
1016157114Sscottl{
1017159806Sps	struct mfi_command *cm = NULL;
1018159806Sps	struct mfi_ctrl_info *ci = NULL;
1019157114Sscottl	uint32_t max_sectors_1, max_sectors_2;
1020157114Sscottl	int error;
1021157114Sscottl
1022159806Sps	mtx_lock(&sc->mfi_io_lock);
1023159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO,
1024159806Sps	    (void **)&ci, sizeof(*ci));
1025159806Sps	if (error)
1026159806Sps		goto out;
1027157114Sscottl	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1028157114Sscottl
1029157114Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
1030157114Sscottl		device_printf(sc->mfi_dev, "Failed to get controller info\n");
1031162458Sscottl		sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE /
1032157114Sscottl		    MFI_SECTOR_LEN;
1033159806Sps		error = 0;
1034159806Sps		goto out;
1035157114Sscottl	}
1036157114Sscottl
1037157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1038157114Sscottl	    BUS_DMASYNC_POSTREAD);
1039157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1040157114Sscottl
1041234429Sambrisko	max_sectors_1 = (1 << ci->stripe_sz_ops.max) * ci->max_strips_per_io;
1042157114Sscottl	max_sectors_2 = ci->max_request_size;
1043157114Sscottl	sc->mfi_max_io = min(max_sectors_1, max_sectors_2);
1044234429Sambrisko	sc->disableOnlineCtrlReset =
1045234429Sambrisko	    ci->properties.OnOffProperties.disableOnlineCtrlReset;
1046157114Sscottl
1047159806Spsout:
1048159806Sps	if (ci)
1049159806Sps		free(ci, M_MFIBUF);
1050159806Sps	if (cm)
1051159806Sps		mfi_release_command(cm);
1052159806Sps	mtx_unlock(&sc->mfi_io_lock);
1053157114Sscottl	return (error);
1054157114Sscottl}
1055157114Sscottl
1056157114Sscottlstatic int
1057159806Spsmfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state)
1058158737Sambrisko{
1059159812Sps	struct mfi_command *cm = NULL;
1060158737Sambrisko	int error;
1061158737Sambrisko
1062250496Ssmh	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1063159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO,
1064159806Sps	    (void **)log_state, sizeof(**log_state));
1065159806Sps	if (error)
1066159806Sps		goto out;
1067159810Sps	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1068158737Sambrisko
1069158737Sambrisko	if ((error = mfi_mapcmd(sc, cm)) != 0) {
1070159802Sps		device_printf(sc->mfi_dev, "Failed to get log state\n");
1071159806Sps		goto out;
1072158737Sambrisko	}
1073158737Sambrisko
1074158737Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1075158737Sambrisko	    BUS_DMASYNC_POSTREAD);
1076158737Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1077158737Sambrisko
1078159806Spsout:
1079159812Sps	if (cm)
1080159812Sps		mfi_release_command(cm);
1081158737Sambrisko
1082158737Sambrisko	return (error);
1083158737Sambrisko}
1084158737Sambrisko
1085234429Sambriskoint
1086158737Sambriskomfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
1087158737Sambrisko{
1088159806Sps	struct mfi_evt_log_state *log_state = NULL;
1089158737Sambrisko	union mfi_evt class_locale;
1090158737Sambrisko	int error = 0;
1091158737Sambrisko	uint32_t seq;
1092158737Sambrisko
1093250496Ssmh	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1094250496Ssmh
1095158737Sambrisko	class_locale.members.reserved = 0;
1096162118Sambrisko	class_locale.members.locale = mfi_event_locale;
1097222589Semaste	class_locale.members.evt_class  = mfi_event_class;
1098158737Sambrisko
1099158737Sambrisko	if (seq_start == 0) {
1100250496Ssmh		if ((error = mfi_get_log_state(sc, &log_state)) != 0)
1101250496Ssmh			goto out;
1102234429Sambrisko		sc->mfi_boot_seq_num = log_state->boot_seq_num;
1103180037Sjhb
1104180037Sjhb		/*
1105180037Sjhb		 * Walk through any events that fired since the last
1106180037Sjhb		 * shutdown.
1107180037Sjhb		 */
1108250496Ssmh		if ((error = mfi_parse_entries(sc, log_state->shutdown_seq_num,
1109250496Ssmh		    log_state->newest_seq_num)) != 0)
1110250496Ssmh			goto out;
1111180037Sjhb		seq = log_state->newest_seq_num;
1112158737Sambrisko	} else
1113158737Sambrisko		seq = seq_start;
1114250496Ssmh	error = mfi_aen_register(sc, seq, class_locale.word);
1115250496Ssmhout:
1116159806Sps	free(log_state, M_MFIBUF);
1117158737Sambrisko
1118250496Ssmh	return (error);
1119158737Sambrisko}
1120158737Sambrisko
1121234429Sambriskoint
1122159811Spsmfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm)
1123159811Sps{
1124159811Sps
1125159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1126159811Sps	cm->cm_complete = NULL;
1127159811Sps
1128170284Sambrisko	/*
1129170284Sambrisko	 * MegaCli can issue a DCMD of 0.  In this case do nothing
1130170284Sambrisko	 * and return 0 to it as status
1131170284Sambrisko	 */
1132170284Sambrisko	if (cm->cm_frame->dcmd.opcode == 0) {
1133170284Sambrisko		cm->cm_frame->header.cmd_status = MFI_STAT_OK;
1134170284Sambrisko		cm->cm_error = 0;
1135170284Sambrisko		return (cm->cm_error);
1136170284Sambrisko	}
1137159811Sps	mfi_enqueue_ready(cm);
1138159811Sps	mfi_startio(sc);
1139170284Sambrisko	if ((cm->cm_flags & MFI_CMD_COMPLETED) == 0)
1140170284Sambrisko		msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0);
1141170284Sambrisko	return (cm->cm_error);
1142159811Sps}
1143159811Sps
1144157114Sscottlvoid
1145157114Sscottlmfi_free(struct mfi_softc *sc)
1146157114Sscottl{
1147157114Sscottl	struct mfi_command *cm;
1148157114Sscottl	int i;
1149157114Sscottl
1150162619Sscottl	callout_drain(&sc->mfi_watchdog_callout);
1151162619Sscottl
1152157114Sscottl	if (sc->mfi_cdev != NULL)
1153157114Sscottl		destroy_dev(sc->mfi_cdev);
1154157114Sscottl
1155250496Ssmh	if (sc->mfi_commands != NULL) {
1156250496Ssmh		for (i = 0; i < sc->mfi_max_fw_cmds; i++) {
1157157114Sscottl			cm = &sc->mfi_commands[i];
1158157114Sscottl			bus_dmamap_destroy(sc->mfi_buffer_dmat, cm->cm_dmamap);
1159157114Sscottl		}
1160157114Sscottl		free(sc->mfi_commands, M_MFIBUF);
1161250496Ssmh		sc->mfi_commands = NULL;
1162157114Sscottl	}
1163157114Sscottl
1164157114Sscottl	if (sc->mfi_intr)
1165157114Sscottl		bus_teardown_intr(sc->mfi_dev, sc->mfi_irq, sc->mfi_intr);
1166157114Sscottl	if (sc->mfi_irq != NULL)
1167157114Sscottl		bus_release_resource(sc->mfi_dev, SYS_RES_IRQ, sc->mfi_irq_rid,
1168157114Sscottl		    sc->mfi_irq);
1169157114Sscottl
1170157114Sscottl	if (sc->mfi_sense_busaddr != 0)
1171157114Sscottl		bus_dmamap_unload(sc->mfi_sense_dmat, sc->mfi_sense_dmamap);
1172157114Sscottl	if (sc->mfi_sense != NULL)
1173157114Sscottl		bus_dmamem_free(sc->mfi_sense_dmat, sc->mfi_sense,
1174157114Sscottl		    sc->mfi_sense_dmamap);
1175157114Sscottl	if (sc->mfi_sense_dmat != NULL)
1176157114Sscottl		bus_dma_tag_destroy(sc->mfi_sense_dmat);
1177157114Sscottl
1178157114Sscottl	if (sc->mfi_frames_busaddr != 0)
1179157114Sscottl		bus_dmamap_unload(sc->mfi_frames_dmat, sc->mfi_frames_dmamap);
1180157114Sscottl	if (sc->mfi_frames != NULL)
1181157114Sscottl		bus_dmamem_free(sc->mfi_frames_dmat, sc->mfi_frames,
1182157114Sscottl		    sc->mfi_frames_dmamap);
1183157114Sscottl	if (sc->mfi_frames_dmat != NULL)
1184157114Sscottl		bus_dma_tag_destroy(sc->mfi_frames_dmat);
1185157114Sscottl
1186157114Sscottl	if (sc->mfi_comms_busaddr != 0)
1187157114Sscottl		bus_dmamap_unload(sc->mfi_comms_dmat, sc->mfi_comms_dmamap);
1188157114Sscottl	if (sc->mfi_comms != NULL)
1189157114Sscottl		bus_dmamem_free(sc->mfi_comms_dmat, sc->mfi_comms,
1190157114Sscottl		    sc->mfi_comms_dmamap);
1191157114Sscottl	if (sc->mfi_comms_dmat != NULL)
1192157114Sscottl		bus_dma_tag_destroy(sc->mfi_comms_dmat);
1193157114Sscottl
1194234429Sambrisko	/* ThunderBolt contiguous memory free here */
1195234429Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
1196234429Sambrisko		if (sc->mfi_tb_busaddr != 0)
1197234429Sambrisko			bus_dmamap_unload(sc->mfi_tb_dmat, sc->mfi_tb_dmamap);
1198234429Sambrisko		if (sc->request_message_pool != NULL)
1199234429Sambrisko			bus_dmamem_free(sc->mfi_tb_dmat, sc->request_message_pool,
1200234429Sambrisko			    sc->mfi_tb_dmamap);
1201234429Sambrisko		if (sc->mfi_tb_dmat != NULL)
1202234429Sambrisko			bus_dma_tag_destroy(sc->mfi_tb_dmat);
1203234429Sambrisko
1204234429Sambrisko		/* Version buffer memory free */
1205234429Sambrisko		/* Start LSIP200113393 */
1206234429Sambrisko		if (sc->verbuf_h_busaddr != 0)
1207234429Sambrisko			bus_dmamap_unload(sc->verbuf_h_dmat, sc->verbuf_h_dmamap);
1208234429Sambrisko		if (sc->verbuf != NULL)
1209234429Sambrisko			bus_dmamem_free(sc->verbuf_h_dmat, sc->verbuf,
1210234429Sambrisko			    sc->verbuf_h_dmamap);
1211234429Sambrisko		if (sc->verbuf_h_dmat != NULL)
1212234429Sambrisko			bus_dma_tag_destroy(sc->verbuf_h_dmat);
1213234429Sambrisko
1214234429Sambrisko		/* End LSIP200113393 */
1215234429Sambrisko		/* ThunderBolt INIT packet memory Free */
1216234429Sambrisko		if (sc->mfi_tb_init_busaddr != 0)
1217250496Ssmh			bus_dmamap_unload(sc->mfi_tb_init_dmat,
1218250496Ssmh			    sc->mfi_tb_init_dmamap);
1219234429Sambrisko		if (sc->mfi_tb_init != NULL)
1220234429Sambrisko			bus_dmamem_free(sc->mfi_tb_init_dmat, sc->mfi_tb_init,
1221234429Sambrisko			    sc->mfi_tb_init_dmamap);
1222234429Sambrisko		if (sc->mfi_tb_init_dmat != NULL)
1223234429Sambrisko			bus_dma_tag_destroy(sc->mfi_tb_init_dmat);
1224234429Sambrisko
1225234429Sambrisko		/* ThunderBolt IOC Init Desc memory free here */
1226234429Sambrisko		if (sc->mfi_tb_ioc_init_busaddr != 0)
1227234429Sambrisko			bus_dmamap_unload(sc->mfi_tb_ioc_init_dmat,
1228234429Sambrisko			    sc->mfi_tb_ioc_init_dmamap);
1229234429Sambrisko		if (sc->mfi_tb_ioc_init_desc != NULL)
1230234429Sambrisko			bus_dmamem_free(sc->mfi_tb_ioc_init_dmat,
1231234429Sambrisko			    sc->mfi_tb_ioc_init_desc,
1232234429Sambrisko			    sc->mfi_tb_ioc_init_dmamap);
1233234429Sambrisko		if (sc->mfi_tb_ioc_init_dmat != NULL)
1234234429Sambrisko			bus_dma_tag_destroy(sc->mfi_tb_ioc_init_dmat);
1235250496Ssmh		if (sc->mfi_cmd_pool_tbolt != NULL) {
1236250496Ssmh			for (int i = 0; i < sc->mfi_max_fw_cmds; i++) {
1237234429Sambrisko				if (sc->mfi_cmd_pool_tbolt[i] != NULL) {
1238234429Sambrisko					free(sc->mfi_cmd_pool_tbolt[i],
1239234429Sambrisko					    M_MFIBUF);
1240234429Sambrisko					sc->mfi_cmd_pool_tbolt[i] = NULL;
1241234429Sambrisko				}
1242234429Sambrisko			}
1243234429Sambrisko			free(sc->mfi_cmd_pool_tbolt, M_MFIBUF);
1244234429Sambrisko			sc->mfi_cmd_pool_tbolt = NULL;
1245234429Sambrisko		}
1246234429Sambrisko		if (sc->request_desc_pool != NULL) {
1247234429Sambrisko			free(sc->request_desc_pool, M_MFIBUF);
1248234429Sambrisko			sc->request_desc_pool = NULL;
1249234429Sambrisko		}
1250234429Sambrisko	}
1251157114Sscottl	if (sc->mfi_buffer_dmat != NULL)
1252157114Sscottl		bus_dma_tag_destroy(sc->mfi_buffer_dmat);
1253157114Sscottl	if (sc->mfi_parent_dmat != NULL)
1254157114Sscottl		bus_dma_tag_destroy(sc->mfi_parent_dmat);
1255157114Sscottl
1256171821Sjhb	if (mtx_initialized(&sc->mfi_io_lock)) {
1257157114Sscottl		mtx_destroy(&sc->mfi_io_lock);
1258171821Sjhb		sx_destroy(&sc->mfi_config_lock);
1259171821Sjhb	}
1260157114Sscottl
1261157114Sscottl	return;
1262157114Sscottl}
1263157114Sscottl
1264157114Sscottlstatic void
1265157114Sscottlmfi_startup(void *arg)
1266157114Sscottl{
1267157114Sscottl	struct mfi_softc *sc;
1268157114Sscottl
1269157114Sscottl	sc = (struct mfi_softc *)arg;
1270157114Sscottl
1271157114Sscottl	config_intrhook_disestablish(&sc->mfi_ich);
1272157114Sscottl
1273171980Sscottl	sc->mfi_enable_intr(sc);
1274171821Sjhb	sx_xlock(&sc->mfi_config_lock);
1275163398Sscottl	mtx_lock(&sc->mfi_io_lock);
1276159811Sps	mfi_ldprobe(sc);
1277234429Sambrisko	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
1278234429Sambrisko	    mfi_syspdprobe(sc);
1279163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1280171821Sjhb	sx_xunlock(&sc->mfi_config_lock);
1281157114Sscottl}
1282157114Sscottl
1283157114Sscottlstatic void
1284157114Sscottlmfi_intr(void *arg)
1285157114Sscottl{
1286157114Sscottl	struct mfi_softc *sc;
1287157114Sscottl	struct mfi_command *cm;
1288171980Sscottl	uint32_t pi, ci, context;
1289157114Sscottl
1290157114Sscottl	sc = (struct mfi_softc *)arg;
1291157114Sscottl
1292171980Sscottl	if (sc->mfi_check_clear_intr(sc))
1293157114Sscottl		return;
1294163398Sscottl
1295234429Sambriskorestart:
1296157114Sscottl	pi = sc->mfi_comms->hw_pi;
1297157114Sscottl	ci = sc->mfi_comms->hw_ci;
1298157114Sscottl	mtx_lock(&sc->mfi_io_lock);
1299157114Sscottl	while (ci != pi) {
1300157114Sscottl		context = sc->mfi_comms->hw_reply_q[ci];
1301170284Sambrisko		if (context < sc->mfi_max_fw_cmds) {
1302170284Sambrisko			cm = &sc->mfi_commands[context];
1303170284Sambrisko			mfi_remove_busy(cm);
1304170284Sambrisko			cm->cm_error = 0;
1305170284Sambrisko			mfi_complete(sc, cm);
1306170284Sambrisko		}
1307250496Ssmh		if (++ci == (sc->mfi_max_fw_cmds + 1))
1308157114Sscottl			ci = 0;
1309157114Sscottl	}
1310157114Sscottl
1311157114Sscottl	sc->mfi_comms->hw_ci = ci;
1312157114Sscottl
1313163398Sscottl	/* Give defered I/O a chance to run */
1314250496Ssmh	sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
1315163398Sscottl	mfi_startio(sc);
1316163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1317163398Sscottl
1318234429Sambrisko	/*
1319234429Sambrisko	 * Dummy read to flush the bus; this ensures that the indexes are up
1320234429Sambrisko	 * to date.  Restart processing if more commands have come it.
1321234429Sambrisko	 */
1322234429Sambrisko	(void)sc->mfi_read_fw_status(sc);
1323234429Sambrisko	if (pi != sc->mfi_comms->hw_pi)
1324234429Sambrisko		goto restart;
1325234429Sambrisko
1326157114Sscottl	return;
1327157114Sscottl}
1328157114Sscottl
1329157114Sscottlint
1330157114Sscottlmfi_shutdown(struct mfi_softc *sc)
1331157114Sscottl{
1332157114Sscottl	struct mfi_dcmd_frame *dcmd;
1333157114Sscottl	struct mfi_command *cm;
1334157114Sscottl	int error;
1335157114Sscottl
1336243824Sdelphij
1337250496Ssmh	if (sc->mfi_aen_cm != NULL) {
1338243824Sdelphij		sc->cm_aen_abort = 1;
1339243824Sdelphij		mfi_abort(sc, &sc->mfi_aen_cm);
1340250496Ssmh	}
1341243824Sdelphij
1342250496Ssmh	if (sc->mfi_map_sync_cm != NULL) {
1343243824Sdelphij		sc->cm_map_abort = 1;
1344243824Sdelphij		mfi_abort(sc, &sc->mfi_map_sync_cm);
1345250496Ssmh	}
1346243824Sdelphij
1347159806Sps	mtx_lock(&sc->mfi_io_lock);
1348159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0);
1349163398Sscottl	if (error) {
1350163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
1351159806Sps		return (error);
1352163398Sscottl	}
1353157114Sscottl
1354157114Sscottl	dcmd = &cm->cm_frame->dcmd;
1355157114Sscottl	dcmd->header.flags = MFI_FRAME_DIR_NONE;
1356164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
1357164375Sscottl	cm->cm_data = NULL;
1358157114Sscottl
1359250496Ssmh	if ((error = mfi_mapcmd(sc, cm)) != 0)
1360157114Sscottl		device_printf(sc->mfi_dev, "Failed to shutdown controller\n");
1361157114Sscottl
1362159812Sps	mfi_release_command(cm);
1363163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1364157114Sscottl	return (error);
1365157114Sscottl}
1366157114Sscottl
1367157114Sscottlstatic void
1368234429Sambriskomfi_syspdprobe(struct mfi_softc *sc)
1369234429Sambrisko{
1370234429Sambrisko	struct mfi_frame_header *hdr;
1371234429Sambrisko	struct mfi_command *cm = NULL;
1372234429Sambrisko	struct mfi_pd_list *pdlist = NULL;
1373234429Sambrisko	struct mfi_system_pd *syspd, *tmp;
1374243824Sdelphij	struct mfi_system_pending *syspd_pend;
1375234429Sambrisko	int error, i, found;
1376234429Sambrisko
1377234429Sambrisko	sx_assert(&sc->mfi_config_lock, SA_XLOCKED);
1378234429Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1379234429Sambrisko	/* Add SYSTEM PD's */
1380234429Sambrisko	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_LIST_QUERY,
1381234429Sambrisko	    (void **)&pdlist, sizeof(*pdlist));
1382235135Sambrisko	if (error) {
1383234429Sambrisko		device_printf(sc->mfi_dev,
1384234429Sambrisko		    "Error while forming SYSTEM PD list\n");
1385234429Sambrisko		goto out;
1386234429Sambrisko	}
1387234429Sambrisko
1388234429Sambrisko	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1389234429Sambrisko	cm->cm_frame->dcmd.mbox[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
1390234429Sambrisko	cm->cm_frame->dcmd.mbox[1] = 0;
1391234429Sambrisko	if (mfi_mapcmd(sc, cm) != 0) {
1392234429Sambrisko		device_printf(sc->mfi_dev,
1393234429Sambrisko		    "Failed to get syspd device listing\n");
1394234429Sambrisko		goto out;
1395234429Sambrisko	}
1396234429Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat,cm->cm_dmamap,
1397234429Sambrisko	    BUS_DMASYNC_POSTREAD);
1398234429Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1399234429Sambrisko	hdr = &cm->cm_frame->header;
1400234429Sambrisko	if (hdr->cmd_status != MFI_STAT_OK) {
1401234429Sambrisko		device_printf(sc->mfi_dev,
1402234429Sambrisko		    "MFI_DCMD_PD_LIST_QUERY failed %x\n", hdr->cmd_status);
1403234429Sambrisko		goto out;
1404234429Sambrisko	}
1405234429Sambrisko	/* Get each PD and add it to the system */
1406234429Sambrisko	for (i = 0; i < pdlist->count; i++) {
1407234429Sambrisko		if (pdlist->addr[i].device_id ==
1408234429Sambrisko		    pdlist->addr[i].encl_device_id)
1409234429Sambrisko			continue;
1410234429Sambrisko		found = 0;
1411234429Sambrisko		TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) {
1412234429Sambrisko			if (syspd->pd_id == pdlist->addr[i].device_id)
1413234429Sambrisko				found = 1;
1414234429Sambrisko		}
1415243824Sdelphij		TAILQ_FOREACH(syspd_pend, &sc->mfi_syspd_pend_tqh, pd_link) {
1416243824Sdelphij			if (syspd_pend->pd_id == pdlist->addr[i].device_id)
1417243824Sdelphij				found = 1;
1418243824Sdelphij		}
1419234429Sambrisko		if (found == 0)
1420234429Sambrisko			mfi_add_sys_pd(sc, pdlist->addr[i].device_id);
1421234429Sambrisko	}
1422234429Sambrisko	/* Delete SYSPD's whose state has been changed */
1423234429Sambrisko	TAILQ_FOREACH_SAFE(syspd, &sc->mfi_syspd_tqh, pd_link, tmp) {
1424234429Sambrisko		found = 0;
1425234429Sambrisko		for (i = 0; i < pdlist->count; i++) {
1426250496Ssmh			if (syspd->pd_id == pdlist->addr[i].device_id) {
1427234429Sambrisko				found = 1;
1428250496Ssmh				break;
1429250496Ssmh			}
1430234429Sambrisko		}
1431234429Sambrisko		if (found == 0) {
1432234429Sambrisko			printf("DELETE\n");
1433234429Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1434234429Sambrisko			mtx_lock(&Giant);
1435234429Sambrisko			device_delete_child(sc->mfi_dev, syspd->pd_dev);
1436234429Sambrisko			mtx_unlock(&Giant);
1437234429Sambrisko			mtx_lock(&sc->mfi_io_lock);
1438234429Sambrisko		}
1439234429Sambrisko	}
1440234429Sambriskoout:
1441234429Sambrisko	if (pdlist)
1442234429Sambrisko	    free(pdlist, M_MFIBUF);
1443234429Sambrisko	if (cm)
1444234429Sambrisko	    mfi_release_command(cm);
1445234429Sambrisko
1446234429Sambrisko	return;
1447234429Sambrisko}
1448234429Sambrisko
1449234429Sambriskostatic void
1450159811Spsmfi_ldprobe(struct mfi_softc *sc)
1451157114Sscottl{
1452159811Sps	struct mfi_frame_header *hdr;
1453159811Sps	struct mfi_command *cm = NULL;
1454159811Sps	struct mfi_ld_list *list = NULL;
1455171821Sjhb	struct mfi_disk *ld;
1456243824Sdelphij	struct mfi_disk_pending *ld_pend;
1457159811Sps	int error, i;
1458157114Sscottl
1459171821Sjhb	sx_assert(&sc->mfi_config_lock, SA_XLOCKED);
1460163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1461163398Sscottl
1462159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
1463159811Sps	    (void **)&list, sizeof(*list));
1464159811Sps	if (error)
1465159811Sps		goto out;
1466159811Sps
1467159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
1468159811Sps	if (mfi_wait_command(sc, cm) != 0) {
1469159811Sps		device_printf(sc->mfi_dev, "Failed to get device listing\n");
1470159811Sps		goto out;
1471157114Sscottl	}
1472157114Sscottl
1473157114Sscottl	hdr = &cm->cm_frame->header;
1474159811Sps	if (hdr->cmd_status != MFI_STAT_OK) {
1475159811Sps		device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n",
1476159811Sps		    hdr->cmd_status);
1477159811Sps		goto out;
1478157114Sscottl	}
1479157114Sscottl
1480171821Sjhb	for (i = 0; i < list->ld_count; i++) {
1481171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1482171821Sjhb			if (ld->ld_id == list->ld_list[i].ld.v.target_id)
1483171821Sjhb				goto skip_add;
1484171821Sjhb		}
1485243824Sdelphij		TAILQ_FOREACH(ld_pend, &sc->mfi_ld_pend_tqh, ld_link) {
1486243824Sdelphij			if (ld_pend->ld_id == list->ld_list[i].ld.v.target_id)
1487243824Sdelphij				goto skip_add;
1488243824Sdelphij		}
1489163398Sscottl		mfi_add_ld(sc, list->ld_list[i].ld.v.target_id);
1490171821Sjhb	skip_add:;
1491171821Sjhb	}
1492159811Spsout:
1493159811Sps	if (list)
1494159811Sps		free(list, M_MFIBUF);
1495159811Sps	if (cm)
1496157114Sscottl		mfi_release_command(cm);
1497163398Sscottl
1498159811Sps	return;
1499157114Sscottl}
1500157114Sscottl
1501180038Sjhb/*
1502180038Sjhb * The timestamp is the number of seconds since 00:00 Jan 1, 2000.  If
1503180038Sjhb * the bits in 24-31 are all set, then it is the number of seconds since
1504180038Sjhb * boot.
1505180038Sjhb */
1506180038Sjhbstatic const char *
1507180038Sjhbformat_timestamp(uint32_t timestamp)
1508158737Sambrisko{
1509180038Sjhb	static char buffer[32];
1510180038Sjhb
1511180038Sjhb	if ((timestamp & 0xff000000) == 0xff000000)
1512180038Sjhb		snprintf(buffer, sizeof(buffer), "boot + %us", timestamp &
1513180038Sjhb		    0x00ffffff);
1514180038Sjhb	else
1515180038Sjhb		snprintf(buffer, sizeof(buffer), "%us", timestamp);
1516180038Sjhb	return (buffer);
1517180038Sjhb}
1518180038Sjhb
1519180038Sjhbstatic const char *
1520180038Sjhbformat_class(int8_t class)
1521180038Sjhb{
1522180038Sjhb	static char buffer[6];
1523180038Sjhb
1524180038Sjhb	switch (class) {
1525180038Sjhb	case MFI_EVT_CLASS_DEBUG:
1526180038Sjhb		return ("debug");
1527180038Sjhb	case MFI_EVT_CLASS_PROGRESS:
1528180038Sjhb		return ("progress");
1529180038Sjhb	case MFI_EVT_CLASS_INFO:
1530180038Sjhb		return ("info");
1531180038Sjhb	case MFI_EVT_CLASS_WARNING:
1532180038Sjhb		return ("WARN");
1533180038Sjhb	case MFI_EVT_CLASS_CRITICAL:
1534180038Sjhb		return ("CRIT");
1535180038Sjhb	case MFI_EVT_CLASS_FATAL:
1536180038Sjhb		return ("FATAL");
1537180038Sjhb	case MFI_EVT_CLASS_DEAD:
1538180038Sjhb		return ("DEAD");
1539158737Sambrisko	default:
1540180038Sjhb		snprintf(buffer, sizeof(buffer), "%d", class);
1541180038Sjhb		return (buffer);
1542158737Sambrisko	}
1543158737Sambrisko}
1544158737Sambrisko
1545180038Sjhbstatic void
1546180038Sjhbmfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
1547180038Sjhb{
1548234429Sambrisko	struct mfi_system_pd *syspd = NULL;
1549180038Sjhb
1550200238Sjkim	device_printf(sc->mfi_dev, "%d (%s/0x%04x/%s) - %s\n", detail->seq,
1551222589Semaste	    format_timestamp(detail->time), detail->evt_class.members.locale,
1552234429Sambrisko	    format_class(detail->evt_class.members.evt_class),
1553234429Sambrisko	    detail->description);
1554234429Sambrisko
1555234429Sambrisko        /* Don't act on old AEN's or while shutting down */
1556234429Sambrisko        if (detail->seq < sc->mfi_boot_seq_num || sc->mfi_detaching)
1557234429Sambrisko                return;
1558234429Sambrisko
1559234429Sambrisko	switch (detail->arg_type) {
1560234429Sambrisko	case MR_EVT_ARGS_NONE:
1561234429Sambrisko		if (detail->code == MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED) {
1562234429Sambrisko		    device_printf(sc->mfi_dev, "HostBus scan raised\n");
1563234429Sambrisko			if (mfi_detect_jbod_change) {
1564234429Sambrisko				/*
1565234429Sambrisko				 * Probe for new SYSPD's and Delete
1566234429Sambrisko				 * invalid SYSPD's
1567234429Sambrisko				 */
1568234429Sambrisko				sx_xlock(&sc->mfi_config_lock);
1569234429Sambrisko				mtx_lock(&sc->mfi_io_lock);
1570234429Sambrisko				mfi_syspdprobe(sc);
1571234429Sambrisko				mtx_unlock(&sc->mfi_io_lock);
1572234429Sambrisko				sx_xunlock(&sc->mfi_config_lock);
1573234429Sambrisko			}
1574234429Sambrisko		}
1575234429Sambrisko		break;
1576234429Sambrisko	case MR_EVT_ARGS_LD_STATE:
1577234429Sambrisko		/* During load time driver reads all the events starting
1578234429Sambrisko		 * from the one that has been logged after shutdown. Avoid
1579234429Sambrisko		 * these old events.
1580234429Sambrisko		 */
1581234429Sambrisko		if (detail->args.ld_state.new_state == MFI_LD_STATE_OFFLINE ) {
1582234429Sambrisko			/* Remove the LD */
1583234429Sambrisko			struct mfi_disk *ld;
1584234429Sambrisko			TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1585234429Sambrisko				if (ld->ld_id ==
1586234429Sambrisko				    detail->args.ld_state.ld.target_id)
1587234429Sambrisko					break;
1588234429Sambrisko			}
1589234429Sambrisko			/*
1590234429Sambrisko			Fix: for kernel panics when SSCD is removed
1591234429Sambrisko			KASSERT(ld != NULL, ("volume dissappeared"));
1592234429Sambrisko			*/
1593234429Sambrisko			if (ld != NULL) {
1594234429Sambrisko				mtx_lock(&Giant);
1595234429Sambrisko				device_delete_child(sc->mfi_dev, ld->ld_dev);
1596234429Sambrisko				mtx_unlock(&Giant);
1597234429Sambrisko			}
1598234429Sambrisko		}
1599234429Sambrisko		break;
1600234429Sambrisko	case MR_EVT_ARGS_PD:
1601234429Sambrisko		if (detail->code == MR_EVT_PD_REMOVED) {
1602234429Sambrisko			if (mfi_detect_jbod_change) {
1603234429Sambrisko				/*
1604234429Sambrisko				 * If the removed device is a SYSPD then
1605234429Sambrisko				 * delete it
1606234429Sambrisko				 */
1607234429Sambrisko				TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,
1608234429Sambrisko				    pd_link) {
1609234429Sambrisko					if (syspd->pd_id ==
1610234429Sambrisko					    detail->args.pd.device_id) {
1611234429Sambrisko						mtx_lock(&Giant);
1612234429Sambrisko						device_delete_child(
1613234429Sambrisko						    sc->mfi_dev,
1614234429Sambrisko						    syspd->pd_dev);
1615234429Sambrisko						mtx_unlock(&Giant);
1616234429Sambrisko						break;
1617234429Sambrisko					}
1618234429Sambrisko				}
1619234429Sambrisko			}
1620234429Sambrisko		}
1621234429Sambrisko		if (detail->code == MR_EVT_PD_INSERTED) {
1622234429Sambrisko			if (mfi_detect_jbod_change) {
1623234429Sambrisko				/* Probe for new SYSPD's */
1624234429Sambrisko				sx_xlock(&sc->mfi_config_lock);
1625234429Sambrisko				mtx_lock(&sc->mfi_io_lock);
1626234429Sambrisko				mfi_syspdprobe(sc);
1627234429Sambrisko				mtx_unlock(&sc->mfi_io_lock);
1628234429Sambrisko				sx_xunlock(&sc->mfi_config_lock);
1629234429Sambrisko			}
1630234429Sambrisko		}
1631252643Smarkj		if (sc->mfi_cam_rescan_cb != NULL &&
1632252643Smarkj		    (detail->code == MR_EVT_PD_INSERTED ||
1633252643Smarkj		    detail->code == MR_EVT_PD_REMOVED)) {
1634252643Smarkj			sc->mfi_cam_rescan_cb(sc, detail->args.pd.device_id);
1635252643Smarkj		}
1636234429Sambrisko		break;
1637234429Sambrisko	}
1638180038Sjhb}
1639180038Sjhb
1640234429Sambriskostatic void
1641234429Sambriskomfi_queue_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
1642234429Sambrisko{
1643234429Sambrisko	struct mfi_evt_queue_elm *elm;
1644234429Sambrisko
1645234429Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1646234429Sambrisko	elm = malloc(sizeof(*elm), M_MFIBUF, M_NOWAIT|M_ZERO);
1647234429Sambrisko	if (elm == NULL)
1648234429Sambrisko		return;
1649234429Sambrisko	memcpy(&elm->detail, detail, sizeof(*detail));
1650234429Sambrisko	TAILQ_INSERT_TAIL(&sc->mfi_evt_queue, elm, link);
1651234429Sambrisko	taskqueue_enqueue(taskqueue_swi, &sc->mfi_evt_task);
1652234429Sambrisko}
1653234429Sambrisko
1654234429Sambriskostatic void
1655234429Sambriskomfi_handle_evt(void *context, int pending)
1656234429Sambrisko{
1657234429Sambrisko	TAILQ_HEAD(,mfi_evt_queue_elm) queue;
1658234429Sambrisko	struct mfi_softc *sc;
1659234429Sambrisko	struct mfi_evt_queue_elm *elm;
1660234429Sambrisko
1661234429Sambrisko	sc = context;
1662234429Sambrisko	TAILQ_INIT(&queue);
1663234429Sambrisko	mtx_lock(&sc->mfi_io_lock);
1664234429Sambrisko	TAILQ_CONCAT(&queue, &sc->mfi_evt_queue, link);
1665234429Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1666234429Sambrisko	while ((elm = TAILQ_FIRST(&queue)) != NULL) {
1667234429Sambrisko		TAILQ_REMOVE(&queue, elm, link);
1668234429Sambrisko		mfi_decode_evt(sc, &elm->detail);
1669234429Sambrisko		free(elm, M_MFIBUF);
1670234429Sambrisko	}
1671234429Sambrisko}
1672234429Sambrisko
1673157114Sscottlstatic int
1674158737Sambriskomfi_aen_register(struct mfi_softc *sc, int seq, int locale)
1675158737Sambrisko{
1676158737Sambrisko	struct mfi_command *cm;
1677158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1678158737Sambrisko	union mfi_evt current_aen, prior_aen;
1679159806Sps	struct mfi_evt_detail *ed = NULL;
1680163398Sscottl	int error = 0;
1681158737Sambrisko
1682250496Ssmh	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1683250496Ssmh
1684158737Sambrisko	current_aen.word = locale;
1685158737Sambrisko	if (sc->mfi_aen_cm != NULL) {
1686158737Sambrisko		prior_aen.word =
1687158737Sambrisko		    ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1];
1688222589Semaste		if (prior_aen.members.evt_class <= current_aen.members.evt_class &&
1689158737Sambrisko		    !((prior_aen.members.locale & current_aen.members.locale)
1690158737Sambrisko		    ^current_aen.members.locale)) {
1691158737Sambrisko			return (0);
1692158737Sambrisko		} else {
1693158737Sambrisko			prior_aen.members.locale |= current_aen.members.locale;
1694222589Semaste			if (prior_aen.members.evt_class
1695222589Semaste			    < current_aen.members.evt_class)
1696222589Semaste				current_aen.members.evt_class =
1697222589Semaste				    prior_aen.members.evt_class;
1698243824Sdelphij			mfi_abort(sc, &sc->mfi_aen_cm);
1699158737Sambrisko		}
1700158737Sambrisko	}
1701158737Sambrisko
1702159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT,
1703159806Sps	    (void **)&ed, sizeof(*ed));
1704250496Ssmh	if (error)
1705163398Sscottl		goto out;
1706158737Sambrisko
1707158737Sambrisko	dcmd = &cm->cm_frame->dcmd;
1708158737Sambrisko	((uint32_t *)&dcmd->mbox)[0] = seq;
1709158737Sambrisko	((uint32_t *)&dcmd->mbox)[1] = locale;
1710158737Sambrisko	cm->cm_flags = MFI_CMD_DATAIN;
1711158737Sambrisko	cm->cm_complete = mfi_aen_complete;
1712158737Sambrisko
1713234429Sambrisko	sc->last_seq_num = seq;
1714158737Sambrisko	sc->mfi_aen_cm = cm;
1715158737Sambrisko
1716158737Sambrisko	mfi_enqueue_ready(cm);
1717158737Sambrisko	mfi_startio(sc);
1718158737Sambrisko
1719163398Sscottlout:
1720163398Sscottl	return (error);
1721158737Sambrisko}
1722158737Sambrisko
1723158737Sambriskostatic void
1724158737Sambriskomfi_aen_complete(struct mfi_command *cm)
1725158737Sambrisko{
1726158737Sambrisko	struct mfi_frame_header *hdr;
1727158737Sambrisko	struct mfi_softc *sc;
1728158737Sambrisko	struct mfi_evt_detail *detail;
1729163398Sscottl	struct mfi_aen *mfi_aen_entry, *tmp;
1730158737Sambrisko	int seq = 0, aborted = 0;
1731158737Sambrisko
1732158737Sambrisko	sc = cm->cm_sc;
1733234429Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1734234429Sambrisko
1735158737Sambrisko	if (sc->mfi_aen_cm == NULL)
1736158737Sambrisko		return;
1737158737Sambrisko
1738250496Ssmh	hdr = &cm->cm_frame->header;
1739250496Ssmh
1740235135Sambrisko	if (sc->cm_aen_abort ||
1741224039Sjhb	    hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
1742235135Sambrisko		sc->cm_aen_abort = 0;
1743158737Sambrisko		aborted = 1;
1744158737Sambrisko	} else {
1745158737Sambrisko		sc->mfi_aen_triggered = 1;
1746163398Sscottl		if (sc->mfi_poll_waiting) {
1747163398Sscottl			sc->mfi_poll_waiting = 0;
1748158737Sambrisko			selwakeup(&sc->mfi_select);
1749163398Sscottl		}
1750158737Sambrisko		detail = cm->cm_data;
1751234429Sambrisko		mfi_queue_evt(sc, detail);
1752158737Sambrisko		seq = detail->seq + 1;
1753234429Sambrisko		TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link,
1754234429Sambrisko		    tmp) {
1755158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
1756158737Sambrisko			    aen_link);
1757163398Sscottl			PROC_LOCK(mfi_aen_entry->p);
1758225617Skmacy			kern_psignal(mfi_aen_entry->p, SIGIO);
1759163398Sscottl			PROC_UNLOCK(mfi_aen_entry->p);
1760158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
1761158737Sambrisko		}
1762158737Sambrisko	}
1763158737Sambrisko
1764158737Sambrisko	free(cm->cm_data, M_MFIBUF);
1765250496Ssmh	wakeup(&sc->mfi_aen_cm);
1766158737Sambrisko	sc->mfi_aen_cm = NULL;
1767158737Sambrisko	mfi_release_command(cm);
1768158737Sambrisko
1769158737Sambrisko	/* set it up again so the driver can catch more events */
1770250496Ssmh	if (!aborted)
1771158737Sambrisko		mfi_aen_setup(sc, seq);
1772158737Sambrisko}
1773158737Sambrisko
1774180037Sjhb#define MAX_EVENTS 15
1775180037Sjhb
1776158737Sambriskostatic int
1777180037Sjhbmfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq)
1778158737Sambrisko{
1779158737Sambrisko	struct mfi_command *cm;
1780158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1781162118Sambrisko	struct mfi_evt_list *el;
1782180037Sjhb	union mfi_evt class_locale;
1783180037Sjhb	int error, i, seq, size;
1784158737Sambrisko
1785250496Ssmh	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1786250496Ssmh
1787180037Sjhb	class_locale.members.reserved = 0;
1788180037Sjhb	class_locale.members.locale = mfi_event_locale;
1789222589Semaste	class_locale.members.evt_class  = mfi_event_class;
1790158737Sambrisko
1791162118Sambrisko	size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail)
1792162118Sambrisko		* (MAX_EVENTS - 1);
1793162118Sambrisko	el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO);
1794180037Sjhb	if (el == NULL)
1795158737Sambrisko		return (ENOMEM);
1796158737Sambrisko
1797180037Sjhb	for (seq = start_seq;;) {
1798180037Sjhb		if ((cm = mfi_dequeue_free(sc)) == NULL) {
1799180037Sjhb			free(el, M_MFIBUF);
1800180037Sjhb			return (EBUSY);
1801180037Sjhb		}
1802158737Sambrisko
1803180037Sjhb		dcmd = &cm->cm_frame->dcmd;
1804180037Sjhb		bzero(dcmd->mbox, MFI_MBOX_SIZE);
1805180037Sjhb		dcmd->header.cmd = MFI_CMD_DCMD;
1806180037Sjhb		dcmd->header.timeout = 0;
1807180037Sjhb		dcmd->header.data_len = size;
1808180037Sjhb		dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET;
1809180037Sjhb		((uint32_t *)&dcmd->mbox)[0] = seq;
1810180037Sjhb		((uint32_t *)&dcmd->mbox)[1] = class_locale.word;
1811180037Sjhb		cm->cm_sg = &dcmd->sgl;
1812180037Sjhb		cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
1813180037Sjhb		cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1814180037Sjhb		cm->cm_data = el;
1815180037Sjhb		cm->cm_len = size;
1816180037Sjhb
1817180037Sjhb		if ((error = mfi_mapcmd(sc, cm)) != 0) {
1818180037Sjhb			device_printf(sc->mfi_dev,
1819180037Sjhb			    "Failed to get controller entries\n");
1820180037Sjhb			mfi_release_command(cm);
1821180037Sjhb			break;
1822180037Sjhb		}
1823180037Sjhb
1824180037Sjhb		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1825180037Sjhb		    BUS_DMASYNC_POSTREAD);
1826180037Sjhb		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1827180037Sjhb
1828180037Sjhb		if (dcmd->header.cmd_status == MFI_STAT_NOT_FOUND) {
1829180037Sjhb			mfi_release_command(cm);
1830180037Sjhb			break;
1831180037Sjhb		}
1832180037Sjhb		if (dcmd->header.cmd_status != MFI_STAT_OK) {
1833180037Sjhb			device_printf(sc->mfi_dev,
1834180037Sjhb			    "Error %d fetching controller entries\n",
1835180037Sjhb			    dcmd->header.cmd_status);
1836180037Sjhb			mfi_release_command(cm);
1837250496Ssmh			error = EIO;
1838180037Sjhb			break;
1839180037Sjhb		}
1840158737Sambrisko		mfi_release_command(cm);
1841158737Sambrisko
1842162473Sambrisko		for (i = 0; i < el->count; i++) {
1843180037Sjhb			/*
1844180037Sjhb			 * If this event is newer than 'stop_seq' then
1845180037Sjhb			 * break out of the loop.  Note that the log
1846180037Sjhb			 * is a circular buffer so we have to handle
1847180037Sjhb			 * the case that our stop point is earlier in
1848180037Sjhb			 * the buffer than our start point.
1849180037Sjhb			 */
1850180037Sjhb			if (el->event[i].seq >= stop_seq) {
1851180037Sjhb				if (start_seq <= stop_seq)
1852180037Sjhb					break;
1853180037Sjhb				else if (el->event[i].seq < start_seq)
1854180037Sjhb					break;
1855180037Sjhb			}
1856234429Sambrisko			mfi_queue_evt(sc, &el->event[i]);
1857162473Sambrisko		}
1858180037Sjhb		seq = el->event[el->count - 1].seq + 1;
1859162118Sambrisko	}
1860158737Sambrisko
1861180037Sjhb	free(el, M_MFIBUF);
1862250496Ssmh	return (error);
1863158737Sambrisko}
1864158737Sambrisko
1865158737Sambriskostatic int
1866159811Spsmfi_add_ld(struct mfi_softc *sc, int id)
1867157114Sscottl{
1868157114Sscottl	struct mfi_command *cm;
1869159811Sps	struct mfi_dcmd_frame *dcmd = NULL;
1870159811Sps	struct mfi_ld_info *ld_info = NULL;
1871243824Sdelphij	struct mfi_disk_pending *ld_pend;
1872159811Sps	int error;
1873157114Sscottl
1874159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1875159811Sps
1876243824Sdelphij	ld_pend = malloc(sizeof(*ld_pend), M_MFIBUF, M_NOWAIT | M_ZERO);
1877243824Sdelphij	if (ld_pend != NULL) {
1878243824Sdelphij		ld_pend->ld_id = id;
1879243824Sdelphij		TAILQ_INSERT_TAIL(&sc->mfi_ld_pend_tqh, ld_pend, ld_link);
1880243824Sdelphij	}
1881243824Sdelphij
1882159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO,
1883159811Sps	    (void **)&ld_info, sizeof(*ld_info));
1884159811Sps	if (error) {
1885159811Sps		device_printf(sc->mfi_dev,
1886159811Sps		    "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error);
1887159811Sps		if (ld_info)
1888159811Sps			free(ld_info, M_MFIBUF);
1889159811Sps		return (error);
1890157624Sscottl	}
1891159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
1892159811Sps	dcmd = &cm->cm_frame->dcmd;
1893159811Sps	dcmd->mbox[0] = id;
1894160052Sambrisko	if (mfi_wait_command(sc, cm) != 0) {
1895160052Sambrisko		device_printf(sc->mfi_dev,
1896160052Sambrisko		    "Failed to get logical drive: %d\n", id);
1897160052Sambrisko		free(ld_info, M_MFIBUF);
1898160052Sambrisko		return (0);
1899160052Sambrisko	}
1900234429Sambrisko	if (ld_info->ld_config.params.isSSCD != 1)
1901234429Sambrisko		mfi_add_ld_complete(cm);
1902234429Sambrisko	else {
1903234429Sambrisko		mfi_release_command(cm);
1904234429Sambrisko		if (ld_info)		/* SSCD drives ld_info free here */
1905234429Sambrisko			free(ld_info, M_MFIBUF);
1906234429Sambrisko	}
1907157114Sscottl	return (0);
1908157114Sscottl}
1909157114Sscottl
1910157114Sscottlstatic void
1911159811Spsmfi_add_ld_complete(struct mfi_command *cm)
1912157114Sscottl{
1913157114Sscottl	struct mfi_frame_header *hdr;
1914159811Sps	struct mfi_ld_info *ld_info;
1915157114Sscottl	struct mfi_softc *sc;
1916159811Sps	device_t child;
1917157114Sscottl
1918157114Sscottl	sc = cm->cm_sc;
1919157114Sscottl	hdr = &cm->cm_frame->header;
1920159811Sps	ld_info = cm->cm_private;
1921157114Sscottl
1922243824Sdelphij	if (sc->cm_map_abort || hdr->cmd_status != MFI_STAT_OK) {
1923159811Sps		free(ld_info, M_MFIBUF);
1924243824Sdelphij		wakeup(&sc->mfi_map_sync_cm);
1925157114Sscottl		mfi_release_command(cm);
1926157114Sscottl		return;
1927157114Sscottl	}
1928243824Sdelphij	wakeup(&sc->mfi_map_sync_cm);
1929157114Sscottl	mfi_release_command(cm);
1930157114Sscottl
1931169611Sscottl	mtx_unlock(&sc->mfi_io_lock);
1932196403Sjhb	mtx_lock(&Giant);
1933157114Sscottl	if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) {
1934157114Sscottl		device_printf(sc->mfi_dev, "Failed to add logical disk\n");
1935159811Sps		free(ld_info, M_MFIBUF);
1936196403Sjhb		mtx_unlock(&Giant);
1937169611Sscottl		mtx_lock(&sc->mfi_io_lock);
1938159811Sps		return;
1939157114Sscottl	}
1940157114Sscottl
1941169451Sscottl	device_set_ivars(child, ld_info);
1942157114Sscottl	device_set_desc(child, "MFI Logical Disk");
1943157114Sscottl	bus_generic_attach(sc->mfi_dev);
1944196403Sjhb	mtx_unlock(&Giant);
1945157114Sscottl	mtx_lock(&sc->mfi_io_lock);
1946157114Sscottl}
1947163399Sscottl
1948234429Sambriskostatic int mfi_add_sys_pd(struct mfi_softc *sc, int id)
1949234429Sambrisko{
1950234429Sambrisko	struct mfi_command *cm;
1951234429Sambrisko	struct mfi_dcmd_frame *dcmd = NULL;
1952234429Sambrisko	struct mfi_pd_info *pd_info = NULL;
1953243824Sdelphij	struct mfi_system_pending *syspd_pend;
1954234429Sambrisko	int error;
1955234429Sambrisko
1956234429Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1957234429Sambrisko
1958243824Sdelphij	syspd_pend = malloc(sizeof(*syspd_pend), M_MFIBUF, M_NOWAIT | M_ZERO);
1959243824Sdelphij	if (syspd_pend != NULL) {
1960243824Sdelphij		syspd_pend->pd_id = id;
1961243824Sdelphij		TAILQ_INSERT_TAIL(&sc->mfi_syspd_pend_tqh, syspd_pend, pd_link);
1962243824Sdelphij	}
1963243824Sdelphij
1964234429Sambrisko	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_GET_INFO,
1965234429Sambrisko		(void **)&pd_info, sizeof(*pd_info));
1966234429Sambrisko	if (error) {
1967234429Sambrisko		device_printf(sc->mfi_dev,
1968234429Sambrisko		    "Failed to allocated for MFI_DCMD_PD_GET_INFO %d\n",
1969234429Sambrisko		    error);
1970234429Sambrisko		if (pd_info)
1971234429Sambrisko			free(pd_info, M_MFIBUF);
1972234429Sambrisko		return (error);
1973234429Sambrisko	}
1974234429Sambrisko	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1975234429Sambrisko	dcmd = &cm->cm_frame->dcmd;
1976234429Sambrisko	dcmd->mbox[0]=id;
1977234429Sambrisko	dcmd->header.scsi_status = 0;
1978234429Sambrisko	dcmd->header.pad0 = 0;
1979250496Ssmh	if ((error = mfi_mapcmd(sc, cm)) != 0) {
1980234429Sambrisko		device_printf(sc->mfi_dev,
1981234429Sambrisko		    "Failed to get physical drive info %d\n", id);
1982234429Sambrisko		free(pd_info, M_MFIBUF);
1983250496Ssmh		mfi_release_command(cm);
1984250496Ssmh		return (error);
1985234429Sambrisko	}
1986234429Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1987234429Sambrisko	    BUS_DMASYNC_POSTREAD);
1988234429Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1989234429Sambrisko	mfi_add_sys_pd_complete(cm);
1990234429Sambrisko	return (0);
1991234429Sambrisko}
1992234429Sambrisko
1993234429Sambriskostatic void
1994234429Sambriskomfi_add_sys_pd_complete(struct mfi_command *cm)
1995234429Sambrisko{
1996234429Sambrisko	struct mfi_frame_header *hdr;
1997234429Sambrisko	struct mfi_pd_info *pd_info;
1998234429Sambrisko	struct mfi_softc *sc;
1999234429Sambrisko	device_t child;
2000234429Sambrisko
2001234429Sambrisko	sc = cm->cm_sc;
2002234429Sambrisko	hdr = &cm->cm_frame->header;
2003234429Sambrisko	pd_info = cm->cm_private;
2004234429Sambrisko
2005234429Sambrisko	if (hdr->cmd_status != MFI_STAT_OK) {
2006234429Sambrisko		free(pd_info, M_MFIBUF);
2007234429Sambrisko		mfi_release_command(cm);
2008234429Sambrisko		return;
2009234429Sambrisko	}
2010234429Sambrisko	if (pd_info->fw_state != MFI_PD_STATE_SYSTEM) {
2011234429Sambrisko		device_printf(sc->mfi_dev, "PD=%x is not SYSTEM PD\n",
2012234429Sambrisko		    pd_info->ref.v.device_id);
2013234429Sambrisko		free(pd_info, M_MFIBUF);
2014234429Sambrisko		mfi_release_command(cm);
2015234429Sambrisko		return;
2016234429Sambrisko	}
2017234429Sambrisko	mfi_release_command(cm);
2018234429Sambrisko
2019234429Sambrisko	mtx_unlock(&sc->mfi_io_lock);
2020234429Sambrisko	mtx_lock(&Giant);
2021234429Sambrisko	if ((child = device_add_child(sc->mfi_dev, "mfisyspd", -1)) == NULL) {
2022234429Sambrisko		device_printf(sc->mfi_dev, "Failed to add system pd\n");
2023234429Sambrisko		free(pd_info, M_MFIBUF);
2024234429Sambrisko		mtx_unlock(&Giant);
2025234429Sambrisko		mtx_lock(&sc->mfi_io_lock);
2026234429Sambrisko		return;
2027234429Sambrisko	}
2028234429Sambrisko
2029234429Sambrisko	device_set_ivars(child, pd_info);
2030234429Sambrisko	device_set_desc(child, "MFI System PD");
2031234429Sambrisko	bus_generic_attach(sc->mfi_dev);
2032234429Sambrisko	mtx_unlock(&Giant);
2033234429Sambrisko	mtx_lock(&sc->mfi_io_lock);
2034234429Sambrisko}
2035235135Sambrisko
2036157114Sscottlstatic struct mfi_command *
2037157114Sscottlmfi_bio_command(struct mfi_softc *sc)
2038157114Sscottl{
2039157114Sscottl	struct bio *bio;
2040234429Sambrisko	struct mfi_command *cm = NULL;
2041157114Sscottl
2042234429Sambrisko	/*reserving two commands to avoid starvation for IOCTL*/
2043235135Sambrisko	if (sc->mfi_qstat[MFIQ_FREE].q_length < 2) {
2044157114Sscottl		return (NULL);
2045234429Sambrisko	}
2046157114Sscottl	if ((bio = mfi_dequeue_bio(sc)) == NULL) {
2047157114Sscottl		return (NULL);
2048157114Sscottl	}
2049234429Sambrisko	if ((uintptr_t)bio->bio_driver2 == MFI_LD_IO) {
2050234429Sambrisko		cm = mfi_build_ldio(sc, bio);
2051234429Sambrisko	} else if ((uintptr_t) bio->bio_driver2 == MFI_SYS_PD_IO) {
2052234429Sambrisko		cm = mfi_build_syspdio(sc, bio);
2053234429Sambrisko	}
2054234429Sambrisko	if (!cm)
2055234429Sambrisko	    mfi_enqueue_bio(sc, bio);
2056234429Sambrisko	return cm;
2057234429Sambrisko}
2058243823Sdelphij
2059243824Sdelphij/*
2060243824Sdelphij * mostly copied from cam/scsi/scsi_all.c:scsi_read_write
2061243824Sdelphij */
2062243824Sdelphij
2063243824Sdelphijint
2064243824Sdelphijmfi_build_cdb(int readop, uint8_t byte2, u_int64_t lba, u_int32_t block_count, uint8_t *cdb)
2065243823Sdelphij{
2066243823Sdelphij	int cdb_len;
2067243823Sdelphij
2068243823Sdelphij	if (((lba & 0x1fffff) == lba)
2069243823Sdelphij         && ((block_count & 0xff) == block_count)
2070243823Sdelphij         && (byte2 == 0)) {
2071243823Sdelphij		/* We can fit in a 6 byte cdb */
2072243823Sdelphij		struct scsi_rw_6 *scsi_cmd;
2073243823Sdelphij
2074243824Sdelphij		scsi_cmd = (struct scsi_rw_6 *)cdb;
2075243823Sdelphij		scsi_cmd->opcode = readop ? READ_6 : WRITE_6;
2076243823Sdelphij		scsi_ulto3b(lba, scsi_cmd->addr);
2077243823Sdelphij		scsi_cmd->length = block_count & 0xff;
2078243823Sdelphij		scsi_cmd->control = 0;
2079243823Sdelphij		cdb_len = sizeof(*scsi_cmd);
2080243823Sdelphij	} else if (((block_count & 0xffff) == block_count) && ((lba & 0xffffffff) == lba)) {
2081243823Sdelphij		/* Need a 10 byte CDB */
2082243823Sdelphij		struct scsi_rw_10 *scsi_cmd;
2083243823Sdelphij
2084243824Sdelphij		scsi_cmd = (struct scsi_rw_10 *)cdb;
2085243823Sdelphij		scsi_cmd->opcode = readop ? READ_10 : WRITE_10;
2086243823Sdelphij		scsi_cmd->byte2 = byte2;
2087243823Sdelphij		scsi_ulto4b(lba, scsi_cmd->addr);
2088243823Sdelphij		scsi_cmd->reserved = 0;
2089243823Sdelphij		scsi_ulto2b(block_count, scsi_cmd->length);
2090243823Sdelphij		scsi_cmd->control = 0;
2091243823Sdelphij		cdb_len = sizeof(*scsi_cmd);
2092243823Sdelphij	} else if (((block_count & 0xffffffff) == block_count) &&
2093243823Sdelphij	    ((lba & 0xffffffff) == lba)) {
2094243823Sdelphij		/* Block count is too big for 10 byte CDB use a 12 byte CDB */
2095243823Sdelphij		struct scsi_rw_12 *scsi_cmd;
2096243823Sdelphij
2097243824Sdelphij		scsi_cmd = (struct scsi_rw_12 *)cdb;
2098243823Sdelphij		scsi_cmd->opcode = readop ? READ_12 : WRITE_12;
2099243823Sdelphij		scsi_cmd->byte2 = byte2;
2100243823Sdelphij		scsi_ulto4b(lba, scsi_cmd->addr);
2101243823Sdelphij		scsi_cmd->reserved = 0;
2102243823Sdelphij		scsi_ulto4b(block_count, scsi_cmd->length);
2103243823Sdelphij		scsi_cmd->control = 0;
2104243823Sdelphij		cdb_len = sizeof(*scsi_cmd);
2105243823Sdelphij	} else {
2106243823Sdelphij		/*
2107243823Sdelphij		 * 16 byte CDB.  We'll only get here if the LBA is larger
2108243823Sdelphij		 * than 2^32
2109243823Sdelphij		 */
2110243823Sdelphij		struct scsi_rw_16 *scsi_cmd;
2111243823Sdelphij
2112243824Sdelphij		scsi_cmd = (struct scsi_rw_16 *)cdb;
2113243823Sdelphij		scsi_cmd->opcode = readop ? READ_16 : WRITE_16;
2114243823Sdelphij		scsi_cmd->byte2 = byte2;
2115243823Sdelphij		scsi_u64to8b(lba, scsi_cmd->addr);
2116243823Sdelphij		scsi_cmd->reserved = 0;
2117243823Sdelphij		scsi_ulto4b(block_count, scsi_cmd->length);
2118243823Sdelphij		scsi_cmd->control = 0;
2119243823Sdelphij		cdb_len = sizeof(*scsi_cmd);
2120243823Sdelphij	}
2121243823Sdelphij
2122243823Sdelphij	return cdb_len;
2123243823Sdelphij}
2124243823Sdelphij
2125234429Sambriskostatic struct mfi_command *
2126234429Sambriskomfi_build_syspdio(struct mfi_softc *sc, struct bio *bio)
2127234429Sambrisko{
2128234429Sambrisko	struct mfi_command *cm;
2129234429Sambrisko	struct mfi_pass_frame *pass;
2130243824Sdelphij	uint32_t context = 0;
2131243824Sdelphij	int flags = 0, blkcount = 0, readop;
2132243823Sdelphij	uint8_t cdb_len;
2133157114Sscottl
2134250496Ssmh	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2135250496Ssmh
2136234429Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL)
2137234429Sambrisko	    return (NULL);
2138234429Sambrisko
2139234429Sambrisko	/* Zero out the MFI frame */
2140243824Sdelphij	context = cm->cm_frame->header.context;
2141234429Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
2142234429Sambrisko	cm->cm_frame->header.context = context;
2143234429Sambrisko	pass = &cm->cm_frame->pass;
2144234429Sambrisko	bzero(pass->cdb, 16);
2145234429Sambrisko	pass->header.cmd = MFI_CMD_PD_SCSI_IO;
2146234429Sambrisko	switch (bio->bio_cmd & 0x03) {
2147234429Sambrisko	case BIO_READ:
2148234429Sambrisko		flags = MFI_CMD_DATAIN;
2149243824Sdelphij		readop = 1;
2150234429Sambrisko		break;
2151234429Sambrisko	case BIO_WRITE:
2152234429Sambrisko		flags = MFI_CMD_DATAOUT;
2153243824Sdelphij		readop = 0;
2154234429Sambrisko		break;
2155234429Sambrisko	default:
2156243823Sdelphij		/* TODO: what about BIO_DELETE??? */
2157243824Sdelphij		panic("Unsupported bio command %x\n", bio->bio_cmd);
2158234429Sambrisko	}
2159234429Sambrisko
2160234429Sambrisko	/* Cheat with the sector length to avoid a non-constant division */
2161243824Sdelphij	blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2162234429Sambrisko	/* Fill the LBA and Transfer length in CDB */
2163243824Sdelphij	cdb_len = mfi_build_cdb(readop, 0, bio->bio_pblkno, blkcount,
2164243824Sdelphij	    pass->cdb);
2165234429Sambrisko	pass->header.target_id = (uintptr_t)bio->bio_driver1;
2166243824Sdelphij	pass->header.lun_id = 0;
2167234429Sambrisko	pass->header.timeout = 0;
2168234429Sambrisko	pass->header.flags = 0;
2169234429Sambrisko	pass->header.scsi_status = 0;
2170234429Sambrisko	pass->header.sense_len = MFI_SENSE_LEN;
2171234429Sambrisko	pass->header.data_len = bio->bio_bcount;
2172243823Sdelphij	pass->header.cdb_len = cdb_len;
2173234429Sambrisko	pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2174234429Sambrisko	pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2175234429Sambrisko	cm->cm_complete = mfi_bio_complete;
2176234429Sambrisko	cm->cm_private = bio;
2177234429Sambrisko	cm->cm_data = bio->bio_data;
2178234429Sambrisko	cm->cm_len = bio->bio_bcount;
2179234429Sambrisko	cm->cm_sg = &pass->sgl;
2180234429Sambrisko	cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
2181234429Sambrisko	cm->cm_flags = flags;
2182250496Ssmh
2183234429Sambrisko	return (cm);
2184234429Sambrisko}
2185234429Sambrisko
2186234429Sambriskostatic struct mfi_command *
2187234429Sambriskomfi_build_ldio(struct mfi_softc *sc, struct bio *bio)
2188234429Sambrisko{
2189234429Sambrisko	struct mfi_io_frame *io;
2190234429Sambrisko	struct mfi_command *cm;
2191243823Sdelphij	int flags;
2192243823Sdelphij	uint32_t blkcount;
2193234429Sambrisko	uint32_t context = 0;
2194234429Sambrisko
2195250496Ssmh	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2196250496Ssmh
2197234429Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL)
2198234429Sambrisko	    return (NULL);
2199234429Sambrisko
2200234429Sambrisko	/* Zero out the MFI frame */
2201234429Sambrisko	context = cm->cm_frame->header.context;
2202234429Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
2203234429Sambrisko	cm->cm_frame->header.context = context;
2204157114Sscottl	io = &cm->cm_frame->io;
2205157114Sscottl	switch (bio->bio_cmd & 0x03) {
2206157114Sscottl	case BIO_READ:
2207157114Sscottl		io->header.cmd = MFI_CMD_LD_READ;
2208157114Sscottl		flags = MFI_CMD_DATAIN;
2209157114Sscottl		break;
2210157114Sscottl	case BIO_WRITE:
2211157114Sscottl		io->header.cmd = MFI_CMD_LD_WRITE;
2212157114Sscottl		flags = MFI_CMD_DATAOUT;
2213157114Sscottl		break;
2214157114Sscottl	default:
2215243823Sdelphij		/* TODO: what about BIO_DELETE??? */
2216243824Sdelphij		panic("Unsupported bio command %x\n", bio->bio_cmd);
2217157114Sscottl	}
2218157114Sscottl
2219157114Sscottl	/* Cheat with the sector length to avoid a non-constant division */
2220157114Sscottl	blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2221157114Sscottl	io->header.target_id = (uintptr_t)bio->bio_driver1;
2222157114Sscottl	io->header.timeout = 0;
2223157114Sscottl	io->header.flags = 0;
2224234429Sambrisko	io->header.scsi_status = 0;
2225157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
2226157114Sscottl	io->header.data_len = blkcount;
2227234429Sambrisko	io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2228234429Sambrisko	io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2229157114Sscottl	io->lba_hi = (bio->bio_pblkno & 0xffffffff00000000) >> 32;
2230157114Sscottl	io->lba_lo = bio->bio_pblkno & 0xffffffff;
2231157114Sscottl	cm->cm_complete = mfi_bio_complete;
2232157114Sscottl	cm->cm_private = bio;
2233157114Sscottl	cm->cm_data = bio->bio_data;
2234157114Sscottl	cm->cm_len = bio->bio_bcount;
2235157114Sscottl	cm->cm_sg = &io->sgl;
2236157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
2237157114Sscottl	cm->cm_flags = flags;
2238250496Ssmh
2239157114Sscottl	return (cm);
2240157114Sscottl}
2241157114Sscottl
2242157114Sscottlstatic void
2243157114Sscottlmfi_bio_complete(struct mfi_command *cm)
2244157114Sscottl{
2245157114Sscottl	struct bio *bio;
2246157114Sscottl	struct mfi_frame_header *hdr;
2247157114Sscottl	struct mfi_softc *sc;
2248157114Sscottl
2249157114Sscottl	bio = cm->cm_private;
2250157114Sscottl	hdr = &cm->cm_frame->header;
2251157114Sscottl	sc = cm->cm_sc;
2252157114Sscottl
2253224039Sjhb	if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0)) {
2254157114Sscottl		bio->bio_flags |= BIO_ERROR;
2255157114Sscottl		bio->bio_error = EIO;
2256250496Ssmh		device_printf(sc->mfi_dev, "I/O error, cmd=%p, status=%#x, "
2257250496Ssmh		    "scsi_status=%#x\n", cm, hdr->cmd_status, hdr->scsi_status);
2258157114Sscottl		mfi_print_sense(cm->cm_sc, cm->cm_sense);
2259184897Sambrisko	} else if (cm->cm_error != 0) {
2260184897Sambrisko		bio->bio_flags |= BIO_ERROR;
2261250496Ssmh		bio->bio_error = cm->cm_error;
2262250496Ssmh		device_printf(sc->mfi_dev, "I/O error, cmd=%p, error=%#x\n",
2263250496Ssmh		    cm, cm->cm_error);
2264157114Sscottl	}
2265157114Sscottl
2266157114Sscottl	mfi_release_command(cm);
2267157114Sscottl	mfi_disk_complete(bio);
2268157114Sscottl}
2269157114Sscottl
2270157114Sscottlvoid
2271157114Sscottlmfi_startio(struct mfi_softc *sc)
2272157114Sscottl{
2273157114Sscottl	struct mfi_command *cm;
2274169611Sscottl	struct ccb_hdr *ccbh;
2275157114Sscottl
2276157114Sscottl	for (;;) {
2277157114Sscottl		/* Don't bother if we're short on resources */
2278157114Sscottl		if (sc->mfi_flags & MFI_FLAGS_QFRZN)
2279157114Sscottl			break;
2280157114Sscottl
2281157114Sscottl		/* Try a command that has already been prepared */
2282157114Sscottl		cm = mfi_dequeue_ready(sc);
2283157114Sscottl
2284169611Sscottl		if (cm == NULL) {
2285169611Sscottl			if ((ccbh = TAILQ_FIRST(&sc->mfi_cam_ccbq)) != NULL)
2286169611Sscottl				cm = sc->mfi_cam_start(ccbh);
2287169611Sscottl		}
2288169611Sscottl
2289157114Sscottl		/* Nope, so look for work on the bioq */
2290157114Sscottl		if (cm == NULL)
2291157114Sscottl			cm = mfi_bio_command(sc);
2292157114Sscottl
2293157114Sscottl		/* No work available, so exit */
2294157114Sscottl		if (cm == NULL)
2295157114Sscottl			break;
2296157114Sscottl
2297157114Sscottl		/* Send the command to the controller */
2298157114Sscottl		if (mfi_mapcmd(sc, cm) != 0) {
2299250496Ssmh			device_printf(sc->mfi_dev, "Failed to startio\n");
2300157114Sscottl			mfi_requeue_ready(cm);
2301157114Sscottl			break;
2302157114Sscottl		}
2303157114Sscottl	}
2304157114Sscottl}
2305157114Sscottl
2306234429Sambriskoint
2307157114Sscottlmfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm)
2308157114Sscottl{
2309157114Sscottl	int error, polled;
2310157114Sscottl
2311163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2312163398Sscottl
2313234429Sambrisko	if ((cm->cm_data != NULL) && (cm->cm_frame->header.cmd != MFI_CMD_STP )) {
2314157114Sscottl		polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0;
2315251874Sscottl		if (cm->cm_flags & MFI_CMD_CCB)
2316251874Sscottl			error = bus_dmamap_load_ccb(sc->mfi_buffer_dmat,
2317251874Sscottl			    cm->cm_dmamap, cm->cm_data, mfi_data_cb, cm,
2318251874Sscottl			    polled);
2319251874Sscottl		else
2320251874Sscottl			error = bus_dmamap_load(sc->mfi_buffer_dmat,
2321251874Sscottl			    cm->cm_dmamap, cm->cm_data, cm->cm_len,
2322251874Sscottl			    mfi_data_cb, cm, polled);
2323157114Sscottl		if (error == EINPROGRESS) {
2324157114Sscottl			sc->mfi_flags |= MFI_FLAGS_QFRZN;
2325157114Sscottl			return (0);
2326157114Sscottl		}
2327157114Sscottl	} else {
2328250496Ssmh		error = mfi_send_frame(sc, cm);
2329157114Sscottl	}
2330157114Sscottl
2331157114Sscottl	return (error);
2332157114Sscottl}
2333157114Sscottl
2334157114Sscottlstatic void
2335157114Sscottlmfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
2336157114Sscottl{
2337157114Sscottl	struct mfi_frame_header *hdr;
2338157114Sscottl	struct mfi_command *cm;
2339157237Sscottl	union mfi_sgl *sgl;
2340157114Sscottl	struct mfi_softc *sc;
2341225918Smav	int i, j, first, dir;
2342250496Ssmh	int sge_size, locked;
2343157114Sscottl
2344157114Sscottl	cm = (struct mfi_command *)arg;
2345157114Sscottl	sc = cm->cm_sc;
2346157237Sscottl	hdr = &cm->cm_frame->header;
2347157237Sscottl	sgl = cm->cm_sg;
2348157114Sscottl
2349250496Ssmh	/*
2350250496Ssmh	 * We need to check if we have the lock as this is async
2351250496Ssmh	 * callback so even though our caller mfi_mapcmd asserts
2352250496Ssmh	 * it has the lock, there is no garantee that hasn't been
2353250496Ssmh	 * dropped if bus_dmamap_load returned prior to our
2354250496Ssmh	 * completion.
2355250496Ssmh	 */
2356250496Ssmh	if ((locked = mtx_owned(&sc->mfi_io_lock)) == 0)
2357250496Ssmh		mtx_lock(&sc->mfi_io_lock);
2358250496Ssmh
2359170284Sambrisko	if (error) {
2360170284Sambrisko		printf("error %d in callback\n", error);
2361170284Sambrisko		cm->cm_error = error;
2362170284Sambrisko		mfi_complete(sc, cm);
2363250496Ssmh		goto out;
2364170284Sambrisko	}
2365234429Sambrisko	/* Use IEEE sgl only for IO's on a SKINNY controller
2366234429Sambrisko	 * For other commands on a SKINNY controller use either
2367234429Sambrisko	 * sg32 or sg64 based on the sizeof(bus_addr_t).
2368234429Sambrisko	 * Also calculate the total frame size based on the type
2369234429Sambrisko	 * of SGL used.
2370234429Sambrisko	 */
2371234429Sambrisko	if (((cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) ||
2372234429Sambrisko	    (cm->cm_frame->header.cmd == MFI_CMD_LD_READ) ||
2373234429Sambrisko	    (cm->cm_frame->header.cmd == MFI_CMD_LD_WRITE)) &&
2374234429Sambrisko	    (sc->mfi_flags & MFI_FLAGS_SKINNY)) {
2375157237Sscottl		for (i = 0; i < nsegs; i++) {
2376234429Sambrisko			sgl->sg_skinny[i].addr = segs[i].ds_addr;
2377234429Sambrisko			sgl->sg_skinny[i].len = segs[i].ds_len;
2378234429Sambrisko			sgl->sg_skinny[i].flag = 0;
2379157114Sscottl		}
2380234429Sambrisko		hdr->flags |= MFI_FRAME_IEEE_SGL | MFI_FRAME_SGL64;
2381234429Sambrisko		sge_size = sizeof(struct mfi_sg_skinny);
2382234429Sambrisko		hdr->sg_count = nsegs;
2383157237Sscottl	} else {
2384234429Sambrisko		j = 0;
2385234429Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
2386234429Sambrisko			first = cm->cm_stp_len;
2387234429Sambrisko			if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
2388234429Sambrisko				sgl->sg32[j].addr = segs[0].ds_addr;
2389234429Sambrisko				sgl->sg32[j++].len = first;
2390234429Sambrisko			} else {
2391234429Sambrisko				sgl->sg64[j].addr = segs[0].ds_addr;
2392234429Sambrisko				sgl->sg64[j++].len = first;
2393234429Sambrisko			}
2394234429Sambrisko		} else
2395225918Smav			first = 0;
2396234429Sambrisko		if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
2397234429Sambrisko			for (i = 0; i < nsegs; i++) {
2398234429Sambrisko				sgl->sg32[j].addr = segs[i].ds_addr + first;
2399234429Sambrisko				sgl->sg32[j++].len = segs[i].ds_len - first;
2400234429Sambrisko				first = 0;
2401234429Sambrisko			}
2402234429Sambrisko		} else {
2403234429Sambrisko			for (i = 0; i < nsegs; i++) {
2404234429Sambrisko				sgl->sg64[j].addr = segs[i].ds_addr + first;
2405234429Sambrisko				sgl->sg64[j++].len = segs[i].ds_len - first;
2406234429Sambrisko				first = 0;
2407234429Sambrisko			}
2408234429Sambrisko			hdr->flags |= MFI_FRAME_SGL64;
2409157237Sscottl		}
2410234429Sambrisko		hdr->sg_count = j;
2411234429Sambrisko		sge_size = sc->mfi_sge_size;
2412157114Sscottl	}
2413157114Sscottl
2414157114Sscottl	dir = 0;
2415157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAIN) {
2416157114Sscottl		dir |= BUS_DMASYNC_PREREAD;
2417157114Sscottl		hdr->flags |= MFI_FRAME_DIR_READ;
2418157114Sscottl	}
2419157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAOUT) {
2420157114Sscottl		dir |= BUS_DMASYNC_PREWRITE;
2421157114Sscottl		hdr->flags |= MFI_FRAME_DIR_WRITE;
2422157114Sscottl	}
2423157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
2424157114Sscottl	cm->cm_flags |= MFI_CMD_MAPPED;
2425157114Sscottl
2426157114Sscottl	/*
2427157114Sscottl	 * Instead of calculating the total number of frames in the
2428157114Sscottl	 * compound frame, it's already assumed that there will be at
2429157114Sscottl	 * least 1 frame, so don't compensate for the modulo of the
2430157114Sscottl	 * following division.
2431157114Sscottl	 */
2432162458Sscottl	cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs);
2433157114Sscottl	cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
2434157114Sscottl
2435250496Ssmh	if ((error = mfi_send_frame(sc, cm)) != 0) {
2436250496Ssmh		printf("error %d in callback from mfi_send_frame\n", error);
2437250496Ssmh		cm->cm_error = error;
2438250496Ssmh		mfi_complete(sc, cm);
2439250496Ssmh		goto out;
2440250496Ssmh	}
2441157114Sscottl
2442250496Ssmhout:
2443250496Ssmh	/* leave the lock in the state we found it */
2444250496Ssmh	if (locked == 0)
2445250496Ssmh		mtx_unlock(&sc->mfi_io_lock);
2446250496Ssmh
2447157114Sscottl	return;
2448157114Sscottl}
2449157114Sscottl
2450157114Sscottlstatic int
2451157114Sscottlmfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
2452157114Sscottl{
2453250496Ssmh	int error;
2454250496Ssmh
2455250496Ssmh	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2456250496Ssmh
2457250496Ssmh	if (sc->MFA_enabled)
2458250496Ssmh		error = mfi_tbolt_send_frame(sc, cm);
2459250496Ssmh	else
2460250496Ssmh		error = mfi_std_send_frame(sc, cm);
2461250496Ssmh
2462250496Ssmh	if (error != 0 && (cm->cm_flags & MFI_ON_MFIQ_BUSY) != 0)
2463250496Ssmh		mfi_remove_busy(cm);
2464250496Ssmh
2465250496Ssmh	return (error);
2466250496Ssmh}
2467250496Ssmh
2468250496Ssmhstatic int
2469250496Ssmhmfi_std_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
2470250496Ssmh{
2471164375Sscottl	struct mfi_frame_header *hdr;
2472250496Ssmh	int tm = mfi_polled_cmd_timeout * 1000;
2473157114Sscottl
2474164375Sscottl	hdr = &cm->cm_frame->header;
2475164375Sscottl
2476164375Sscottl	if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
2477164375Sscottl		cm->cm_timestamp = time_uptime;
2478164375Sscottl		mfi_enqueue_busy(cm);
2479164375Sscottl	} else {
2480224039Sjhb		hdr->cmd_status = MFI_STAT_INVALID_STATUS;
2481164375Sscottl		hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
2482164375Sscottl	}
2483164375Sscottl
2484157114Sscottl	/*
2485157114Sscottl	 * The bus address of the command is aligned on a 64 byte boundary,
2486157114Sscottl	 * leaving the least 6 bits as zero.  For whatever reason, the
2487157114Sscottl	 * hardware wants the address shifted right by three, leaving just
2488162458Sscottl	 * 3 zero bits.  These three bits are then used as a prefetching
2489162458Sscottl	 * hint for the hardware to predict how many frames need to be
2490162458Sscottl	 * fetched across the bus.  If a command has more than 8 frames
2491162458Sscottl	 * then the 3 bits are set to 0x7 and the firmware uses other
2492162458Sscottl	 * information in the command to determine the total amount to fetch.
2493162458Sscottl	 * However, FreeBSD doesn't support I/O larger than 128K, so 8 frames
2494162458Sscottl	 * is enough for both 32bit and 64bit systems.
2495157114Sscottl	 */
2496162458Sscottl	if (cm->cm_extra_frames > 7)
2497162458Sscottl		cm->cm_extra_frames = 7;
2498162458Sscottl
2499234429Sambrisko	sc->mfi_issue_cmd(sc, cm->cm_frame_busaddr, cm->cm_extra_frames);
2500164375Sscottl
2501164375Sscottl	if ((cm->cm_flags & MFI_CMD_POLLED) == 0)
2502164375Sscottl		return (0);
2503164375Sscottl
2504164375Sscottl	/* This is a polled command, so busy-wait for it to complete. */
2505224039Sjhb	while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
2506164375Sscottl		DELAY(1000);
2507165225Sambrisko		tm -= 1;
2508164375Sscottl		if (tm <= 0)
2509164375Sscottl			break;
2510164375Sscottl	}
2511164375Sscottl
2512224039Sjhb	if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
2513165225Sambrisko		device_printf(sc->mfi_dev, "Frame %p timed out "
2514234429Sambrisko		    "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
2515164375Sscottl		return (ETIMEDOUT);
2516164375Sscottl	}
2517164375Sscottl
2518157114Sscottl	return (0);
2519157114Sscottl}
2520157114Sscottl
2521234429Sambrisko
2522234429Sambriskovoid
2523157114Sscottlmfi_complete(struct mfi_softc *sc, struct mfi_command *cm)
2524157114Sscottl{
2525157114Sscottl	int dir;
2526250496Ssmh	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2527157114Sscottl
2528157114Sscottl	if ((cm->cm_flags & MFI_CMD_MAPPED) != 0) {
2529157114Sscottl		dir = 0;
2530225918Smav		if ((cm->cm_flags & MFI_CMD_DATAIN) ||
2531225918Smav		    (cm->cm_frame->header.cmd == MFI_CMD_STP))
2532157114Sscottl			dir |= BUS_DMASYNC_POSTREAD;
2533157114Sscottl		if (cm->cm_flags & MFI_CMD_DATAOUT)
2534157114Sscottl			dir |= BUS_DMASYNC_POSTWRITE;
2535157114Sscottl
2536157114Sscottl		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
2537157114Sscottl		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
2538157114Sscottl		cm->cm_flags &= ~MFI_CMD_MAPPED;
2539157114Sscottl	}
2540157114Sscottl
2541170284Sambrisko	cm->cm_flags |= MFI_CMD_COMPLETED;
2542170284Sambrisko
2543157114Sscottl	if (cm->cm_complete != NULL)
2544157114Sscottl		cm->cm_complete(cm);
2545159811Sps	else
2546159811Sps		wakeup(cm);
2547157114Sscottl}
2548157114Sscottl
2549158737Sambriskostatic int
2550243824Sdelphijmfi_abort(struct mfi_softc *sc, struct mfi_command **cm_abort)
2551158737Sambrisko{
2552158737Sambrisko	struct mfi_command *cm;
2553158737Sambrisko	struct mfi_abort_frame *abort;
2554250496Ssmh	int i = 0, error;
2555234429Sambrisko	uint32_t context = 0;
2556158737Sambrisko
2557243824Sdelphij	mtx_lock(&sc->mfi_io_lock);
2558158737Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL) {
2559250496Ssmh		mtx_unlock(&sc->mfi_io_lock);
2560158737Sambrisko		return (EBUSY);
2561158737Sambrisko	}
2562158737Sambrisko
2563234429Sambrisko	/* Zero out the MFI frame */
2564234429Sambrisko	context = cm->cm_frame->header.context;
2565234429Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
2566234429Sambrisko	cm->cm_frame->header.context = context;
2567234429Sambrisko
2568158737Sambrisko	abort = &cm->cm_frame->abort;
2569158737Sambrisko	abort->header.cmd = MFI_CMD_ABORT;
2570158737Sambrisko	abort->header.flags = 0;
2571234429Sambrisko	abort->header.scsi_status = 0;
2572243824Sdelphij	abort->abort_context = (*cm_abort)->cm_frame->header.context;
2573243824Sdelphij	abort->abort_mfi_addr_lo = (uint32_t)(*cm_abort)->cm_frame_busaddr;
2574234429Sambrisko	abort->abort_mfi_addr_hi =
2575243824Sdelphij		(uint32_t)((uint64_t)(*cm_abort)->cm_frame_busaddr >> 32);
2576158737Sambrisko	cm->cm_data = NULL;
2577164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
2578158737Sambrisko
2579250496Ssmh	if ((error = mfi_mapcmd(sc, cm)) != 0)
2580250496Ssmh		device_printf(sc->mfi_dev, "failed to abort command\n");
2581158737Sambrisko	mfi_release_command(cm);
2582158737Sambrisko
2583243824Sdelphij	mtx_unlock(&sc->mfi_io_lock);
2584243824Sdelphij	while (i < 5 && *cm_abort != NULL) {
2585243824Sdelphij		tsleep(cm_abort, 0, "mfiabort",
2586234429Sambrisko		    5 * hz);
2587165225Sambrisko		i++;
2588158737Sambrisko	}
2589243824Sdelphij	if (*cm_abort != NULL) {
2590243824Sdelphij		/* Force a complete if command didn't abort */
2591243824Sdelphij		mtx_lock(&sc->mfi_io_lock);
2592243824Sdelphij		(*cm_abort)->cm_complete(*cm_abort);
2593243824Sdelphij		mtx_unlock(&sc->mfi_io_lock);
2594235135Sambrisko	}
2595158737Sambrisko
2596250496Ssmh	return (error);
2597158737Sambrisko}
2598158737Sambrisko
2599157114Sscottlint
2600234429Sambriskomfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt,
2601234429Sambrisko     int len)
2602157114Sscottl{
2603157114Sscottl	struct mfi_command *cm;
2604157114Sscottl	struct mfi_io_frame *io;
2605157114Sscottl	int error;
2606234429Sambrisko	uint32_t context = 0;
2607157114Sscottl
2608157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
2609157114Sscottl		return (EBUSY);
2610157114Sscottl
2611234429Sambrisko	/* Zero out the MFI frame */
2612234429Sambrisko	context = cm->cm_frame->header.context;
2613234429Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
2614234429Sambrisko	cm->cm_frame->header.context = context;
2615234429Sambrisko
2616157114Sscottl	io = &cm->cm_frame->io;
2617157114Sscottl	io->header.cmd = MFI_CMD_LD_WRITE;
2618157114Sscottl	io->header.target_id = id;
2619157114Sscottl	io->header.timeout = 0;
2620157114Sscottl	io->header.flags = 0;
2621234429Sambrisko	io->header.scsi_status = 0;
2622157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
2623157114Sscottl	io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2624234429Sambrisko	io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2625234429Sambrisko	io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2626157114Sscottl	io->lba_hi = (lba & 0xffffffff00000000) >> 32;
2627157114Sscottl	io->lba_lo = lba & 0xffffffff;
2628157114Sscottl	cm->cm_data = virt;
2629157114Sscottl	cm->cm_len = len;
2630157114Sscottl	cm->cm_sg = &io->sgl;
2631157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
2632157114Sscottl	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT;
2633157114Sscottl
2634250496Ssmh	if ((error = mfi_mapcmd(sc, cm)) != 0)
2635250496Ssmh		device_printf(sc->mfi_dev, "failed dump blocks\n");
2636157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
2637157114Sscottl	    BUS_DMASYNC_POSTWRITE);
2638157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
2639157114Sscottl	mfi_release_command(cm);
2640157114Sscottl
2641157114Sscottl	return (error);
2642157114Sscottl}
2643157114Sscottl
2644234429Sambriskoint
2645234429Sambriskomfi_dump_syspd_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt,
2646234429Sambrisko    int len)
2647234429Sambrisko{
2648234429Sambrisko	struct mfi_command *cm;
2649234429Sambrisko	struct mfi_pass_frame *pass;
2650243824Sdelphij	int error, readop, cdb_len;
2651243823Sdelphij	uint32_t blkcount;
2652234429Sambrisko
2653234429Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL)
2654234429Sambrisko		return (EBUSY);
2655234429Sambrisko
2656234429Sambrisko	pass = &cm->cm_frame->pass;
2657234429Sambrisko	bzero(pass->cdb, 16);
2658234429Sambrisko	pass->header.cmd = MFI_CMD_PD_SCSI_IO;
2659243824Sdelphij
2660243824Sdelphij	readop = 0;
2661234429Sambrisko	blkcount = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2662243824Sdelphij	cdb_len = mfi_build_cdb(readop, 0, lba, blkcount, pass->cdb);
2663234429Sambrisko	pass->header.target_id = id;
2664234429Sambrisko	pass->header.timeout = 0;
2665234429Sambrisko	pass->header.flags = 0;
2666234429Sambrisko	pass->header.scsi_status = 0;
2667234429Sambrisko	pass->header.sense_len = MFI_SENSE_LEN;
2668234429Sambrisko	pass->header.data_len = len;
2669243824Sdelphij	pass->header.cdb_len = cdb_len;
2670234429Sambrisko	pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2671234429Sambrisko	pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2672234429Sambrisko	cm->cm_data = virt;
2673234429Sambrisko	cm->cm_len = len;
2674234429Sambrisko	cm->cm_sg = &pass->sgl;
2675234429Sambrisko	cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
2676243824Sdelphij	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT | MFI_CMD_SCSI;
2677234429Sambrisko
2678250496Ssmh	if ((error = mfi_mapcmd(sc, cm)) != 0)
2679250496Ssmh		device_printf(sc->mfi_dev, "failed dump blocks\n");
2680234429Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
2681234429Sambrisko	    BUS_DMASYNC_POSTWRITE);
2682234429Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
2683234429Sambrisko	mfi_release_command(cm);
2684234429Sambrisko
2685234429Sambrisko	return (error);
2686234429Sambrisko}
2687234429Sambrisko
2688157114Sscottlstatic int
2689192450Simpmfi_open(struct cdev *dev, int flags, int fmt, struct thread *td)
2690157114Sscottl{
2691157114Sscottl	struct mfi_softc *sc;
2692171822Sjhb	int error;
2693157114Sscottl
2694157114Sscottl	sc = dev->si_drv1;
2695163398Sscottl
2696163398Sscottl	mtx_lock(&sc->mfi_io_lock);
2697171822Sjhb	if (sc->mfi_detaching)
2698171822Sjhb		error = ENXIO;
2699171822Sjhb	else {
2700171822Sjhb		sc->mfi_flags |= MFI_FLAGS_OPEN;
2701171822Sjhb		error = 0;
2702171822Sjhb	}
2703163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
2704157114Sscottl
2705171822Sjhb	return (error);
2706157114Sscottl}
2707157114Sscottl
2708157114Sscottlstatic int
2709192450Simpmfi_close(struct cdev *dev, int flags, int fmt, struct thread *td)
2710157114Sscottl{
2711157114Sscottl	struct mfi_softc *sc;
2712163398Sscottl	struct mfi_aen *mfi_aen_entry, *tmp;
2713157114Sscottl
2714157114Sscottl	sc = dev->si_drv1;
2715163398Sscottl
2716163398Sscottl	mtx_lock(&sc->mfi_io_lock);
2717157114Sscottl	sc->mfi_flags &= ~MFI_FLAGS_OPEN;
2718157114Sscottl
2719163398Sscottl	TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
2720158737Sambrisko		if (mfi_aen_entry->p == curproc) {
2721158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
2722158737Sambrisko			    aen_link);
2723158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
2724158737Sambrisko		}
2725158737Sambrisko	}
2726163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
2727157114Sscottl	return (0);
2728157114Sscottl}
2729157114Sscottl
2730157114Sscottlstatic int
2731171821Sjhbmfi_config_lock(struct mfi_softc *sc, uint32_t opcode)
2732171821Sjhb{
2733171821Sjhb
2734171821Sjhb	switch (opcode) {
2735171821Sjhb	case MFI_DCMD_LD_DELETE:
2736171821Sjhb	case MFI_DCMD_CFG_ADD:
2737171821Sjhb	case MFI_DCMD_CFG_CLEAR:
2738241324Sjhb	case MFI_DCMD_CFG_FOREIGN_IMPORT:
2739171821Sjhb		sx_xlock(&sc->mfi_config_lock);
2740171821Sjhb		return (1);
2741171821Sjhb	default:
2742171821Sjhb		return (0);
2743171821Sjhb	}
2744171821Sjhb}
2745171821Sjhb
2746171821Sjhbstatic void
2747171821Sjhbmfi_config_unlock(struct mfi_softc *sc, int locked)
2748171821Sjhb{
2749171821Sjhb
2750171821Sjhb	if (locked)
2751171821Sjhb		sx_xunlock(&sc->mfi_config_lock);
2752171821Sjhb}
2753171821Sjhb
2754234429Sambrisko/*
2755234429Sambrisko * Perform pre-issue checks on commands from userland and possibly veto
2756234429Sambrisko * them.
2757234429Sambrisko */
2758171821Sjhbstatic int
2759171821Sjhbmfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm)
2760171821Sjhb{
2761171821Sjhb	struct mfi_disk *ld, *ld2;
2762171821Sjhb	int error;
2763234429Sambrisko	struct mfi_system_pd *syspd = NULL;
2764234429Sambrisko	uint16_t syspd_id;
2765234429Sambrisko	uint16_t *mbox;
2766171821Sjhb
2767171821Sjhb	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2768171821Sjhb	error = 0;
2769171821Sjhb	switch (cm->cm_frame->dcmd.opcode) {
2770171821Sjhb	case MFI_DCMD_LD_DELETE:
2771171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
2772171821Sjhb			if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
2773171821Sjhb				break;
2774171821Sjhb		}
2775171821Sjhb		if (ld == NULL)
2776171821Sjhb			error = ENOENT;
2777171821Sjhb		else
2778171821Sjhb			error = mfi_disk_disable(ld);
2779171821Sjhb		break;
2780171821Sjhb	case MFI_DCMD_CFG_CLEAR:
2781171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
2782171821Sjhb			error = mfi_disk_disable(ld);
2783171821Sjhb			if (error)
2784171821Sjhb				break;
2785171821Sjhb		}
2786171821Sjhb		if (error) {
2787171821Sjhb			TAILQ_FOREACH(ld2, &sc->mfi_ld_tqh, ld_link) {
2788171821Sjhb				if (ld2 == ld)
2789171821Sjhb					break;
2790171821Sjhb				mfi_disk_enable(ld2);
2791171821Sjhb			}
2792171821Sjhb		}
2793171821Sjhb		break;
2794234429Sambrisko	case MFI_DCMD_PD_STATE_SET:
2795234429Sambrisko		mbox = (uint16_t *) cm->cm_frame->dcmd.mbox;
2796234429Sambrisko		syspd_id = mbox[0];
2797234429Sambrisko		if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) {
2798234429Sambrisko			TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) {
2799234429Sambrisko				if (syspd->pd_id == syspd_id)
2800234429Sambrisko					break;
2801234429Sambrisko			}
2802234429Sambrisko		}
2803234429Sambrisko		else
2804234429Sambrisko			break;
2805234429Sambrisko		if (syspd)
2806234429Sambrisko			error = mfi_syspd_disable(syspd);
2807234429Sambrisko		break;
2808171821Sjhb	default:
2809171821Sjhb		break;
2810171821Sjhb	}
2811171821Sjhb	return (error);
2812171821Sjhb}
2813171821Sjhb
2814171821Sjhb/* Perform post-issue checks on commands from userland. */
2815171821Sjhbstatic void
2816171821Sjhbmfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm)
2817171821Sjhb{
2818171821Sjhb	struct mfi_disk *ld, *ldn;
2819234429Sambrisko	struct mfi_system_pd *syspd = NULL;
2820234429Sambrisko	uint16_t syspd_id;
2821234429Sambrisko	uint16_t *mbox;
2822171821Sjhb
2823171821Sjhb	switch (cm->cm_frame->dcmd.opcode) {
2824171821Sjhb	case MFI_DCMD_LD_DELETE:
2825171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
2826171821Sjhb			if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
2827171821Sjhb				break;
2828171821Sjhb		}
2829171821Sjhb		KASSERT(ld != NULL, ("volume dissappeared"));
2830171821Sjhb		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
2831171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
2832196403Sjhb			mtx_lock(&Giant);
2833171821Sjhb			device_delete_child(sc->mfi_dev, ld->ld_dev);
2834196403Sjhb			mtx_unlock(&Giant);
2835171821Sjhb			mtx_lock(&sc->mfi_io_lock);
2836171821Sjhb		} else
2837171821Sjhb			mfi_disk_enable(ld);
2838171821Sjhb		break;
2839171821Sjhb	case MFI_DCMD_CFG_CLEAR:
2840171821Sjhb		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
2841171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
2842196403Sjhb			mtx_lock(&Giant);
2843171821Sjhb			TAILQ_FOREACH_SAFE(ld, &sc->mfi_ld_tqh, ld_link, ldn) {
2844171821Sjhb				device_delete_child(sc->mfi_dev, ld->ld_dev);
2845171821Sjhb			}
2846196403Sjhb			mtx_unlock(&Giant);
2847171821Sjhb			mtx_lock(&sc->mfi_io_lock);
2848171821Sjhb		} else {
2849171821Sjhb			TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link)
2850171821Sjhb				mfi_disk_enable(ld);
2851171821Sjhb		}
2852171821Sjhb		break;
2853171821Sjhb	case MFI_DCMD_CFG_ADD:
2854171821Sjhb		mfi_ldprobe(sc);
2855171821Sjhb		break;
2856184897Sambrisko	case MFI_DCMD_CFG_FOREIGN_IMPORT:
2857184897Sambrisko		mfi_ldprobe(sc);
2858184897Sambrisko		break;
2859234429Sambrisko	case MFI_DCMD_PD_STATE_SET:
2860234429Sambrisko		mbox = (uint16_t *) cm->cm_frame->dcmd.mbox;
2861234429Sambrisko		syspd_id = mbox[0];
2862234429Sambrisko		if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) {
2863234429Sambrisko			TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) {
2864234429Sambrisko				if (syspd->pd_id == syspd_id)
2865234429Sambrisko					break;
2866234429Sambrisko			}
2867234429Sambrisko		}
2868234429Sambrisko		else
2869234429Sambrisko			break;
2870234429Sambrisko		/* If the transition fails then enable the syspd again */
2871234429Sambrisko		if (syspd && cm->cm_frame->header.cmd_status != MFI_STAT_OK)
2872234429Sambrisko			mfi_syspd_enable(syspd);
2873234429Sambrisko		break;
2874171821Sjhb	}
2875171821Sjhb}
2876171821Sjhb
2877243824Sdelphijstatic int
2878243824Sdelphijmfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm)
2879234429Sambrisko{
2880243824Sdelphij	struct mfi_config_data *conf_data;
2881234429Sambrisko	struct mfi_command *ld_cm = NULL;
2882234429Sambrisko	struct mfi_ld_info *ld_info = NULL;
2883243824Sdelphij	struct mfi_ld_config *ld;
2884243824Sdelphij	char *p;
2885234429Sambrisko	int error = 0;
2886234429Sambrisko
2887243824Sdelphij	conf_data = (struct mfi_config_data *)cm->cm_data;
2888243824Sdelphij
2889243824Sdelphij	if (cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) {
2890243824Sdelphij		p = (char *)conf_data->array;
2891243824Sdelphij		p += conf_data->array_size * conf_data->array_count;
2892243824Sdelphij		ld = (struct mfi_ld_config *)p;
2893243824Sdelphij		if (ld->params.isSSCD == 1)
2894243824Sdelphij			error = 1;
2895234429Sambrisko	} else if (cm->cm_frame->dcmd.opcode == MFI_DCMD_LD_DELETE) {
2896234429Sambrisko		error = mfi_dcmd_command (sc, &ld_cm, MFI_DCMD_LD_GET_INFO,
2897234429Sambrisko		    (void **)&ld_info, sizeof(*ld_info));
2898235135Sambrisko		if (error) {
2899234429Sambrisko			device_printf(sc->mfi_dev, "Failed to allocate"
2900234429Sambrisko			    "MFI_DCMD_LD_GET_INFO %d", error);
2901234429Sambrisko			if (ld_info)
2902234429Sambrisko				free(ld_info, M_MFIBUF);
2903234429Sambrisko			return 0;
2904234429Sambrisko		}
2905234429Sambrisko		ld_cm->cm_flags = MFI_CMD_DATAIN;
2906234429Sambrisko		ld_cm->cm_frame->dcmd.mbox[0]= cm->cm_frame->dcmd.mbox[0];
2907234429Sambrisko		ld_cm->cm_frame->header.target_id = cm->cm_frame->dcmd.mbox[0];
2908235135Sambrisko		if (mfi_wait_command(sc, ld_cm) != 0) {
2909234429Sambrisko			device_printf(sc->mfi_dev, "failed to get log drv\n");
2910234429Sambrisko			mfi_release_command(ld_cm);
2911234429Sambrisko			free(ld_info, M_MFIBUF);
2912234429Sambrisko			return 0;
2913234429Sambrisko		}
2914234429Sambrisko
2915234429Sambrisko		if (ld_cm->cm_frame->header.cmd_status != MFI_STAT_OK) {
2916234429Sambrisko			free(ld_info, M_MFIBUF);
2917234429Sambrisko			mfi_release_command(ld_cm);
2918234429Sambrisko			return 0;
2919234429Sambrisko		}
2920234429Sambrisko		else
2921234429Sambrisko			ld_info = (struct mfi_ld_info *)ld_cm->cm_private;
2922234429Sambrisko
2923234429Sambrisko		if (ld_info->ld_config.params.isSSCD == 1)
2924234429Sambrisko			error = 1;
2925234429Sambrisko
2926234429Sambrisko		mfi_release_command(ld_cm);
2927234429Sambrisko		free(ld_info, M_MFIBUF);
2928234429Sambrisko
2929234429Sambrisko	}
2930234429Sambrisko	return error;
2931234429Sambrisko}
2932234429Sambrisko
2933171821Sjhbstatic int
2934234429Sambriskomfi_stp_cmd(struct mfi_softc *sc, struct mfi_command *cm,caddr_t arg)
2935234429Sambrisko{
2936234429Sambrisko	uint8_t i;
2937234429Sambrisko	struct mfi_ioc_packet *ioc;
2938234429Sambrisko	ioc = (struct mfi_ioc_packet *)arg;
2939234429Sambrisko	int sge_size, error;
2940234429Sambrisko	struct megasas_sge *kern_sge;
2941234429Sambrisko
2942234429Sambrisko	memset(sc->kbuff_arr, 0, sizeof(sc->kbuff_arr));
2943234429Sambrisko	kern_sge =(struct megasas_sge *) ((uintptr_t)cm->cm_frame + ioc->mfi_sgl_off);
2944234429Sambrisko	cm->cm_frame->header.sg_count = ioc->mfi_sge_count;
2945234429Sambrisko
2946234429Sambrisko	if (sizeof(bus_addr_t) == 8) {
2947234429Sambrisko		cm->cm_frame->header.flags |= MFI_FRAME_SGL64;
2948234429Sambrisko		cm->cm_extra_frames = 2;
2949234429Sambrisko		sge_size = sizeof(struct mfi_sg64);
2950234429Sambrisko	} else {
2951234429Sambrisko		cm->cm_extra_frames =  (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
2952234429Sambrisko		sge_size = sizeof(struct mfi_sg32);
2953234429Sambrisko	}
2954234429Sambrisko
2955234429Sambrisko	cm->cm_total_frame_size += (sge_size * ioc->mfi_sge_count);
2956234429Sambrisko	for (i = 0; i < ioc->mfi_sge_count; i++) {
2957234429Sambrisko			if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
2958234429Sambrisko			1, 0,			/* algnmnt, boundary */
2959234429Sambrisko			BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
2960234429Sambrisko			BUS_SPACE_MAXADDR,	/* highaddr */
2961234429Sambrisko			NULL, NULL,		/* filter, filterarg */
2962234429Sambrisko			ioc->mfi_sgl[i].iov_len,/* maxsize */
2963234429Sambrisko			2,			/* nsegments */
2964234429Sambrisko			ioc->mfi_sgl[i].iov_len,/* maxsegsize */
2965234429Sambrisko			BUS_DMA_ALLOCNOW,	/* flags */
2966234429Sambrisko			NULL, NULL,		/* lockfunc, lockarg */
2967234429Sambrisko			&sc->mfi_kbuff_arr_dmat[i])) {
2968234429Sambrisko			device_printf(sc->mfi_dev,
2969234429Sambrisko			    "Cannot allocate mfi_kbuff_arr_dmat tag\n");
2970234429Sambrisko			return (ENOMEM);
2971234429Sambrisko		}
2972234429Sambrisko
2973234429Sambrisko		if (bus_dmamem_alloc(sc->mfi_kbuff_arr_dmat[i],
2974234429Sambrisko		    (void **)&sc->kbuff_arr[i], BUS_DMA_NOWAIT,
2975234429Sambrisko		    &sc->mfi_kbuff_arr_dmamap[i])) {
2976234429Sambrisko			device_printf(sc->mfi_dev,
2977234429Sambrisko			    "Cannot allocate mfi_kbuff_arr_dmamap memory\n");
2978234429Sambrisko			return (ENOMEM);
2979234429Sambrisko		}
2980234429Sambrisko
2981234429Sambrisko		bus_dmamap_load(sc->mfi_kbuff_arr_dmat[i],
2982234429Sambrisko		    sc->mfi_kbuff_arr_dmamap[i], sc->kbuff_arr[i],
2983234429Sambrisko		    ioc->mfi_sgl[i].iov_len, mfi_addr_cb,
2984234429Sambrisko		    &sc->mfi_kbuff_arr_busaddr[i], 0);
2985234429Sambrisko
2986234429Sambrisko		if (!sc->kbuff_arr[i]) {
2987234429Sambrisko			device_printf(sc->mfi_dev,
2988234429Sambrisko			    "Could not allocate memory for kbuff_arr info\n");
2989234429Sambrisko			return -1;
2990234429Sambrisko		}
2991234429Sambrisko		kern_sge[i].phys_addr = sc->mfi_kbuff_arr_busaddr[i];
2992234429Sambrisko		kern_sge[i].length = ioc->mfi_sgl[i].iov_len;
2993234429Sambrisko
2994234429Sambrisko		if (sizeof(bus_addr_t) == 8) {
2995234429Sambrisko			cm->cm_frame->stp.sgl.sg64[i].addr =
2996234429Sambrisko			    kern_sge[i].phys_addr;
2997234429Sambrisko			cm->cm_frame->stp.sgl.sg64[i].len =
2998234429Sambrisko			    ioc->mfi_sgl[i].iov_len;
2999234429Sambrisko		} else {
3000247828Sdelphij			cm->cm_frame->stp.sgl.sg32[i].addr =
3001234429Sambrisko			    kern_sge[i].phys_addr;
3002234429Sambrisko			cm->cm_frame->stp.sgl.sg32[i].len =
3003234429Sambrisko			    ioc->mfi_sgl[i].iov_len;
3004234429Sambrisko		}
3005234429Sambrisko
3006234429Sambrisko		error = copyin(ioc->mfi_sgl[i].iov_base,
3007234429Sambrisko		    sc->kbuff_arr[i],
3008234429Sambrisko		    ioc->mfi_sgl[i].iov_len);
3009234429Sambrisko		if (error != 0) {
3010234429Sambrisko			device_printf(sc->mfi_dev, "Copy in failed\n");
3011234429Sambrisko			return error;
3012234429Sambrisko		}
3013234429Sambrisko	}
3014234429Sambrisko
3015234429Sambrisko	cm->cm_flags |=MFI_CMD_MAPPED;
3016234429Sambrisko	return 0;
3017234429Sambrisko}
3018234429Sambrisko
3019234429Sambriskostatic int
3020178968Sscottlmfi_user_command(struct mfi_softc *sc, struct mfi_ioc_passthru *ioc)
3021178968Sscottl{
3022178968Sscottl	struct mfi_command *cm;
3023178968Sscottl	struct mfi_dcmd_frame *dcmd;
3024178968Sscottl	void *ioc_buf = NULL;
3025178968Sscottl	uint32_t context;
3026178968Sscottl	int error = 0, locked;
3027178968Sscottl
3028178968Sscottl
3029178968Sscottl	if (ioc->buf_size > 0) {
3030239866Sjhb		if (ioc->buf_size > 1024 * 1024)
3031239866Sjhb			return (ENOMEM);
3032178968Sscottl		ioc_buf = malloc(ioc->buf_size, M_MFIBUF, M_WAITOK);
3033178968Sscottl		error = copyin(ioc->buf, ioc_buf, ioc->buf_size);
3034178968Sscottl		if (error) {
3035178968Sscottl			device_printf(sc->mfi_dev, "failed to copyin\n");
3036178968Sscottl			free(ioc_buf, M_MFIBUF);
3037178968Sscottl			return (error);
3038178968Sscottl		}
3039178968Sscottl	}
3040178968Sscottl
3041178968Sscottl	locked = mfi_config_lock(sc, ioc->ioc_frame.opcode);
3042178968Sscottl
3043178968Sscottl	mtx_lock(&sc->mfi_io_lock);
3044178968Sscottl	while ((cm = mfi_dequeue_free(sc)) == NULL)
3045178968Sscottl		msleep(mfi_user_command, &sc->mfi_io_lock, 0, "mfiioc", hz);
3046178968Sscottl
3047178968Sscottl	/* Save context for later */
3048178968Sscottl	context = cm->cm_frame->header.context;
3049178968Sscottl
3050178968Sscottl	dcmd = &cm->cm_frame->dcmd;
3051178968Sscottl	bcopy(&ioc->ioc_frame, dcmd, sizeof(struct mfi_dcmd_frame));
3052178968Sscottl
3053178968Sscottl	cm->cm_sg = &dcmd->sgl;
3054178968Sscottl	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
3055178968Sscottl	cm->cm_data = ioc_buf;
3056178968Sscottl	cm->cm_len = ioc->buf_size;
3057178968Sscottl
3058178968Sscottl	/* restore context */
3059178968Sscottl	cm->cm_frame->header.context = context;
3060178968Sscottl
3061178968Sscottl	/* Cheat since we don't know if we're writing or reading */
3062178968Sscottl	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
3063178968Sscottl
3064178968Sscottl	error = mfi_check_command_pre(sc, cm);
3065178968Sscottl	if (error)
3066178968Sscottl		goto out;
3067178968Sscottl
3068178968Sscottl	error = mfi_wait_command(sc, cm);
3069178968Sscottl	if (error) {
3070178968Sscottl		device_printf(sc->mfi_dev, "ioctl failed %d\n", error);
3071178968Sscottl		goto out;
3072178968Sscottl	}
3073178968Sscottl	bcopy(dcmd, &ioc->ioc_frame, sizeof(struct mfi_dcmd_frame));
3074178968Sscottl	mfi_check_command_post(sc, cm);
3075178968Sscottlout:
3076178968Sscottl	mfi_release_command(cm);
3077178968Sscottl	mtx_unlock(&sc->mfi_io_lock);
3078178968Sscottl	mfi_config_unlock(sc, locked);
3079178968Sscottl	if (ioc->buf_size > 0)
3080178968Sscottl		error = copyout(ioc_buf, ioc->buf, ioc->buf_size);
3081178968Sscottl	if (ioc_buf)
3082178968Sscottl		free(ioc_buf, M_MFIBUF);
3083178968Sscottl	return (error);
3084178968Sscottl}
3085178968Sscottl
3086178968Sscottl#define	PTRIN(p)		((void *)(uintptr_t)(p))
3087178968Sscottl
3088178968Sscottlstatic int
3089192450Simpmfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
3090157114Sscottl{
3091157114Sscottl	struct mfi_softc *sc;
3092157114Sscottl	union mfi_statrequest *ms;
3093164281Sambrisko	struct mfi_ioc_packet *ioc;
3094234429Sambrisko#ifdef COMPAT_FREEBSD32
3095179392Sambrisko	struct mfi_ioc_packet32 *ioc32;
3096179392Sambrisko#endif
3097164281Sambrisko	struct mfi_ioc_aen *aen;
3098164281Sambrisko	struct mfi_command *cm = NULL;
3099234429Sambrisko	uint32_t context = 0;
3100184897Sambrisko	union mfi_sense_ptr sense_ptr;
3101234429Sambrisko	uint8_t *data = NULL, *temp, *addr, skip_pre_post = 0;
3102225918Smav	size_t len;
3103234429Sambrisko	int i, res;
3104178968Sscottl	struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg;
3105234429Sambrisko#ifdef COMPAT_FREEBSD32
3106178968Sscottl	struct mfi_ioc_passthru32 *iop32 = (struct mfi_ioc_passthru32 *)arg;
3107178968Sscottl	struct mfi_ioc_passthru iop_swab;
3108178968Sscottl#endif
3109171821Sjhb	int error, locked;
3110234429Sambrisko	union mfi_sgl *sgl;
3111157114Sscottl	sc = dev->si_drv1;
3112157114Sscottl	error = 0;
3113157114Sscottl
3114234429Sambrisko	if (sc->adpreset)
3115234429Sambrisko		return EBUSY;
3116234429Sambrisko
3117234429Sambrisko	if (sc->hw_crit_error)
3118234429Sambrisko		return EBUSY;
3119234429Sambrisko
3120234429Sambrisko	if (sc->issuepend_done == 0)
3121234429Sambrisko		return EBUSY;
3122234429Sambrisko
3123157114Sscottl	switch (cmd) {
3124157114Sscottl	case MFIIO_STATS:
3125157114Sscottl		ms = (union mfi_statrequest *)arg;
3126157114Sscottl		switch (ms->ms_item) {
3127157114Sscottl		case MFIQ_FREE:
3128157114Sscottl		case MFIQ_BIO:
3129157114Sscottl		case MFIQ_READY:
3130157114Sscottl		case MFIQ_BUSY:
3131157114Sscottl			bcopy(&sc->mfi_qstat[ms->ms_item], &ms->ms_qstat,
3132157114Sscottl			    sizeof(struct mfi_qstat));
3133157114Sscottl			break;
3134157114Sscottl		default:
3135158737Sambrisko			error = ENOIOCTL;
3136157114Sscottl			break;
3137157114Sscottl		}
3138157114Sscottl		break;
3139169451Sscottl	case MFIIO_QUERY_DISK:
3140169451Sscottl	{
3141169451Sscottl		struct mfi_query_disk *qd;
3142169451Sscottl		struct mfi_disk *ld;
3143169451Sscottl
3144169451Sscottl		qd = (struct mfi_query_disk *)arg;
3145169451Sscottl		mtx_lock(&sc->mfi_io_lock);
3146169451Sscottl		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
3147169451Sscottl			if (ld->ld_id == qd->array_id)
3148169451Sscottl				break;
3149169451Sscottl		}
3150169451Sscottl		if (ld == NULL) {
3151169451Sscottl			qd->present = 0;
3152169451Sscottl			mtx_unlock(&sc->mfi_io_lock);
3153169451Sscottl			return (0);
3154169451Sscottl		}
3155169451Sscottl		qd->present = 1;
3156169451Sscottl		if (ld->ld_flags & MFI_DISK_FLAGS_OPEN)
3157169451Sscottl			qd->open = 1;
3158169451Sscottl		bzero(qd->devname, SPECNAMELEN + 1);
3159169451Sscottl		snprintf(qd->devname, SPECNAMELEN, "mfid%d", ld->ld_unit);
3160169451Sscottl		mtx_unlock(&sc->mfi_io_lock);
3161169451Sscottl		break;
3162169451Sscottl	}
3163164281Sambrisko	case MFI_CMD:
3164234429Sambrisko#ifdef COMPAT_FREEBSD32
3165179392Sambrisko	case MFI_CMD32:
3166179392Sambrisko#endif
3167177489Sambrisko		{
3168177489Sambrisko		devclass_t devclass;
3169164281Sambrisko		ioc = (struct mfi_ioc_packet *)arg;
3170177489Sambrisko		int adapter;
3171164281Sambrisko
3172177489Sambrisko		adapter = ioc->mfi_adapter_no;
3173177489Sambrisko		if (device_get_unit(sc->mfi_dev) == 0 && adapter != 0) {
3174177489Sambrisko			devclass = devclass_find("mfi");
3175177489Sambrisko			sc = devclass_get_softc(devclass, adapter);
3176177489Sambrisko		}
3177164281Sambrisko		mtx_lock(&sc->mfi_io_lock);
3178164281Sambrisko		if ((cm = mfi_dequeue_free(sc)) == NULL) {
3179164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3180164281Sambrisko			return (EBUSY);
3181164281Sambrisko		}
3182164281Sambrisko		mtx_unlock(&sc->mfi_io_lock);
3183171821Sjhb		locked = 0;
3184164281Sambrisko
3185164281Sambrisko		/*
3186164281Sambrisko		 * save off original context since copying from user
3187164281Sambrisko		 * will clobber some data
3188164281Sambrisko		 */
3189164281Sambrisko		context = cm->cm_frame->header.context;
3190234429Sambrisko		cm->cm_frame->header.context = cm->cm_index;
3191164281Sambrisko
3192165225Sambrisko		bcopy(ioc->mfi_frame.raw, cm->cm_frame,
3193234429Sambrisko		    2 * MEGAMFI_FRAME_SIZE);
3194184897Sambrisko		cm->cm_total_frame_size = (sizeof(union mfi_sgl)
3195184897Sambrisko		    * ioc->mfi_sge_count) + ioc->mfi_sgl_off;
3196234429Sambrisko		cm->cm_frame->header.scsi_status = 0;
3197234429Sambrisko		cm->cm_frame->header.pad0 = 0;
3198175897Sambrisko		if (ioc->mfi_sge_count) {
3199175897Sambrisko			cm->cm_sg =
3200175897Sambrisko			    (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off];
3201175897Sambrisko		}
3202234429Sambrisko		sgl = cm->cm_sg;
3203175897Sambrisko		cm->cm_flags = 0;
3204175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
3205175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN;
3206175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
3207175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAOUT;
3208175897Sambrisko		/* Legacy app shim */
3209175897Sambrisko		if (cm->cm_flags == 0)
3210175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
3211164281Sambrisko		cm->cm_len = cm->cm_frame->header.data_len;
3212225918Smav		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
3213234429Sambrisko#ifdef COMPAT_FREEBSD32
3214225918Smav			if (cmd == MFI_CMD) {
3215225918Smav#endif
3216225918Smav				/* Native */
3217225918Smav				cm->cm_stp_len = ioc->mfi_sgl[0].iov_len;
3218234429Sambrisko#ifdef COMPAT_FREEBSD32
3219225918Smav			} else {
3220225918Smav				/* 32bit on 64bit */
3221225918Smav				ioc32 = (struct mfi_ioc_packet32 *)ioc;
3222225918Smav				cm->cm_stp_len = ioc32->mfi_sgl[0].iov_len;
3223225918Smav			}
3224225918Smav#endif
3225225918Smav			cm->cm_len += cm->cm_stp_len;
3226225918Smav		}
3227184897Sambrisko		if (cm->cm_len &&
3228184897Sambrisko		    (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
3229175897Sambrisko			cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
3230175897Sambrisko			    M_WAITOK | M_ZERO);
3231175897Sambrisko			if (cm->cm_data == NULL) {
3232175897Sambrisko				device_printf(sc->mfi_dev, "Malloc failed\n");
3233175897Sambrisko				goto out;
3234175897Sambrisko			}
3235175897Sambrisko		} else {
3236175897Sambrisko			cm->cm_data = 0;
3237165225Sambrisko		}
3238164281Sambrisko
3239164281Sambrisko		/* restore header context */
3240164281Sambrisko		cm->cm_frame->header.context = context;
3241164281Sambrisko
3242234429Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
3243234429Sambrisko			res = mfi_stp_cmd(sc, cm, arg);
3244234429Sambrisko			if (res != 0)
3245234429Sambrisko				goto out;
3246234429Sambrisko		} else {
3247234429Sambrisko			temp = data;
3248234429Sambrisko			if ((cm->cm_flags & MFI_CMD_DATAOUT) ||
3249234429Sambrisko			    (cm->cm_frame->header.cmd == MFI_CMD_STP)) {
3250234429Sambrisko				for (i = 0; i < ioc->mfi_sge_count; i++) {
3251234429Sambrisko#ifdef COMPAT_FREEBSD32
3252234429Sambrisko					if (cmd == MFI_CMD) {
3253225918Smav#endif
3254234429Sambrisko						/* Native */
3255234429Sambrisko						addr = ioc->mfi_sgl[i].iov_base;
3256234429Sambrisko						len = ioc->mfi_sgl[i].iov_len;
3257234429Sambrisko#ifdef COMPAT_FREEBSD32
3258234429Sambrisko					} else {
3259234429Sambrisko						/* 32bit on 64bit */
3260234429Sambrisko						ioc32 = (struct mfi_ioc_packet32 *)ioc;
3261234429Sambrisko						addr = PTRIN(ioc32->mfi_sgl[i].iov_base);
3262234429Sambrisko						len = ioc32->mfi_sgl[i].iov_len;
3263234429Sambrisko					}
3264179392Sambrisko#endif
3265234429Sambrisko					error = copyin(addr, temp, len);
3266234429Sambrisko					if (error != 0) {
3267234429Sambrisko						device_printf(sc->mfi_dev,
3268234429Sambrisko						    "Copy in failed\n");
3269234429Sambrisko						goto out;
3270234429Sambrisko					}
3271234429Sambrisko					temp = &temp[len];
3272175897Sambrisko				}
3273164281Sambrisko			}
3274164281Sambrisko		}
3275164281Sambrisko
3276171821Sjhb		if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
3277234429Sambrisko			locked = mfi_config_lock(sc,
3278234429Sambrisko			     cm->cm_frame->dcmd.opcode);
3279171821Sjhb
3280184933Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
3281234429Sambrisko			cm->cm_frame->pass.sense_addr_lo =
3282234429Sambrisko			    (uint32_t)cm->cm_sense_busaddr;
3283234429Sambrisko			cm->cm_frame->pass.sense_addr_hi =
3284234429Sambrisko			    (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
3285184933Sambrisko		}
3286164281Sambrisko		mtx_lock(&sc->mfi_io_lock);
3287234429Sambrisko		skip_pre_post = mfi_check_for_sscd (sc, cm);
3288234429Sambrisko		if (!skip_pre_post) {
3289234429Sambrisko			error = mfi_check_command_pre(sc, cm);
3290234429Sambrisko			if (error) {
3291234429Sambrisko				mtx_unlock(&sc->mfi_io_lock);
3292234429Sambrisko				goto out;
3293234429Sambrisko			}
3294171821Sjhb		}
3295170284Sambrisko		if ((error = mfi_wait_command(sc, cm)) != 0) {
3296164281Sambrisko			device_printf(sc->mfi_dev,
3297165225Sambrisko			    "Controller polled failed\n");
3298164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3299164281Sambrisko			goto out;
3300164281Sambrisko		}
3301234429Sambrisko		if (!skip_pre_post) {
3302234429Sambrisko			mfi_check_command_post(sc, cm);
3303234429Sambrisko		}
3304164281Sambrisko		mtx_unlock(&sc->mfi_io_lock);
3305164281Sambrisko
3306234429Sambrisko		if (cm->cm_frame->header.cmd != MFI_CMD_STP) {
3307234429Sambrisko			temp = data;
3308234429Sambrisko			if ((cm->cm_flags & MFI_CMD_DATAIN) ||
3309234429Sambrisko			    (cm->cm_frame->header.cmd == MFI_CMD_STP)) {
3310234429Sambrisko				for (i = 0; i < ioc->mfi_sge_count; i++) {
3311234429Sambrisko#ifdef COMPAT_FREEBSD32
3312234429Sambrisko					if (cmd == MFI_CMD) {
3313225918Smav#endif
3314234429Sambrisko						/* Native */
3315234429Sambrisko						addr = ioc->mfi_sgl[i].iov_base;
3316234429Sambrisko						len = ioc->mfi_sgl[i].iov_len;
3317234429Sambrisko#ifdef COMPAT_FREEBSD32
3318234429Sambrisko					} else {
3319234429Sambrisko						/* 32bit on 64bit */
3320234429Sambrisko						ioc32 = (struct mfi_ioc_packet32 *)ioc;
3321234429Sambrisko						addr = PTRIN(ioc32->mfi_sgl[i].iov_base);
3322234429Sambrisko						len = ioc32->mfi_sgl[i].iov_len;
3323234429Sambrisko					}
3324179392Sambrisko#endif
3325234429Sambrisko					error = copyout(temp, addr, len);
3326234429Sambrisko					if (error != 0) {
3327234429Sambrisko						device_printf(sc->mfi_dev,
3328234429Sambrisko						    "Copy out failed\n");
3329234429Sambrisko						goto out;
3330234429Sambrisko					}
3331234429Sambrisko					temp = &temp[len];
3332175897Sambrisko				}
3333164281Sambrisko			}
3334164281Sambrisko		}
3335164281Sambrisko
3336165225Sambrisko		if (ioc->mfi_sense_len) {
3337184897Sambrisko			/* get user-space sense ptr then copy out sense */
3338225428Sbz			bcopy(&ioc->mfi_frame.raw[ioc->mfi_sense_off],
3339184897Sambrisko			    &sense_ptr.sense_ptr_data[0],
3340184897Sambrisko			    sizeof(sense_ptr.sense_ptr_data));
3341234429Sambrisko#ifdef COMPAT_FREEBSD32
3342184974Sambrisko			if (cmd != MFI_CMD) {
3343184974Sambrisko				/*
3344184974Sambrisko				 * not 64bit native so zero out any address
3345184974Sambrisko				 * over 32bit */
3346184975Sambrisko				sense_ptr.addr.high = 0;
3347184974Sambrisko			}
3348184974Sambrisko#endif
3349184897Sambrisko			error = copyout(cm->cm_sense, sense_ptr.user_space,
3350165225Sambrisko			    ioc->mfi_sense_len);
3351164281Sambrisko			if (error != 0) {
3352164281Sambrisko				device_printf(sc->mfi_dev,
3353165225Sambrisko				    "Copy out failed\n");
3354164281Sambrisko				goto out;
3355164281Sambrisko			}
3356164281Sambrisko		}
3357164281Sambrisko
3358165225Sambrisko		ioc->mfi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status;
3359164281Sambriskoout:
3360171821Sjhb		mfi_config_unlock(sc, locked);
3361164281Sambrisko		if (data)
3362164281Sambrisko			free(data, M_MFIBUF);
3363234429Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
3364234429Sambrisko			for (i = 0; i < 2; i++) {
3365234429Sambrisko				if (sc->kbuff_arr[i]) {
3366234429Sambrisko					if (sc->mfi_kbuff_arr_busaddr != 0)
3367234429Sambrisko						bus_dmamap_unload(
3368234429Sambrisko						    sc->mfi_kbuff_arr_dmat[i],
3369234429Sambrisko						    sc->mfi_kbuff_arr_dmamap[i]
3370234429Sambrisko						    );
3371234429Sambrisko					if (sc->kbuff_arr[i] != NULL)
3372234429Sambrisko						bus_dmamem_free(
3373234429Sambrisko						    sc->mfi_kbuff_arr_dmat[i],
3374234429Sambrisko						    sc->kbuff_arr[i],
3375234429Sambrisko						    sc->mfi_kbuff_arr_dmamap[i]
3376234429Sambrisko						    );
3377234429Sambrisko					if (sc->mfi_kbuff_arr_dmat[i] != NULL)
3378234429Sambrisko						bus_dma_tag_destroy(
3379234429Sambrisko						    sc->mfi_kbuff_arr_dmat[i]);
3380234429Sambrisko				}
3381234429Sambrisko			}
3382234429Sambrisko		}
3383164281Sambrisko		if (cm) {
3384164281Sambrisko			mtx_lock(&sc->mfi_io_lock);
3385164281Sambrisko			mfi_release_command(cm);
3386164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3387164281Sambrisko		}
3388164281Sambrisko
3389164281Sambrisko		break;
3390177489Sambrisko		}
3391164281Sambrisko	case MFI_SET_AEN:
3392164281Sambrisko		aen = (struct mfi_ioc_aen *)arg;
3393250496Ssmh		mtx_lock(&sc->mfi_io_lock);
3394164281Sambrisko		error = mfi_aen_register(sc, aen->aen_seq_num,
3395164281Sambrisko		    aen->aen_class_locale);
3396250496Ssmh		mtx_unlock(&sc->mfi_io_lock);
3397164281Sambrisko
3398164281Sambrisko		break;
3399164281Sambrisko	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
3400158737Sambrisko		{
3401158737Sambrisko			devclass_t devclass;
3402158737Sambrisko			struct mfi_linux_ioc_packet l_ioc;
3403158737Sambrisko			int adapter;
3404158737Sambrisko
3405158737Sambrisko			devclass = devclass_find("mfi");
3406158737Sambrisko			if (devclass == NULL)
3407158737Sambrisko				return (ENOENT);
3408158737Sambrisko
3409158737Sambrisko			error = copyin(arg, &l_ioc, sizeof(l_ioc));
3410158737Sambrisko			if (error)
3411158737Sambrisko				return (error);
3412158737Sambrisko			adapter = l_ioc.lioc_adapter_no;
3413158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
3414158737Sambrisko			if (sc == NULL)
3415158737Sambrisko				return (ENOENT);
3416158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
3417158737Sambrisko			    cmd, arg, flag, td));
3418158737Sambrisko			break;
3419158737Sambrisko		}
3420164281Sambrisko	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
3421158737Sambrisko		{
3422158737Sambrisko			devclass_t devclass;
3423158737Sambrisko			struct mfi_linux_ioc_aen l_aen;
3424158737Sambrisko			int adapter;
3425158737Sambrisko
3426158737Sambrisko			devclass = devclass_find("mfi");
3427158737Sambrisko			if (devclass == NULL)
3428158737Sambrisko				return (ENOENT);
3429158737Sambrisko
3430158737Sambrisko			error = copyin(arg, &l_aen, sizeof(l_aen));
3431158737Sambrisko			if (error)
3432158737Sambrisko				return (error);
3433158737Sambrisko			adapter = l_aen.laen_adapter_no;
3434158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
3435158737Sambrisko			if (sc == NULL)
3436158737Sambrisko				return (ENOENT);
3437158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
3438158737Sambrisko			    cmd, arg, flag, td));
3439158737Sambrisko			break;
3440158737Sambrisko		}
3441234429Sambrisko#ifdef COMPAT_FREEBSD32
3442178968Sscottl	case MFIIO_PASSTHRU32:
3443239866Sjhb		if (!SV_CURPROC_FLAG(SV_ILP32)) {
3444239866Sjhb			error = ENOTTY;
3445239866Sjhb			break;
3446239866Sjhb		}
3447178968Sscottl		iop_swab.ioc_frame	= iop32->ioc_frame;
3448178968Sscottl		iop_swab.buf_size	= iop32->buf_size;
3449178968Sscottl		iop_swab.buf		= PTRIN(iop32->buf);
3450178968Sscottl		iop			= &iop_swab;
3451178968Sscottl		/* FALLTHROUGH */
3452178968Sscottl#endif
3453178968Sscottl	case MFIIO_PASSTHRU:
3454178968Sscottl		error = mfi_user_command(sc, iop);
3455234429Sambrisko#ifdef COMPAT_FREEBSD32
3456178968Sscottl		if (cmd == MFIIO_PASSTHRU32)
3457178968Sscottl			iop32->ioc_frame = iop_swab.ioc_frame;
3458178968Sscottl#endif
3459178968Sscottl		break;
3460157114Sscottl	default:
3461163398Sscottl		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
3462239866Sjhb		error = ENOTTY;
3463157114Sscottl		break;
3464157114Sscottl	}
3465157114Sscottl
3466157114Sscottl	return (error);
3467157114Sscottl}
3468158737Sambrisko
3469158737Sambriskostatic int
3470192450Simpmfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
3471158737Sambrisko{
3472158737Sambrisko	struct mfi_softc *sc;
3473158737Sambrisko	struct mfi_linux_ioc_packet l_ioc;
3474158737Sambrisko	struct mfi_linux_ioc_aen l_aen;
3475158737Sambrisko	struct mfi_command *cm = NULL;
3476158737Sambrisko	struct mfi_aen *mfi_aen_entry;
3477184897Sambrisko	union mfi_sense_ptr sense_ptr;
3478234429Sambrisko	uint32_t context = 0;
3479158737Sambrisko	uint8_t *data = NULL, *temp;
3480158737Sambrisko	int i;
3481171821Sjhb	int error, locked;
3482158737Sambrisko
3483158737Sambrisko	sc = dev->si_drv1;
3484158737Sambrisko	error = 0;
3485158737Sambrisko	switch (cmd) {
3486164281Sambrisko	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
3487158737Sambrisko		error = copyin(arg, &l_ioc, sizeof(l_ioc));
3488158737Sambrisko		if (error != 0)
3489158737Sambrisko			return (error);
3490158737Sambrisko
3491158737Sambrisko		if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) {
3492158737Sambrisko			return (EINVAL);
3493158737Sambrisko		}
3494158737Sambrisko
3495158737Sambrisko		mtx_lock(&sc->mfi_io_lock);
3496158737Sambrisko		if ((cm = mfi_dequeue_free(sc)) == NULL) {
3497158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3498158737Sambrisko			return (EBUSY);
3499158737Sambrisko		}
3500158737Sambrisko		mtx_unlock(&sc->mfi_io_lock);
3501171821Sjhb		locked = 0;
3502158737Sambrisko
3503158737Sambrisko		/*
3504158737Sambrisko		 * save off original context since copying from user
3505158737Sambrisko		 * will clobber some data
3506158737Sambrisko		 */
3507158737Sambrisko		context = cm->cm_frame->header.context;
3508158737Sambrisko
3509158737Sambrisko		bcopy(l_ioc.lioc_frame.raw, cm->cm_frame,
3510175897Sambrisko		      2 * MFI_DCMD_FRAME_SIZE);	/* this isn't quite right */
3511184897Sambrisko		cm->cm_total_frame_size = (sizeof(union mfi_sgl)
3512184897Sambrisko		      * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off;
3513234429Sambrisko		cm->cm_frame->header.scsi_status = 0;
3514234429Sambrisko		cm->cm_frame->header.pad0 = 0;
3515175897Sambrisko		if (l_ioc.lioc_sge_count)
3516175897Sambrisko			cm->cm_sg =
3517175897Sambrisko			    (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
3518175897Sambrisko		cm->cm_flags = 0;
3519175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
3520175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN;
3521175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
3522175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAOUT;
3523158737Sambrisko		cm->cm_len = cm->cm_frame->header.data_len;
3524184897Sambrisko		if (cm->cm_len &&
3525184897Sambrisko		      (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
3526175897Sambrisko			cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
3527175897Sambrisko			    M_WAITOK | M_ZERO);
3528175897Sambrisko			if (cm->cm_data == NULL) {
3529175897Sambrisko				device_printf(sc->mfi_dev, "Malloc failed\n");
3530175897Sambrisko				goto out;
3531175897Sambrisko			}
3532175897Sambrisko		} else {
3533175897Sambrisko			cm->cm_data = 0;
3534175897Sambrisko		}
3535158737Sambrisko
3536158737Sambrisko		/* restore header context */
3537158737Sambrisko		cm->cm_frame->header.context = context;
3538158737Sambrisko
3539158737Sambrisko		temp = data;
3540175897Sambrisko		if (cm->cm_flags & MFI_CMD_DATAOUT) {
3541175897Sambrisko			for (i = 0; i < l_ioc.lioc_sge_count; i++) {
3542178968Sscottl				error = copyin(PTRIN(l_ioc.lioc_sgl[i].iov_base),
3543175897Sambrisko				       temp,
3544175897Sambrisko				       l_ioc.lioc_sgl[i].iov_len);
3545175897Sambrisko				if (error != 0) {
3546175897Sambrisko					device_printf(sc->mfi_dev,
3547175897Sambrisko					    "Copy in failed\n");
3548175897Sambrisko					goto out;
3549175897Sambrisko				}
3550175897Sambrisko				temp = &temp[l_ioc.lioc_sgl[i].iov_len];
3551158737Sambrisko			}
3552158737Sambrisko		}
3553158737Sambrisko
3554171821Sjhb		if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
3555171821Sjhb			locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
3556171821Sjhb
3557184933Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
3558234429Sambrisko			cm->cm_frame->pass.sense_addr_lo =
3559234429Sambrisko			    (uint32_t)cm->cm_sense_busaddr;
3560234429Sambrisko			cm->cm_frame->pass.sense_addr_hi =
3561234429Sambrisko			    (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
3562184933Sambrisko		}
3563184933Sambrisko
3564163398Sscottl		mtx_lock(&sc->mfi_io_lock);
3565171821Sjhb		error = mfi_check_command_pre(sc, cm);
3566171821Sjhb		if (error) {
3567171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
3568171821Sjhb			goto out;
3569171821Sjhb		}
3570171821Sjhb
3571170284Sambrisko		if ((error = mfi_wait_command(sc, cm)) != 0) {
3572158737Sambrisko			device_printf(sc->mfi_dev,
3573165225Sambrisko			    "Controller polled failed\n");
3574163398Sscottl			mtx_unlock(&sc->mfi_io_lock);
3575158737Sambrisko			goto out;
3576158737Sambrisko		}
3577158737Sambrisko
3578171821Sjhb		mfi_check_command_post(sc, cm);
3579163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
3580158737Sambrisko
3581158737Sambrisko		temp = data;
3582175897Sambrisko		if (cm->cm_flags & MFI_CMD_DATAIN) {
3583175897Sambrisko			for (i = 0; i < l_ioc.lioc_sge_count; i++) {
3584175897Sambrisko				error = copyout(temp,
3585178968Sscottl					PTRIN(l_ioc.lioc_sgl[i].iov_base),
3586175897Sambrisko					l_ioc.lioc_sgl[i].iov_len);
3587175897Sambrisko				if (error != 0) {
3588175897Sambrisko					device_printf(sc->mfi_dev,
3589175897Sambrisko					    "Copy out failed\n");
3590175897Sambrisko					goto out;
3591175897Sambrisko				}
3592175897Sambrisko				temp = &temp[l_ioc.lioc_sgl[i].iov_len];
3593158737Sambrisko			}
3594158737Sambrisko		}
3595158737Sambrisko
3596158737Sambrisko		if (l_ioc.lioc_sense_len) {
3597184897Sambrisko			/* get user-space sense ptr then copy out sense */
3598184897Sambrisko			bcopy(&((struct mfi_linux_ioc_packet*)arg)
3599184897Sambrisko                            ->lioc_frame.raw[l_ioc.lioc_sense_off],
3600184897Sambrisko			    &sense_ptr.sense_ptr_data[0],
3601184897Sambrisko			    sizeof(sense_ptr.sense_ptr_data));
3602184974Sambrisko#ifdef __amd64__
3603184974Sambrisko			/*
3604184974Sambrisko			 * only 32bit Linux support so zero out any
3605184974Sambrisko			 * address over 32bit
3606184974Sambrisko			 */
3607184975Sambrisko			sense_ptr.addr.high = 0;
3608184974Sambrisko#endif
3609184897Sambrisko			error = copyout(cm->cm_sense, sense_ptr.user_space,
3610158737Sambrisko			    l_ioc.lioc_sense_len);
3611158737Sambrisko			if (error != 0) {
3612158737Sambrisko				device_printf(sc->mfi_dev,
3613165225Sambrisko				    "Copy out failed\n");
3614158737Sambrisko				goto out;
3615158737Sambrisko			}
3616158737Sambrisko		}
3617158737Sambrisko
3618158737Sambrisko		error = copyout(&cm->cm_frame->header.cmd_status,
3619158737Sambrisko			&((struct mfi_linux_ioc_packet*)arg)
3620158737Sambrisko			->lioc_frame.hdr.cmd_status,
3621158737Sambrisko			1);
3622158737Sambrisko		if (error != 0) {
3623158737Sambrisko			device_printf(sc->mfi_dev,
3624165225Sambrisko				      "Copy out failed\n");
3625158737Sambrisko			goto out;
3626158737Sambrisko		}
3627158737Sambrisko
3628158737Sambriskoout:
3629171821Sjhb		mfi_config_unlock(sc, locked);
3630158737Sambrisko		if (data)
3631158737Sambrisko			free(data, M_MFIBUF);
3632158737Sambrisko		if (cm) {
3633158737Sambrisko			mtx_lock(&sc->mfi_io_lock);
3634158737Sambrisko			mfi_release_command(cm);
3635158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3636158737Sambrisko		}
3637158737Sambrisko
3638158737Sambrisko		return (error);
3639164281Sambrisko	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
3640158737Sambrisko		error = copyin(arg, &l_aen, sizeof(l_aen));
3641158737Sambrisko		if (error != 0)
3642158737Sambrisko			return (error);
3643158737Sambrisko		printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid);
3644158737Sambrisko		mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF,
3645158737Sambrisko		    M_WAITOK);
3646163398Sscottl		mtx_lock(&sc->mfi_io_lock);
3647158737Sambrisko		if (mfi_aen_entry != NULL) {
3648158737Sambrisko			mfi_aen_entry->p = curproc;
3649158737Sambrisko			TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry,
3650158737Sambrisko			    aen_link);
3651158737Sambrisko		}
3652158737Sambrisko		error = mfi_aen_register(sc, l_aen.laen_seq_num,
3653158737Sambrisko		    l_aen.laen_class_locale);
3654158737Sambrisko
3655158737Sambrisko		if (error != 0) {
3656158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
3657158737Sambrisko			    aen_link);
3658158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
3659158737Sambrisko		}
3660163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
3661158737Sambrisko
3662158737Sambrisko		return (error);
3663158737Sambrisko	default:
3664158737Sambrisko		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
3665158737Sambrisko		error = ENOENT;
3666158737Sambrisko		break;
3667158737Sambrisko	}
3668158737Sambrisko
3669158737Sambrisko	return (error);
3670158737Sambrisko}
3671158737Sambrisko
3672158737Sambriskostatic int
3673158737Sambriskomfi_poll(struct cdev *dev, int poll_events, struct thread *td)
3674158737Sambrisko{
3675158737Sambrisko	struct mfi_softc *sc;
3676158737Sambrisko	int revents = 0;
3677158737Sambrisko
3678158737Sambrisko	sc = dev->si_drv1;
3679158737Sambrisko
3680158737Sambrisko	if (poll_events & (POLLIN | POLLRDNORM)) {
3681163398Sscottl		if (sc->mfi_aen_triggered != 0) {
3682158737Sambrisko			revents |= poll_events & (POLLIN | POLLRDNORM);
3683163398Sscottl			sc->mfi_aen_triggered = 0;
3684163398Sscottl		}
3685158737Sambrisko		if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) {
3686158737Sambrisko			revents |= POLLERR;
3687158737Sambrisko		}
3688158737Sambrisko	}
3689158737Sambrisko
3690158737Sambrisko	if (revents == 0) {
3691158737Sambrisko		if (poll_events & (POLLIN | POLLRDNORM)) {
3692158737Sambrisko			sc->mfi_poll_waiting = 1;
3693158737Sambrisko			selrecord(td, &sc->mfi_select);
3694158737Sambrisko		}
3695158737Sambrisko	}
3696158737Sambrisko
3697158737Sambrisko	return revents;
3698158737Sambrisko}
3699162619Sscottl
3700162619Sscottlstatic void
3701163398Sscottlmfi_dump_all(void)
3702163398Sscottl{
3703163398Sscottl	struct mfi_softc *sc;
3704163398Sscottl	struct mfi_command *cm;
3705163398Sscottl	devclass_t dc;
3706163398Sscottl	time_t deadline;
3707163398Sscottl	int timedout;
3708163398Sscottl	int i;
3709163398Sscottl
3710163398Sscottl	dc = devclass_find("mfi");
3711163398Sscottl	if (dc == NULL) {
3712163398Sscottl		printf("No mfi dev class\n");
3713163398Sscottl		return;
3714163398Sscottl	}
3715163398Sscottl
3716163398Sscottl	for (i = 0; ; i++) {
3717163398Sscottl		sc = devclass_get_softc(dc, i);
3718163398Sscottl		if (sc == NULL)
3719163398Sscottl			break;
3720163398Sscottl		device_printf(sc->mfi_dev, "Dumping\n\n");
3721163398Sscottl		timedout = 0;
3722251406Ssmh		deadline = time_uptime - mfi_cmd_timeout;
3723163398Sscottl		mtx_lock(&sc->mfi_io_lock);
3724163398Sscottl		TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
3725250496Ssmh			if (cm->cm_timestamp <= deadline) {
3726163398Sscottl				device_printf(sc->mfi_dev,
3727234429Sambrisko				    "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
3728234429Sambrisko				    cm, (int)(time_uptime - cm->cm_timestamp));
3729163398Sscottl				MFI_PRINT_CMD(cm);
3730163398Sscottl				timedout++;
3731163398Sscottl			}
3732163398Sscottl		}
3733163398Sscottl
3734163398Sscottl#if 0
3735163398Sscottl		if (timedout)
3736250496Ssmh			MFI_DUMP_CMDS(sc);
3737163398Sscottl#endif
3738163398Sscottl
3739163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
3740163398Sscottl	}
3741163398Sscottl
3742163398Sscottl	return;
3743163398Sscottl}
3744163398Sscottl
3745163398Sscottlstatic void
3746162619Sscottlmfi_timeout(void *data)
3747162619Sscottl{
3748162619Sscottl	struct mfi_softc *sc = (struct mfi_softc *)data;
3749250496Ssmh	struct mfi_command *cm, *tmp;
3750162619Sscottl	time_t deadline;
3751162619Sscottl	int timedout = 0;
3752162619Sscottl
3753251406Ssmh	deadline = time_uptime - mfi_cmd_timeout;
3754234429Sambrisko	if (sc->adpreset == 0) {
3755234429Sambrisko		if (!mfi_tbolt_reset(sc)) {
3756251406Ssmh			callout_reset(&sc->mfi_watchdog_callout,
3757251406Ssmh			    mfi_cmd_timeout * hz, mfi_timeout, sc);
3758234429Sambrisko			return;
3759234429Sambrisko		}
3760234429Sambrisko	}
3761162619Sscottl	mtx_lock(&sc->mfi_io_lock);
3762250496Ssmh	TAILQ_FOREACH_SAFE(cm, &sc->mfi_busy, cm_link, tmp) {
3763235135Sambrisko		if (sc->mfi_aen_cm == cm || sc->mfi_map_sync_cm == cm)
3764162688Sscottl			continue;
3765250496Ssmh		if (cm->cm_timestamp <= deadline) {
3766234429Sambrisko			if (sc->adpreset != 0 && sc->issuepend_done == 0) {
3767234429Sambrisko				cm->cm_timestamp = time_uptime;
3768234429Sambrisko			} else {
3769234429Sambrisko				device_printf(sc->mfi_dev,
3770234429Sambrisko				    "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
3771234429Sambrisko				     cm, (int)(time_uptime - cm->cm_timestamp)
3772234429Sambrisko				     );
3773234429Sambrisko				MFI_PRINT_CMD(cm);
3774234429Sambrisko				MFI_VALIDATE_CMD(sc, cm);
3775250496Ssmh				/*
3776252554Ssmh				 * While commands can get stuck forever we do
3777252554Ssmh				 * not fail them as there is no way to tell if
3778252554Ssmh				 * the controller has actually processed them
3779252554Ssmh				 * or not.
3780252554Ssmh				 *
3781252554Ssmh				 * In addition its very likely that force
3782252554Ssmh				 * failing a command here would cause a panic
3783252554Ssmh				 * e.g. in UFS.
3784250496Ssmh				 */
3785234429Sambrisko				timedout++;
3786234429Sambrisko			}
3787162619Sscottl		}
3788162619Sscottl	}
3789162619Sscottl
3790162619Sscottl#if 0
3791162619Sscottl	if (timedout)
3792250496Ssmh		MFI_DUMP_CMDS(sc);
3793162619Sscottl#endif
3794162619Sscottl
3795162619Sscottl	mtx_unlock(&sc->mfi_io_lock);
3796162619Sscottl
3797251406Ssmh	callout_reset(&sc->mfi_watchdog_callout, mfi_cmd_timeout * hz,
3798162619Sscottl	    mfi_timeout, sc);
3799162619Sscottl
3800163398Sscottl	if (0)
3801163398Sscottl		mfi_dump_all();
3802162619Sscottl	return;
3803162619Sscottl}
3804