mfi.c revision 165852
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 165852 2007-01-07 06:43:25Z 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 *);
60159811Spsstatic int	mfi_wait_command(struct mfi_softc *, struct mfi_command *);
61157114Sscottlstatic int	mfi_get_controller_info(struct mfi_softc *);
62158737Sambriskostatic int	mfi_get_log_state(struct mfi_softc *,
63159806Sps		    struct mfi_evt_log_state **);
64158737Sambriskostatic int	mfi_get_entry(struct mfi_softc *, int);
65159806Spsstatic int	mfi_dcmd_command(struct mfi_softc *, struct mfi_command **,
66159806Sps		    uint32_t, void **, size_t);
67157114Sscottlstatic void	mfi_data_cb(void *, bus_dma_segment_t *, int, int);
68157114Sscottlstatic void	mfi_startup(void *arg);
69157114Sscottlstatic void	mfi_intr(void *arg);
70157114Sscottlstatic void	mfi_enable_intr(struct mfi_softc *sc);
71159811Spsstatic void	mfi_ldprobe(struct mfi_softc *sc);
72158737Sambriskostatic int	mfi_aen_register(struct mfi_softc *sc, int seq, int locale);
73158737Sambriskostatic void	mfi_aen_complete(struct mfi_command *);
74158737Sambriskostatic int	mfi_aen_setup(struct mfi_softc *, uint32_t);
75159811Spsstatic int	mfi_add_ld(struct mfi_softc *sc, int);
76159811Spsstatic void	mfi_add_ld_complete(struct mfi_command *);
77157114Sscottlstatic struct mfi_command * mfi_bio_command(struct mfi_softc *);
78157114Sscottlstatic void	mfi_bio_complete(struct mfi_command *);
79157114Sscottlstatic int	mfi_mapcmd(struct mfi_softc *, struct mfi_command *);
80157114Sscottlstatic int	mfi_send_frame(struct mfi_softc *, struct mfi_command *);
81157114Sscottlstatic void	mfi_complete(struct mfi_softc *, struct mfi_command *);
82158737Sambriskostatic int	mfi_abort(struct mfi_softc *, struct mfi_command *);
83158737Sambriskostatic int	mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int, d_thread_t *);
84162619Sscottlstatic void	mfi_timeout(void *);
85157114Sscottl
86162118Sambrisko
87162118SambriskoSYSCTL_NODE(_hw, OID_AUTO, mfi, CTLFLAG_RD, 0, "MFI driver parameters");
88162118Sambriskostatic int	mfi_event_locale = MFI_EVT_LOCALE_ALL;
89162473SambriskoTUNABLE_INT("hw.mfi.event_locale", &mfi_event_locale);
90162118SambriskoSYSCTL_INT(_hw_mfi, OID_AUTO, event_locale, CTLFLAG_RW, &mfi_event_locale,
91162118Sambrisko            0, "event message locale");
92162473Sambrisko
93165852Sscottlstatic int	mfi_event_class = MFI_EVT_CLASS_INFO;
94162473SambriskoTUNABLE_INT("hw.mfi.event_class", &mfi_event_class);
95162118SambriskoSYSCTL_INT(_hw_mfi, OID_AUTO, event_class, CTLFLAG_RW, &mfi_event_class,
96162118Sambrisko          0, "event message class");
97162118Sambrisko
98157114Sscottl/* Management interface */
99157114Sscottlstatic d_open_t		mfi_open;
100157114Sscottlstatic d_close_t	mfi_close;
101157114Sscottlstatic d_ioctl_t	mfi_ioctl;
102158737Sambriskostatic d_poll_t		mfi_poll;
103157114Sscottl
104157114Sscottlstatic struct cdevsw mfi_cdevsw = {
105157114Sscottl	.d_version = 	D_VERSION,
106157114Sscottl	.d_flags =	0,
107157114Sscottl	.d_open = 	mfi_open,
108157114Sscottl	.d_close =	mfi_close,
109157114Sscottl	.d_ioctl =	mfi_ioctl,
110158737Sambrisko	.d_poll =	mfi_poll,
111157114Sscottl	.d_name =	"mfi",
112157114Sscottl};
113157114Sscottl
114157114SscottlMALLOC_DEFINE(M_MFIBUF, "mfibuf", "Buffers for the MFI driver");
115157114Sscottl
116158737Sambrisko#define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH
117157114Sscottl
118157114Sscottlstatic int
119157114Sscottlmfi_transition_firmware(struct mfi_softc *sc)
120157114Sscottl{
121157114Sscottl	int32_t fw_state, cur_state;
122157114Sscottl	int max_wait, i;
123157114Sscottl
124157114Sscottl	fw_state = MFI_READ4(sc, MFI_OMSG0) & MFI_FWSTATE_MASK;
125157114Sscottl	while (fw_state != MFI_FWSTATE_READY) {
126157114Sscottl		if (bootverbose)
127157114Sscottl			device_printf(sc->mfi_dev, "Waiting for firmware to "
128157114Sscottl			    "become ready\n");
129157114Sscottl		cur_state = fw_state;
130157114Sscottl		switch (fw_state) {
131157114Sscottl		case MFI_FWSTATE_FAULT:
132157114Sscottl			device_printf(sc->mfi_dev, "Firmware fault\n");
133157114Sscottl			return (ENXIO);
134157114Sscottl		case MFI_FWSTATE_WAIT_HANDSHAKE:
135157114Sscottl			MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
136157114Sscottl			max_wait = 2;
137157114Sscottl			break;
138157114Sscottl		case MFI_FWSTATE_OPERATIONAL:
139157114Sscottl			MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY);
140157114Sscottl			max_wait = 10;
141157114Sscottl			break;
142157114Sscottl		case MFI_FWSTATE_UNDEFINED:
143157114Sscottl		case MFI_FWSTATE_BB_INIT:
144157114Sscottl			max_wait = 2;
145157114Sscottl			break;
146157114Sscottl		case MFI_FWSTATE_FW_INIT:
147157114Sscottl		case MFI_FWSTATE_DEVICE_SCAN:
148157114Sscottl		case MFI_FWSTATE_FLUSH_CACHE:
149157114Sscottl			max_wait = 20;
150157114Sscottl			break;
151157114Sscottl		default:
152157114Sscottl			device_printf(sc->mfi_dev,"Unknown firmware state %d\n",
153157114Sscottl			    fw_state);
154157114Sscottl			return (ENXIO);
155157114Sscottl		}
156157114Sscottl		for (i = 0; i < (max_wait * 10); i++) {
157157114Sscottl			fw_state = MFI_READ4(sc, MFI_OMSG0) & MFI_FWSTATE_MASK;
158157114Sscottl			if (fw_state == cur_state)
159157114Sscottl				DELAY(100000);
160157114Sscottl			else
161157114Sscottl				break;
162157114Sscottl		}
163157114Sscottl		if (fw_state == cur_state) {
164157114Sscottl			device_printf(sc->mfi_dev, "firmware stuck in state "
165157114Sscottl			    "%#x\n", fw_state);
166157114Sscottl			return (ENXIO);
167157114Sscottl		}
168157114Sscottl	}
169157114Sscottl	return (0);
170157114Sscottl}
171157114Sscottl
172157114Sscottlstatic void
173157114Sscottlmfi_addr32_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
174157114Sscottl{
175157114Sscottl	uint32_t *addr;
176157114Sscottl
177157114Sscottl	addr = arg;
178157114Sscottl	*addr = segs[0].ds_addr;
179157114Sscottl}
180157114Sscottl
181157114Sscottlint
182157114Sscottlmfi_attach(struct mfi_softc *sc)
183157114Sscottl{
184157114Sscottl	uint32_t status;
185157114Sscottl	int error, commsz, framessz, sensesz;
186162458Sscottl	int frames, unit, max_fw_sge;
187157114Sscottl
188157114Sscottl	mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF);
189157114Sscottl	TAILQ_INIT(&sc->mfi_ld_tqh);
190158737Sambrisko	TAILQ_INIT(&sc->mfi_aen_pids);
191157114Sscottl
192157114Sscottl	mfi_initq_free(sc);
193157114Sscottl	mfi_initq_ready(sc);
194157114Sscottl	mfi_initq_busy(sc);
195157114Sscottl	mfi_initq_bio(sc);
196157114Sscottl
197157114Sscottl	/* Before we get too far, see if the firmware is working */
198157114Sscottl	if ((error = mfi_transition_firmware(sc)) != 0) {
199157114Sscottl		device_printf(sc->mfi_dev, "Firmware not in READY state, "
200157114Sscottl		    "error %d\n", error);
201157114Sscottl		return (ENXIO);
202157114Sscottl	}
203157114Sscottl
204157114Sscottl	/*
205157114Sscottl	 * Get information needed for sizing the contiguous memory for the
206157114Sscottl	 * frame pool.  Size down the sgl parameter since we know that
207157114Sscottl	 * we will never need more than what's required for MAXPHYS.
208157114Sscottl	 * It would be nice if these constants were available at runtime
209157114Sscottl	 * instead of compile time.
210157114Sscottl	 */
211157114Sscottl	status = MFI_READ4(sc, MFI_OMSG0);
212157114Sscottl	sc->mfi_max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK;
213162458Sscottl	max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16;
214162458Sscottl	sc->mfi_max_sge = min(max_fw_sge, ((MAXPHYS / PAGE_SIZE) + 1));
215157114Sscottl
216157114Sscottl	/*
217157114Sscottl	 * Create the dma tag for data buffers.  Used both for block I/O
218157114Sscottl	 * and for various internal data queries.
219157114Sscottl	 */
220157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
221157114Sscottl				1, 0,			/* algnmnt, boundary */
222157114Sscottl				BUS_SPACE_MAXADDR,	/* lowaddr */
223157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
224157114Sscottl				NULL, NULL,		/* filter, filterarg */
225157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
226162458Sscottl				sc->mfi_max_sge,	/* nsegments */
227157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
228157114Sscottl				BUS_DMA_ALLOCNOW,	/* flags */
229157114Sscottl				busdma_lock_mutex,	/* lockfunc */
230157114Sscottl				&sc->mfi_io_lock,	/* lockfuncarg */
231157114Sscottl				&sc->mfi_buffer_dmat)) {
232157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate buffer DMA tag\n");
233157114Sscottl		return (ENOMEM);
234157114Sscottl	}
235157114Sscottl
236157114Sscottl	/*
237157114Sscottl	 * Allocate DMA memory for the comms queues.  Keep it under 4GB for
238157114Sscottl	 * efficiency.  The mfi_hwcomms struct includes space for 1 reply queue
239157114Sscottl	 * entry, so the calculated size here will be will be 1 more than
240157114Sscottl	 * mfi_max_fw_cmds.  This is apparently a requirement of the hardware.
241157114Sscottl	 */
242157114Sscottl	commsz = (sizeof(uint32_t) * sc->mfi_max_fw_cmds) +
243157114Sscottl	    sizeof(struct mfi_hwcomms);
244157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
245157114Sscottl				1, 0,			/* algnmnt, boundary */
246157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
247157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
248157114Sscottl				NULL, NULL,		/* filter, filterarg */
249157114Sscottl				commsz,			/* maxsize */
250157114Sscottl				1,			/* msegments */
251157114Sscottl				commsz,			/* maxsegsize */
252157114Sscottl				0,			/* flags */
253157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
254157114Sscottl				&sc->mfi_comms_dmat)) {
255157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
256157114Sscottl		return (ENOMEM);
257157114Sscottl	}
258157114Sscottl	if (bus_dmamem_alloc(sc->mfi_comms_dmat, (void **)&sc->mfi_comms,
259157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_comms_dmamap)) {
260157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
261157114Sscottl		return (ENOMEM);
262157114Sscottl	}
263157114Sscottl	bzero(sc->mfi_comms, commsz);
264157114Sscottl	bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap,
265157114Sscottl	    sc->mfi_comms, commsz, mfi_addr32_cb, &sc->mfi_comms_busaddr, 0);
266157114Sscottl
267157114Sscottl	/*
268157114Sscottl	 * Allocate DMA memory for the command frames.  Keep them in the
269162458Sscottl	 * lower 4GB for efficiency.  Calculate the size of the commands at
270162458Sscottl	 * the same time; each command is one 64 byte frame plus a set of
271162458Sscottl         * additional frames for holding sg lists or other data.
272157114Sscottl	 * The assumption here is that the SG list will start at the second
273162458Sscottl	 * frame and not use the unused bytes in the first frame.  While this
274162458Sscottl	 * isn't technically correct, it simplifies the calculation and allows
275162458Sscottl	 * for command frames that might be larger than an mfi_io_frame.
276157114Sscottl	 */
277157114Sscottl	if (sizeof(bus_addr_t) == 8) {
278162458Sscottl		sc->mfi_sge_size = sizeof(struct mfi_sg64);
279157114Sscottl		sc->mfi_flags |= MFI_FLAGS_SG64;
280157114Sscottl	} else {
281162458Sscottl		sc->mfi_sge_size = sizeof(struct mfi_sg32);
282157114Sscottl	}
283162458Sscottl	frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2;
284162458Sscottl	sc->mfi_cmd_size = frames * MFI_FRAME_SIZE;
285162458Sscottl	framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds;
286157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
287157114Sscottl				64, 0,			/* algnmnt, boundary */
288157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
289157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
290157114Sscottl				NULL, NULL,		/* filter, filterarg */
291157114Sscottl				framessz,		/* maxsize */
292157114Sscottl				1,			/* nsegments */
293157114Sscottl				framessz,		/* maxsegsize */
294157114Sscottl				0,			/* flags */
295157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
296157114Sscottl				&sc->mfi_frames_dmat)) {
297157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frame DMA tag\n");
298157114Sscottl		return (ENOMEM);
299157114Sscottl	}
300157114Sscottl	if (bus_dmamem_alloc(sc->mfi_frames_dmat, (void **)&sc->mfi_frames,
301157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_frames_dmamap)) {
302157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frames memory\n");
303157114Sscottl		return (ENOMEM);
304157114Sscottl	}
305157114Sscottl	bzero(sc->mfi_frames, framessz);
306157114Sscottl	bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap,
307157114Sscottl	    sc->mfi_frames, framessz, mfi_addr32_cb, &sc->mfi_frames_busaddr,0);
308157114Sscottl
309157114Sscottl	/*
310157114Sscottl	 * Allocate DMA memory for the frame sense data.  Keep them in the
311157114Sscottl	 * lower 4GB for efficiency
312157114Sscottl	 */
313157114Sscottl	sensesz = sc->mfi_max_fw_cmds * MFI_SENSE_LEN;
314157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
315157114Sscottl				4, 0,			/* algnmnt, boundary */
316157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
317157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
318157114Sscottl				NULL, NULL,		/* filter, filterarg */
319157114Sscottl				sensesz,		/* maxsize */
320157114Sscottl				1,			/* nsegments */
321157114Sscottl				sensesz,		/* maxsegsize */
322157114Sscottl				0,			/* flags */
323157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
324157114Sscottl				&sc->mfi_sense_dmat)) {
325157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense DMA tag\n");
326157114Sscottl		return (ENOMEM);
327157114Sscottl	}
328157114Sscottl	if (bus_dmamem_alloc(sc->mfi_sense_dmat, (void **)&sc->mfi_sense,
329157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_sense_dmamap)) {
330157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense memory\n");
331157114Sscottl		return (ENOMEM);
332157114Sscottl	}
333157114Sscottl	bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap,
334157114Sscottl	    sc->mfi_sense, sensesz, mfi_addr32_cb, &sc->mfi_sense_busaddr, 0);
335157114Sscottl
336157114Sscottl	if ((error = mfi_alloc_commands(sc)) != 0)
337157114Sscottl		return (error);
338157114Sscottl
339157114Sscottl	if ((error = mfi_comms_init(sc)) != 0)
340157114Sscottl		return (error);
341157114Sscottl
342157114Sscottl	if ((error = mfi_get_controller_info(sc)) != 0)
343157114Sscottl		return (error);
344157114Sscottl
345163398Sscottl	mtx_lock(&sc->mfi_io_lock);
346163398Sscottl	if ((error = mfi_aen_setup(sc, 0), 0) != 0) {
347163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
348157114Sscottl		return (error);
349163398Sscottl	}
350163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
351157114Sscottl
352157114Sscottl	/*
353157114Sscottl	 * Set up the interrupt handler.  XXX This should happen in
354157114Sscottl	 * mfi_pci.c
355157114Sscottl	 */
356157114Sscottl	sc->mfi_irq_rid = 0;
357157114Sscottl	if ((sc->mfi_irq = bus_alloc_resource_any(sc->mfi_dev, SYS_RES_IRQ,
358157114Sscottl	    &sc->mfi_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
359157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate interrupt\n");
360157114Sscottl		return (EINVAL);
361157114Sscottl	}
362157114Sscottl	if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, INTR_MPSAFE|INTR_TYPE_BIO,
363157114Sscottl	    mfi_intr, sc, &sc->mfi_intr)) {
364157114Sscottl		device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
365157114Sscottl		return (EINVAL);
366157114Sscottl	}
367157114Sscottl
368157114Sscottl	/* Register a config hook to probe the bus for arrays */
369157114Sscottl	sc->mfi_ich.ich_func = mfi_startup;
370157114Sscottl	sc->mfi_ich.ich_arg = sc;
371157114Sscottl	if (config_intrhook_establish(&sc->mfi_ich) != 0) {
372157114Sscottl		device_printf(sc->mfi_dev, "Cannot establish configuration "
373157114Sscottl		    "hook\n");
374157114Sscottl		return (EINVAL);
375157114Sscottl	}
376157114Sscottl
377157114Sscottl	/*
378157114Sscottl	 * Register a shutdown handler.
379157114Sscottl	 */
380157114Sscottl	if ((sc->mfi_eh = EVENTHANDLER_REGISTER(shutdown_final, mfi_shutdown,
381157114Sscottl	    sc, SHUTDOWN_PRI_DEFAULT)) == NULL) {
382157114Sscottl		device_printf(sc->mfi_dev, "Warning: shutdown event "
383157114Sscottl		    "registration failed\n");
384157114Sscottl	}
385157114Sscottl
386157114Sscottl	/*
387157114Sscottl	 * Create the control device for doing management
388157114Sscottl	 */
389157114Sscottl	unit = device_get_unit(sc->mfi_dev);
390157114Sscottl	sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR,
391157114Sscottl	    0640, "mfi%d", unit);
392158737Sambrisko	if (unit == 0)
393158737Sambrisko		make_dev_alias(sc->mfi_cdev, "megaraid_sas_ioctl_node");
394157114Sscottl	if (sc->mfi_cdev != NULL)
395157114Sscottl		sc->mfi_cdev->si_drv1 = sc;
396157114Sscottl
397162619Sscottl	/* Start the timeout watchdog */
398162619Sscottl	callout_init(&sc->mfi_watchdog_callout, 1);
399162619Sscottl	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
400162619Sscottl	    mfi_timeout, sc);
401162619Sscottl
402157114Sscottl	return (0);
403157114Sscottl}
404157114Sscottl
405157114Sscottlstatic int
406157114Sscottlmfi_alloc_commands(struct mfi_softc *sc)
407157114Sscottl{
408157114Sscottl	struct mfi_command *cm;
409157114Sscottl	int i, ncmds;
410157114Sscottl
411157114Sscottl	/*
412157114Sscottl	 * XXX Should we allocate all the commands up front, or allocate on
413157114Sscottl	 * demand later like 'aac' does?
414157114Sscottl	 */
415157114Sscottl	ncmds = sc->mfi_max_fw_cmds;
416157114Sscottl	sc->mfi_commands = malloc(sizeof(struct mfi_command) * ncmds, M_MFIBUF,
417157114Sscottl	    M_WAITOK | M_ZERO);
418157114Sscottl
419157114Sscottl	for (i = 0; i < ncmds; i++) {
420157114Sscottl		cm = &sc->mfi_commands[i];
421158737Sambrisko		cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames +
422162458Sscottl		    sc->mfi_cmd_size * i);
423157114Sscottl		cm->cm_frame_busaddr = sc->mfi_frames_busaddr +
424162458Sscottl		    sc->mfi_cmd_size * i;
425157114Sscottl		cm->cm_frame->header.context = i;
426157114Sscottl		cm->cm_sense = &sc->mfi_sense[i];
427157114Sscottl		cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i;
428157114Sscottl		cm->cm_sc = sc;
429162619Sscottl		cm->cm_index = i;
430157114Sscottl		if (bus_dmamap_create(sc->mfi_buffer_dmat, 0,
431157114Sscottl		    &cm->cm_dmamap) == 0)
432157114Sscottl			mfi_release_command(cm);
433157114Sscottl		else
434157114Sscottl			break;
435157114Sscottl		sc->mfi_total_cmds++;
436157114Sscottl	}
437157114Sscottl
438157114Sscottl	return (0);
439157114Sscottl}
440157114Sscottl
441157114Sscottlstatic void
442157114Sscottlmfi_release_command(struct mfi_command *cm)
443157114Sscottl{
444163398Sscottl	struct mfi_frame_header *hdr;
445157114Sscottl	uint32_t *hdr_data;
446157114Sscottl
447157114Sscottl	/*
448157114Sscottl	 * Zero out the important fields of the frame, but make sure the
449165727Sscottl	 * context field is preserved.  For efficiency, handle the fields
450165727Sscottl	 * as 32 bit words.  Clear out the first S/G entry too for safety.
451157114Sscottl	 */
452163398Sscottl	hdr = &cm->cm_frame->header;
453163398Sscottl	if (hdr->sg_count) {
454163398Sscottl		cm->cm_sg->sg32[0].len = 0;
455163398Sscottl		cm->cm_sg->sg32[0].addr = 0;
456163398Sscottl	}
457165727Sscottl
458165727Sscottl	hdr_data = (uint32_t *)cm->cm_frame;
459165727Sscottl	hdr_data[0] = 0;	/* cmd, sense_len, cmd_status, scsi_status */
460165727Sscottl	hdr_data[1] = 0;	/* target_id, lun_id, cdb_len, sg_count */
461165727Sscottl	hdr_data[4] = 0;	/* flags, timeout */
462165727Sscottl	hdr_data[5] = 0;	/* data_len */
463165727Sscottl
464157114Sscottl	cm->cm_extra_frames = 0;
465157114Sscottl	cm->cm_flags = 0;
466157114Sscottl	cm->cm_complete = NULL;
467157114Sscottl	cm->cm_private = NULL;
468157114Sscottl	cm->cm_sg = 0;
469157114Sscottl	cm->cm_total_frame_size = 0;
470163398Sscottl
471157114Sscottl	mfi_enqueue_free(cm);
472157114Sscottl}
473157114Sscottl
474157114Sscottlstatic int
475159806Spsmfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, uint32_t opcode,
476159806Sps    void **bufp, size_t bufsize)
477159806Sps{
478159806Sps	struct mfi_command *cm;
479159806Sps	struct mfi_dcmd_frame *dcmd;
480159806Sps	void *buf = NULL;
481159806Sps
482159806Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
483159806Sps
484159806Sps	cm = mfi_dequeue_free(sc);
485159806Sps	if (cm == NULL)
486159806Sps		return (EBUSY);
487159806Sps
488159806Sps	if ((bufsize > 0) && (bufp != NULL)) {
489159806Sps		if (*bufp == NULL) {
490159806Sps			buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO);
491159806Sps			if (buf == NULL) {
492159806Sps				mfi_release_command(cm);
493159806Sps				return (ENOMEM);
494159806Sps			}
495159806Sps			*bufp = buf;
496159806Sps		} else {
497159806Sps			buf = *bufp;
498159806Sps		}
499159806Sps	}
500159806Sps
501159806Sps	dcmd =  &cm->cm_frame->dcmd;
502159806Sps	bzero(dcmd->mbox, MFI_MBOX_SIZE);
503159806Sps	dcmd->header.cmd = MFI_CMD_DCMD;
504159806Sps	dcmd->header.timeout = 0;
505159806Sps	dcmd->header.flags = 0;
506159806Sps	dcmd->header.data_len = bufsize;
507159806Sps	dcmd->opcode = opcode;
508159806Sps	cm->cm_sg = &dcmd->sgl;
509159806Sps	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
510159806Sps	cm->cm_flags = 0;
511159806Sps	cm->cm_data = buf;
512159806Sps	cm->cm_private = buf;
513159806Sps	cm->cm_len = bufsize;
514159806Sps
515159806Sps	*cmp = cm;
516159806Sps	if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL))
517159806Sps		*bufp = buf;
518159806Sps	return (0);
519159806Sps}
520159806Sps
521159806Spsstatic int
522157114Sscottlmfi_comms_init(struct mfi_softc *sc)
523157114Sscottl{
524157114Sscottl	struct mfi_command *cm;
525157114Sscottl	struct mfi_init_frame *init;
526157114Sscottl	struct mfi_init_qinfo *qinfo;
527157114Sscottl	int error;
528157114Sscottl
529163398Sscottl	mtx_lock(&sc->mfi_io_lock);
530157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
531157114Sscottl		return (EBUSY);
532157114Sscottl
533157114Sscottl	/*
534157114Sscottl	 * Abuse the SG list area of the frame to hold the init_qinfo
535157114Sscottl	 * object;
536157114Sscottl	 */
537157114Sscottl	init = &cm->cm_frame->init;
538157114Sscottl	qinfo = (struct mfi_init_qinfo *)((uintptr_t)init + MFI_FRAME_SIZE);
539157114Sscottl
540157114Sscottl	bzero(qinfo, sizeof(struct mfi_init_qinfo));
541157114Sscottl	qinfo->rq_entries = sc->mfi_max_fw_cmds + 1;
542157114Sscottl	qinfo->rq_addr_lo = sc->mfi_comms_busaddr +
543157114Sscottl	    offsetof(struct mfi_hwcomms, hw_reply_q);
544157114Sscottl	qinfo->pi_addr_lo = sc->mfi_comms_busaddr +
545157114Sscottl	    offsetof(struct mfi_hwcomms, hw_pi);
546157114Sscottl	qinfo->ci_addr_lo = sc->mfi_comms_busaddr +
547157114Sscottl	    offsetof(struct mfi_hwcomms, hw_ci);
548157114Sscottl
549157114Sscottl	init->header.cmd = MFI_CMD_INIT;
550157114Sscottl	init->header.data_len = sizeof(struct mfi_init_qinfo);
551157114Sscottl	init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE;
552164375Sscottl	cm->cm_data = NULL;
553164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
554157114Sscottl
555164375Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
556157114Sscottl		device_printf(sc->mfi_dev, "failed to send init command\n");
557163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
558157114Sscottl		return (error);
559157114Sscottl	}
560157114Sscottl	mfi_release_command(cm);
561163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
562157114Sscottl
563157114Sscottl	return (0);
564157114Sscottl}
565157114Sscottl
566157114Sscottlstatic int
567157114Sscottlmfi_get_controller_info(struct mfi_softc *sc)
568157114Sscottl{
569159806Sps	struct mfi_command *cm = NULL;
570159806Sps	struct mfi_ctrl_info *ci = NULL;
571157114Sscottl	uint32_t max_sectors_1, max_sectors_2;
572157114Sscottl	int error;
573157114Sscottl
574159806Sps	mtx_lock(&sc->mfi_io_lock);
575159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO,
576159806Sps	    (void **)&ci, sizeof(*ci));
577159806Sps	if (error)
578159806Sps		goto out;
579157114Sscottl	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
580157114Sscottl
581157114Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
582157114Sscottl		device_printf(sc->mfi_dev, "Failed to get controller info\n");
583162458Sscottl		sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE /
584157114Sscottl		    MFI_SECTOR_LEN;
585159806Sps		error = 0;
586159806Sps		goto out;
587157114Sscottl	}
588157114Sscottl
589157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
590157114Sscottl	    BUS_DMASYNC_POSTREAD);
591157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
592157114Sscottl
593157114Sscottl	max_sectors_1 = (1 << ci->stripe_sz_ops.min) * ci->max_strips_per_io;
594157114Sscottl	max_sectors_2 = ci->max_request_size;
595157114Sscottl	sc->mfi_max_io = min(max_sectors_1, max_sectors_2);
596157114Sscottl
597159806Spsout:
598159806Sps	if (ci)
599159806Sps		free(ci, M_MFIBUF);
600159806Sps	if (cm)
601159806Sps		mfi_release_command(cm);
602159806Sps	mtx_unlock(&sc->mfi_io_lock);
603157114Sscottl	return (error);
604157114Sscottl}
605157114Sscottl
606157114Sscottlstatic int
607159806Spsmfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state)
608158737Sambrisko{
609159812Sps	struct mfi_command *cm = NULL;
610158737Sambrisko	int error;
611158737Sambrisko
612159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO,
613159806Sps	    (void **)log_state, sizeof(**log_state));
614159806Sps	if (error)
615159806Sps		goto out;
616159810Sps	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
617158737Sambrisko
618158737Sambrisko	if ((error = mfi_mapcmd(sc, cm)) != 0) {
619159802Sps		device_printf(sc->mfi_dev, "Failed to get log state\n");
620159806Sps		goto out;
621158737Sambrisko	}
622158737Sambrisko
623158737Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
624158737Sambrisko	    BUS_DMASYNC_POSTREAD);
625158737Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
626158737Sambrisko
627159806Spsout:
628159812Sps	if (cm)
629159812Sps		mfi_release_command(cm);
630158737Sambrisko
631158737Sambrisko	return (error);
632158737Sambrisko}
633158737Sambrisko
634158737Sambriskostatic int
635158737Sambriskomfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
636158737Sambrisko{
637159806Sps	struct mfi_evt_log_state *log_state = NULL;
638158737Sambrisko	union mfi_evt class_locale;
639158737Sambrisko	int error = 0;
640158737Sambrisko	uint32_t seq;
641158737Sambrisko
642158737Sambrisko	class_locale.members.reserved = 0;
643162118Sambrisko	class_locale.members.locale = mfi_event_locale;
644162118Sambrisko	class_locale.members.class  = mfi_event_class;
645158737Sambrisko
646158737Sambrisko	if (seq_start == 0) {
647158737Sambrisko		error = mfi_get_log_state(sc, &log_state);
648159806Sps		if (error) {
649159806Sps			if (log_state)
650159806Sps				free(log_state, M_MFIBUF);
651158737Sambrisko			return (error);
652159806Sps		}
653158737Sambrisko		/*
654158737Sambrisko		 * Don't run them yet since we can't parse them.
655158737Sambrisko		 * We can indirectly get the contents from
656158737Sambrisko		 * the AEN mechanism via setting it lower then
657158737Sambrisko		 * current.  The firmware will iterate through them.
658158737Sambrisko		 */
659159806Sps		for (seq = log_state->shutdown_seq_num;
660159806Sps		     seq <= log_state->newest_seq_num; seq++) {
661158737Sambrisko			mfi_get_entry(sc, seq);
662158737Sambrisko		}
663158737Sambrisko	} else
664158737Sambrisko		seq = seq_start;
665158737Sambrisko	mfi_aen_register(sc, seq, class_locale.word);
666159806Sps	free(log_state, M_MFIBUF);
667158737Sambrisko
668158737Sambrisko	return 0;
669158737Sambrisko}
670158737Sambrisko
671158737Sambriskostatic int
672159811Spsmfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm)
673159811Sps{
674159811Sps
675159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
676159811Sps	cm->cm_complete = NULL;
677159811Sps
678159811Sps	mfi_enqueue_ready(cm);
679159811Sps	mfi_startio(sc);
680159811Sps	return (msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0));
681159811Sps}
682159811Sps
683157114Sscottlvoid
684157114Sscottlmfi_free(struct mfi_softc *sc)
685157114Sscottl{
686157114Sscottl	struct mfi_command *cm;
687157114Sscottl	int i;
688157114Sscottl
689162619Sscottl	callout_drain(&sc->mfi_watchdog_callout);
690162619Sscottl
691157114Sscottl	if (sc->mfi_cdev != NULL)
692157114Sscottl		destroy_dev(sc->mfi_cdev);
693157114Sscottl
694157114Sscottl	if (sc->mfi_total_cmds != 0) {
695157114Sscottl		for (i = 0; i < sc->mfi_total_cmds; i++) {
696157114Sscottl			cm = &sc->mfi_commands[i];
697157114Sscottl			bus_dmamap_destroy(sc->mfi_buffer_dmat, cm->cm_dmamap);
698157114Sscottl		}
699157114Sscottl		free(sc->mfi_commands, M_MFIBUF);
700157114Sscottl	}
701157114Sscottl
702157114Sscottl	if (sc->mfi_intr)
703157114Sscottl		bus_teardown_intr(sc->mfi_dev, sc->mfi_irq, sc->mfi_intr);
704157114Sscottl	if (sc->mfi_irq != NULL)
705157114Sscottl		bus_release_resource(sc->mfi_dev, SYS_RES_IRQ, sc->mfi_irq_rid,
706157114Sscottl		    sc->mfi_irq);
707157114Sscottl
708157114Sscottl	if (sc->mfi_sense_busaddr != 0)
709157114Sscottl		bus_dmamap_unload(sc->mfi_sense_dmat, sc->mfi_sense_dmamap);
710157114Sscottl	if (sc->mfi_sense != NULL)
711157114Sscottl		bus_dmamem_free(sc->mfi_sense_dmat, sc->mfi_sense,
712157114Sscottl		    sc->mfi_sense_dmamap);
713157114Sscottl	if (sc->mfi_sense_dmat != NULL)
714157114Sscottl		bus_dma_tag_destroy(sc->mfi_sense_dmat);
715157114Sscottl
716157114Sscottl	if (sc->mfi_frames_busaddr != 0)
717157114Sscottl		bus_dmamap_unload(sc->mfi_frames_dmat, sc->mfi_frames_dmamap);
718157114Sscottl	if (sc->mfi_frames != NULL)
719157114Sscottl		bus_dmamem_free(sc->mfi_frames_dmat, sc->mfi_frames,
720157114Sscottl		    sc->mfi_frames_dmamap);
721157114Sscottl	if (sc->mfi_frames_dmat != NULL)
722157114Sscottl		bus_dma_tag_destroy(sc->mfi_frames_dmat);
723157114Sscottl
724157114Sscottl	if (sc->mfi_comms_busaddr != 0)
725157114Sscottl		bus_dmamap_unload(sc->mfi_comms_dmat, sc->mfi_comms_dmamap);
726157114Sscottl	if (sc->mfi_comms != NULL)
727157114Sscottl		bus_dmamem_free(sc->mfi_comms_dmat, sc->mfi_comms,
728157114Sscottl		    sc->mfi_comms_dmamap);
729157114Sscottl	if (sc->mfi_comms_dmat != NULL)
730157114Sscottl		bus_dma_tag_destroy(sc->mfi_comms_dmat);
731157114Sscottl
732157114Sscottl	if (sc->mfi_buffer_dmat != NULL)
733157114Sscottl		bus_dma_tag_destroy(sc->mfi_buffer_dmat);
734157114Sscottl	if (sc->mfi_parent_dmat != NULL)
735157114Sscottl		bus_dma_tag_destroy(sc->mfi_parent_dmat);
736157114Sscottl
737157114Sscottl	if (mtx_initialized(&sc->mfi_io_lock))
738157114Sscottl		mtx_destroy(&sc->mfi_io_lock);
739157114Sscottl
740157114Sscottl	return;
741157114Sscottl}
742157114Sscottl
743157114Sscottlstatic void
744157114Sscottlmfi_startup(void *arg)
745157114Sscottl{
746157114Sscottl	struct mfi_softc *sc;
747157114Sscottl
748157114Sscottl	sc = (struct mfi_softc *)arg;
749157114Sscottl
750157114Sscottl	config_intrhook_disestablish(&sc->mfi_ich);
751157114Sscottl
752157114Sscottl	mfi_enable_intr(sc);
753163398Sscottl	mtx_lock(&sc->mfi_io_lock);
754159811Sps	mfi_ldprobe(sc);
755163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
756157114Sscottl}
757157114Sscottl
758157114Sscottlstatic void
759157114Sscottlmfi_intr(void *arg)
760157114Sscottl{
761157114Sscottl	struct mfi_softc *sc;
762157114Sscottl	struct mfi_command *cm;
763157114Sscottl	uint32_t status, pi, ci, context;
764157114Sscottl
765157114Sscottl	sc = (struct mfi_softc *)arg;
766157114Sscottl
767157114Sscottl	status = MFI_READ4(sc, MFI_OSTS);
768157114Sscottl	if ((status & MFI_OSTS_INTR_VALID) == 0)
769157114Sscottl		return;
770163398Sscottl
771157114Sscottl	MFI_WRITE4(sc, MFI_OSTS, status);
772157114Sscottl
773157114Sscottl	pi = sc->mfi_comms->hw_pi;
774157114Sscottl	ci = sc->mfi_comms->hw_ci;
775157114Sscottl	mtx_lock(&sc->mfi_io_lock);
776157114Sscottl	while (ci != pi) {
777157114Sscottl		context = sc->mfi_comms->hw_reply_q[ci];
778162099Sscottl		cm = &sc->mfi_commands[context];
779162099Sscottl		mfi_remove_busy(cm);
780162099Sscottl		mfi_complete(sc, cm);
781162099Sscottl		if (++ci == (sc->mfi_max_fw_cmds + 1)) {
782157114Sscottl			ci = 0;
783157114Sscottl		}
784157114Sscottl	}
785157114Sscottl
786157114Sscottl	sc->mfi_comms->hw_ci = ci;
787157114Sscottl
788163398Sscottl	/* Give defered I/O a chance to run */
789163398Sscottl	if (sc->mfi_flags & MFI_FLAGS_QFRZN)
790163398Sscottl		sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
791163398Sscottl	mfi_startio(sc);
792163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
793163398Sscottl
794157114Sscottl	return;
795157114Sscottl}
796157114Sscottl
797157114Sscottlint
798157114Sscottlmfi_shutdown(struct mfi_softc *sc)
799157114Sscottl{
800157114Sscottl	struct mfi_dcmd_frame *dcmd;
801157114Sscottl	struct mfi_command *cm;
802157114Sscottl	int error;
803157114Sscottl
804159806Sps	mtx_lock(&sc->mfi_io_lock);
805159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0);
806163398Sscottl	if (error) {
807163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
808159806Sps		return (error);
809163398Sscottl	}
810157114Sscottl
811158737Sambrisko	if (sc->mfi_aen_cm != NULL)
812158737Sambrisko		mfi_abort(sc, sc->mfi_aen_cm);
813157114Sscottl
814157114Sscottl	dcmd = &cm->cm_frame->dcmd;
815157114Sscottl	dcmd->header.flags = MFI_FRAME_DIR_NONE;
816164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
817164375Sscottl	cm->cm_data = NULL;
818157114Sscottl
819164375Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
820157114Sscottl		device_printf(sc->mfi_dev, "Failed to shutdown controller\n");
821157114Sscottl	}
822157114Sscottl
823159812Sps	mfi_release_command(cm);
824163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
825157114Sscottl	return (error);
826157114Sscottl}
827157114Sscottl
828157114Sscottlstatic void
829157114Sscottlmfi_enable_intr(struct mfi_softc *sc)
830157114Sscottl{
831157114Sscottl
832157114Sscottl	MFI_WRITE4(sc, MFI_OMSK, 0x01);
833157114Sscottl}
834157114Sscottl
835157114Sscottlstatic void
836159811Spsmfi_ldprobe(struct mfi_softc *sc)
837157114Sscottl{
838159811Sps	struct mfi_frame_header *hdr;
839159811Sps	struct mfi_command *cm = NULL;
840159811Sps	struct mfi_ld_list *list = NULL;
841159811Sps	int error, i;
842157114Sscottl
843163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
844163398Sscottl
845159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
846159811Sps	    (void **)&list, sizeof(*list));
847159811Sps	if (error)
848159811Sps		goto out;
849159811Sps
850159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
851159811Sps	if (mfi_wait_command(sc, cm) != 0) {
852159811Sps		device_printf(sc->mfi_dev, "Failed to get device listing\n");
853159811Sps		goto out;
854157114Sscottl	}
855157114Sscottl
856157114Sscottl	hdr = &cm->cm_frame->header;
857159811Sps	if (hdr->cmd_status != MFI_STAT_OK) {
858159811Sps		device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n",
859159811Sps		    hdr->cmd_status);
860159811Sps		goto out;
861157114Sscottl	}
862157114Sscottl
863159811Sps	for (i = 0; i < list->ld_count; i++)
864163398Sscottl		mfi_add_ld(sc, list->ld_list[i].ld.v.target_id);
865159811Spsout:
866159811Sps	if (list)
867159811Sps		free(list, M_MFIBUF);
868159811Sps	if (cm)
869157114Sscottl		mfi_release_command(cm);
870163398Sscottl
871159811Sps	return;
872157114Sscottl}
873157114Sscottl
874158737Sambriskostatic void
875158737Sambriskomfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
876158737Sambrisko{
877158737Sambrisko	switch (detail->arg_type) {
878158737Sambrisko	case MR_EVT_ARGS_NONE:
879162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - %s\n",
880159574Sambrisko		    detail->seq,
881162118Sambrisko		    detail->time,
882162118Sambrisko		    detail->class.members.locale,
883162118Sambrisko		    detail->class.members.class,
884159574Sambrisko		    detail->description
885159574Sambrisko		    );
886158737Sambrisko		break;
887158737Sambrisko	case MR_EVT_ARGS_CDB_SENSE:
888162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) CDB %*D"
889159574Sambrisko		    "Sense %*D\n: %s\n",
890158737Sambrisko		    detail->seq,
891162118Sambrisko		    detail->time,
892162118Sambrisko		    detail->class.members.locale,
893162118Sambrisko		    detail->class.members.class,
894158737Sambrisko		    detail->args.cdb_sense.pd.device_id,
895158737Sambrisko		    detail->args.cdb_sense.pd.enclosure_index,
896158737Sambrisko		    detail->args.cdb_sense.pd.slot_number,
897158737Sambrisko		    detail->args.cdb_sense.cdb_len,
898158737Sambrisko		    detail->args.cdb_sense.cdb,
899158737Sambrisko		    ":",
900158737Sambrisko		    detail->args.cdb_sense.sense_len,
901158737Sambrisko		    detail->args.cdb_sense.sense,
902158737Sambrisko		    ":",
903158737Sambrisko		    detail->description
904158737Sambrisko		    );
905158737Sambrisko		break;
906158737Sambrisko	case MR_EVT_ARGS_LD:
907162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
908158737Sambrisko		    "event: %s\n",
909158737Sambrisko		    detail->seq,
910162118Sambrisko		    detail->time,
911162118Sambrisko		    detail->class.members.locale,
912162118Sambrisko		    detail->class.members.class,
913158737Sambrisko		    detail->args.ld.ld_index,
914158737Sambrisko		    detail->args.ld.target_id,
915158737Sambrisko		    detail->description
916158737Sambrisko		    );
917158737Sambrisko		break;
918158737Sambrisko	case MR_EVT_ARGS_LD_COUNT:
919162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
920158737Sambrisko		    "count %lld: %s\n",
921158737Sambrisko		    detail->seq,
922162118Sambrisko		    detail->time,
923162118Sambrisko		    detail->class.members.locale,
924162118Sambrisko		    detail->class.members.class,
925158737Sambrisko		    detail->args.ld_count.ld.ld_index,
926158737Sambrisko		    detail->args.ld_count.ld.target_id,
927158737Sambrisko		    (long long)detail->args.ld_count.count,
928158737Sambrisko		    detail->description
929158737Sambrisko		    );
930158737Sambrisko		break;
931158737Sambrisko	case MR_EVT_ARGS_LD_LBA:
932162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
933158737Sambrisko		    "lba %lld: %s\n",
934158737Sambrisko		    detail->seq,
935162118Sambrisko		    detail->time,
936162118Sambrisko		    detail->class.members.locale,
937162118Sambrisko		    detail->class.members.class,
938158737Sambrisko		    detail->args.ld_lba.ld.ld_index,
939158737Sambrisko		    detail->args.ld_lba.ld.target_id,
940158737Sambrisko		    (long long)detail->args.ld_lba.lba,
941158737Sambrisko		    detail->description
942158737Sambrisko		    );
943158737Sambrisko		break;
944158737Sambrisko	case MR_EVT_ARGS_LD_OWNER:
945162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
946158737Sambrisko		    "owner changed: prior %d, new %d: %s\n",
947158737Sambrisko		    detail->seq,
948162118Sambrisko		    detail->time,
949162118Sambrisko		    detail->class.members.locale,
950162118Sambrisko		    detail->class.members.class,
951158737Sambrisko		    detail->args.ld_owner.ld.ld_index,
952158737Sambrisko		    detail->args.ld_owner.ld.target_id,
953158737Sambrisko		    detail->args.ld_owner.pre_owner,
954158737Sambrisko		    detail->args.ld_owner.new_owner,
955158737Sambrisko		    detail->description
956158737Sambrisko		    );
957158737Sambrisko		break;
958158737Sambrisko	case MR_EVT_ARGS_LD_LBA_PD_LBA:
959162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
960158737Sambrisko		    "lba %lld, physical drive PD %02d(e%d/s%d) lba %lld: %s\n",
961158737Sambrisko		    detail->seq,
962162118Sambrisko		    detail->time,
963162118Sambrisko		    detail->class.members.locale,
964162118Sambrisko		    detail->class.members.class,
965158737Sambrisko		    detail->args.ld_lba_pd_lba.ld.ld_index,
966158737Sambrisko		    detail->args.ld_lba_pd_lba.ld.target_id,
967158737Sambrisko		    (long long)detail->args.ld_lba_pd_lba.ld_lba,
968158737Sambrisko		    detail->args.ld_lba_pd_lba.pd.device_id,
969158737Sambrisko		    detail->args.ld_lba_pd_lba.pd.enclosure_index,
970158737Sambrisko		    detail->args.ld_lba_pd_lba.pd.slot_number,
971158737Sambrisko		    (long long)detail->args.ld_lba_pd_lba.pd_lba,
972158737Sambrisko		    detail->description
973158737Sambrisko		    );
974158737Sambrisko		break;
975158737Sambrisko	case MR_EVT_ARGS_LD_PROG:
976162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
977158737Sambrisko		    "progress %d%% in %ds: %s\n",
978158737Sambrisko		    detail->seq,
979162118Sambrisko		    detail->time,
980162118Sambrisko		    detail->class.members.locale,
981162118Sambrisko		    detail->class.members.class,
982158737Sambrisko		    detail->args.ld_prog.ld.ld_index,
983158737Sambrisko		    detail->args.ld_prog.ld.target_id,
984158737Sambrisko		    detail->args.ld_prog.prog.progress/655,
985158737Sambrisko		    detail->args.ld_prog.prog.elapsed_seconds,
986158737Sambrisko		    detail->description
987158737Sambrisko		    );
988158737Sambrisko		break;
989158737Sambrisko	case MR_EVT_ARGS_LD_STATE:
990162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
991158737Sambrisko		    "state prior %d new %d: %s\n",
992158737Sambrisko		    detail->seq,
993162118Sambrisko		    detail->time,
994162118Sambrisko		    detail->class.members.locale,
995162118Sambrisko		    detail->class.members.class,
996158737Sambrisko		    detail->args.ld_state.ld.ld_index,
997158737Sambrisko		    detail->args.ld_state.ld.target_id,
998158737Sambrisko		    detail->args.ld_state.prev_state,
999158737Sambrisko		    detail->args.ld_state.new_state,
1000158737Sambrisko		    detail->description
1001158737Sambrisko		    );
1002158737Sambrisko		break;
1003158737Sambrisko	case MR_EVT_ARGS_LD_STRIP:
1004162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - VD %02d/%d "
1005158737Sambrisko		    "strip %lld: %s\n",
1006158737Sambrisko		    detail->seq,
1007162118Sambrisko		    detail->time,
1008162118Sambrisko		    detail->class.members.locale,
1009162118Sambrisko		    detail->class.members.class,
1010158737Sambrisko		    detail->args.ld_strip.ld.ld_index,
1011158737Sambrisko		    detail->args.ld_strip.ld.target_id,
1012158737Sambrisko		    (long long)detail->args.ld_strip.strip,
1013158737Sambrisko		    detail->description
1014158737Sambrisko		    );
1015158737Sambrisko		break;
1016158737Sambrisko	case MR_EVT_ARGS_PD:
1017162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
1018158737Sambrisko		    "event: %s\n",
1019158737Sambrisko		    detail->seq,
1020162118Sambrisko		    detail->time,
1021162118Sambrisko		    detail->class.members.locale,
1022162118Sambrisko		    detail->class.members.class,
1023158737Sambrisko		    detail->args.pd.device_id,
1024158737Sambrisko		    detail->args.pd.enclosure_index,
1025158737Sambrisko		    detail->args.pd.slot_number,
1026158737Sambrisko		    detail->description
1027158737Sambrisko		    );
1028158737Sambrisko		break;
1029158737Sambrisko	case MR_EVT_ARGS_PD_ERR:
1030162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
1031158737Sambrisko		    "err %d: %s\n",
1032158737Sambrisko		    detail->seq,
1033162118Sambrisko		    detail->time,
1034162118Sambrisko		    detail->class.members.locale,
1035162118Sambrisko		    detail->class.members.class,
1036158737Sambrisko		    detail->args.pd_err.pd.device_id,
1037158737Sambrisko		    detail->args.pd_err.pd.enclosure_index,
1038158737Sambrisko		    detail->args.pd_err.pd.slot_number,
1039158737Sambrisko		    detail->args.pd_err.err,
1040158737Sambrisko		    detail->description
1041158737Sambrisko		    );
1042158737Sambrisko		break;
1043158737Sambrisko	case MR_EVT_ARGS_PD_LBA:
1044162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
1045158737Sambrisko		    "lba %lld: %s\n",
1046158737Sambrisko		    detail->seq,
1047162118Sambrisko		    detail->time,
1048162118Sambrisko		    detail->class.members.locale,
1049162118Sambrisko		    detail->class.members.class,
1050158737Sambrisko		    detail->args.pd_lba.pd.device_id,
1051158737Sambrisko		    detail->args.pd_lba.pd.enclosure_index,
1052158737Sambrisko		    detail->args.pd_lba.pd.slot_number,
1053158737Sambrisko		    (long long)detail->args.pd_lba.lba,
1054158737Sambrisko		    detail->description
1055158737Sambrisko		    );
1056158737Sambrisko		break;
1057158737Sambrisko	case MR_EVT_ARGS_PD_LBA_LD:
1058162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
1059158737Sambrisko		    "lba %lld VD %02d/%d: %s\n",
1060158737Sambrisko		    detail->seq,
1061162118Sambrisko		    detail->time,
1062162118Sambrisko		    detail->class.members.locale,
1063162118Sambrisko		    detail->class.members.class,
1064158737Sambrisko		    detail->args.pd_lba_ld.pd.device_id,
1065158737Sambrisko		    detail->args.pd_lba_ld.pd.enclosure_index,
1066158737Sambrisko		    detail->args.pd_lba_ld.pd.slot_number,
1067158737Sambrisko		    (long long)detail->args.pd_lba.lba,
1068158737Sambrisko		    detail->args.pd_lba_ld.ld.ld_index,
1069158737Sambrisko		    detail->args.pd_lba_ld.ld.target_id,
1070158737Sambrisko		    detail->description
1071158737Sambrisko		    );
1072158737Sambrisko		break;
1073158737Sambrisko	case MR_EVT_ARGS_PD_PROG:
1074162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
1075158737Sambrisko		    "progress %d%% seconds %ds: %s\n",
1076158737Sambrisko		    detail->seq,
1077162118Sambrisko		    detail->time,
1078162118Sambrisko		    detail->class.members.locale,
1079162118Sambrisko		    detail->class.members.class,
1080158737Sambrisko		    detail->args.pd_prog.pd.device_id,
1081158737Sambrisko		    detail->args.pd_prog.pd.enclosure_index,
1082158737Sambrisko		    detail->args.pd_prog.pd.slot_number,
1083158737Sambrisko		    detail->args.pd_prog.prog.progress/655,
1084158737Sambrisko		    detail->args.pd_prog.prog.elapsed_seconds,
1085158737Sambrisko		    detail->description
1086158737Sambrisko		    );
1087158737Sambrisko		break;
1088158737Sambrisko	case MR_EVT_ARGS_PD_STATE:
1089162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PD %02d(e%d/s%d) "
1090158737Sambrisko		    "state prior %d new %d: %s\n",
1091158737Sambrisko		    detail->seq,
1092162118Sambrisko		    detail->time,
1093162118Sambrisko		    detail->class.members.locale,
1094162118Sambrisko		    detail->class.members.class,
1095158737Sambrisko		    detail->args.pd_prog.pd.device_id,
1096158737Sambrisko		    detail->args.pd_prog.pd.enclosure_index,
1097158737Sambrisko		    detail->args.pd_prog.pd.slot_number,
1098158737Sambrisko		    detail->args.pd_state.prev_state,
1099158737Sambrisko		    detail->args.pd_state.new_state,
1100158737Sambrisko		    detail->description
1101158737Sambrisko		    );
1102158737Sambrisko		break;
1103158737Sambrisko	case MR_EVT_ARGS_PCI:
1104162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - PCI 0x04%x 0x04%x "
1105158737Sambrisko		    "0x04%x 0x04%x: %s\n",
1106158737Sambrisko		    detail->seq,
1107162118Sambrisko		    detail->time,
1108162118Sambrisko		    detail->class.members.locale,
1109162118Sambrisko		    detail->class.members.class,
1110158737Sambrisko		    detail->args.pci.venderId,
1111158737Sambrisko		    detail->args.pci.deviceId,
1112158737Sambrisko		    detail->args.pci.subVenderId,
1113158737Sambrisko		    detail->args.pci.subDeviceId,
1114158737Sambrisko		    detail->description
1115158737Sambrisko		    );
1116158737Sambrisko		break;
1117158737Sambrisko	case MR_EVT_ARGS_RATE:
1118162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - Rebuild rate %d: %s\n",
1119158737Sambrisko		    detail->seq,
1120162118Sambrisko		    detail->time,
1121162118Sambrisko		    detail->class.members.locale,
1122162118Sambrisko		    detail->class.members.class,
1123158737Sambrisko		    detail->args.rate,
1124158737Sambrisko		    detail->description
1125158737Sambrisko		    );
1126158737Sambrisko		break;
1127158737Sambrisko	case MR_EVT_ARGS_TIME:
1128162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - Adapter ticks %d "
1129158737Sambrisko		    "elapsed %ds: %s\n",
1130158737Sambrisko		    detail->seq,
1131162118Sambrisko		    detail->time,
1132162118Sambrisko		    detail->class.members.locale,
1133162118Sambrisko		    detail->class.members.class,
1134158737Sambrisko		    detail->args.time.rtc,
1135158737Sambrisko		    detail->args.time.elapsedSeconds,
1136158737Sambrisko		    detail->description
1137158737Sambrisko		    );
1138158737Sambrisko		break;
1139158737Sambrisko	case MR_EVT_ARGS_ECC:
1140162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - Adapter ECC %x,%x: %s: %s\n",
1141158737Sambrisko		    detail->seq,
1142162118Sambrisko		    detail->time,
1143162118Sambrisko		    detail->class.members.locale,
1144162118Sambrisko		    detail->class.members.class,
1145158737Sambrisko		    detail->args.ecc.ecar,
1146158737Sambrisko		    detail->args.ecc.elog,
1147158737Sambrisko		    detail->args.ecc.str,
1148158737Sambrisko		    detail->description
1149158737Sambrisko		    );
1150158737Sambrisko		break;
1151158737Sambrisko	default:
1152162118Sambrisko		device_printf(sc->mfi_dev, "%d (%us/0x%04x/%d) - Type %d: %s\n",
1153158737Sambrisko		    detail->seq,
1154162118Sambrisko		    detail->time,
1155162118Sambrisko		    detail->class.members.locale,
1156162118Sambrisko		    detail->class.members.class,
1157158737Sambrisko		    detail->arg_type, detail->description
1158158737Sambrisko		    );
1159158737Sambrisko	}
1160158737Sambrisko}
1161158737Sambrisko
1162157114Sscottlstatic int
1163158737Sambriskomfi_aen_register(struct mfi_softc *sc, int seq, int locale)
1164158737Sambrisko{
1165158737Sambrisko	struct mfi_command *cm;
1166158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1167158737Sambrisko	union mfi_evt current_aen, prior_aen;
1168159806Sps	struct mfi_evt_detail *ed = NULL;
1169163398Sscottl	int error = 0;
1170158737Sambrisko
1171158737Sambrisko	current_aen.word = locale;
1172158737Sambrisko	if (sc->mfi_aen_cm != NULL) {
1173158737Sambrisko		prior_aen.word =
1174158737Sambrisko		    ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1];
1175158737Sambrisko		if (prior_aen.members.class <= current_aen.members.class &&
1176158737Sambrisko		    !((prior_aen.members.locale & current_aen.members.locale)
1177158737Sambrisko		    ^current_aen.members.locale)) {
1178158737Sambrisko			return (0);
1179158737Sambrisko		} else {
1180158737Sambrisko			prior_aen.members.locale |= current_aen.members.locale;
1181158737Sambrisko			if (prior_aen.members.class
1182158737Sambrisko			    < current_aen.members.class)
1183158737Sambrisko				current_aen.members.class =
1184158737Sambrisko				    prior_aen.members.class;
1185158737Sambrisko			mfi_abort(sc, sc->mfi_aen_cm);
1186158737Sambrisko		}
1187158737Sambrisko	}
1188158737Sambrisko
1189159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT,
1190159806Sps	    (void **)&ed, sizeof(*ed));
1191163398Sscottl	if (error) {
1192163398Sscottl		goto out;
1193163398Sscottl	}
1194158737Sambrisko
1195158737Sambrisko	dcmd = &cm->cm_frame->dcmd;
1196158737Sambrisko	((uint32_t *)&dcmd->mbox)[0] = seq;
1197158737Sambrisko	((uint32_t *)&dcmd->mbox)[1] = locale;
1198158737Sambrisko	cm->cm_flags = MFI_CMD_DATAIN;
1199158737Sambrisko	cm->cm_complete = mfi_aen_complete;
1200158737Sambrisko
1201158737Sambrisko	sc->mfi_aen_cm = cm;
1202158737Sambrisko
1203158737Sambrisko	mfi_enqueue_ready(cm);
1204158737Sambrisko	mfi_startio(sc);
1205158737Sambrisko
1206163398Sscottlout:
1207163398Sscottl	return (error);
1208158737Sambrisko}
1209158737Sambrisko
1210158737Sambriskostatic void
1211158737Sambriskomfi_aen_complete(struct mfi_command *cm)
1212158737Sambrisko{
1213158737Sambrisko	struct mfi_frame_header *hdr;
1214158737Sambrisko	struct mfi_softc *sc;
1215158737Sambrisko	struct mfi_evt_detail *detail;
1216163398Sscottl	struct mfi_aen *mfi_aen_entry, *tmp;
1217158737Sambrisko	int seq = 0, aborted = 0;
1218158737Sambrisko
1219158737Sambrisko	sc = cm->cm_sc;
1220158737Sambrisko	hdr = &cm->cm_frame->header;
1221158737Sambrisko
1222158737Sambrisko	if (sc->mfi_aen_cm == NULL)
1223158737Sambrisko		return;
1224158737Sambrisko
1225158737Sambrisko	if (sc->mfi_aen_cm->cm_aen_abort || hdr->cmd_status == 0xff) {
1226158737Sambrisko		sc->mfi_aen_cm->cm_aen_abort = 0;
1227158737Sambrisko		aborted = 1;
1228158737Sambrisko	} else {
1229158737Sambrisko		sc->mfi_aen_triggered = 1;
1230163398Sscottl		if (sc->mfi_poll_waiting) {
1231163398Sscottl			sc->mfi_poll_waiting = 0;
1232158737Sambrisko			selwakeup(&sc->mfi_select);
1233163398Sscottl		}
1234158737Sambrisko		detail = cm->cm_data;
1235163398Sscottl		/*
1236163398Sscottl		 * XXX If this function is too expensive or is recursive, then
1237163398Sscottl		 * events should be put onto a queue and processed later.
1238163398Sscottl		 */
1239158737Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1240158737Sambrisko		mfi_decode_evt(sc, detail);
1241158737Sambrisko		mtx_lock(&sc->mfi_io_lock);
1242158737Sambrisko		seq = detail->seq + 1;
1243163398Sscottl		TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
1244158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
1245158737Sambrisko			    aen_link);
1246163398Sscottl			PROC_LOCK(mfi_aen_entry->p);
1247158737Sambrisko			psignal(mfi_aen_entry->p, SIGIO);
1248163398Sscottl			PROC_UNLOCK(mfi_aen_entry->p);
1249158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
1250158737Sambrisko		}
1251158737Sambrisko	}
1252158737Sambrisko
1253158737Sambrisko	free(cm->cm_data, M_MFIBUF);
1254158737Sambrisko	sc->mfi_aen_cm = NULL;
1255158737Sambrisko	wakeup(&sc->mfi_aen_cm);
1256158737Sambrisko	mfi_release_command(cm);
1257158737Sambrisko
1258158737Sambrisko	/* set it up again so the driver can catch more events */
1259158737Sambrisko	if (!aborted) {
1260158737Sambrisko		mfi_aen_setup(sc, seq);
1261158737Sambrisko	}
1262158737Sambrisko}
1263158737Sambrisko
1264162118Sambrisko/* Only do one event for now so we can easily iterate through them */
1265162118Sambrisko#define MAX_EVENTS 1
1266158737Sambriskostatic int
1267158737Sambriskomfi_get_entry(struct mfi_softc *sc, int seq)
1268158737Sambrisko{
1269158737Sambrisko	struct mfi_command *cm;
1270158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1271162118Sambrisko	struct mfi_evt_list *el;
1272158737Sambrisko	int error;
1273162118Sambrisko	int i;
1274162118Sambrisko	int size;
1275158737Sambrisko
1276158737Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL) {
1277158737Sambrisko		return (EBUSY);
1278158737Sambrisko	}
1279158737Sambrisko
1280162118Sambrisko	size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail)
1281162118Sambrisko		* (MAX_EVENTS - 1);
1282162118Sambrisko	el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO);
1283162118Sambrisko	if (el == NULL) {
1284158737Sambrisko		mfi_release_command(cm);
1285158737Sambrisko		return (ENOMEM);
1286158737Sambrisko	}
1287158737Sambrisko
1288158737Sambrisko	dcmd = &cm->cm_frame->dcmd;
1289158737Sambrisko	bzero(dcmd->mbox, MFI_MBOX_SIZE);
1290158737Sambrisko	dcmd->header.cmd = MFI_CMD_DCMD;
1291158737Sambrisko	dcmd->header.timeout = 0;
1292162118Sambrisko	dcmd->header.data_len = size;
1293158737Sambrisko	dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET;
1294158737Sambrisko	((uint32_t *)&dcmd->mbox)[0] = seq;
1295158737Sambrisko	((uint32_t *)&dcmd->mbox)[1] = MFI_EVT_LOCALE_ALL;
1296158737Sambrisko	cm->cm_sg = &dcmd->sgl;
1297158737Sambrisko	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
1298158737Sambrisko	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1299162118Sambrisko	cm->cm_data = el;
1300162118Sambrisko	cm->cm_len = size;
1301158737Sambrisko
1302158737Sambrisko	if ((error = mfi_mapcmd(sc, cm)) != 0) {
1303158737Sambrisko		device_printf(sc->mfi_dev, "Failed to get controller entry\n");
1304162458Sscottl		sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE /
1305158737Sambrisko		    MFI_SECTOR_LEN;
1306162118Sambrisko		free(el, M_MFIBUF);
1307158737Sambrisko		mfi_release_command(cm);
1308158737Sambrisko		return (0);
1309158737Sambrisko	}
1310158737Sambrisko
1311158737Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1312158737Sambrisko	    BUS_DMASYNC_POSTREAD);
1313158737Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1314158737Sambrisko
1315162473Sambrisko	if (dcmd->header.cmd_status != MFI_STAT_NOT_FOUND) {
1316162473Sambrisko		for (i = 0; i < el->count; i++) {
1317162473Sambrisko			if (seq + i == el->event[i].seq)
1318162473Sambrisko				mfi_decode_evt(sc, &el->event[i]);
1319162473Sambrisko		}
1320162118Sambrisko	}
1321158737Sambrisko
1322158737Sambrisko	free(cm->cm_data, M_MFIBUF);
1323158737Sambrisko	mfi_release_command(cm);
1324158737Sambrisko	return (0);
1325158737Sambrisko}
1326158737Sambrisko
1327158737Sambriskostatic int
1328159811Spsmfi_add_ld(struct mfi_softc *sc, int id)
1329157114Sscottl{
1330157114Sscottl	struct mfi_command *cm;
1331159811Sps	struct mfi_dcmd_frame *dcmd = NULL;
1332159811Sps	struct mfi_ld_info *ld_info = NULL;
1333159811Sps	int error;
1334157114Sscottl
1335159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1336159811Sps
1337159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO,
1338159811Sps	    (void **)&ld_info, sizeof(*ld_info));
1339159811Sps	if (error) {
1340159811Sps		device_printf(sc->mfi_dev,
1341159811Sps		    "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error);
1342159811Sps		if (ld_info)
1343159811Sps			free(ld_info, M_MFIBUF);
1344159811Sps		return (error);
1345157624Sscottl	}
1346159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
1347159811Sps	dcmd = &cm->cm_frame->dcmd;
1348159811Sps	dcmd->mbox[0] = id;
1349160052Sambrisko	if (mfi_wait_command(sc, cm) != 0) {
1350160052Sambrisko		device_printf(sc->mfi_dev,
1351160052Sambrisko		    "Failed to get logical drive: %d\n", id);
1352160052Sambrisko		free(ld_info, M_MFIBUF);
1353160052Sambrisko		return (0);
1354160052Sambrisko	}
1355159811Sps
1356160052Sambrisko	mfi_add_ld_complete(cm);
1357157114Sscottl	return (0);
1358157114Sscottl}
1359157114Sscottl
1360157114Sscottlstatic void
1361159811Spsmfi_add_ld_complete(struct mfi_command *cm)
1362157114Sscottl{
1363157114Sscottl	struct mfi_frame_header *hdr;
1364159811Sps	struct mfi_ld_info *ld_info;
1365157114Sscottl	struct mfi_softc *sc;
1366159811Sps	struct mfi_ld *ld;
1367159811Sps	device_t child;
1368157114Sscottl
1369157114Sscottl	sc = cm->cm_sc;
1370157114Sscottl	hdr = &cm->cm_frame->header;
1371159811Sps	ld_info = cm->cm_private;
1372157114Sscottl
1373159811Sps	if (hdr->cmd_status != MFI_STAT_OK) {
1374159811Sps		free(ld_info, M_MFIBUF);
1375157114Sscottl		mfi_release_command(cm);
1376157114Sscottl		return;
1377157114Sscottl	}
1378157114Sscottl	mfi_release_command(cm);
1379157114Sscottl
1380157114Sscottl	ld = malloc(sizeof(struct mfi_ld), M_MFIBUF, M_NOWAIT|M_ZERO);
1381157114Sscottl	if (ld == NULL) {
1382157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate ld\n");
1383159811Sps		free(ld_info, M_MFIBUF);
1384159811Sps		return;
1385157114Sscottl	}
1386157114Sscottl
1387157114Sscottl	if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) {
1388157114Sscottl		device_printf(sc->mfi_dev, "Failed to add logical disk\n");
1389157624Sscottl		free(ld, M_MFIBUF);
1390159811Sps		free(ld_info, M_MFIBUF);
1391159811Sps		return;
1392157114Sscottl	}
1393157114Sscottl
1394163398Sscottl	ld->ld_id = ld_info->ld_config.properties.ld.v.target_id;
1395157114Sscottl	ld->ld_disk = child;
1396159811Sps	ld->ld_info = ld_info;
1397157114Sscottl
1398157114Sscottl	device_set_ivars(child, ld);
1399157114Sscottl	device_set_desc(child, "MFI Logical Disk");
1400157114Sscottl	mtx_unlock(&sc->mfi_io_lock);
1401157114Sscottl	mtx_lock(&Giant);
1402157114Sscottl	bus_generic_attach(sc->mfi_dev);
1403157114Sscottl	mtx_unlock(&Giant);
1404157114Sscottl	mtx_lock(&sc->mfi_io_lock);
1405157114Sscottl}
1406163399Sscottl
1407157114Sscottlstatic struct mfi_command *
1408157114Sscottlmfi_bio_command(struct mfi_softc *sc)
1409157114Sscottl{
1410157114Sscottl	struct mfi_io_frame *io;
1411157114Sscottl	struct mfi_command *cm;
1412157114Sscottl	struct bio *bio;
1413158737Sambrisko	int flags, blkcount;
1414157114Sscottl
1415157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
1416157114Sscottl		return (NULL);
1417157114Sscottl
1418157114Sscottl	if ((bio = mfi_dequeue_bio(sc)) == NULL) {
1419157114Sscottl		mfi_release_command(cm);
1420157114Sscottl		return (NULL);
1421157114Sscottl	}
1422157114Sscottl
1423157114Sscottl	io = &cm->cm_frame->io;
1424157114Sscottl	switch (bio->bio_cmd & 0x03) {
1425157114Sscottl	case BIO_READ:
1426157114Sscottl		io->header.cmd = MFI_CMD_LD_READ;
1427157114Sscottl		flags = MFI_CMD_DATAIN;
1428157114Sscottl		break;
1429157114Sscottl	case BIO_WRITE:
1430157114Sscottl		io->header.cmd = MFI_CMD_LD_WRITE;
1431157114Sscottl		flags = MFI_CMD_DATAOUT;
1432157114Sscottl		break;
1433157114Sscottl	default:
1434157114Sscottl		panic("Invalid bio command");
1435157114Sscottl	}
1436157114Sscottl
1437157114Sscottl	/* Cheat with the sector length to avoid a non-constant division */
1438157114Sscottl	blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
1439157114Sscottl	io->header.target_id = (uintptr_t)bio->bio_driver1;
1440157114Sscottl	io->header.timeout = 0;
1441157114Sscottl	io->header.flags = 0;
1442157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
1443157114Sscottl	io->header.data_len = blkcount;
1444157114Sscottl	io->sense_addr_lo = cm->cm_sense_busaddr;
1445157114Sscottl	io->sense_addr_hi = 0;
1446157114Sscottl	io->lba_hi = (bio->bio_pblkno & 0xffffffff00000000) >> 32;
1447157114Sscottl	io->lba_lo = bio->bio_pblkno & 0xffffffff;
1448157114Sscottl	cm->cm_complete = mfi_bio_complete;
1449157114Sscottl	cm->cm_private = bio;
1450157114Sscottl	cm->cm_data = bio->bio_data;
1451157114Sscottl	cm->cm_len = bio->bio_bcount;
1452157114Sscottl	cm->cm_sg = &io->sgl;
1453157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
1454157114Sscottl	cm->cm_flags = flags;
1455157114Sscottl	return (cm);
1456157114Sscottl}
1457157114Sscottl
1458157114Sscottlstatic void
1459157114Sscottlmfi_bio_complete(struct mfi_command *cm)
1460157114Sscottl{
1461157114Sscottl	struct bio *bio;
1462157114Sscottl	struct mfi_frame_header *hdr;
1463157114Sscottl	struct mfi_softc *sc;
1464157114Sscottl
1465157114Sscottl	bio = cm->cm_private;
1466157114Sscottl	hdr = &cm->cm_frame->header;
1467157114Sscottl	sc = cm->cm_sc;
1468157114Sscottl
1469157114Sscottl	if ((hdr->cmd_status != 0) || (hdr->scsi_status != 0)) {
1470157114Sscottl		bio->bio_flags |= BIO_ERROR;
1471157114Sscottl		bio->bio_error = EIO;
1472157114Sscottl		device_printf(sc->mfi_dev, "I/O error, status= %d "
1473157114Sscottl		    "scsi_status= %d\n", hdr->cmd_status, hdr->scsi_status);
1474157114Sscottl		mfi_print_sense(cm->cm_sc, cm->cm_sense);
1475157114Sscottl	}
1476157114Sscottl
1477157114Sscottl	mfi_release_command(cm);
1478157114Sscottl	mfi_disk_complete(bio);
1479157114Sscottl}
1480157114Sscottl
1481157114Sscottlvoid
1482157114Sscottlmfi_startio(struct mfi_softc *sc)
1483157114Sscottl{
1484157114Sscottl	struct mfi_command *cm;
1485157114Sscottl
1486157114Sscottl	for (;;) {
1487157114Sscottl		/* Don't bother if we're short on resources */
1488157114Sscottl		if (sc->mfi_flags & MFI_FLAGS_QFRZN)
1489157114Sscottl			break;
1490157114Sscottl
1491157114Sscottl		/* Try a command that has already been prepared */
1492157114Sscottl		cm = mfi_dequeue_ready(sc);
1493157114Sscottl
1494157114Sscottl		/* Nope, so look for work on the bioq */
1495157114Sscottl		if (cm == NULL)
1496157114Sscottl			cm = mfi_bio_command(sc);
1497157114Sscottl
1498157114Sscottl		/* No work available, so exit */
1499157114Sscottl		if (cm == NULL)
1500157114Sscottl			break;
1501157114Sscottl
1502157114Sscottl		/* Send the command to the controller */
1503157114Sscottl		if (mfi_mapcmd(sc, cm) != 0) {
1504157114Sscottl			mfi_requeue_ready(cm);
1505157114Sscottl			break;
1506157114Sscottl		}
1507157114Sscottl	}
1508157114Sscottl}
1509157114Sscottl
1510157114Sscottlstatic int
1511157114Sscottlmfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm)
1512157114Sscottl{
1513157114Sscottl	int error, polled;
1514157114Sscottl
1515163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1516163398Sscottl
1517157114Sscottl	if (cm->cm_data != NULL) {
1518157114Sscottl		polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0;
1519157114Sscottl		error = bus_dmamap_load(sc->mfi_buffer_dmat, cm->cm_dmamap,
1520157114Sscottl		    cm->cm_data, cm->cm_len, mfi_data_cb, cm, polled);
1521157114Sscottl		if (error == EINPROGRESS) {
1522157114Sscottl			sc->mfi_flags |= MFI_FLAGS_QFRZN;
1523157114Sscottl			return (0);
1524157114Sscottl		}
1525157114Sscottl	} else {
1526157114Sscottl		error = mfi_send_frame(sc, cm);
1527157114Sscottl	}
1528157114Sscottl
1529157114Sscottl	return (error);
1530157114Sscottl}
1531157114Sscottl
1532157114Sscottlstatic void
1533157114Sscottlmfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
1534157114Sscottl{
1535157114Sscottl	struct mfi_frame_header *hdr;
1536157114Sscottl	struct mfi_command *cm;
1537157237Sscottl	union mfi_sgl *sgl;
1538157114Sscottl	struct mfi_softc *sc;
1539157114Sscottl	int i, dir;
1540157114Sscottl
1541157114Sscottl	if (error)
1542157114Sscottl		return;
1543157114Sscottl
1544157114Sscottl	cm = (struct mfi_command *)arg;
1545157114Sscottl	sc = cm->cm_sc;
1546157237Sscottl	hdr = &cm->cm_frame->header;
1547157237Sscottl	sgl = cm->cm_sg;
1548157114Sscottl
1549157237Sscottl	if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
1550157237Sscottl		for (i = 0; i < nsegs; i++) {
1551157237Sscottl			sgl->sg32[i].addr = segs[i].ds_addr;
1552157237Sscottl			sgl->sg32[i].len = segs[i].ds_len;
1553157114Sscottl		}
1554157237Sscottl	} else {
1555157237Sscottl		for (i = 0; i < nsegs; i++) {
1556157237Sscottl			sgl->sg64[i].addr = segs[i].ds_addr;
1557157237Sscottl			sgl->sg64[i].len = segs[i].ds_len;
1558157237Sscottl		}
1559157237Sscottl		hdr->flags |= MFI_FRAME_SGL64;
1560157114Sscottl	}
1561157114Sscottl	hdr->sg_count = nsegs;
1562157114Sscottl
1563157114Sscottl	dir = 0;
1564157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAIN) {
1565157114Sscottl		dir |= BUS_DMASYNC_PREREAD;
1566157114Sscottl		hdr->flags |= MFI_FRAME_DIR_READ;
1567157114Sscottl	}
1568157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAOUT) {
1569157114Sscottl		dir |= BUS_DMASYNC_PREWRITE;
1570157114Sscottl		hdr->flags |= MFI_FRAME_DIR_WRITE;
1571157114Sscottl	}
1572157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
1573157114Sscottl	cm->cm_flags |= MFI_CMD_MAPPED;
1574157114Sscottl
1575157114Sscottl	/*
1576157114Sscottl	 * Instead of calculating the total number of frames in the
1577157114Sscottl	 * compound frame, it's already assumed that there will be at
1578157114Sscottl	 * least 1 frame, so don't compensate for the modulo of the
1579157114Sscottl	 * following division.
1580157114Sscottl	 */
1581162458Sscottl	cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs);
1582157114Sscottl	cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
1583157114Sscottl
1584164375Sscottl	mfi_send_frame(sc, cm);
1585157114Sscottl
1586157114Sscottl	return;
1587157114Sscottl}
1588157114Sscottl
1589157114Sscottlstatic int
1590157114Sscottlmfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
1591157114Sscottl{
1592164375Sscottl	struct mfi_frame_header *hdr;
1593165225Sambrisko	int tm = MFI_POLL_TIMEOUT_SECS * 1000;
1594157114Sscottl
1595164375Sscottl	hdr = &cm->cm_frame->header;
1596164375Sscottl
1597164375Sscottl	if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
1598164375Sscottl		cm->cm_timestamp = time_uptime;
1599164375Sscottl		mfi_enqueue_busy(cm);
1600164375Sscottl	} else {
1601164375Sscottl		hdr->cmd_status = 0xff;
1602164375Sscottl		hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
1603164375Sscottl	}
1604164375Sscottl
1605157114Sscottl	/*
1606157114Sscottl	 * The bus address of the command is aligned on a 64 byte boundary,
1607157114Sscottl	 * leaving the least 6 bits as zero.  For whatever reason, the
1608157114Sscottl	 * hardware wants the address shifted right by three, leaving just
1609162458Sscottl	 * 3 zero bits.  These three bits are then used as a prefetching
1610162458Sscottl	 * hint for the hardware to predict how many frames need to be
1611162458Sscottl	 * fetched across the bus.  If a command has more than 8 frames
1612162458Sscottl	 * then the 3 bits are set to 0x7 and the firmware uses other
1613162458Sscottl	 * information in the command to determine the total amount to fetch.
1614162458Sscottl	 * However, FreeBSD doesn't support I/O larger than 128K, so 8 frames
1615162458Sscottl	 * is enough for both 32bit and 64bit systems.
1616157114Sscottl	 */
1617162458Sscottl	if (cm->cm_extra_frames > 7)
1618162458Sscottl		cm->cm_extra_frames = 7;
1619162458Sscottl
1620157114Sscottl	MFI_WRITE4(sc, MFI_IQP, (cm->cm_frame_busaddr >> 3) |
1621157114Sscottl	    cm->cm_extra_frames);
1622164375Sscottl
1623164375Sscottl	if ((cm->cm_flags & MFI_CMD_POLLED) == 0)
1624164375Sscottl		return (0);
1625164375Sscottl
1626164375Sscottl	/* This is a polled command, so busy-wait for it to complete. */
1627164375Sscottl	while (hdr->cmd_status == 0xff) {
1628164375Sscottl		DELAY(1000);
1629165225Sambrisko		tm -= 1;
1630164375Sscottl		if (tm <= 0)
1631164375Sscottl			break;
1632164375Sscottl	}
1633164375Sscottl
1634164375Sscottl	if (hdr->cmd_status == 0xff) {
1635165225Sambrisko		device_printf(sc->mfi_dev, "Frame %p timed out "
1636165225Sambrisko			      "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
1637164375Sscottl		return (ETIMEDOUT);
1638164375Sscottl	}
1639164375Sscottl
1640157114Sscottl	return (0);
1641157114Sscottl}
1642157114Sscottl
1643157114Sscottlstatic void
1644157114Sscottlmfi_complete(struct mfi_softc *sc, struct mfi_command *cm)
1645157114Sscottl{
1646157114Sscottl	int dir;
1647157114Sscottl
1648157114Sscottl	if ((cm->cm_flags & MFI_CMD_MAPPED) != 0) {
1649157114Sscottl		dir = 0;
1650157114Sscottl		if (cm->cm_flags & MFI_CMD_DATAIN)
1651157114Sscottl			dir |= BUS_DMASYNC_POSTREAD;
1652157114Sscottl		if (cm->cm_flags & MFI_CMD_DATAOUT)
1653157114Sscottl			dir |= BUS_DMASYNC_POSTWRITE;
1654157114Sscottl
1655157114Sscottl		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
1656157114Sscottl		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1657157114Sscottl		cm->cm_flags &= ~MFI_CMD_MAPPED;
1658157114Sscottl	}
1659157114Sscottl
1660157114Sscottl	if (cm->cm_complete != NULL)
1661157114Sscottl		cm->cm_complete(cm);
1662159811Sps	else
1663159811Sps		wakeup(cm);
1664157114Sscottl}
1665157114Sscottl
1666158737Sambriskostatic int
1667158737Sambriskomfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort)
1668158737Sambrisko{
1669158737Sambrisko	struct mfi_command *cm;
1670158737Sambrisko	struct mfi_abort_frame *abort;
1671165225Sambrisko	int i = 0;
1672158737Sambrisko
1673163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1674163398Sscottl
1675158737Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL) {
1676158737Sambrisko		return (EBUSY);
1677158737Sambrisko	}
1678158737Sambrisko
1679158737Sambrisko	abort = &cm->cm_frame->abort;
1680158737Sambrisko	abort->header.cmd = MFI_CMD_ABORT;
1681158737Sambrisko	abort->header.flags = 0;
1682158737Sambrisko	abort->abort_context = cm_abort->cm_frame->header.context;
1683158737Sambrisko	abort->abort_mfi_addr_lo = cm_abort->cm_frame_busaddr;
1684158737Sambrisko	abort->abort_mfi_addr_hi = 0;
1685158737Sambrisko	cm->cm_data = NULL;
1686164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
1687158737Sambrisko
1688158737Sambrisko	sc->mfi_aen_cm->cm_aen_abort = 1;
1689158737Sambrisko	mfi_mapcmd(sc, cm);
1690158737Sambrisko	mfi_release_command(cm);
1691158737Sambrisko
1692165225Sambrisko	while (i < 5 && sc->mfi_aen_cm != NULL) {
1693163398Sscottl		msleep(&sc->mfi_aen_cm, &sc->mfi_io_lock, 0, "mfiabort", 5 * hz);
1694165225Sambrisko		i++;
1695158737Sambrisko	}
1696158737Sambrisko
1697158737Sambrisko	return (0);
1698158737Sambrisko}
1699158737Sambrisko
1700157114Sscottlint
1701157114Sscottlmfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, int len)
1702157114Sscottl{
1703157114Sscottl	struct mfi_command *cm;
1704157114Sscottl	struct mfi_io_frame *io;
1705157114Sscottl	int error;
1706157114Sscottl
1707157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
1708157114Sscottl		return (EBUSY);
1709157114Sscottl
1710157114Sscottl	io = &cm->cm_frame->io;
1711157114Sscottl	io->header.cmd = MFI_CMD_LD_WRITE;
1712157114Sscottl	io->header.target_id = id;
1713157114Sscottl	io->header.timeout = 0;
1714157114Sscottl	io->header.flags = 0;
1715157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
1716157114Sscottl	io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
1717157114Sscottl	io->sense_addr_lo = cm->cm_sense_busaddr;
1718157114Sscottl	io->sense_addr_hi = 0;
1719157114Sscottl	io->lba_hi = (lba & 0xffffffff00000000) >> 32;
1720157114Sscottl	io->lba_lo = lba & 0xffffffff;
1721157114Sscottl	cm->cm_data = virt;
1722157114Sscottl	cm->cm_len = len;
1723157114Sscottl	cm->cm_sg = &io->sgl;
1724157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
1725157114Sscottl	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT;
1726157114Sscottl
1727164375Sscottl	error = mfi_mapcmd(sc, cm);
1728157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1729157114Sscottl	    BUS_DMASYNC_POSTWRITE);
1730157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1731157114Sscottl	mfi_release_command(cm);
1732157114Sscottl
1733157114Sscottl	return (error);
1734157114Sscottl}
1735157114Sscottl
1736157114Sscottlstatic int
1737157114Sscottlmfi_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
1738157114Sscottl{
1739157114Sscottl	struct mfi_softc *sc;
1740157114Sscottl
1741157114Sscottl	sc = dev->si_drv1;
1742163398Sscottl
1743163398Sscottl	mtx_lock(&sc->mfi_io_lock);
1744157114Sscottl	sc->mfi_flags |= MFI_FLAGS_OPEN;
1745163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1746157114Sscottl
1747157114Sscottl	return (0);
1748157114Sscottl}
1749157114Sscottl
1750157114Sscottlstatic int
1751157114Sscottlmfi_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
1752157114Sscottl{
1753157114Sscottl	struct mfi_softc *sc;
1754163398Sscottl	struct mfi_aen *mfi_aen_entry, *tmp;
1755157114Sscottl
1756157114Sscottl	sc = dev->si_drv1;
1757163398Sscottl
1758163398Sscottl	mtx_lock(&sc->mfi_io_lock);
1759157114Sscottl	sc->mfi_flags &= ~MFI_FLAGS_OPEN;
1760157114Sscottl
1761163398Sscottl	TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
1762158737Sambrisko		if (mfi_aen_entry->p == curproc) {
1763158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
1764158737Sambrisko			    aen_link);
1765158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
1766158737Sambrisko		}
1767158737Sambrisko	}
1768163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1769157114Sscottl	return (0);
1770157114Sscottl}
1771157114Sscottl
1772157114Sscottlstatic int
1773157114Sscottlmfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
1774157114Sscottl{
1775157114Sscottl	struct mfi_softc *sc;
1776157114Sscottl	union mfi_statrequest *ms;
1777164281Sambrisko	struct mfi_ioc_packet *ioc;
1778164281Sambrisko	struct mfi_ioc_aen *aen;
1779164281Sambrisko	struct mfi_command *cm = NULL;
1780164281Sambrisko	uint32_t context;
1781165225Sambrisko	uint8_t *sense_ptr;
1782164281Sambrisko	uint8_t *data = NULL, *temp;
1783164281Sambrisko	int i;
1784157114Sscottl	int error;
1785157114Sscottl
1786157114Sscottl	sc = dev->si_drv1;
1787157114Sscottl	error = 0;
1788157114Sscottl
1789157114Sscottl	switch (cmd) {
1790157114Sscottl	case MFIIO_STATS:
1791157114Sscottl		ms = (union mfi_statrequest *)arg;
1792157114Sscottl		switch (ms->ms_item) {
1793157114Sscottl		case MFIQ_FREE:
1794157114Sscottl		case MFIQ_BIO:
1795157114Sscottl		case MFIQ_READY:
1796157114Sscottl		case MFIQ_BUSY:
1797157114Sscottl			bcopy(&sc->mfi_qstat[ms->ms_item], &ms->ms_qstat,
1798157114Sscottl			    sizeof(struct mfi_qstat));
1799157114Sscottl			break;
1800157114Sscottl		default:
1801158737Sambrisko			error = ENOIOCTL;
1802157114Sscottl			break;
1803157114Sscottl		}
1804157114Sscottl		break;
1805164281Sambrisko	case MFI_CMD:
1806164281Sambrisko		ioc = (struct mfi_ioc_packet *)arg;
1807164281Sambrisko
1808164281Sambrisko		mtx_lock(&sc->mfi_io_lock);
1809164281Sambrisko		if ((cm = mfi_dequeue_free(sc)) == NULL) {
1810164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1811164281Sambrisko			return (EBUSY);
1812164281Sambrisko		}
1813164281Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1814164281Sambrisko
1815164281Sambrisko		/*
1816164281Sambrisko		 * save off original context since copying from user
1817164281Sambrisko		 * will clobber some data
1818164281Sambrisko		 */
1819164281Sambrisko		context = cm->cm_frame->header.context;
1820164281Sambrisko
1821165225Sambrisko		bcopy(ioc->mfi_frame.raw, cm->cm_frame,
1822165225Sambrisko		      ioc->mfi_sgl_off); /* Linux can do 2 frames ? */
1823165225Sambrisko		cm->cm_total_frame_size = ioc->mfi_sgl_off;
1824164281Sambrisko		cm->cm_sg =
1825165225Sambrisko		    (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off];
1826164281Sambrisko		cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT
1827164281Sambrisko			| MFI_CMD_POLLED;
1828164281Sambrisko		cm->cm_len = cm->cm_frame->header.data_len;
1829164281Sambrisko		cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
1830164281Sambrisko					    M_WAITOK | M_ZERO);
1831165225Sambrisko		if (cm->cm_data == NULL) {
1832165225Sambrisko			device_printf(sc->mfi_dev, "Malloc failed\n");
1833165225Sambrisko			goto out;
1834165225Sambrisko		}
1835164281Sambrisko
1836164281Sambrisko		/* restore header context */
1837164281Sambrisko		cm->cm_frame->header.context = context;
1838164281Sambrisko
1839164281Sambrisko		temp = data;
1840165225Sambrisko		for (i = 0; i < ioc->mfi_sge_count; i++) {
1841165225Sambrisko			error = copyin(ioc->mfi_sgl[i].iov_base,
1842164281Sambrisko			       temp,
1843165225Sambrisko			       ioc->mfi_sgl[i].iov_len);
1844164281Sambrisko			if (error != 0) {
1845164281Sambrisko				device_printf(sc->mfi_dev,
1846165225Sambrisko				    "Copy in failed\n");
1847164281Sambrisko				goto out;
1848164281Sambrisko			}
1849165225Sambrisko			temp = &temp[ioc->mfi_sgl[i].iov_len];
1850164281Sambrisko		}
1851164281Sambrisko
1852164281Sambrisko		mtx_lock(&sc->mfi_io_lock);
1853164281Sambrisko		if ((error = mfi_mapcmd(sc, cm)) != 0) {
1854164281Sambrisko			device_printf(sc->mfi_dev,
1855165225Sambrisko			    "Controller polled failed\n");
1856164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1857164281Sambrisko			goto out;
1858164281Sambrisko		}
1859164281Sambrisko
1860164281Sambrisko		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1861164281Sambrisko				BUS_DMASYNC_POSTREAD);
1862164281Sambrisko		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1863164281Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1864164281Sambrisko
1865164281Sambrisko		temp = data;
1866165225Sambrisko		for (i = 0; i < ioc->mfi_sge_count; i++) {
1867164281Sambrisko			error = copyout(temp,
1868165225Sambrisko				ioc->mfi_sgl[i].iov_base,
1869165225Sambrisko				ioc->mfi_sgl[i].iov_len);
1870164281Sambrisko			if (error != 0) {
1871164281Sambrisko				device_printf(sc->mfi_dev,
1872165225Sambrisko				    "Copy out failed\n");
1873164281Sambrisko				goto out;
1874164281Sambrisko			}
1875165225Sambrisko			temp = &temp[ioc->mfi_sgl[i].iov_len];
1876164281Sambrisko		}
1877164281Sambrisko
1878165225Sambrisko		if (ioc->mfi_sense_len) {
1879164281Sambrisko			/* copy out sense */
1880165225Sambrisko			sense_ptr = &((struct mfi_ioc_packet*)arg)
1881165225Sambrisko			    ->mfi_frame.raw[0];
1882165225Sambrisko			error = copyout(cm->cm_sense, sense_ptr,
1883165225Sambrisko			    ioc->mfi_sense_len);
1884164281Sambrisko			if (error != 0) {
1885164281Sambrisko				device_printf(sc->mfi_dev,
1886165225Sambrisko				    "Copy out failed\n");
1887164281Sambrisko				goto out;
1888164281Sambrisko			}
1889164281Sambrisko		}
1890164281Sambrisko
1891165225Sambrisko		ioc->mfi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status;
1892164281Sambrisko		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
1893165225Sambrisko			switch (cm->cm_frame->dcmd.opcode) {
1894164281Sambrisko			case MFI_DCMD_CFG_CLEAR:
1895164281Sambrisko			case MFI_DCMD_CFG_ADD:
1896164281Sambrisko/*
1897164281Sambrisko				mfi_ldrescan(sc);
1898164281Sambrisko*/
1899164281Sambrisko				break;
1900164281Sambrisko			}
1901164281Sambrisko		}
1902164281Sambriskoout:
1903164281Sambrisko		if (data)
1904164281Sambrisko			free(data, M_MFIBUF);
1905164281Sambrisko		if (cm) {
1906164281Sambrisko			mtx_lock(&sc->mfi_io_lock);
1907164281Sambrisko			mfi_release_command(cm);
1908164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1909164281Sambrisko		}
1910164281Sambrisko
1911164281Sambrisko		break;
1912164281Sambrisko	case MFI_SET_AEN:
1913164281Sambrisko		aen = (struct mfi_ioc_aen *)arg;
1914164281Sambrisko		error = mfi_aen_register(sc, aen->aen_seq_num,
1915164281Sambrisko		    aen->aen_class_locale);
1916164281Sambrisko
1917164281Sambrisko		break;
1918164281Sambrisko	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
1919158737Sambrisko		{
1920158737Sambrisko			devclass_t devclass;
1921158737Sambrisko			struct mfi_linux_ioc_packet l_ioc;
1922158737Sambrisko			int adapter;
1923158737Sambrisko
1924158737Sambrisko			devclass = devclass_find("mfi");
1925158737Sambrisko			if (devclass == NULL)
1926158737Sambrisko				return (ENOENT);
1927158737Sambrisko
1928158737Sambrisko			error = copyin(arg, &l_ioc, sizeof(l_ioc));
1929158737Sambrisko			if (error)
1930158737Sambrisko				return (error);
1931158737Sambrisko			adapter = l_ioc.lioc_adapter_no;
1932158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
1933158737Sambrisko			if (sc == NULL)
1934158737Sambrisko				return (ENOENT);
1935158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
1936158737Sambrisko			    cmd, arg, flag, td));
1937158737Sambrisko			break;
1938158737Sambrisko		}
1939164281Sambrisko	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
1940158737Sambrisko		{
1941158737Sambrisko			devclass_t devclass;
1942158737Sambrisko			struct mfi_linux_ioc_aen l_aen;
1943158737Sambrisko			int adapter;
1944158737Sambrisko
1945158737Sambrisko			devclass = devclass_find("mfi");
1946158737Sambrisko			if (devclass == NULL)
1947158737Sambrisko				return (ENOENT);
1948158737Sambrisko
1949158737Sambrisko			error = copyin(arg, &l_aen, sizeof(l_aen));
1950158737Sambrisko			if (error)
1951158737Sambrisko				return (error);
1952158737Sambrisko			adapter = l_aen.laen_adapter_no;
1953158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
1954158737Sambrisko			if (sc == NULL)
1955158737Sambrisko				return (ENOENT);
1956158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
1957158737Sambrisko			    cmd, arg, flag, td));
1958158737Sambrisko			break;
1959158737Sambrisko		}
1960157114Sscottl	default:
1961163398Sscottl		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
1962157114Sscottl		error = ENOENT;
1963157114Sscottl		break;
1964157114Sscottl	}
1965157114Sscottl
1966157114Sscottl	return (error);
1967157114Sscottl}
1968158737Sambrisko
1969158737Sambriskostatic int
1970158737Sambriskomfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
1971158737Sambrisko{
1972158737Sambrisko	struct mfi_softc *sc;
1973158737Sambrisko	struct mfi_linux_ioc_packet l_ioc;
1974158737Sambrisko	struct mfi_linux_ioc_aen l_aen;
1975158737Sambrisko	struct mfi_command *cm = NULL;
1976158737Sambrisko	struct mfi_aen *mfi_aen_entry;
1977165225Sambrisko	uint8_t *sense_ptr;
1978158737Sambrisko	uint32_t context;
1979158737Sambrisko	uint8_t *data = NULL, *temp;
1980164281Sambrisko	void *temp_convert;
1981158737Sambrisko	int i;
1982158737Sambrisko	int error;
1983158737Sambrisko
1984158737Sambrisko	sc = dev->si_drv1;
1985158737Sambrisko	error = 0;
1986158737Sambrisko	switch (cmd) {
1987164281Sambrisko	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
1988158737Sambrisko		error = copyin(arg, &l_ioc, sizeof(l_ioc));
1989158737Sambrisko		if (error != 0)
1990158737Sambrisko			return (error);
1991158737Sambrisko
1992158737Sambrisko		if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) {
1993158737Sambrisko			return (EINVAL);
1994158737Sambrisko		}
1995158737Sambrisko
1996158737Sambrisko		mtx_lock(&sc->mfi_io_lock);
1997158737Sambrisko		if ((cm = mfi_dequeue_free(sc)) == NULL) {
1998158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1999158737Sambrisko			return (EBUSY);
2000158737Sambrisko		}
2001158737Sambrisko		mtx_unlock(&sc->mfi_io_lock);
2002158737Sambrisko
2003158737Sambrisko		/*
2004158737Sambrisko		 * save off original context since copying from user
2005158737Sambrisko		 * will clobber some data
2006158737Sambrisko		 */
2007158737Sambrisko		context = cm->cm_frame->header.context;
2008158737Sambrisko
2009158737Sambrisko		bcopy(l_ioc.lioc_frame.raw, cm->cm_frame,
2010158737Sambrisko		      l_ioc.lioc_sgl_off); /* Linux can do 2 frames ? */
2011158737Sambrisko		cm->cm_total_frame_size = l_ioc.lioc_sgl_off;
2012158737Sambrisko		cm->cm_sg =
2013158737Sambrisko		    (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
2014158737Sambrisko		cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT
2015158737Sambrisko			| MFI_CMD_POLLED;
2016158737Sambrisko		cm->cm_len = cm->cm_frame->header.data_len;
2017158737Sambrisko		cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
2018158737Sambrisko					    M_WAITOK | M_ZERO);
2019158737Sambrisko
2020158737Sambrisko		/* restore header context */
2021158737Sambrisko		cm->cm_frame->header.context = context;
2022158737Sambrisko
2023158737Sambrisko		temp = data;
2024158737Sambrisko		for (i = 0; i < l_ioc.lioc_sge_count; i++) {
2025164281Sambrisko			temp_convert =
2026164281Sambrisko			    (void *)(uintptr_t)l_ioc.lioc_sgl[i].iov_base;
2027164281Sambrisko			error = copyin(temp_convert,
2028158737Sambrisko			       temp,
2029158737Sambrisko			       l_ioc.lioc_sgl[i].iov_len);
2030158737Sambrisko			if (error != 0) {
2031158737Sambrisko				device_printf(sc->mfi_dev,
2032165225Sambrisko				    "Copy in failed\n");
2033158737Sambrisko				goto out;
2034158737Sambrisko			}
2035158737Sambrisko			temp = &temp[l_ioc.lioc_sgl[i].iov_len];
2036158737Sambrisko		}
2037158737Sambrisko
2038163398Sscottl		mtx_lock(&sc->mfi_io_lock);
2039158737Sambrisko		if ((error = mfi_mapcmd(sc, cm)) != 0) {
2040158737Sambrisko			device_printf(sc->mfi_dev,
2041165225Sambrisko			    "Controller polled failed\n");
2042163398Sscottl			mtx_unlock(&sc->mfi_io_lock);
2043158737Sambrisko			goto out;
2044158737Sambrisko		}
2045158737Sambrisko
2046158737Sambrisko		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
2047158737Sambrisko				BUS_DMASYNC_POSTREAD);
2048158737Sambrisko		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
2049163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
2050158737Sambrisko
2051158737Sambrisko		temp = data;
2052158737Sambrisko		for (i = 0; i < l_ioc.lioc_sge_count; i++) {
2053164281Sambrisko			temp_convert =
2054164281Sambrisko			    (void *)(uintptr_t)l_ioc.lioc_sgl[i].iov_base;
2055158737Sambrisko			error = copyout(temp,
2056164281Sambrisko				temp_convert,
2057158737Sambrisko				l_ioc.lioc_sgl[i].iov_len);
2058158737Sambrisko			if (error != 0) {
2059158737Sambrisko				device_printf(sc->mfi_dev,
2060165225Sambrisko				    "Copy out failed\n");
2061158737Sambrisko				goto out;
2062158737Sambrisko			}
2063158737Sambrisko			temp = &temp[l_ioc.lioc_sgl[i].iov_len];
2064158737Sambrisko		}
2065158737Sambrisko
2066158737Sambrisko		if (l_ioc.lioc_sense_len) {
2067158737Sambrisko			/* copy out sense */
2068165225Sambrisko			sense_ptr = &((struct mfi_linux_ioc_packet*)arg)
2069165225Sambrisko			    ->lioc_frame.raw[0];
2070165225Sambrisko			error = copyout(cm->cm_sense, sense_ptr,
2071158737Sambrisko			    l_ioc.lioc_sense_len);
2072158737Sambrisko			if (error != 0) {
2073158737Sambrisko				device_printf(sc->mfi_dev,
2074165225Sambrisko				    "Copy out failed\n");
2075158737Sambrisko				goto out;
2076158737Sambrisko			}
2077158737Sambrisko		}
2078158737Sambrisko
2079158737Sambrisko		error = copyout(&cm->cm_frame->header.cmd_status,
2080158737Sambrisko			&((struct mfi_linux_ioc_packet*)arg)
2081158737Sambrisko			->lioc_frame.hdr.cmd_status,
2082158737Sambrisko			1);
2083158737Sambrisko		if (error != 0) {
2084158737Sambrisko			device_printf(sc->mfi_dev,
2085165225Sambrisko				      "Copy out failed\n");
2086158737Sambrisko			goto out;
2087158737Sambrisko		}
2088158737Sambrisko
2089163398Sscottl		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
2090163398Sscottl			switch (cm->cm_frame->dcmd.opcode) {
2091163398Sscottl			case MFI_DCMD_CFG_CLEAR:
2092163398Sscottl			case MFI_DCMD_CFG_ADD:
2093163398Sscottl				/* mfi_ldrescan(sc); */
2094163398Sscottl				break;
2095163398Sscottl			}
2096163398Sscottl		}
2097158737Sambriskoout:
2098158737Sambrisko		if (data)
2099158737Sambrisko			free(data, M_MFIBUF);
2100158737Sambrisko		if (cm) {
2101158737Sambrisko			mtx_lock(&sc->mfi_io_lock);
2102158737Sambrisko			mfi_release_command(cm);
2103158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
2104158737Sambrisko		}
2105158737Sambrisko
2106158737Sambrisko		return (error);
2107164281Sambrisko	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
2108158737Sambrisko		error = copyin(arg, &l_aen, sizeof(l_aen));
2109158737Sambrisko		if (error != 0)
2110158737Sambrisko			return (error);
2111158737Sambrisko		printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid);
2112158737Sambrisko		mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF,
2113158737Sambrisko		    M_WAITOK);
2114163398Sscottl		mtx_lock(&sc->mfi_io_lock);
2115158737Sambrisko		if (mfi_aen_entry != NULL) {
2116158737Sambrisko			mfi_aen_entry->p = curproc;
2117158737Sambrisko			TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry,
2118158737Sambrisko			    aen_link);
2119158737Sambrisko		}
2120158737Sambrisko		error = mfi_aen_register(sc, l_aen.laen_seq_num,
2121158737Sambrisko		    l_aen.laen_class_locale);
2122158737Sambrisko
2123158737Sambrisko		if (error != 0) {
2124158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
2125158737Sambrisko			    aen_link);
2126158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
2127158737Sambrisko		}
2128163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
2129158737Sambrisko
2130158737Sambrisko		return (error);
2131158737Sambrisko	default:
2132158737Sambrisko		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
2133158737Sambrisko		error = ENOENT;
2134158737Sambrisko		break;
2135158737Sambrisko	}
2136158737Sambrisko
2137158737Sambrisko	return (error);
2138158737Sambrisko}
2139158737Sambrisko
2140158737Sambriskostatic int
2141158737Sambriskomfi_poll(struct cdev *dev, int poll_events, struct thread *td)
2142158737Sambrisko{
2143158737Sambrisko	struct mfi_softc *sc;
2144158737Sambrisko	int revents = 0;
2145158737Sambrisko
2146158737Sambrisko	sc = dev->si_drv1;
2147158737Sambrisko
2148158737Sambrisko	if (poll_events & (POLLIN | POLLRDNORM)) {
2149163398Sscottl		if (sc->mfi_aen_triggered != 0) {
2150158737Sambrisko			revents |= poll_events & (POLLIN | POLLRDNORM);
2151163398Sscottl			sc->mfi_aen_triggered = 0;
2152163398Sscottl		}
2153158737Sambrisko		if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) {
2154158737Sambrisko			revents |= POLLERR;
2155158737Sambrisko		}
2156158737Sambrisko	}
2157158737Sambrisko
2158158737Sambrisko	if (revents == 0) {
2159158737Sambrisko		if (poll_events & (POLLIN | POLLRDNORM)) {
2160158737Sambrisko			sc->mfi_poll_waiting = 1;
2161158737Sambrisko			selrecord(td, &sc->mfi_select);
2162158737Sambrisko		}
2163158737Sambrisko	}
2164158737Sambrisko
2165158737Sambrisko	return revents;
2166158737Sambrisko}
2167162619Sscottl
2168163398Sscottl
2169162619Sscottlstatic void
2170163398Sscottlmfi_dump_all(void)
2171163398Sscottl{
2172163398Sscottl	struct mfi_softc *sc;
2173163398Sscottl	struct mfi_command *cm;
2174163398Sscottl	devclass_t dc;
2175163398Sscottl	time_t deadline;
2176163398Sscottl	int timedout;
2177163398Sscottl	int i;
2178163398Sscottl
2179163398Sscottl	dc = devclass_find("mfi");
2180163398Sscottl	if (dc == NULL) {
2181163398Sscottl		printf("No mfi dev class\n");
2182163398Sscottl		return;
2183163398Sscottl	}
2184163398Sscottl
2185163398Sscottl	for (i = 0; ; i++) {
2186163398Sscottl		sc = devclass_get_softc(dc, i);
2187163398Sscottl		if (sc == NULL)
2188163398Sscottl			break;
2189163398Sscottl		device_printf(sc->mfi_dev, "Dumping\n\n");
2190163398Sscottl		timedout = 0;
2191163398Sscottl		deadline = time_uptime - MFI_CMD_TIMEOUT;
2192163398Sscottl		mtx_lock(&sc->mfi_io_lock);
2193163398Sscottl		TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
2194163398Sscottl			if (cm->cm_timestamp < deadline) {
2195163398Sscottl				device_printf(sc->mfi_dev,
2196163398Sscottl				    "COMMAND %p TIMEOUT AFTER %d SECONDS\n", cm,
2197163398Sscottl				    (int)(time_uptime - cm->cm_timestamp));
2198163398Sscottl				MFI_PRINT_CMD(cm);
2199163398Sscottl				timedout++;
2200163398Sscottl			}
2201163398Sscottl		}
2202163398Sscottl
2203163398Sscottl#if 0
2204163398Sscottl		if (timedout)
2205163398Sscottl			MFI_DUMP_CMDS(SC);
2206163398Sscottl#endif
2207163398Sscottl
2208163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
2209163398Sscottl	}
2210163398Sscottl
2211163398Sscottl	return;
2212163398Sscottl}
2213163398Sscottl
2214163398Sscottlstatic void
2215162619Sscottlmfi_timeout(void *data)
2216162619Sscottl{
2217162619Sscottl	struct mfi_softc *sc = (struct mfi_softc *)data;
2218162619Sscottl	struct mfi_command *cm;
2219162619Sscottl	time_t deadline;
2220162619Sscottl	int timedout = 0;
2221162619Sscottl
2222162619Sscottl	deadline = time_uptime - MFI_CMD_TIMEOUT;
2223162619Sscottl	mtx_lock(&sc->mfi_io_lock);
2224162619Sscottl	TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
2225162688Sscottl		if (sc->mfi_aen_cm == cm)
2226162688Sscottl			continue;
2227163398Sscottl		if ((sc->mfi_aen_cm != cm) && (cm->cm_timestamp < deadline)) {
2228162619Sscottl			device_printf(sc->mfi_dev,
2229162619Sscottl			    "COMMAND %p TIMEOUT AFTER %d SECONDS\n", cm,
2230162619Sscottl			    (int)(time_uptime - cm->cm_timestamp));
2231162619Sscottl			MFI_PRINT_CMD(cm);
2232163398Sscottl			MFI_VALIDATE_CMD(sc, cm);
2233162619Sscottl			timedout++;
2234162619Sscottl		}
2235162619Sscottl	}
2236162619Sscottl
2237162619Sscottl#if 0
2238162619Sscottl	if (timedout)
2239162619Sscottl		MFI_DUMP_CMDS(SC);
2240162619Sscottl#endif
2241162619Sscottl
2242162619Sscottl	mtx_unlock(&sc->mfi_io_lock);
2243162619Sscottl
2244162619Sscottl	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
2245162619Sscottl	    mfi_timeout, sc);
2246162619Sscottl
2247163398Sscottl	if (0)
2248163398Sscottl		mfi_dump_all();
2249162619Sscottl	return;
2250162619Sscottl}
2251