mfi.c revision 240962
1254721Semaste/*-
2254721Semaste * Copyright (c) 2006 IronPort Systems
3254721Semaste * All rights reserved.
4254721Semaste *
5254721Semaste * Redistribution and use in source and binary forms, with or without
6254721Semaste * modification, are permitted provided that the following conditions
7254721Semaste * are met:
8254721Semaste * 1. Redistributions of source code must retain the above copyright
9254721Semaste *    notice, this list of conditions and the following disclaimer.
10254721Semaste * 2. Redistributions in binary form must reproduce the above copyright
11254721Semaste *    notice, this list of conditions and the following disclaimer in the
12254721Semaste *    documentation and/or other materials provided with the distribution.
13263367Semaste *
14263367Semaste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15263367Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16263363Semaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17263363Semaste * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18254721Semaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19263363Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20254721Semaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21263363Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22254721Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23263363Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24263363Semaste * SUCH DAMAGE.
25263363Semaste */
26269024Semaste/*-
27263363Semaste * Copyright (c) 2007 LSI Corp.
28263363Semaste * Copyright (c) 2007 Rajesh Prabhakaran.
29263363Semaste * All rights reserved.
30263363Semaste *
31263363Semaste * Redistribution and use in source and binary forms, with or without
32263363Semaste * modification, are permitted provided that the following conditions
33263363Semaste * are met:
34269024Semaste * 1. Redistributions of source code must retain the above copyright
35263363Semaste *    notice, this list of conditions and the following disclaimer.
36263363Semaste * 2. Redistributions in binary form must reproduce the above copyright
37269024Semaste *    notice, this list of conditions and the following disclaimer in the
38269024Semaste *    documentation and/or other materials provided with the distribution.
39269024Semaste *
40269024Semaste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
41269024Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42269024Semaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43269024Semaste * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44269024Semaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45269024Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46269024Semaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47269024Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48269024Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49269024Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50269024Semaste * SUCH DAMAGE.
51269024Semaste */
52269024Semaste
53269024Semaste#include <sys/cdefs.h>
54269024Semaste__FBSDID("$FreeBSD: head/sys/dev/mfi/mfi.c 240962 2012-09-26 14:14:06Z jhb $");
55269024Semaste
56269024Semaste#include "opt_compat.h"
57269024Semaste#include "opt_mfi.h"
58269024Semaste
59269024Semaste#include <sys/param.h>
60263363Semaste#include <sys/systm.h>
61263363Semaste#include <sys/sysctl.h>
62263363Semaste#include <sys/malloc.h>
63263363Semaste#include <sys/kernel.h>
64263363Semaste#include <sys/poll.h>
65263363Semaste#include <sys/selinfo.h>
66263363Semaste#include <sys/bus.h>
67263363Semaste#include <sys/conf.h>
68263363Semaste#include <sys/eventhandler.h>
69263363Semaste#include <sys/rman.h>
70263363Semaste#include <sys/bus_dma.h>
71263363Semaste#include <sys/bio.h>
72263363Semaste#include <sys/ioccom.h>
73263363Semaste#include <sys/uio.h>
74263363Semaste#include <sys/proc.h>
75263363Semaste#include <sys/signalvar.h>
76263363Semaste#include <sys/sysent.h>
77263363Semaste#include <sys/taskqueue.h>
78263363Semaste
79263363Semaste#include <machine/bus.h>
80263363Semaste#include <machine/resource.h>
81263363Semaste
82263363Semaste#include <dev/mfi/mfireg.h>
83263363Semaste#include <dev/mfi/mfi_ioctl.h>
84263363Semaste#include <dev/mfi/mfivar.h>
85263363Semaste#include <sys/interrupt.h>
86263363Semaste#include <sys/priority.h>
87263363Semaste
88263363Semastestatic int	mfi_alloc_commands(struct mfi_softc *);
89263363Semastestatic int	mfi_comms_init(struct mfi_softc *);
90263363Semastestatic int	mfi_get_controller_info(struct mfi_softc *);
91263363Semastestatic int	mfi_get_log_state(struct mfi_softc *,
92263363Semaste		    struct mfi_evt_log_state **);
93263363Semastestatic int	mfi_parse_entries(struct mfi_softc *, int, int);
94263363Semastestatic void	mfi_data_cb(void *, bus_dma_segment_t *, int, int);
95263363Semastestatic void	mfi_startup(void *arg);
96263363Semastestatic void	mfi_intr(void *arg);
97263363Semastestatic void	mfi_ldprobe(struct mfi_softc *sc);
98263363Semastestatic void	mfi_syspdprobe(struct mfi_softc *sc);
99263363Semastestatic void	mfi_handle_evt(void *context, int pending);
100263363Semastestatic int	mfi_aen_register(struct mfi_softc *sc, int seq, int locale);
101263363Semastestatic void	mfi_aen_complete(struct mfi_command *);
102263363Semastestatic int	mfi_add_ld(struct mfi_softc *sc, int);
103263363Semastestatic void	mfi_add_ld_complete(struct mfi_command *);
104263363Semastestatic int	mfi_add_sys_pd(struct mfi_softc *sc, int);
105263363Semastestatic void	mfi_add_sys_pd_complete(struct mfi_command *);
106263363Semastestatic struct mfi_command * mfi_bio_command(struct mfi_softc *);
107263363Semastestatic void	mfi_bio_complete(struct mfi_command *);
108263363Semastestatic struct mfi_command *mfi_build_ldio(struct mfi_softc *,struct bio*);
109263363Semastestatic struct mfi_command *mfi_build_syspdio(struct mfi_softc *,struct bio*);
110263363Semastestatic int	mfi_send_frame(struct mfi_softc *, struct mfi_command *);
111263363Semastestatic int	mfi_abort(struct mfi_softc *, struct mfi_command *);
112263363Semastestatic int	mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int, struct thread *);
113263363Semastestatic void	mfi_timeout(void *);
114263363Semastestatic int	mfi_user_command(struct mfi_softc *,
115263363Semaste		    struct mfi_ioc_passthru *);
116263363Semastestatic void	mfi_enable_intr_xscale(struct mfi_softc *sc);
117263363Semastestatic void	mfi_enable_intr_ppc(struct mfi_softc *sc);
118263363Semastestatic int32_t	mfi_read_fw_status_xscale(struct mfi_softc *sc);
119263363Semastestatic int32_t	mfi_read_fw_status_ppc(struct mfi_softc *sc);
120263363Semastestatic int	mfi_check_clear_intr_xscale(struct mfi_softc *sc);
121263363Semastestatic int	mfi_check_clear_intr_ppc(struct mfi_softc *sc);
122263363Semastestatic void 	mfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add,
123263363Semaste		    uint32_t frame_cnt);
124263363Semastestatic void 	mfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add,
125263363Semaste		    uint32_t frame_cnt);
126263363Semastestatic int mfi_config_lock(struct mfi_softc *sc, uint32_t opcode);
127263363Semastestatic void mfi_config_unlock(struct mfi_softc *sc, int locked);
128263363Semastestatic int mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm);
129263363Semastestatic void mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm);
130263363Semastestatic int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm);
131263363Semaste
132263363SemasteSYSCTL_NODE(_hw, OID_AUTO, mfi, CTLFLAG_RD, 0, "MFI driver parameters");
133263363Semastestatic int	mfi_event_locale = MFI_EVT_LOCALE_ALL;
134263363SemasteTUNABLE_INT("hw.mfi.event_locale", &mfi_event_locale);
135263363SemasteSYSCTL_INT(_hw_mfi, OID_AUTO, event_locale, CTLFLAG_RW, &mfi_event_locale,
136263363Semaste            0, "event message locale");
137263363Semaste
138263363Semastestatic int	mfi_event_class = MFI_EVT_CLASS_INFO;
139263363SemasteTUNABLE_INT("hw.mfi.event_class", &mfi_event_class);
140263363SemasteSYSCTL_INT(_hw_mfi, OID_AUTO, event_class, CTLFLAG_RW, &mfi_event_class,
141263363Semaste          0, "event message class");
142263363Semaste
143263363Semastestatic int	mfi_max_cmds = 128;
144263363SemasteTUNABLE_INT("hw.mfi.max_cmds", &mfi_max_cmds);
145263363SemasteSYSCTL_INT(_hw_mfi, OID_AUTO, max_cmds, CTLFLAG_RD, &mfi_max_cmds,
146263363Semaste	   0, "Max commands");
147263363Semaste
148263363Semastestatic int	mfi_detect_jbod_change = 1;
149263363SemasteTUNABLE_INT("hw.mfi.detect_jbod_change", &mfi_detect_jbod_change);
150263363SemasteSYSCTL_INT(_hw_mfi, OID_AUTO, detect_jbod_change, CTLFLAG_RW,
151263363Semaste	   &mfi_detect_jbod_change, 0, "Detect a change to a JBOD");
152263363Semaste
153263363Semaste/* Management interface */
154263363Semastestatic d_open_t		mfi_open;
155263363Semastestatic d_close_t	mfi_close;
156263363Semastestatic d_ioctl_t	mfi_ioctl;
157263363Semastestatic d_poll_t		mfi_poll;
158263363Semaste
159263363Semastestatic struct cdevsw mfi_cdevsw = {
160263363Semaste	.d_version = 	D_VERSION,
161263363Semaste	.d_flags =	0,
162263363Semaste	.d_open = 	mfi_open,
163263363Semaste	.d_close =	mfi_close,
164263363Semaste	.d_ioctl =	mfi_ioctl,
165263363Semaste	.d_poll =	mfi_poll,
166263363Semaste	.d_name =	"mfi",
167263363Semaste};
168263363Semaste
169263363SemasteMALLOC_DEFINE(M_MFIBUF, "mfibuf", "Buffers for the MFI driver");
170263363Semaste
171263363Semaste#define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH
172263363Semastestruct mfi_skinny_dma_info mfi_skinny;
173263363Semaste
174263363Semastestatic void
175263363Semastemfi_enable_intr_xscale(struct mfi_softc *sc)
176263363Semaste{
177263363Semaste	MFI_WRITE4(sc, MFI_OMSK, 0x01);
178263363Semaste}
179263363Semaste
180263363Semastestatic void
181263363Semastemfi_enable_intr_ppc(struct mfi_softc *sc)
182263363Semaste{
183263363Semaste	if (sc->mfi_flags & MFI_FLAGS_1078) {
184263363Semaste		MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
185263363Semaste		MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM);
186263363Semaste	}
187263363Semaste	else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
188263363Semaste		MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
189263363Semaste		MFI_WRITE4(sc, MFI_OMSK, ~MFI_GEN2_EIM);
190263363Semaste	}
191263363Semaste	else if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
192263363Semaste		MFI_WRITE4(sc, MFI_OMSK, ~0x00000001);
193263363Semaste	}
194263363Semaste}
195263363Semaste
196263363Semastestatic int32_t
197263363Semastemfi_read_fw_status_xscale(struct mfi_softc *sc)
198263363Semaste{
199263363Semaste	return MFI_READ4(sc, MFI_OMSG0);
200263363Semaste}
201263363Semaste
202263363Semastestatic int32_t
203263363Semastemfi_read_fw_status_ppc(struct mfi_softc *sc)
204263363Semaste{
205263363Semaste	return MFI_READ4(sc, MFI_OSP0);
206263363Semaste}
207263363Semaste
208263363Semastestatic int
209263363Semastemfi_check_clear_intr_xscale(struct mfi_softc *sc)
210263363Semaste{
211263363Semaste	int32_t status;
212263363Semaste
213263363Semaste	status = MFI_READ4(sc, MFI_OSTS);
214263363Semaste	if ((status & MFI_OSTS_INTR_VALID) == 0)
215263363Semaste		return 1;
216263363Semaste
217263363Semaste	MFI_WRITE4(sc, MFI_OSTS, status);
218263363Semaste	return 0;
219263363Semaste}
220263363Semaste
221263363Semastestatic int
222263363Semastemfi_check_clear_intr_ppc(struct mfi_softc *sc)
223263363Semaste{
224263363Semaste	int32_t status;
225263363Semaste
226263363Semaste	status = MFI_READ4(sc, MFI_OSTS);
227263363Semaste	if (sc->mfi_flags & MFI_FLAGS_1078) {
228263363Semaste		if (!(status & MFI_1078_RM)) {
229263363Semaste			return 1;
230263363Semaste		}
231263363Semaste	}
232263363Semaste	else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
233263363Semaste		if (!(status & MFI_GEN2_RM)) {
234263363Semaste			return 1;
235263363Semaste		}
236263363Semaste	}
237263363Semaste	else if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
238263363Semaste		if (!(status & MFI_SKINNY_RM)) {
239263363Semaste			return 1;
240263363Semaste		}
241263363Semaste	}
242263363Semaste	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
243263363Semaste		MFI_WRITE4(sc, MFI_OSTS, status);
244263363Semaste	else
245263363Semaste		MFI_WRITE4(sc, MFI_ODCR0, status);
246263363Semaste	return 0;
247263363Semaste}
248263363Semaste
249263363Semastestatic void
250263363Semastemfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt)
251263363Semaste{
252263363Semaste	MFI_WRITE4(sc, MFI_IQP,(bus_add >>3)|frame_cnt);
253263363Semaste}
254263363Semaste
255263363Semastestatic void
256263363Semastemfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt)
257263363Semaste{
258263363Semaste	if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
259263363Semaste	    MFI_WRITE4(sc, MFI_IQPL, (bus_add | frame_cnt <<1)|1 );
260263363Semaste	    MFI_WRITE4(sc, MFI_IQPH, 0x00000000);
261263363Semaste	} else {
262263363Semaste	    MFI_WRITE4(sc, MFI_IQP, (bus_add | frame_cnt <<1)|1 );
263263363Semaste	}
264263363Semaste}
265263363Semaste
266263363Semasteint
267263363Semastemfi_transition_firmware(struct mfi_softc *sc)
268263363Semaste{
269263363Semaste	uint32_t fw_state, cur_state;
270263363Semaste	int max_wait, i;
271263363Semaste	uint32_t cur_abs_reg_val = 0;
272263363Semaste	uint32_t prev_abs_reg_val = 0;
273263363Semaste
274263363Semaste	cur_abs_reg_val = sc->mfi_read_fw_status(sc);
275263363Semaste	fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK;
276263363Semaste	while (fw_state != MFI_FWSTATE_READY) {
277263363Semaste		if (bootverbose)
278263363Semaste			device_printf(sc->mfi_dev, "Waiting for firmware to "
279263363Semaste			"become ready\n");
280263363Semaste		cur_state = fw_state;
281263363Semaste		switch (fw_state) {
282263363Semaste		case MFI_FWSTATE_FAULT:
283263363Semaste			device_printf(sc->mfi_dev, "Firmware fault\n");
284263363Semaste			return (ENXIO);
285263363Semaste		case MFI_FWSTATE_WAIT_HANDSHAKE:
286263363Semaste			if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
287263363Semaste			    MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
288263363Semaste			else
289263363Semaste			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
290263363Semaste			max_wait = MFI_RESET_WAIT_TIME;
291263363Semaste			break;
292263363Semaste		case MFI_FWSTATE_OPERATIONAL:
293263363Semaste			if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
294263363Semaste			    MFI_WRITE4(sc, MFI_SKINNY_IDB, 7);
295263363Semaste			else
296263363Semaste			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY);
297263363Semaste			max_wait = MFI_RESET_WAIT_TIME;
298263363Semaste			break;
299263363Semaste		case MFI_FWSTATE_UNDEFINED:
300263363Semaste		case MFI_FWSTATE_BB_INIT:
301263363Semaste			max_wait = MFI_RESET_WAIT_TIME;
302263363Semaste			break;
303263363Semaste		case MFI_FWSTATE_FW_INIT_2:
304263363Semaste			max_wait = MFI_RESET_WAIT_TIME;
305263363Semaste			break;
306263363Semaste		case MFI_FWSTATE_FW_INIT:
307263363Semaste		case MFI_FWSTATE_FLUSH_CACHE:
308263363Semaste			max_wait = MFI_RESET_WAIT_TIME;
309263363Semaste			break;
310263363Semaste		case MFI_FWSTATE_DEVICE_SCAN:
311263363Semaste			max_wait = MFI_RESET_WAIT_TIME; /* wait for 180 seconds */
312263363Semaste			prev_abs_reg_val = cur_abs_reg_val;
313263363Semaste			break;
314263363Semaste		case MFI_FWSTATE_BOOT_MESSAGE_PENDING:
315263363Semaste			if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
316263363Semaste			    MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_HOTPLUG);
317263363Semaste			else
318263363Semaste			    MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG);
319263363Semaste			max_wait = MFI_RESET_WAIT_TIME;
320263363Semaste			break;
321263363Semaste		default:
322263363Semaste			device_printf(sc->mfi_dev, "Unknown firmware state %#x\n",
323263363Semaste			    fw_state);
324263363Semaste			return (ENXIO);
325263363Semaste		}
326263363Semaste		for (i = 0; i < (max_wait * 10); i++) {
327263363Semaste			cur_abs_reg_val = sc->mfi_read_fw_status(sc);
328263363Semaste			fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK;
329263363Semaste			if (fw_state == cur_state)
330263363Semaste				DELAY(100000);
331263363Semaste			else
332263363Semaste				break;
333263363Semaste		}
334263363Semaste		if (fw_state == MFI_FWSTATE_DEVICE_SCAN) {
335263363Semaste			/* Check the device scanning progress */
336263363Semaste			if (prev_abs_reg_val != cur_abs_reg_val) {
337263363Semaste				continue;
338263363Semaste			}
339263363Semaste		}
340263363Semaste		if (fw_state == cur_state) {
341263363Semaste			device_printf(sc->mfi_dev, "Firmware stuck in state "
342263363Semaste			    "%#x\n", fw_state);
343263363Semaste			return (ENXIO);
344263363Semaste		}
345263363Semaste	}
346263363Semaste	return (0);
347263363Semaste}
348263363Semaste
349263363Semastestatic void
350263363Semastemfi_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
351263363Semaste{
352263363Semaste	bus_addr_t *addr;
353263363Semaste
354263363Semaste	addr = arg;
355263363Semaste	*addr = segs[0].ds_addr;
356263363Semaste}
357263363Semaste
358263363Semaste
359263363Semasteint
360263363Semastemfi_attach(struct mfi_softc *sc)
361263363Semaste{
362263363Semaste	uint32_t status;
363263363Semaste	int error, commsz, framessz, sensesz;
364263363Semaste	int frames, unit, max_fw_sge;
365263363Semaste	uint32_t tb_mem_size = 0;
366263363Semaste
367263363Semaste	if (sc == NULL)
368263363Semaste		return EINVAL;
369263363Semaste
370263363Semaste	device_printf(sc->mfi_dev, "Megaraid SAS driver Ver %s \n",
371263363Semaste	    MEGASAS_VERSION);
372263363Semaste
373263363Semaste	mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF);
374263363Semaste	sx_init(&sc->mfi_config_lock, "MFI config");
375263363Semaste	TAILQ_INIT(&sc->mfi_ld_tqh);
376263363Semaste	TAILQ_INIT(&sc->mfi_syspd_tqh);
377263363Semaste	TAILQ_INIT(&sc->mfi_evt_queue);
378263363Semaste	TASK_INIT(&sc->mfi_evt_task, 0, mfi_handle_evt, sc);
379263363Semaste	TASK_INIT(&sc->mfi_map_sync_task, 0, mfi_handle_map_sync, sc);
380263363Semaste	TAILQ_INIT(&sc->mfi_aen_pids);
381263363Semaste	TAILQ_INIT(&sc->mfi_cam_ccbq);
382263363Semaste
383263363Semaste	mfi_initq_free(sc);
384263363Semaste	mfi_initq_ready(sc);
385263363Semaste	mfi_initq_busy(sc);
386263363Semaste	mfi_initq_bio(sc);
387263363Semaste
388263363Semaste	sc->adpreset = 0;
389263363Semaste	sc->last_seq_num = 0;
390263363Semaste	sc->disableOnlineCtrlReset = 1;
391263363Semaste	sc->issuepend_done = 1;
392263363Semaste	sc->hw_crit_error = 0;
393263363Semaste
394263363Semaste	if (sc->mfi_flags & MFI_FLAGS_1064R) {
395263363Semaste		sc->mfi_enable_intr = mfi_enable_intr_xscale;
396263363Semaste		sc->mfi_read_fw_status = mfi_read_fw_status_xscale;
397263363Semaste		sc->mfi_check_clear_intr = mfi_check_clear_intr_xscale;
398263363Semaste		sc->mfi_issue_cmd = mfi_issue_cmd_xscale;
399263363Semaste	} else if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
400263363Semaste		sc->mfi_enable_intr = mfi_tbolt_enable_intr_ppc;
401263363Semaste		sc->mfi_disable_intr = mfi_tbolt_disable_intr_ppc;
402263363Semaste		sc->mfi_read_fw_status = mfi_tbolt_read_fw_status_ppc;
403263363Semaste		sc->mfi_check_clear_intr = mfi_tbolt_check_clear_intr_ppc;
404263363Semaste		sc->mfi_issue_cmd = mfi_tbolt_issue_cmd_ppc;
405263363Semaste		sc->mfi_adp_reset = mfi_tbolt_adp_reset;
406263363Semaste		sc->mfi_tbolt = 1;
407263363Semaste		TAILQ_INIT(&sc->mfi_cmd_tbolt_tqh);
408263363Semaste	} else {
409263363Semaste		sc->mfi_enable_intr =  mfi_enable_intr_ppc;
410263363Semaste		sc->mfi_read_fw_status = mfi_read_fw_status_ppc;
411263363Semaste		sc->mfi_check_clear_intr = mfi_check_clear_intr_ppc;
412263363Semaste		sc->mfi_issue_cmd = mfi_issue_cmd_ppc;
413263363Semaste	}
414263363Semaste
415263363Semaste
416263363Semaste	/* Before we get too far, see if the firmware is working */
417263363Semaste	if ((error = mfi_transition_firmware(sc)) != 0) {
418263363Semaste		device_printf(sc->mfi_dev, "Firmware not in READY state, "
419263363Semaste		    "error %d\n", error);
420263363Semaste		return (ENXIO);
421263363Semaste	}
422263363Semaste
423263363Semaste	/* Start: LSIP200113393 */
424263363Semaste	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
425263363Semaste				1, 0,			/* algnmnt, boundary */
426263363Semaste				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
427263363Semaste				BUS_SPACE_MAXADDR,	/* highaddr */
428263363Semaste				NULL, NULL,		/* filter, filterarg */
429263363Semaste				MEGASAS_MAX_NAME*sizeof(bus_addr_t),			/* maxsize */
430263363Semaste				1,			/* msegments */
431263363Semaste				MEGASAS_MAX_NAME*sizeof(bus_addr_t),			/* maxsegsize */
432263363Semaste				0,			/* flags */
433263363Semaste				NULL, NULL,		/* lockfunc, lockarg */
434263363Semaste				&sc->verbuf_h_dmat)) {
435263363Semaste		device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmat DMA tag\n");
436263363Semaste		return (ENOMEM);
437263363Semaste	}
438263363Semaste	if (bus_dmamem_alloc(sc->verbuf_h_dmat, (void **)&sc->verbuf,
439263363Semaste	    BUS_DMA_NOWAIT, &sc->verbuf_h_dmamap)) {
440263363Semaste		device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmamap memory\n");
441263363Semaste		return (ENOMEM);
442263363Semaste	}
443263363Semaste	bzero(sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t));
444263363Semaste	bus_dmamap_load(sc->verbuf_h_dmat, sc->verbuf_h_dmamap,
445263363Semaste	    sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t),
446263363Semaste	    mfi_addr_cb, &sc->verbuf_h_busaddr, 0);
447263363Semaste	/* End: LSIP200113393 */
448263363Semaste
449263363Semaste	/*
450263363Semaste	 * Get information needed for sizing the contiguous memory for the
451263363Semaste	 * frame pool.  Size down the sgl parameter since we know that
452263363Semaste	 * we will never need more than what's required for MAXPHYS.
453263363Semaste	 * It would be nice if these constants were available at runtime
454263363Semaste	 * instead of compile time.
455263363Semaste	 */
456263363Semaste	status = sc->mfi_read_fw_status(sc);
457263363Semaste	sc->mfi_max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK;
458263363Semaste	max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16;
459263363Semaste	sc->mfi_max_sge = min(max_fw_sge, ((MFI_MAXPHYS / PAGE_SIZE) + 1));
460263363Semaste
461263363Semaste	/* ThunderBolt Support get the contiguous memory */
462263363Semaste
463263363Semaste	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
464263363Semaste		mfi_tbolt_init_globals(sc);
465263363Semaste		device_printf(sc->mfi_dev, "MaxCmd = %x MaxSgl = %x state = %x \n",
466263363Semaste		    sc->mfi_max_fw_cmds, sc->mfi_max_sge, status);
467263363Semaste		tb_mem_size = mfi_tbolt_get_memory_requirement(sc);
468263363Semaste
469263363Semaste		if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
470263363Semaste				1, 0,			/* algnmnt, boundary */
471263363Semaste				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
472263363Semaste				BUS_SPACE_MAXADDR,	/* highaddr */
473263363Semaste				NULL, NULL,		/* filter, filterarg */
474263363Semaste				tb_mem_size,		/* maxsize */
475263363Semaste				1,			/* msegments */
476263363Semaste				tb_mem_size,		/* maxsegsize */
477263363Semaste				0,			/* flags */
478263363Semaste				NULL, NULL,		/* lockfunc, lockarg */
479263363Semaste				&sc->mfi_tb_dmat)) {
480263363Semaste			device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
481263363Semaste			return (ENOMEM);
482263363Semaste		}
483263363Semaste		if (bus_dmamem_alloc(sc->mfi_tb_dmat, (void **)&sc->request_message_pool,
484263363Semaste		BUS_DMA_NOWAIT, &sc->mfi_tb_dmamap)) {
485263363Semaste			device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
486263363Semaste			return (ENOMEM);
487263363Semaste		}
488263363Semaste		bzero(sc->request_message_pool, tb_mem_size);
489263363Semaste		bus_dmamap_load(sc->mfi_tb_dmat, sc->mfi_tb_dmamap,
490263363Semaste		sc->request_message_pool, tb_mem_size, mfi_addr_cb, &sc->mfi_tb_busaddr, 0);
491263363Semaste
492263363Semaste		/* For ThunderBolt memory init */
493263363Semaste		if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
494263363Semaste				0x100, 0,		/* alignmnt, boundary */
495263363Semaste				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
496263363Semaste				BUS_SPACE_MAXADDR,	/* highaddr */
497263363Semaste				NULL, NULL,		/* filter, filterarg */
498263363Semaste				MFI_FRAME_SIZE,		/* maxsize */
499263363Semaste				1,			/* msegments */
500263363Semaste				MFI_FRAME_SIZE,		/* maxsegsize */
501263363Semaste				0,			/* flags */
502263363Semaste				NULL, NULL,		/* lockfunc, lockarg */
503263363Semaste				&sc->mfi_tb_init_dmat)) {
504263363Semaste		device_printf(sc->mfi_dev, "Cannot allocate init DMA tag\n");
505263363Semaste		return (ENOMEM);
506263363Semaste		}
507263363Semaste		if (bus_dmamem_alloc(sc->mfi_tb_init_dmat, (void **)&sc->mfi_tb_init,
508263363Semaste		    BUS_DMA_NOWAIT, &sc->mfi_tb_init_dmamap)) {
509263363Semaste			device_printf(sc->mfi_dev, "Cannot allocate init memory\n");
510263363Semaste			return (ENOMEM);
511263363Semaste		}
512263363Semaste		bzero(sc->mfi_tb_init, MFI_FRAME_SIZE);
513263363Semaste		bus_dmamap_load(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap,
514263363Semaste		sc->mfi_tb_init, MFI_FRAME_SIZE, mfi_addr_cb,
515263363Semaste		    &sc->mfi_tb_init_busaddr, 0);
516263363Semaste		if (mfi_tbolt_init_desc_pool(sc, sc->request_message_pool,
517263363Semaste		    tb_mem_size)) {
518263363Semaste			device_printf(sc->mfi_dev,
519263363Semaste			    "Thunderbolt pool preparation error\n");
520263363Semaste			return 0;
521263363Semaste		}
522263363Semaste
523263363Semaste		/*
524263363Semaste		  Allocate DMA memory mapping for MPI2 IOC Init descriptor,
525263363Semaste		  we are taking it diffrent from what we have allocated for Request
526263363Semaste		  and reply descriptors to avoid confusion later
527263363Semaste		*/
528263363Semaste		tb_mem_size = sizeof(struct MPI2_IOC_INIT_REQUEST);
529263363Semaste		if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
530263363Semaste				1, 0,			/* algnmnt, boundary */
531263363Semaste				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
532263363Semaste				BUS_SPACE_MAXADDR,	/* highaddr */
533263363Semaste				NULL, NULL,		/* filter, filterarg */
534263363Semaste				tb_mem_size,		/* maxsize */
535263363Semaste				1,			/* msegments */
536263363Semaste				tb_mem_size,		/* maxsegsize */
537263363Semaste				0,			/* flags */
538263363Semaste				NULL, NULL,		/* lockfunc, lockarg */
539263363Semaste				&sc->mfi_tb_ioc_init_dmat)) {
540263363Semaste			device_printf(sc->mfi_dev,
541263363Semaste			    "Cannot allocate comms DMA tag\n");
542263363Semaste			return (ENOMEM);
543263363Semaste		}
544263363Semaste		if (bus_dmamem_alloc(sc->mfi_tb_ioc_init_dmat,
545263363Semaste		    (void **)&sc->mfi_tb_ioc_init_desc,
546263363Semaste		    BUS_DMA_NOWAIT, &sc->mfi_tb_ioc_init_dmamap)) {
547263363Semaste			device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
548263363Semaste			return (ENOMEM);
549263363Semaste		}
550263363Semaste		bzero(sc->mfi_tb_ioc_init_desc, tb_mem_size);
551263363Semaste		bus_dmamap_load(sc->mfi_tb_ioc_init_dmat, sc->mfi_tb_ioc_init_dmamap,
552263363Semaste		sc->mfi_tb_ioc_init_desc, tb_mem_size, mfi_addr_cb,
553263363Semaste		    &sc->mfi_tb_ioc_init_busaddr, 0);
554263363Semaste	}
555263363Semaste	/*
556263363Semaste	 * Create the dma tag for data buffers.  Used both for block I/O
557263363Semaste	 * and for various internal data queries.
558263363Semaste	 */
559263363Semaste	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
560263363Semaste				1, 0,			/* algnmnt, boundary */
561263363Semaste				BUS_SPACE_MAXADDR,	/* lowaddr */
562263363Semaste				BUS_SPACE_MAXADDR,	/* highaddr */
563263363Semaste				NULL, NULL,		/* filter, filterarg */
564263363Semaste				BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
565263363Semaste				sc->mfi_max_sge,	/* nsegments */
566263363Semaste				BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
567263363Semaste				BUS_DMA_ALLOCNOW,	/* flags */
568263363Semaste				busdma_lock_mutex,	/* lockfunc */
569263363Semaste				&sc->mfi_io_lock,	/* lockfuncarg */
570263363Semaste				&sc->mfi_buffer_dmat)) {
571263363Semaste		device_printf(sc->mfi_dev, "Cannot allocate buffer DMA tag\n");
572263363Semaste		return (ENOMEM);
573263363Semaste	}
574263363Semaste
575263363Semaste	/*
576263363Semaste	 * Allocate DMA memory for the comms queues.  Keep it under 4GB for
577263363Semaste	 * efficiency.  The mfi_hwcomms struct includes space for 1 reply queue
578269024Semaste	 * entry, so the calculated size here will be will be 1 more than
579269024Semaste	 * mfi_max_fw_cmds.  This is apparently a requirement of the hardware.
580263363Semaste	 */
581263363Semaste	commsz = (sizeof(uint32_t) * sc->mfi_max_fw_cmds) +
582263363Semaste	    sizeof(struct mfi_hwcomms);
583263363Semaste	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
584263363Semaste				1, 0,			/* algnmnt, boundary */
585263363Semaste				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
586263363Semaste				BUS_SPACE_MAXADDR,	/* highaddr */
587263363Semaste				NULL, NULL,		/* filter, filterarg */
588263363Semaste				commsz,			/* maxsize */
589263363Semaste				1,			/* msegments */
590263363Semaste				commsz,			/* maxsegsize */
591263363Semaste				0,			/* flags */
592263363Semaste				NULL, NULL,		/* lockfunc, lockarg */
593263363Semaste				&sc->mfi_comms_dmat)) {
594263363Semaste		device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
595263363Semaste		return (ENOMEM);
596263363Semaste	}
597263363Semaste	if (bus_dmamem_alloc(sc->mfi_comms_dmat, (void **)&sc->mfi_comms,
598263363Semaste	    BUS_DMA_NOWAIT, &sc->mfi_comms_dmamap)) {
599263363Semaste		device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
600263363Semaste		return (ENOMEM);
601263363Semaste	}
602269024Semaste	bzero(sc->mfi_comms, commsz);
603263363Semaste	bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap,
604263363Semaste	    sc->mfi_comms, commsz, mfi_addr_cb, &sc->mfi_comms_busaddr, 0);
605263363Semaste	/*
606263363Semaste	 * Allocate DMA memory for the command frames.  Keep them in the
607263363Semaste	 * lower 4GB for efficiency.  Calculate the size of the commands at
608263363Semaste	 * the same time; each command is one 64 byte frame plus a set of
609263363Semaste         * additional frames for holding sg lists or other data.
610263363Semaste	 * The assumption here is that the SG list will start at the second
611263363Semaste	 * frame and not use the unused bytes in the first frame.  While this
612263363Semaste	 * isn't technically correct, it simplifies the calculation and allows
613263363Semaste	 * for command frames that might be larger than an mfi_io_frame.
614263363Semaste	 */
615263363Semaste	if (sizeof(bus_addr_t) == 8) {
616263363Semaste		sc->mfi_sge_size = sizeof(struct mfi_sg64);
617263363Semaste		sc->mfi_flags |= MFI_FLAGS_SG64;
618263363Semaste	} else {
619263363Semaste		sc->mfi_sge_size = sizeof(struct mfi_sg32);
620263363Semaste	}
621263363Semaste	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
622263363Semaste		sc->mfi_sge_size = sizeof(struct mfi_sg_skinny);
623263363Semaste	frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2;
624263363Semaste	sc->mfi_cmd_size = frames * MFI_FRAME_SIZE;
625263363Semaste	framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds;
626263363Semaste	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
627263363Semaste				64, 0,			/* algnmnt, boundary */
628263363Semaste				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
629263363Semaste				BUS_SPACE_MAXADDR,	/* highaddr */
630263363Semaste				NULL, NULL,		/* filter, filterarg */
631263363Semaste				framessz,		/* maxsize */
632263363Semaste				1,			/* nsegments */
633263363Semaste				framessz,		/* maxsegsize */
634263363Semaste				0,			/* flags */
635263363Semaste				NULL, NULL,		/* lockfunc, lockarg */
636263363Semaste				&sc->mfi_frames_dmat)) {
637269024Semaste		device_printf(sc->mfi_dev, "Cannot allocate frame DMA tag\n");
638269024Semaste		return (ENOMEM);
639263363Semaste	}
640263363Semaste	if (bus_dmamem_alloc(sc->mfi_frames_dmat, (void **)&sc->mfi_frames,
641263363Semaste	    BUS_DMA_NOWAIT, &sc->mfi_frames_dmamap)) {
642263363Semaste		device_printf(sc->mfi_dev, "Cannot allocate frames memory\n");
643263363Semaste		return (ENOMEM);
644263363Semaste	}
645263363Semaste	bzero(sc->mfi_frames, framessz);
646263363Semaste	bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap,
647263363Semaste	    sc->mfi_frames, framessz, mfi_addr_cb, &sc->mfi_frames_busaddr,0);
648263363Semaste	/*
649263363Semaste	 * Allocate DMA memory for the frame sense data.  Keep them in the
650263363Semaste	 * lower 4GB for efficiency
651263363Semaste	 */
652263363Semaste	sensesz = sc->mfi_max_fw_cmds * MFI_SENSE_LEN;
653263363Semaste	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
654263363Semaste				4, 0,			/* algnmnt, boundary */
655263363Semaste				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
656263363Semaste				BUS_SPACE_MAXADDR,	/* highaddr */
657263363Semaste				NULL, NULL,		/* filter, filterarg */
658263363Semaste				sensesz,		/* maxsize */
659263363Semaste				1,			/* nsegments */
660263363Semaste				sensesz,		/* maxsegsize */
661263363Semaste				0,			/* flags */
662263363Semaste				NULL, NULL,		/* lockfunc, lockarg */
663269024Semaste				&sc->mfi_sense_dmat)) {
664269024Semaste		device_printf(sc->mfi_dev, "Cannot allocate sense DMA tag\n");
665263363Semaste		return (ENOMEM);
666263363Semaste	}
667263363Semaste	if (bus_dmamem_alloc(sc->mfi_sense_dmat, (void **)&sc->mfi_sense,
668263363Semaste	    BUS_DMA_NOWAIT, &sc->mfi_sense_dmamap)) {
669263363Semaste		device_printf(sc->mfi_dev, "Cannot allocate sense memory\n");
670263363Semaste		return (ENOMEM);
671263363Semaste	}
672263363Semaste	bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap,
673263363Semaste	    sc->mfi_sense, sensesz, mfi_addr_cb, &sc->mfi_sense_busaddr, 0);
674263363Semaste	if ((error = mfi_alloc_commands(sc)) != 0)
675263363Semaste		return (error);
676263363Semaste
677263363Semaste	/* Before moving the FW to operational state, check whether
678263363Semaste	 * hostmemory is required by the FW or not
679263363Semaste	 */
680263363Semaste
681263363Semaste	/* ThunderBolt MFI_IOC2 INIT */
682263363Semaste	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
683263363Semaste		sc->mfi_disable_intr(sc);
684263363Semaste		if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0) {
685263363Semaste			device_printf(sc->mfi_dev,
686263363Semaste			    "TB Init has failed with error %d\n",error);
687263363Semaste			return error;
688263363Semaste		}
689269024Semaste
690269024Semaste		if ((error = mfi_tbolt_alloc_cmd(sc)) != 0)
691263363Semaste			return error;
692263363Semaste		if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq,
693263363Semaste		    INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr_tbolt, sc,
694263363Semaste		    &sc->mfi_intr)) {
695263363Semaste			device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
696263363Semaste			return (EINVAL);
697263363Semaste		}
698263363Semaste		sc->mfi_enable_intr(sc);
699263363Semaste	} else {
700263363Semaste		if ((error = mfi_comms_init(sc)) != 0)
701263363Semaste			return (error);
702263363Semaste
703263363Semaste		if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq,
704263363Semaste		    INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr, sc, &sc->mfi_intr)) {
705263363Semaste			device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
706263363Semaste			return (EINVAL);
707263363Semaste		}
708263363Semaste		sc->mfi_enable_intr(sc);
709263363Semaste	}
710263363Semaste	if ((error = mfi_get_controller_info(sc)) != 0)
711263363Semaste		return (error);
712263363Semaste	sc->disableOnlineCtrlReset = 0;
713263363Semaste
714263363Semaste	/* Register a config hook to probe the bus for arrays */
715269024Semaste	sc->mfi_ich.ich_func = mfi_startup;
716269024Semaste	sc->mfi_ich.ich_arg = sc;
717263363Semaste	if (config_intrhook_establish(&sc->mfi_ich) != 0) {
718263363Semaste		device_printf(sc->mfi_dev, "Cannot establish configuration "
719263363Semaste		    "hook\n");
720263363Semaste		return (EINVAL);
721263363Semaste	}
722263363Semaste	if ((error = mfi_aen_setup(sc, 0), 0) != 0) {
723263363Semaste		mtx_unlock(&sc->mfi_io_lock);
724263363Semaste		return (error);
725263363Semaste	}
726263363Semaste
727263363Semaste	/*
728263363Semaste	 * Register a shutdown handler.
729263363Semaste	 */
730263363Semaste	if ((sc->mfi_eh = EVENTHANDLER_REGISTER(shutdown_final, mfi_shutdown,
731263363Semaste	    sc, SHUTDOWN_PRI_DEFAULT)) == NULL) {
732263363Semaste		device_printf(sc->mfi_dev, "Warning: shutdown event "
733263363Semaste		    "registration failed\n");
734263363Semaste	}
735263363Semaste
736263363Semaste	/*
737263363Semaste	 * Create the control device for doing management
738263363Semaste	 */
739263363Semaste	unit = device_get_unit(sc->mfi_dev);
740263363Semaste	sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR,
741263363Semaste	    0640, "mfi%d", unit);
742263363Semaste	if (unit == 0)
743263363Semaste		make_dev_alias(sc->mfi_cdev, "megaraid_sas_ioctl_node");
744263363Semaste	if (sc->mfi_cdev != NULL)
745263363Semaste		sc->mfi_cdev->si_drv1 = sc;
746263363Semaste	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
747263363Semaste	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
748263363Semaste	    OID_AUTO, "delete_busy_volumes", CTLFLAG_RW,
749263363Semaste	    &sc->mfi_delete_busy_volumes, 0, "Allow removal of busy volumes");
750263363Semaste	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
751263363Semaste	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
752263363Semaste	    OID_AUTO, "keep_deleted_volumes", CTLFLAG_RW,
753269024Semaste	    &sc->mfi_keep_deleted_volumes, 0,
754269024Semaste	    "Don't detach the mfid device for a busy volume that is deleted");
755263363Semaste
756263363Semaste	device_add_child(sc->mfi_dev, "mfip", -1);
757263363Semaste	bus_generic_attach(sc->mfi_dev);
758263363Semaste
759263363Semaste	/* Start the timeout watchdog */
760263363Semaste	callout_init(&sc->mfi_watchdog_callout, CALLOUT_MPSAFE);
761263363Semaste	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
762263363Semaste	    mfi_timeout, sc);
763263363Semaste
764263363Semaste	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
765263363Semaste		mfi_tbolt_sync_map_info(sc);
766263363Semaste	}
767263363Semaste
768263363Semaste	return (0);
769263363Semaste}
770263363Semaste
771263363Semastestatic int
772263363Semastemfi_alloc_commands(struct mfi_softc *sc)
773269024Semaste{
774269024Semaste	struct mfi_command *cm;
775263363Semaste	int i, ncmds;
776263363Semaste
777263363Semaste	/*
778263363Semaste	 * XXX Should we allocate all the commands up front, or allocate on
779263363Semaste	 * demand later like 'aac' does?
780263363Semaste	 */
781263363Semaste	ncmds = MIN(mfi_max_cmds, sc->mfi_max_fw_cmds);
782263363Semaste	if (bootverbose)
783263363Semaste		device_printf(sc->mfi_dev, "Max fw cmds= %d, sizing driver "
784263363Semaste		   "pool to %d\n", sc->mfi_max_fw_cmds, ncmds);
785263363Semaste
786263363Semaste	sc->mfi_commands = malloc(sizeof(struct mfi_command) * ncmds, M_MFIBUF,
787263363Semaste	    M_WAITOK | M_ZERO);
788263363Semaste
789263363Semaste	for (i = 0; i < ncmds; i++) {
790263363Semaste		cm = &sc->mfi_commands[i];
791263363Semaste		cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames +
792263363Semaste		    sc->mfi_cmd_size * i);
793263363Semaste		cm->cm_frame_busaddr = sc->mfi_frames_busaddr +
794263363Semaste		    sc->mfi_cmd_size * i;
795263363Semaste		cm->cm_frame->header.context = i;
796263363Semaste		cm->cm_sense = &sc->mfi_sense[i];
797263363Semaste		cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i;
798263363Semaste		cm->cm_sc = sc;
799263363Semaste		cm->cm_index = i;
800263363Semaste		if (bus_dmamap_create(sc->mfi_buffer_dmat, 0,
801263363Semaste		    &cm->cm_dmamap) == 0) {
802263363Semaste			mtx_lock(&sc->mfi_io_lock);
803263363Semaste			mfi_release_command(cm);
804263363Semaste			mtx_unlock(&sc->mfi_io_lock);
805263363Semaste		}
806263363Semaste		else
807263363Semaste			break;
808263363Semaste		sc->mfi_total_cmds++;
809263363Semaste	}
810263363Semaste
811263363Semaste	return (0);
812263363Semaste}
813263363Semaste
814263363Semastevoid
815263363Semastemfi_release_command(struct mfi_command *cm)
816263363Semaste{
817263363Semaste	struct mfi_frame_header *hdr;
818263363Semaste	uint32_t *hdr_data;
819263363Semaste
820263363Semaste	mtx_assert(&cm->cm_sc->mfi_io_lock, MA_OWNED);
821263363Semaste
822263363Semaste	/*
823263363Semaste	 * Zero out the important fields of the frame, but make sure the
824263363Semaste	 * context field is preserved.  For efficiency, handle the fields
825263363Semaste	 * as 32 bit words.  Clear out the first S/G entry too for safety.
826263363Semaste	 */
827263363Semaste	hdr = &cm->cm_frame->header;
828263363Semaste	if (cm->cm_data != NULL && hdr->sg_count) {
829263363Semaste		cm->cm_sg->sg32[0].len = 0;
830263363Semaste		cm->cm_sg->sg32[0].addr = 0;
831263363Semaste	}
832263363Semaste
833263363Semaste	hdr_data = (uint32_t *)cm->cm_frame;
834263363Semaste	hdr_data[0] = 0;	/* cmd, sense_len, cmd_status, scsi_status */
835263363Semaste	hdr_data[1] = 0;	/* target_id, lun_id, cdb_len, sg_count */
836263363Semaste	hdr_data[4] = 0;	/* flags, timeout */
837263363Semaste	hdr_data[5] = 0;	/* data_len */
838263363Semaste
839263363Semaste	cm->cm_extra_frames = 0;
840263363Semaste	cm->cm_flags = 0;
841263363Semaste	cm->cm_complete = NULL;
842263363Semaste	cm->cm_private = NULL;
843263363Semaste	cm->cm_data = NULL;
844263363Semaste	cm->cm_sg = 0;
845263363Semaste	cm->cm_total_frame_size = 0;
846263363Semaste	cm->retry_for_fw_reset = 0;
847263363Semaste
848263363Semaste	mfi_enqueue_free(cm);
849263363Semaste}
850263363Semaste
851263363Semasteint
852263363Semastemfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp,
853263363Semaste    uint32_t opcode, void **bufp, size_t bufsize)
854263363Semaste{
855263363Semaste	struct mfi_command *cm;
856263363Semaste	struct mfi_dcmd_frame *dcmd;
857263363Semaste	void *buf = NULL;
858263363Semaste	uint32_t context = 0;
859263363Semaste
860263363Semaste	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
861263363Semaste
862263363Semaste	cm = mfi_dequeue_free(sc);
863263363Semaste	if (cm == NULL)
864263363Semaste		return (EBUSY);
865263363Semaste
866269024Semaste	/* Zero out the MFI frame */
867269024Semaste	context = cm->cm_frame->header.context;
868263363Semaste	bzero(cm->cm_frame, sizeof(union mfi_frame));
869263363Semaste	cm->cm_frame->header.context = context;
870263363Semaste
871263363Semaste	if ((bufsize > 0) && (bufp != NULL)) {
872263363Semaste		if (*bufp == NULL) {
873263363Semaste			buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO);
874263363Semaste			if (buf == NULL) {
875263363Semaste				mfi_release_command(cm);
876263363Semaste				return (ENOMEM);
877263363Semaste			}
878263363Semaste			*bufp = buf;
879263363Semaste		} else {
880263363Semaste			buf = *bufp;
881263363Semaste		}
882263363Semaste	}
883263363Semaste
884263363Semaste	dcmd =  &cm->cm_frame->dcmd;
885263363Semaste	bzero(dcmd->mbox, MFI_MBOX_SIZE);
886263363Semaste	dcmd->header.cmd = MFI_CMD_DCMD;
887263363Semaste	dcmd->header.timeout = 0;
888263363Semaste	dcmd->header.flags = 0;
889263363Semaste	dcmd->header.data_len = bufsize;
890263363Semaste	dcmd->header.scsi_status = 0;
891269024Semaste	dcmd->opcode = opcode;
892269024Semaste	cm->cm_sg = &dcmd->sgl;
893263363Semaste	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
894263363Semaste	cm->cm_flags = 0;
895263363Semaste	cm->cm_data = buf;
896263363Semaste	cm->cm_private = buf;
897263363Semaste	cm->cm_len = bufsize;
898263363Semaste
899263363Semaste	*cmp = cm;
900263363Semaste	if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL))
901263363Semaste		*bufp = buf;
902263363Semaste	return (0);
903263363Semaste}
904263363Semaste
905263363Semastestatic int
906263363Semastemfi_comms_init(struct mfi_softc *sc)
907263363Semaste{
908263363Semaste	struct mfi_command *cm;
909263363Semaste	struct mfi_init_frame *init;
910263363Semaste	struct mfi_init_qinfo *qinfo;
911269024Semaste	int error;
912269024Semaste	uint32_t context = 0;
913263363Semaste
914263363Semaste	mtx_lock(&sc->mfi_io_lock);
915263363Semaste	if ((cm = mfi_dequeue_free(sc)) == NULL)
916263363Semaste		return (EBUSY);
917263363Semaste
918263363Semaste	/* Zero out the MFI frame */
919263363Semaste	context = cm->cm_frame->header.context;
920263363Semaste	bzero(cm->cm_frame, sizeof(union mfi_frame));
921263363Semaste	cm->cm_frame->header.context = context;
922263363Semaste
923263363Semaste	/*
924263363Semaste	 * Abuse the SG list area of the frame to hold the init_qinfo
925263363Semaste	 * object;
926263363Semaste	 */
927263363Semaste	init = &cm->cm_frame->init;
928263363Semaste	qinfo = (struct mfi_init_qinfo *)((uintptr_t)init + MFI_FRAME_SIZE);
929263363Semaste
930263363Semaste	bzero(qinfo, sizeof(struct mfi_init_qinfo));
931263363Semaste	qinfo->rq_entries = sc->mfi_max_fw_cmds + 1;
932263363Semaste	qinfo->rq_addr_lo = sc->mfi_comms_busaddr +
933263363Semaste	    offsetof(struct mfi_hwcomms, hw_reply_q);
934269024Semaste	qinfo->pi_addr_lo = sc->mfi_comms_busaddr +
935269024Semaste	    offsetof(struct mfi_hwcomms, hw_pi);
936263363Semaste	qinfo->ci_addr_lo = sc->mfi_comms_busaddr +
937263363Semaste	    offsetof(struct mfi_hwcomms, hw_ci);
938263363Semaste
939263363Semaste	init->header.cmd = MFI_CMD_INIT;
940263363Semaste	init->header.data_len = sizeof(struct mfi_init_qinfo);
941263363Semaste	init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE;
942263363Semaste	cm->cm_data = NULL;
943263363Semaste	cm->cm_flags = MFI_CMD_POLLED;
944263363Semaste
945263363Semaste	if ((error = mfi_mapcmd(sc, cm)) != 0) {
946263363Semaste		device_printf(sc->mfi_dev, "failed to send init command\n");
947263363Semaste		mtx_unlock(&sc->mfi_io_lock);
948263363Semaste		return (error);
949263363Semaste	}
950263363Semaste	mfi_release_command(cm);
951263363Semaste	mtx_unlock(&sc->mfi_io_lock);
952263363Semaste
953263363Semaste	return (0);
954263363Semaste}
955263363Semaste
956263363Semastestatic int
957263363Semastemfi_get_controller_info(struct mfi_softc *sc)
958263363Semaste{
959263363Semaste	struct mfi_command *cm = NULL;
960269024Semaste	struct mfi_ctrl_info *ci = NULL;
961269024Semaste	uint32_t max_sectors_1, max_sectors_2;
962263363Semaste	int error;
963263363Semaste
964263363Semaste	mtx_lock(&sc->mfi_io_lock);
965263363Semaste	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO,
966263363Semaste	    (void **)&ci, sizeof(*ci));
967263363Semaste	if (error)
968263363Semaste		goto out;
969263363Semaste	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
970263363Semaste
971263363Semaste	if ((error = mfi_mapcmd(sc, cm)) != 0) {
972263363Semaste		device_printf(sc->mfi_dev, "Failed to get controller info\n");
973263363Semaste		sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE /
974263363Semaste		    MFI_SECTOR_LEN;
975263363Semaste		error = 0;
976263363Semaste		goto out;
977263363Semaste	}
978263363Semaste
979263363Semaste	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
980263363Semaste	    BUS_DMASYNC_POSTREAD);
981263363Semaste	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
982263363Semaste
983263363Semaste	max_sectors_1 = (1 << ci->stripe_sz_ops.max) * ci->max_strips_per_io;
984263363Semaste	max_sectors_2 = ci->max_request_size;
985263363Semaste	sc->mfi_max_io = min(max_sectors_1, max_sectors_2);
986263363Semaste	sc->disableOnlineCtrlReset =
987263363Semaste	    ci->properties.OnOffProperties.disableOnlineCtrlReset;
988263363Semaste
989263363Semasteout:
990263363Semaste	if (ci)
991263363Semaste		free(ci, M_MFIBUF);
992263363Semaste	if (cm)
993263363Semaste		mfi_release_command(cm);
994263363Semaste	mtx_unlock(&sc->mfi_io_lock);
995263363Semaste	return (error);
996263363Semaste}
997263363Semaste
998263363Semastestatic int
999263363Semastemfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state)
1000263363Semaste{
1001263363Semaste	struct mfi_command *cm = NULL;
1002263363Semaste	int error;
1003263363Semaste
1004263363Semaste	mtx_lock(&sc->mfi_io_lock);
1005263363Semaste	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO,
1006263363Semaste	    (void **)log_state, sizeof(**log_state));
1007263363Semaste	if (error)
1008269024Semaste		goto out;
1009269024Semaste	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1010263363Semaste
1011263363Semaste	if ((error = mfi_mapcmd(sc, cm)) != 0) {
1012263363Semaste		device_printf(sc->mfi_dev, "Failed to get log state\n");
1013263363Semaste		goto out;
1014263363Semaste	}
1015263363Semaste
1016263363Semaste	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1017263363Semaste	    BUS_DMASYNC_POSTREAD);
1018263363Semaste	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1019263363Semaste
1020263363Semasteout:
1021263363Semaste	if (cm)
1022263363Semaste		mfi_release_command(cm);
1023263363Semaste	mtx_unlock(&sc->mfi_io_lock);
1024263363Semaste
1025269024Semaste	return (error);
1026269024Semaste}
1027263363Semaste
1028263363Semasteint
1029263363Semastemfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
1030263363Semaste{
1031263363Semaste	struct mfi_evt_log_state *log_state = NULL;
1032263363Semaste	union mfi_evt class_locale;
1033263363Semaste	int error = 0;
1034263363Semaste	uint32_t seq;
1035263363Semaste
1036263363Semaste	class_locale.members.reserved = 0;
1037263363Semaste	class_locale.members.locale = mfi_event_locale;
1038263363Semaste	class_locale.members.evt_class  = mfi_event_class;
1039263363Semaste
1040263363Semaste	if (seq_start == 0) {
1041263363Semaste		error = mfi_get_log_state(sc, &log_state);
1042263363Semaste		sc->mfi_boot_seq_num = log_state->boot_seq_num;
1043263363Semaste		if (error) {
1044263363Semaste			if (log_state)
1045263363Semaste				free(log_state, M_MFIBUF);
1046263363Semaste			return (error);
1047263363Semaste		}
1048263363Semaste
1049263363Semaste		/*
1050263363Semaste		 * Walk through any events that fired since the last
1051263363Semaste		 * shutdown.
1052263363Semaste		 */
1053269024Semaste		mfi_parse_entries(sc, log_state->shutdown_seq_num,
1054269024Semaste		    log_state->newest_seq_num);
1055263363Semaste		seq = log_state->newest_seq_num;
1056263363Semaste	} else
1057263363Semaste		seq = seq_start;
1058263363Semaste	mfi_aen_register(sc, seq, class_locale.word);
1059263363Semaste	free(log_state, M_MFIBUF);
1060263363Semaste
1061263363Semaste	return 0;
1062263363Semaste}
1063263363Semaste
1064263363Semasteint
1065263363Semastemfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm)
1066263363Semaste{
1067263363Semaste
1068263363Semaste	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1069263363Semaste	cm->cm_complete = NULL;
1070263363Semaste
1071263363Semaste
1072263363Semaste	/*
1073263363Semaste	 * MegaCli can issue a DCMD of 0.  In this case do nothing
1074263363Semaste	 * and return 0 to it as status
1075263363Semaste	 */
1076263363Semaste	if (cm->cm_frame->dcmd.opcode == 0) {
1077263363Semaste		cm->cm_frame->header.cmd_status = MFI_STAT_OK;
1078263363Semaste		cm->cm_error = 0;
1079263363Semaste		return (cm->cm_error);
1080263363Semaste	}
1081263363Semaste	mfi_enqueue_ready(cm);
1082263363Semaste	mfi_startio(sc);
1083263363Semaste	if ((cm->cm_flags & MFI_CMD_COMPLETED) == 0)
1084263363Semaste		msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0);
1085263363Semaste	return (cm->cm_error);
1086269024Semaste}
1087269024Semaste
1088263363Semastevoid
1089263363Semastemfi_free(struct mfi_softc *sc)
1090263363Semaste{
1091263363Semaste	struct mfi_command *cm;
1092263363Semaste	int i;
1093263363Semaste
1094263363Semaste	callout_drain(&sc->mfi_watchdog_callout);
1095263363Semaste
1096263363Semaste	if (sc->mfi_cdev != NULL)
1097263363Semaste		destroy_dev(sc->mfi_cdev);
1098263363Semaste
1099263363Semaste	if (sc->mfi_total_cmds != 0) {
1100263363Semaste		for (i = 0; i < sc->mfi_total_cmds; i++) {
1101263363Semaste			cm = &sc->mfi_commands[i];
1102263363Semaste			bus_dmamap_destroy(sc->mfi_buffer_dmat, cm->cm_dmamap);
1103263363Semaste		}
1104263363Semaste		free(sc->mfi_commands, M_MFIBUF);
1105263363Semaste	}
1106263363Semaste
1107263363Semaste	if (sc->mfi_intr)
1108263363Semaste		bus_teardown_intr(sc->mfi_dev, sc->mfi_irq, sc->mfi_intr);
1109263363Semaste	if (sc->mfi_irq != NULL)
1110263363Semaste		bus_release_resource(sc->mfi_dev, SYS_RES_IRQ, sc->mfi_irq_rid,
1111263363Semaste		    sc->mfi_irq);
1112269024Semaste
1113269024Semaste	if (sc->mfi_sense_busaddr != 0)
1114263363Semaste		bus_dmamap_unload(sc->mfi_sense_dmat, sc->mfi_sense_dmamap);
1115263363Semaste	if (sc->mfi_sense != NULL)
1116263363Semaste		bus_dmamem_free(sc->mfi_sense_dmat, sc->mfi_sense,
1117263363Semaste		    sc->mfi_sense_dmamap);
1118263363Semaste	if (sc->mfi_sense_dmat != NULL)
1119263363Semaste		bus_dma_tag_destroy(sc->mfi_sense_dmat);
1120263363Semaste
1121263363Semaste	if (sc->mfi_frames_busaddr != 0)
1122263363Semaste		bus_dmamap_unload(sc->mfi_frames_dmat, sc->mfi_frames_dmamap);
1123263363Semaste	if (sc->mfi_frames != NULL)
1124263363Semaste		bus_dmamem_free(sc->mfi_frames_dmat, sc->mfi_frames,
1125263363Semaste		    sc->mfi_frames_dmamap);
1126263363Semaste	if (sc->mfi_frames_dmat != NULL)
1127263363Semaste		bus_dma_tag_destroy(sc->mfi_frames_dmat);
1128263363Semaste
1129263363Semaste	if (sc->mfi_comms_busaddr != 0)
1130263363Semaste		bus_dmamap_unload(sc->mfi_comms_dmat, sc->mfi_comms_dmamap);
1131263363Semaste	if (sc->mfi_comms != NULL)
1132263363Semaste		bus_dmamem_free(sc->mfi_comms_dmat, sc->mfi_comms,
1133263363Semaste		    sc->mfi_comms_dmamap);
1134263363Semaste	if (sc->mfi_comms_dmat != NULL)
1135263363Semaste		bus_dma_tag_destroy(sc->mfi_comms_dmat);
1136263363Semaste
1137263363Semaste	/* ThunderBolt contiguous memory free here */
1138263363Semaste	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
1139263363Semaste		if (sc->mfi_tb_busaddr != 0)
1140263363Semaste			bus_dmamap_unload(sc->mfi_tb_dmat, sc->mfi_tb_dmamap);
1141263363Semaste		if (sc->request_message_pool != NULL)
1142263363Semaste			bus_dmamem_free(sc->mfi_tb_dmat, sc->request_message_pool,
1143263363Semaste			    sc->mfi_tb_dmamap);
1144263363Semaste		if (sc->mfi_tb_dmat != NULL)
1145263363Semaste			bus_dma_tag_destroy(sc->mfi_tb_dmat);
1146263363Semaste
1147263363Semaste		/* Version buffer memory free */
1148263363Semaste		/* Start LSIP200113393 */
1149263363Semaste		if (sc->verbuf_h_busaddr != 0)
1150263363Semaste			bus_dmamap_unload(sc->verbuf_h_dmat, sc->verbuf_h_dmamap);
1151263363Semaste		if (sc->verbuf != NULL)
1152263363Semaste			bus_dmamem_free(sc->verbuf_h_dmat, sc->verbuf,
1153263363Semaste			    sc->verbuf_h_dmamap);
1154263363Semaste		if (sc->verbuf_h_dmat != NULL)
1155263363Semaste			bus_dma_tag_destroy(sc->verbuf_h_dmat);
1156263363Semaste
1157263363Semaste		/* End LSIP200113393 */
1158263363Semaste		/* ThunderBolt INIT packet memory Free */
1159263363Semaste		if (sc->mfi_tb_init_busaddr != 0)
1160263363Semaste			bus_dmamap_unload(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap);
1161263363Semaste		if (sc->mfi_tb_init != NULL)
1162263363Semaste			bus_dmamem_free(sc->mfi_tb_init_dmat, sc->mfi_tb_init,
1163269024Semaste			    sc->mfi_tb_init_dmamap);
1164269024Semaste		if (sc->mfi_tb_init_dmat != NULL)
1165269024Semaste			bus_dma_tag_destroy(sc->mfi_tb_init_dmat);
1166263363Semaste
1167269024Semaste		/* ThunderBolt IOC Init Desc memory free here */
1168263363Semaste		if (sc->mfi_tb_ioc_init_busaddr != 0)
1169263363Semaste			bus_dmamap_unload(sc->mfi_tb_ioc_init_dmat,
1170263363Semaste			    sc->mfi_tb_ioc_init_dmamap);
1171263363Semaste		if (sc->mfi_tb_ioc_init_desc != NULL)
1172263363Semaste			bus_dmamem_free(sc->mfi_tb_ioc_init_dmat,
1173263363Semaste			    sc->mfi_tb_ioc_init_desc,
1174263363Semaste			    sc->mfi_tb_ioc_init_dmamap);
1175263363Semaste		if (sc->mfi_tb_ioc_init_dmat != NULL)
1176263363Semaste			bus_dma_tag_destroy(sc->mfi_tb_ioc_init_dmat);
1177263363Semaste		for (int i = 0; i < sc->mfi_max_fw_cmds; i++) {
1178263363Semaste			if (sc->mfi_cmd_pool_tbolt != NULL) {
1179263363Semaste				if (sc->mfi_cmd_pool_tbolt[i] != NULL) {
1180263363Semaste					free(sc->mfi_cmd_pool_tbolt[i],
1181263363Semaste					    M_MFIBUF);
1182269024Semaste					sc->mfi_cmd_pool_tbolt[i] = NULL;
1183269024Semaste				}
1184263363Semaste			}
1185263363Semaste		}
1186263363Semaste		if (sc->mfi_cmd_pool_tbolt != NULL) {
1187263363Semaste			free(sc->mfi_cmd_pool_tbolt, M_MFIBUF);
1188263363Semaste			sc->mfi_cmd_pool_tbolt = NULL;
1189263363Semaste		}
1190263363Semaste		if (sc->request_desc_pool != NULL) {
1191263363Semaste			free(sc->request_desc_pool, M_MFIBUF);
1192263363Semaste			sc->request_desc_pool = NULL;
1193263363Semaste		}
1194263363Semaste	}
1195263363Semaste	if (sc->mfi_buffer_dmat != NULL)
1196263363Semaste		bus_dma_tag_destroy(sc->mfi_buffer_dmat);
1197269024Semaste	if (sc->mfi_parent_dmat != NULL)
1198263363Semaste		bus_dma_tag_destroy(sc->mfi_parent_dmat);
1199263363Semaste
1200263363Semaste	if (mtx_initialized(&sc->mfi_io_lock)) {
1201263363Semaste		mtx_destroy(&sc->mfi_io_lock);
1202263363Semaste		sx_destroy(&sc->mfi_config_lock);
1203263363Semaste	}
1204263363Semaste
1205263363Semaste	return;
1206263363Semaste}
1207263363Semaste
1208269024Semastestatic void
1209269024Semastemfi_startup(void *arg)
1210263363Semaste{
1211263363Semaste	struct mfi_softc *sc;
1212269024Semaste
1213269024Semaste	sc = (struct mfi_softc *)arg;
1214263363Semaste
1215263363Semaste	config_intrhook_disestablish(&sc->mfi_ich);
1216263363Semaste
1217263363Semaste	sc->mfi_enable_intr(sc);
1218263363Semaste	sx_xlock(&sc->mfi_config_lock);
1219263363Semaste	mtx_lock(&sc->mfi_io_lock);
1220263363Semaste	mfi_ldprobe(sc);
1221263363Semaste	if (sc->mfi_flags & MFI_FLAGS_SKINNY)
1222263363Semaste	    mfi_syspdprobe(sc);
1223263363Semaste	mtx_unlock(&sc->mfi_io_lock);
1224263363Semaste	sx_xunlock(&sc->mfi_config_lock);
1225263363Semaste}
1226263363Semaste
1227263363Semastestatic void
1228263363Semastemfi_intr(void *arg)
1229269024Semaste{
1230269024Semaste	struct mfi_softc *sc;
1231263363Semaste	struct mfi_command *cm;
1232263363Semaste	uint32_t pi, ci, context;
1233263363Semaste
1234263363Semaste	sc = (struct mfi_softc *)arg;
1235263363Semaste
1236263363Semaste	if (sc->mfi_check_clear_intr(sc))
1237263363Semaste		return;
1238263363Semaste
1239269024Semasterestart:
1240269024Semaste	pi = sc->mfi_comms->hw_pi;
1241263363Semaste	ci = sc->mfi_comms->hw_ci;
1242263363Semaste	mtx_lock(&sc->mfi_io_lock);
1243269024Semaste	while (ci != pi) {
1244269024Semaste		context = sc->mfi_comms->hw_reply_q[ci];
1245263363Semaste		if (context < sc->mfi_max_fw_cmds) {
1246263363Semaste			cm = &sc->mfi_commands[context];
1247263363Semaste			mfi_remove_busy(cm);
1248263363Semaste			cm->cm_error = 0;
1249263363Semaste			mfi_complete(sc, cm);
1250263363Semaste		}
1251263363Semaste		if (++ci == (sc->mfi_max_fw_cmds + 1)) {
1252263363Semaste			ci = 0;
1253263363Semaste		}
1254263363Semaste	}
1255263363Semaste
1256263363Semaste	sc->mfi_comms->hw_ci = ci;
1257269024Semaste
1258269024Semaste	/* Give defered I/O a chance to run */
1259269024Semaste	if (sc->mfi_flags & MFI_FLAGS_QFRZN)
1260263363Semaste		sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
1261269024Semaste	mfi_startio(sc);
1262263363Semaste	mtx_unlock(&sc->mfi_io_lock);
1263263363Semaste
1264263363Semaste	/*
1265269024Semaste	 * Dummy read to flush the bus; this ensures that the indexes are up
1266263363Semaste	 * to date.  Restart processing if more commands have come it.
1267263363Semaste	 */
1268263363Semaste	(void)sc->mfi_read_fw_status(sc);
1269263363Semaste	if (pi != sc->mfi_comms->hw_pi)
1270263363Semaste		goto restart;
1271263363Semaste
1272263363Semaste	return;
1273263363Semaste}
1274263363Semaste
1275263363Semasteint
1276269024Semastemfi_shutdown(struct mfi_softc *sc)
1277269024Semaste{
1278263363Semaste	struct mfi_dcmd_frame *dcmd;
1279263363Semaste	struct mfi_command *cm;
1280269024Semaste	int error;
1281269024Semaste
1282263363Semaste	mtx_lock(&sc->mfi_io_lock);
1283263363Semaste	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0);
1284263363Semaste	if (error) {
1285263363Semaste		mtx_unlock(&sc->mfi_io_lock);
1286263363Semaste		return (error);
1287263363Semaste	}
1288263363Semaste
1289263363Semaste	if (sc->mfi_aen_cm != NULL)
1290263363Semaste		mfi_abort(sc, sc->mfi_aen_cm);
1291263363Semaste
1292263363Semaste	if (sc->mfi_map_sync_cm != NULL)
1293263363Semaste		mfi_abort(sc, sc->mfi_map_sync_cm);
1294263363Semaste
1295263363Semaste	dcmd = &cm->cm_frame->dcmd;
1296263363Semaste	dcmd->header.flags = MFI_FRAME_DIR_NONE;
1297263363Semaste	cm->cm_flags = MFI_CMD_POLLED;
1298263363Semaste	cm->cm_data = NULL;
1299263363Semaste
1300263363Semaste	if ((error = mfi_mapcmd(sc, cm)) != 0) {
1301263363Semaste		device_printf(sc->mfi_dev, "Failed to shutdown controller\n");
1302263363Semaste	}
1303263363Semaste
1304263363Semaste	mfi_release_command(cm);
1305263363Semaste	mtx_unlock(&sc->mfi_io_lock);
1306263363Semaste	return (error);
1307269024Semaste}
1308269024Semaste
1309263363Semastestatic void
1310263363Semastemfi_syspdprobe(struct mfi_softc *sc)
1311263363Semaste{
1312263363Semaste	struct mfi_frame_header *hdr;
1313263363Semaste	struct mfi_command *cm = NULL;
1314263363Semaste	struct mfi_pd_list *pdlist = NULL;
1315263363Semaste	struct mfi_system_pd *syspd, *tmp;
1316263363Semaste	int error, i, found;
1317263363Semaste
1318263363Semaste	sx_assert(&sc->mfi_config_lock, SA_XLOCKED);
1319263363Semaste	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1320263363Semaste	/* Add SYSTEM PD's */
1321263363Semaste	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_LIST_QUERY,
1322263363Semaste	    (void **)&pdlist, sizeof(*pdlist));
1323263363Semaste	if (error) {
1324263363Semaste		device_printf(sc->mfi_dev,
1325263363Semaste		    "Error while forming SYSTEM PD list\n");
1326263363Semaste		goto out;
1327263363Semaste	}
1328263363Semaste
1329263363Semaste	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1330263363Semaste	cm->cm_frame->dcmd.mbox[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
1331263363Semaste	cm->cm_frame->dcmd.mbox[1] = 0;
1332269024Semaste	if (mfi_mapcmd(sc, cm) != 0) {
1333269024Semaste		device_printf(sc->mfi_dev,
1334263363Semaste		    "Failed to get syspd device listing\n");
1335263363Semaste		goto out;
1336263363Semaste	}
1337263363Semaste	bus_dmamap_sync(sc->mfi_buffer_dmat,cm->cm_dmamap,
1338263363Semaste	    BUS_DMASYNC_POSTREAD);
1339263363Semaste	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1340263363Semaste	hdr = &cm->cm_frame->header;
1341263363Semaste	if (hdr->cmd_status != MFI_STAT_OK) {
1342263363Semaste		device_printf(sc->mfi_dev,
1343269024Semaste		    "MFI_DCMD_PD_LIST_QUERY failed %x\n", hdr->cmd_status);
1344269024Semaste		goto out;
1345263363Semaste	}
1346263363Semaste	/* Get each PD and add it to the system */
1347263363Semaste	for (i = 0; i < pdlist->count; i++) {
1348263363Semaste		if (pdlist->addr[i].device_id ==
1349269024Semaste		    pdlist->addr[i].encl_device_id)
1350269024Semaste			continue;
1351263363Semaste		found = 0;
1352263363Semaste		TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) {
1353263363Semaste			if (syspd->pd_id == pdlist->addr[i].device_id)
1354263363Semaste				found = 1;
1355263363Semaste		}
1356263363Semaste		if (found == 0)
1357263363Semaste			mfi_add_sys_pd(sc, pdlist->addr[i].device_id);
1358263363Semaste	}
1359263363Semaste	/* Delete SYSPD's whose state has been changed */
1360263363Semaste	TAILQ_FOREACH_SAFE(syspd, &sc->mfi_syspd_tqh, pd_link, tmp) {
1361269024Semaste		found = 0;
1362269024Semaste		for (i = 0; i < pdlist->count; i++) {
1363263363Semaste			if (syspd->pd_id == pdlist->addr[i].device_id)
1364263363Semaste				found = 1;
1365263363Semaste		}
1366263363Semaste		if (found == 0) {
1367263363Semaste			printf("DELETE\n");
1368263363Semaste			mtx_unlock(&sc->mfi_io_lock);
1369263363Semaste			mtx_lock(&Giant);
1370263363Semaste			device_delete_child(sc->mfi_dev, syspd->pd_dev);
1371263363Semaste			mtx_unlock(&Giant);
1372263363Semaste			mtx_lock(&sc->mfi_io_lock);
1373263363Semaste		}
1374263363Semaste	}
1375263363Semasteout:
1376263363Semaste	if (pdlist)
1377263363Semaste	    free(pdlist, M_MFIBUF);
1378263363Semaste	if (cm)
1379263363Semaste	    mfi_release_command(cm);
1380263363Semaste
1381263363Semaste	return;
1382263363Semaste}
1383263363Semaste
1384263363Semastestatic void
1385263363Semastemfi_ldprobe(struct mfi_softc *sc)
1386263363Semaste{
1387263363Semaste	struct mfi_frame_header *hdr;
1388263363Semaste	struct mfi_command *cm = NULL;
1389263363Semaste	struct mfi_ld_list *list = NULL;
1390263363Semaste	struct mfi_disk *ld;
1391263363Semaste	int error, i;
1392263363Semaste
1393263363Semaste	sx_assert(&sc->mfi_config_lock, SA_XLOCKED);
1394263363Semaste	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1395263363Semaste
1396263363Semaste	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
1397263363Semaste	    (void **)&list, sizeof(*list));
1398263363Semaste	if (error)
1399263363Semaste		goto out;
1400263363Semaste
1401263363Semaste	cm->cm_flags = MFI_CMD_DATAIN;
1402263363Semaste	if (mfi_wait_command(sc, cm) != 0) {
1403263363Semaste		device_printf(sc->mfi_dev, "Failed to get device listing\n");
1404263363Semaste		goto out;
1405269024Semaste	}
1406269024Semaste
1407263363Semaste	hdr = &cm->cm_frame->header;
1408263363Semaste	if (hdr->cmd_status != MFI_STAT_OK) {
1409263363Semaste		device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n",
1410263363Semaste		    hdr->cmd_status);
1411269024Semaste		goto out;
1412269024Semaste	}
1413263363Semaste
1414263363Semaste	for (i = 0; i < list->ld_count; i++) {
1415263363Semaste		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1416263363Semaste			if (ld->ld_id == list->ld_list[i].ld.v.target_id)
1417263363Semaste				goto skip_add;
1418263363Semaste		}
1419263363Semaste		mfi_add_ld(sc, list->ld_list[i].ld.v.target_id);
1420263363Semaste	skip_add:;
1421263363Semaste	}
1422263363Semasteout:
1423263363Semaste	if (list)
1424263363Semaste		free(list, M_MFIBUF);
1425263363Semaste	if (cm)
1426263363Semaste		mfi_release_command(cm);
1427263363Semaste
1428263363Semaste	return;
1429263363Semaste}
1430263363Semaste
1431263363Semaste/*
1432263363Semaste * The timestamp is the number of seconds since 00:00 Jan 1, 2000.  If
1433263363Semaste * the bits in 24-31 are all set, then it is the number of seconds since
1434263363Semaste * boot.
1435263363Semaste */
1436263363Semastestatic const char *
1437263363Semasteformat_timestamp(uint32_t timestamp)
1438269024Semaste{
1439269024Semaste	static char buffer[32];
1440263363Semaste
1441263363Semaste	if ((timestamp & 0xff000000) == 0xff000000)
1442263363Semaste		snprintf(buffer, sizeof(buffer), "boot + %us", timestamp &
1443263363Semaste		    0x00ffffff);
1444269024Semaste	else
1445269024Semaste		snprintf(buffer, sizeof(buffer), "%us", timestamp);
1446263363Semaste	return (buffer);
1447263363Semaste}
1448263363Semaste
1449263363Semastestatic const char *
1450263363Semasteformat_class(int8_t class)
1451263363Semaste{
1452263363Semaste	static char buffer[6];
1453263363Semaste
1454263363Semaste	switch (class) {
1455263363Semaste	case MFI_EVT_CLASS_DEBUG:
1456263363Semaste		return ("debug");
1457263363Semaste	case MFI_EVT_CLASS_PROGRESS:
1458263363Semaste		return ("progress");
1459269024Semaste	case MFI_EVT_CLASS_INFO:
1460269024Semaste		return ("info");
1461263363Semaste	case MFI_EVT_CLASS_WARNING:
1462263363Semaste		return ("WARN");
1463263363Semaste	case MFI_EVT_CLASS_CRITICAL:
1464269024Semaste		return ("CRIT");
1465269024Semaste	case MFI_EVT_CLASS_FATAL:
1466263363Semaste		return ("FATAL");
1467263363Semaste	case MFI_EVT_CLASS_DEAD:
1468263363Semaste		return ("DEAD");
1469263363Semaste	default:
1470263363Semaste		snprintf(buffer, sizeof(buffer), "%d", class);
1471269024Semaste		return (buffer);
1472269024Semaste	}
1473263363Semaste}
1474263363Semaste
1475263363Semastestatic void
1476263363Semastemfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
1477263363Semaste{
1478263363Semaste	struct mfi_system_pd *syspd = NULL;
1479263363Semaste
1480263363Semaste	device_printf(sc->mfi_dev, "%d (%s/0x%04x/%s) - %s\n", detail->seq,
1481263363Semaste	    format_timestamp(detail->time), detail->evt_class.members.locale,
1482263363Semaste	    format_class(detail->evt_class.members.evt_class),
1483263363Semaste	    detail->description);
1484263363Semaste
1485263363Semaste        /* Don't act on old AEN's or while shutting down */
1486263363Semaste        if (detail->seq < sc->mfi_boot_seq_num || sc->mfi_detaching)
1487263363Semaste                return;
1488263363Semaste
1489263363Semaste	switch (detail->arg_type) {
1490263363Semaste	case MR_EVT_ARGS_NONE:
1491263363Semaste		if (detail->code == MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED) {
1492263363Semaste		    device_printf(sc->mfi_dev, "HostBus scan raised\n");
1493263363Semaste			if (mfi_detect_jbod_change) {
1494263363Semaste				/*
1495263363Semaste				 * Probe for new SYSPD's and Delete
1496263363Semaste				 * invalid SYSPD's
1497263363Semaste				 */
1498263363Semaste				sx_xlock(&sc->mfi_config_lock);
1499263363Semaste				mtx_lock(&sc->mfi_io_lock);
1500263363Semaste				mfi_syspdprobe(sc);
1501263363Semaste				mtx_unlock(&sc->mfi_io_lock);
1502263363Semaste				sx_xunlock(&sc->mfi_config_lock);
1503263363Semaste			}
1504263363Semaste		}
1505263363Semaste		break;
1506263363Semaste	case MR_EVT_ARGS_LD_STATE:
1507263363Semaste		/* During load time driver reads all the events starting
1508263363Semaste		 * from the one that has been logged after shutdown. Avoid
1509263363Semaste		 * these old events.
1510263363Semaste		 */
1511263363Semaste		if (detail->args.ld_state.new_state == MFI_LD_STATE_OFFLINE ) {
1512263363Semaste			/* Remove the LD */
1513263363Semaste			struct mfi_disk *ld;
1514263363Semaste			TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1515263363Semaste				if (ld->ld_id ==
1516263363Semaste				    detail->args.ld_state.ld.target_id)
1517263363Semaste					break;
1518263363Semaste			}
1519263363Semaste			/*
1520263363Semaste			Fix: for kernel panics when SSCD is removed
1521263363Semaste			KASSERT(ld != NULL, ("volume dissappeared"));
1522263363Semaste			*/
1523263363Semaste			if (ld != NULL) {
1524263363Semaste				mtx_lock(&Giant);
1525263363Semaste				device_delete_child(sc->mfi_dev, ld->ld_dev);
1526263363Semaste				mtx_unlock(&Giant);
1527263363Semaste			}
1528263363Semaste		}
1529263363Semaste		break;
1530263363Semaste	case MR_EVT_ARGS_PD:
1531263363Semaste		if (detail->code == MR_EVT_PD_REMOVED) {
1532263363Semaste			if (mfi_detect_jbod_change) {
1533263363Semaste				/*
1534269024Semaste				 * If the removed device is a SYSPD then
1535269024Semaste				 * delete it
1536263363Semaste				 */
1537263363Semaste				TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,
1538263363Semaste				    pd_link) {
1539263363Semaste					if (syspd->pd_id ==
1540269024Semaste					    detail->args.pd.device_id) {
1541269024Semaste						mtx_lock(&Giant);
1542263363Semaste						device_delete_child(
1543263363Semaste						    sc->mfi_dev,
1544263363Semaste						    syspd->pd_dev);
1545263363Semaste						mtx_unlock(&Giant);
1546263363Semaste						break;
1547263363Semaste					}
1548263363Semaste				}
1549263363Semaste			}
1550263363Semaste		}
1551263363Semaste		if (detail->code == MR_EVT_PD_INSERTED) {
1552269024Semaste			if (mfi_detect_jbod_change) {
1553269024Semaste				/* Probe for new SYSPD's */
1554263363Semaste				sx_xlock(&sc->mfi_config_lock);
1555263363Semaste				mtx_lock(&sc->mfi_io_lock);
1556263363Semaste				mfi_syspdprobe(sc);
1557263363Semaste				mtx_unlock(&sc->mfi_io_lock);
1558263363Semaste				sx_xunlock(&sc->mfi_config_lock);
1559263363Semaste			}
1560263363Semaste		}
1561263363Semaste		break;
1562263363Semaste	}
1563263363Semaste}
1564263363Semaste
1565263363Semastestatic void
1566263363Semastemfi_queue_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
1567263363Semaste{
1568263363Semaste	struct mfi_evt_queue_elm *elm;
1569263363Semaste
1570263363Semaste	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1571263363Semaste	elm = malloc(sizeof(*elm), M_MFIBUF, M_NOWAIT|M_ZERO);
1572263363Semaste	if (elm == NULL)
1573263363Semaste		return;
1574263363Semaste	memcpy(&elm->detail, detail, sizeof(*detail));
1575263363Semaste	TAILQ_INSERT_TAIL(&sc->mfi_evt_queue, elm, link);
1576263363Semaste	taskqueue_enqueue(taskqueue_swi, &sc->mfi_evt_task);
1577269024Semaste}
1578269024Semaste
1579263363Semastestatic void
1580263363Semastemfi_handle_evt(void *context, int pending)
1581263363Semaste{
1582263363Semaste	TAILQ_HEAD(,mfi_evt_queue_elm) queue;
1583263363Semaste	struct mfi_softc *sc;
1584263363Semaste	struct mfi_evt_queue_elm *elm;
1585263363Semaste
1586263363Semaste	sc = context;
1587263363Semaste	TAILQ_INIT(&queue);
1588263363Semaste	mtx_lock(&sc->mfi_io_lock);
1589263363Semaste	TAILQ_CONCAT(&queue, &sc->mfi_evt_queue, link);
1590263363Semaste	mtx_unlock(&sc->mfi_io_lock);
1591263363Semaste	while ((elm = TAILQ_FIRST(&queue)) != NULL) {
1592263363Semaste		TAILQ_REMOVE(&queue, elm, link);
1593263363Semaste		mfi_decode_evt(sc, &elm->detail);
1594263363Semaste		free(elm, M_MFIBUF);
1595263363Semaste	}
1596263363Semaste}
1597263363Semaste
1598263363Semastestatic int
1599263363Semastemfi_aen_register(struct mfi_softc *sc, int seq, int locale)
1600263363Semaste{
1601263363Semaste	struct mfi_command *cm;
1602263363Semaste	struct mfi_dcmd_frame *dcmd;
1603263363Semaste	union mfi_evt current_aen, prior_aen;
1604263363Semaste	struct mfi_evt_detail *ed = NULL;
1605263363Semaste	int error = 0;
1606263363Semaste
1607263363Semaste	current_aen.word = locale;
1608263363Semaste	if (sc->mfi_aen_cm != NULL) {
1609263363Semaste		prior_aen.word =
1610263363Semaste		    ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1];
1611263363Semaste		if (prior_aen.members.evt_class <= current_aen.members.evt_class &&
1612263363Semaste		    !((prior_aen.members.locale & current_aen.members.locale)
1613263363Semaste		    ^current_aen.members.locale)) {
1614263363Semaste			return (0);
1615263363Semaste		} else {
1616263363Semaste			prior_aen.members.locale |= current_aen.members.locale;
1617263363Semaste			if (prior_aen.members.evt_class
1618263363Semaste			    < current_aen.members.evt_class)
1619263363Semaste				current_aen.members.evt_class =
1620263363Semaste				    prior_aen.members.evt_class;
1621263363Semaste			mtx_lock(&sc->mfi_io_lock);
1622263363Semaste			mfi_abort(sc, sc->mfi_aen_cm);
1623263363Semaste			mtx_unlock(&sc->mfi_io_lock);
1624263363Semaste		}
1625263363Semaste	}
1626263363Semaste
1627263363Semaste	mtx_lock(&sc->mfi_io_lock);
1628263363Semaste	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT,
1629263363Semaste	    (void **)&ed, sizeof(*ed));
1630263363Semaste	mtx_unlock(&sc->mfi_io_lock);
1631263363Semaste	if (error) {
1632263363Semaste		goto out;
1633263363Semaste	}
1634263363Semaste
1635263363Semaste	dcmd = &cm->cm_frame->dcmd;
1636263363Semaste	((uint32_t *)&dcmd->mbox)[0] = seq;
1637263363Semaste	((uint32_t *)&dcmd->mbox)[1] = locale;
1638263363Semaste	cm->cm_flags = MFI_CMD_DATAIN;
1639263363Semaste	cm->cm_complete = mfi_aen_complete;
1640263363Semaste
1641263363Semaste	sc->last_seq_num = seq;
1642263363Semaste	sc->mfi_aen_cm = cm;
1643263363Semaste
1644263363Semaste	mtx_lock(&sc->mfi_io_lock);
1645263363Semaste	mfi_enqueue_ready(cm);
1646263363Semaste	mfi_startio(sc);
1647263363Semaste	mtx_unlock(&sc->mfi_io_lock);
1648263363Semaste
1649263363Semasteout:
1650263363Semaste	return (error);
1651263363Semaste}
1652263363Semaste
1653263363Semastestatic void
1654263363Semastemfi_aen_complete(struct mfi_command *cm)
1655263363Semaste{
1656263363Semaste	struct mfi_frame_header *hdr;
1657263363Semaste	struct mfi_softc *sc;
1658263363Semaste	struct mfi_evt_detail *detail;
1659263363Semaste	struct mfi_aen *mfi_aen_entry, *tmp;
1660263363Semaste	int seq = 0, aborted = 0;
1661263363Semaste
1662263363Semaste	sc = cm->cm_sc;
1663263363Semaste	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1664263363Semaste
1665263363Semaste	hdr = &cm->cm_frame->header;
1666263363Semaste
1667263363Semaste	if (sc->mfi_aen_cm == NULL)
1668263363Semaste		return;
1669263363Semaste
1670263363Semaste	if (sc->cm_aen_abort ||
1671269024Semaste	    hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
1672269024Semaste		sc->cm_aen_abort = 0;
1673263363Semaste		aborted = 1;
1674263363Semaste	} else {
1675263363Semaste		sc->mfi_aen_triggered = 1;
1676263363Semaste		if (sc->mfi_poll_waiting) {
1677263363Semaste			sc->mfi_poll_waiting = 0;
1678263363Semaste			selwakeup(&sc->mfi_select);
1679263363Semaste		}
1680263363Semaste		detail = cm->cm_data;
1681263363Semaste		mfi_queue_evt(sc, detail);
1682263363Semaste		seq = detail->seq + 1;
1683263363Semaste		TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link,
1684263363Semaste		    tmp) {
1685263363Semaste			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
1686263363Semaste			    aen_link);
1687263363Semaste			PROC_LOCK(mfi_aen_entry->p);
1688263363Semaste			kern_psignal(mfi_aen_entry->p, SIGIO);
1689263363Semaste			PROC_UNLOCK(mfi_aen_entry->p);
1690263363Semaste			free(mfi_aen_entry, M_MFIBUF);
1691263363Semaste		}
1692263363Semaste	}
1693263363Semaste
1694263363Semaste	free(cm->cm_data, M_MFIBUF);
1695263363Semaste	sc->mfi_aen_cm = NULL;
1696269024Semaste	wakeup(&sc->mfi_aen_cm);
1697269024Semaste	mfi_release_command(cm);
1698263363Semaste
1699263363Semaste	/* set it up again so the driver can catch more events */
1700263363Semaste	if (!aborted) {
1701263363Semaste		mtx_unlock(&sc->mfi_io_lock);
1702263363Semaste		mfi_aen_setup(sc, seq);
1703263363Semaste		mtx_lock(&sc->mfi_io_lock);
1704263363Semaste	}
1705263363Semaste}
1706263363Semaste
1707263363Semaste#define MAX_EVENTS 15
1708263363Semaste
1709263363Semastestatic int
1710263363Semastemfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq)
1711263363Semaste{
1712263363Semaste	struct mfi_command *cm;
1713263363Semaste	struct mfi_dcmd_frame *dcmd;
1714263363Semaste	struct mfi_evt_list *el;
1715263363Semaste	union mfi_evt class_locale;
1716263363Semaste	int error, i, seq, size;
1717263363Semaste
1718263363Semaste	class_locale.members.reserved = 0;
1719263363Semaste	class_locale.members.locale = mfi_event_locale;
1720263363Semaste	class_locale.members.evt_class  = mfi_event_class;
1721263363Semaste
1722263363Semaste	size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail)
1723263363Semaste		* (MAX_EVENTS - 1);
1724263363Semaste	el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO);
1725263363Semaste	if (el == NULL)
1726263363Semaste		return (ENOMEM);
1727263363Semaste
1728263363Semaste	for (seq = start_seq;;) {
1729263363Semaste		mtx_lock(&sc->mfi_io_lock);
1730263363Semaste		if ((cm = mfi_dequeue_free(sc)) == NULL) {
1731263363Semaste			free(el, M_MFIBUF);
1732269024Semaste			mtx_unlock(&sc->mfi_io_lock);
1733269024Semaste			return (EBUSY);
1734263363Semaste		}
1735263363Semaste		mtx_unlock(&sc->mfi_io_lock);
1736263363Semaste
1737263363Semaste		dcmd = &cm->cm_frame->dcmd;
1738263363Semaste		bzero(dcmd->mbox, MFI_MBOX_SIZE);
1739263363Semaste		dcmd->header.cmd = MFI_CMD_DCMD;
1740263363Semaste		dcmd->header.timeout = 0;
1741263363Semaste		dcmd->header.data_len = size;
1742263363Semaste		dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET;
1743263363Semaste		((uint32_t *)&dcmd->mbox)[0] = seq;
1744263363Semaste		((uint32_t *)&dcmd->mbox)[1] = class_locale.word;
1745263363Semaste		cm->cm_sg = &dcmd->sgl;
1746263363Semaste		cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
1747263363Semaste		cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1748269024Semaste		cm->cm_data = el;
1749269024Semaste		cm->cm_len = size;
1750263363Semaste
1751263363Semaste		mtx_lock(&sc->mfi_io_lock);
1752263363Semaste		if ((error = mfi_mapcmd(sc, cm)) != 0) {
1753263363Semaste			device_printf(sc->mfi_dev,
1754263363Semaste			    "Failed to get controller entries\n");
1755263363Semaste			mfi_release_command(cm);
1756263363Semaste			mtx_unlock(&sc->mfi_io_lock);
1757263363Semaste			break;
1758263363Semaste		}
1759263363Semaste
1760263363Semaste		mtx_unlock(&sc->mfi_io_lock);
1761263363Semaste		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1762263363Semaste		    BUS_DMASYNC_POSTREAD);
1763263363Semaste		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1764263363Semaste
1765269024Semaste		if (dcmd->header.cmd_status == MFI_STAT_NOT_FOUND) {
1766269024Semaste			mtx_lock(&sc->mfi_io_lock);
1767263363Semaste			mfi_release_command(cm);
1768263363Semaste			mtx_unlock(&sc->mfi_io_lock);
1769263363Semaste			break;
1770263363Semaste		}
1771263363Semaste		if (dcmd->header.cmd_status != MFI_STAT_OK) {
1772263363Semaste			device_printf(sc->mfi_dev,
1773263363Semaste			    "Error %d fetching controller entries\n",
1774263363Semaste			    dcmd->header.cmd_status);
1775263363Semaste			mtx_lock(&sc->mfi_io_lock);
1776263363Semaste			mfi_release_command(cm);
1777263363Semaste			mtx_unlock(&sc->mfi_io_lock);
1778263363Semaste			break;
1779263363Semaste		}
1780263363Semaste		mtx_lock(&sc->mfi_io_lock);
1781263363Semaste		mfi_release_command(cm);
1782263363Semaste		mtx_unlock(&sc->mfi_io_lock);
1783263363Semaste
1784263363Semaste		for (i = 0; i < el->count; i++) {
1785263363Semaste			/*
1786263363Semaste			 * If this event is newer than 'stop_seq' then
1787263363Semaste			 * break out of the loop.  Note that the log
1788263363Semaste			 * is a circular buffer so we have to handle
1789263363Semaste			 * the case that our stop point is earlier in
1790263363Semaste			 * the buffer than our start point.
1791263363Semaste			 */
1792263363Semaste			if (el->event[i].seq >= stop_seq) {
1793263363Semaste				if (start_seq <= stop_seq)
1794263363Semaste					break;
1795263363Semaste				else if (el->event[i].seq < start_seq)
1796263363Semaste					break;
1797263363Semaste			}
1798263363Semaste			mtx_lock(&sc->mfi_io_lock);
1799269024Semaste			mfi_queue_evt(sc, &el->event[i]);
1800269024Semaste			mtx_unlock(&sc->mfi_io_lock);
1801263363Semaste		}
1802263363Semaste		seq = el->event[el->count - 1].seq + 1;
1803263363Semaste	}
1804263363Semaste
1805263363Semaste	free(el, M_MFIBUF);
1806263363Semaste	return (0);
1807263363Semaste}
1808263363Semaste
1809263363Semastestatic int
1810263363Semastemfi_add_ld(struct mfi_softc *sc, int id)
1811263363Semaste{
1812263363Semaste	struct mfi_command *cm;
1813263363Semaste	struct mfi_dcmd_frame *dcmd = NULL;
1814263363Semaste	struct mfi_ld_info *ld_info = NULL;
1815263363Semaste	int error;
1816263363Semaste
1817263363Semaste	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1818263363Semaste
1819263363Semaste	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO,
1820263363Semaste	    (void **)&ld_info, sizeof(*ld_info));
1821263363Semaste	if (error) {
1822263363Semaste		device_printf(sc->mfi_dev,
1823263363Semaste		    "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error);
1824263363Semaste		if (ld_info)
1825263363Semaste			free(ld_info, M_MFIBUF);
1826263363Semaste		return (error);
1827263363Semaste	}
1828263363Semaste	cm->cm_flags = MFI_CMD_DATAIN;
1829263363Semaste	dcmd = &cm->cm_frame->dcmd;
1830263363Semaste	dcmd->mbox[0] = id;
1831263363Semaste	if (mfi_wait_command(sc, cm) != 0) {
1832263363Semaste		device_printf(sc->mfi_dev,
1833263363Semaste		    "Failed to get logical drive: %d\n", id);
1834263363Semaste		free(ld_info, M_MFIBUF);
1835263363Semaste		return (0);
1836263363Semaste	}
1837263363Semaste	if (ld_info->ld_config.params.isSSCD != 1)
1838269024Semaste		mfi_add_ld_complete(cm);
1839269024Semaste	else {
1840263363Semaste		mfi_release_command(cm);
1841263363Semaste		if (ld_info)		/* SSCD drives ld_info free here */
1842263363Semaste			free(ld_info, M_MFIBUF);
1843263363Semaste	}
1844263363Semaste	return (0);
1845263363Semaste}
1846263363Semaste
1847263363Semastestatic void
1848263363Semastemfi_add_ld_complete(struct mfi_command *cm)
1849263363Semaste{
1850263363Semaste	struct mfi_frame_header *hdr;
1851263363Semaste	struct mfi_ld_info *ld_info;
1852263363Semaste	struct mfi_softc *sc;
1853263363Semaste	device_t child;
1854263363Semaste
1855263363Semaste	sc = cm->cm_sc;
1856263363Semaste	hdr = &cm->cm_frame->header;
1857263363Semaste	ld_info = cm->cm_private;
1858263363Semaste
1859263363Semaste	if (hdr->cmd_status != MFI_STAT_OK) {
1860263363Semaste		free(ld_info, M_MFIBUF);
1861269024Semaste		mfi_release_command(cm);
1862269024Semaste		return;
1863263363Semaste	}
1864263363Semaste	mfi_release_command(cm);
1865263363Semaste
1866263363Semaste	mtx_unlock(&sc->mfi_io_lock);
1867263363Semaste	mtx_lock(&Giant);
1868263363Semaste	if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) {
1869263363Semaste		device_printf(sc->mfi_dev, "Failed to add logical disk\n");
1870263363Semaste		free(ld_info, M_MFIBUF);
1871263363Semaste		mtx_unlock(&Giant);
1872263363Semaste		mtx_lock(&sc->mfi_io_lock);
1873269024Semaste		return;
1874269024Semaste	}
1875263363Semaste
1876263363Semaste	device_set_ivars(child, ld_info);
1877263363Semaste	device_set_desc(child, "MFI Logical Disk");
1878263363Semaste	bus_generic_attach(sc->mfi_dev);
1879263363Semaste	mtx_unlock(&Giant);
1880263363Semaste	mtx_lock(&sc->mfi_io_lock);
1881263363Semaste}
1882263363Semaste
1883263363Semastestatic int mfi_add_sys_pd(struct mfi_softc *sc, int id)
1884263363Semaste{
1885263363Semaste	struct mfi_command *cm;
1886263363Semaste	struct mfi_dcmd_frame *dcmd = NULL;
1887263363Semaste	struct mfi_pd_info *pd_info = NULL;
1888263363Semaste	int error;
1889263363Semaste
1890263363Semaste	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1891263363Semaste
1892263363Semaste	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_GET_INFO,
1893263363Semaste		(void **)&pd_info, sizeof(*pd_info));
1894263363Semaste	if (error) {
1895263363Semaste		device_printf(sc->mfi_dev,
1896263363Semaste		    "Failed to allocated for MFI_DCMD_PD_GET_INFO %d\n",
1897263363Semaste		    error);
1898263363Semaste		if (pd_info)
1899263363Semaste			free(pd_info, M_MFIBUF);
1900263363Semaste		return (error);
1901263363Semaste	}
1902263363Semaste	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1903263363Semaste	dcmd = &cm->cm_frame->dcmd;
1904263363Semaste	dcmd->mbox[0]=id;
1905263363Semaste	dcmd->header.scsi_status = 0;
1906263363Semaste	dcmd->header.pad0 = 0;
1907263363Semaste	if (mfi_mapcmd(sc, cm) != 0) {
1908263363Semaste		device_printf(sc->mfi_dev,
1909263363Semaste		    "Failed to get physical drive info %d\n", id);
1910263363Semaste		free(pd_info, M_MFIBUF);
1911263363Semaste		return (0);
1912263363Semaste	}
1913263363Semaste	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1914263363Semaste	    BUS_DMASYNC_POSTREAD);
1915263363Semaste	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1916263363Semaste	mfi_add_sys_pd_complete(cm);
1917263363Semaste	return (0);
1918263363Semaste}
1919263363Semaste
1920263363Semastestatic void
1921263363Semastemfi_add_sys_pd_complete(struct mfi_command *cm)
1922263363Semaste{
1923263363Semaste	struct mfi_frame_header *hdr;
1924263363Semaste	struct mfi_pd_info *pd_info;
1925263363Semaste	struct mfi_softc *sc;
1926263363Semaste	device_t child;
1927263363Semaste
1928263363Semaste	sc = cm->cm_sc;
1929263363Semaste	hdr = &cm->cm_frame->header;
1930263363Semaste	pd_info = cm->cm_private;
1931263363Semaste
1932263363Semaste	if (hdr->cmd_status != MFI_STAT_OK) {
1933263363Semaste		free(pd_info, M_MFIBUF);
1934263363Semaste		mfi_release_command(cm);
1935263363Semaste		return;
1936263363Semaste	}
1937263363Semaste	if (pd_info->fw_state != MFI_PD_STATE_SYSTEM) {
1938263363Semaste		device_printf(sc->mfi_dev, "PD=%x is not SYSTEM PD\n",
1939263363Semaste		    pd_info->ref.v.device_id);
1940263363Semaste		free(pd_info, M_MFIBUF);
1941263363Semaste		mfi_release_command(cm);
1942263363Semaste		return;
1943263363Semaste	}
1944263363Semaste	mfi_release_command(cm);
1945263363Semaste
1946263363Semaste	mtx_unlock(&sc->mfi_io_lock);
1947263363Semaste	mtx_lock(&Giant);
1948263363Semaste	if ((child = device_add_child(sc->mfi_dev, "mfisyspd", -1)) == NULL) {
1949263363Semaste		device_printf(sc->mfi_dev, "Failed to add system pd\n");
1950263363Semaste		free(pd_info, M_MFIBUF);
1951263363Semaste		mtx_unlock(&Giant);
1952263363Semaste		mtx_lock(&sc->mfi_io_lock);
1953263363Semaste		return;
1954263363Semaste	}
1955263363Semaste
1956263363Semaste	device_set_ivars(child, pd_info);
1957263363Semaste	device_set_desc(child, "MFI System PD");
1958263363Semaste	bus_generic_attach(sc->mfi_dev);
1959263363Semaste	mtx_unlock(&Giant);
1960263363Semaste	mtx_lock(&sc->mfi_io_lock);
1961263363Semaste}
1962263363Semaste
1963263363Semastestatic struct mfi_command *
1964263363Semastemfi_bio_command(struct mfi_softc *sc)
1965263363Semaste{
1966263363Semaste	struct bio *bio;
1967263363Semaste	struct mfi_command *cm = NULL;
1968263363Semaste
1969263363Semaste	/*reserving two commands to avoid starvation for IOCTL*/
1970263363Semaste	if (sc->mfi_qstat[MFIQ_FREE].q_length < 2) {
1971263363Semaste		return (NULL);
1972263363Semaste	}
1973263363Semaste	if ((bio = mfi_dequeue_bio(sc)) == NULL) {
1974263363Semaste		return (NULL);
1975263363Semaste	}
1976263363Semaste	if ((uintptr_t)bio->bio_driver2 == MFI_LD_IO) {
1977263363Semaste		cm = mfi_build_ldio(sc, bio);
1978263363Semaste	} else if ((uintptr_t) bio->bio_driver2 == MFI_SYS_PD_IO) {
1979263363Semaste		cm = mfi_build_syspdio(sc, bio);
1980263363Semaste	}
1981263363Semaste	if (!cm)
1982263363Semaste	    mfi_enqueue_bio(sc, bio);
1983263363Semaste	return cm;
1984263363Semaste}
1985269024Semastestatic struct mfi_command *
1986269024Semastemfi_build_syspdio(struct mfi_softc *sc, struct bio *bio)
1987263363Semaste{
1988263363Semaste	struct mfi_command *cm;
1989263363Semaste	struct mfi_pass_frame *pass;
1990263363Semaste	int flags = 0, blkcount = 0;
1991263363Semaste	uint32_t context = 0;
1992263363Semaste
1993263363Semaste	if ((cm = mfi_dequeue_free(sc)) == NULL)
1994263363Semaste	    return (NULL);
1995269024Semaste
1996269024Semaste	/* Zero out the MFI frame */
1997263363Semaste 	context = cm->cm_frame->header.context;
1998263363Semaste	bzero(cm->cm_frame, sizeof(union mfi_frame));
1999263363Semaste	cm->cm_frame->header.context = context;
2000263363Semaste	pass = &cm->cm_frame->pass;
2001263363Semaste	bzero(pass->cdb, 16);
2002263363Semaste	pass->header.cmd = MFI_CMD_PD_SCSI_IO;
2003263363Semaste	switch (bio->bio_cmd & 0x03) {
2004263363Semaste	case BIO_READ:
2005263363Semaste#define SCSI_READ 0x28
2006269024Semaste		pass->cdb[0] = SCSI_READ;
2007269024Semaste		flags = MFI_CMD_DATAIN;
2008263363Semaste		break;
2009263363Semaste	case BIO_WRITE:
2010263363Semaste#define SCSI_WRITE 0x2a
2011263363Semaste		pass->cdb[0] = SCSI_WRITE;
2012263363Semaste		flags = MFI_CMD_DATAOUT;
2013263363Semaste		break;
2014263363Semaste	default:
2015263363Semaste		panic("Invalid bio command");
2016269024Semaste	}
2017269024Semaste
2018263363Semaste	/* Cheat with the sector length to avoid a non-constant division */
2019263363Semaste	blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2020263363Semaste	/* Fill the LBA and Transfer length in CDB */
2021263363Semaste	pass->cdb[2] = (bio->bio_pblkno & 0xff000000) >> 24;
2022263363Semaste	pass->cdb[3] = (bio->bio_pblkno & 0x00ff0000) >> 16;
2023263363Semaste	pass->cdb[4] = (bio->bio_pblkno & 0x0000ff00) >> 8;
2024263363Semaste	pass->cdb[5] = bio->bio_pblkno & 0x000000ff;
2025263363Semaste	pass->cdb[7] = (blkcount & 0xff00) >> 8;
2026263363Semaste	pass->cdb[8] = (blkcount & 0x00ff);
2027269024Semaste	pass->header.target_id = (uintptr_t)bio->bio_driver1;
2028269024Semaste	pass->header.timeout = 0;
2029263363Semaste	pass->header.flags = 0;
2030263363Semaste	pass->header.scsi_status = 0;
2031263363Semaste	pass->header.sense_len = MFI_SENSE_LEN;
2032263363Semaste	pass->header.data_len = bio->bio_bcount;
2033263363Semaste	pass->header.cdb_len = 10;
2034263363Semaste	pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2035263363Semaste	pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2036263363Semaste	cm->cm_complete = mfi_bio_complete;
2037263363Semaste	cm->cm_private = bio;
2038263363Semaste	cm->cm_data = bio->bio_data;
2039263363Semaste	cm->cm_len = bio->bio_bcount;
2040263363Semaste	cm->cm_sg = &pass->sgl;
2041263363Semaste	cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
2042263363Semaste	cm->cm_flags = flags;
2043263363Semaste	return (cm);
2044263363Semaste}
2045263363Semaste
2046263363Semastestatic struct mfi_command *
2047263363Semastemfi_build_ldio(struct mfi_softc *sc, struct bio *bio)
2048263363Semaste{
2049263363Semaste	struct mfi_io_frame *io;
2050263363Semaste	struct mfi_command *cm;
2051263363Semaste	int flags, blkcount;
2052263363Semaste	uint32_t context = 0;
2053263363Semaste
2054263363Semaste	if ((cm = mfi_dequeue_free(sc)) == NULL)
2055263363Semaste	    return (NULL);
2056263363Semaste
2057263363Semaste	/* Zero out the MFI frame */
2058263363Semaste	context = cm->cm_frame->header.context;
2059263363Semaste	bzero(cm->cm_frame, sizeof(union mfi_frame));
2060263363Semaste	cm->cm_frame->header.context = context;
2061263363Semaste	io = &cm->cm_frame->io;
2062263363Semaste	switch (bio->bio_cmd & 0x03) {
2063263363Semaste	case BIO_READ:
2064263363Semaste		io->header.cmd = MFI_CMD_LD_READ;
2065263363Semaste		flags = MFI_CMD_DATAIN;
2066263363Semaste		break;
2067263363Semaste	case BIO_WRITE:
2068263363Semaste		io->header.cmd = MFI_CMD_LD_WRITE;
2069263363Semaste		flags = MFI_CMD_DATAOUT;
2070263363Semaste		break;
2071263363Semaste	default:
2072263363Semaste		panic("Invalid bio command");
2073263363Semaste	}
2074263363Semaste
2075263363Semaste	/* Cheat with the sector length to avoid a non-constant division */
2076263363Semaste	blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2077263363Semaste	io->header.target_id = (uintptr_t)bio->bio_driver1;
2078263363Semaste	io->header.timeout = 0;
2079263363Semaste	io->header.flags = 0;
2080263363Semaste	io->header.scsi_status = 0;
2081263363Semaste	io->header.sense_len = MFI_SENSE_LEN;
2082263363Semaste	io->header.data_len = blkcount;
2083263363Semaste	io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2084263363Semaste	io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2085263363Semaste	io->lba_hi = (bio->bio_pblkno & 0xffffffff00000000) >> 32;
2086263363Semaste	io->lba_lo = bio->bio_pblkno & 0xffffffff;
2087263363Semaste	cm->cm_complete = mfi_bio_complete;
2088263363Semaste	cm->cm_private = bio;
2089263363Semaste	cm->cm_data = bio->bio_data;
2090263363Semaste	cm->cm_len = bio->bio_bcount;
2091263363Semaste	cm->cm_sg = &io->sgl;
2092263363Semaste	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
2093263363Semaste	cm->cm_flags = flags;
2094263363Semaste	return (cm);
2095263363Semaste}
2096263363Semaste
2097263363Semastestatic void
2098263363Semastemfi_bio_complete(struct mfi_command *cm)
2099263363Semaste{
2100263363Semaste	struct bio *bio;
2101263363Semaste	struct mfi_frame_header *hdr;
2102263363Semaste	struct mfi_softc *sc;
2103263363Semaste
2104263363Semaste	bio = cm->cm_private;
2105263363Semaste	hdr = &cm->cm_frame->header;
2106263363Semaste	sc = cm->cm_sc;
2107263363Semaste
2108263363Semaste	if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0)) {
2109263363Semaste		bio->bio_flags |= BIO_ERROR;
2110263363Semaste		bio->bio_error = EIO;
2111263363Semaste		device_printf(sc->mfi_dev, "I/O error, status= %d "
2112263363Semaste		    "scsi_status= %d\n", hdr->cmd_status, hdr->scsi_status);
2113263363Semaste		mfi_print_sense(cm->cm_sc, cm->cm_sense);
2114263363Semaste	} else if (cm->cm_error != 0) {
2115263363Semaste		bio->bio_flags |= BIO_ERROR;
2116263363Semaste	}
2117263363Semaste
2118263363Semaste	mfi_release_command(cm);
2119263363Semaste	mfi_disk_complete(bio);
2120263363Semaste}
2121263363Semaste
2122263363Semastevoid
2123263363Semastemfi_startio(struct mfi_softc *sc)
2124263363Semaste{
2125263363Semaste	struct mfi_command *cm;
2126263363Semaste	struct ccb_hdr *ccbh;
2127263363Semaste
2128263363Semaste	for (;;) {
2129263363Semaste		/* Don't bother if we're short on resources */
2130263363Semaste		if (sc->mfi_flags & MFI_FLAGS_QFRZN)
2131263363Semaste			break;
2132263363Semaste
2133263363Semaste		/* Try a command that has already been prepared */
2134263363Semaste		cm = mfi_dequeue_ready(sc);
2135263363Semaste
2136263363Semaste		if (cm == NULL) {
2137263363Semaste			if ((ccbh = TAILQ_FIRST(&sc->mfi_cam_ccbq)) != NULL)
2138263363Semaste				cm = sc->mfi_cam_start(ccbh);
2139263363Semaste		}
2140263363Semaste
2141263363Semaste		/* Nope, so look for work on the bioq */
2142263363Semaste		if (cm == NULL)
2143263363Semaste			cm = mfi_bio_command(sc);
2144263363Semaste
2145263363Semaste		/* No work available, so exit */
2146263363Semaste		if (cm == NULL)
2147263363Semaste			break;
2148263363Semaste
2149263363Semaste		/* Send the command to the controller */
2150263363Semaste		if (mfi_mapcmd(sc, cm) != 0) {
2151263363Semaste			mfi_requeue_ready(cm);
2152263363Semaste			break;
2153263363Semaste		}
2154263363Semaste	}
2155263363Semaste}
2156269024Semaste
2157269024Semasteint
2158263363Semastemfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm)
2159263363Semaste{
2160263363Semaste	int error, polled;
2161263363Semaste
2162263363Semaste	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2163263363Semaste
2164263363Semaste	if ((cm->cm_data != NULL) && (cm->cm_frame->header.cmd != MFI_CMD_STP )) {
2165263363Semaste		polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0;
2166263363Semaste		error = bus_dmamap_load(sc->mfi_buffer_dmat, cm->cm_dmamap,
2167263363Semaste		    cm->cm_data, cm->cm_len, mfi_data_cb, cm, polled);
2168263363Semaste		if (error == EINPROGRESS) {
2169263363Semaste			sc->mfi_flags |= MFI_FLAGS_QFRZN;
2170263363Semaste			return (0);
2171263363Semaste		}
2172263363Semaste	} else {
2173263363Semaste		if (sc->MFA_enabled)
2174263363Semaste			error = mfi_tbolt_send_frame(sc, cm);
2175263363Semaste		else
2176263363Semaste			error = mfi_send_frame(sc, cm);
2177263363Semaste	}
2178263363Semaste
2179263363Semaste	return (error);
2180263363Semaste}
2181263363Semaste
2182263363Semastestatic void
2183263363Semastemfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
2184263363Semaste{
2185263363Semaste	struct mfi_frame_header *hdr;
2186263363Semaste	struct mfi_command *cm;
2187263363Semaste	union mfi_sgl *sgl;
2188263363Semaste	struct mfi_softc *sc;
2189263363Semaste	int i, j, first, dir;
2190269024Semaste	int sge_size;
2191269024Semaste
2192263363Semaste	cm = (struct mfi_command *)arg;
2193263363Semaste	sc = cm->cm_sc;
2194263363Semaste	hdr = &cm->cm_frame->header;
2195263363Semaste	sgl = cm->cm_sg;
2196263363Semaste
2197263363Semaste	if (error) {
2198263363Semaste		printf("error %d in callback\n", error);
2199263363Semaste		cm->cm_error = error;
2200263363Semaste		mfi_complete(sc, cm);
2201263363Semaste		return;
2202263363Semaste	}
2203263363Semaste	/* Use IEEE sgl only for IO's on a SKINNY controller
2204263363Semaste	 * For other commands on a SKINNY controller use either
2205263363Semaste	 * sg32 or sg64 based on the sizeof(bus_addr_t).
2206263363Semaste	 * Also calculate the total frame size based on the type
2207269024Semaste	 * of SGL used.
2208269024Semaste	 */
2209263363Semaste	if (((cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) ||
2210263363Semaste	    (cm->cm_frame->header.cmd == MFI_CMD_LD_READ) ||
2211263363Semaste	    (cm->cm_frame->header.cmd == MFI_CMD_LD_WRITE)) &&
2212263363Semaste	    (sc->mfi_flags & MFI_FLAGS_SKINNY)) {
2213263363Semaste		for (i = 0; i < nsegs; i++) {
2214263363Semaste			sgl->sg_skinny[i].addr = segs[i].ds_addr;
2215263363Semaste			sgl->sg_skinny[i].len = segs[i].ds_len;
2216263363Semaste			sgl->sg_skinny[i].flag = 0;
2217263363Semaste		}
2218263363Semaste		hdr->flags |= MFI_FRAME_IEEE_SGL | MFI_FRAME_SGL64;
2219263363Semaste		sge_size = sizeof(struct mfi_sg_skinny);
2220263363Semaste		hdr->sg_count = nsegs;
2221263363Semaste	} else {
2222263363Semaste		j = 0;
2223263363Semaste		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
2224263363Semaste			first = cm->cm_stp_len;
2225263363Semaste			if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
2226263363Semaste				sgl->sg32[j].addr = segs[0].ds_addr;
2227263363Semaste				sgl->sg32[j++].len = first;
2228263363Semaste			} else {
2229263363Semaste				sgl->sg64[j].addr = segs[0].ds_addr;
2230263363Semaste				sgl->sg64[j++].len = first;
2231263363Semaste			}
2232263363Semaste		} else
2233263363Semaste			first = 0;
2234263363Semaste		if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
2235263363Semaste			for (i = 0; i < nsegs; i++) {
2236263363Semaste				sgl->sg32[j].addr = segs[i].ds_addr + first;
2237263363Semaste				sgl->sg32[j++].len = segs[i].ds_len - first;
2238263363Semaste				first = 0;
2239263363Semaste			}
2240263363Semaste		} else {
2241263363Semaste			for (i = 0; i < nsegs; i++) {
2242263363Semaste				sgl->sg64[j].addr = segs[i].ds_addr + first;
2243263363Semaste				sgl->sg64[j++].len = segs[i].ds_len - first;
2244269024Semaste				first = 0;
2245269024Semaste			}
2246263363Semaste			hdr->flags |= MFI_FRAME_SGL64;
2247263363Semaste		}
2248263363Semaste		hdr->sg_count = j;
2249263363Semaste		sge_size = sc->mfi_sge_size;
2250263363Semaste	}
2251263363Semaste
2252263363Semaste	dir = 0;
2253263363Semaste	if (cm->cm_flags & MFI_CMD_DATAIN) {
2254263363Semaste		dir |= BUS_DMASYNC_PREREAD;
2255269024Semaste		hdr->flags |= MFI_FRAME_DIR_READ;
2256269024Semaste	}
2257263363Semaste	if (cm->cm_flags & MFI_CMD_DATAOUT) {
2258263363Semaste		dir |= BUS_DMASYNC_PREWRITE;
2259263363Semaste		hdr->flags |= MFI_FRAME_DIR_WRITE;
2260263363Semaste	}
2261263363Semaste	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
2262263363Semaste	cm->cm_flags |= MFI_CMD_MAPPED;
2263263363Semaste
2264263363Semaste	/*
2265263363Semaste	 * Instead of calculating the total number of frames in the
2266263363Semaste	 * compound frame, it's already assumed that there will be at
2267263363Semaste	 * least 1 frame, so don't compensate for the modulo of the
2268263363Semaste	 * following division.
2269263363Semaste	 */
2270263363Semaste	cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs);
2271263363Semaste	cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
2272263363Semaste
2273263363Semaste	if (sc->MFA_enabled)
2274263363Semaste			mfi_tbolt_send_frame(sc, cm);
2275263363Semaste	else
2276263363Semaste		mfi_send_frame(sc, cm);
2277263363Semaste
2278269024Semaste	return;
2279269024Semaste}
2280263363Semaste
2281263363Semastestatic int
2282263363Semastemfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
2283263363Semaste{
2284263363Semaste	struct mfi_frame_header *hdr;
2285263363Semaste	int tm = MFI_POLL_TIMEOUT_SECS * 1000;
2286263363Semaste
2287263363Semaste	hdr = &cm->cm_frame->header;
2288263363Semaste
2289263363Semaste	if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
2290263363Semaste		cm->cm_timestamp = time_uptime;
2291263363Semaste		mfi_enqueue_busy(cm);
2292263363Semaste	} else {
2293263363Semaste		hdr->cmd_status = MFI_STAT_INVALID_STATUS;
2294263363Semaste		hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
2295263363Semaste	}
2296263363Semaste
2297263363Semaste	/*
2298263363Semaste	 * The bus address of the command is aligned on a 64 byte boundary,
2299263363Semaste	 * leaving the least 6 bits as zero.  For whatever reason, the
2300263363Semaste	 * hardware wants the address shifted right by three, leaving just
2301263363Semaste	 * 3 zero bits.  These three bits are then used as a prefetching
2302263363Semaste	 * hint for the hardware to predict how many frames need to be
2303263363Semaste	 * fetched across the bus.  If a command has more than 8 frames
2304263363Semaste	 * then the 3 bits are set to 0x7 and the firmware uses other
2305263363Semaste	 * information in the command to determine the total amount to fetch.
2306263363Semaste	 * However, FreeBSD doesn't support I/O larger than 128K, so 8 frames
2307263363Semaste	 * is enough for both 32bit and 64bit systems.
2308263363Semaste	 */
2309263363Semaste	if (cm->cm_extra_frames > 7)
2310263363Semaste		cm->cm_extra_frames = 7;
2311263363Semaste
2312263363Semaste	sc->mfi_issue_cmd(sc, cm->cm_frame_busaddr, cm->cm_extra_frames);
2313263363Semaste
2314263363Semaste	if ((cm->cm_flags & MFI_CMD_POLLED) == 0)
2315263363Semaste		return (0);
2316269024Semaste
2317263363Semaste	/* This is a polled command, so busy-wait for it to complete. */
2318263363Semaste	while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
2319263363Semaste		DELAY(1000);
2320263363Semaste		tm -= 1;
2321263363Semaste		if (tm <= 0)
2322263363Semaste			break;
2323263363Semaste	}
2324263363Semaste
2325263363Semaste	if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
2326263363Semaste		device_printf(sc->mfi_dev, "Frame %p timed out "
2327263363Semaste		    "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
2328263363Semaste		return (ETIMEDOUT);
2329263363Semaste	}
2330263363Semaste
2331263363Semaste	return (0);
2332263363Semaste}
2333263363Semaste
2334263363Semaste
2335263363Semastevoid
2336263363Semastemfi_complete(struct mfi_softc *sc, struct mfi_command *cm)
2337263363Semaste{
2338263363Semaste	int dir;
2339263363Semaste
2340263363Semaste	if ((cm->cm_flags & MFI_CMD_MAPPED) != 0) {
2341263363Semaste		dir = 0;
2342263363Semaste		if ((cm->cm_flags & MFI_CMD_DATAIN) ||
2343263363Semaste		    (cm->cm_frame->header.cmd == MFI_CMD_STP))
2344263363Semaste			dir |= BUS_DMASYNC_POSTREAD;
2345263363Semaste		if (cm->cm_flags & MFI_CMD_DATAOUT)
2346263363Semaste			dir |= BUS_DMASYNC_POSTWRITE;
2347263363Semaste
2348263363Semaste		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
2349263363Semaste		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
2350263363Semaste		cm->cm_flags &= ~MFI_CMD_MAPPED;
2351263363Semaste	}
2352263363Semaste
2353263363Semaste	cm->cm_flags |= MFI_CMD_COMPLETED;
2354263363Semaste
2355263363Semaste	if (cm->cm_complete != NULL)
2356263363Semaste		cm->cm_complete(cm);
2357263363Semaste	else
2358263363Semaste		wakeup(cm);
2359263363Semaste}
2360263363Semaste
2361263363Semastestatic int
2362263363Semastemfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort)
2363263363Semaste{
2364263363Semaste	struct mfi_command *cm;
2365263363Semaste	struct mfi_abort_frame *abort;
2366263363Semaste	int i = 0;
2367263363Semaste	uint32_t context = 0;
2368263363Semaste
2369263363Semaste	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2370263363Semaste
2371263363Semaste	if ((cm = mfi_dequeue_free(sc)) == NULL) {
2372263363Semaste		return (EBUSY);
2373263363Semaste	}
2374263363Semaste
2375263363Semaste	/* Zero out the MFI frame */
2376263363Semaste	context = cm->cm_frame->header.context;
2377263363Semaste	bzero(cm->cm_frame, sizeof(union mfi_frame));
2378263363Semaste	cm->cm_frame->header.context = context;
2379263363Semaste
2380263363Semaste	abort = &cm->cm_frame->abort;
2381263363Semaste	abort->header.cmd = MFI_CMD_ABORT;
2382263363Semaste	abort->header.flags = 0;
2383263363Semaste	abort->header.scsi_status = 0;
2384263363Semaste	abort->abort_context = cm_abort->cm_frame->header.context;
2385263363Semaste	abort->abort_mfi_addr_lo = (uint32_t)cm_abort->cm_frame_busaddr;
2386263363Semaste	abort->abort_mfi_addr_hi =
2387263363Semaste	    (uint32_t)((uint64_t)cm_abort->cm_frame_busaddr >> 32);
2388263363Semaste	cm->cm_data = NULL;
2389263363Semaste	cm->cm_flags = MFI_CMD_POLLED;
2390263363Semaste
2391263363Semaste	if (sc->mfi_aen_cm)
2392263363Semaste		sc->cm_aen_abort = 1;
2393263363Semaste	if (sc->mfi_map_sync_cm)
2394263363Semaste		sc->cm_map_abort = 1;
2395263363Semaste	mfi_mapcmd(sc, cm);
2396263363Semaste	mfi_release_command(cm);
2397263363Semaste
2398263363Semaste	while (i < 5 && sc->mfi_aen_cm != NULL) {
2399269024Semaste		msleep(&sc->mfi_aen_cm, &sc->mfi_io_lock, 0, "mfiabort",
2400269024Semaste		    5 * hz);
2401263363Semaste		i++;
2402263363Semaste	}
2403263363Semaste	while (i < 5 && sc->mfi_map_sync_cm != NULL) {
2404263363Semaste		msleep(&sc->mfi_map_sync_cm, &sc->mfi_io_lock, 0, "mfiabort",
2405263363Semaste		    5 * hz);
2406263363Semaste		i++;
2407263363Semaste	}
2408263363Semaste
2409263363Semaste	return (0);
2410263363Semaste}
2411263363Semaste
2412263363Semasteint
2413263363Semastemfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt,
2414263363Semaste     int len)
2415263363Semaste{
2416263363Semaste	struct mfi_command *cm;
2417263363Semaste	struct mfi_io_frame *io;
2418263363Semaste	int error;
2419263363Semaste	uint32_t context = 0;
2420263363Semaste
2421263363Semaste	if ((cm = mfi_dequeue_free(sc)) == NULL)
2422263363Semaste		return (EBUSY);
2423263363Semaste
2424263363Semaste	/* Zero out the MFI frame */
2425263363Semaste	context = cm->cm_frame->header.context;
2426263363Semaste	bzero(cm->cm_frame, sizeof(union mfi_frame));
2427263363Semaste	cm->cm_frame->header.context = context;
2428263363Semaste
2429263363Semaste	io = &cm->cm_frame->io;
2430263363Semaste	io->header.cmd = MFI_CMD_LD_WRITE;
2431263363Semaste	io->header.target_id = id;
2432263363Semaste	io->header.timeout = 0;
2433263363Semaste	io->header.flags = 0;
2434263363Semaste	io->header.scsi_status = 0;
2435263363Semaste	io->header.sense_len = MFI_SENSE_LEN;
2436263363Semaste	io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2437263363Semaste	io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2438263363Semaste	io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2439263363Semaste	io->lba_hi = (lba & 0xffffffff00000000) >> 32;
2440263363Semaste	io->lba_lo = lba & 0xffffffff;
2441263363Semaste	cm->cm_data = virt;
2442263363Semaste	cm->cm_len = len;
2443263363Semaste	cm->cm_sg = &io->sgl;
2444263363Semaste	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
2445263363Semaste	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT;
2446263363Semaste
2447263363Semaste	error = mfi_mapcmd(sc, cm);
2448263363Semaste	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
2449263363Semaste	    BUS_DMASYNC_POSTWRITE);
2450263363Semaste	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
2451263363Semaste	mfi_release_command(cm);
2452263363Semaste
2453263363Semaste	return (error);
2454263363Semaste}
2455263363Semaste
2456263363Semasteint
2457263363Semastemfi_dump_syspd_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt,
2458263363Semaste    int len)
2459263363Semaste{
2460263363Semaste	struct mfi_command *cm;
2461263363Semaste	struct mfi_pass_frame *pass;
2462263363Semaste	int error;
2463263363Semaste	int blkcount = 0;
2464263363Semaste
2465263363Semaste	if ((cm = mfi_dequeue_free(sc)) == NULL)
2466263363Semaste		return (EBUSY);
2467263363Semaste
2468263363Semaste	pass = &cm->cm_frame->pass;
2469263363Semaste	bzero(pass->cdb, 16);
2470263363Semaste	pass->header.cmd = MFI_CMD_PD_SCSI_IO;
2471263363Semaste	pass->cdb[0] = SCSI_WRITE;
2472263363Semaste	pass->cdb[2] = (lba & 0xff000000) >> 24;
2473263363Semaste	pass->cdb[3] = (lba & 0x00ff0000) >> 16;
2474263363Semaste	pass->cdb[4] = (lba & 0x0000ff00) >> 8;
2475263363Semaste	pass->cdb[5] = (lba & 0x000000ff);
2476263363Semaste	blkcount = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
2477263363Semaste	pass->cdb[7] = (blkcount & 0xff00) >> 8;
2478269024Semaste	pass->cdb[8] = (blkcount & 0x00ff);
2479269024Semaste	pass->header.target_id = id;
2480269024Semaste	pass->header.timeout = 0;
2481269024Semaste	pass->header.flags = 0;
2482269024Semaste	pass->header.scsi_status = 0;
2483269024Semaste	pass->header.sense_len = MFI_SENSE_LEN;
2484269024Semaste	pass->header.data_len = len;
2485269024Semaste	pass->header.cdb_len = 10;
2486269024Semaste	pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2487269024Semaste	pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
2488269024Semaste	cm->cm_data = virt;
2489269024Semaste	cm->cm_len = len;
2490263363Semaste	cm->cm_sg = &pass->sgl;
2491263363Semaste	cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
2492263363Semaste	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT;
2493263363Semaste
2494263363Semaste	error = mfi_mapcmd(sc, cm);
2495263363Semaste	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
2496263363Semaste	    BUS_DMASYNC_POSTWRITE);
2497263363Semaste	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
2498263363Semaste	mfi_release_command(cm);
2499263363Semaste
2500263363Semaste	return (error);
2501263363Semaste}
2502263363Semaste
2503263363Semastestatic int
2504263363Semastemfi_open(struct cdev *dev, int flags, int fmt, struct thread *td)
2505263363Semaste{
2506263363Semaste	struct mfi_softc *sc;
2507263363Semaste	int error;
2508263363Semaste
2509263363Semaste	sc = dev->si_drv1;
2510263363Semaste
2511263363Semaste	mtx_lock(&sc->mfi_io_lock);
2512263363Semaste	if (sc->mfi_detaching)
2513263363Semaste		error = ENXIO;
2514263363Semaste	else {
2515263363Semaste		sc->mfi_flags |= MFI_FLAGS_OPEN;
2516263363Semaste		error = 0;
2517263363Semaste	}
2518263363Semaste	mtx_unlock(&sc->mfi_io_lock);
2519263363Semaste
2520263363Semaste	return (error);
2521263363Semaste}
2522263363Semaste
2523263363Semastestatic int
2524263363Semastemfi_close(struct cdev *dev, int flags, int fmt, struct thread *td)
2525263363Semaste{
2526263363Semaste	struct mfi_softc *sc;
2527263363Semaste	struct mfi_aen *mfi_aen_entry, *tmp;
2528263363Semaste
2529263363Semaste	sc = dev->si_drv1;
2530263363Semaste
2531263363Semaste	mtx_lock(&sc->mfi_io_lock);
2532263363Semaste	sc->mfi_flags &= ~MFI_FLAGS_OPEN;
2533263363Semaste
2534263363Semaste	TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
2535263363Semaste		if (mfi_aen_entry->p == curproc) {
2536263363Semaste			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
2537263363Semaste			    aen_link);
2538263363Semaste			free(mfi_aen_entry, M_MFIBUF);
2539263363Semaste		}
2540263363Semaste	}
2541263363Semaste	mtx_unlock(&sc->mfi_io_lock);
2542263363Semaste	return (0);
2543263363Semaste}
2544263363Semaste
2545263363Semastestatic int
2546263363Semastemfi_config_lock(struct mfi_softc *sc, uint32_t opcode)
2547263363Semaste{
2548263363Semaste
2549263363Semaste	switch (opcode) {
2550263363Semaste	case MFI_DCMD_LD_DELETE:
2551263363Semaste	case MFI_DCMD_CFG_ADD:
2552263363Semaste	case MFI_DCMD_CFG_CLEAR:
2553263363Semaste	case MFI_DCMD_CFG_FOREIGN_IMPORT:
2554263363Semaste		sx_xlock(&sc->mfi_config_lock);
2555263363Semaste		return (1);
2556263363Semaste	default:
2557263363Semaste		return (0);
2558263363Semaste	}
2559263363Semaste}
2560263363Semaste
2561263363Semastestatic void
2562263363Semastemfi_config_unlock(struct mfi_softc *sc, int locked)
2563263363Semaste{
2564263363Semaste
2565263363Semaste	if (locked)
2566263363Semaste		sx_xunlock(&sc->mfi_config_lock);
2567263363Semaste}
2568263363Semaste
2569263363Semaste/*
2570263363Semaste * Perform pre-issue checks on commands from userland and possibly veto
2571263363Semaste * them.
2572263363Semaste */
2573263363Semastestatic int
2574263363Semastemfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm)
2575263363Semaste{
2576263363Semaste	struct mfi_disk *ld, *ld2;
2577263363Semaste	int error;
2578263363Semaste	struct mfi_system_pd *syspd = NULL;
2579263363Semaste	uint16_t syspd_id;
2580263363Semaste	uint16_t *mbox;
2581263363Semaste
2582263363Semaste	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2583263363Semaste	error = 0;
2584263363Semaste	switch (cm->cm_frame->dcmd.opcode) {
2585263363Semaste	case MFI_DCMD_LD_DELETE:
2586263363Semaste		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
2587263363Semaste			if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
2588263363Semaste				break;
2589263363Semaste		}
2590263363Semaste		if (ld == NULL)
2591263363Semaste			error = ENOENT;
2592263363Semaste		else
2593263363Semaste			error = mfi_disk_disable(ld);
2594263363Semaste		break;
2595263363Semaste	case MFI_DCMD_CFG_CLEAR:
2596263363Semaste		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
2597263363Semaste			error = mfi_disk_disable(ld);
2598263363Semaste			if (error)
2599263363Semaste				break;
2600263363Semaste		}
2601263363Semaste		if (error) {
2602263363Semaste			TAILQ_FOREACH(ld2, &sc->mfi_ld_tqh, ld_link) {
2603263363Semaste				if (ld2 == ld)
2604263363Semaste					break;
2605263363Semaste				mfi_disk_enable(ld2);
2606263363Semaste			}
2607263363Semaste		}
2608263363Semaste		break;
2609263363Semaste	case MFI_DCMD_PD_STATE_SET:
2610263363Semaste		mbox = (uint16_t *) cm->cm_frame->dcmd.mbox;
2611263363Semaste		syspd_id = mbox[0];
2612263363Semaste		if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) {
2613263363Semaste			TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) {
2614263363Semaste				if (syspd->pd_id == syspd_id)
2615263363Semaste					break;
2616263363Semaste			}
2617263363Semaste		}
2618263363Semaste		else
2619263363Semaste			break;
2620263363Semaste		if (syspd)
2621263363Semaste			error = mfi_syspd_disable(syspd);
2622263363Semaste		break;
2623263363Semaste	default:
2624263363Semaste		break;
2625263363Semaste	}
2626263363Semaste	return (error);
2627263363Semaste}
2628263363Semaste
2629263363Semaste/* Perform post-issue checks on commands from userland. */
2630263363Semastestatic void
2631263363Semastemfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm)
2632263363Semaste{
2633263363Semaste	struct mfi_disk *ld, *ldn;
2634269024Semaste	struct mfi_system_pd *syspd = NULL;
2635269024Semaste	uint16_t syspd_id;
2636263363Semaste	uint16_t *mbox;
2637263363Semaste
2638263363Semaste	switch (cm->cm_frame->dcmd.opcode) {
2639263363Semaste	case MFI_DCMD_LD_DELETE:
2640263363Semaste		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
2641263363Semaste			if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
2642263363Semaste				break;
2643263363Semaste		}
2644263363Semaste		KASSERT(ld != NULL, ("volume dissappeared"));
2645263363Semaste		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
2646263363Semaste			mtx_unlock(&sc->mfi_io_lock);
2647263363Semaste			mtx_lock(&Giant);
2648263363Semaste			device_delete_child(sc->mfi_dev, ld->ld_dev);
2649263363Semaste			mtx_unlock(&Giant);
2650263363Semaste			mtx_lock(&sc->mfi_io_lock);
2651263363Semaste		} else
2652263363Semaste			mfi_disk_enable(ld);
2653263363Semaste		break;
2654263363Semaste	case MFI_DCMD_CFG_CLEAR:
2655263363Semaste		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
2656263363Semaste			mtx_unlock(&sc->mfi_io_lock);
2657263363Semaste			mtx_lock(&Giant);
2658263363Semaste			TAILQ_FOREACH_SAFE(ld, &sc->mfi_ld_tqh, ld_link, ldn) {
2659263363Semaste				device_delete_child(sc->mfi_dev, ld->ld_dev);
2660263363Semaste			}
2661263363Semaste			mtx_unlock(&Giant);
2662263363Semaste			mtx_lock(&sc->mfi_io_lock);
2663263363Semaste		} else {
2664263363Semaste			TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link)
2665263363Semaste				mfi_disk_enable(ld);
2666263363Semaste		}
2667263363Semaste		break;
2668263363Semaste	case MFI_DCMD_CFG_ADD:
2669263363Semaste		mfi_ldprobe(sc);
2670263363Semaste		break;
2671263363Semaste	case MFI_DCMD_CFG_FOREIGN_IMPORT:
2672263363Semaste		mfi_ldprobe(sc);
2673263363Semaste		break;
2674263363Semaste	case MFI_DCMD_PD_STATE_SET:
2675263363Semaste		mbox = (uint16_t *) cm->cm_frame->dcmd.mbox;
2676263363Semaste		syspd_id = mbox[0];
2677263363Semaste		if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) {
2678263363Semaste			TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) {
2679263363Semaste				if (syspd->pd_id == syspd_id)
2680263363Semaste					break;
2681263363Semaste			}
2682263363Semaste		}
2683263363Semaste		else
2684263363Semaste			break;
2685263363Semaste		/* If the transition fails then enable the syspd again */
2686263363Semaste		if (syspd && cm->cm_frame->header.cmd_status != MFI_STAT_OK)
2687263363Semaste			mfi_syspd_enable(syspd);
2688263363Semaste		break;
2689263363Semaste	}
2690263363Semaste}
2691263363Semaste
2692263363Semastestatic int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm)
2693263363Semaste{
2694263363Semaste	struct mfi_config_data *conf_data=(struct mfi_config_data *)cm->cm_data;
2695263363Semaste	struct mfi_command *ld_cm = NULL;
2696263363Semaste	struct mfi_ld_info *ld_info = NULL;
2697263363Semaste	int error = 0;
2698263363Semaste
2699263363Semaste	if ((cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) &&
2700263363Semaste	    (conf_data->ld[0].params.isSSCD == 1)) {
2701263363Semaste		error = 1;
2702263363Semaste	} else if (cm->cm_frame->dcmd.opcode == MFI_DCMD_LD_DELETE) {
2703263363Semaste		error = mfi_dcmd_command (sc, &ld_cm, MFI_DCMD_LD_GET_INFO,
2704263363Semaste		    (void **)&ld_info, sizeof(*ld_info));
2705263363Semaste		if (error) {
2706263363Semaste			device_printf(sc->mfi_dev, "Failed to allocate"
2707263363Semaste			    "MFI_DCMD_LD_GET_INFO %d", error);
2708263363Semaste			if (ld_info)
2709263363Semaste				free(ld_info, M_MFIBUF);
2710263363Semaste			return 0;
2711263363Semaste		}
2712263363Semaste		ld_cm->cm_flags = MFI_CMD_DATAIN;
2713263363Semaste		ld_cm->cm_frame->dcmd.mbox[0]= cm->cm_frame->dcmd.mbox[0];
2714263363Semaste		ld_cm->cm_frame->header.target_id = cm->cm_frame->dcmd.mbox[0];
2715263363Semaste		if (mfi_wait_command(sc, ld_cm) != 0) {
2716263363Semaste			device_printf(sc->mfi_dev, "failed to get log drv\n");
2717263363Semaste			mfi_release_command(ld_cm);
2718263363Semaste			free(ld_info, M_MFIBUF);
2719263363Semaste			return 0;
2720263363Semaste		}
2721263363Semaste
2722263363Semaste		if (ld_cm->cm_frame->header.cmd_status != MFI_STAT_OK) {
2723263363Semaste			free(ld_info, M_MFIBUF);
2724263363Semaste			mfi_release_command(ld_cm);
2725263363Semaste			return 0;
2726263363Semaste		}
2727263363Semaste		else
2728263363Semaste			ld_info = (struct mfi_ld_info *)ld_cm->cm_private;
2729263363Semaste
2730263363Semaste		if (ld_info->ld_config.params.isSSCD == 1)
2731263363Semaste			error = 1;
2732263363Semaste
2733263363Semaste		mfi_release_command(ld_cm);
2734263363Semaste		free(ld_info, M_MFIBUF);
2735263363Semaste
2736263363Semaste	}
2737263363Semaste	return error;
2738263363Semaste}
2739263363Semaste
2740263363Semastestatic int
2741263363Semastemfi_stp_cmd(struct mfi_softc *sc, struct mfi_command *cm,caddr_t arg)
2742263363Semaste{
2743263363Semaste	uint8_t i;
2744263363Semaste	struct mfi_ioc_packet *ioc;
2745263363Semaste	ioc = (struct mfi_ioc_packet *)arg;
2746263363Semaste	int sge_size, error;
2747263363Semaste	struct megasas_sge *kern_sge;
2748263363Semaste
2749263363Semaste	memset(sc->kbuff_arr, 0, sizeof(sc->kbuff_arr));
2750263363Semaste	kern_sge =(struct megasas_sge *) ((uintptr_t)cm->cm_frame + ioc->mfi_sgl_off);
2751263363Semaste	cm->cm_frame->header.sg_count = ioc->mfi_sge_count;
2752263363Semaste
2753263363Semaste	if (sizeof(bus_addr_t) == 8) {
2754263363Semaste		cm->cm_frame->header.flags |= MFI_FRAME_SGL64;
2755263363Semaste		cm->cm_extra_frames = 2;
2756263363Semaste		sge_size = sizeof(struct mfi_sg64);
2757263363Semaste	} else {
2758263363Semaste		cm->cm_extra_frames =  (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
2759263363Semaste		sge_size = sizeof(struct mfi_sg32);
2760263363Semaste	}
2761263363Semaste
2762263363Semaste	cm->cm_total_frame_size += (sge_size * ioc->mfi_sge_count);
2763263363Semaste	for (i = 0; i < ioc->mfi_sge_count; i++) {
2764263363Semaste			if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
2765263363Semaste			1, 0,			/* algnmnt, boundary */
2766263363Semaste			BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
2767263363Semaste			BUS_SPACE_MAXADDR,	/* highaddr */
2768263363Semaste			NULL, NULL,		/* filter, filterarg */
2769263363Semaste			ioc->mfi_sgl[i].iov_len,/* maxsize */
2770263363Semaste			2,			/* nsegments */
2771263363Semaste			ioc->mfi_sgl[i].iov_len,/* maxsegsize */
2772263363Semaste			BUS_DMA_ALLOCNOW,	/* flags */
2773263363Semaste			NULL, NULL,		/* lockfunc, lockarg */
2774263363Semaste			&sc->mfi_kbuff_arr_dmat[i])) {
2775263363Semaste			device_printf(sc->mfi_dev,
2776263363Semaste			    "Cannot allocate mfi_kbuff_arr_dmat tag\n");
2777263363Semaste			return (ENOMEM);
2778263363Semaste		}
2779263363Semaste
2780263363Semaste		if (bus_dmamem_alloc(sc->mfi_kbuff_arr_dmat[i],
2781263363Semaste		    (void **)&sc->kbuff_arr[i], BUS_DMA_NOWAIT,
2782263363Semaste		    &sc->mfi_kbuff_arr_dmamap[i])) {
2783263363Semaste			device_printf(sc->mfi_dev,
2784263363Semaste			    "Cannot allocate mfi_kbuff_arr_dmamap memory\n");
2785263363Semaste			return (ENOMEM);
2786263363Semaste		}
2787263363Semaste
2788263363Semaste		bus_dmamap_load(sc->mfi_kbuff_arr_dmat[i],
2789263363Semaste		    sc->mfi_kbuff_arr_dmamap[i], sc->kbuff_arr[i],
2790263363Semaste		    ioc->mfi_sgl[i].iov_len, mfi_addr_cb,
2791263363Semaste		    &sc->mfi_kbuff_arr_busaddr[i], 0);
2792263363Semaste
2793263363Semaste		if (!sc->kbuff_arr[i]) {
2794263363Semaste			device_printf(sc->mfi_dev,
2795263363Semaste			    "Could not allocate memory for kbuff_arr info\n");
2796263363Semaste			return -1;
2797263363Semaste		}
2798263363Semaste		kern_sge[i].phys_addr = sc->mfi_kbuff_arr_busaddr[i];
2799263363Semaste		kern_sge[i].length = ioc->mfi_sgl[i].iov_len;
2800263363Semaste
2801263363Semaste		if (sizeof(bus_addr_t) == 8) {
2802263363Semaste			cm->cm_frame->stp.sgl.sg64[i].addr =
2803263363Semaste			    kern_sge[i].phys_addr;
2804263363Semaste			cm->cm_frame->stp.sgl.sg64[i].len =
2805263363Semaste			    ioc->mfi_sgl[i].iov_len;
2806263363Semaste		} else {
2807263363Semaste			cm->cm_frame->stp.sgl.sg32[i].len =
2808263363Semaste			    kern_sge[i].phys_addr;
2809263363Semaste			cm->cm_frame->stp.sgl.sg32[i].len =
2810263363Semaste			    ioc->mfi_sgl[i].iov_len;
2811263363Semaste		}
2812263363Semaste
2813263363Semaste		error = copyin(ioc->mfi_sgl[i].iov_base,
2814263363Semaste		    sc->kbuff_arr[i],
2815263363Semaste		    ioc->mfi_sgl[i].iov_len);
2816263363Semaste		if (error != 0) {
2817263363Semaste			device_printf(sc->mfi_dev, "Copy in failed\n");
2818263363Semaste			return error;
2819263363Semaste		}
2820263363Semaste	}
2821263363Semaste
2822263363Semaste	cm->cm_flags |=MFI_CMD_MAPPED;
2823263363Semaste	return 0;
2824263363Semaste}
2825263363Semaste
2826263363Semastestatic int
2827263363Semastemfi_user_command(struct mfi_softc *sc, struct mfi_ioc_passthru *ioc)
2828263363Semaste{
2829263363Semaste	struct mfi_command *cm;
2830263363Semaste	struct mfi_dcmd_frame *dcmd;
2831263363Semaste	void *ioc_buf = NULL;
2832263363Semaste	uint32_t context;
2833263363Semaste	int error = 0, locked;
2834263363Semaste
2835263363Semaste
2836263363Semaste	if (ioc->buf_size > 0) {
2837263363Semaste		if (ioc->buf_size > 1024 * 1024)
2838263363Semaste			return (ENOMEM);
2839263363Semaste		ioc_buf = malloc(ioc->buf_size, M_MFIBUF, M_WAITOK);
2840263363Semaste		error = copyin(ioc->buf, ioc_buf, ioc->buf_size);
2841263363Semaste		if (error) {
2842263363Semaste			device_printf(sc->mfi_dev, "failed to copyin\n");
2843263363Semaste			free(ioc_buf, M_MFIBUF);
2844263363Semaste			return (error);
2845269024Semaste		}
2846269024Semaste	}
2847263363Semaste
2848263363Semaste	locked = mfi_config_lock(sc, ioc->ioc_frame.opcode);
2849263363Semaste
2850263363Semaste	mtx_lock(&sc->mfi_io_lock);
2851263363Semaste	while ((cm = mfi_dequeue_free(sc)) == NULL)
2852263363Semaste		msleep(mfi_user_command, &sc->mfi_io_lock, 0, "mfiioc", hz);
2853263363Semaste
2854263363Semaste	/* Save context for later */
2855263363Semaste	context = cm->cm_frame->header.context;
2856263363Semaste
2857263363Semaste	dcmd = &cm->cm_frame->dcmd;
2858263363Semaste	bcopy(&ioc->ioc_frame, dcmd, sizeof(struct mfi_dcmd_frame));
2859263363Semaste
2860263363Semaste	cm->cm_sg = &dcmd->sgl;
2861263363Semaste	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
2862263363Semaste	cm->cm_data = ioc_buf;
2863263363Semaste	cm->cm_len = ioc->buf_size;
2864263363Semaste
2865263363Semaste	/* restore context */
2866263363Semaste	cm->cm_frame->header.context = context;
2867263363Semaste
2868263363Semaste	/* Cheat since we don't know if we're writing or reading */
2869263363Semaste	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
2870263363Semaste
2871263363Semaste	error = mfi_check_command_pre(sc, cm);
2872263363Semaste	if (error)
2873263363Semaste		goto out;
2874263363Semaste
2875263363Semaste	error = mfi_wait_command(sc, cm);
2876263363Semaste	if (error) {
2877263363Semaste		device_printf(sc->mfi_dev, "ioctl failed %d\n", error);
2878263363Semaste		goto out;
2879263363Semaste	}
2880263363Semaste	bcopy(dcmd, &ioc->ioc_frame, sizeof(struct mfi_dcmd_frame));
2881263363Semaste	mfi_check_command_post(sc, cm);
2882263363Semasteout:
2883263363Semaste	mfi_release_command(cm);
2884263363Semaste	mtx_unlock(&sc->mfi_io_lock);
2885263363Semaste	mfi_config_unlock(sc, locked);
2886263363Semaste	if (ioc->buf_size > 0)
2887263363Semaste		error = copyout(ioc_buf, ioc->buf, ioc->buf_size);
2888263363Semaste	if (ioc_buf)
2889263363Semaste		free(ioc_buf, M_MFIBUF);
2890263363Semaste	return (error);
2891263363Semaste}
2892263363Semaste
2893263363Semaste#define	PTRIN(p)		((void *)(uintptr_t)(p))
2894263363Semaste
2895263363Semastestatic int
2896263363Semastemfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
2897263363Semaste{
2898263363Semaste	struct mfi_softc *sc;
2899263363Semaste	union mfi_statrequest *ms;
2900263363Semaste	struct mfi_ioc_packet *ioc;
2901263363Semaste#ifdef COMPAT_FREEBSD32
2902263363Semaste	struct mfi_ioc_packet32 *ioc32;
2903263363Semaste#endif
2904263363Semaste	struct mfi_ioc_aen *aen;
2905263363Semaste	struct mfi_command *cm = NULL;
2906263363Semaste	uint32_t context = 0;
2907263363Semaste	union mfi_sense_ptr sense_ptr;
2908263363Semaste	uint8_t *data = NULL, *temp, *addr, skip_pre_post = 0;
2909263363Semaste	size_t len;
2910263363Semaste	int i, res;
2911263363Semaste	struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg;
2912263363Semaste#ifdef COMPAT_FREEBSD32
2913263363Semaste	struct mfi_ioc_passthru32 *iop32 = (struct mfi_ioc_passthru32 *)arg;
2914263363Semaste	struct mfi_ioc_passthru iop_swab;
2915263363Semaste#endif
2916263363Semaste	int error, locked;
2917263363Semaste	union mfi_sgl *sgl;
2918263363Semaste	sc = dev->si_drv1;
2919263363Semaste	error = 0;
2920263363Semaste
2921263363Semaste	if (sc->adpreset)
2922263363Semaste		return EBUSY;
2923263363Semaste
2924263363Semaste	if (sc->hw_crit_error)
2925263363Semaste		return EBUSY;
2926263363Semaste
2927263363Semaste	if (sc->issuepend_done == 0)
2928263363Semaste		return EBUSY;
2929263363Semaste
2930263363Semaste	switch (cmd) {
2931263363Semaste	case MFIIO_STATS:
2932263363Semaste		ms = (union mfi_statrequest *)arg;
2933263363Semaste		switch (ms->ms_item) {
2934263363Semaste		case MFIQ_FREE:
2935263363Semaste		case MFIQ_BIO:
2936263363Semaste		case MFIQ_READY:
2937263363Semaste		case MFIQ_BUSY:
2938263363Semaste			bcopy(&sc->mfi_qstat[ms->ms_item], &ms->ms_qstat,
2939263363Semaste			    sizeof(struct mfi_qstat));
2940263363Semaste			break;
2941263363Semaste		default:
2942263363Semaste			error = ENOIOCTL;
2943263363Semaste			break;
2944263363Semaste		}
2945263363Semaste		break;
2946263363Semaste	case MFIIO_QUERY_DISK:
2947269024Semaste	{
2948269024Semaste		struct mfi_query_disk *qd;
2949263363Semaste		struct mfi_disk *ld;
2950263363Semaste
2951263363Semaste		qd = (struct mfi_query_disk *)arg;
2952263363Semaste		mtx_lock(&sc->mfi_io_lock);
2953263363Semaste		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
2954263363Semaste			if (ld->ld_id == qd->array_id)
2955263363Semaste				break;
2956263363Semaste		}
2957263363Semaste		if (ld == NULL) {
2958263363Semaste			qd->present = 0;
2959263363Semaste			mtx_unlock(&sc->mfi_io_lock);
2960263363Semaste			return (0);
2961263363Semaste		}
2962269024Semaste		qd->present = 1;
2963269024Semaste		if (ld->ld_flags & MFI_DISK_FLAGS_OPEN)
2964263363Semaste			qd->open = 1;
2965263363Semaste		bzero(qd->devname, SPECNAMELEN + 1);
2966263363Semaste		snprintf(qd->devname, SPECNAMELEN, "mfid%d", ld->ld_unit);
2967263363Semaste		mtx_unlock(&sc->mfi_io_lock);
2968263363Semaste		break;
2969263363Semaste	}
2970263363Semaste	case MFI_CMD:
2971263363Semaste#ifdef COMPAT_FREEBSD32
2972263363Semaste	case MFI_CMD32:
2973263363Semaste#endif
2974263363Semaste		{
2975263363Semaste		devclass_t devclass;
2976263363Semaste		ioc = (struct mfi_ioc_packet *)arg;
2977263363Semaste		int adapter;
2978263363Semaste
2979263363Semaste		adapter = ioc->mfi_adapter_no;
2980263363Semaste		if (device_get_unit(sc->mfi_dev) == 0 && adapter != 0) {
2981263363Semaste			devclass = devclass_find("mfi");
2982263363Semaste			sc = devclass_get_softc(devclass, adapter);
2983263363Semaste		}
2984263363Semaste		mtx_lock(&sc->mfi_io_lock);
2985263363Semaste		if ((cm = mfi_dequeue_free(sc)) == NULL) {
2986263363Semaste			mtx_unlock(&sc->mfi_io_lock);
2987263363Semaste			return (EBUSY);
2988263363Semaste		}
2989263363Semaste		mtx_unlock(&sc->mfi_io_lock);
2990263363Semaste		locked = 0;
2991263363Semaste
2992263363Semaste		/*
2993263363Semaste		 * save off original context since copying from user
2994263363Semaste		 * will clobber some data
2995263363Semaste		 */
2996263363Semaste		context = cm->cm_frame->header.context;
2997263363Semaste		cm->cm_frame->header.context = cm->cm_index;
2998263363Semaste
2999263363Semaste		bcopy(ioc->mfi_frame.raw, cm->cm_frame,
3000263363Semaste		    2 * MEGAMFI_FRAME_SIZE);
3001263363Semaste		cm->cm_total_frame_size = (sizeof(union mfi_sgl)
3002263363Semaste		    * ioc->mfi_sge_count) + ioc->mfi_sgl_off;
3003263363Semaste		cm->cm_frame->header.scsi_status = 0;
3004263363Semaste		cm->cm_frame->header.pad0 = 0;
3005263363Semaste		if (ioc->mfi_sge_count) {
3006263363Semaste			cm->cm_sg =
3007263363Semaste			    (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off];
3008263363Semaste		}
3009263363Semaste		sgl = cm->cm_sg;
3010263363Semaste		cm->cm_flags = 0;
3011263363Semaste		if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
3012263363Semaste			cm->cm_flags |= MFI_CMD_DATAIN;
3013263363Semaste		if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
3014263363Semaste			cm->cm_flags |= MFI_CMD_DATAOUT;
3015263363Semaste		/* Legacy app shim */
3016263363Semaste		if (cm->cm_flags == 0)
3017263363Semaste			cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
3018263363Semaste		cm->cm_len = cm->cm_frame->header.data_len;
3019263363Semaste		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
3020263363Semaste#ifdef COMPAT_FREEBSD32
3021263363Semaste			if (cmd == MFI_CMD) {
3022263363Semaste#endif
3023263363Semaste				/* Native */
3024263363Semaste				cm->cm_stp_len = ioc->mfi_sgl[0].iov_len;
3025263363Semaste#ifdef COMPAT_FREEBSD32
3026263363Semaste			} else {
3027263363Semaste				/* 32bit on 64bit */
3028263363Semaste				ioc32 = (struct mfi_ioc_packet32 *)ioc;
3029263363Semaste				cm->cm_stp_len = ioc32->mfi_sgl[0].iov_len;
3030263363Semaste			}
3031263363Semaste#endif
3032263363Semaste			cm->cm_len += cm->cm_stp_len;
3033263363Semaste		}
3034269024Semaste		if (cm->cm_len &&
3035269024Semaste		    (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
3036263363Semaste			cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
3037263363Semaste			    M_WAITOK | M_ZERO);
3038263363Semaste			if (cm->cm_data == NULL) {
3039263363Semaste				device_printf(sc->mfi_dev, "Malloc failed\n");
3040263363Semaste				goto out;
3041263363Semaste			}
3042263363Semaste		} else {
3043263363Semaste			cm->cm_data = 0;
3044263363Semaste		}
3045269024Semaste
3046269024Semaste		/* restore header context */
3047263363Semaste		cm->cm_frame->header.context = context;
3048263363Semaste
3049263363Semaste		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
3050263363Semaste			res = mfi_stp_cmd(sc, cm, arg);
3051263363Semaste			if (res != 0)
3052263363Semaste				goto out;
3053263363Semaste		} else {
3054263363Semaste			temp = data;
3055263363Semaste			if ((cm->cm_flags & MFI_CMD_DATAOUT) ||
3056263363Semaste			    (cm->cm_frame->header.cmd == MFI_CMD_STP)) {
3057263363Semaste				for (i = 0; i < ioc->mfi_sge_count; i++) {
3058263363Semaste#ifdef COMPAT_FREEBSD32
3059263363Semaste					if (cmd == MFI_CMD) {
3060263363Semaste#endif
3061263363Semaste						/* Native */
3062263363Semaste						addr = ioc->mfi_sgl[i].iov_base;
3063263363Semaste						len = ioc->mfi_sgl[i].iov_len;
3064263363Semaste#ifdef COMPAT_FREEBSD32
3065263363Semaste					} else {
3066263363Semaste						/* 32bit on 64bit */
3067263363Semaste						ioc32 = (struct mfi_ioc_packet32 *)ioc;
3068263363Semaste						addr = PTRIN(ioc32->mfi_sgl[i].iov_base);
3069263363Semaste						len = ioc32->mfi_sgl[i].iov_len;
3070263363Semaste					}
3071263363Semaste#endif
3072263363Semaste					error = copyin(addr, temp, len);
3073263363Semaste					if (error != 0) {
3074263363Semaste						device_printf(sc->mfi_dev,
3075263363Semaste						    "Copy in failed\n");
3076263363Semaste						goto out;
3077263363Semaste					}
3078263363Semaste					temp = &temp[len];
3079263363Semaste				}
3080263363Semaste			}
3081263363Semaste		}
3082263363Semaste
3083263363Semaste		if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
3084263363Semaste			locked = mfi_config_lock(sc,
3085263363Semaste			     cm->cm_frame->dcmd.opcode);
3086263363Semaste
3087263363Semaste		if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
3088263363Semaste			cm->cm_frame->pass.sense_addr_lo =
3089263363Semaste			    (uint32_t)cm->cm_sense_busaddr;
3090263363Semaste			cm->cm_frame->pass.sense_addr_hi =
3091263363Semaste			    (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
3092263363Semaste		}
3093263363Semaste		mtx_lock(&sc->mfi_io_lock);
3094263363Semaste		skip_pre_post = mfi_check_for_sscd (sc, cm);
3095263363Semaste		if (!skip_pre_post) {
3096263363Semaste			error = mfi_check_command_pre(sc, cm);
3097263363Semaste			if (error) {
3098263363Semaste				mtx_unlock(&sc->mfi_io_lock);
3099263363Semaste				goto out;
3100263363Semaste			}
3101263363Semaste		}
3102263363Semaste		if ((error = mfi_wait_command(sc, cm)) != 0) {
3103263363Semaste			device_printf(sc->mfi_dev,
3104263363Semaste			    "Controller polled failed\n");
3105263363Semaste			mtx_unlock(&sc->mfi_io_lock);
3106263363Semaste			goto out;
3107263363Semaste		}
3108263363Semaste		if (!skip_pre_post) {
3109263363Semaste			mfi_check_command_post(sc, cm);
3110263363Semaste		}
3111263363Semaste		mtx_unlock(&sc->mfi_io_lock);
3112263363Semaste
3113263363Semaste		if (cm->cm_frame->header.cmd != MFI_CMD_STP) {
3114263363Semaste			temp = data;
3115263363Semaste			if ((cm->cm_flags & MFI_CMD_DATAIN) ||
3116263363Semaste			    (cm->cm_frame->header.cmd == MFI_CMD_STP)) {
3117263363Semaste				for (i = 0; i < ioc->mfi_sge_count; i++) {
3118263363Semaste#ifdef COMPAT_FREEBSD32
3119263363Semaste					if (cmd == MFI_CMD) {
3120263363Semaste#endif
3121263363Semaste						/* Native */
3122263363Semaste						addr = ioc->mfi_sgl[i].iov_base;
3123263363Semaste						len = ioc->mfi_sgl[i].iov_len;
3124263363Semaste#ifdef COMPAT_FREEBSD32
3125263363Semaste					} else {
3126263363Semaste						/* 32bit on 64bit */
3127263363Semaste						ioc32 = (struct mfi_ioc_packet32 *)ioc;
3128263363Semaste						addr = PTRIN(ioc32->mfi_sgl[i].iov_base);
3129263363Semaste						len = ioc32->mfi_sgl[i].iov_len;
3130263363Semaste					}
3131263363Semaste#endif
3132263363Semaste					error = copyout(temp, addr, len);
3133263363Semaste					if (error != 0) {
3134263363Semaste						device_printf(sc->mfi_dev,
3135263363Semaste						    "Copy out failed\n");
3136263363Semaste						goto out;
3137263363Semaste					}
3138263363Semaste					temp = &temp[len];
3139263363Semaste				}
3140263363Semaste			}
3141263363Semaste		}
3142263363Semaste
3143263363Semaste		if (ioc->mfi_sense_len) {
3144263363Semaste			/* get user-space sense ptr then copy out sense */
3145263363Semaste			bcopy(&ioc->mfi_frame.raw[ioc->mfi_sense_off],
3146263363Semaste			    &sense_ptr.sense_ptr_data[0],
3147263363Semaste			    sizeof(sense_ptr.sense_ptr_data));
3148263363Semaste#ifdef COMPAT_FREEBSD32
3149263363Semaste			if (cmd != MFI_CMD) {
3150263363Semaste				/*
3151263363Semaste				 * not 64bit native so zero out any address
3152263363Semaste				 * over 32bit */
3153263363Semaste				sense_ptr.addr.high = 0;
3154263363Semaste			}
3155263363Semaste#endif
3156263363Semaste			error = copyout(cm->cm_sense, sense_ptr.user_space,
3157263363Semaste			    ioc->mfi_sense_len);
3158263363Semaste			if (error != 0) {
3159263363Semaste				device_printf(sc->mfi_dev,
3160263363Semaste				    "Copy out failed\n");
3161269024Semaste				goto out;
3162269024Semaste			}
3163269024Semaste		}
3164263363Semaste
3165269024Semaste		ioc->mfi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status;
3166263363Semasteout:
3167263363Semaste		mfi_config_unlock(sc, locked);
3168263363Semaste		if (data)
3169263363Semaste			free(data, M_MFIBUF);
3170263363Semaste		if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
3171263363Semaste			for (i = 0; i < 2; i++) {
3172263363Semaste				if (sc->kbuff_arr[i]) {
3173263363Semaste					if (sc->mfi_kbuff_arr_busaddr != 0)
3174263363Semaste						bus_dmamap_unload(
3175263363Semaste						    sc->mfi_kbuff_arr_dmat[i],
3176263363Semaste						    sc->mfi_kbuff_arr_dmamap[i]
3177263363Semaste						    );
3178263363Semaste					if (sc->kbuff_arr[i] != NULL)
3179263363Semaste						bus_dmamem_free(
3180263363Semaste						    sc->mfi_kbuff_arr_dmat[i],
3181263363Semaste						    sc->kbuff_arr[i],
3182263363Semaste						    sc->mfi_kbuff_arr_dmamap[i]
3183269024Semaste						    );
3184269024Semaste					if (sc->mfi_kbuff_arr_dmat[i] != NULL)
3185263363Semaste						bus_dma_tag_destroy(
3186263363Semaste						    sc->mfi_kbuff_arr_dmat[i]);
3187263363Semaste				}
3188263363Semaste			}
3189263363Semaste		}
3190263363Semaste		if (cm) {
3191263363Semaste			mtx_lock(&sc->mfi_io_lock);
3192263363Semaste			mfi_release_command(cm);
3193263363Semaste			mtx_unlock(&sc->mfi_io_lock);
3194263363Semaste		}
3195263363Semaste
3196263363Semaste		break;
3197263363Semaste		}
3198263363Semaste	case MFI_SET_AEN:
3199263363Semaste		aen = (struct mfi_ioc_aen *)arg;
3200263363Semaste		error = mfi_aen_register(sc, aen->aen_seq_num,
3201263363Semaste		    aen->aen_class_locale);
3202263363Semaste
3203269024Semaste		break;
3204269024Semaste	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
3205263363Semaste		{
3206263363Semaste			devclass_t devclass;
3207263363Semaste			struct mfi_linux_ioc_packet l_ioc;
3208263363Semaste			int adapter;
3209263363Semaste
3210263363Semaste			devclass = devclass_find("mfi");
3211263363Semaste			if (devclass == NULL)
3212263363Semaste				return (ENOENT);
3213263363Semaste
3214263363Semaste			error = copyin(arg, &l_ioc, sizeof(l_ioc));
3215263363Semaste			if (error)
3216263363Semaste				return (error);
3217263363Semaste			adapter = l_ioc.lioc_adapter_no;
3218263363Semaste			sc = devclass_get_softc(devclass, adapter);
3219269024Semaste			if (sc == NULL)
3220269024Semaste				return (ENOENT);
3221263363Semaste			return (mfi_linux_ioctl_int(sc->mfi_cdev,
3222263363Semaste			    cmd, arg, flag, td));
3223263363Semaste			break;
3224263363Semaste		}
3225263363Semaste	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
3226263363Semaste		{
3227263363Semaste			devclass_t devclass;
3228263363Semaste			struct mfi_linux_ioc_aen l_aen;
3229263363Semaste			int adapter;
3230263363Semaste
3231263363Semaste			devclass = devclass_find("mfi");
3232263363Semaste			if (devclass == NULL)
3233263363Semaste				return (ENOENT);
3234269024Semaste
3235269024Semaste			error = copyin(arg, &l_aen, sizeof(l_aen));
3236263363Semaste			if (error)
3237263363Semaste				return (error);
3238263363Semaste			adapter = l_aen.laen_adapter_no;
3239263363Semaste			sc = devclass_get_softc(devclass, adapter);
3240263363Semaste			if (sc == NULL)
3241263363Semaste				return (ENOENT);
3242263363Semaste			return (mfi_linux_ioctl_int(sc->mfi_cdev,
3243263363Semaste			    cmd, arg, flag, td));
3244263363Semaste			break;
3245263363Semaste		}
3246263363Semaste#ifdef COMPAT_FREEBSD32
3247263363Semaste	case MFIIO_PASSTHRU32:
3248263363Semaste		if (!SV_CURPROC_FLAG(SV_ILP32)) {
3249263363Semaste			error = ENOTTY;
3250263363Semaste			break;
3251263363Semaste		}
3252269024Semaste		iop_swab.ioc_frame	= iop32->ioc_frame;
3253269024Semaste		iop_swab.buf_size	= iop32->buf_size;
3254263363Semaste		iop_swab.buf		= PTRIN(iop32->buf);
3255263363Semaste		iop			= &iop_swab;
3256263363Semaste		/* FALLTHROUGH */
3257263363Semaste#endif
3258263363Semaste	case MFIIO_PASSTHRU:
3259263363Semaste		error = mfi_user_command(sc, iop);
3260263363Semaste#ifdef COMPAT_FREEBSD32
3261263363Semaste		if (cmd == MFIIO_PASSTHRU32)
3262263363Semaste			iop32->ioc_frame = iop_swab.ioc_frame;
3263263363Semaste#endif
3264263363Semaste		break;
3265263363Semaste	default:
3266263363Semaste		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
3267263363Semaste		error = ENOTTY;
3268263363Semaste		break;
3269263363Semaste	}
3270263363Semaste
3271263363Semaste	return (error);
3272263363Semaste}
3273263363Semaste
3274263363Semastestatic int
3275263363Semastemfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
3276263363Semaste{
3277263363Semaste	struct mfi_softc *sc;
3278263363Semaste	struct mfi_linux_ioc_packet l_ioc;
3279263363Semaste	struct mfi_linux_ioc_aen l_aen;
3280263363Semaste	struct mfi_command *cm = NULL;
3281263363Semaste	struct mfi_aen *mfi_aen_entry;
3282263363Semaste	union mfi_sense_ptr sense_ptr;
3283263363Semaste	uint32_t context = 0;
3284263363Semaste	uint8_t *data = NULL, *temp;
3285263363Semaste	int i;
3286263363Semaste	int error, locked;
3287263363Semaste
3288263363Semaste	sc = dev->si_drv1;
3289263363Semaste	error = 0;
3290263363Semaste	switch (cmd) {
3291263363Semaste	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
3292263363Semaste		error = copyin(arg, &l_ioc, sizeof(l_ioc));
3293263363Semaste		if (error != 0)
3294263363Semaste			return (error);
3295263363Semaste
3296263363Semaste		if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) {
3297263363Semaste			return (EINVAL);
3298263363Semaste		}
3299263363Semaste
3300263363Semaste		mtx_lock(&sc->mfi_io_lock);
3301263363Semaste		if ((cm = mfi_dequeue_free(sc)) == NULL) {
3302263363Semaste			mtx_unlock(&sc->mfi_io_lock);
3303263363Semaste			return (EBUSY);
3304263363Semaste		}
3305263363Semaste		mtx_unlock(&sc->mfi_io_lock);
3306263363Semaste		locked = 0;
3307263363Semaste
3308263363Semaste		/*
3309263363Semaste		 * save off original context since copying from user
3310263363Semaste		 * will clobber some data
3311263363Semaste		 */
3312263363Semaste		context = cm->cm_frame->header.context;
3313263363Semaste
3314263363Semaste		bcopy(l_ioc.lioc_frame.raw, cm->cm_frame,
3315263363Semaste		      2 * MFI_DCMD_FRAME_SIZE);	/* this isn't quite right */
3316263363Semaste		cm->cm_total_frame_size = (sizeof(union mfi_sgl)
3317263363Semaste		      * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off;
3318263363Semaste		cm->cm_frame->header.scsi_status = 0;
3319263363Semaste		cm->cm_frame->header.pad0 = 0;
3320263363Semaste		if (l_ioc.lioc_sge_count)
3321263363Semaste			cm->cm_sg =
3322263363Semaste			    (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
3323263363Semaste		cm->cm_flags = 0;
3324263363Semaste		if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
3325263363Semaste			cm->cm_flags |= MFI_CMD_DATAIN;
3326263363Semaste		if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
3327263363Semaste			cm->cm_flags |= MFI_CMD_DATAOUT;
3328263363Semaste		cm->cm_len = cm->cm_frame->header.data_len;
3329263363Semaste		if (cm->cm_len &&
3330263363Semaste		      (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
3331263363Semaste			cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
3332263363Semaste			    M_WAITOK | M_ZERO);
3333263363Semaste			if (cm->cm_data == NULL) {
3334263363Semaste				device_printf(sc->mfi_dev, "Malloc failed\n");
3335263363Semaste				goto out;
3336263363Semaste			}
3337263363Semaste		} else {
3338263363Semaste			cm->cm_data = 0;
3339263363Semaste		}
3340263363Semaste
3341263363Semaste		/* restore header context */
3342263363Semaste		cm->cm_frame->header.context = context;
3343263363Semaste
3344263363Semaste		temp = data;
3345263363Semaste		if (cm->cm_flags & MFI_CMD_DATAOUT) {
3346263363Semaste			for (i = 0; i < l_ioc.lioc_sge_count; i++) {
3347263363Semaste				error = copyin(PTRIN(l_ioc.lioc_sgl[i].iov_base),
3348263363Semaste				       temp,
3349263363Semaste				       l_ioc.lioc_sgl[i].iov_len);
3350263363Semaste				if (error != 0) {
3351263363Semaste					device_printf(sc->mfi_dev,
3352263363Semaste					    "Copy in failed\n");
3353263363Semaste					goto out;
3354263363Semaste				}
3355263363Semaste				temp = &temp[l_ioc.lioc_sgl[i].iov_len];
3356263363Semaste			}
3357263363Semaste		}
3358263363Semaste
3359263363Semaste		if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
3360263363Semaste			locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
3361263363Semaste
3362263363Semaste		if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
3363263363Semaste			cm->cm_frame->pass.sense_addr_lo =
3364263363Semaste			    (uint32_t)cm->cm_sense_busaddr;
3365263363Semaste			cm->cm_frame->pass.sense_addr_hi =
3366263363Semaste			    (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
3367263363Semaste		}
3368263363Semaste
3369263363Semaste		mtx_lock(&sc->mfi_io_lock);
3370263363Semaste		error = mfi_check_command_pre(sc, cm);
3371263363Semaste		if (error) {
3372263363Semaste			mtx_unlock(&sc->mfi_io_lock);
3373263363Semaste			goto out;
3374263363Semaste		}
3375263363Semaste
3376263363Semaste		if ((error = mfi_wait_command(sc, cm)) != 0) {
3377263363Semaste			device_printf(sc->mfi_dev,
3378263363Semaste			    "Controller polled failed\n");
3379263363Semaste			mtx_unlock(&sc->mfi_io_lock);
3380263363Semaste			goto out;
3381263363Semaste		}
3382263363Semaste
3383263363Semaste		mfi_check_command_post(sc, cm);
3384263363Semaste		mtx_unlock(&sc->mfi_io_lock);
3385263363Semaste
3386263363Semaste		temp = data;
3387263363Semaste		if (cm->cm_flags & MFI_CMD_DATAIN) {
3388263363Semaste			for (i = 0; i < l_ioc.lioc_sge_count; i++) {
3389263363Semaste				error = copyout(temp,
3390263363Semaste					PTRIN(l_ioc.lioc_sgl[i].iov_base),
3391263363Semaste					l_ioc.lioc_sgl[i].iov_len);
3392263363Semaste				if (error != 0) {
3393263363Semaste					device_printf(sc->mfi_dev,
3394263363Semaste					    "Copy out failed\n");
3395263363Semaste					goto out;
3396263363Semaste				}
3397263363Semaste				temp = &temp[l_ioc.lioc_sgl[i].iov_len];
3398263363Semaste			}
3399263363Semaste		}
3400263363Semaste
3401263363Semaste		if (l_ioc.lioc_sense_len) {
3402263363Semaste			/* get user-space sense ptr then copy out sense */
3403263363Semaste			bcopy(&((struct mfi_linux_ioc_packet*)arg)
3404269024Semaste                            ->lioc_frame.raw[l_ioc.lioc_sense_off],
3405269024Semaste			    &sense_ptr.sense_ptr_data[0],
3406263363Semaste			    sizeof(sense_ptr.sense_ptr_data));
3407263363Semaste#ifdef __amd64__
3408263363Semaste			/*
3409263363Semaste			 * only 32bit Linux support so zero out any
3410263363Semaste			 * address over 32bit
3411263363Semaste			 */
3412263363Semaste			sense_ptr.addr.high = 0;
3413263363Semaste#endif
3414263363Semaste			error = copyout(cm->cm_sense, sense_ptr.user_space,
3415263363Semaste			    l_ioc.lioc_sense_len);
3416263363Semaste			if (error != 0) {
3417263363Semaste				device_printf(sc->mfi_dev,
3418263363Semaste				    "Copy out failed\n");
3419263363Semaste				goto out;
3420263363Semaste			}
3421263363Semaste		}
3422263363Semaste
3423263363Semaste		error = copyout(&cm->cm_frame->header.cmd_status,
3424263363Semaste			&((struct mfi_linux_ioc_packet*)arg)
3425269024Semaste			->lioc_frame.hdr.cmd_status,
3426269024Semaste			1);
3427263363Semaste		if (error != 0) {
3428263363Semaste			device_printf(sc->mfi_dev,
3429263363Semaste				      "Copy out failed\n");
3430263363Semaste			goto out;
3431263363Semaste		}
3432263363Semaste
3433263363Semasteout:
3434263363Semaste		mfi_config_unlock(sc, locked);
3435263363Semaste		if (data)
3436263363Semaste			free(data, M_MFIBUF);
3437263363Semaste		if (cm) {
3438263363Semaste			mtx_lock(&sc->mfi_io_lock);
3439263363Semaste			mfi_release_command(cm);
3440263363Semaste			mtx_unlock(&sc->mfi_io_lock);
3441263363Semaste		}
3442263363Semaste
3443263363Semaste		return (error);
3444263363Semaste	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
3445263363Semaste		error = copyin(arg, &l_aen, sizeof(l_aen));
3446263363Semaste		if (error != 0)
3447263363Semaste			return (error);
3448263363Semaste		printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid);
3449263363Semaste		mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF,
3450263363Semaste		    M_WAITOK);
3451263363Semaste		mtx_lock(&sc->mfi_io_lock);
3452263363Semaste		if (mfi_aen_entry != NULL) {
3453263363Semaste			mfi_aen_entry->p = curproc;
3454263363Semaste			TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry,
3455263363Semaste			    aen_link);
3456263363Semaste		}
3457263363Semaste		error = mfi_aen_register(sc, l_aen.laen_seq_num,
3458263363Semaste		    l_aen.laen_class_locale);
3459263363Semaste
3460263363Semaste		if (error != 0) {
3461263363Semaste			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
3462263363Semaste			    aen_link);
3463263363Semaste			free(mfi_aen_entry, M_MFIBUF);
3464263363Semaste		}
3465263363Semaste		mtx_unlock(&sc->mfi_io_lock);
3466263363Semaste
3467263363Semaste		return (error);
3468263363Semaste	default:
3469263363Semaste		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
3470263363Semaste		error = ENOENT;
3471263363Semaste		break;
3472263363Semaste	}
3473263363Semaste
3474263363Semaste	return (error);
3475263363Semaste}
3476263363Semaste
3477263363Semastestatic int
3478263363Semastemfi_poll(struct cdev *dev, int poll_events, struct thread *td)
3479263363Semaste{
3480263363Semaste	struct mfi_softc *sc;
3481263363Semaste	int revents = 0;
3482263363Semaste
3483263363Semaste	sc = dev->si_drv1;
3484263363Semaste
3485263363Semaste	if (poll_events & (POLLIN | POLLRDNORM)) {
3486263363Semaste		if (sc->mfi_aen_triggered != 0) {
3487263363Semaste			revents |= poll_events & (POLLIN | POLLRDNORM);
3488263363Semaste			sc->mfi_aen_triggered = 0;
3489263363Semaste		}
3490263363Semaste		if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) {
3491263363Semaste			revents |= POLLERR;
3492263363Semaste		}
3493263363Semaste	}
3494263363Semaste
3495263363Semaste	if (revents == 0) {
3496263363Semaste		if (poll_events & (POLLIN | POLLRDNORM)) {
3497269024Semaste			sc->mfi_poll_waiting = 1;
3498269024Semaste			selrecord(td, &sc->mfi_select);
3499263363Semaste		}
3500263363Semaste	}
3501263363Semaste
3502263363Semaste	return revents;
3503263363Semaste}
3504263363Semaste
3505263363Semastestatic void
3506263363Semastemfi_dump_all(void)
3507263363Semaste{
3508263363Semaste	struct mfi_softc *sc;
3509263363Semaste	struct mfi_command *cm;
3510263363Semaste	devclass_t dc;
3511263363Semaste	time_t deadline;
3512263363Semaste	int timedout;
3513263363Semaste	int i;
3514263363Semaste
3515263363Semaste	dc = devclass_find("mfi");
3516263363Semaste	if (dc == NULL) {
3517263363Semaste		printf("No mfi dev class\n");
3518263363Semaste		return;
3519263363Semaste	}
3520263363Semaste
3521263363Semaste	for (i = 0; ; i++) {
3522263363Semaste		sc = devclass_get_softc(dc, i);
3523263363Semaste		if (sc == NULL)
3524263363Semaste			break;
3525263363Semaste		device_printf(sc->mfi_dev, "Dumping\n\n");
3526263363Semaste		timedout = 0;
3527263363Semaste		deadline = time_uptime - MFI_CMD_TIMEOUT;
3528263363Semaste		mtx_lock(&sc->mfi_io_lock);
3529263363Semaste		TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
3530263363Semaste			if (cm->cm_timestamp < deadline) {
3531263363Semaste				device_printf(sc->mfi_dev,
3532263363Semaste				    "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
3533263363Semaste				    cm, (int)(time_uptime - cm->cm_timestamp));
3534263363Semaste				MFI_PRINT_CMD(cm);
3535263363Semaste				timedout++;
3536263363Semaste			}
3537263363Semaste		}
3538263363Semaste
3539263363Semaste#if 0
3540263363Semaste		if (timedout)
3541263363Semaste			MFI_DUMP_CMDS(SC);
3542263363Semaste#endif
3543263363Semaste
3544263363Semaste		mtx_unlock(&sc->mfi_io_lock);
3545263363Semaste	}
3546263363Semaste
3547263363Semaste	return;
3548263363Semaste}
3549263363Semaste
3550263363Semastestatic void
3551263363Semastemfi_timeout(void *data)
3552263363Semaste{
3553263363Semaste	struct mfi_softc *sc = (struct mfi_softc *)data;
3554263363Semaste	struct mfi_command *cm;
3555263363Semaste	time_t deadline;
3556263363Semaste	int timedout = 0;
3557263363Semaste
3558263363Semaste	deadline = time_uptime - MFI_CMD_TIMEOUT;
3559263363Semaste	if (sc->adpreset == 0) {
3560263363Semaste		if (!mfi_tbolt_reset(sc)) {
3561263363Semaste			callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz, mfi_timeout, sc);
3562263363Semaste			return;
3563263363Semaste		}
3564263363Semaste	}
3565263363Semaste	mtx_lock(&sc->mfi_io_lock);
3566263363Semaste	TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
3567263363Semaste		if (sc->mfi_aen_cm == cm || sc->mfi_map_sync_cm == cm)
3568263363Semaste			continue;
3569263363Semaste		if (cm->cm_timestamp < deadline) {
3570269024Semaste			if (sc->adpreset != 0 && sc->issuepend_done == 0) {
3571269024Semaste				cm->cm_timestamp = time_uptime;
3572263363Semaste			} else {
3573263363Semaste				device_printf(sc->mfi_dev,
3574263363Semaste				    "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
3575263363Semaste				     cm, (int)(time_uptime - cm->cm_timestamp)
3576263363Semaste				     );
3577263363Semaste				MFI_PRINT_CMD(cm);
3578263363Semaste				MFI_VALIDATE_CMD(sc, cm);
3579263363Semaste				timedout++;
3580263363Semaste			}
3581263363Semaste		}
3582263363Semaste	}
3583263363Semaste
3584263363Semaste#if 0
3585263363Semaste	if (timedout)
3586263363Semaste		MFI_DUMP_CMDS(SC);
3587263363Semaste#endif
3588263363Semaste
3589263363Semaste	mtx_unlock(&sc->mfi_io_lock);
3590263363Semaste
3591263363Semaste	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
3592263363Semaste	    mfi_timeout, sc);
3593263363Semaste
3594263363Semaste	if (0)
3595263363Semaste		mfi_dump_all();
3596263363Semaste	return;
3597263363Semaste}
3598263363Semaste