1/* $OpenBSD: mfi.c,v 1.191 2023/11/28 09:29:20 jsg Exp $ */
2/*
3 * Copyright (c) 2006 Marco Peereboom <marco@peereboom.us>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include "bio.h"
19
20#include <sys/param.h>
21#include <sys/systm.h>
22#include <sys/buf.h>
23#include <sys/device.h>
24#include <sys/kernel.h>
25#include <sys/malloc.h>
26#include <sys/rwlock.h>
27#include <sys/sensors.h>
28#include <sys/dkio.h>
29#include <sys/pool.h>
30
31#include <machine/bus.h>
32
33#include <scsi/scsi_all.h>
34#include <scsi/scsi_disk.h>
35#include <scsi/scsiconf.h>
36
37#include <dev/biovar.h>
38#include <dev/ic/mfireg.h>
39#include <dev/ic/mfivar.h>
40
41#ifdef MFI_DEBUG
42uint32_t	mfi_debug = 0
43/*		    | MFI_D_CMD */
44/*		    | MFI_D_INTR */
45/*		    | MFI_D_MISC */
46/*		    | MFI_D_DMA */
47/*		    | MFI_D_IOCTL */
48/*		    | MFI_D_RW */
49/*		    | MFI_D_MEM */
50/*		    | MFI_D_CCB */
51		;
52#endif
53
54struct cfdriver mfi_cd = {
55	NULL, "mfi", DV_DULL
56};
57
58void	mfi_scsi_cmd(struct scsi_xfer *);
59int	mfi_scsi_ioctl(struct scsi_link *, u_long, caddr_t, int);
60int	mfi_ioctl_cache(struct scsi_link *, u_long,  struct dk_cache *);
61
62void	mfi_pd_scsi_cmd(struct scsi_xfer *);
63int	mfi_pd_scsi_probe(struct scsi_link *);
64
65const struct scsi_adapter mfi_switch = {
66	mfi_scsi_cmd, NULL, NULL, NULL, mfi_scsi_ioctl
67};
68
69const struct scsi_adapter mfi_pd_switch = {
70	mfi_pd_scsi_cmd, NULL, mfi_pd_scsi_probe, NULL, mfi_scsi_ioctl
71};
72
73void *		mfi_get_ccb(void *);
74void		mfi_put_ccb(void *, void *);
75void		mfi_scrub_ccb(struct mfi_ccb *);
76int		mfi_init_ccb(struct mfi_softc *);
77
78struct mfi_mem	*mfi_allocmem(struct mfi_softc *, size_t);
79void		mfi_freemem(struct mfi_softc *, struct mfi_mem *);
80
81int		mfi_transition_firmware(struct mfi_softc *);
82int		mfi_initialize_firmware(struct mfi_softc *);
83int		mfi_get_info(struct mfi_softc *);
84uint32_t	mfi_read(struct mfi_softc *, bus_size_t);
85void		mfi_write(struct mfi_softc *, bus_size_t, uint32_t);
86void		mfi_poll(struct mfi_softc *, struct mfi_ccb *);
87void		mfi_exec(struct mfi_softc *, struct mfi_ccb *);
88void		mfi_exec_done(struct mfi_softc *, struct mfi_ccb *);
89int		mfi_create_sgl(struct mfi_softc *, struct mfi_ccb *, int);
90u_int		mfi_default_sgd_load(struct mfi_softc *, struct mfi_ccb *);
91int		mfi_syspd(struct mfi_softc *);
92
93/* commands */
94int		mfi_scsi_ld(struct mfi_softc *sc, struct mfi_ccb *,
95		    struct scsi_xfer *);
96int		mfi_scsi_io(struct mfi_softc *sc, struct mfi_ccb *,
97		    struct scsi_xfer *, uint64_t, uint32_t);
98void		mfi_scsi_xs_done(struct mfi_softc *sc, struct mfi_ccb *);
99int		mfi_mgmt(struct mfi_softc *, uint32_t, uint32_t, uint32_t,
100		    void *, const union mfi_mbox *);
101int		mfi_do_mgmt(struct mfi_softc *, struct mfi_ccb * , uint32_t,
102		    uint32_t, uint32_t, void *, const union mfi_mbox *);
103void		mfi_empty_done(struct mfi_softc *, struct mfi_ccb *);
104
105#if NBIO > 0
106int		mfi_ioctl(struct device *, u_long, caddr_t);
107int		mfi_bio_getitall(struct mfi_softc *);
108int		mfi_ioctl_inq(struct mfi_softc *, struct bioc_inq *);
109int		mfi_ioctl_vol(struct mfi_softc *, struct bioc_vol *);
110int		mfi_ioctl_disk(struct mfi_softc *, struct bioc_disk *);
111int		mfi_ioctl_alarm(struct mfi_softc *, struct bioc_alarm *);
112int		mfi_ioctl_blink(struct mfi_softc *sc, struct bioc_blink *);
113int		mfi_ioctl_setstate(struct mfi_softc *, struct bioc_setstate *);
114int		mfi_ioctl_patrol(struct mfi_softc *sc, struct bioc_patrol *);
115int		mfi_bio_hs(struct mfi_softc *, int, int, void *);
116#ifndef SMALL_KERNEL
117int		mfi_create_sensors(struct mfi_softc *);
118void		mfi_refresh_sensors(void *);
119int		mfi_bbu(struct mfi_softc *);
120#endif /* SMALL_KERNEL */
121#endif /* NBIO > 0 */
122
123void		mfi_start(struct mfi_softc *, struct mfi_ccb *);
124void		mfi_done(struct mfi_softc *, struct mfi_ccb *);
125u_int32_t	mfi_xscale_fw_state(struct mfi_softc *);
126void		mfi_xscale_intr_ena(struct mfi_softc *);
127int		mfi_xscale_intr(struct mfi_softc *);
128void		mfi_xscale_post(struct mfi_softc *, struct mfi_ccb *);
129
130static const struct mfi_iop_ops mfi_iop_xscale = {
131	mfi_xscale_fw_state,
132	mfi_xscale_intr_ena,
133	mfi_xscale_intr,
134	mfi_xscale_post,
135	mfi_default_sgd_load,
136	0,
137};
138
139u_int32_t	mfi_ppc_fw_state(struct mfi_softc *);
140void		mfi_ppc_intr_ena(struct mfi_softc *);
141int		mfi_ppc_intr(struct mfi_softc *);
142void		mfi_ppc_post(struct mfi_softc *, struct mfi_ccb *);
143
144static const struct mfi_iop_ops mfi_iop_ppc = {
145	mfi_ppc_fw_state,
146	mfi_ppc_intr_ena,
147	mfi_ppc_intr,
148	mfi_ppc_post,
149	mfi_default_sgd_load,
150	MFI_IDB,
151	0
152};
153
154u_int32_t	mfi_gen2_fw_state(struct mfi_softc *);
155void		mfi_gen2_intr_ena(struct mfi_softc *);
156int		mfi_gen2_intr(struct mfi_softc *);
157void		mfi_gen2_post(struct mfi_softc *, struct mfi_ccb *);
158
159static const struct mfi_iop_ops mfi_iop_gen2 = {
160	mfi_gen2_fw_state,
161	mfi_gen2_intr_ena,
162	mfi_gen2_intr,
163	mfi_gen2_post,
164	mfi_default_sgd_load,
165	MFI_IDB,
166	0
167};
168
169u_int32_t	mfi_skinny_fw_state(struct mfi_softc *);
170void		mfi_skinny_intr_ena(struct mfi_softc *);
171int		mfi_skinny_intr(struct mfi_softc *);
172void		mfi_skinny_post(struct mfi_softc *, struct mfi_ccb *);
173u_int		mfi_skinny_sgd_load(struct mfi_softc *, struct mfi_ccb *);
174
175static const struct mfi_iop_ops mfi_iop_skinny = {
176	mfi_skinny_fw_state,
177	mfi_skinny_intr_ena,
178	mfi_skinny_intr,
179	mfi_skinny_post,
180	mfi_skinny_sgd_load,
181	MFI_SKINNY_IDB,
182	MFI_IOP_F_SYSPD
183};
184
185#define mfi_fw_state(_s)	((_s)->sc_iop->mio_fw_state(_s))
186#define mfi_intr_enable(_s)	((_s)->sc_iop->mio_intr_ena(_s))
187#define mfi_my_intr(_s)		((_s)->sc_iop->mio_intr(_s))
188#define mfi_post(_s, _c)	((_s)->sc_iop->mio_post((_s), (_c)))
189#define mfi_sgd_load(_s, _c)	((_s)->sc_iop->mio_sgd_load((_s), (_c)))
190
191void *
192mfi_get_ccb(void *cookie)
193{
194	struct mfi_softc	*sc = cookie;
195	struct mfi_ccb		*ccb;
196
197	KERNEL_UNLOCK();
198
199	mtx_enter(&sc->sc_ccb_mtx);
200	ccb = SLIST_FIRST(&sc->sc_ccb_freeq);
201	if (ccb != NULL) {
202		SLIST_REMOVE_HEAD(&sc->sc_ccb_freeq, ccb_link);
203		ccb->ccb_state = MFI_CCB_READY;
204	}
205	mtx_leave(&sc->sc_ccb_mtx);
206
207	DNPRINTF(MFI_D_CCB, "%s: mfi_get_ccb: %p\n", DEVNAME(sc), ccb);
208	KERNEL_LOCK();
209
210	return (ccb);
211}
212
213void
214mfi_put_ccb(void *cookie, void *io)
215{
216	struct mfi_softc	*sc = cookie;
217	struct mfi_ccb		*ccb = io;
218
219	DNPRINTF(MFI_D_CCB, "%s: mfi_put_ccb: %p\n", DEVNAME(sc), ccb);
220
221	KERNEL_UNLOCK();
222	mtx_enter(&sc->sc_ccb_mtx);
223	SLIST_INSERT_HEAD(&sc->sc_ccb_freeq, ccb, ccb_link);
224	mtx_leave(&sc->sc_ccb_mtx);
225	KERNEL_LOCK();
226}
227
228void
229mfi_scrub_ccb(struct mfi_ccb *ccb)
230{
231	struct mfi_frame_header	*hdr = &ccb->ccb_frame->mfr_header;
232
233	hdr->mfh_cmd_status = 0x0;
234	hdr->mfh_flags = 0x0;
235	ccb->ccb_state = MFI_CCB_FREE;
236	ccb->ccb_cookie = NULL;
237	ccb->ccb_flags = 0;
238	ccb->ccb_done = NULL;
239	ccb->ccb_direction = 0;
240	ccb->ccb_frame_size = 0;
241	ccb->ccb_extra_frames = 0;
242	ccb->ccb_sgl = NULL;
243	ccb->ccb_data = NULL;
244	ccb->ccb_len = 0;
245}
246
247int
248mfi_init_ccb(struct mfi_softc *sc)
249{
250	struct mfi_ccb		*ccb;
251	uint32_t		i;
252	int			error;
253
254	DNPRINTF(MFI_D_CCB, "%s: mfi_init_ccb\n", DEVNAME(sc));
255
256	sc->sc_ccb = mallocarray(sc->sc_max_cmds, sizeof(struct mfi_ccb),
257	    M_DEVBUF, M_WAITOK|M_ZERO);
258
259	for (i = 0; i < sc->sc_max_cmds; i++) {
260		ccb = &sc->sc_ccb[i];
261
262		/* select i'th frame */
263		ccb->ccb_frame = (union mfi_frame *)
264		    (MFIMEM_KVA(sc->sc_frames) + sc->sc_frames_size * i);
265		ccb->ccb_pframe =
266		    MFIMEM_DVA(sc->sc_frames) + sc->sc_frames_size * i;
267		ccb->ccb_pframe_offset = sc->sc_frames_size * i;
268		ccb->ccb_frame->mfr_header.mfh_context = i;
269
270		/* select i'th sense */
271		ccb->ccb_sense = (struct mfi_sense *)
272		    (MFIMEM_KVA(sc->sc_sense) + MFI_SENSE_SIZE * i);
273		ccb->ccb_psense =
274		    (MFIMEM_DVA(sc->sc_sense) + MFI_SENSE_SIZE * i);
275
276		/* create a dma map for transfer */
277		error = bus_dmamap_create(sc->sc_dmat,
278		    MAXPHYS, sc->sc_max_sgl, MAXPHYS, 0,
279		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap);
280		if (error) {
281			printf("%s: cannot create ccb dmamap (%d)\n",
282			    DEVNAME(sc), error);
283			goto destroy;
284		}
285
286		DNPRINTF(MFI_D_CCB,
287		    "ccb(%d): %p frame: %p (%#lx) sense: %p (%#lx) map: %p\n",
288		    ccb->ccb_frame->mfr_header.mfh_context, ccb,
289		    ccb->ccb_frame, ccb->ccb_pframe,
290		    ccb->ccb_sense, ccb->ccb_psense,
291		    ccb->ccb_dmamap);
292
293		/* add ccb to queue */
294		mfi_put_ccb(sc, ccb);
295	}
296
297	return (0);
298destroy:
299	/* free dma maps and ccb memory */
300	while ((ccb = mfi_get_ccb(sc)) != NULL)
301		bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
302
303	free(sc->sc_ccb, M_DEVBUF, 0);
304
305	return (1);
306}
307
308uint32_t
309mfi_read(struct mfi_softc *sc, bus_size_t r)
310{
311	uint32_t rv;
312
313	bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
314	    BUS_SPACE_BARRIER_READ);
315	rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, r);
316
317	DNPRINTF(MFI_D_RW, "%s: mr 0x%lx 0x08%x ", DEVNAME(sc), r, rv);
318	return (rv);
319}
320
321void
322mfi_write(struct mfi_softc *sc, bus_size_t r, uint32_t v)
323{
324	DNPRINTF(MFI_D_RW, "%s: mw 0x%lx 0x%08x", DEVNAME(sc), r, v);
325
326	bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v);
327	bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
328	    BUS_SPACE_BARRIER_WRITE);
329}
330
331struct mfi_mem *
332mfi_allocmem(struct mfi_softc *sc, size_t size)
333{
334	struct mfi_mem		*mm;
335	int			nsegs;
336
337	DNPRINTF(MFI_D_MEM, "%s: mfi_allocmem: %zu\n", DEVNAME(sc),
338	    size);
339
340	mm = malloc(sizeof(struct mfi_mem), M_DEVBUF, M_NOWAIT|M_ZERO);
341	if (mm == NULL)
342		return (NULL);
343
344	mm->am_size = size;
345
346	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
347	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &mm->am_map) != 0)
348		goto amfree;
349
350	if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &mm->am_seg, 1,
351	    &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO) != 0)
352		goto destroy;
353
354	if (bus_dmamem_map(sc->sc_dmat, &mm->am_seg, nsegs, size, &mm->am_kva,
355	    BUS_DMA_NOWAIT) != 0)
356		goto free;
357
358	if (bus_dmamap_load(sc->sc_dmat, mm->am_map, mm->am_kva, size, NULL,
359	    BUS_DMA_NOWAIT) != 0)
360		goto unmap;
361
362	DNPRINTF(MFI_D_MEM, "  kva: %p  dva: %lx  map: %p\n",
363	    mm->am_kva, mm->am_map->dm_segs[0].ds_addr, mm->am_map);
364
365	return (mm);
366
367unmap:
368	bus_dmamem_unmap(sc->sc_dmat, mm->am_kva, size);
369free:
370	bus_dmamem_free(sc->sc_dmat, &mm->am_seg, 1);
371destroy:
372	bus_dmamap_destroy(sc->sc_dmat, mm->am_map);
373amfree:
374	free(mm, M_DEVBUF, sizeof *mm);
375
376	return (NULL);
377}
378
379void
380mfi_freemem(struct mfi_softc *sc, struct mfi_mem *mm)
381{
382	DNPRINTF(MFI_D_MEM, "%s: mfi_freemem: %p\n", DEVNAME(sc), mm);
383
384	bus_dmamap_unload(sc->sc_dmat, mm->am_map);
385	bus_dmamem_unmap(sc->sc_dmat, mm->am_kva, mm->am_size);
386	bus_dmamem_free(sc->sc_dmat, &mm->am_seg, 1);
387	bus_dmamap_destroy(sc->sc_dmat, mm->am_map);
388	free(mm, M_DEVBUF, sizeof *mm);
389}
390
391int
392mfi_transition_firmware(struct mfi_softc *sc)
393{
394	int32_t			fw_state, cur_state;
395	u_int32_t		idb = sc->sc_iop->mio_idb;
396	int			max_wait, i;
397
398	fw_state = mfi_fw_state(sc) & MFI_STATE_MASK;
399
400	DNPRINTF(MFI_D_CMD, "%s: mfi_transition_firmware: %#x\n", DEVNAME(sc),
401	    fw_state);
402
403	while (fw_state != MFI_STATE_READY) {
404		DNPRINTF(MFI_D_MISC,
405		    "%s: waiting for firmware to become ready\n",
406		    DEVNAME(sc));
407		cur_state = fw_state;
408		switch (fw_state) {
409		case MFI_STATE_FAULT:
410			printf("%s: firmware fault\n", DEVNAME(sc));
411			return (1);
412		case MFI_STATE_WAIT_HANDSHAKE:
413			mfi_write(sc, idb, MFI_INIT_CLEAR_HANDSHAKE);
414			max_wait = 2;
415			break;
416		case MFI_STATE_OPERATIONAL:
417			mfi_write(sc, idb, MFI_INIT_READY);
418			max_wait = 10;
419			break;
420		case MFI_STATE_UNDEFINED:
421		case MFI_STATE_BB_INIT:
422			max_wait = 2;
423			break;
424		case MFI_STATE_FW_INIT:
425		case MFI_STATE_DEVICE_SCAN:
426		case MFI_STATE_FLUSH_CACHE:
427			max_wait = 20;
428			break;
429		default:
430			printf("%s: unknown firmware state %d\n",
431			    DEVNAME(sc), fw_state);
432			return (1);
433		}
434		for (i = 0; i < (max_wait * 10); i++) {
435			fw_state = mfi_fw_state(sc) & MFI_STATE_MASK;
436			if (fw_state == cur_state)
437				DELAY(100000);
438			else
439				break;
440		}
441		if (fw_state == cur_state) {
442			printf("%s: firmware stuck in state %#x\n",
443			    DEVNAME(sc), fw_state);
444			return (1);
445		}
446	}
447
448	return (0);
449}
450
451int
452mfi_initialize_firmware(struct mfi_softc *sc)
453{
454	struct mfi_ccb		*ccb;
455	struct mfi_init_frame	*init;
456	struct mfi_init_qinfo	*qinfo;
457	int			rv = 0;
458
459	DNPRINTF(MFI_D_MISC, "%s: mfi_initialize_firmware\n", DEVNAME(sc));
460
461	ccb = scsi_io_get(&sc->sc_iopool, 0);
462	mfi_scrub_ccb(ccb);
463
464	init = &ccb->ccb_frame->mfr_init;
465	qinfo = (struct mfi_init_qinfo *)((uint8_t *)init + MFI_FRAME_SIZE);
466
467	memset(qinfo, 0, sizeof(*qinfo));
468	qinfo->miq_rq_entries = htole32(sc->sc_max_cmds + 1);
469
470	qinfo->miq_rq_addr = htole64(MFIMEM_DVA(sc->sc_pcq) +
471	    offsetof(struct mfi_prod_cons, mpc_reply_q));
472
473	qinfo->miq_pi_addr = htole64(MFIMEM_DVA(sc->sc_pcq) +
474	    offsetof(struct mfi_prod_cons, mpc_producer));
475
476	qinfo->miq_ci_addr = htole64(MFIMEM_DVA(sc->sc_pcq) +
477	    offsetof(struct mfi_prod_cons, mpc_consumer));
478
479	init->mif_header.mfh_cmd = MFI_CMD_INIT;
480	init->mif_header.mfh_data_len = htole32(sizeof(*qinfo));
481	init->mif_qinfo_new_addr = htole64(ccb->ccb_pframe + MFI_FRAME_SIZE);
482
483	bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_pcq),
484	    0, MFIMEM_LEN(sc->sc_pcq),
485	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
486
487	ccb->ccb_done = mfi_empty_done;
488	mfi_poll(sc, ccb);
489	if (init->mif_header.mfh_cmd_status != MFI_STAT_OK)
490		rv = 1;
491
492	mfi_put_ccb(sc, ccb);
493
494	return (rv);
495}
496
497void
498mfi_empty_done(struct mfi_softc *sc, struct mfi_ccb *ccb)
499{
500	/* nop */
501}
502
503int
504mfi_get_info(struct mfi_softc *sc)
505{
506#ifdef MFI_DEBUG
507	int i;
508#endif
509	DNPRINTF(MFI_D_MISC, "%s: mfi_get_info\n", DEVNAME(sc));
510
511	if (mfi_mgmt(sc, MR_DCMD_CTRL_GET_INFO, MFI_DATA_IN,
512	    sizeof(sc->sc_info), &sc->sc_info, NULL))
513		return (1);
514
515#ifdef MFI_DEBUG
516	for (i = 0; i < sc->sc_info.mci_image_component_count; i++) {
517		printf("%s: active FW %s Version %s date %s time %s\n",
518		    DEVNAME(sc),
519		    sc->sc_info.mci_image_component[i].mic_name,
520		    sc->sc_info.mci_image_component[i].mic_version,
521		    sc->sc_info.mci_image_component[i].mic_build_date,
522		    sc->sc_info.mci_image_component[i].mic_build_time);
523	}
524
525	for (i = 0; i < sc->sc_info.mci_pending_image_component_count; i++) {
526		printf("%s: pending FW %s Version %s date %s time %s\n",
527		    DEVNAME(sc),
528		    sc->sc_info.mci_pending_image_component[i].mic_name,
529		    sc->sc_info.mci_pending_image_component[i].mic_version,
530		    sc->sc_info.mci_pending_image_component[i].mic_build_date,
531		    sc->sc_info.mci_pending_image_component[i].mic_build_time);
532	}
533
534	printf("%s: max_arms %d max_spans %d max_arrs %d max_lds %d name %s\n",
535	    DEVNAME(sc),
536	    sc->sc_info.mci_max_arms,
537	    sc->sc_info.mci_max_spans,
538	    sc->sc_info.mci_max_arrays,
539	    sc->sc_info.mci_max_lds,
540	    sc->sc_info.mci_product_name);
541
542	printf("%s: serial %s present %#x fw time %d max_cmds %d max_sg %d\n",
543	    DEVNAME(sc),
544	    sc->sc_info.mci_serial_number,
545	    sc->sc_info.mci_hw_present,
546	    sc->sc_info.mci_current_fw_time,
547	    sc->sc_info.mci_max_cmds,
548	    sc->sc_info.mci_max_sg_elements);
549
550	printf("%s: max_rq %d lds_pres %d lds_deg %d lds_off %d pd_pres %d\n",
551	    DEVNAME(sc),
552	    sc->sc_info.mci_max_request_size,
553	    sc->sc_info.mci_lds_present,
554	    sc->sc_info.mci_lds_degraded,
555	    sc->sc_info.mci_lds_offline,
556	    sc->sc_info.mci_pd_present);
557
558	printf("%s: pd_dsk_prs %d pd_dsk_pred_fail %d pd_dsk_fail %d\n",
559	    DEVNAME(sc),
560	    sc->sc_info.mci_pd_disks_present,
561	    sc->sc_info.mci_pd_disks_pred_failure,
562	    sc->sc_info.mci_pd_disks_failed);
563
564	printf("%s: nvram %d mem %d flash %d\n",
565	    DEVNAME(sc),
566	    sc->sc_info.mci_nvram_size,
567	    sc->sc_info.mci_memory_size,
568	    sc->sc_info.mci_flash_size);
569
570	printf("%s: ram_cor %d ram_uncor %d clus_all %d clus_act %d\n",
571	    DEVNAME(sc),
572	    sc->sc_info.mci_ram_correctable_errors,
573	    sc->sc_info.mci_ram_uncorrectable_errors,
574	    sc->sc_info.mci_cluster_allowed,
575	    sc->sc_info.mci_cluster_active);
576
577	printf("%s: max_strps_io %d raid_lvl %#x adapt_ops %#x ld_ops %#x\n",
578	    DEVNAME(sc),
579	    sc->sc_info.mci_max_strips_per_io,
580	    sc->sc_info.mci_raid_levels,
581	    sc->sc_info.mci_adapter_ops,
582	    sc->sc_info.mci_ld_ops);
583
584	printf("%s: strp_sz_min %d strp_sz_max %d pd_ops %#x pd_mix %#x\n",
585	    DEVNAME(sc),
586	    sc->sc_info.mci_stripe_sz_ops.min,
587	    sc->sc_info.mci_stripe_sz_ops.max,
588	    sc->sc_info.mci_pd_ops,
589	    sc->sc_info.mci_pd_mix_support);
590
591	printf("%s: ecc_bucket %d pckg_prop %s\n",
592	    DEVNAME(sc),
593	    sc->sc_info.mci_ecc_bucket_count,
594	    sc->sc_info.mci_package_version);
595
596	printf("%s: sq_nm %d prd_fail_poll %d intr_thrtl %d intr_thrtl_to %d\n",
597	    DEVNAME(sc),
598	    sc->sc_info.mci_properties.mcp_seq_num,
599	    sc->sc_info.mci_properties.mcp_pred_fail_poll_interval,
600	    sc->sc_info.mci_properties.mcp_intr_throttle_cnt,
601	    sc->sc_info.mci_properties.mcp_intr_throttle_timeout);
602
603	printf("%s: rbld_rate %d patr_rd_rate %d bgi_rate %d cc_rate %d\n",
604	    DEVNAME(sc),
605	    sc->sc_info.mci_properties.mcp_rebuild_rate,
606	    sc->sc_info.mci_properties.mcp_patrol_read_rate,
607	    sc->sc_info.mci_properties.mcp_bgi_rate,
608	    sc->sc_info.mci_properties.mcp_cc_rate);
609
610	printf("%s: rc_rate %d ch_flsh %d spin_cnt %d spin_dly %d clus_en %d\n",
611	    DEVNAME(sc),
612	    sc->sc_info.mci_properties.mcp_recon_rate,
613	    sc->sc_info.mci_properties.mcp_cache_flush_interval,
614	    sc->sc_info.mci_properties.mcp_spinup_drv_cnt,
615	    sc->sc_info.mci_properties.mcp_spinup_delay,
616	    sc->sc_info.mci_properties.mcp_cluster_enable);
617
618	printf("%s: coerc %d alarm %d dis_auto_rbld %d dis_bat_wrn %d ecc %d\n",
619	    DEVNAME(sc),
620	    sc->sc_info.mci_properties.mcp_coercion_mode,
621	    sc->sc_info.mci_properties.mcp_alarm_enable,
622	    sc->sc_info.mci_properties.mcp_disable_auto_rebuild,
623	    sc->sc_info.mci_properties.mcp_disable_battery_warn,
624	    sc->sc_info.mci_properties.mcp_ecc_bucket_size);
625
626	printf("%s: ecc_leak %d rest_hs %d exp_encl_dev %d\n",
627	    DEVNAME(sc),
628	    sc->sc_info.mci_properties.mcp_ecc_bucket_leak_rate,
629	    sc->sc_info.mci_properties.mcp_restore_hotspare_on_insertion,
630	    sc->sc_info.mci_properties.mcp_expose_encl_devices);
631
632	printf("%s: vendor %#x device %#x subvendor %#x subdevice %#x\n",
633	    DEVNAME(sc),
634	    sc->sc_info.mci_pci.mip_vendor,
635	    sc->sc_info.mci_pci.mip_device,
636	    sc->sc_info.mci_pci.mip_subvendor,
637	    sc->sc_info.mci_pci.mip_subdevice);
638
639	printf("%s: type %#x port_count %d port_addr ",
640	    DEVNAME(sc),
641	    sc->sc_info.mci_host.mih_type,
642	    sc->sc_info.mci_host.mih_port_count);
643
644	for (i = 0; i < 8; i++)
645		printf("%.0llx ", sc->sc_info.mci_host.mih_port_addr[i]);
646	printf("\n");
647
648	printf("%s: type %.x port_count %d port_addr ",
649	    DEVNAME(sc),
650	    sc->sc_info.mci_device.mid_type,
651	    sc->sc_info.mci_device.mid_port_count);
652
653	for (i = 0; i < 8; i++)
654		printf("%.0llx ", sc->sc_info.mci_device.mid_port_addr[i]);
655	printf("\n");
656#endif /* MFI_DEBUG */
657
658	return (0);
659}
660
661int
662mfi_attach(struct mfi_softc *sc, enum mfi_iop iop)
663{
664	struct scsibus_attach_args saa;
665	uint32_t		status, frames, max_sgl;
666	int			i;
667
668	switch (iop) {
669	case MFI_IOP_XSCALE:
670		sc->sc_iop = &mfi_iop_xscale;
671		break;
672	case MFI_IOP_PPC:
673		sc->sc_iop = &mfi_iop_ppc;
674		break;
675	case MFI_IOP_GEN2:
676		sc->sc_iop = &mfi_iop_gen2;
677		break;
678	case MFI_IOP_SKINNY:
679		sc->sc_iop = &mfi_iop_skinny;
680		break;
681	default:
682		panic("%s: unknown iop %d", DEVNAME(sc), iop);
683	}
684
685	DNPRINTF(MFI_D_MISC, "%s: mfi_attach\n", DEVNAME(sc));
686
687	if (mfi_transition_firmware(sc))
688		return (1);
689
690	SLIST_INIT(&sc->sc_ccb_freeq);
691	mtx_init(&sc->sc_ccb_mtx, IPL_BIO);
692	scsi_iopool_init(&sc->sc_iopool, sc, mfi_get_ccb, mfi_put_ccb);
693
694	rw_init(&sc->sc_lock, "mfi_lock");
695
696	status = mfi_fw_state(sc);
697	sc->sc_max_cmds = status & MFI_STATE_MAXCMD_MASK;
698	max_sgl = (status & MFI_STATE_MAXSGL_MASK) >> 16;
699	if (sc->sc_64bit_dma) {
700		sc->sc_max_sgl = min(max_sgl, (128 * 1024) / PAGE_SIZE + 1);
701		sc->sc_sgl_size = sizeof(struct mfi_sg64);
702		sc->sc_sgl_flags = MFI_FRAME_SGL64;
703	} else {
704		sc->sc_max_sgl = max_sgl;
705		sc->sc_sgl_size = sizeof(struct mfi_sg32);
706		sc->sc_sgl_flags = MFI_FRAME_SGL32;
707	}
708	if (iop == MFI_IOP_SKINNY)
709		sc->sc_sgl_size = sizeof(struct mfi_sg_skinny);
710	DNPRINTF(MFI_D_MISC, "%s: 64bit: %d max commands: %u, max sgl: %u\n",
711	    DEVNAME(sc), sc->sc_64bit_dma, sc->sc_max_cmds, sc->sc_max_sgl);
712
713	/* consumer/producer and reply queue memory */
714	sc->sc_pcq = mfi_allocmem(sc, (sizeof(uint32_t) * sc->sc_max_cmds) +
715	    sizeof(struct mfi_prod_cons));
716	if (sc->sc_pcq == NULL) {
717		printf("%s: unable to allocate reply queue memory\n",
718		    DEVNAME(sc));
719		goto nopcq;
720	}
721
722	/* frame memory */
723	/* we are not doing 64 bit IO so only calculate # of 32 bit frames */
724	frames = (sc->sc_sgl_size * sc->sc_max_sgl + MFI_FRAME_SIZE - 1) /
725	    MFI_FRAME_SIZE + 1;
726	sc->sc_frames_size = frames * MFI_FRAME_SIZE;
727	sc->sc_frames = mfi_allocmem(sc, sc->sc_frames_size * sc->sc_max_cmds);
728	if (sc->sc_frames == NULL) {
729		printf("%s: unable to allocate frame memory\n", DEVNAME(sc));
730		goto noframe;
731	}
732	/* XXX hack, fix this */
733	if (MFIMEM_DVA(sc->sc_frames) & 0x3f) {
734		printf("%s: improper frame alignment (%#lx) FIXME\n",
735		    DEVNAME(sc), MFIMEM_DVA(sc->sc_frames));
736		goto noframe;
737	}
738
739	/* sense memory */
740	sc->sc_sense = mfi_allocmem(sc, sc->sc_max_cmds * MFI_SENSE_SIZE);
741	if (sc->sc_sense == NULL) {
742		printf("%s: unable to allocate sense memory\n", DEVNAME(sc));
743		goto nosense;
744	}
745
746	/* now that we have all memory bits go initialize ccbs */
747	if (mfi_init_ccb(sc)) {
748		printf("%s: could not init ccb list\n", DEVNAME(sc));
749		goto noinit;
750	}
751
752	/* kickstart firmware with all addresses and pointers */
753	if (mfi_initialize_firmware(sc)) {
754		printf("%s: could not initialize firmware\n", DEVNAME(sc));
755		goto noinit;
756	}
757
758	if (mfi_get_info(sc)) {
759		printf("%s: could not retrieve controller information\n",
760		    DEVNAME(sc));
761		goto noinit;
762	}
763
764	printf("%s: \"%s\", firmware %s", DEVNAME(sc),
765	    sc->sc_info.mci_product_name, sc->sc_info.mci_package_version);
766	if (letoh16(sc->sc_info.mci_memory_size) > 0)
767		printf(", %uMB cache", letoh16(sc->sc_info.mci_memory_size));
768	printf("\n");
769
770	sc->sc_ld_cnt = sc->sc_info.mci_lds_present;
771	for (i = 0; i < sc->sc_ld_cnt; i++)
772		sc->sc_ld[i].ld_present = 1;
773
774	saa.saa_adapter = &mfi_switch;
775	saa.saa_adapter_softc = sc;
776	saa.saa_adapter_buswidth = sc->sc_info.mci_max_lds;
777	saa.saa_adapter_target = SDEV_NO_ADAPTER_TARGET;
778	saa.saa_luns = 1;
779	saa.saa_openings = sc->sc_max_cmds - 1;
780	saa.saa_pool = &sc->sc_iopool;
781	saa.saa_quirks = saa.saa_flags = 0;
782	saa.saa_wwpn = saa.saa_wwnn = 0;
783
784	sc->sc_scsibus = (struct scsibus_softc *)
785	    config_found(&sc->sc_dev, &saa, scsiprint);
786
787	if (ISSET(sc->sc_iop->mio_flags, MFI_IOP_F_SYSPD))
788		mfi_syspd(sc);
789
790	/* enable interrupts */
791	mfi_intr_enable(sc);
792
793#if NBIO > 0
794	if (bio_register(&sc->sc_dev, mfi_ioctl) != 0)
795		panic("%s: controller registration failed", DEVNAME(sc));
796	else
797		sc->sc_ioctl = mfi_ioctl;
798
799#ifndef SMALL_KERNEL
800	if (mfi_create_sensors(sc) != 0)
801		printf("%s: unable to create sensors\n", DEVNAME(sc));
802#endif
803#endif /* NBIO > 0 */
804
805	return (0);
806noinit:
807	mfi_freemem(sc, sc->sc_sense);
808nosense:
809	mfi_freemem(sc, sc->sc_frames);
810noframe:
811	mfi_freemem(sc, sc->sc_pcq);
812nopcq:
813	return (1);
814}
815
816int
817mfi_syspd(struct mfi_softc *sc)
818{
819	struct scsibus_attach_args saa;
820	struct mfi_pd_link *pl;
821	struct mfi_pd_list *pd;
822	u_int npds, i;
823
824	sc->sc_pd = malloc(sizeof(*sc->sc_pd), M_DEVBUF, M_WAITOK|M_ZERO);
825	if (sc->sc_pd == NULL)
826		return (1);
827
828	pd = malloc(sizeof(*pd), M_TEMP, M_WAITOK|M_ZERO);
829	if (pd == NULL)
830		goto nopdsc;
831
832	if (mfi_mgmt(sc, MR_DCMD_PD_GET_LIST, MFI_DATA_IN,
833	    sizeof(*pd), pd, NULL) != 0)
834		goto nopd;
835
836	npds = letoh32(pd->mpl_no_pd);
837	for (i = 0; i < npds; i++) {
838		pl = malloc(sizeof(*pl), M_DEVBUF, M_WAITOK|M_ZERO);
839		if (pl == NULL)
840			goto nopl;
841
842		pl->pd_id = pd->mpl_address[i].mpa_pd_id;
843		sc->sc_pd->pd_links[i] = pl;
844	}
845
846	free(pd, M_TEMP, sizeof *pd);
847
848	saa.saa_adapter = &mfi_pd_switch;
849	saa.saa_adapter_softc = sc;
850	saa.saa_adapter_buswidth = MFI_MAX_PD;
851	saa.saa_adapter_target = SDEV_NO_ADAPTER_TARGET;
852	saa.saa_luns = 8;
853	saa.saa_openings = sc->sc_max_cmds - 1;
854	saa.saa_pool = &sc->sc_iopool;
855	saa.saa_quirks = saa.saa_flags = 0;
856	saa.saa_wwpn = saa.saa_wwnn = 0;
857
858	sc->sc_pd->pd_scsibus = (struct scsibus_softc *)
859	    config_found(&sc->sc_dev, &saa, scsiprint);
860
861	return (0);
862nopl:
863	for (i = 0; i < npds; i++) {
864		pl = sc->sc_pd->pd_links[i];
865		if (pl == NULL)
866			break;
867
868		free(pl, M_DEVBUF, sizeof *pl);
869	}
870nopd:
871	free(pd, M_TEMP, sizeof *pd);
872nopdsc:
873	free(sc->sc_pd, M_DEVBUF, sizeof *sc->sc_pd);
874	return (1);
875}
876
877void
878mfi_poll(struct mfi_softc *sc, struct mfi_ccb *ccb)
879{
880	struct mfi_frame_header *hdr;
881	int to = 0;
882
883	DNPRINTF(MFI_D_CMD, "%s: mfi_poll\n", DEVNAME(sc));
884
885	hdr = &ccb->ccb_frame->mfr_header;
886	hdr->mfh_cmd_status = 0xff;
887	hdr->mfh_flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
888
889	mfi_start(sc, ccb);
890
891	for (;;) {
892		delay(1000);
893
894		bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_frames),
895		    ccb->ccb_pframe_offset, sc->sc_frames_size,
896		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
897
898		if (hdr->mfh_cmd_status != 0xff)
899			break;
900
901		if (to++ > 5000) {
902			printf("%s: timeout on ccb %d\n", DEVNAME(sc),
903			    hdr->mfh_context);
904			ccb->ccb_flags |= MFI_CCB_F_ERR;
905			break;
906		}
907
908		bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_frames),
909		    ccb->ccb_pframe_offset, sc->sc_frames_size,
910		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
911	}
912
913	if (ccb->ccb_len > 0) {
914		bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
915		    ccb->ccb_dmamap->dm_mapsize,
916		    (ccb->ccb_direction & MFI_DATA_IN) ?
917		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
918
919		bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
920	}
921
922	ccb->ccb_done(sc, ccb);
923}
924
925void
926mfi_exec(struct mfi_softc *sc, struct mfi_ccb *ccb)
927{
928	struct mutex m;
929
930	mtx_init(&m, IPL_BIO);
931
932#ifdef DIAGNOSTIC
933	if (ccb->ccb_cookie != NULL || ccb->ccb_done != NULL)
934		panic("mfi_exec called with cookie or done set");
935#endif
936
937	ccb->ccb_cookie = &m;
938	ccb->ccb_done = mfi_exec_done;
939
940	mfi_start(sc, ccb);
941
942	mtx_enter(&m);
943	while (ccb->ccb_cookie != NULL)
944		msleep_nsec(ccb, &m, PRIBIO, "mfiexec", INFSLP);
945	mtx_leave(&m);
946}
947
948void
949mfi_exec_done(struct mfi_softc *sc, struct mfi_ccb *ccb)
950{
951	struct mutex *m = ccb->ccb_cookie;
952
953	mtx_enter(m);
954	ccb->ccb_cookie = NULL;
955	wakeup_one(ccb);
956	mtx_leave(m);
957}
958
959int
960mfi_intr(void *arg)
961{
962	struct mfi_softc	*sc = arg;
963	struct mfi_prod_cons	*pcq = MFIMEM_KVA(sc->sc_pcq);
964	struct mfi_ccb		*ccb;
965	uint32_t		producer, consumer, ctx;
966	int			claimed = 0;
967
968	if (!mfi_my_intr(sc))
969		return (0);
970
971	bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_pcq),
972	    0, MFIMEM_LEN(sc->sc_pcq),
973	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
974
975	producer = letoh32(pcq->mpc_producer);
976	consumer = letoh32(pcq->mpc_consumer);
977
978	DNPRINTF(MFI_D_INTR, "%s: mfi_intr %p %p\n", DEVNAME(sc), sc, pcq);
979
980	while (consumer != producer) {
981		DNPRINTF(MFI_D_INTR, "%s: mfi_intr pi %#x ci %#x\n",
982		    DEVNAME(sc), producer, consumer);
983
984		ctx = pcq->mpc_reply_q[consumer];
985		pcq->mpc_reply_q[consumer] = MFI_INVALID_CTX;
986		if (ctx == MFI_INVALID_CTX)
987			printf("%s: invalid context, p: %d c: %d\n",
988			    DEVNAME(sc), producer, consumer);
989		else {
990			/* XXX remove from queue and call scsi_done */
991			ccb = &sc->sc_ccb[ctx];
992			DNPRINTF(MFI_D_INTR, "%s: mfi_intr context %#x\n",
993			    DEVNAME(sc), ctx);
994			mfi_done(sc, ccb);
995
996			claimed = 1;
997		}
998		consumer++;
999		if (consumer == (sc->sc_max_cmds + 1))
1000			consumer = 0;
1001	}
1002
1003	pcq->mpc_consumer = htole32(consumer);
1004
1005	bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_pcq),
1006	    0, MFIMEM_LEN(sc->sc_pcq),
1007	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1008
1009	return (claimed);
1010}
1011
1012int
1013mfi_scsi_io(struct mfi_softc *sc, struct mfi_ccb *ccb,
1014    struct scsi_xfer *xs, uint64_t blockno, uint32_t blockcnt)
1015{
1016	struct scsi_link	*link = xs->sc_link;
1017	struct mfi_io_frame	*io;
1018
1019	DNPRINTF(MFI_D_CMD, "%s: mfi_scsi_io: %d\n",
1020	    DEVNAME((struct mfi_softc *)link->bus->sb_adapter_softc), link->target);
1021
1022	if (!xs->data)
1023		return (1);
1024
1025	io = &ccb->ccb_frame->mfr_io;
1026	if (xs->flags & SCSI_DATA_IN) {
1027		io->mif_header.mfh_cmd = MFI_CMD_LD_READ;
1028		ccb->ccb_direction = MFI_DATA_IN;
1029	} else {
1030		io->mif_header.mfh_cmd = MFI_CMD_LD_WRITE;
1031		ccb->ccb_direction = MFI_DATA_OUT;
1032	}
1033	io->mif_header.mfh_target_id = link->target;
1034	io->mif_header.mfh_timeout = 0;
1035	io->mif_header.mfh_flags = 0;
1036	io->mif_header.mfh_sense_len = MFI_SENSE_SIZE;
1037	io->mif_header.mfh_data_len = htole32(blockcnt);
1038	io->mif_lba = htole64(blockno);
1039	io->mif_sense_addr = htole64(ccb->ccb_psense);
1040
1041	ccb->ccb_done = mfi_scsi_xs_done;
1042	ccb->ccb_cookie = xs;
1043	ccb->ccb_frame_size = MFI_IO_FRAME_SIZE;
1044	ccb->ccb_sgl = &io->mif_sgl;
1045	ccb->ccb_data = xs->data;
1046	ccb->ccb_len = xs->datalen;
1047
1048	if (mfi_create_sgl(sc, ccb, (xs->flags & SCSI_NOSLEEP) ?
1049	    BUS_DMA_NOWAIT : BUS_DMA_WAITOK))
1050		return (1);
1051
1052	return (0);
1053}
1054
1055void
1056mfi_scsi_xs_done(struct mfi_softc *sc, struct mfi_ccb *ccb)
1057{
1058	struct scsi_xfer	*xs = ccb->ccb_cookie;
1059	struct mfi_frame_header	*hdr = &ccb->ccb_frame->mfr_header;
1060
1061	DNPRINTF(MFI_D_INTR, "%s: mfi_scsi_xs_done %p %p\n",
1062	    DEVNAME(sc), ccb, ccb->ccb_frame);
1063
1064	switch (hdr->mfh_cmd_status) {
1065	case MFI_STAT_OK:
1066		xs->resid = 0;
1067		break;
1068
1069	case MFI_STAT_SCSI_DONE_WITH_ERROR:
1070		xs->error = XS_SENSE;
1071		xs->resid = 0;
1072		memset(&xs->sense, 0, sizeof(xs->sense));
1073		memcpy(&xs->sense, ccb->ccb_sense, sizeof(xs->sense));
1074		break;
1075
1076	case MFI_STAT_DEVICE_NOT_FOUND:
1077		xs->error = XS_SELTIMEOUT;
1078		break;
1079
1080	default:
1081		xs->error = XS_DRIVER_STUFFUP;
1082		DNPRINTF(MFI_D_CMD,
1083		    "%s: mfi_scsi_xs_done stuffup %02x on %02x\n",
1084		    DEVNAME(sc), hdr->mfh_cmd_status, xs->cmd.opcode);
1085
1086		if (hdr->mfh_scsi_status != 0) {
1087			DNPRINTF(MFI_D_INTR,
1088			    "%s: mfi_scsi_xs_done sense %#x %p %p\n",
1089			    DEVNAME(sc), hdr->mfh_scsi_status,
1090			    &xs->sense, ccb->ccb_sense);
1091			memset(&xs->sense, 0, sizeof(xs->sense));
1092			memcpy(&xs->sense, ccb->ccb_sense,
1093			    sizeof(struct scsi_sense_data));
1094			xs->error = XS_SENSE;
1095		}
1096		break;
1097	}
1098
1099	KERNEL_LOCK();
1100	scsi_done(xs);
1101	KERNEL_UNLOCK();
1102}
1103
1104int
1105mfi_scsi_ld(struct mfi_softc *sc, struct mfi_ccb *ccb, struct scsi_xfer *xs)
1106{
1107	struct scsi_link	*link = xs->sc_link;
1108	struct mfi_pass_frame	*pf;
1109
1110	DNPRINTF(MFI_D_CMD, "%s: mfi_scsi_ld: %d\n",
1111	    DEVNAME((struct mfi_softc *)link->bus->sb_adapter_softc), link->target);
1112
1113	pf = &ccb->ccb_frame->mfr_pass;
1114	pf->mpf_header.mfh_cmd = MFI_CMD_LD_SCSI_IO;
1115	pf->mpf_header.mfh_target_id = link->target;
1116	pf->mpf_header.mfh_lun_id = 0;
1117	pf->mpf_header.mfh_cdb_len = xs->cmdlen;
1118	pf->mpf_header.mfh_timeout = 0;
1119	pf->mpf_header.mfh_data_len = htole32(xs->datalen); /* XXX */
1120	pf->mpf_header.mfh_sense_len = MFI_SENSE_SIZE;
1121
1122	pf->mpf_sense_addr = htole64(ccb->ccb_psense);
1123
1124	memset(pf->mpf_cdb, 0, 16);
1125	memcpy(pf->mpf_cdb, &xs->cmd, xs->cmdlen);
1126
1127	ccb->ccb_done = mfi_scsi_xs_done;
1128	ccb->ccb_cookie = xs;
1129	ccb->ccb_frame_size = MFI_PASS_FRAME_SIZE;
1130	ccb->ccb_sgl = &pf->mpf_sgl;
1131
1132	if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT))
1133		ccb->ccb_direction = xs->flags & SCSI_DATA_IN ?
1134		    MFI_DATA_IN : MFI_DATA_OUT;
1135	else
1136		ccb->ccb_direction = MFI_DATA_NONE;
1137
1138	if (xs->data) {
1139		ccb->ccb_data = xs->data;
1140		ccb->ccb_len = xs->datalen;
1141
1142		if (mfi_create_sgl(sc, ccb, (xs->flags & SCSI_NOSLEEP) ?
1143		    BUS_DMA_NOWAIT : BUS_DMA_WAITOK))
1144			return (1);
1145	}
1146
1147	return (0);
1148}
1149
1150void
1151mfi_scsi_cmd(struct scsi_xfer *xs)
1152{
1153	struct scsi_link	*link = xs->sc_link;
1154	struct mfi_softc	*sc = link->bus->sb_adapter_softc;
1155	struct mfi_ccb		*ccb = xs->io;
1156	struct scsi_rw		*rw;
1157	struct scsi_rw_10	*rw10;
1158	struct scsi_rw_16	*rw16;
1159	uint64_t		blockno;
1160	uint32_t		blockcnt;
1161	uint8_t			target = link->target;
1162	union mfi_mbox		mbox;
1163
1164	DNPRINTF(MFI_D_CMD, "%s: mfi_scsi_cmd opcode: %#x\n",
1165	    DEVNAME(sc), xs->cmd.opcode);
1166
1167	KERNEL_UNLOCK();
1168
1169	if (!sc->sc_ld[target].ld_present) {
1170		DNPRINTF(MFI_D_CMD, "%s: invalid target %d\n",
1171		    DEVNAME(sc), target);
1172		goto stuffup;
1173	}
1174
1175	mfi_scrub_ccb(ccb);
1176
1177	xs->error = XS_NOERROR;
1178
1179	switch (xs->cmd.opcode) {
1180	/* IO path */
1181	case READ_10:
1182	case WRITE_10:
1183		rw10 = (struct scsi_rw_10 *)&xs->cmd;
1184		blockno = (uint64_t)_4btol(rw10->addr);
1185		blockcnt = _2btol(rw10->length);
1186		if (mfi_scsi_io(sc, ccb, xs, blockno, blockcnt))
1187			goto stuffup;
1188		break;
1189
1190	case READ_COMMAND:
1191	case WRITE_COMMAND:
1192		rw = (struct scsi_rw *)&xs->cmd;
1193		blockno =
1194		    (uint64_t)(_3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff));
1195		blockcnt = rw->length ? rw->length : 0x100;
1196		if (mfi_scsi_io(sc, ccb, xs, blockno, blockcnt))
1197			goto stuffup;
1198		break;
1199
1200	case READ_16:
1201	case WRITE_16:
1202		rw16 = (struct scsi_rw_16 *)&xs->cmd;
1203		blockno = _8btol(rw16->addr);
1204		blockcnt = _4btol(rw16->length);
1205		if (mfi_scsi_io(sc, ccb, xs, blockno, blockcnt))
1206			goto stuffup;
1207		break;
1208
1209	case SYNCHRONIZE_CACHE:
1210		mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
1211		if (mfi_do_mgmt(sc, ccb, MR_DCMD_CTRL_CACHE_FLUSH,
1212		    MFI_DATA_NONE, 0, NULL, &mbox))
1213			goto stuffup;
1214
1215		goto complete;
1216		/* NOTREACHED */
1217
1218	default:
1219		if (mfi_scsi_ld(sc, ccb, xs))
1220			goto stuffup;
1221		break;
1222	}
1223
1224	DNPRINTF(MFI_D_CMD, "%s: start io %d\n", DEVNAME(sc), target);
1225
1226	if (xs->flags & SCSI_POLL)
1227		mfi_poll(sc, ccb);
1228	else
1229		mfi_start(sc, ccb);
1230
1231	KERNEL_LOCK();
1232	return;
1233
1234stuffup:
1235	xs->error = XS_DRIVER_STUFFUP;
1236complete:
1237	KERNEL_LOCK();
1238	scsi_done(xs);
1239}
1240
1241u_int
1242mfi_default_sgd_load(struct mfi_softc *sc, struct mfi_ccb *ccb)
1243{
1244	struct mfi_frame_header	*hdr = &ccb->ccb_frame->mfr_header;
1245	union mfi_sgl		*sgl = ccb->ccb_sgl;
1246	bus_dma_segment_t	*sgd = ccb->ccb_dmamap->dm_segs;
1247	int			 i;
1248
1249	hdr->mfh_flags |= sc->sc_sgl_flags;
1250
1251	for (i = 0; i < ccb->ccb_dmamap->dm_nsegs; i++) {
1252		if (sc->sc_64bit_dma) {
1253			sgl->sg64[i].addr = htole64(sgd[i].ds_addr);
1254			sgl->sg64[i].len = htole32(sgd[i].ds_len);
1255			DNPRINTF(MFI_D_DMA, "%s: addr: %#llx  len: %#x\n",
1256			    DEVNAME(sc), sgl->sg64[i].addr, sgl->sg64[i].len);
1257		} else {
1258			sgl->sg32[i].addr = htole32(sgd[i].ds_addr);
1259			sgl->sg32[i].len = htole32(sgd[i].ds_len);
1260			DNPRINTF(MFI_D_DMA, "%s: addr: %#x  len: %#x\n",
1261			    DEVNAME(sc), sgl->sg32[i].addr, sgl->sg32[i].len);
1262		}
1263	}
1264
1265	return (ccb->ccb_dmamap->dm_nsegs *
1266	    (sc->sc_64bit_dma ? sizeof(sgl->sg64) : sizeof(sgl->sg32)));
1267}
1268
1269int
1270mfi_create_sgl(struct mfi_softc *sc, struct mfi_ccb *ccb, int flags)
1271{
1272	struct mfi_frame_header	*hdr = &ccb->ccb_frame->mfr_header;
1273	int			error;
1274
1275	DNPRINTF(MFI_D_DMA, "%s: mfi_create_sgl %p\n", DEVNAME(sc),
1276	    ccb->ccb_data);
1277
1278	if (!ccb->ccb_data) {
1279		hdr->mfh_sg_count = 0;
1280		return (1);
1281	}
1282
1283	error = bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap,
1284	    ccb->ccb_data, ccb->ccb_len, NULL, flags);
1285	if (error) {
1286		if (error == EFBIG)
1287			printf("more than %d dma segs\n",
1288			    sc->sc_max_sgl);
1289		else
1290			printf("error %d loading dma map\n", error);
1291		return (1);
1292	}
1293
1294	ccb->ccb_frame_size += mfi_sgd_load(sc, ccb);
1295
1296	if (ccb->ccb_direction == MFI_DATA_IN) {
1297		hdr->mfh_flags |= MFI_FRAME_DIR_READ;
1298		bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
1299		    ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
1300	} else {
1301		hdr->mfh_flags |= MFI_FRAME_DIR_WRITE;
1302		bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
1303		    ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_PREWRITE);
1304	}
1305
1306	hdr->mfh_sg_count = ccb->ccb_dmamap->dm_nsegs;
1307	ccb->ccb_extra_frames = (ccb->ccb_frame_size - 1) / MFI_FRAME_SIZE;
1308
1309	DNPRINTF(MFI_D_DMA, "%s: sg_count: %d  frame_size: %d  frames_size: %d"
1310	    "  dm_nsegs: %d  extra_frames: %d\n",
1311	    DEVNAME(sc),
1312	    hdr->mfh_sg_count,
1313	    ccb->ccb_frame_size,
1314	    sc->sc_frames_size,
1315	    ccb->ccb_dmamap->dm_nsegs,
1316	    ccb->ccb_extra_frames);
1317
1318	return (0);
1319}
1320
1321int
1322mfi_mgmt(struct mfi_softc *sc, uint32_t opc, uint32_t dir, uint32_t len,
1323    void *buf, const union mfi_mbox *mbox)
1324{
1325	struct mfi_ccb *ccb;
1326	int rv;
1327
1328	ccb = scsi_io_get(&sc->sc_iopool, 0);
1329	mfi_scrub_ccb(ccb);
1330	rv = mfi_do_mgmt(sc, ccb, opc, dir, len, buf, mbox);
1331	scsi_io_put(&sc->sc_iopool, ccb);
1332
1333	return (rv);
1334}
1335
1336int
1337mfi_do_mgmt(struct mfi_softc *sc, struct mfi_ccb *ccb, uint32_t opc,
1338    uint32_t dir, uint32_t len, void *buf, const union mfi_mbox *mbox)
1339{
1340	struct mfi_dcmd_frame *dcmd;
1341	uint8_t *dma_buf = NULL;
1342	int rv = EINVAL;
1343
1344	DNPRINTF(MFI_D_MISC, "%s: mfi_do_mgmt %#x\n", DEVNAME(sc), opc);
1345
1346	dma_buf = dma_alloc(len, cold ? PR_NOWAIT : PR_WAITOK);
1347	if (dma_buf == NULL)
1348		goto done;
1349
1350	dcmd = &ccb->ccb_frame->mfr_dcmd;
1351	memset(&dcmd->mdf_mbox, 0, sizeof(dcmd->mdf_mbox));
1352	dcmd->mdf_header.mfh_cmd = MFI_CMD_DCMD;
1353	dcmd->mdf_header.mfh_timeout = 0;
1354
1355	dcmd->mdf_opcode = opc;
1356	dcmd->mdf_header.mfh_data_len = 0;
1357	ccb->ccb_direction = dir;
1358
1359	ccb->ccb_frame_size = MFI_DCMD_FRAME_SIZE;
1360
1361	/* handle special opcodes */
1362	if (mbox != NULL)
1363		memcpy(&dcmd->mdf_mbox, mbox, sizeof(dcmd->mdf_mbox));
1364
1365	if (dir != MFI_DATA_NONE) {
1366		if (dir == MFI_DATA_OUT)
1367			memcpy(dma_buf, buf, len);
1368		dcmd->mdf_header.mfh_data_len = len;
1369		ccb->ccb_data = dma_buf;
1370		ccb->ccb_len = len;
1371		ccb->ccb_sgl = &dcmd->mdf_sgl;
1372
1373		if (mfi_create_sgl(sc, ccb, cold ? BUS_DMA_NOWAIT :
1374		    BUS_DMA_WAITOK)) {
1375			rv = EINVAL;
1376			goto done;
1377		}
1378	}
1379
1380	if (cold) {
1381		ccb->ccb_done = mfi_empty_done;
1382		mfi_poll(sc, ccb);
1383	} else
1384		mfi_exec(sc, ccb);
1385
1386	if (dcmd->mdf_header.mfh_cmd_status != MFI_STAT_OK) {
1387		if (dcmd->mdf_header.mfh_cmd_status == MFI_STAT_WRONG_STATE)
1388			rv = ENXIO;
1389		else
1390			rv = EIO;
1391		goto done;
1392	}
1393
1394	if (dir == MFI_DATA_IN)
1395		memcpy(buf, dma_buf, len);
1396
1397	rv = 0;
1398done:
1399	if (dma_buf)
1400		dma_free(dma_buf, len);
1401
1402	return (rv);
1403}
1404
1405int
1406mfi_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag)
1407{
1408	struct mfi_softc	*sc = link->bus->sb_adapter_softc;
1409
1410	DNPRINTF(MFI_D_IOCTL, "%s: mfi_scsi_ioctl\n", DEVNAME(sc));
1411
1412	switch (cmd) {
1413	case DIOCGCACHE:
1414	case DIOCSCACHE:
1415		return (mfi_ioctl_cache(link, cmd, (struct dk_cache *)addr));
1416		break;
1417
1418	default:
1419		if (sc->sc_ioctl)
1420			return (sc->sc_ioctl(&sc->sc_dev, cmd, addr));
1421		break;
1422	}
1423
1424	return (ENOTTY);
1425}
1426
1427int
1428mfi_ioctl_cache(struct scsi_link *link, u_long cmd,  struct dk_cache *dc)
1429{
1430	struct mfi_softc	*sc = link->bus->sb_adapter_softc;
1431	int			 rv, wrenable, rdenable;
1432	struct mfi_ld_prop	 ldp;
1433	union mfi_mbox		 mbox;
1434
1435	if (mfi_get_info(sc)) {
1436		rv = EIO;
1437		goto done;
1438	}
1439
1440	if (!sc->sc_ld[link->target].ld_present) {
1441		rv = EIO;
1442		goto done;
1443	}
1444
1445	memset(&mbox, 0, sizeof(mbox));
1446	mbox.b[0] = link->target;
1447	if ((rv = mfi_mgmt(sc, MR_DCMD_LD_GET_PROPERTIES, MFI_DATA_IN,
1448	    sizeof(ldp), &ldp, &mbox)) != 0)
1449		goto done;
1450
1451	if (sc->sc_info.mci_memory_size > 0) {
1452		wrenable = ISSET(ldp.mlp_cur_cache_policy,
1453		    MR_LD_CACHE_ALLOW_WRITE_CACHE)? 1 : 0;
1454		rdenable = ISSET(ldp.mlp_cur_cache_policy,
1455		    MR_LD_CACHE_ALLOW_READ_CACHE)? 1 : 0;
1456	} else {
1457		wrenable = ISSET(ldp.mlp_diskcache_policy,
1458		    MR_LD_DISK_CACHE_ENABLE)? 1 : 0;
1459		rdenable = 0;
1460	}
1461
1462	if (cmd == DIOCGCACHE) {
1463		dc->wrcache = wrenable;
1464		dc->rdcache = rdenable;
1465		goto done;
1466	} /* else DIOCSCACHE */
1467
1468	if (((dc->wrcache) ? 1 : 0) == wrenable &&
1469	    ((dc->rdcache) ? 1 : 0) == rdenable)
1470		goto done;
1471
1472	memset(&mbox, 0, sizeof(mbox));
1473	mbox.b[0] = ldp.mlp_ld.mld_target;
1474	mbox.b[1] = ldp.mlp_ld.mld_res;
1475	mbox.s[1] = ldp.mlp_ld.mld_seq;
1476
1477	if (sc->sc_info.mci_memory_size > 0) {
1478		if (dc->rdcache)
1479			SET(ldp.mlp_cur_cache_policy,
1480			    MR_LD_CACHE_ALLOW_READ_CACHE);
1481		else
1482			CLR(ldp.mlp_cur_cache_policy,
1483			    MR_LD_CACHE_ALLOW_READ_CACHE);
1484		if (dc->wrcache)
1485			SET(ldp.mlp_cur_cache_policy,
1486			    MR_LD_CACHE_ALLOW_WRITE_CACHE);
1487		else
1488			CLR(ldp.mlp_cur_cache_policy,
1489			    MR_LD_CACHE_ALLOW_WRITE_CACHE);
1490	} else {
1491		if (dc->rdcache) {
1492			rv = EOPNOTSUPP;
1493			goto done;
1494		}
1495		if (dc->wrcache)
1496			ldp.mlp_diskcache_policy = MR_LD_DISK_CACHE_ENABLE;
1497		else
1498			ldp.mlp_diskcache_policy = MR_LD_DISK_CACHE_DISABLE;
1499	}
1500
1501	rv = mfi_mgmt(sc, MR_DCMD_LD_SET_PROPERTIES, MFI_DATA_OUT, sizeof(ldp),
1502	    &ldp, &mbox);
1503
1504done:
1505	return (rv);
1506}
1507
1508#if NBIO > 0
1509int
1510mfi_ioctl(struct device *dev, u_long cmd, caddr_t addr)
1511{
1512	struct mfi_softc	*sc = (struct mfi_softc *)dev;
1513	int error = 0;
1514
1515	DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl ", DEVNAME(sc));
1516
1517	rw_enter_write(&sc->sc_lock);
1518
1519	switch (cmd) {
1520	case BIOCINQ:
1521		DNPRINTF(MFI_D_IOCTL, "inq\n");
1522		error = mfi_ioctl_inq(sc, (struct bioc_inq *)addr);
1523		break;
1524
1525	case BIOCVOL:
1526		DNPRINTF(MFI_D_IOCTL, "vol\n");
1527		error = mfi_ioctl_vol(sc, (struct bioc_vol *)addr);
1528		break;
1529
1530	case BIOCDISK:
1531		DNPRINTF(MFI_D_IOCTL, "disk\n");
1532		error = mfi_ioctl_disk(sc, (struct bioc_disk *)addr);
1533		break;
1534
1535	case BIOCALARM:
1536		DNPRINTF(MFI_D_IOCTL, "alarm\n");
1537		error = mfi_ioctl_alarm(sc, (struct bioc_alarm *)addr);
1538		break;
1539
1540	case BIOCBLINK:
1541		DNPRINTF(MFI_D_IOCTL, "blink\n");
1542		error = mfi_ioctl_blink(sc, (struct bioc_blink *)addr);
1543		break;
1544
1545	case BIOCSETSTATE:
1546		DNPRINTF(MFI_D_IOCTL, "setstate\n");
1547		error = mfi_ioctl_setstate(sc, (struct bioc_setstate *)addr);
1548		break;
1549
1550	case BIOCPATROL:
1551		DNPRINTF(MFI_D_IOCTL, "patrol\n");
1552		error = mfi_ioctl_patrol(sc, (struct bioc_patrol *)addr);
1553		break;
1554
1555	default:
1556		DNPRINTF(MFI_D_IOCTL, " invalid ioctl\n");
1557		error = ENOTTY;
1558	}
1559
1560	rw_exit_write(&sc->sc_lock);
1561
1562	return (error);
1563}
1564
1565int
1566mfi_bio_getitall(struct mfi_softc *sc)
1567{
1568	int			i, d, size, rv = EINVAL;
1569	union mfi_mbox		mbox;
1570	struct mfi_conf		*cfg = NULL;
1571	struct mfi_ld_details	*ld_det = NULL;
1572
1573	/* get info */
1574	if (mfi_get_info(sc)) {
1575		DNPRINTF(MFI_D_IOCTL, "%s: mfi_get_info failed\n",
1576		    DEVNAME(sc));
1577		goto done;
1578	}
1579
1580	/* send single element command to retrieve size for full structure */
1581	cfg = malloc(sizeof *cfg, M_DEVBUF, M_NOWAIT | M_ZERO);
1582	if (cfg == NULL)
1583		goto done;
1584	if (mfi_mgmt(sc, MR_DCMD_CONF_GET, MFI_DATA_IN, sizeof *cfg, cfg,
1585	    NULL)) {
1586		free(cfg, M_DEVBUF, sizeof *cfg);
1587		goto done;
1588	}
1589
1590	size = cfg->mfc_size;
1591	free(cfg, M_DEVBUF, sizeof *cfg);
1592
1593	/* memory for read config */
1594	cfg = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
1595	if (cfg == NULL)
1596		goto done;
1597	if (mfi_mgmt(sc, MR_DCMD_CONF_GET, MFI_DATA_IN, size, cfg, NULL)) {
1598		free(cfg, M_DEVBUF, size);
1599		goto done;
1600	}
1601
1602	/* replace current pointer with new one */
1603	if (sc->sc_cfg)
1604		free(sc->sc_cfg, M_DEVBUF, 0);
1605	sc->sc_cfg = cfg;
1606
1607	/* get all ld info */
1608	if (mfi_mgmt(sc, MR_DCMD_LD_GET_LIST, MFI_DATA_IN,
1609	    sizeof(sc->sc_ld_list), &sc->sc_ld_list, NULL))
1610		goto done;
1611
1612	/* get memory for all ld structures */
1613	size = cfg->mfc_no_ld * sizeof(struct mfi_ld_details);
1614	if (sc->sc_ld_sz != size) {
1615		if (sc->sc_ld_details)
1616			free(sc->sc_ld_details, M_DEVBUF, 0);
1617
1618		ld_det = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
1619		if (ld_det == NULL)
1620			goto done;
1621		sc->sc_ld_sz = size;
1622		sc->sc_ld_details = ld_det;
1623	}
1624
1625	/* find used physical disks */
1626	size = sizeof(struct mfi_ld_details);
1627	for (i = 0, d = 0; i < cfg->mfc_no_ld; i++) {
1628		memset(&mbox, 0, sizeof(mbox));
1629		mbox.b[0] = sc->sc_ld_list.mll_list[i].mll_ld.mld_target;
1630		if (mfi_mgmt(sc, MR_DCMD_LD_GET_INFO, MFI_DATA_IN, size,
1631		    &sc->sc_ld_details[i], &mbox))
1632			goto done;
1633
1634		d += sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_no_drv_per_span *
1635		    sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_span_depth;
1636	}
1637	sc->sc_no_pd = d;
1638
1639	rv = 0;
1640done:
1641	return (rv);
1642}
1643
1644int
1645mfi_ioctl_inq(struct mfi_softc *sc, struct bioc_inq *bi)
1646{
1647	int			rv = EINVAL;
1648	struct mfi_conf		*cfg = NULL;
1649
1650	DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_inq\n", DEVNAME(sc));
1651
1652	if (mfi_bio_getitall(sc)) {
1653		DNPRINTF(MFI_D_IOCTL, "%s: mfi_bio_getitall failed\n",
1654		    DEVNAME(sc));
1655		goto done;
1656	}
1657
1658	/* count unused disks as volumes */
1659	if (sc->sc_cfg == NULL)
1660		goto done;
1661	cfg = sc->sc_cfg;
1662
1663	bi->bi_nodisk = sc->sc_info.mci_pd_disks_present;
1664	bi->bi_novol = cfg->mfc_no_ld + cfg->mfc_no_hs;
1665#if notyet
1666	bi->bi_novol = cfg->mfc_no_ld + cfg->mfc_no_hs +
1667	    (bi->bi_nodisk - sc->sc_no_pd);
1668#endif
1669	/* tell bio who we are */
1670	strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev));
1671
1672	rv = 0;
1673done:
1674	return (rv);
1675}
1676
1677int
1678mfi_ioctl_vol(struct mfi_softc *sc, struct bioc_vol *bv)
1679{
1680	int			i, per, rv = EINVAL;
1681	struct scsi_link	*link;
1682	struct device		*dev;
1683
1684	DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_vol %#x\n",
1685	    DEVNAME(sc), bv->bv_volid);
1686
1687	/* we really could skip and expect that inq took care of it */
1688	if (mfi_bio_getitall(sc)) {
1689		DNPRINTF(MFI_D_IOCTL, "%s: mfi_bio_getitall failed\n",
1690		    DEVNAME(sc));
1691		goto done;
1692	}
1693
1694	if (bv->bv_volid >= sc->sc_ld_list.mll_no_ld) {
1695		/* go do hotspares & unused disks */
1696		rv = mfi_bio_hs(sc, bv->bv_volid, MFI_MGMT_VD, bv);
1697		goto done;
1698	}
1699
1700	i = bv->bv_volid;
1701	link = scsi_get_link(sc->sc_scsibus, i, 0);
1702	if (link != NULL && link->device_softc != NULL) {
1703		dev = link->device_softc;
1704		strlcpy(bv->bv_dev, dev->dv_xname, sizeof(bv->bv_dev));
1705	}
1706
1707	switch(sc->sc_ld_list.mll_list[i].mll_state) {
1708	case MFI_LD_OFFLINE:
1709		bv->bv_status = BIOC_SVOFFLINE;
1710		break;
1711
1712	case MFI_LD_PART_DEGRADED:
1713	case MFI_LD_DEGRADED:
1714		bv->bv_status = BIOC_SVDEGRADED;
1715		break;
1716
1717	case MFI_LD_ONLINE:
1718		bv->bv_status = BIOC_SVONLINE;
1719		break;
1720
1721	default:
1722		bv->bv_status = BIOC_SVINVALID;
1723		DNPRINTF(MFI_D_IOCTL, "%s: invalid logical disk state %#x\n",
1724		    DEVNAME(sc),
1725		    sc->sc_ld_list.mll_list[i].mll_state);
1726	}
1727
1728	/* additional status can modify MFI status */
1729	switch (sc->sc_ld_details[i].mld_progress.mlp_in_prog) {
1730	case MFI_LD_PROG_CC:
1731		bv->bv_status = BIOC_SVSCRUB;
1732		per = (int)sc->sc_ld_details[i].mld_progress.mlp_cc.mp_progress;
1733		bv->bv_percent = (per * 100) / 0xffff;
1734		bv->bv_seconds =
1735		    sc->sc_ld_details[i].mld_progress.mlp_cc.mp_elapsed_seconds;
1736		break;
1737
1738	case MFI_LD_PROG_BGI:
1739		bv->bv_status = BIOC_SVSCRUB;
1740		per = (int)sc->sc_ld_details[i].mld_progress.mlp_bgi.mp_progress;
1741		bv->bv_percent = (per * 100) / 0xffff;
1742		bv->bv_seconds =
1743		    sc->sc_ld_details[i].mld_progress.mlp_bgi.mp_elapsed_seconds;
1744		break;
1745
1746	case MFI_LD_PROG_FGI:
1747	case MFI_LD_PROG_RECONSTRUCT:
1748		/* nothing yet */
1749		break;
1750	}
1751
1752	if (sc->sc_ld_details[i].mld_cfg.mlc_prop.mlp_cur_cache_policy & 0x01)
1753		bv->bv_cache = BIOC_CVWRITEBACK;
1754	else
1755		bv->bv_cache = BIOC_CVWRITETHROUGH;
1756
1757	/*
1758	 * The RAID levels are determined per the SNIA DDF spec, this is only
1759	 * a subset that is valid for the MFI controller.
1760	 */
1761	bv->bv_level = sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_pri_raid;
1762	if (sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_sec_raid ==
1763	    MFI_DDF_SRL_SPANNED)
1764		bv->bv_level *= 10;
1765
1766	bv->bv_nodisk = sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_no_drv_per_span *
1767	    sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_span_depth;
1768
1769	bv->bv_size = sc->sc_ld_details[i].mld_size * 512; /* bytes per block */
1770
1771	rv = 0;
1772done:
1773	return (rv);
1774}
1775
1776int
1777mfi_ioctl_disk(struct mfi_softc *sc, struct bioc_disk *bd)
1778{
1779	struct mfi_conf		*cfg;
1780	struct mfi_array	*ar;
1781	struct mfi_ld_cfg	*ld;
1782	struct mfi_pd_details	*pd;
1783	struct mfi_pd_progress	*mfp;
1784	struct mfi_progress	*mp;
1785	struct scsi_inquiry_data *inqbuf;
1786	char			vend[8+16+4+1], *vendp;
1787	int			rv = EINVAL;
1788	int			arr, vol, disk, span;
1789	union mfi_mbox		mbox;
1790
1791	DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_disk %#x\n",
1792	    DEVNAME(sc), bd->bd_diskid);
1793
1794	/* we really could skip and expect that inq took care of it */
1795	if (mfi_bio_getitall(sc)) {
1796		DNPRINTF(MFI_D_IOCTL, "%s: mfi_bio_getitall failed\n",
1797		    DEVNAME(sc));
1798		return (rv);
1799	}
1800	cfg = sc->sc_cfg;
1801
1802	pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
1803
1804	ar = cfg->mfc_array;
1805	vol = bd->bd_volid;
1806	if (vol >= cfg->mfc_no_ld) {
1807		/* do hotspares */
1808		rv = mfi_bio_hs(sc, bd->bd_volid, MFI_MGMT_SD, bd);
1809		goto freeme;
1810	}
1811
1812	/* calculate offset to ld structure */
1813	ld = (struct mfi_ld_cfg *)(
1814	    ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) +
1815	    cfg->mfc_array_size * cfg->mfc_no_array);
1816
1817	/* use span 0 only when raid group is not spanned */
1818	if (ld[vol].mlc_parm.mpa_span_depth > 1)
1819		span = bd->bd_diskid / ld[vol].mlc_parm.mpa_no_drv_per_span;
1820	else
1821		span = 0;
1822	arr = ld[vol].mlc_span[span].mls_index;
1823
1824	/* offset disk into pd list */
1825	disk = bd->bd_diskid % ld[vol].mlc_parm.mpa_no_drv_per_span;
1826	bd->bd_target = ar[arr].pd[disk].mar_enc_slot;
1827
1828	/* get status */
1829	switch (ar[arr].pd[disk].mar_pd_state){
1830	case MFI_PD_UNCONFIG_GOOD:
1831	case MFI_PD_FAILED:
1832		bd->bd_status = BIOC_SDFAILED;
1833		break;
1834
1835	case MFI_PD_HOTSPARE: /* XXX dedicated hotspare part of array? */
1836		bd->bd_status = BIOC_SDHOTSPARE;
1837		break;
1838
1839	case MFI_PD_OFFLINE:
1840		bd->bd_status = BIOC_SDOFFLINE;
1841		break;
1842
1843	case MFI_PD_REBUILD:
1844		bd->bd_status = BIOC_SDREBUILD;
1845		break;
1846
1847	case MFI_PD_ONLINE:
1848		bd->bd_status = BIOC_SDONLINE;
1849		break;
1850
1851	case MFI_PD_UNCONFIG_BAD: /* XXX define new state in bio */
1852	default:
1853		bd->bd_status = BIOC_SDINVALID;
1854		break;
1855	}
1856
1857	/* get the remaining fields */
1858	memset(&mbox, 0, sizeof(mbox));
1859	mbox.s[0] = ar[arr].pd[disk].mar_pd.mfp_id;
1860	if (mfi_mgmt(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN,
1861	    sizeof *pd, pd, &mbox)) {
1862		/* disk is missing but succeed command */
1863		rv = 0;
1864		goto freeme;
1865	}
1866
1867	bd->bd_size = pd->mpd_size * 512; /* bytes per block */
1868
1869	/* if pd->mpd_enc_idx is 0 then it is not in an enclosure */
1870	bd->bd_channel = pd->mpd_enc_idx;
1871
1872	inqbuf = (struct scsi_inquiry_data *)&pd->mpd_inq_data;
1873	vendp = inqbuf->vendor;
1874	memcpy(vend, vendp, sizeof vend - 1);
1875	vend[sizeof vend - 1] = '\0';
1876	strlcpy(bd->bd_vendor, vend, sizeof(bd->bd_vendor));
1877
1878	/* XXX find a way to retrieve serial nr from drive */
1879	/* XXX find a way to get bd_procdev */
1880
1881	mfp = &pd->mpd_progress;
1882	if (mfp->mfp_in_prog & MFI_PD_PROG_PR) {
1883		mp = &mfp->mfp_patrol_read;
1884		bd->bd_patrol.bdp_percent = (mp->mp_progress * 100) / 0xffff;
1885		bd->bd_patrol.bdp_seconds = mp->mp_elapsed_seconds;
1886	}
1887
1888	rv = 0;
1889freeme:
1890	free(pd, M_DEVBUF, sizeof *pd);
1891
1892	return (rv);
1893}
1894
1895int
1896mfi_ioctl_alarm(struct mfi_softc *sc, struct bioc_alarm *ba)
1897{
1898	uint32_t		opc, dir = MFI_DATA_NONE;
1899	int			rv = 0;
1900	int8_t			ret;
1901
1902	switch(ba->ba_opcode) {
1903	case BIOC_SADISABLE:
1904		opc = MR_DCMD_SPEAKER_DISABLE;
1905		break;
1906
1907	case BIOC_SAENABLE:
1908		opc = MR_DCMD_SPEAKER_ENABLE;
1909		break;
1910
1911	case BIOC_SASILENCE:
1912		opc = MR_DCMD_SPEAKER_SILENCE;
1913		break;
1914
1915	case BIOC_GASTATUS:
1916		opc = MR_DCMD_SPEAKER_GET;
1917		dir = MFI_DATA_IN;
1918		break;
1919
1920	case BIOC_SATEST:
1921		opc = MR_DCMD_SPEAKER_TEST;
1922		break;
1923
1924	default:
1925		DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_alarm biocalarm invalid "
1926		    "opcode %x\n", DEVNAME(sc), ba->ba_opcode);
1927		return (EINVAL);
1928	}
1929
1930	if (mfi_mgmt(sc, opc, dir, sizeof(ret), &ret, NULL))
1931		rv = EINVAL;
1932	else
1933		if (ba->ba_opcode == BIOC_GASTATUS)
1934			ba->ba_status = ret;
1935		else
1936			ba->ba_status = 0;
1937
1938	return (rv);
1939}
1940
1941int
1942mfi_ioctl_blink(struct mfi_softc *sc, struct bioc_blink *bb)
1943{
1944	int			i, found, rv = EINVAL;
1945	union mfi_mbox		mbox;
1946	uint32_t		cmd;
1947	struct mfi_pd_list	*pd;
1948
1949	DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_blink %x\n", DEVNAME(sc),
1950	    bb->bb_status);
1951
1952	/* channel 0 means not in an enclosure so can't be blinked */
1953	if (bb->bb_channel == 0)
1954		return (EINVAL);
1955
1956	pd = malloc(sizeof(*pd), M_DEVBUF, M_WAITOK);
1957
1958	if (mfi_mgmt(sc, MR_DCMD_PD_GET_LIST, MFI_DATA_IN,
1959	    sizeof(*pd), pd, NULL))
1960		goto done;
1961
1962	for (i = 0, found = 0; i < pd->mpl_no_pd; i++)
1963		if (bb->bb_channel == pd->mpl_address[i].mpa_enc_index &&
1964		    bb->bb_target == pd->mpl_address[i].mpa_enc_slot) {
1965			found = 1;
1966			break;
1967		}
1968
1969	if (!found)
1970		goto done;
1971
1972	memset(&mbox, 0, sizeof(mbox));
1973	mbox.s[0] = pd->mpl_address[i].mpa_pd_id;
1974
1975	switch (bb->bb_status) {
1976	case BIOC_SBUNBLINK:
1977		cmd = MR_DCMD_PD_UNBLINK;
1978		break;
1979
1980	case BIOC_SBBLINK:
1981		cmd = MR_DCMD_PD_BLINK;
1982		break;
1983
1984	case BIOC_SBALARM:
1985	default:
1986		DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_blink biocblink invalid "
1987		    "opcode %x\n", DEVNAME(sc), bb->bb_status);
1988		goto done;
1989	}
1990
1991
1992	rv = mfi_mgmt(sc, cmd, MFI_DATA_NONE, 0, NULL, &mbox);
1993
1994done:
1995	free(pd, M_DEVBUF, sizeof *pd);
1996	return (rv);
1997}
1998
1999int
2000mfi_ioctl_setstate(struct mfi_softc *sc, struct bioc_setstate *bs)
2001{
2002	struct mfi_pd_list	*pd;
2003	struct mfi_pd_details	*info;
2004	int			i, found, rv = EINVAL;
2005	union mfi_mbox		mbox;
2006
2007	DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_setstate %x\n", DEVNAME(sc),
2008	    bs->bs_status);
2009
2010	pd = malloc(sizeof(*pd), M_DEVBUF, M_WAITOK);
2011	info = malloc(sizeof *info, M_DEVBUF, M_WAITOK);
2012
2013	if (mfi_mgmt(sc, MR_DCMD_PD_GET_LIST, MFI_DATA_IN,
2014	    sizeof(*pd), pd, NULL))
2015		goto done;
2016
2017	for (i = 0, found = 0; i < pd->mpl_no_pd; i++)
2018		if (bs->bs_channel == pd->mpl_address[i].mpa_enc_index &&
2019		    bs->bs_target == pd->mpl_address[i].mpa_enc_slot) {
2020			found = 1;
2021			break;
2022		}
2023
2024	if (!found)
2025		goto done;
2026
2027	memset(&mbox, 0, sizeof(mbox));
2028	mbox.s[0] = pd->mpl_address[i].mpa_pd_id;
2029
2030	if (mfi_mgmt(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN,
2031	    sizeof *info, info, &mbox))
2032		goto done;
2033
2034	mbox.s[0] = pd->mpl_address[i].mpa_pd_id;
2035	mbox.s[1] = info->mpd_pd.mfp_seq;
2036
2037	switch (bs->bs_status) {
2038	case BIOC_SSONLINE:
2039		mbox.b[4] = MFI_PD_ONLINE;
2040		break;
2041
2042	case BIOC_SSOFFLINE:
2043		mbox.b[4] = MFI_PD_OFFLINE;
2044		break;
2045
2046	case BIOC_SSHOTSPARE:
2047		mbox.b[4] = MFI_PD_HOTSPARE;
2048		break;
2049
2050	case BIOC_SSREBUILD:
2051		mbox.b[4] = MFI_PD_REBUILD;
2052		break;
2053
2054	default:
2055		DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_setstate invalid "
2056		    "opcode %x\n", DEVNAME(sc), bs->bs_status);
2057		goto done;
2058	}
2059
2060	rv = mfi_mgmt(sc, MR_DCMD_PD_SET_STATE, MFI_DATA_NONE, 0, NULL, &mbox);
2061
2062done:
2063	free(pd, M_DEVBUF, sizeof *pd);
2064	free(info, M_DEVBUF, sizeof *info);
2065	return (rv);
2066}
2067
2068int
2069mfi_ioctl_patrol(struct mfi_softc *sc, struct bioc_patrol *bp)
2070{
2071	uint32_t		opc, dir = MFI_DATA_NONE;
2072	int			rv = 0;
2073	struct mfi_pr_properties prop;
2074	struct mfi_pr_status	status;
2075	uint32_t		time, exec_freq;
2076
2077	switch (bp->bp_opcode) {
2078	case BIOC_SPSTOP:
2079	case BIOC_SPSTART:
2080		if (bp->bp_opcode == BIOC_SPSTART)
2081			opc = MR_DCMD_PR_START;
2082		else
2083			opc = MR_DCMD_PR_STOP;
2084		dir = MFI_DATA_IN;
2085		if (mfi_mgmt(sc, opc, dir, 0, NULL, NULL))
2086			return (EINVAL);
2087		break;
2088
2089	case BIOC_SPMANUAL:
2090	case BIOC_SPDISABLE:
2091	case BIOC_SPAUTO:
2092		/* Get device's time. */
2093		opc = MR_DCMD_TIME_SECS_GET;
2094		dir = MFI_DATA_IN;
2095		if (mfi_mgmt(sc, opc, dir, sizeof(time), &time, NULL))
2096			return (EINVAL);
2097
2098		opc = MR_DCMD_PR_GET_PROPERTIES;
2099		dir = MFI_DATA_IN;
2100		if (mfi_mgmt(sc, opc, dir, sizeof(prop), &prop, NULL))
2101			return (EINVAL);
2102
2103		switch (bp->bp_opcode) {
2104		case BIOC_SPMANUAL:
2105			prop.op_mode = MFI_PR_OPMODE_MANUAL;
2106			break;
2107		case BIOC_SPDISABLE:
2108			prop.op_mode = MFI_PR_OPMODE_DISABLED;
2109			break;
2110		case BIOC_SPAUTO:
2111			if (bp->bp_autoival != 0) {
2112				if (bp->bp_autoival == -1)
2113					/* continuously */
2114					exec_freq = 0xffffffffU;
2115				else if (bp->bp_autoival > 0)
2116					exec_freq = bp->bp_autoival;
2117				else
2118					return (EINVAL);
2119				prop.exec_freq = exec_freq;
2120			}
2121			if (bp->bp_autonext != 0) {
2122				if (bp->bp_autonext < 0)
2123					return (EINVAL);
2124				else
2125					prop.next_exec = time + bp->bp_autonext;
2126			}
2127			prop.op_mode = MFI_PR_OPMODE_AUTO;
2128			break;
2129		}
2130
2131		opc = MR_DCMD_PR_SET_PROPERTIES;
2132		dir = MFI_DATA_OUT;
2133		if (mfi_mgmt(sc, opc, dir, sizeof(prop), &prop, NULL))
2134			return (EINVAL);
2135
2136		break;
2137
2138	case BIOC_GPSTATUS:
2139		opc = MR_DCMD_PR_GET_PROPERTIES;
2140		dir = MFI_DATA_IN;
2141		if (mfi_mgmt(sc, opc, dir, sizeof(prop), &prop, NULL))
2142			return (EINVAL);
2143
2144		opc = MR_DCMD_PR_GET_STATUS;
2145		dir = MFI_DATA_IN;
2146		if (mfi_mgmt(sc, opc, dir, sizeof(status), &status, NULL))
2147			return (EINVAL);
2148
2149		/* Get device's time. */
2150		opc = MR_DCMD_TIME_SECS_GET;
2151		dir = MFI_DATA_IN;
2152		if (mfi_mgmt(sc, opc, dir, sizeof(time), &time, NULL))
2153			return (EINVAL);
2154
2155		switch (prop.op_mode) {
2156		case MFI_PR_OPMODE_AUTO:
2157			bp->bp_mode = BIOC_SPMAUTO;
2158			bp->bp_autoival = prop.exec_freq;
2159			bp->bp_autonext = prop.next_exec;
2160			bp->bp_autonow = time;
2161			break;
2162		case MFI_PR_OPMODE_MANUAL:
2163			bp->bp_mode = BIOC_SPMMANUAL;
2164			break;
2165		case MFI_PR_OPMODE_DISABLED:
2166			bp->bp_mode = BIOC_SPMDISABLED;
2167			break;
2168		default:
2169			printf("%s: unknown patrol mode %d\n",
2170			    DEVNAME(sc), prop.op_mode);
2171			break;
2172		}
2173
2174		switch (status.state) {
2175		case MFI_PR_STATE_STOPPED:
2176			bp->bp_status = BIOC_SPSSTOPPED;
2177			break;
2178		case MFI_PR_STATE_READY:
2179			bp->bp_status = BIOC_SPSREADY;
2180			break;
2181		case MFI_PR_STATE_ACTIVE:
2182			bp->bp_status = BIOC_SPSACTIVE;
2183			break;
2184		case MFI_PR_STATE_ABORTED:
2185			bp->bp_status = BIOC_SPSABORTED;
2186			break;
2187		default:
2188			printf("%s: unknown patrol state %d\n",
2189			    DEVNAME(sc), status.state);
2190			break;
2191		}
2192
2193		break;
2194
2195	default:
2196		DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_patrol biocpatrol invalid "
2197		    "opcode %x\n", DEVNAME(sc), bp->bp_opcode);
2198		return (EINVAL);
2199	}
2200
2201	return (rv);
2202}
2203
2204int
2205mfi_bio_hs(struct mfi_softc *sc, int volid, int type, void *bio_hs)
2206{
2207	struct mfi_conf		*cfg;
2208	struct mfi_hotspare	*hs;
2209	struct mfi_pd_details	*pd;
2210	struct bioc_disk	*sdhs;
2211	struct bioc_vol		*vdhs;
2212	struct scsi_inquiry_data *inqbuf;
2213	char			vend[8+16+4+1], *vendp;
2214	int			i, rv = EINVAL;
2215	uint32_t		size;
2216	union mfi_mbox		mbox;
2217
2218	DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs %d\n", DEVNAME(sc), volid);
2219
2220	if (!bio_hs)
2221		return (EINVAL);
2222
2223	pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
2224
2225	/* send single element command to retrieve size for full structure */
2226	cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK);
2227	if (mfi_mgmt(sc, MR_DCMD_CONF_GET, MFI_DATA_IN, sizeof *cfg, cfg, NULL))
2228		goto freeme;
2229
2230	size = cfg->mfc_size;
2231	free(cfg, M_DEVBUF, sizeof *cfg);
2232
2233	/* memory for read config */
2234	cfg = malloc(size, M_DEVBUF, M_WAITOK|M_ZERO);
2235	if (mfi_mgmt(sc, MR_DCMD_CONF_GET, MFI_DATA_IN, size, cfg, NULL))
2236		goto freeme;
2237
2238	/* calculate offset to hs structure */
2239	hs = (struct mfi_hotspare *)(
2240	    ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) +
2241	    cfg->mfc_array_size * cfg->mfc_no_array +
2242	    cfg->mfc_ld_size * cfg->mfc_no_ld);
2243
2244	if (volid < cfg->mfc_no_ld)
2245		goto freeme; /* not a hotspare */
2246
2247	if (volid > (cfg->mfc_no_ld + cfg->mfc_no_hs))
2248		goto freeme; /* not a hotspare */
2249
2250	/* offset into hotspare structure */
2251	i = volid - cfg->mfc_no_ld;
2252
2253	DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs i %d volid %d no_ld %d no_hs %d "
2254	    "hs %p cfg %p id %02x\n", DEVNAME(sc), i, volid, cfg->mfc_no_ld,
2255	    cfg->mfc_no_hs, hs, cfg, hs[i].mhs_pd.mfp_id);
2256
2257	/* get pd fields */
2258	memset(&mbox, 0, sizeof(mbox));
2259	mbox.s[0] = hs[i].mhs_pd.mfp_id;
2260	if (mfi_mgmt(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN,
2261	    sizeof *pd, pd, &mbox)) {
2262		DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs illegal PD\n",
2263		    DEVNAME(sc));
2264		goto freeme;
2265	}
2266
2267	switch (type) {
2268	case MFI_MGMT_VD:
2269		vdhs = bio_hs;
2270		vdhs->bv_status = BIOC_SVONLINE;
2271		vdhs->bv_size = pd->mpd_size / 2 * 1024; /* XXX why? */
2272		vdhs->bv_level = -1; /* hotspare */
2273		vdhs->bv_nodisk = 1;
2274		break;
2275
2276	case MFI_MGMT_SD:
2277		sdhs = bio_hs;
2278		sdhs->bd_status = BIOC_SDHOTSPARE;
2279		sdhs->bd_size = pd->mpd_size / 2 * 1024; /* XXX why? */
2280		sdhs->bd_channel = pd->mpd_enc_idx;
2281		sdhs->bd_target = pd->mpd_enc_slot;
2282		inqbuf = (struct scsi_inquiry_data *)&pd->mpd_inq_data;
2283		vendp = inqbuf->vendor;
2284		memcpy(vend, vendp, sizeof vend - 1);
2285		vend[sizeof vend - 1] = '\0';
2286		strlcpy(sdhs->bd_vendor, vend, sizeof(sdhs->bd_vendor));
2287		break;
2288
2289	default:
2290		goto freeme;
2291	}
2292
2293	DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs 6\n", DEVNAME(sc));
2294	rv = 0;
2295freeme:
2296	free(pd, M_DEVBUF, sizeof *pd);
2297	free(cfg, M_DEVBUF, 0);
2298
2299	return (rv);
2300}
2301
2302#ifndef SMALL_KERNEL
2303
2304static const char *mfi_bbu_indicators[] = {
2305	"pack missing",
2306	"voltage low",
2307	"temp high",
2308	"charge active",
2309	"discharge active",
2310	"learn cycle req'd",
2311	"learn cycle active",
2312	"learn cycle failed",
2313	"learn cycle timeout",
2314	"I2C errors",
2315	"replace pack",
2316	"low capacity",
2317	"periodic learn req'd"
2318};
2319
2320#define MFI_BBU_SENSORS 4
2321
2322int
2323mfi_bbu(struct mfi_softc *sc)
2324{
2325	struct mfi_bbu_status bbu;
2326	u_int32_t status;
2327	u_int32_t mask;
2328	u_int32_t soh_bad;
2329	int i;
2330
2331	if (mfi_mgmt(sc, MR_DCMD_BBU_GET_STATUS, MFI_DATA_IN,
2332	    sizeof(bbu), &bbu, NULL) != 0) {
2333		for (i = 0; i < MFI_BBU_SENSORS; i++) {
2334			sc->sc_bbu[i].value = 0;
2335			sc->sc_bbu[i].status = SENSOR_S_UNKNOWN;
2336		}
2337		for (i = 0; i < nitems(mfi_bbu_indicators); i++) {
2338			sc->sc_bbu_status[i].value = 0;
2339			sc->sc_bbu_status[i].status = SENSOR_S_UNKNOWN;
2340		}
2341		return (-1);
2342	}
2343
2344	switch (bbu.battery_type) {
2345	case MFI_BBU_TYPE_IBBU:
2346		mask = MFI_BBU_STATE_BAD_IBBU;
2347		soh_bad = 0;
2348		break;
2349	case MFI_BBU_TYPE_BBU:
2350		mask = MFI_BBU_STATE_BAD_BBU;
2351		soh_bad = (bbu.detail.bbu.is_SOH_good == 0);
2352		break;
2353
2354	case MFI_BBU_TYPE_NONE:
2355	default:
2356		sc->sc_bbu[0].value = 0;
2357		sc->sc_bbu[0].status = SENSOR_S_CRIT;
2358		for (i = 1; i < MFI_BBU_SENSORS; i++) {
2359			sc->sc_bbu[i].value = 0;
2360			sc->sc_bbu[i].status = SENSOR_S_UNKNOWN;
2361		}
2362		for (i = 0; i < nitems(mfi_bbu_indicators); i++) {
2363			sc->sc_bbu_status[i].value = 0;
2364			sc->sc_bbu_status[i].status = SENSOR_S_UNKNOWN;
2365		}
2366		return (0);
2367	}
2368
2369	status = letoh32(bbu.fw_status);
2370
2371	sc->sc_bbu[0].value = ((status & mask) || soh_bad) ? 0 : 1;
2372	sc->sc_bbu[0].status = ((status & mask) || soh_bad) ? SENSOR_S_CRIT :
2373	    SENSOR_S_OK;
2374
2375	sc->sc_bbu[1].value = letoh16(bbu.voltage) * 1000;
2376	sc->sc_bbu[2].value = (int16_t)letoh16(bbu.current) * 1000;
2377	sc->sc_bbu[3].value = letoh16(bbu.temperature) * 1000000 + 273150000;
2378	for (i = 1; i < MFI_BBU_SENSORS; i++)
2379		sc->sc_bbu[i].status = SENSOR_S_UNSPEC;
2380
2381	for (i = 0; i < nitems(mfi_bbu_indicators); i++) {
2382		sc->sc_bbu_status[i].value = (status & (1 << i)) ? 1 : 0;
2383		sc->sc_bbu_status[i].status = SENSOR_S_UNSPEC;
2384	}
2385
2386	return (0);
2387}
2388
2389int
2390mfi_create_sensors(struct mfi_softc *sc)
2391{
2392	struct device		*dev;
2393	struct scsi_link	*link;
2394	int			i;
2395
2396	strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
2397	    sizeof(sc->sc_sensordev.xname));
2398
2399	if (ISSET(letoh32(sc->sc_info.mci_adapter_ops ), MFI_INFO_AOPS_BBU)) {
2400		sc->sc_bbu = mallocarray(4, sizeof(*sc->sc_bbu),
2401		    M_DEVBUF, M_WAITOK | M_ZERO);
2402
2403		sc->sc_bbu[0].type = SENSOR_INDICATOR;
2404		sc->sc_bbu[0].status = SENSOR_S_UNKNOWN;
2405		strlcpy(sc->sc_bbu[0].desc, "bbu ok",
2406		    sizeof(sc->sc_bbu[0].desc));
2407		sensor_attach(&sc->sc_sensordev, &sc->sc_bbu[0]);
2408
2409		sc->sc_bbu[1].type = SENSOR_VOLTS_DC;
2410		sc->sc_bbu[1].status = SENSOR_S_UNSPEC;
2411		sc->sc_bbu[2].type = SENSOR_AMPS;
2412		sc->sc_bbu[2].status = SENSOR_S_UNSPEC;
2413		sc->sc_bbu[3].type = SENSOR_TEMP;
2414		sc->sc_bbu[3].status = SENSOR_S_UNSPEC;
2415		for (i = 1; i < MFI_BBU_SENSORS; i++) {
2416			strlcpy(sc->sc_bbu[i].desc, "bbu",
2417			    sizeof(sc->sc_bbu[i].desc));
2418			sensor_attach(&sc->sc_sensordev, &sc->sc_bbu[i]);
2419		}
2420
2421		sc->sc_bbu_status = malloc(sizeof(*sc->sc_bbu_status) *
2422		    sizeof(mfi_bbu_indicators), M_DEVBUF, M_WAITOK | M_ZERO);
2423
2424		for (i = 0; i < nitems(mfi_bbu_indicators); i++) {
2425			sc->sc_bbu_status[i].type = SENSOR_INDICATOR;
2426			sc->sc_bbu_status[i].status = SENSOR_S_UNSPEC;
2427			strlcpy(sc->sc_bbu_status[i].desc,
2428			    mfi_bbu_indicators[i],
2429			    sizeof(sc->sc_bbu_status[i].desc));
2430
2431			sensor_attach(&sc->sc_sensordev, &sc->sc_bbu_status[i]);
2432		}
2433	}
2434
2435	sc->sc_sensors = mallocarray(sc->sc_ld_cnt, sizeof(struct ksensor),
2436	    M_DEVBUF, M_NOWAIT | M_ZERO);
2437	if (sc->sc_sensors == NULL)
2438		return (1);
2439
2440	for (i = 0; i < sc->sc_ld_cnt; i++) {
2441		link = scsi_get_link(sc->sc_scsibus, i, 0);
2442		if (link == NULL)
2443			goto bad;
2444
2445		dev = link->device_softc;
2446
2447		sc->sc_sensors[i].type = SENSOR_DRIVE;
2448		sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
2449
2450		strlcpy(sc->sc_sensors[i].desc, dev->dv_xname,
2451		    sizeof(sc->sc_sensors[i].desc));
2452
2453		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
2454	}
2455
2456	if (sensor_task_register(sc, mfi_refresh_sensors, 10) == NULL)
2457		goto bad;
2458
2459	sensordev_install(&sc->sc_sensordev);
2460
2461	return (0);
2462
2463bad:
2464	free(sc->sc_sensors, M_DEVBUF,
2465	    sc->sc_ld_cnt * sizeof(struct ksensor));
2466
2467	return (1);
2468}
2469
2470void
2471mfi_refresh_sensors(void *arg)
2472{
2473	struct mfi_softc	*sc = arg;
2474	int			i, rv;
2475	struct bioc_vol		bv;
2476
2477	if (sc->sc_bbu != NULL && mfi_bbu(sc) != 0)
2478		return;
2479
2480	for (i = 0; i < sc->sc_ld_cnt; i++) {
2481		bzero(&bv, sizeof(bv));
2482		bv.bv_volid = i;
2483
2484		rw_enter_write(&sc->sc_lock);
2485		rv = mfi_ioctl_vol(sc, &bv);
2486		rw_exit_write(&sc->sc_lock);
2487
2488		if (rv != 0)
2489			return;
2490
2491		switch(bv.bv_status) {
2492		case BIOC_SVOFFLINE:
2493			sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL;
2494			sc->sc_sensors[i].status = SENSOR_S_CRIT;
2495			break;
2496
2497		case BIOC_SVDEGRADED:
2498			sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL;
2499			sc->sc_sensors[i].status = SENSOR_S_WARN;
2500			break;
2501
2502		case BIOC_SVSCRUB:
2503		case BIOC_SVONLINE:
2504			sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE;
2505			sc->sc_sensors[i].status = SENSOR_S_OK;
2506			break;
2507
2508		case BIOC_SVINVALID:
2509			/* FALLTHROUGH */
2510		default:
2511			sc->sc_sensors[i].value = 0; /* unknown */
2512			sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
2513			break;
2514		}
2515	}
2516}
2517#endif /* SMALL_KERNEL */
2518#endif /* NBIO > 0 */
2519
2520void
2521mfi_start(struct mfi_softc *sc, struct mfi_ccb *ccb)
2522{
2523	bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_frames),
2524	    ccb->ccb_pframe_offset, sc->sc_frames_size,
2525	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2526
2527	mfi_post(sc, ccb);
2528}
2529
2530void
2531mfi_done(struct mfi_softc *sc, struct mfi_ccb *ccb)
2532{
2533	bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_frames),
2534	    ccb->ccb_pframe_offset, sc->sc_frames_size,
2535	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2536
2537	if (ccb->ccb_len > 0) {
2538		bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap,
2539		    0, ccb->ccb_dmamap->dm_mapsize,
2540		    (ccb->ccb_direction == MFI_DATA_IN) ?
2541		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
2542
2543		bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
2544	}
2545
2546	ccb->ccb_done(sc, ccb);
2547}
2548
2549u_int32_t
2550mfi_xscale_fw_state(struct mfi_softc *sc)
2551{
2552	return (mfi_read(sc, MFI_OMSG0));
2553}
2554
2555void
2556mfi_xscale_intr_ena(struct mfi_softc *sc)
2557{
2558	mfi_write(sc, MFI_OMSK, MFI_ENABLE_INTR);
2559}
2560
2561int
2562mfi_xscale_intr(struct mfi_softc *sc)
2563{
2564	u_int32_t status;
2565
2566	status = mfi_read(sc, MFI_OSTS);
2567	if (!ISSET(status, MFI_OSTS_INTR_VALID))
2568		return (0);
2569
2570	/* write status back to acknowledge interrupt */
2571	mfi_write(sc, MFI_OSTS, status);
2572
2573	return (1);
2574}
2575
2576void
2577mfi_xscale_post(struct mfi_softc *sc, struct mfi_ccb *ccb)
2578{
2579	mfi_write(sc, MFI_IQP, (ccb->ccb_pframe >> 3) |
2580	    ccb->ccb_extra_frames);
2581}
2582
2583u_int32_t
2584mfi_ppc_fw_state(struct mfi_softc *sc)
2585{
2586	return (mfi_read(sc, MFI_OSP));
2587}
2588
2589void
2590mfi_ppc_intr_ena(struct mfi_softc *sc)
2591{
2592	mfi_write(sc, MFI_ODC, 0xffffffff);
2593	mfi_write(sc, MFI_OMSK, ~0x80000004);
2594}
2595
2596int
2597mfi_ppc_intr(struct mfi_softc *sc)
2598{
2599	u_int32_t status;
2600
2601	status = mfi_read(sc, MFI_OSTS);
2602	if (!ISSET(status, MFI_OSTS_PPC_INTR_VALID))
2603		return (0);
2604
2605	/* write status back to acknowledge interrupt */
2606	mfi_write(sc, MFI_ODC, status);
2607
2608	return (1);
2609}
2610
2611void
2612mfi_ppc_post(struct mfi_softc *sc, struct mfi_ccb *ccb)
2613{
2614	mfi_write(sc, MFI_IQP, 0x1 | ccb->ccb_pframe |
2615	    (ccb->ccb_extra_frames << 1));
2616}
2617
2618u_int32_t
2619mfi_gen2_fw_state(struct mfi_softc *sc)
2620{
2621	return (mfi_read(sc, MFI_OSP));
2622}
2623
2624void
2625mfi_gen2_intr_ena(struct mfi_softc *sc)
2626{
2627	mfi_write(sc, MFI_ODC, 0xffffffff);
2628	mfi_write(sc, MFI_OMSK, ~MFI_OSTS_GEN2_INTR_VALID);
2629}
2630
2631int
2632mfi_gen2_intr(struct mfi_softc *sc)
2633{
2634	u_int32_t status;
2635
2636	status = mfi_read(sc, MFI_OSTS);
2637	if (!ISSET(status, MFI_OSTS_GEN2_INTR_VALID))
2638		return (0);
2639
2640	/* write status back to acknowledge interrupt */
2641	mfi_write(sc, MFI_ODC, status);
2642
2643	return (1);
2644}
2645
2646void
2647mfi_gen2_post(struct mfi_softc *sc, struct mfi_ccb *ccb)
2648{
2649	mfi_write(sc, MFI_IQP, 0x1 | ccb->ccb_pframe |
2650	    (ccb->ccb_extra_frames << 1));
2651}
2652
2653u_int32_t
2654mfi_skinny_fw_state(struct mfi_softc *sc)
2655{
2656	return (mfi_read(sc, MFI_OSP));
2657}
2658
2659void
2660mfi_skinny_intr_ena(struct mfi_softc *sc)
2661{
2662	mfi_write(sc, MFI_OMSK, ~0x00000001);
2663}
2664
2665int
2666mfi_skinny_intr(struct mfi_softc *sc)
2667{
2668	u_int32_t status;
2669
2670	status = mfi_read(sc, MFI_OSTS);
2671	if (!ISSET(status, MFI_OSTS_SKINNY_INTR_VALID))
2672		return (0);
2673
2674	/* write status back to acknowledge interrupt */
2675	mfi_write(sc, MFI_OSTS, status);
2676
2677	return (1);
2678}
2679
2680void
2681mfi_skinny_post(struct mfi_softc *sc, struct mfi_ccb *ccb)
2682{
2683	mfi_write(sc, MFI_IQPL, 0x1 | ccb->ccb_pframe |
2684	    (ccb->ccb_extra_frames << 1));
2685	mfi_write(sc, MFI_IQPH, 0x00000000);
2686}
2687
2688u_int
2689mfi_skinny_sgd_load(struct mfi_softc *sc, struct mfi_ccb *ccb)
2690{
2691	struct mfi_frame_header	*hdr = &ccb->ccb_frame->mfr_header;
2692	union mfi_sgl		*sgl = ccb->ccb_sgl;
2693	bus_dma_segment_t	*sgd = ccb->ccb_dmamap->dm_segs;
2694	int			 i;
2695
2696	switch (hdr->mfh_cmd) {
2697	case MFI_CMD_LD_READ:
2698	case MFI_CMD_LD_WRITE:
2699	case MFI_CMD_PD_SCSI_IO:
2700		/* Use MF_FRAME_IEEE for some IO commands on skinny adapters */
2701		for (i = 0; i < ccb->ccb_dmamap->dm_nsegs; i++) {
2702			sgl->sg_skinny[i].addr = htole64(sgd[i].ds_addr);
2703			sgl->sg_skinny[i].len = htole32(sgd[i].ds_len);
2704			sgl->sg_skinny[i].flag = 0;
2705		}
2706		hdr->mfh_flags |= MFI_FRAME_IEEE | MFI_FRAME_SGL64;
2707
2708		return (ccb->ccb_dmamap->dm_nsegs * sizeof(sgl->sg_skinny));
2709	default:
2710		return (mfi_default_sgd_load(sc, ccb));
2711	}
2712}
2713
2714int
2715mfi_pd_scsi_probe(struct scsi_link *link)
2716{
2717	union mfi_mbox mbox;
2718	struct mfi_softc *sc = link->bus->sb_adapter_softc;
2719	struct mfi_pd_link *pl = sc->sc_pd->pd_links[link->target];
2720
2721	if (link->lun > 0)
2722		return (0);
2723
2724	if (pl == NULL)
2725		return (ENXIO);
2726
2727	memset(&mbox, 0, sizeof(mbox));
2728	mbox.s[0] = pl->pd_id;
2729
2730	if (mfi_mgmt(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN,
2731	    sizeof(pl->pd_info), &pl->pd_info, &mbox))
2732		return (EIO);
2733
2734	if (letoh16(pl->pd_info.mpd_fw_state) != MFI_PD_SYSTEM)
2735		return (ENXIO);
2736
2737	return (0);
2738}
2739
2740void
2741mfi_pd_scsi_cmd(struct scsi_xfer *xs)
2742{
2743	struct scsi_link *link = xs->sc_link;
2744	struct mfi_softc *sc = link->bus->sb_adapter_softc;
2745	struct mfi_ccb *ccb = xs->io;
2746	struct mfi_pass_frame *pf = &ccb->ccb_frame->mfr_pass;
2747	struct mfi_pd_link *pl = sc->sc_pd->pd_links[link->target];
2748
2749	KERNEL_UNLOCK();
2750
2751	mfi_scrub_ccb(ccb);
2752	xs->error = XS_NOERROR;
2753
2754	pf->mpf_header.mfh_cmd = MFI_CMD_PD_SCSI_IO;
2755	pf->mpf_header.mfh_target_id = pl->pd_id;
2756	pf->mpf_header.mfh_lun_id = link->lun;
2757	pf->mpf_header.mfh_cdb_len = xs->cmdlen;
2758	pf->mpf_header.mfh_timeout = 0;
2759	pf->mpf_header.mfh_data_len = htole32(xs->datalen); /* XXX */
2760	pf->mpf_header.mfh_sense_len = MFI_SENSE_SIZE;
2761	pf->mpf_sense_addr = htole64(ccb->ccb_psense);
2762
2763	memset(pf->mpf_cdb, 0, sizeof(pf->mpf_cdb));
2764	memcpy(pf->mpf_cdb, &xs->cmd, xs->cmdlen);
2765
2766	ccb->ccb_done = mfi_scsi_xs_done;
2767	ccb->ccb_cookie = xs;
2768	ccb->ccb_frame_size = MFI_PASS_FRAME_SIZE;
2769	ccb->ccb_sgl = &pf->mpf_sgl;
2770
2771	if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT))
2772		ccb->ccb_direction = xs->flags & SCSI_DATA_IN ?
2773		    MFI_DATA_IN : MFI_DATA_OUT;
2774	else
2775		ccb->ccb_direction = MFI_DATA_NONE;
2776
2777	if (xs->data) {
2778		ccb->ccb_data = xs->data;
2779		ccb->ccb_len = xs->datalen;
2780
2781		if (mfi_create_sgl(sc, ccb, (xs->flags & SCSI_NOSLEEP) ?
2782		    BUS_DMA_NOWAIT : BUS_DMA_WAITOK))
2783			goto stuffup;
2784	}
2785
2786	if (xs->flags & SCSI_POLL)
2787		mfi_poll(sc, ccb);
2788	else
2789		mfi_start(sc, ccb);
2790
2791	KERNEL_LOCK();
2792	return;
2793
2794stuffup:
2795	xs->error = XS_DRIVER_STUFFUP;
2796	KERNEL_LOCK();
2797	scsi_done(xs);
2798}
2799