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: releng/10.2/sys/dev/mfi/mfi.c 284429 2015-06-15 21:08:08Z ambrisko $");
55157114Sscottl
56233711Sambrisko#include "opt_compat.h"
57157114Sscottl#include "opt_mfi.h"
58157114Sscottl
59157114Sscottl#include <sys/param.h>
60157114Sscottl#include <sys/systm.h>
61162118Sambrisko#include <sys/sysctl.h>
62157114Sscottl#include <sys/malloc.h>
63157114Sscottl#include <sys/kernel.h>
64158737Sambrisko#include <sys/poll.h>
65158737Sambrisko#include <sys/selinfo.h>
66157114Sscottl#include <sys/bus.h>
67157114Sscottl#include <sys/conf.h>
68157114Sscottl#include <sys/eventhandler.h>
69157114Sscottl#include <sys/rman.h>
70157114Sscottl#include <sys/bus_dma.h>
71157114Sscottl#include <sys/bio.h>
72157114Sscottl#include <sys/ioccom.h>
73158737Sambrisko#include <sys/uio.h>
74158737Sambrisko#include <sys/proc.h>
75163398Sscottl#include <sys/signalvar.h>
76238077Sjhb#include <sys/sysent.h>
77233711Sambrisko#include <sys/taskqueue.h>
78157114Sscottl
79157114Sscottl#include <machine/bus.h>
80157114Sscottl#include <machine/resource.h>
81157114Sscottl
82157114Sscottl#include <dev/mfi/mfireg.h>
83157114Sscottl#include <dev/mfi/mfi_ioctl.h>
84157114Sscottl#include <dev/mfi/mfivar.h>
85233711Sambrisko#include <sys/interrupt.h>
86233711Sambrisko#include <sys/priority.h>
87157114Sscottl
88157114Sscottlstatic int	mfi_alloc_commands(struct mfi_softc *);
89157114Sscottlstatic int	mfi_comms_init(struct mfi_softc *);
90157114Sscottlstatic int	mfi_get_controller_info(struct mfi_softc *);
91158737Sambriskostatic int	mfi_get_log_state(struct mfi_softc *,
92159806Sps		    struct mfi_evt_log_state **);
93180037Sjhbstatic int	mfi_parse_entries(struct mfi_softc *, int, int);
94157114Sscottlstatic void	mfi_data_cb(void *, bus_dma_segment_t *, int, int);
95157114Sscottlstatic void	mfi_startup(void *arg);
96157114Sscottlstatic void	mfi_intr(void *arg);
97159811Spsstatic void	mfi_ldprobe(struct mfi_softc *sc);
98233711Sambriskostatic void	mfi_syspdprobe(struct mfi_softc *sc);
99233711Sambriskostatic void	mfi_handle_evt(void *context, int pending);
100158737Sambriskostatic int	mfi_aen_register(struct mfi_softc *sc, int seq, int locale);
101158737Sambriskostatic void	mfi_aen_complete(struct mfi_command *);
102159811Spsstatic int	mfi_add_ld(struct mfi_softc *sc, int);
103159811Spsstatic void	mfi_add_ld_complete(struct mfi_command *);
104233711Sambriskostatic int	mfi_add_sys_pd(struct mfi_softc *sc, int);
105233711Sambriskostatic void	mfi_add_sys_pd_complete(struct mfi_command *);
106157114Sscottlstatic struct mfi_command * mfi_bio_command(struct mfi_softc *);
107157114Sscottlstatic void	mfi_bio_complete(struct mfi_command *);
108233711Sambriskostatic struct mfi_command *mfi_build_ldio(struct mfi_softc *,struct bio*);
109233711Sambriskostatic struct mfi_command *mfi_build_syspdio(struct mfi_softc *,struct bio*);
110157114Sscottlstatic int	mfi_send_frame(struct mfi_softc *, struct mfi_command *);
111247369Ssmhstatic int	mfi_std_send_frame(struct mfi_softc *, struct mfi_command *);
112242681Sambriskostatic 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 *);
117233711Sambriskostatic void	mfi_enable_intr_xscale(struct mfi_softc *sc);
118233711Sambriskostatic void	mfi_enable_intr_ppc(struct mfi_softc *sc);
119233711Sambriskostatic int32_t	mfi_read_fw_status_xscale(struct mfi_softc *sc);
120233711Sambriskostatic int32_t	mfi_read_fw_status_ppc(struct mfi_softc *sc);
121233711Sambriskostatic int	mfi_check_clear_intr_xscale(struct mfi_softc *sc);
122233711Sambriskostatic int	mfi_check_clear_intr_ppc(struct mfi_softc *sc);
123233711Sambriskostatic void 	mfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add,
124233711Sambrisko		    uint32_t frame_cnt);
125233711Sambriskostatic void 	mfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add,
126233711Sambrisko		    uint32_t frame_cnt);
127233711Sambriskostatic int mfi_config_lock(struct mfi_softc *sc, uint32_t opcode);
128233711Sambriskostatic void mfi_config_unlock(struct mfi_softc *sc, int locked);
129233711Sambriskostatic int mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm);
130233711Sambriskostatic void mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm);
131233711Sambriskostatic int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm);
132157114Sscottl
133227562SjhbSYSCTL_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);
136247369SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, event_locale, CTLFLAG_RWTUN, &mfi_event_locale,
137247369Ssmh           0, "event message locale");
138162473Sambrisko
139165852Sscottlstatic int	mfi_event_class = MFI_EVT_CLASS_INFO;
140162473SambriskoTUNABLE_INT("hw.mfi.event_class", &mfi_event_class);
141247369SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, event_class, CTLFLAG_RWTUN, &mfi_event_class,
142247369Ssmh           0, "event message class");
143162118Sambrisko
144178968Sscottlstatic int	mfi_max_cmds = 128;
145178968SscottlTUNABLE_INT("hw.mfi.max_cmds", &mfi_max_cmds);
146247369SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, max_cmds, CTLFLAG_RDTUN, &mfi_max_cmds,
147247369Ssmh	   0, "Max commands limit (-1 = controller limit)");
148178968Sscottl
149233711Sambriskostatic int	mfi_detect_jbod_change = 1;
150233711SambriskoTUNABLE_INT("hw.mfi.detect_jbod_change", &mfi_detect_jbod_change);
151247369SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, detect_jbod_change, CTLFLAG_RWTUN,
152233711Sambrisko	   &mfi_detect_jbod_change, 0, "Detect a change to a JBOD");
153233711Sambrisko
154247369Ssmhint		mfi_polled_cmd_timeout = MFI_POLL_TIMEOUT_SECS;
155247369SsmhTUNABLE_INT("hw.mfi.polled_cmd_timeout", &mfi_polled_cmd_timeout);
156247369SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, polled_cmd_timeout, CTLFLAG_RWTUN,
157247369Ssmh	   &mfi_polled_cmd_timeout, 0,
158247369Ssmh	   "Polled command timeout - used for firmware flash etc (in seconds)");
159247369Ssmh
160247426Ssmhstatic int	mfi_cmd_timeout = MFI_CMD_TIMEOUT;
161247426SsmhTUNABLE_INT("hw.mfi.cmd_timeout", &mfi_cmd_timeout);
162247426SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, cmd_timeout, CTLFLAG_RWTUN, &mfi_cmd_timeout,
163247426Ssmh	   0, "Command timeout (in seconds)");
164247426Ssmh
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
184233711Sambriskostruct 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) {
196233711Sambrisko		MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
197184897Sambrisko		MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM);
198233711Sambrisko	}
199233711Sambrisko	else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
200233711Sambrisko		MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
201184897Sambrisko		MFI_WRITE4(sc, MFI_OMSK, ~MFI_GEN2_EIM);
202184897Sambrisko	}
203233711Sambrisko	else if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
204233711Sambrisko		MFI_WRITE4(sc, MFI_OMSK, ~0x00000001);
205233711Sambrisko	}
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		}
243233711Sambrisko	}
244233711Sambrisko	else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
245184897Sambrisko		if (!(status & MFI_GEN2_RM)) {
246184897Sambrisko			return 1;
247184897Sambrisko		}
248184897Sambrisko	}
249233711Sambrisko	else if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
250233711Sambrisko		if (!(status & MFI_SKINNY_RM)) {
251233711Sambrisko			return 1;
252233711Sambrisko		}
253233711Sambrisko	}
254233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
255233711Sambrisko		MFI_WRITE4(sc, MFI_OSTS, status);
256233711Sambrisko	else
257233711Sambrisko		MFI_WRITE4(sc, MFI_ODCR0, status);
258171980Sscottl	return 0;
259182085Simp}
260171980Sscottl
261184897Sambriskostatic void
262233711Sambriskomfi_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
268233711Sambriskomfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt)
269171980Sscottl{
270233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
271233711Sambrisko	    MFI_WRITE4(sc, MFI_IQPL, (bus_add | frame_cnt <<1)|1 );
272233711Sambrisko	    MFI_WRITE4(sc, MFI_IQPH, 0x00000000);
273233711Sambrisko	} else {
274233711Sambrisko	    MFI_WRITE4(sc, MFI_IQP, (bus_add | frame_cnt <<1)|1 );
275233711Sambrisko	}
276171980Sscottl}
277171980Sscottl
278233711Sambriskoint
279157114Sscottlmfi_transition_firmware(struct mfi_softc *sc)
280157114Sscottl{
281194851Sscottl	uint32_t fw_state, cur_state;
282157114Sscottl	int max_wait, i;
283233711Sambrisko	uint32_t cur_abs_reg_val = 0;
284233711Sambrisko	uint32_t prev_abs_reg_val = 0;
285157114Sscottl
286233711Sambrisko	cur_abs_reg_val = sc->mfi_read_fw_status(sc);
287233711Sambrisko	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:
298233711Sambrisko			if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
299233711Sambrisko			    MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
300233711Sambrisko			else
301233711Sambrisko			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
302233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
303157114Sscottl			break;
304157114Sscottl		case MFI_FWSTATE_OPERATIONAL:
305233711Sambrisko			if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
306233711Sambrisko			    MFI_WRITE4(sc, MFI_SKINNY_IDB, 7);
307233711Sambrisko			else
308233711Sambrisko			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY);
309233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
310157114Sscottl			break;
311157114Sscottl		case MFI_FWSTATE_UNDEFINED:
312157114Sscottl		case MFI_FWSTATE_BB_INIT:
313233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
314157114Sscottl			break;
315233711Sambrisko		case MFI_FWSTATE_FW_INIT_2:
316233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
317233711Sambrisko			break;
318157114Sscottl		case MFI_FWSTATE_FW_INIT:
319157114Sscottl		case MFI_FWSTATE_FLUSH_CACHE:
320233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
321157114Sscottl			break;
322233711Sambrisko		case MFI_FWSTATE_DEVICE_SCAN:
323233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME; /* wait for 180 seconds */
324233711Sambrisko			prev_abs_reg_val = cur_abs_reg_val;
325233711Sambrisko			break;
326224041Sjhb		case MFI_FWSTATE_BOOT_MESSAGE_PENDING:
327233711Sambrisko			if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
328233711Sambrisko			    MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_HOTPLUG);
329233711Sambrisko			else
330233711Sambrisko			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG);
331233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
332224041Sjhb			break;
333157114Sscottl		default:
334233711Sambrisko			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++) {
339233711Sambrisko			cur_abs_reg_val = sc->mfi_read_fw_status(sc);
340233711Sambrisko			fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK;
341157114Sscottl			if (fw_state == cur_state)
342157114Sscottl				DELAY(100000);
343157114Sscottl			else
344157114Sscottl				break;
345157114Sscottl		}
346233711Sambrisko		if (fw_state == MFI_FWSTATE_DEVICE_SCAN) {
347233711Sambrisko			/* Check the device scanning progress */
348233711Sambrisko			if (prev_abs_reg_val != cur_abs_reg_val) {
349233711Sambrisko				continue;
350233711Sambrisko			}
351233711Sambrisko		}
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
362233711Sambriskomfi_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
363157114Sscottl{
364233711Sambrisko	bus_addr_t *addr;
365157114Sscottl
366157114Sscottl	addr = arg;
367157114Sscottl	*addr = segs[0].ds_addr;
368157114Sscottl}
369157114Sscottl
370233711Sambrisko
371157114Sscottlint
372157114Sscottlmfi_attach(struct mfi_softc *sc)
373157114Sscottl{
374157114Sscottl	uint32_t status;
375157114Sscottl	int error, commsz, framessz, sensesz;
376247369Ssmh	int frames, unit, max_fw_sge, max_fw_cmds;
377233711Sambrisko	uint32_t tb_mem_size = 0;
378284429Sambrisko	struct cdev *dev_t;
379157114Sscottl
380233711Sambrisko	if (sc == NULL)
381233711Sambrisko		return EINVAL;
382186132Sambrisko
383233711Sambrisko	device_printf(sc->mfi_dev, "Megaraid SAS driver Ver %s \n",
384233711Sambrisko	    MEGASAS_VERSION);
385233711Sambrisko
386157114Sscottl	mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF);
387171821Sjhb	sx_init(&sc->mfi_config_lock, "MFI config");
388157114Sscottl	TAILQ_INIT(&sc->mfi_ld_tqh);
389233711Sambrisko	TAILQ_INIT(&sc->mfi_syspd_tqh);
390242681Sambrisko	TAILQ_INIT(&sc->mfi_ld_pend_tqh);
391242681Sambrisko	TAILQ_INIT(&sc->mfi_syspd_pend_tqh);
392233711Sambrisko	TAILQ_INIT(&sc->mfi_evt_queue);
393233711Sambrisko	TASK_INIT(&sc->mfi_evt_task, 0, mfi_handle_evt, sc);
394235014Sambrisko	TASK_INIT(&sc->mfi_map_sync_task, 0, mfi_handle_map_sync, sc);
395158737Sambrisko	TAILQ_INIT(&sc->mfi_aen_pids);
396169611Sscottl	TAILQ_INIT(&sc->mfi_cam_ccbq);
397157114Sscottl
398157114Sscottl	mfi_initq_free(sc);
399157114Sscottl	mfi_initq_ready(sc);
400157114Sscottl	mfi_initq_busy(sc);
401157114Sscottl	mfi_initq_bio(sc);
402157114Sscottl
403233711Sambrisko	sc->adpreset = 0;
404233711Sambrisko	sc->last_seq_num = 0;
405233711Sambrisko	sc->disableOnlineCtrlReset = 1;
406233711Sambrisko	sc->issuepend_done = 1;
407233711Sambrisko	sc->hw_crit_error = 0;
408233711Sambrisko
409171980Sscottl	if (sc->mfi_flags & MFI_FLAGS_1064R) {
410171980Sscottl		sc->mfi_enable_intr = mfi_enable_intr_xscale;
411171980Sscottl		sc->mfi_read_fw_status = mfi_read_fw_status_xscale;
412171980Sscottl		sc->mfi_check_clear_intr = mfi_check_clear_intr_xscale;
413171980Sscottl		sc->mfi_issue_cmd = mfi_issue_cmd_xscale;
414233711Sambrisko	} else if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
415233711Sambrisko		sc->mfi_enable_intr = mfi_tbolt_enable_intr_ppc;
416233711Sambrisko		sc->mfi_disable_intr = mfi_tbolt_disable_intr_ppc;
417233711Sambrisko		sc->mfi_read_fw_status = mfi_tbolt_read_fw_status_ppc;
418233711Sambrisko		sc->mfi_check_clear_intr = mfi_tbolt_check_clear_intr_ppc;
419233711Sambrisko		sc->mfi_issue_cmd = mfi_tbolt_issue_cmd_ppc;
420233711Sambrisko		sc->mfi_adp_reset = mfi_tbolt_adp_reset;
421233711Sambrisko		sc->mfi_tbolt = 1;
422233711Sambrisko		TAILQ_INIT(&sc->mfi_cmd_tbolt_tqh);
423233711Sambrisko	} else {
424171980Sscottl		sc->mfi_enable_intr =  mfi_enable_intr_ppc;
425233711Sambrisko		sc->mfi_read_fw_status = mfi_read_fw_status_ppc;
426171980Sscottl		sc->mfi_check_clear_intr = mfi_check_clear_intr_ppc;
427171980Sscottl		sc->mfi_issue_cmd = mfi_issue_cmd_ppc;
428171980Sscottl	}
429171980Sscottl
430171980Sscottl
431157114Sscottl	/* Before we get too far, see if the firmware is working */
432157114Sscottl	if ((error = mfi_transition_firmware(sc)) != 0) {
433157114Sscottl		device_printf(sc->mfi_dev, "Firmware not in READY state, "
434157114Sscottl		    "error %d\n", error);
435157114Sscottl		return (ENXIO);
436157114Sscottl	}
437157114Sscottl
438233711Sambrisko	/* Start: LSIP200113393 */
439233711Sambrisko	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
440233711Sambrisko				1, 0,			/* algnmnt, boundary */
441233711Sambrisko				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
442233711Sambrisko				BUS_SPACE_MAXADDR,	/* highaddr */
443233711Sambrisko				NULL, NULL,		/* filter, filterarg */
444233711Sambrisko				MEGASAS_MAX_NAME*sizeof(bus_addr_t),			/* maxsize */
445233711Sambrisko				1,			/* msegments */
446233711Sambrisko				MEGASAS_MAX_NAME*sizeof(bus_addr_t),			/* maxsegsize */
447233711Sambrisko				0,			/* flags */
448233711Sambrisko				NULL, NULL,		/* lockfunc, lockarg */
449233711Sambrisko				&sc->verbuf_h_dmat)) {
450233711Sambrisko		device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmat DMA tag\n");
451233711Sambrisko		return (ENOMEM);
452233711Sambrisko	}
453233711Sambrisko	if (bus_dmamem_alloc(sc->verbuf_h_dmat, (void **)&sc->verbuf,
454233711Sambrisko	    BUS_DMA_NOWAIT, &sc->verbuf_h_dmamap)) {
455233711Sambrisko		device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmamap memory\n");
456233711Sambrisko		return (ENOMEM);
457233711Sambrisko	}
458233711Sambrisko	bzero(sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t));
459233711Sambrisko	bus_dmamap_load(sc->verbuf_h_dmat, sc->verbuf_h_dmamap,
460233711Sambrisko	    sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t),
461233711Sambrisko	    mfi_addr_cb, &sc->verbuf_h_busaddr, 0);
462233711Sambrisko	/* End: LSIP200113393 */
463233711Sambrisko
464157114Sscottl	/*
465157114Sscottl	 * Get information needed for sizing the contiguous memory for the
466157114Sscottl	 * frame pool.  Size down the sgl parameter since we know that
467157114Sscottl	 * we will never need more than what's required for MAXPHYS.
468157114Sscottl	 * It would be nice if these constants were available at runtime
469157114Sscottl	 * instead of compile time.
470157114Sscottl	 */
471171980Sscottl	status = sc->mfi_read_fw_status(sc);
472247369Ssmh	max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK;
473247369Ssmh	if (mfi_max_cmds > 0 && mfi_max_cmds < max_fw_cmds) {
474247369Ssmh		device_printf(sc->mfi_dev, "FW MaxCmds = %d, limiting to %d\n",
475247369Ssmh		    max_fw_cmds, mfi_max_cmds);
476247369Ssmh		sc->mfi_max_fw_cmds = mfi_max_cmds;
477247369Ssmh	} else {
478247369Ssmh		sc->mfi_max_fw_cmds = max_fw_cmds;
479247369Ssmh	}
480162458Sscottl	max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16;
481195534Sscottl	sc->mfi_max_sge = min(max_fw_sge, ((MFI_MAXPHYS / PAGE_SIZE) + 1));
482157114Sscottl
483233711Sambrisko	/* ThunderBolt Support get the contiguous memory */
484233711Sambrisko
485233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
486233711Sambrisko		mfi_tbolt_init_globals(sc);
487247369Ssmh		device_printf(sc->mfi_dev, "MaxCmd = %d, Drv MaxCmd = %d, "
488247369Ssmh		    "MaxSgl = %d, state = %#x\n", max_fw_cmds,
489233711Sambrisko		    sc->mfi_max_fw_cmds, sc->mfi_max_sge, status);
490233711Sambrisko		tb_mem_size = mfi_tbolt_get_memory_requirement(sc);
491233711Sambrisko
492233711Sambrisko		if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
493233711Sambrisko				1, 0,			/* algnmnt, boundary */
494233711Sambrisko				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
495233711Sambrisko				BUS_SPACE_MAXADDR,	/* highaddr */
496233711Sambrisko				NULL, NULL,		/* filter, filterarg */
497233711Sambrisko				tb_mem_size,		/* maxsize */
498233711Sambrisko				1,			/* msegments */
499233711Sambrisko				tb_mem_size,		/* maxsegsize */
500233711Sambrisko				0,			/* flags */
501233711Sambrisko				NULL, NULL,		/* lockfunc, lockarg */
502233711Sambrisko				&sc->mfi_tb_dmat)) {
503233711Sambrisko			device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
504233711Sambrisko			return (ENOMEM);
505233711Sambrisko		}
506233711Sambrisko		if (bus_dmamem_alloc(sc->mfi_tb_dmat, (void **)&sc->request_message_pool,
507233711Sambrisko		BUS_DMA_NOWAIT, &sc->mfi_tb_dmamap)) {
508233711Sambrisko			device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
509233711Sambrisko			return (ENOMEM);
510233711Sambrisko		}
511233711Sambrisko		bzero(sc->request_message_pool, tb_mem_size);
512233711Sambrisko		bus_dmamap_load(sc->mfi_tb_dmat, sc->mfi_tb_dmamap,
513233711Sambrisko		sc->request_message_pool, tb_mem_size, mfi_addr_cb, &sc->mfi_tb_busaddr, 0);
514233711Sambrisko
515233711Sambrisko		/* For ThunderBolt memory init */
516233711Sambrisko		if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
517233711Sambrisko				0x100, 0,		/* alignmnt, boundary */
518233711Sambrisko				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
519233711Sambrisko				BUS_SPACE_MAXADDR,	/* highaddr */
520233711Sambrisko				NULL, NULL,		/* filter, filterarg */
521233711Sambrisko				MFI_FRAME_SIZE,		/* maxsize */
522233711Sambrisko				1,			/* msegments */
523233711Sambrisko				MFI_FRAME_SIZE,		/* maxsegsize */
524233711Sambrisko				0,			/* flags */
525233711Sambrisko				NULL, NULL,		/* lockfunc, lockarg */
526233711Sambrisko				&sc->mfi_tb_init_dmat)) {
527247369Ssmh			device_printf(sc->mfi_dev, "Cannot allocate init DMA tag\n");
528247369Ssmh			return (ENOMEM);
529233711Sambrisko		}
530233711Sambrisko		if (bus_dmamem_alloc(sc->mfi_tb_init_dmat, (void **)&sc->mfi_tb_init,
531233711Sambrisko		    BUS_DMA_NOWAIT, &sc->mfi_tb_init_dmamap)) {
532233711Sambrisko			device_printf(sc->mfi_dev, "Cannot allocate init memory\n");
533233711Sambrisko			return (ENOMEM);
534233711Sambrisko		}
535233711Sambrisko		bzero(sc->mfi_tb_init, MFI_FRAME_SIZE);
536233711Sambrisko		bus_dmamap_load(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap,
537233711Sambrisko		sc->mfi_tb_init, MFI_FRAME_SIZE, mfi_addr_cb,
538233711Sambrisko		    &sc->mfi_tb_init_busaddr, 0);
539233711Sambrisko		if (mfi_tbolt_init_desc_pool(sc, sc->request_message_pool,
540233711Sambrisko		    tb_mem_size)) {
541233711Sambrisko			device_printf(sc->mfi_dev,
542233711Sambrisko			    "Thunderbolt pool preparation error\n");
543233711Sambrisko			return 0;
544233711Sambrisko		}
545233711Sambrisko
546233711Sambrisko		/*
547233711Sambrisko		  Allocate DMA memory mapping for MPI2 IOC Init descriptor,
548233711Sambrisko		  we are taking it diffrent from what we have allocated for Request
549233711Sambrisko		  and reply descriptors to avoid confusion later
550233711Sambrisko		*/
551233711Sambrisko		tb_mem_size = sizeof(struct MPI2_IOC_INIT_REQUEST);
552233711Sambrisko		if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
553233711Sambrisko				1, 0,			/* algnmnt, boundary */
554233711Sambrisko				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
555233711Sambrisko				BUS_SPACE_MAXADDR,	/* highaddr */
556233711Sambrisko				NULL, NULL,		/* filter, filterarg */
557233711Sambrisko				tb_mem_size,		/* maxsize */
558233711Sambrisko				1,			/* msegments */
559233711Sambrisko				tb_mem_size,		/* maxsegsize */
560233711Sambrisko				0,			/* flags */
561233711Sambrisko				NULL, NULL,		/* lockfunc, lockarg */
562233711Sambrisko				&sc->mfi_tb_ioc_init_dmat)) {
563233711Sambrisko			device_printf(sc->mfi_dev,
564233711Sambrisko			    "Cannot allocate comms DMA tag\n");
565233711Sambrisko			return (ENOMEM);
566233711Sambrisko		}
567233711Sambrisko		if (bus_dmamem_alloc(sc->mfi_tb_ioc_init_dmat,
568233711Sambrisko		    (void **)&sc->mfi_tb_ioc_init_desc,
569233711Sambrisko		    BUS_DMA_NOWAIT, &sc->mfi_tb_ioc_init_dmamap)) {
570233711Sambrisko			device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
571233711Sambrisko			return (ENOMEM);
572233711Sambrisko		}
573233711Sambrisko		bzero(sc->mfi_tb_ioc_init_desc, tb_mem_size);
574233711Sambrisko		bus_dmamap_load(sc->mfi_tb_ioc_init_dmat, sc->mfi_tb_ioc_init_dmamap,
575233711Sambrisko		sc->mfi_tb_ioc_init_desc, tb_mem_size, mfi_addr_cb,
576233711Sambrisko		    &sc->mfi_tb_ioc_init_busaddr, 0);
577233711Sambrisko	}
578157114Sscottl	/*
579157114Sscottl	 * Create the dma tag for data buffers.  Used both for block I/O
580157114Sscottl	 * and for various internal data queries.
581157114Sscottl	 */
582157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
583157114Sscottl				1, 0,			/* algnmnt, boundary */
584157114Sscottl				BUS_SPACE_MAXADDR,	/* lowaddr */
585157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
586157114Sscottl				NULL, NULL,		/* filter, filterarg */
587157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
588162458Sscottl				sc->mfi_max_sge,	/* nsegments */
589157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
590157114Sscottl				BUS_DMA_ALLOCNOW,	/* flags */
591157114Sscottl				busdma_lock_mutex,	/* lockfunc */
592157114Sscottl				&sc->mfi_io_lock,	/* lockfuncarg */
593157114Sscottl				&sc->mfi_buffer_dmat)) {
594157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate buffer DMA tag\n");
595157114Sscottl		return (ENOMEM);
596157114Sscottl	}
597157114Sscottl
598157114Sscottl	/*
599157114Sscottl	 * Allocate DMA memory for the comms queues.  Keep it under 4GB for
600157114Sscottl	 * efficiency.  The mfi_hwcomms struct includes space for 1 reply queue
601157114Sscottl	 * entry, so the calculated size here will be will be 1 more than
602157114Sscottl	 * mfi_max_fw_cmds.  This is apparently a requirement of the hardware.
603157114Sscottl	 */
604157114Sscottl	commsz = (sizeof(uint32_t) * sc->mfi_max_fw_cmds) +
605157114Sscottl	    sizeof(struct mfi_hwcomms);
606157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
607157114Sscottl				1, 0,			/* algnmnt, boundary */
608157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
609157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
610157114Sscottl				NULL, NULL,		/* filter, filterarg */
611157114Sscottl				commsz,			/* maxsize */
612157114Sscottl				1,			/* msegments */
613157114Sscottl				commsz,			/* maxsegsize */
614157114Sscottl				0,			/* flags */
615157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
616157114Sscottl				&sc->mfi_comms_dmat)) {
617157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
618157114Sscottl		return (ENOMEM);
619157114Sscottl	}
620157114Sscottl	if (bus_dmamem_alloc(sc->mfi_comms_dmat, (void **)&sc->mfi_comms,
621157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_comms_dmamap)) {
622157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
623157114Sscottl		return (ENOMEM);
624157114Sscottl	}
625157114Sscottl	bzero(sc->mfi_comms, commsz);
626157114Sscottl	bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap,
627233711Sambrisko	    sc->mfi_comms, commsz, mfi_addr_cb, &sc->mfi_comms_busaddr, 0);
628157114Sscottl	/*
629157114Sscottl	 * Allocate DMA memory for the command frames.  Keep them in the
630162458Sscottl	 * lower 4GB for efficiency.  Calculate the size of the commands at
631162458Sscottl	 * the same time; each command is one 64 byte frame plus a set of
632162458Sscottl         * additional frames for holding sg lists or other data.
633157114Sscottl	 * The assumption here is that the SG list will start at the second
634162458Sscottl	 * frame and not use the unused bytes in the first frame.  While this
635162458Sscottl	 * isn't technically correct, it simplifies the calculation and allows
636162458Sscottl	 * for command frames that might be larger than an mfi_io_frame.
637157114Sscottl	 */
638157114Sscottl	if (sizeof(bus_addr_t) == 8) {
639162458Sscottl		sc->mfi_sge_size = sizeof(struct mfi_sg64);
640157114Sscottl		sc->mfi_flags |= MFI_FLAGS_SG64;
641157114Sscottl	} else {
642162458Sscottl		sc->mfi_sge_size = sizeof(struct mfi_sg32);
643157114Sscottl	}
644233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
645233711Sambrisko		sc->mfi_sge_size = sizeof(struct mfi_sg_skinny);
646162458Sscottl	frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2;
647162458Sscottl	sc->mfi_cmd_size = frames * MFI_FRAME_SIZE;
648162458Sscottl	framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds;
649157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
650157114Sscottl				64, 0,			/* algnmnt, boundary */
651157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
652157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
653157114Sscottl				NULL, NULL,		/* filter, filterarg */
654157114Sscottl				framessz,		/* maxsize */
655157114Sscottl				1,			/* nsegments */
656157114Sscottl				framessz,		/* maxsegsize */
657157114Sscottl				0,			/* flags */
658157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
659157114Sscottl				&sc->mfi_frames_dmat)) {
660157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frame DMA tag\n");
661157114Sscottl		return (ENOMEM);
662157114Sscottl	}
663157114Sscottl	if (bus_dmamem_alloc(sc->mfi_frames_dmat, (void **)&sc->mfi_frames,
664157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_frames_dmamap)) {
665157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frames memory\n");
666157114Sscottl		return (ENOMEM);
667157114Sscottl	}
668157114Sscottl	bzero(sc->mfi_frames, framessz);
669157114Sscottl	bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap,
670233711Sambrisko	    sc->mfi_frames, framessz, mfi_addr_cb, &sc->mfi_frames_busaddr,0);
671157114Sscottl	/*
672157114Sscottl	 * Allocate DMA memory for the frame sense data.  Keep them in the
673157114Sscottl	 * lower 4GB for efficiency
674157114Sscottl	 */
675157114Sscottl	sensesz = sc->mfi_max_fw_cmds * MFI_SENSE_LEN;
676157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
677157114Sscottl				4, 0,			/* algnmnt, boundary */
678157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
679157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
680157114Sscottl				NULL, NULL,		/* filter, filterarg */
681157114Sscottl				sensesz,		/* maxsize */
682157114Sscottl				1,			/* nsegments */
683157114Sscottl				sensesz,		/* maxsegsize */
684157114Sscottl				0,			/* flags */
685157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
686157114Sscottl				&sc->mfi_sense_dmat)) {
687157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense DMA tag\n");
688157114Sscottl		return (ENOMEM);
689157114Sscottl	}
690157114Sscottl	if (bus_dmamem_alloc(sc->mfi_sense_dmat, (void **)&sc->mfi_sense,
691157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_sense_dmamap)) {
692157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense memory\n");
693157114Sscottl		return (ENOMEM);
694157114Sscottl	}
695157114Sscottl	bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap,
696233711Sambrisko	    sc->mfi_sense, sensesz, mfi_addr_cb, &sc->mfi_sense_busaddr, 0);
697157114Sscottl	if ((error = mfi_alloc_commands(sc)) != 0)
698157114Sscottl		return (error);
699157114Sscottl
700233711Sambrisko	/* Before moving the FW to operational state, check whether
701233711Sambrisko	 * hostmemory is required by the FW or not
702233711Sambrisko	 */
703157114Sscottl
704233711Sambrisko	/* ThunderBolt MFI_IOC2 INIT */
705233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
706233711Sambrisko		sc->mfi_disable_intr(sc);
707247369Ssmh		mtx_lock(&sc->mfi_io_lock);
708233711Sambrisko		if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0) {
709233711Sambrisko			device_printf(sc->mfi_dev,
710233711Sambrisko			    "TB Init has failed with error %d\n",error);
711247369Ssmh			mtx_unlock(&sc->mfi_io_lock);
712233711Sambrisko			return error;
713233711Sambrisko		}
714247369Ssmh		mtx_unlock(&sc->mfi_io_lock);
715157114Sscottl
716233711Sambrisko		if ((error = mfi_tbolt_alloc_cmd(sc)) != 0)
717233711Sambrisko			return error;
718233711Sambrisko		if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq,
719233711Sambrisko		    INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr_tbolt, sc,
720233711Sambrisko		    &sc->mfi_intr)) {
721233711Sambrisko			device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
722233711Sambrisko			return (EINVAL);
723233711Sambrisko		}
724242681Sambrisko		sc->mfi_intr_ptr = mfi_intr_tbolt;
725233711Sambrisko		sc->mfi_enable_intr(sc);
726233711Sambrisko	} else {
727233711Sambrisko		if ((error = mfi_comms_init(sc)) != 0)
728233711Sambrisko			return (error);
729157114Sscottl
730233711Sambrisko		if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq,
731233711Sambrisko		    INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr, sc, &sc->mfi_intr)) {
732233711Sambrisko			device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
733233711Sambrisko			return (EINVAL);
734233711Sambrisko		}
735242681Sambrisko		sc->mfi_intr_ptr = mfi_intr;
736233711Sambrisko		sc->mfi_enable_intr(sc);
737157114Sscottl	}
738233711Sambrisko	if ((error = mfi_get_controller_info(sc)) != 0)
739233711Sambrisko		return (error);
740233711Sambrisko	sc->disableOnlineCtrlReset = 0;
741157114Sscottl
742157114Sscottl	/* Register a config hook to probe the bus for arrays */
743157114Sscottl	sc->mfi_ich.ich_func = mfi_startup;
744157114Sscottl	sc->mfi_ich.ich_arg = sc;
745157114Sscottl	if (config_intrhook_establish(&sc->mfi_ich) != 0) {
746157114Sscottl		device_printf(sc->mfi_dev, "Cannot establish configuration "
747157114Sscottl		    "hook\n");
748157114Sscottl		return (EINVAL);
749157114Sscottl	}
750247369Ssmh	mtx_lock(&sc->mfi_io_lock);
751247369Ssmh	if ((error = mfi_aen_setup(sc, 0), 0) != 0) {
752247369Ssmh		mtx_unlock(&sc->mfi_io_lock);
753233711Sambrisko		return (error);
754247369Ssmh	}
755247369Ssmh	mtx_unlock(&sc->mfi_io_lock);
756157114Sscottl
757157114Sscottl	/*
758157114Sscottl	 * Register a shutdown handler.
759157114Sscottl	 */
760157114Sscottl	if ((sc->mfi_eh = EVENTHANDLER_REGISTER(shutdown_final, mfi_shutdown,
761157114Sscottl	    sc, SHUTDOWN_PRI_DEFAULT)) == NULL) {
762157114Sscottl		device_printf(sc->mfi_dev, "Warning: shutdown event "
763157114Sscottl		    "registration failed\n");
764157114Sscottl	}
765157114Sscottl
766157114Sscottl	/*
767157114Sscottl	 * Create the control device for doing management
768157114Sscottl	 */
769157114Sscottl	unit = device_get_unit(sc->mfi_dev);
770157114Sscottl	sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR,
771157114Sscottl	    0640, "mfi%d", unit);
772158737Sambrisko	if (unit == 0)
773284429Sambrisko		make_dev_alias_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, &dev_t,
774284429Sambrisko		    sc->mfi_cdev, "%s", "megaraid_sas_ioctl_node");
775157114Sscottl	if (sc->mfi_cdev != NULL)
776157114Sscottl		sc->mfi_cdev->si_drv1 = sc;
777171821Sjhb	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
778171821Sjhb	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
779171821Sjhb	    OID_AUTO, "delete_busy_volumes", CTLFLAG_RW,
780171821Sjhb	    &sc->mfi_delete_busy_volumes, 0, "Allow removal of busy volumes");
781171821Sjhb	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
782171821Sjhb	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
783171821Sjhb	    OID_AUTO, "keep_deleted_volumes", CTLFLAG_RW,
784171821Sjhb	    &sc->mfi_keep_deleted_volumes, 0,
785171821Sjhb	    "Don't detach the mfid device for a busy volume that is deleted");
786157114Sscottl
787169611Sscottl	device_add_child(sc->mfi_dev, "mfip", -1);
788169611Sscottl	bus_generic_attach(sc->mfi_dev);
789169611Sscottl
790162619Sscottl	/* Start the timeout watchdog */
791178250Skris	callout_init(&sc->mfi_watchdog_callout, CALLOUT_MPSAFE);
792247426Ssmh	callout_reset(&sc->mfi_watchdog_callout, mfi_cmd_timeout * hz,
793162619Sscottl	    mfi_timeout, sc);
794162619Sscottl
795235014Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
796247369Ssmh		mtx_lock(&sc->mfi_io_lock);
797235014Sambrisko		mfi_tbolt_sync_map_info(sc);
798247369Ssmh		mtx_unlock(&sc->mfi_io_lock);
799235014Sambrisko	}
800235014Sambrisko
801157114Sscottl	return (0);
802157114Sscottl}
803157114Sscottl
804157114Sscottlstatic int
805157114Sscottlmfi_alloc_commands(struct mfi_softc *sc)
806157114Sscottl{
807157114Sscottl	struct mfi_command *cm;
808247369Ssmh	int i, j;
809157114Sscottl
810157114Sscottl	/*
811157114Sscottl	 * XXX Should we allocate all the commands up front, or allocate on
812157114Sscottl	 * demand later like 'aac' does?
813157114Sscottl	 */
814247369Ssmh	sc->mfi_commands = malloc(sizeof(sc->mfi_commands[0]) *
815247369Ssmh	    sc->mfi_max_fw_cmds, M_MFIBUF, M_WAITOK | M_ZERO);
816178968Sscottl
817247369Ssmh	for (i = 0; i < sc->mfi_max_fw_cmds; i++) {
818157114Sscottl		cm = &sc->mfi_commands[i];
819158737Sambrisko		cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames +
820162458Sscottl		    sc->mfi_cmd_size * i);
821157114Sscottl		cm->cm_frame_busaddr = sc->mfi_frames_busaddr +
822162458Sscottl		    sc->mfi_cmd_size * i;
823157114Sscottl		cm->cm_frame->header.context = i;
824157114Sscottl		cm->cm_sense = &sc->mfi_sense[i];
825157114Sscottl		cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i;
826157114Sscottl		cm->cm_sc = sc;
827162619Sscottl		cm->cm_index = i;
828157114Sscottl		if (bus_dmamap_create(sc->mfi_buffer_dmat, 0,
829233711Sambrisko		    &cm->cm_dmamap) == 0) {
830233711Sambrisko			mtx_lock(&sc->mfi_io_lock);
831157114Sscottl			mfi_release_command(cm);
832233711Sambrisko			mtx_unlock(&sc->mfi_io_lock);
833247369Ssmh		} else {
834247369Ssmh			device_printf(sc->mfi_dev, "Failed to allocate %d "
835247369Ssmh			   "command blocks, only allocated %d\n",
836247369Ssmh			    sc->mfi_max_fw_cmds, i - 1);
837247369Ssmh			for (j = 0; j < i; j++) {
838247369Ssmh				cm = &sc->mfi_commands[i];
839247369Ssmh				bus_dmamap_destroy(sc->mfi_buffer_dmat,
840247369Ssmh				    cm->cm_dmamap);
841247369Ssmh			}
842247369Ssmh			free(sc->mfi_commands, M_MFIBUF);
843247369Ssmh			sc->mfi_commands = NULL;
844247369Ssmh
845247369Ssmh			return (ENOMEM);
846233711Sambrisko		}
847157114Sscottl	}
848157114Sscottl
849157114Sscottl	return (0);
850157114Sscottl}
851157114Sscottl
852169611Sscottlvoid
853157114Sscottlmfi_release_command(struct mfi_command *cm)
854157114Sscottl{
855163398Sscottl	struct mfi_frame_header *hdr;
856157114Sscottl	uint32_t *hdr_data;
857157114Sscottl
858233711Sambrisko	mtx_assert(&cm->cm_sc->mfi_io_lock, MA_OWNED);
859233711Sambrisko
860157114Sscottl	/*
861157114Sscottl	 * Zero out the important fields of the frame, but make sure the
862165727Sscottl	 * context field is preserved.  For efficiency, handle the fields
863165727Sscottl	 * as 32 bit words.  Clear out the first S/G entry too for safety.
864157114Sscottl	 */
865163398Sscottl	hdr = &cm->cm_frame->header;
866175897Sambrisko	if (cm->cm_data != NULL && hdr->sg_count) {
867163398Sscottl		cm->cm_sg->sg32[0].len = 0;
868163398Sscottl		cm->cm_sg->sg32[0].addr = 0;
869163398Sscottl	}
870165727Sscottl
871247369Ssmh	/*
872247369Ssmh	 * Command may be on other queues e.g. busy queue depending on the
873247369Ssmh	 * flow of a previous call to mfi_mapcmd, so ensure its dequeued
874247369Ssmh	 * properly
875247369Ssmh	 */
876247369Ssmh	if ((cm->cm_flags & MFI_ON_MFIQ_BUSY) != 0)
877247369Ssmh		mfi_remove_busy(cm);
878247369Ssmh	if ((cm->cm_flags & MFI_ON_MFIQ_READY) != 0)
879247369Ssmh		mfi_remove_ready(cm);
880247369Ssmh
881247369Ssmh	/* We're not expecting it to be on any other queue but check */
882247369Ssmh	if ((cm->cm_flags & MFI_ON_MFIQ_MASK) != 0) {
883247369Ssmh		panic("Command %p is still on another queue, flags = %#x",
884247369Ssmh		    cm, cm->cm_flags);
885247369Ssmh	}
886247369Ssmh
887247369Ssmh	/* tbolt cleanup */
888247369Ssmh	if ((cm->cm_flags & MFI_CMD_TBOLT) != 0) {
889247369Ssmh		mfi_tbolt_return_cmd(cm->cm_sc,
890247369Ssmh		    cm->cm_sc->mfi_cmd_pool_tbolt[cm->cm_extra_frames - 1],
891247369Ssmh		    cm);
892247369Ssmh	}
893247369Ssmh
894165727Sscottl	hdr_data = (uint32_t *)cm->cm_frame;
895165727Sscottl	hdr_data[0] = 0;	/* cmd, sense_len, cmd_status, scsi_status */
896165727Sscottl	hdr_data[1] = 0;	/* target_id, lun_id, cdb_len, sg_count */
897165727Sscottl	hdr_data[4] = 0;	/* flags, timeout */
898165727Sscottl	hdr_data[5] = 0;	/* data_len */
899165727Sscottl
900157114Sscottl	cm->cm_extra_frames = 0;
901157114Sscottl	cm->cm_flags = 0;
902157114Sscottl	cm->cm_complete = NULL;
903157114Sscottl	cm->cm_private = NULL;
904169611Sscottl	cm->cm_data = NULL;
905157114Sscottl	cm->cm_sg = 0;
906157114Sscottl	cm->cm_total_frame_size = 0;
907233711Sambrisko	cm->retry_for_fw_reset = 0;
908163398Sscottl
909157114Sscottl	mfi_enqueue_free(cm);
910157114Sscottl}
911157114Sscottl
912235014Sambriskoint
913233711Sambriskomfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp,
914233711Sambrisko    uint32_t opcode, void **bufp, size_t bufsize)
915159806Sps{
916159806Sps	struct mfi_command *cm;
917159806Sps	struct mfi_dcmd_frame *dcmd;
918159806Sps	void *buf = NULL;
919233711Sambrisko	uint32_t context = 0;
920233711Sambrisko
921159806Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
922233711Sambrisko
923159806Sps	cm = mfi_dequeue_free(sc);
924159806Sps	if (cm == NULL)
925159806Sps		return (EBUSY);
926159806Sps
927233711Sambrisko	/* Zero out the MFI frame */
928233711Sambrisko	context = cm->cm_frame->header.context;
929233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
930233711Sambrisko	cm->cm_frame->header.context = context;
931233711Sambrisko
932159806Sps	if ((bufsize > 0) && (bufp != NULL)) {
933159806Sps		if (*bufp == NULL) {
934159806Sps			buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO);
935159806Sps			if (buf == NULL) {
936159806Sps				mfi_release_command(cm);
937159806Sps				return (ENOMEM);
938159806Sps			}
939159806Sps			*bufp = buf;
940159806Sps		} else {
941159806Sps			buf = *bufp;
942159806Sps		}
943159806Sps	}
944159806Sps
945159806Sps	dcmd =  &cm->cm_frame->dcmd;
946159806Sps	bzero(dcmd->mbox, MFI_MBOX_SIZE);
947159806Sps	dcmd->header.cmd = MFI_CMD_DCMD;
948159806Sps	dcmd->header.timeout = 0;
949159806Sps	dcmd->header.flags = 0;
950159806Sps	dcmd->header.data_len = bufsize;
951233711Sambrisko	dcmd->header.scsi_status = 0;
952159806Sps	dcmd->opcode = opcode;
953159806Sps	cm->cm_sg = &dcmd->sgl;
954159806Sps	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
955159806Sps	cm->cm_flags = 0;
956159806Sps	cm->cm_data = buf;
957159806Sps	cm->cm_private = buf;
958159806Sps	cm->cm_len = bufsize;
959159806Sps
960159806Sps	*cmp = cm;
961159806Sps	if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL))
962159806Sps		*bufp = buf;
963159806Sps	return (0);
964159806Sps}
965159806Sps
966159806Spsstatic int
967157114Sscottlmfi_comms_init(struct mfi_softc *sc)
968157114Sscottl{
969157114Sscottl	struct mfi_command *cm;
970157114Sscottl	struct mfi_init_frame *init;
971157114Sscottl	struct mfi_init_qinfo *qinfo;
972157114Sscottl	int error;
973233711Sambrisko	uint32_t context = 0;
974157114Sscottl
975163398Sscottl	mtx_lock(&sc->mfi_io_lock);
976247369Ssmh	if ((cm = mfi_dequeue_free(sc)) == NULL) {
977247369Ssmh		mtx_unlock(&sc->mfi_io_lock);
978157114Sscottl		return (EBUSY);
979247369Ssmh	}
980157114Sscottl
981233711Sambrisko	/* Zero out the MFI frame */
982233711Sambrisko	context = cm->cm_frame->header.context;
983233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
984233711Sambrisko	cm->cm_frame->header.context = context;
985233711Sambrisko
986157114Sscottl	/*
987157114Sscottl	 * Abuse the SG list area of the frame to hold the init_qinfo
988157114Sscottl	 * object;
989157114Sscottl	 */
990157114Sscottl	init = &cm->cm_frame->init;
991157114Sscottl	qinfo = (struct mfi_init_qinfo *)((uintptr_t)init + MFI_FRAME_SIZE);
992157114Sscottl
993157114Sscottl	bzero(qinfo, sizeof(struct mfi_init_qinfo));
994157114Sscottl	qinfo->rq_entries = sc->mfi_max_fw_cmds + 1;
995157114Sscottl	qinfo->rq_addr_lo = sc->mfi_comms_busaddr +
996157114Sscottl	    offsetof(struct mfi_hwcomms, hw_reply_q);
997157114Sscottl	qinfo->pi_addr_lo = sc->mfi_comms_busaddr +
998157114Sscottl	    offsetof(struct mfi_hwcomms, hw_pi);
999157114Sscottl	qinfo->ci_addr_lo = sc->mfi_comms_busaddr +
1000157114Sscottl	    offsetof(struct mfi_hwcomms, hw_ci);
1001157114Sscottl
1002157114Sscottl	init->header.cmd = MFI_CMD_INIT;
1003157114Sscottl	init->header.data_len = sizeof(struct mfi_init_qinfo);
1004157114Sscottl	init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE;
1005164375Sscottl	cm->cm_data = NULL;
1006164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
1007157114Sscottl
1008247369Ssmh	if ((error = mfi_mapcmd(sc, cm)) != 0)
1009157114Sscottl		device_printf(sc->mfi_dev, "failed to send init command\n");
1010157114Sscottl	mfi_release_command(cm);
1011163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1012157114Sscottl
1013247369Ssmh	return (error);
1014157114Sscottl}
1015157114Sscottl
1016157114Sscottlstatic int
1017157114Sscottlmfi_get_controller_info(struct mfi_softc *sc)
1018157114Sscottl{
1019159806Sps	struct mfi_command *cm = NULL;
1020159806Sps	struct mfi_ctrl_info *ci = NULL;
1021157114Sscottl	uint32_t max_sectors_1, max_sectors_2;
1022157114Sscottl	int error;
1023157114Sscottl
1024159806Sps	mtx_lock(&sc->mfi_io_lock);
1025159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO,
1026159806Sps	    (void **)&ci, sizeof(*ci));
1027159806Sps	if (error)
1028159806Sps		goto out;
1029157114Sscottl	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1030157114Sscottl
1031157114Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
1032157114Sscottl		device_printf(sc->mfi_dev, "Failed to get controller info\n");
1033162458Sscottl		sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE /
1034157114Sscottl		    MFI_SECTOR_LEN;
1035159806Sps		error = 0;
1036159806Sps		goto out;
1037157114Sscottl	}
1038157114Sscottl
1039157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1040157114Sscottl	    BUS_DMASYNC_POSTREAD);
1041157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1042157114Sscottl
1043233711Sambrisko	max_sectors_1 = (1 << ci->stripe_sz_ops.max) * ci->max_strips_per_io;
1044157114Sscottl	max_sectors_2 = ci->max_request_size;
1045157114Sscottl	sc->mfi_max_io = min(max_sectors_1, max_sectors_2);
1046233711Sambrisko	sc->disableOnlineCtrlReset =
1047233711Sambrisko	    ci->properties.OnOffProperties.disableOnlineCtrlReset;
1048157114Sscottl
1049159806Spsout:
1050159806Sps	if (ci)
1051159806Sps		free(ci, M_MFIBUF);
1052159806Sps	if (cm)
1053159806Sps		mfi_release_command(cm);
1054159806Sps	mtx_unlock(&sc->mfi_io_lock);
1055157114Sscottl	return (error);
1056157114Sscottl}
1057157114Sscottl
1058157114Sscottlstatic int
1059159806Spsmfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state)
1060158737Sambrisko{
1061159812Sps	struct mfi_command *cm = NULL;
1062158737Sambrisko	int error;
1063158737Sambrisko
1064247369Ssmh	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1065159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO,
1066159806Sps	    (void **)log_state, sizeof(**log_state));
1067159806Sps	if (error)
1068159806Sps		goto out;
1069159810Sps	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1070158737Sambrisko
1071158737Sambrisko	if ((error = mfi_mapcmd(sc, cm)) != 0) {
1072159802Sps		device_printf(sc->mfi_dev, "Failed to get log state\n");
1073159806Sps		goto out;
1074158737Sambrisko	}
1075158737Sambrisko
1076158737Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1077158737Sambrisko	    BUS_DMASYNC_POSTREAD);
1078158737Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1079158737Sambrisko
1080159806Spsout:
1081159812Sps	if (cm)
1082159812Sps		mfi_release_command(cm);
1083158737Sambrisko
1084158737Sambrisko	return (error);
1085158737Sambrisko}
1086158737Sambrisko
1087233711Sambriskoint
1088158737Sambriskomfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
1089158737Sambrisko{
1090159806Sps	struct mfi_evt_log_state *log_state = NULL;
1091158737Sambrisko	union mfi_evt class_locale;
1092158737Sambrisko	int error = 0;
1093158737Sambrisko	uint32_t seq;
1094158737Sambrisko
1095247369Ssmh	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1096247369Ssmh
1097158737Sambrisko	class_locale.members.reserved = 0;
1098162118Sambrisko	class_locale.members.locale = mfi_event_locale;
1099222589Semaste	class_locale.members.evt_class  = mfi_event_class;
1100158737Sambrisko
1101158737Sambrisko	if (seq_start == 0) {
1102247369Ssmh		if ((error = mfi_get_log_state(sc, &log_state)) != 0)
1103247369Ssmh			goto out;
1104233711Sambrisko		sc->mfi_boot_seq_num = log_state->boot_seq_num;
1105180037Sjhb
1106180037Sjhb		/*
1107180037Sjhb		 * Walk through any events that fired since the last
1108180037Sjhb		 * shutdown.
1109180037Sjhb		 */
1110247369Ssmh		if ((error = mfi_parse_entries(sc, log_state->shutdown_seq_num,
1111247369Ssmh		    log_state->newest_seq_num)) != 0)
1112247369Ssmh			goto out;
1113180037Sjhb		seq = log_state->newest_seq_num;
1114158737Sambrisko	} else
1115158737Sambrisko		seq = seq_start;
1116247369Ssmh	error = mfi_aen_register(sc, seq, class_locale.word);
1117247369Ssmhout:
1118159806Sps	free(log_state, M_MFIBUF);
1119158737Sambrisko
1120247369Ssmh	return (error);
1121158737Sambrisko}
1122158737Sambrisko
1123233711Sambriskoint
1124159811Spsmfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm)
1125159811Sps{
1126159811Sps
1127159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1128159811Sps	cm->cm_complete = NULL;
1129159811Sps
1130170284Sambrisko	/*
1131170284Sambrisko	 * MegaCli can issue a DCMD of 0.  In this case do nothing
1132170284Sambrisko	 * and return 0 to it as status
1133170284Sambrisko	 */
1134170284Sambrisko	if (cm->cm_frame->dcmd.opcode == 0) {
1135170284Sambrisko		cm->cm_frame->header.cmd_status = MFI_STAT_OK;
1136170284Sambrisko		cm->cm_error = 0;
1137170284Sambrisko		return (cm->cm_error);
1138170284Sambrisko	}
1139159811Sps	mfi_enqueue_ready(cm);
1140159811Sps	mfi_startio(sc);
1141170284Sambrisko	if ((cm->cm_flags & MFI_CMD_COMPLETED) == 0)
1142170284Sambrisko		msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0);
1143170284Sambrisko	return (cm->cm_error);
1144159811Sps}
1145159811Sps
1146157114Sscottlvoid
1147157114Sscottlmfi_free(struct mfi_softc *sc)
1148157114Sscottl{
1149157114Sscottl	struct mfi_command *cm;
1150157114Sscottl	int i;
1151157114Sscottl
1152162619Sscottl	callout_drain(&sc->mfi_watchdog_callout);
1153162619Sscottl
1154157114Sscottl	if (sc->mfi_cdev != NULL)
1155157114Sscottl		destroy_dev(sc->mfi_cdev);
1156157114Sscottl
1157247369Ssmh	if (sc->mfi_commands != NULL) {
1158247369Ssmh		for (i = 0; i < sc->mfi_max_fw_cmds; i++) {
1159157114Sscottl			cm = &sc->mfi_commands[i];
1160157114Sscottl			bus_dmamap_destroy(sc->mfi_buffer_dmat, cm->cm_dmamap);
1161157114Sscottl		}
1162157114Sscottl		free(sc->mfi_commands, M_MFIBUF);
1163247369Ssmh		sc->mfi_commands = NULL;
1164157114Sscottl	}
1165157114Sscottl
1166157114Sscottl	if (sc->mfi_intr)
1167157114Sscottl		bus_teardown_intr(sc->mfi_dev, sc->mfi_irq, sc->mfi_intr);
1168157114Sscottl	if (sc->mfi_irq != NULL)
1169157114Sscottl		bus_release_resource(sc->mfi_dev, SYS_RES_IRQ, sc->mfi_irq_rid,
1170157114Sscottl		    sc->mfi_irq);
1171157114Sscottl
1172157114Sscottl	if (sc->mfi_sense_busaddr != 0)
1173157114Sscottl		bus_dmamap_unload(sc->mfi_sense_dmat, sc->mfi_sense_dmamap);
1174157114Sscottl	if (sc->mfi_sense != NULL)
1175157114Sscottl		bus_dmamem_free(sc->mfi_sense_dmat, sc->mfi_sense,
1176157114Sscottl		    sc->mfi_sense_dmamap);
1177157114Sscottl	if (sc->mfi_sense_dmat != NULL)
1178157114Sscottl		bus_dma_tag_destroy(sc->mfi_sense_dmat);
1179157114Sscottl
1180157114Sscottl	if (sc->mfi_frames_busaddr != 0)
1181157114Sscottl		bus_dmamap_unload(sc->mfi_frames_dmat, sc->mfi_frames_dmamap);
1182157114Sscottl	if (sc->mfi_frames != NULL)
1183157114Sscottl		bus_dmamem_free(sc->mfi_frames_dmat, sc->mfi_frames,
1184157114Sscottl		    sc->mfi_frames_dmamap);
1185157114Sscottl	if (sc->mfi_frames_dmat != NULL)
1186157114Sscottl		bus_dma_tag_destroy(sc->mfi_frames_dmat);
1187157114Sscottl
1188157114Sscottl	if (sc->mfi_comms_busaddr != 0)
1189157114Sscottl		bus_dmamap_unload(sc->mfi_comms_dmat, sc->mfi_comms_dmamap);
1190157114Sscottl	if (sc->mfi_comms != NULL)
1191157114Sscottl		bus_dmamem_free(sc->mfi_comms_dmat, sc->mfi_comms,
1192157114Sscottl		    sc->mfi_comms_dmamap);
1193157114Sscottl	if (sc->mfi_comms_dmat != NULL)
1194157114Sscottl		bus_dma_tag_destroy(sc->mfi_comms_dmat);
1195157114Sscottl
1196233711Sambrisko	/* ThunderBolt contiguous memory free here */
1197233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
1198233711Sambrisko		if (sc->mfi_tb_busaddr != 0)
1199233711Sambrisko			bus_dmamap_unload(sc->mfi_tb_dmat, sc->mfi_tb_dmamap);
1200233711Sambrisko		if (sc->request_message_pool != NULL)
1201233711Sambrisko			bus_dmamem_free(sc->mfi_tb_dmat, sc->request_message_pool,
1202233711Sambrisko			    sc->mfi_tb_dmamap);
1203233711Sambrisko		if (sc->mfi_tb_dmat != NULL)
1204233711Sambrisko			bus_dma_tag_destroy(sc->mfi_tb_dmat);
1205233711Sambrisko
1206233711Sambrisko		/* Version buffer memory free */
1207233711Sambrisko		/* Start LSIP200113393 */
1208233711Sambrisko		if (sc->verbuf_h_busaddr != 0)
1209233711Sambrisko			bus_dmamap_unload(sc->verbuf_h_dmat, sc->verbuf_h_dmamap);
1210233711Sambrisko		if (sc->verbuf != NULL)
1211233711Sambrisko			bus_dmamem_free(sc->verbuf_h_dmat, sc->verbuf,
1212233711Sambrisko			    sc->verbuf_h_dmamap);
1213233711Sambrisko		if (sc->verbuf_h_dmat != NULL)
1214233711Sambrisko			bus_dma_tag_destroy(sc->verbuf_h_dmat);
1215233711Sambrisko
1216233711Sambrisko		/* End LSIP200113393 */
1217233711Sambrisko		/* ThunderBolt INIT packet memory Free */
1218233711Sambrisko		if (sc->mfi_tb_init_busaddr != 0)
1219247369Ssmh			bus_dmamap_unload(sc->mfi_tb_init_dmat,
1220247369Ssmh			    sc->mfi_tb_init_dmamap);
1221233711Sambrisko		if (sc->mfi_tb_init != NULL)
1222233711Sambrisko			bus_dmamem_free(sc->mfi_tb_init_dmat, sc->mfi_tb_init,
1223233711Sambrisko			    sc->mfi_tb_init_dmamap);
1224233711Sambrisko		if (sc->mfi_tb_init_dmat != NULL)
1225233711Sambrisko			bus_dma_tag_destroy(sc->mfi_tb_init_dmat);
1226233711Sambrisko
1227233711Sambrisko		/* ThunderBolt IOC Init Desc memory free here */
1228233711Sambrisko		if (sc->mfi_tb_ioc_init_busaddr != 0)
1229233711Sambrisko			bus_dmamap_unload(sc->mfi_tb_ioc_init_dmat,
1230233711Sambrisko			    sc->mfi_tb_ioc_init_dmamap);
1231233711Sambrisko		if (sc->mfi_tb_ioc_init_desc != NULL)
1232233711Sambrisko			bus_dmamem_free(sc->mfi_tb_ioc_init_dmat,
1233233711Sambrisko			    sc->mfi_tb_ioc_init_desc,
1234233711Sambrisko			    sc->mfi_tb_ioc_init_dmamap);
1235233711Sambrisko		if (sc->mfi_tb_ioc_init_dmat != NULL)
1236233711Sambrisko			bus_dma_tag_destroy(sc->mfi_tb_ioc_init_dmat);
1237247369Ssmh		if (sc->mfi_cmd_pool_tbolt != NULL) {
1238247369Ssmh			for (int i = 0; i < sc->mfi_max_fw_cmds; i++) {
1239233711Sambrisko				if (sc->mfi_cmd_pool_tbolt[i] != NULL) {
1240233711Sambrisko					free(sc->mfi_cmd_pool_tbolt[i],
1241233711Sambrisko					    M_MFIBUF);
1242233711Sambrisko					sc->mfi_cmd_pool_tbolt[i] = NULL;
1243233711Sambrisko				}
1244233711Sambrisko			}
1245233711Sambrisko			free(sc->mfi_cmd_pool_tbolt, M_MFIBUF);
1246233711Sambrisko			sc->mfi_cmd_pool_tbolt = NULL;
1247233711Sambrisko		}
1248233711Sambrisko		if (sc->request_desc_pool != NULL) {
1249233711Sambrisko			free(sc->request_desc_pool, M_MFIBUF);
1250233711Sambrisko			sc->request_desc_pool = NULL;
1251233711Sambrisko		}
1252233711Sambrisko	}
1253157114Sscottl	if (sc->mfi_buffer_dmat != NULL)
1254157114Sscottl		bus_dma_tag_destroy(sc->mfi_buffer_dmat);
1255157114Sscottl	if (sc->mfi_parent_dmat != NULL)
1256157114Sscottl		bus_dma_tag_destroy(sc->mfi_parent_dmat);
1257157114Sscottl
1258171821Sjhb	if (mtx_initialized(&sc->mfi_io_lock)) {
1259157114Sscottl		mtx_destroy(&sc->mfi_io_lock);
1260171821Sjhb		sx_destroy(&sc->mfi_config_lock);
1261171821Sjhb	}
1262157114Sscottl
1263157114Sscottl	return;
1264157114Sscottl}
1265157114Sscottl
1266157114Sscottlstatic void
1267157114Sscottlmfi_startup(void *arg)
1268157114Sscottl{
1269157114Sscottl	struct mfi_softc *sc;
1270157114Sscottl
1271157114Sscottl	sc = (struct mfi_softc *)arg;
1272157114Sscottl
1273157114Sscottl	config_intrhook_disestablish(&sc->mfi_ich);
1274157114Sscottl
1275171980Sscottl	sc->mfi_enable_intr(sc);
1276171821Sjhb	sx_xlock(&sc->mfi_config_lock);
1277163398Sscottl	mtx_lock(&sc->mfi_io_lock);
1278159811Sps	mfi_ldprobe(sc);
1279233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
1280233711Sambrisko	    mfi_syspdprobe(sc);
1281163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1282171821Sjhb	sx_xunlock(&sc->mfi_config_lock);
1283157114Sscottl}
1284157114Sscottl
1285157114Sscottlstatic void
1286157114Sscottlmfi_intr(void *arg)
1287157114Sscottl{
1288157114Sscottl	struct mfi_softc *sc;
1289157114Sscottl	struct mfi_command *cm;
1290171980Sscottl	uint32_t pi, ci, context;
1291157114Sscottl
1292157114Sscottl	sc = (struct mfi_softc *)arg;
1293157114Sscottl
1294171980Sscottl	if (sc->mfi_check_clear_intr(sc))
1295157114Sscottl		return;
1296163398Sscottl
1297233711Sambriskorestart:
1298157114Sscottl	pi = sc->mfi_comms->hw_pi;
1299157114Sscottl	ci = sc->mfi_comms->hw_ci;
1300157114Sscottl	mtx_lock(&sc->mfi_io_lock);
1301157114Sscottl	while (ci != pi) {
1302157114Sscottl		context = sc->mfi_comms->hw_reply_q[ci];
1303170284Sambrisko		if (context < sc->mfi_max_fw_cmds) {
1304170284Sambrisko			cm = &sc->mfi_commands[context];
1305170284Sambrisko			mfi_remove_busy(cm);
1306170284Sambrisko			cm->cm_error = 0;
1307170284Sambrisko			mfi_complete(sc, cm);
1308170284Sambrisko		}
1309247369Ssmh		if (++ci == (sc->mfi_max_fw_cmds + 1))
1310157114Sscottl			ci = 0;
1311157114Sscottl	}
1312157114Sscottl
1313157114Sscottl	sc->mfi_comms->hw_ci = ci;
1314157114Sscottl
1315163398Sscottl	/* Give defered I/O a chance to run */
1316247369Ssmh	sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
1317163398Sscottl	mfi_startio(sc);
1318163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1319163398Sscottl
1320233711Sambrisko	/*
1321233711Sambrisko	 * Dummy read to flush the bus; this ensures that the indexes are up
1322233711Sambrisko	 * to date.  Restart processing if more commands have come it.
1323233711Sambrisko	 */
1324233711Sambrisko	(void)sc->mfi_read_fw_status(sc);
1325233711Sambrisko	if (pi != sc->mfi_comms->hw_pi)
1326233711Sambrisko		goto restart;
1327233711Sambrisko
1328157114Sscottl	return;
1329157114Sscottl}
1330157114Sscottl
1331157114Sscottlint
1332157114Sscottlmfi_shutdown(struct mfi_softc *sc)
1333157114Sscottl{
1334157114Sscottl	struct mfi_dcmd_frame *dcmd;
1335157114Sscottl	struct mfi_command *cm;
1336157114Sscottl	int error;
1337157114Sscottl
1338242681Sambrisko
1339247369Ssmh	if (sc->mfi_aen_cm != NULL) {
1340242681Sambrisko		sc->cm_aen_abort = 1;
1341242681Sambrisko		mfi_abort(sc, &sc->mfi_aen_cm);
1342247369Ssmh	}
1343242681Sambrisko
1344247369Ssmh	if (sc->mfi_map_sync_cm != NULL) {
1345242681Sambrisko		sc->cm_map_abort = 1;
1346242681Sambrisko		mfi_abort(sc, &sc->mfi_map_sync_cm);
1347247369Ssmh	}
1348242681Sambrisko
1349159806Sps	mtx_lock(&sc->mfi_io_lock);
1350159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0);
1351163398Sscottl	if (error) {
1352163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
1353159806Sps		return (error);
1354163398Sscottl	}
1355157114Sscottl
1356157114Sscottl	dcmd = &cm->cm_frame->dcmd;
1357157114Sscottl	dcmd->header.flags = MFI_FRAME_DIR_NONE;
1358164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
1359164375Sscottl	cm->cm_data = NULL;
1360157114Sscottl
1361247369Ssmh	if ((error = mfi_mapcmd(sc, cm)) != 0)
1362157114Sscottl		device_printf(sc->mfi_dev, "Failed to shutdown controller\n");
1363157114Sscottl
1364159812Sps	mfi_release_command(cm);
1365163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1366157114Sscottl	return (error);
1367157114Sscottl}
1368157114Sscottl
1369157114Sscottlstatic void
1370233711Sambriskomfi_syspdprobe(struct mfi_softc *sc)
1371233711Sambrisko{
1372233711Sambrisko	struct mfi_frame_header *hdr;
1373233711Sambrisko	struct mfi_command *cm = NULL;
1374233711Sambrisko	struct mfi_pd_list *pdlist = NULL;
1375233711Sambrisko	struct mfi_system_pd *syspd, *tmp;
1376242681Sambrisko	struct mfi_system_pending *syspd_pend;
1377233711Sambrisko	int error, i, found;
1378233711Sambrisko
1379233711Sambrisko	sx_assert(&sc->mfi_config_lock, SA_XLOCKED);
1380233711Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1381233711Sambrisko	/* Add SYSTEM PD's */
1382233711Sambrisko	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_LIST_QUERY,
1383233711Sambrisko	    (void **)&pdlist, sizeof(*pdlist));
1384235016Sambrisko	if (error) {
1385233711Sambrisko		device_printf(sc->mfi_dev,
1386233711Sambrisko		    "Error while forming SYSTEM PD list\n");
1387233711Sambrisko		goto out;
1388233711Sambrisko	}
1389233711Sambrisko
1390233711Sambrisko	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1391233711Sambrisko	cm->cm_frame->dcmd.mbox[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
1392233711Sambrisko	cm->cm_frame->dcmd.mbox[1] = 0;
1393233711Sambrisko	if (mfi_mapcmd(sc, cm) != 0) {
1394233711Sambrisko		device_printf(sc->mfi_dev,
1395233711Sambrisko		    "Failed to get syspd device listing\n");
1396233711Sambrisko		goto out;
1397233711Sambrisko	}
1398233711Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat,cm->cm_dmamap,
1399233711Sambrisko	    BUS_DMASYNC_POSTREAD);
1400233711Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1401233711Sambrisko	hdr = &cm->cm_frame->header;
1402233711Sambrisko	if (hdr->cmd_status != MFI_STAT_OK) {
1403233711Sambrisko		device_printf(sc->mfi_dev,
1404233711Sambrisko		    "MFI_DCMD_PD_LIST_QUERY failed %x\n", hdr->cmd_status);
1405233711Sambrisko		goto out;
1406233711Sambrisko	}
1407233711Sambrisko	/* Get each PD and add it to the system */
1408233711Sambrisko	for (i = 0; i < pdlist->count; i++) {
1409233711Sambrisko		if (pdlist->addr[i].device_id ==
1410233711Sambrisko		    pdlist->addr[i].encl_device_id)
1411233711Sambrisko			continue;
1412233711Sambrisko		found = 0;
1413233711Sambrisko		TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) {
1414233711Sambrisko			if (syspd->pd_id == pdlist->addr[i].device_id)
1415233711Sambrisko				found = 1;
1416233711Sambrisko		}
1417242681Sambrisko		TAILQ_FOREACH(syspd_pend, &sc->mfi_syspd_pend_tqh, pd_link) {
1418242681Sambrisko			if (syspd_pend->pd_id == pdlist->addr[i].device_id)
1419242681Sambrisko				found = 1;
1420242681Sambrisko		}
1421233711Sambrisko		if (found == 0)
1422233711Sambrisko			mfi_add_sys_pd(sc, pdlist->addr[i].device_id);
1423233711Sambrisko	}
1424233711Sambrisko	/* Delete SYSPD's whose state has been changed */
1425233711Sambrisko	TAILQ_FOREACH_SAFE(syspd, &sc->mfi_syspd_tqh, pd_link, tmp) {
1426233711Sambrisko		found = 0;
1427233711Sambrisko		for (i = 0; i < pdlist->count; i++) {
1428247369Ssmh			if (syspd->pd_id == pdlist->addr[i].device_id) {
1429233711Sambrisko				found = 1;
1430247369Ssmh				break;
1431247369Ssmh			}
1432233711Sambrisko		}
1433233711Sambrisko		if (found == 0) {
1434233711Sambrisko			printf("DELETE\n");
1435233711Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1436233711Sambrisko			mtx_lock(&Giant);
1437233711Sambrisko			device_delete_child(sc->mfi_dev, syspd->pd_dev);
1438233711Sambrisko			mtx_unlock(&Giant);
1439233711Sambrisko			mtx_lock(&sc->mfi_io_lock);
1440233711Sambrisko		}
1441233711Sambrisko	}
1442233711Sambriskoout:
1443233711Sambrisko	if (pdlist)
1444233711Sambrisko	    free(pdlist, M_MFIBUF);
1445233711Sambrisko	if (cm)
1446233711Sambrisko	    mfi_release_command(cm);
1447233711Sambrisko
1448233711Sambrisko	return;
1449233711Sambrisko}
1450233711Sambrisko
1451233711Sambriskostatic void
1452159811Spsmfi_ldprobe(struct mfi_softc *sc)
1453157114Sscottl{
1454159811Sps	struct mfi_frame_header *hdr;
1455159811Sps	struct mfi_command *cm = NULL;
1456159811Sps	struct mfi_ld_list *list = NULL;
1457171821Sjhb	struct mfi_disk *ld;
1458242681Sambrisko	struct mfi_disk_pending *ld_pend;
1459159811Sps	int error, i;
1460157114Sscottl
1461171821Sjhb	sx_assert(&sc->mfi_config_lock, SA_XLOCKED);
1462163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1463163398Sscottl
1464159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
1465159811Sps	    (void **)&list, sizeof(*list));
1466159811Sps	if (error)
1467159811Sps		goto out;
1468159811Sps
1469159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
1470159811Sps	if (mfi_wait_command(sc, cm) != 0) {
1471159811Sps		device_printf(sc->mfi_dev, "Failed to get device listing\n");
1472159811Sps		goto out;
1473157114Sscottl	}
1474157114Sscottl
1475157114Sscottl	hdr = &cm->cm_frame->header;
1476159811Sps	if (hdr->cmd_status != MFI_STAT_OK) {
1477159811Sps		device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n",
1478159811Sps		    hdr->cmd_status);
1479159811Sps		goto out;
1480157114Sscottl	}
1481157114Sscottl
1482171821Sjhb	for (i = 0; i < list->ld_count; i++) {
1483171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1484171821Sjhb			if (ld->ld_id == list->ld_list[i].ld.v.target_id)
1485171821Sjhb				goto skip_add;
1486171821Sjhb		}
1487242681Sambrisko		TAILQ_FOREACH(ld_pend, &sc->mfi_ld_pend_tqh, ld_link) {
1488242681Sambrisko			if (ld_pend->ld_id == list->ld_list[i].ld.v.target_id)
1489242681Sambrisko				goto skip_add;
1490242681Sambrisko		}
1491163398Sscottl		mfi_add_ld(sc, list->ld_list[i].ld.v.target_id);
1492171821Sjhb	skip_add:;
1493171821Sjhb	}
1494159811Spsout:
1495159811Sps	if (list)
1496159811Sps		free(list, M_MFIBUF);
1497159811Sps	if (cm)
1498157114Sscottl		mfi_release_command(cm);
1499163398Sscottl
1500159811Sps	return;
1501157114Sscottl}
1502157114Sscottl
1503180038Sjhb/*
1504180038Sjhb * The timestamp is the number of seconds since 00:00 Jan 1, 2000.  If
1505180038Sjhb * the bits in 24-31 are all set, then it is the number of seconds since
1506180038Sjhb * boot.
1507180038Sjhb */
1508180038Sjhbstatic const char *
1509180038Sjhbformat_timestamp(uint32_t timestamp)
1510158737Sambrisko{
1511180038Sjhb	static char buffer[32];
1512180038Sjhb
1513180038Sjhb	if ((timestamp & 0xff000000) == 0xff000000)
1514180038Sjhb		snprintf(buffer, sizeof(buffer), "boot + %us", timestamp &
1515180038Sjhb		    0x00ffffff);
1516180038Sjhb	else
1517180038Sjhb		snprintf(buffer, sizeof(buffer), "%us", timestamp);
1518180038Sjhb	return (buffer);
1519180038Sjhb}
1520180038Sjhb
1521180038Sjhbstatic const char *
1522180038Sjhbformat_class(int8_t class)
1523180038Sjhb{
1524180038Sjhb	static char buffer[6];
1525180038Sjhb
1526180038Sjhb	switch (class) {
1527180038Sjhb	case MFI_EVT_CLASS_DEBUG:
1528180038Sjhb		return ("debug");
1529180038Sjhb	case MFI_EVT_CLASS_PROGRESS:
1530180038Sjhb		return ("progress");
1531180038Sjhb	case MFI_EVT_CLASS_INFO:
1532180038Sjhb		return ("info");
1533180038Sjhb	case MFI_EVT_CLASS_WARNING:
1534180038Sjhb		return ("WARN");
1535180038Sjhb	case MFI_EVT_CLASS_CRITICAL:
1536180038Sjhb		return ("CRIT");
1537180038Sjhb	case MFI_EVT_CLASS_FATAL:
1538180038Sjhb		return ("FATAL");
1539180038Sjhb	case MFI_EVT_CLASS_DEAD:
1540180038Sjhb		return ("DEAD");
1541158737Sambrisko	default:
1542180038Sjhb		snprintf(buffer, sizeof(buffer), "%d", class);
1543180038Sjhb		return (buffer);
1544158737Sambrisko	}
1545158737Sambrisko}
1546158737Sambrisko
1547180038Sjhbstatic void
1548180038Sjhbmfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
1549180038Sjhb{
1550233711Sambrisko	struct mfi_system_pd *syspd = NULL;
1551180038Sjhb
1552200238Sjkim	device_printf(sc->mfi_dev, "%d (%s/0x%04x/%s) - %s\n", detail->seq,
1553222589Semaste	    format_timestamp(detail->time), detail->evt_class.members.locale,
1554233711Sambrisko	    format_class(detail->evt_class.members.evt_class),
1555233711Sambrisko	    detail->description);
1556233711Sambrisko
1557233711Sambrisko        /* Don't act on old AEN's or while shutting down */
1558233711Sambrisko        if (detail->seq < sc->mfi_boot_seq_num || sc->mfi_detaching)
1559233711Sambrisko                return;
1560233711Sambrisko
1561233711Sambrisko	switch (detail->arg_type) {
1562233711Sambrisko	case MR_EVT_ARGS_NONE:
1563233711Sambrisko		if (detail->code == MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED) {
1564233711Sambrisko		    device_printf(sc->mfi_dev, "HostBus scan raised\n");
1565233711Sambrisko			if (mfi_detect_jbod_change) {
1566233711Sambrisko				/*
1567233711Sambrisko				 * Probe for new SYSPD's and Delete
1568233711Sambrisko				 * invalid SYSPD's
1569233711Sambrisko				 */
1570233711Sambrisko				sx_xlock(&sc->mfi_config_lock);
1571233711Sambrisko				mtx_lock(&sc->mfi_io_lock);
1572233711Sambrisko				mfi_syspdprobe(sc);
1573233711Sambrisko				mtx_unlock(&sc->mfi_io_lock);
1574233711Sambrisko				sx_xunlock(&sc->mfi_config_lock);
1575233711Sambrisko			}
1576233711Sambrisko		}
1577233711Sambrisko		break;
1578233711Sambrisko	case MR_EVT_ARGS_LD_STATE:
1579233711Sambrisko		/* During load time driver reads all the events starting
1580233711Sambrisko		 * from the one that has been logged after shutdown. Avoid
1581233711Sambrisko		 * these old events.
1582233711Sambrisko		 */
1583233711Sambrisko		if (detail->args.ld_state.new_state == MFI_LD_STATE_OFFLINE ) {
1584233711Sambrisko			/* Remove the LD */
1585233711Sambrisko			struct mfi_disk *ld;
1586233711Sambrisko			TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1587233711Sambrisko				if (ld->ld_id ==
1588233711Sambrisko				    detail->args.ld_state.ld.target_id)
1589233711Sambrisko					break;
1590233711Sambrisko			}
1591233711Sambrisko			/*
1592233711Sambrisko			Fix: for kernel panics when SSCD is removed
1593233711Sambrisko			KASSERT(ld != NULL, ("volume dissappeared"));
1594233711Sambrisko			*/
1595233711Sambrisko			if (ld != NULL) {
1596233711Sambrisko				mtx_lock(&Giant);
1597233711Sambrisko				device_delete_child(sc->mfi_dev, ld->ld_dev);
1598233711Sambrisko				mtx_unlock(&Giant);
1599233711Sambrisko			}
1600233711Sambrisko		}
1601233711Sambrisko		break;
1602233711Sambrisko	case MR_EVT_ARGS_PD:
1603233711Sambrisko		if (detail->code == MR_EVT_PD_REMOVED) {
1604233711Sambrisko			if (mfi_detect_jbod_change) {
1605233711Sambrisko				/*
1606233711Sambrisko				 * If the removed device is a SYSPD then
1607233711Sambrisko				 * delete it
1608233711Sambrisko				 */
1609233711Sambrisko				TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,
1610233711Sambrisko				    pd_link) {
1611233711Sambrisko					if (syspd->pd_id ==
1612233711Sambrisko					    detail->args.pd.device_id) {
1613233711Sambrisko						mtx_lock(&Giant);
1614233711Sambrisko						device_delete_child(
1615233711Sambrisko						    sc->mfi_dev,
1616233711Sambrisko						    syspd->pd_dev);
1617233711Sambrisko						mtx_unlock(&Giant);
1618233711Sambrisko						break;
1619233711Sambrisko					}
1620233711Sambrisko				}
1621233711Sambrisko			}
1622233711Sambrisko		}
1623233711Sambrisko		if (detail->code == MR_EVT_PD_INSERTED) {
1624233711Sambrisko			if (mfi_detect_jbod_change) {
1625233711Sambrisko				/* Probe for new SYSPD's */
1626233711Sambrisko				sx_xlock(&sc->mfi_config_lock);
1627233711Sambrisko				mtx_lock(&sc->mfi_io_lock);
1628233711Sambrisko				mfi_syspdprobe(sc);
1629233711Sambrisko				mtx_unlock(&sc->mfi_io_lock);
1630233711Sambrisko				sx_xunlock(&sc->mfi_config_lock);
1631233711Sambrisko			}
1632233711Sambrisko		}
1633242726Sambrisko		if (sc->mfi_cam_rescan_cb != NULL &&
1634242726Sambrisko		    (detail->code == MR_EVT_PD_INSERTED ||
1635242726Sambrisko		    detail->code == MR_EVT_PD_REMOVED)) {
1636242726Sambrisko			sc->mfi_cam_rescan_cb(sc, detail->args.pd.device_id);
1637242726Sambrisko		}
1638233711Sambrisko		break;
1639233711Sambrisko	}
1640180038Sjhb}
1641180038Sjhb
1642233711Sambriskostatic void
1643233711Sambriskomfi_queue_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
1644233711Sambrisko{
1645233711Sambrisko	struct mfi_evt_queue_elm *elm;
1646233711Sambrisko
1647233711Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1648233711Sambrisko	elm = malloc(sizeof(*elm), M_MFIBUF, M_NOWAIT|M_ZERO);
1649233711Sambrisko	if (elm == NULL)
1650233711Sambrisko		return;
1651233711Sambrisko	memcpy(&elm->detail, detail, sizeof(*detail));
1652233711Sambrisko	TAILQ_INSERT_TAIL(&sc->mfi_evt_queue, elm, link);
1653233711Sambrisko	taskqueue_enqueue(taskqueue_swi, &sc->mfi_evt_task);
1654233711Sambrisko}
1655233711Sambrisko
1656233711Sambriskostatic void
1657233711Sambriskomfi_handle_evt(void *context, int pending)
1658233711Sambrisko{
1659233711Sambrisko	TAILQ_HEAD(,mfi_evt_queue_elm) queue;
1660233711Sambrisko	struct mfi_softc *sc;
1661233711Sambrisko	struct mfi_evt_queue_elm *elm;
1662233711Sambrisko
1663233711Sambrisko	sc = context;
1664233711Sambrisko	TAILQ_INIT(&queue);
1665233711Sambrisko	mtx_lock(&sc->mfi_io_lock);
1666233711Sambrisko	TAILQ_CONCAT(&queue, &sc->mfi_evt_queue, link);
1667233711Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1668233711Sambrisko	while ((elm = TAILQ_FIRST(&queue)) != NULL) {
1669233711Sambrisko		TAILQ_REMOVE(&queue, elm, link);
1670233711Sambrisko		mfi_decode_evt(sc, &elm->detail);
1671233711Sambrisko		free(elm, M_MFIBUF);
1672233711Sambrisko	}
1673233711Sambrisko}
1674233711Sambrisko
1675157114Sscottlstatic int
1676158737Sambriskomfi_aen_register(struct mfi_softc *sc, int seq, int locale)
1677158737Sambrisko{
1678158737Sambrisko	struct mfi_command *cm;
1679158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1680158737Sambrisko	union mfi_evt current_aen, prior_aen;
1681159806Sps	struct mfi_evt_detail *ed = NULL;
1682163398Sscottl	int error = 0;
1683158737Sambrisko
1684247369Ssmh	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1685247369Ssmh
1686158737Sambrisko	current_aen.word = locale;
1687158737Sambrisko	if (sc->mfi_aen_cm != NULL) {
1688158737Sambrisko		prior_aen.word =
1689158737Sambrisko		    ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1];
1690222589Semaste		if (prior_aen.members.evt_class <= current_aen.members.evt_class &&
1691158737Sambrisko		    !((prior_aen.members.locale & current_aen.members.locale)
1692158737Sambrisko		    ^current_aen.members.locale)) {
1693158737Sambrisko			return (0);
1694158737Sambrisko		} else {
1695158737Sambrisko			prior_aen.members.locale |= current_aen.members.locale;
1696222589Semaste			if (prior_aen.members.evt_class
1697222589Semaste			    < current_aen.members.evt_class)
1698222589Semaste				current_aen.members.evt_class =
1699222589Semaste				    prior_aen.members.evt_class;
1700242681Sambrisko			mfi_abort(sc, &sc->mfi_aen_cm);
1701158737Sambrisko		}
1702158737Sambrisko	}
1703158737Sambrisko
1704159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT,
1705159806Sps	    (void **)&ed, sizeof(*ed));
1706247369Ssmh	if (error)
1707163398Sscottl		goto out;
1708158737Sambrisko
1709158737Sambrisko	dcmd = &cm->cm_frame->dcmd;
1710158737Sambrisko	((uint32_t *)&dcmd->mbox)[0] = seq;
1711158737Sambrisko	((uint32_t *)&dcmd->mbox)[1] = locale;
1712158737Sambrisko	cm->cm_flags = MFI_CMD_DATAIN;
1713158737Sambrisko	cm->cm_complete = mfi_aen_complete;
1714158737Sambrisko
1715233711Sambrisko	sc->last_seq_num = seq;
1716158737Sambrisko	sc->mfi_aen_cm = cm;
1717158737Sambrisko
1718158737Sambrisko	mfi_enqueue_ready(cm);
1719158737Sambrisko	mfi_startio(sc);
1720158737Sambrisko
1721163398Sscottlout:
1722163398Sscottl	return (error);
1723158737Sambrisko}
1724158737Sambrisko
1725158737Sambriskostatic void
1726158737Sambriskomfi_aen_complete(struct mfi_command *cm)
1727158737Sambrisko{
1728158737Sambrisko	struct mfi_frame_header *hdr;
1729158737Sambrisko	struct mfi_softc *sc;
1730158737Sambrisko	struct mfi_evt_detail *detail;
1731163398Sscottl	struct mfi_aen *mfi_aen_entry, *tmp;
1732158737Sambrisko	int seq = 0, aborted = 0;
1733158737Sambrisko
1734158737Sambrisko	sc = cm->cm_sc;
1735233711Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1736233711Sambrisko
1737158737Sambrisko	if (sc->mfi_aen_cm == NULL)
1738158737Sambrisko		return;
1739158737Sambrisko
1740247369Ssmh	hdr = &cm->cm_frame->header;
1741247369Ssmh
1742235014Sambrisko	if (sc->cm_aen_abort ||
1743224039Sjhb	    hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
1744235014Sambrisko		sc->cm_aen_abort = 0;
1745158737Sambrisko		aborted = 1;
1746158737Sambrisko	} else {
1747158737Sambrisko		sc->mfi_aen_triggered = 1;
1748163398Sscottl		if (sc->mfi_poll_waiting) {
1749163398Sscottl			sc->mfi_poll_waiting = 0;
1750158737Sambrisko			selwakeup(&sc->mfi_select);
1751163398Sscottl		}
1752158737Sambrisko		detail = cm->cm_data;
1753233711Sambrisko		mfi_queue_evt(sc, detail);
1754158737Sambrisko		seq = detail->seq + 1;
1755233711Sambrisko		TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link,
1756233711Sambrisko		    tmp) {
1757158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
1758158737Sambrisko			    aen_link);
1759163398Sscottl			PROC_LOCK(mfi_aen_entry->p);
1760225617Skmacy			kern_psignal(mfi_aen_entry->p, SIGIO);
1761163398Sscottl			PROC_UNLOCK(mfi_aen_entry->p);
1762158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
1763158737Sambrisko		}
1764158737Sambrisko	}
1765158737Sambrisko
1766158737Sambrisko	free(cm->cm_data, M_MFIBUF);
1767247369Ssmh	wakeup(&sc->mfi_aen_cm);
1768158737Sambrisko	sc->mfi_aen_cm = NULL;
1769158737Sambrisko	mfi_release_command(cm);
1770158737Sambrisko
1771158737Sambrisko	/* set it up again so the driver can catch more events */
1772247369Ssmh	if (!aborted)
1773158737Sambrisko		mfi_aen_setup(sc, seq);
1774158737Sambrisko}
1775158737Sambrisko
1776180037Sjhb#define MAX_EVENTS 15
1777180037Sjhb
1778158737Sambriskostatic int
1779180037Sjhbmfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq)
1780158737Sambrisko{
1781158737Sambrisko	struct mfi_command *cm;
1782158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1783162118Sambrisko	struct mfi_evt_list *el;
1784180037Sjhb	union mfi_evt class_locale;
1785180037Sjhb	int error, i, seq, size;
1786158737Sambrisko
1787247369Ssmh	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1788247369Ssmh
1789180037Sjhb	class_locale.members.reserved = 0;
1790180037Sjhb	class_locale.members.locale = mfi_event_locale;
1791222589Semaste	class_locale.members.evt_class  = mfi_event_class;
1792158737Sambrisko
1793162118Sambrisko	size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail)
1794162118Sambrisko		* (MAX_EVENTS - 1);
1795162118Sambrisko	el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO);
1796180037Sjhb	if (el == NULL)
1797158737Sambrisko		return (ENOMEM);
1798158737Sambrisko
1799180037Sjhb	for (seq = start_seq;;) {
1800180037Sjhb		if ((cm = mfi_dequeue_free(sc)) == NULL) {
1801180037Sjhb			free(el, M_MFIBUF);
1802180037Sjhb			return (EBUSY);
1803180037Sjhb		}
1804158737Sambrisko
1805180037Sjhb		dcmd = &cm->cm_frame->dcmd;
1806180037Sjhb		bzero(dcmd->mbox, MFI_MBOX_SIZE);
1807180037Sjhb		dcmd->header.cmd = MFI_CMD_DCMD;
1808180037Sjhb		dcmd->header.timeout = 0;
1809180037Sjhb		dcmd->header.data_len = size;
1810180037Sjhb		dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET;
1811180037Sjhb		((uint32_t *)&dcmd->mbox)[0] = seq;
1812180037Sjhb		((uint32_t *)&dcmd->mbox)[1] = class_locale.word;
1813180037Sjhb		cm->cm_sg = &dcmd->sgl;
1814180037Sjhb		cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
1815180037Sjhb		cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1816180037Sjhb		cm->cm_data = el;
1817180037Sjhb		cm->cm_len = size;
1818180037Sjhb
1819180037Sjhb		if ((error = mfi_mapcmd(sc, cm)) != 0) {
1820180037Sjhb			device_printf(sc->mfi_dev,
1821180037Sjhb			    "Failed to get controller entries\n");
1822180037Sjhb			mfi_release_command(cm);
1823180037Sjhb			break;
1824180037Sjhb		}
1825180037Sjhb
1826180037Sjhb		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1827180037Sjhb		    BUS_DMASYNC_POSTREAD);
1828180037Sjhb		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1829180037Sjhb
1830180037Sjhb		if (dcmd->header.cmd_status == MFI_STAT_NOT_FOUND) {
1831180037Sjhb			mfi_release_command(cm);
1832180037Sjhb			break;
1833180037Sjhb		}
1834180037Sjhb		if (dcmd->header.cmd_status != MFI_STAT_OK) {
1835180037Sjhb			device_printf(sc->mfi_dev,
1836180037Sjhb			    "Error %d fetching controller entries\n",
1837180037Sjhb			    dcmd->header.cmd_status);
1838180037Sjhb			mfi_release_command(cm);
1839247369Ssmh			error = EIO;
1840180037Sjhb			break;
1841180037Sjhb		}
1842158737Sambrisko		mfi_release_command(cm);
1843158737Sambrisko
1844162473Sambrisko		for (i = 0; i < el->count; i++) {
1845180037Sjhb			/*
1846180037Sjhb			 * If this event is newer than 'stop_seq' then
1847180037Sjhb			 * break out of the loop.  Note that the log
1848180037Sjhb			 * is a circular buffer so we have to handle
1849180037Sjhb			 * the case that our stop point is earlier in
1850180037Sjhb			 * the buffer than our start point.
1851180037Sjhb			 */
1852180037Sjhb			if (el->event[i].seq >= stop_seq) {
1853180037Sjhb				if (start_seq <= stop_seq)
1854180037Sjhb					break;
1855180037Sjhb				else if (el->event[i].seq < start_seq)
1856180037Sjhb					break;
1857180037Sjhb			}
1858233711Sambrisko			mfi_queue_evt(sc, &el->event[i]);
1859162473Sambrisko		}
1860180037Sjhb		seq = el->event[el->count - 1].seq + 1;
1861162118Sambrisko	}
1862158737Sambrisko
1863180037Sjhb	free(el, M_MFIBUF);
1864247369Ssmh	return (error);
1865158737Sambrisko}
1866158737Sambrisko
1867158737Sambriskostatic int
1868159811Spsmfi_add_ld(struct mfi_softc *sc, int id)
1869157114Sscottl{
1870157114Sscottl	struct mfi_command *cm;
1871159811Sps	struct mfi_dcmd_frame *dcmd = NULL;
1872159811Sps	struct mfi_ld_info *ld_info = NULL;
1873242681Sambrisko	struct mfi_disk_pending *ld_pend;
1874159811Sps	int error;
1875157114Sscottl
1876159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1877159811Sps
1878242681Sambrisko	ld_pend = malloc(sizeof(*ld_pend), M_MFIBUF, M_NOWAIT | M_ZERO);
1879242681Sambrisko	if (ld_pend != NULL) {
1880242681Sambrisko		ld_pend->ld_id = id;
1881242681Sambrisko		TAILQ_INSERT_TAIL(&sc->mfi_ld_pend_tqh, ld_pend, ld_link);
1882242681Sambrisko	}
1883242681Sambrisko
1884159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO,
1885159811Sps	    (void **)&ld_info, sizeof(*ld_info));
1886159811Sps	if (error) {
1887159811Sps		device_printf(sc->mfi_dev,
1888159811Sps		    "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error);
1889159811Sps		if (ld_info)
1890159811Sps			free(ld_info, M_MFIBUF);
1891159811Sps		return (error);
1892157624Sscottl	}
1893159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
1894159811Sps	dcmd = &cm->cm_frame->dcmd;
1895159811Sps	dcmd->mbox[0] = id;
1896160052Sambrisko	if (mfi_wait_command(sc, cm) != 0) {
1897160052Sambrisko		device_printf(sc->mfi_dev,
1898160052Sambrisko		    "Failed to get logical drive: %d\n", id);
1899160052Sambrisko		free(ld_info, M_MFIBUF);
1900160052Sambrisko		return (0);
1901160052Sambrisko	}
1902233711Sambrisko	if (ld_info->ld_config.params.isSSCD != 1)
1903233711Sambrisko		mfi_add_ld_complete(cm);
1904233711Sambrisko	else {
1905233711Sambrisko		mfi_release_command(cm);
1906233711Sambrisko		if (ld_info)		/* SSCD drives ld_info free here */
1907233711Sambrisko			free(ld_info, M_MFIBUF);
1908233711Sambrisko	}
1909157114Sscottl	return (0);
1910157114Sscottl}
1911157114Sscottl
1912157114Sscottlstatic void
1913159811Spsmfi_add_ld_complete(struct mfi_command *cm)
1914157114Sscottl{
1915157114Sscottl	struct mfi_frame_header *hdr;
1916159811Sps	struct mfi_ld_info *ld_info;
1917157114Sscottl	struct mfi_softc *sc;
1918159811Sps	device_t child;
1919157114Sscottl
1920157114Sscottl	sc = cm->cm_sc;
1921157114Sscottl	hdr = &cm->cm_frame->header;
1922159811Sps	ld_info = cm->cm_private;
1923157114Sscottl
1924242681Sambrisko	if (sc->cm_map_abort || hdr->cmd_status != MFI_STAT_OK) {
1925159811Sps		free(ld_info, M_MFIBUF);
1926242681Sambrisko		wakeup(&sc->mfi_map_sync_cm);
1927157114Sscottl		mfi_release_command(cm);
1928157114Sscottl		return;
1929157114Sscottl	}
1930242681Sambrisko	wakeup(&sc->mfi_map_sync_cm);
1931157114Sscottl	mfi_release_command(cm);
1932157114Sscottl
1933169611Sscottl	mtx_unlock(&sc->mfi_io_lock);
1934196403Sjhb	mtx_lock(&Giant);
1935157114Sscottl	if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) {
1936157114Sscottl		device_printf(sc->mfi_dev, "Failed to add logical disk\n");
1937159811Sps		free(ld_info, M_MFIBUF);
1938196403Sjhb		mtx_unlock(&Giant);
1939169611Sscottl		mtx_lock(&sc->mfi_io_lock);
1940159811Sps		return;
1941157114Sscottl	}
1942157114Sscottl
1943169451Sscottl	device_set_ivars(child, ld_info);
1944157114Sscottl	device_set_desc(child, "MFI Logical Disk");
1945157114Sscottl	bus_generic_attach(sc->mfi_dev);
1946196403Sjhb	mtx_unlock(&Giant);
1947157114Sscottl	mtx_lock(&sc->mfi_io_lock);
1948157114Sscottl}
1949163399Sscottl
1950233711Sambriskostatic int mfi_add_sys_pd(struct mfi_softc *sc, int id)
1951233711Sambrisko{
1952233711Sambrisko	struct mfi_command *cm;
1953233711Sambrisko	struct mfi_dcmd_frame *dcmd = NULL;
1954233711Sambrisko	struct mfi_pd_info *pd_info = NULL;
1955242681Sambrisko	struct mfi_system_pending *syspd_pend;
1956233711Sambrisko	int error;
1957233711Sambrisko
1958233711Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1959233711Sambrisko
1960242681Sambrisko	syspd_pend = malloc(sizeof(*syspd_pend), M_MFIBUF, M_NOWAIT | M_ZERO);
1961242681Sambrisko	if (syspd_pend != NULL) {
1962242681Sambrisko		syspd_pend->pd_id = id;
1963242681Sambrisko		TAILQ_INSERT_TAIL(&sc->mfi_syspd_pend_tqh, syspd_pend, pd_link);
1964242681Sambrisko	}
1965242681Sambrisko
1966233711Sambrisko	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_GET_INFO,
1967233711Sambrisko		(void **)&pd_info, sizeof(*pd_info));
1968233711Sambrisko	if (error) {
1969233711Sambrisko		device_printf(sc->mfi_dev,
1970233711Sambrisko		    "Failed to allocated for MFI_DCMD_PD_GET_INFO %d\n",
1971233711Sambrisko		    error);
1972233711Sambrisko		if (pd_info)
1973233711Sambrisko			free(pd_info, M_MFIBUF);
1974233711Sambrisko		return (error);
1975233711Sambrisko	}
1976233711Sambrisko	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1977233711Sambrisko	dcmd = &cm->cm_frame->dcmd;
1978233711Sambrisko	dcmd->mbox[0]=id;
1979233711Sambrisko	dcmd->header.scsi_status = 0;
1980233711Sambrisko	dcmd->header.pad0 = 0;
1981247369Ssmh	if ((error = mfi_mapcmd(sc, cm)) != 0) {
1982233711Sambrisko		device_printf(sc->mfi_dev,
1983233711Sambrisko		    "Failed to get physical drive info %d\n", id);
1984233711Sambrisko		free(pd_info, M_MFIBUF);
1985247369Ssmh		mfi_release_command(cm);
1986247369Ssmh		return (error);
1987233711Sambrisko	}
1988233711Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1989233711Sambrisko	    BUS_DMASYNC_POSTREAD);
1990233711Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1991233711Sambrisko	mfi_add_sys_pd_complete(cm);
1992233711Sambrisko	return (0);
1993233711Sambrisko}
1994233711Sambrisko
1995233711Sambriskostatic void
1996233711Sambriskomfi_add_sys_pd_complete(struct mfi_command *cm)
1997233711Sambrisko{
1998233711Sambrisko	struct mfi_frame_header *hdr;
1999233711Sambrisko	struct mfi_pd_info *pd_info;
2000233711Sambrisko	struct mfi_softc *sc;
2001233711Sambrisko	device_t child;
2002233711Sambrisko
2003233711Sambrisko	sc = cm->cm_sc;
2004233711Sambrisko	hdr = &cm->cm_frame->header;
2005233711Sambrisko	pd_info = cm->cm_private;
2006233711Sambrisko
2007233711Sambrisko	if (hdr->cmd_status != MFI_STAT_OK) {
2008233711Sambrisko		free(pd_info, M_MFIBUF);
2009233711Sambrisko		mfi_release_command(cm);
2010233711Sambrisko		return;
2011233711Sambrisko	}
2012233711Sambrisko	if (pd_info->fw_state != MFI_PD_STATE_SYSTEM) {
2013233711Sambrisko		device_printf(sc->mfi_dev, "PD=%x is not SYSTEM PD\n",
2014233711Sambrisko		    pd_info->ref.v.device_id);
2015233711Sambrisko		free(pd_info, M_MFIBUF);
2016233711Sambrisko		mfi_release_command(cm);
2017233711Sambrisko		return;
2018233711Sambrisko	}
2019233711Sambrisko	mfi_release_command(cm);
2020233711Sambrisko
2021233711Sambrisko	mtx_unlock(&sc->mfi_io_lock);
2022233711Sambrisko	mtx_lock(&Giant);
2023233711Sambrisko	if ((child = device_add_child(sc->mfi_dev, "mfisyspd", -1)) == NULL) {
2024233711Sambrisko		device_printf(sc->mfi_dev, "Failed to add system pd\n");
2025233711Sambrisko		free(pd_info, M_MFIBUF);
2026233711Sambrisko		mtx_unlock(&Giant);
2027233711Sambrisko		mtx_lock(&sc->mfi_io_lock);
2028233711Sambrisko		return;
2029233711Sambrisko	}
2030233711Sambrisko
2031233711Sambrisko	device_set_ivars(child, pd_info);
2032233711Sambrisko	device_set_desc(child, "MFI System PD");
2033233711Sambrisko	bus_generic_attach(sc->mfi_dev);
2034233711Sambrisko	mtx_unlock(&Giant);
2035233711Sambrisko	mtx_lock(&sc->mfi_io_lock);
2036233711Sambrisko}
2037235016Sambrisko
2038157114Sscottlstatic struct mfi_command *
2039157114Sscottlmfi_bio_command(struct mfi_softc *sc)
2040157114Sscottl{
2041157114Sscottl	struct bio *bio;
2042233711Sambrisko	struct mfi_command *cm = NULL;
2043157114Sscottl
2044233711Sambrisko	/*reserving two commands to avoid starvation for IOCTL*/
2045235016Sambrisko	if (sc->mfi_qstat[MFIQ_FREE].q_length < 2) {
2046157114Sscottl		return (NULL);
2047233711Sambrisko	}
2048157114Sscottl	if ((bio = mfi_dequeue_bio(sc)) == NULL) {
2049157114Sscottl		return (NULL);
2050157114Sscottl	}
2051233711Sambrisko	if ((uintptr_t)bio->bio_driver2 == MFI_LD_IO) {
2052233711Sambrisko		cm = mfi_build_ldio(sc, bio);
2053233711Sambrisko	} else if ((uintptr_t) bio->bio_driver2 == MFI_SYS_PD_IO) {
2054233711Sambrisko		cm = mfi_build_syspdio(sc, bio);
2055233711Sambrisko	}
2056233711Sambrisko	if (!cm)
2057233711Sambrisko	    mfi_enqueue_bio(sc, bio);
2058233711Sambrisko	return cm;
2059233711Sambrisko}
2060242497Sdelphij
2061242681Sambrisko/*
2062242681Sambrisko * mostly copied from cam/scsi/scsi_all.c:scsi_read_write
2063242681Sambrisko */
2064242681Sambrisko
2065242681Sambriskoint
2066242681Sambriskomfi_build_cdb(int readop, uint8_t byte2, u_int64_t lba, u_int32_t block_count, uint8_t *cdb)
2067242497Sdelphij{
2068242497Sdelphij	int cdb_len;
2069242497Sdelphij
2070242497Sdelphij	if (((lba & 0x1fffff) == lba)
2071242497Sdelphij         && ((block_count & 0xff) == block_count)
2072242497Sdelphij         && (byte2 == 0)) {
2073242497Sdelphij		/* We can fit in a 6 byte cdb */
2074242497Sdelphij		struct scsi_rw_6 *scsi_cmd;
2075242497Sdelphij
2076242681Sambrisko		scsi_cmd = (struct scsi_rw_6 *)cdb;
2077242497Sdelphij		scsi_cmd->opcode = readop ? READ_6 : WRITE_6;
2078242497Sdelphij		scsi_ulto3b(lba, scsi_cmd->addr);
2079242497Sdelphij		scsi_cmd->length = block_count & 0xff;
2080242497Sdelphij		scsi_cmd->control = 0;
2081242497Sdelphij		cdb_len = sizeof(*scsi_cmd);
2082242497Sdelphij	} else if (((block_count & 0xffff) == block_count) && ((lba & 0xffffffff) == lba)) {
2083242497Sdelphij		/* Need a 10 byte CDB */
2084242497Sdelphij		struct scsi_rw_10 *scsi_cmd;
2085242497Sdelphij
2086242681Sambrisko		scsi_cmd = (struct scsi_rw_10 *)cdb;
2087242497Sdelphij		scsi_cmd->opcode = readop ? READ_10 : WRITE_10;
2088242497Sdelphij		scsi_cmd->byte2 = byte2;
2089242497Sdelphij		scsi_ulto4b(lba, scsi_cmd->addr);
2090242497Sdelphij		scsi_cmd->reserved = 0;
2091242497Sdelphij		scsi_ulto2b(block_count, scsi_cmd->length);
2092242497Sdelphij		scsi_cmd->control = 0;
2093242497Sdelphij		cdb_len = sizeof(*scsi_cmd);
2094242497Sdelphij	} else if (((block_count & 0xffffffff) == block_count) &&
2095242497Sdelphij	    ((lba & 0xffffffff) == lba)) {
2096242497Sdelphij		/* Block count is too big for 10 byte CDB use a 12 byte CDB */
2097242497Sdelphij		struct scsi_rw_12 *scsi_cmd;
2098242497Sdelphij
2099242681Sambrisko		scsi_cmd = (struct scsi_rw_12 *)cdb;
2100242497Sdelphij		scsi_cmd->opcode = readop ? READ_12 : WRITE_12;
2101242497Sdelphij		scsi_cmd->byte2 = byte2;
2102242497Sdelphij		scsi_ulto4b(lba, scsi_cmd->addr);
2103242497Sdelphij		scsi_cmd->reserved = 0;
2104242497Sdelphij		scsi_ulto4b(block_count, scsi_cmd->length);
2105242497Sdelphij		scsi_cmd->control = 0;
2106242497Sdelphij		cdb_len = sizeof(*scsi_cmd);
2107242497Sdelphij	} else {
2108242497Sdelphij		/*
2109242497Sdelphij		 * 16 byte CDB.  We'll only get here if the LBA is larger
2110242497Sdelphij		 * than 2^32
2111242497Sdelphij		 */
2112242497Sdelphij		struct scsi_rw_16 *scsi_cmd;
2113242497Sdelphij
2114242681Sambrisko		scsi_cmd = (struct scsi_rw_16 *)cdb;
2115242497Sdelphij		scsi_cmd->opcode = readop ? READ_16 : WRITE_16;
2116242497Sdelphij		scsi_cmd->byte2 = byte2;
2117242497Sdelphij		scsi_u64to8b(lba, scsi_cmd->addr);
2118242497Sdelphij		scsi_cmd->reserved = 0;
2119242497Sdelphij		scsi_ulto4b(block_count, scsi_cmd->length);
2120242497Sdelphij		scsi_cmd->control = 0;
2121242497Sdelphij		cdb_len = sizeof(*scsi_cmd);
2122242497Sdelphij	}
2123242497Sdelphij
2124242497Sdelphij	return cdb_len;
2125242497Sdelphij}
2126242497Sdelphij
2127267084Skibextern char *unmapped_buf;
2128267084Skib
2129233711Sambriskostatic struct mfi_command *
2130233711Sambriskomfi_build_syspdio(struct mfi_softc *sc, struct bio *bio)
2131233711Sambrisko{
2132233711Sambrisko	struct mfi_command *cm;
2133233711Sambrisko	struct mfi_pass_frame *pass;
2134242681Sambrisko	uint32_t context = 0;
2135242681Sambrisko	int flags = 0, blkcount = 0, readop;
2136242497Sdelphij	uint8_t cdb_len;
2137157114Sscottl
2138247369Ssmh	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2139247369Ssmh
2140233711Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL)
2141233711Sambrisko	    return (NULL);
2142233711Sambrisko
2143233711Sambrisko	/* Zero out the MFI frame */
2144242681Sambrisko	context = cm->cm_frame->header.context;
2145233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
2146233711Sambrisko	cm->cm_frame->header.context = context;
2147233711Sambrisko	pass = &cm->cm_frame->pass;
2148233711Sambrisko	bzero(pass->cdb, 16);
2149233711Sambrisko	pass->header.cmd = MFI_CMD_PD_SCSI_IO;
2150233711Sambrisko	switch (bio->bio_cmd & 0x03) {
2151233711Sambrisko	case BIO_READ:
2152267084Skib		flags = MFI_CMD_DATAIN | MFI_CMD_BIO;
2153242681Sambrisko		readop = 1;
2154233711Sambrisko		break;
2155233711Sambrisko	case BIO_WRITE:
2156267084Skib		flags = MFI_CMD_DATAOUT | MFI_CMD_BIO;
2157242681Sambrisko		readop = 0;
2158233711Sambrisko		break;
2159233711Sambrisko	default:
2160242497Sdelphij		/* TODO: what about BIO_DELETE??? */
2161242681Sambrisko		panic("Unsupported bio command %x\n", bio->bio_cmd);
2162233711Sambrisko	}
2163233711Sambrisko
2164233711Sambrisko	/* Cheat with the sector length to avoid a non-constant division */
2165242681Sambrisko	blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2166233711Sambrisko	/* Fill the LBA and Transfer length in CDB */
2167242681Sambrisko	cdb_len = mfi_build_cdb(readop, 0, bio->bio_pblkno, blkcount,
2168242681Sambrisko	    pass->cdb);
2169233711Sambrisko	pass->header.target_id = (uintptr_t)bio->bio_driver1;
2170242681Sambrisko	pass->header.lun_id = 0;
2171233711Sambrisko	pass->header.timeout = 0;
2172233711Sambrisko	pass->header.flags = 0;
2173233711Sambrisko	pass->header.scsi_status = 0;
2174233711Sambrisko	pass->header.sense_len = MFI_SENSE_LEN;
2175233711Sambrisko	pass->header.data_len = bio->bio_bcount;
2176242497Sdelphij	pass->header.cdb_len = cdb_len;
2177233711Sambrisko	pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2178233711Sambrisko	pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2179233711Sambrisko	cm->cm_complete = mfi_bio_complete;
2180233711Sambrisko	cm->cm_private = bio;
2181267084Skib	cm->cm_data = unmapped_buf;
2182233711Sambrisko	cm->cm_len = bio->bio_bcount;
2183233711Sambrisko	cm->cm_sg = &pass->sgl;
2184233711Sambrisko	cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
2185233711Sambrisko	cm->cm_flags = flags;
2186247369Ssmh
2187233711Sambrisko	return (cm);
2188233711Sambrisko}
2189233711Sambrisko
2190233711Sambriskostatic struct mfi_command *
2191233711Sambriskomfi_build_ldio(struct mfi_softc *sc, struct bio *bio)
2192233711Sambrisko{
2193233711Sambrisko	struct mfi_io_frame *io;
2194233711Sambrisko	struct mfi_command *cm;
2195242497Sdelphij	int flags;
2196242497Sdelphij	uint32_t blkcount;
2197233711Sambrisko	uint32_t context = 0;
2198233711Sambrisko
2199247369Ssmh	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2200247369Ssmh
2201233711Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL)
2202233711Sambrisko	    return (NULL);
2203233711Sambrisko
2204233711Sambrisko	/* Zero out the MFI frame */
2205233711Sambrisko	context = cm->cm_frame->header.context;
2206233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
2207233711Sambrisko	cm->cm_frame->header.context = context;
2208157114Sscottl	io = &cm->cm_frame->io;
2209157114Sscottl	switch (bio->bio_cmd & 0x03) {
2210157114Sscottl	case BIO_READ:
2211157114Sscottl		io->header.cmd = MFI_CMD_LD_READ;
2212267084Skib		flags = MFI_CMD_DATAIN | MFI_CMD_BIO;
2213157114Sscottl		break;
2214157114Sscottl	case BIO_WRITE:
2215157114Sscottl		io->header.cmd = MFI_CMD_LD_WRITE;
2216267084Skib		flags = MFI_CMD_DATAOUT | MFI_CMD_BIO;
2217157114Sscottl		break;
2218157114Sscottl	default:
2219242497Sdelphij		/* TODO: what about BIO_DELETE??? */
2220242681Sambrisko		panic("Unsupported bio command %x\n", bio->bio_cmd);
2221157114Sscottl	}
2222157114Sscottl
2223157114Sscottl	/* Cheat with the sector length to avoid a non-constant division */
2224157114Sscottl	blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2225157114Sscottl	io->header.target_id = (uintptr_t)bio->bio_driver1;
2226157114Sscottl	io->header.timeout = 0;
2227157114Sscottl	io->header.flags = 0;
2228233711Sambrisko	io->header.scsi_status = 0;
2229157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
2230157114Sscottl	io->header.data_len = blkcount;
2231233711Sambrisko	io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2232233711Sambrisko	io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2233157114Sscottl	io->lba_hi = (bio->bio_pblkno & 0xffffffff00000000) >> 32;
2234157114Sscottl	io->lba_lo = bio->bio_pblkno & 0xffffffff;
2235157114Sscottl	cm->cm_complete = mfi_bio_complete;
2236157114Sscottl	cm->cm_private = bio;
2237267084Skib	cm->cm_data = unmapped_buf;
2238157114Sscottl	cm->cm_len = bio->bio_bcount;
2239157114Sscottl	cm->cm_sg = &io->sgl;
2240157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
2241157114Sscottl	cm->cm_flags = flags;
2242247369Ssmh
2243157114Sscottl	return (cm);
2244157114Sscottl}
2245157114Sscottl
2246157114Sscottlstatic void
2247157114Sscottlmfi_bio_complete(struct mfi_command *cm)
2248157114Sscottl{
2249157114Sscottl	struct bio *bio;
2250157114Sscottl	struct mfi_frame_header *hdr;
2251157114Sscottl	struct mfi_softc *sc;
2252157114Sscottl
2253157114Sscottl	bio = cm->cm_private;
2254157114Sscottl	hdr = &cm->cm_frame->header;
2255157114Sscottl	sc = cm->cm_sc;
2256157114Sscottl
2257224039Sjhb	if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0)) {
2258157114Sscottl		bio->bio_flags |= BIO_ERROR;
2259157114Sscottl		bio->bio_error = EIO;
2260247369Ssmh		device_printf(sc->mfi_dev, "I/O error, cmd=%p, status=%#x, "
2261247369Ssmh		    "scsi_status=%#x\n", cm, hdr->cmd_status, hdr->scsi_status);
2262157114Sscottl		mfi_print_sense(cm->cm_sc, cm->cm_sense);
2263184897Sambrisko	} else if (cm->cm_error != 0) {
2264184897Sambrisko		bio->bio_flags |= BIO_ERROR;
2265247369Ssmh		bio->bio_error = cm->cm_error;
2266247369Ssmh		device_printf(sc->mfi_dev, "I/O error, cmd=%p, error=%#x\n",
2267247369Ssmh		    cm, cm->cm_error);
2268157114Sscottl	}
2269157114Sscottl
2270157114Sscottl	mfi_release_command(cm);
2271157114Sscottl	mfi_disk_complete(bio);
2272157114Sscottl}
2273157114Sscottl
2274157114Sscottlvoid
2275157114Sscottlmfi_startio(struct mfi_softc *sc)
2276157114Sscottl{
2277157114Sscottl	struct mfi_command *cm;
2278169611Sscottl	struct ccb_hdr *ccbh;
2279157114Sscottl
2280157114Sscottl	for (;;) {
2281157114Sscottl		/* Don't bother if we're short on resources */
2282157114Sscottl		if (sc->mfi_flags & MFI_FLAGS_QFRZN)
2283157114Sscottl			break;
2284157114Sscottl
2285157114Sscottl		/* Try a command that has already been prepared */
2286157114Sscottl		cm = mfi_dequeue_ready(sc);
2287157114Sscottl
2288169611Sscottl		if (cm == NULL) {
2289169611Sscottl			if ((ccbh = TAILQ_FIRST(&sc->mfi_cam_ccbq)) != NULL)
2290169611Sscottl				cm = sc->mfi_cam_start(ccbh);
2291169611Sscottl		}
2292169611Sscottl
2293157114Sscottl		/* Nope, so look for work on the bioq */
2294157114Sscottl		if (cm == NULL)
2295157114Sscottl			cm = mfi_bio_command(sc);
2296157114Sscottl
2297157114Sscottl		/* No work available, so exit */
2298157114Sscottl		if (cm == NULL)
2299157114Sscottl			break;
2300157114Sscottl
2301157114Sscottl		/* Send the command to the controller */
2302157114Sscottl		if (mfi_mapcmd(sc, cm) != 0) {
2303247369Ssmh			device_printf(sc->mfi_dev, "Failed to startio\n");
2304157114Sscottl			mfi_requeue_ready(cm);
2305157114Sscottl			break;
2306157114Sscottl		}
2307157114Sscottl	}
2308157114Sscottl}
2309157114Sscottl
2310233711Sambriskoint
2311157114Sscottlmfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm)
2312157114Sscottl{
2313157114Sscottl	int error, polled;
2314157114Sscottl
2315163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2316163398Sscottl
2317233711Sambrisko	if ((cm->cm_data != NULL) && (cm->cm_frame->header.cmd != MFI_CMD_STP )) {
2318157114Sscottl		polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0;
2319246713Skib		if (cm->cm_flags & MFI_CMD_CCB)
2320246713Skib			error = bus_dmamap_load_ccb(sc->mfi_buffer_dmat,
2321246713Skib			    cm->cm_dmamap, cm->cm_data, mfi_data_cb, cm,
2322246713Skib			    polled);
2323267084Skib		else if (cm->cm_flags & MFI_CMD_BIO)
2324267084Skib			error = bus_dmamap_load_bio(sc->mfi_buffer_dmat,
2325267084Skib			    cm->cm_dmamap, cm->cm_private, mfi_data_cb, cm,
2326267084Skib			    polled);
2327246713Skib		else
2328246713Skib			error = bus_dmamap_load(sc->mfi_buffer_dmat,
2329246713Skib			    cm->cm_dmamap, cm->cm_data, cm->cm_len,
2330246713Skib			    mfi_data_cb, cm, polled);
2331157114Sscottl		if (error == EINPROGRESS) {
2332157114Sscottl			sc->mfi_flags |= MFI_FLAGS_QFRZN;
2333157114Sscottl			return (0);
2334157114Sscottl		}
2335157114Sscottl	} else {
2336247369Ssmh		error = mfi_send_frame(sc, cm);
2337157114Sscottl	}
2338157114Sscottl
2339157114Sscottl	return (error);
2340157114Sscottl}
2341157114Sscottl
2342157114Sscottlstatic void
2343157114Sscottlmfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
2344157114Sscottl{
2345157114Sscottl	struct mfi_frame_header *hdr;
2346157114Sscottl	struct mfi_command *cm;
2347157237Sscottl	union mfi_sgl *sgl;
2348157114Sscottl	struct mfi_softc *sc;
2349225869Smav	int i, j, first, dir;
2350247369Ssmh	int sge_size, locked;
2351157114Sscottl
2352157114Sscottl	cm = (struct mfi_command *)arg;
2353157114Sscottl	sc = cm->cm_sc;
2354157237Sscottl	hdr = &cm->cm_frame->header;
2355157237Sscottl	sgl = cm->cm_sg;
2356157114Sscottl
2357247369Ssmh	/*
2358247369Ssmh	 * We need to check if we have the lock as this is async
2359247369Ssmh	 * callback so even though our caller mfi_mapcmd asserts
2360247369Ssmh	 * it has the lock, there is no garantee that hasn't been
2361247369Ssmh	 * dropped if bus_dmamap_load returned prior to our
2362247369Ssmh	 * completion.
2363247369Ssmh	 */
2364247369Ssmh	if ((locked = mtx_owned(&sc->mfi_io_lock)) == 0)
2365247369Ssmh		mtx_lock(&sc->mfi_io_lock);
2366247369Ssmh
2367170284Sambrisko	if (error) {
2368170284Sambrisko		printf("error %d in callback\n", error);
2369170284Sambrisko		cm->cm_error = error;
2370170284Sambrisko		mfi_complete(sc, cm);
2371247369Ssmh		goto out;
2372170284Sambrisko	}
2373233711Sambrisko	/* Use IEEE sgl only for IO's on a SKINNY controller
2374233711Sambrisko	 * For other commands on a SKINNY controller use either
2375233711Sambrisko	 * sg32 or sg64 based on the sizeof(bus_addr_t).
2376233711Sambrisko	 * Also calculate the total frame size based on the type
2377233711Sambrisko	 * of SGL used.
2378233711Sambrisko	 */
2379233711Sambrisko	if (((cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) ||
2380233711Sambrisko	    (cm->cm_frame->header.cmd == MFI_CMD_LD_READ) ||
2381233711Sambrisko	    (cm->cm_frame->header.cmd == MFI_CMD_LD_WRITE)) &&
2382233711Sambrisko	    (sc->mfi_flags & MFI_FLAGS_SKINNY)) {
2383157237Sscottl		for (i = 0; i < nsegs; i++) {
2384233711Sambrisko			sgl->sg_skinny[i].addr = segs[i].ds_addr;
2385233711Sambrisko			sgl->sg_skinny[i].len = segs[i].ds_len;
2386233711Sambrisko			sgl->sg_skinny[i].flag = 0;
2387157114Sscottl		}
2388233711Sambrisko		hdr->flags |= MFI_FRAME_IEEE_SGL | MFI_FRAME_SGL64;
2389233711Sambrisko		sge_size = sizeof(struct mfi_sg_skinny);
2390233711Sambrisko		hdr->sg_count = nsegs;
2391157237Sscottl	} else {
2392233711Sambrisko		j = 0;
2393233711Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
2394233711Sambrisko			first = cm->cm_stp_len;
2395233711Sambrisko			if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
2396233711Sambrisko				sgl->sg32[j].addr = segs[0].ds_addr;
2397233711Sambrisko				sgl->sg32[j++].len = first;
2398233711Sambrisko			} else {
2399233711Sambrisko				sgl->sg64[j].addr = segs[0].ds_addr;
2400233711Sambrisko				sgl->sg64[j++].len = first;
2401233711Sambrisko			}
2402233711Sambrisko		} else
2403225869Smav			first = 0;
2404233711Sambrisko		if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
2405233711Sambrisko			for (i = 0; i < nsegs; i++) {
2406233711Sambrisko				sgl->sg32[j].addr = segs[i].ds_addr + first;
2407233711Sambrisko				sgl->sg32[j++].len = segs[i].ds_len - first;
2408233711Sambrisko				first = 0;
2409233711Sambrisko			}
2410233711Sambrisko		} else {
2411233711Sambrisko			for (i = 0; i < nsegs; i++) {
2412233711Sambrisko				sgl->sg64[j].addr = segs[i].ds_addr + first;
2413233711Sambrisko				sgl->sg64[j++].len = segs[i].ds_len - first;
2414233711Sambrisko				first = 0;
2415233711Sambrisko			}
2416233711Sambrisko			hdr->flags |= MFI_FRAME_SGL64;
2417157237Sscottl		}
2418233711Sambrisko		hdr->sg_count = j;
2419233711Sambrisko		sge_size = sc->mfi_sge_size;
2420157114Sscottl	}
2421157114Sscottl
2422157114Sscottl	dir = 0;
2423157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAIN) {
2424157114Sscottl		dir |= BUS_DMASYNC_PREREAD;
2425157114Sscottl		hdr->flags |= MFI_FRAME_DIR_READ;
2426157114Sscottl	}
2427157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAOUT) {
2428157114Sscottl		dir |= BUS_DMASYNC_PREWRITE;
2429157114Sscottl		hdr->flags |= MFI_FRAME_DIR_WRITE;
2430157114Sscottl	}
2431157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
2432157114Sscottl	cm->cm_flags |= MFI_CMD_MAPPED;
2433157114Sscottl
2434157114Sscottl	/*
2435157114Sscottl	 * Instead of calculating the total number of frames in the
2436157114Sscottl	 * compound frame, it's already assumed that there will be at
2437157114Sscottl	 * least 1 frame, so don't compensate for the modulo of the
2438157114Sscottl	 * following division.
2439157114Sscottl	 */
2440162458Sscottl	cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs);
2441157114Sscottl	cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
2442157114Sscottl
2443247369Ssmh	if ((error = mfi_send_frame(sc, cm)) != 0) {
2444247369Ssmh		printf("error %d in callback from mfi_send_frame\n", error);
2445247369Ssmh		cm->cm_error = error;
2446247369Ssmh		mfi_complete(sc, cm);
2447247369Ssmh		goto out;
2448247369Ssmh	}
2449157114Sscottl
2450247369Ssmhout:
2451247369Ssmh	/* leave the lock in the state we found it */
2452247369Ssmh	if (locked == 0)
2453247369Ssmh		mtx_unlock(&sc->mfi_io_lock);
2454247369Ssmh
2455157114Sscottl	return;
2456157114Sscottl}
2457157114Sscottl
2458157114Sscottlstatic int
2459157114Sscottlmfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
2460157114Sscottl{
2461247369Ssmh	int error;
2462247369Ssmh
2463247369Ssmh	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2464247369Ssmh
2465247369Ssmh	if (sc->MFA_enabled)
2466247369Ssmh		error = mfi_tbolt_send_frame(sc, cm);
2467247369Ssmh	else
2468247369Ssmh		error = mfi_std_send_frame(sc, cm);
2469247369Ssmh
2470247369Ssmh	if (error != 0 && (cm->cm_flags & MFI_ON_MFIQ_BUSY) != 0)
2471247369Ssmh		mfi_remove_busy(cm);
2472247369Ssmh
2473247369Ssmh	return (error);
2474247369Ssmh}
2475247369Ssmh
2476247369Ssmhstatic int
2477247369Ssmhmfi_std_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
2478247369Ssmh{
2479164375Sscottl	struct mfi_frame_header *hdr;
2480247369Ssmh	int tm = mfi_polled_cmd_timeout * 1000;
2481157114Sscottl
2482164375Sscottl	hdr = &cm->cm_frame->header;
2483164375Sscottl
2484164375Sscottl	if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
2485164375Sscottl		cm->cm_timestamp = time_uptime;
2486164375Sscottl		mfi_enqueue_busy(cm);
2487164375Sscottl	} else {
2488224039Sjhb		hdr->cmd_status = MFI_STAT_INVALID_STATUS;
2489164375Sscottl		hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
2490164375Sscottl	}
2491164375Sscottl
2492157114Sscottl	/*
2493157114Sscottl	 * The bus address of the command is aligned on a 64 byte boundary,
2494157114Sscottl	 * leaving the least 6 bits as zero.  For whatever reason, the
2495157114Sscottl	 * hardware wants the address shifted right by three, leaving just
2496162458Sscottl	 * 3 zero bits.  These three bits are then used as a prefetching
2497162458Sscottl	 * hint for the hardware to predict how many frames need to be
2498162458Sscottl	 * fetched across the bus.  If a command has more than 8 frames
2499162458Sscottl	 * then the 3 bits are set to 0x7 and the firmware uses other
2500162458Sscottl	 * information in the command to determine the total amount to fetch.
2501162458Sscottl	 * However, FreeBSD doesn't support I/O larger than 128K, so 8 frames
2502162458Sscottl	 * is enough for both 32bit and 64bit systems.
2503157114Sscottl	 */
2504162458Sscottl	if (cm->cm_extra_frames > 7)
2505162458Sscottl		cm->cm_extra_frames = 7;
2506162458Sscottl
2507233711Sambrisko	sc->mfi_issue_cmd(sc, cm->cm_frame_busaddr, cm->cm_extra_frames);
2508164375Sscottl
2509164375Sscottl	if ((cm->cm_flags & MFI_CMD_POLLED) == 0)
2510164375Sscottl		return (0);
2511164375Sscottl
2512164375Sscottl	/* This is a polled command, so busy-wait for it to complete. */
2513224039Sjhb	while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
2514164375Sscottl		DELAY(1000);
2515165225Sambrisko		tm -= 1;
2516164375Sscottl		if (tm <= 0)
2517164375Sscottl			break;
2518164375Sscottl	}
2519164375Sscottl
2520224039Sjhb	if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
2521165225Sambrisko		device_printf(sc->mfi_dev, "Frame %p timed out "
2522233711Sambrisko		    "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
2523164375Sscottl		return (ETIMEDOUT);
2524164375Sscottl	}
2525164375Sscottl
2526157114Sscottl	return (0);
2527157114Sscottl}
2528157114Sscottl
2529233711Sambrisko
2530233711Sambriskovoid
2531157114Sscottlmfi_complete(struct mfi_softc *sc, struct mfi_command *cm)
2532157114Sscottl{
2533157114Sscottl	int dir;
2534247369Ssmh	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2535157114Sscottl
2536157114Sscottl	if ((cm->cm_flags & MFI_CMD_MAPPED) != 0) {
2537157114Sscottl		dir = 0;
2538225869Smav		if ((cm->cm_flags & MFI_CMD_DATAIN) ||
2539225869Smav		    (cm->cm_frame->header.cmd == MFI_CMD_STP))
2540157114Sscottl			dir |= BUS_DMASYNC_POSTREAD;
2541157114Sscottl		if (cm->cm_flags & MFI_CMD_DATAOUT)
2542157114Sscottl			dir |= BUS_DMASYNC_POSTWRITE;
2543157114Sscottl
2544157114Sscottl		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
2545157114Sscottl		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
2546157114Sscottl		cm->cm_flags &= ~MFI_CMD_MAPPED;
2547157114Sscottl	}
2548157114Sscottl
2549170284Sambrisko	cm->cm_flags |= MFI_CMD_COMPLETED;
2550170284Sambrisko
2551157114Sscottl	if (cm->cm_complete != NULL)
2552157114Sscottl		cm->cm_complete(cm);
2553159811Sps	else
2554159811Sps		wakeup(cm);
2555157114Sscottl}
2556157114Sscottl
2557158737Sambriskostatic int
2558242681Sambriskomfi_abort(struct mfi_softc *sc, struct mfi_command **cm_abort)
2559158737Sambrisko{
2560158737Sambrisko	struct mfi_command *cm;
2561158737Sambrisko	struct mfi_abort_frame *abort;
2562247369Ssmh	int i = 0, error;
2563233711Sambrisko	uint32_t context = 0;
2564158737Sambrisko
2565242681Sambrisko	mtx_lock(&sc->mfi_io_lock);
2566158737Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL) {
2567247369Ssmh		mtx_unlock(&sc->mfi_io_lock);
2568158737Sambrisko		return (EBUSY);
2569158737Sambrisko	}
2570158737Sambrisko
2571233711Sambrisko	/* Zero out the MFI frame */
2572233711Sambrisko	context = cm->cm_frame->header.context;
2573233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
2574233711Sambrisko	cm->cm_frame->header.context = context;
2575233711Sambrisko
2576158737Sambrisko	abort = &cm->cm_frame->abort;
2577158737Sambrisko	abort->header.cmd = MFI_CMD_ABORT;
2578158737Sambrisko	abort->header.flags = 0;
2579233711Sambrisko	abort->header.scsi_status = 0;
2580242681Sambrisko	abort->abort_context = (*cm_abort)->cm_frame->header.context;
2581242681Sambrisko	abort->abort_mfi_addr_lo = (uint32_t)(*cm_abort)->cm_frame_busaddr;
2582233711Sambrisko	abort->abort_mfi_addr_hi =
2583242681Sambrisko		(uint32_t)((uint64_t)(*cm_abort)->cm_frame_busaddr >> 32);
2584158737Sambrisko	cm->cm_data = NULL;
2585164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
2586158737Sambrisko
2587247369Ssmh	if ((error = mfi_mapcmd(sc, cm)) != 0)
2588247369Ssmh		device_printf(sc->mfi_dev, "failed to abort command\n");
2589158737Sambrisko	mfi_release_command(cm);
2590158737Sambrisko
2591242681Sambrisko	mtx_unlock(&sc->mfi_io_lock);
2592242681Sambrisko	while (i < 5 && *cm_abort != NULL) {
2593242681Sambrisko		tsleep(cm_abort, 0, "mfiabort",
2594233711Sambrisko		    5 * hz);
2595165225Sambrisko		i++;
2596158737Sambrisko	}
2597242681Sambrisko	if (*cm_abort != NULL) {
2598242681Sambrisko		/* Force a complete if command didn't abort */
2599242681Sambrisko		mtx_lock(&sc->mfi_io_lock);
2600242681Sambrisko		(*cm_abort)->cm_complete(*cm_abort);
2601242681Sambrisko		mtx_unlock(&sc->mfi_io_lock);
2602235014Sambrisko	}
2603158737Sambrisko
2604247369Ssmh	return (error);
2605158737Sambrisko}
2606158737Sambrisko
2607157114Sscottlint
2608233711Sambriskomfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt,
2609233711Sambrisko     int len)
2610157114Sscottl{
2611157114Sscottl	struct mfi_command *cm;
2612157114Sscottl	struct mfi_io_frame *io;
2613157114Sscottl	int error;
2614233711Sambrisko	uint32_t context = 0;
2615157114Sscottl
2616157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
2617157114Sscottl		return (EBUSY);
2618157114Sscottl
2619233711Sambrisko	/* Zero out the MFI frame */
2620233711Sambrisko	context = cm->cm_frame->header.context;
2621233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
2622233711Sambrisko	cm->cm_frame->header.context = context;
2623233711Sambrisko
2624157114Sscottl	io = &cm->cm_frame->io;
2625157114Sscottl	io->header.cmd = MFI_CMD_LD_WRITE;
2626157114Sscottl	io->header.target_id = id;
2627157114Sscottl	io->header.timeout = 0;
2628157114Sscottl	io->header.flags = 0;
2629233711Sambrisko	io->header.scsi_status = 0;
2630157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
2631157114Sscottl	io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2632233711Sambrisko	io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2633233711Sambrisko	io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2634157114Sscottl	io->lba_hi = (lba & 0xffffffff00000000) >> 32;
2635157114Sscottl	io->lba_lo = lba & 0xffffffff;
2636157114Sscottl	cm->cm_data = virt;
2637157114Sscottl	cm->cm_len = len;
2638157114Sscottl	cm->cm_sg = &io->sgl;
2639157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
2640157114Sscottl	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT;
2641157114Sscottl
2642247369Ssmh	if ((error = mfi_mapcmd(sc, cm)) != 0)
2643247369Ssmh		device_printf(sc->mfi_dev, "failed dump blocks\n");
2644157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
2645157114Sscottl	    BUS_DMASYNC_POSTWRITE);
2646157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
2647157114Sscottl	mfi_release_command(cm);
2648157114Sscottl
2649157114Sscottl	return (error);
2650157114Sscottl}
2651157114Sscottl
2652233711Sambriskoint
2653233711Sambriskomfi_dump_syspd_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt,
2654233711Sambrisko    int len)
2655233711Sambrisko{
2656233711Sambrisko	struct mfi_command *cm;
2657233711Sambrisko	struct mfi_pass_frame *pass;
2658242681Sambrisko	int error, readop, cdb_len;
2659242497Sdelphij	uint32_t blkcount;
2660233711Sambrisko
2661233711Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL)
2662233711Sambrisko		return (EBUSY);
2663233711Sambrisko
2664233711Sambrisko	pass = &cm->cm_frame->pass;
2665233711Sambrisko	bzero(pass->cdb, 16);
2666233711Sambrisko	pass->header.cmd = MFI_CMD_PD_SCSI_IO;
2667242681Sambrisko
2668242681Sambrisko	readop = 0;
2669233711Sambrisko	blkcount = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2670242681Sambrisko	cdb_len = mfi_build_cdb(readop, 0, lba, blkcount, pass->cdb);
2671233711Sambrisko	pass->header.target_id = id;
2672233711Sambrisko	pass->header.timeout = 0;
2673233711Sambrisko	pass->header.flags = 0;
2674233711Sambrisko	pass->header.scsi_status = 0;
2675233711Sambrisko	pass->header.sense_len = MFI_SENSE_LEN;
2676233711Sambrisko	pass->header.data_len = len;
2677242681Sambrisko	pass->header.cdb_len = cdb_len;
2678233711Sambrisko	pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2679233711Sambrisko	pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2680233711Sambrisko	cm->cm_data = virt;
2681233711Sambrisko	cm->cm_len = len;
2682233711Sambrisko	cm->cm_sg = &pass->sgl;
2683233711Sambrisko	cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
2684242681Sambrisko	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT | MFI_CMD_SCSI;
2685233711Sambrisko
2686247369Ssmh	if ((error = mfi_mapcmd(sc, cm)) != 0)
2687247369Ssmh		device_printf(sc->mfi_dev, "failed dump blocks\n");
2688233711Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
2689233711Sambrisko	    BUS_DMASYNC_POSTWRITE);
2690233711Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
2691233711Sambrisko	mfi_release_command(cm);
2692233711Sambrisko
2693233711Sambrisko	return (error);
2694233711Sambrisko}
2695233711Sambrisko
2696157114Sscottlstatic int
2697192450Simpmfi_open(struct cdev *dev, int flags, int fmt, struct thread *td)
2698157114Sscottl{
2699157114Sscottl	struct mfi_softc *sc;
2700171822Sjhb	int error;
2701157114Sscottl
2702157114Sscottl	sc = dev->si_drv1;
2703163398Sscottl
2704163398Sscottl	mtx_lock(&sc->mfi_io_lock);
2705171822Sjhb	if (sc->mfi_detaching)
2706171822Sjhb		error = ENXIO;
2707171822Sjhb	else {
2708171822Sjhb		sc->mfi_flags |= MFI_FLAGS_OPEN;
2709171822Sjhb		error = 0;
2710171822Sjhb	}
2711163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
2712157114Sscottl
2713171822Sjhb	return (error);
2714157114Sscottl}
2715157114Sscottl
2716157114Sscottlstatic int
2717192450Simpmfi_close(struct cdev *dev, int flags, int fmt, struct thread *td)
2718157114Sscottl{
2719157114Sscottl	struct mfi_softc *sc;
2720163398Sscottl	struct mfi_aen *mfi_aen_entry, *tmp;
2721157114Sscottl
2722157114Sscottl	sc = dev->si_drv1;
2723163398Sscottl
2724163398Sscottl	mtx_lock(&sc->mfi_io_lock);
2725157114Sscottl	sc->mfi_flags &= ~MFI_FLAGS_OPEN;
2726157114Sscottl
2727163398Sscottl	TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
2728158737Sambrisko		if (mfi_aen_entry->p == curproc) {
2729158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
2730158737Sambrisko			    aen_link);
2731158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
2732158737Sambrisko		}
2733158737Sambrisko	}
2734163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
2735157114Sscottl	return (0);
2736157114Sscottl}
2737157114Sscottl
2738157114Sscottlstatic int
2739171821Sjhbmfi_config_lock(struct mfi_softc *sc, uint32_t opcode)
2740171821Sjhb{
2741171821Sjhb
2742171821Sjhb	switch (opcode) {
2743171821Sjhb	case MFI_DCMD_LD_DELETE:
2744171821Sjhb	case MFI_DCMD_CFG_ADD:
2745171821Sjhb	case MFI_DCMD_CFG_CLEAR:
2746240962Sjhb	case MFI_DCMD_CFG_FOREIGN_IMPORT:
2747171821Sjhb		sx_xlock(&sc->mfi_config_lock);
2748171821Sjhb		return (1);
2749171821Sjhb	default:
2750171821Sjhb		return (0);
2751171821Sjhb	}
2752171821Sjhb}
2753171821Sjhb
2754171821Sjhbstatic void
2755171821Sjhbmfi_config_unlock(struct mfi_softc *sc, int locked)
2756171821Sjhb{
2757171821Sjhb
2758171821Sjhb	if (locked)
2759171821Sjhb		sx_xunlock(&sc->mfi_config_lock);
2760171821Sjhb}
2761171821Sjhb
2762233711Sambrisko/*
2763233711Sambrisko * Perform pre-issue checks on commands from userland and possibly veto
2764233711Sambrisko * them.
2765233711Sambrisko */
2766171821Sjhbstatic int
2767171821Sjhbmfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm)
2768171821Sjhb{
2769171821Sjhb	struct mfi_disk *ld, *ld2;
2770171821Sjhb	int error;
2771233711Sambrisko	struct mfi_system_pd *syspd = NULL;
2772233711Sambrisko	uint16_t syspd_id;
2773233711Sambrisko	uint16_t *mbox;
2774171821Sjhb
2775171821Sjhb	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2776171821Sjhb	error = 0;
2777171821Sjhb	switch (cm->cm_frame->dcmd.opcode) {
2778171821Sjhb	case MFI_DCMD_LD_DELETE:
2779171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
2780171821Sjhb			if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
2781171821Sjhb				break;
2782171821Sjhb		}
2783171821Sjhb		if (ld == NULL)
2784171821Sjhb			error = ENOENT;
2785171821Sjhb		else
2786171821Sjhb			error = mfi_disk_disable(ld);
2787171821Sjhb		break;
2788171821Sjhb	case MFI_DCMD_CFG_CLEAR:
2789171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
2790171821Sjhb			error = mfi_disk_disable(ld);
2791171821Sjhb			if (error)
2792171821Sjhb				break;
2793171821Sjhb		}
2794171821Sjhb		if (error) {
2795171821Sjhb			TAILQ_FOREACH(ld2, &sc->mfi_ld_tqh, ld_link) {
2796171821Sjhb				if (ld2 == ld)
2797171821Sjhb					break;
2798171821Sjhb				mfi_disk_enable(ld2);
2799171821Sjhb			}
2800171821Sjhb		}
2801171821Sjhb		break;
2802233711Sambrisko	case MFI_DCMD_PD_STATE_SET:
2803233711Sambrisko		mbox = (uint16_t *) cm->cm_frame->dcmd.mbox;
2804233711Sambrisko		syspd_id = mbox[0];
2805233711Sambrisko		if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) {
2806233711Sambrisko			TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) {
2807233711Sambrisko				if (syspd->pd_id == syspd_id)
2808233711Sambrisko					break;
2809233711Sambrisko			}
2810233711Sambrisko		}
2811233711Sambrisko		else
2812233711Sambrisko			break;
2813233711Sambrisko		if (syspd)
2814233711Sambrisko			error = mfi_syspd_disable(syspd);
2815233711Sambrisko		break;
2816171821Sjhb	default:
2817171821Sjhb		break;
2818171821Sjhb	}
2819171821Sjhb	return (error);
2820171821Sjhb}
2821171821Sjhb
2822171821Sjhb/* Perform post-issue checks on commands from userland. */
2823171821Sjhbstatic void
2824171821Sjhbmfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm)
2825171821Sjhb{
2826171821Sjhb	struct mfi_disk *ld, *ldn;
2827233711Sambrisko	struct mfi_system_pd *syspd = NULL;
2828233711Sambrisko	uint16_t syspd_id;
2829233711Sambrisko	uint16_t *mbox;
2830171821Sjhb
2831171821Sjhb	switch (cm->cm_frame->dcmd.opcode) {
2832171821Sjhb	case MFI_DCMD_LD_DELETE:
2833171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
2834171821Sjhb			if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
2835171821Sjhb				break;
2836171821Sjhb		}
2837171821Sjhb		KASSERT(ld != NULL, ("volume dissappeared"));
2838171821Sjhb		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
2839171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
2840196403Sjhb			mtx_lock(&Giant);
2841171821Sjhb			device_delete_child(sc->mfi_dev, ld->ld_dev);
2842196403Sjhb			mtx_unlock(&Giant);
2843171821Sjhb			mtx_lock(&sc->mfi_io_lock);
2844171821Sjhb		} else
2845171821Sjhb			mfi_disk_enable(ld);
2846171821Sjhb		break;
2847171821Sjhb	case MFI_DCMD_CFG_CLEAR:
2848171821Sjhb		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
2849171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
2850196403Sjhb			mtx_lock(&Giant);
2851171821Sjhb			TAILQ_FOREACH_SAFE(ld, &sc->mfi_ld_tqh, ld_link, ldn) {
2852171821Sjhb				device_delete_child(sc->mfi_dev, ld->ld_dev);
2853171821Sjhb			}
2854196403Sjhb			mtx_unlock(&Giant);
2855171821Sjhb			mtx_lock(&sc->mfi_io_lock);
2856171821Sjhb		} else {
2857171821Sjhb			TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link)
2858171821Sjhb				mfi_disk_enable(ld);
2859171821Sjhb		}
2860171821Sjhb		break;
2861171821Sjhb	case MFI_DCMD_CFG_ADD:
2862171821Sjhb		mfi_ldprobe(sc);
2863171821Sjhb		break;
2864184897Sambrisko	case MFI_DCMD_CFG_FOREIGN_IMPORT:
2865184897Sambrisko		mfi_ldprobe(sc);
2866184897Sambrisko		break;
2867233711Sambrisko	case MFI_DCMD_PD_STATE_SET:
2868233711Sambrisko		mbox = (uint16_t *) cm->cm_frame->dcmd.mbox;
2869233711Sambrisko		syspd_id = mbox[0];
2870233711Sambrisko		if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) {
2871233711Sambrisko			TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) {
2872233711Sambrisko				if (syspd->pd_id == syspd_id)
2873233711Sambrisko					break;
2874233711Sambrisko			}
2875233711Sambrisko		}
2876233711Sambrisko		else
2877233711Sambrisko			break;
2878233711Sambrisko		/* If the transition fails then enable the syspd again */
2879233711Sambrisko		if (syspd && cm->cm_frame->header.cmd_status != MFI_STAT_OK)
2880233711Sambrisko			mfi_syspd_enable(syspd);
2881233711Sambrisko		break;
2882171821Sjhb	}
2883171821Sjhb}
2884171821Sjhb
2885242681Sambriskostatic int
2886242681Sambriskomfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm)
2887233711Sambrisko{
2888242681Sambrisko	struct mfi_config_data *conf_data;
2889233711Sambrisko	struct mfi_command *ld_cm = NULL;
2890233711Sambrisko	struct mfi_ld_info *ld_info = NULL;
2891242681Sambrisko	struct mfi_ld_config *ld;
2892242681Sambrisko	char *p;
2893233711Sambrisko	int error = 0;
2894233711Sambrisko
2895242681Sambrisko	conf_data = (struct mfi_config_data *)cm->cm_data;
2896242681Sambrisko
2897242681Sambrisko	if (cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) {
2898242681Sambrisko		p = (char *)conf_data->array;
2899242681Sambrisko		p += conf_data->array_size * conf_data->array_count;
2900242681Sambrisko		ld = (struct mfi_ld_config *)p;
2901242681Sambrisko		if (ld->params.isSSCD == 1)
2902242681Sambrisko			error = 1;
2903233711Sambrisko	} else if (cm->cm_frame->dcmd.opcode == MFI_DCMD_LD_DELETE) {
2904233711Sambrisko		error = mfi_dcmd_command (sc, &ld_cm, MFI_DCMD_LD_GET_INFO,
2905233711Sambrisko		    (void **)&ld_info, sizeof(*ld_info));
2906235016Sambrisko		if (error) {
2907233711Sambrisko			device_printf(sc->mfi_dev, "Failed to allocate"
2908233711Sambrisko			    "MFI_DCMD_LD_GET_INFO %d", error);
2909233711Sambrisko			if (ld_info)
2910233711Sambrisko				free(ld_info, M_MFIBUF);
2911233711Sambrisko			return 0;
2912233711Sambrisko		}
2913233711Sambrisko		ld_cm->cm_flags = MFI_CMD_DATAIN;
2914233711Sambrisko		ld_cm->cm_frame->dcmd.mbox[0]= cm->cm_frame->dcmd.mbox[0];
2915233711Sambrisko		ld_cm->cm_frame->header.target_id = cm->cm_frame->dcmd.mbox[0];
2916235016Sambrisko		if (mfi_wait_command(sc, ld_cm) != 0) {
2917233711Sambrisko			device_printf(sc->mfi_dev, "failed to get log drv\n");
2918233711Sambrisko			mfi_release_command(ld_cm);
2919233711Sambrisko			free(ld_info, M_MFIBUF);
2920233711Sambrisko			return 0;
2921233711Sambrisko		}
2922233711Sambrisko
2923233711Sambrisko		if (ld_cm->cm_frame->header.cmd_status != MFI_STAT_OK) {
2924233711Sambrisko			free(ld_info, M_MFIBUF);
2925233711Sambrisko			mfi_release_command(ld_cm);
2926233711Sambrisko			return 0;
2927233711Sambrisko		}
2928233711Sambrisko		else
2929233711Sambrisko			ld_info = (struct mfi_ld_info *)ld_cm->cm_private;
2930233711Sambrisko
2931233711Sambrisko		if (ld_info->ld_config.params.isSSCD == 1)
2932233711Sambrisko			error = 1;
2933233711Sambrisko
2934233711Sambrisko		mfi_release_command(ld_cm);
2935233711Sambrisko		free(ld_info, M_MFIBUF);
2936233711Sambrisko
2937233711Sambrisko	}
2938233711Sambrisko	return error;
2939233711Sambrisko}
2940233711Sambrisko
2941171821Sjhbstatic int
2942233711Sambriskomfi_stp_cmd(struct mfi_softc *sc, struct mfi_command *cm,caddr_t arg)
2943233711Sambrisko{
2944233711Sambrisko	uint8_t i;
2945233711Sambrisko	struct mfi_ioc_packet *ioc;
2946233711Sambrisko	ioc = (struct mfi_ioc_packet *)arg;
2947233711Sambrisko	int sge_size, error;
2948233711Sambrisko	struct megasas_sge *kern_sge;
2949233711Sambrisko
2950233711Sambrisko	memset(sc->kbuff_arr, 0, sizeof(sc->kbuff_arr));
2951233711Sambrisko	kern_sge =(struct megasas_sge *) ((uintptr_t)cm->cm_frame + ioc->mfi_sgl_off);
2952233711Sambrisko	cm->cm_frame->header.sg_count = ioc->mfi_sge_count;
2953233711Sambrisko
2954233711Sambrisko	if (sizeof(bus_addr_t) == 8) {
2955233711Sambrisko		cm->cm_frame->header.flags |= MFI_FRAME_SGL64;
2956233711Sambrisko		cm->cm_extra_frames = 2;
2957233711Sambrisko		sge_size = sizeof(struct mfi_sg64);
2958233711Sambrisko	} else {
2959233711Sambrisko		cm->cm_extra_frames =  (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
2960233711Sambrisko		sge_size = sizeof(struct mfi_sg32);
2961233711Sambrisko	}
2962233711Sambrisko
2963233711Sambrisko	cm->cm_total_frame_size += (sge_size * ioc->mfi_sge_count);
2964233711Sambrisko	for (i = 0; i < ioc->mfi_sge_count; i++) {
2965233711Sambrisko			if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
2966233711Sambrisko			1, 0,			/* algnmnt, boundary */
2967233711Sambrisko			BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
2968233711Sambrisko			BUS_SPACE_MAXADDR,	/* highaddr */
2969233711Sambrisko			NULL, NULL,		/* filter, filterarg */
2970233711Sambrisko			ioc->mfi_sgl[i].iov_len,/* maxsize */
2971233711Sambrisko			2,			/* nsegments */
2972233711Sambrisko			ioc->mfi_sgl[i].iov_len,/* maxsegsize */
2973233711Sambrisko			BUS_DMA_ALLOCNOW,	/* flags */
2974233711Sambrisko			NULL, NULL,		/* lockfunc, lockarg */
2975233711Sambrisko			&sc->mfi_kbuff_arr_dmat[i])) {
2976233711Sambrisko			device_printf(sc->mfi_dev,
2977233711Sambrisko			    "Cannot allocate mfi_kbuff_arr_dmat tag\n");
2978233711Sambrisko			return (ENOMEM);
2979233711Sambrisko		}
2980233711Sambrisko
2981233711Sambrisko		if (bus_dmamem_alloc(sc->mfi_kbuff_arr_dmat[i],
2982233711Sambrisko		    (void **)&sc->kbuff_arr[i], BUS_DMA_NOWAIT,
2983233711Sambrisko		    &sc->mfi_kbuff_arr_dmamap[i])) {
2984233711Sambrisko			device_printf(sc->mfi_dev,
2985233711Sambrisko			    "Cannot allocate mfi_kbuff_arr_dmamap memory\n");
2986233711Sambrisko			return (ENOMEM);
2987233711Sambrisko		}
2988233711Sambrisko
2989233711Sambrisko		bus_dmamap_load(sc->mfi_kbuff_arr_dmat[i],
2990233711Sambrisko		    sc->mfi_kbuff_arr_dmamap[i], sc->kbuff_arr[i],
2991233711Sambrisko		    ioc->mfi_sgl[i].iov_len, mfi_addr_cb,
2992233711Sambrisko		    &sc->mfi_kbuff_arr_busaddr[i], 0);
2993233711Sambrisko
2994233711Sambrisko		if (!sc->kbuff_arr[i]) {
2995233711Sambrisko			device_printf(sc->mfi_dev,
2996233711Sambrisko			    "Could not allocate memory for kbuff_arr info\n");
2997233711Sambrisko			return -1;
2998233711Sambrisko		}
2999233711Sambrisko		kern_sge[i].phys_addr = sc->mfi_kbuff_arr_busaddr[i];
3000233711Sambrisko		kern_sge[i].length = ioc->mfi_sgl[i].iov_len;
3001233711Sambrisko
3002233711Sambrisko		if (sizeof(bus_addr_t) == 8) {
3003233711Sambrisko			cm->cm_frame->stp.sgl.sg64[i].addr =
3004233711Sambrisko			    kern_sge[i].phys_addr;
3005233711Sambrisko			cm->cm_frame->stp.sgl.sg64[i].len =
3006233711Sambrisko			    ioc->mfi_sgl[i].iov_len;
3007233711Sambrisko		} else {
3008247594Sdelphij			cm->cm_frame->stp.sgl.sg32[i].addr =
3009233711Sambrisko			    kern_sge[i].phys_addr;
3010233711Sambrisko			cm->cm_frame->stp.sgl.sg32[i].len =
3011233711Sambrisko			    ioc->mfi_sgl[i].iov_len;
3012233711Sambrisko		}
3013233711Sambrisko
3014233711Sambrisko		error = copyin(ioc->mfi_sgl[i].iov_base,
3015233711Sambrisko		    sc->kbuff_arr[i],
3016233711Sambrisko		    ioc->mfi_sgl[i].iov_len);
3017233711Sambrisko		if (error != 0) {
3018233711Sambrisko			device_printf(sc->mfi_dev, "Copy in failed\n");
3019233711Sambrisko			return error;
3020233711Sambrisko		}
3021233711Sambrisko	}
3022233711Sambrisko
3023233711Sambrisko	cm->cm_flags |=MFI_CMD_MAPPED;
3024233711Sambrisko	return 0;
3025233711Sambrisko}
3026233711Sambrisko
3027233711Sambriskostatic int
3028178968Sscottlmfi_user_command(struct mfi_softc *sc, struct mfi_ioc_passthru *ioc)
3029178968Sscottl{
3030178968Sscottl	struct mfi_command *cm;
3031178968Sscottl	struct mfi_dcmd_frame *dcmd;
3032178968Sscottl	void *ioc_buf = NULL;
3033178968Sscottl	uint32_t context;
3034178968Sscottl	int error = 0, locked;
3035178968Sscottl
3036178968Sscottl
3037178968Sscottl	if (ioc->buf_size > 0) {
3038238077Sjhb		if (ioc->buf_size > 1024 * 1024)
3039238077Sjhb			return (ENOMEM);
3040178968Sscottl		ioc_buf = malloc(ioc->buf_size, M_MFIBUF, M_WAITOK);
3041178968Sscottl		error = copyin(ioc->buf, ioc_buf, ioc->buf_size);
3042178968Sscottl		if (error) {
3043178968Sscottl			device_printf(sc->mfi_dev, "failed to copyin\n");
3044178968Sscottl			free(ioc_buf, M_MFIBUF);
3045178968Sscottl			return (error);
3046178968Sscottl		}
3047178968Sscottl	}
3048178968Sscottl
3049178968Sscottl	locked = mfi_config_lock(sc, ioc->ioc_frame.opcode);
3050178968Sscottl
3051178968Sscottl	mtx_lock(&sc->mfi_io_lock);
3052178968Sscottl	while ((cm = mfi_dequeue_free(sc)) == NULL)
3053178968Sscottl		msleep(mfi_user_command, &sc->mfi_io_lock, 0, "mfiioc", hz);
3054178968Sscottl
3055178968Sscottl	/* Save context for later */
3056178968Sscottl	context = cm->cm_frame->header.context;
3057178968Sscottl
3058178968Sscottl	dcmd = &cm->cm_frame->dcmd;
3059178968Sscottl	bcopy(&ioc->ioc_frame, dcmd, sizeof(struct mfi_dcmd_frame));
3060178968Sscottl
3061178968Sscottl	cm->cm_sg = &dcmd->sgl;
3062178968Sscottl	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
3063178968Sscottl	cm->cm_data = ioc_buf;
3064178968Sscottl	cm->cm_len = ioc->buf_size;
3065178968Sscottl
3066178968Sscottl	/* restore context */
3067178968Sscottl	cm->cm_frame->header.context = context;
3068178968Sscottl
3069178968Sscottl	/* Cheat since we don't know if we're writing or reading */
3070178968Sscottl	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
3071178968Sscottl
3072178968Sscottl	error = mfi_check_command_pre(sc, cm);
3073178968Sscottl	if (error)
3074178968Sscottl		goto out;
3075178968Sscottl
3076178968Sscottl	error = mfi_wait_command(sc, cm);
3077178968Sscottl	if (error) {
3078178968Sscottl		device_printf(sc->mfi_dev, "ioctl failed %d\n", error);
3079178968Sscottl		goto out;
3080178968Sscottl	}
3081178968Sscottl	bcopy(dcmd, &ioc->ioc_frame, sizeof(struct mfi_dcmd_frame));
3082178968Sscottl	mfi_check_command_post(sc, cm);
3083178968Sscottlout:
3084178968Sscottl	mfi_release_command(cm);
3085178968Sscottl	mtx_unlock(&sc->mfi_io_lock);
3086178968Sscottl	mfi_config_unlock(sc, locked);
3087178968Sscottl	if (ioc->buf_size > 0)
3088178968Sscottl		error = copyout(ioc_buf, ioc->buf, ioc->buf_size);
3089178968Sscottl	if (ioc_buf)
3090178968Sscottl		free(ioc_buf, M_MFIBUF);
3091178968Sscottl	return (error);
3092178968Sscottl}
3093178968Sscottl
3094178968Sscottl#define	PTRIN(p)		((void *)(uintptr_t)(p))
3095178968Sscottl
3096178968Sscottlstatic int
3097192450Simpmfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
3098157114Sscottl{
3099157114Sscottl	struct mfi_softc *sc;
3100157114Sscottl	union mfi_statrequest *ms;
3101164281Sambrisko	struct mfi_ioc_packet *ioc;
3102233711Sambrisko#ifdef COMPAT_FREEBSD32
3103179392Sambrisko	struct mfi_ioc_packet32 *ioc32;
3104179392Sambrisko#endif
3105164281Sambrisko	struct mfi_ioc_aen *aen;
3106164281Sambrisko	struct mfi_command *cm = NULL;
3107233711Sambrisko	uint32_t context = 0;
3108184897Sambrisko	union mfi_sense_ptr sense_ptr;
3109233711Sambrisko	uint8_t *data = NULL, *temp, *addr, skip_pre_post = 0;
3110225869Smav	size_t len;
3111233711Sambrisko	int i, res;
3112178968Sscottl	struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg;
3113233711Sambrisko#ifdef COMPAT_FREEBSD32
3114178968Sscottl	struct mfi_ioc_passthru32 *iop32 = (struct mfi_ioc_passthru32 *)arg;
3115178968Sscottl	struct mfi_ioc_passthru iop_swab;
3116178968Sscottl#endif
3117171821Sjhb	int error, locked;
3118233711Sambrisko	union mfi_sgl *sgl;
3119157114Sscottl	sc = dev->si_drv1;
3120157114Sscottl	error = 0;
3121157114Sscottl
3122233711Sambrisko	if (sc->adpreset)
3123233711Sambrisko		return EBUSY;
3124233711Sambrisko
3125233711Sambrisko	if (sc->hw_crit_error)
3126233711Sambrisko		return EBUSY;
3127233711Sambrisko
3128233711Sambrisko	if (sc->issuepend_done == 0)
3129233711Sambrisko		return EBUSY;
3130233711Sambrisko
3131157114Sscottl	switch (cmd) {
3132157114Sscottl	case MFIIO_STATS:
3133157114Sscottl		ms = (union mfi_statrequest *)arg;
3134157114Sscottl		switch (ms->ms_item) {
3135157114Sscottl		case MFIQ_FREE:
3136157114Sscottl		case MFIQ_BIO:
3137157114Sscottl		case MFIQ_READY:
3138157114Sscottl		case MFIQ_BUSY:
3139157114Sscottl			bcopy(&sc->mfi_qstat[ms->ms_item], &ms->ms_qstat,
3140157114Sscottl			    sizeof(struct mfi_qstat));
3141157114Sscottl			break;
3142157114Sscottl		default:
3143158737Sambrisko			error = ENOIOCTL;
3144157114Sscottl			break;
3145157114Sscottl		}
3146157114Sscottl		break;
3147169451Sscottl	case MFIIO_QUERY_DISK:
3148169451Sscottl	{
3149169451Sscottl		struct mfi_query_disk *qd;
3150169451Sscottl		struct mfi_disk *ld;
3151169451Sscottl
3152169451Sscottl		qd = (struct mfi_query_disk *)arg;
3153169451Sscottl		mtx_lock(&sc->mfi_io_lock);
3154169451Sscottl		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
3155169451Sscottl			if (ld->ld_id == qd->array_id)
3156169451Sscottl				break;
3157169451Sscottl		}
3158169451Sscottl		if (ld == NULL) {
3159169451Sscottl			qd->present = 0;
3160169451Sscottl			mtx_unlock(&sc->mfi_io_lock);
3161169451Sscottl			return (0);
3162169451Sscottl		}
3163169451Sscottl		qd->present = 1;
3164169451Sscottl		if (ld->ld_flags & MFI_DISK_FLAGS_OPEN)
3165169451Sscottl			qd->open = 1;
3166169451Sscottl		bzero(qd->devname, SPECNAMELEN + 1);
3167169451Sscottl		snprintf(qd->devname, SPECNAMELEN, "mfid%d", ld->ld_unit);
3168169451Sscottl		mtx_unlock(&sc->mfi_io_lock);
3169169451Sscottl		break;
3170169451Sscottl	}
3171164281Sambrisko	case MFI_CMD:
3172233711Sambrisko#ifdef COMPAT_FREEBSD32
3173179392Sambrisko	case MFI_CMD32:
3174179392Sambrisko#endif
3175177489Sambrisko		{
3176177489Sambrisko		devclass_t devclass;
3177164281Sambrisko		ioc = (struct mfi_ioc_packet *)arg;
3178177489Sambrisko		int adapter;
3179164281Sambrisko
3180177489Sambrisko		adapter = ioc->mfi_adapter_no;
3181177489Sambrisko		if (device_get_unit(sc->mfi_dev) == 0 && adapter != 0) {
3182177489Sambrisko			devclass = devclass_find("mfi");
3183177489Sambrisko			sc = devclass_get_softc(devclass, adapter);
3184177489Sambrisko		}
3185164281Sambrisko		mtx_lock(&sc->mfi_io_lock);
3186164281Sambrisko		if ((cm = mfi_dequeue_free(sc)) == NULL) {
3187164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3188164281Sambrisko			return (EBUSY);
3189164281Sambrisko		}
3190164281Sambrisko		mtx_unlock(&sc->mfi_io_lock);
3191171821Sjhb		locked = 0;
3192164281Sambrisko
3193164281Sambrisko		/*
3194164281Sambrisko		 * save off original context since copying from user
3195164281Sambrisko		 * will clobber some data
3196164281Sambrisko		 */
3197164281Sambrisko		context = cm->cm_frame->header.context;
3198233711Sambrisko		cm->cm_frame->header.context = cm->cm_index;
3199164281Sambrisko
3200165225Sambrisko		bcopy(ioc->mfi_frame.raw, cm->cm_frame,
3201233711Sambrisko		    2 * MEGAMFI_FRAME_SIZE);
3202184897Sambrisko		cm->cm_total_frame_size = (sizeof(union mfi_sgl)
3203184897Sambrisko		    * ioc->mfi_sge_count) + ioc->mfi_sgl_off;
3204233711Sambrisko		cm->cm_frame->header.scsi_status = 0;
3205233711Sambrisko		cm->cm_frame->header.pad0 = 0;
3206175897Sambrisko		if (ioc->mfi_sge_count) {
3207175897Sambrisko			cm->cm_sg =
3208175897Sambrisko			    (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off];
3209175897Sambrisko		}
3210233711Sambrisko		sgl = cm->cm_sg;
3211175897Sambrisko		cm->cm_flags = 0;
3212175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
3213175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN;
3214175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
3215175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAOUT;
3216175897Sambrisko		/* Legacy app shim */
3217175897Sambrisko		if (cm->cm_flags == 0)
3218175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
3219164281Sambrisko		cm->cm_len = cm->cm_frame->header.data_len;
3220225869Smav		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
3221233711Sambrisko#ifdef COMPAT_FREEBSD32
3222225869Smav			if (cmd == MFI_CMD) {
3223225869Smav#endif
3224225869Smav				/* Native */
3225225869Smav				cm->cm_stp_len = ioc->mfi_sgl[0].iov_len;
3226233711Sambrisko#ifdef COMPAT_FREEBSD32
3227225869Smav			} else {
3228225869Smav				/* 32bit on 64bit */
3229225869Smav				ioc32 = (struct mfi_ioc_packet32 *)ioc;
3230225869Smav				cm->cm_stp_len = ioc32->mfi_sgl[0].iov_len;
3231225869Smav			}
3232225869Smav#endif
3233225869Smav			cm->cm_len += cm->cm_stp_len;
3234225869Smav		}
3235184897Sambrisko		if (cm->cm_len &&
3236184897Sambrisko		    (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
3237175897Sambrisko			cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
3238175897Sambrisko			    M_WAITOK | M_ZERO);
3239175897Sambrisko			if (cm->cm_data == NULL) {
3240175897Sambrisko				device_printf(sc->mfi_dev, "Malloc failed\n");
3241175897Sambrisko				goto out;
3242175897Sambrisko			}
3243175897Sambrisko		} else {
3244175897Sambrisko			cm->cm_data = 0;
3245165225Sambrisko		}
3246164281Sambrisko
3247164281Sambrisko		/* restore header context */
3248164281Sambrisko		cm->cm_frame->header.context = context;
3249164281Sambrisko
3250233711Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
3251233711Sambrisko			res = mfi_stp_cmd(sc, cm, arg);
3252233711Sambrisko			if (res != 0)
3253233711Sambrisko				goto out;
3254233711Sambrisko		} else {
3255233711Sambrisko			temp = data;
3256233711Sambrisko			if ((cm->cm_flags & MFI_CMD_DATAOUT) ||
3257233711Sambrisko			    (cm->cm_frame->header.cmd == MFI_CMD_STP)) {
3258233711Sambrisko				for (i = 0; i < ioc->mfi_sge_count; i++) {
3259233711Sambrisko#ifdef COMPAT_FREEBSD32
3260233711Sambrisko					if (cmd == MFI_CMD) {
3261225869Smav#endif
3262233711Sambrisko						/* Native */
3263233711Sambrisko						addr = ioc->mfi_sgl[i].iov_base;
3264233711Sambrisko						len = ioc->mfi_sgl[i].iov_len;
3265233711Sambrisko#ifdef COMPAT_FREEBSD32
3266233711Sambrisko					} else {
3267233711Sambrisko						/* 32bit on 64bit */
3268233711Sambrisko						ioc32 = (struct mfi_ioc_packet32 *)ioc;
3269233711Sambrisko						addr = PTRIN(ioc32->mfi_sgl[i].iov_base);
3270233711Sambrisko						len = ioc32->mfi_sgl[i].iov_len;
3271233711Sambrisko					}
3272179392Sambrisko#endif
3273233711Sambrisko					error = copyin(addr, temp, len);
3274233711Sambrisko					if (error != 0) {
3275233711Sambrisko						device_printf(sc->mfi_dev,
3276233711Sambrisko						    "Copy in failed\n");
3277233711Sambrisko						goto out;
3278233711Sambrisko					}
3279233711Sambrisko					temp = &temp[len];
3280175897Sambrisko				}
3281164281Sambrisko			}
3282164281Sambrisko		}
3283164281Sambrisko
3284171821Sjhb		if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
3285233711Sambrisko			locked = mfi_config_lock(sc,
3286233711Sambrisko			     cm->cm_frame->dcmd.opcode);
3287171821Sjhb
3288184933Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
3289233711Sambrisko			cm->cm_frame->pass.sense_addr_lo =
3290233711Sambrisko			    (uint32_t)cm->cm_sense_busaddr;
3291233711Sambrisko			cm->cm_frame->pass.sense_addr_hi =
3292233711Sambrisko			    (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
3293184933Sambrisko		}
3294164281Sambrisko		mtx_lock(&sc->mfi_io_lock);
3295233711Sambrisko		skip_pre_post = mfi_check_for_sscd (sc, cm);
3296233711Sambrisko		if (!skip_pre_post) {
3297233711Sambrisko			error = mfi_check_command_pre(sc, cm);
3298233711Sambrisko			if (error) {
3299233711Sambrisko				mtx_unlock(&sc->mfi_io_lock);
3300233711Sambrisko				goto out;
3301233711Sambrisko			}
3302171821Sjhb		}
3303170284Sambrisko		if ((error = mfi_wait_command(sc, cm)) != 0) {
3304164281Sambrisko			device_printf(sc->mfi_dev,
3305165225Sambrisko			    "Controller polled failed\n");
3306164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3307164281Sambrisko			goto out;
3308164281Sambrisko		}
3309233711Sambrisko		if (!skip_pre_post) {
3310233711Sambrisko			mfi_check_command_post(sc, cm);
3311233711Sambrisko		}
3312164281Sambrisko		mtx_unlock(&sc->mfi_io_lock);
3313164281Sambrisko
3314233711Sambrisko		if (cm->cm_frame->header.cmd != MFI_CMD_STP) {
3315233711Sambrisko			temp = data;
3316233711Sambrisko			if ((cm->cm_flags & MFI_CMD_DATAIN) ||
3317233711Sambrisko			    (cm->cm_frame->header.cmd == MFI_CMD_STP)) {
3318233711Sambrisko				for (i = 0; i < ioc->mfi_sge_count; i++) {
3319233711Sambrisko#ifdef COMPAT_FREEBSD32
3320233711Sambrisko					if (cmd == MFI_CMD) {
3321225869Smav#endif
3322233711Sambrisko						/* Native */
3323233711Sambrisko						addr = ioc->mfi_sgl[i].iov_base;
3324233711Sambrisko						len = ioc->mfi_sgl[i].iov_len;
3325233711Sambrisko#ifdef COMPAT_FREEBSD32
3326233711Sambrisko					} else {
3327233711Sambrisko						/* 32bit on 64bit */
3328233711Sambrisko						ioc32 = (struct mfi_ioc_packet32 *)ioc;
3329233711Sambrisko						addr = PTRIN(ioc32->mfi_sgl[i].iov_base);
3330233711Sambrisko						len = ioc32->mfi_sgl[i].iov_len;
3331233711Sambrisko					}
3332179392Sambrisko#endif
3333233711Sambrisko					error = copyout(temp, addr, len);
3334233711Sambrisko					if (error != 0) {
3335233711Sambrisko						device_printf(sc->mfi_dev,
3336233711Sambrisko						    "Copy out failed\n");
3337233711Sambrisko						goto out;
3338233711Sambrisko					}
3339233711Sambrisko					temp = &temp[len];
3340175897Sambrisko				}
3341164281Sambrisko			}
3342164281Sambrisko		}
3343164281Sambrisko
3344165225Sambrisko		if (ioc->mfi_sense_len) {
3345184897Sambrisko			/* get user-space sense ptr then copy out sense */
3346225428Sbz			bcopy(&ioc->mfi_frame.raw[ioc->mfi_sense_off],
3347184897Sambrisko			    &sense_ptr.sense_ptr_data[0],
3348184897Sambrisko			    sizeof(sense_ptr.sense_ptr_data));
3349233711Sambrisko#ifdef COMPAT_FREEBSD32
3350184974Sambrisko			if (cmd != MFI_CMD) {
3351184974Sambrisko				/*
3352184974Sambrisko				 * not 64bit native so zero out any address
3353184974Sambrisko				 * over 32bit */
3354184975Sambrisko				sense_ptr.addr.high = 0;
3355184974Sambrisko			}
3356184974Sambrisko#endif
3357184897Sambrisko			error = copyout(cm->cm_sense, sense_ptr.user_space,
3358165225Sambrisko			    ioc->mfi_sense_len);
3359164281Sambrisko			if (error != 0) {
3360164281Sambrisko				device_printf(sc->mfi_dev,
3361165225Sambrisko				    "Copy out failed\n");
3362164281Sambrisko				goto out;
3363164281Sambrisko			}
3364164281Sambrisko		}
3365164281Sambrisko
3366165225Sambrisko		ioc->mfi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status;
3367164281Sambriskoout:
3368171821Sjhb		mfi_config_unlock(sc, locked);
3369164281Sambrisko		if (data)
3370164281Sambrisko			free(data, M_MFIBUF);
3371233711Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
3372233711Sambrisko			for (i = 0; i < 2; i++) {
3373233711Sambrisko				if (sc->kbuff_arr[i]) {
3374233711Sambrisko					if (sc->mfi_kbuff_arr_busaddr != 0)
3375233711Sambrisko						bus_dmamap_unload(
3376233711Sambrisko						    sc->mfi_kbuff_arr_dmat[i],
3377233711Sambrisko						    sc->mfi_kbuff_arr_dmamap[i]
3378233711Sambrisko						    );
3379233711Sambrisko					if (sc->kbuff_arr[i] != NULL)
3380233711Sambrisko						bus_dmamem_free(
3381233711Sambrisko						    sc->mfi_kbuff_arr_dmat[i],
3382233711Sambrisko						    sc->kbuff_arr[i],
3383233711Sambrisko						    sc->mfi_kbuff_arr_dmamap[i]
3384233711Sambrisko						    );
3385233711Sambrisko					if (sc->mfi_kbuff_arr_dmat[i] != NULL)
3386233711Sambrisko						bus_dma_tag_destroy(
3387233711Sambrisko						    sc->mfi_kbuff_arr_dmat[i]);
3388233711Sambrisko				}
3389233711Sambrisko			}
3390233711Sambrisko		}
3391164281Sambrisko		if (cm) {
3392164281Sambrisko			mtx_lock(&sc->mfi_io_lock);
3393164281Sambrisko			mfi_release_command(cm);
3394164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3395164281Sambrisko		}
3396164281Sambrisko
3397164281Sambrisko		break;
3398177489Sambrisko		}
3399164281Sambrisko	case MFI_SET_AEN:
3400164281Sambrisko		aen = (struct mfi_ioc_aen *)arg;
3401247369Ssmh		mtx_lock(&sc->mfi_io_lock);
3402164281Sambrisko		error = mfi_aen_register(sc, aen->aen_seq_num,
3403164281Sambrisko		    aen->aen_class_locale);
3404247369Ssmh		mtx_unlock(&sc->mfi_io_lock);
3405164281Sambrisko
3406164281Sambrisko		break;
3407164281Sambrisko	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
3408158737Sambrisko		{
3409158737Sambrisko			devclass_t devclass;
3410158737Sambrisko			struct mfi_linux_ioc_packet l_ioc;
3411158737Sambrisko			int adapter;
3412158737Sambrisko
3413158737Sambrisko			devclass = devclass_find("mfi");
3414158737Sambrisko			if (devclass == NULL)
3415158737Sambrisko				return (ENOENT);
3416158737Sambrisko
3417158737Sambrisko			error = copyin(arg, &l_ioc, sizeof(l_ioc));
3418158737Sambrisko			if (error)
3419158737Sambrisko				return (error);
3420158737Sambrisko			adapter = l_ioc.lioc_adapter_no;
3421158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
3422158737Sambrisko			if (sc == NULL)
3423158737Sambrisko				return (ENOENT);
3424158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
3425158737Sambrisko			    cmd, arg, flag, td));
3426158737Sambrisko			break;
3427158737Sambrisko		}
3428164281Sambrisko	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
3429158737Sambrisko		{
3430158737Sambrisko			devclass_t devclass;
3431158737Sambrisko			struct mfi_linux_ioc_aen l_aen;
3432158737Sambrisko			int adapter;
3433158737Sambrisko
3434158737Sambrisko			devclass = devclass_find("mfi");
3435158737Sambrisko			if (devclass == NULL)
3436158737Sambrisko				return (ENOENT);
3437158737Sambrisko
3438158737Sambrisko			error = copyin(arg, &l_aen, sizeof(l_aen));
3439158737Sambrisko			if (error)
3440158737Sambrisko				return (error);
3441158737Sambrisko			adapter = l_aen.laen_adapter_no;
3442158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
3443158737Sambrisko			if (sc == NULL)
3444158737Sambrisko				return (ENOENT);
3445158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
3446158737Sambrisko			    cmd, arg, flag, td));
3447158737Sambrisko			break;
3448158737Sambrisko		}
3449233711Sambrisko#ifdef COMPAT_FREEBSD32
3450178968Sscottl	case MFIIO_PASSTHRU32:
3451238077Sjhb		if (!SV_CURPROC_FLAG(SV_ILP32)) {
3452238077Sjhb			error = ENOTTY;
3453238077Sjhb			break;
3454238077Sjhb		}
3455178968Sscottl		iop_swab.ioc_frame	= iop32->ioc_frame;
3456178968Sscottl		iop_swab.buf_size	= iop32->buf_size;
3457178968Sscottl		iop_swab.buf		= PTRIN(iop32->buf);
3458178968Sscottl		iop			= &iop_swab;
3459178968Sscottl		/* FALLTHROUGH */
3460178968Sscottl#endif
3461178968Sscottl	case MFIIO_PASSTHRU:
3462178968Sscottl		error = mfi_user_command(sc, iop);
3463233711Sambrisko#ifdef COMPAT_FREEBSD32
3464178968Sscottl		if (cmd == MFIIO_PASSTHRU32)
3465178968Sscottl			iop32->ioc_frame = iop_swab.ioc_frame;
3466178968Sscottl#endif
3467178968Sscottl		break;
3468157114Sscottl	default:
3469163398Sscottl		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
3470238077Sjhb		error = ENOTTY;
3471157114Sscottl		break;
3472157114Sscottl	}
3473157114Sscottl
3474157114Sscottl	return (error);
3475157114Sscottl}
3476158737Sambrisko
3477158737Sambriskostatic int
3478192450Simpmfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
3479158737Sambrisko{
3480158737Sambrisko	struct mfi_softc *sc;
3481158737Sambrisko	struct mfi_linux_ioc_packet l_ioc;
3482158737Sambrisko	struct mfi_linux_ioc_aen l_aen;
3483158737Sambrisko	struct mfi_command *cm = NULL;
3484158737Sambrisko	struct mfi_aen *mfi_aen_entry;
3485184897Sambrisko	union mfi_sense_ptr sense_ptr;
3486233711Sambrisko	uint32_t context = 0;
3487158737Sambrisko	uint8_t *data = NULL, *temp;
3488158737Sambrisko	int i;
3489171821Sjhb	int error, locked;
3490158737Sambrisko
3491158737Sambrisko	sc = dev->si_drv1;
3492158737Sambrisko	error = 0;
3493158737Sambrisko	switch (cmd) {
3494164281Sambrisko	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
3495158737Sambrisko		error = copyin(arg, &l_ioc, sizeof(l_ioc));
3496158737Sambrisko		if (error != 0)
3497158737Sambrisko			return (error);
3498158737Sambrisko
3499158737Sambrisko		if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) {
3500158737Sambrisko			return (EINVAL);
3501158737Sambrisko		}
3502158737Sambrisko
3503158737Sambrisko		mtx_lock(&sc->mfi_io_lock);
3504158737Sambrisko		if ((cm = mfi_dequeue_free(sc)) == NULL) {
3505158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3506158737Sambrisko			return (EBUSY);
3507158737Sambrisko		}
3508158737Sambrisko		mtx_unlock(&sc->mfi_io_lock);
3509171821Sjhb		locked = 0;
3510158737Sambrisko
3511158737Sambrisko		/*
3512158737Sambrisko		 * save off original context since copying from user
3513158737Sambrisko		 * will clobber some data
3514158737Sambrisko		 */
3515158737Sambrisko		context = cm->cm_frame->header.context;
3516158737Sambrisko
3517158737Sambrisko		bcopy(l_ioc.lioc_frame.raw, cm->cm_frame,
3518175897Sambrisko		      2 * MFI_DCMD_FRAME_SIZE);	/* this isn't quite right */
3519184897Sambrisko		cm->cm_total_frame_size = (sizeof(union mfi_sgl)
3520184897Sambrisko		      * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off;
3521233711Sambrisko		cm->cm_frame->header.scsi_status = 0;
3522233711Sambrisko		cm->cm_frame->header.pad0 = 0;
3523175897Sambrisko		if (l_ioc.lioc_sge_count)
3524175897Sambrisko			cm->cm_sg =
3525175897Sambrisko			    (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
3526175897Sambrisko		cm->cm_flags = 0;
3527175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
3528175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN;
3529175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
3530175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAOUT;
3531158737Sambrisko		cm->cm_len = cm->cm_frame->header.data_len;
3532184897Sambrisko		if (cm->cm_len &&
3533184897Sambrisko		      (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
3534175897Sambrisko			cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
3535175897Sambrisko			    M_WAITOK | M_ZERO);
3536175897Sambrisko			if (cm->cm_data == NULL) {
3537175897Sambrisko				device_printf(sc->mfi_dev, "Malloc failed\n");
3538175897Sambrisko				goto out;
3539175897Sambrisko			}
3540175897Sambrisko		} else {
3541175897Sambrisko			cm->cm_data = 0;
3542175897Sambrisko		}
3543158737Sambrisko
3544158737Sambrisko		/* restore header context */
3545158737Sambrisko		cm->cm_frame->header.context = context;
3546158737Sambrisko
3547158737Sambrisko		temp = data;
3548175897Sambrisko		if (cm->cm_flags & MFI_CMD_DATAOUT) {
3549175897Sambrisko			for (i = 0; i < l_ioc.lioc_sge_count; i++) {
3550178968Sscottl				error = copyin(PTRIN(l_ioc.lioc_sgl[i].iov_base),
3551175897Sambrisko				       temp,
3552175897Sambrisko				       l_ioc.lioc_sgl[i].iov_len);
3553175897Sambrisko				if (error != 0) {
3554175897Sambrisko					device_printf(sc->mfi_dev,
3555175897Sambrisko					    "Copy in failed\n");
3556175897Sambrisko					goto out;
3557175897Sambrisko				}
3558175897Sambrisko				temp = &temp[l_ioc.lioc_sgl[i].iov_len];
3559158737Sambrisko			}
3560158737Sambrisko		}
3561158737Sambrisko
3562171821Sjhb		if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
3563171821Sjhb			locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
3564171821Sjhb
3565184933Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
3566233711Sambrisko			cm->cm_frame->pass.sense_addr_lo =
3567233711Sambrisko			    (uint32_t)cm->cm_sense_busaddr;
3568233711Sambrisko			cm->cm_frame->pass.sense_addr_hi =
3569233711Sambrisko			    (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
3570184933Sambrisko		}
3571184933Sambrisko
3572163398Sscottl		mtx_lock(&sc->mfi_io_lock);
3573171821Sjhb		error = mfi_check_command_pre(sc, cm);
3574171821Sjhb		if (error) {
3575171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
3576171821Sjhb			goto out;
3577171821Sjhb		}
3578171821Sjhb
3579170284Sambrisko		if ((error = mfi_wait_command(sc, cm)) != 0) {
3580158737Sambrisko			device_printf(sc->mfi_dev,
3581165225Sambrisko			    "Controller polled failed\n");
3582163398Sscottl			mtx_unlock(&sc->mfi_io_lock);
3583158737Sambrisko			goto out;
3584158737Sambrisko		}
3585158737Sambrisko
3586171821Sjhb		mfi_check_command_post(sc, cm);
3587163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
3588158737Sambrisko
3589158737Sambrisko		temp = data;
3590175897Sambrisko		if (cm->cm_flags & MFI_CMD_DATAIN) {
3591175897Sambrisko			for (i = 0; i < l_ioc.lioc_sge_count; i++) {
3592175897Sambrisko				error = copyout(temp,
3593178968Sscottl					PTRIN(l_ioc.lioc_sgl[i].iov_base),
3594175897Sambrisko					l_ioc.lioc_sgl[i].iov_len);
3595175897Sambrisko				if (error != 0) {
3596175897Sambrisko					device_printf(sc->mfi_dev,
3597175897Sambrisko					    "Copy out failed\n");
3598175897Sambrisko					goto out;
3599175897Sambrisko				}
3600175897Sambrisko				temp = &temp[l_ioc.lioc_sgl[i].iov_len];
3601158737Sambrisko			}
3602158737Sambrisko		}
3603158737Sambrisko
3604158737Sambrisko		if (l_ioc.lioc_sense_len) {
3605184897Sambrisko			/* get user-space sense ptr then copy out sense */
3606184897Sambrisko			bcopy(&((struct mfi_linux_ioc_packet*)arg)
3607184897Sambrisko                            ->lioc_frame.raw[l_ioc.lioc_sense_off],
3608184897Sambrisko			    &sense_ptr.sense_ptr_data[0],
3609184897Sambrisko			    sizeof(sense_ptr.sense_ptr_data));
3610184974Sambrisko#ifdef __amd64__
3611184974Sambrisko			/*
3612184974Sambrisko			 * only 32bit Linux support so zero out any
3613184974Sambrisko			 * address over 32bit
3614184974Sambrisko			 */
3615184975Sambrisko			sense_ptr.addr.high = 0;
3616184974Sambrisko#endif
3617184897Sambrisko			error = copyout(cm->cm_sense, sense_ptr.user_space,
3618158737Sambrisko			    l_ioc.lioc_sense_len);
3619158737Sambrisko			if (error != 0) {
3620158737Sambrisko				device_printf(sc->mfi_dev,
3621165225Sambrisko				    "Copy out failed\n");
3622158737Sambrisko				goto out;
3623158737Sambrisko			}
3624158737Sambrisko		}
3625158737Sambrisko
3626158737Sambrisko		error = copyout(&cm->cm_frame->header.cmd_status,
3627158737Sambrisko			&((struct mfi_linux_ioc_packet*)arg)
3628158737Sambrisko			->lioc_frame.hdr.cmd_status,
3629158737Sambrisko			1);
3630158737Sambrisko		if (error != 0) {
3631158737Sambrisko			device_printf(sc->mfi_dev,
3632165225Sambrisko				      "Copy out failed\n");
3633158737Sambrisko			goto out;
3634158737Sambrisko		}
3635158737Sambrisko
3636158737Sambriskoout:
3637171821Sjhb		mfi_config_unlock(sc, locked);
3638158737Sambrisko		if (data)
3639158737Sambrisko			free(data, M_MFIBUF);
3640158737Sambrisko		if (cm) {
3641158737Sambrisko			mtx_lock(&sc->mfi_io_lock);
3642158737Sambrisko			mfi_release_command(cm);
3643158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3644158737Sambrisko		}
3645158737Sambrisko
3646158737Sambrisko		return (error);
3647164281Sambrisko	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
3648158737Sambrisko		error = copyin(arg, &l_aen, sizeof(l_aen));
3649158737Sambrisko		if (error != 0)
3650158737Sambrisko			return (error);
3651158737Sambrisko		printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid);
3652158737Sambrisko		mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF,
3653158737Sambrisko		    M_WAITOK);
3654163398Sscottl		mtx_lock(&sc->mfi_io_lock);
3655158737Sambrisko		if (mfi_aen_entry != NULL) {
3656158737Sambrisko			mfi_aen_entry->p = curproc;
3657158737Sambrisko			TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry,
3658158737Sambrisko			    aen_link);
3659158737Sambrisko		}
3660158737Sambrisko		error = mfi_aen_register(sc, l_aen.laen_seq_num,
3661158737Sambrisko		    l_aen.laen_class_locale);
3662158737Sambrisko
3663158737Sambrisko		if (error != 0) {
3664158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
3665158737Sambrisko			    aen_link);
3666158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
3667158737Sambrisko		}
3668163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
3669158737Sambrisko
3670158737Sambrisko		return (error);
3671158737Sambrisko	default:
3672158737Sambrisko		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
3673158737Sambrisko		error = ENOENT;
3674158737Sambrisko		break;
3675158737Sambrisko	}
3676158737Sambrisko
3677158737Sambrisko	return (error);
3678158737Sambrisko}
3679158737Sambrisko
3680158737Sambriskostatic int
3681158737Sambriskomfi_poll(struct cdev *dev, int poll_events, struct thread *td)
3682158737Sambrisko{
3683158737Sambrisko	struct mfi_softc *sc;
3684158737Sambrisko	int revents = 0;
3685158737Sambrisko
3686158737Sambrisko	sc = dev->si_drv1;
3687158737Sambrisko
3688158737Sambrisko	if (poll_events & (POLLIN | POLLRDNORM)) {
3689163398Sscottl		if (sc->mfi_aen_triggered != 0) {
3690158737Sambrisko			revents |= poll_events & (POLLIN | POLLRDNORM);
3691163398Sscottl			sc->mfi_aen_triggered = 0;
3692163398Sscottl		}
3693158737Sambrisko		if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) {
3694158737Sambrisko			revents |= POLLERR;
3695158737Sambrisko		}
3696158737Sambrisko	}
3697158737Sambrisko
3698158737Sambrisko	if (revents == 0) {
3699158737Sambrisko		if (poll_events & (POLLIN | POLLRDNORM)) {
3700158737Sambrisko			sc->mfi_poll_waiting = 1;
3701158737Sambrisko			selrecord(td, &sc->mfi_select);
3702158737Sambrisko		}
3703158737Sambrisko	}
3704158737Sambrisko
3705158737Sambrisko	return revents;
3706158737Sambrisko}
3707162619Sscottl
3708162619Sscottlstatic void
3709163398Sscottlmfi_dump_all(void)
3710163398Sscottl{
3711163398Sscottl	struct mfi_softc *sc;
3712163398Sscottl	struct mfi_command *cm;
3713163398Sscottl	devclass_t dc;
3714163398Sscottl	time_t deadline;
3715163398Sscottl	int timedout;
3716163398Sscottl	int i;
3717163398Sscottl
3718163398Sscottl	dc = devclass_find("mfi");
3719163398Sscottl	if (dc == NULL) {
3720163398Sscottl		printf("No mfi dev class\n");
3721163398Sscottl		return;
3722163398Sscottl	}
3723163398Sscottl
3724163398Sscottl	for (i = 0; ; i++) {
3725163398Sscottl		sc = devclass_get_softc(dc, i);
3726163398Sscottl		if (sc == NULL)
3727163398Sscottl			break;
3728163398Sscottl		device_printf(sc->mfi_dev, "Dumping\n\n");
3729163398Sscottl		timedout = 0;
3730247426Ssmh		deadline = time_uptime - mfi_cmd_timeout;
3731163398Sscottl		mtx_lock(&sc->mfi_io_lock);
3732163398Sscottl		TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
3733247369Ssmh			if (cm->cm_timestamp <= deadline) {
3734163398Sscottl				device_printf(sc->mfi_dev,
3735233711Sambrisko				    "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
3736233711Sambrisko				    cm, (int)(time_uptime - cm->cm_timestamp));
3737163398Sscottl				MFI_PRINT_CMD(cm);
3738163398Sscottl				timedout++;
3739163398Sscottl			}
3740163398Sscottl		}
3741163398Sscottl
3742163398Sscottl#if 0
3743163398Sscottl		if (timedout)
3744247369Ssmh			MFI_DUMP_CMDS(sc);
3745163398Sscottl#endif
3746163398Sscottl
3747163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
3748163398Sscottl	}
3749163398Sscottl
3750163398Sscottl	return;
3751163398Sscottl}
3752163398Sscottl
3753163398Sscottlstatic void
3754162619Sscottlmfi_timeout(void *data)
3755162619Sscottl{
3756162619Sscottl	struct mfi_softc *sc = (struct mfi_softc *)data;
3757247369Ssmh	struct mfi_command *cm, *tmp;
3758162619Sscottl	time_t deadline;
3759162619Sscottl	int timedout = 0;
3760162619Sscottl
3761247426Ssmh	deadline = time_uptime - mfi_cmd_timeout;
3762233711Sambrisko	if (sc->adpreset == 0) {
3763233711Sambrisko		if (!mfi_tbolt_reset(sc)) {
3764247426Ssmh			callout_reset(&sc->mfi_watchdog_callout,
3765247426Ssmh			    mfi_cmd_timeout * hz, mfi_timeout, sc);
3766233711Sambrisko			return;
3767233711Sambrisko		}
3768233711Sambrisko	}
3769162619Sscottl	mtx_lock(&sc->mfi_io_lock);
3770247369Ssmh	TAILQ_FOREACH_SAFE(cm, &sc->mfi_busy, cm_link, tmp) {
3771235014Sambrisko		if (sc->mfi_aen_cm == cm || sc->mfi_map_sync_cm == cm)
3772162688Sscottl			continue;
3773247369Ssmh		if (cm->cm_timestamp <= deadline) {
3774233711Sambrisko			if (sc->adpreset != 0 && sc->issuepend_done == 0) {
3775233711Sambrisko				cm->cm_timestamp = time_uptime;
3776233711Sambrisko			} else {
3777233711Sambrisko				device_printf(sc->mfi_dev,
3778233711Sambrisko				    "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
3779233711Sambrisko				     cm, (int)(time_uptime - cm->cm_timestamp)
3780233711Sambrisko				     );
3781233711Sambrisko				MFI_PRINT_CMD(cm);
3782233711Sambrisko				MFI_VALIDATE_CMD(sc, cm);
3783247369Ssmh				/*
3784252471Ssmh				 * While commands can get stuck forever we do
3785252471Ssmh				 * not fail them as there is no way to tell if
3786252471Ssmh				 * the controller has actually processed them
3787252471Ssmh				 * or not.
3788252471Ssmh				 *
3789252471Ssmh				 * In addition its very likely that force
3790252471Ssmh				 * failing a command here would cause a panic
3791252471Ssmh				 * e.g. in UFS.
3792247369Ssmh				 */
3793233711Sambrisko				timedout++;
3794233711Sambrisko			}
3795162619Sscottl		}
3796162619Sscottl	}
3797162619Sscottl
3798162619Sscottl#if 0
3799162619Sscottl	if (timedout)
3800247369Ssmh		MFI_DUMP_CMDS(sc);
3801162619Sscottl#endif
3802162619Sscottl
3803162619Sscottl	mtx_unlock(&sc->mfi_io_lock);
3804162619Sscottl
3805247426Ssmh	callout_reset(&sc->mfi_watchdog_callout, mfi_cmd_timeout * hz,
3806162619Sscottl	    mfi_timeout, sc);
3807162619Sscottl
3808163398Sscottl	if (0)
3809163398Sscottl		mfi_dump_all();
3810162619Sscottl	return;
3811162619Sscottl}
3812