mfi.c revision 163399
1157114Sscottl/*-
2157114Sscottl * Copyright (c) 2006 IronPort Systems
3157114Sscottl * All rights reserved.
4157114Sscottl *
5157114Sscottl * Redistribution and use in source and binary forms, with or without
6157114Sscottl * modification, are permitted provided that the following conditions
7157114Sscottl * are met:
8157114Sscottl * 1. Redistributions of source code must retain the above copyright
9157114Sscottl *    notice, this list of conditions and the following disclaimer.
10157114Sscottl * 2. Redistributions in binary form must reproduce the above copyright
11157114Sscottl *    notice, this list of conditions and the following disclaimer in the
12157114Sscottl *    documentation and/or other materials provided with the distribution.
13157114Sscottl *
14157114Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15157114Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16157114Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17157114Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18157114Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19157114Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20157114Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21157114Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22157114Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23157114Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24157114Sscottl * SUCH DAMAGE.
25157114Sscottl */
26157114Sscottl
27157114Sscottl#include <sys/cdefs.h>
28157114Sscottl__FBSDID("$FreeBSD: head/sys/dev/mfi/mfi.c 163399 2006-10-16 04:30:09Z scottl $");
29157114Sscottl
30157114Sscottl#include "opt_mfi.h"
31157114Sscottl
32157114Sscottl#include <sys/param.h>
33157114Sscottl#include <sys/systm.h>
34162118Sambrisko#include <sys/sysctl.h>
35157114Sscottl#include <sys/malloc.h>
36157114Sscottl#include <sys/kernel.h>
37158737Sambrisko#include <sys/poll.h>
38158737Sambrisko#include <sys/selinfo.h>
39157114Sscottl#include <sys/bus.h>
40157114Sscottl#include <sys/conf.h>
41157114Sscottl#include <sys/eventhandler.h>
42157114Sscottl#include <sys/rman.h>
43157114Sscottl#include <sys/bus_dma.h>
44157114Sscottl#include <sys/bio.h>
45157114Sscottl#include <sys/ioccom.h>
46158737Sambrisko#include <sys/uio.h>
47158737Sambrisko#include <sys/proc.h>
48163398Sscottl#include <sys/signalvar.h>
49157114Sscottl
50157114Sscottl#include <machine/bus.h>
51157114Sscottl#include <machine/resource.h>
52157114Sscottl
53157114Sscottl#include <dev/mfi/mfireg.h>
54157114Sscottl#include <dev/mfi/mfi_ioctl.h>
55157114Sscottl#include <dev/mfi/mfivar.h>
56157114Sscottl
57157114Sscottlstatic int	mfi_alloc_commands(struct mfi_softc *);
58157114Sscottlstatic void	mfi_release_command(struct mfi_command *cm);
59157114Sscottlstatic int	mfi_comms_init(struct mfi_softc *);
60157114Sscottlstatic int	mfi_polled_command(struct mfi_softc *, struct mfi_command *);
61159811Spsstatic int	mfi_wait_command(struct mfi_softc *, struct mfi_command *);
62157114Sscottlstatic int	mfi_get_controller_info(struct mfi_softc *);
63158737Sambriskostatic int	mfi_get_log_state(struct mfi_softc *,
64159806Sps		    struct mfi_evt_log_state **);
65158737Sambriskostatic int	mfi_get_entry(struct mfi_softc *, int);
66159806Spsstatic int	mfi_dcmd_command(struct mfi_softc *, struct mfi_command **,
67159806Sps		    uint32_t, void **, size_t);
68157114Sscottlstatic void	mfi_data_cb(void *, bus_dma_segment_t *, int, int);
69157114Sscottlstatic void	mfi_startup(void *arg);
70157114Sscottlstatic void	mfi_intr(void *arg);
71157114Sscottlstatic void	mfi_enable_intr(struct mfi_softc *sc);
72159811Spsstatic void	mfi_ldprobe(struct mfi_softc *sc);
73158737Sambriskostatic int	mfi_aen_register(struct mfi_softc *sc, int seq, int locale);
74158737Sambriskostatic void	mfi_aen_complete(struct mfi_command *);
75158737Sambriskostatic int	mfi_aen_setup(struct mfi_softc *, uint32_t);
76159811Spsstatic int	mfi_add_ld(struct mfi_softc *sc, int);
77159811Spsstatic void	mfi_add_ld_complete(struct mfi_command *);
78157114Sscottlstatic struct mfi_command * mfi_bio_command(struct mfi_softc *);
79157114Sscottlstatic void	mfi_bio_complete(struct mfi_command *);
80157114Sscottlstatic int	mfi_mapcmd(struct mfi_softc *, struct mfi_command *);
81157114Sscottlstatic int	mfi_send_frame(struct mfi_softc *, struct mfi_command *);
82157114Sscottlstatic void	mfi_complete(struct mfi_softc *, struct mfi_command *);
83158737Sambriskostatic int	mfi_abort(struct mfi_softc *, struct mfi_command *);
84158737Sambriskostatic int	mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int, d_thread_t *);
85162619Sscottlstatic void	mfi_timeout(void *);
86157114Sscottl
87162118Sambrisko
88162118SambriskoSYSCTL_NODE(_hw, OID_AUTO, mfi, CTLFLAG_RD, 0, "MFI driver parameters");
89162118Sambriskostatic int	mfi_event_locale = MFI_EVT_LOCALE_ALL;
90162473SambriskoTUNABLE_INT("hw.mfi.event_locale", &mfi_event_locale);
91162118SambriskoSYSCTL_INT(_hw_mfi, OID_AUTO, event_locale, CTLFLAG_RW, &mfi_event_locale,
92162118Sambrisko            0, "event message locale");
93162473Sambrisko
94162118Sambriskostatic int	mfi_event_class =  MFI_EVT_CLASS_DEBUG;
95162473SambriskoTUNABLE_INT("hw.mfi.event_class", &mfi_event_class);
96162118SambriskoSYSCTL_INT(_hw_mfi, OID_AUTO, event_class, CTLFLAG_RW, &mfi_event_class,
97162118Sambrisko          0, "event message class");
98162118Sambrisko
99157114Sscottl/* Management interface */
100157114Sscottlstatic d_open_t		mfi_open;
101157114Sscottlstatic d_close_t	mfi_close;
102157114Sscottlstatic d_ioctl_t	mfi_ioctl;
103158737Sambriskostatic d_poll_t		mfi_poll;
104157114Sscottl
105157114Sscottlstatic struct cdevsw mfi_cdevsw = {
106157114Sscottl	.d_version = 	D_VERSION,
107157114Sscottl	.d_flags =	0,
108157114Sscottl	.d_open = 	mfi_open,
109157114Sscottl	.d_close =	mfi_close,
110157114Sscottl	.d_ioctl =	mfi_ioctl,
111158737Sambrisko	.d_poll =	mfi_poll,
112157114Sscottl	.d_name =	"mfi",
113157114Sscottl};
114157114Sscottl
115157114SscottlMALLOC_DEFINE(M_MFIBUF, "mfibuf", "Buffers for the MFI driver");
116157114Sscottl
117158737Sambrisko#define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH
118157114Sscottl
119157114Sscottlstatic int
120157114Sscottlmfi_transition_firmware(struct mfi_softc *sc)
121157114Sscottl{
122157114Sscottl	int32_t fw_state, cur_state;
123157114Sscottl	int max_wait, i;
124157114Sscottl
125157114Sscottl	fw_state = MFI_READ4(sc, MFI_OMSG0) & MFI_FWSTATE_MASK;
126157114Sscottl	while (fw_state != MFI_FWSTATE_READY) {
127157114Sscottl		if (bootverbose)
128157114Sscottl			device_printf(sc->mfi_dev, "Waiting for firmware to "
129157114Sscottl			    "become ready\n");
130157114Sscottl		cur_state = fw_state;
131157114Sscottl		switch (fw_state) {
132157114Sscottl		case MFI_FWSTATE_FAULT:
133157114Sscottl			device_printf(sc->mfi_dev, "Firmware fault\n");
134157114Sscottl			return (ENXIO);
135157114Sscottl		case MFI_FWSTATE_WAIT_HANDSHAKE:
136157114Sscottl			MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
137157114Sscottl			max_wait = 2;
138157114Sscottl			break;
139157114Sscottl		case MFI_FWSTATE_OPERATIONAL:
140157114Sscottl			MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY);
141157114Sscottl			max_wait = 10;
142157114Sscottl			break;
143157114Sscottl		case MFI_FWSTATE_UNDEFINED:
144157114Sscottl		case MFI_FWSTATE_BB_INIT:
145157114Sscottl			max_wait = 2;
146157114Sscottl			break;
147157114Sscottl		case MFI_FWSTATE_FW_INIT:
148157114Sscottl		case MFI_FWSTATE_DEVICE_SCAN:
149157114Sscottl		case MFI_FWSTATE_FLUSH_CACHE:
150157114Sscottl			max_wait = 20;
151157114Sscottl			break;
152157114Sscottl		default:
153157114Sscottl			device_printf(sc->mfi_dev,"Unknown firmware state %d\n",
154157114Sscottl			    fw_state);
155157114Sscottl			return (ENXIO);
156157114Sscottl		}
157157114Sscottl		for (i = 0; i < (max_wait * 10); i++) {
158157114Sscottl			fw_state = MFI_READ4(sc, MFI_OMSG0) & MFI_FWSTATE_MASK;
159157114Sscottl			if (fw_state == cur_state)
160157114Sscottl				DELAY(100000);
161157114Sscottl			else
162157114Sscottl				break;
163157114Sscottl		}
164157114Sscottl		if (fw_state == cur_state) {
165157114Sscottl			device_printf(sc->mfi_dev, "firmware stuck in state "
166157114Sscottl			    "%#x\n", fw_state);
167157114Sscottl			return (ENXIO);
168157114Sscottl		}
169157114Sscottl	}
170157114Sscottl	return (0);
171157114Sscottl}
172157114Sscottl
173157114Sscottlstatic void
174157114Sscottlmfi_addr32_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
175157114Sscottl{
176157114Sscottl	uint32_t *addr;
177157114Sscottl
178157114Sscottl	addr = arg;
179157114Sscottl	*addr = segs[0].ds_addr;
180157114Sscottl}
181157114Sscottl
182157114Sscottlint
183157114Sscottlmfi_attach(struct mfi_softc *sc)
184157114Sscottl{
185157114Sscottl	uint32_t status;
186157114Sscottl	int error, commsz, framessz, sensesz;
187162458Sscottl	int frames, unit, max_fw_sge;
188157114Sscottl
189157114Sscottl	mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF);
190157114Sscottl	TAILQ_INIT(&sc->mfi_ld_tqh);
191158737Sambrisko	TAILQ_INIT(&sc->mfi_aen_pids);
192157114Sscottl
193157114Sscottl	mfi_initq_free(sc);
194157114Sscottl	mfi_initq_ready(sc);
195157114Sscottl	mfi_initq_busy(sc);
196157114Sscottl	mfi_initq_bio(sc);
197157114Sscottl
198157114Sscottl	/* Before we get too far, see if the firmware is working */
199157114Sscottl	if ((error = mfi_transition_firmware(sc)) != 0) {
200157114Sscottl		device_printf(sc->mfi_dev, "Firmware not in READY state, "
201157114Sscottl		    "error %d\n", error);
202157114Sscottl		return (ENXIO);
203157114Sscottl	}
204157114Sscottl
205157114Sscottl	/*
206157114Sscottl	 * Get information needed for sizing the contiguous memory for the
207157114Sscottl	 * frame pool.  Size down the sgl parameter since we know that
208157114Sscottl	 * we will never need more than what's required for MAXPHYS.
209157114Sscottl	 * It would be nice if these constants were available at runtime
210157114Sscottl	 * instead of compile time.
211157114Sscottl	 */
212157114Sscottl	status = MFI_READ4(sc, MFI_OMSG0);
213157114Sscottl	sc->mfi_max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK;
214162458Sscottl	max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16;
215162458Sscottl	sc->mfi_max_sge = min(max_fw_sge, ((MAXPHYS / PAGE_SIZE) + 1));
216157114Sscottl
217157114Sscottl	/*
218157114Sscottl	 * Create the dma tag for data buffers.  Used both for block I/O
219157114Sscottl	 * and for various internal data queries.
220157114Sscottl	 */
221157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
222157114Sscottl				1, 0,			/* algnmnt, boundary */
223157114Sscottl				BUS_SPACE_MAXADDR,	/* lowaddr */
224157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
225157114Sscottl				NULL, NULL,		/* filter, filterarg */
226157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
227162458Sscottl				sc->mfi_max_sge,	/* nsegments */
228157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
229157114Sscottl				BUS_DMA_ALLOCNOW,	/* flags */
230157114Sscottl				busdma_lock_mutex,	/* lockfunc */
231157114Sscottl				&sc->mfi_io_lock,	/* lockfuncarg */
232157114Sscottl				&sc->mfi_buffer_dmat)) {
233157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate buffer DMA tag\n");
234157114Sscottl		return (ENOMEM);
235157114Sscottl	}
236157114Sscottl
237157114Sscottl	/*
238157114Sscottl	 * Allocate DMA memory for the comms queues.  Keep it under 4GB for
239157114Sscottl	 * efficiency.  The mfi_hwcomms struct includes space for 1 reply queue
240157114Sscottl	 * entry, so the calculated size here will be will be 1 more than
241157114Sscottl	 * mfi_max_fw_cmds.  This is apparently a requirement of the hardware.
242157114Sscottl	 */
243157114Sscottl	commsz = (sizeof(uint32_t) * sc->mfi_max_fw_cmds) +
244157114Sscottl	    sizeof(struct mfi_hwcomms);
245157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
246157114Sscottl				1, 0,			/* algnmnt, boundary */
247157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
248157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
249157114Sscottl				NULL, NULL,		/* filter, filterarg */
250157114Sscottl				commsz,			/* maxsize */
251157114Sscottl				1,			/* msegments */
252157114Sscottl				commsz,			/* maxsegsize */
253157114Sscottl				0,			/* flags */
254157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
255157114Sscottl				&sc->mfi_comms_dmat)) {
256157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
257157114Sscottl		return (ENOMEM);
258157114Sscottl	}
259157114Sscottl	if (bus_dmamem_alloc(sc->mfi_comms_dmat, (void **)&sc->mfi_comms,
260157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_comms_dmamap)) {
261157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
262157114Sscottl		return (ENOMEM);
263157114Sscottl	}
264157114Sscottl	bzero(sc->mfi_comms, commsz);
265157114Sscottl	bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap,
266157114Sscottl	    sc->mfi_comms, commsz, mfi_addr32_cb, &sc->mfi_comms_busaddr, 0);
267157114Sscottl
268157114Sscottl	/*
269157114Sscottl	 * Allocate DMA memory for the command frames.  Keep them in the
270162458Sscottl	 * lower 4GB for efficiency.  Calculate the size of the commands at
271162458Sscottl	 * the same time; each command is one 64 byte frame plus a set of
272162458Sscottl         * additional frames for holding sg lists or other data.
273157114Sscottl	 * The assumption here is that the SG list will start at the second
274162458Sscottl	 * frame and not use the unused bytes in the first frame.  While this
275162458Sscottl	 * isn't technically correct, it simplifies the calculation and allows
276162458Sscottl	 * for command frames that might be larger than an mfi_io_frame.
277157114Sscottl	 */
278157114Sscottl	if (sizeof(bus_addr_t) == 8) {
279162458Sscottl		sc->mfi_sge_size = sizeof(struct mfi_sg64);
280157114Sscottl		sc->mfi_flags |= MFI_FLAGS_SG64;
281157114Sscottl	} else {
282162458Sscottl		sc->mfi_sge_size = sizeof(struct mfi_sg32);
283157114Sscottl	}
284162458Sscottl	frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2;
285162458Sscottl	sc->mfi_cmd_size = frames * MFI_FRAME_SIZE;
286162458Sscottl	framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds;
287157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
288157114Sscottl				64, 0,			/* algnmnt, boundary */
289157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
290157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
291157114Sscottl				NULL, NULL,		/* filter, filterarg */
292157114Sscottl				framessz,		/* maxsize */
293157114Sscottl				1,			/* nsegments */
294157114Sscottl				framessz,		/* maxsegsize */
295157114Sscottl				0,			/* flags */
296157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
297157114Sscottl				&sc->mfi_frames_dmat)) {
298157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frame DMA tag\n");
299157114Sscottl		return (ENOMEM);
300157114Sscottl	}
301157114Sscottl	if (bus_dmamem_alloc(sc->mfi_frames_dmat, (void **)&sc->mfi_frames,
302157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_frames_dmamap)) {
303157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frames memory\n");
304157114Sscottl		return (ENOMEM);
305157114Sscottl	}
306157114Sscottl	bzero(sc->mfi_frames, framessz);
307157114Sscottl	bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap,
308157114Sscottl	    sc->mfi_frames, framessz, mfi_addr32_cb, &sc->mfi_frames_busaddr,0);
309157114Sscottl
310157114Sscottl	/*
311157114Sscottl	 * Allocate DMA memory for the frame sense data.  Keep them in the
312157114Sscottl	 * lower 4GB for efficiency
313157114Sscottl	 */
314157114Sscottl	sensesz = sc->mfi_max_fw_cmds * MFI_SENSE_LEN;
315157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
316157114Sscottl				4, 0,			/* algnmnt, boundary */
317157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
318157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
319157114Sscottl				NULL, NULL,		/* filter, filterarg */
320157114Sscottl				sensesz,		/* maxsize */
321157114Sscottl				1,			/* nsegments */
322157114Sscottl				sensesz,		/* maxsegsize */
323157114Sscottl				0,			/* flags */
324157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
325157114Sscottl				&sc->mfi_sense_dmat)) {
326157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense DMA tag\n");
327157114Sscottl		return (ENOMEM);
328157114Sscottl	}
329157114Sscottl	if (bus_dmamem_alloc(sc->mfi_sense_dmat, (void **)&sc->mfi_sense,
330157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_sense_dmamap)) {
331157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense memory\n");
332157114Sscottl		return (ENOMEM);
333157114Sscottl	}
334157114Sscottl	bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap,
335157114Sscottl	    sc->mfi_sense, sensesz, mfi_addr32_cb, &sc->mfi_sense_busaddr, 0);
336157114Sscottl
337157114Sscottl	if ((error = mfi_alloc_commands(sc)) != 0)
338157114Sscottl		return (error);
339157114Sscottl
340157114Sscottl	if ((error = mfi_comms_init(sc)) != 0)
341157114Sscottl		return (error);
342157114Sscottl
343157114Sscottl	if ((error = mfi_get_controller_info(sc)) != 0)
344157114Sscottl		return (error);
345157114Sscottl
346163398Sscottl	mtx_lock(&sc->mfi_io_lock);
347163398Sscottl	if ((error = mfi_aen_setup(sc, 0), 0) != 0) {
348163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
349157114Sscottl		return (error);
350163398Sscottl	}
351163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
352157114Sscottl
353157114Sscottl	/*
354157114Sscottl	 * Set up the interrupt handler.  XXX This should happen in
355157114Sscottl	 * mfi_pci.c
356157114Sscottl	 */
357157114Sscottl	sc->mfi_irq_rid = 0;
358157114Sscottl	if ((sc->mfi_irq = bus_alloc_resource_any(sc->mfi_dev, SYS_RES_IRQ,
359157114Sscottl	    &sc->mfi_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
360157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate interrupt\n");
361157114Sscottl		return (EINVAL);
362157114Sscottl	}
363157114Sscottl	if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, INTR_MPSAFE|INTR_TYPE_BIO,
364157114Sscottl	    mfi_intr, sc, &sc->mfi_intr)) {
365157114Sscottl		device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
366157114Sscottl		return (EINVAL);
367157114Sscottl	}
368157114Sscottl
369157114Sscottl	/* Register a config hook to probe the bus for arrays */
370157114Sscottl	sc->mfi_ich.ich_func = mfi_startup;
371157114Sscottl	sc->mfi_ich.ich_arg = sc;
372157114Sscottl	if (config_intrhook_establish(&sc->mfi_ich) != 0) {
373157114Sscottl		device_printf(sc->mfi_dev, "Cannot establish configuration "
374157114Sscottl		    "hook\n");
375157114Sscottl		return (EINVAL);
376157114Sscottl	}
377157114Sscottl
378157114Sscottl	/*
379157114Sscottl	 * Register a shutdown handler.
380157114Sscottl	 */
381157114Sscottl	if ((sc->mfi_eh = EVENTHANDLER_REGISTER(shutdown_final, mfi_shutdown,
382157114Sscottl	    sc, SHUTDOWN_PRI_DEFAULT)) == NULL) {
383157114Sscottl		device_printf(sc->mfi_dev, "Warning: shutdown event "
384157114Sscottl		    "registration failed\n");
385157114Sscottl	}
386157114Sscottl
387157114Sscottl	/*
388157114Sscottl	 * Create the control device for doing management
389157114Sscottl	 */
390157114Sscottl	unit = device_get_unit(sc->mfi_dev);
391157114Sscottl	sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR,
392157114Sscottl	    0640, "mfi%d", unit);
393158737Sambrisko	if (unit == 0)
394158737Sambrisko		make_dev_alias(sc->mfi_cdev, "megaraid_sas_ioctl_node");
395157114Sscottl	if (sc->mfi_cdev != NULL)
396157114Sscottl		sc->mfi_cdev->si_drv1 = sc;
397157114Sscottl
398162619Sscottl	/* Start the timeout watchdog */
399162619Sscottl	callout_init(&sc->mfi_watchdog_callout, 1);
400162619Sscottl	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
401162619Sscottl	    mfi_timeout, sc);
402162619Sscottl
403157114Sscottl	return (0);
404157114Sscottl}
405157114Sscottl
406157114Sscottlstatic int
407157114Sscottlmfi_alloc_commands(struct mfi_softc *sc)
408157114Sscottl{
409157114Sscottl	struct mfi_command *cm;
410157114Sscottl	int i, ncmds;
411157114Sscottl
412157114Sscottl	/*
413157114Sscottl	 * XXX Should we allocate all the commands up front, or allocate on
414157114Sscottl	 * demand later like 'aac' does?
415157114Sscottl	 */
416157114Sscottl	ncmds = sc->mfi_max_fw_cmds;
417157114Sscottl	sc->mfi_commands = malloc(sizeof(struct mfi_command) * ncmds, M_MFIBUF,
418157114Sscottl	    M_WAITOK | M_ZERO);
419157114Sscottl
420157114Sscottl	for (i = 0; i < ncmds; i++) {
421157114Sscottl		cm = &sc->mfi_commands[i];
422158737Sambrisko		cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames +
423162458Sscottl		    sc->mfi_cmd_size * i);
424157114Sscottl		cm->cm_frame_busaddr = sc->mfi_frames_busaddr +
425162458Sscottl		    sc->mfi_cmd_size * i;
426157114Sscottl		cm->cm_frame->header.context = i;
427157114Sscottl		cm->cm_sense = &sc->mfi_sense[i];
428157114Sscottl		cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i;
429157114Sscottl		cm->cm_sc = sc;
430162619Sscottl		cm->cm_index = i;
431157114Sscottl		if (bus_dmamap_create(sc->mfi_buffer_dmat, 0,
432157114Sscottl		    &cm->cm_dmamap) == 0)
433157114Sscottl			mfi_release_command(cm);
434157114Sscottl		else
435157114Sscottl			break;
436157114Sscottl		sc->mfi_total_cmds++;
437157114Sscottl	}
438157114Sscottl
439157114Sscottl	return (0);
440157114Sscottl}
441157114Sscottl
442157114Sscottlstatic void
443157114Sscottlmfi_release_command(struct mfi_command *cm)
444157114Sscottl{
445163398Sscottl	struct mfi_frame_header *hdr;
446157114Sscottl	uint32_t *hdr_data;
447157114Sscottl
448157114Sscottl	/*
449157114Sscottl	 * Zero out the important fields of the frame, but make sure the
450157114Sscottl	 * context field is preserved
451157114Sscottl	 */
452157114Sscottl	hdr_data = (uint32_t *)cm->cm_frame;
453157114Sscottl	hdr_data[0] = 0;
454157114Sscottl	hdr_data[1] = 0;
455157114Sscottl
456163398Sscottl	hdr = &cm->cm_frame->header;
457163398Sscottl	if (hdr->sg_count) {
458163398Sscottl		cm->cm_sg->sg32[0].len = 0;
459163398Sscottl		cm->cm_sg->sg32[0].addr = 0;
460163398Sscottl	}
461157114Sscottl	cm->cm_extra_frames = 0;
462157114Sscottl	cm->cm_flags = 0;
463157114Sscottl	cm->cm_complete = NULL;
464157114Sscottl	cm->cm_private = NULL;
465157114Sscottl	cm->cm_sg = 0;
466157114Sscottl	cm->cm_total_frame_size = 0;
467163398Sscottl
468157114Sscottl	mfi_enqueue_free(cm);
469157114Sscottl}
470157114Sscottl
471157114Sscottlstatic int
472159806Spsmfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, uint32_t opcode,
473159806Sps    void **bufp, size_t bufsize)
474159806Sps{
475159806Sps	struct mfi_command *cm;
476159806Sps	struct mfi_dcmd_frame *dcmd;
477159806Sps	void *buf = NULL;
478159806Sps
479159806Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
480159806Sps
481159806Sps	cm = mfi_dequeue_free(sc);
482159806Sps	if (cm == NULL)
483159806Sps		return (EBUSY);
484159806Sps
485159806Sps	if ((bufsize > 0) && (bufp != NULL)) {
486159806Sps		if (*bufp == NULL) {
487159806Sps			buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO);
488159806Sps			if (buf == NULL) {
489159806Sps				mfi_release_command(cm);
490159806Sps				return (ENOMEM);
491159806Sps			}
492159806Sps			*bufp = buf;
493159806Sps		} else {
494159806Sps			buf = *bufp;
495159806Sps		}
496159806Sps	}
497159806Sps
498159806Sps	dcmd =  &cm->cm_frame->dcmd;
499159806Sps	bzero(dcmd->mbox, MFI_MBOX_SIZE);
500159806Sps	dcmd->header.cmd = MFI_CMD_DCMD;
501159806Sps	dcmd->header.timeout = 0;
502159806Sps	dcmd->header.flags = 0;
503159806Sps	dcmd->header.data_len = bufsize;
504159806Sps	dcmd->opcode = opcode;
505159806Sps	cm->cm_sg = &dcmd->sgl;
506159806Sps	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
507159806Sps	cm->cm_flags = 0;
508159806Sps	cm->cm_data = buf;
509159806Sps	cm->cm_private = buf;
510159806Sps	cm->cm_len = bufsize;
511159806Sps
512159806Sps	*cmp = cm;
513159806Sps	if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL))
514159806Sps		*bufp = buf;
515159806Sps	return (0);
516159806Sps}
517159806Sps
518159806Spsstatic int
519157114Sscottlmfi_comms_init(struct mfi_softc *sc)
520157114Sscottl{
521157114Sscottl	struct mfi_command *cm;
522157114Sscottl	struct mfi_init_frame *init;
523157114Sscottl	struct mfi_init_qinfo *qinfo;
524157114Sscottl	int error;
525157114Sscottl
526163398Sscottl	mtx_lock(&sc->mfi_io_lock);
527157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
528157114Sscottl		return (EBUSY);
529157114Sscottl
530157114Sscottl	/*
531157114Sscottl	 * Abuse the SG list area of the frame to hold the init_qinfo
532157114Sscottl	 * object;
533157114Sscottl	 */
534157114Sscottl	init = &cm->cm_frame->init;
535157114Sscottl	qinfo = (struct mfi_init_qinfo *)((uintptr_t)init + MFI_FRAME_SIZE);
536157114Sscottl
537157114Sscottl	bzero(qinfo, sizeof(struct mfi_init_qinfo));
538157114Sscottl	qinfo->rq_entries = sc->mfi_max_fw_cmds + 1;
539157114Sscottl	qinfo->rq_addr_lo = sc->mfi_comms_busaddr +
540157114Sscottl	    offsetof(struct mfi_hwcomms, hw_reply_q);
541157114Sscottl	qinfo->pi_addr_lo = sc->mfi_comms_busaddr +
542157114Sscottl	    offsetof(struct mfi_hwcomms, hw_pi);
543157114Sscottl	qinfo->ci_addr_lo = sc->mfi_comms_busaddr +
544157114Sscottl	    offsetof(struct mfi_hwcomms, hw_ci);
545157114Sscottl
546157114Sscottl	init->header.cmd = MFI_CMD_INIT;
547157114Sscottl	init->header.data_len = sizeof(struct mfi_init_qinfo);
548157114Sscottl	init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE;
549157114Sscottl
550157114Sscottl	if ((error = mfi_polled_command(sc, cm)) != 0) {
551157114Sscottl		device_printf(sc->mfi_dev, "failed to send init command\n");
552163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
553157114Sscottl		return (error);
554157114Sscottl	}
555157114Sscottl	mfi_release_command(cm);
556163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
557157114Sscottl
558157114Sscottl	return (0);
559157114Sscottl}
560157114Sscottl
561157114Sscottlstatic int
562157114Sscottlmfi_get_controller_info(struct mfi_softc *sc)
563157114Sscottl{
564159806Sps	struct mfi_command *cm = NULL;
565159806Sps	struct mfi_ctrl_info *ci = NULL;
566157114Sscottl	uint32_t max_sectors_1, max_sectors_2;
567157114Sscottl	int error;
568157114Sscottl
569159806Sps	mtx_lock(&sc->mfi_io_lock);
570159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO,
571159806Sps	    (void **)&ci, sizeof(*ci));
572159806Sps	if (error)
573159806Sps		goto out;
574157114Sscottl	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
575157114Sscottl
576157114Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
577159802Sps		device_printf(sc->mfi_dev, "Controller info buffer map failed\n");
578157114Sscottl		free(ci, M_MFIBUF);
579157114Sscottl		mfi_release_command(cm);
580163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
581157114Sscottl		return (error);
582157114Sscottl	}
583157114Sscottl
584157114Sscottl	/* It's ok if this fails, just use default info instead */
585157114Sscottl	if ((error = mfi_polled_command(sc, cm)) != 0) {
586157114Sscottl		device_printf(sc->mfi_dev, "Failed to get controller info\n");
587162458Sscottl		sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE /
588157114Sscottl		    MFI_SECTOR_LEN;
589159806Sps		error = 0;
590159806Sps		goto out;
591157114Sscottl	}
592157114Sscottl
593157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
594157114Sscottl	    BUS_DMASYNC_POSTREAD);
595157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
596157114Sscottl
597157114Sscottl	max_sectors_1 = (1 << ci->stripe_sz_ops.min) * ci->max_strips_per_io;
598157114Sscottl	max_sectors_2 = ci->max_request_size;
599157114Sscottl	sc->mfi_max_io = min(max_sectors_1, max_sectors_2);
600157114Sscottl
601159806Spsout:
602159806Sps	if (ci)
603159806Sps		free(ci, M_MFIBUF);
604159806Sps	if (cm)
605159806Sps		mfi_release_command(cm);
606159806Sps	mtx_unlock(&sc->mfi_io_lock);
607157114Sscottl	return (error);
608157114Sscottl}
609157114Sscottl
610157114Sscottlstatic int
611159806Spsmfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state)
612158737Sambrisko{
613159812Sps	struct mfi_command *cm = NULL;
614158737Sambrisko	int error;
615158737Sambrisko
616159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO,
617159806Sps	    (void **)log_state, sizeof(**log_state));
618159806Sps	if (error)
619159806Sps		goto out;
620159810Sps	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
621158737Sambrisko
622158737Sambrisko	if ((error = mfi_mapcmd(sc, cm)) != 0) {
623159802Sps		device_printf(sc->mfi_dev, "Log state buffer map failed\n");
624159806Sps		goto out;
625158737Sambrisko	}
626158737Sambrisko
627158737Sambrisko	if ((error = mfi_polled_command(sc, cm)) != 0) {
628159802Sps		device_printf(sc->mfi_dev, "Failed to get log state\n");
629159806Sps		goto out;
630158737Sambrisko	}
631158737Sambrisko
632158737Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
633158737Sambrisko	    BUS_DMASYNC_POSTREAD);
634158737Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
635158737Sambrisko
636159806Spsout:
637159812Sps	if (cm)
638159812Sps		mfi_release_command(cm);
639158737Sambrisko
640158737Sambrisko	return (error);
641158737Sambrisko}
642158737Sambrisko
643158737Sambriskostatic int
644158737Sambriskomfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
645158737Sambrisko{
646159806Sps	struct mfi_evt_log_state *log_state = NULL;
647158737Sambrisko	union mfi_evt class_locale;
648158737Sambrisko	int error = 0;
649158737Sambrisko	uint32_t seq;
650158737Sambrisko
651158737Sambrisko	class_locale.members.reserved = 0;
652162118Sambrisko	class_locale.members.locale = mfi_event_locale;
653162118Sambrisko	class_locale.members.class  = mfi_event_class;
654158737Sambrisko
655158737Sambrisko	if (seq_start == 0) {
656158737Sambrisko		error = mfi_get_log_state(sc, &log_state);
657159806Sps		if (error) {
658159806Sps			if (log_state)
659159806Sps				free(log_state, M_MFIBUF);
660158737Sambrisko			return (error);
661159806Sps		}
662158737Sambrisko		/*
663158737Sambrisko		 * Don't run them yet since we can't parse them.
664158737Sambrisko		 * We can indirectly get the contents from
665158737Sambrisko		 * the AEN mechanism via setting it lower then
666158737Sambrisko		 * current.  The firmware will iterate through them.
667158737Sambrisko		 */
668159806Sps		for (seq = log_state->shutdown_seq_num;
669159806Sps		     seq <= log_state->newest_seq_num; seq++) {
670158737Sambrisko			mfi_get_entry(sc, seq);
671158737Sambrisko		}
672158737Sambrisko	} else
673158737Sambrisko		seq = seq_start;
674158737Sambrisko	mfi_aen_register(sc, seq, class_locale.word);
675159806Sps	free(log_state, M_MFIBUF);
676158737Sambrisko
677158737Sambrisko	return 0;
678158737Sambrisko}
679158737Sambrisko
680158737Sambriskostatic int
681157114Sscottlmfi_polled_command(struct mfi_softc *sc, struct mfi_command *cm)
682157114Sscottl{
683157114Sscottl	struct mfi_frame_header *hdr;
684157114Sscottl	int tm = MFI_POLL_TIMEOUT_SECS * 1000000;
685157114Sscottl
686163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
687163398Sscottl
688157114Sscottl	hdr = &cm->cm_frame->header;
689157114Sscottl	hdr->cmd_status = 0xff;
690157114Sscottl	hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
691157114Sscottl
692157114Sscottl	mfi_send_frame(sc, cm);
693157114Sscottl
694157114Sscottl	while (hdr->cmd_status == 0xff) {
695157114Sscottl		DELAY(1000);
696157114Sscottl		tm -= 1000;
697157114Sscottl		if (tm <= 0)
698157114Sscottl			break;
699157114Sscottl	}
700157114Sscottl
701157114Sscottl	if (hdr->cmd_status == 0xff) {
702157114Sscottl		device_printf(sc->mfi_dev, "Frame %p timed out\n", hdr);
703157114Sscottl		return (ETIMEDOUT);
704157114Sscottl	}
705157114Sscottl
706157114Sscottl	return (0);
707157114Sscottl}
708157114Sscottl
709159811Spsstatic int
710159811Spsmfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm)
711159811Sps{
712159811Sps
713159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
714159811Sps	cm->cm_complete = NULL;
715159811Sps
716159811Sps	mfi_enqueue_ready(cm);
717159811Sps	mfi_startio(sc);
718159811Sps	return (msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0));
719159811Sps}
720159811Sps
721157114Sscottlvoid
722157114Sscottlmfi_free(struct mfi_softc *sc)
723157114Sscottl{
724157114Sscottl	struct mfi_command *cm;
725157114Sscottl	int i;
726157114Sscottl
727162619Sscottl	callout_drain(&sc->mfi_watchdog_callout);
728162619Sscottl
729157114Sscottl	if (sc->mfi_cdev != NULL)
730157114Sscottl		destroy_dev(sc->mfi_cdev);
731157114Sscottl
732157114Sscottl	if (sc->mfi_total_cmds != 0) {
733157114Sscottl		for (i = 0; i < sc->mfi_total_cmds; i++) {
734157114Sscottl			cm = &sc->mfi_commands[i];
735157114Sscottl			bus_dmamap_destroy(sc->mfi_buffer_dmat, cm->cm_dmamap);
736157114Sscottl		}
737157114Sscottl		free(sc->mfi_commands, M_MFIBUF);
738157114Sscottl	}
739157114Sscottl
740157114Sscottl	if (sc->mfi_intr)
741157114Sscottl		bus_teardown_intr(sc->mfi_dev, sc->mfi_irq, sc->mfi_intr);
742157114Sscottl	if (sc->mfi_irq != NULL)
743157114Sscottl		bus_release_resource(sc->mfi_dev, SYS_RES_IRQ, sc->mfi_irq_rid,
744157114Sscottl		    sc->mfi_irq);
745157114Sscottl
746157114Sscottl	if (sc->mfi_sense_busaddr != 0)
747157114Sscottl		bus_dmamap_unload(sc->mfi_sense_dmat, sc->mfi_sense_dmamap);
748157114Sscottl	if (sc->mfi_sense != NULL)
749157114Sscottl		bus_dmamem_free(sc->mfi_sense_dmat, sc->mfi_sense,
750157114Sscottl		    sc->mfi_sense_dmamap);
751157114Sscottl	if (sc->mfi_sense_dmat != NULL)
752157114Sscottl		bus_dma_tag_destroy(sc->mfi_sense_dmat);
753157114Sscottl
754157114Sscottl	if (sc->mfi_frames_busaddr != 0)
755157114Sscottl		bus_dmamap_unload(sc->mfi_frames_dmat, sc->mfi_frames_dmamap);
756157114Sscottl	if (sc->mfi_frames != NULL)
757157114Sscottl		bus_dmamem_free(sc->mfi_frames_dmat, sc->mfi_frames,
758157114Sscottl		    sc->mfi_frames_dmamap);
759157114Sscottl	if (sc->mfi_frames_dmat != NULL)
760157114Sscottl		bus_dma_tag_destroy(sc->mfi_frames_dmat);
761157114Sscottl
762157114Sscottl	if (sc->mfi_comms_busaddr != 0)
763157114Sscottl		bus_dmamap_unload(sc->mfi_comms_dmat, sc->mfi_comms_dmamap);
764157114Sscottl	if (sc->mfi_comms != NULL)
765157114Sscottl		bus_dmamem_free(sc->mfi_comms_dmat, sc->mfi_comms,
766157114Sscottl		    sc->mfi_comms_dmamap);
767157114Sscottl	if (sc->mfi_comms_dmat != NULL)
768157114Sscottl		bus_dma_tag_destroy(sc->mfi_comms_dmat);
769157114Sscottl
770157114Sscottl	if (sc->mfi_buffer_dmat != NULL)
771157114Sscottl		bus_dma_tag_destroy(sc->mfi_buffer_dmat);
772157114Sscottl	if (sc->mfi_parent_dmat != NULL)
773157114Sscottl		bus_dma_tag_destroy(sc->mfi_parent_dmat);
774157114Sscottl
775157114Sscottl	if (mtx_initialized(&sc->mfi_io_lock))
776157114Sscottl		mtx_destroy(&sc->mfi_io_lock);
777157114Sscottl
778157114Sscottl	return;
779157114Sscottl}
780157114Sscottl
781157114Sscottlstatic void
782157114Sscottlmfi_startup(void *arg)
783157114Sscottl{
784157114Sscottl	struct mfi_softc *sc;
785157114Sscottl
786157114Sscottl	sc = (struct mfi_softc *)arg;
787157114Sscottl
788157114Sscottl	config_intrhook_disestablish(&sc->mfi_ich);
789157114Sscottl
790157114Sscottl	mfi_enable_intr(sc);
791163398Sscottl	mtx_lock(&sc->mfi_io_lock);
792159811Sps	mfi_ldprobe(sc);
793163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
794157114Sscottl}
795157114Sscottl
796157114Sscottlstatic void
797157114Sscottlmfi_intr(void *arg)
798157114Sscottl{
799157114Sscottl	struct mfi_softc *sc;
800157114Sscottl	struct mfi_command *cm;
801157114Sscottl	uint32_t status, pi, ci, context;
802157114Sscottl
803157114Sscottl	sc = (struct mfi_softc *)arg;
804157114Sscottl
805157114Sscottl	status = MFI_READ4(sc, MFI_OSTS);
806157114Sscottl	if ((status & MFI_OSTS_INTR_VALID) == 0)
807157114Sscottl		return;
808163398Sscottl
809157114Sscottl	MFI_WRITE4(sc, MFI_OSTS, status);
810157114Sscottl
811157114Sscottl	pi = sc->mfi_comms->hw_pi;
812157114Sscottl	ci = sc->mfi_comms->hw_ci;
813157114Sscottl	mtx_lock(&sc->mfi_io_lock);
814157114Sscottl	while (ci != pi) {
815157114Sscottl		context = sc->mfi_comms->hw_reply_q[ci];
816162099Sscottl		cm = &sc->mfi_commands[context];
817162099Sscottl		mfi_remove_busy(cm);
818162099Sscottl		mfi_complete(sc, cm);
819162099Sscottl		if (++ci == (sc->mfi_max_fw_cmds + 1)) {
820157114Sscottl			ci = 0;
821157114Sscottl		}
822157114Sscottl	}
823157114Sscottl
824157114Sscottl	sc->mfi_comms->hw_ci = ci;
825157114Sscottl
826163398Sscottl	/* Give defered I/O a chance to run */
827163398Sscottl	if (sc->mfi_flags & MFI_FLAGS_QFRZN)
828163398Sscottl		sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
829163398Sscottl	mfi_startio(sc);
830163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
831163398Sscottl
832157114Sscottl	return;
833157114Sscottl}
834157114Sscottl
835157114Sscottlint
836157114Sscottlmfi_shutdown(struct mfi_softc *sc)
837157114Sscottl{
838157114Sscottl	struct mfi_dcmd_frame *dcmd;
839157114Sscottl	struct mfi_command *cm;
840157114Sscottl	int error;
841157114Sscottl
842159806Sps	mtx_lock(&sc->mfi_io_lock);
843159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0);
844163398Sscottl	if (error) {
845163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
846159806Sps		return (error);
847163398Sscottl	}
848157114Sscottl
849158737Sambrisko	if (sc->mfi_aen_cm != NULL)
850158737Sambrisko		mfi_abort(sc, sc->mfi_aen_cm);
851157114Sscottl
852157114Sscottl	dcmd = &cm->cm_frame->dcmd;
853157114Sscottl	dcmd->header.flags = MFI_FRAME_DIR_NONE;
854157114Sscottl
855157114Sscottl	if ((error = mfi_polled_command(sc, cm)) != 0) {
856157114Sscottl		device_printf(sc->mfi_dev, "Failed to shutdown controller\n");
857157114Sscottl	}
858157114Sscottl
859159812Sps	mfi_release_command(cm);
860163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
861157114Sscottl	return (error);
862157114Sscottl}
863157114Sscottl
864157114Sscottlstatic void
865157114Sscottlmfi_enable_intr(struct mfi_softc *sc)
866157114Sscottl{
867157114Sscottl
868157114Sscottl	MFI_WRITE4(sc, MFI_OMSK, 0x01);
869157114Sscottl}
870157114Sscottl
871157114Sscottlstatic void
872159811Spsmfi_ldprobe(struct mfi_softc *sc)
873157114Sscottl{
874159811Sps	struct mfi_frame_header *hdr;
875159811Sps	struct mfi_command *cm = NULL;
876159811Sps	struct mfi_ld_list *list = NULL;
877159811Sps	int error, i;
878157114Sscottl
879163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
880163398Sscottl
881159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
882159811Sps	    (void **)&list, sizeof(*list));
883159811Sps	if (error)
884159811Sps		goto out;
885159811Sps
886159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
887159811Sps	if (mfi_wait_command(sc, cm) != 0) {
888159811Sps		device_printf(sc->mfi_dev, "Failed to get device listing\n");
889159811Sps		goto out;
890157114Sscottl	}
891157114Sscottl
892157114Sscottl	hdr = &cm->cm_frame->header;
893159811Sps	if (hdr->cmd_status != MFI_STAT_OK) {
894159811Sps		device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n",
895159811Sps		    hdr->cmd_status);
896159811Sps		goto out;
897157114Sscottl	}
898157114Sscottl
899159811Sps	for (i = 0; i < list->ld_count; i++)
900163398Sscottl		mfi_add_ld(sc, list->ld_list[i].ld.v.target_id);
901159811Spsout:
902159811Sps	if (list)
903159811Sps		free(list, M_MFIBUF);
904159811Sps	if (cm)
905157114Sscottl		mfi_release_command(cm);
906163398Sscottl
907159811Sps	return;
908157114Sscottl}
909157114Sscottl
910158737Sambriskostatic void
911158737Sambriskomfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
912158737Sambrisko{
913158737Sambrisko	switch (detail->arg_type) {
914158737Sambrisko	case MR_EVT_ARGS_NONE:
915162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - %s\n",
916159574Sambrisko		    detail->seq,
917162118Sambrisko		    detail->time,
918162118Sambrisko		    detail->class.members.locale,
919162118Sambrisko		    detail->class.members.class,
920159574Sambrisko		    detail->description
921159574Sambrisko		    );
922158737Sambrisko		break;
923158737Sambrisko	case MR_EVT_ARGS_CDB_SENSE:
924162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) CDB %*D"
925159574Sambrisko		    "Sense %*D\n: %s\n",
926158737Sambrisko		    detail->seq,
927162118Sambrisko		    detail->time,
928162118Sambrisko		    detail->class.members.locale,
929162118Sambrisko		    detail->class.members.class,
930158737Sambrisko		    detail->args.cdb_sense.pd.device_id,
931158737Sambrisko		    detail->args.cdb_sense.pd.enclosure_index,
932158737Sambrisko		    detail->args.cdb_sense.pd.slot_number,
933158737Sambrisko		    detail->args.cdb_sense.cdb_len,
934158737Sambrisko		    detail->args.cdb_sense.cdb,
935158737Sambrisko		    ":",
936158737Sambrisko		    detail->args.cdb_sense.sense_len,
937158737Sambrisko		    detail->args.cdb_sense.sense,
938158737Sambrisko		    ":",
939158737Sambrisko		    detail->description
940158737Sambrisko		    );
941158737Sambrisko		break;
942158737Sambrisko	case MR_EVT_ARGS_LD:
943162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
944158737Sambrisko		    "event: %s\n",
945158737Sambrisko		    detail->seq,
946162118Sambrisko		    detail->time,
947162118Sambrisko		    detail->class.members.locale,
948162118Sambrisko		    detail->class.members.class,
949158737Sambrisko		    detail->args.ld.ld_index,
950158737Sambrisko		    detail->args.ld.target_id,
951158737Sambrisko		    detail->description
952158737Sambrisko		    );
953158737Sambrisko		break;
954158737Sambrisko	case MR_EVT_ARGS_LD_COUNT:
955162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
956158737Sambrisko		    "count %lld: %s\n",
957158737Sambrisko		    detail->seq,
958162118Sambrisko		    detail->time,
959162118Sambrisko		    detail->class.members.locale,
960162118Sambrisko		    detail->class.members.class,
961158737Sambrisko		    detail->args.ld_count.ld.ld_index,
962158737Sambrisko		    detail->args.ld_count.ld.target_id,
963158737Sambrisko		    (long long)detail->args.ld_count.count,
964158737Sambrisko		    detail->description
965158737Sambrisko		    );
966158737Sambrisko		break;
967158737Sambrisko	case MR_EVT_ARGS_LD_LBA:
968162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
969158737Sambrisko		    "lba %lld: %s\n",
970158737Sambrisko		    detail->seq,
971162118Sambrisko		    detail->time,
972162118Sambrisko		    detail->class.members.locale,
973162118Sambrisko		    detail->class.members.class,
974158737Sambrisko		    detail->args.ld_lba.ld.ld_index,
975158737Sambrisko		    detail->args.ld_lba.ld.target_id,
976158737Sambrisko		    (long long)detail->args.ld_lba.lba,
977158737Sambrisko		    detail->description
978158737Sambrisko		    );
979158737Sambrisko		break;
980158737Sambrisko	case MR_EVT_ARGS_LD_OWNER:
981162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
982158737Sambrisko		    "owner changed: prior %d, new %d: %s\n",
983158737Sambrisko		    detail->seq,
984162118Sambrisko		    detail->time,
985162118Sambrisko		    detail->class.members.locale,
986162118Sambrisko		    detail->class.members.class,
987158737Sambrisko		    detail->args.ld_owner.ld.ld_index,
988158737Sambrisko		    detail->args.ld_owner.ld.target_id,
989158737Sambrisko		    detail->args.ld_owner.pre_owner,
990158737Sambrisko		    detail->args.ld_owner.new_owner,
991158737Sambrisko		    detail->description
992158737Sambrisko		    );
993158737Sambrisko		break;
994158737Sambrisko	case MR_EVT_ARGS_LD_LBA_PD_LBA:
995162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
996158737Sambrisko		    "lba %lld, physical drive PD %02d(e%d/s%d) lba %lld: %s\n",
997158737Sambrisko		    detail->seq,
998162118Sambrisko		    detail->time,
999162118Sambrisko		    detail->class.members.locale,
1000162118Sambrisko		    detail->class.members.class,
1001158737Sambrisko		    detail->args.ld_lba_pd_lba.ld.ld_index,
1002158737Sambrisko		    detail->args.ld_lba_pd_lba.ld.target_id,
1003158737Sambrisko		    (long long)detail->args.ld_lba_pd_lba.ld_lba,
1004158737Sambrisko		    detail->args.ld_lba_pd_lba.pd.device_id,
1005158737Sambrisko		    detail->args.ld_lba_pd_lba.pd.enclosure_index,
1006158737Sambrisko		    detail->args.ld_lba_pd_lba.pd.slot_number,
1007158737Sambrisko		    (long long)detail->args.ld_lba_pd_lba.pd_lba,
1008158737Sambrisko		    detail->description
1009158737Sambrisko		    );
1010158737Sambrisko		break;
1011158737Sambrisko	case MR_EVT_ARGS_LD_PROG:
1012162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
1013158737Sambrisko		    "progress %d%% in %ds: %s\n",
1014158737Sambrisko		    detail->seq,
1015162118Sambrisko		    detail->time,
1016162118Sambrisko		    detail->class.members.locale,
1017162118Sambrisko		    detail->class.members.class,
1018158737Sambrisko		    detail->args.ld_prog.ld.ld_index,
1019158737Sambrisko		    detail->args.ld_prog.ld.target_id,
1020158737Sambrisko		    detail->args.ld_prog.prog.progress/655,
1021158737Sambrisko		    detail->args.ld_prog.prog.elapsed_seconds,
1022158737Sambrisko		    detail->description
1023158737Sambrisko		    );
1024158737Sambrisko		break;
1025158737Sambrisko	case MR_EVT_ARGS_LD_STATE:
1026162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
1027158737Sambrisko		    "state prior %d new %d: %s\n",
1028158737Sambrisko		    detail->seq,
1029162118Sambrisko		    detail->time,
1030162118Sambrisko		    detail->class.members.locale,
1031162118Sambrisko		    detail->class.members.class,
1032158737Sambrisko		    detail->args.ld_state.ld.ld_index,
1033158737Sambrisko		    detail->args.ld_state.ld.target_id,
1034158737Sambrisko		    detail->args.ld_state.prev_state,
1035158737Sambrisko		    detail->args.ld_state.new_state,
1036158737Sambrisko		    detail->description
1037158737Sambrisko		    );
1038158737Sambrisko		break;
1039158737Sambrisko	case MR_EVT_ARGS_LD_STRIP:
1040162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
1041158737Sambrisko		    "strip %lld: %s\n",
1042158737Sambrisko		    detail->seq,
1043162118Sambrisko		    detail->time,
1044162118Sambrisko		    detail->class.members.locale,
1045162118Sambrisko		    detail->class.members.class,
1046158737Sambrisko		    detail->args.ld_strip.ld.ld_index,
1047158737Sambrisko		    detail->args.ld_strip.ld.target_id,
1048158737Sambrisko		    (long long)detail->args.ld_strip.strip,
1049158737Sambrisko		    detail->description
1050158737Sambrisko		    );
1051158737Sambrisko		break;
1052158737Sambrisko	case MR_EVT_ARGS_PD:
1053162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
1054158737Sambrisko		    "event: %s\n",
1055158737Sambrisko		    detail->seq,
1056162118Sambrisko		    detail->time,
1057162118Sambrisko		    detail->class.members.locale,
1058162118Sambrisko		    detail->class.members.class,
1059158737Sambrisko		    detail->args.pd.device_id,
1060158737Sambrisko		    detail->args.pd.enclosure_index,
1061158737Sambrisko		    detail->args.pd.slot_number,
1062158737Sambrisko		    detail->description
1063158737Sambrisko		    );
1064158737Sambrisko		break;
1065158737Sambrisko	case MR_EVT_ARGS_PD_ERR:
1066162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
1067158737Sambrisko		    "err %d: %s\n",
1068158737Sambrisko		    detail->seq,
1069162118Sambrisko		    detail->time,
1070162118Sambrisko		    detail->class.members.locale,
1071162118Sambrisko		    detail->class.members.class,
1072158737Sambrisko		    detail->args.pd_err.pd.device_id,
1073158737Sambrisko		    detail->args.pd_err.pd.enclosure_index,
1074158737Sambrisko		    detail->args.pd_err.pd.slot_number,
1075158737Sambrisko		    detail->args.pd_err.err,
1076158737Sambrisko		    detail->description
1077158737Sambrisko		    );
1078158737Sambrisko		break;
1079158737Sambrisko	case MR_EVT_ARGS_PD_LBA:
1080162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
1081158737Sambrisko		    "lba %lld: %s\n",
1082158737Sambrisko		    detail->seq,
1083162118Sambrisko		    detail->time,
1084162118Sambrisko		    detail->class.members.locale,
1085162118Sambrisko		    detail->class.members.class,
1086158737Sambrisko		    detail->args.pd_lba.pd.device_id,
1087158737Sambrisko		    detail->args.pd_lba.pd.enclosure_index,
1088158737Sambrisko		    detail->args.pd_lba.pd.slot_number,
1089158737Sambrisko		    (long long)detail->args.pd_lba.lba,
1090158737Sambrisko		    detail->description
1091158737Sambrisko		    );
1092158737Sambrisko		break;
1093158737Sambrisko	case MR_EVT_ARGS_PD_LBA_LD:
1094162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
1095158737Sambrisko		    "lba %lld VD %02d/%d: %s\n",
1096158737Sambrisko		    detail->seq,
1097162118Sambrisko		    detail->time,
1098162118Sambrisko		    detail->class.members.locale,
1099162118Sambrisko		    detail->class.members.class,
1100158737Sambrisko		    detail->args.pd_lba_ld.pd.device_id,
1101158737Sambrisko		    detail->args.pd_lba_ld.pd.enclosure_index,
1102158737Sambrisko		    detail->args.pd_lba_ld.pd.slot_number,
1103158737Sambrisko		    (long long)detail->args.pd_lba.lba,
1104158737Sambrisko		    detail->args.pd_lba_ld.ld.ld_index,
1105158737Sambrisko		    detail->args.pd_lba_ld.ld.target_id,
1106158737Sambrisko		    detail->description
1107158737Sambrisko		    );
1108158737Sambrisko		break;
1109158737Sambrisko	case MR_EVT_ARGS_PD_PROG:
1110162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
1111158737Sambrisko		    "progress %d%% seconds %ds: %s\n",
1112158737Sambrisko		    detail->seq,
1113162118Sambrisko		    detail->time,
1114162118Sambrisko		    detail->class.members.locale,
1115162118Sambrisko		    detail->class.members.class,
1116158737Sambrisko		    detail->args.pd_prog.pd.device_id,
1117158737Sambrisko		    detail->args.pd_prog.pd.enclosure_index,
1118158737Sambrisko		    detail->args.pd_prog.pd.slot_number,
1119158737Sambrisko		    detail->args.pd_prog.prog.progress/655,
1120158737Sambrisko		    detail->args.pd_prog.prog.elapsed_seconds,
1121158737Sambrisko		    detail->description
1122158737Sambrisko		    );
1123158737Sambrisko		break;
1124158737Sambrisko	case MR_EVT_ARGS_PD_STATE:
1125162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
1126158737Sambrisko		    "state prior %d new %d: %s\n",
1127158737Sambrisko		    detail->seq,
1128162118Sambrisko		    detail->time,
1129162118Sambrisko		    detail->class.members.locale,
1130162118Sambrisko		    detail->class.members.class,
1131158737Sambrisko		    detail->args.pd_prog.pd.device_id,
1132158737Sambrisko		    detail->args.pd_prog.pd.enclosure_index,
1133158737Sambrisko		    detail->args.pd_prog.pd.slot_number,
1134158737Sambrisko		    detail->args.pd_state.prev_state,
1135158737Sambrisko		    detail->args.pd_state.new_state,
1136158737Sambrisko		    detail->description
1137158737Sambrisko		    );
1138158737Sambrisko		break;
1139158737Sambrisko	case MR_EVT_ARGS_PCI:
1140162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PCI 0x04%x 0x04%x "
1141158737Sambrisko		    "0x04%x 0x04%x: %s\n",
1142158737Sambrisko		    detail->seq,
1143162118Sambrisko		    detail->time,
1144162118Sambrisko		    detail->class.members.locale,
1145162118Sambrisko		    detail->class.members.class,
1146158737Sambrisko		    detail->args.pci.venderId,
1147158737Sambrisko		    detail->args.pci.deviceId,
1148158737Sambrisko		    detail->args.pci.subVenderId,
1149158737Sambrisko		    detail->args.pci.subDeviceId,
1150158737Sambrisko		    detail->description
1151158737Sambrisko		    );
1152158737Sambrisko		break;
1153158737Sambrisko	case MR_EVT_ARGS_RATE:
1154162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - Rebuild rate %d: %s\n",
1155158737Sambrisko		    detail->seq,
1156162118Sambrisko		    detail->time,
1157162118Sambrisko		    detail->class.members.locale,
1158162118Sambrisko		    detail->class.members.class,
1159158737Sambrisko		    detail->args.rate,
1160158737Sambrisko		    detail->description
1161158737Sambrisko		    );
1162158737Sambrisko		break;
1163158737Sambrisko	case MR_EVT_ARGS_TIME:
1164162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - Adapter ticks %d "
1165158737Sambrisko		    "elapsed %ds: %s\n",
1166158737Sambrisko		    detail->seq,
1167162118Sambrisko		    detail->time,
1168162118Sambrisko		    detail->class.members.locale,
1169162118Sambrisko		    detail->class.members.class,
1170158737Sambrisko		    detail->args.time.rtc,
1171158737Sambrisko		    detail->args.time.elapsedSeconds,
1172158737Sambrisko		    detail->description
1173158737Sambrisko		    );
1174158737Sambrisko		break;
1175158737Sambrisko	case MR_EVT_ARGS_ECC:
1176162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - Adapter ECC %x,%x: %s: %s\n",
1177158737Sambrisko		    detail->seq,
1178162118Sambrisko		    detail->time,
1179162118Sambrisko		    detail->class.members.locale,
1180162118Sambrisko		    detail->class.members.class,
1181158737Sambrisko		    detail->args.ecc.ecar,
1182158737Sambrisko		    detail->args.ecc.elog,
1183158737Sambrisko		    detail->args.ecc.str,
1184158737Sambrisko		    detail->description
1185158737Sambrisko		    );
1186158737Sambrisko		break;
1187158737Sambrisko	default:
1188162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - Type %d: %s\n",
1189158737Sambrisko		    detail->seq,
1190162118Sambrisko		    detail->time,
1191162118Sambrisko		    detail->class.members.locale,
1192162118Sambrisko		    detail->class.members.class,
1193158737Sambrisko		    detail->arg_type, detail->description
1194158737Sambrisko		    );
1195158737Sambrisko	}
1196158737Sambrisko}
1197158737Sambrisko
1198157114Sscottlstatic int
1199158737Sambriskomfi_aen_register(struct mfi_softc *sc, int seq, int locale)
1200158737Sambrisko{
1201158737Sambrisko	struct mfi_command *cm;
1202158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1203158737Sambrisko	union mfi_evt current_aen, prior_aen;
1204159806Sps	struct mfi_evt_detail *ed = NULL;
1205163398Sscottl	int error = 0;
1206158737Sambrisko
1207158737Sambrisko	current_aen.word = locale;
1208158737Sambrisko	if (sc->mfi_aen_cm != NULL) {
1209158737Sambrisko		prior_aen.word =
1210158737Sambrisko		    ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1];
1211158737Sambrisko		if (prior_aen.members.class <= current_aen.members.class &&
1212158737Sambrisko		    !((prior_aen.members.locale & current_aen.members.locale)
1213158737Sambrisko		    ^current_aen.members.locale)) {
1214158737Sambrisko			return (0);
1215158737Sambrisko		} else {
1216158737Sambrisko			prior_aen.members.locale |= current_aen.members.locale;
1217158737Sambrisko			if (prior_aen.members.class
1218158737Sambrisko			    < current_aen.members.class)
1219158737Sambrisko				current_aen.members.class =
1220158737Sambrisko				    prior_aen.members.class;
1221158737Sambrisko			mfi_abort(sc, sc->mfi_aen_cm);
1222158737Sambrisko		}
1223158737Sambrisko	}
1224158737Sambrisko
1225159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT,
1226159806Sps	    (void **)&ed, sizeof(*ed));
1227163398Sscottl	if (error) {
1228163398Sscottl		goto out;
1229163398Sscottl	}
1230158737Sambrisko
1231158737Sambrisko	dcmd = &cm->cm_frame->dcmd;
1232158737Sambrisko	((uint32_t *)&dcmd->mbox)[0] = seq;
1233158737Sambrisko	((uint32_t *)&dcmd->mbox)[1] = locale;
1234158737Sambrisko	cm->cm_flags = MFI_CMD_DATAIN;
1235158737Sambrisko	cm->cm_complete = mfi_aen_complete;
1236158737Sambrisko
1237158737Sambrisko	sc->mfi_aen_cm = cm;
1238158737Sambrisko
1239158737Sambrisko	mfi_enqueue_ready(cm);
1240158737Sambrisko	mfi_startio(sc);
1241158737Sambrisko
1242163398Sscottlout:
1243163398Sscottl	return (error);
1244158737Sambrisko}
1245158737Sambrisko
1246158737Sambriskostatic void
1247158737Sambriskomfi_aen_complete(struct mfi_command *cm)
1248158737Sambrisko{
1249158737Sambrisko	struct mfi_frame_header *hdr;
1250158737Sambrisko	struct mfi_softc *sc;
1251158737Sambrisko	struct mfi_evt_detail *detail;
1252163398Sscottl	struct mfi_aen *mfi_aen_entry, *tmp;
1253158737Sambrisko	int seq = 0, aborted = 0;
1254158737Sambrisko
1255158737Sambrisko	sc = cm->cm_sc;
1256158737Sambrisko	hdr = &cm->cm_frame->header;
1257158737Sambrisko
1258158737Sambrisko	if (sc->mfi_aen_cm == NULL)
1259158737Sambrisko		return;
1260158737Sambrisko
1261158737Sambrisko	if (sc->mfi_aen_cm->cm_aen_abort || hdr->cmd_status == 0xff) {
1262158737Sambrisko		sc->mfi_aen_cm->cm_aen_abort = 0;
1263158737Sambrisko		aborted = 1;
1264158737Sambrisko	} else {
1265158737Sambrisko		sc->mfi_aen_triggered = 1;
1266163398Sscottl		if (sc->mfi_poll_waiting) {
1267163398Sscottl			sc->mfi_poll_waiting = 0;
1268158737Sambrisko			selwakeup(&sc->mfi_select);
1269163398Sscottl		}
1270158737Sambrisko		detail = cm->cm_data;
1271163398Sscottl		/*
1272163398Sscottl		 * XXX If this function is too expensive or is recursive, then
1273163398Sscottl		 * events should be put onto a queue and processed later.
1274163398Sscottl		 */
1275158737Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1276158737Sambrisko		mfi_decode_evt(sc, detail);
1277158737Sambrisko		mtx_lock(&sc->mfi_io_lock);
1278158737Sambrisko		seq = detail->seq + 1;
1279163398Sscottl		TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
1280158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
1281158737Sambrisko			    aen_link);
1282163398Sscottl			PROC_LOCK(mfi_aen_entry->p);
1283158737Sambrisko			psignal(mfi_aen_entry->p, SIGIO);
1284163398Sscottl			PROC_UNLOCK(mfi_aen_entry->p);
1285158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
1286158737Sambrisko		}
1287158737Sambrisko	}
1288158737Sambrisko
1289158737Sambrisko	free(cm->cm_data, M_MFIBUF);
1290158737Sambrisko	sc->mfi_aen_cm = NULL;
1291158737Sambrisko	wakeup(&sc->mfi_aen_cm);
1292158737Sambrisko	mfi_release_command(cm);
1293158737Sambrisko
1294158737Sambrisko	/* set it up again so the driver can catch more events */
1295158737Sambrisko	if (!aborted) {
1296158737Sambrisko		mfi_aen_setup(sc, seq);
1297158737Sambrisko	}
1298158737Sambrisko}
1299158737Sambrisko
1300162118Sambrisko/* Only do one event for now so we can easily iterate through them */
1301162118Sambrisko#define MAX_EVENTS 1
1302158737Sambriskostatic int
1303158737Sambriskomfi_get_entry(struct mfi_softc *sc, int seq)
1304158737Sambrisko{
1305158737Sambrisko	struct mfi_command *cm;
1306158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1307162118Sambrisko	struct mfi_evt_list *el;
1308158737Sambrisko	int error;
1309162118Sambrisko	int i;
1310162118Sambrisko	int size;
1311158737Sambrisko
1312158737Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL) {
1313158737Sambrisko		return (EBUSY);
1314158737Sambrisko	}
1315158737Sambrisko
1316162118Sambrisko	size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail)
1317162118Sambrisko		* (MAX_EVENTS - 1);
1318162118Sambrisko	el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO);
1319162118Sambrisko	if (el == NULL) {
1320158737Sambrisko		mfi_release_command(cm);
1321158737Sambrisko		return (ENOMEM);
1322158737Sambrisko	}
1323158737Sambrisko
1324158737Sambrisko	dcmd = &cm->cm_frame->dcmd;
1325158737Sambrisko	bzero(dcmd->mbox, MFI_MBOX_SIZE);
1326158737Sambrisko	dcmd->header.cmd = MFI_CMD_DCMD;
1327158737Sambrisko	dcmd->header.timeout = 0;
1328162118Sambrisko	dcmd->header.data_len = size;
1329158737Sambrisko	dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET;
1330158737Sambrisko	((uint32_t *)&dcmd->mbox)[0] = seq;
1331158737Sambrisko	((uint32_t *)&dcmd->mbox)[1] = MFI_EVT_LOCALE_ALL;
1332158737Sambrisko	cm->cm_sg = &dcmd->sgl;
1333158737Sambrisko	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
1334158737Sambrisko	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1335162118Sambrisko	cm->cm_data = el;
1336162118Sambrisko	cm->cm_len = size;
1337158737Sambrisko
1338158737Sambrisko	if ((error = mfi_mapcmd(sc, cm)) != 0) {
1339158737Sambrisko		device_printf(sc->mfi_dev, "Controller info buffer map failed");
1340162118Sambrisko		free(el, M_MFIBUF);
1341158737Sambrisko		mfi_release_command(cm);
1342158737Sambrisko		return (error);
1343158737Sambrisko	}
1344158737Sambrisko
1345158737Sambrisko	if ((error = mfi_polled_command(sc, cm)) != 0) {
1346158737Sambrisko		device_printf(sc->mfi_dev, "Failed to get controller entry\n");
1347162458Sscottl		sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE /
1348158737Sambrisko		    MFI_SECTOR_LEN;
1349162118Sambrisko		free(el, M_MFIBUF);
1350158737Sambrisko		mfi_release_command(cm);
1351158737Sambrisko		return (0);
1352158737Sambrisko	}
1353158737Sambrisko
1354158737Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1355158737Sambrisko	    BUS_DMASYNC_POSTREAD);
1356158737Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1357158737Sambrisko
1358162473Sambrisko	if (dcmd->header.cmd_status != MFI_STAT_NOT_FOUND) {
1359162473Sambrisko		for (i = 0; i < el->count; i++) {
1360162473Sambrisko			if (seq + i == el->event[i].seq)
1361162473Sambrisko				mfi_decode_evt(sc, &el->event[i]);
1362162473Sambrisko		}
1363162118Sambrisko	}
1364158737Sambrisko
1365158737Sambrisko	free(cm->cm_data, M_MFIBUF);
1366158737Sambrisko	mfi_release_command(cm);
1367158737Sambrisko	return (0);
1368158737Sambrisko}
1369158737Sambrisko
1370158737Sambriskostatic int
1371159811Spsmfi_add_ld(struct mfi_softc *sc, int id)
1372157114Sscottl{
1373157114Sscottl	struct mfi_command *cm;
1374159811Sps	struct mfi_dcmd_frame *dcmd = NULL;
1375159811Sps	struct mfi_ld_info *ld_info = NULL;
1376159811Sps	int error;
1377157114Sscottl
1378159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1379159811Sps
1380159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO,
1381159811Sps	    (void **)&ld_info, sizeof(*ld_info));
1382159811Sps	if (error) {
1383159811Sps		device_printf(sc->mfi_dev,
1384159811Sps		    "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error);
1385159811Sps		if (ld_info)
1386159811Sps			free(ld_info, M_MFIBUF);
1387159811Sps		return (error);
1388157624Sscottl	}
1389159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
1390159811Sps	dcmd = &cm->cm_frame->dcmd;
1391159811Sps	dcmd->mbox[0] = id;
1392160052Sambrisko	if (mfi_wait_command(sc, cm) != 0) {
1393160052Sambrisko		device_printf(sc->mfi_dev,
1394160052Sambrisko		    "Failed to get logical drive: %d\n", id);
1395160052Sambrisko		free(ld_info, M_MFIBUF);
1396160052Sambrisko		return (0);
1397160052Sambrisko	}
1398159811Sps
1399160052Sambrisko	mfi_add_ld_complete(cm);
1400157114Sscottl	return (0);
1401157114Sscottl}
1402157114Sscottl
1403157114Sscottlstatic void
1404159811Spsmfi_add_ld_complete(struct mfi_command *cm)
1405157114Sscottl{
1406157114Sscottl	struct mfi_frame_header *hdr;
1407159811Sps	struct mfi_ld_info *ld_info;
1408157114Sscottl	struct mfi_softc *sc;
1409159811Sps	struct mfi_ld *ld;
1410159811Sps	device_t child;
1411157114Sscottl
1412157114Sscottl	sc = cm->cm_sc;
1413157114Sscottl	hdr = &cm->cm_frame->header;
1414159811Sps	ld_info = cm->cm_private;
1415157114Sscottl
1416159811Sps	if (hdr->cmd_status != MFI_STAT_OK) {
1417159811Sps		free(ld_info, M_MFIBUF);
1418157114Sscottl		mfi_release_command(cm);
1419157114Sscottl		return;
1420157114Sscottl	}
1421157114Sscottl	mfi_release_command(cm);
1422157114Sscottl
1423157114Sscottl	ld = malloc(sizeof(struct mfi_ld), M_MFIBUF, M_NOWAIT|M_ZERO);
1424157114Sscottl	if (ld == NULL) {
1425157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate ld\n");
1426159811Sps		free(ld_info, M_MFIBUF);
1427159811Sps		return;
1428157114Sscottl	}
1429157114Sscottl
1430157114Sscottl	if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) {
1431157114Sscottl		device_printf(sc->mfi_dev, "Failed to add logical disk\n");
1432157624Sscottl		free(ld, M_MFIBUF);
1433159811Sps		free(ld_info, M_MFIBUF);
1434159811Sps		return;
1435157114Sscottl	}
1436157114Sscottl
1437163398Sscottl	ld->ld_id = ld_info->ld_config.properties.ld.v.target_id;
1438157114Sscottl	ld->ld_disk = child;
1439159811Sps	ld->ld_info = ld_info;
1440157114Sscottl
1441157114Sscottl	device_set_ivars(child, ld);
1442157114Sscottl	device_set_desc(child, "MFI Logical Disk");
1443157114Sscottl	mtx_unlock(&sc->mfi_io_lock);
1444157114Sscottl	mtx_lock(&Giant);
1445157114Sscottl	bus_generic_attach(sc->mfi_dev);
1446157114Sscottl	mtx_unlock(&Giant);
1447157114Sscottl	mtx_lock(&sc->mfi_io_lock);
1448157114Sscottl}
1449163399Sscottl
1450157114Sscottlstatic struct mfi_command *
1451157114Sscottlmfi_bio_command(struct mfi_softc *sc)
1452157114Sscottl{
1453157114Sscottl	struct mfi_io_frame *io;
1454157114Sscottl	struct mfi_command *cm;
1455157114Sscottl	struct bio *bio;
1456158737Sambrisko	int flags, blkcount;
1457157114Sscottl
1458157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
1459157114Sscottl		return (NULL);
1460157114Sscottl
1461157114Sscottl	if ((bio = mfi_dequeue_bio(sc)) == NULL) {
1462157114Sscottl		mfi_release_command(cm);
1463157114Sscottl		return (NULL);
1464157114Sscottl	}
1465157114Sscottl
1466157114Sscottl	io = &cm->cm_frame->io;
1467157114Sscottl	switch (bio->bio_cmd & 0x03) {
1468157114Sscottl	case BIO_READ:
1469157114Sscottl		io->header.cmd = MFI_CMD_LD_READ;
1470157114Sscottl		flags = MFI_CMD_DATAIN;
1471157114Sscottl		break;
1472157114Sscottl	case BIO_WRITE:
1473157114Sscottl		io->header.cmd = MFI_CMD_LD_WRITE;
1474157114Sscottl		flags = MFI_CMD_DATAOUT;
1475157114Sscottl		break;
1476157114Sscottl	default:
1477157114Sscottl		panic("Invalid bio command");
1478157114Sscottl	}
1479157114Sscottl
1480157114Sscottl	/* Cheat with the sector length to avoid a non-constant division */
1481157114Sscottl	blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
1482157114Sscottl	io->header.target_id = (uintptr_t)bio->bio_driver1;
1483157114Sscottl	io->header.timeout = 0;
1484157114Sscottl	io->header.flags = 0;
1485157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
1486157114Sscottl	io->header.data_len = blkcount;
1487157114Sscottl	io->sense_addr_lo = cm->cm_sense_busaddr;
1488157114Sscottl	io->sense_addr_hi = 0;
1489157114Sscottl	io->lba_hi = (bio->bio_pblkno & 0xffffffff00000000) >> 32;
1490157114Sscottl	io->lba_lo = bio->bio_pblkno & 0xffffffff;
1491157114Sscottl	cm->cm_complete = mfi_bio_complete;
1492157114Sscottl	cm->cm_private = bio;
1493157114Sscottl	cm->cm_data = bio->bio_data;
1494157114Sscottl	cm->cm_len = bio->bio_bcount;
1495157114Sscottl	cm->cm_sg = &io->sgl;
1496157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
1497157114Sscottl	cm->cm_flags = flags;
1498157114Sscottl	return (cm);
1499157114Sscottl}
1500157114Sscottl
1501157114Sscottlstatic void
1502157114Sscottlmfi_bio_complete(struct mfi_command *cm)
1503157114Sscottl{
1504157114Sscottl	struct bio *bio;
1505157114Sscottl	struct mfi_frame_header *hdr;
1506157114Sscottl	struct mfi_softc *sc;
1507157114Sscottl
1508157114Sscottl	bio = cm->cm_private;
1509157114Sscottl	hdr = &cm->cm_frame->header;
1510157114Sscottl	sc = cm->cm_sc;
1511157114Sscottl
1512157114Sscottl	if ((hdr->cmd_status != 0) || (hdr->scsi_status != 0)) {
1513157114Sscottl		bio->bio_flags |= BIO_ERROR;
1514157114Sscottl		bio->bio_error = EIO;
1515157114Sscottl		device_printf(sc->mfi_dev, "I/O error, status= %d "
1516157114Sscottl		    "scsi_status= %d\n", hdr->cmd_status, hdr->scsi_status);
1517157114Sscottl		mfi_print_sense(cm->cm_sc, cm->cm_sense);
1518157114Sscottl	}
1519157114Sscottl
1520157114Sscottl	mfi_release_command(cm);
1521157114Sscottl	mfi_disk_complete(bio);
1522157114Sscottl}
1523157114Sscottl
1524157114Sscottlvoid
1525157114Sscottlmfi_startio(struct mfi_softc *sc)
1526157114Sscottl{
1527157114Sscottl	struct mfi_command *cm;
1528157114Sscottl
1529157114Sscottl	for (;;) {
1530157114Sscottl		/* Don't bother if we're short on resources */
1531157114Sscottl		if (sc->mfi_flags & MFI_FLAGS_QFRZN)
1532157114Sscottl			break;
1533157114Sscottl
1534157114Sscottl		/* Try a command that has already been prepared */
1535157114Sscottl		cm = mfi_dequeue_ready(sc);
1536157114Sscottl
1537157114Sscottl		/* Nope, so look for work on the bioq */
1538157114Sscottl		if (cm == NULL)
1539157114Sscottl			cm = mfi_bio_command(sc);
1540157114Sscottl
1541157114Sscottl		/* No work available, so exit */
1542157114Sscottl		if (cm == NULL)
1543157114Sscottl			break;
1544157114Sscottl
1545157114Sscottl		/* Send the command to the controller */
1546157114Sscottl		if (mfi_mapcmd(sc, cm) != 0) {
1547157114Sscottl			mfi_requeue_ready(cm);
1548157114Sscottl			break;
1549157114Sscottl		}
1550157114Sscottl	}
1551157114Sscottl}
1552157114Sscottl
1553157114Sscottlstatic int
1554157114Sscottlmfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm)
1555157114Sscottl{
1556157114Sscottl	int error, polled;
1557157114Sscottl
1558163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1559163398Sscottl
1560157114Sscottl	if (cm->cm_data != NULL) {
1561157114Sscottl		polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0;
1562157114Sscottl		error = bus_dmamap_load(sc->mfi_buffer_dmat, cm->cm_dmamap,
1563157114Sscottl		    cm->cm_data, cm->cm_len, mfi_data_cb, cm, polled);
1564157114Sscottl		if (error == EINPROGRESS) {
1565157114Sscottl			sc->mfi_flags |= MFI_FLAGS_QFRZN;
1566157114Sscottl			return (0);
1567157114Sscottl		}
1568157114Sscottl	} else {
1569162619Sscottl		cm->cm_timestamp = time_uptime;
1570157114Sscottl		mfi_enqueue_busy(cm);
1571157114Sscottl		error = mfi_send_frame(sc, cm);
1572157114Sscottl	}
1573157114Sscottl
1574157114Sscottl	return (error);
1575157114Sscottl}
1576157114Sscottl
1577157114Sscottlstatic void
1578157114Sscottlmfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
1579157114Sscottl{
1580157114Sscottl	struct mfi_frame_header *hdr;
1581157114Sscottl	struct mfi_command *cm;
1582157237Sscottl	union mfi_sgl *sgl;
1583157114Sscottl	struct mfi_softc *sc;
1584157114Sscottl	int i, dir;
1585157114Sscottl
1586157114Sscottl	if (error)
1587157114Sscottl		return;
1588157114Sscottl
1589157114Sscottl	cm = (struct mfi_command *)arg;
1590157114Sscottl	sc = cm->cm_sc;
1591157237Sscottl	hdr = &cm->cm_frame->header;
1592157237Sscottl	sgl = cm->cm_sg;
1593157114Sscottl
1594157237Sscottl	if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
1595157237Sscottl		for (i = 0; i < nsegs; i++) {
1596157237Sscottl			sgl->sg32[i].addr = segs[i].ds_addr;
1597157237Sscottl			sgl->sg32[i].len = segs[i].ds_len;
1598157114Sscottl		}
1599157237Sscottl	} else {
1600157237Sscottl		for (i = 0; i < nsegs; i++) {
1601157237Sscottl			sgl->sg64[i].addr = segs[i].ds_addr;
1602157237Sscottl			sgl->sg64[i].len = segs[i].ds_len;
1603157237Sscottl		}
1604157237Sscottl		hdr->flags |= MFI_FRAME_SGL64;
1605157114Sscottl	}
1606157114Sscottl	hdr->sg_count = nsegs;
1607157114Sscottl
1608157114Sscottl	dir = 0;
1609157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAIN) {
1610157114Sscottl		dir |= BUS_DMASYNC_PREREAD;
1611157114Sscottl		hdr->flags |= MFI_FRAME_DIR_READ;
1612157114Sscottl	}
1613157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAOUT) {
1614157114Sscottl		dir |= BUS_DMASYNC_PREWRITE;
1615157114Sscottl		hdr->flags |= MFI_FRAME_DIR_WRITE;
1616157114Sscottl	}
1617157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
1618157114Sscottl	cm->cm_flags |= MFI_CMD_MAPPED;
1619157114Sscottl
1620157114Sscottl	/*
1621157114Sscottl	 * Instead of calculating the total number of frames in the
1622157114Sscottl	 * compound frame, it's already assumed that there will be at
1623157114Sscottl	 * least 1 frame, so don't compensate for the modulo of the
1624157114Sscottl	 * following division.
1625157114Sscottl	 */
1626162458Sscottl	cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs);
1627157114Sscottl	cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
1628157114Sscottl
1629157114Sscottl	/* The caller will take care of delivering polled commands */
1630157114Sscottl	if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
1631162619Sscottl		cm->cm_timestamp = time_uptime;
1632157114Sscottl		mfi_enqueue_busy(cm);
1633157114Sscottl		mfi_send_frame(sc, cm);
1634157114Sscottl	}
1635157114Sscottl
1636157114Sscottl	return;
1637157114Sscottl}
1638157114Sscottl
1639157114Sscottlstatic int
1640157114Sscottlmfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
1641157114Sscottl{
1642157114Sscottl
1643157114Sscottl	/*
1644157114Sscottl	 * The bus address of the command is aligned on a 64 byte boundary,
1645157114Sscottl	 * leaving the least 6 bits as zero.  For whatever reason, the
1646157114Sscottl	 * hardware wants the address shifted right by three, leaving just
1647162458Sscottl	 * 3 zero bits.  These three bits are then used as a prefetching
1648162458Sscottl	 * hint for the hardware to predict how many frames need to be
1649162458Sscottl	 * fetched across the bus.  If a command has more than 8 frames
1650162458Sscottl	 * then the 3 bits are set to 0x7 and the firmware uses other
1651162458Sscottl	 * information in the command to determine the total amount to fetch.
1652162458Sscottl	 * However, FreeBSD doesn't support I/O larger than 128K, so 8 frames
1653162458Sscottl	 * is enough for both 32bit and 64bit systems.
1654157114Sscottl	 */
1655162458Sscottl	if (cm->cm_extra_frames > 7)
1656162458Sscottl		cm->cm_extra_frames = 7;
1657162458Sscottl
1658157114Sscottl	MFI_WRITE4(sc, MFI_IQP, (cm->cm_frame_busaddr >> 3) |
1659157114Sscottl	    cm->cm_extra_frames);
1660157114Sscottl	return (0);
1661157114Sscottl}
1662157114Sscottl
1663157114Sscottlstatic void
1664157114Sscottlmfi_complete(struct mfi_softc *sc, struct mfi_command *cm)
1665157114Sscottl{
1666157114Sscottl	int dir;
1667157114Sscottl
1668157114Sscottl	if ((cm->cm_flags & MFI_CMD_MAPPED) != 0) {
1669157114Sscottl		dir = 0;
1670157114Sscottl		if (cm->cm_flags & MFI_CMD_DATAIN)
1671157114Sscottl			dir |= BUS_DMASYNC_POSTREAD;
1672157114Sscottl		if (cm->cm_flags & MFI_CMD_DATAOUT)
1673157114Sscottl			dir |= BUS_DMASYNC_POSTWRITE;
1674157114Sscottl
1675157114Sscottl		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
1676157114Sscottl		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1677157114Sscottl		cm->cm_flags &= ~MFI_CMD_MAPPED;
1678157114Sscottl	}
1679157114Sscottl
1680157114Sscottl	if (cm->cm_complete != NULL)
1681157114Sscottl		cm->cm_complete(cm);
1682159811Sps	else
1683159811Sps		wakeup(cm);
1684157114Sscottl}
1685157114Sscottl
1686158737Sambriskostatic int
1687158737Sambriskomfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort)
1688158737Sambrisko{
1689158737Sambrisko	struct mfi_command *cm;
1690158737Sambrisko	struct mfi_abort_frame *abort;
1691158737Sambrisko
1692163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1693163398Sscottl
1694158737Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL) {
1695158737Sambrisko		return (EBUSY);
1696158737Sambrisko	}
1697158737Sambrisko
1698158737Sambrisko	abort = &cm->cm_frame->abort;
1699158737Sambrisko	abort->header.cmd = MFI_CMD_ABORT;
1700158737Sambrisko	abort->header.flags = 0;
1701158737Sambrisko	abort->abort_context = cm_abort->cm_frame->header.context;
1702158737Sambrisko	abort->abort_mfi_addr_lo = cm_abort->cm_frame_busaddr;
1703158737Sambrisko	abort->abort_mfi_addr_hi = 0;
1704158737Sambrisko	cm->cm_data = NULL;
1705158737Sambrisko
1706158737Sambrisko	sc->mfi_aen_cm->cm_aen_abort = 1;
1707158737Sambrisko	mfi_mapcmd(sc, cm);
1708158737Sambrisko	mfi_polled_command(sc, cm);
1709158737Sambrisko	mfi_release_command(cm);
1710158737Sambrisko
1711158737Sambrisko	while (sc->mfi_aen_cm != NULL) {
1712163398Sscottl		msleep(&sc->mfi_aen_cm, &sc->mfi_io_lock, 0, "mfiabort", 5 * hz);
1713158737Sambrisko	}
1714158737Sambrisko
1715158737Sambrisko	return (0);
1716158737Sambrisko}
1717158737Sambrisko
1718157114Sscottlint
1719157114Sscottlmfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, int len)
1720157114Sscottl{
1721157114Sscottl	struct mfi_command *cm;
1722157114Sscottl	struct mfi_io_frame *io;
1723157114Sscottl	int error;
1724157114Sscottl
1725157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
1726157114Sscottl		return (EBUSY);
1727157114Sscottl
1728157114Sscottl	io = &cm->cm_frame->io;
1729157114Sscottl	io->header.cmd = MFI_CMD_LD_WRITE;
1730157114Sscottl	io->header.target_id = id;
1731157114Sscottl	io->header.timeout = 0;
1732157114Sscottl	io->header.flags = 0;
1733157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
1734157114Sscottl	io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
1735157114Sscottl	io->sense_addr_lo = cm->cm_sense_busaddr;
1736157114Sscottl	io->sense_addr_hi = 0;
1737157114Sscottl	io->lba_hi = (lba & 0xffffffff00000000) >> 32;
1738157114Sscottl	io->lba_lo = lba & 0xffffffff;
1739157114Sscottl	cm->cm_data = virt;
1740157114Sscottl	cm->cm_len = len;
1741157114Sscottl	cm->cm_sg = &io->sgl;
1742157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
1743157114Sscottl	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT;
1744157114Sscottl
1745157114Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
1746157114Sscottl		mfi_release_command(cm);
1747157114Sscottl		return (error);
1748157114Sscottl	}
1749157114Sscottl
1750157114Sscottl	error = mfi_polled_command(sc, cm);
1751157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1752157114Sscottl	    BUS_DMASYNC_POSTWRITE);
1753157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1754157114Sscottl	mfi_release_command(cm);
1755157114Sscottl
1756157114Sscottl	return (error);
1757157114Sscottl}
1758157114Sscottl
1759157114Sscottlstatic int
1760157114Sscottlmfi_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
1761157114Sscottl{
1762157114Sscottl	struct mfi_softc *sc;
1763157114Sscottl
1764157114Sscottl	sc = dev->si_drv1;
1765163398Sscottl
1766163398Sscottl	mtx_lock(&sc->mfi_io_lock);
1767157114Sscottl	sc->mfi_flags |= MFI_FLAGS_OPEN;
1768163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1769157114Sscottl
1770157114Sscottl	return (0);
1771157114Sscottl}
1772157114Sscottl
1773157114Sscottlstatic int
1774157114Sscottlmfi_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
1775157114Sscottl{
1776157114Sscottl	struct mfi_softc *sc;
1777163398Sscottl	struct mfi_aen *mfi_aen_entry, *tmp;
1778157114Sscottl
1779157114Sscottl	sc = dev->si_drv1;
1780163398Sscottl
1781163398Sscottl	mtx_lock(&sc->mfi_io_lock);
1782157114Sscottl	sc->mfi_flags &= ~MFI_FLAGS_OPEN;
1783157114Sscottl
1784163398Sscottl	TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
1785158737Sambrisko		if (mfi_aen_entry->p == curproc) {
1786158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
1787158737Sambrisko			    aen_link);
1788158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
1789158737Sambrisko		}
1790158737Sambrisko	}
1791163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1792157114Sscottl	return (0);
1793157114Sscottl}
1794157114Sscottl
1795157114Sscottlstatic int
1796157114Sscottlmfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
1797157114Sscottl{
1798157114Sscottl	struct mfi_softc *sc;
1799157114Sscottl	union mfi_statrequest *ms;
1800157114Sscottl	int error;
1801157114Sscottl
1802157114Sscottl	sc = dev->si_drv1;
1803157114Sscottl	error = 0;
1804157114Sscottl
1805157114Sscottl	switch (cmd) {
1806157114Sscottl	case MFIIO_STATS:
1807157114Sscottl		ms = (union mfi_statrequest *)arg;
1808157114Sscottl		switch (ms->ms_item) {
1809157114Sscottl		case MFIQ_FREE:
1810157114Sscottl		case MFIQ_BIO:
1811157114Sscottl		case MFIQ_READY:
1812157114Sscottl		case MFIQ_BUSY:
1813157114Sscottl			bcopy(&sc->mfi_qstat[ms->ms_item], &ms->ms_qstat,
1814157114Sscottl			    sizeof(struct mfi_qstat));
1815157114Sscottl			break;
1816157114Sscottl		default:
1817158737Sambrisko			error = ENOIOCTL;
1818157114Sscottl			break;
1819157114Sscottl		}
1820157114Sscottl		break;
1821158737Sambrisko	case 0xc1144d01: /* Firmware Linux ioctl shim */
1822158737Sambrisko		{
1823158737Sambrisko			devclass_t devclass;
1824158737Sambrisko			struct mfi_linux_ioc_packet l_ioc;
1825158737Sambrisko			int adapter;
1826158737Sambrisko
1827158737Sambrisko			devclass = devclass_find("mfi");
1828158737Sambrisko			if (devclass == NULL)
1829158737Sambrisko				return (ENOENT);
1830158737Sambrisko
1831158737Sambrisko			error = copyin(arg, &l_ioc, sizeof(l_ioc));
1832158737Sambrisko			if (error)
1833158737Sambrisko				return (error);
1834158737Sambrisko			adapter = l_ioc.lioc_adapter_no;
1835158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
1836158737Sambrisko			if (sc == NULL)
1837158737Sambrisko				return (ENOENT);
1838158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
1839158737Sambrisko			    cmd, arg, flag, td));
1840158737Sambrisko			break;
1841158737Sambrisko		}
1842158737Sambrisko	case 0x400c4d03: /* AEN Linux ioctl shim */
1843158737Sambrisko		{
1844158737Sambrisko			devclass_t devclass;
1845158737Sambrisko			struct mfi_linux_ioc_aen l_aen;
1846158737Sambrisko			int adapter;
1847158737Sambrisko
1848158737Sambrisko			devclass = devclass_find("mfi");
1849158737Sambrisko			if (devclass == NULL)
1850158737Sambrisko				return (ENOENT);
1851158737Sambrisko
1852158737Sambrisko			error = copyin(arg, &l_aen, sizeof(l_aen));
1853158737Sambrisko			if (error)
1854158737Sambrisko				return (error);
1855158737Sambrisko			adapter = l_aen.laen_adapter_no;
1856158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
1857158737Sambrisko			if (sc == NULL)
1858158737Sambrisko				return (ENOENT);
1859158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
1860158737Sambrisko			    cmd, arg, flag, td));
1861158737Sambrisko			break;
1862158737Sambrisko		}
1863157114Sscottl	default:
1864163398Sscottl		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
1865157114Sscottl		error = ENOENT;
1866157114Sscottl		break;
1867157114Sscottl	}
1868157114Sscottl
1869157114Sscottl	return (error);
1870157114Sscottl}
1871158737Sambrisko
1872158737Sambriskostatic int
1873158737Sambriskomfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
1874158737Sambrisko{
1875158737Sambrisko	struct mfi_softc *sc;
1876158737Sambrisko	struct mfi_linux_ioc_packet l_ioc;
1877158737Sambrisko	struct mfi_linux_ioc_aen l_aen;
1878158737Sambrisko	struct mfi_command *cm = NULL;
1879158737Sambrisko	struct mfi_aen *mfi_aen_entry;
1880158737Sambrisko	uint32_t *sense_ptr;
1881158737Sambrisko	uint32_t context;
1882158737Sambrisko	uint8_t *data = NULL, *temp;
1883158737Sambrisko	int i;
1884158737Sambrisko	int error;
1885158737Sambrisko
1886158737Sambrisko	sc = dev->si_drv1;
1887158737Sambrisko	error = 0;
1888158737Sambrisko	switch (cmd) {
1889158737Sambrisko	case 0xc1144d01: /* Firmware Linux ioctl shim */
1890158737Sambrisko		error = copyin(arg, &l_ioc, sizeof(l_ioc));
1891158737Sambrisko		if (error != 0)
1892158737Sambrisko			return (error);
1893158737Sambrisko
1894158737Sambrisko		if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) {
1895158737Sambrisko			return (EINVAL);
1896158737Sambrisko		}
1897158737Sambrisko
1898158737Sambrisko		mtx_lock(&sc->mfi_io_lock);
1899158737Sambrisko		if ((cm = mfi_dequeue_free(sc)) == NULL) {
1900158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1901158737Sambrisko			return (EBUSY);
1902158737Sambrisko		}
1903158737Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1904158737Sambrisko
1905158737Sambrisko		/*
1906158737Sambrisko		 * save off original context since copying from user
1907158737Sambrisko		 * will clobber some data
1908158737Sambrisko		 */
1909158737Sambrisko		context = cm->cm_frame->header.context;
1910158737Sambrisko
1911158737Sambrisko		bcopy(l_ioc.lioc_frame.raw, cm->cm_frame,
1912158737Sambrisko		      l_ioc.lioc_sgl_off); /* Linux can do 2 frames ? */
1913158737Sambrisko		cm->cm_total_frame_size = l_ioc.lioc_sgl_off;
1914158737Sambrisko		cm->cm_sg =
1915158737Sambrisko		    (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
1916158737Sambrisko		cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT
1917158737Sambrisko			| MFI_CMD_POLLED;
1918158737Sambrisko		cm->cm_len = cm->cm_frame->header.data_len;
1919158737Sambrisko		cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
1920158737Sambrisko					    M_WAITOK | M_ZERO);
1921158737Sambrisko
1922158737Sambrisko		/* restore header context */
1923158737Sambrisko		cm->cm_frame->header.context = context;
1924158737Sambrisko
1925158737Sambrisko		temp = data;
1926158737Sambrisko		for (i = 0; i < l_ioc.lioc_sge_count; i++) {
1927158737Sambrisko			error = copyin(l_ioc.lioc_sgl[i].iov_base,
1928158737Sambrisko			       temp,
1929158737Sambrisko			       l_ioc.lioc_sgl[i].iov_len);
1930158737Sambrisko			if (error != 0) {
1931158737Sambrisko				device_printf(sc->mfi_dev,
1932158737Sambrisko				    "Copy in failed");
1933158737Sambrisko				goto out;
1934158737Sambrisko			}
1935158737Sambrisko			temp = &temp[l_ioc.lioc_sgl[i].iov_len];
1936158737Sambrisko		}
1937158737Sambrisko
1938158737Sambrisko		if (l_ioc.lioc_sense_len) {
1939158737Sambrisko			sense_ptr =
1940158737Sambrisko			    (void *)&cm->cm_frame->bytes[l_ioc.lioc_sense_off];
1941158737Sambrisko			*sense_ptr = cm->cm_sense_busaddr;
1942158737Sambrisko		}
1943158737Sambrisko
1944163398Sscottl		mtx_lock(&sc->mfi_io_lock);
1945158737Sambrisko		if ((error = mfi_mapcmd(sc, cm)) != 0) {
1946158737Sambrisko			device_printf(sc->mfi_dev,
1947158737Sambrisko			    "Controller info buffer map failed");
1948163398Sscottl			mtx_unlock(&sc->mfi_io_lock);
1949158737Sambrisko			goto out;
1950158737Sambrisko		}
1951158737Sambrisko
1952158737Sambrisko		if ((error = mfi_polled_command(sc, cm)) != 0) {
1953158737Sambrisko			device_printf(sc->mfi_dev,
1954158737Sambrisko			    "Controller polled failed");
1955163398Sscottl			mtx_unlock(&sc->mfi_io_lock);
1956158737Sambrisko			goto out;
1957158737Sambrisko		}
1958158737Sambrisko
1959158737Sambrisko		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1960158737Sambrisko				BUS_DMASYNC_POSTREAD);
1961158737Sambrisko		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1962163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
1963158737Sambrisko
1964158737Sambrisko		temp = data;
1965158737Sambrisko		for (i = 0; i < l_ioc.lioc_sge_count; i++) {
1966158737Sambrisko			error = copyout(temp,
1967158737Sambrisko				l_ioc.lioc_sgl[i].iov_base,
1968158737Sambrisko				l_ioc.lioc_sgl[i].iov_len);
1969158737Sambrisko			if (error != 0) {
1970158737Sambrisko				device_printf(sc->mfi_dev,
1971158737Sambrisko				    "Copy out failed");
1972158737Sambrisko				goto out;
1973158737Sambrisko			}
1974158737Sambrisko			temp = &temp[l_ioc.lioc_sgl[i].iov_len];
1975158737Sambrisko		}
1976158737Sambrisko
1977158737Sambrisko		if (l_ioc.lioc_sense_len) {
1978158737Sambrisko			/* copy out sense */
1979158737Sambrisko			sense_ptr = (void *)
1980158737Sambrisko			    &l_ioc.lioc_frame.raw[l_ioc.lioc_sense_off];
1981158737Sambrisko			temp = 0;
1982158737Sambrisko			temp += cm->cm_sense_busaddr;
1983158737Sambrisko			error = copyout(temp, sense_ptr,
1984158737Sambrisko			    l_ioc.lioc_sense_len);
1985158737Sambrisko			if (error != 0) {
1986158737Sambrisko				device_printf(sc->mfi_dev,
1987158737Sambrisko				    "Copy out failed");
1988158737Sambrisko				goto out;
1989158737Sambrisko			}
1990158737Sambrisko		}
1991158737Sambrisko
1992158737Sambrisko		error = copyout(&cm->cm_frame->header.cmd_status,
1993158737Sambrisko			&((struct mfi_linux_ioc_packet*)arg)
1994158737Sambrisko			->lioc_frame.hdr.cmd_status,
1995158737Sambrisko			1);
1996158737Sambrisko		if (error != 0) {
1997158737Sambrisko			device_printf(sc->mfi_dev,
1998158737Sambrisko				      "Copy out failed");
1999158737Sambrisko			goto out;
2000158737Sambrisko		}
2001158737Sambrisko
2002163398Sscottl		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
2003163398Sscottl			switch (cm->cm_frame->dcmd.opcode) {
2004163398Sscottl			case MFI_DCMD_CFG_CLEAR:
2005163398Sscottl			case MFI_DCMD_CFG_ADD:
2006163398Sscottl				/* mfi_ldrescan(sc); */
2007163398Sscottl				break;
2008163398Sscottl			}
2009163398Sscottl		}
2010158737Sambriskoout:
2011158737Sambrisko		if (data)
2012158737Sambrisko			free(data, M_MFIBUF);
2013158737Sambrisko		if (cm) {
2014158737Sambrisko			mtx_lock(&sc->mfi_io_lock);
2015158737Sambrisko			mfi_release_command(cm);
2016158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
2017158737Sambrisko		}
2018158737Sambrisko
2019158737Sambrisko		return (error);
2020158737Sambrisko	case 0x400c4d03: /* AEN Linux ioctl shim */
2021158737Sambrisko		error = copyin(arg, &l_aen, sizeof(l_aen));
2022158737Sambrisko		if (error != 0)
2023158737Sambrisko			return (error);
2024158737Sambrisko		printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid);
2025158737Sambrisko		mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF,
2026158737Sambrisko		    M_WAITOK);
2027163398Sscottl		mtx_lock(&sc->mfi_io_lock);
2028158737Sambrisko		if (mfi_aen_entry != NULL) {
2029158737Sambrisko			mfi_aen_entry->p = curproc;
2030158737Sambrisko			TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry,
2031158737Sambrisko			    aen_link);
2032158737Sambrisko		}
2033158737Sambrisko		error = mfi_aen_register(sc, l_aen.laen_seq_num,
2034158737Sambrisko		    l_aen.laen_class_locale);
2035158737Sambrisko
2036158737Sambrisko		if (error != 0) {
2037158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
2038158737Sambrisko			    aen_link);
2039158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
2040158737Sambrisko		}
2041163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
2042158737Sambrisko
2043158737Sambrisko		return (error);
2044158737Sambrisko	default:
2045158737Sambrisko		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
2046158737Sambrisko		error = ENOENT;
2047158737Sambrisko		break;
2048158737Sambrisko	}
2049158737Sambrisko
2050158737Sambrisko	return (error);
2051158737Sambrisko}
2052158737Sambrisko
2053158737Sambriskostatic int
2054158737Sambriskomfi_poll(struct cdev *dev, int poll_events, struct thread *td)
2055158737Sambrisko{
2056158737Sambrisko	struct mfi_softc *sc;
2057158737Sambrisko	int revents = 0;
2058158737Sambrisko
2059158737Sambrisko	sc = dev->si_drv1;
2060158737Sambrisko
2061158737Sambrisko	if (poll_events & (POLLIN | POLLRDNORM)) {
2062163398Sscottl		if (sc->mfi_aen_triggered != 0) {
2063158737Sambrisko			revents |= poll_events & (POLLIN | POLLRDNORM);
2064163398Sscottl			sc->mfi_aen_triggered = 0;
2065163398Sscottl		}
2066158737Sambrisko		if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) {
2067158737Sambrisko			revents |= POLLERR;
2068158737Sambrisko		}
2069158737Sambrisko	}
2070158737Sambrisko
2071158737Sambrisko	if (revents == 0) {
2072158737Sambrisko		if (poll_events & (POLLIN | POLLRDNORM)) {
2073158737Sambrisko			sc->mfi_poll_waiting = 1;
2074158737Sambrisko			selrecord(td, &sc->mfi_select);
2075158737Sambrisko		}
2076158737Sambrisko	}
2077158737Sambrisko
2078158737Sambrisko	return revents;
2079158737Sambrisko}
2080162619Sscottl
2081163398Sscottl
2082162619Sscottlstatic void
2083163398Sscottlmfi_dump_all(void)
2084163398Sscottl{
2085163398Sscottl	struct mfi_softc *sc;
2086163398Sscottl	struct mfi_command *cm;
2087163398Sscottl	devclass_t dc;
2088163398Sscottl	time_t deadline;
2089163398Sscottl	int timedout;
2090163398Sscottl	int i;
2091163398Sscottl
2092163398Sscottl	dc = devclass_find("mfi");
2093163398Sscottl	if (dc == NULL) {
2094163398Sscottl		printf("No mfi dev class\n");
2095163398Sscottl		return;
2096163398Sscottl	}
2097163398Sscottl
2098163398Sscottl	for (i = 0; ; i++) {
2099163398Sscottl		sc = devclass_get_softc(dc, i);
2100163398Sscottl		if (sc == NULL)
2101163398Sscottl			break;
2102163398Sscottl		device_printf(sc->mfi_dev, "Dumping\n\n");
2103163398Sscottl		timedout = 0;
2104163398Sscottl		deadline = time_uptime - MFI_CMD_TIMEOUT;
2105163398Sscottl		mtx_lock(&sc->mfi_io_lock);
2106163398Sscottl		TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
2107163398Sscottl			if (cm->cm_timestamp < deadline) {
2108163398Sscottl				device_printf(sc->mfi_dev,
2109163398Sscottl				    "COMMAND %p TIMEOUT AFTER %d SECONDS\n", cm,
2110163398Sscottl				    (int)(time_uptime - cm->cm_timestamp));
2111163398Sscottl				MFI_PRINT_CMD(cm);
2112163398Sscottl				timedout++;
2113163398Sscottl			}
2114163398Sscottl		}
2115163398Sscottl
2116163398Sscottl#if 0
2117163398Sscottl		if (timedout)
2118163398Sscottl			MFI_DUMP_CMDS(SC);
2119163398Sscottl#endif
2120163398Sscottl
2121163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
2122163398Sscottl	}
2123163398Sscottl
2124163398Sscottl	return;
2125163398Sscottl}
2126163398Sscottl
2127163398Sscottlstatic void
2128162619Sscottlmfi_timeout(void *data)
2129162619Sscottl{
2130162619Sscottl	struct mfi_softc *sc = (struct mfi_softc *)data;
2131162619Sscottl	struct mfi_command *cm;
2132162619Sscottl	time_t deadline;
2133162619Sscottl	int timedout = 0;
2134162619Sscottl
2135162619Sscottl	deadline = time_uptime - MFI_CMD_TIMEOUT;
2136162619Sscottl	mtx_lock(&sc->mfi_io_lock);
2137162619Sscottl	TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
2138162688Sscottl		if (sc->mfi_aen_cm == cm)
2139162688Sscottl			continue;
2140163398Sscottl		if ((sc->mfi_aen_cm != cm) && (cm->cm_timestamp < deadline)) {
2141162619Sscottl			device_printf(sc->mfi_dev,
2142162619Sscottl			    "COMMAND %p TIMEOUT AFTER %d SECONDS\n", cm,
2143162619Sscottl			    (int)(time_uptime - cm->cm_timestamp));
2144162619Sscottl			MFI_PRINT_CMD(cm);
2145163398Sscottl			MFI_VALIDATE_CMD(sc, cm);
2146162619Sscottl			timedout++;
2147162619Sscottl		}
2148162619Sscottl	}
2149162619Sscottl
2150162619Sscottl#if 0
2151162619Sscottl	if (timedout)
2152162619Sscottl		MFI_DUMP_CMDS(SC);
2153162619Sscottl#endif
2154162619Sscottl
2155162619Sscottl	mtx_unlock(&sc->mfi_io_lock);
2156162619Sscottl
2157162619Sscottl	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
2158162619Sscottl	    mfi_timeout, sc);
2159162619Sscottl
2160163398Sscottl	if (0)
2161163398Sscottl		mfi_dump_all();
2162162619Sscottl	return;
2163162619Sscottl}
2164