mfi.c revision 240962
1157114Sscottl/*-
2157114Sscottl * Copyright (c) 2006 IronPort Systems
3157114Sscottl * All rights reserved.
4157114Sscottl *
5157114Sscottl * Redistribution and use in source and binary forms, with or without
6157114Sscottl * modification, are permitted provided that the following conditions
7157114Sscottl * are met:
8157114Sscottl * 1. Redistributions of source code must retain the above copyright
9157114Sscottl *    notice, this list of conditions and the following disclaimer.
10157114Sscottl * 2. Redistributions in binary form must reproduce the above copyright
11157114Sscottl *    notice, this list of conditions and the following disclaimer in the
12157114Sscottl *    documentation and/or other materials provided with the distribution.
13157114Sscottl *
14157114Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15157114Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16157114Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17157114Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18157114Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19157114Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20157114Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21157114Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22157114Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23157114Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24157114Sscottl * SUCH DAMAGE.
25157114Sscottl */
26171980Sscottl/*-
27171980Sscottl * Copyright (c) 2007 LSI Corp.
28171980Sscottl * Copyright (c) 2007 Rajesh Prabhakaran.
29171980Sscottl * All rights reserved.
30171980Sscottl *
31171980Sscottl * Redistribution and use in source and binary forms, with or without
32171980Sscottl * modification, are permitted provided that the following conditions
33171980Sscottl * are met:
34171980Sscottl * 1. Redistributions of source code must retain the above copyright
35171980Sscottl *    notice, this list of conditions and the following disclaimer.
36171980Sscottl * 2. Redistributions in binary form must reproduce the above copyright
37171980Sscottl *    notice, this list of conditions and the following disclaimer in the
38171980Sscottl *    documentation and/or other materials provided with the distribution.
39171980Sscottl *
40171980Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
41171980Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42171980Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43171980Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44171980Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45171980Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46171980Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47171980Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48171980Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49171980Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50171980Sscottl * SUCH DAMAGE.
51171980Sscottl */
52157114Sscottl
53157114Sscottl#include <sys/cdefs.h>
54157114Sscottl__FBSDID("$FreeBSD: head/sys/dev/mfi/mfi.c 240962 2012-09-26 14:14:06Z jhb $");
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 *);
111158737Sambriskostatic int	mfi_abort(struct mfi_softc *, struct mfi_command *);
112192450Simpstatic int	mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int, struct thread *);
113162619Sscottlstatic void	mfi_timeout(void *);
114178968Sscottlstatic int	mfi_user_command(struct mfi_softc *,
115178968Sscottl		    struct mfi_ioc_passthru *);
116233711Sambriskostatic void	mfi_enable_intr_xscale(struct mfi_softc *sc);
117233711Sambriskostatic void	mfi_enable_intr_ppc(struct mfi_softc *sc);
118233711Sambriskostatic int32_t	mfi_read_fw_status_xscale(struct mfi_softc *sc);
119233711Sambriskostatic int32_t	mfi_read_fw_status_ppc(struct mfi_softc *sc);
120233711Sambriskostatic int	mfi_check_clear_intr_xscale(struct mfi_softc *sc);
121233711Sambriskostatic int	mfi_check_clear_intr_ppc(struct mfi_softc *sc);
122233711Sambriskostatic void 	mfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add,
123233711Sambrisko		    uint32_t frame_cnt);
124233711Sambriskostatic void 	mfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add,
125233711Sambrisko		    uint32_t frame_cnt);
126233711Sambriskostatic int mfi_config_lock(struct mfi_softc *sc, uint32_t opcode);
127233711Sambriskostatic void mfi_config_unlock(struct mfi_softc *sc, int locked);
128233711Sambriskostatic int mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm);
129233711Sambriskostatic void mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm);
130233711Sambriskostatic int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm);
131157114Sscottl
132227562SjhbSYSCTL_NODE(_hw, OID_AUTO, mfi, CTLFLAG_RD, 0, "MFI driver parameters");
133162118Sambriskostatic int	mfi_event_locale = MFI_EVT_LOCALE_ALL;
134162473SambriskoTUNABLE_INT("hw.mfi.event_locale", &mfi_event_locale);
135162118SambriskoSYSCTL_INT(_hw_mfi, OID_AUTO, event_locale, CTLFLAG_RW, &mfi_event_locale,
136162118Sambrisko            0, "event message locale");
137162473Sambrisko
138165852Sscottlstatic int	mfi_event_class = MFI_EVT_CLASS_INFO;
139162473SambriskoTUNABLE_INT("hw.mfi.event_class", &mfi_event_class);
140162118SambriskoSYSCTL_INT(_hw_mfi, OID_AUTO, event_class, CTLFLAG_RW, &mfi_event_class,
141162118Sambrisko          0, "event message class");
142162118Sambrisko
143178968Sscottlstatic int	mfi_max_cmds = 128;
144178968SscottlTUNABLE_INT("hw.mfi.max_cmds", &mfi_max_cmds);
145178968SscottlSYSCTL_INT(_hw_mfi, OID_AUTO, max_cmds, CTLFLAG_RD, &mfi_max_cmds,
146178968Sscottl	   0, "Max commands");
147178968Sscottl
148233711Sambriskostatic int	mfi_detect_jbod_change = 1;
149233711SambriskoTUNABLE_INT("hw.mfi.detect_jbod_change", &mfi_detect_jbod_change);
150233711SambriskoSYSCTL_INT(_hw_mfi, OID_AUTO, detect_jbod_change, CTLFLAG_RW,
151233711Sambrisko	   &mfi_detect_jbod_change, 0, "Detect a change to a JBOD");
152233711Sambrisko
153157114Sscottl/* Management interface */
154157114Sscottlstatic d_open_t		mfi_open;
155157114Sscottlstatic d_close_t	mfi_close;
156157114Sscottlstatic d_ioctl_t	mfi_ioctl;
157158737Sambriskostatic d_poll_t		mfi_poll;
158157114Sscottl
159157114Sscottlstatic struct cdevsw mfi_cdevsw = {
160157114Sscottl	.d_version = 	D_VERSION,
161157114Sscottl	.d_flags =	0,
162157114Sscottl	.d_open = 	mfi_open,
163157114Sscottl	.d_close =	mfi_close,
164157114Sscottl	.d_ioctl =	mfi_ioctl,
165158737Sambrisko	.d_poll =	mfi_poll,
166157114Sscottl	.d_name =	"mfi",
167157114Sscottl};
168157114Sscottl
169157114SscottlMALLOC_DEFINE(M_MFIBUF, "mfibuf", "Buffers for the MFI driver");
170157114Sscottl
171158737Sambrisko#define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH
172233711Sambriskostruct mfi_skinny_dma_info mfi_skinny;
173157114Sscottl
174171980Sscottlstatic void
175171980Sscottlmfi_enable_intr_xscale(struct mfi_softc *sc)
176171980Sscottl{
177171980Sscottl	MFI_WRITE4(sc, MFI_OMSK, 0x01);
178171980Sscottl}
179171980Sscottl
180171980Sscottlstatic void
181171980Sscottlmfi_enable_intr_ppc(struct mfi_softc *sc)
182171980Sscottl{
183184897Sambrisko	if (sc->mfi_flags & MFI_FLAGS_1078) {
184233711Sambrisko		MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
185184897Sambrisko		MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM);
186233711Sambrisko	}
187233711Sambrisko	else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
188233711Sambrisko		MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
189184897Sambrisko		MFI_WRITE4(sc, MFI_OMSK, ~MFI_GEN2_EIM);
190184897Sambrisko	}
191233711Sambrisko	else if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
192233711Sambrisko		MFI_WRITE4(sc, MFI_OMSK, ~0x00000001);
193233711Sambrisko	}
194171980Sscottl}
195171980Sscottl
196171980Sscottlstatic int32_t
197171980Sscottlmfi_read_fw_status_xscale(struct mfi_softc *sc)
198171980Sscottl{
199171980Sscottl	return MFI_READ4(sc, MFI_OMSG0);
200171980Sscottl}
201184897Sambrisko
202171980Sscottlstatic int32_t
203171980Sscottlmfi_read_fw_status_ppc(struct mfi_softc *sc)
204171980Sscottl{
205171980Sscottl	return MFI_READ4(sc, MFI_OSP0);
206171980Sscottl}
207171980Sscottl
208184897Sambriskostatic int
209171980Sscottlmfi_check_clear_intr_xscale(struct mfi_softc *sc)
210171980Sscottl{
211171980Sscottl	int32_t status;
212171980Sscottl
213171980Sscottl	status = MFI_READ4(sc, MFI_OSTS);
214171980Sscottl	if ((status & MFI_OSTS_INTR_VALID) == 0)
215171980Sscottl		return 1;
216171980Sscottl
217171980Sscottl	MFI_WRITE4(sc, MFI_OSTS, status);
218171980Sscottl	return 0;
219182085Simp}
220171980Sscottl
221184897Sambriskostatic int
222171980Sscottlmfi_check_clear_intr_ppc(struct mfi_softc *sc)
223171980Sscottl{
224171980Sscottl	int32_t status;
225171980Sscottl
226171980Sscottl	status = MFI_READ4(sc, MFI_OSTS);
227184897Sambrisko	if (sc->mfi_flags & MFI_FLAGS_1078) {
228184897Sambrisko		if (!(status & MFI_1078_RM)) {
229184897Sambrisko			return 1;
230184897Sambrisko		}
231233711Sambrisko	}
232233711Sambrisko	else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
233184897Sambrisko		if (!(status & MFI_GEN2_RM)) {
234184897Sambrisko			return 1;
235184897Sambrisko		}
236184897Sambrisko	}
237233711Sambrisko	else if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
238233711Sambrisko		if (!(status & MFI_SKINNY_RM)) {
239233711Sambrisko			return 1;
240233711Sambrisko		}
241233711Sambrisko	}
242233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
243233711Sambrisko		MFI_WRITE4(sc, MFI_OSTS, status);
244233711Sambrisko	else
245233711Sambrisko		MFI_WRITE4(sc, MFI_ODCR0, status);
246171980Sscottl	return 0;
247182085Simp}
248171980Sscottl
249184897Sambriskostatic void
250233711Sambriskomfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt)
251171980Sscottl{
252171980Sscottl	MFI_WRITE4(sc, MFI_IQP,(bus_add >>3)|frame_cnt);
253171980Sscottl}
254184897Sambrisko
255184897Sambriskostatic void
256233711Sambriskomfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt)
257171980Sscottl{
258233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
259233711Sambrisko	    MFI_WRITE4(sc, MFI_IQPL, (bus_add | frame_cnt <<1)|1 );
260233711Sambrisko	    MFI_WRITE4(sc, MFI_IQPH, 0x00000000);
261233711Sambrisko	} else {
262233711Sambrisko	    MFI_WRITE4(sc, MFI_IQP, (bus_add | frame_cnt <<1)|1 );
263233711Sambrisko	}
264171980Sscottl}
265171980Sscottl
266233711Sambriskoint
267157114Sscottlmfi_transition_firmware(struct mfi_softc *sc)
268157114Sscottl{
269194851Sscottl	uint32_t fw_state, cur_state;
270157114Sscottl	int max_wait, i;
271233711Sambrisko	uint32_t cur_abs_reg_val = 0;
272233711Sambrisko	uint32_t prev_abs_reg_val = 0;
273157114Sscottl
274233711Sambrisko	cur_abs_reg_val = sc->mfi_read_fw_status(sc);
275233711Sambrisko	fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK;
276157114Sscottl	while (fw_state != MFI_FWSTATE_READY) {
277157114Sscottl		if (bootverbose)
278157114Sscottl			device_printf(sc->mfi_dev, "Waiting for firmware to "
279171980Sscottl			"become ready\n");
280157114Sscottl		cur_state = fw_state;
281157114Sscottl		switch (fw_state) {
282157114Sscottl		case MFI_FWSTATE_FAULT:
283157114Sscottl			device_printf(sc->mfi_dev, "Firmware fault\n");
284157114Sscottl			return (ENXIO);
285157114Sscottl		case MFI_FWSTATE_WAIT_HANDSHAKE:
286233711Sambrisko			if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
287233711Sambrisko			    MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
288233711Sambrisko			else
289233711Sambrisko			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
290233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
291157114Sscottl			break;
292157114Sscottl		case MFI_FWSTATE_OPERATIONAL:
293233711Sambrisko			if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
294233711Sambrisko			    MFI_WRITE4(sc, MFI_SKINNY_IDB, 7);
295233711Sambrisko			else
296233711Sambrisko			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY);
297233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
298157114Sscottl			break;
299157114Sscottl		case MFI_FWSTATE_UNDEFINED:
300157114Sscottl		case MFI_FWSTATE_BB_INIT:
301233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
302157114Sscottl			break;
303233711Sambrisko		case MFI_FWSTATE_FW_INIT_2:
304233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
305233711Sambrisko			break;
306157114Sscottl		case MFI_FWSTATE_FW_INIT:
307157114Sscottl		case MFI_FWSTATE_FLUSH_CACHE:
308233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
309157114Sscottl			break;
310233711Sambrisko		case MFI_FWSTATE_DEVICE_SCAN:
311233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME; /* wait for 180 seconds */
312233711Sambrisko			prev_abs_reg_val = cur_abs_reg_val;
313233711Sambrisko			break;
314224041Sjhb		case MFI_FWSTATE_BOOT_MESSAGE_PENDING:
315233711Sambrisko			if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
316233711Sambrisko			    MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_HOTPLUG);
317233711Sambrisko			else
318233711Sambrisko			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG);
319233711Sambrisko			max_wait = MFI_RESET_WAIT_TIME;
320224041Sjhb			break;
321157114Sscottl		default:
322233711Sambrisko			device_printf(sc->mfi_dev, "Unknown firmware state %#x\n",
323157114Sscottl			    fw_state);
324157114Sscottl			return (ENXIO);
325157114Sscottl		}
326157114Sscottl		for (i = 0; i < (max_wait * 10); i++) {
327233711Sambrisko			cur_abs_reg_val = sc->mfi_read_fw_status(sc);
328233711Sambrisko			fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK;
329157114Sscottl			if (fw_state == cur_state)
330157114Sscottl				DELAY(100000);
331157114Sscottl			else
332157114Sscottl				break;
333157114Sscottl		}
334233711Sambrisko		if (fw_state == MFI_FWSTATE_DEVICE_SCAN) {
335233711Sambrisko			/* Check the device scanning progress */
336233711Sambrisko			if (prev_abs_reg_val != cur_abs_reg_val) {
337233711Sambrisko				continue;
338233711Sambrisko			}
339233711Sambrisko		}
340157114Sscottl		if (fw_state == cur_state) {
341224041Sjhb			device_printf(sc->mfi_dev, "Firmware stuck in state "
342157114Sscottl			    "%#x\n", fw_state);
343157114Sscottl			return (ENXIO);
344157114Sscottl		}
345157114Sscottl	}
346157114Sscottl	return (0);
347157114Sscottl}
348157114Sscottl
349157114Sscottlstatic void
350233711Sambriskomfi_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
351157114Sscottl{
352233711Sambrisko	bus_addr_t *addr;
353157114Sscottl
354157114Sscottl	addr = arg;
355157114Sscottl	*addr = segs[0].ds_addr;
356157114Sscottl}
357157114Sscottl
358233711Sambrisko
359157114Sscottlint
360157114Sscottlmfi_attach(struct mfi_softc *sc)
361157114Sscottl{
362157114Sscottl	uint32_t status;
363157114Sscottl	int error, commsz, framessz, sensesz;
364162458Sscottl	int frames, unit, max_fw_sge;
365233711Sambrisko	uint32_t tb_mem_size = 0;
366157114Sscottl
367233711Sambrisko	if (sc == NULL)
368233711Sambrisko		return EINVAL;
369186132Sambrisko
370233711Sambrisko	device_printf(sc->mfi_dev, "Megaraid SAS driver Ver %s \n",
371233711Sambrisko	    MEGASAS_VERSION);
372233711Sambrisko
373157114Sscottl	mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF);
374171821Sjhb	sx_init(&sc->mfi_config_lock, "MFI config");
375157114Sscottl	TAILQ_INIT(&sc->mfi_ld_tqh);
376233711Sambrisko	TAILQ_INIT(&sc->mfi_syspd_tqh);
377233711Sambrisko	TAILQ_INIT(&sc->mfi_evt_queue);
378233711Sambrisko	TASK_INIT(&sc->mfi_evt_task, 0, mfi_handle_evt, sc);
379235014Sambrisko	TASK_INIT(&sc->mfi_map_sync_task, 0, mfi_handle_map_sync, sc);
380158737Sambrisko	TAILQ_INIT(&sc->mfi_aen_pids);
381169611Sscottl	TAILQ_INIT(&sc->mfi_cam_ccbq);
382157114Sscottl
383157114Sscottl	mfi_initq_free(sc);
384157114Sscottl	mfi_initq_ready(sc);
385157114Sscottl	mfi_initq_busy(sc);
386157114Sscottl	mfi_initq_bio(sc);
387157114Sscottl
388233711Sambrisko	sc->adpreset = 0;
389233711Sambrisko	sc->last_seq_num = 0;
390233711Sambrisko	sc->disableOnlineCtrlReset = 1;
391233711Sambrisko	sc->issuepend_done = 1;
392233711Sambrisko	sc->hw_crit_error = 0;
393233711Sambrisko
394171980Sscottl	if (sc->mfi_flags & MFI_FLAGS_1064R) {
395171980Sscottl		sc->mfi_enable_intr = mfi_enable_intr_xscale;
396171980Sscottl		sc->mfi_read_fw_status = mfi_read_fw_status_xscale;
397171980Sscottl		sc->mfi_check_clear_intr = mfi_check_clear_intr_xscale;
398171980Sscottl		sc->mfi_issue_cmd = mfi_issue_cmd_xscale;
399233711Sambrisko	} else if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
400233711Sambrisko		sc->mfi_enable_intr = mfi_tbolt_enable_intr_ppc;
401233711Sambrisko		sc->mfi_disable_intr = mfi_tbolt_disable_intr_ppc;
402233711Sambrisko		sc->mfi_read_fw_status = mfi_tbolt_read_fw_status_ppc;
403233711Sambrisko		sc->mfi_check_clear_intr = mfi_tbolt_check_clear_intr_ppc;
404233711Sambrisko		sc->mfi_issue_cmd = mfi_tbolt_issue_cmd_ppc;
405233711Sambrisko		sc->mfi_adp_reset = mfi_tbolt_adp_reset;
406233711Sambrisko		sc->mfi_tbolt = 1;
407233711Sambrisko		TAILQ_INIT(&sc->mfi_cmd_tbolt_tqh);
408233711Sambrisko	} else {
409171980Sscottl		sc->mfi_enable_intr =  mfi_enable_intr_ppc;
410233711Sambrisko		sc->mfi_read_fw_status = mfi_read_fw_status_ppc;
411171980Sscottl		sc->mfi_check_clear_intr = mfi_check_clear_intr_ppc;
412171980Sscottl		sc->mfi_issue_cmd = mfi_issue_cmd_ppc;
413171980Sscottl	}
414171980Sscottl
415171980Sscottl
416157114Sscottl	/* Before we get too far, see if the firmware is working */
417157114Sscottl	if ((error = mfi_transition_firmware(sc)) != 0) {
418157114Sscottl		device_printf(sc->mfi_dev, "Firmware not in READY state, "
419157114Sscottl		    "error %d\n", error);
420157114Sscottl		return (ENXIO);
421157114Sscottl	}
422157114Sscottl
423233711Sambrisko	/* Start: LSIP200113393 */
424233711Sambrisko	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
425233711Sambrisko				1, 0,			/* algnmnt, boundary */
426233711Sambrisko				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
427233711Sambrisko				BUS_SPACE_MAXADDR,	/* highaddr */
428233711Sambrisko				NULL, NULL,		/* filter, filterarg */
429233711Sambrisko				MEGASAS_MAX_NAME*sizeof(bus_addr_t),			/* maxsize */
430233711Sambrisko				1,			/* msegments */
431233711Sambrisko				MEGASAS_MAX_NAME*sizeof(bus_addr_t),			/* maxsegsize */
432233711Sambrisko				0,			/* flags */
433233711Sambrisko				NULL, NULL,		/* lockfunc, lockarg */
434233711Sambrisko				&sc->verbuf_h_dmat)) {
435233711Sambrisko		device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmat DMA tag\n");
436233711Sambrisko		return (ENOMEM);
437233711Sambrisko	}
438233711Sambrisko	if (bus_dmamem_alloc(sc->verbuf_h_dmat, (void **)&sc->verbuf,
439233711Sambrisko	    BUS_DMA_NOWAIT, &sc->verbuf_h_dmamap)) {
440233711Sambrisko		device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmamap memory\n");
441233711Sambrisko		return (ENOMEM);
442233711Sambrisko	}
443233711Sambrisko	bzero(sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t));
444233711Sambrisko	bus_dmamap_load(sc->verbuf_h_dmat, sc->verbuf_h_dmamap,
445233711Sambrisko	    sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t),
446233711Sambrisko	    mfi_addr_cb, &sc->verbuf_h_busaddr, 0);
447233711Sambrisko	/* End: LSIP200113393 */
448233711Sambrisko
449157114Sscottl	/*
450157114Sscottl	 * Get information needed for sizing the contiguous memory for the
451157114Sscottl	 * frame pool.  Size down the sgl parameter since we know that
452157114Sscottl	 * we will never need more than what's required for MAXPHYS.
453157114Sscottl	 * It would be nice if these constants were available at runtime
454157114Sscottl	 * instead of compile time.
455157114Sscottl	 */
456171980Sscottl	status = sc->mfi_read_fw_status(sc);
457157114Sscottl	sc->mfi_max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK;
458162458Sscottl	max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16;
459195534Sscottl	sc->mfi_max_sge = min(max_fw_sge, ((MFI_MAXPHYS / PAGE_SIZE) + 1));
460157114Sscottl
461233711Sambrisko	/* ThunderBolt Support get the contiguous memory */
462233711Sambrisko
463233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
464233711Sambrisko		mfi_tbolt_init_globals(sc);
465233711Sambrisko		device_printf(sc->mfi_dev, "MaxCmd = %x MaxSgl = %x state = %x \n",
466233711Sambrisko		    sc->mfi_max_fw_cmds, sc->mfi_max_sge, status);
467233711Sambrisko		tb_mem_size = mfi_tbolt_get_memory_requirement(sc);
468233711Sambrisko
469233711Sambrisko		if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
470233711Sambrisko				1, 0,			/* algnmnt, boundary */
471233711Sambrisko				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
472233711Sambrisko				BUS_SPACE_MAXADDR,	/* highaddr */
473233711Sambrisko				NULL, NULL,		/* filter, filterarg */
474233711Sambrisko				tb_mem_size,		/* maxsize */
475233711Sambrisko				1,			/* msegments */
476233711Sambrisko				tb_mem_size,		/* maxsegsize */
477233711Sambrisko				0,			/* flags */
478233711Sambrisko				NULL, NULL,		/* lockfunc, lockarg */
479233711Sambrisko				&sc->mfi_tb_dmat)) {
480233711Sambrisko			device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
481233711Sambrisko			return (ENOMEM);
482233711Sambrisko		}
483233711Sambrisko		if (bus_dmamem_alloc(sc->mfi_tb_dmat, (void **)&sc->request_message_pool,
484233711Sambrisko		BUS_DMA_NOWAIT, &sc->mfi_tb_dmamap)) {
485233711Sambrisko			device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
486233711Sambrisko			return (ENOMEM);
487233711Sambrisko		}
488233711Sambrisko		bzero(sc->request_message_pool, tb_mem_size);
489233711Sambrisko		bus_dmamap_load(sc->mfi_tb_dmat, sc->mfi_tb_dmamap,
490233711Sambrisko		sc->request_message_pool, tb_mem_size, mfi_addr_cb, &sc->mfi_tb_busaddr, 0);
491233711Sambrisko
492233711Sambrisko		/* For ThunderBolt memory init */
493233711Sambrisko		if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
494233711Sambrisko				0x100, 0,		/* alignmnt, boundary */
495233711Sambrisko				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
496233711Sambrisko				BUS_SPACE_MAXADDR,	/* highaddr */
497233711Sambrisko				NULL, NULL,		/* filter, filterarg */
498233711Sambrisko				MFI_FRAME_SIZE,		/* maxsize */
499233711Sambrisko				1,			/* msegments */
500233711Sambrisko				MFI_FRAME_SIZE,		/* maxsegsize */
501233711Sambrisko				0,			/* flags */
502233711Sambrisko				NULL, NULL,		/* lockfunc, lockarg */
503233711Sambrisko				&sc->mfi_tb_init_dmat)) {
504233711Sambrisko		device_printf(sc->mfi_dev, "Cannot allocate init DMA tag\n");
505233711Sambrisko		return (ENOMEM);
506233711Sambrisko		}
507233711Sambrisko		if (bus_dmamem_alloc(sc->mfi_tb_init_dmat, (void **)&sc->mfi_tb_init,
508233711Sambrisko		    BUS_DMA_NOWAIT, &sc->mfi_tb_init_dmamap)) {
509233711Sambrisko			device_printf(sc->mfi_dev, "Cannot allocate init memory\n");
510233711Sambrisko			return (ENOMEM);
511233711Sambrisko		}
512233711Sambrisko		bzero(sc->mfi_tb_init, MFI_FRAME_SIZE);
513233711Sambrisko		bus_dmamap_load(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap,
514233711Sambrisko		sc->mfi_tb_init, MFI_FRAME_SIZE, mfi_addr_cb,
515233711Sambrisko		    &sc->mfi_tb_init_busaddr, 0);
516233711Sambrisko		if (mfi_tbolt_init_desc_pool(sc, sc->request_message_pool,
517233711Sambrisko		    tb_mem_size)) {
518233711Sambrisko			device_printf(sc->mfi_dev,
519233711Sambrisko			    "Thunderbolt pool preparation error\n");
520233711Sambrisko			return 0;
521233711Sambrisko		}
522233711Sambrisko
523233711Sambrisko		/*
524233711Sambrisko		  Allocate DMA memory mapping for MPI2 IOC Init descriptor,
525233711Sambrisko		  we are taking it diffrent from what we have allocated for Request
526233711Sambrisko		  and reply descriptors to avoid confusion later
527233711Sambrisko		*/
528233711Sambrisko		tb_mem_size = sizeof(struct MPI2_IOC_INIT_REQUEST);
529233711Sambrisko		if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
530233711Sambrisko				1, 0,			/* algnmnt, boundary */
531233711Sambrisko				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
532233711Sambrisko				BUS_SPACE_MAXADDR,	/* highaddr */
533233711Sambrisko				NULL, NULL,		/* filter, filterarg */
534233711Sambrisko				tb_mem_size,		/* maxsize */
535233711Sambrisko				1,			/* msegments */
536233711Sambrisko				tb_mem_size,		/* maxsegsize */
537233711Sambrisko				0,			/* flags */
538233711Sambrisko				NULL, NULL,		/* lockfunc, lockarg */
539233711Sambrisko				&sc->mfi_tb_ioc_init_dmat)) {
540233711Sambrisko			device_printf(sc->mfi_dev,
541233711Sambrisko			    "Cannot allocate comms DMA tag\n");
542233711Sambrisko			return (ENOMEM);
543233711Sambrisko		}
544233711Sambrisko		if (bus_dmamem_alloc(sc->mfi_tb_ioc_init_dmat,
545233711Sambrisko		    (void **)&sc->mfi_tb_ioc_init_desc,
546233711Sambrisko		    BUS_DMA_NOWAIT, &sc->mfi_tb_ioc_init_dmamap)) {
547233711Sambrisko			device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
548233711Sambrisko			return (ENOMEM);
549233711Sambrisko		}
550233711Sambrisko		bzero(sc->mfi_tb_ioc_init_desc, tb_mem_size);
551233711Sambrisko		bus_dmamap_load(sc->mfi_tb_ioc_init_dmat, sc->mfi_tb_ioc_init_dmamap,
552233711Sambrisko		sc->mfi_tb_ioc_init_desc, tb_mem_size, mfi_addr_cb,
553233711Sambrisko		    &sc->mfi_tb_ioc_init_busaddr, 0);
554233711Sambrisko	}
555157114Sscottl	/*
556157114Sscottl	 * Create the dma tag for data buffers.  Used both for block I/O
557157114Sscottl	 * and for various internal data queries.
558157114Sscottl	 */
559157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
560157114Sscottl				1, 0,			/* algnmnt, boundary */
561157114Sscottl				BUS_SPACE_MAXADDR,	/* lowaddr */
562157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
563157114Sscottl				NULL, NULL,		/* filter, filterarg */
564157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
565162458Sscottl				sc->mfi_max_sge,	/* nsegments */
566157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
567157114Sscottl				BUS_DMA_ALLOCNOW,	/* flags */
568157114Sscottl				busdma_lock_mutex,	/* lockfunc */
569157114Sscottl				&sc->mfi_io_lock,	/* lockfuncarg */
570157114Sscottl				&sc->mfi_buffer_dmat)) {
571157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate buffer DMA tag\n");
572157114Sscottl		return (ENOMEM);
573157114Sscottl	}
574157114Sscottl
575157114Sscottl	/*
576157114Sscottl	 * Allocate DMA memory for the comms queues.  Keep it under 4GB for
577157114Sscottl	 * efficiency.  The mfi_hwcomms struct includes space for 1 reply queue
578157114Sscottl	 * entry, so the calculated size here will be will be 1 more than
579157114Sscottl	 * mfi_max_fw_cmds.  This is apparently a requirement of the hardware.
580157114Sscottl	 */
581157114Sscottl	commsz = (sizeof(uint32_t) * sc->mfi_max_fw_cmds) +
582157114Sscottl	    sizeof(struct mfi_hwcomms);
583157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
584157114Sscottl				1, 0,			/* algnmnt, boundary */
585157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
586157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
587157114Sscottl				NULL, NULL,		/* filter, filterarg */
588157114Sscottl				commsz,			/* maxsize */
589157114Sscottl				1,			/* msegments */
590157114Sscottl				commsz,			/* maxsegsize */
591157114Sscottl				0,			/* flags */
592157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
593157114Sscottl				&sc->mfi_comms_dmat)) {
594157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
595157114Sscottl		return (ENOMEM);
596157114Sscottl	}
597157114Sscottl	if (bus_dmamem_alloc(sc->mfi_comms_dmat, (void **)&sc->mfi_comms,
598157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_comms_dmamap)) {
599157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
600157114Sscottl		return (ENOMEM);
601157114Sscottl	}
602157114Sscottl	bzero(sc->mfi_comms, commsz);
603157114Sscottl	bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap,
604233711Sambrisko	    sc->mfi_comms, commsz, mfi_addr_cb, &sc->mfi_comms_busaddr, 0);
605157114Sscottl	/*
606157114Sscottl	 * Allocate DMA memory for the command frames.  Keep them in the
607162458Sscottl	 * lower 4GB for efficiency.  Calculate the size of the commands at
608162458Sscottl	 * the same time; each command is one 64 byte frame plus a set of
609162458Sscottl         * additional frames for holding sg lists or other data.
610157114Sscottl	 * The assumption here is that the SG list will start at the second
611162458Sscottl	 * frame and not use the unused bytes in the first frame.  While this
612162458Sscottl	 * isn't technically correct, it simplifies the calculation and allows
613162458Sscottl	 * for command frames that might be larger than an mfi_io_frame.
614157114Sscottl	 */
615157114Sscottl	if (sizeof(bus_addr_t) == 8) {
616162458Sscottl		sc->mfi_sge_size = sizeof(struct mfi_sg64);
617157114Sscottl		sc->mfi_flags |= MFI_FLAGS_SG64;
618157114Sscottl	} else {
619162458Sscottl		sc->mfi_sge_size = sizeof(struct mfi_sg32);
620157114Sscottl	}
621233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
622233711Sambrisko		sc->mfi_sge_size = sizeof(struct mfi_sg_skinny);
623162458Sscottl	frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2;
624162458Sscottl	sc->mfi_cmd_size = frames * MFI_FRAME_SIZE;
625162458Sscottl	framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds;
626157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
627157114Sscottl				64, 0,			/* algnmnt, boundary */
628157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
629157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
630157114Sscottl				NULL, NULL,		/* filter, filterarg */
631157114Sscottl				framessz,		/* maxsize */
632157114Sscottl				1,			/* nsegments */
633157114Sscottl				framessz,		/* maxsegsize */
634157114Sscottl				0,			/* flags */
635157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
636157114Sscottl				&sc->mfi_frames_dmat)) {
637157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frame DMA tag\n");
638157114Sscottl		return (ENOMEM);
639157114Sscottl	}
640157114Sscottl	if (bus_dmamem_alloc(sc->mfi_frames_dmat, (void **)&sc->mfi_frames,
641157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_frames_dmamap)) {
642157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frames memory\n");
643157114Sscottl		return (ENOMEM);
644157114Sscottl	}
645157114Sscottl	bzero(sc->mfi_frames, framessz);
646157114Sscottl	bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap,
647233711Sambrisko	    sc->mfi_frames, framessz, mfi_addr_cb, &sc->mfi_frames_busaddr,0);
648157114Sscottl	/*
649157114Sscottl	 * Allocate DMA memory for the frame sense data.  Keep them in the
650157114Sscottl	 * lower 4GB for efficiency
651157114Sscottl	 */
652157114Sscottl	sensesz = sc->mfi_max_fw_cmds * MFI_SENSE_LEN;
653157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
654157114Sscottl				4, 0,			/* algnmnt, boundary */
655157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
656157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
657157114Sscottl				NULL, NULL,		/* filter, filterarg */
658157114Sscottl				sensesz,		/* maxsize */
659157114Sscottl				1,			/* nsegments */
660157114Sscottl				sensesz,		/* maxsegsize */
661157114Sscottl				0,			/* flags */
662157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
663157114Sscottl				&sc->mfi_sense_dmat)) {
664157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense DMA tag\n");
665157114Sscottl		return (ENOMEM);
666157114Sscottl	}
667157114Sscottl	if (bus_dmamem_alloc(sc->mfi_sense_dmat, (void **)&sc->mfi_sense,
668157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_sense_dmamap)) {
669157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense memory\n");
670157114Sscottl		return (ENOMEM);
671157114Sscottl	}
672157114Sscottl	bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap,
673233711Sambrisko	    sc->mfi_sense, sensesz, mfi_addr_cb, &sc->mfi_sense_busaddr, 0);
674157114Sscottl	if ((error = mfi_alloc_commands(sc)) != 0)
675157114Sscottl		return (error);
676157114Sscottl
677233711Sambrisko	/* Before moving the FW to operational state, check whether
678233711Sambrisko	 * hostmemory is required by the FW or not
679233711Sambrisko	 */
680157114Sscottl
681233711Sambrisko	/* ThunderBolt MFI_IOC2 INIT */
682233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
683233711Sambrisko		sc->mfi_disable_intr(sc);
684233711Sambrisko		if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0) {
685233711Sambrisko			device_printf(sc->mfi_dev,
686233711Sambrisko			    "TB Init has failed with error %d\n",error);
687233711Sambrisko			return error;
688233711Sambrisko		}
689157114Sscottl
690233711Sambrisko		if ((error = mfi_tbolt_alloc_cmd(sc)) != 0)
691233711Sambrisko			return error;
692233711Sambrisko		if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq,
693233711Sambrisko		    INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr_tbolt, sc,
694233711Sambrisko		    &sc->mfi_intr)) {
695233711Sambrisko			device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
696233711Sambrisko			return (EINVAL);
697233711Sambrisko		}
698233711Sambrisko		sc->mfi_enable_intr(sc);
699233711Sambrisko	} else {
700233711Sambrisko		if ((error = mfi_comms_init(sc)) != 0)
701233711Sambrisko			return (error);
702157114Sscottl
703233711Sambrisko		if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq,
704233711Sambrisko		    INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr, sc, &sc->mfi_intr)) {
705233711Sambrisko			device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
706233711Sambrisko			return (EINVAL);
707233711Sambrisko		}
708233711Sambrisko		sc->mfi_enable_intr(sc);
709157114Sscottl	}
710233711Sambrisko	if ((error = mfi_get_controller_info(sc)) != 0)
711233711Sambrisko		return (error);
712233711Sambrisko	sc->disableOnlineCtrlReset = 0;
713157114Sscottl
714157114Sscottl	/* Register a config hook to probe the bus for arrays */
715157114Sscottl	sc->mfi_ich.ich_func = mfi_startup;
716157114Sscottl	sc->mfi_ich.ich_arg = sc;
717157114Sscottl	if (config_intrhook_establish(&sc->mfi_ich) != 0) {
718157114Sscottl		device_printf(sc->mfi_dev, "Cannot establish configuration "
719157114Sscottl		    "hook\n");
720157114Sscottl		return (EINVAL);
721157114Sscottl	}
722233711Sambrisko	if ((error = mfi_aen_setup(sc, 0), 0) != 0) {
723233711Sambrisko		mtx_unlock(&sc->mfi_io_lock);
724233711Sambrisko		return (error);
725233711Sambrisko	}
726157114Sscottl
727157114Sscottl	/*
728157114Sscottl	 * Register a shutdown handler.
729157114Sscottl	 */
730157114Sscottl	if ((sc->mfi_eh = EVENTHANDLER_REGISTER(shutdown_final, mfi_shutdown,
731157114Sscottl	    sc, SHUTDOWN_PRI_DEFAULT)) == NULL) {
732157114Sscottl		device_printf(sc->mfi_dev, "Warning: shutdown event "
733157114Sscottl		    "registration failed\n");
734157114Sscottl	}
735157114Sscottl
736157114Sscottl	/*
737157114Sscottl	 * Create the control device for doing management
738157114Sscottl	 */
739157114Sscottl	unit = device_get_unit(sc->mfi_dev);
740157114Sscottl	sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR,
741157114Sscottl	    0640, "mfi%d", unit);
742158737Sambrisko	if (unit == 0)
743158737Sambrisko		make_dev_alias(sc->mfi_cdev, "megaraid_sas_ioctl_node");
744157114Sscottl	if (sc->mfi_cdev != NULL)
745157114Sscottl		sc->mfi_cdev->si_drv1 = sc;
746171821Sjhb	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
747171821Sjhb	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
748171821Sjhb	    OID_AUTO, "delete_busy_volumes", CTLFLAG_RW,
749171821Sjhb	    &sc->mfi_delete_busy_volumes, 0, "Allow removal of busy volumes");
750171821Sjhb	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
751171821Sjhb	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
752171821Sjhb	    OID_AUTO, "keep_deleted_volumes", CTLFLAG_RW,
753171821Sjhb	    &sc->mfi_keep_deleted_volumes, 0,
754171821Sjhb	    "Don't detach the mfid device for a busy volume that is deleted");
755157114Sscottl
756169611Sscottl	device_add_child(sc->mfi_dev, "mfip", -1);
757169611Sscottl	bus_generic_attach(sc->mfi_dev);
758169611Sscottl
759162619Sscottl	/* Start the timeout watchdog */
760178250Skris	callout_init(&sc->mfi_watchdog_callout, CALLOUT_MPSAFE);
761162619Sscottl	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
762162619Sscottl	    mfi_timeout, sc);
763162619Sscottl
764235014Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
765235014Sambrisko		mfi_tbolt_sync_map_info(sc);
766235014Sambrisko	}
767235014Sambrisko
768157114Sscottl	return (0);
769157114Sscottl}
770157114Sscottl
771157114Sscottlstatic int
772157114Sscottlmfi_alloc_commands(struct mfi_softc *sc)
773157114Sscottl{
774157114Sscottl	struct mfi_command *cm;
775157114Sscottl	int i, ncmds;
776157114Sscottl
777157114Sscottl	/*
778157114Sscottl	 * XXX Should we allocate all the commands up front, or allocate on
779157114Sscottl	 * demand later like 'aac' does?
780157114Sscottl	 */
781178968Sscottl	ncmds = MIN(mfi_max_cmds, sc->mfi_max_fw_cmds);
782178968Sscottl	if (bootverbose)
783178968Sscottl		device_printf(sc->mfi_dev, "Max fw cmds= %d, sizing driver "
784178968Sscottl		   "pool to %d\n", sc->mfi_max_fw_cmds, ncmds);
785178968Sscottl
786157114Sscottl	sc->mfi_commands = malloc(sizeof(struct mfi_command) * ncmds, M_MFIBUF,
787157114Sscottl	    M_WAITOK | M_ZERO);
788157114Sscottl
789157114Sscottl	for (i = 0; i < ncmds; i++) {
790157114Sscottl		cm = &sc->mfi_commands[i];
791158737Sambrisko		cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames +
792162458Sscottl		    sc->mfi_cmd_size * i);
793157114Sscottl		cm->cm_frame_busaddr = sc->mfi_frames_busaddr +
794162458Sscottl		    sc->mfi_cmd_size * i;
795157114Sscottl		cm->cm_frame->header.context = i;
796157114Sscottl		cm->cm_sense = &sc->mfi_sense[i];
797157114Sscottl		cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i;
798157114Sscottl		cm->cm_sc = sc;
799162619Sscottl		cm->cm_index = i;
800157114Sscottl		if (bus_dmamap_create(sc->mfi_buffer_dmat, 0,
801233711Sambrisko		    &cm->cm_dmamap) == 0) {
802233711Sambrisko			mtx_lock(&sc->mfi_io_lock);
803157114Sscottl			mfi_release_command(cm);
804233711Sambrisko			mtx_unlock(&sc->mfi_io_lock);
805233711Sambrisko		}
806157114Sscottl		else
807157114Sscottl			break;
808157114Sscottl		sc->mfi_total_cmds++;
809157114Sscottl	}
810157114Sscottl
811157114Sscottl	return (0);
812157114Sscottl}
813157114Sscottl
814169611Sscottlvoid
815157114Sscottlmfi_release_command(struct mfi_command *cm)
816157114Sscottl{
817163398Sscottl	struct mfi_frame_header *hdr;
818157114Sscottl	uint32_t *hdr_data;
819157114Sscottl
820233711Sambrisko	mtx_assert(&cm->cm_sc->mfi_io_lock, MA_OWNED);
821233711Sambrisko
822157114Sscottl	/*
823157114Sscottl	 * Zero out the important fields of the frame, but make sure the
824165727Sscottl	 * context field is preserved.  For efficiency, handle the fields
825165727Sscottl	 * as 32 bit words.  Clear out the first S/G entry too for safety.
826157114Sscottl	 */
827163398Sscottl	hdr = &cm->cm_frame->header;
828175897Sambrisko	if (cm->cm_data != NULL && hdr->sg_count) {
829163398Sscottl		cm->cm_sg->sg32[0].len = 0;
830163398Sscottl		cm->cm_sg->sg32[0].addr = 0;
831163398Sscottl	}
832165727Sscottl
833165727Sscottl	hdr_data = (uint32_t *)cm->cm_frame;
834165727Sscottl	hdr_data[0] = 0;	/* cmd, sense_len, cmd_status, scsi_status */
835165727Sscottl	hdr_data[1] = 0;	/* target_id, lun_id, cdb_len, sg_count */
836165727Sscottl	hdr_data[4] = 0;	/* flags, timeout */
837165727Sscottl	hdr_data[5] = 0;	/* data_len */
838165727Sscottl
839157114Sscottl	cm->cm_extra_frames = 0;
840157114Sscottl	cm->cm_flags = 0;
841157114Sscottl	cm->cm_complete = NULL;
842157114Sscottl	cm->cm_private = NULL;
843169611Sscottl	cm->cm_data = NULL;
844157114Sscottl	cm->cm_sg = 0;
845157114Sscottl	cm->cm_total_frame_size = 0;
846233711Sambrisko	cm->retry_for_fw_reset = 0;
847163398Sscottl
848157114Sscottl	mfi_enqueue_free(cm);
849157114Sscottl}
850157114Sscottl
851235014Sambriskoint
852233711Sambriskomfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp,
853233711Sambrisko    uint32_t opcode, void **bufp, size_t bufsize)
854159806Sps{
855159806Sps	struct mfi_command *cm;
856159806Sps	struct mfi_dcmd_frame *dcmd;
857159806Sps	void *buf = NULL;
858233711Sambrisko	uint32_t context = 0;
859233711Sambrisko
860159806Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
861233711Sambrisko
862159806Sps	cm = mfi_dequeue_free(sc);
863159806Sps	if (cm == NULL)
864159806Sps		return (EBUSY);
865159806Sps
866233711Sambrisko	/* Zero out the MFI frame */
867233711Sambrisko	context = cm->cm_frame->header.context;
868233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
869233711Sambrisko	cm->cm_frame->header.context = context;
870233711Sambrisko
871159806Sps	if ((bufsize > 0) && (bufp != NULL)) {
872159806Sps		if (*bufp == NULL) {
873159806Sps			buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO);
874159806Sps			if (buf == NULL) {
875159806Sps				mfi_release_command(cm);
876159806Sps				return (ENOMEM);
877159806Sps			}
878159806Sps			*bufp = buf;
879159806Sps		} else {
880159806Sps			buf = *bufp;
881159806Sps		}
882159806Sps	}
883159806Sps
884159806Sps	dcmd =  &cm->cm_frame->dcmd;
885159806Sps	bzero(dcmd->mbox, MFI_MBOX_SIZE);
886159806Sps	dcmd->header.cmd = MFI_CMD_DCMD;
887159806Sps	dcmd->header.timeout = 0;
888159806Sps	dcmd->header.flags = 0;
889159806Sps	dcmd->header.data_len = bufsize;
890233711Sambrisko	dcmd->header.scsi_status = 0;
891159806Sps	dcmd->opcode = opcode;
892159806Sps	cm->cm_sg = &dcmd->sgl;
893159806Sps	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
894159806Sps	cm->cm_flags = 0;
895159806Sps	cm->cm_data = buf;
896159806Sps	cm->cm_private = buf;
897159806Sps	cm->cm_len = bufsize;
898159806Sps
899159806Sps	*cmp = cm;
900159806Sps	if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL))
901159806Sps		*bufp = buf;
902159806Sps	return (0);
903159806Sps}
904159806Sps
905159806Spsstatic int
906157114Sscottlmfi_comms_init(struct mfi_softc *sc)
907157114Sscottl{
908157114Sscottl	struct mfi_command *cm;
909157114Sscottl	struct mfi_init_frame *init;
910157114Sscottl	struct mfi_init_qinfo *qinfo;
911157114Sscottl	int error;
912233711Sambrisko	uint32_t context = 0;
913157114Sscottl
914163398Sscottl	mtx_lock(&sc->mfi_io_lock);
915157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
916157114Sscottl		return (EBUSY);
917157114Sscottl
918233711Sambrisko	/* Zero out the MFI frame */
919233711Sambrisko	context = cm->cm_frame->header.context;
920233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
921233711Sambrisko	cm->cm_frame->header.context = context;
922233711Sambrisko
923157114Sscottl	/*
924157114Sscottl	 * Abuse the SG list area of the frame to hold the init_qinfo
925157114Sscottl	 * object;
926157114Sscottl	 */
927157114Sscottl	init = &cm->cm_frame->init;
928157114Sscottl	qinfo = (struct mfi_init_qinfo *)((uintptr_t)init + MFI_FRAME_SIZE);
929157114Sscottl
930157114Sscottl	bzero(qinfo, sizeof(struct mfi_init_qinfo));
931157114Sscottl	qinfo->rq_entries = sc->mfi_max_fw_cmds + 1;
932157114Sscottl	qinfo->rq_addr_lo = sc->mfi_comms_busaddr +
933157114Sscottl	    offsetof(struct mfi_hwcomms, hw_reply_q);
934157114Sscottl	qinfo->pi_addr_lo = sc->mfi_comms_busaddr +
935157114Sscottl	    offsetof(struct mfi_hwcomms, hw_pi);
936157114Sscottl	qinfo->ci_addr_lo = sc->mfi_comms_busaddr +
937157114Sscottl	    offsetof(struct mfi_hwcomms, hw_ci);
938157114Sscottl
939157114Sscottl	init->header.cmd = MFI_CMD_INIT;
940157114Sscottl	init->header.data_len = sizeof(struct mfi_init_qinfo);
941157114Sscottl	init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE;
942164375Sscottl	cm->cm_data = NULL;
943164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
944157114Sscottl
945164375Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
946157114Sscottl		device_printf(sc->mfi_dev, "failed to send init command\n");
947163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
948157114Sscottl		return (error);
949157114Sscottl	}
950157114Sscottl	mfi_release_command(cm);
951163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
952157114Sscottl
953157114Sscottl	return (0);
954157114Sscottl}
955157114Sscottl
956157114Sscottlstatic int
957157114Sscottlmfi_get_controller_info(struct mfi_softc *sc)
958157114Sscottl{
959159806Sps	struct mfi_command *cm = NULL;
960159806Sps	struct mfi_ctrl_info *ci = NULL;
961157114Sscottl	uint32_t max_sectors_1, max_sectors_2;
962157114Sscottl	int error;
963157114Sscottl
964159806Sps	mtx_lock(&sc->mfi_io_lock);
965159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO,
966159806Sps	    (void **)&ci, sizeof(*ci));
967159806Sps	if (error)
968159806Sps		goto out;
969157114Sscottl	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
970157114Sscottl
971157114Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
972157114Sscottl		device_printf(sc->mfi_dev, "Failed to get controller info\n");
973162458Sscottl		sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE /
974157114Sscottl		    MFI_SECTOR_LEN;
975159806Sps		error = 0;
976159806Sps		goto out;
977157114Sscottl	}
978157114Sscottl
979157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
980157114Sscottl	    BUS_DMASYNC_POSTREAD);
981157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
982157114Sscottl
983233711Sambrisko	max_sectors_1 = (1 << ci->stripe_sz_ops.max) * ci->max_strips_per_io;
984157114Sscottl	max_sectors_2 = ci->max_request_size;
985157114Sscottl	sc->mfi_max_io = min(max_sectors_1, max_sectors_2);
986233711Sambrisko	sc->disableOnlineCtrlReset =
987233711Sambrisko	    ci->properties.OnOffProperties.disableOnlineCtrlReset;
988157114Sscottl
989159806Spsout:
990159806Sps	if (ci)
991159806Sps		free(ci, M_MFIBUF);
992159806Sps	if (cm)
993159806Sps		mfi_release_command(cm);
994159806Sps	mtx_unlock(&sc->mfi_io_lock);
995157114Sscottl	return (error);
996157114Sscottl}
997157114Sscottl
998157114Sscottlstatic int
999159806Spsmfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state)
1000158737Sambrisko{
1001159812Sps	struct mfi_command *cm = NULL;
1002158737Sambrisko	int error;
1003158737Sambrisko
1004233711Sambrisko	mtx_lock(&sc->mfi_io_lock);
1005159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO,
1006159806Sps	    (void **)log_state, sizeof(**log_state));
1007159806Sps	if (error)
1008159806Sps		goto out;
1009159810Sps	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1010158737Sambrisko
1011158737Sambrisko	if ((error = mfi_mapcmd(sc, cm)) != 0) {
1012159802Sps		device_printf(sc->mfi_dev, "Failed to get log state\n");
1013159806Sps		goto out;
1014158737Sambrisko	}
1015158737Sambrisko
1016158737Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1017158737Sambrisko	    BUS_DMASYNC_POSTREAD);
1018158737Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1019158737Sambrisko
1020159806Spsout:
1021159812Sps	if (cm)
1022159812Sps		mfi_release_command(cm);
1023233711Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1024158737Sambrisko
1025158737Sambrisko	return (error);
1026158737Sambrisko}
1027158737Sambrisko
1028233711Sambriskoint
1029158737Sambriskomfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
1030158737Sambrisko{
1031159806Sps	struct mfi_evt_log_state *log_state = NULL;
1032158737Sambrisko	union mfi_evt class_locale;
1033158737Sambrisko	int error = 0;
1034158737Sambrisko	uint32_t seq;
1035158737Sambrisko
1036158737Sambrisko	class_locale.members.reserved = 0;
1037162118Sambrisko	class_locale.members.locale = mfi_event_locale;
1038222589Semaste	class_locale.members.evt_class  = mfi_event_class;
1039158737Sambrisko
1040158737Sambrisko	if (seq_start == 0) {
1041158737Sambrisko		error = mfi_get_log_state(sc, &log_state);
1042233711Sambrisko		sc->mfi_boot_seq_num = log_state->boot_seq_num;
1043159806Sps		if (error) {
1044159806Sps			if (log_state)
1045159806Sps				free(log_state, M_MFIBUF);
1046158737Sambrisko			return (error);
1047159806Sps		}
1048180037Sjhb
1049180037Sjhb		/*
1050180037Sjhb		 * Walk through any events that fired since the last
1051180037Sjhb		 * shutdown.
1052180037Sjhb		 */
1053180037Sjhb		mfi_parse_entries(sc, log_state->shutdown_seq_num,
1054180037Sjhb		    log_state->newest_seq_num);
1055180037Sjhb		seq = log_state->newest_seq_num;
1056158737Sambrisko	} else
1057158737Sambrisko		seq = seq_start;
1058158737Sambrisko	mfi_aen_register(sc, seq, class_locale.word);
1059159806Sps	free(log_state, M_MFIBUF);
1060158737Sambrisko
1061158737Sambrisko	return 0;
1062158737Sambrisko}
1063158737Sambrisko
1064233711Sambriskoint
1065159811Spsmfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm)
1066159811Sps{
1067159811Sps
1068159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1069159811Sps	cm->cm_complete = NULL;
1070159811Sps
1071170284Sambrisko
1072170284Sambrisko	/*
1073170284Sambrisko	 * MegaCli can issue a DCMD of 0.  In this case do nothing
1074170284Sambrisko	 * and return 0 to it as status
1075170284Sambrisko	 */
1076170284Sambrisko	if (cm->cm_frame->dcmd.opcode == 0) {
1077170284Sambrisko		cm->cm_frame->header.cmd_status = MFI_STAT_OK;
1078170284Sambrisko		cm->cm_error = 0;
1079170284Sambrisko		return (cm->cm_error);
1080170284Sambrisko	}
1081159811Sps	mfi_enqueue_ready(cm);
1082159811Sps	mfi_startio(sc);
1083170284Sambrisko	if ((cm->cm_flags & MFI_CMD_COMPLETED) == 0)
1084170284Sambrisko		msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0);
1085170284Sambrisko	return (cm->cm_error);
1086159811Sps}
1087159811Sps
1088157114Sscottlvoid
1089157114Sscottlmfi_free(struct mfi_softc *sc)
1090157114Sscottl{
1091157114Sscottl	struct mfi_command *cm;
1092157114Sscottl	int i;
1093157114Sscottl
1094162619Sscottl	callout_drain(&sc->mfi_watchdog_callout);
1095162619Sscottl
1096157114Sscottl	if (sc->mfi_cdev != NULL)
1097157114Sscottl		destroy_dev(sc->mfi_cdev);
1098157114Sscottl
1099157114Sscottl	if (sc->mfi_total_cmds != 0) {
1100157114Sscottl		for (i = 0; i < sc->mfi_total_cmds; i++) {
1101157114Sscottl			cm = &sc->mfi_commands[i];
1102157114Sscottl			bus_dmamap_destroy(sc->mfi_buffer_dmat, cm->cm_dmamap);
1103157114Sscottl		}
1104157114Sscottl		free(sc->mfi_commands, M_MFIBUF);
1105157114Sscottl	}
1106157114Sscottl
1107157114Sscottl	if (sc->mfi_intr)
1108157114Sscottl		bus_teardown_intr(sc->mfi_dev, sc->mfi_irq, sc->mfi_intr);
1109157114Sscottl	if (sc->mfi_irq != NULL)
1110157114Sscottl		bus_release_resource(sc->mfi_dev, SYS_RES_IRQ, sc->mfi_irq_rid,
1111157114Sscottl		    sc->mfi_irq);
1112157114Sscottl
1113157114Sscottl	if (sc->mfi_sense_busaddr != 0)
1114157114Sscottl		bus_dmamap_unload(sc->mfi_sense_dmat, sc->mfi_sense_dmamap);
1115157114Sscottl	if (sc->mfi_sense != NULL)
1116157114Sscottl		bus_dmamem_free(sc->mfi_sense_dmat, sc->mfi_sense,
1117157114Sscottl		    sc->mfi_sense_dmamap);
1118157114Sscottl	if (sc->mfi_sense_dmat != NULL)
1119157114Sscottl		bus_dma_tag_destroy(sc->mfi_sense_dmat);
1120157114Sscottl
1121157114Sscottl	if (sc->mfi_frames_busaddr != 0)
1122157114Sscottl		bus_dmamap_unload(sc->mfi_frames_dmat, sc->mfi_frames_dmamap);
1123157114Sscottl	if (sc->mfi_frames != NULL)
1124157114Sscottl		bus_dmamem_free(sc->mfi_frames_dmat, sc->mfi_frames,
1125157114Sscottl		    sc->mfi_frames_dmamap);
1126157114Sscottl	if (sc->mfi_frames_dmat != NULL)
1127157114Sscottl		bus_dma_tag_destroy(sc->mfi_frames_dmat);
1128157114Sscottl
1129157114Sscottl	if (sc->mfi_comms_busaddr != 0)
1130157114Sscottl		bus_dmamap_unload(sc->mfi_comms_dmat, sc->mfi_comms_dmamap);
1131157114Sscottl	if (sc->mfi_comms != NULL)
1132157114Sscottl		bus_dmamem_free(sc->mfi_comms_dmat, sc->mfi_comms,
1133157114Sscottl		    sc->mfi_comms_dmamap);
1134157114Sscottl	if (sc->mfi_comms_dmat != NULL)
1135157114Sscottl		bus_dma_tag_destroy(sc->mfi_comms_dmat);
1136157114Sscottl
1137233711Sambrisko	/* ThunderBolt contiguous memory free here */
1138233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
1139233711Sambrisko		if (sc->mfi_tb_busaddr != 0)
1140233711Sambrisko			bus_dmamap_unload(sc->mfi_tb_dmat, sc->mfi_tb_dmamap);
1141233711Sambrisko		if (sc->request_message_pool != NULL)
1142233711Sambrisko			bus_dmamem_free(sc->mfi_tb_dmat, sc->request_message_pool,
1143233711Sambrisko			    sc->mfi_tb_dmamap);
1144233711Sambrisko		if (sc->mfi_tb_dmat != NULL)
1145233711Sambrisko			bus_dma_tag_destroy(sc->mfi_tb_dmat);
1146233711Sambrisko
1147233711Sambrisko		/* Version buffer memory free */
1148233711Sambrisko		/* Start LSIP200113393 */
1149233711Sambrisko		if (sc->verbuf_h_busaddr != 0)
1150233711Sambrisko			bus_dmamap_unload(sc->verbuf_h_dmat, sc->verbuf_h_dmamap);
1151233711Sambrisko		if (sc->verbuf != NULL)
1152233711Sambrisko			bus_dmamem_free(sc->verbuf_h_dmat, sc->verbuf,
1153233711Sambrisko			    sc->verbuf_h_dmamap);
1154233711Sambrisko		if (sc->verbuf_h_dmat != NULL)
1155233711Sambrisko			bus_dma_tag_destroy(sc->verbuf_h_dmat);
1156233711Sambrisko
1157233711Sambrisko		/* End LSIP200113393 */
1158233711Sambrisko		/* ThunderBolt INIT packet memory Free */
1159233711Sambrisko		if (sc->mfi_tb_init_busaddr != 0)
1160233711Sambrisko			bus_dmamap_unload(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap);
1161233711Sambrisko		if (sc->mfi_tb_init != NULL)
1162233711Sambrisko			bus_dmamem_free(sc->mfi_tb_init_dmat, sc->mfi_tb_init,
1163233711Sambrisko			    sc->mfi_tb_init_dmamap);
1164233711Sambrisko		if (sc->mfi_tb_init_dmat != NULL)
1165233711Sambrisko			bus_dma_tag_destroy(sc->mfi_tb_init_dmat);
1166233711Sambrisko
1167233711Sambrisko		/* ThunderBolt IOC Init Desc memory free here */
1168233711Sambrisko		if (sc->mfi_tb_ioc_init_busaddr != 0)
1169233711Sambrisko			bus_dmamap_unload(sc->mfi_tb_ioc_init_dmat,
1170233711Sambrisko			    sc->mfi_tb_ioc_init_dmamap);
1171233711Sambrisko		if (sc->mfi_tb_ioc_init_desc != NULL)
1172233711Sambrisko			bus_dmamem_free(sc->mfi_tb_ioc_init_dmat,
1173233711Sambrisko			    sc->mfi_tb_ioc_init_desc,
1174233711Sambrisko			    sc->mfi_tb_ioc_init_dmamap);
1175233711Sambrisko		if (sc->mfi_tb_ioc_init_dmat != NULL)
1176233711Sambrisko			bus_dma_tag_destroy(sc->mfi_tb_ioc_init_dmat);
1177233711Sambrisko		for (int i = 0; i < sc->mfi_max_fw_cmds; i++) {
1178233711Sambrisko			if (sc->mfi_cmd_pool_tbolt != NULL) {
1179233711Sambrisko				if (sc->mfi_cmd_pool_tbolt[i] != NULL) {
1180233711Sambrisko					free(sc->mfi_cmd_pool_tbolt[i],
1181233711Sambrisko					    M_MFIBUF);
1182233711Sambrisko					sc->mfi_cmd_pool_tbolt[i] = NULL;
1183233711Sambrisko				}
1184233711Sambrisko			}
1185233711Sambrisko		}
1186233711Sambrisko		if (sc->mfi_cmd_pool_tbolt != NULL) {
1187233711Sambrisko			free(sc->mfi_cmd_pool_tbolt, M_MFIBUF);
1188233711Sambrisko			sc->mfi_cmd_pool_tbolt = NULL;
1189233711Sambrisko		}
1190233711Sambrisko		if (sc->request_desc_pool != NULL) {
1191233711Sambrisko			free(sc->request_desc_pool, M_MFIBUF);
1192233711Sambrisko			sc->request_desc_pool = NULL;
1193233711Sambrisko		}
1194233711Sambrisko	}
1195157114Sscottl	if (sc->mfi_buffer_dmat != NULL)
1196157114Sscottl		bus_dma_tag_destroy(sc->mfi_buffer_dmat);
1197157114Sscottl	if (sc->mfi_parent_dmat != NULL)
1198157114Sscottl		bus_dma_tag_destroy(sc->mfi_parent_dmat);
1199157114Sscottl
1200171821Sjhb	if (mtx_initialized(&sc->mfi_io_lock)) {
1201157114Sscottl		mtx_destroy(&sc->mfi_io_lock);
1202171821Sjhb		sx_destroy(&sc->mfi_config_lock);
1203171821Sjhb	}
1204157114Sscottl
1205157114Sscottl	return;
1206157114Sscottl}
1207157114Sscottl
1208157114Sscottlstatic void
1209157114Sscottlmfi_startup(void *arg)
1210157114Sscottl{
1211157114Sscottl	struct mfi_softc *sc;
1212157114Sscottl
1213157114Sscottl	sc = (struct mfi_softc *)arg;
1214157114Sscottl
1215157114Sscottl	config_intrhook_disestablish(&sc->mfi_ich);
1216157114Sscottl
1217171980Sscottl	sc->mfi_enable_intr(sc);
1218171821Sjhb	sx_xlock(&sc->mfi_config_lock);
1219163398Sscottl	mtx_lock(&sc->mfi_io_lock);
1220159811Sps	mfi_ldprobe(sc);
1221233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
1222233711Sambrisko	    mfi_syspdprobe(sc);
1223163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1224171821Sjhb	sx_xunlock(&sc->mfi_config_lock);
1225157114Sscottl}
1226157114Sscottl
1227157114Sscottlstatic void
1228157114Sscottlmfi_intr(void *arg)
1229157114Sscottl{
1230157114Sscottl	struct mfi_softc *sc;
1231157114Sscottl	struct mfi_command *cm;
1232171980Sscottl	uint32_t pi, ci, context;
1233157114Sscottl
1234157114Sscottl	sc = (struct mfi_softc *)arg;
1235157114Sscottl
1236171980Sscottl	if (sc->mfi_check_clear_intr(sc))
1237157114Sscottl		return;
1238163398Sscottl
1239233711Sambriskorestart:
1240157114Sscottl	pi = sc->mfi_comms->hw_pi;
1241157114Sscottl	ci = sc->mfi_comms->hw_ci;
1242157114Sscottl	mtx_lock(&sc->mfi_io_lock);
1243157114Sscottl	while (ci != pi) {
1244157114Sscottl		context = sc->mfi_comms->hw_reply_q[ci];
1245170284Sambrisko		if (context < sc->mfi_max_fw_cmds) {
1246170284Sambrisko			cm = &sc->mfi_commands[context];
1247170284Sambrisko			mfi_remove_busy(cm);
1248170284Sambrisko			cm->cm_error = 0;
1249170284Sambrisko			mfi_complete(sc, cm);
1250170284Sambrisko		}
1251162099Sscottl		if (++ci == (sc->mfi_max_fw_cmds + 1)) {
1252157114Sscottl			ci = 0;
1253157114Sscottl		}
1254157114Sscottl	}
1255157114Sscottl
1256157114Sscottl	sc->mfi_comms->hw_ci = ci;
1257157114Sscottl
1258163398Sscottl	/* Give defered I/O a chance to run */
1259163398Sscottl	if (sc->mfi_flags & MFI_FLAGS_QFRZN)
1260163398Sscottl		sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
1261163398Sscottl	mfi_startio(sc);
1262163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1263163398Sscottl
1264233711Sambrisko	/*
1265233711Sambrisko	 * Dummy read to flush the bus; this ensures that the indexes are up
1266233711Sambrisko	 * to date.  Restart processing if more commands have come it.
1267233711Sambrisko	 */
1268233711Sambrisko	(void)sc->mfi_read_fw_status(sc);
1269233711Sambrisko	if (pi != sc->mfi_comms->hw_pi)
1270233711Sambrisko		goto restart;
1271233711Sambrisko
1272157114Sscottl	return;
1273157114Sscottl}
1274157114Sscottl
1275157114Sscottlint
1276157114Sscottlmfi_shutdown(struct mfi_softc *sc)
1277157114Sscottl{
1278157114Sscottl	struct mfi_dcmd_frame *dcmd;
1279157114Sscottl	struct mfi_command *cm;
1280157114Sscottl	int error;
1281157114Sscottl
1282159806Sps	mtx_lock(&sc->mfi_io_lock);
1283159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0);
1284163398Sscottl	if (error) {
1285163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
1286159806Sps		return (error);
1287163398Sscottl	}
1288157114Sscottl
1289158737Sambrisko	if (sc->mfi_aen_cm != NULL)
1290158737Sambrisko		mfi_abort(sc, sc->mfi_aen_cm);
1291157114Sscottl
1292235014Sambrisko	if (sc->mfi_map_sync_cm != NULL)
1293235014Sambrisko		mfi_abort(sc, sc->mfi_map_sync_cm);
1294233711Sambrisko
1295157114Sscottl	dcmd = &cm->cm_frame->dcmd;
1296157114Sscottl	dcmd->header.flags = MFI_FRAME_DIR_NONE;
1297164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
1298164375Sscottl	cm->cm_data = NULL;
1299157114Sscottl
1300164375Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
1301157114Sscottl		device_printf(sc->mfi_dev, "Failed to shutdown controller\n");
1302157114Sscottl	}
1303157114Sscottl
1304159812Sps	mfi_release_command(cm);
1305163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1306157114Sscottl	return (error);
1307157114Sscottl}
1308157114Sscottl
1309157114Sscottlstatic void
1310233711Sambriskomfi_syspdprobe(struct mfi_softc *sc)
1311233711Sambrisko{
1312233711Sambrisko	struct mfi_frame_header *hdr;
1313233711Sambrisko	struct mfi_command *cm = NULL;
1314233711Sambrisko	struct mfi_pd_list *pdlist = NULL;
1315233711Sambrisko	struct mfi_system_pd *syspd, *tmp;
1316233711Sambrisko	int error, i, found;
1317233711Sambrisko
1318233711Sambrisko	sx_assert(&sc->mfi_config_lock, SA_XLOCKED);
1319233711Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1320233711Sambrisko	/* Add SYSTEM PD's */
1321233711Sambrisko	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_LIST_QUERY,
1322233711Sambrisko	    (void **)&pdlist, sizeof(*pdlist));
1323235016Sambrisko	if (error) {
1324233711Sambrisko		device_printf(sc->mfi_dev,
1325233711Sambrisko		    "Error while forming SYSTEM PD list\n");
1326233711Sambrisko		goto out;
1327233711Sambrisko	}
1328233711Sambrisko
1329233711Sambrisko	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1330233711Sambrisko	cm->cm_frame->dcmd.mbox[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
1331233711Sambrisko	cm->cm_frame->dcmd.mbox[1] = 0;
1332233711Sambrisko	if (mfi_mapcmd(sc, cm) != 0) {
1333233711Sambrisko		device_printf(sc->mfi_dev,
1334233711Sambrisko		    "Failed to get syspd device listing\n");
1335233711Sambrisko		goto out;
1336233711Sambrisko	}
1337233711Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat,cm->cm_dmamap,
1338233711Sambrisko	    BUS_DMASYNC_POSTREAD);
1339233711Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1340233711Sambrisko	hdr = &cm->cm_frame->header;
1341233711Sambrisko	if (hdr->cmd_status != MFI_STAT_OK) {
1342233711Sambrisko		device_printf(sc->mfi_dev,
1343233711Sambrisko		    "MFI_DCMD_PD_LIST_QUERY failed %x\n", hdr->cmd_status);
1344233711Sambrisko		goto out;
1345233711Sambrisko	}
1346233711Sambrisko	/* Get each PD and add it to the system */
1347233711Sambrisko	for (i = 0; i < pdlist->count; i++) {
1348233711Sambrisko		if (pdlist->addr[i].device_id ==
1349233711Sambrisko		    pdlist->addr[i].encl_device_id)
1350233711Sambrisko			continue;
1351233711Sambrisko		found = 0;
1352233711Sambrisko		TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) {
1353233711Sambrisko			if (syspd->pd_id == pdlist->addr[i].device_id)
1354233711Sambrisko				found = 1;
1355233711Sambrisko		}
1356233711Sambrisko		if (found == 0)
1357233711Sambrisko			mfi_add_sys_pd(sc, pdlist->addr[i].device_id);
1358233711Sambrisko	}
1359233711Sambrisko	/* Delete SYSPD's whose state has been changed */
1360233711Sambrisko	TAILQ_FOREACH_SAFE(syspd, &sc->mfi_syspd_tqh, pd_link, tmp) {
1361233711Sambrisko		found = 0;
1362233711Sambrisko		for (i = 0; i < pdlist->count; i++) {
1363233711Sambrisko			if (syspd->pd_id == pdlist->addr[i].device_id)
1364233711Sambrisko				found = 1;
1365233711Sambrisko		}
1366233711Sambrisko		if (found == 0) {
1367233711Sambrisko			printf("DELETE\n");
1368233711Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1369233711Sambrisko			mtx_lock(&Giant);
1370233711Sambrisko			device_delete_child(sc->mfi_dev, syspd->pd_dev);
1371233711Sambrisko			mtx_unlock(&Giant);
1372233711Sambrisko			mtx_lock(&sc->mfi_io_lock);
1373233711Sambrisko		}
1374233711Sambrisko	}
1375233711Sambriskoout:
1376233711Sambrisko	if (pdlist)
1377233711Sambrisko	    free(pdlist, M_MFIBUF);
1378233711Sambrisko	if (cm)
1379233711Sambrisko	    mfi_release_command(cm);
1380233711Sambrisko
1381233711Sambrisko	return;
1382233711Sambrisko}
1383233711Sambrisko
1384233711Sambriskostatic void
1385159811Spsmfi_ldprobe(struct mfi_softc *sc)
1386157114Sscottl{
1387159811Sps	struct mfi_frame_header *hdr;
1388159811Sps	struct mfi_command *cm = NULL;
1389159811Sps	struct mfi_ld_list *list = NULL;
1390171821Sjhb	struct mfi_disk *ld;
1391159811Sps	int error, i;
1392157114Sscottl
1393171821Sjhb	sx_assert(&sc->mfi_config_lock, SA_XLOCKED);
1394163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1395163398Sscottl
1396159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
1397159811Sps	    (void **)&list, sizeof(*list));
1398159811Sps	if (error)
1399159811Sps		goto out;
1400159811Sps
1401159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
1402159811Sps	if (mfi_wait_command(sc, cm) != 0) {
1403159811Sps		device_printf(sc->mfi_dev, "Failed to get device listing\n");
1404159811Sps		goto out;
1405157114Sscottl	}
1406157114Sscottl
1407157114Sscottl	hdr = &cm->cm_frame->header;
1408159811Sps	if (hdr->cmd_status != MFI_STAT_OK) {
1409159811Sps		device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n",
1410159811Sps		    hdr->cmd_status);
1411159811Sps		goto out;
1412157114Sscottl	}
1413157114Sscottl
1414171821Sjhb	for (i = 0; i < list->ld_count; i++) {
1415171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1416171821Sjhb			if (ld->ld_id == list->ld_list[i].ld.v.target_id)
1417171821Sjhb				goto skip_add;
1418171821Sjhb		}
1419163398Sscottl		mfi_add_ld(sc, list->ld_list[i].ld.v.target_id);
1420171821Sjhb	skip_add:;
1421171821Sjhb	}
1422159811Spsout:
1423159811Sps	if (list)
1424159811Sps		free(list, M_MFIBUF);
1425159811Sps	if (cm)
1426157114Sscottl		mfi_release_command(cm);
1427163398Sscottl
1428159811Sps	return;
1429157114Sscottl}
1430157114Sscottl
1431180038Sjhb/*
1432180038Sjhb * The timestamp is the number of seconds since 00:00 Jan 1, 2000.  If
1433180038Sjhb * the bits in 24-31 are all set, then it is the number of seconds since
1434180038Sjhb * boot.
1435180038Sjhb */
1436180038Sjhbstatic const char *
1437180038Sjhbformat_timestamp(uint32_t timestamp)
1438158737Sambrisko{
1439180038Sjhb	static char buffer[32];
1440180038Sjhb
1441180038Sjhb	if ((timestamp & 0xff000000) == 0xff000000)
1442180038Sjhb		snprintf(buffer, sizeof(buffer), "boot + %us", timestamp &
1443180038Sjhb		    0x00ffffff);
1444180038Sjhb	else
1445180038Sjhb		snprintf(buffer, sizeof(buffer), "%us", timestamp);
1446180038Sjhb	return (buffer);
1447180038Sjhb}
1448180038Sjhb
1449180038Sjhbstatic const char *
1450180038Sjhbformat_class(int8_t class)
1451180038Sjhb{
1452180038Sjhb	static char buffer[6];
1453180038Sjhb
1454180038Sjhb	switch (class) {
1455180038Sjhb	case MFI_EVT_CLASS_DEBUG:
1456180038Sjhb		return ("debug");
1457180038Sjhb	case MFI_EVT_CLASS_PROGRESS:
1458180038Sjhb		return ("progress");
1459180038Sjhb	case MFI_EVT_CLASS_INFO:
1460180038Sjhb		return ("info");
1461180038Sjhb	case MFI_EVT_CLASS_WARNING:
1462180038Sjhb		return ("WARN");
1463180038Sjhb	case MFI_EVT_CLASS_CRITICAL:
1464180038Sjhb		return ("CRIT");
1465180038Sjhb	case MFI_EVT_CLASS_FATAL:
1466180038Sjhb		return ("FATAL");
1467180038Sjhb	case MFI_EVT_CLASS_DEAD:
1468180038Sjhb		return ("DEAD");
1469158737Sambrisko	default:
1470180038Sjhb		snprintf(buffer, sizeof(buffer), "%d", class);
1471180038Sjhb		return (buffer);
1472158737Sambrisko	}
1473158737Sambrisko}
1474158737Sambrisko
1475180038Sjhbstatic void
1476180038Sjhbmfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
1477180038Sjhb{
1478233711Sambrisko	struct mfi_system_pd *syspd = NULL;
1479180038Sjhb
1480200238Sjkim	device_printf(sc->mfi_dev, "%d (%s/0x%04x/%s) - %s\n", detail->seq,
1481222589Semaste	    format_timestamp(detail->time), detail->evt_class.members.locale,
1482233711Sambrisko	    format_class(detail->evt_class.members.evt_class),
1483233711Sambrisko	    detail->description);
1484233711Sambrisko
1485233711Sambrisko        /* Don't act on old AEN's or while shutting down */
1486233711Sambrisko        if (detail->seq < sc->mfi_boot_seq_num || sc->mfi_detaching)
1487233711Sambrisko                return;
1488233711Sambrisko
1489233711Sambrisko	switch (detail->arg_type) {
1490233711Sambrisko	case MR_EVT_ARGS_NONE:
1491233711Sambrisko		if (detail->code == MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED) {
1492233711Sambrisko		    device_printf(sc->mfi_dev, "HostBus scan raised\n");
1493233711Sambrisko			if (mfi_detect_jbod_change) {
1494233711Sambrisko				/*
1495233711Sambrisko				 * Probe for new SYSPD's and Delete
1496233711Sambrisko				 * invalid SYSPD's
1497233711Sambrisko				 */
1498233711Sambrisko				sx_xlock(&sc->mfi_config_lock);
1499233711Sambrisko				mtx_lock(&sc->mfi_io_lock);
1500233711Sambrisko				mfi_syspdprobe(sc);
1501233711Sambrisko				mtx_unlock(&sc->mfi_io_lock);
1502233711Sambrisko				sx_xunlock(&sc->mfi_config_lock);
1503233711Sambrisko			}
1504233711Sambrisko		}
1505233711Sambrisko		break;
1506233711Sambrisko	case MR_EVT_ARGS_LD_STATE:
1507233711Sambrisko		/* During load time driver reads all the events starting
1508233711Sambrisko		 * from the one that has been logged after shutdown. Avoid
1509233711Sambrisko		 * these old events.
1510233711Sambrisko		 */
1511233711Sambrisko		if (detail->args.ld_state.new_state == MFI_LD_STATE_OFFLINE ) {
1512233711Sambrisko			/* Remove the LD */
1513233711Sambrisko			struct mfi_disk *ld;
1514233711Sambrisko			TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1515233711Sambrisko				if (ld->ld_id ==
1516233711Sambrisko				    detail->args.ld_state.ld.target_id)
1517233711Sambrisko					break;
1518233711Sambrisko			}
1519233711Sambrisko			/*
1520233711Sambrisko			Fix: for kernel panics when SSCD is removed
1521233711Sambrisko			KASSERT(ld != NULL, ("volume dissappeared"));
1522233711Sambrisko			*/
1523233711Sambrisko			if (ld != NULL) {
1524233711Sambrisko				mtx_lock(&Giant);
1525233711Sambrisko				device_delete_child(sc->mfi_dev, ld->ld_dev);
1526233711Sambrisko				mtx_unlock(&Giant);
1527233711Sambrisko			}
1528233711Sambrisko		}
1529233711Sambrisko		break;
1530233711Sambrisko	case MR_EVT_ARGS_PD:
1531233711Sambrisko		if (detail->code == MR_EVT_PD_REMOVED) {
1532233711Sambrisko			if (mfi_detect_jbod_change) {
1533233711Sambrisko				/*
1534233711Sambrisko				 * If the removed device is a SYSPD then
1535233711Sambrisko				 * delete it
1536233711Sambrisko				 */
1537233711Sambrisko				TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,
1538233711Sambrisko				    pd_link) {
1539233711Sambrisko					if (syspd->pd_id ==
1540233711Sambrisko					    detail->args.pd.device_id) {
1541233711Sambrisko						mtx_lock(&Giant);
1542233711Sambrisko						device_delete_child(
1543233711Sambrisko						    sc->mfi_dev,
1544233711Sambrisko						    syspd->pd_dev);
1545233711Sambrisko						mtx_unlock(&Giant);
1546233711Sambrisko						break;
1547233711Sambrisko					}
1548233711Sambrisko				}
1549233711Sambrisko			}
1550233711Sambrisko		}
1551233711Sambrisko		if (detail->code == MR_EVT_PD_INSERTED) {
1552233711Sambrisko			if (mfi_detect_jbod_change) {
1553233711Sambrisko				/* Probe for new SYSPD's */
1554233711Sambrisko				sx_xlock(&sc->mfi_config_lock);
1555233711Sambrisko				mtx_lock(&sc->mfi_io_lock);
1556233711Sambrisko				mfi_syspdprobe(sc);
1557233711Sambrisko				mtx_unlock(&sc->mfi_io_lock);
1558233711Sambrisko				sx_xunlock(&sc->mfi_config_lock);
1559233711Sambrisko			}
1560233711Sambrisko		}
1561233711Sambrisko		break;
1562233711Sambrisko	}
1563180038Sjhb}
1564180038Sjhb
1565233711Sambriskostatic void
1566233711Sambriskomfi_queue_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
1567233711Sambrisko{
1568233711Sambrisko	struct mfi_evt_queue_elm *elm;
1569233711Sambrisko
1570233711Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1571233711Sambrisko	elm = malloc(sizeof(*elm), M_MFIBUF, M_NOWAIT|M_ZERO);
1572233711Sambrisko	if (elm == NULL)
1573233711Sambrisko		return;
1574233711Sambrisko	memcpy(&elm->detail, detail, sizeof(*detail));
1575233711Sambrisko	TAILQ_INSERT_TAIL(&sc->mfi_evt_queue, elm, link);
1576233711Sambrisko	taskqueue_enqueue(taskqueue_swi, &sc->mfi_evt_task);
1577233711Sambrisko}
1578233711Sambrisko
1579233711Sambriskostatic void
1580233711Sambriskomfi_handle_evt(void *context, int pending)
1581233711Sambrisko{
1582233711Sambrisko	TAILQ_HEAD(,mfi_evt_queue_elm) queue;
1583233711Sambrisko	struct mfi_softc *sc;
1584233711Sambrisko	struct mfi_evt_queue_elm *elm;
1585233711Sambrisko
1586233711Sambrisko	sc = context;
1587233711Sambrisko	TAILQ_INIT(&queue);
1588233711Sambrisko	mtx_lock(&sc->mfi_io_lock);
1589233711Sambrisko	TAILQ_CONCAT(&queue, &sc->mfi_evt_queue, link);
1590233711Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1591233711Sambrisko	while ((elm = TAILQ_FIRST(&queue)) != NULL) {
1592233711Sambrisko		TAILQ_REMOVE(&queue, elm, link);
1593233711Sambrisko		mfi_decode_evt(sc, &elm->detail);
1594233711Sambrisko		free(elm, M_MFIBUF);
1595233711Sambrisko	}
1596233711Sambrisko}
1597233711Sambrisko
1598157114Sscottlstatic int
1599158737Sambriskomfi_aen_register(struct mfi_softc *sc, int seq, int locale)
1600158737Sambrisko{
1601158737Sambrisko	struct mfi_command *cm;
1602158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1603158737Sambrisko	union mfi_evt current_aen, prior_aen;
1604159806Sps	struct mfi_evt_detail *ed = NULL;
1605163398Sscottl	int error = 0;
1606158737Sambrisko
1607158737Sambrisko	current_aen.word = locale;
1608158737Sambrisko	if (sc->mfi_aen_cm != NULL) {
1609158737Sambrisko		prior_aen.word =
1610158737Sambrisko		    ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1];
1611222589Semaste		if (prior_aen.members.evt_class <= current_aen.members.evt_class &&
1612158737Sambrisko		    !((prior_aen.members.locale & current_aen.members.locale)
1613158737Sambrisko		    ^current_aen.members.locale)) {
1614158737Sambrisko			return (0);
1615158737Sambrisko		} else {
1616158737Sambrisko			prior_aen.members.locale |= current_aen.members.locale;
1617222589Semaste			if (prior_aen.members.evt_class
1618222589Semaste			    < current_aen.members.evt_class)
1619222589Semaste				current_aen.members.evt_class =
1620222589Semaste				    prior_aen.members.evt_class;
1621233711Sambrisko			mtx_lock(&sc->mfi_io_lock);
1622158737Sambrisko			mfi_abort(sc, sc->mfi_aen_cm);
1623233711Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1624158737Sambrisko		}
1625158737Sambrisko	}
1626158737Sambrisko
1627233711Sambrisko	mtx_lock(&sc->mfi_io_lock);
1628159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT,
1629159806Sps	    (void **)&ed, sizeof(*ed));
1630233711Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1631163398Sscottl	if (error) {
1632163398Sscottl		goto out;
1633163398Sscottl	}
1634158737Sambrisko
1635158737Sambrisko	dcmd = &cm->cm_frame->dcmd;
1636158737Sambrisko	((uint32_t *)&dcmd->mbox)[0] = seq;
1637158737Sambrisko	((uint32_t *)&dcmd->mbox)[1] = locale;
1638158737Sambrisko	cm->cm_flags = MFI_CMD_DATAIN;
1639158737Sambrisko	cm->cm_complete = mfi_aen_complete;
1640158737Sambrisko
1641233711Sambrisko	sc->last_seq_num = seq;
1642158737Sambrisko	sc->mfi_aen_cm = cm;
1643158737Sambrisko
1644233711Sambrisko	mtx_lock(&sc->mfi_io_lock);
1645158737Sambrisko	mfi_enqueue_ready(cm);
1646158737Sambrisko	mfi_startio(sc);
1647233711Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1648158737Sambrisko
1649163398Sscottlout:
1650163398Sscottl	return (error);
1651158737Sambrisko}
1652158737Sambrisko
1653158737Sambriskostatic void
1654158737Sambriskomfi_aen_complete(struct mfi_command *cm)
1655158737Sambrisko{
1656158737Sambrisko	struct mfi_frame_header *hdr;
1657158737Sambrisko	struct mfi_softc *sc;
1658158737Sambrisko	struct mfi_evt_detail *detail;
1659163398Sscottl	struct mfi_aen *mfi_aen_entry, *tmp;
1660158737Sambrisko	int seq = 0, aborted = 0;
1661158737Sambrisko
1662158737Sambrisko	sc = cm->cm_sc;
1663233711Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1664233711Sambrisko
1665158737Sambrisko	hdr = &cm->cm_frame->header;
1666158737Sambrisko
1667158737Sambrisko	if (sc->mfi_aen_cm == NULL)
1668158737Sambrisko		return;
1669158737Sambrisko
1670235014Sambrisko	if (sc->cm_aen_abort ||
1671224039Sjhb	    hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
1672235014Sambrisko		sc->cm_aen_abort = 0;
1673158737Sambrisko		aborted = 1;
1674158737Sambrisko	} else {
1675158737Sambrisko		sc->mfi_aen_triggered = 1;
1676163398Sscottl		if (sc->mfi_poll_waiting) {
1677163398Sscottl			sc->mfi_poll_waiting = 0;
1678158737Sambrisko			selwakeup(&sc->mfi_select);
1679163398Sscottl		}
1680158737Sambrisko		detail = cm->cm_data;
1681233711Sambrisko		mfi_queue_evt(sc, detail);
1682158737Sambrisko		seq = detail->seq + 1;
1683233711Sambrisko		TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link,
1684233711Sambrisko		    tmp) {
1685158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
1686158737Sambrisko			    aen_link);
1687163398Sscottl			PROC_LOCK(mfi_aen_entry->p);
1688225617Skmacy			kern_psignal(mfi_aen_entry->p, SIGIO);
1689163398Sscottl			PROC_UNLOCK(mfi_aen_entry->p);
1690158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
1691158737Sambrisko		}
1692158737Sambrisko	}
1693158737Sambrisko
1694158737Sambrisko	free(cm->cm_data, M_MFIBUF);
1695158737Sambrisko	sc->mfi_aen_cm = NULL;
1696158737Sambrisko	wakeup(&sc->mfi_aen_cm);
1697158737Sambrisko	mfi_release_command(cm);
1698158737Sambrisko
1699158737Sambrisko	/* set it up again so the driver can catch more events */
1700158737Sambrisko	if (!aborted) {
1701233711Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1702158737Sambrisko		mfi_aen_setup(sc, seq);
1703233711Sambrisko		mtx_lock(&sc->mfi_io_lock);
1704158737Sambrisko	}
1705158737Sambrisko}
1706158737Sambrisko
1707180037Sjhb#define MAX_EVENTS 15
1708180037Sjhb
1709158737Sambriskostatic int
1710180037Sjhbmfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq)
1711158737Sambrisko{
1712158737Sambrisko	struct mfi_command *cm;
1713158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1714162118Sambrisko	struct mfi_evt_list *el;
1715180037Sjhb	union mfi_evt class_locale;
1716180037Sjhb	int error, i, seq, size;
1717158737Sambrisko
1718180037Sjhb	class_locale.members.reserved = 0;
1719180037Sjhb	class_locale.members.locale = mfi_event_locale;
1720222589Semaste	class_locale.members.evt_class  = mfi_event_class;
1721158737Sambrisko
1722162118Sambrisko	size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail)
1723162118Sambrisko		* (MAX_EVENTS - 1);
1724162118Sambrisko	el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO);
1725180037Sjhb	if (el == NULL)
1726158737Sambrisko		return (ENOMEM);
1727158737Sambrisko
1728180037Sjhb	for (seq = start_seq;;) {
1729233711Sambrisko		mtx_lock(&sc->mfi_io_lock);
1730180037Sjhb		if ((cm = mfi_dequeue_free(sc)) == NULL) {
1731180037Sjhb			free(el, M_MFIBUF);
1732233711Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1733180037Sjhb			return (EBUSY);
1734180037Sjhb		}
1735233711Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1736158737Sambrisko
1737180037Sjhb		dcmd = &cm->cm_frame->dcmd;
1738180037Sjhb		bzero(dcmd->mbox, MFI_MBOX_SIZE);
1739180037Sjhb		dcmd->header.cmd = MFI_CMD_DCMD;
1740180037Sjhb		dcmd->header.timeout = 0;
1741180037Sjhb		dcmd->header.data_len = size;
1742180037Sjhb		dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET;
1743180037Sjhb		((uint32_t *)&dcmd->mbox)[0] = seq;
1744180037Sjhb		((uint32_t *)&dcmd->mbox)[1] = class_locale.word;
1745180037Sjhb		cm->cm_sg = &dcmd->sgl;
1746180037Sjhb		cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
1747180037Sjhb		cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1748180037Sjhb		cm->cm_data = el;
1749180037Sjhb		cm->cm_len = size;
1750180037Sjhb
1751233711Sambrisko		mtx_lock(&sc->mfi_io_lock);
1752180037Sjhb		if ((error = mfi_mapcmd(sc, cm)) != 0) {
1753180037Sjhb			device_printf(sc->mfi_dev,
1754180037Sjhb			    "Failed to get controller entries\n");
1755180037Sjhb			mfi_release_command(cm);
1756233711Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1757180037Sjhb			break;
1758180037Sjhb		}
1759180037Sjhb
1760233711Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1761180037Sjhb		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1762180037Sjhb		    BUS_DMASYNC_POSTREAD);
1763180037Sjhb		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1764180037Sjhb
1765180037Sjhb		if (dcmd->header.cmd_status == MFI_STAT_NOT_FOUND) {
1766233711Sambrisko			mtx_lock(&sc->mfi_io_lock);
1767180037Sjhb			mfi_release_command(cm);
1768233711Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1769180037Sjhb			break;
1770180037Sjhb		}
1771180037Sjhb		if (dcmd->header.cmd_status != MFI_STAT_OK) {
1772180037Sjhb			device_printf(sc->mfi_dev,
1773180037Sjhb			    "Error %d fetching controller entries\n",
1774180037Sjhb			    dcmd->header.cmd_status);
1775233711Sambrisko			mtx_lock(&sc->mfi_io_lock);
1776180037Sjhb			mfi_release_command(cm);
1777233711Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1778180037Sjhb			break;
1779180037Sjhb		}
1780233711Sambrisko		mtx_lock(&sc->mfi_io_lock);
1781158737Sambrisko		mfi_release_command(cm);
1782233711Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1783158737Sambrisko
1784162473Sambrisko		for (i = 0; i < el->count; i++) {
1785180037Sjhb			/*
1786180037Sjhb			 * If this event is newer than 'stop_seq' then
1787180037Sjhb			 * break out of the loop.  Note that the log
1788180037Sjhb			 * is a circular buffer so we have to handle
1789180037Sjhb			 * the case that our stop point is earlier in
1790180037Sjhb			 * the buffer than our start point.
1791180037Sjhb			 */
1792180037Sjhb			if (el->event[i].seq >= stop_seq) {
1793180037Sjhb				if (start_seq <= stop_seq)
1794180037Sjhb					break;
1795180037Sjhb				else if (el->event[i].seq < start_seq)
1796180037Sjhb					break;
1797180037Sjhb			}
1798233711Sambrisko			mtx_lock(&sc->mfi_io_lock);
1799233711Sambrisko			mfi_queue_evt(sc, &el->event[i]);
1800233711Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1801162473Sambrisko		}
1802180037Sjhb		seq = el->event[el->count - 1].seq + 1;
1803162118Sambrisko	}
1804158737Sambrisko
1805180037Sjhb	free(el, M_MFIBUF);
1806158737Sambrisko	return (0);
1807158737Sambrisko}
1808158737Sambrisko
1809158737Sambriskostatic int
1810159811Spsmfi_add_ld(struct mfi_softc *sc, int id)
1811157114Sscottl{
1812157114Sscottl	struct mfi_command *cm;
1813159811Sps	struct mfi_dcmd_frame *dcmd = NULL;
1814159811Sps	struct mfi_ld_info *ld_info = NULL;
1815159811Sps	int error;
1816157114Sscottl
1817159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1818159811Sps
1819159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO,
1820159811Sps	    (void **)&ld_info, sizeof(*ld_info));
1821159811Sps	if (error) {
1822159811Sps		device_printf(sc->mfi_dev,
1823159811Sps		    "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error);
1824159811Sps		if (ld_info)
1825159811Sps			free(ld_info, M_MFIBUF);
1826159811Sps		return (error);
1827157624Sscottl	}
1828159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
1829159811Sps	dcmd = &cm->cm_frame->dcmd;
1830159811Sps	dcmd->mbox[0] = id;
1831160052Sambrisko	if (mfi_wait_command(sc, cm) != 0) {
1832160052Sambrisko		device_printf(sc->mfi_dev,
1833160052Sambrisko		    "Failed to get logical drive: %d\n", id);
1834160052Sambrisko		free(ld_info, M_MFIBUF);
1835160052Sambrisko		return (0);
1836160052Sambrisko	}
1837233711Sambrisko	if (ld_info->ld_config.params.isSSCD != 1)
1838233711Sambrisko		mfi_add_ld_complete(cm);
1839233711Sambrisko	else {
1840233711Sambrisko		mfi_release_command(cm);
1841233711Sambrisko		if (ld_info)		/* SSCD drives ld_info free here */
1842233711Sambrisko			free(ld_info, M_MFIBUF);
1843233711Sambrisko	}
1844157114Sscottl	return (0);
1845157114Sscottl}
1846157114Sscottl
1847157114Sscottlstatic void
1848159811Spsmfi_add_ld_complete(struct mfi_command *cm)
1849157114Sscottl{
1850157114Sscottl	struct mfi_frame_header *hdr;
1851159811Sps	struct mfi_ld_info *ld_info;
1852157114Sscottl	struct mfi_softc *sc;
1853159811Sps	device_t child;
1854157114Sscottl
1855157114Sscottl	sc = cm->cm_sc;
1856157114Sscottl	hdr = &cm->cm_frame->header;
1857159811Sps	ld_info = cm->cm_private;
1858157114Sscottl
1859159811Sps	if (hdr->cmd_status != MFI_STAT_OK) {
1860159811Sps		free(ld_info, M_MFIBUF);
1861157114Sscottl		mfi_release_command(cm);
1862157114Sscottl		return;
1863157114Sscottl	}
1864157114Sscottl	mfi_release_command(cm);
1865157114Sscottl
1866169611Sscottl	mtx_unlock(&sc->mfi_io_lock);
1867196403Sjhb	mtx_lock(&Giant);
1868157114Sscottl	if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) {
1869157114Sscottl		device_printf(sc->mfi_dev, "Failed to add logical disk\n");
1870159811Sps		free(ld_info, M_MFIBUF);
1871196403Sjhb		mtx_unlock(&Giant);
1872169611Sscottl		mtx_lock(&sc->mfi_io_lock);
1873159811Sps		return;
1874157114Sscottl	}
1875157114Sscottl
1876169451Sscottl	device_set_ivars(child, ld_info);
1877157114Sscottl	device_set_desc(child, "MFI Logical Disk");
1878157114Sscottl	bus_generic_attach(sc->mfi_dev);
1879196403Sjhb	mtx_unlock(&Giant);
1880157114Sscottl	mtx_lock(&sc->mfi_io_lock);
1881157114Sscottl}
1882163399Sscottl
1883233711Sambriskostatic int mfi_add_sys_pd(struct mfi_softc *sc, int id)
1884233711Sambrisko{
1885233711Sambrisko	struct mfi_command *cm;
1886233711Sambrisko	struct mfi_dcmd_frame *dcmd = NULL;
1887233711Sambrisko	struct mfi_pd_info *pd_info = NULL;
1888233711Sambrisko	int error;
1889233711Sambrisko
1890233711Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1891233711Sambrisko
1892233711Sambrisko	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_GET_INFO,
1893233711Sambrisko		(void **)&pd_info, sizeof(*pd_info));
1894233711Sambrisko	if (error) {
1895233711Sambrisko		device_printf(sc->mfi_dev,
1896233711Sambrisko		    "Failed to allocated for MFI_DCMD_PD_GET_INFO %d\n",
1897233711Sambrisko		    error);
1898233711Sambrisko		if (pd_info)
1899233711Sambrisko			free(pd_info, M_MFIBUF);
1900233711Sambrisko		return (error);
1901233711Sambrisko	}
1902233711Sambrisko	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1903233711Sambrisko	dcmd = &cm->cm_frame->dcmd;
1904233711Sambrisko	dcmd->mbox[0]=id;
1905233711Sambrisko	dcmd->header.scsi_status = 0;
1906233711Sambrisko	dcmd->header.pad0 = 0;
1907233711Sambrisko	if (mfi_mapcmd(sc, cm) != 0) {
1908233711Sambrisko		device_printf(sc->mfi_dev,
1909233711Sambrisko		    "Failed to get physical drive info %d\n", id);
1910233711Sambrisko		free(pd_info, M_MFIBUF);
1911233711Sambrisko		return (0);
1912233711Sambrisko	}
1913233711Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1914233711Sambrisko	    BUS_DMASYNC_POSTREAD);
1915233711Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1916233711Sambrisko	mfi_add_sys_pd_complete(cm);
1917233711Sambrisko	return (0);
1918233711Sambrisko}
1919233711Sambrisko
1920233711Sambriskostatic void
1921233711Sambriskomfi_add_sys_pd_complete(struct mfi_command *cm)
1922233711Sambrisko{
1923233711Sambrisko	struct mfi_frame_header *hdr;
1924233711Sambrisko	struct mfi_pd_info *pd_info;
1925233711Sambrisko	struct mfi_softc *sc;
1926233711Sambrisko	device_t child;
1927233711Sambrisko
1928233711Sambrisko	sc = cm->cm_sc;
1929233711Sambrisko	hdr = &cm->cm_frame->header;
1930233711Sambrisko	pd_info = cm->cm_private;
1931233711Sambrisko
1932233711Sambrisko	if (hdr->cmd_status != MFI_STAT_OK) {
1933233711Sambrisko		free(pd_info, M_MFIBUF);
1934233711Sambrisko		mfi_release_command(cm);
1935233711Sambrisko		return;
1936233711Sambrisko	}
1937233711Sambrisko	if (pd_info->fw_state != MFI_PD_STATE_SYSTEM) {
1938233711Sambrisko		device_printf(sc->mfi_dev, "PD=%x is not SYSTEM PD\n",
1939233711Sambrisko		    pd_info->ref.v.device_id);
1940233711Sambrisko		free(pd_info, M_MFIBUF);
1941233711Sambrisko		mfi_release_command(cm);
1942233711Sambrisko		return;
1943233711Sambrisko	}
1944233711Sambrisko	mfi_release_command(cm);
1945233711Sambrisko
1946233711Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1947233711Sambrisko	mtx_lock(&Giant);
1948233711Sambrisko	if ((child = device_add_child(sc->mfi_dev, "mfisyspd", -1)) == NULL) {
1949233711Sambrisko		device_printf(sc->mfi_dev, "Failed to add system pd\n");
1950233711Sambrisko		free(pd_info, M_MFIBUF);
1951233711Sambrisko		mtx_unlock(&Giant);
1952233711Sambrisko		mtx_lock(&sc->mfi_io_lock);
1953233711Sambrisko		return;
1954233711Sambrisko	}
1955233711Sambrisko
1956233711Sambrisko	device_set_ivars(child, pd_info);
1957233711Sambrisko	device_set_desc(child, "MFI System PD");
1958233711Sambrisko	bus_generic_attach(sc->mfi_dev);
1959233711Sambrisko	mtx_unlock(&Giant);
1960233711Sambrisko	mtx_lock(&sc->mfi_io_lock);
1961233711Sambrisko}
1962235016Sambrisko
1963157114Sscottlstatic struct mfi_command *
1964157114Sscottlmfi_bio_command(struct mfi_softc *sc)
1965157114Sscottl{
1966157114Sscottl	struct bio *bio;
1967233711Sambrisko	struct mfi_command *cm = NULL;
1968157114Sscottl
1969233711Sambrisko	/*reserving two commands to avoid starvation for IOCTL*/
1970235016Sambrisko	if (sc->mfi_qstat[MFIQ_FREE].q_length < 2) {
1971157114Sscottl		return (NULL);
1972233711Sambrisko	}
1973157114Sscottl	if ((bio = mfi_dequeue_bio(sc)) == NULL) {
1974157114Sscottl		return (NULL);
1975157114Sscottl	}
1976233711Sambrisko	if ((uintptr_t)bio->bio_driver2 == MFI_LD_IO) {
1977233711Sambrisko		cm = mfi_build_ldio(sc, bio);
1978233711Sambrisko	} else if ((uintptr_t) bio->bio_driver2 == MFI_SYS_PD_IO) {
1979233711Sambrisko		cm = mfi_build_syspdio(sc, bio);
1980233711Sambrisko	}
1981233711Sambrisko	if (!cm)
1982233711Sambrisko	    mfi_enqueue_bio(sc, bio);
1983233711Sambrisko	return cm;
1984233711Sambrisko}
1985233711Sambriskostatic struct mfi_command *
1986233711Sambriskomfi_build_syspdio(struct mfi_softc *sc, struct bio *bio)
1987233711Sambrisko{
1988233711Sambrisko	struct mfi_command *cm;
1989233711Sambrisko	struct mfi_pass_frame *pass;
1990233711Sambrisko	int flags = 0, blkcount = 0;
1991233711Sambrisko	uint32_t context = 0;
1992157114Sscottl
1993233711Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL)
1994233711Sambrisko	    return (NULL);
1995233711Sambrisko
1996233711Sambrisko	/* Zero out the MFI frame */
1997233711Sambrisko 	context = cm->cm_frame->header.context;
1998233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
1999233711Sambrisko	cm->cm_frame->header.context = context;
2000233711Sambrisko	pass = &cm->cm_frame->pass;
2001233711Sambrisko	bzero(pass->cdb, 16);
2002233711Sambrisko	pass->header.cmd = MFI_CMD_PD_SCSI_IO;
2003233711Sambrisko	switch (bio->bio_cmd & 0x03) {
2004233711Sambrisko	case BIO_READ:
2005233711Sambrisko#define SCSI_READ 0x28
2006233711Sambrisko		pass->cdb[0] = SCSI_READ;
2007233711Sambrisko		flags = MFI_CMD_DATAIN;
2008233711Sambrisko		break;
2009233711Sambrisko	case BIO_WRITE:
2010233711Sambrisko#define SCSI_WRITE 0x2a
2011233711Sambrisko		pass->cdb[0] = SCSI_WRITE;
2012233711Sambrisko		flags = MFI_CMD_DATAOUT;
2013233711Sambrisko		break;
2014233711Sambrisko	default:
2015233711Sambrisko		panic("Invalid bio command");
2016233711Sambrisko	}
2017233711Sambrisko
2018233711Sambrisko	/* Cheat with the sector length to avoid a non-constant division */
2019233711Sambrisko	blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2020233711Sambrisko	/* Fill the LBA and Transfer length in CDB */
2021233711Sambrisko	pass->cdb[2] = (bio->bio_pblkno & 0xff000000) >> 24;
2022233711Sambrisko	pass->cdb[3] = (bio->bio_pblkno & 0x00ff0000) >> 16;
2023233711Sambrisko	pass->cdb[4] = (bio->bio_pblkno & 0x0000ff00) >> 8;
2024233711Sambrisko	pass->cdb[5] = bio->bio_pblkno & 0x000000ff;
2025233711Sambrisko	pass->cdb[7] = (blkcount & 0xff00) >> 8;
2026233711Sambrisko	pass->cdb[8] = (blkcount & 0x00ff);
2027233711Sambrisko	pass->header.target_id = (uintptr_t)bio->bio_driver1;
2028233711Sambrisko	pass->header.timeout = 0;
2029233711Sambrisko	pass->header.flags = 0;
2030233711Sambrisko	pass->header.scsi_status = 0;
2031233711Sambrisko	pass->header.sense_len = MFI_SENSE_LEN;
2032233711Sambrisko	pass->header.data_len = bio->bio_bcount;
2033233711Sambrisko	pass->header.cdb_len = 10;
2034233711Sambrisko	pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2035233711Sambrisko	pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2036233711Sambrisko	cm->cm_complete = mfi_bio_complete;
2037233711Sambrisko	cm->cm_private = bio;
2038233711Sambrisko	cm->cm_data = bio->bio_data;
2039233711Sambrisko	cm->cm_len = bio->bio_bcount;
2040233711Sambrisko	cm->cm_sg = &pass->sgl;
2041233711Sambrisko	cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
2042233711Sambrisko	cm->cm_flags = flags;
2043233711Sambrisko	return (cm);
2044233711Sambrisko}
2045233711Sambrisko
2046233711Sambriskostatic struct mfi_command *
2047233711Sambriskomfi_build_ldio(struct mfi_softc *sc, struct bio *bio)
2048233711Sambrisko{
2049233711Sambrisko	struct mfi_io_frame *io;
2050233711Sambrisko	struct mfi_command *cm;
2051233711Sambrisko	int flags, blkcount;
2052233711Sambrisko	uint32_t context = 0;
2053233711Sambrisko
2054233711Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL)
2055233711Sambrisko	    return (NULL);
2056233711Sambrisko
2057233711Sambrisko	/* Zero out the MFI frame */
2058233711Sambrisko	context = cm->cm_frame->header.context;
2059233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
2060233711Sambrisko	cm->cm_frame->header.context = context;
2061157114Sscottl	io = &cm->cm_frame->io;
2062157114Sscottl	switch (bio->bio_cmd & 0x03) {
2063157114Sscottl	case BIO_READ:
2064157114Sscottl		io->header.cmd = MFI_CMD_LD_READ;
2065157114Sscottl		flags = MFI_CMD_DATAIN;
2066157114Sscottl		break;
2067157114Sscottl	case BIO_WRITE:
2068157114Sscottl		io->header.cmd = MFI_CMD_LD_WRITE;
2069157114Sscottl		flags = MFI_CMD_DATAOUT;
2070157114Sscottl		break;
2071157114Sscottl	default:
2072157114Sscottl		panic("Invalid bio command");
2073157114Sscottl	}
2074157114Sscottl
2075157114Sscottl	/* Cheat with the sector length to avoid a non-constant division */
2076157114Sscottl	blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2077157114Sscottl	io->header.target_id = (uintptr_t)bio->bio_driver1;
2078157114Sscottl	io->header.timeout = 0;
2079157114Sscottl	io->header.flags = 0;
2080233711Sambrisko	io->header.scsi_status = 0;
2081157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
2082157114Sscottl	io->header.data_len = blkcount;
2083233711Sambrisko	io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2084233711Sambrisko	io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2085157114Sscottl	io->lba_hi = (bio->bio_pblkno & 0xffffffff00000000) >> 32;
2086157114Sscottl	io->lba_lo = bio->bio_pblkno & 0xffffffff;
2087157114Sscottl	cm->cm_complete = mfi_bio_complete;
2088157114Sscottl	cm->cm_private = bio;
2089157114Sscottl	cm->cm_data = bio->bio_data;
2090157114Sscottl	cm->cm_len = bio->bio_bcount;
2091157114Sscottl	cm->cm_sg = &io->sgl;
2092157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
2093157114Sscottl	cm->cm_flags = flags;
2094157114Sscottl	return (cm);
2095157114Sscottl}
2096157114Sscottl
2097157114Sscottlstatic void
2098157114Sscottlmfi_bio_complete(struct mfi_command *cm)
2099157114Sscottl{
2100157114Sscottl	struct bio *bio;
2101157114Sscottl	struct mfi_frame_header *hdr;
2102157114Sscottl	struct mfi_softc *sc;
2103157114Sscottl
2104157114Sscottl	bio = cm->cm_private;
2105157114Sscottl	hdr = &cm->cm_frame->header;
2106157114Sscottl	sc = cm->cm_sc;
2107157114Sscottl
2108224039Sjhb	if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0)) {
2109157114Sscottl		bio->bio_flags |= BIO_ERROR;
2110157114Sscottl		bio->bio_error = EIO;
2111157114Sscottl		device_printf(sc->mfi_dev, "I/O error, status= %d "
2112157114Sscottl		    "scsi_status= %d\n", hdr->cmd_status, hdr->scsi_status);
2113157114Sscottl		mfi_print_sense(cm->cm_sc, cm->cm_sense);
2114184897Sambrisko	} else if (cm->cm_error != 0) {
2115184897Sambrisko		bio->bio_flags |= BIO_ERROR;
2116157114Sscottl	}
2117157114Sscottl
2118157114Sscottl	mfi_release_command(cm);
2119157114Sscottl	mfi_disk_complete(bio);
2120157114Sscottl}
2121157114Sscottl
2122157114Sscottlvoid
2123157114Sscottlmfi_startio(struct mfi_softc *sc)
2124157114Sscottl{
2125157114Sscottl	struct mfi_command *cm;
2126169611Sscottl	struct ccb_hdr *ccbh;
2127157114Sscottl
2128157114Sscottl	for (;;) {
2129157114Sscottl		/* Don't bother if we're short on resources */
2130157114Sscottl		if (sc->mfi_flags & MFI_FLAGS_QFRZN)
2131157114Sscottl			break;
2132157114Sscottl
2133157114Sscottl		/* Try a command that has already been prepared */
2134157114Sscottl		cm = mfi_dequeue_ready(sc);
2135157114Sscottl
2136169611Sscottl		if (cm == NULL) {
2137169611Sscottl			if ((ccbh = TAILQ_FIRST(&sc->mfi_cam_ccbq)) != NULL)
2138169611Sscottl				cm = sc->mfi_cam_start(ccbh);
2139169611Sscottl		}
2140169611Sscottl
2141157114Sscottl		/* Nope, so look for work on the bioq */
2142157114Sscottl		if (cm == NULL)
2143157114Sscottl			cm = mfi_bio_command(sc);
2144157114Sscottl
2145157114Sscottl		/* No work available, so exit */
2146157114Sscottl		if (cm == NULL)
2147157114Sscottl			break;
2148157114Sscottl
2149157114Sscottl		/* Send the command to the controller */
2150157114Sscottl		if (mfi_mapcmd(sc, cm) != 0) {
2151157114Sscottl			mfi_requeue_ready(cm);
2152157114Sscottl			break;
2153157114Sscottl		}
2154157114Sscottl	}
2155157114Sscottl}
2156157114Sscottl
2157233711Sambriskoint
2158157114Sscottlmfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm)
2159157114Sscottl{
2160157114Sscottl	int error, polled;
2161157114Sscottl
2162163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2163163398Sscottl
2164233711Sambrisko	if ((cm->cm_data != NULL) && (cm->cm_frame->header.cmd != MFI_CMD_STP )) {
2165157114Sscottl		polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0;
2166157114Sscottl		error = bus_dmamap_load(sc->mfi_buffer_dmat, cm->cm_dmamap,
2167157114Sscottl		    cm->cm_data, cm->cm_len, mfi_data_cb, cm, polled);
2168157114Sscottl		if (error == EINPROGRESS) {
2169157114Sscottl			sc->mfi_flags |= MFI_FLAGS_QFRZN;
2170157114Sscottl			return (0);
2171157114Sscottl		}
2172157114Sscottl	} else {
2173233711Sambrisko		if (sc->MFA_enabled)
2174233711Sambrisko			error = mfi_tbolt_send_frame(sc, cm);
2175233711Sambrisko		else
2176233711Sambrisko			error = mfi_send_frame(sc, cm);
2177157114Sscottl	}
2178157114Sscottl
2179157114Sscottl	return (error);
2180157114Sscottl}
2181157114Sscottl
2182157114Sscottlstatic void
2183157114Sscottlmfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
2184157114Sscottl{
2185157114Sscottl	struct mfi_frame_header *hdr;
2186157114Sscottl	struct mfi_command *cm;
2187157237Sscottl	union mfi_sgl *sgl;
2188157114Sscottl	struct mfi_softc *sc;
2189225869Smav	int i, j, first, dir;
2190233711Sambrisko	int sge_size;
2191157114Sscottl
2192157114Sscottl	cm = (struct mfi_command *)arg;
2193157114Sscottl	sc = cm->cm_sc;
2194157237Sscottl	hdr = &cm->cm_frame->header;
2195157237Sscottl	sgl = cm->cm_sg;
2196157114Sscottl
2197170284Sambrisko	if (error) {
2198170284Sambrisko		printf("error %d in callback\n", error);
2199170284Sambrisko		cm->cm_error = error;
2200170284Sambrisko		mfi_complete(sc, cm);
2201170284Sambrisko		return;
2202170284Sambrisko	}
2203233711Sambrisko	/* Use IEEE sgl only for IO's on a SKINNY controller
2204233711Sambrisko	 * For other commands on a SKINNY controller use either
2205233711Sambrisko	 * sg32 or sg64 based on the sizeof(bus_addr_t).
2206233711Sambrisko	 * Also calculate the total frame size based on the type
2207233711Sambrisko	 * of SGL used.
2208233711Sambrisko	 */
2209233711Sambrisko	if (((cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) ||
2210233711Sambrisko	    (cm->cm_frame->header.cmd == MFI_CMD_LD_READ) ||
2211233711Sambrisko	    (cm->cm_frame->header.cmd == MFI_CMD_LD_WRITE)) &&
2212233711Sambrisko	    (sc->mfi_flags & MFI_FLAGS_SKINNY)) {
2213157237Sscottl		for (i = 0; i < nsegs; i++) {
2214233711Sambrisko			sgl->sg_skinny[i].addr = segs[i].ds_addr;
2215233711Sambrisko			sgl->sg_skinny[i].len = segs[i].ds_len;
2216233711Sambrisko			sgl->sg_skinny[i].flag = 0;
2217157114Sscottl		}
2218233711Sambrisko		hdr->flags |= MFI_FRAME_IEEE_SGL | MFI_FRAME_SGL64;
2219233711Sambrisko		sge_size = sizeof(struct mfi_sg_skinny);
2220233711Sambrisko		hdr->sg_count = nsegs;
2221157237Sscottl	} else {
2222233711Sambrisko		j = 0;
2223233711Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
2224233711Sambrisko			first = cm->cm_stp_len;
2225233711Sambrisko			if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
2226233711Sambrisko				sgl->sg32[j].addr = segs[0].ds_addr;
2227233711Sambrisko				sgl->sg32[j++].len = first;
2228233711Sambrisko			} else {
2229233711Sambrisko				sgl->sg64[j].addr = segs[0].ds_addr;
2230233711Sambrisko				sgl->sg64[j++].len = first;
2231233711Sambrisko			}
2232233711Sambrisko		} else
2233225869Smav			first = 0;
2234233711Sambrisko		if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
2235233711Sambrisko			for (i = 0; i < nsegs; i++) {
2236233711Sambrisko				sgl->sg32[j].addr = segs[i].ds_addr + first;
2237233711Sambrisko				sgl->sg32[j++].len = segs[i].ds_len - first;
2238233711Sambrisko				first = 0;
2239233711Sambrisko			}
2240233711Sambrisko		} else {
2241233711Sambrisko			for (i = 0; i < nsegs; i++) {
2242233711Sambrisko				sgl->sg64[j].addr = segs[i].ds_addr + first;
2243233711Sambrisko				sgl->sg64[j++].len = segs[i].ds_len - first;
2244233711Sambrisko				first = 0;
2245233711Sambrisko			}
2246233711Sambrisko			hdr->flags |= MFI_FRAME_SGL64;
2247157237Sscottl		}
2248233711Sambrisko		hdr->sg_count = j;
2249233711Sambrisko		sge_size = sc->mfi_sge_size;
2250157114Sscottl	}
2251157114Sscottl
2252157114Sscottl	dir = 0;
2253157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAIN) {
2254157114Sscottl		dir |= BUS_DMASYNC_PREREAD;
2255157114Sscottl		hdr->flags |= MFI_FRAME_DIR_READ;
2256157114Sscottl	}
2257157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAOUT) {
2258157114Sscottl		dir |= BUS_DMASYNC_PREWRITE;
2259157114Sscottl		hdr->flags |= MFI_FRAME_DIR_WRITE;
2260157114Sscottl	}
2261157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
2262157114Sscottl	cm->cm_flags |= MFI_CMD_MAPPED;
2263157114Sscottl
2264157114Sscottl	/*
2265157114Sscottl	 * Instead of calculating the total number of frames in the
2266157114Sscottl	 * compound frame, it's already assumed that there will be at
2267157114Sscottl	 * least 1 frame, so don't compensate for the modulo of the
2268157114Sscottl	 * following division.
2269157114Sscottl	 */
2270162458Sscottl	cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs);
2271157114Sscottl	cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
2272157114Sscottl
2273233711Sambrisko	if (sc->MFA_enabled)
2274233711Sambrisko			mfi_tbolt_send_frame(sc, cm);
2275233711Sambrisko	else
2276233711Sambrisko		mfi_send_frame(sc, cm);
2277157114Sscottl
2278157114Sscottl	return;
2279157114Sscottl}
2280157114Sscottl
2281157114Sscottlstatic int
2282157114Sscottlmfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
2283157114Sscottl{
2284164375Sscottl	struct mfi_frame_header *hdr;
2285165225Sambrisko	int tm = MFI_POLL_TIMEOUT_SECS * 1000;
2286157114Sscottl
2287164375Sscottl	hdr = &cm->cm_frame->header;
2288164375Sscottl
2289164375Sscottl	if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
2290164375Sscottl		cm->cm_timestamp = time_uptime;
2291164375Sscottl		mfi_enqueue_busy(cm);
2292164375Sscottl	} else {
2293224039Sjhb		hdr->cmd_status = MFI_STAT_INVALID_STATUS;
2294164375Sscottl		hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
2295164375Sscottl	}
2296164375Sscottl
2297157114Sscottl	/*
2298157114Sscottl	 * The bus address of the command is aligned on a 64 byte boundary,
2299157114Sscottl	 * leaving the least 6 bits as zero.  For whatever reason, the
2300157114Sscottl	 * hardware wants the address shifted right by three, leaving just
2301162458Sscottl	 * 3 zero bits.  These three bits are then used as a prefetching
2302162458Sscottl	 * hint for the hardware to predict how many frames need to be
2303162458Sscottl	 * fetched across the bus.  If a command has more than 8 frames
2304162458Sscottl	 * then the 3 bits are set to 0x7 and the firmware uses other
2305162458Sscottl	 * information in the command to determine the total amount to fetch.
2306162458Sscottl	 * However, FreeBSD doesn't support I/O larger than 128K, so 8 frames
2307162458Sscottl	 * is enough for both 32bit and 64bit systems.
2308157114Sscottl	 */
2309162458Sscottl	if (cm->cm_extra_frames > 7)
2310162458Sscottl		cm->cm_extra_frames = 7;
2311162458Sscottl
2312233711Sambrisko	sc->mfi_issue_cmd(sc, cm->cm_frame_busaddr, cm->cm_extra_frames);
2313164375Sscottl
2314164375Sscottl	if ((cm->cm_flags & MFI_CMD_POLLED) == 0)
2315164375Sscottl		return (0);
2316164375Sscottl
2317164375Sscottl	/* This is a polled command, so busy-wait for it to complete. */
2318224039Sjhb	while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
2319164375Sscottl		DELAY(1000);
2320165225Sambrisko		tm -= 1;
2321164375Sscottl		if (tm <= 0)
2322164375Sscottl			break;
2323164375Sscottl	}
2324164375Sscottl
2325224039Sjhb	if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
2326165225Sambrisko		device_printf(sc->mfi_dev, "Frame %p timed out "
2327233711Sambrisko		    "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
2328164375Sscottl		return (ETIMEDOUT);
2329164375Sscottl	}
2330164375Sscottl
2331157114Sscottl	return (0);
2332157114Sscottl}
2333157114Sscottl
2334233711Sambrisko
2335233711Sambriskovoid
2336157114Sscottlmfi_complete(struct mfi_softc *sc, struct mfi_command *cm)
2337157114Sscottl{
2338157114Sscottl	int dir;
2339157114Sscottl
2340157114Sscottl	if ((cm->cm_flags & MFI_CMD_MAPPED) != 0) {
2341157114Sscottl		dir = 0;
2342225869Smav		if ((cm->cm_flags & MFI_CMD_DATAIN) ||
2343225869Smav		    (cm->cm_frame->header.cmd == MFI_CMD_STP))
2344157114Sscottl			dir |= BUS_DMASYNC_POSTREAD;
2345157114Sscottl		if (cm->cm_flags & MFI_CMD_DATAOUT)
2346157114Sscottl			dir |= BUS_DMASYNC_POSTWRITE;
2347157114Sscottl
2348157114Sscottl		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
2349157114Sscottl		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
2350157114Sscottl		cm->cm_flags &= ~MFI_CMD_MAPPED;
2351157114Sscottl	}
2352157114Sscottl
2353170284Sambrisko	cm->cm_flags |= MFI_CMD_COMPLETED;
2354170284Sambrisko
2355157114Sscottl	if (cm->cm_complete != NULL)
2356157114Sscottl		cm->cm_complete(cm);
2357159811Sps	else
2358159811Sps		wakeup(cm);
2359157114Sscottl}
2360157114Sscottl
2361158737Sambriskostatic int
2362158737Sambriskomfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort)
2363158737Sambrisko{
2364158737Sambrisko	struct mfi_command *cm;
2365158737Sambrisko	struct mfi_abort_frame *abort;
2366165225Sambrisko	int i = 0;
2367233711Sambrisko	uint32_t context = 0;
2368158737Sambrisko
2369163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2370163398Sscottl
2371158737Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL) {
2372158737Sambrisko		return (EBUSY);
2373158737Sambrisko	}
2374158737Sambrisko
2375233711Sambrisko	/* Zero out the MFI frame */
2376233711Sambrisko	context = cm->cm_frame->header.context;
2377233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
2378233711Sambrisko	cm->cm_frame->header.context = context;
2379233711Sambrisko
2380158737Sambrisko	abort = &cm->cm_frame->abort;
2381158737Sambrisko	abort->header.cmd = MFI_CMD_ABORT;
2382158737Sambrisko	abort->header.flags = 0;
2383233711Sambrisko	abort->header.scsi_status = 0;
2384158737Sambrisko	abort->abort_context = cm_abort->cm_frame->header.context;
2385233711Sambrisko	abort->abort_mfi_addr_lo = (uint32_t)cm_abort->cm_frame_busaddr;
2386233711Sambrisko	abort->abort_mfi_addr_hi =
2387233711Sambrisko	    (uint32_t)((uint64_t)cm_abort->cm_frame_busaddr >> 32);
2388158737Sambrisko	cm->cm_data = NULL;
2389164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
2390158737Sambrisko
2391233711Sambrisko	if (sc->mfi_aen_cm)
2392235014Sambrisko		sc->cm_aen_abort = 1;
2393235014Sambrisko	if (sc->mfi_map_sync_cm)
2394235014Sambrisko		sc->cm_map_abort = 1;
2395158737Sambrisko	mfi_mapcmd(sc, cm);
2396158737Sambrisko	mfi_release_command(cm);
2397158737Sambrisko
2398165225Sambrisko	while (i < 5 && sc->mfi_aen_cm != NULL) {
2399233711Sambrisko		msleep(&sc->mfi_aen_cm, &sc->mfi_io_lock, 0, "mfiabort",
2400233711Sambrisko		    5 * hz);
2401165225Sambrisko		i++;
2402158737Sambrisko	}
2403235014Sambrisko	while (i < 5 && sc->mfi_map_sync_cm != NULL) {
2404235014Sambrisko		msleep(&sc->mfi_map_sync_cm, &sc->mfi_io_lock, 0, "mfiabort",
2405235014Sambrisko		    5 * hz);
2406235014Sambrisko		i++;
2407235014Sambrisko	}
2408158737Sambrisko
2409158737Sambrisko	return (0);
2410158737Sambrisko}
2411158737Sambrisko
2412157114Sscottlint
2413233711Sambriskomfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt,
2414233711Sambrisko     int len)
2415157114Sscottl{
2416157114Sscottl	struct mfi_command *cm;
2417157114Sscottl	struct mfi_io_frame *io;
2418157114Sscottl	int error;
2419233711Sambrisko	uint32_t context = 0;
2420157114Sscottl
2421157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
2422157114Sscottl		return (EBUSY);
2423157114Sscottl
2424233711Sambrisko	/* Zero out the MFI frame */
2425233711Sambrisko	context = cm->cm_frame->header.context;
2426233711Sambrisko	bzero(cm->cm_frame, sizeof(union mfi_frame));
2427233711Sambrisko	cm->cm_frame->header.context = context;
2428233711Sambrisko
2429157114Sscottl	io = &cm->cm_frame->io;
2430157114Sscottl	io->header.cmd = MFI_CMD_LD_WRITE;
2431157114Sscottl	io->header.target_id = id;
2432157114Sscottl	io->header.timeout = 0;
2433157114Sscottl	io->header.flags = 0;
2434233711Sambrisko	io->header.scsi_status = 0;
2435157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
2436157114Sscottl	io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2437233711Sambrisko	io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2438233711Sambrisko	io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2439157114Sscottl	io->lba_hi = (lba & 0xffffffff00000000) >> 32;
2440157114Sscottl	io->lba_lo = lba & 0xffffffff;
2441157114Sscottl	cm->cm_data = virt;
2442157114Sscottl	cm->cm_len = len;
2443157114Sscottl	cm->cm_sg = &io->sgl;
2444157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
2445157114Sscottl	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT;
2446157114Sscottl
2447164375Sscottl	error = mfi_mapcmd(sc, cm);
2448157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
2449157114Sscottl	    BUS_DMASYNC_POSTWRITE);
2450157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
2451157114Sscottl	mfi_release_command(cm);
2452157114Sscottl
2453157114Sscottl	return (error);
2454157114Sscottl}
2455157114Sscottl
2456233711Sambriskoint
2457233711Sambriskomfi_dump_syspd_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt,
2458233711Sambrisko    int len)
2459233711Sambrisko{
2460233711Sambrisko	struct mfi_command *cm;
2461233711Sambrisko	struct mfi_pass_frame *pass;
2462233711Sambrisko	int error;
2463233711Sambrisko	int blkcount = 0;
2464233711Sambrisko
2465233711Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL)
2466233711Sambrisko		return (EBUSY);
2467233711Sambrisko
2468233711Sambrisko	pass = &cm->cm_frame->pass;
2469233711Sambrisko	bzero(pass->cdb, 16);
2470233711Sambrisko	pass->header.cmd = MFI_CMD_PD_SCSI_IO;
2471233711Sambrisko	pass->cdb[0] = SCSI_WRITE;
2472233711Sambrisko	pass->cdb[2] = (lba & 0xff000000) >> 24;
2473233711Sambrisko	pass->cdb[3] = (lba & 0x00ff0000) >> 16;
2474233711Sambrisko	pass->cdb[4] = (lba & 0x0000ff00) >> 8;
2475233711Sambrisko	pass->cdb[5] = (lba & 0x000000ff);
2476233711Sambrisko	blkcount = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2477233711Sambrisko	pass->cdb[7] = (blkcount & 0xff00) >> 8;
2478233711Sambrisko	pass->cdb[8] = (blkcount & 0x00ff);
2479233711Sambrisko	pass->header.target_id = id;
2480233711Sambrisko	pass->header.timeout = 0;
2481233711Sambrisko	pass->header.flags = 0;
2482233711Sambrisko	pass->header.scsi_status = 0;
2483233711Sambrisko	pass->header.sense_len = MFI_SENSE_LEN;
2484233711Sambrisko	pass->header.data_len = len;
2485233711Sambrisko	pass->header.cdb_len = 10;
2486233711Sambrisko	pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2487233711Sambrisko	pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2488233711Sambrisko	cm->cm_data = virt;
2489233711Sambrisko	cm->cm_len = len;
2490233711Sambrisko	cm->cm_sg = &pass->sgl;
2491233711Sambrisko	cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
2492233711Sambrisko	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT;
2493233711Sambrisko
2494233711Sambrisko	error = mfi_mapcmd(sc, cm);
2495233711Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
2496233711Sambrisko	    BUS_DMASYNC_POSTWRITE);
2497233711Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
2498233711Sambrisko	mfi_release_command(cm);
2499233711Sambrisko
2500233711Sambrisko	return (error);
2501233711Sambrisko}
2502233711Sambrisko
2503157114Sscottlstatic int
2504192450Simpmfi_open(struct cdev *dev, int flags, int fmt, struct thread *td)
2505157114Sscottl{
2506157114Sscottl	struct mfi_softc *sc;
2507171822Sjhb	int error;
2508157114Sscottl
2509157114Sscottl	sc = dev->si_drv1;
2510163398Sscottl
2511163398Sscottl	mtx_lock(&sc->mfi_io_lock);
2512171822Sjhb	if (sc->mfi_detaching)
2513171822Sjhb		error = ENXIO;
2514171822Sjhb	else {
2515171822Sjhb		sc->mfi_flags |= MFI_FLAGS_OPEN;
2516171822Sjhb		error = 0;
2517171822Sjhb	}
2518163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
2519157114Sscottl
2520171822Sjhb	return (error);
2521157114Sscottl}
2522157114Sscottl
2523157114Sscottlstatic int
2524192450Simpmfi_close(struct cdev *dev, int flags, int fmt, struct thread *td)
2525157114Sscottl{
2526157114Sscottl	struct mfi_softc *sc;
2527163398Sscottl	struct mfi_aen *mfi_aen_entry, *tmp;
2528157114Sscottl
2529157114Sscottl	sc = dev->si_drv1;
2530163398Sscottl
2531163398Sscottl	mtx_lock(&sc->mfi_io_lock);
2532157114Sscottl	sc->mfi_flags &= ~MFI_FLAGS_OPEN;
2533157114Sscottl
2534163398Sscottl	TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
2535158737Sambrisko		if (mfi_aen_entry->p == curproc) {
2536158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
2537158737Sambrisko			    aen_link);
2538158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
2539158737Sambrisko		}
2540158737Sambrisko	}
2541163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
2542157114Sscottl	return (0);
2543157114Sscottl}
2544157114Sscottl
2545157114Sscottlstatic int
2546171821Sjhbmfi_config_lock(struct mfi_softc *sc, uint32_t opcode)
2547171821Sjhb{
2548171821Sjhb
2549171821Sjhb	switch (opcode) {
2550171821Sjhb	case MFI_DCMD_LD_DELETE:
2551171821Sjhb	case MFI_DCMD_CFG_ADD:
2552171821Sjhb	case MFI_DCMD_CFG_CLEAR:
2553240962Sjhb	case MFI_DCMD_CFG_FOREIGN_IMPORT:
2554171821Sjhb		sx_xlock(&sc->mfi_config_lock);
2555171821Sjhb		return (1);
2556171821Sjhb	default:
2557171821Sjhb		return (0);
2558171821Sjhb	}
2559171821Sjhb}
2560171821Sjhb
2561171821Sjhbstatic void
2562171821Sjhbmfi_config_unlock(struct mfi_softc *sc, int locked)
2563171821Sjhb{
2564171821Sjhb
2565171821Sjhb	if (locked)
2566171821Sjhb		sx_xunlock(&sc->mfi_config_lock);
2567171821Sjhb}
2568171821Sjhb
2569233711Sambrisko/*
2570233711Sambrisko * Perform pre-issue checks on commands from userland and possibly veto
2571233711Sambrisko * them.
2572233711Sambrisko */
2573171821Sjhbstatic int
2574171821Sjhbmfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm)
2575171821Sjhb{
2576171821Sjhb	struct mfi_disk *ld, *ld2;
2577171821Sjhb	int error;
2578233711Sambrisko	struct mfi_system_pd *syspd = NULL;
2579233711Sambrisko	uint16_t syspd_id;
2580233711Sambrisko	uint16_t *mbox;
2581171821Sjhb
2582171821Sjhb	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2583171821Sjhb	error = 0;
2584171821Sjhb	switch (cm->cm_frame->dcmd.opcode) {
2585171821Sjhb	case MFI_DCMD_LD_DELETE:
2586171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
2587171821Sjhb			if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
2588171821Sjhb				break;
2589171821Sjhb		}
2590171821Sjhb		if (ld == NULL)
2591171821Sjhb			error = ENOENT;
2592171821Sjhb		else
2593171821Sjhb			error = mfi_disk_disable(ld);
2594171821Sjhb		break;
2595171821Sjhb	case MFI_DCMD_CFG_CLEAR:
2596171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
2597171821Sjhb			error = mfi_disk_disable(ld);
2598171821Sjhb			if (error)
2599171821Sjhb				break;
2600171821Sjhb		}
2601171821Sjhb		if (error) {
2602171821Sjhb			TAILQ_FOREACH(ld2, &sc->mfi_ld_tqh, ld_link) {
2603171821Sjhb				if (ld2 == ld)
2604171821Sjhb					break;
2605171821Sjhb				mfi_disk_enable(ld2);
2606171821Sjhb			}
2607171821Sjhb		}
2608171821Sjhb		break;
2609233711Sambrisko	case MFI_DCMD_PD_STATE_SET:
2610233711Sambrisko		mbox = (uint16_t *) cm->cm_frame->dcmd.mbox;
2611233711Sambrisko		syspd_id = mbox[0];
2612233711Sambrisko		if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) {
2613233711Sambrisko			TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) {
2614233711Sambrisko				if (syspd->pd_id == syspd_id)
2615233711Sambrisko					break;
2616233711Sambrisko			}
2617233711Sambrisko		}
2618233711Sambrisko		else
2619233711Sambrisko			break;
2620233711Sambrisko		if (syspd)
2621233711Sambrisko			error = mfi_syspd_disable(syspd);
2622233711Sambrisko		break;
2623171821Sjhb	default:
2624171821Sjhb		break;
2625171821Sjhb	}
2626171821Sjhb	return (error);
2627171821Sjhb}
2628171821Sjhb
2629171821Sjhb/* Perform post-issue checks on commands from userland. */
2630171821Sjhbstatic void
2631171821Sjhbmfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm)
2632171821Sjhb{
2633171821Sjhb	struct mfi_disk *ld, *ldn;
2634233711Sambrisko	struct mfi_system_pd *syspd = NULL;
2635233711Sambrisko	uint16_t syspd_id;
2636233711Sambrisko	uint16_t *mbox;
2637171821Sjhb
2638171821Sjhb	switch (cm->cm_frame->dcmd.opcode) {
2639171821Sjhb	case MFI_DCMD_LD_DELETE:
2640171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
2641171821Sjhb			if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
2642171821Sjhb				break;
2643171821Sjhb		}
2644171821Sjhb		KASSERT(ld != NULL, ("volume dissappeared"));
2645171821Sjhb		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
2646171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
2647196403Sjhb			mtx_lock(&Giant);
2648171821Sjhb			device_delete_child(sc->mfi_dev, ld->ld_dev);
2649196403Sjhb			mtx_unlock(&Giant);
2650171821Sjhb			mtx_lock(&sc->mfi_io_lock);
2651171821Sjhb		} else
2652171821Sjhb			mfi_disk_enable(ld);
2653171821Sjhb		break;
2654171821Sjhb	case MFI_DCMD_CFG_CLEAR:
2655171821Sjhb		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
2656171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
2657196403Sjhb			mtx_lock(&Giant);
2658171821Sjhb			TAILQ_FOREACH_SAFE(ld, &sc->mfi_ld_tqh, ld_link, ldn) {
2659171821Sjhb				device_delete_child(sc->mfi_dev, ld->ld_dev);
2660171821Sjhb			}
2661196403Sjhb			mtx_unlock(&Giant);
2662171821Sjhb			mtx_lock(&sc->mfi_io_lock);
2663171821Sjhb		} else {
2664171821Sjhb			TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link)
2665171821Sjhb				mfi_disk_enable(ld);
2666171821Sjhb		}
2667171821Sjhb		break;
2668171821Sjhb	case MFI_DCMD_CFG_ADD:
2669171821Sjhb		mfi_ldprobe(sc);
2670171821Sjhb		break;
2671184897Sambrisko	case MFI_DCMD_CFG_FOREIGN_IMPORT:
2672184897Sambrisko		mfi_ldprobe(sc);
2673184897Sambrisko		break;
2674233711Sambrisko	case MFI_DCMD_PD_STATE_SET:
2675233711Sambrisko		mbox = (uint16_t *) cm->cm_frame->dcmd.mbox;
2676233711Sambrisko		syspd_id = mbox[0];
2677233711Sambrisko		if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) {
2678233711Sambrisko			TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) {
2679233711Sambrisko				if (syspd->pd_id == syspd_id)
2680233711Sambrisko					break;
2681233711Sambrisko			}
2682233711Sambrisko		}
2683233711Sambrisko		else
2684233711Sambrisko			break;
2685233711Sambrisko		/* If the transition fails then enable the syspd again */
2686233711Sambrisko		if (syspd && cm->cm_frame->header.cmd_status != MFI_STAT_OK)
2687233711Sambrisko			mfi_syspd_enable(syspd);
2688233711Sambrisko		break;
2689171821Sjhb	}
2690171821Sjhb}
2691171821Sjhb
2692233711Sambriskostatic int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm)
2693233711Sambrisko{
2694233711Sambrisko	struct mfi_config_data *conf_data=(struct mfi_config_data *)cm->cm_data;
2695233711Sambrisko	struct mfi_command *ld_cm = NULL;
2696233711Sambrisko	struct mfi_ld_info *ld_info = NULL;
2697233711Sambrisko	int error = 0;
2698233711Sambrisko
2699233711Sambrisko	if ((cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) &&
2700235016Sambrisko	    (conf_data->ld[0].params.isSSCD == 1)) {
2701233711Sambrisko		error = 1;
2702233711Sambrisko	} else if (cm->cm_frame->dcmd.opcode == MFI_DCMD_LD_DELETE) {
2703233711Sambrisko		error = mfi_dcmd_command (sc, &ld_cm, MFI_DCMD_LD_GET_INFO,
2704233711Sambrisko		    (void **)&ld_info, sizeof(*ld_info));
2705235016Sambrisko		if (error) {
2706233711Sambrisko			device_printf(sc->mfi_dev, "Failed to allocate"
2707233711Sambrisko			    "MFI_DCMD_LD_GET_INFO %d", error);
2708233711Sambrisko			if (ld_info)
2709233711Sambrisko				free(ld_info, M_MFIBUF);
2710233711Sambrisko			return 0;
2711233711Sambrisko		}
2712233711Sambrisko		ld_cm->cm_flags = MFI_CMD_DATAIN;
2713233711Sambrisko		ld_cm->cm_frame->dcmd.mbox[0]= cm->cm_frame->dcmd.mbox[0];
2714233711Sambrisko		ld_cm->cm_frame->header.target_id = cm->cm_frame->dcmd.mbox[0];
2715235016Sambrisko		if (mfi_wait_command(sc, ld_cm) != 0) {
2716233711Sambrisko			device_printf(sc->mfi_dev, "failed to get log drv\n");
2717233711Sambrisko			mfi_release_command(ld_cm);
2718233711Sambrisko			free(ld_info, M_MFIBUF);
2719233711Sambrisko			return 0;
2720233711Sambrisko		}
2721233711Sambrisko
2722233711Sambrisko		if (ld_cm->cm_frame->header.cmd_status != MFI_STAT_OK) {
2723233711Sambrisko			free(ld_info, M_MFIBUF);
2724233711Sambrisko			mfi_release_command(ld_cm);
2725233711Sambrisko			return 0;
2726233711Sambrisko		}
2727233711Sambrisko		else
2728233711Sambrisko			ld_info = (struct mfi_ld_info *)ld_cm->cm_private;
2729233711Sambrisko
2730233711Sambrisko		if (ld_info->ld_config.params.isSSCD == 1)
2731233711Sambrisko			error = 1;
2732233711Sambrisko
2733233711Sambrisko		mfi_release_command(ld_cm);
2734233711Sambrisko		free(ld_info, M_MFIBUF);
2735233711Sambrisko
2736233711Sambrisko	}
2737233711Sambrisko	return error;
2738233711Sambrisko}
2739233711Sambrisko
2740171821Sjhbstatic int
2741233711Sambriskomfi_stp_cmd(struct mfi_softc *sc, struct mfi_command *cm,caddr_t arg)
2742233711Sambrisko{
2743233711Sambrisko	uint8_t i;
2744233711Sambrisko	struct mfi_ioc_packet *ioc;
2745233711Sambrisko	ioc = (struct mfi_ioc_packet *)arg;
2746233711Sambrisko	int sge_size, error;
2747233711Sambrisko	struct megasas_sge *kern_sge;
2748233711Sambrisko
2749233711Sambrisko	memset(sc->kbuff_arr, 0, sizeof(sc->kbuff_arr));
2750233711Sambrisko	kern_sge =(struct megasas_sge *) ((uintptr_t)cm->cm_frame + ioc->mfi_sgl_off);
2751233711Sambrisko	cm->cm_frame->header.sg_count = ioc->mfi_sge_count;
2752233711Sambrisko
2753233711Sambrisko	if (sizeof(bus_addr_t) == 8) {
2754233711Sambrisko		cm->cm_frame->header.flags |= MFI_FRAME_SGL64;
2755233711Sambrisko		cm->cm_extra_frames = 2;
2756233711Sambrisko		sge_size = sizeof(struct mfi_sg64);
2757233711Sambrisko	} else {
2758233711Sambrisko		cm->cm_extra_frames =  (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
2759233711Sambrisko		sge_size = sizeof(struct mfi_sg32);
2760233711Sambrisko	}
2761233711Sambrisko
2762233711Sambrisko	cm->cm_total_frame_size += (sge_size * ioc->mfi_sge_count);
2763233711Sambrisko	for (i = 0; i < ioc->mfi_sge_count; i++) {
2764233711Sambrisko			if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
2765233711Sambrisko			1, 0,			/* algnmnt, boundary */
2766233711Sambrisko			BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
2767233711Sambrisko			BUS_SPACE_MAXADDR,	/* highaddr */
2768233711Sambrisko			NULL, NULL,		/* filter, filterarg */
2769233711Sambrisko			ioc->mfi_sgl[i].iov_len,/* maxsize */
2770233711Sambrisko			2,			/* nsegments */
2771233711Sambrisko			ioc->mfi_sgl[i].iov_len,/* maxsegsize */
2772233711Sambrisko			BUS_DMA_ALLOCNOW,	/* flags */
2773233711Sambrisko			NULL, NULL,		/* lockfunc, lockarg */
2774233711Sambrisko			&sc->mfi_kbuff_arr_dmat[i])) {
2775233711Sambrisko			device_printf(sc->mfi_dev,
2776233711Sambrisko			    "Cannot allocate mfi_kbuff_arr_dmat tag\n");
2777233711Sambrisko			return (ENOMEM);
2778233711Sambrisko		}
2779233711Sambrisko
2780233711Sambrisko		if (bus_dmamem_alloc(sc->mfi_kbuff_arr_dmat[i],
2781233711Sambrisko		    (void **)&sc->kbuff_arr[i], BUS_DMA_NOWAIT,
2782233711Sambrisko		    &sc->mfi_kbuff_arr_dmamap[i])) {
2783233711Sambrisko			device_printf(sc->mfi_dev,
2784233711Sambrisko			    "Cannot allocate mfi_kbuff_arr_dmamap memory\n");
2785233711Sambrisko			return (ENOMEM);
2786233711Sambrisko		}
2787233711Sambrisko
2788233711Sambrisko		bus_dmamap_load(sc->mfi_kbuff_arr_dmat[i],
2789233711Sambrisko		    sc->mfi_kbuff_arr_dmamap[i], sc->kbuff_arr[i],
2790233711Sambrisko		    ioc->mfi_sgl[i].iov_len, mfi_addr_cb,
2791233711Sambrisko		    &sc->mfi_kbuff_arr_busaddr[i], 0);
2792233711Sambrisko
2793233711Sambrisko		if (!sc->kbuff_arr[i]) {
2794233711Sambrisko			device_printf(sc->mfi_dev,
2795233711Sambrisko			    "Could not allocate memory for kbuff_arr info\n");
2796233711Sambrisko			return -1;
2797233711Sambrisko		}
2798233711Sambrisko		kern_sge[i].phys_addr = sc->mfi_kbuff_arr_busaddr[i];
2799233711Sambrisko		kern_sge[i].length = ioc->mfi_sgl[i].iov_len;
2800233711Sambrisko
2801233711Sambrisko		if (sizeof(bus_addr_t) == 8) {
2802233711Sambrisko			cm->cm_frame->stp.sgl.sg64[i].addr =
2803233711Sambrisko			    kern_sge[i].phys_addr;
2804233711Sambrisko			cm->cm_frame->stp.sgl.sg64[i].len =
2805233711Sambrisko			    ioc->mfi_sgl[i].iov_len;
2806233711Sambrisko		} else {
2807233711Sambrisko			cm->cm_frame->stp.sgl.sg32[i].len =
2808233711Sambrisko			    kern_sge[i].phys_addr;
2809233711Sambrisko			cm->cm_frame->stp.sgl.sg32[i].len =
2810233711Sambrisko			    ioc->mfi_sgl[i].iov_len;
2811233711Sambrisko		}
2812233711Sambrisko
2813233711Sambrisko		error = copyin(ioc->mfi_sgl[i].iov_base,
2814233711Sambrisko		    sc->kbuff_arr[i],
2815233711Sambrisko		    ioc->mfi_sgl[i].iov_len);
2816233711Sambrisko		if (error != 0) {
2817233711Sambrisko			device_printf(sc->mfi_dev, "Copy in failed\n");
2818233711Sambrisko			return error;
2819233711Sambrisko		}
2820233711Sambrisko	}
2821233711Sambrisko
2822233711Sambrisko	cm->cm_flags |=MFI_CMD_MAPPED;
2823233711Sambrisko	return 0;
2824233711Sambrisko}
2825233711Sambrisko
2826233711Sambriskostatic int
2827178968Sscottlmfi_user_command(struct mfi_softc *sc, struct mfi_ioc_passthru *ioc)
2828178968Sscottl{
2829178968Sscottl	struct mfi_command *cm;
2830178968Sscottl	struct mfi_dcmd_frame *dcmd;
2831178968Sscottl	void *ioc_buf = NULL;
2832178968Sscottl	uint32_t context;
2833178968Sscottl	int error = 0, locked;
2834178968Sscottl
2835178968Sscottl
2836178968Sscottl	if (ioc->buf_size > 0) {
2837238077Sjhb		if (ioc->buf_size > 1024 * 1024)
2838238077Sjhb			return (ENOMEM);
2839178968Sscottl		ioc_buf = malloc(ioc->buf_size, M_MFIBUF, M_WAITOK);
2840178968Sscottl		error = copyin(ioc->buf, ioc_buf, ioc->buf_size);
2841178968Sscottl		if (error) {
2842178968Sscottl			device_printf(sc->mfi_dev, "failed to copyin\n");
2843178968Sscottl			free(ioc_buf, M_MFIBUF);
2844178968Sscottl			return (error);
2845178968Sscottl		}
2846178968Sscottl	}
2847178968Sscottl
2848178968Sscottl	locked = mfi_config_lock(sc, ioc->ioc_frame.opcode);
2849178968Sscottl
2850178968Sscottl	mtx_lock(&sc->mfi_io_lock);
2851178968Sscottl	while ((cm = mfi_dequeue_free(sc)) == NULL)
2852178968Sscottl		msleep(mfi_user_command, &sc->mfi_io_lock, 0, "mfiioc", hz);
2853178968Sscottl
2854178968Sscottl	/* Save context for later */
2855178968Sscottl	context = cm->cm_frame->header.context;
2856178968Sscottl
2857178968Sscottl	dcmd = &cm->cm_frame->dcmd;
2858178968Sscottl	bcopy(&ioc->ioc_frame, dcmd, sizeof(struct mfi_dcmd_frame));
2859178968Sscottl
2860178968Sscottl	cm->cm_sg = &dcmd->sgl;
2861178968Sscottl	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
2862178968Sscottl	cm->cm_data = ioc_buf;
2863178968Sscottl	cm->cm_len = ioc->buf_size;
2864178968Sscottl
2865178968Sscottl	/* restore context */
2866178968Sscottl	cm->cm_frame->header.context = context;
2867178968Sscottl
2868178968Sscottl	/* Cheat since we don't know if we're writing or reading */
2869178968Sscottl	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
2870178968Sscottl
2871178968Sscottl	error = mfi_check_command_pre(sc, cm);
2872178968Sscottl	if (error)
2873178968Sscottl		goto out;
2874178968Sscottl
2875178968Sscottl	error = mfi_wait_command(sc, cm);
2876178968Sscottl	if (error) {
2877178968Sscottl		device_printf(sc->mfi_dev, "ioctl failed %d\n", error);
2878178968Sscottl		goto out;
2879178968Sscottl	}
2880178968Sscottl	bcopy(dcmd, &ioc->ioc_frame, sizeof(struct mfi_dcmd_frame));
2881178968Sscottl	mfi_check_command_post(sc, cm);
2882178968Sscottlout:
2883178968Sscottl	mfi_release_command(cm);
2884178968Sscottl	mtx_unlock(&sc->mfi_io_lock);
2885178968Sscottl	mfi_config_unlock(sc, locked);
2886178968Sscottl	if (ioc->buf_size > 0)
2887178968Sscottl		error = copyout(ioc_buf, ioc->buf, ioc->buf_size);
2888178968Sscottl	if (ioc_buf)
2889178968Sscottl		free(ioc_buf, M_MFIBUF);
2890178968Sscottl	return (error);
2891178968Sscottl}
2892178968Sscottl
2893178968Sscottl#define	PTRIN(p)		((void *)(uintptr_t)(p))
2894178968Sscottl
2895178968Sscottlstatic int
2896192450Simpmfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
2897157114Sscottl{
2898157114Sscottl	struct mfi_softc *sc;
2899157114Sscottl	union mfi_statrequest *ms;
2900164281Sambrisko	struct mfi_ioc_packet *ioc;
2901233711Sambrisko#ifdef COMPAT_FREEBSD32
2902179392Sambrisko	struct mfi_ioc_packet32 *ioc32;
2903179392Sambrisko#endif
2904164281Sambrisko	struct mfi_ioc_aen *aen;
2905164281Sambrisko	struct mfi_command *cm = NULL;
2906233711Sambrisko	uint32_t context = 0;
2907184897Sambrisko	union mfi_sense_ptr sense_ptr;
2908233711Sambrisko	uint8_t *data = NULL, *temp, *addr, skip_pre_post = 0;
2909225869Smav	size_t len;
2910233711Sambrisko	int i, res;
2911178968Sscottl	struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg;
2912233711Sambrisko#ifdef COMPAT_FREEBSD32
2913178968Sscottl	struct mfi_ioc_passthru32 *iop32 = (struct mfi_ioc_passthru32 *)arg;
2914178968Sscottl	struct mfi_ioc_passthru iop_swab;
2915178968Sscottl#endif
2916171821Sjhb	int error, locked;
2917233711Sambrisko	union mfi_sgl *sgl;
2918157114Sscottl	sc = dev->si_drv1;
2919157114Sscottl	error = 0;
2920157114Sscottl
2921233711Sambrisko	if (sc->adpreset)
2922233711Sambrisko		return EBUSY;
2923233711Sambrisko
2924233711Sambrisko	if (sc->hw_crit_error)
2925233711Sambrisko		return EBUSY;
2926233711Sambrisko
2927233711Sambrisko	if (sc->issuepend_done == 0)
2928233711Sambrisko		return EBUSY;
2929233711Sambrisko
2930157114Sscottl	switch (cmd) {
2931157114Sscottl	case MFIIO_STATS:
2932157114Sscottl		ms = (union mfi_statrequest *)arg;
2933157114Sscottl		switch (ms->ms_item) {
2934157114Sscottl		case MFIQ_FREE:
2935157114Sscottl		case MFIQ_BIO:
2936157114Sscottl		case MFIQ_READY:
2937157114Sscottl		case MFIQ_BUSY:
2938157114Sscottl			bcopy(&sc->mfi_qstat[ms->ms_item], &ms->ms_qstat,
2939157114Sscottl			    sizeof(struct mfi_qstat));
2940157114Sscottl			break;
2941157114Sscottl		default:
2942158737Sambrisko			error = ENOIOCTL;
2943157114Sscottl			break;
2944157114Sscottl		}
2945157114Sscottl		break;
2946169451Sscottl	case MFIIO_QUERY_DISK:
2947169451Sscottl	{
2948169451Sscottl		struct mfi_query_disk *qd;
2949169451Sscottl		struct mfi_disk *ld;
2950169451Sscottl
2951169451Sscottl		qd = (struct mfi_query_disk *)arg;
2952169451Sscottl		mtx_lock(&sc->mfi_io_lock);
2953169451Sscottl		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
2954169451Sscottl			if (ld->ld_id == qd->array_id)
2955169451Sscottl				break;
2956169451Sscottl		}
2957169451Sscottl		if (ld == NULL) {
2958169451Sscottl			qd->present = 0;
2959169451Sscottl			mtx_unlock(&sc->mfi_io_lock);
2960169451Sscottl			return (0);
2961169451Sscottl		}
2962169451Sscottl		qd->present = 1;
2963169451Sscottl		if (ld->ld_flags & MFI_DISK_FLAGS_OPEN)
2964169451Sscottl			qd->open = 1;
2965169451Sscottl		bzero(qd->devname, SPECNAMELEN + 1);
2966169451Sscottl		snprintf(qd->devname, SPECNAMELEN, "mfid%d", ld->ld_unit);
2967169451Sscottl		mtx_unlock(&sc->mfi_io_lock);
2968169451Sscottl		break;
2969169451Sscottl	}
2970164281Sambrisko	case MFI_CMD:
2971233711Sambrisko#ifdef COMPAT_FREEBSD32
2972179392Sambrisko	case MFI_CMD32:
2973179392Sambrisko#endif
2974177489Sambrisko		{
2975177489Sambrisko		devclass_t devclass;
2976164281Sambrisko		ioc = (struct mfi_ioc_packet *)arg;
2977177489Sambrisko		int adapter;
2978164281Sambrisko
2979177489Sambrisko		adapter = ioc->mfi_adapter_no;
2980177489Sambrisko		if (device_get_unit(sc->mfi_dev) == 0 && adapter != 0) {
2981177489Sambrisko			devclass = devclass_find("mfi");
2982177489Sambrisko			sc = devclass_get_softc(devclass, adapter);
2983177489Sambrisko		}
2984164281Sambrisko		mtx_lock(&sc->mfi_io_lock);
2985164281Sambrisko		if ((cm = mfi_dequeue_free(sc)) == NULL) {
2986164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
2987164281Sambrisko			return (EBUSY);
2988164281Sambrisko		}
2989164281Sambrisko		mtx_unlock(&sc->mfi_io_lock);
2990171821Sjhb		locked = 0;
2991164281Sambrisko
2992164281Sambrisko		/*
2993164281Sambrisko		 * save off original context since copying from user
2994164281Sambrisko		 * will clobber some data
2995164281Sambrisko		 */
2996164281Sambrisko		context = cm->cm_frame->header.context;
2997233711Sambrisko		cm->cm_frame->header.context = cm->cm_index;
2998164281Sambrisko
2999165225Sambrisko		bcopy(ioc->mfi_frame.raw, cm->cm_frame,
3000233711Sambrisko		    2 * MEGAMFI_FRAME_SIZE);
3001184897Sambrisko		cm->cm_total_frame_size = (sizeof(union mfi_sgl)
3002184897Sambrisko		    * ioc->mfi_sge_count) + ioc->mfi_sgl_off;
3003233711Sambrisko		cm->cm_frame->header.scsi_status = 0;
3004233711Sambrisko		cm->cm_frame->header.pad0 = 0;
3005175897Sambrisko		if (ioc->mfi_sge_count) {
3006175897Sambrisko			cm->cm_sg =
3007175897Sambrisko			    (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off];
3008175897Sambrisko		}
3009233711Sambrisko		sgl = cm->cm_sg;
3010175897Sambrisko		cm->cm_flags = 0;
3011175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
3012175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN;
3013175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
3014175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAOUT;
3015175897Sambrisko		/* Legacy app shim */
3016175897Sambrisko		if (cm->cm_flags == 0)
3017175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
3018164281Sambrisko		cm->cm_len = cm->cm_frame->header.data_len;
3019225869Smav		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
3020233711Sambrisko#ifdef COMPAT_FREEBSD32
3021225869Smav			if (cmd == MFI_CMD) {
3022225869Smav#endif
3023225869Smav				/* Native */
3024225869Smav				cm->cm_stp_len = ioc->mfi_sgl[0].iov_len;
3025233711Sambrisko#ifdef COMPAT_FREEBSD32
3026225869Smav			} else {
3027225869Smav				/* 32bit on 64bit */
3028225869Smav				ioc32 = (struct mfi_ioc_packet32 *)ioc;
3029225869Smav				cm->cm_stp_len = ioc32->mfi_sgl[0].iov_len;
3030225869Smav			}
3031225869Smav#endif
3032225869Smav			cm->cm_len += cm->cm_stp_len;
3033225869Smav		}
3034184897Sambrisko		if (cm->cm_len &&
3035184897Sambrisko		    (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
3036175897Sambrisko			cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
3037175897Sambrisko			    M_WAITOK | M_ZERO);
3038175897Sambrisko			if (cm->cm_data == NULL) {
3039175897Sambrisko				device_printf(sc->mfi_dev, "Malloc failed\n");
3040175897Sambrisko				goto out;
3041175897Sambrisko			}
3042175897Sambrisko		} else {
3043175897Sambrisko			cm->cm_data = 0;
3044165225Sambrisko		}
3045164281Sambrisko
3046164281Sambrisko		/* restore header context */
3047164281Sambrisko		cm->cm_frame->header.context = context;
3048164281Sambrisko
3049233711Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
3050233711Sambrisko			res = mfi_stp_cmd(sc, cm, arg);
3051233711Sambrisko			if (res != 0)
3052233711Sambrisko				goto out;
3053233711Sambrisko		} else {
3054233711Sambrisko			temp = data;
3055233711Sambrisko			if ((cm->cm_flags & MFI_CMD_DATAOUT) ||
3056233711Sambrisko			    (cm->cm_frame->header.cmd == MFI_CMD_STP)) {
3057233711Sambrisko				for (i = 0; i < ioc->mfi_sge_count; i++) {
3058233711Sambrisko#ifdef COMPAT_FREEBSD32
3059233711Sambrisko					if (cmd == MFI_CMD) {
3060225869Smav#endif
3061233711Sambrisko						/* Native */
3062233711Sambrisko						addr = ioc->mfi_sgl[i].iov_base;
3063233711Sambrisko						len = ioc->mfi_sgl[i].iov_len;
3064233711Sambrisko#ifdef COMPAT_FREEBSD32
3065233711Sambrisko					} else {
3066233711Sambrisko						/* 32bit on 64bit */
3067233711Sambrisko						ioc32 = (struct mfi_ioc_packet32 *)ioc;
3068233711Sambrisko						addr = PTRIN(ioc32->mfi_sgl[i].iov_base);
3069233711Sambrisko						len = ioc32->mfi_sgl[i].iov_len;
3070233711Sambrisko					}
3071179392Sambrisko#endif
3072233711Sambrisko					error = copyin(addr, temp, len);
3073233711Sambrisko					if (error != 0) {
3074233711Sambrisko						device_printf(sc->mfi_dev,
3075233711Sambrisko						    "Copy in failed\n");
3076233711Sambrisko						goto out;
3077233711Sambrisko					}
3078233711Sambrisko					temp = &temp[len];
3079175897Sambrisko				}
3080164281Sambrisko			}
3081164281Sambrisko		}
3082164281Sambrisko
3083171821Sjhb		if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
3084233711Sambrisko			locked = mfi_config_lock(sc,
3085233711Sambrisko			     cm->cm_frame->dcmd.opcode);
3086171821Sjhb
3087184933Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
3088233711Sambrisko			cm->cm_frame->pass.sense_addr_lo =
3089233711Sambrisko			    (uint32_t)cm->cm_sense_busaddr;
3090233711Sambrisko			cm->cm_frame->pass.sense_addr_hi =
3091233711Sambrisko			    (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
3092184933Sambrisko		}
3093164281Sambrisko		mtx_lock(&sc->mfi_io_lock);
3094233711Sambrisko		skip_pre_post = mfi_check_for_sscd (sc, cm);
3095233711Sambrisko		if (!skip_pre_post) {
3096233711Sambrisko			error = mfi_check_command_pre(sc, cm);
3097233711Sambrisko			if (error) {
3098233711Sambrisko				mtx_unlock(&sc->mfi_io_lock);
3099233711Sambrisko				goto out;
3100233711Sambrisko			}
3101171821Sjhb		}
3102170284Sambrisko		if ((error = mfi_wait_command(sc, cm)) != 0) {
3103164281Sambrisko			device_printf(sc->mfi_dev,
3104165225Sambrisko			    "Controller polled failed\n");
3105164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3106164281Sambrisko			goto out;
3107164281Sambrisko		}
3108233711Sambrisko		if (!skip_pre_post) {
3109233711Sambrisko			mfi_check_command_post(sc, cm);
3110233711Sambrisko		}
3111164281Sambrisko		mtx_unlock(&sc->mfi_io_lock);
3112164281Sambrisko
3113233711Sambrisko		if (cm->cm_frame->header.cmd != MFI_CMD_STP) {
3114233711Sambrisko			temp = data;
3115233711Sambrisko			if ((cm->cm_flags & MFI_CMD_DATAIN) ||
3116233711Sambrisko			    (cm->cm_frame->header.cmd == MFI_CMD_STP)) {
3117233711Sambrisko				for (i = 0; i < ioc->mfi_sge_count; i++) {
3118233711Sambrisko#ifdef COMPAT_FREEBSD32
3119233711Sambrisko					if (cmd == MFI_CMD) {
3120225869Smav#endif
3121233711Sambrisko						/* Native */
3122233711Sambrisko						addr = ioc->mfi_sgl[i].iov_base;
3123233711Sambrisko						len = ioc->mfi_sgl[i].iov_len;
3124233711Sambrisko#ifdef COMPAT_FREEBSD32
3125233711Sambrisko					} else {
3126233711Sambrisko						/* 32bit on 64bit */
3127233711Sambrisko						ioc32 = (struct mfi_ioc_packet32 *)ioc;
3128233711Sambrisko						addr = PTRIN(ioc32->mfi_sgl[i].iov_base);
3129233711Sambrisko						len = ioc32->mfi_sgl[i].iov_len;
3130233711Sambrisko					}
3131179392Sambrisko#endif
3132233711Sambrisko					error = copyout(temp, addr, len);
3133233711Sambrisko					if (error != 0) {
3134233711Sambrisko						device_printf(sc->mfi_dev,
3135233711Sambrisko						    "Copy out failed\n");
3136233711Sambrisko						goto out;
3137233711Sambrisko					}
3138233711Sambrisko					temp = &temp[len];
3139175897Sambrisko				}
3140164281Sambrisko			}
3141164281Sambrisko		}
3142164281Sambrisko
3143165225Sambrisko		if (ioc->mfi_sense_len) {
3144184897Sambrisko			/* get user-space sense ptr then copy out sense */
3145225428Sbz			bcopy(&ioc->mfi_frame.raw[ioc->mfi_sense_off],
3146184897Sambrisko			    &sense_ptr.sense_ptr_data[0],
3147184897Sambrisko			    sizeof(sense_ptr.sense_ptr_data));
3148233711Sambrisko#ifdef COMPAT_FREEBSD32
3149184974Sambrisko			if (cmd != MFI_CMD) {
3150184974Sambrisko				/*
3151184974Sambrisko				 * not 64bit native so zero out any address
3152184974Sambrisko				 * over 32bit */
3153184975Sambrisko				sense_ptr.addr.high = 0;
3154184974Sambrisko			}
3155184974Sambrisko#endif
3156184897Sambrisko			error = copyout(cm->cm_sense, sense_ptr.user_space,
3157165225Sambrisko			    ioc->mfi_sense_len);
3158164281Sambrisko			if (error != 0) {
3159164281Sambrisko				device_printf(sc->mfi_dev,
3160165225Sambrisko				    "Copy out failed\n");
3161164281Sambrisko				goto out;
3162164281Sambrisko			}
3163164281Sambrisko		}
3164164281Sambrisko
3165165225Sambrisko		ioc->mfi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status;
3166164281Sambriskoout:
3167171821Sjhb		mfi_config_unlock(sc, locked);
3168164281Sambrisko		if (data)
3169164281Sambrisko			free(data, M_MFIBUF);
3170233711Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
3171233711Sambrisko			for (i = 0; i < 2; i++) {
3172233711Sambrisko				if (sc->kbuff_arr[i]) {
3173233711Sambrisko					if (sc->mfi_kbuff_arr_busaddr != 0)
3174233711Sambrisko						bus_dmamap_unload(
3175233711Sambrisko						    sc->mfi_kbuff_arr_dmat[i],
3176233711Sambrisko						    sc->mfi_kbuff_arr_dmamap[i]
3177233711Sambrisko						    );
3178233711Sambrisko					if (sc->kbuff_arr[i] != NULL)
3179233711Sambrisko						bus_dmamem_free(
3180233711Sambrisko						    sc->mfi_kbuff_arr_dmat[i],
3181233711Sambrisko						    sc->kbuff_arr[i],
3182233711Sambrisko						    sc->mfi_kbuff_arr_dmamap[i]
3183233711Sambrisko						    );
3184233711Sambrisko					if (sc->mfi_kbuff_arr_dmat[i] != NULL)
3185233711Sambrisko						bus_dma_tag_destroy(
3186233711Sambrisko						    sc->mfi_kbuff_arr_dmat[i]);
3187233711Sambrisko				}
3188233711Sambrisko			}
3189233711Sambrisko		}
3190164281Sambrisko		if (cm) {
3191164281Sambrisko			mtx_lock(&sc->mfi_io_lock);
3192164281Sambrisko			mfi_release_command(cm);
3193164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3194164281Sambrisko		}
3195164281Sambrisko
3196164281Sambrisko		break;
3197177489Sambrisko		}
3198164281Sambrisko	case MFI_SET_AEN:
3199164281Sambrisko		aen = (struct mfi_ioc_aen *)arg;
3200164281Sambrisko		error = mfi_aen_register(sc, aen->aen_seq_num,
3201164281Sambrisko		    aen->aen_class_locale);
3202164281Sambrisko
3203164281Sambrisko		break;
3204164281Sambrisko	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
3205158737Sambrisko		{
3206158737Sambrisko			devclass_t devclass;
3207158737Sambrisko			struct mfi_linux_ioc_packet l_ioc;
3208158737Sambrisko			int adapter;
3209158737Sambrisko
3210158737Sambrisko			devclass = devclass_find("mfi");
3211158737Sambrisko			if (devclass == NULL)
3212158737Sambrisko				return (ENOENT);
3213158737Sambrisko
3214158737Sambrisko			error = copyin(arg, &l_ioc, sizeof(l_ioc));
3215158737Sambrisko			if (error)
3216158737Sambrisko				return (error);
3217158737Sambrisko			adapter = l_ioc.lioc_adapter_no;
3218158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
3219158737Sambrisko			if (sc == NULL)
3220158737Sambrisko				return (ENOENT);
3221158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
3222158737Sambrisko			    cmd, arg, flag, td));
3223158737Sambrisko			break;
3224158737Sambrisko		}
3225164281Sambrisko	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
3226158737Sambrisko		{
3227158737Sambrisko			devclass_t devclass;
3228158737Sambrisko			struct mfi_linux_ioc_aen l_aen;
3229158737Sambrisko			int adapter;
3230158737Sambrisko
3231158737Sambrisko			devclass = devclass_find("mfi");
3232158737Sambrisko			if (devclass == NULL)
3233158737Sambrisko				return (ENOENT);
3234158737Sambrisko
3235158737Sambrisko			error = copyin(arg, &l_aen, sizeof(l_aen));
3236158737Sambrisko			if (error)
3237158737Sambrisko				return (error);
3238158737Sambrisko			adapter = l_aen.laen_adapter_no;
3239158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
3240158737Sambrisko			if (sc == NULL)
3241158737Sambrisko				return (ENOENT);
3242158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
3243158737Sambrisko			    cmd, arg, flag, td));
3244158737Sambrisko			break;
3245158737Sambrisko		}
3246233711Sambrisko#ifdef COMPAT_FREEBSD32
3247178968Sscottl	case MFIIO_PASSTHRU32:
3248238077Sjhb		if (!SV_CURPROC_FLAG(SV_ILP32)) {
3249238077Sjhb			error = ENOTTY;
3250238077Sjhb			break;
3251238077Sjhb		}
3252178968Sscottl		iop_swab.ioc_frame	= iop32->ioc_frame;
3253178968Sscottl		iop_swab.buf_size	= iop32->buf_size;
3254178968Sscottl		iop_swab.buf		= PTRIN(iop32->buf);
3255178968Sscottl		iop			= &iop_swab;
3256178968Sscottl		/* FALLTHROUGH */
3257178968Sscottl#endif
3258178968Sscottl	case MFIIO_PASSTHRU:
3259178968Sscottl		error = mfi_user_command(sc, iop);
3260233711Sambrisko#ifdef COMPAT_FREEBSD32
3261178968Sscottl		if (cmd == MFIIO_PASSTHRU32)
3262178968Sscottl			iop32->ioc_frame = iop_swab.ioc_frame;
3263178968Sscottl#endif
3264178968Sscottl		break;
3265157114Sscottl	default:
3266163398Sscottl		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
3267238077Sjhb		error = ENOTTY;
3268157114Sscottl		break;
3269157114Sscottl	}
3270157114Sscottl
3271157114Sscottl	return (error);
3272157114Sscottl}
3273158737Sambrisko
3274158737Sambriskostatic int
3275192450Simpmfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
3276158737Sambrisko{
3277158737Sambrisko	struct mfi_softc *sc;
3278158737Sambrisko	struct mfi_linux_ioc_packet l_ioc;
3279158737Sambrisko	struct mfi_linux_ioc_aen l_aen;
3280158737Sambrisko	struct mfi_command *cm = NULL;
3281158737Sambrisko	struct mfi_aen *mfi_aen_entry;
3282184897Sambrisko	union mfi_sense_ptr sense_ptr;
3283233711Sambrisko	uint32_t context = 0;
3284158737Sambrisko	uint8_t *data = NULL, *temp;
3285158737Sambrisko	int i;
3286171821Sjhb	int error, locked;
3287158737Sambrisko
3288158737Sambrisko	sc = dev->si_drv1;
3289158737Sambrisko	error = 0;
3290158737Sambrisko	switch (cmd) {
3291164281Sambrisko	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
3292158737Sambrisko		error = copyin(arg, &l_ioc, sizeof(l_ioc));
3293158737Sambrisko		if (error != 0)
3294158737Sambrisko			return (error);
3295158737Sambrisko
3296158737Sambrisko		if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) {
3297158737Sambrisko			return (EINVAL);
3298158737Sambrisko		}
3299158737Sambrisko
3300158737Sambrisko		mtx_lock(&sc->mfi_io_lock);
3301158737Sambrisko		if ((cm = mfi_dequeue_free(sc)) == NULL) {
3302158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3303158737Sambrisko			return (EBUSY);
3304158737Sambrisko		}
3305158737Sambrisko		mtx_unlock(&sc->mfi_io_lock);
3306171821Sjhb		locked = 0;
3307158737Sambrisko
3308158737Sambrisko		/*
3309158737Sambrisko		 * save off original context since copying from user
3310158737Sambrisko		 * will clobber some data
3311158737Sambrisko		 */
3312158737Sambrisko		context = cm->cm_frame->header.context;
3313158737Sambrisko
3314158737Sambrisko		bcopy(l_ioc.lioc_frame.raw, cm->cm_frame,
3315175897Sambrisko		      2 * MFI_DCMD_FRAME_SIZE);	/* this isn't quite right */
3316184897Sambrisko		cm->cm_total_frame_size = (sizeof(union mfi_sgl)
3317184897Sambrisko		      * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off;
3318233711Sambrisko		cm->cm_frame->header.scsi_status = 0;
3319233711Sambrisko		cm->cm_frame->header.pad0 = 0;
3320175897Sambrisko		if (l_ioc.lioc_sge_count)
3321175897Sambrisko			cm->cm_sg =
3322175897Sambrisko			    (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
3323175897Sambrisko		cm->cm_flags = 0;
3324175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
3325175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN;
3326175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
3327175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAOUT;
3328158737Sambrisko		cm->cm_len = cm->cm_frame->header.data_len;
3329184897Sambrisko		if (cm->cm_len &&
3330184897Sambrisko		      (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
3331175897Sambrisko			cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
3332175897Sambrisko			    M_WAITOK | M_ZERO);
3333175897Sambrisko			if (cm->cm_data == NULL) {
3334175897Sambrisko				device_printf(sc->mfi_dev, "Malloc failed\n");
3335175897Sambrisko				goto out;
3336175897Sambrisko			}
3337175897Sambrisko		} else {
3338175897Sambrisko			cm->cm_data = 0;
3339175897Sambrisko		}
3340158737Sambrisko
3341158737Sambrisko		/* restore header context */
3342158737Sambrisko		cm->cm_frame->header.context = context;
3343158737Sambrisko
3344158737Sambrisko		temp = data;
3345175897Sambrisko		if (cm->cm_flags & MFI_CMD_DATAOUT) {
3346175897Sambrisko			for (i = 0; i < l_ioc.lioc_sge_count; i++) {
3347178968Sscottl				error = copyin(PTRIN(l_ioc.lioc_sgl[i].iov_base),
3348175897Sambrisko				       temp,
3349175897Sambrisko				       l_ioc.lioc_sgl[i].iov_len);
3350175897Sambrisko				if (error != 0) {
3351175897Sambrisko					device_printf(sc->mfi_dev,
3352175897Sambrisko					    "Copy in failed\n");
3353175897Sambrisko					goto out;
3354175897Sambrisko				}
3355175897Sambrisko				temp = &temp[l_ioc.lioc_sgl[i].iov_len];
3356158737Sambrisko			}
3357158737Sambrisko		}
3358158737Sambrisko
3359171821Sjhb		if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
3360171821Sjhb			locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
3361171821Sjhb
3362184933Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
3363233711Sambrisko			cm->cm_frame->pass.sense_addr_lo =
3364233711Sambrisko			    (uint32_t)cm->cm_sense_busaddr;
3365233711Sambrisko			cm->cm_frame->pass.sense_addr_hi =
3366233711Sambrisko			    (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
3367184933Sambrisko		}
3368184933Sambrisko
3369163398Sscottl		mtx_lock(&sc->mfi_io_lock);
3370171821Sjhb		error = mfi_check_command_pre(sc, cm);
3371171821Sjhb		if (error) {
3372171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
3373171821Sjhb			goto out;
3374171821Sjhb		}
3375171821Sjhb
3376170284Sambrisko		if ((error = mfi_wait_command(sc, cm)) != 0) {
3377158737Sambrisko			device_printf(sc->mfi_dev,
3378165225Sambrisko			    "Controller polled failed\n");
3379163398Sscottl			mtx_unlock(&sc->mfi_io_lock);
3380158737Sambrisko			goto out;
3381158737Sambrisko		}
3382158737Sambrisko
3383171821Sjhb		mfi_check_command_post(sc, cm);
3384163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
3385158737Sambrisko
3386158737Sambrisko		temp = data;
3387175897Sambrisko		if (cm->cm_flags & MFI_CMD_DATAIN) {
3388175897Sambrisko			for (i = 0; i < l_ioc.lioc_sge_count; i++) {
3389175897Sambrisko				error = copyout(temp,
3390178968Sscottl					PTRIN(l_ioc.lioc_sgl[i].iov_base),
3391175897Sambrisko					l_ioc.lioc_sgl[i].iov_len);
3392175897Sambrisko				if (error != 0) {
3393175897Sambrisko					device_printf(sc->mfi_dev,
3394175897Sambrisko					    "Copy out failed\n");
3395175897Sambrisko					goto out;
3396175897Sambrisko				}
3397175897Sambrisko				temp = &temp[l_ioc.lioc_sgl[i].iov_len];
3398158737Sambrisko			}
3399158737Sambrisko		}
3400158737Sambrisko
3401158737Sambrisko		if (l_ioc.lioc_sense_len) {
3402184897Sambrisko			/* get user-space sense ptr then copy out sense */
3403184897Sambrisko			bcopy(&((struct mfi_linux_ioc_packet*)arg)
3404184897Sambrisko                            ->lioc_frame.raw[l_ioc.lioc_sense_off],
3405184897Sambrisko			    &sense_ptr.sense_ptr_data[0],
3406184897Sambrisko			    sizeof(sense_ptr.sense_ptr_data));
3407184974Sambrisko#ifdef __amd64__
3408184974Sambrisko			/*
3409184974Sambrisko			 * only 32bit Linux support so zero out any
3410184974Sambrisko			 * address over 32bit
3411184974Sambrisko			 */
3412184975Sambrisko			sense_ptr.addr.high = 0;
3413184974Sambrisko#endif
3414184897Sambrisko			error = copyout(cm->cm_sense, sense_ptr.user_space,
3415158737Sambrisko			    l_ioc.lioc_sense_len);
3416158737Sambrisko			if (error != 0) {
3417158737Sambrisko				device_printf(sc->mfi_dev,
3418165225Sambrisko				    "Copy out failed\n");
3419158737Sambrisko				goto out;
3420158737Sambrisko			}
3421158737Sambrisko		}
3422158737Sambrisko
3423158737Sambrisko		error = copyout(&cm->cm_frame->header.cmd_status,
3424158737Sambrisko			&((struct mfi_linux_ioc_packet*)arg)
3425158737Sambrisko			->lioc_frame.hdr.cmd_status,
3426158737Sambrisko			1);
3427158737Sambrisko		if (error != 0) {
3428158737Sambrisko			device_printf(sc->mfi_dev,
3429165225Sambrisko				      "Copy out failed\n");
3430158737Sambrisko			goto out;
3431158737Sambrisko		}
3432158737Sambrisko
3433158737Sambriskoout:
3434171821Sjhb		mfi_config_unlock(sc, locked);
3435158737Sambrisko		if (data)
3436158737Sambrisko			free(data, M_MFIBUF);
3437158737Sambrisko		if (cm) {
3438158737Sambrisko			mtx_lock(&sc->mfi_io_lock);
3439158737Sambrisko			mfi_release_command(cm);
3440158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
3441158737Sambrisko		}
3442158737Sambrisko
3443158737Sambrisko		return (error);
3444164281Sambrisko	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
3445158737Sambrisko		error = copyin(arg, &l_aen, sizeof(l_aen));
3446158737Sambrisko		if (error != 0)
3447158737Sambrisko			return (error);
3448158737Sambrisko		printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid);
3449158737Sambrisko		mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF,
3450158737Sambrisko		    M_WAITOK);
3451163398Sscottl		mtx_lock(&sc->mfi_io_lock);
3452158737Sambrisko		if (mfi_aen_entry != NULL) {
3453158737Sambrisko			mfi_aen_entry->p = curproc;
3454158737Sambrisko			TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry,
3455158737Sambrisko			    aen_link);
3456158737Sambrisko		}
3457158737Sambrisko		error = mfi_aen_register(sc, l_aen.laen_seq_num,
3458158737Sambrisko		    l_aen.laen_class_locale);
3459158737Sambrisko
3460158737Sambrisko		if (error != 0) {
3461158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
3462158737Sambrisko			    aen_link);
3463158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
3464158737Sambrisko		}
3465163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
3466158737Sambrisko
3467158737Sambrisko		return (error);
3468158737Sambrisko	default:
3469158737Sambrisko		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
3470158737Sambrisko		error = ENOENT;
3471158737Sambrisko		break;
3472158737Sambrisko	}
3473158737Sambrisko
3474158737Sambrisko	return (error);
3475158737Sambrisko}
3476158737Sambrisko
3477158737Sambriskostatic int
3478158737Sambriskomfi_poll(struct cdev *dev, int poll_events, struct thread *td)
3479158737Sambrisko{
3480158737Sambrisko	struct mfi_softc *sc;
3481158737Sambrisko	int revents = 0;
3482158737Sambrisko
3483158737Sambrisko	sc = dev->si_drv1;
3484158737Sambrisko
3485158737Sambrisko	if (poll_events & (POLLIN | POLLRDNORM)) {
3486163398Sscottl		if (sc->mfi_aen_triggered != 0) {
3487158737Sambrisko			revents |= poll_events & (POLLIN | POLLRDNORM);
3488163398Sscottl			sc->mfi_aen_triggered = 0;
3489163398Sscottl		}
3490158737Sambrisko		if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) {
3491158737Sambrisko			revents |= POLLERR;
3492158737Sambrisko		}
3493158737Sambrisko	}
3494158737Sambrisko
3495158737Sambrisko	if (revents == 0) {
3496158737Sambrisko		if (poll_events & (POLLIN | POLLRDNORM)) {
3497158737Sambrisko			sc->mfi_poll_waiting = 1;
3498158737Sambrisko			selrecord(td, &sc->mfi_select);
3499158737Sambrisko		}
3500158737Sambrisko	}
3501158737Sambrisko
3502158737Sambrisko	return revents;
3503158737Sambrisko}
3504162619Sscottl
3505162619Sscottlstatic void
3506163398Sscottlmfi_dump_all(void)
3507163398Sscottl{
3508163398Sscottl	struct mfi_softc *sc;
3509163398Sscottl	struct mfi_command *cm;
3510163398Sscottl	devclass_t dc;
3511163398Sscottl	time_t deadline;
3512163398Sscottl	int timedout;
3513163398Sscottl	int i;
3514163398Sscottl
3515163398Sscottl	dc = devclass_find("mfi");
3516163398Sscottl	if (dc == NULL) {
3517163398Sscottl		printf("No mfi dev class\n");
3518163398Sscottl		return;
3519163398Sscottl	}
3520163398Sscottl
3521163398Sscottl	for (i = 0; ; i++) {
3522163398Sscottl		sc = devclass_get_softc(dc, i);
3523163398Sscottl		if (sc == NULL)
3524163398Sscottl			break;
3525163398Sscottl		device_printf(sc->mfi_dev, "Dumping\n\n");
3526163398Sscottl		timedout = 0;
3527163398Sscottl		deadline = time_uptime - MFI_CMD_TIMEOUT;
3528163398Sscottl		mtx_lock(&sc->mfi_io_lock);
3529163398Sscottl		TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
3530163398Sscottl			if (cm->cm_timestamp < deadline) {
3531163398Sscottl				device_printf(sc->mfi_dev,
3532233711Sambrisko				    "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
3533233711Sambrisko				    cm, (int)(time_uptime - cm->cm_timestamp));
3534163398Sscottl				MFI_PRINT_CMD(cm);
3535163398Sscottl				timedout++;
3536163398Sscottl			}
3537163398Sscottl		}
3538163398Sscottl
3539163398Sscottl#if 0
3540163398Sscottl		if (timedout)
3541163398Sscottl			MFI_DUMP_CMDS(SC);
3542163398Sscottl#endif
3543163398Sscottl
3544163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
3545163398Sscottl	}
3546163398Sscottl
3547163398Sscottl	return;
3548163398Sscottl}
3549163398Sscottl
3550163398Sscottlstatic void
3551162619Sscottlmfi_timeout(void *data)
3552162619Sscottl{
3553162619Sscottl	struct mfi_softc *sc = (struct mfi_softc *)data;
3554162619Sscottl	struct mfi_command *cm;
3555162619Sscottl	time_t deadline;
3556162619Sscottl	int timedout = 0;
3557162619Sscottl
3558162619Sscottl	deadline = time_uptime - MFI_CMD_TIMEOUT;
3559233711Sambrisko	if (sc->adpreset == 0) {
3560233711Sambrisko		if (!mfi_tbolt_reset(sc)) {
3561233711Sambrisko			callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz, mfi_timeout, sc);
3562233711Sambrisko			return;
3563233711Sambrisko		}
3564233711Sambrisko	}
3565162619Sscottl	mtx_lock(&sc->mfi_io_lock);
3566162619Sscottl	TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
3567235014Sambrisko		if (sc->mfi_aen_cm == cm || sc->mfi_map_sync_cm == cm)
3568162688Sscottl			continue;
3569235014Sambrisko		if (cm->cm_timestamp < deadline) {
3570233711Sambrisko			if (sc->adpreset != 0 && sc->issuepend_done == 0) {
3571233711Sambrisko				cm->cm_timestamp = time_uptime;
3572233711Sambrisko			} else {
3573233711Sambrisko				device_printf(sc->mfi_dev,
3574233711Sambrisko				    "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
3575233711Sambrisko				     cm, (int)(time_uptime - cm->cm_timestamp)
3576233711Sambrisko				     );
3577233711Sambrisko				MFI_PRINT_CMD(cm);
3578233711Sambrisko				MFI_VALIDATE_CMD(sc, cm);
3579233711Sambrisko				timedout++;
3580233711Sambrisko			}
3581162619Sscottl		}
3582162619Sscottl	}
3583162619Sscottl
3584162619Sscottl#if 0
3585162619Sscottl	if (timedout)
3586162619Sscottl		MFI_DUMP_CMDS(SC);
3587162619Sscottl#endif
3588162619Sscottl
3589162619Sscottl	mtx_unlock(&sc->mfi_io_lock);
3590162619Sscottl
3591162619Sscottl	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
3592162619Sscottl	    mfi_timeout, sc);
3593162619Sscottl
3594163398Sscottl	if (0)
3595163398Sscottl		mfi_dump_all();
3596162619Sscottl	return;
3597162619Sscottl}
3598