mfi.c revision 159811
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 159811 2006-06-20 22:41:44Z ps $");
29157114Sscottl
30157114Sscottl#include "opt_mfi.h"
31157114Sscottl
32157114Sscottl#include <sys/param.h>
33157114Sscottl#include <sys/systm.h>
34157114Sscottl#include <sys/malloc.h>
35157114Sscottl#include <sys/kernel.h>
36158737Sambrisko#include <sys/poll.h>
37158737Sambrisko#include <sys/selinfo.h>
38157114Sscottl#include <sys/bus.h>
39157114Sscottl#include <sys/conf.h>
40157114Sscottl#include <sys/eventhandler.h>
41157114Sscottl#include <sys/rman.h>
42157114Sscottl#include <sys/bus_dma.h>
43157114Sscottl#include <sys/bio.h>
44157114Sscottl#include <sys/ioccom.h>
45158737Sambrisko#include <sys/uio.h>
46158737Sambrisko#include <sys/proc.h>
47157114Sscottl
48157114Sscottl#include <machine/bus.h>
49157114Sscottl#include <machine/resource.h>
50157114Sscottl
51157114Sscottl#include <dev/mfi/mfireg.h>
52157114Sscottl#include <dev/mfi/mfi_ioctl.h>
53157114Sscottl#include <dev/mfi/mfivar.h>
54157114Sscottl
55157114Sscottlstatic int	mfi_alloc_commands(struct mfi_softc *);
56157114Sscottlstatic void	mfi_release_command(struct mfi_command *cm);
57157114Sscottlstatic int	mfi_comms_init(struct mfi_softc *);
58157114Sscottlstatic int	mfi_polled_command(struct mfi_softc *, struct mfi_command *);
59159811Spsstatic int	mfi_wait_command(struct mfi_softc *, struct mfi_command *);
60157114Sscottlstatic int	mfi_get_controller_info(struct mfi_softc *);
61158737Sambriskostatic int	mfi_get_log_state(struct mfi_softc *,
62159806Sps		    struct mfi_evt_log_state **);
63159574Sambrisko#ifdef NOTYET
64158737Sambriskostatic int	mfi_get_entry(struct mfi_softc *, int);
65159574Sambrisko#endif
66159806Spsstatic int	mfi_dcmd_command(struct mfi_softc *, struct mfi_command **,
67159806Sps		    uint32_t, void **, size_t);
68157114Sscottlstatic void	mfi_data_cb(void *, bus_dma_segment_t *, int, int);
69157114Sscottlstatic void	mfi_startup(void *arg);
70157114Sscottlstatic void	mfi_intr(void *arg);
71157114Sscottlstatic void	mfi_enable_intr(struct mfi_softc *sc);
72159811Spsstatic void	mfi_ldprobe(struct mfi_softc *sc);
73158737Sambriskostatic int	mfi_aen_register(struct mfi_softc *sc, int seq, int locale);
74158737Sambriskostatic void	mfi_aen_complete(struct mfi_command *);
75158737Sambriskostatic int	mfi_aen_setup(struct mfi_softc *, uint32_t);
76159811Spsstatic int	mfi_add_ld(struct mfi_softc *sc, int);
77159811Spsstatic void	mfi_add_ld_complete(struct mfi_command *);
78157114Sscottlstatic struct mfi_command * mfi_bio_command(struct mfi_softc *);
79157114Sscottlstatic void	mfi_bio_complete(struct mfi_command *);
80157114Sscottlstatic int	mfi_mapcmd(struct mfi_softc *, struct mfi_command *);
81157114Sscottlstatic int	mfi_send_frame(struct mfi_softc *, struct mfi_command *);
82157114Sscottlstatic void	mfi_complete(struct mfi_softc *, struct mfi_command *);
83158737Sambriskostatic int	mfi_abort(struct mfi_softc *, struct mfi_command *);
84158737Sambriskostatic int	mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int, d_thread_t *);
85157114Sscottl
86157114Sscottl/* Management interface */
87157114Sscottlstatic d_open_t		mfi_open;
88157114Sscottlstatic d_close_t	mfi_close;
89157114Sscottlstatic d_ioctl_t	mfi_ioctl;
90158737Sambriskostatic d_poll_t		mfi_poll;
91157114Sscottl
92157114Sscottlstatic struct cdevsw mfi_cdevsw = {
93157114Sscottl	.d_version = 	D_VERSION,
94157114Sscottl	.d_flags =	0,
95157114Sscottl	.d_open = 	mfi_open,
96157114Sscottl	.d_close =	mfi_close,
97157114Sscottl	.d_ioctl =	mfi_ioctl,
98158737Sambrisko	.d_poll =	mfi_poll,
99157114Sscottl	.d_name =	"mfi",
100157114Sscottl};
101157114Sscottl
102157114SscottlMALLOC_DEFINE(M_MFIBUF, "mfibuf", "Buffers for the MFI driver");
103157114Sscottl
104158737Sambrisko#define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH
105157114Sscottl
106157114Sscottlstatic int
107157114Sscottlmfi_transition_firmware(struct mfi_softc *sc)
108157114Sscottl{
109157114Sscottl	int32_t fw_state, cur_state;
110157114Sscottl	int max_wait, i;
111157114Sscottl
112157114Sscottl	fw_state = MFI_READ4(sc, MFI_OMSG0) & MFI_FWSTATE_MASK;
113157114Sscottl	while (fw_state != MFI_FWSTATE_READY) {
114157114Sscottl		if (bootverbose)
115157114Sscottl			device_printf(sc->mfi_dev, "Waiting for firmware to "
116157114Sscottl			    "become ready\n");
117157114Sscottl		cur_state = fw_state;
118157114Sscottl		switch (fw_state) {
119157114Sscottl		case MFI_FWSTATE_FAULT:
120157114Sscottl			device_printf(sc->mfi_dev, "Firmware fault\n");
121157114Sscottl			return (ENXIO);
122157114Sscottl		case MFI_FWSTATE_WAIT_HANDSHAKE:
123157114Sscottl			MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
124157114Sscottl			max_wait = 2;
125157114Sscottl			break;
126157114Sscottl		case MFI_FWSTATE_OPERATIONAL:
127157114Sscottl			MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY);
128157114Sscottl			max_wait = 10;
129157114Sscottl			break;
130157114Sscottl		case MFI_FWSTATE_UNDEFINED:
131157114Sscottl		case MFI_FWSTATE_BB_INIT:
132157114Sscottl			max_wait = 2;
133157114Sscottl			break;
134157114Sscottl		case MFI_FWSTATE_FW_INIT:
135157114Sscottl		case MFI_FWSTATE_DEVICE_SCAN:
136157114Sscottl		case MFI_FWSTATE_FLUSH_CACHE:
137157114Sscottl			max_wait = 20;
138157114Sscottl			break;
139157114Sscottl		default:
140157114Sscottl			device_printf(sc->mfi_dev,"Unknown firmware state %d\n",
141157114Sscottl			    fw_state);
142157114Sscottl			return (ENXIO);
143157114Sscottl		}
144157114Sscottl		for (i = 0; i < (max_wait * 10); i++) {
145157114Sscottl			fw_state = MFI_READ4(sc, MFI_OMSG0) & MFI_FWSTATE_MASK;
146157114Sscottl			if (fw_state == cur_state)
147157114Sscottl				DELAY(100000);
148157114Sscottl			else
149157114Sscottl				break;
150157114Sscottl		}
151157114Sscottl		if (fw_state == cur_state) {
152157114Sscottl			device_printf(sc->mfi_dev, "firmware stuck in state "
153157114Sscottl			    "%#x\n", fw_state);
154157114Sscottl			return (ENXIO);
155157114Sscottl		}
156157114Sscottl	}
157157114Sscottl	return (0);
158157114Sscottl}
159157114Sscottl
160157114Sscottlstatic void
161157114Sscottlmfi_addr32_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
162157114Sscottl{
163157114Sscottl	uint32_t *addr;
164157114Sscottl
165157114Sscottl	addr = arg;
166157114Sscottl	*addr = segs[0].ds_addr;
167157114Sscottl}
168157114Sscottl
169157114Sscottlint
170157114Sscottlmfi_attach(struct mfi_softc *sc)
171157114Sscottl{
172157114Sscottl	uint32_t status;
173157114Sscottl	int error, commsz, framessz, sensesz;
174157114Sscottl	int frames, unit;
175157114Sscottl
176157114Sscottl	mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF);
177157114Sscottl	TAILQ_INIT(&sc->mfi_ld_tqh);
178158737Sambrisko	TAILQ_INIT(&sc->mfi_aen_pids);
179157114Sscottl
180157114Sscottl	mfi_initq_free(sc);
181157114Sscottl	mfi_initq_ready(sc);
182157114Sscottl	mfi_initq_busy(sc);
183157114Sscottl	mfi_initq_bio(sc);
184157114Sscottl
185157114Sscottl	/* Before we get too far, see if the firmware is working */
186157114Sscottl	if ((error = mfi_transition_firmware(sc)) != 0) {
187157114Sscottl		device_printf(sc->mfi_dev, "Firmware not in READY state, "
188157114Sscottl		    "error %d\n", error);
189157114Sscottl		return (ENXIO);
190157114Sscottl	}
191157114Sscottl
192157114Sscottl	/*
193157114Sscottl	 * Get information needed for sizing the contiguous memory for the
194157114Sscottl	 * frame pool.  Size down the sgl parameter since we know that
195157114Sscottl	 * we will never need more than what's required for MAXPHYS.
196157114Sscottl	 * It would be nice if these constants were available at runtime
197157114Sscottl	 * instead of compile time.
198157114Sscottl	 */
199157114Sscottl	status = MFI_READ4(sc, MFI_OMSG0);
200157114Sscottl	sc->mfi_max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK;
201157114Sscottl	sc->mfi_max_fw_sgl = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16;
202157114Sscottl	sc->mfi_total_sgl = min(sc->mfi_max_fw_sgl, ((MAXPHYS / PAGE_SIZE) +1));
203157114Sscottl
204157114Sscottl	/*
205157114Sscottl	 * Create the dma tag for data buffers.  Used both for block I/O
206157114Sscottl	 * and for various internal data queries.
207157114Sscottl	 */
208157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
209157114Sscottl				1, 0,			/* algnmnt, boundary */
210157114Sscottl				BUS_SPACE_MAXADDR,	/* lowaddr */
211157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
212157114Sscottl				NULL, NULL,		/* filter, filterarg */
213157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
214157114Sscottl				sc->mfi_total_sgl,	/* nsegments */
215157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
216157114Sscottl				BUS_DMA_ALLOCNOW,	/* flags */
217157114Sscottl				busdma_lock_mutex,	/* lockfunc */
218157114Sscottl				&sc->mfi_io_lock,	/* lockfuncarg */
219157114Sscottl				&sc->mfi_buffer_dmat)) {
220157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate buffer DMA tag\n");
221157114Sscottl		return (ENOMEM);
222157114Sscottl	}
223157114Sscottl
224157114Sscottl	/*
225157114Sscottl	 * Allocate DMA memory for the comms queues.  Keep it under 4GB for
226157114Sscottl	 * efficiency.  The mfi_hwcomms struct includes space for 1 reply queue
227157114Sscottl	 * entry, so the calculated size here will be will be 1 more than
228157114Sscottl	 * mfi_max_fw_cmds.  This is apparently a requirement of the hardware.
229157114Sscottl	 */
230157114Sscottl	commsz = (sizeof(uint32_t) * sc->mfi_max_fw_cmds) +
231157114Sscottl	    sizeof(struct mfi_hwcomms);
232157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
233157114Sscottl				1, 0,			/* algnmnt, boundary */
234157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
235157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
236157114Sscottl				NULL, NULL,		/* filter, filterarg */
237157114Sscottl				commsz,			/* maxsize */
238157114Sscottl				1,			/* msegments */
239157114Sscottl				commsz,			/* maxsegsize */
240157114Sscottl				0,			/* flags */
241157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
242157114Sscottl				&sc->mfi_comms_dmat)) {
243157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
244157114Sscottl		return (ENOMEM);
245157114Sscottl	}
246157114Sscottl	if (bus_dmamem_alloc(sc->mfi_comms_dmat, (void **)&sc->mfi_comms,
247157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_comms_dmamap)) {
248157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
249157114Sscottl		return (ENOMEM);
250157114Sscottl	}
251157114Sscottl	bzero(sc->mfi_comms, commsz);
252157114Sscottl	bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap,
253157114Sscottl	    sc->mfi_comms, commsz, mfi_addr32_cb, &sc->mfi_comms_busaddr, 0);
254157114Sscottl
255157114Sscottl	/*
256157114Sscottl	 * Allocate DMA memory for the command frames.  Keep them in the
257157114Sscottl	 * lower 4GB for efficiency.  Calculate the size of the frames at
258157114Sscottl	 * the same time; the frame is 64 bytes plus space for the SG lists.
259157114Sscottl	 * The assumption here is that the SG list will start at the second
260157114Sscottl	 * 64 byte segment of the frame and not use the unused bytes in the
261157114Sscottl	 * frame.  While this might seem wasteful, apparently the frames must
262157114Sscottl	 * be 64 byte aligned, so any savings would be negated by the extra
263157114Sscottl	 * alignment padding.
264157114Sscottl	 */
265157114Sscottl	if (sizeof(bus_addr_t) == 8) {
266157114Sscottl		sc->mfi_sgsize = sizeof(struct mfi_sg64);
267157114Sscottl		sc->mfi_flags |= MFI_FLAGS_SG64;
268157114Sscottl	} else {
269157237Sscottl		sc->mfi_sgsize = sizeof(struct mfi_sg32);
270157114Sscottl	}
271157114Sscottl	frames = (sc->mfi_sgsize * sc->mfi_total_sgl + MFI_FRAME_SIZE - 1) /
272157114Sscottl	    MFI_FRAME_SIZE + 1;
273157114Sscottl	sc->mfi_frame_size = frames * MFI_FRAME_SIZE;
274157114Sscottl	framessz = sc->mfi_frame_size * sc->mfi_max_fw_cmds;
275157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
276157114Sscottl				64, 0,			/* algnmnt, boundary */
277157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
278157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
279157114Sscottl				NULL, NULL,		/* filter, filterarg */
280157114Sscottl				framessz,		/* maxsize */
281157114Sscottl				1,			/* nsegments */
282157114Sscottl				framessz,		/* maxsegsize */
283157114Sscottl				0,			/* flags */
284157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
285157114Sscottl				&sc->mfi_frames_dmat)) {
286157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frame DMA tag\n");
287157114Sscottl		return (ENOMEM);
288157114Sscottl	}
289157114Sscottl	if (bus_dmamem_alloc(sc->mfi_frames_dmat, (void **)&sc->mfi_frames,
290157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_frames_dmamap)) {
291157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frames memory\n");
292157114Sscottl		return (ENOMEM);
293157114Sscottl	}
294157114Sscottl	bzero(sc->mfi_frames, framessz);
295157114Sscottl	bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap,
296157114Sscottl	    sc->mfi_frames, framessz, mfi_addr32_cb, &sc->mfi_frames_busaddr,0);
297157114Sscottl
298157114Sscottl	/*
299157114Sscottl	 * Allocate DMA memory for the frame sense data.  Keep them in the
300157114Sscottl	 * lower 4GB for efficiency
301157114Sscottl	 */
302157114Sscottl	sensesz = sc->mfi_max_fw_cmds * MFI_SENSE_LEN;
303157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
304157114Sscottl				4, 0,			/* algnmnt, boundary */
305157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
306157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
307157114Sscottl				NULL, NULL,		/* filter, filterarg */
308157114Sscottl				sensesz,		/* maxsize */
309157114Sscottl				1,			/* nsegments */
310157114Sscottl				sensesz,		/* maxsegsize */
311157114Sscottl				0,			/* flags */
312157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
313157114Sscottl				&sc->mfi_sense_dmat)) {
314157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense DMA tag\n");
315157114Sscottl		return (ENOMEM);
316157114Sscottl	}
317157114Sscottl	if (bus_dmamem_alloc(sc->mfi_sense_dmat, (void **)&sc->mfi_sense,
318157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_sense_dmamap)) {
319157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense memory\n");
320157114Sscottl		return (ENOMEM);
321157114Sscottl	}
322157114Sscottl	bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap,
323157114Sscottl	    sc->mfi_sense, sensesz, mfi_addr32_cb, &sc->mfi_sense_busaddr, 0);
324157114Sscottl
325157114Sscottl	if ((error = mfi_alloc_commands(sc)) != 0)
326157114Sscottl		return (error);
327157114Sscottl
328157114Sscottl	if ((error = mfi_comms_init(sc)) != 0)
329157114Sscottl		return (error);
330157114Sscottl
331157114Sscottl	if ((error = mfi_get_controller_info(sc)) != 0)
332157114Sscottl		return (error);
333157114Sscottl
334158737Sambrisko	if ((error = mfi_aen_setup(sc, 0), 0) != 0)
335157114Sscottl		return (error);
336157114Sscottl
337157114Sscottl	/*
338157114Sscottl	 * Set up the interrupt handler.  XXX This should happen in
339157114Sscottl	 * mfi_pci.c
340157114Sscottl	 */
341157114Sscottl	sc->mfi_irq_rid = 0;
342157114Sscottl	if ((sc->mfi_irq = bus_alloc_resource_any(sc->mfi_dev, SYS_RES_IRQ,
343157114Sscottl	    &sc->mfi_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
344157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate interrupt\n");
345157114Sscottl		return (EINVAL);
346157114Sscottl	}
347157114Sscottl	if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, INTR_MPSAFE|INTR_TYPE_BIO,
348157114Sscottl	    mfi_intr, sc, &sc->mfi_intr)) {
349157114Sscottl		device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
350157114Sscottl		return (EINVAL);
351157114Sscottl	}
352157114Sscottl
353157114Sscottl	/* Register a config hook to probe the bus for arrays */
354157114Sscottl	sc->mfi_ich.ich_func = mfi_startup;
355157114Sscottl	sc->mfi_ich.ich_arg = sc;
356157114Sscottl	if (config_intrhook_establish(&sc->mfi_ich) != 0) {
357157114Sscottl		device_printf(sc->mfi_dev, "Cannot establish configuration "
358157114Sscottl		    "hook\n");
359157114Sscottl		return (EINVAL);
360157114Sscottl	}
361157114Sscottl
362157114Sscottl	/*
363157114Sscottl	 * Register a shutdown handler.
364157114Sscottl	 */
365157114Sscottl	if ((sc->mfi_eh = EVENTHANDLER_REGISTER(shutdown_final, mfi_shutdown,
366157114Sscottl	    sc, SHUTDOWN_PRI_DEFAULT)) == NULL) {
367157114Sscottl		device_printf(sc->mfi_dev, "Warning: shutdown event "
368157114Sscottl		    "registration failed\n");
369157114Sscottl	}
370157114Sscottl
371157114Sscottl	/*
372157114Sscottl	 * Create the control device for doing management
373157114Sscottl	 */
374157114Sscottl	unit = device_get_unit(sc->mfi_dev);
375157114Sscottl	sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR,
376157114Sscottl	    0640, "mfi%d", unit);
377158737Sambrisko	if (unit == 0)
378158737Sambrisko		make_dev_alias(sc->mfi_cdev, "megaraid_sas_ioctl_node");
379157114Sscottl	if (sc->mfi_cdev != NULL)
380157114Sscottl		sc->mfi_cdev->si_drv1 = sc;
381157114Sscottl
382157114Sscottl	return (0);
383157114Sscottl}
384157114Sscottl
385157114Sscottlstatic int
386157114Sscottlmfi_alloc_commands(struct mfi_softc *sc)
387157114Sscottl{
388157114Sscottl	struct mfi_command *cm;
389157114Sscottl	int i, ncmds;
390157114Sscottl
391157114Sscottl	/*
392157114Sscottl	 * XXX Should we allocate all the commands up front, or allocate on
393157114Sscottl	 * demand later like 'aac' does?
394157114Sscottl	 */
395157114Sscottl	ncmds = sc->mfi_max_fw_cmds;
396157114Sscottl	sc->mfi_commands = malloc(sizeof(struct mfi_command) * ncmds, M_MFIBUF,
397157114Sscottl	    M_WAITOK | M_ZERO);
398157114Sscottl
399157114Sscottl	for (i = 0; i < ncmds; i++) {
400157114Sscottl		cm = &sc->mfi_commands[i];
401158737Sambrisko		cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames +
402157114Sscottl		    sc->mfi_frame_size * i);
403157114Sscottl		cm->cm_frame_busaddr = sc->mfi_frames_busaddr +
404157114Sscottl		    sc->mfi_frame_size * i;
405157114Sscottl		cm->cm_frame->header.context = i;
406157114Sscottl		cm->cm_sense = &sc->mfi_sense[i];
407157114Sscottl		cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i;
408157114Sscottl		cm->cm_sc = sc;
409157114Sscottl		if (bus_dmamap_create(sc->mfi_buffer_dmat, 0,
410157114Sscottl		    &cm->cm_dmamap) == 0)
411157114Sscottl			mfi_release_command(cm);
412157114Sscottl		else
413157114Sscottl			break;
414157114Sscottl		sc->mfi_total_cmds++;
415157114Sscottl	}
416157114Sscottl
417157114Sscottl	return (0);
418157114Sscottl}
419157114Sscottl
420157114Sscottlstatic void
421157114Sscottlmfi_release_command(struct mfi_command *cm)
422157114Sscottl{
423157114Sscottl	uint32_t *hdr_data;
424157114Sscottl
425157114Sscottl	/*
426157114Sscottl	 * Zero out the important fields of the frame, but make sure the
427157114Sscottl	 * context field is preserved
428157114Sscottl	 */
429157114Sscottl	hdr_data = (uint32_t *)cm->cm_frame;
430157114Sscottl	hdr_data[0] = 0;
431157114Sscottl	hdr_data[1] = 0;
432157114Sscottl
433157114Sscottl	cm->cm_extra_frames = 0;
434157114Sscottl	cm->cm_flags = 0;
435157114Sscottl	cm->cm_complete = NULL;
436157114Sscottl	cm->cm_private = NULL;
437157114Sscottl	cm->cm_sg = 0;
438157114Sscottl	cm->cm_total_frame_size = 0;
439157114Sscottl	mfi_enqueue_free(cm);
440157114Sscottl}
441157114Sscottl
442157114Sscottlstatic int
443159806Spsmfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, uint32_t opcode,
444159806Sps    void **bufp, size_t bufsize)
445159806Sps{
446159806Sps	struct mfi_command *cm;
447159806Sps	struct mfi_dcmd_frame *dcmd;
448159806Sps	void *buf = NULL;
449159806Sps
450159806Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
451159806Sps
452159806Sps	cm = mfi_dequeue_free(sc);
453159806Sps	if (cm == NULL)
454159806Sps		return (EBUSY);
455159806Sps
456159806Sps	if ((bufsize > 0) && (bufp != NULL)) {
457159806Sps		if (*bufp == NULL) {
458159806Sps			buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO);
459159806Sps			if (buf == NULL) {
460159806Sps				mfi_release_command(cm);
461159806Sps				return (ENOMEM);
462159806Sps			}
463159806Sps			*bufp = buf;
464159806Sps		} else {
465159806Sps			buf = *bufp;
466159806Sps		}
467159806Sps	}
468159806Sps
469159806Sps	dcmd =  &cm->cm_frame->dcmd;
470159806Sps	bzero(dcmd->mbox, MFI_MBOX_SIZE);
471159806Sps	dcmd->header.cmd = MFI_CMD_DCMD;
472159806Sps	dcmd->header.timeout = 0;
473159806Sps	dcmd->header.flags = 0;
474159806Sps	dcmd->header.data_len = bufsize;
475159806Sps	dcmd->opcode = opcode;
476159806Sps	cm->cm_sg = &dcmd->sgl;
477159806Sps	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
478159806Sps	cm->cm_flags = 0;
479159806Sps	cm->cm_data = buf;
480159806Sps	cm->cm_private = buf;
481159806Sps	cm->cm_len = bufsize;
482159806Sps
483159806Sps	*cmp = cm;
484159806Sps	if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL))
485159806Sps		*bufp = buf;
486159806Sps	return (0);
487159806Sps}
488159806Sps
489159806Spsstatic int
490157114Sscottlmfi_comms_init(struct mfi_softc *sc)
491157114Sscottl{
492157114Sscottl	struct mfi_command *cm;
493157114Sscottl	struct mfi_init_frame *init;
494157114Sscottl	struct mfi_init_qinfo *qinfo;
495157114Sscottl	int error;
496157114Sscottl
497157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
498157114Sscottl		return (EBUSY);
499157114Sscottl
500157114Sscottl	/*
501157114Sscottl	 * Abuse the SG list area of the frame to hold the init_qinfo
502157114Sscottl	 * object;
503157114Sscottl	 */
504157114Sscottl	init = &cm->cm_frame->init;
505157114Sscottl	qinfo = (struct mfi_init_qinfo *)((uintptr_t)init + MFI_FRAME_SIZE);
506157114Sscottl
507157114Sscottl	bzero(qinfo, sizeof(struct mfi_init_qinfo));
508157114Sscottl	qinfo->rq_entries = sc->mfi_max_fw_cmds + 1;
509157114Sscottl	qinfo->rq_addr_lo = sc->mfi_comms_busaddr +
510157114Sscottl	    offsetof(struct mfi_hwcomms, hw_reply_q);
511157114Sscottl	qinfo->pi_addr_lo = sc->mfi_comms_busaddr +
512157114Sscottl	    offsetof(struct mfi_hwcomms, hw_pi);
513157114Sscottl	qinfo->ci_addr_lo = sc->mfi_comms_busaddr +
514157114Sscottl	    offsetof(struct mfi_hwcomms, hw_ci);
515157114Sscottl
516157114Sscottl	init->header.cmd = MFI_CMD_INIT;
517157114Sscottl	init->header.data_len = sizeof(struct mfi_init_qinfo);
518157114Sscottl	init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE;
519157114Sscottl
520157114Sscottl	if ((error = mfi_polled_command(sc, cm)) != 0) {
521157114Sscottl		device_printf(sc->mfi_dev, "failed to send init command\n");
522157114Sscottl		return (error);
523157114Sscottl	}
524157114Sscottl	mfi_release_command(cm);
525157114Sscottl
526157114Sscottl	return (0);
527157114Sscottl}
528157114Sscottl
529157114Sscottlstatic int
530157114Sscottlmfi_get_controller_info(struct mfi_softc *sc)
531157114Sscottl{
532159806Sps	struct mfi_command *cm = NULL;
533159806Sps	struct mfi_ctrl_info *ci = NULL;
534157114Sscottl	uint32_t max_sectors_1, max_sectors_2;
535157114Sscottl	int error;
536157114Sscottl
537159806Sps	mtx_lock(&sc->mfi_io_lock);
538159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO,
539159806Sps	    (void **)&ci, sizeof(*ci));
540159806Sps	if (error)
541159806Sps		goto out;
542157114Sscottl	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
543157114Sscottl
544157114Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
545159802Sps		device_printf(sc->mfi_dev, "Controller info buffer map failed\n");
546157114Sscottl		free(ci, M_MFIBUF);
547157114Sscottl		mfi_release_command(cm);
548157114Sscottl		return (error);
549157114Sscottl	}
550157114Sscottl
551157114Sscottl	/* It's ok if this fails, just use default info instead */
552157114Sscottl	if ((error = mfi_polled_command(sc, cm)) != 0) {
553157114Sscottl		device_printf(sc->mfi_dev, "Failed to get controller info\n");
554157114Sscottl		sc->mfi_max_io = (sc->mfi_total_sgl - 1) * PAGE_SIZE /
555157114Sscottl		    MFI_SECTOR_LEN;
556159806Sps		error = 0;
557159806Sps		goto out;
558157114Sscottl	}
559157114Sscottl
560157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
561157114Sscottl	    BUS_DMASYNC_POSTREAD);
562157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
563157114Sscottl
564157114Sscottl	max_sectors_1 = (1 << ci->stripe_sz_ops.min) * ci->max_strips_per_io;
565157114Sscottl	max_sectors_2 = ci->max_request_size;
566157114Sscottl	sc->mfi_max_io = min(max_sectors_1, max_sectors_2);
567157114Sscottl
568159806Spsout:
569159806Sps	if (ci)
570159806Sps		free(ci, M_MFIBUF);
571159806Sps	if (cm)
572159806Sps		mfi_release_command(cm);
573159806Sps	mtx_unlock(&sc->mfi_io_lock);
574157114Sscottl	return (error);
575157114Sscottl}
576157114Sscottl
577157114Sscottlstatic int
578159806Spsmfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state)
579158737Sambrisko{
580158737Sambrisko	struct mfi_command *cm;
581158737Sambrisko	int error;
582158737Sambrisko
583159806Sps	mtx_lock(&sc->mfi_io_lock);
584159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO,
585159806Sps	    (void **)log_state, sizeof(**log_state));
586159806Sps	if (error)
587159806Sps		goto out;
588159810Sps	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
589158737Sambrisko
590158737Sambrisko	if ((error = mfi_mapcmd(sc, cm)) != 0) {
591159802Sps		device_printf(sc->mfi_dev, "Log state buffer map failed\n");
592159806Sps		goto out;
593158737Sambrisko	}
594158737Sambrisko
595158737Sambrisko	if ((error = mfi_polled_command(sc, cm)) != 0) {
596159802Sps		device_printf(sc->mfi_dev, "Failed to get log state\n");
597159806Sps		goto out;
598158737Sambrisko	}
599158737Sambrisko
600158737Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
601158737Sambrisko	    BUS_DMASYNC_POSTREAD);
602158737Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
603158737Sambrisko
604159806Spsout:
605158737Sambrisko	mfi_release_command(cm);
606159806Sps	mtx_unlock(&sc->mfi_io_lock);
607158737Sambrisko
608158737Sambrisko	return (error);
609158737Sambrisko}
610158737Sambrisko
611158737Sambriskostatic int
612158737Sambriskomfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
613158737Sambrisko{
614159806Sps	struct mfi_evt_log_state *log_state = NULL;
615158737Sambrisko	union mfi_evt class_locale;
616158737Sambrisko	int error = 0;
617158737Sambrisko	uint32_t seq;
618158737Sambrisko
619158737Sambrisko	class_locale.members.reserved = 0;
620158737Sambrisko	class_locale.members.locale = MFI_EVT_LOCALE_ALL;
621158737Sambrisko	class_locale.members.class  = MFI_EVT_CLASS_DEBUG;
622158737Sambrisko
623158737Sambrisko	if (seq_start == 0) {
624158737Sambrisko		error = mfi_get_log_state(sc, &log_state);
625159806Sps		if (error) {
626159806Sps			if (log_state)
627159806Sps				free(log_state, M_MFIBUF);
628158737Sambrisko			return (error);
629159806Sps		}
630158737Sambrisko		/*
631158737Sambrisko		 * Don't run them yet since we can't parse them.
632158737Sambrisko		 * We can indirectly get the contents from
633158737Sambrisko		 * the AEN mechanism via setting it lower then
634158737Sambrisko		 * current.  The firmware will iterate through them.
635158737Sambrisko		 */
636159574Sambrisko#ifdef NOTYET
637159806Sps		for (seq = log_state->shutdown_seq_num;
638159806Sps		     seq <= log_state->newest_seq_num; seq++) {
639158737Sambrisko			mfi_get_entry(sc, seq);
640158737Sambrisko		}
641158737Sambrisko#endif
642158737Sambrisko
643159806Sps		seq = log_state->shutdown_seq_num + 1;
644158737Sambrisko	} else
645158737Sambrisko		seq = seq_start;
646158737Sambrisko	mfi_aen_register(sc, seq, class_locale.word);
647159806Sps	free(log_state, M_MFIBUF);
648158737Sambrisko
649158737Sambrisko	return 0;
650158737Sambrisko}
651158737Sambrisko
652158737Sambriskostatic int
653157114Sscottlmfi_polled_command(struct mfi_softc *sc, struct mfi_command *cm)
654157114Sscottl{
655157114Sscottl	struct mfi_frame_header *hdr;
656157114Sscottl	int tm = MFI_POLL_TIMEOUT_SECS * 1000000;
657157114Sscottl
658157114Sscottl	hdr = &cm->cm_frame->header;
659157114Sscottl	hdr->cmd_status = 0xff;
660157114Sscottl	hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
661157114Sscottl
662157114Sscottl	mfi_send_frame(sc, cm);
663157114Sscottl
664157114Sscottl	while (hdr->cmd_status == 0xff) {
665157114Sscottl		DELAY(1000);
666157114Sscottl		tm -= 1000;
667157114Sscottl		if (tm <= 0)
668157114Sscottl			break;
669157114Sscottl	}
670157114Sscottl
671157114Sscottl	if (hdr->cmd_status == 0xff) {
672157114Sscottl		device_printf(sc->mfi_dev, "Frame %p timed out\n", hdr);
673157114Sscottl		return (ETIMEDOUT);
674157114Sscottl	}
675157114Sscottl
676157114Sscottl	return (0);
677157114Sscottl}
678157114Sscottl
679159811Spsstatic int
680159811Spsmfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm)
681159811Sps{
682159811Sps
683159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
684159811Sps	cm->cm_complete = NULL;
685159811Sps
686159811Sps	mfi_enqueue_ready(cm);
687159811Sps	mfi_startio(sc);
688159811Sps	return (msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0));
689159811Sps}
690159811Sps
691157114Sscottlvoid
692157114Sscottlmfi_free(struct mfi_softc *sc)
693157114Sscottl{
694157114Sscottl	struct mfi_command *cm;
695157114Sscottl	int i;
696157114Sscottl
697157114Sscottl	if (sc->mfi_cdev != NULL)
698157114Sscottl		destroy_dev(sc->mfi_cdev);
699157114Sscottl
700157114Sscottl	if (sc->mfi_total_cmds != 0) {
701157114Sscottl		for (i = 0; i < sc->mfi_total_cmds; i++) {
702157114Sscottl			cm = &sc->mfi_commands[i];
703157114Sscottl			bus_dmamap_destroy(sc->mfi_buffer_dmat, cm->cm_dmamap);
704157114Sscottl		}
705157114Sscottl		free(sc->mfi_commands, M_MFIBUF);
706157114Sscottl	}
707157114Sscottl
708157114Sscottl	if (sc->mfi_intr)
709157114Sscottl		bus_teardown_intr(sc->mfi_dev, sc->mfi_irq, sc->mfi_intr);
710157114Sscottl	if (sc->mfi_irq != NULL)
711157114Sscottl		bus_release_resource(sc->mfi_dev, SYS_RES_IRQ, sc->mfi_irq_rid,
712157114Sscottl		    sc->mfi_irq);
713157114Sscottl
714157114Sscottl	if (sc->mfi_sense_busaddr != 0)
715157114Sscottl		bus_dmamap_unload(sc->mfi_sense_dmat, sc->mfi_sense_dmamap);
716157114Sscottl	if (sc->mfi_sense != NULL)
717157114Sscottl		bus_dmamem_free(sc->mfi_sense_dmat, sc->mfi_sense,
718157114Sscottl		    sc->mfi_sense_dmamap);
719157114Sscottl	if (sc->mfi_sense_dmat != NULL)
720157114Sscottl		bus_dma_tag_destroy(sc->mfi_sense_dmat);
721157114Sscottl
722157114Sscottl	if (sc->mfi_frames_busaddr != 0)
723157114Sscottl		bus_dmamap_unload(sc->mfi_frames_dmat, sc->mfi_frames_dmamap);
724157114Sscottl	if (sc->mfi_frames != NULL)
725157114Sscottl		bus_dmamem_free(sc->mfi_frames_dmat, sc->mfi_frames,
726157114Sscottl		    sc->mfi_frames_dmamap);
727157114Sscottl	if (sc->mfi_frames_dmat != NULL)
728157114Sscottl		bus_dma_tag_destroy(sc->mfi_frames_dmat);
729157114Sscottl
730157114Sscottl	if (sc->mfi_comms_busaddr != 0)
731157114Sscottl		bus_dmamap_unload(sc->mfi_comms_dmat, sc->mfi_comms_dmamap);
732157114Sscottl	if (sc->mfi_comms != NULL)
733157114Sscottl		bus_dmamem_free(sc->mfi_comms_dmat, sc->mfi_comms,
734157114Sscottl		    sc->mfi_comms_dmamap);
735157114Sscottl	if (sc->mfi_comms_dmat != NULL)
736157114Sscottl		bus_dma_tag_destroy(sc->mfi_comms_dmat);
737157114Sscottl
738157114Sscottl	if (sc->mfi_buffer_dmat != NULL)
739157114Sscottl		bus_dma_tag_destroy(sc->mfi_buffer_dmat);
740157114Sscottl	if (sc->mfi_parent_dmat != NULL)
741157114Sscottl		bus_dma_tag_destroy(sc->mfi_parent_dmat);
742157114Sscottl
743157114Sscottl	if (mtx_initialized(&sc->mfi_io_lock))
744157114Sscottl		mtx_destroy(&sc->mfi_io_lock);
745157114Sscottl
746157114Sscottl	return;
747157114Sscottl}
748157114Sscottl
749157114Sscottlstatic void
750157114Sscottlmfi_startup(void *arg)
751157114Sscottl{
752157114Sscottl	struct mfi_softc *sc;
753157114Sscottl
754157114Sscottl	sc = (struct mfi_softc *)arg;
755157114Sscottl
756157114Sscottl	config_intrhook_disestablish(&sc->mfi_ich);
757157114Sscottl
758157114Sscottl	mfi_enable_intr(sc);
759159811Sps	mfi_ldprobe(sc);
760157114Sscottl}
761157114Sscottl
762157114Sscottlstatic void
763157114Sscottlmfi_intr(void *arg)
764157114Sscottl{
765157114Sscottl	struct mfi_softc *sc;
766157114Sscottl	struct mfi_command *cm;
767157114Sscottl	uint32_t status, pi, ci, context;
768157114Sscottl
769157114Sscottl	sc = (struct mfi_softc *)arg;
770157114Sscottl
771157114Sscottl	status = MFI_READ4(sc, MFI_OSTS);
772157114Sscottl	if ((status & MFI_OSTS_INTR_VALID) == 0)
773157114Sscottl		return;
774157114Sscottl	MFI_WRITE4(sc, MFI_OSTS, status);
775157114Sscottl
776157114Sscottl	pi = sc->mfi_comms->hw_pi;
777157114Sscottl	ci = sc->mfi_comms->hw_ci;
778157114Sscottl	mtx_lock(&sc->mfi_io_lock);
779157114Sscottl	while (ci != pi) {
780157114Sscottl		context = sc->mfi_comms->hw_reply_q[ci];
781157114Sscottl		sc->mfi_comms->hw_reply_q[ci] = 0xffffffff;
782157114Sscottl		if (context == 0xffffffff) {
783157114Sscottl			device_printf(sc->mfi_dev, "mfi_intr: invalid context "
784157114Sscottl			    "pi= %d ci= %d\n", pi, ci);
785157114Sscottl		} else {
786157114Sscottl			cm = &sc->mfi_commands[context];
787157114Sscottl			mfi_remove_busy(cm);
788157114Sscottl			mfi_complete(sc, cm);
789157114Sscottl		}
790157114Sscottl		ci++;
791157114Sscottl		if (ci == (sc->mfi_max_fw_cmds + 1)) {
792157114Sscottl			ci = 0;
793157114Sscottl		}
794157114Sscottl	}
795157114Sscottl	mtx_unlock(&sc->mfi_io_lock);
796157114Sscottl
797157114Sscottl	sc->mfi_comms->hw_ci = ci;
798157114Sscottl
799157114Sscottl	return;
800157114Sscottl}
801157114Sscottl
802157114Sscottlint
803157114Sscottlmfi_shutdown(struct mfi_softc *sc)
804157114Sscottl{
805157114Sscottl	struct mfi_dcmd_frame *dcmd;
806157114Sscottl	struct mfi_command *cm;
807157114Sscottl	int error;
808157114Sscottl
809159806Sps	mtx_lock(&sc->mfi_io_lock);
810159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0);
811159806Sps	mtx_unlock(&sc->mfi_io_lock);
812159806Sps	if (error)
813159806Sps		return (error);
814157114Sscottl
815158737Sambrisko	if (sc->mfi_aen_cm != NULL)
816158737Sambrisko		mfi_abort(sc, sc->mfi_aen_cm);
817157114Sscottl
818157114Sscottl	dcmd = &cm->cm_frame->dcmd;
819157114Sscottl	dcmd->header.flags = MFI_FRAME_DIR_NONE;
820157114Sscottl
821157114Sscottl	if ((error = mfi_polled_command(sc, cm)) != 0) {
822157114Sscottl		device_printf(sc->mfi_dev, "Failed to shutdown controller\n");
823157114Sscottl	}
824157114Sscottl
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
843157114Sscottl	mtx_lock(&sc->mfi_io_lock);
844159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
845159811Sps	    (void **)&list, sizeof(*list));
846159811Sps	if (error)
847159811Sps		goto out;
848159811Sps
849159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
850159811Sps	if (mfi_wait_command(sc, cm) != 0) {
851159811Sps		device_printf(sc->mfi_dev, "Failed to get device listing\n");
852159811Sps		goto out;
853157114Sscottl	}
854157114Sscottl
855157114Sscottl	hdr = &cm->cm_frame->header;
856159811Sps	if (hdr->cmd_status != MFI_STAT_OK) {
857159811Sps		device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n",
858159811Sps		    hdr->cmd_status);
859159811Sps		goto out;
860157114Sscottl	}
861157114Sscottl
862159811Sps	for (i = 0; i < list->ld_count; i++)
863159811Sps		mfi_add_ld(sc, list->ld_list[i].ld.target_id);
864159811Spsout:
865159811Sps	if (list)
866159811Sps		free(list, M_MFIBUF);
867159811Sps	if (cm)
868157114Sscottl		mfi_release_command(cm);
869159811Sps	mtx_unlock(&sc->mfi_io_lock);
870159811Sps	return;
871157114Sscottl}
872157114Sscottl
873159574Sambrisko#ifdef NOTYET
874158737Sambriskostatic void
875158737Sambriskomfi_decode_log(struct mfi_softc *sc, struct mfi_log_detail *detail)
876158737Sambrisko{
877158737Sambrisko        switch (detail->arg_type) {
878158737Sambrisko	default:
879158737Sambrisko		device_printf(sc->mfi_dev, "%d - Log entry type %d\n",
880158737Sambrisko		    detail->seq,
881158737Sambrisko		    detail->arg_type
882158737Sambrisko		);
883158737Sambrisko		break;
884158737Sambrisko	}
885158737Sambrisko}
886158737Sambrisko#endif
887158737Sambrisko
888158737Sambriskostatic void
889158737Sambriskomfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
890158737Sambrisko{
891158737Sambrisko	switch (detail->arg_type) {
892158737Sambrisko	case MR_EVT_ARGS_NONE:
893159574Sambrisko		device_printf(sc->mfi_dev, "%d - %s\n",
894159574Sambrisko		    detail->seq,
895159574Sambrisko		    detail->description
896159574Sambrisko		    );
897158737Sambrisko		break;
898158737Sambrisko	case MR_EVT_ARGS_CDB_SENSE:
899158737Sambrisko		device_printf(sc->mfi_dev, "%d - PD %02d(e%d/s%d) CDB %*D"
900159574Sambrisko		    "Sense %*D\n: %s\n",
901158737Sambrisko		    detail->seq,
902158737Sambrisko		    detail->args.cdb_sense.pd.device_id,
903158737Sambrisko		    detail->args.cdb_sense.pd.enclosure_index,
904158737Sambrisko		    detail->args.cdb_sense.pd.slot_number,
905158737Sambrisko		    detail->args.cdb_sense.cdb_len,
906158737Sambrisko		    detail->args.cdb_sense.cdb,
907158737Sambrisko		    ":",
908158737Sambrisko		    detail->args.cdb_sense.sense_len,
909158737Sambrisko		    detail->args.cdb_sense.sense,
910158737Sambrisko		    ":",
911158737Sambrisko		    detail->description
912158737Sambrisko		    );
913158737Sambrisko		break;
914158737Sambrisko	case MR_EVT_ARGS_LD:
915158737Sambrisko		device_printf(sc->mfi_dev, "%d - VD %02d/%d "
916158737Sambrisko		    "event: %s\n",
917158737Sambrisko		    detail->seq,
918158737Sambrisko		    detail->args.ld.ld_index,
919158737Sambrisko		    detail->args.ld.target_id,
920158737Sambrisko		    detail->description
921158737Sambrisko		    );
922158737Sambrisko		break;
923158737Sambrisko	case MR_EVT_ARGS_LD_COUNT:
924158737Sambrisko		device_printf(sc->mfi_dev, "%d - VD %02d/%d "
925158737Sambrisko		    "count %lld: %s\n",
926158737Sambrisko		    detail->seq,
927158737Sambrisko		    detail->args.ld_count.ld.ld_index,
928158737Sambrisko		    detail->args.ld_count.ld.target_id,
929158737Sambrisko		    (long long)detail->args.ld_count.count,
930158737Sambrisko		    detail->description
931158737Sambrisko		    );
932158737Sambrisko		break;
933158737Sambrisko	case MR_EVT_ARGS_LD_LBA:
934158737Sambrisko		device_printf(sc->mfi_dev, "%d - VD %02d/%d "
935158737Sambrisko		    "lba %lld: %s\n",
936158737Sambrisko		    detail->seq,
937158737Sambrisko		    detail->args.ld_lba.ld.ld_index,
938158737Sambrisko		    detail->args.ld_lba.ld.target_id,
939158737Sambrisko		    (long long)detail->args.ld_lba.lba,
940158737Sambrisko		    detail->description
941158737Sambrisko		    );
942158737Sambrisko		break;
943158737Sambrisko	case MR_EVT_ARGS_LD_OWNER:
944158737Sambrisko		device_printf(sc->mfi_dev, "%d - VD %02d/%d "
945158737Sambrisko		    "owner changed: prior %d, new %d: %s\n",
946158737Sambrisko		    detail->seq,
947158737Sambrisko		    detail->args.ld_owner.ld.ld_index,
948158737Sambrisko		    detail->args.ld_owner.ld.target_id,
949158737Sambrisko		    detail->args.ld_owner.pre_owner,
950158737Sambrisko		    detail->args.ld_owner.new_owner,
951158737Sambrisko		    detail->description
952158737Sambrisko		    );
953158737Sambrisko		break;
954158737Sambrisko	case MR_EVT_ARGS_LD_LBA_PD_LBA:
955158737Sambrisko		device_printf(sc->mfi_dev, "%d - VD %02d/%d "
956158737Sambrisko		    "lba %lld, physical drive PD %02d(e%d/s%d) lba %lld: %s\n",
957158737Sambrisko		    detail->seq,
958158737Sambrisko		    detail->args.ld_lba_pd_lba.ld.ld_index,
959158737Sambrisko		    detail->args.ld_lba_pd_lba.ld.target_id,
960158737Sambrisko		    (long long)detail->args.ld_lba_pd_lba.ld_lba,
961158737Sambrisko		    detail->args.ld_lba_pd_lba.pd.device_id,
962158737Sambrisko		    detail->args.ld_lba_pd_lba.pd.enclosure_index,
963158737Sambrisko		    detail->args.ld_lba_pd_lba.pd.slot_number,
964158737Sambrisko		    (long long)detail->args.ld_lba_pd_lba.pd_lba,
965158737Sambrisko		    detail->description
966158737Sambrisko		    );
967158737Sambrisko		break;
968158737Sambrisko	case MR_EVT_ARGS_LD_PROG:
969158737Sambrisko		device_printf(sc->mfi_dev, "%d - VD %02d/%d "
970158737Sambrisko		    "progress %d%% in %ds: %s\n",
971158737Sambrisko		    detail->seq,
972158737Sambrisko		    detail->args.ld_prog.ld.ld_index,
973158737Sambrisko		    detail->args.ld_prog.ld.target_id,
974158737Sambrisko		    detail->args.ld_prog.prog.progress/655,
975158737Sambrisko		    detail->args.ld_prog.prog.elapsed_seconds,
976158737Sambrisko		    detail->description
977158737Sambrisko		    );
978158737Sambrisko		break;
979158737Sambrisko	case MR_EVT_ARGS_LD_STATE:
980158737Sambrisko		device_printf(sc->mfi_dev, "%d - VD %02d/%d "
981158737Sambrisko		    "state prior %d new %d: %s\n",
982158737Sambrisko		    detail->seq,
983158737Sambrisko		    detail->args.ld_state.ld.ld_index,
984158737Sambrisko		    detail->args.ld_state.ld.target_id,
985158737Sambrisko		    detail->args.ld_state.prev_state,
986158737Sambrisko		    detail->args.ld_state.new_state,
987158737Sambrisko		    detail->description
988158737Sambrisko		    );
989158737Sambrisko		break;
990158737Sambrisko	case MR_EVT_ARGS_LD_STRIP:
991158737Sambrisko		device_printf(sc->mfi_dev, "%d - VD %02d/%d "
992158737Sambrisko		    "strip %lld: %s\n",
993158737Sambrisko		    detail->seq,
994158737Sambrisko		    detail->args.ld_strip.ld.ld_index,
995158737Sambrisko		    detail->args.ld_strip.ld.target_id,
996158737Sambrisko		    (long long)detail->args.ld_strip.strip,
997158737Sambrisko		    detail->description
998158737Sambrisko		    );
999158737Sambrisko		break;
1000158737Sambrisko	case MR_EVT_ARGS_PD:
1001158737Sambrisko		device_printf(sc->mfi_dev, "%d - PD %02d(e%d/s%d) "
1002158737Sambrisko		    "event: %s\n",
1003158737Sambrisko		    detail->seq,
1004158737Sambrisko		    detail->args.pd.device_id,
1005158737Sambrisko		    detail->args.pd.enclosure_index,
1006158737Sambrisko		    detail->args.pd.slot_number,
1007158737Sambrisko		    detail->description
1008158737Sambrisko		    );
1009158737Sambrisko		break;
1010158737Sambrisko	case MR_EVT_ARGS_PD_ERR:
1011158737Sambrisko		device_printf(sc->mfi_dev, "%d - PD %02d(e%d/s%d) "
1012158737Sambrisko		    "err %d: %s\n",
1013158737Sambrisko		    detail->seq,
1014158737Sambrisko		    detail->args.pd_err.pd.device_id,
1015158737Sambrisko		    detail->args.pd_err.pd.enclosure_index,
1016158737Sambrisko		    detail->args.pd_err.pd.slot_number,
1017158737Sambrisko		    detail->args.pd_err.err,
1018158737Sambrisko		    detail->description
1019158737Sambrisko		    );
1020158737Sambrisko		break;
1021158737Sambrisko	case MR_EVT_ARGS_PD_LBA:
1022158737Sambrisko		device_printf(sc->mfi_dev, "%d - PD %02d(e%d/s%d) "
1023158737Sambrisko		    "lba %lld: %s\n",
1024158737Sambrisko		    detail->seq,
1025158737Sambrisko		    detail->args.pd_lba.pd.device_id,
1026158737Sambrisko		    detail->args.pd_lba.pd.enclosure_index,
1027158737Sambrisko		    detail->args.pd_lba.pd.slot_number,
1028158737Sambrisko		    (long long)detail->args.pd_lba.lba,
1029158737Sambrisko		    detail->description
1030158737Sambrisko		    );
1031158737Sambrisko		break;
1032158737Sambrisko	case MR_EVT_ARGS_PD_LBA_LD:
1033158737Sambrisko		device_printf(sc->mfi_dev, "%d - PD %02d(e%d/s%d) "
1034158737Sambrisko		    "lba %lld VD %02d/%d: %s\n",
1035158737Sambrisko		    detail->seq,
1036158737Sambrisko		    detail->args.pd_lba_ld.pd.device_id,
1037158737Sambrisko		    detail->args.pd_lba_ld.pd.enclosure_index,
1038158737Sambrisko		    detail->args.pd_lba_ld.pd.slot_number,
1039158737Sambrisko		    (long long)detail->args.pd_lba.lba,
1040158737Sambrisko		    detail->args.pd_lba_ld.ld.ld_index,
1041158737Sambrisko		    detail->args.pd_lba_ld.ld.target_id,
1042158737Sambrisko		    detail->description
1043158737Sambrisko		    );
1044158737Sambrisko		break;
1045158737Sambrisko	case MR_EVT_ARGS_PD_PROG:
1046158737Sambrisko		device_printf(sc->mfi_dev, "%d - PD %02d(e%d/s%d) "
1047158737Sambrisko		    "progress %d%% seconds %ds: %s\n",
1048158737Sambrisko		    detail->seq,
1049158737Sambrisko		    detail->args.pd_prog.pd.device_id,
1050158737Sambrisko		    detail->args.pd_prog.pd.enclosure_index,
1051158737Sambrisko		    detail->args.pd_prog.pd.slot_number,
1052158737Sambrisko		    detail->args.pd_prog.prog.progress/655,
1053158737Sambrisko		    detail->args.pd_prog.prog.elapsed_seconds,
1054158737Sambrisko		    detail->description
1055158737Sambrisko		    );
1056158737Sambrisko		break;
1057158737Sambrisko	case MR_EVT_ARGS_PD_STATE:
1058158737Sambrisko		device_printf(sc->mfi_dev, "%d - PD %02d(e%d/s%d) "
1059158737Sambrisko		    "state prior %d new %d: %s\n",
1060158737Sambrisko		    detail->seq,
1061158737Sambrisko		    detail->args.pd_prog.pd.device_id,
1062158737Sambrisko		    detail->args.pd_prog.pd.enclosure_index,
1063158737Sambrisko		    detail->args.pd_prog.pd.slot_number,
1064158737Sambrisko		    detail->args.pd_state.prev_state,
1065158737Sambrisko		    detail->args.pd_state.new_state,
1066158737Sambrisko		    detail->description
1067158737Sambrisko		    );
1068158737Sambrisko		break;
1069158737Sambrisko	case MR_EVT_ARGS_PCI:
1070158737Sambrisko		device_printf(sc->mfi_dev, "%d - PCI 0x04%x 0x04%x "
1071158737Sambrisko		    "0x04%x 0x04%x: %s\n",
1072158737Sambrisko		    detail->seq,
1073158737Sambrisko		    detail->args.pci.venderId,
1074158737Sambrisko		    detail->args.pci.deviceId,
1075158737Sambrisko		    detail->args.pci.subVenderId,
1076158737Sambrisko		    detail->args.pci.subDeviceId,
1077158737Sambrisko		    detail->description
1078158737Sambrisko		    );
1079158737Sambrisko		break;
1080158737Sambrisko	case MR_EVT_ARGS_RATE:
1081158737Sambrisko		device_printf(sc->mfi_dev, "%d - Rebuild rate %d: %s\n",
1082158737Sambrisko		    detail->seq,
1083158737Sambrisko		    detail->args.rate,
1084158737Sambrisko		    detail->description
1085158737Sambrisko		    );
1086158737Sambrisko		break;
1087158737Sambrisko	case MR_EVT_ARGS_TIME:
1088158737Sambrisko		device_printf(sc->mfi_dev, "%d - Adapter ticks %d "
1089158737Sambrisko		    "elapsed %ds: %s\n",
1090158737Sambrisko		    detail->seq,
1091158737Sambrisko		    detail->args.time.rtc,
1092158737Sambrisko		    detail->args.time.elapsedSeconds,
1093158737Sambrisko		    detail->description
1094158737Sambrisko		    );
1095158737Sambrisko		break;
1096158737Sambrisko	case MR_EVT_ARGS_ECC:
1097158737Sambrisko		device_printf(sc->mfi_dev, "%d - Adapter ECC %x,%x: %s: %s\n",
1098158737Sambrisko		    detail->seq,
1099158737Sambrisko		    detail->args.ecc.ecar,
1100158737Sambrisko		    detail->args.ecc.elog,
1101158737Sambrisko		    detail->args.ecc.str,
1102158737Sambrisko		    detail->description
1103158737Sambrisko		    );
1104158737Sambrisko		break;
1105158737Sambrisko	default:
1106158737Sambrisko		device_printf(sc->mfi_dev, "%d - Type %d: %s\n",
1107158737Sambrisko		    detail->seq,
1108158737Sambrisko		    detail->arg_type, detail->description
1109158737Sambrisko		    );
1110158737Sambrisko	}
1111158737Sambrisko}
1112158737Sambrisko
1113157114Sscottlstatic int
1114158737Sambriskomfi_aen_register(struct mfi_softc *sc, int seq, int locale)
1115158737Sambrisko{
1116158737Sambrisko	struct mfi_command *cm;
1117158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1118158737Sambrisko	union mfi_evt current_aen, prior_aen;
1119159806Sps	struct mfi_evt_detail *ed = NULL;
1120159806Sps	int error;
1121158737Sambrisko
1122158737Sambrisko	current_aen.word = locale;
1123158737Sambrisko	if (sc->mfi_aen_cm != NULL) {
1124158737Sambrisko		prior_aen.word =
1125158737Sambrisko		    ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1];
1126158737Sambrisko		if (prior_aen.members.class <= current_aen.members.class &&
1127158737Sambrisko		    !((prior_aen.members.locale & current_aen.members.locale)
1128158737Sambrisko		    ^current_aen.members.locale)) {
1129158737Sambrisko			return (0);
1130158737Sambrisko		} else {
1131158737Sambrisko			prior_aen.members.locale |= current_aen.members.locale;
1132158737Sambrisko			if (prior_aen.members.class
1133158737Sambrisko			    < current_aen.members.class)
1134158737Sambrisko				current_aen.members.class =
1135158737Sambrisko				    prior_aen.members.class;
1136158737Sambrisko			mfi_abort(sc, sc->mfi_aen_cm);
1137158737Sambrisko		}
1138158737Sambrisko	}
1139158737Sambrisko
1140158737Sambrisko	mtx_lock(&sc->mfi_io_lock);
1141159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT,
1142159806Sps	    (void **)&ed, sizeof(*ed));
1143158737Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1144159806Sps	if (error)
1145159806Sps		return (error);
1146158737Sambrisko
1147158737Sambrisko	dcmd = &cm->cm_frame->dcmd;
1148158737Sambrisko	((uint32_t *)&dcmd->mbox)[0] = seq;
1149158737Sambrisko	((uint32_t *)&dcmd->mbox)[1] = locale;
1150158737Sambrisko	cm->cm_flags = MFI_CMD_DATAIN;
1151158737Sambrisko	cm->cm_complete = mfi_aen_complete;
1152158737Sambrisko
1153158737Sambrisko	sc->mfi_aen_cm = cm;
1154158737Sambrisko
1155158737Sambrisko	mfi_enqueue_ready(cm);
1156158737Sambrisko	mfi_startio(sc);
1157158737Sambrisko
1158158737Sambrisko	return (0);
1159158737Sambrisko}
1160158737Sambrisko
1161158737Sambriskostatic void
1162158737Sambriskomfi_aen_complete(struct mfi_command *cm)
1163158737Sambrisko{
1164158737Sambrisko	struct mfi_frame_header *hdr;
1165158737Sambrisko	struct mfi_softc *sc;
1166158737Sambrisko	struct mfi_evt_detail *detail;
1167158737Sambrisko	struct mfi_aen *mfi_aen_entry;
1168158737Sambrisko	int seq = 0, aborted = 0;
1169158737Sambrisko
1170158737Sambrisko	sc = cm->cm_sc;
1171158737Sambrisko	hdr = &cm->cm_frame->header;
1172158737Sambrisko
1173158737Sambrisko	if (sc->mfi_aen_cm == NULL)
1174158737Sambrisko		return;
1175158737Sambrisko
1176158737Sambrisko	if (sc->mfi_aen_cm->cm_aen_abort || hdr->cmd_status == 0xff) {
1177158737Sambrisko		sc->mfi_aen_cm->cm_aen_abort = 0;
1178158737Sambrisko		aborted = 1;
1179158737Sambrisko	} else {
1180158737Sambrisko		sc->mfi_aen_triggered = 1;
1181158737Sambrisko		if (sc->mfi_poll_waiting)
1182158737Sambrisko			selwakeup(&sc->mfi_select);
1183158737Sambrisko		detail = cm->cm_data;
1184158737Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1185158737Sambrisko		mfi_decode_evt(sc, detail);
1186158737Sambrisko		mtx_lock(&sc->mfi_io_lock);
1187158737Sambrisko		seq = detail->seq + 1;
1188158737Sambrisko		TAILQ_FOREACH(mfi_aen_entry, &sc->mfi_aen_pids, aen_link) {
1189158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
1190158737Sambrisko			    aen_link);
1191158737Sambrisko			psignal(mfi_aen_entry->p, SIGIO);
1192158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
1193158737Sambrisko		}
1194158737Sambrisko	}
1195158737Sambrisko
1196158737Sambrisko	free(cm->cm_data, M_MFIBUF);
1197158737Sambrisko	sc->mfi_aen_cm = NULL;
1198158737Sambrisko	wakeup(&sc->mfi_aen_cm);
1199158737Sambrisko	mfi_release_command(cm);
1200158737Sambrisko
1201158737Sambrisko	/* set it up again so the driver can catch more events */
1202158737Sambrisko	if (!aborted) {
1203158737Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1204158737Sambrisko		mfi_aen_setup(sc, seq);
1205158737Sambrisko		mtx_lock(&sc->mfi_io_lock);
1206158737Sambrisko	}
1207158737Sambrisko}
1208158737Sambrisko
1209159574Sambrisko#ifdef NOTYET
1210158737Sambriskostatic int
1211158737Sambriskomfi_get_entry(struct mfi_softc *sc, int seq)
1212158737Sambrisko{
1213158737Sambrisko	struct mfi_command *cm;
1214158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1215158737Sambrisko	struct mfi_log_detail *ed;
1216158737Sambrisko	int error;
1217158737Sambrisko
1218158737Sambrisko	mtx_lock(&sc->mfi_io_lock);
1219158737Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL) {
1220158737Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1221158737Sambrisko		return (EBUSY);
1222158737Sambrisko	}
1223158737Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1224158737Sambrisko
1225158737Sambrisko	ed = malloc(sizeof(struct mfi_log_detail), M_MFIBUF, M_NOWAIT | M_ZERO);
1226158737Sambrisko	if (ed == NULL) {
1227158737Sambrisko		mtx_lock(&sc->mfi_io_lock);
1228158737Sambrisko		mfi_release_command(cm);
1229158737Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1230158737Sambrisko		return (ENOMEM);
1231158737Sambrisko	}
1232158737Sambrisko
1233158737Sambrisko	dcmd = &cm->cm_frame->dcmd;
1234158737Sambrisko	bzero(dcmd->mbox, MFI_MBOX_SIZE);
1235158737Sambrisko	dcmd->header.cmd = MFI_CMD_DCMD;
1236158737Sambrisko	dcmd->header.timeout = 0;
1237158737Sambrisko	dcmd->header.data_len = sizeof(struct mfi_log_detail);
1238158737Sambrisko	dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET;
1239158737Sambrisko	((uint32_t *)&dcmd->mbox)[0] = seq;
1240158737Sambrisko	((uint32_t *)&dcmd->mbox)[1] = MFI_EVT_LOCALE_ALL;
1241158737Sambrisko	cm->cm_sg = &dcmd->sgl;
1242158737Sambrisko	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
1243158737Sambrisko	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1244158737Sambrisko	cm->cm_data = ed;
1245158737Sambrisko	cm->cm_len = sizeof(struct mfi_evt_detail);
1246158737Sambrisko
1247158737Sambrisko	if ((error = mfi_mapcmd(sc, cm)) != 0) {
1248158737Sambrisko		device_printf(sc->mfi_dev, "Controller info buffer map failed");
1249158737Sambrisko		free(ed, M_MFIBUF);
1250158737Sambrisko		mfi_release_command(cm);
1251158737Sambrisko		return (error);
1252158737Sambrisko	}
1253158737Sambrisko
1254158737Sambrisko	if ((error = mfi_polled_command(sc, cm)) != 0) {
1255158737Sambrisko		device_printf(sc->mfi_dev, "Failed to get controller entry\n");
1256158737Sambrisko		sc->mfi_max_io = (sc->mfi_total_sgl - 1) * PAGE_SIZE /
1257158737Sambrisko		    MFI_SECTOR_LEN;
1258158737Sambrisko		free(ed, M_MFIBUF);
1259158737Sambrisko		mfi_release_command(cm);
1260158737Sambrisko		return (0);
1261158737Sambrisko	}
1262158737Sambrisko
1263158737Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1264158737Sambrisko	    BUS_DMASYNC_POSTREAD);
1265158737Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1266158737Sambrisko
1267158737Sambrisko	mfi_decode_log(sc, ed);
1268158737Sambrisko
1269158737Sambrisko	mtx_lock(&sc->mfi_io_lock);
1270158737Sambrisko	free(cm->cm_data, M_MFIBUF);
1271158737Sambrisko	mfi_release_command(cm);
1272158737Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1273158737Sambrisko	return (0);
1274158737Sambrisko}
1275159574Sambrisko#endif
1276158737Sambrisko
1277158737Sambriskostatic int
1278159811Spsmfi_add_ld(struct mfi_softc *sc, int id)
1279157114Sscottl{
1280157114Sscottl	struct mfi_command *cm;
1281159811Sps	struct mfi_dcmd_frame *dcmd = NULL;
1282159811Sps	struct mfi_ld_info *ld_info = NULL;
1283159811Sps	int error;
1284157114Sscottl
1285159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1286159811Sps
1287159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO,
1288159811Sps	    (void **)&ld_info, sizeof(*ld_info));
1289159811Sps	if (error) {
1290159811Sps		device_printf(sc->mfi_dev,
1291159811Sps		    "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error);
1292159811Sps		if (ld_info)
1293159811Sps			free(ld_info, M_MFIBUF);
1294159811Sps		return (error);
1295157624Sscottl	}
1296159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
1297159811Sps	cm->cm_complete = mfi_add_ld_complete;
1298159811Sps	dcmd = &cm->cm_frame->dcmd;
1299159811Sps	dcmd->mbox[0] = id;
1300159811Sps
1301157114Sscottl	mfi_enqueue_ready(cm);
1302157114Sscottl	mfi_startio(sc);
1303157114Sscottl
1304157114Sscottl	return (0);
1305157114Sscottl}
1306157114Sscottl
1307157114Sscottlstatic void
1308159811Spsmfi_add_ld_complete(struct mfi_command *cm)
1309157114Sscottl{
1310157114Sscottl	struct mfi_frame_header *hdr;
1311159811Sps	struct mfi_ld_info *ld_info;
1312157114Sscottl	struct mfi_softc *sc;
1313159811Sps	struct mfi_ld *ld;
1314159811Sps	device_t child;
1315157114Sscottl
1316157114Sscottl	sc = cm->cm_sc;
1317157114Sscottl	hdr = &cm->cm_frame->header;
1318159811Sps	ld_info = cm->cm_private;
1319157114Sscottl
1320159811Sps	if (hdr->cmd_status != MFI_STAT_OK) {
1321159811Sps		free(ld_info, M_MFIBUF);
1322157114Sscottl		mfi_release_command(cm);
1323157114Sscottl		return;
1324157114Sscottl	}
1325157114Sscottl	mfi_release_command(cm);
1326157114Sscottl
1327157114Sscottl	ld = malloc(sizeof(struct mfi_ld), M_MFIBUF, M_NOWAIT|M_ZERO);
1328157114Sscottl	if (ld == NULL) {
1329157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate ld\n");
1330159811Sps		free(ld_info, M_MFIBUF);
1331159811Sps		return;
1332157114Sscottl	}
1333157114Sscottl
1334157114Sscottl	if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) {
1335157114Sscottl		device_printf(sc->mfi_dev, "Failed to add logical disk\n");
1336157624Sscottl		free(ld, M_MFIBUF);
1337159811Sps		free(ld_info, M_MFIBUF);
1338159811Sps		return;
1339157114Sscottl	}
1340157114Sscottl
1341159811Sps	ld->ld_id = ld_info->ld_config.properties.ld.target_id;
1342157114Sscottl	ld->ld_disk = child;
1343159811Sps	ld->ld_info = ld_info;
1344157114Sscottl
1345157114Sscottl	device_set_ivars(child, ld);
1346157114Sscottl	device_set_desc(child, "MFI Logical Disk");
1347157114Sscottl	mtx_unlock(&sc->mfi_io_lock);
1348157114Sscottl	mtx_lock(&Giant);
1349157114Sscottl	bus_generic_attach(sc->mfi_dev);
1350157114Sscottl	mtx_unlock(&Giant);
1351157114Sscottl	mtx_lock(&sc->mfi_io_lock);
1352157114Sscottl}
1353157114Sscottl
1354157114Sscottlstatic struct mfi_command *
1355157114Sscottlmfi_bio_command(struct mfi_softc *sc)
1356157114Sscottl{
1357157114Sscottl	struct mfi_io_frame *io;
1358157114Sscottl	struct mfi_command *cm;
1359157114Sscottl	struct bio *bio;
1360158737Sambrisko	int flags, blkcount;
1361157114Sscottl
1362157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
1363157114Sscottl		return (NULL);
1364157114Sscottl
1365157114Sscottl	if ((bio = mfi_dequeue_bio(sc)) == NULL) {
1366157114Sscottl		mfi_release_command(cm);
1367157114Sscottl		return (NULL);
1368157114Sscottl	}
1369157114Sscottl
1370157114Sscottl	io = &cm->cm_frame->io;
1371157114Sscottl	switch (bio->bio_cmd & 0x03) {
1372157114Sscottl	case BIO_READ:
1373157114Sscottl		io->header.cmd = MFI_CMD_LD_READ;
1374157114Sscottl		flags = MFI_CMD_DATAIN;
1375157114Sscottl		break;
1376157114Sscottl	case BIO_WRITE:
1377157114Sscottl		io->header.cmd = MFI_CMD_LD_WRITE;
1378157114Sscottl		flags = MFI_CMD_DATAOUT;
1379157114Sscottl		break;
1380157114Sscottl	default:
1381157114Sscottl		panic("Invalid bio command");
1382157114Sscottl	}
1383157114Sscottl
1384157114Sscottl	/* Cheat with the sector length to avoid a non-constant division */
1385157114Sscottl	blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
1386157114Sscottl	io->header.target_id = (uintptr_t)bio->bio_driver1;
1387157114Sscottl	io->header.timeout = 0;
1388157114Sscottl	io->header.flags = 0;
1389157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
1390157114Sscottl	io->header.data_len = blkcount;
1391157114Sscottl	io->sense_addr_lo = cm->cm_sense_busaddr;
1392157114Sscottl	io->sense_addr_hi = 0;
1393157114Sscottl	io->lba_hi = (bio->bio_pblkno & 0xffffffff00000000) >> 32;
1394157114Sscottl	io->lba_lo = bio->bio_pblkno & 0xffffffff;
1395157114Sscottl	cm->cm_complete = mfi_bio_complete;
1396157114Sscottl	cm->cm_private = bio;
1397157114Sscottl	cm->cm_data = bio->bio_data;
1398157114Sscottl	cm->cm_len = bio->bio_bcount;
1399157114Sscottl	cm->cm_sg = &io->sgl;
1400157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
1401157114Sscottl	cm->cm_flags = flags;
1402157114Sscottl
1403157114Sscottl	return (cm);
1404157114Sscottl}
1405157114Sscottl
1406157114Sscottlstatic void
1407157114Sscottlmfi_bio_complete(struct mfi_command *cm)
1408157114Sscottl{
1409157114Sscottl	struct bio *bio;
1410157114Sscottl	struct mfi_frame_header *hdr;
1411157114Sscottl	struct mfi_softc *sc;
1412157114Sscottl
1413157114Sscottl	bio = cm->cm_private;
1414157114Sscottl	hdr = &cm->cm_frame->header;
1415157114Sscottl	sc = cm->cm_sc;
1416157114Sscottl
1417157114Sscottl	if ((hdr->cmd_status != 0) || (hdr->scsi_status != 0)) {
1418157114Sscottl		bio->bio_flags |= BIO_ERROR;
1419157114Sscottl		bio->bio_error = EIO;
1420157114Sscottl		device_printf(sc->mfi_dev, "I/O error, status= %d "
1421157114Sscottl		    "scsi_status= %d\n", hdr->cmd_status, hdr->scsi_status);
1422157114Sscottl		mfi_print_sense(cm->cm_sc, cm->cm_sense);
1423157114Sscottl	}
1424157114Sscottl
1425157114Sscottl	mfi_release_command(cm);
1426157114Sscottl	mfi_disk_complete(bio);
1427157114Sscottl}
1428157114Sscottl
1429157114Sscottlvoid
1430157114Sscottlmfi_startio(struct mfi_softc *sc)
1431157114Sscottl{
1432157114Sscottl	struct mfi_command *cm;
1433157114Sscottl
1434157114Sscottl	for (;;) {
1435157114Sscottl		/* Don't bother if we're short on resources */
1436157114Sscottl		if (sc->mfi_flags & MFI_FLAGS_QFRZN)
1437157114Sscottl			break;
1438157114Sscottl
1439157114Sscottl		/* Try a command that has already been prepared */
1440157114Sscottl		cm = mfi_dequeue_ready(sc);
1441157114Sscottl
1442157114Sscottl		/* Nope, so look for work on the bioq */
1443157114Sscottl		if (cm == NULL)
1444157114Sscottl			cm = mfi_bio_command(sc);
1445157114Sscottl
1446157114Sscottl		/* No work available, so exit */
1447157114Sscottl		if (cm == NULL)
1448157114Sscottl			break;
1449157114Sscottl
1450157114Sscottl		/* Send the command to the controller */
1451157114Sscottl		if (mfi_mapcmd(sc, cm) != 0) {
1452157114Sscottl			mfi_requeue_ready(cm);
1453157114Sscottl			break;
1454157114Sscottl		}
1455157114Sscottl	}
1456157114Sscottl}
1457157114Sscottl
1458157114Sscottlstatic int
1459157114Sscottlmfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm)
1460157114Sscottl{
1461157114Sscottl	int error, polled;
1462157114Sscottl
1463157114Sscottl	if (cm->cm_data != NULL) {
1464157114Sscottl		polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0;
1465157114Sscottl		error = bus_dmamap_load(sc->mfi_buffer_dmat, cm->cm_dmamap,
1466157114Sscottl		    cm->cm_data, cm->cm_len, mfi_data_cb, cm, polled);
1467157114Sscottl		if (error == EINPROGRESS) {
1468157114Sscottl			sc->mfi_flags |= MFI_FLAGS_QFRZN;
1469157114Sscottl			return (0);
1470157114Sscottl		}
1471157114Sscottl	} else {
1472157114Sscottl		mfi_enqueue_busy(cm);
1473157114Sscottl		error = mfi_send_frame(sc, cm);
1474157114Sscottl	}
1475157114Sscottl
1476157114Sscottl	return (error);
1477157114Sscottl}
1478157114Sscottl
1479157114Sscottlstatic void
1480157114Sscottlmfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
1481157114Sscottl{
1482157114Sscottl	struct mfi_frame_header *hdr;
1483157114Sscottl	struct mfi_command *cm;
1484157237Sscottl	union mfi_sgl *sgl;
1485157114Sscottl	struct mfi_softc *sc;
1486157114Sscottl	int i, dir;
1487157114Sscottl
1488157114Sscottl	if (error)
1489157114Sscottl		return;
1490157114Sscottl
1491157114Sscottl	cm = (struct mfi_command *)arg;
1492157114Sscottl	sc = cm->cm_sc;
1493157237Sscottl	hdr = &cm->cm_frame->header;
1494157237Sscottl	sgl = cm->cm_sg;
1495157114Sscottl
1496157237Sscottl	if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
1497157237Sscottl		for (i = 0; i < nsegs; i++) {
1498157237Sscottl			sgl->sg32[i].addr = segs[i].ds_addr;
1499157237Sscottl			sgl->sg32[i].len = segs[i].ds_len;
1500157114Sscottl		}
1501157237Sscottl	} else {
1502157237Sscottl		for (i = 0; i < nsegs; i++) {
1503157237Sscottl			sgl->sg64[i].addr = segs[i].ds_addr;
1504157237Sscottl			sgl->sg64[i].len = segs[i].ds_len;
1505157237Sscottl		}
1506157237Sscottl		hdr->flags |= MFI_FRAME_SGL64;
1507157114Sscottl	}
1508157114Sscottl	hdr->sg_count = nsegs;
1509157114Sscottl
1510157114Sscottl	dir = 0;
1511157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAIN) {
1512157114Sscottl		dir |= BUS_DMASYNC_PREREAD;
1513157114Sscottl		hdr->flags |= MFI_FRAME_DIR_READ;
1514157114Sscottl	}
1515157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAOUT) {
1516157114Sscottl		dir |= BUS_DMASYNC_PREWRITE;
1517157114Sscottl		hdr->flags |= MFI_FRAME_DIR_WRITE;
1518157114Sscottl	}
1519157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
1520157114Sscottl	cm->cm_flags |= MFI_CMD_MAPPED;
1521157114Sscottl
1522157114Sscottl	/*
1523157114Sscottl	 * Instead of calculating the total number of frames in the
1524157114Sscottl	 * compound frame, it's already assumed that there will be at
1525157114Sscottl	 * least 1 frame, so don't compensate for the modulo of the
1526157114Sscottl	 * following division.
1527157114Sscottl	 */
1528157114Sscottl	cm->cm_total_frame_size += (sc->mfi_sgsize * nsegs);
1529157114Sscottl	cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
1530157114Sscottl
1531157114Sscottl	/* The caller will take care of delivering polled commands */
1532157114Sscottl	if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
1533157114Sscottl		mfi_enqueue_busy(cm);
1534157114Sscottl		mfi_send_frame(sc, cm);
1535157114Sscottl	}
1536157114Sscottl
1537157114Sscottl	return;
1538157114Sscottl}
1539157114Sscottl
1540157114Sscottlstatic int
1541157114Sscottlmfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
1542157114Sscottl{
1543157114Sscottl
1544157114Sscottl	/*
1545157114Sscottl	 * The bus address of the command is aligned on a 64 byte boundary,
1546157114Sscottl	 * leaving the least 6 bits as zero.  For whatever reason, the
1547157114Sscottl	 * hardware wants the address shifted right by three, leaving just
1548157114Sscottl	 * 3 zero bits.  These three bits are then used to indicate how many
1549157114Sscottl	 * 64 byte frames beyond the first one are used in the command.  The
1550157114Sscottl	 * extra frames are typically filled with S/G elements.  The extra
1551157114Sscottl	 * frames must also be contiguous.  Thus, a compound frame can be at
1552157114Sscottl	 * most 512 bytes long, allowing for up to 59 32-bit S/G elements or
1553157114Sscottl	 * 39 64-bit S/G elements for block I/O commands.  This means that
1554157114Sscottl	 * I/O transfers of 256k and higher simply are not possible, which
1555157114Sscottl	 * is quite odd for such a modern adapter.
1556157114Sscottl	 */
1557157114Sscottl	MFI_WRITE4(sc, MFI_IQP, (cm->cm_frame_busaddr >> 3) |
1558157114Sscottl	    cm->cm_extra_frames);
1559157114Sscottl	return (0);
1560157114Sscottl}
1561157114Sscottl
1562157114Sscottlstatic void
1563157114Sscottlmfi_complete(struct mfi_softc *sc, struct mfi_command *cm)
1564157114Sscottl{
1565157114Sscottl	int dir;
1566157114Sscottl
1567157114Sscottl	if ((cm->cm_flags & MFI_CMD_MAPPED) != 0) {
1568157114Sscottl		dir = 0;
1569157114Sscottl		if (cm->cm_flags & MFI_CMD_DATAIN)
1570157114Sscottl			dir |= BUS_DMASYNC_POSTREAD;
1571157114Sscottl		if (cm->cm_flags & MFI_CMD_DATAOUT)
1572157114Sscottl			dir |= BUS_DMASYNC_POSTWRITE;
1573157114Sscottl
1574157114Sscottl		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
1575157114Sscottl		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1576157114Sscottl		cm->cm_flags &= ~MFI_CMD_MAPPED;
1577157114Sscottl	}
1578157114Sscottl
1579157114Sscottl	if (cm->cm_complete != NULL)
1580157114Sscottl		cm->cm_complete(cm);
1581159811Sps	else
1582159811Sps		wakeup(cm);
1583157114Sscottl
1584157114Sscottl	sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
1585157114Sscottl	mfi_startio(sc);
1586157114Sscottl}
1587157114Sscottl
1588158737Sambriskostatic int
1589158737Sambriskomfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort)
1590158737Sambrisko{
1591158737Sambrisko	struct mfi_command *cm;
1592158737Sambrisko	struct mfi_abort_frame *abort;
1593158737Sambrisko
1594158737Sambrisko	mtx_lock(&sc->mfi_io_lock);
1595158737Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL) {
1596158737Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1597158737Sambrisko		return (EBUSY);
1598158737Sambrisko	}
1599158737Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1600158737Sambrisko
1601158737Sambrisko	abort = &cm->cm_frame->abort;
1602158737Sambrisko	abort->header.cmd = MFI_CMD_ABORT;
1603158737Sambrisko	abort->header.flags = 0;
1604158737Sambrisko	abort->abort_context = cm_abort->cm_frame->header.context;
1605158737Sambrisko	abort->abort_mfi_addr_lo = cm_abort->cm_frame_busaddr;
1606158737Sambrisko	abort->abort_mfi_addr_hi = 0;
1607158737Sambrisko	cm->cm_data = NULL;
1608158737Sambrisko
1609158737Sambrisko	sc->mfi_aen_cm->cm_aen_abort = 1;
1610158737Sambrisko	mfi_mapcmd(sc, cm);
1611158737Sambrisko	mfi_polled_command(sc, cm);
1612158737Sambrisko	mtx_lock(&sc->mfi_io_lock);
1613158737Sambrisko	mfi_release_command(cm);
1614158737Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1615158737Sambrisko
1616158737Sambrisko	while (sc->mfi_aen_cm != NULL) {
1617158737Sambrisko		tsleep(&sc->mfi_aen_cm, 0, "mfiabort", 5 * hz);
1618158737Sambrisko	}
1619158737Sambrisko
1620158737Sambrisko	return (0);
1621158737Sambrisko}
1622158737Sambrisko
1623157114Sscottlint
1624157114Sscottlmfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, int len)
1625157114Sscottl{
1626157114Sscottl	struct mfi_command *cm;
1627157114Sscottl	struct mfi_io_frame *io;
1628157114Sscottl	int error;
1629157114Sscottl
1630157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
1631157114Sscottl		return (EBUSY);
1632157114Sscottl
1633157114Sscottl	io = &cm->cm_frame->io;
1634157114Sscottl	io->header.cmd = MFI_CMD_LD_WRITE;
1635157114Sscottl	io->header.target_id = id;
1636157114Sscottl	io->header.timeout = 0;
1637157114Sscottl	io->header.flags = 0;
1638157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
1639157114Sscottl	io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
1640157114Sscottl	io->sense_addr_lo = cm->cm_sense_busaddr;
1641157114Sscottl	io->sense_addr_hi = 0;
1642157114Sscottl	io->lba_hi = (lba & 0xffffffff00000000) >> 32;
1643157114Sscottl	io->lba_lo = lba & 0xffffffff;
1644157114Sscottl	cm->cm_data = virt;
1645157114Sscottl	cm->cm_len = len;
1646157114Sscottl	cm->cm_sg = &io->sgl;
1647157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
1648157114Sscottl	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT;
1649157114Sscottl
1650157114Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
1651157114Sscottl		mfi_release_command(cm);
1652157114Sscottl		return (error);
1653157114Sscottl	}
1654157114Sscottl
1655157114Sscottl	error = mfi_polled_command(sc, cm);
1656157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1657157114Sscottl	    BUS_DMASYNC_POSTWRITE);
1658157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1659157114Sscottl	mfi_release_command(cm);
1660157114Sscottl
1661157114Sscottl	return (error);
1662157114Sscottl}
1663157114Sscottl
1664157114Sscottlstatic int
1665157114Sscottlmfi_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
1666157114Sscottl{
1667157114Sscottl	struct mfi_softc *sc;
1668157114Sscottl
1669157114Sscottl	sc = dev->si_drv1;
1670157114Sscottl	sc->mfi_flags |= MFI_FLAGS_OPEN;
1671157114Sscottl
1672157114Sscottl	return (0);
1673157114Sscottl}
1674157114Sscottl
1675157114Sscottlstatic int
1676157114Sscottlmfi_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
1677157114Sscottl{
1678157114Sscottl	struct mfi_softc *sc;
1679158737Sambrisko	struct mfi_aen *mfi_aen_entry;
1680157114Sscottl
1681157114Sscottl	sc = dev->si_drv1;
1682157114Sscottl	sc->mfi_flags &= ~MFI_FLAGS_OPEN;
1683157114Sscottl
1684158737Sambrisko	TAILQ_FOREACH(mfi_aen_entry, &sc->mfi_aen_pids, aen_link) {
1685158737Sambrisko		if (mfi_aen_entry->p == curproc) {
1686158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
1687158737Sambrisko			    aen_link);
1688158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
1689158737Sambrisko		}
1690158737Sambrisko	}
1691157114Sscottl	return (0);
1692157114Sscottl}
1693157114Sscottl
1694157114Sscottlstatic int
1695157114Sscottlmfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
1696157114Sscottl{
1697157114Sscottl	struct mfi_softc *sc;
1698157114Sscottl	union mfi_statrequest *ms;
1699157114Sscottl	int error;
1700157114Sscottl
1701157114Sscottl	sc = dev->si_drv1;
1702157114Sscottl	error = 0;
1703157114Sscottl
1704157114Sscottl	switch (cmd) {
1705157114Sscottl	case MFIIO_STATS:
1706157114Sscottl		ms = (union mfi_statrequest *)arg;
1707157114Sscottl		switch (ms->ms_item) {
1708157114Sscottl		case MFIQ_FREE:
1709157114Sscottl		case MFIQ_BIO:
1710157114Sscottl		case MFIQ_READY:
1711157114Sscottl		case MFIQ_BUSY:
1712157114Sscottl			bcopy(&sc->mfi_qstat[ms->ms_item], &ms->ms_qstat,
1713157114Sscottl			    sizeof(struct mfi_qstat));
1714157114Sscottl			break;
1715157114Sscottl		default:
1716158737Sambrisko			error = ENOIOCTL;
1717157114Sscottl			break;
1718157114Sscottl		}
1719157114Sscottl		break;
1720158737Sambrisko	case 0xc1144d01: /* Firmware Linux ioctl shim */
1721158737Sambrisko		{
1722158737Sambrisko			devclass_t devclass;
1723158737Sambrisko			struct mfi_linux_ioc_packet l_ioc;
1724158737Sambrisko			int adapter;
1725158737Sambrisko
1726158737Sambrisko			devclass = devclass_find("mfi");
1727158737Sambrisko			if (devclass == NULL)
1728158737Sambrisko				return (ENOENT);
1729158737Sambrisko
1730158737Sambrisko			error = copyin(arg, &l_ioc, sizeof(l_ioc));
1731158737Sambrisko			if (error)
1732158737Sambrisko				return (error);
1733158737Sambrisko			adapter = l_ioc.lioc_adapter_no;
1734158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
1735158737Sambrisko			if (sc == NULL)
1736158737Sambrisko				return (ENOENT);
1737158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
1738158737Sambrisko			    cmd, arg, flag, td));
1739158737Sambrisko			break;
1740158737Sambrisko		}
1741158737Sambrisko	case 0x400c4d03: /* AEN Linux ioctl shim */
1742158737Sambrisko		{
1743158737Sambrisko			devclass_t devclass;
1744158737Sambrisko			struct mfi_linux_ioc_aen l_aen;
1745158737Sambrisko			int adapter;
1746158737Sambrisko
1747158737Sambrisko			devclass = devclass_find("mfi");
1748158737Sambrisko			if (devclass == NULL)
1749158737Sambrisko				return (ENOENT);
1750158737Sambrisko
1751158737Sambrisko			error = copyin(arg, &l_aen, sizeof(l_aen));
1752158737Sambrisko			if (error)
1753158737Sambrisko				return (error);
1754158737Sambrisko			adapter = l_aen.laen_adapter_no;
1755158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
1756158737Sambrisko			if (sc == NULL)
1757158737Sambrisko				return (ENOENT);
1758158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
1759158737Sambrisko			    cmd, arg, flag, td));
1760158737Sambrisko			break;
1761158737Sambrisko		}
1762157114Sscottl	default:
1763157114Sscottl		error = ENOENT;
1764157114Sscottl		break;
1765157114Sscottl	}
1766157114Sscottl
1767157114Sscottl	return (error);
1768157114Sscottl}
1769158737Sambrisko
1770158737Sambriskostatic int
1771158737Sambriskomfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
1772158737Sambrisko{
1773158737Sambrisko	struct mfi_softc *sc;
1774158737Sambrisko	struct mfi_linux_ioc_packet l_ioc;
1775158737Sambrisko	struct mfi_linux_ioc_aen l_aen;
1776158737Sambrisko	struct mfi_command *cm = NULL;
1777158737Sambrisko	struct mfi_aen *mfi_aen_entry;
1778158737Sambrisko	uint32_t *sense_ptr;
1779158737Sambrisko	uint32_t context;
1780158737Sambrisko	uint8_t *data = NULL, *temp;
1781158737Sambrisko	int i;
1782158737Sambrisko	int error;
1783158737Sambrisko
1784158737Sambrisko	sc = dev->si_drv1;
1785158737Sambrisko	error = 0;
1786158737Sambrisko	switch (cmd) {
1787158737Sambrisko	case 0xc1144d01: /* Firmware Linux ioctl shim */
1788158737Sambrisko		error = copyin(arg, &l_ioc, sizeof(l_ioc));
1789158737Sambrisko		if (error != 0)
1790158737Sambrisko			return (error);
1791158737Sambrisko
1792158737Sambrisko		if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) {
1793158737Sambrisko			return (EINVAL);
1794158737Sambrisko		}
1795158737Sambrisko
1796158737Sambrisko		mtx_lock(&sc->mfi_io_lock);
1797158737Sambrisko		if ((cm = mfi_dequeue_free(sc)) == NULL) {
1798158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1799158737Sambrisko			return (EBUSY);
1800158737Sambrisko		}
1801158737Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1802158737Sambrisko
1803158737Sambrisko		/*
1804158737Sambrisko		 * save off original context since copying from user
1805158737Sambrisko		 * will clobber some data
1806158737Sambrisko		 */
1807158737Sambrisko		context = cm->cm_frame->header.context;
1808158737Sambrisko
1809158737Sambrisko		bcopy(l_ioc.lioc_frame.raw, cm->cm_frame,
1810158737Sambrisko		      l_ioc.lioc_sgl_off); /* Linux can do 2 frames ? */
1811158737Sambrisko		cm->cm_total_frame_size = l_ioc.lioc_sgl_off;
1812158737Sambrisko		cm->cm_sg =
1813158737Sambrisko		    (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
1814158737Sambrisko		cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT
1815158737Sambrisko			| MFI_CMD_POLLED;
1816158737Sambrisko		cm->cm_len = cm->cm_frame->header.data_len;
1817158737Sambrisko		cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
1818158737Sambrisko					    M_WAITOK | M_ZERO);
1819158737Sambrisko
1820158737Sambrisko		/* restore header context */
1821158737Sambrisko		cm->cm_frame->header.context = context;
1822158737Sambrisko
1823158737Sambrisko		temp = data;
1824158737Sambrisko		for (i = 0; i < l_ioc.lioc_sge_count; i++) {
1825158737Sambrisko			error = copyin(l_ioc.lioc_sgl[i].iov_base,
1826158737Sambrisko			       temp,
1827158737Sambrisko			       l_ioc.lioc_sgl[i].iov_len);
1828158737Sambrisko			if (error != 0) {
1829158737Sambrisko				device_printf(sc->mfi_dev,
1830158737Sambrisko				    "Copy in failed");
1831158737Sambrisko				goto out;
1832158737Sambrisko			}
1833158737Sambrisko			temp = &temp[l_ioc.lioc_sgl[i].iov_len];
1834158737Sambrisko		}
1835158737Sambrisko
1836158737Sambrisko		if (l_ioc.lioc_sense_len) {
1837158737Sambrisko			sense_ptr =
1838158737Sambrisko			    (void *)&cm->cm_frame->bytes[l_ioc.lioc_sense_off];
1839158737Sambrisko			*sense_ptr = cm->cm_sense_busaddr;
1840158737Sambrisko		}
1841158737Sambrisko
1842158737Sambrisko		if ((error = mfi_mapcmd(sc, cm)) != 0) {
1843158737Sambrisko			device_printf(sc->mfi_dev,
1844158737Sambrisko			    "Controller info buffer map failed");
1845158737Sambrisko			goto out;
1846158737Sambrisko		}
1847158737Sambrisko
1848158737Sambrisko		if ((error = mfi_polled_command(sc, cm)) != 0) {
1849158737Sambrisko			device_printf(sc->mfi_dev,
1850158737Sambrisko			    "Controller polled failed");
1851158737Sambrisko			goto out;
1852158737Sambrisko		}
1853158737Sambrisko
1854158737Sambrisko		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1855158737Sambrisko				BUS_DMASYNC_POSTREAD);
1856158737Sambrisko		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1857158737Sambrisko
1858158737Sambrisko		temp = data;
1859158737Sambrisko		for (i = 0; i < l_ioc.lioc_sge_count; i++) {
1860158737Sambrisko			error = copyout(temp,
1861158737Sambrisko				l_ioc.lioc_sgl[i].iov_base,
1862158737Sambrisko				l_ioc.lioc_sgl[i].iov_len);
1863158737Sambrisko			if (error != 0) {
1864158737Sambrisko				device_printf(sc->mfi_dev,
1865158737Sambrisko				    "Copy out failed");
1866158737Sambrisko				goto out;
1867158737Sambrisko			}
1868158737Sambrisko			temp = &temp[l_ioc.lioc_sgl[i].iov_len];
1869158737Sambrisko		}
1870158737Sambrisko
1871158737Sambrisko		if (l_ioc.lioc_sense_len) {
1872158737Sambrisko			/* copy out sense */
1873158737Sambrisko			sense_ptr = (void *)
1874158737Sambrisko			    &l_ioc.lioc_frame.raw[l_ioc.lioc_sense_off];
1875158737Sambrisko			temp = 0;
1876158737Sambrisko			temp += cm->cm_sense_busaddr;
1877158737Sambrisko			error = copyout(temp, sense_ptr,
1878158737Sambrisko			    l_ioc.lioc_sense_len);
1879158737Sambrisko			if (error != 0) {
1880158737Sambrisko				device_printf(sc->mfi_dev,
1881158737Sambrisko				    "Copy out failed");
1882158737Sambrisko				goto out;
1883158737Sambrisko			}
1884158737Sambrisko		}
1885158737Sambrisko
1886158737Sambrisko		error = copyout(&cm->cm_frame->header.cmd_status,
1887158737Sambrisko			&((struct mfi_linux_ioc_packet*)arg)
1888158737Sambrisko			->lioc_frame.hdr.cmd_status,
1889158737Sambrisko			1);
1890158737Sambrisko		if (error != 0) {
1891158737Sambrisko			device_printf(sc->mfi_dev,
1892158737Sambrisko				      "Copy out failed");
1893158737Sambrisko			goto out;
1894158737Sambrisko		}
1895158737Sambrisko
1896158737Sambriskoout:
1897158737Sambrisko		if (data)
1898158737Sambrisko			free(data, M_MFIBUF);
1899158737Sambrisko		if (cm) {
1900158737Sambrisko			mtx_lock(&sc->mfi_io_lock);
1901158737Sambrisko			mfi_release_command(cm);
1902158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1903158737Sambrisko		}
1904158737Sambrisko
1905158737Sambrisko		return (error);
1906158737Sambrisko	case 0x400c4d03: /* AEN Linux ioctl shim */
1907158737Sambrisko		error = copyin(arg, &l_aen, sizeof(l_aen));
1908158737Sambrisko		if (error != 0)
1909158737Sambrisko			return (error);
1910158737Sambrisko		printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid);
1911158737Sambrisko		mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF,
1912158737Sambrisko		    M_WAITOK);
1913158737Sambrisko		if (mfi_aen_entry != NULL) {
1914158737Sambrisko			mfi_aen_entry->p = curproc;
1915158737Sambrisko			TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry,
1916158737Sambrisko			    aen_link);
1917158737Sambrisko		}
1918158737Sambrisko		error = mfi_aen_register(sc, l_aen.laen_seq_num,
1919158737Sambrisko		    l_aen.laen_class_locale);
1920158737Sambrisko
1921158737Sambrisko		if (error != 0) {
1922158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
1923158737Sambrisko			    aen_link);
1924158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
1925158737Sambrisko		}
1926158737Sambrisko
1927158737Sambrisko		return (error);
1928158737Sambrisko	default:
1929158737Sambrisko		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
1930158737Sambrisko		error = ENOENT;
1931158737Sambrisko		break;
1932158737Sambrisko	}
1933158737Sambrisko
1934158737Sambrisko	return (error);
1935158737Sambrisko}
1936158737Sambrisko
1937158737Sambriskostatic int
1938158737Sambriskomfi_poll(struct cdev *dev, int poll_events, struct thread *td)
1939158737Sambrisko{
1940158737Sambrisko	struct mfi_softc *sc;
1941158737Sambrisko	int revents = 0;
1942158737Sambrisko
1943158737Sambrisko	sc = dev->si_drv1;
1944158737Sambrisko
1945158737Sambrisko	if (poll_events & (POLLIN | POLLRDNORM)) {
1946158737Sambrisko		if (sc->mfi_aen_triggered != 0)
1947158737Sambrisko			revents |= poll_events & (POLLIN | POLLRDNORM);
1948158737Sambrisko		if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) {
1949158737Sambrisko			revents |= POLLERR;
1950158737Sambrisko		}
1951158737Sambrisko	}
1952158737Sambrisko
1953158737Sambrisko	if (revents == 0) {
1954158737Sambrisko		if (poll_events & (POLLIN | POLLRDNORM)) {
1955158737Sambrisko			sc->mfi_poll_waiting = 1;
1956158737Sambrisko			selrecord(td, &sc->mfi_select);
1957158737Sambrisko			sc->mfi_poll_waiting = 0;
1958158737Sambrisko		}
1959158737Sambrisko	}
1960158737Sambrisko
1961158737Sambrisko	return revents;
1962158737Sambrisko}
1963