xref: /netbsd/sys/dev/pci/mfii.c (revision d82b910d)
1*d82b910dSbouyer /* $NetBSD: mfii.c,v 1.28 2022/09/29 10:27:02 bouyer Exp $ */
277961cf6Sbouyer /* $OpenBSD: mfii.c,v 1.58 2018/08/14 05:22:21 jmatthew Exp $ */
377961cf6Sbouyer 
477961cf6Sbouyer /*
5a59f2b68Sbouyer  * Copyright (c) 2018 Manuel Bouyer <Manuel.Bouyer@lip6.fr>
677961cf6Sbouyer  * Copyright (c) 2012 David Gwynne <dlg@openbsd.org>
777961cf6Sbouyer  *
877961cf6Sbouyer  * Permission to use, copy, modify, and distribute this software for any
977961cf6Sbouyer  * purpose with or without fee is hereby granted, provided that the above
1077961cf6Sbouyer  * copyright notice and this permission notice appear in all copies.
1177961cf6Sbouyer  *
1277961cf6Sbouyer  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1377961cf6Sbouyer  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1477961cf6Sbouyer  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1577961cf6Sbouyer  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1677961cf6Sbouyer  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1777961cf6Sbouyer  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1877961cf6Sbouyer  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1977961cf6Sbouyer  */
2077961cf6Sbouyer 
2177961cf6Sbouyer #include <sys/cdefs.h>
22*d82b910dSbouyer __KERNEL_RCSID(0, "$NetBSD: mfii.c,v 1.28 2022/09/29 10:27:02 bouyer Exp $");
2377961cf6Sbouyer 
2477961cf6Sbouyer #include "bio.h"
2577961cf6Sbouyer 
2677961cf6Sbouyer #include <sys/atomic.h>
2777961cf6Sbouyer #include <sys/param.h>
2877961cf6Sbouyer #include <sys/systm.h>
2977961cf6Sbouyer #include <sys/buf.h>
3077961cf6Sbouyer #include <sys/ioctl.h>
3177961cf6Sbouyer #include <sys/device.h>
3277961cf6Sbouyer #include <sys/kernel.h>
3377961cf6Sbouyer #include <sys/proc.h>
3477961cf6Sbouyer #include <sys/cpu.h>
3577961cf6Sbouyer #include <sys/conf.h>
3677961cf6Sbouyer #include <sys/kauth.h>
3777961cf6Sbouyer #include <sys/workqueue.h>
3877961cf6Sbouyer #include <sys/malloc.h>
3977961cf6Sbouyer 
4077961cf6Sbouyer #include <uvm/uvm_param.h>
4177961cf6Sbouyer 
4277961cf6Sbouyer #include <dev/pci/pcidevs.h>
4377961cf6Sbouyer #include <dev/pci/pcivar.h>
4477961cf6Sbouyer 
4577961cf6Sbouyer #include <sys/bus.h>
4677961cf6Sbouyer 
4777961cf6Sbouyer #include <dev/sysmon/sysmonvar.h>
4877961cf6Sbouyer #include <sys/envsys.h>
4977961cf6Sbouyer 
5077961cf6Sbouyer #include <dev/scsipi/scsipi_all.h>
5177961cf6Sbouyer #include <dev/scsipi/scsi_all.h>
5277961cf6Sbouyer #include <dev/scsipi/scsi_spc.h>
5377961cf6Sbouyer #include <dev/scsipi/scsipi_disk.h>
5477961cf6Sbouyer #include <dev/scsipi/scsi_disk.h>
5577961cf6Sbouyer #include <dev/scsipi/scsiconf.h>
5677961cf6Sbouyer 
5777961cf6Sbouyer #if NBIO > 0
5877961cf6Sbouyer #include <dev/biovar.h>
5977961cf6Sbouyer #endif /* NBIO > 0 */
6077961cf6Sbouyer 
6177961cf6Sbouyer #include <dev/ic/mfireg.h>
6277961cf6Sbouyer #include <dev/pci/mpiireg.h>
6377961cf6Sbouyer 
6477961cf6Sbouyer #define	MFII_BAR		0x14
6577961cf6Sbouyer #define MFII_BAR_35		0x10
6677961cf6Sbouyer #define	MFII_PCI_MEMSIZE	0x2000 /* 8k */
6777961cf6Sbouyer 
6877961cf6Sbouyer #define MFII_OSTS_INTR_VALID	0x00000009
6977961cf6Sbouyer #define MFII_RPI		0x6c /* reply post host index */
7077961cf6Sbouyer #define MFII_OSP2		0xb4 /* outbound scratch pad 2 */
7177961cf6Sbouyer #define MFII_OSP3		0xb8 /* outbound scratch pad 3 */
7277961cf6Sbouyer 
7377961cf6Sbouyer #define MFII_REQ_TYPE_SCSI	MPII_REQ_DESCR_SCSI_IO
7477961cf6Sbouyer #define MFII_REQ_TYPE_LDIO	(0x7 << 1)
7577961cf6Sbouyer #define MFII_REQ_TYPE_MFA	(0x1 << 1)
7677961cf6Sbouyer #define MFII_REQ_TYPE_NO_LOCK	(0x2 << 1)
7777961cf6Sbouyer #define MFII_REQ_TYPE_HI_PRI	(0x6 << 1)
7877961cf6Sbouyer 
7977961cf6Sbouyer #define MFII_REQ_MFA(_a)	htole64((_a) | MFII_REQ_TYPE_MFA)
8077961cf6Sbouyer 
8177961cf6Sbouyer #define MFII_FUNCTION_PASSTHRU_IO			(0xf0)
8277961cf6Sbouyer #define MFII_FUNCTION_LDIO_REQUEST			(0xf1)
8377961cf6Sbouyer 
8477961cf6Sbouyer #define MFII_MAX_CHAIN_UNIT	0x00400000
8577961cf6Sbouyer #define MFII_MAX_CHAIN_MASK	0x000003E0
8677961cf6Sbouyer #define MFII_MAX_CHAIN_SHIFT	5
8777961cf6Sbouyer 
8877961cf6Sbouyer #define MFII_256K_IO		128
8977961cf6Sbouyer #define MFII_1MB_IO		(MFII_256K_IO * 4)
9077961cf6Sbouyer 
9177961cf6Sbouyer #define MFII_CHAIN_FRAME_MIN	1024
9277961cf6Sbouyer 
9377961cf6Sbouyer struct mfii_request_descr {
9477961cf6Sbouyer 	u_int8_t	flags;
9577961cf6Sbouyer 	u_int8_t	msix_index;
9677961cf6Sbouyer 	u_int16_t	smid;
9777961cf6Sbouyer 
9877961cf6Sbouyer 	u_int16_t	lmid;
9977961cf6Sbouyer 	u_int16_t	dev_handle;
10077961cf6Sbouyer } __packed;
10177961cf6Sbouyer 
10277961cf6Sbouyer #define MFII_RAID_CTX_IO_TYPE_SYSPD	(0x1 << 4)
10377961cf6Sbouyer #define MFII_RAID_CTX_TYPE_CUDA		(0x2 << 4)
10477961cf6Sbouyer 
10577961cf6Sbouyer struct mfii_raid_context {
10677961cf6Sbouyer 	u_int8_t	type_nseg;
10777961cf6Sbouyer 	u_int8_t	_reserved1;
10877961cf6Sbouyer 	u_int16_t	timeout_value;
10977961cf6Sbouyer 
11077961cf6Sbouyer 	u_int16_t	reg_lock_flags;
11177961cf6Sbouyer #define MFII_RAID_CTX_RL_FLAGS_SEQNO_EN	(0x08)
11277961cf6Sbouyer #define MFII_RAID_CTX_RL_FLAGS_CPU0	(0x00)
11377961cf6Sbouyer #define MFII_RAID_CTX_RL_FLAGS_CPU1	(0x10)
11477961cf6Sbouyer #define MFII_RAID_CTX_RL_FLAGS_CUDA	(0x80)
11577961cf6Sbouyer 
11677961cf6Sbouyer #define MFII_RAID_CTX_ROUTING_FLAGS_SQN	(1 << 4)
11777961cf6Sbouyer #define MFII_RAID_CTX_ROUTING_FLAGS_CPU0 0
11877961cf6Sbouyer 	u_int16_t	virtual_disk_target_id;
11977961cf6Sbouyer 
12077961cf6Sbouyer 	u_int64_t	reg_lock_row_lba;
12177961cf6Sbouyer 
12277961cf6Sbouyer 	u_int32_t	reg_lock_length;
12377961cf6Sbouyer 
12477961cf6Sbouyer 	u_int16_t	next_lm_id;
12577961cf6Sbouyer 	u_int8_t	ex_status;
12677961cf6Sbouyer 	u_int8_t	status;
12777961cf6Sbouyer 
12877961cf6Sbouyer 	u_int8_t	raid_flags;
12977961cf6Sbouyer 	u_int8_t	num_sge;
13077961cf6Sbouyer 	u_int16_t	config_seq_num;
13177961cf6Sbouyer 
13277961cf6Sbouyer 	u_int8_t	span_arm;
13377961cf6Sbouyer 	u_int8_t	_reserved3[3];
13477961cf6Sbouyer } __packed;
13577961cf6Sbouyer 
13677961cf6Sbouyer struct mfii_sge {
13777961cf6Sbouyer 	u_int64_t	sg_addr;
13877961cf6Sbouyer 	u_int32_t	sg_len;
13977961cf6Sbouyer 	u_int16_t	_reserved;
14077961cf6Sbouyer 	u_int8_t	sg_next_chain_offset;
14177961cf6Sbouyer 	u_int8_t	sg_flags;
14277961cf6Sbouyer } __packed;
14377961cf6Sbouyer 
14477961cf6Sbouyer #define MFII_SGE_ADDR_MASK		(0x03)
14577961cf6Sbouyer #define MFII_SGE_ADDR_SYSTEM		(0x00)
14677961cf6Sbouyer #define MFII_SGE_ADDR_IOCDDR		(0x01)
14777961cf6Sbouyer #define MFII_SGE_ADDR_IOCPLB		(0x02)
14877961cf6Sbouyer #define MFII_SGE_ADDR_IOCPLBNTA		(0x03)
14977961cf6Sbouyer #define MFII_SGE_END_OF_LIST		(0x40)
15077961cf6Sbouyer #define MFII_SGE_CHAIN_ELEMENT		(0x80)
15177961cf6Sbouyer 
15277961cf6Sbouyer #define MFII_REQUEST_SIZE	256
15377961cf6Sbouyer 
15477961cf6Sbouyer #define MR_DCMD_LD_MAP_GET_INFO			0x0300e101
15577961cf6Sbouyer 
15677961cf6Sbouyer #define MFII_MAX_ROW		32
15777961cf6Sbouyer #define MFII_MAX_ARRAY		128
15877961cf6Sbouyer 
15977961cf6Sbouyer struct mfii_array_map {
16077961cf6Sbouyer 	uint16_t		mam_pd[MFII_MAX_ROW];
16177961cf6Sbouyer } __packed;
16277961cf6Sbouyer 
16377961cf6Sbouyer struct mfii_dev_handle {
16477961cf6Sbouyer 	uint16_t		mdh_cur_handle;
16577961cf6Sbouyer 	uint8_t			mdh_valid;
16677961cf6Sbouyer 	uint8_t			mdh_reserved;
16777961cf6Sbouyer 	uint16_t		mdh_handle[2];
16877961cf6Sbouyer } __packed;
16977961cf6Sbouyer 
17077961cf6Sbouyer struct mfii_ld_map {
17177961cf6Sbouyer 	uint32_t		mlm_total_size;
17277961cf6Sbouyer 	uint32_t		mlm_reserved1[5];
17377961cf6Sbouyer 	uint32_t		mlm_num_lds;
17477961cf6Sbouyer 	uint32_t		mlm_reserved2;
17577961cf6Sbouyer 	uint8_t			mlm_tgtid_to_ld[2 * MFI_MAX_LD];
17677961cf6Sbouyer 	uint8_t			mlm_pd_timeout;
17777961cf6Sbouyer 	uint8_t			mlm_reserved3[7];
17877961cf6Sbouyer 	struct mfii_array_map	mlm_am[MFII_MAX_ARRAY];
17977961cf6Sbouyer 	struct mfii_dev_handle	mlm_dev_handle[MFI_MAX_PD];
18077961cf6Sbouyer } __packed;
18177961cf6Sbouyer 
18277961cf6Sbouyer struct mfii_task_mgmt {
18377961cf6Sbouyer 	union {
18477961cf6Sbouyer 		uint8_t			request[128];
18577961cf6Sbouyer 		struct mpii_msg_scsi_task_request
18677961cf6Sbouyer 					mpii_request;
18777961cf6Sbouyer 	} __packed __aligned(8);
18877961cf6Sbouyer 
18977961cf6Sbouyer 	union {
19077961cf6Sbouyer 		uint8_t			reply[128];
19177961cf6Sbouyer 		uint32_t		flags;
19277961cf6Sbouyer #define MFII_TASK_MGMT_FLAGS_LD				(1 << 0)
19377961cf6Sbouyer #define MFII_TASK_MGMT_FLAGS_PD				(1 << 1)
19477961cf6Sbouyer 		struct mpii_msg_scsi_task_reply
19577961cf6Sbouyer 					mpii_reply;
19677961cf6Sbouyer 	} __packed __aligned(8);
19777961cf6Sbouyer } __packed __aligned(8);
19877961cf6Sbouyer 
19977961cf6Sbouyer /* We currently don't know the full details of the following struct */
20077961cf6Sbouyer struct mfii_foreign_scan_cfg {
20177961cf6Sbouyer 	char data[24];
20277961cf6Sbouyer } __packed;
20377961cf6Sbouyer 
20477961cf6Sbouyer struct mfii_foreign_scan_info {
20577961cf6Sbouyer 	uint32_t count; /* Number of foreign configs found */
20677961cf6Sbouyer 	struct mfii_foreign_scan_cfg cfgs[8];
20777961cf6Sbouyer } __packed;
20877961cf6Sbouyer 
209c6bee2b8Smsaitoh #define MFII_MAX_LD_EXT		256
210c6bee2b8Smsaitoh 
211c6bee2b8Smsaitoh struct mfii_ld_list_ext {
212c6bee2b8Smsaitoh 	uint32_t		mll_no_ld;
213c6bee2b8Smsaitoh 	uint32_t		mll_res;
214c6bee2b8Smsaitoh 	struct {
215c6bee2b8Smsaitoh 		struct mfi_ld	mll_ld;
216c6bee2b8Smsaitoh 		uint8_t		mll_state; /* states are the same as MFI_ */
217c6bee2b8Smsaitoh 		uint8_t		mll_res2;
218c6bee2b8Smsaitoh 		uint8_t		mll_res3;
219c6bee2b8Smsaitoh 		uint8_t		mll_res4;
220c6bee2b8Smsaitoh 		uint64_t	mll_size;
221c6bee2b8Smsaitoh 	} mll_list[MFII_MAX_LD_EXT];
222c6bee2b8Smsaitoh } __packed;
223c6bee2b8Smsaitoh 
22477961cf6Sbouyer struct mfii_dmamem {
22577961cf6Sbouyer 	bus_dmamap_t		mdm_map;
22677961cf6Sbouyer 	bus_dma_segment_t	mdm_seg;
22777961cf6Sbouyer 	size_t			mdm_size;
22877961cf6Sbouyer 	void *			mdm_kva;
22977961cf6Sbouyer };
23077961cf6Sbouyer #define MFII_DMA_MAP(_mdm)	((_mdm)->mdm_map)
23177961cf6Sbouyer #define MFII_DMA_LEN(_mdm)	((_mdm)->mdm_size)
23277961cf6Sbouyer #define MFII_DMA_DVA(_mdm)	((u_int64_t)(_mdm)->mdm_map->dm_segs[0].ds_addr)
23377961cf6Sbouyer #define MFII_DMA_KVA(_mdm)	((void *)(_mdm)->mdm_kva)
23477961cf6Sbouyer 
23577961cf6Sbouyer struct mfii_softc;
23677961cf6Sbouyer 
23777961cf6Sbouyer typedef enum mfii_direction {
23877961cf6Sbouyer 	MFII_DATA_NONE = 0,
23977961cf6Sbouyer 	MFII_DATA_IN,
24077961cf6Sbouyer 	MFII_DATA_OUT
24177961cf6Sbouyer } mfii_direction_t;
24277961cf6Sbouyer 
24377961cf6Sbouyer struct mfii_ccb {
24477961cf6Sbouyer 	struct mfii_softc	*ccb_sc;
24577961cf6Sbouyer 	void			*ccb_request;
24677961cf6Sbouyer 	u_int64_t		ccb_request_dva;
24777961cf6Sbouyer 	bus_addr_t		ccb_request_offset;
24877961cf6Sbouyer 
24977961cf6Sbouyer 	void			*ccb_mfi;
25077961cf6Sbouyer 	u_int64_t		ccb_mfi_dva;
25177961cf6Sbouyer 	bus_addr_t		ccb_mfi_offset;
25277961cf6Sbouyer 
25377961cf6Sbouyer 	struct mfi_sense	*ccb_sense;
25477961cf6Sbouyer 	u_int64_t		ccb_sense_dva;
25577961cf6Sbouyer 	bus_addr_t		ccb_sense_offset;
25677961cf6Sbouyer 
25777961cf6Sbouyer 	struct mfii_sge		*ccb_sgl;
25877961cf6Sbouyer 	u_int64_t		ccb_sgl_dva;
25977961cf6Sbouyer 	bus_addr_t		ccb_sgl_offset;
26077961cf6Sbouyer 	u_int			ccb_sgl_len;
26177961cf6Sbouyer 
26277961cf6Sbouyer 	struct mfii_request_descr ccb_req;
26377961cf6Sbouyer 
26477961cf6Sbouyer 	bus_dmamap_t		ccb_dmamap64;
26577961cf6Sbouyer 	bus_dmamap_t		ccb_dmamap32;
26677961cf6Sbouyer 	bool			ccb_dma64;
26777961cf6Sbouyer 
26877961cf6Sbouyer 	/* data for sgl */
26977961cf6Sbouyer 	void			*ccb_data;
27077961cf6Sbouyer 	size_t			ccb_len;
27177961cf6Sbouyer 
27277961cf6Sbouyer 	mfii_direction_t	ccb_direction;
27377961cf6Sbouyer 
27477961cf6Sbouyer 	void			*ccb_cookie;
27577961cf6Sbouyer 	kmutex_t		ccb_mtx;
27677961cf6Sbouyer 	kcondvar_t		ccb_cv;
27777961cf6Sbouyer 	void			(*ccb_done)(struct mfii_softc *,
27877961cf6Sbouyer 				    struct mfii_ccb *);
27977961cf6Sbouyer 
28077961cf6Sbouyer 	u_int32_t		ccb_flags;
28177961cf6Sbouyer #define MFI_CCB_F_ERR			(1<<0)
28277961cf6Sbouyer 	u_int			ccb_smid;
28377961cf6Sbouyer 	SIMPLEQ_ENTRY(mfii_ccb)	ccb_link;
28477961cf6Sbouyer };
28577961cf6Sbouyer SIMPLEQ_HEAD(mfii_ccb_list, mfii_ccb);
28677961cf6Sbouyer 
28777961cf6Sbouyer struct mfii_iop {
28877961cf6Sbouyer 	int bar;
28977961cf6Sbouyer 	int num_sge_loc;
29077961cf6Sbouyer #define MFII_IOP_NUM_SGE_LOC_ORIG	0
29177961cf6Sbouyer #define MFII_IOP_NUM_SGE_LOC_35		1
29277961cf6Sbouyer 	u_int16_t ldio_ctx_reg_lock_flags;
29377961cf6Sbouyer 	u_int8_t ldio_req_type;
29477961cf6Sbouyer 	u_int8_t ldio_ctx_type_nseg;
29577961cf6Sbouyer 	u_int8_t sge_flag_chain;
29677961cf6Sbouyer 	u_int8_t sge_flag_eol;
297e490de0bSmsaitoh 	u_int8_t iop_flag;
298e490de0bSmsaitoh #define MFII_IOP_QUIRK_REGREAD		0x01
299e490de0bSmsaitoh #define MFII_IOP_HAS_32BITDESC_BIT	0x02
30077961cf6Sbouyer };
30177961cf6Sbouyer 
30277961cf6Sbouyer struct mfii_softc {
30377961cf6Sbouyer 	device_t		sc_dev;
30477961cf6Sbouyer 	struct scsipi_channel   sc_chan;
30577961cf6Sbouyer 	struct scsipi_adapter   sc_adapt;
30677961cf6Sbouyer 
30777961cf6Sbouyer 	const struct mfii_iop	*sc_iop;
308e490de0bSmsaitoh 	u_int			sc_iop_flag;
309e490de0bSmsaitoh #define MFII_IOP_DESC_32BIT		0x01
31077961cf6Sbouyer 
31177961cf6Sbouyer 	pci_chipset_tag_t	sc_pc;
31277961cf6Sbouyer 	pcitag_t		sc_tag;
31377961cf6Sbouyer 
31477961cf6Sbouyer 	bus_space_tag_t		sc_iot;
31577961cf6Sbouyer 	bus_space_handle_t	sc_ioh;
31677961cf6Sbouyer 	bus_size_t		sc_ios;
31777961cf6Sbouyer 	bus_dma_tag_t		sc_dmat;
31877961cf6Sbouyer 	bus_dma_tag_t		sc_dmat64;
31977961cf6Sbouyer 	bool			sc_64bit_dma;
32077961cf6Sbouyer 
32177961cf6Sbouyer 	void			*sc_ih;
32277961cf6Sbouyer 
32377961cf6Sbouyer 	kmutex_t		sc_ccb_mtx;
32477961cf6Sbouyer 	kmutex_t		sc_post_mtx;
32577961cf6Sbouyer 
32677961cf6Sbouyer 	u_int			sc_max_fw_cmds;
32777961cf6Sbouyer 	u_int			sc_max_cmds;
32877961cf6Sbouyer 	u_int			sc_max_sgl;
32977961cf6Sbouyer 
33077961cf6Sbouyer 	u_int			sc_reply_postq_depth;
33177961cf6Sbouyer 	u_int			sc_reply_postq_index;
33277961cf6Sbouyer 	kmutex_t		sc_reply_postq_mtx;
33377961cf6Sbouyer 	struct mfii_dmamem	*sc_reply_postq;
33477961cf6Sbouyer 
33577961cf6Sbouyer 	struct mfii_dmamem	*sc_requests;
33677961cf6Sbouyer 	struct mfii_dmamem	*sc_mfi;
33777961cf6Sbouyer 	struct mfii_dmamem	*sc_sense;
33877961cf6Sbouyer 	struct mfii_dmamem	*sc_sgl;
33977961cf6Sbouyer 
34077961cf6Sbouyer 	struct mfii_ccb		*sc_ccb;
34177961cf6Sbouyer 	struct mfii_ccb_list	sc_ccb_freeq;
34277961cf6Sbouyer 
34377961cf6Sbouyer 	struct mfii_ccb		*sc_aen_ccb;
34477961cf6Sbouyer 	struct workqueue	*sc_aen_wq;
34577961cf6Sbouyer 	struct work		sc_aen_work;
34677961cf6Sbouyer 
34777961cf6Sbouyer 	kmutex_t		sc_abort_mtx;
34877961cf6Sbouyer 	struct mfii_ccb_list	sc_abort_list;
34977961cf6Sbouyer 	struct workqueue	*sc_abort_wq;
35077961cf6Sbouyer 	struct work		sc_abort_work;
35177961cf6Sbouyer 
35277961cf6Sbouyer 	/* save some useful information for logical drives that is missing
35377961cf6Sbouyer 	 * in sc_ld_list
35477961cf6Sbouyer 	 */
35577961cf6Sbouyer 	struct {
35677961cf6Sbouyer 		bool		ld_present;
35777961cf6Sbouyer 		char		ld_dev[16];	/* device name sd? */
3583b643292Smsaitoh 		int		ld_target_id;
359c6bee2b8Smsaitoh 	}			sc_ld[MFII_MAX_LD_EXT];
360c6bee2b8Smsaitoh 	int			sc_target_lds[MFII_MAX_LD_EXT];
361c6bee2b8Smsaitoh 	bool			sc_max256vd;
36277961cf6Sbouyer 
36377961cf6Sbouyer 	/* bio */
36477961cf6Sbouyer 	struct mfi_conf		*sc_cfg;
36577961cf6Sbouyer 	struct mfi_ctrl_info	sc_info;
366c6bee2b8Smsaitoh 	struct mfii_ld_list_ext	sc_ld_list;
36777961cf6Sbouyer 	struct mfi_ld_details	*sc_ld_details; /* array to all logical disks */
36877961cf6Sbouyer 	int			sc_no_pd; /* used physical disks */
36977961cf6Sbouyer 	int			sc_ld_sz; /* sizeof sc_ld_details */
37077961cf6Sbouyer 
37177961cf6Sbouyer 	/* mgmt lock */
37277961cf6Sbouyer 	kmutex_t		sc_lock;
37377961cf6Sbouyer 	bool			sc_running;
37477961cf6Sbouyer 
37577961cf6Sbouyer 	/* sensors */
37677961cf6Sbouyer 	struct sysmon_envsys	*sc_sme;
37777961cf6Sbouyer 	envsys_data_t		*sc_sensors;
37877961cf6Sbouyer 	bool			sc_bbuok;
37977961cf6Sbouyer 
38077961cf6Sbouyer 	device_t		sc_child;
38177961cf6Sbouyer };
38277961cf6Sbouyer 
38377961cf6Sbouyer // #define MFII_DEBUG
38477961cf6Sbouyer #ifdef MFII_DEBUG
38577961cf6Sbouyer #define DPRINTF(x...)		do { if (mfii_debug) printf(x); } while(0)
38677961cf6Sbouyer #define DNPRINTF(n,x...)	do { if (mfii_debug & n) printf(x); } while(0)
38777961cf6Sbouyer #define	MFII_D_CMD		0x0001
38877961cf6Sbouyer #define	MFII_D_INTR		0x0002
38977961cf6Sbouyer #define	MFII_D_MISC		0x0004
39077961cf6Sbouyer #define	MFII_D_DMA		0x0008
39177961cf6Sbouyer #define	MFII_D_IOCTL		0x0010
39277961cf6Sbouyer #define	MFII_D_RW		0x0020
39377961cf6Sbouyer #define	MFII_D_MEM		0x0040
39477961cf6Sbouyer #define	MFII_D_CCB		0x0080
39577961cf6Sbouyer uint32_t	mfii_debug = 0
39677961cf6Sbouyer /*		    | MFII_D_CMD */
39777961cf6Sbouyer /*		    | MFII_D_INTR */
39877961cf6Sbouyer 		    | MFII_D_MISC
39977961cf6Sbouyer /*		    | MFII_D_DMA */
40077961cf6Sbouyer /*		    | MFII_D_IOCTL */
40177961cf6Sbouyer /*		    | MFII_D_RW */
40277961cf6Sbouyer /*		    | MFII_D_MEM */
40377961cf6Sbouyer /*		    | MFII_D_CCB */
40477961cf6Sbouyer 		;
40577961cf6Sbouyer #else
40677961cf6Sbouyer #define DPRINTF(x...)
40777961cf6Sbouyer #define DNPRINTF(n,x...)
40877961cf6Sbouyer #endif
40977961cf6Sbouyer 
410bfa22340Smaxv static int	mfii_match(device_t, cfdata_t, void *);
411bfa22340Smaxv static void	mfii_attach(device_t, device_t, void *);
412bfa22340Smaxv static int	mfii_detach(device_t, int);
413bfa22340Smaxv static int	mfii_rescan(device_t, const char *, const int *);
414bfa22340Smaxv static void	mfii_childdetached(device_t, device_t);
41577961cf6Sbouyer static bool	mfii_suspend(device_t, const pmf_qual_t *);
41677961cf6Sbouyer static bool	mfii_resume(device_t, const pmf_qual_t *);
41777961cf6Sbouyer static bool	mfii_shutdown(device_t, int);
41877961cf6Sbouyer 
41977961cf6Sbouyer 
42077961cf6Sbouyer CFATTACH_DECL3_NEW(mfii, sizeof(struct mfii_softc),
42177961cf6Sbouyer     mfii_match, mfii_attach, mfii_detach, NULL, mfii_rescan,
42277961cf6Sbouyer 	mfii_childdetached, DVF_DETACH_SHUTDOWN);
42377961cf6Sbouyer 
424bfa22340Smaxv static void	mfii_scsipi_request(struct scsipi_channel *,
42577961cf6Sbouyer 			scsipi_adapter_req_t, void *);
426bfa22340Smaxv static void	mfii_scsi_cmd_done(struct mfii_softc *, struct mfii_ccb *);
42777961cf6Sbouyer 
42877961cf6Sbouyer #define DEVNAME(_sc)		(device_xname((_sc)->sc_dev))
42977961cf6Sbouyer 
43077961cf6Sbouyer static u_int32_t	mfii_read(struct mfii_softc *, bus_size_t);
43177961cf6Sbouyer static void		mfii_write(struct mfii_softc *, bus_size_t, u_int32_t);
43277961cf6Sbouyer 
433bfa22340Smaxv static struct mfii_dmamem *	mfii_dmamem_alloc(struct mfii_softc *, size_t);
434bfa22340Smaxv static void		mfii_dmamem_free(struct mfii_softc *,
43577961cf6Sbouyer 			    struct mfii_dmamem *);
43677961cf6Sbouyer 
437bfa22340Smaxv static struct mfii_ccb *	mfii_get_ccb(struct mfii_softc *);
438bfa22340Smaxv static void		mfii_put_ccb(struct mfii_softc *, struct mfii_ccb *);
439bfa22340Smaxv static int		mfii_init_ccb(struct mfii_softc *);
440bfa22340Smaxv static void		mfii_scrub_ccb(struct mfii_ccb *);
44177961cf6Sbouyer 
442bfa22340Smaxv static int		mfii_transition_firmware(struct mfii_softc *);
443bfa22340Smaxv static int		mfii_initialise_firmware(struct mfii_softc *);
444bfa22340Smaxv static int		mfii_get_info(struct mfii_softc *);
44577961cf6Sbouyer 
446bfa22340Smaxv static void		mfii_start(struct mfii_softc *, struct mfii_ccb *);
447e490de0bSmsaitoh static void		mfii_start64(struct mfii_softc *, struct mfii_ccb *);
448e490de0bSmsaitoh static void		mfii_start_common(struct mfii_softc *,
449e490de0bSmsaitoh 			    struct mfii_ccb *, bool);
450bfa22340Smaxv static void		mfii_done(struct mfii_softc *, struct mfii_ccb *);
451bfa22340Smaxv static int		mfii_poll(struct mfii_softc *, struct mfii_ccb *);
452bfa22340Smaxv static void		mfii_poll_done(struct mfii_softc *, struct mfii_ccb *);
453bfa22340Smaxv static int		mfii_exec(struct mfii_softc *, struct mfii_ccb *);
454bfa22340Smaxv static void		mfii_exec_done(struct mfii_softc *, struct mfii_ccb *);
455bfa22340Smaxv static int		mfii_my_intr(struct mfii_softc *);
456bfa22340Smaxv static int		mfii_intr(void *);
457bfa22340Smaxv static void		mfii_postq(struct mfii_softc *);
45877961cf6Sbouyer 
459bfa22340Smaxv static int		mfii_load_ccb(struct mfii_softc *, struct mfii_ccb *,
46077961cf6Sbouyer 			    void *, int);
461bfa22340Smaxv static int		mfii_load_mfa(struct mfii_softc *, struct mfii_ccb *,
46277961cf6Sbouyer 			    void *, int);
46377961cf6Sbouyer 
464bfa22340Smaxv static int		mfii_mfa_poll(struct mfii_softc *, struct mfii_ccb *);
46577961cf6Sbouyer 
466bfa22340Smaxv static int		mfii_mgmt(struct mfii_softc *, uint32_t,
46777961cf6Sbouyer 			    const union mfi_mbox *, void *, size_t,
46877961cf6Sbouyer 			    mfii_direction_t, bool);
469bfa22340Smaxv static int		mfii_do_mgmt(struct mfii_softc *, struct mfii_ccb *,
47077961cf6Sbouyer 			    uint32_t, const union mfi_mbox *, void *, size_t,
47177961cf6Sbouyer 			    mfii_direction_t, bool);
472bfa22340Smaxv static void		mfii_empty_done(struct mfii_softc *, struct mfii_ccb *);
47377961cf6Sbouyer 
474bfa22340Smaxv static int		mfii_scsi_cmd_io(struct mfii_softc *,
47577961cf6Sbouyer 			    struct mfii_ccb *, struct scsipi_xfer *);
476bfa22340Smaxv static int		mfii_scsi_cmd_cdb(struct mfii_softc *,
47777961cf6Sbouyer 			    struct mfii_ccb *, struct scsipi_xfer *);
478bfa22340Smaxv static void		mfii_scsi_cmd_tmo(void *);
47977961cf6Sbouyer 
480bfa22340Smaxv static void		mfii_abort_task(struct work *, void *);
481bfa22340Smaxv static void		mfii_abort(struct mfii_softc *, struct mfii_ccb *,
48277961cf6Sbouyer 			    uint16_t, uint16_t, uint8_t, uint32_t);
483bfa22340Smaxv static void		mfii_scsi_cmd_abort_done(struct mfii_softc *,
48477961cf6Sbouyer 			    struct mfii_ccb *);
48577961cf6Sbouyer 
486bfa22340Smaxv static int		mfii_aen_register(struct mfii_softc *);
487bfa22340Smaxv static void		mfii_aen_start(struct mfii_softc *, struct mfii_ccb *,
48877961cf6Sbouyer 			    struct mfii_dmamem *, uint32_t);
489bfa22340Smaxv static void		mfii_aen_done(struct mfii_softc *, struct mfii_ccb *);
490bfa22340Smaxv static void		mfii_aen(struct work *, void *);
491bfa22340Smaxv static void		mfii_aen_unregister(struct mfii_softc *);
49277961cf6Sbouyer 
493bfa22340Smaxv static void		mfii_aen_pd_insert(struct mfii_softc *,
49477961cf6Sbouyer 			    const struct mfi_evtarg_pd_address *);
495bfa22340Smaxv static void		mfii_aen_pd_remove(struct mfii_softc *,
49677961cf6Sbouyer 			    const struct mfi_evtarg_pd_address *);
497bfa22340Smaxv static void		mfii_aen_pd_state_change(struct mfii_softc *,
49877961cf6Sbouyer 			    const struct mfi_evtarg_pd_state *);
499bfa22340Smaxv static void		mfii_aen_ld_update(struct mfii_softc *);
50077961cf6Sbouyer 
50177961cf6Sbouyer #if NBIO > 0
502bfa22340Smaxv static int	mfii_ioctl(device_t, u_long, void *);
503bfa22340Smaxv static int	mfii_ioctl_inq(struct mfii_softc *, struct bioc_inq *);
504bfa22340Smaxv static int	mfii_ioctl_vol(struct mfii_softc *, struct bioc_vol *);
505bfa22340Smaxv static int	mfii_ioctl_disk(struct mfii_softc *, struct bioc_disk *);
506bfa22340Smaxv static int	mfii_ioctl_alarm(struct mfii_softc *, struct bioc_alarm *);
507bfa22340Smaxv static int	mfii_ioctl_blink(struct mfii_softc *sc, struct bioc_blink *);
508bfa22340Smaxv static int	mfii_ioctl_setstate(struct mfii_softc *,
50977961cf6Sbouyer 		    struct bioc_setstate *);
510bfa22340Smaxv static int	mfii_bio_hs(struct mfii_softc *, int, int, void *);
511bfa22340Smaxv static int	mfii_bio_getitall(struct mfii_softc *);
51277961cf6Sbouyer #endif /* NBIO > 0 */
51377961cf6Sbouyer 
51477961cf6Sbouyer #if 0
51577961cf6Sbouyer static const char *mfi_bbu_indicators[] = {
51677961cf6Sbouyer 	"pack missing",
51777961cf6Sbouyer 	"voltage low",
51877961cf6Sbouyer 	"temp high",
51977961cf6Sbouyer 	"charge active",
52077961cf6Sbouyer 	"discharge active",
52177961cf6Sbouyer 	"learn cycle req'd",
52277961cf6Sbouyer 	"learn cycle active",
52377961cf6Sbouyer 	"learn cycle failed",
52477961cf6Sbouyer 	"learn cycle timeout",
52577961cf6Sbouyer 	"I2C errors",
52677961cf6Sbouyer 	"replace pack",
52777961cf6Sbouyer 	"low capacity",
52877961cf6Sbouyer 	"periodic learn req'd"
52977961cf6Sbouyer };
53077961cf6Sbouyer #endif
53177961cf6Sbouyer 
532bfa22340Smaxv static void	mfii_init_ld_sensor(struct mfii_softc *, envsys_data_t *, int);
533bfa22340Smaxv static void	mfii_refresh_ld_sensor(struct mfii_softc *, envsys_data_t *);
53477961cf6Sbouyer static void	mfii_attach_sensor(struct mfii_softc *, envsys_data_t *);
535bfa22340Smaxv static int	mfii_create_sensors(struct mfii_softc *);
53677961cf6Sbouyer static int	mfii_destroy_sensors(struct mfii_softc *);
537bfa22340Smaxv static void	mfii_refresh_sensor(struct sysmon_envsys *, envsys_data_t *);
538bfa22340Smaxv static void	mfii_bbu(struct mfii_softc *, envsys_data_t *);
53977961cf6Sbouyer 
54077961cf6Sbouyer /*
54177961cf6Sbouyer  * mfii boards support asynchronous (and non-polled) completion of
54277961cf6Sbouyer  * dcmds by proxying them through a passthru mpii command that points
54377961cf6Sbouyer  * at a dcmd frame. since the passthru command is submitted like
54477961cf6Sbouyer  * the scsi commands using an SMID in the request descriptor,
54577961cf6Sbouyer  * ccb_request memory * must contain the passthru command because
54677961cf6Sbouyer  * that is what the SMID refers to. this means ccb_request cannot
54777961cf6Sbouyer  * contain the dcmd. rather than allocating separate dma memory to
54877961cf6Sbouyer  * hold the dcmd, we reuse the sense memory buffer for it.
54977961cf6Sbouyer  */
55077961cf6Sbouyer 
551bfa22340Smaxv static void	mfii_dcmd_start(struct mfii_softc *, struct mfii_ccb *);
55277961cf6Sbouyer 
55377961cf6Sbouyer static inline void
mfii_dcmd_scrub(struct mfii_ccb * ccb)55477961cf6Sbouyer mfii_dcmd_scrub(struct mfii_ccb *ccb)
55577961cf6Sbouyer {
55677961cf6Sbouyer 	memset(ccb->ccb_sense, 0, sizeof(*ccb->ccb_sense));
55777961cf6Sbouyer }
55877961cf6Sbouyer 
55977961cf6Sbouyer static inline struct mfi_dcmd_frame *
mfii_dcmd_frame(struct mfii_ccb * ccb)56077961cf6Sbouyer mfii_dcmd_frame(struct mfii_ccb *ccb)
56177961cf6Sbouyer {
56277961cf6Sbouyer 	CTASSERT(sizeof(struct mfi_dcmd_frame) <= sizeof(*ccb->ccb_sense));
56377961cf6Sbouyer 	return ((struct mfi_dcmd_frame *)ccb->ccb_sense);
56477961cf6Sbouyer }
56577961cf6Sbouyer 
56677961cf6Sbouyer static inline void
mfii_dcmd_sync(struct mfii_softc * sc,struct mfii_ccb * ccb,int flags)56777961cf6Sbouyer mfii_dcmd_sync(struct mfii_softc *sc, struct mfii_ccb *ccb, int flags)
56877961cf6Sbouyer {
56977961cf6Sbouyer 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_sense),
57077961cf6Sbouyer 	    ccb->ccb_sense_offset, sizeof(*ccb->ccb_sense), flags);
57177961cf6Sbouyer }
57277961cf6Sbouyer 
57377961cf6Sbouyer #define mfii_fw_state(_sc) mfii_read((_sc), MFI_OSP)
57477961cf6Sbouyer 
575bfa22340Smaxv static const struct mfii_iop mfii_iop_thunderbolt = {
57677961cf6Sbouyer 	MFII_BAR,
57777961cf6Sbouyer 	MFII_IOP_NUM_SGE_LOC_ORIG,
57877961cf6Sbouyer 	0,
57977961cf6Sbouyer 	MFII_REQ_TYPE_LDIO,
58077961cf6Sbouyer 	0,
58177961cf6Sbouyer 	MFII_SGE_CHAIN_ELEMENT | MFII_SGE_ADDR_IOCPLBNTA,
582e490de0bSmsaitoh 	0,
58377961cf6Sbouyer 	0
58477961cf6Sbouyer };
58577961cf6Sbouyer 
58677961cf6Sbouyer /*
58777961cf6Sbouyer  * a lot of these values depend on us not implementing fastpath yet.
58877961cf6Sbouyer  */
589bfa22340Smaxv static const struct mfii_iop mfii_iop_25 = {
59077961cf6Sbouyer 	MFII_BAR,
59177961cf6Sbouyer 	MFII_IOP_NUM_SGE_LOC_ORIG,
59277961cf6Sbouyer 	MFII_RAID_CTX_RL_FLAGS_CPU0, /* | MFII_RAID_CTX_RL_FLAGS_SEQNO_EN */
59377961cf6Sbouyer 	MFII_REQ_TYPE_NO_LOCK,
59477961cf6Sbouyer 	MFII_RAID_CTX_TYPE_CUDA | 0x1,
59577961cf6Sbouyer 	MFII_SGE_CHAIN_ELEMENT,
596e490de0bSmsaitoh 	MFII_SGE_END_OF_LIST,
597e490de0bSmsaitoh 	0
59877961cf6Sbouyer };
59977961cf6Sbouyer 
600bfa22340Smaxv static const struct mfii_iop mfii_iop_35 = {
60177961cf6Sbouyer 	MFII_BAR_35,
60277961cf6Sbouyer 	MFII_IOP_NUM_SGE_LOC_35,
60377961cf6Sbouyer 	MFII_RAID_CTX_ROUTING_FLAGS_CPU0, /* | MFII_RAID_CTX_ROUTING_FLAGS_SQN */
60477961cf6Sbouyer 	MFII_REQ_TYPE_NO_LOCK,
60577961cf6Sbouyer 	MFII_RAID_CTX_TYPE_CUDA | 0x1,
60677961cf6Sbouyer 	MFII_SGE_CHAIN_ELEMENT,
607e490de0bSmsaitoh 	MFII_SGE_END_OF_LIST,
608e490de0bSmsaitoh 	0
60977961cf6Sbouyer };
61077961cf6Sbouyer 
611e490de0bSmsaitoh static const struct mfii_iop mfii_iop_aero = {
612e490de0bSmsaitoh 	MFII_BAR_35,
613e490de0bSmsaitoh 	MFII_IOP_NUM_SGE_LOC_35,
614e490de0bSmsaitoh 	MFII_RAID_CTX_ROUTING_FLAGS_CPU0, /* | MFII_RAID_CTX_ROUTING_FLAGS_SQN */
615e490de0bSmsaitoh 	MFII_REQ_TYPE_NO_LOCK,
616e490de0bSmsaitoh 	MFII_RAID_CTX_TYPE_CUDA | 0x1,
617e490de0bSmsaitoh 	MFII_SGE_CHAIN_ELEMENT,
618e490de0bSmsaitoh 	MFII_SGE_END_OF_LIST,
619e490de0bSmsaitoh 	MFII_IOP_QUIRK_REGREAD | MFII_IOP_HAS_32BITDESC_BIT
620e490de0bSmsaitoh };
621e490de0bSmsaitoh 
62277961cf6Sbouyer struct mfii_device {
62377961cf6Sbouyer 	pcireg_t		mpd_vendor;
62477961cf6Sbouyer 	pcireg_t		mpd_product;
62577961cf6Sbouyer 	const struct mfii_iop	*mpd_iop;
62677961cf6Sbouyer };
62777961cf6Sbouyer 
628bfa22340Smaxv static const struct mfii_device mfii_devices[] = {
629b570acafSmsaitoh 	/* Fusion */
63077961cf6Sbouyer 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_2208,
63177961cf6Sbouyer 	    &mfii_iop_thunderbolt },
632b570acafSmsaitoh 	/* Fury */
63377961cf6Sbouyer 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3008,
63477961cf6Sbouyer 	    &mfii_iop_25 },
635b570acafSmsaitoh 	/* Invader */
63677961cf6Sbouyer 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3108,
63777961cf6Sbouyer 	    &mfii_iop_25 },
638302cc191Smsaitoh 	/* Intruder */
639302cc191Smsaitoh 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3316,
640302cc191Smsaitoh 	    &mfii_iop_25 },
641302cc191Smsaitoh 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3324,
642302cc191Smsaitoh 	    &mfii_iop_25 },
643302cc191Smsaitoh 	/* Cutlass */
644302cc191Smsaitoh 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_32XX_1,
645302cc191Smsaitoh 	    &mfii_iop_25 },
646302cc191Smsaitoh 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_32XX_2,
647302cc191Smsaitoh 	    &mfii_iop_25 },
648b570acafSmsaitoh 	/* Crusader */
64977961cf6Sbouyer 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3404,
65077961cf6Sbouyer 	    &mfii_iop_35 },
65177961cf6Sbouyer 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3416,
65277961cf6Sbouyer 	    &mfii_iop_35 },
653b570acafSmsaitoh 	/* Ventura */
654b570acafSmsaitoh 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3504,
655b570acafSmsaitoh 	    &mfii_iop_35 },
65677961cf6Sbouyer 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3516,
657b570acafSmsaitoh 	    &mfii_iop_35 },
658b570acafSmsaitoh 	/* Tomcat */
659b570acafSmsaitoh 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3408,
660b570acafSmsaitoh 	    &mfii_iop_35 },
661b570acafSmsaitoh 	/* Harpoon */
662b570acafSmsaitoh 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3508,
663e490de0bSmsaitoh 	    &mfii_iop_35 },
664e490de0bSmsaitoh 	/* Aero */
665e490de0bSmsaitoh 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_39XX_2,
666e490de0bSmsaitoh 	    &mfii_iop_aero },
667e490de0bSmsaitoh 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_39XX_3,
668e490de0bSmsaitoh 	    &mfii_iop_aero },
669e490de0bSmsaitoh 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_38XX_2,
670e490de0bSmsaitoh 	    &mfii_iop_aero },
671e490de0bSmsaitoh 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_38XX_3,
672e490de0bSmsaitoh 	    &mfii_iop_aero }
67377961cf6Sbouyer };
67477961cf6Sbouyer 
675bfa22340Smaxv static const struct mfii_iop *mfii_find_iop(struct pci_attach_args *);
67677961cf6Sbouyer 
677bfa22340Smaxv static const struct mfii_iop *
mfii_find_iop(struct pci_attach_args * pa)67877961cf6Sbouyer mfii_find_iop(struct pci_attach_args *pa)
67977961cf6Sbouyer {
68077961cf6Sbouyer 	const struct mfii_device *mpd;
68177961cf6Sbouyer 	int i;
68277961cf6Sbouyer 
68377961cf6Sbouyer 	for (i = 0; i < __arraycount(mfii_devices); i++) {
68477961cf6Sbouyer 		mpd = &mfii_devices[i];
68577961cf6Sbouyer 
68677961cf6Sbouyer 		if (mpd->mpd_vendor == PCI_VENDOR(pa->pa_id) &&
68777961cf6Sbouyer 		    mpd->mpd_product == PCI_PRODUCT(pa->pa_id))
68877961cf6Sbouyer 			return (mpd->mpd_iop);
68977961cf6Sbouyer 	}
69077961cf6Sbouyer 
69177961cf6Sbouyer 	return (NULL);
69277961cf6Sbouyer }
69377961cf6Sbouyer 
694bfa22340Smaxv static int
mfii_match(device_t parent,cfdata_t match,void * aux)69577961cf6Sbouyer mfii_match(device_t parent, cfdata_t match, void *aux)
69677961cf6Sbouyer {
69777961cf6Sbouyer 	return ((mfii_find_iop(aux) != NULL) ? 2 : 0);
69877961cf6Sbouyer }
69977961cf6Sbouyer 
700bfa22340Smaxv static void
mfii_attach(device_t parent,device_t self,void * aux)70177961cf6Sbouyer mfii_attach(device_t parent, device_t self, void *aux)
70277961cf6Sbouyer {
70377961cf6Sbouyer 	struct mfii_softc *sc = device_private(self);
70477961cf6Sbouyer 	struct pci_attach_args *pa = aux;
70577961cf6Sbouyer 	pcireg_t memtype;
706*d82b910dSbouyer 	pci_intr_handle_t *ihp;
70777961cf6Sbouyer 	char intrbuf[PCI_INTRSTR_LEN];
70877961cf6Sbouyer 	const char *intrstr;
70977961cf6Sbouyer 	u_int32_t status, scpad2, scpad3;
71077961cf6Sbouyer 	int chain_frame_sz, nsge_in_io, nsge_in_chain, i;
71177961cf6Sbouyer 	struct scsipi_adapter *adapt = &sc->sc_adapt;
71277961cf6Sbouyer 	struct scsipi_channel *chan = &sc->sc_chan;
713c6bee2b8Smsaitoh 	union mfi_mbox mbox;
71477961cf6Sbouyer 
71577961cf6Sbouyer 	/* init sc */
71677961cf6Sbouyer 	sc->sc_dev = self;
71777961cf6Sbouyer 	sc->sc_iop = mfii_find_iop(aux);
71877961cf6Sbouyer 	sc->sc_dmat = pa->pa_dmat;
71977961cf6Sbouyer 	if (pci_dma64_available(pa)) {
72077961cf6Sbouyer 		sc->sc_dmat64 = pa->pa_dmat64;
72177961cf6Sbouyer 		sc->sc_64bit_dma = 1;
72277961cf6Sbouyer 	} else {
72377961cf6Sbouyer 		sc->sc_dmat64 = pa->pa_dmat;
72477961cf6Sbouyer 		sc->sc_64bit_dma = 0;
72577961cf6Sbouyer 	}
72677961cf6Sbouyer 	SIMPLEQ_INIT(&sc->sc_ccb_freeq);
72777961cf6Sbouyer 	mutex_init(&sc->sc_ccb_mtx, MUTEX_DEFAULT, IPL_BIO);
72877961cf6Sbouyer 	mutex_init(&sc->sc_post_mtx, MUTEX_DEFAULT, IPL_BIO);
72977961cf6Sbouyer 	mutex_init(&sc->sc_reply_postq_mtx, MUTEX_DEFAULT, IPL_BIO);
73077961cf6Sbouyer 
73177961cf6Sbouyer 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
73277961cf6Sbouyer 
73377961cf6Sbouyer 	sc->sc_aen_ccb = NULL;
73477961cf6Sbouyer 	snprintf(intrbuf, sizeof(intrbuf) - 1, "%saen", device_xname(self));
73577961cf6Sbouyer 	workqueue_create(&sc->sc_aen_wq, intrbuf, mfii_aen, sc,
73677961cf6Sbouyer 	    PRI_BIO, IPL_BIO, WQ_MPSAFE);
73777961cf6Sbouyer 
73877961cf6Sbouyer 	snprintf(intrbuf, sizeof(intrbuf) - 1, "%sabrt", device_xname(self));
73977961cf6Sbouyer 	workqueue_create(&sc->sc_abort_wq, intrbuf, mfii_abort_task,
74077961cf6Sbouyer 	    sc, PRI_BIO, IPL_BIO, WQ_MPSAFE);
74177961cf6Sbouyer 
74277961cf6Sbouyer 	mutex_init(&sc->sc_abort_mtx, MUTEX_DEFAULT, IPL_BIO);
74377961cf6Sbouyer 	SIMPLEQ_INIT(&sc->sc_abort_list);
74477961cf6Sbouyer 
74577961cf6Sbouyer 	/* wire up the bus shizz */
74677961cf6Sbouyer 	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, sc->sc_iop->bar);
74777961cf6Sbouyer 	memtype |= PCI_MAPREG_MEM_TYPE_32BIT;
74877961cf6Sbouyer 	if (pci_mapreg_map(pa, sc->sc_iop->bar, memtype, 0,
74977961cf6Sbouyer 	    &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_ios)) {
75077961cf6Sbouyer 		aprint_error(": unable to map registers\n");
75177961cf6Sbouyer 		return;
75277961cf6Sbouyer 	}
75377961cf6Sbouyer 
75477961cf6Sbouyer 	/* disable interrupts */
75577961cf6Sbouyer 	mfii_write(sc, MFI_OMSK, 0xffffffff);
75677961cf6Sbouyer 
757*d82b910dSbouyer 	if (pci_intr_alloc(pa, &ihp, NULL, 0)) {
75877961cf6Sbouyer 		aprint_error(": unable to map interrupt\n");
75977961cf6Sbouyer 		goto pci_unmap;
76077961cf6Sbouyer 	}
761*d82b910dSbouyer 	intrstr = pci_intr_string(pa->pa_pc, ihp[0], intrbuf, sizeof(intrbuf));
762*d82b910dSbouyer 	pci_intr_setattr(pa->pa_pc, &ihp[0], PCI_INTR_MPSAFE, true);
76377961cf6Sbouyer 
76477961cf6Sbouyer 	/* lets get started */
76577961cf6Sbouyer 	if (mfii_transition_firmware(sc))
76677961cf6Sbouyer 		goto pci_unmap;
76777961cf6Sbouyer 	sc->sc_running = true;
76877961cf6Sbouyer 
76977961cf6Sbouyer 	/* determine max_cmds (refer to the Linux megaraid_sas driver) */
77077961cf6Sbouyer 	scpad3 = mfii_read(sc, MFII_OSP3);
77177961cf6Sbouyer 	status = mfii_fw_state(sc);
77277961cf6Sbouyer 	sc->sc_max_fw_cmds = scpad3 & MFI_STATE_MAXCMD_MASK;
77377961cf6Sbouyer 	if (sc->sc_max_fw_cmds == 0)
77477961cf6Sbouyer 		sc->sc_max_fw_cmds = status & MFI_STATE_MAXCMD_MASK;
77577961cf6Sbouyer 	/*
77677961cf6Sbouyer 	 * reduce max_cmds by 1 to ensure that the reply queue depth does not
77777961cf6Sbouyer 	 * exceed FW supplied max_fw_cmds.
77877961cf6Sbouyer 	 */
77977961cf6Sbouyer 	sc->sc_max_cmds = uimin(sc->sc_max_fw_cmds, 1024) - 1;
78077961cf6Sbouyer 
78177961cf6Sbouyer 	/* determine max_sgl (refer to the Linux megaraid_sas driver) */
78277961cf6Sbouyer 	scpad2 = mfii_read(sc, MFII_OSP2);
78377961cf6Sbouyer 	chain_frame_sz =
78477961cf6Sbouyer 		((scpad2 & MFII_MAX_CHAIN_MASK) >> MFII_MAX_CHAIN_SHIFT) *
78577961cf6Sbouyer 		((scpad2 & MFII_MAX_CHAIN_UNIT) ? MFII_1MB_IO : MFII_256K_IO);
78677961cf6Sbouyer 	if (chain_frame_sz < MFII_CHAIN_FRAME_MIN)
78777961cf6Sbouyer 		chain_frame_sz = MFII_CHAIN_FRAME_MIN;
78877961cf6Sbouyer 
78977961cf6Sbouyer 	nsge_in_io = (MFII_REQUEST_SIZE -
79077961cf6Sbouyer 		sizeof(struct mpii_msg_scsi_io) -
79177961cf6Sbouyer 		sizeof(struct mfii_raid_context)) / sizeof(struct mfii_sge);
79277961cf6Sbouyer 	nsge_in_chain = chain_frame_sz / sizeof(struct mfii_sge);
79377961cf6Sbouyer 
79477961cf6Sbouyer 	/* round down to nearest power of two */
79577961cf6Sbouyer 	sc->sc_max_sgl = 1;
79677961cf6Sbouyer 	while ((sc->sc_max_sgl << 1) <= (nsge_in_io + nsge_in_chain))
79777961cf6Sbouyer 		sc->sc_max_sgl <<= 1;
79877961cf6Sbouyer 
799e490de0bSmsaitoh 	/* Check for atomic(32bit) descriptor */
800e490de0bSmsaitoh 	if (((sc->sc_iop->iop_flag & MFII_IOP_HAS_32BITDESC_BIT) != 0) &&
801e490de0bSmsaitoh 	    ((scpad2 & MFI_STATE_ATOMIC_DESCRIPTOR) != 0))
802e490de0bSmsaitoh 		sc->sc_iop_flag |= MFII_IOP_DESC_32BIT;
803e490de0bSmsaitoh 
80477961cf6Sbouyer 	DNPRINTF(MFII_D_MISC, "%s: OSP 0x%08x, OSP2 0x%08x, OSP3 0x%08x\n",
80577961cf6Sbouyer 	    DEVNAME(sc), status, scpad2, scpad3);
80677961cf6Sbouyer 	DNPRINTF(MFII_D_MISC, "%s: max_fw_cmds %d, max_cmds %d\n",
80777961cf6Sbouyer 	    DEVNAME(sc), sc->sc_max_fw_cmds, sc->sc_max_cmds);
80877961cf6Sbouyer 	DNPRINTF(MFII_D_MISC, "%s: nsge_in_io %d, nsge_in_chain %d, "
80977961cf6Sbouyer 	    "max_sgl %d\n", DEVNAME(sc), nsge_in_io, nsge_in_chain,
81077961cf6Sbouyer 	    sc->sc_max_sgl);
81177961cf6Sbouyer 
81277961cf6Sbouyer 	/* sense memory */
81377961cf6Sbouyer 	CTASSERT(sizeof(struct mfi_sense) == MFI_SENSE_SIZE);
81477961cf6Sbouyer 	sc->sc_sense = mfii_dmamem_alloc(sc, sc->sc_max_cmds * MFI_SENSE_SIZE);
81577961cf6Sbouyer 	if (sc->sc_sense == NULL) {
81677961cf6Sbouyer 		aprint_error(": unable to allocate sense memory\n");
81777961cf6Sbouyer 		goto pci_unmap;
81877961cf6Sbouyer 	}
81977961cf6Sbouyer 
82077961cf6Sbouyer 	/* reply post queue */
82177961cf6Sbouyer 	sc->sc_reply_postq_depth = roundup(sc->sc_max_fw_cmds, 16);
82277961cf6Sbouyer 
82377961cf6Sbouyer 	sc->sc_reply_postq = mfii_dmamem_alloc(sc,
82477961cf6Sbouyer 	    sc->sc_reply_postq_depth * sizeof(struct mpii_reply_descr));
82577961cf6Sbouyer 	if (sc->sc_reply_postq == NULL)
82677961cf6Sbouyer 		goto free_sense;
82777961cf6Sbouyer 
82877961cf6Sbouyer 	memset(MFII_DMA_KVA(sc->sc_reply_postq), 0xff,
82977961cf6Sbouyer 	    MFII_DMA_LEN(sc->sc_reply_postq));
83077961cf6Sbouyer 
83177961cf6Sbouyer 	/* MPII request frame array */
83277961cf6Sbouyer 	sc->sc_requests = mfii_dmamem_alloc(sc,
83377961cf6Sbouyer 	    MFII_REQUEST_SIZE * (sc->sc_max_cmds + 1));
83477961cf6Sbouyer 	if (sc->sc_requests == NULL)
83577961cf6Sbouyer 		goto free_reply_postq;
83677961cf6Sbouyer 
83777961cf6Sbouyer 	/* MFI command frame array */
83877961cf6Sbouyer 	sc->sc_mfi = mfii_dmamem_alloc(sc, sc->sc_max_cmds * MFI_FRAME_SIZE);
83977961cf6Sbouyer 	if (sc->sc_mfi == NULL)
84077961cf6Sbouyer 		goto free_requests;
84177961cf6Sbouyer 
84277961cf6Sbouyer 	/* MPII SGL array */
84377961cf6Sbouyer 	sc->sc_sgl = mfii_dmamem_alloc(sc, sc->sc_max_cmds *
84477961cf6Sbouyer 	    sizeof(struct mfii_sge) * sc->sc_max_sgl);
84577961cf6Sbouyer 	if (sc->sc_sgl == NULL)
84677961cf6Sbouyer 		goto free_mfi;
84777961cf6Sbouyer 
84877961cf6Sbouyer 	if (mfii_init_ccb(sc) != 0) {
84977961cf6Sbouyer 		aprint_error(": could not init ccb list\n");
85077961cf6Sbouyer 		goto free_sgl;
85177961cf6Sbouyer 	}
85277961cf6Sbouyer 
85377961cf6Sbouyer 	/* kickstart firmware with all addresses and pointers */
85477961cf6Sbouyer 	if (mfii_initialise_firmware(sc) != 0) {
85577961cf6Sbouyer 		aprint_error(": could not initialize firmware\n");
85677961cf6Sbouyer 		goto free_sgl;
85777961cf6Sbouyer 	}
85877961cf6Sbouyer 
85977961cf6Sbouyer 	mutex_enter(&sc->sc_lock);
86077961cf6Sbouyer 	if (mfii_get_info(sc) != 0) {
86177961cf6Sbouyer 		mutex_exit(&sc->sc_lock);
86277961cf6Sbouyer 		aprint_error(": could not retrieve controller information\n");
86377961cf6Sbouyer 		goto free_sgl;
86477961cf6Sbouyer 	}
86577961cf6Sbouyer 	mutex_exit(&sc->sc_lock);
86677961cf6Sbouyer 
86777961cf6Sbouyer 	aprint_normal(": \"%s\", firmware %s",
86877961cf6Sbouyer 	    sc->sc_info.mci_product_name, sc->sc_info.mci_package_version);
86977961cf6Sbouyer 	if (le16toh(sc->sc_info.mci_memory_size) > 0) {
87077961cf6Sbouyer 		aprint_normal(", %uMB cache",
87177961cf6Sbouyer 		    le16toh(sc->sc_info.mci_memory_size));
87277961cf6Sbouyer 	}
87377961cf6Sbouyer 	aprint_normal("\n");
87477961cf6Sbouyer 	aprint_naive("\n");
87577961cf6Sbouyer 
876*d82b910dSbouyer 	sc->sc_ih = pci_intr_establish_xname(sc->sc_pc, ihp[0], IPL_BIO,
87777961cf6Sbouyer 	    mfii_intr, sc, DEVNAME(sc));
87877961cf6Sbouyer 	if (sc->sc_ih == NULL) {
87977961cf6Sbouyer 		aprint_error_dev(self, "can't establish interrupt");
88077961cf6Sbouyer 		if (intrstr)
88177961cf6Sbouyer 			aprint_error(" at %s", intrstr);
88277961cf6Sbouyer 		aprint_error("\n");
88377961cf6Sbouyer 		goto free_sgl;
88477961cf6Sbouyer 	}
88577961cf6Sbouyer 	aprint_normal_dev(self, "interrupting at %s\n", intrstr);
88677961cf6Sbouyer 
88777961cf6Sbouyer 	for (i = 0; i < sc->sc_info.mci_lds_present; i++)
88877961cf6Sbouyer 		sc->sc_ld[i].ld_present = 1;
88977961cf6Sbouyer 
890c6bee2b8Smsaitoh 	sc->sc_max256vd =
891c6bee2b8Smsaitoh 	    (sc->sc_info.mci_adapter_ops3 & MFI_INFO_AOPS3_SUPP_MAX_EXT_LDS) ?
892c6bee2b8Smsaitoh 	    true : false;
893c6bee2b8Smsaitoh 
894c6bee2b8Smsaitoh 	if (sc->sc_max256vd)
895c6bee2b8Smsaitoh 		aprint_verbose_dev(self, "Max 256 VD support\n");
896c6bee2b8Smsaitoh 
89777961cf6Sbouyer 	memset(adapt, 0, sizeof(*adapt));
89877961cf6Sbouyer 	adapt->adapt_dev = sc->sc_dev;
89977961cf6Sbouyer 	adapt->adapt_nchannels = 1;
90077961cf6Sbouyer 	/* keep a few commands for management */
90177961cf6Sbouyer 	if (sc->sc_max_cmds > 4)
90277961cf6Sbouyer 		adapt->adapt_openings = sc->sc_max_cmds - 4;
90377961cf6Sbouyer 	else
90477961cf6Sbouyer 		adapt->adapt_openings = sc->sc_max_cmds;
90577961cf6Sbouyer 	adapt->adapt_max_periph = adapt->adapt_openings;
90677961cf6Sbouyer 	adapt->adapt_request = mfii_scsipi_request;
90777961cf6Sbouyer 	adapt->adapt_minphys = minphys;
90877961cf6Sbouyer 	adapt->adapt_flags = SCSIPI_ADAPT_MPSAFE;
90977961cf6Sbouyer 
91077961cf6Sbouyer 	memset(chan, 0, sizeof(*chan));
91177961cf6Sbouyer 	chan->chan_adapter = adapt;
91277961cf6Sbouyer 	chan->chan_bustype = &scsi_sas_bustype;
91377961cf6Sbouyer 	chan->chan_channel = 0;
91477961cf6Sbouyer 	chan->chan_flags = 0;
91577961cf6Sbouyer 	chan->chan_nluns = 8;
91677961cf6Sbouyer 	chan->chan_ntargets = sc->sc_info.mci_max_lds;
91777961cf6Sbouyer 	chan->chan_id = sc->sc_info.mci_max_lds;
91877961cf6Sbouyer 
9193bee0c11Sthorpej 	mfii_rescan(sc->sc_dev, NULL, NULL);
92077961cf6Sbouyer 
92177961cf6Sbouyer 	if (mfii_aen_register(sc) != 0) {
92277961cf6Sbouyer 		/* error printed by mfii_aen_register */
92377961cf6Sbouyer 		goto intr_disestablish;
92477961cf6Sbouyer 	}
92577961cf6Sbouyer 
926c6bee2b8Smsaitoh 	memset(&mbox, 0, sizeof(mbox));
927c6bee2b8Smsaitoh 	if (sc->sc_max256vd)
928c6bee2b8Smsaitoh 		mbox.b[0] = 1;
92977961cf6Sbouyer 	mutex_enter(&sc->sc_lock);
930c6bee2b8Smsaitoh 	if (mfii_mgmt(sc, MR_DCMD_LD_GET_LIST, &mbox, &sc->sc_ld_list,
93177961cf6Sbouyer 	    sizeof(sc->sc_ld_list), MFII_DATA_IN, true) != 0) {
93277961cf6Sbouyer 		mutex_exit(&sc->sc_lock);
93377961cf6Sbouyer 		aprint_error_dev(self,
93477961cf6Sbouyer 		    "getting list of logical disks failed\n");
93577961cf6Sbouyer 		goto intr_disestablish;
93677961cf6Sbouyer 	}
93777961cf6Sbouyer 	mutex_exit(&sc->sc_lock);
93877961cf6Sbouyer 	memset(sc->sc_target_lds, -1, sizeof(sc->sc_target_lds));
93977961cf6Sbouyer 	for (i = 0; i < sc->sc_ld_list.mll_no_ld; i++) {
94077961cf6Sbouyer 		int target = sc->sc_ld_list.mll_list[i].mll_ld.mld_target;
94177961cf6Sbouyer 		sc->sc_target_lds[target] = i;
9423b643292Smsaitoh 		sc->sc_ld[i].ld_target_id = target;
94377961cf6Sbouyer 	}
94477961cf6Sbouyer 
94577961cf6Sbouyer 	/* enable interrupts */
94677961cf6Sbouyer 	mfii_write(sc, MFI_OSTS, 0xffffffff);
94777961cf6Sbouyer 	mfii_write(sc, MFI_OMSK, ~MFII_OSTS_INTR_VALID);
94877961cf6Sbouyer 
94977961cf6Sbouyer #if NBIO > 0
95077961cf6Sbouyer 	if (bio_register(sc->sc_dev, mfii_ioctl) != 0)
95177961cf6Sbouyer 		panic("%s: controller registration failed", DEVNAME(sc));
95277961cf6Sbouyer #endif /* NBIO > 0 */
95377961cf6Sbouyer 
95477961cf6Sbouyer 	if (mfii_create_sensors(sc) != 0)
95577961cf6Sbouyer 		aprint_error_dev(self, "unable to create sensors\n");
95677961cf6Sbouyer 
95777961cf6Sbouyer 	if (!pmf_device_register1(sc->sc_dev, mfii_suspend, mfii_resume,
95877961cf6Sbouyer 	    mfii_shutdown))
95977961cf6Sbouyer 		aprint_error_dev(self, "couldn't establish power handler\n");
96077961cf6Sbouyer 	return;
96177961cf6Sbouyer intr_disestablish:
96277961cf6Sbouyer 	pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
96377961cf6Sbouyer free_sgl:
96477961cf6Sbouyer 	mfii_dmamem_free(sc, sc->sc_sgl);
96577961cf6Sbouyer free_mfi:
96677961cf6Sbouyer 	mfii_dmamem_free(sc, sc->sc_mfi);
96777961cf6Sbouyer free_requests:
96877961cf6Sbouyer 	mfii_dmamem_free(sc, sc->sc_requests);
96977961cf6Sbouyer free_reply_postq:
97077961cf6Sbouyer 	mfii_dmamem_free(sc, sc->sc_reply_postq);
97177961cf6Sbouyer free_sense:
97277961cf6Sbouyer 	mfii_dmamem_free(sc, sc->sc_sense);
97377961cf6Sbouyer pci_unmap:
97477961cf6Sbouyer 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
97577961cf6Sbouyer }
97677961cf6Sbouyer 
97777961cf6Sbouyer #if 0
97877961cf6Sbouyer struct srp_gc mfii_dev_handles_gc =
97977961cf6Sbouyer     SRP_GC_INITIALIZER(mfii_dev_handles_dtor, NULL);
98077961cf6Sbouyer 
98177961cf6Sbouyer static inline uint16_t
98277961cf6Sbouyer mfii_dev_handle(struct mfii_softc *sc, uint16_t target)
98377961cf6Sbouyer {
98477961cf6Sbouyer 	struct srp_ref sr;
98577961cf6Sbouyer 	uint16_t *map, handle;
98677961cf6Sbouyer 
98777961cf6Sbouyer 	map = srp_enter(&sr, &sc->sc_pd->pd_dev_handles);
98877961cf6Sbouyer 	handle = map[target];
98977961cf6Sbouyer 	srp_leave(&sr);
99077961cf6Sbouyer 
99177961cf6Sbouyer 	return (handle);
99277961cf6Sbouyer }
99377961cf6Sbouyer 
994bfa22340Smaxv static int
99577961cf6Sbouyer mfii_dev_handles_update(struct mfii_softc *sc)
99677961cf6Sbouyer {
99777961cf6Sbouyer 	struct mfii_ld_map *lm;
99877961cf6Sbouyer 	uint16_t *dev_handles = NULL;
99977961cf6Sbouyer 	int i;
100077961cf6Sbouyer 	int rv = 0;
100177961cf6Sbouyer 
100277961cf6Sbouyer 	lm = malloc(sizeof(*lm), M_TEMP, M_WAITOK|M_ZERO);
100377961cf6Sbouyer 
100477961cf6Sbouyer 	rv = mfii_mgmt(sc, MR_DCMD_LD_MAP_GET_INFO, NULL, lm, sizeof(*lm),
100577961cf6Sbouyer 	    MFII_DATA_IN, false);
100677961cf6Sbouyer 
100777961cf6Sbouyer 	if (rv != 0) {
100877961cf6Sbouyer 		rv = EIO;
100977961cf6Sbouyer 		goto free_lm;
101077961cf6Sbouyer 	}
101177961cf6Sbouyer 
101277961cf6Sbouyer 	dev_handles = mallocarray(MFI_MAX_PD, sizeof(*dev_handles),
101377961cf6Sbouyer 	    M_DEVBUF, M_WAITOK);
101477961cf6Sbouyer 
101577961cf6Sbouyer 	for (i = 0; i < MFI_MAX_PD; i++)
101677961cf6Sbouyer 		dev_handles[i] = lm->mlm_dev_handle[i].mdh_cur_handle;
101777961cf6Sbouyer 
101877961cf6Sbouyer 	/* commit the updated info */
101977961cf6Sbouyer 	sc->sc_pd->pd_timeout = lm->mlm_pd_timeout;
102077961cf6Sbouyer 	srp_update_locked(&mfii_dev_handles_gc,
102177961cf6Sbouyer 	    &sc->sc_pd->pd_dev_handles, dev_handles);
102277961cf6Sbouyer 
102377961cf6Sbouyer free_lm:
102477961cf6Sbouyer 	free(lm, M_TEMP, sizeof(*lm));
102577961cf6Sbouyer 
102677961cf6Sbouyer 	return (rv);
102777961cf6Sbouyer }
102877961cf6Sbouyer 
1029bfa22340Smaxv static void
103077961cf6Sbouyer mfii_dev_handles_dtor(void *null, void *v)
103177961cf6Sbouyer {
103277961cf6Sbouyer 	uint16_t *dev_handles = v;
103377961cf6Sbouyer 
103477961cf6Sbouyer 	free(dev_handles, M_DEVBUF, sizeof(*dev_handles) * MFI_MAX_PD);
103577961cf6Sbouyer }
103677961cf6Sbouyer #endif /* 0 */
103777961cf6Sbouyer 
1038bfa22340Smaxv static int
mfii_detach(device_t self,int flags)103977961cf6Sbouyer mfii_detach(device_t self, int flags)
104077961cf6Sbouyer {
104177961cf6Sbouyer 	struct mfii_softc *sc = device_private(self);
104277961cf6Sbouyer 	int error;
104377961cf6Sbouyer 
104477961cf6Sbouyer 	if (sc->sc_ih == NULL)
104577961cf6Sbouyer 		return (0);
104677961cf6Sbouyer 
104777961cf6Sbouyer 	if ((error = config_detach_children(sc->sc_dev, flags)) != 0)
104877961cf6Sbouyer 		return error;
104977961cf6Sbouyer 
105077961cf6Sbouyer 	mfii_destroy_sensors(sc);
105177961cf6Sbouyer #if NBIO > 0
105277961cf6Sbouyer 	bio_unregister(sc->sc_dev);
105377961cf6Sbouyer #endif
105477961cf6Sbouyer 	mfii_shutdown(sc->sc_dev, 0);
105577961cf6Sbouyer 	mfii_write(sc, MFI_OMSK, 0xffffffff);
105677961cf6Sbouyer 
105777961cf6Sbouyer 	mfii_aen_unregister(sc);
105877961cf6Sbouyer 	pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
105977961cf6Sbouyer 	mfii_dmamem_free(sc, sc->sc_sgl);
106077961cf6Sbouyer 	mfii_dmamem_free(sc, sc->sc_mfi);
106177961cf6Sbouyer 	mfii_dmamem_free(sc, sc->sc_requests);
106277961cf6Sbouyer 	mfii_dmamem_free(sc, sc->sc_reply_postq);
106377961cf6Sbouyer 	mfii_dmamem_free(sc, sc->sc_sense);
106477961cf6Sbouyer 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
106577961cf6Sbouyer 
106677961cf6Sbouyer 	return (0);
106777961cf6Sbouyer }
106877961cf6Sbouyer 
1069bfa22340Smaxv static int
mfii_rescan(device_t self,const char * ifattr,const int * locators)107077961cf6Sbouyer mfii_rescan(device_t self, const char *ifattr, const int *locators)
107177961cf6Sbouyer {
107277961cf6Sbouyer 	struct mfii_softc *sc = device_private(self);
10733bee0c11Sthorpej 
107477961cf6Sbouyer 	if (sc->sc_child != NULL)
107577961cf6Sbouyer 		return 0;
107677961cf6Sbouyer 
1077277d1243Smsaitoh 	sc->sc_child = config_found(self, &sc->sc_chan, scsiprint,
1078277d1243Smsaitoh 	    CFARGS_NONE);
107977961cf6Sbouyer 	return 0;
108077961cf6Sbouyer }
108177961cf6Sbouyer 
1082bfa22340Smaxv static void
mfii_childdetached(device_t self,device_t child)108377961cf6Sbouyer mfii_childdetached(device_t self, device_t child)
108477961cf6Sbouyer {
108577961cf6Sbouyer 	struct mfii_softc *sc = device_private(self);
108677961cf6Sbouyer 
108777961cf6Sbouyer 	KASSERT(self == sc->sc_dev);
108877961cf6Sbouyer 	KASSERT(child == sc->sc_child);
108977961cf6Sbouyer 
109077961cf6Sbouyer 	if (child == sc->sc_child)
109177961cf6Sbouyer 		sc->sc_child = NULL;
109277961cf6Sbouyer }
109377961cf6Sbouyer 
109477961cf6Sbouyer static bool
mfii_suspend(device_t dev,const pmf_qual_t * q)109577961cf6Sbouyer mfii_suspend(device_t dev, const pmf_qual_t *q)
109677961cf6Sbouyer {
109777961cf6Sbouyer 	/* XXX to be implemented */
109877961cf6Sbouyer 	return false;
109977961cf6Sbouyer }
110077961cf6Sbouyer 
110177961cf6Sbouyer static bool
mfii_resume(device_t dev,const pmf_qual_t * q)110277961cf6Sbouyer mfii_resume(device_t dev, const pmf_qual_t *q)
110377961cf6Sbouyer {
110477961cf6Sbouyer 	/* XXX to be implemented */
110577961cf6Sbouyer 	return false;
110677961cf6Sbouyer }
110777961cf6Sbouyer 
110877961cf6Sbouyer static bool
mfii_shutdown(device_t dev,int how)110977961cf6Sbouyer mfii_shutdown(device_t dev, int how)
111077961cf6Sbouyer {
111177961cf6Sbouyer 	struct mfii_softc	*sc = device_private(dev);
111277961cf6Sbouyer 	struct mfii_ccb *ccb;
111377961cf6Sbouyer 	union mfi_mbox		mbox;
111469912035Smsaitoh 	bool rv = true;
111577961cf6Sbouyer 
111677961cf6Sbouyer 	memset(&mbox, 0, sizeof(mbox));
111777961cf6Sbouyer 
111877961cf6Sbouyer 	mutex_enter(&sc->sc_lock);
111912f3d15bSmsaitoh 	DNPRINTF(MFII_D_MISC, "%s: mfii_shutdown\n", DEVNAME(sc));
112077961cf6Sbouyer 	ccb = mfii_get_ccb(sc);
112177961cf6Sbouyer 	if (ccb == NULL)
112277961cf6Sbouyer 		return false;
112377961cf6Sbouyer 	mutex_enter(&sc->sc_ccb_mtx);
112477961cf6Sbouyer 	if (sc->sc_running) {
112577961cf6Sbouyer 		sc->sc_running = 0; /* prevent new commands */
112677961cf6Sbouyer 		mutex_exit(&sc->sc_ccb_mtx);
112777961cf6Sbouyer #if 0 /* XXX why does this hang ? */
112877961cf6Sbouyer 		mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
112977961cf6Sbouyer 		mfii_scrub_ccb(ccb);
113077961cf6Sbouyer 		if (mfii_do_mgmt(sc, ccb, MR_DCMD_CTRL_CACHE_FLUSH, &mbox,
113177961cf6Sbouyer 		    NULL, 0, MFII_DATA_NONE, true)) {
1132277d1243Smsaitoh 			aprint_error_dev(dev,
1133277d1243Smsaitoh 			    "shutdown: cache flush failed\n");
113477961cf6Sbouyer 			rv = false;
113577961cf6Sbouyer 			goto fail;
113677961cf6Sbouyer 		}
113777961cf6Sbouyer 		printf("ok1\n");
113877961cf6Sbouyer #endif
113977961cf6Sbouyer 		mbox.b[0] = 0;
114077961cf6Sbouyer 		mfii_scrub_ccb(ccb);
114177961cf6Sbouyer 		if (mfii_do_mgmt(sc, ccb, MR_DCMD_CTRL_SHUTDOWN, &mbox,
114277961cf6Sbouyer 		    NULL, 0, MFII_DATA_NONE, true)) {
114377961cf6Sbouyer 			aprint_error_dev(dev, "shutdown: "
114477961cf6Sbouyer 			    "firmware shutdown failed\n");
114577961cf6Sbouyer 			rv = false;
114677961cf6Sbouyer 			goto fail;
114777961cf6Sbouyer 		}
114877961cf6Sbouyer 	} else {
114977961cf6Sbouyer 		mutex_exit(&sc->sc_ccb_mtx);
115077961cf6Sbouyer 	}
115177961cf6Sbouyer fail:
115277961cf6Sbouyer 	mfii_put_ccb(sc, ccb);
115377961cf6Sbouyer 	mutex_exit(&sc->sc_lock);
115477961cf6Sbouyer 	return rv;
115577961cf6Sbouyer }
115677961cf6Sbouyer 
1157e490de0bSmsaitoh /* Register read function without retry */
1158e490de0bSmsaitoh static inline u_int32_t
mfii_read_wor(struct mfii_softc * sc,bus_size_t r)1159e490de0bSmsaitoh mfii_read_wor(struct mfii_softc *sc, bus_size_t r)
116077961cf6Sbouyer {
116177961cf6Sbouyer 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
116277961cf6Sbouyer 	    BUS_SPACE_BARRIER_READ);
116377961cf6Sbouyer 	return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, r));
116477961cf6Sbouyer }
116577961cf6Sbouyer 
1166e490de0bSmsaitoh static u_int32_t
mfii_read(struct mfii_softc * sc,bus_size_t r)1167e490de0bSmsaitoh mfii_read(struct mfii_softc *sc, bus_size_t r)
1168e490de0bSmsaitoh {
1169e490de0bSmsaitoh 	uint32_t rv;
1170e490de0bSmsaitoh 	int i = 0;
1171e490de0bSmsaitoh 
1172e490de0bSmsaitoh 	if ((sc->sc_iop->iop_flag & MFII_IOP_QUIRK_REGREAD) != 0) {
1173e490de0bSmsaitoh 		do {
1174e490de0bSmsaitoh 			rv = mfii_read_wor(sc, r);
1175e490de0bSmsaitoh 			i++;
1176e490de0bSmsaitoh 		} while ((rv == 0) && (i < 3));
1177e490de0bSmsaitoh 	} else
1178e490de0bSmsaitoh 		rv = mfii_read_wor(sc, r);
1179e490de0bSmsaitoh 
1180e490de0bSmsaitoh 	return rv;
1181e490de0bSmsaitoh }
1182e490de0bSmsaitoh 
118377961cf6Sbouyer static void
mfii_write(struct mfii_softc * sc,bus_size_t r,u_int32_t v)118477961cf6Sbouyer mfii_write(struct mfii_softc *sc, bus_size_t r, u_int32_t v)
118577961cf6Sbouyer {
118677961cf6Sbouyer 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v);
118777961cf6Sbouyer 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
118877961cf6Sbouyer 	    BUS_SPACE_BARRIER_WRITE);
118977961cf6Sbouyer }
119077961cf6Sbouyer 
1191bfa22340Smaxv static struct mfii_dmamem *
mfii_dmamem_alloc(struct mfii_softc * sc,size_t size)119277961cf6Sbouyer mfii_dmamem_alloc(struct mfii_softc *sc, size_t size)
119377961cf6Sbouyer {
119477961cf6Sbouyer 	struct mfii_dmamem *m;
119577961cf6Sbouyer 	int nsegs;
119677961cf6Sbouyer 
119770747dc1Schs 	m = malloc(sizeof(*m), M_DEVBUF, M_WAITOK | M_ZERO);
119877961cf6Sbouyer 	m->mdm_size = size;
119977961cf6Sbouyer 
120077961cf6Sbouyer 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
120177961cf6Sbouyer 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &m->mdm_map) != 0)
120277961cf6Sbouyer 		goto mdmfree;
120377961cf6Sbouyer 
120477961cf6Sbouyer 	if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &m->mdm_seg, 1,
120577961cf6Sbouyer 	    &nsegs, BUS_DMA_NOWAIT) != 0)
120677961cf6Sbouyer 		goto destroy;
120777961cf6Sbouyer 
120877961cf6Sbouyer 	if (bus_dmamem_map(sc->sc_dmat, &m->mdm_seg, nsegs, size, &m->mdm_kva,
120977961cf6Sbouyer 	    BUS_DMA_NOWAIT) != 0)
121077961cf6Sbouyer 		goto free;
121177961cf6Sbouyer 
121277961cf6Sbouyer 	if (bus_dmamap_load(sc->sc_dmat, m->mdm_map, m->mdm_kva, size, NULL,
121377961cf6Sbouyer 	    BUS_DMA_NOWAIT) != 0)
121477961cf6Sbouyer 		goto unmap;
121577961cf6Sbouyer 
121677961cf6Sbouyer 	memset(m->mdm_kva, 0, size);
121777961cf6Sbouyer 	return (m);
121877961cf6Sbouyer 
121977961cf6Sbouyer unmap:
122077961cf6Sbouyer 	bus_dmamem_unmap(sc->sc_dmat, m->mdm_kva, m->mdm_size);
122177961cf6Sbouyer free:
122277961cf6Sbouyer 	bus_dmamem_free(sc->sc_dmat, &m->mdm_seg, 1);
122377961cf6Sbouyer destroy:
122477961cf6Sbouyer 	bus_dmamap_destroy(sc->sc_dmat, m->mdm_map);
122577961cf6Sbouyer mdmfree:
122677961cf6Sbouyer 	free(m, M_DEVBUF);
122777961cf6Sbouyer 
122877961cf6Sbouyer 	return (NULL);
122977961cf6Sbouyer }
123077961cf6Sbouyer 
1231bfa22340Smaxv static void
mfii_dmamem_free(struct mfii_softc * sc,struct mfii_dmamem * m)123277961cf6Sbouyer mfii_dmamem_free(struct mfii_softc *sc, struct mfii_dmamem *m)
123377961cf6Sbouyer {
123477961cf6Sbouyer 	bus_dmamap_unload(sc->sc_dmat, m->mdm_map);
123577961cf6Sbouyer 	bus_dmamem_unmap(sc->sc_dmat, m->mdm_kva, m->mdm_size);
123677961cf6Sbouyer 	bus_dmamem_free(sc->sc_dmat, &m->mdm_seg, 1);
123777961cf6Sbouyer 	bus_dmamap_destroy(sc->sc_dmat, m->mdm_map);
123877961cf6Sbouyer 	free(m, M_DEVBUF);
123977961cf6Sbouyer }
124077961cf6Sbouyer 
1241bfa22340Smaxv static void
mfii_dcmd_start(struct mfii_softc * sc,struct mfii_ccb * ccb)124277961cf6Sbouyer mfii_dcmd_start(struct mfii_softc *sc, struct mfii_ccb *ccb)
124377961cf6Sbouyer {
124477961cf6Sbouyer 	struct mpii_msg_scsi_io *io = ccb->ccb_request;
124577961cf6Sbouyer 	struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
124677961cf6Sbouyer 	struct mfii_sge *sge = (struct mfii_sge *)(ctx + 1);
124777961cf6Sbouyer 
124877961cf6Sbouyer 	io->function = MFII_FUNCTION_PASSTHRU_IO;
124977961cf6Sbouyer 	io->sgl_offset0 = (uint32_t *)sge - (uint32_t *)io;
125077961cf6Sbouyer 	io->chain_offset = io->sgl_offset0 / 4;
125177961cf6Sbouyer 
125277961cf6Sbouyer 	sge->sg_addr = htole64(ccb->ccb_sense_dva);
125377961cf6Sbouyer 	sge->sg_len = htole32(sizeof(*ccb->ccb_sense));
125477961cf6Sbouyer 	sge->sg_flags = MFII_SGE_CHAIN_ELEMENT | MFII_SGE_ADDR_IOCPLBNTA;
125577961cf6Sbouyer 
125677961cf6Sbouyer 	ccb->ccb_req.flags = MFII_REQ_TYPE_SCSI;
125777961cf6Sbouyer 	ccb->ccb_req.smid = le16toh(ccb->ccb_smid);
125877961cf6Sbouyer 
125977961cf6Sbouyer 	mfii_start(sc, ccb);
126077961cf6Sbouyer }
126177961cf6Sbouyer 
1262bfa22340Smaxv static int
mfii_aen_register(struct mfii_softc * sc)126377961cf6Sbouyer mfii_aen_register(struct mfii_softc *sc)
126477961cf6Sbouyer {
126577961cf6Sbouyer 	struct mfi_evt_log_info mel;
126677961cf6Sbouyer 	struct mfii_ccb *ccb;
126777961cf6Sbouyer 	struct mfii_dmamem *mdm;
126877961cf6Sbouyer 	int rv;
126977961cf6Sbouyer 
127077961cf6Sbouyer 	ccb = mfii_get_ccb(sc);
127177961cf6Sbouyer 	if (ccb == NULL) {
127277961cf6Sbouyer 		printf("%s: unable to allocate ccb for aen\n", DEVNAME(sc));
127377961cf6Sbouyer 		return (ENOMEM);
127477961cf6Sbouyer 	}
127577961cf6Sbouyer 
127677961cf6Sbouyer 	memset(&mel, 0, sizeof(mel));
127777961cf6Sbouyer 	mfii_scrub_ccb(ccb);
127877961cf6Sbouyer 
127977961cf6Sbouyer 	rv = mfii_do_mgmt(sc, ccb, MR_DCMD_CTRL_EVENT_GET_INFO, NULL,
128077961cf6Sbouyer 	    &mel, sizeof(mel), MFII_DATA_IN, true);
128177961cf6Sbouyer 	if (rv != 0) {
128277961cf6Sbouyer 		mfii_put_ccb(sc, ccb);
128377961cf6Sbouyer 		aprint_error_dev(sc->sc_dev, "unable to get event info\n");
128477961cf6Sbouyer 		return (EIO);
128577961cf6Sbouyer 	}
128677961cf6Sbouyer 
128777961cf6Sbouyer 	mdm = mfii_dmamem_alloc(sc, sizeof(struct mfi_evt_detail));
128877961cf6Sbouyer 	if (mdm == NULL) {
128977961cf6Sbouyer 		mfii_put_ccb(sc, ccb);
1290277d1243Smsaitoh 		aprint_error_dev(sc->sc_dev,
1291277d1243Smsaitoh 		    "unable to allocate event data\n");
129277961cf6Sbouyer 		return (ENOMEM);
129377961cf6Sbouyer 	}
129477961cf6Sbouyer 
129577961cf6Sbouyer 	/* replay all the events from boot */
129677961cf6Sbouyer 	mfii_aen_start(sc, ccb, mdm, le32toh(mel.mel_boot_seq_num));
129777961cf6Sbouyer 
129877961cf6Sbouyer 	return (0);
129977961cf6Sbouyer }
130077961cf6Sbouyer 
1301bfa22340Smaxv static void
mfii_aen_start(struct mfii_softc * sc,struct mfii_ccb * ccb,struct mfii_dmamem * mdm,uint32_t seq)130277961cf6Sbouyer mfii_aen_start(struct mfii_softc *sc, struct mfii_ccb *ccb,
130377961cf6Sbouyer     struct mfii_dmamem *mdm, uint32_t seq)
130477961cf6Sbouyer {
130577961cf6Sbouyer 	struct mfi_dcmd_frame *dcmd = mfii_dcmd_frame(ccb);
130677961cf6Sbouyer 	struct mfi_frame_header *hdr = &dcmd->mdf_header;
130777961cf6Sbouyer 	union mfi_sgl *sgl = &dcmd->mdf_sgl;
130877961cf6Sbouyer 	union mfi_evt_class_locale mec;
130977961cf6Sbouyer 
131077961cf6Sbouyer 	mfii_scrub_ccb(ccb);
131177961cf6Sbouyer 	mfii_dcmd_scrub(ccb);
131277961cf6Sbouyer 	memset(MFII_DMA_KVA(mdm), 0, MFII_DMA_LEN(mdm));
131377961cf6Sbouyer 
131477961cf6Sbouyer 	ccb->ccb_cookie = mdm;
131577961cf6Sbouyer 	ccb->ccb_done = mfii_aen_done;
131677961cf6Sbouyer 	sc->sc_aen_ccb = ccb;
131777961cf6Sbouyer 
131877961cf6Sbouyer 	mec.mec_members.class = MFI_EVT_CLASS_DEBUG;
131977961cf6Sbouyer 	mec.mec_members.reserved = 0;
132077961cf6Sbouyer 	mec.mec_members.locale = htole16(MFI_EVT_LOCALE_ALL);
132177961cf6Sbouyer 
132277961cf6Sbouyer 	hdr->mfh_cmd = MFI_CMD_DCMD;
132377961cf6Sbouyer 	hdr->mfh_sg_count = 1;
132477961cf6Sbouyer 	hdr->mfh_flags = htole16(MFI_FRAME_DIR_READ | MFI_FRAME_SGL64);
132577961cf6Sbouyer 	hdr->mfh_data_len = htole32(MFII_DMA_LEN(mdm));
132677961cf6Sbouyer 	dcmd->mdf_opcode = htole32(MR_DCMD_CTRL_EVENT_WAIT);
132777961cf6Sbouyer 	dcmd->mdf_mbox.w[0] = htole32(seq);
132877961cf6Sbouyer 	dcmd->mdf_mbox.w[1] = htole32(mec.mec_word);
132977961cf6Sbouyer 	sgl->sg64[0].addr = htole64(MFII_DMA_DVA(mdm));
133077961cf6Sbouyer 	sgl->sg64[0].len = htole32(MFII_DMA_LEN(mdm));
133177961cf6Sbouyer 
133277961cf6Sbouyer 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(mdm),
133377961cf6Sbouyer 	    0, MFII_DMA_LEN(mdm), BUS_DMASYNC_PREREAD);
133477961cf6Sbouyer 
133577961cf6Sbouyer 	mfii_dcmd_sync(sc, ccb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
133677961cf6Sbouyer 	mfii_dcmd_start(sc, ccb);
133777961cf6Sbouyer }
133877961cf6Sbouyer 
1339bfa22340Smaxv static void
mfii_aen_done(struct mfii_softc * sc,struct mfii_ccb * ccb)134077961cf6Sbouyer mfii_aen_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
134177961cf6Sbouyer {
134277961cf6Sbouyer 	KASSERT(sc->sc_aen_ccb == ccb);
134377961cf6Sbouyer 
134477961cf6Sbouyer 	/*
134577961cf6Sbouyer 	 * defer to a thread with KERNEL_LOCK so we can run autoconf
134677961cf6Sbouyer 	 * We shouldn't have more than one AEN command pending at a time,
134777961cf6Sbouyer 	 * so no need to lock
134877961cf6Sbouyer 	 */
134977961cf6Sbouyer 	if (sc->sc_running)
135077961cf6Sbouyer 		workqueue_enqueue(sc->sc_aen_wq, &sc->sc_aen_work, NULL);
135177961cf6Sbouyer }
135277961cf6Sbouyer 
1353bfa22340Smaxv static void
mfii_aen(struct work * wk,void * arg)135477961cf6Sbouyer mfii_aen(struct work *wk, void *arg)
135577961cf6Sbouyer {
135677961cf6Sbouyer 	struct mfii_softc *sc = arg;
135777961cf6Sbouyer 	struct mfii_ccb *ccb = sc->sc_aen_ccb;
135877961cf6Sbouyer 	struct mfii_dmamem *mdm = ccb->ccb_cookie;
135977961cf6Sbouyer 	const struct mfi_evt_detail *med = MFII_DMA_KVA(mdm);
136077961cf6Sbouyer 
136177961cf6Sbouyer 	mfii_dcmd_sync(sc, ccb,
136277961cf6Sbouyer 	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
136377961cf6Sbouyer 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(mdm),
136477961cf6Sbouyer 	    0, MFII_DMA_LEN(mdm), BUS_DMASYNC_POSTREAD);
136577961cf6Sbouyer 
136677961cf6Sbouyer 	DNPRINTF(MFII_D_MISC, "%s: %u %08x %02x %s\n", DEVNAME(sc),
136777961cf6Sbouyer 	    le32toh(med->med_seq_num), le32toh(med->med_code),
136877961cf6Sbouyer 	    med->med_arg_type, med->med_description);
136977961cf6Sbouyer 
137077961cf6Sbouyer 	switch (le32toh(med->med_code)) {
137177961cf6Sbouyer 	case MR_EVT_PD_INSERTED_EXT:
137277961cf6Sbouyer 		if (med->med_arg_type != MR_EVT_ARGS_PD_ADDRESS)
137377961cf6Sbouyer 			break;
137477961cf6Sbouyer 
137577961cf6Sbouyer 		mfii_aen_pd_insert(sc, &med->args.pd_address);
137677961cf6Sbouyer 		break;
137777961cf6Sbouyer 	case MR_EVT_PD_REMOVED_EXT:
137877961cf6Sbouyer 		if (med->med_arg_type != MR_EVT_ARGS_PD_ADDRESS)
137977961cf6Sbouyer 			break;
138077961cf6Sbouyer 
138177961cf6Sbouyer 		mfii_aen_pd_remove(sc, &med->args.pd_address);
138277961cf6Sbouyer 		break;
138377961cf6Sbouyer 
138477961cf6Sbouyer 	case MR_EVT_PD_STATE_CHANGE:
138577961cf6Sbouyer 		if (med->med_arg_type != MR_EVT_ARGS_PD_STATE)
138677961cf6Sbouyer 			break;
138777961cf6Sbouyer 
138877961cf6Sbouyer 		mfii_aen_pd_state_change(sc, &med->args.pd_state);
138977961cf6Sbouyer 		break;
139077961cf6Sbouyer 
139177961cf6Sbouyer 	case MR_EVT_LD_CREATED:
139277961cf6Sbouyer 	case MR_EVT_LD_DELETED:
139377961cf6Sbouyer 		mfii_aen_ld_update(sc);
139477961cf6Sbouyer 		break;
139577961cf6Sbouyer 
139677961cf6Sbouyer 	default:
139777961cf6Sbouyer 		break;
139877961cf6Sbouyer 	}
139977961cf6Sbouyer 
140077961cf6Sbouyer 	mfii_aen_start(sc, ccb, mdm, le32toh(med->med_seq_num) + 1);
140177961cf6Sbouyer }
140277961cf6Sbouyer 
1403bfa22340Smaxv static void
mfii_aen_pd_insert(struct mfii_softc * sc,const struct mfi_evtarg_pd_address * pd)140477961cf6Sbouyer mfii_aen_pd_insert(struct mfii_softc *sc,
140577961cf6Sbouyer     const struct mfi_evtarg_pd_address *pd)
140677961cf6Sbouyer {
140777961cf6Sbouyer 	printf("%s: physical disk inserted id %d enclosure %d\n", DEVNAME(sc),
140877961cf6Sbouyer 	    le16toh(pd->device_id), le16toh(pd->encl_id));
140977961cf6Sbouyer }
141077961cf6Sbouyer 
1411bfa22340Smaxv static void
mfii_aen_pd_remove(struct mfii_softc * sc,const struct mfi_evtarg_pd_address * pd)141277961cf6Sbouyer mfii_aen_pd_remove(struct mfii_softc *sc,
141377961cf6Sbouyer     const struct mfi_evtarg_pd_address *pd)
141477961cf6Sbouyer {
141577961cf6Sbouyer 	printf("%s: physical disk removed id %d enclosure %d\n", DEVNAME(sc),
141677961cf6Sbouyer 	    le16toh(pd->device_id), le16toh(pd->encl_id));
141777961cf6Sbouyer }
141877961cf6Sbouyer 
1419bfa22340Smaxv static void
mfii_aen_pd_state_change(struct mfii_softc * sc,const struct mfi_evtarg_pd_state * state)142077961cf6Sbouyer mfii_aen_pd_state_change(struct mfii_softc *sc,
142177961cf6Sbouyer     const struct mfi_evtarg_pd_state *state)
142277961cf6Sbouyer {
142377961cf6Sbouyer 	return;
142477961cf6Sbouyer }
142577961cf6Sbouyer 
1426bfa22340Smaxv static void
mfii_aen_ld_update(struct mfii_softc * sc)142777961cf6Sbouyer mfii_aen_ld_update(struct mfii_softc *sc)
142877961cf6Sbouyer {
1429c6bee2b8Smsaitoh 	union mfi_mbox mbox;
143077961cf6Sbouyer 	int i, target, old, nld;
1431c6bee2b8Smsaitoh 	int newlds[MFII_MAX_LD_EXT];
143277961cf6Sbouyer 
1433c6bee2b8Smsaitoh 	memset(&mbox, 0, sizeof(mbox));
1434c6bee2b8Smsaitoh 	if (sc->sc_max256vd)
1435c6bee2b8Smsaitoh 		mbox.b[0] = 1;
143677961cf6Sbouyer 	mutex_enter(&sc->sc_lock);
1437c6bee2b8Smsaitoh 	if (mfii_mgmt(sc, MR_DCMD_LD_GET_LIST, &mbox, &sc->sc_ld_list,
143877961cf6Sbouyer 	    sizeof(sc->sc_ld_list), MFII_DATA_IN, false) != 0) {
143977961cf6Sbouyer 		mutex_exit(&sc->sc_lock);
1440277d1243Smsaitoh 		DNPRINTF(MFII_D_MISC,
1441277d1243Smsaitoh 		    "%s: getting list of logical disks failed\n", DEVNAME(sc));
144277961cf6Sbouyer 		return;
144377961cf6Sbouyer 	}
144477961cf6Sbouyer 	mutex_exit(&sc->sc_lock);
144577961cf6Sbouyer 
144677961cf6Sbouyer 	memset(newlds, -1, sizeof(newlds));
144777961cf6Sbouyer 
144877961cf6Sbouyer 	for (i = 0; i < sc->sc_ld_list.mll_no_ld; i++) {
144977961cf6Sbouyer 		target = sc->sc_ld_list.mll_list[i].mll_ld.mld_target;
145077961cf6Sbouyer 		DNPRINTF(MFII_D_MISC, "%s: target %d: state %d\n",
145177961cf6Sbouyer 		    DEVNAME(sc), target, sc->sc_ld_list.mll_list[i].mll_state);
145277961cf6Sbouyer 		newlds[target] = i;
14533b643292Smsaitoh 		sc->sc_ld[i].ld_target_id = target;
145477961cf6Sbouyer 	}
145577961cf6Sbouyer 
1456c6bee2b8Smsaitoh 	for (i = 0; i < MFII_MAX_LD_EXT; i++) {
145777961cf6Sbouyer 		old = sc->sc_target_lds[i];
145877961cf6Sbouyer 		nld = newlds[i];
145977961cf6Sbouyer 
146077961cf6Sbouyer 		if (old == -1 && nld != -1) {
146177961cf6Sbouyer 			printf("%s: logical drive %d added (target %d)\n",
146277961cf6Sbouyer 			    DEVNAME(sc), i, nld);
146377961cf6Sbouyer 
146477961cf6Sbouyer 			// XXX scsi_probe_target(sc->sc_scsibus, i);
146577961cf6Sbouyer 
146677961cf6Sbouyer 			mfii_init_ld_sensor(sc, &sc->sc_sensors[i], i);
146777961cf6Sbouyer 			mfii_attach_sensor(sc, &sc->sc_sensors[i]);
146877961cf6Sbouyer 		} else if (nld == -1 && old != -1) {
146977961cf6Sbouyer 			printf("%s: logical drive %d removed (target %d)\n",
147077961cf6Sbouyer 			    DEVNAME(sc), i, old);
147177961cf6Sbouyer 
147277961cf6Sbouyer 			scsipi_target_detach(&sc->sc_chan, i, 0, DETACH_FORCE);
147377961cf6Sbouyer 			sysmon_envsys_sensor_detach(sc->sc_sme,
147477961cf6Sbouyer 			    &sc->sc_sensors[i]);
147577961cf6Sbouyer 		}
147677961cf6Sbouyer 	}
147777961cf6Sbouyer 
147877961cf6Sbouyer 	memcpy(sc->sc_target_lds, newlds, sizeof(sc->sc_target_lds));
147977961cf6Sbouyer }
148077961cf6Sbouyer 
1481bfa22340Smaxv static void
mfii_aen_unregister(struct mfii_softc * sc)148277961cf6Sbouyer mfii_aen_unregister(struct mfii_softc *sc)
148377961cf6Sbouyer {
148477961cf6Sbouyer 	/* XXX */
148577961cf6Sbouyer }
148677961cf6Sbouyer 
1487bfa22340Smaxv static int
mfii_transition_firmware(struct mfii_softc * sc)148877961cf6Sbouyer mfii_transition_firmware(struct mfii_softc *sc)
148977961cf6Sbouyer {
149077961cf6Sbouyer 	int32_t			fw_state, cur_state;
149177961cf6Sbouyer 	int			max_wait, i;
149277961cf6Sbouyer 
149377961cf6Sbouyer 	fw_state = mfii_fw_state(sc) & MFI_STATE_MASK;
149477961cf6Sbouyer 
149577961cf6Sbouyer 	while (fw_state != MFI_STATE_READY) {
149677961cf6Sbouyer 		cur_state = fw_state;
149777961cf6Sbouyer 		switch (fw_state) {
149877961cf6Sbouyer 		case MFI_STATE_FAULT:
149977961cf6Sbouyer 			printf("%s: firmware fault\n", DEVNAME(sc));
150077961cf6Sbouyer 			return (1);
150177961cf6Sbouyer 		case MFI_STATE_WAIT_HANDSHAKE:
150277961cf6Sbouyer 			mfii_write(sc, MFI_SKINNY_IDB,
150377961cf6Sbouyer 			    MFI_INIT_CLEAR_HANDSHAKE);
150477961cf6Sbouyer 			max_wait = 2;
150577961cf6Sbouyer 			break;
150677961cf6Sbouyer 		case MFI_STATE_OPERATIONAL:
150777961cf6Sbouyer 			mfii_write(sc, MFI_SKINNY_IDB, MFI_INIT_READY);
150877961cf6Sbouyer 			max_wait = 10;
150977961cf6Sbouyer 			break;
151077961cf6Sbouyer 		case MFI_STATE_UNDEFINED:
151177961cf6Sbouyer 		case MFI_STATE_BB_INIT:
151277961cf6Sbouyer 			max_wait = 2;
151377961cf6Sbouyer 			break;
151477961cf6Sbouyer 		case MFI_STATE_FW_INIT:
151577961cf6Sbouyer 		case MFI_STATE_DEVICE_SCAN:
151677961cf6Sbouyer 		case MFI_STATE_FLUSH_CACHE:
151777961cf6Sbouyer 			max_wait = 20;
151877961cf6Sbouyer 			break;
151977961cf6Sbouyer 		default:
152077961cf6Sbouyer 			printf("%s: unknown firmware state %d\n",
152177961cf6Sbouyer 			    DEVNAME(sc), fw_state);
152277961cf6Sbouyer 			return (1);
152377961cf6Sbouyer 		}
152477961cf6Sbouyer 		for (i = 0; i < (max_wait * 10); i++) {
152577961cf6Sbouyer 			fw_state = mfii_fw_state(sc) & MFI_STATE_MASK;
152677961cf6Sbouyer 			if (fw_state == cur_state)
152777961cf6Sbouyer 				DELAY(100000);
152877961cf6Sbouyer 			else
152977961cf6Sbouyer 				break;
153077961cf6Sbouyer 		}
153177961cf6Sbouyer 		if (fw_state == cur_state) {
153277961cf6Sbouyer 			printf("%s: firmware stuck in state %#x\n",
153377961cf6Sbouyer 			    DEVNAME(sc), fw_state);
153477961cf6Sbouyer 			return (1);
153577961cf6Sbouyer 		}
153677961cf6Sbouyer 	}
153777961cf6Sbouyer 
153877961cf6Sbouyer 	return (0);
153977961cf6Sbouyer }
154077961cf6Sbouyer 
1541bfa22340Smaxv static int
mfii_get_info(struct mfii_softc * sc)154277961cf6Sbouyer mfii_get_info(struct mfii_softc *sc)
154377961cf6Sbouyer {
154477961cf6Sbouyer 	int i, rv;
154577961cf6Sbouyer 
154677961cf6Sbouyer 	rv = mfii_mgmt(sc, MR_DCMD_CTRL_GET_INFO, NULL, &sc->sc_info,
154777961cf6Sbouyer 	    sizeof(sc->sc_info), MFII_DATA_IN, true);
154877961cf6Sbouyer 
154977961cf6Sbouyer 	if (rv != 0)
155077961cf6Sbouyer 		return (rv);
155177961cf6Sbouyer 
155277961cf6Sbouyer 	for (i = 0; i < sc->sc_info.mci_image_component_count; i++) {
155377961cf6Sbouyer 		DPRINTF("%s: active FW %s Version %s date %s time %s\n",
155477961cf6Sbouyer 		    DEVNAME(sc),
155577961cf6Sbouyer 		    sc->sc_info.mci_image_component[i].mic_name,
155677961cf6Sbouyer 		    sc->sc_info.mci_image_component[i].mic_version,
155777961cf6Sbouyer 		    sc->sc_info.mci_image_component[i].mic_build_date,
155877961cf6Sbouyer 		    sc->sc_info.mci_image_component[i].mic_build_time);
155977961cf6Sbouyer 	}
156077961cf6Sbouyer 
156177961cf6Sbouyer 	for (i = 0; i < sc->sc_info.mci_pending_image_component_count; i++) {
156277961cf6Sbouyer 		DPRINTF("%s: pending FW %s Version %s date %s time %s\n",
156377961cf6Sbouyer 		    DEVNAME(sc),
156477961cf6Sbouyer 		    sc->sc_info.mci_pending_image_component[i].mic_name,
156577961cf6Sbouyer 		    sc->sc_info.mci_pending_image_component[i].mic_version,
156677961cf6Sbouyer 		    sc->sc_info.mci_pending_image_component[i].mic_build_date,
156777961cf6Sbouyer 		    sc->sc_info.mci_pending_image_component[i].mic_build_time);
156877961cf6Sbouyer 	}
156977961cf6Sbouyer 
157077961cf6Sbouyer 	DPRINTF("%s: max_arms %d max_spans %d max_arrs %d max_lds %d name %s\n",
157177961cf6Sbouyer 	    DEVNAME(sc),
157277961cf6Sbouyer 	    sc->sc_info.mci_max_arms,
157377961cf6Sbouyer 	    sc->sc_info.mci_max_spans,
157477961cf6Sbouyer 	    sc->sc_info.mci_max_arrays,
157577961cf6Sbouyer 	    sc->sc_info.mci_max_lds,
157677961cf6Sbouyer 	    sc->sc_info.mci_product_name);
157777961cf6Sbouyer 
157877961cf6Sbouyer 	DPRINTF("%s: serial %s present %#x fw time %d max_cmds %d max_sg %d\n",
157977961cf6Sbouyer 	    DEVNAME(sc),
158077961cf6Sbouyer 	    sc->sc_info.mci_serial_number,
158177961cf6Sbouyer 	    sc->sc_info.mci_hw_present,
158277961cf6Sbouyer 	    sc->sc_info.mci_current_fw_time,
158377961cf6Sbouyer 	    sc->sc_info.mci_max_cmds,
158477961cf6Sbouyer 	    sc->sc_info.mci_max_sg_elements);
158577961cf6Sbouyer 
158677961cf6Sbouyer 	DPRINTF("%s: max_rq %d lds_pres %d lds_deg %d lds_off %d pd_pres %d\n",
158777961cf6Sbouyer 	    DEVNAME(sc),
158877961cf6Sbouyer 	    sc->sc_info.mci_max_request_size,
158977961cf6Sbouyer 	    sc->sc_info.mci_lds_present,
159077961cf6Sbouyer 	    sc->sc_info.mci_lds_degraded,
159177961cf6Sbouyer 	    sc->sc_info.mci_lds_offline,
159277961cf6Sbouyer 	    sc->sc_info.mci_pd_present);
159377961cf6Sbouyer 
159477961cf6Sbouyer 	DPRINTF("%s: pd_dsk_prs %d pd_dsk_pred_fail %d pd_dsk_fail %d\n",
159577961cf6Sbouyer 	    DEVNAME(sc),
159677961cf6Sbouyer 	    sc->sc_info.mci_pd_disks_present,
159777961cf6Sbouyer 	    sc->sc_info.mci_pd_disks_pred_failure,
159877961cf6Sbouyer 	    sc->sc_info.mci_pd_disks_failed);
159977961cf6Sbouyer 
160077961cf6Sbouyer 	DPRINTF("%s: nvram %d mem %d flash %d\n",
160177961cf6Sbouyer 	    DEVNAME(sc),
160277961cf6Sbouyer 	    sc->sc_info.mci_nvram_size,
160377961cf6Sbouyer 	    sc->sc_info.mci_memory_size,
160477961cf6Sbouyer 	    sc->sc_info.mci_flash_size);
160577961cf6Sbouyer 
160677961cf6Sbouyer 	DPRINTF("%s: ram_cor %d ram_uncor %d clus_all %d clus_act %d\n",
160777961cf6Sbouyer 	    DEVNAME(sc),
160877961cf6Sbouyer 	    sc->sc_info.mci_ram_correctable_errors,
160977961cf6Sbouyer 	    sc->sc_info.mci_ram_uncorrectable_errors,
161077961cf6Sbouyer 	    sc->sc_info.mci_cluster_allowed,
161177961cf6Sbouyer 	    sc->sc_info.mci_cluster_active);
161277961cf6Sbouyer 
161377961cf6Sbouyer 	DPRINTF("%s: max_strps_io %d raid_lvl %#x adapt_ops %#x ld_ops %#x\n",
161477961cf6Sbouyer 	    DEVNAME(sc),
161577961cf6Sbouyer 	    sc->sc_info.mci_max_strips_per_io,
161677961cf6Sbouyer 	    sc->sc_info.mci_raid_levels,
161777961cf6Sbouyer 	    sc->sc_info.mci_adapter_ops,
161877961cf6Sbouyer 	    sc->sc_info.mci_ld_ops);
161977961cf6Sbouyer 
162077961cf6Sbouyer 	DPRINTF("%s: strp_sz_min %d strp_sz_max %d pd_ops %#x pd_mix %#x\n",
162177961cf6Sbouyer 	    DEVNAME(sc),
162277961cf6Sbouyer 	    sc->sc_info.mci_stripe_sz_ops.min,
162377961cf6Sbouyer 	    sc->sc_info.mci_stripe_sz_ops.max,
162477961cf6Sbouyer 	    sc->sc_info.mci_pd_ops,
162577961cf6Sbouyer 	    sc->sc_info.mci_pd_mix_support);
162677961cf6Sbouyer 
162777961cf6Sbouyer 	DPRINTF("%s: ecc_bucket %d pckg_prop %s\n",
162877961cf6Sbouyer 	    DEVNAME(sc),
162977961cf6Sbouyer 	    sc->sc_info.mci_ecc_bucket_count,
163077961cf6Sbouyer 	    sc->sc_info.mci_package_version);
163177961cf6Sbouyer 
163277961cf6Sbouyer 	DPRINTF("%s: sq_nm %d prd_fail_poll %d intr_thrtl %d intr_thrtl_to %d\n",
163377961cf6Sbouyer 	    DEVNAME(sc),
163477961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_seq_num,
163577961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_pred_fail_poll_interval,
163677961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_intr_throttle_cnt,
163777961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_intr_throttle_timeout);
163877961cf6Sbouyer 
163977961cf6Sbouyer 	DPRINTF("%s: rbld_rate %d patr_rd_rate %d bgi_rate %d cc_rate %d\n",
164077961cf6Sbouyer 	    DEVNAME(sc),
164177961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_rebuild_rate,
164277961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_patrol_read_rate,
164377961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_bgi_rate,
164477961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_cc_rate);
164577961cf6Sbouyer 
164677961cf6Sbouyer 	DPRINTF("%s: rc_rate %d ch_flsh %d spin_cnt %d spin_dly %d clus_en %d\n",
164777961cf6Sbouyer 	    DEVNAME(sc),
164877961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_recon_rate,
164977961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_cache_flush_interval,
165077961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_spinup_drv_cnt,
165177961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_spinup_delay,
165277961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_cluster_enable);
165377961cf6Sbouyer 
165477961cf6Sbouyer 	DPRINTF("%s: coerc %d alarm %d dis_auto_rbld %d dis_bat_wrn %d ecc %d\n",
165577961cf6Sbouyer 	    DEVNAME(sc),
165677961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_coercion_mode,
165777961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_alarm_enable,
165877961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_disable_auto_rebuild,
165977961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_disable_battery_warn,
166077961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_ecc_bucket_size);
166177961cf6Sbouyer 
166277961cf6Sbouyer 	DPRINTF("%s: ecc_leak %d rest_hs %d exp_encl_dev %d\n",
166377961cf6Sbouyer 	    DEVNAME(sc),
166477961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_ecc_bucket_leak_rate,
166577961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_restore_hotspare_on_insertion,
166677961cf6Sbouyer 	    sc->sc_info.mci_properties.mcp_expose_encl_devices);
166777961cf6Sbouyer 
166877961cf6Sbouyer 	DPRINTF("%s: vendor %#x device %#x subvendor %#x subdevice %#x\n",
166977961cf6Sbouyer 	    DEVNAME(sc),
167077961cf6Sbouyer 	    sc->sc_info.mci_pci.mip_vendor,
167177961cf6Sbouyer 	    sc->sc_info.mci_pci.mip_device,
167277961cf6Sbouyer 	    sc->sc_info.mci_pci.mip_subvendor,
167377961cf6Sbouyer 	    sc->sc_info.mci_pci.mip_subdevice);
167477961cf6Sbouyer 
167577961cf6Sbouyer 	DPRINTF("%s: type %#x port_count %d port_addr ",
167677961cf6Sbouyer 	    DEVNAME(sc),
167777961cf6Sbouyer 	    sc->sc_info.mci_host.mih_type,
167877961cf6Sbouyer 	    sc->sc_info.mci_host.mih_port_count);
167977961cf6Sbouyer 
168077961cf6Sbouyer 	for (i = 0; i < 8; i++)
1681277d1243Smsaitoh 		DPRINTF("%.0" PRIx64 " ",
1682277d1243Smsaitoh 		    sc->sc_info.mci_host.mih_port_addr[i]);
168377961cf6Sbouyer 	DPRINTF("\n");
168477961cf6Sbouyer 
168577961cf6Sbouyer 	DPRINTF("%s: type %.x port_count %d port_addr ",
168677961cf6Sbouyer 	    DEVNAME(sc),
168777961cf6Sbouyer 	    sc->sc_info.mci_device.mid_type,
168877961cf6Sbouyer 	    sc->sc_info.mci_device.mid_port_count);
168977961cf6Sbouyer 
169077961cf6Sbouyer 	for (i = 0; i < 8; i++)
1691277d1243Smsaitoh 		DPRINTF("%.0" PRIx64 " ",
1692277d1243Smsaitoh 		    sc->sc_info.mci_device.mid_port_addr[i]);
169377961cf6Sbouyer 	DPRINTF("\n");
169477961cf6Sbouyer 
169577961cf6Sbouyer 	return (0);
169677961cf6Sbouyer }
169777961cf6Sbouyer 
1698bfa22340Smaxv static int
mfii_mfa_poll(struct mfii_softc * sc,struct mfii_ccb * ccb)169977961cf6Sbouyer mfii_mfa_poll(struct mfii_softc *sc, struct mfii_ccb *ccb)
170077961cf6Sbouyer {
170177961cf6Sbouyer 	struct mfi_frame_header	*hdr = ccb->ccb_request;
170277961cf6Sbouyer 	u_int64_t r;
170377961cf6Sbouyer 	int to = 0, rv = 0;
170477961cf6Sbouyer 
170577961cf6Sbouyer #ifdef DIAGNOSTIC
170677961cf6Sbouyer 	if (ccb->ccb_cookie != NULL || ccb->ccb_done != NULL)
170777961cf6Sbouyer 		panic("mfii_mfa_poll called with cookie or done set");
170877961cf6Sbouyer #endif
170977961cf6Sbouyer 
171077961cf6Sbouyer 	hdr->mfh_context = ccb->ccb_smid;
171177961cf6Sbouyer 	hdr->mfh_cmd_status = MFI_STAT_INVALID_STATUS;
171277961cf6Sbouyer 	hdr->mfh_flags |= htole16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
171377961cf6Sbouyer 
171477961cf6Sbouyer 	r = MFII_REQ_MFA(ccb->ccb_request_dva);
171577961cf6Sbouyer 	memcpy(&ccb->ccb_req, &r, sizeof(ccb->ccb_req));
171677961cf6Sbouyer 
1717e490de0bSmsaitoh 	/*
1718e490de0bSmsaitoh 	 * Even if the Aero card supports 32bit descriptor, 64bit descriptor
1719e490de0bSmsaitoh 	 * access is required for MFI_CMD_INIT.
1720e490de0bSmsaitoh 	 * Currently, mfii_mfa_poll() is called for MFI_CMD_INIT only.
1721e490de0bSmsaitoh 	 */
1722e490de0bSmsaitoh 	mfii_start64(sc, ccb);
172377961cf6Sbouyer 
172477961cf6Sbouyer 	for (;;) {
172577961cf6Sbouyer 		bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_requests),
172677961cf6Sbouyer 		    ccb->ccb_request_offset, MFII_REQUEST_SIZE,
172777961cf6Sbouyer 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
172877961cf6Sbouyer 
172977961cf6Sbouyer 		if (hdr->mfh_cmd_status != MFI_STAT_INVALID_STATUS)
173077961cf6Sbouyer 			break;
173177961cf6Sbouyer 
173277961cf6Sbouyer 		if (to++ > 5000) { /* XXX 5 seconds busywait sucks */
173377961cf6Sbouyer 			printf("%s: timeout on ccb %d\n", DEVNAME(sc),
173477961cf6Sbouyer 			    ccb->ccb_smid);
173577961cf6Sbouyer 			ccb->ccb_flags |= MFI_CCB_F_ERR;
173677961cf6Sbouyer 			rv = 1;
173777961cf6Sbouyer 			break;
173877961cf6Sbouyer 		}
173977961cf6Sbouyer 
174077961cf6Sbouyer 		bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_requests),
174177961cf6Sbouyer 		    ccb->ccb_request_offset, MFII_REQUEST_SIZE,
174277961cf6Sbouyer 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
174377961cf6Sbouyer 
174477961cf6Sbouyer 		delay(1000);
174577961cf6Sbouyer 	}
174677961cf6Sbouyer 
174777961cf6Sbouyer 	if (ccb->ccb_len > 0) {
174877961cf6Sbouyer 		bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap32,
174977961cf6Sbouyer 		    0, ccb->ccb_dmamap32->dm_mapsize,
175077961cf6Sbouyer 		    (ccb->ccb_direction == MFII_DATA_IN) ?
175177961cf6Sbouyer 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
175277961cf6Sbouyer 
175377961cf6Sbouyer 		bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap32);
175477961cf6Sbouyer 	}
175577961cf6Sbouyer 
175677961cf6Sbouyer 	return (rv);
175777961cf6Sbouyer }
175877961cf6Sbouyer 
1759bfa22340Smaxv static int
mfii_poll(struct mfii_softc * sc,struct mfii_ccb * ccb)176077961cf6Sbouyer mfii_poll(struct mfii_softc *sc, struct mfii_ccb *ccb)
176177961cf6Sbouyer {
176277961cf6Sbouyer 	void (*done)(struct mfii_softc *, struct mfii_ccb *);
176377961cf6Sbouyer 	void *cookie;
176477961cf6Sbouyer 	int rv = 1;
176577961cf6Sbouyer 
176677961cf6Sbouyer 	done = ccb->ccb_done;
176777961cf6Sbouyer 	cookie = ccb->ccb_cookie;
176877961cf6Sbouyer 
176977961cf6Sbouyer 	ccb->ccb_done = mfii_poll_done;
177077961cf6Sbouyer 	ccb->ccb_cookie = &rv;
177177961cf6Sbouyer 
177277961cf6Sbouyer 	mfii_start(sc, ccb);
177377961cf6Sbouyer 
177477961cf6Sbouyer 	do {
177577961cf6Sbouyer 		delay(10);
177677961cf6Sbouyer 		mfii_postq(sc);
177777961cf6Sbouyer 	} while (rv == 1);
177877961cf6Sbouyer 
177977961cf6Sbouyer 	ccb->ccb_cookie = cookie;
178077961cf6Sbouyer 	done(sc, ccb);
178177961cf6Sbouyer 
178277961cf6Sbouyer 	return (0);
178377961cf6Sbouyer }
178477961cf6Sbouyer 
1785bfa22340Smaxv static void
mfii_poll_done(struct mfii_softc * sc,struct mfii_ccb * ccb)178677961cf6Sbouyer mfii_poll_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
178777961cf6Sbouyer {
178877961cf6Sbouyer 	int *rv = ccb->ccb_cookie;
178977961cf6Sbouyer 
179077961cf6Sbouyer 	*rv = 0;
179177961cf6Sbouyer }
179277961cf6Sbouyer 
1793bfa22340Smaxv static int
mfii_exec(struct mfii_softc * sc,struct mfii_ccb * ccb)179477961cf6Sbouyer mfii_exec(struct mfii_softc *sc, struct mfii_ccb *ccb)
179577961cf6Sbouyer {
179677961cf6Sbouyer #ifdef DIAGNOSTIC
179777961cf6Sbouyer 	if (ccb->ccb_cookie != NULL || ccb->ccb_done != NULL)
179877961cf6Sbouyer 		panic("mfii_exec called with cookie or done set");
179977961cf6Sbouyer #endif
180077961cf6Sbouyer 
180177961cf6Sbouyer 	ccb->ccb_cookie = ccb;
180277961cf6Sbouyer 	ccb->ccb_done = mfii_exec_done;
180377961cf6Sbouyer 
180477961cf6Sbouyer 	mfii_start(sc, ccb);
180577961cf6Sbouyer 
180677961cf6Sbouyer 	mutex_enter(&ccb->ccb_mtx);
180777961cf6Sbouyer 	while (ccb->ccb_cookie != NULL)
180877961cf6Sbouyer 		cv_wait(&ccb->ccb_cv, &ccb->ccb_mtx);
180977961cf6Sbouyer 	mutex_exit(&ccb->ccb_mtx);
181077961cf6Sbouyer 
181177961cf6Sbouyer 	return (0);
181277961cf6Sbouyer }
181377961cf6Sbouyer 
1814bfa22340Smaxv static void
mfii_exec_done(struct mfii_softc * sc,struct mfii_ccb * ccb)181577961cf6Sbouyer mfii_exec_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
181677961cf6Sbouyer {
181777961cf6Sbouyer 	mutex_enter(&ccb->ccb_mtx);
181877961cf6Sbouyer 	ccb->ccb_cookie = NULL;
181977961cf6Sbouyer 	cv_signal(&ccb->ccb_cv);
182077961cf6Sbouyer 	mutex_exit(&ccb->ccb_mtx);
182177961cf6Sbouyer }
182277961cf6Sbouyer 
1823bfa22340Smaxv static int
mfii_mgmt(struct mfii_softc * sc,uint32_t opc,const union mfi_mbox * mbox,void * buf,size_t len,mfii_direction_t dir,bool poll)182477961cf6Sbouyer mfii_mgmt(struct mfii_softc *sc, uint32_t opc, const union mfi_mbox *mbox,
182577961cf6Sbouyer     void *buf, size_t len, mfii_direction_t dir, bool poll)
182677961cf6Sbouyer {
182777961cf6Sbouyer 	struct mfii_ccb *ccb;
182877961cf6Sbouyer 	int rv;
182977961cf6Sbouyer 
183077961cf6Sbouyer 	KASSERT(mutex_owned(&sc->sc_lock));
183177961cf6Sbouyer 	if (!sc->sc_running)
183277961cf6Sbouyer 		return EAGAIN;
183377961cf6Sbouyer 
183477961cf6Sbouyer 	ccb = mfii_get_ccb(sc);
183577961cf6Sbouyer 	if (ccb == NULL)
183677961cf6Sbouyer 		return (ENOMEM);
183777961cf6Sbouyer 
183877961cf6Sbouyer 	mfii_scrub_ccb(ccb);
183977961cf6Sbouyer 	rv = mfii_do_mgmt(sc, ccb, opc, mbox, buf, len, dir, poll);
184077961cf6Sbouyer 	mfii_put_ccb(sc, ccb);
184177961cf6Sbouyer 
184277961cf6Sbouyer 	return (rv);
184377961cf6Sbouyer }
184477961cf6Sbouyer 
1845bfa22340Smaxv static int
mfii_do_mgmt(struct mfii_softc * sc,struct mfii_ccb * ccb,uint32_t opc,const union mfi_mbox * mbox,void * buf,size_t len,mfii_direction_t dir,bool poll)184677961cf6Sbouyer mfii_do_mgmt(struct mfii_softc *sc, struct mfii_ccb *ccb, uint32_t opc,
184777961cf6Sbouyer     const union mfi_mbox *mbox, void *buf, size_t len, mfii_direction_t dir,
184877961cf6Sbouyer     bool poll)
184977961cf6Sbouyer {
185077961cf6Sbouyer 	struct mpii_msg_scsi_io *io = ccb->ccb_request;
185177961cf6Sbouyer 	struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
185277961cf6Sbouyer 	struct mfii_sge *sge = (struct mfii_sge *)(ctx + 1);
185377961cf6Sbouyer 	struct mfi_dcmd_frame *dcmd = ccb->ccb_mfi;
185477961cf6Sbouyer 	struct mfi_frame_header *hdr = &dcmd->mdf_header;
185577961cf6Sbouyer 	int rv = EIO;
185677961cf6Sbouyer 
185777961cf6Sbouyer 	if (cold)
185877961cf6Sbouyer 		poll = true;
185977961cf6Sbouyer 
186077961cf6Sbouyer 	ccb->ccb_data = buf;
186177961cf6Sbouyer 	ccb->ccb_len = len;
186277961cf6Sbouyer 	ccb->ccb_direction = dir;
186377961cf6Sbouyer 	switch (dir) {
186477961cf6Sbouyer 	case MFII_DATA_IN:
186577961cf6Sbouyer 		hdr->mfh_flags = htole16(MFI_FRAME_DIR_READ);
186677961cf6Sbouyer 		break;
186777961cf6Sbouyer 	case MFII_DATA_OUT:
186877961cf6Sbouyer 		hdr->mfh_flags = htole16(MFI_FRAME_DIR_WRITE);
186977961cf6Sbouyer 		break;
187077961cf6Sbouyer 	case MFII_DATA_NONE:
187177961cf6Sbouyer 		hdr->mfh_flags = htole16(MFI_FRAME_DIR_NONE);
187277961cf6Sbouyer 		break;
187377961cf6Sbouyer 	}
187477961cf6Sbouyer 
187577961cf6Sbouyer 	if (mfii_load_mfa(sc, ccb, &dcmd->mdf_sgl, poll) != 0) {
187677961cf6Sbouyer 		rv = ENOMEM;
187777961cf6Sbouyer 		goto done;
187877961cf6Sbouyer 	}
187977961cf6Sbouyer 
188077961cf6Sbouyer 	hdr->mfh_cmd = MFI_CMD_DCMD;
188177961cf6Sbouyer 	hdr->mfh_context = ccb->ccb_smid;
188277961cf6Sbouyer 	hdr->mfh_data_len = htole32(len);
188377961cf6Sbouyer 	hdr->mfh_sg_count = ccb->ccb_dmamap32->dm_nsegs;
188477961cf6Sbouyer 	KASSERT(!ccb->ccb_dma64);
188577961cf6Sbouyer 
188677961cf6Sbouyer 	dcmd->mdf_opcode = opc;
188777961cf6Sbouyer 	/* handle special opcodes */
188877961cf6Sbouyer 	if (mbox != NULL)
188977961cf6Sbouyer 		memcpy(&dcmd->mdf_mbox, mbox, sizeof(dcmd->mdf_mbox));
189077961cf6Sbouyer 
189177961cf6Sbouyer 	io->function = MFII_FUNCTION_PASSTHRU_IO;
189277961cf6Sbouyer 	io->sgl_offset0 = ((u_int8_t *)sge - (u_int8_t *)io) / 4;
189377961cf6Sbouyer 	io->chain_offset = ((u_int8_t *)sge - (u_int8_t *)io) / 16;
189477961cf6Sbouyer 
189577961cf6Sbouyer 	sge->sg_addr = htole64(ccb->ccb_mfi_dva);
189677961cf6Sbouyer 	sge->sg_len = htole32(MFI_FRAME_SIZE);
189777961cf6Sbouyer 	sge->sg_flags = MFII_SGE_CHAIN_ELEMENT | MFII_SGE_ADDR_IOCPLBNTA;
189877961cf6Sbouyer 
189977961cf6Sbouyer 	ccb->ccb_req.flags = MFII_REQ_TYPE_SCSI;
190077961cf6Sbouyer 	ccb->ccb_req.smid = le16toh(ccb->ccb_smid);
190177961cf6Sbouyer 
190277961cf6Sbouyer 	if (poll) {
190377961cf6Sbouyer 		ccb->ccb_done = mfii_empty_done;
190477961cf6Sbouyer 		mfii_poll(sc, ccb);
190577961cf6Sbouyer 	} else
190677961cf6Sbouyer 		mfii_exec(sc, ccb);
190777961cf6Sbouyer 
190877961cf6Sbouyer 	if (hdr->mfh_cmd_status == MFI_STAT_OK) {
190977961cf6Sbouyer 		rv = 0;
191077961cf6Sbouyer 	}
191177961cf6Sbouyer 
191277961cf6Sbouyer done:
191377961cf6Sbouyer 	return (rv);
191477961cf6Sbouyer }
191577961cf6Sbouyer 
1916bfa22340Smaxv static void
mfii_empty_done(struct mfii_softc * sc,struct mfii_ccb * ccb)191777961cf6Sbouyer mfii_empty_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
191877961cf6Sbouyer {
191977961cf6Sbouyer 	return;
192077961cf6Sbouyer }
192177961cf6Sbouyer 
1922bfa22340Smaxv static int
mfii_load_mfa(struct mfii_softc * sc,struct mfii_ccb * ccb,void * sglp,int nosleep)192377961cf6Sbouyer mfii_load_mfa(struct mfii_softc *sc, struct mfii_ccb *ccb,
192477961cf6Sbouyer     void *sglp, int nosleep)
192577961cf6Sbouyer {
192677961cf6Sbouyer 	union mfi_sgl *sgl = sglp;
192777961cf6Sbouyer 	bus_dmamap_t dmap = ccb->ccb_dmamap32;
192877961cf6Sbouyer 	int error;
192977961cf6Sbouyer 	int i;
193077961cf6Sbouyer 
193177961cf6Sbouyer 	KASSERT(!ccb->ccb_dma64);
193277961cf6Sbouyer 	if (ccb->ccb_len == 0)
193377961cf6Sbouyer 		return (0);
193477961cf6Sbouyer 
193577961cf6Sbouyer 	error = bus_dmamap_load(sc->sc_dmat, dmap,
193677961cf6Sbouyer 	    ccb->ccb_data, ccb->ccb_len, NULL,
193777961cf6Sbouyer 	    nosleep ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
193877961cf6Sbouyer 	if (error) {
193977961cf6Sbouyer 		printf("%s: error %d loading dmamap\n", DEVNAME(sc), error);
194077961cf6Sbouyer 		return (1);
194177961cf6Sbouyer 	}
194277961cf6Sbouyer 
194377961cf6Sbouyer 	for (i = 0; i < dmap->dm_nsegs; i++) {
194477961cf6Sbouyer 		sgl->sg32[i].addr = htole32(dmap->dm_segs[i].ds_addr);
194577961cf6Sbouyer 		sgl->sg32[i].len = htole32(dmap->dm_segs[i].ds_len);
194677961cf6Sbouyer 	}
194777961cf6Sbouyer 
194877961cf6Sbouyer 	bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
194977961cf6Sbouyer 	    ccb->ccb_direction == MFII_DATA_OUT ?
195077961cf6Sbouyer 	    BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
195177961cf6Sbouyer 
195277961cf6Sbouyer 	return (0);
195377961cf6Sbouyer }
195477961cf6Sbouyer 
1955bfa22340Smaxv static void
mfii_start(struct mfii_softc * sc,struct mfii_ccb * ccb)195677961cf6Sbouyer mfii_start(struct mfii_softc *sc, struct mfii_ccb *ccb)
195777961cf6Sbouyer {
1958e490de0bSmsaitoh 
1959e490de0bSmsaitoh 	mfii_start_common(sc, ccb,
1960e490de0bSmsaitoh 	    ((sc->sc_iop_flag & MFII_IOP_DESC_32BIT) != 0) ? true : false);
1961e490de0bSmsaitoh }
1962e490de0bSmsaitoh 
1963e490de0bSmsaitoh static void
mfii_start64(struct mfii_softc * sc,struct mfii_ccb * ccb)1964e490de0bSmsaitoh mfii_start64(struct mfii_softc *sc, struct mfii_ccb *ccb)
1965e490de0bSmsaitoh {
1966e490de0bSmsaitoh 
1967e490de0bSmsaitoh 	mfii_start_common(sc, ccb, false);
1968e490de0bSmsaitoh }
1969e490de0bSmsaitoh 
1970e490de0bSmsaitoh static void
mfii_start_common(struct mfii_softc * sc,struct mfii_ccb * ccb,bool do32)1971e490de0bSmsaitoh mfii_start_common(struct mfii_softc *sc, struct mfii_ccb *ccb, bool do32)
1972e490de0bSmsaitoh {
1973e8526317Smsaitoh 	uint32_t *r = (uint32_t *)&ccb->ccb_req;
197477961cf6Sbouyer 
197577961cf6Sbouyer 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_requests),
197677961cf6Sbouyer 	    ccb->ccb_request_offset, MFII_REQUEST_SIZE,
197777961cf6Sbouyer 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
197877961cf6Sbouyer 
1979e490de0bSmsaitoh 	if (do32)
1980e490de0bSmsaitoh 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MFI_ISQP, r[0]);
1981e490de0bSmsaitoh 	else {
1982ddd37802Smsaitoh #if defined(__LP64__)
1983e490de0bSmsaitoh 		uint64_t buf;
1984e490de0bSmsaitoh 
1985ddd37802Smsaitoh 		buf = ((uint64_t)r[1] << 32) | r[0];
1986ddd37802Smsaitoh 		bus_space_write_8(sc->sc_iot, sc->sc_ioh, MFI_IQPL, buf);
198777961cf6Sbouyer #else
198877961cf6Sbouyer 		mutex_enter(&sc->sc_post_mtx);
198977961cf6Sbouyer 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MFI_IQPL, r[0]);
199077961cf6Sbouyer 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MFI_IQPH, r[1]);
199177961cf6Sbouyer 		bus_space_barrier(sc->sc_iot, sc->sc_ioh,
1992b6f340dfSmsaitoh 		    MFI_IQPL, 8, BUS_SPACE_BARRIER_WRITE);
199377961cf6Sbouyer 		mutex_exit(&sc->sc_post_mtx);
199477961cf6Sbouyer #endif
199577961cf6Sbouyer 	}
1996e490de0bSmsaitoh }
199777961cf6Sbouyer 
1998bfa22340Smaxv static void
mfii_done(struct mfii_softc * sc,struct mfii_ccb * ccb)199977961cf6Sbouyer mfii_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
200077961cf6Sbouyer {
200177961cf6Sbouyer 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_requests),
200277961cf6Sbouyer 	    ccb->ccb_request_offset, MFII_REQUEST_SIZE,
200377961cf6Sbouyer 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
200477961cf6Sbouyer 
200577961cf6Sbouyer 	if (ccb->ccb_sgl_len > 0) {
200677961cf6Sbouyer 		bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_sgl),
200777961cf6Sbouyer 		    ccb->ccb_sgl_offset, ccb->ccb_sgl_len,
200877961cf6Sbouyer 		    BUS_DMASYNC_POSTWRITE);
200977961cf6Sbouyer 	}
201077961cf6Sbouyer 
201177961cf6Sbouyer 	if (ccb->ccb_dma64) {
201277961cf6Sbouyer 		KASSERT(ccb->ccb_len > 0);
201377961cf6Sbouyer 		bus_dmamap_sync(sc->sc_dmat64, ccb->ccb_dmamap64,
201477961cf6Sbouyer 		    0, ccb->ccb_dmamap64->dm_mapsize,
201577961cf6Sbouyer 		    (ccb->ccb_direction == MFII_DATA_IN) ?
201677961cf6Sbouyer 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
201777961cf6Sbouyer 
201877961cf6Sbouyer 		bus_dmamap_unload(sc->sc_dmat64, ccb->ccb_dmamap64);
201977961cf6Sbouyer 	} else if (ccb->ccb_len > 0) {
202077961cf6Sbouyer 		bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap32,
202177961cf6Sbouyer 		    0, ccb->ccb_dmamap32->dm_mapsize,
202277961cf6Sbouyer 		    (ccb->ccb_direction == MFII_DATA_IN) ?
202377961cf6Sbouyer 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
202477961cf6Sbouyer 
202577961cf6Sbouyer 		bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap32);
202677961cf6Sbouyer 	}
202777961cf6Sbouyer 
202877961cf6Sbouyer 	ccb->ccb_done(sc, ccb);
202977961cf6Sbouyer }
203077961cf6Sbouyer 
2031bfa22340Smaxv static int
mfii_initialise_firmware(struct mfii_softc * sc)203277961cf6Sbouyer mfii_initialise_firmware(struct mfii_softc *sc)
203377961cf6Sbouyer {
203477961cf6Sbouyer 	struct mpii_msg_iocinit_request *iiq;
203577961cf6Sbouyer 	struct mfii_dmamem *m;
203677961cf6Sbouyer 	struct mfii_ccb *ccb;
203777961cf6Sbouyer 	struct mfi_init_frame *init;
203877961cf6Sbouyer 	int rv;
203977961cf6Sbouyer 
204077961cf6Sbouyer 	m = mfii_dmamem_alloc(sc, sizeof(*iiq));
204177961cf6Sbouyer 	if (m == NULL)
204277961cf6Sbouyer 		return (1);
204377961cf6Sbouyer 
204477961cf6Sbouyer 	iiq = MFII_DMA_KVA(m);
204577961cf6Sbouyer 	memset(iiq, 0, sizeof(*iiq));
204677961cf6Sbouyer 
204777961cf6Sbouyer 	iiq->function = MPII_FUNCTION_IOC_INIT;
204877961cf6Sbouyer 	iiq->whoinit = MPII_WHOINIT_HOST_DRIVER;
204977961cf6Sbouyer 
205077961cf6Sbouyer 	iiq->msg_version_maj = 0x02;
205177961cf6Sbouyer 	iiq->msg_version_min = 0x00;
205277961cf6Sbouyer 	iiq->hdr_version_unit = 0x10;
205377961cf6Sbouyer 	iiq->hdr_version_dev = 0x0;
205477961cf6Sbouyer 
205577961cf6Sbouyer 	iiq->system_request_frame_size = htole16(MFII_REQUEST_SIZE / 4);
205677961cf6Sbouyer 
205777961cf6Sbouyer 	iiq->reply_descriptor_post_queue_depth =
205877961cf6Sbouyer 	    htole16(sc->sc_reply_postq_depth);
205977961cf6Sbouyer 	iiq->reply_free_queue_depth = htole16(0);
206077961cf6Sbouyer 
206177961cf6Sbouyer 	iiq->sense_buffer_address_high = htole32(
206277961cf6Sbouyer 	    MFII_DMA_DVA(sc->sc_sense) >> 32);
206377961cf6Sbouyer 
20644b48710dSbouyer 	iiq->reply_descriptor_post_queue_address_lo =
20654b48710dSbouyer 	    htole32(MFII_DMA_DVA(sc->sc_reply_postq));
20664b48710dSbouyer 	iiq->reply_descriptor_post_queue_address_hi =
20674b48710dSbouyer 	    htole32(MFII_DMA_DVA(sc->sc_reply_postq) >> 32);
206877961cf6Sbouyer 
20694b48710dSbouyer 	iiq->system_request_frame_base_address_lo =
20704b48710dSbouyer 	    htole32(MFII_DMA_DVA(sc->sc_requests));
20714b48710dSbouyer 	iiq->system_request_frame_base_address_hi =
20724b48710dSbouyer 	    htole32(MFII_DMA_DVA(sc->sc_requests) >> 32);
207377961cf6Sbouyer 
207477961cf6Sbouyer 	iiq->timestamp = htole64(time_uptime);
207577961cf6Sbouyer 
207677961cf6Sbouyer 	ccb = mfii_get_ccb(sc);
207777961cf6Sbouyer 	if (ccb == NULL) {
207877961cf6Sbouyer 		/* shouldn't ever run out of ccbs during attach */
207977961cf6Sbouyer 		return (1);
208077961cf6Sbouyer 	}
208177961cf6Sbouyer 	mfii_scrub_ccb(ccb);
208277961cf6Sbouyer 	init = ccb->ccb_request;
208377961cf6Sbouyer 
208477961cf6Sbouyer 	init->mif_header.mfh_cmd = MFI_CMD_INIT;
208577961cf6Sbouyer 	init->mif_header.mfh_data_len = htole32(sizeof(*iiq));
208677961cf6Sbouyer 	init->mif_qinfo_new_addr_lo = htole32(MFII_DMA_DVA(m));
208777961cf6Sbouyer 	init->mif_qinfo_new_addr_hi = htole32((uint64_t)MFII_DMA_DVA(m) >> 32);
208877961cf6Sbouyer 
208977961cf6Sbouyer 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_reply_postq),
209077961cf6Sbouyer 	    0, MFII_DMA_LEN(sc->sc_reply_postq),
209177961cf6Sbouyer 	    BUS_DMASYNC_PREREAD);
209277961cf6Sbouyer 
209377961cf6Sbouyer 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(m),
209477961cf6Sbouyer 	    0, sizeof(*iiq), BUS_DMASYNC_PREREAD);
209577961cf6Sbouyer 
209677961cf6Sbouyer 	rv = mfii_mfa_poll(sc, ccb);
209777961cf6Sbouyer 
209877961cf6Sbouyer 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(m),
209977961cf6Sbouyer 	    0, sizeof(*iiq), BUS_DMASYNC_POSTREAD);
210077961cf6Sbouyer 
210177961cf6Sbouyer 	mfii_put_ccb(sc, ccb);
210277961cf6Sbouyer 	mfii_dmamem_free(sc, m);
210377961cf6Sbouyer 
210477961cf6Sbouyer 	return (rv);
210577961cf6Sbouyer }
210677961cf6Sbouyer 
2107bfa22340Smaxv static int
mfii_my_intr(struct mfii_softc * sc)210877961cf6Sbouyer mfii_my_intr(struct mfii_softc *sc)
210977961cf6Sbouyer {
211077961cf6Sbouyer 	u_int32_t status;
211177961cf6Sbouyer 
211277961cf6Sbouyer 	status = mfii_read(sc, MFI_OSTS);
211377961cf6Sbouyer 
211477961cf6Sbouyer 	DNPRINTF(MFII_D_INTR, "%s: intr status 0x%x\n", DEVNAME(sc), status);
211577961cf6Sbouyer 	if (ISSET(status, 0x1)) {
211677961cf6Sbouyer 		mfii_write(sc, MFI_OSTS, status);
211777961cf6Sbouyer 		return (1);
211877961cf6Sbouyer 	}
211977961cf6Sbouyer 
212077961cf6Sbouyer 	return (ISSET(status, MFII_OSTS_INTR_VALID) ? 1 : 0);
212177961cf6Sbouyer }
212277961cf6Sbouyer 
2123bfa22340Smaxv static int
mfii_intr(void * arg)212477961cf6Sbouyer mfii_intr(void *arg)
212577961cf6Sbouyer {
212677961cf6Sbouyer 	struct mfii_softc *sc = arg;
212777961cf6Sbouyer 
212877961cf6Sbouyer 	if (!mfii_my_intr(sc))
212977961cf6Sbouyer 		return (0);
213077961cf6Sbouyer 
213177961cf6Sbouyer 	mfii_postq(sc);
213277961cf6Sbouyer 
213377961cf6Sbouyer 	return (1);
213477961cf6Sbouyer }
213577961cf6Sbouyer 
2136bfa22340Smaxv static void
mfii_postq(struct mfii_softc * sc)213777961cf6Sbouyer mfii_postq(struct mfii_softc *sc)
213877961cf6Sbouyer {
213977961cf6Sbouyer 	struct mfii_ccb_list ccbs = SIMPLEQ_HEAD_INITIALIZER(ccbs);
214077961cf6Sbouyer 	struct mpii_reply_descr *postq = MFII_DMA_KVA(sc->sc_reply_postq);
214177961cf6Sbouyer 	struct mpii_reply_descr *rdp;
214277961cf6Sbouyer 	struct mfii_ccb *ccb;
214377961cf6Sbouyer 	int rpi = 0;
214477961cf6Sbouyer 
214577961cf6Sbouyer 	mutex_enter(&sc->sc_reply_postq_mtx);
214677961cf6Sbouyer 
214777961cf6Sbouyer 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_reply_postq),
214877961cf6Sbouyer 	    0, MFII_DMA_LEN(sc->sc_reply_postq),
214977961cf6Sbouyer 	    BUS_DMASYNC_POSTREAD);
215077961cf6Sbouyer 
215177961cf6Sbouyer 	for (;;) {
215277961cf6Sbouyer 		rdp = &postq[sc->sc_reply_postq_index];
2153277d1243Smsaitoh 		DNPRINTF(MFII_D_INTR,
2154277d1243Smsaitoh 		    "%s: mfii_postq index %d flags 0x%x data 0x%x\n",
215577961cf6Sbouyer 		    DEVNAME(sc), sc->sc_reply_postq_index, rdp->reply_flags,
215677961cf6Sbouyer 			rdp->data == 0xffffffff);
215777961cf6Sbouyer 		if ((rdp->reply_flags & MPII_REPLY_DESCR_TYPE_MASK) ==
215877961cf6Sbouyer 		    MPII_REPLY_DESCR_UNUSED)
215977961cf6Sbouyer 			break;
216077961cf6Sbouyer 		if (rdp->data == 0xffffffff) {
216177961cf6Sbouyer 			/*
216277961cf6Sbouyer 			 * ioc is still writing to the reply post queue
216377961cf6Sbouyer 			 * race condition - bail!
216477961cf6Sbouyer 			 */
216577961cf6Sbouyer 			break;
216677961cf6Sbouyer 		}
216777961cf6Sbouyer 
216877961cf6Sbouyer 		ccb = &sc->sc_ccb[le16toh(rdp->smid) - 1];
216977961cf6Sbouyer 		SIMPLEQ_INSERT_TAIL(&ccbs, ccb, ccb_link);
217077961cf6Sbouyer 		memset(rdp, 0xff, sizeof(*rdp));
217177961cf6Sbouyer 
217277961cf6Sbouyer 		sc->sc_reply_postq_index++;
217377961cf6Sbouyer 		sc->sc_reply_postq_index %= sc->sc_reply_postq_depth;
217477961cf6Sbouyer 		rpi = 1;
217577961cf6Sbouyer 	}
217677961cf6Sbouyer 
217777961cf6Sbouyer 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_reply_postq),
217877961cf6Sbouyer 	    0, MFII_DMA_LEN(sc->sc_reply_postq),
217977961cf6Sbouyer 	    BUS_DMASYNC_PREREAD);
218077961cf6Sbouyer 
218177961cf6Sbouyer 	if (rpi)
218277961cf6Sbouyer 		mfii_write(sc, MFII_RPI, sc->sc_reply_postq_index);
218377961cf6Sbouyer 
218477961cf6Sbouyer 	mutex_exit(&sc->sc_reply_postq_mtx);
218577961cf6Sbouyer 
218677961cf6Sbouyer 	while ((ccb = SIMPLEQ_FIRST(&ccbs)) != NULL) {
218777961cf6Sbouyer 		SIMPLEQ_REMOVE_HEAD(&ccbs, ccb_link);
218877961cf6Sbouyer 		mfii_done(sc, ccb);
218977961cf6Sbouyer 	}
219077961cf6Sbouyer }
219177961cf6Sbouyer 
2192bfa22340Smaxv static void
mfii_scsipi_request(struct scsipi_channel * chan,scsipi_adapter_req_t req,void * arg)219377961cf6Sbouyer mfii_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
219477961cf6Sbouyer     void *arg)
219577961cf6Sbouyer {
219677961cf6Sbouyer 	struct scsipi_periph    *periph;
219777961cf6Sbouyer 	struct scsipi_xfer	*xs;
219877961cf6Sbouyer 	struct scsipi_adapter   *adapt = chan->chan_adapter;
219977961cf6Sbouyer 	struct mfii_softc	*sc = device_private(adapt->adapt_dev);
220077961cf6Sbouyer 	struct mfii_ccb *ccb;
220177961cf6Sbouyer 	int timeout;
220277961cf6Sbouyer 	int target;
220377961cf6Sbouyer 
220477961cf6Sbouyer 	switch (req) {
220577961cf6Sbouyer 		case ADAPTER_REQ_GROW_RESOURCES:
220677961cf6Sbouyer 		/* Not supported. */
220777961cf6Sbouyer 		return;
220877961cf6Sbouyer 	case ADAPTER_REQ_SET_XFER_MODE:
220977961cf6Sbouyer 	{
221077961cf6Sbouyer 		struct scsipi_xfer_mode *xm = arg;
221177961cf6Sbouyer 		xm->xm_mode = PERIPH_CAP_TQING;
221277961cf6Sbouyer 		xm->xm_period = 0;
221377961cf6Sbouyer 		xm->xm_offset = 0;
221477961cf6Sbouyer 		scsipi_async_event(&sc->sc_chan, ASYNC_EVENT_XFER_MODE, xm);
221577961cf6Sbouyer 		return;
221677961cf6Sbouyer 	}
221777961cf6Sbouyer 	case ADAPTER_REQ_RUN_XFER:
221877961cf6Sbouyer 		break;
221977961cf6Sbouyer 	}
222077961cf6Sbouyer 
222177961cf6Sbouyer 	xs = arg;
222277961cf6Sbouyer 	periph = xs->xs_periph;
222377961cf6Sbouyer 	target = periph->periph_target;
222477961cf6Sbouyer 
2225c6bee2b8Smsaitoh 	if (target >= MFII_MAX_LD_EXT || !sc->sc_ld[target].ld_present ||
222677961cf6Sbouyer 	    periph->periph_lun != 0) {
222777961cf6Sbouyer 		xs->error = XS_SELTIMEOUT;
222877961cf6Sbouyer 		scsipi_done(xs);
222977961cf6Sbouyer 		return;
223077961cf6Sbouyer 	}
223177961cf6Sbouyer 
223277961cf6Sbouyer 	if ((xs->cmd->opcode == SCSI_SYNCHRONIZE_CACHE_10 ||
223377961cf6Sbouyer 	    xs->cmd->opcode == SCSI_SYNCHRONIZE_CACHE_16) && sc->sc_bbuok) {
223477961cf6Sbouyer 		/* the cache is stable storage, don't flush */
223577961cf6Sbouyer 		xs->error = XS_NOERROR;
223677961cf6Sbouyer 		xs->status = SCSI_OK;
223777961cf6Sbouyer 		xs->resid = 0;
223877961cf6Sbouyer 		scsipi_done(xs);
223977961cf6Sbouyer 		return;
224077961cf6Sbouyer 	}
224177961cf6Sbouyer 
224277961cf6Sbouyer 	ccb = mfii_get_ccb(sc);
224377961cf6Sbouyer 	if (ccb == NULL) {
224477961cf6Sbouyer 		xs->error = XS_RESOURCE_SHORTAGE;
224577961cf6Sbouyer 		scsipi_done(xs);
224677961cf6Sbouyer 		return;
224777961cf6Sbouyer 	}
224877961cf6Sbouyer 	mfii_scrub_ccb(ccb);
224977961cf6Sbouyer 	ccb->ccb_cookie = xs;
225077961cf6Sbouyer 	ccb->ccb_done = mfii_scsi_cmd_done;
225177961cf6Sbouyer 	ccb->ccb_data = xs->data;
225277961cf6Sbouyer 	ccb->ccb_len = xs->datalen;
225377961cf6Sbouyer 
225477961cf6Sbouyer 	timeout = mstohz(xs->timeout);
225577961cf6Sbouyer 	if (timeout == 0)
225677961cf6Sbouyer 		timeout = 1;
225777961cf6Sbouyer 	callout_reset(&xs->xs_callout, timeout, mfii_scsi_cmd_tmo, ccb);
225877961cf6Sbouyer 
225977961cf6Sbouyer 	switch (xs->cmd->opcode) {
226077961cf6Sbouyer 	case SCSI_READ_6_COMMAND:
226177961cf6Sbouyer 	case READ_10:
226277961cf6Sbouyer 	case READ_12:
226377961cf6Sbouyer 	case READ_16:
226477961cf6Sbouyer 	case SCSI_WRITE_6_COMMAND:
226577961cf6Sbouyer 	case WRITE_10:
226677961cf6Sbouyer 	case WRITE_12:
226777961cf6Sbouyer 	case WRITE_16:
226877961cf6Sbouyer 		if (mfii_scsi_cmd_io(sc, ccb, xs) != 0)
226977961cf6Sbouyer 			goto stuffup;
227077961cf6Sbouyer 		break;
227177961cf6Sbouyer 
227277961cf6Sbouyer 	default:
227377961cf6Sbouyer 		if (mfii_scsi_cmd_cdb(sc, ccb, xs) != 0)
227477961cf6Sbouyer 			goto stuffup;
227577961cf6Sbouyer 		break;
227677961cf6Sbouyer 	}
227777961cf6Sbouyer 
227877961cf6Sbouyer 	xs->error = XS_NOERROR;
227977961cf6Sbouyer 	xs->resid = 0;
228077961cf6Sbouyer 
228177961cf6Sbouyer 	DNPRINTF(MFII_D_CMD, "%s: start io %d cmd %d\n", DEVNAME(sc), target,
228277961cf6Sbouyer 	    xs->cmd->opcode);
228377961cf6Sbouyer 
228477961cf6Sbouyer 	if (xs->xs_control & XS_CTL_POLL) {
228577961cf6Sbouyer 		if (mfii_poll(sc, ccb) != 0)
228677961cf6Sbouyer 			goto stuffup;
228777961cf6Sbouyer 		return;
228877961cf6Sbouyer 	}
228977961cf6Sbouyer 
229077961cf6Sbouyer 	mfii_start(sc, ccb);
229177961cf6Sbouyer 
229277961cf6Sbouyer 	return;
229377961cf6Sbouyer 
229477961cf6Sbouyer stuffup:
229577961cf6Sbouyer 	xs->error = XS_DRIVER_STUFFUP;
229677961cf6Sbouyer 	scsipi_done(xs);
229777961cf6Sbouyer 	mfii_put_ccb(sc, ccb);
229877961cf6Sbouyer }
229977961cf6Sbouyer 
2300bfa22340Smaxv static void
mfii_scsi_cmd_done(struct mfii_softc * sc,struct mfii_ccb * ccb)230177961cf6Sbouyer mfii_scsi_cmd_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
230277961cf6Sbouyer {
230377961cf6Sbouyer 	struct scsipi_xfer *xs = ccb->ccb_cookie;
230477961cf6Sbouyer 	struct mpii_msg_scsi_io *io = ccb->ccb_request;
230577961cf6Sbouyer 	struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
230677961cf6Sbouyer 
230777961cf6Sbouyer 	if (callout_stop(&xs->xs_callout) != 0)
2308d38daeb6Sbouyer 		return;
230977961cf6Sbouyer 
231077961cf6Sbouyer 	switch (ctx->status) {
231177961cf6Sbouyer 	case MFI_STAT_OK:
231277961cf6Sbouyer 		break;
231377961cf6Sbouyer 
231477961cf6Sbouyer 	case MFI_STAT_SCSI_DONE_WITH_ERROR:
231577961cf6Sbouyer 		xs->error = XS_SENSE;
231677961cf6Sbouyer 		memset(&xs->sense, 0, sizeof(xs->sense));
231777961cf6Sbouyer 		memcpy(&xs->sense, ccb->ccb_sense, sizeof(xs->sense));
231877961cf6Sbouyer 		break;
231977961cf6Sbouyer 
232077961cf6Sbouyer 	case MFI_STAT_LD_OFFLINE:
232177961cf6Sbouyer 	case MFI_STAT_DEVICE_NOT_FOUND:
232277961cf6Sbouyer 		xs->error = XS_SELTIMEOUT;
232377961cf6Sbouyer 		break;
232477961cf6Sbouyer 
232577961cf6Sbouyer 	default:
232677961cf6Sbouyer 		xs->error = XS_DRIVER_STUFFUP;
232777961cf6Sbouyer 		break;
232877961cf6Sbouyer 	}
232977961cf6Sbouyer 
233077961cf6Sbouyer 	scsipi_done(xs);
233177961cf6Sbouyer 	mfii_put_ccb(sc, ccb);
233277961cf6Sbouyer }
233377961cf6Sbouyer 
2334bfa22340Smaxv static int
mfii_scsi_cmd_io(struct mfii_softc * sc,struct mfii_ccb * ccb,struct scsipi_xfer * xs)233577961cf6Sbouyer mfii_scsi_cmd_io(struct mfii_softc *sc, struct mfii_ccb *ccb,
233677961cf6Sbouyer     struct scsipi_xfer *xs)
233777961cf6Sbouyer {
233877961cf6Sbouyer 	struct scsipi_periph *periph = xs->xs_periph;
233977961cf6Sbouyer 	struct mpii_msg_scsi_io *io = ccb->ccb_request;
234077961cf6Sbouyer 	struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
23413b643292Smsaitoh 	int segs, target;
234277961cf6Sbouyer 
23433b643292Smsaitoh 	target = sc->sc_ld[periph->periph_target].ld_target_id;
23443b643292Smsaitoh 	io->dev_handle = htole16(target);
234577961cf6Sbouyer 	io->function = MFII_FUNCTION_LDIO_REQUEST;
234677961cf6Sbouyer 	io->sense_buffer_low_address = htole32(ccb->ccb_sense_dva);
234777961cf6Sbouyer 	io->sgl_flags = htole16(0x02); /* XXX */
234877961cf6Sbouyer 	io->sense_buffer_length = sizeof(xs->sense);
234977961cf6Sbouyer 	io->sgl_offset0 = (sizeof(*io) + sizeof(*ctx)) / 4;
235077961cf6Sbouyer 	io->data_length = htole32(xs->datalen);
235177961cf6Sbouyer 	io->io_flags = htole16(xs->cmdlen);
235277961cf6Sbouyer 	switch (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
235377961cf6Sbouyer 	case XS_CTL_DATA_IN:
235477961cf6Sbouyer 		ccb->ccb_direction = MFII_DATA_IN;
235577961cf6Sbouyer 		io->direction = MPII_SCSIIO_DIR_READ;
235677961cf6Sbouyer 		break;
235777961cf6Sbouyer 	case XS_CTL_DATA_OUT:
235877961cf6Sbouyer 		ccb->ccb_direction = MFII_DATA_OUT;
235977961cf6Sbouyer 		io->direction = MPII_SCSIIO_DIR_WRITE;
236077961cf6Sbouyer 		break;
236177961cf6Sbouyer 	default:
236277961cf6Sbouyer 		ccb->ccb_direction = MFII_DATA_NONE;
236377961cf6Sbouyer 		io->direction = MPII_SCSIIO_DIR_NONE;
236477961cf6Sbouyer 		break;
236577961cf6Sbouyer 	}
236677961cf6Sbouyer 	memcpy(io->cdb, xs->cmd, xs->cmdlen);
236777961cf6Sbouyer 
236877961cf6Sbouyer 	ctx->type_nseg = sc->sc_iop->ldio_ctx_type_nseg;
236977961cf6Sbouyer 	ctx->timeout_value = htole16(0x14); /* XXX */
237077961cf6Sbouyer 	ctx->reg_lock_flags = htole16(sc->sc_iop->ldio_ctx_reg_lock_flags);
23713b643292Smsaitoh 	ctx->virtual_disk_target_id = htole16(target);
237277961cf6Sbouyer 
237377961cf6Sbouyer 	if (mfii_load_ccb(sc, ccb, ctx + 1,
237477961cf6Sbouyer 	    ISSET(xs->xs_control, XS_CTL_NOSLEEP)) != 0)
237577961cf6Sbouyer 		return (1);
237677961cf6Sbouyer 
237777961cf6Sbouyer 	KASSERT(ccb->ccb_len == 0 || ccb->ccb_dma64);
237877961cf6Sbouyer 	segs = (ccb->ccb_len == 0) ? 0 : ccb->ccb_dmamap64->dm_nsegs;
237977961cf6Sbouyer 	switch (sc->sc_iop->num_sge_loc) {
238077961cf6Sbouyer 	case MFII_IOP_NUM_SGE_LOC_ORIG:
238177961cf6Sbouyer 		ctx->num_sge = segs;
238277961cf6Sbouyer 		break;
238377961cf6Sbouyer 	case MFII_IOP_NUM_SGE_LOC_35:
238477961cf6Sbouyer 		/* 12 bit field, but we're only using the lower 8 */
238577961cf6Sbouyer 		ctx->span_arm = segs;
238677961cf6Sbouyer 		break;
238777961cf6Sbouyer 	}
238877961cf6Sbouyer 
238977961cf6Sbouyer 	ccb->ccb_req.flags = sc->sc_iop->ldio_req_type;
239077961cf6Sbouyer 	ccb->ccb_req.smid = le16toh(ccb->ccb_smid);
239177961cf6Sbouyer 
239277961cf6Sbouyer 	return (0);
239377961cf6Sbouyer }
239477961cf6Sbouyer 
2395bfa22340Smaxv static int
mfii_scsi_cmd_cdb(struct mfii_softc * sc,struct mfii_ccb * ccb,struct scsipi_xfer * xs)239677961cf6Sbouyer mfii_scsi_cmd_cdb(struct mfii_softc *sc, struct mfii_ccb *ccb,
239777961cf6Sbouyer     struct scsipi_xfer *xs)
239877961cf6Sbouyer {
239977961cf6Sbouyer 	struct scsipi_periph *periph = xs->xs_periph;
240077961cf6Sbouyer 	struct mpii_msg_scsi_io *io = ccb->ccb_request;
240177961cf6Sbouyer 	struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
24023b643292Smsaitoh 	int target;
240377961cf6Sbouyer 
24043b643292Smsaitoh 	target = sc->sc_ld[periph->periph_target].ld_target_id;
24053b643292Smsaitoh 	io->dev_handle = htole16(target);
240677961cf6Sbouyer 	io->function = MFII_FUNCTION_LDIO_REQUEST;
240777961cf6Sbouyer 	io->sense_buffer_low_address = htole32(ccb->ccb_sense_dva);
240877961cf6Sbouyer 	io->sgl_flags = htole16(0x02); /* XXX */
240977961cf6Sbouyer 	io->sense_buffer_length = sizeof(xs->sense);
241077961cf6Sbouyer 	io->sgl_offset0 = (sizeof(*io) + sizeof(*ctx)) / 4;
241177961cf6Sbouyer 	io->data_length = htole32(xs->datalen);
241277961cf6Sbouyer 	io->io_flags = htole16(xs->cmdlen);
241377961cf6Sbouyer 	io->lun[0] = htobe16(periph->periph_lun);
241477961cf6Sbouyer 	switch (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
241577961cf6Sbouyer 	case XS_CTL_DATA_IN:
241677961cf6Sbouyer 		ccb->ccb_direction = MFII_DATA_IN;
241777961cf6Sbouyer 		io->direction = MPII_SCSIIO_DIR_READ;
241877961cf6Sbouyer 		break;
241977961cf6Sbouyer 	case XS_CTL_DATA_OUT:
242077961cf6Sbouyer 		ccb->ccb_direction = MFII_DATA_OUT;
242177961cf6Sbouyer 		io->direction = MPII_SCSIIO_DIR_WRITE;
242277961cf6Sbouyer 		break;
242377961cf6Sbouyer 	default:
242477961cf6Sbouyer 		ccb->ccb_direction = MFII_DATA_NONE;
242577961cf6Sbouyer 		io->direction = MPII_SCSIIO_DIR_NONE;
242677961cf6Sbouyer 		break;
242777961cf6Sbouyer 	}
242877961cf6Sbouyer 	memcpy(io->cdb, xs->cmd, xs->cmdlen);
242977961cf6Sbouyer 
24303b643292Smsaitoh 	ctx->virtual_disk_target_id = htole16(target);
243177961cf6Sbouyer 
243277961cf6Sbouyer 	if (mfii_load_ccb(sc, ccb, ctx + 1,
243377961cf6Sbouyer 	    ISSET(xs->xs_control, XS_CTL_NOSLEEP)) != 0)
243477961cf6Sbouyer 		return (1);
243577961cf6Sbouyer 
243677961cf6Sbouyer 	ctx->num_sge = (ccb->ccb_len == 0) ? 0 : ccb->ccb_dmamap64->dm_nsegs;
243777961cf6Sbouyer 	KASSERT(ccb->ccb_len == 0 || ccb->ccb_dma64);
243877961cf6Sbouyer 
243977961cf6Sbouyer 	ccb->ccb_req.flags = MFII_REQ_TYPE_SCSI;
244077961cf6Sbouyer 	ccb->ccb_req.smid = le16toh(ccb->ccb_smid);
244177961cf6Sbouyer 
244277961cf6Sbouyer 	return (0);
244377961cf6Sbouyer }
244477961cf6Sbouyer 
244577961cf6Sbouyer #if 0
244677961cf6Sbouyer void
244777961cf6Sbouyer mfii_pd_scsi_cmd(struct scsipi_xfer *xs)
244877961cf6Sbouyer {
244977961cf6Sbouyer 	struct scsi_link *link = xs->sc_link;
245077961cf6Sbouyer 	struct mfii_softc *sc = link->adapter_softc;
245177961cf6Sbouyer 	struct mfii_ccb *ccb = xs->io;
245277961cf6Sbouyer 
245377961cf6Sbouyer 	mfii_scrub_ccb(ccb);
245477961cf6Sbouyer 	ccb->ccb_cookie = xs;
245577961cf6Sbouyer 	ccb->ccb_done = mfii_scsi_cmd_done;
245677961cf6Sbouyer 	ccb->ccb_data = xs->data;
245777961cf6Sbouyer 	ccb->ccb_len = xs->datalen;
245877961cf6Sbouyer 
245977961cf6Sbouyer 	// XXX timeout_set(&xs->stimeout, mfii_scsi_cmd_tmo, xs);
246077961cf6Sbouyer 
246177961cf6Sbouyer 	xs->error = mfii_pd_scsi_cmd_cdb(sc, xs);
246277961cf6Sbouyer 	if (xs->error != XS_NOERROR)
246377961cf6Sbouyer 		goto done;
246477961cf6Sbouyer 
246577961cf6Sbouyer 	xs->resid = 0;
246677961cf6Sbouyer 
246777961cf6Sbouyer 	if (ISSET(xs->xs_control, XS_CTL_POLL)) {
246877961cf6Sbouyer 		if (mfii_poll(sc, ccb) != 0)
246977961cf6Sbouyer 			goto stuffup;
247077961cf6Sbouyer 		return;
247177961cf6Sbouyer 	}
247277961cf6Sbouyer 
247377961cf6Sbouyer 	// XXX timeout_add_msec(&xs->stimeout, xs->timeout);
247477961cf6Sbouyer 	mfii_start(sc, ccb);
247577961cf6Sbouyer 
247677961cf6Sbouyer 	return;
247777961cf6Sbouyer 
247877961cf6Sbouyer stuffup:
247977961cf6Sbouyer 	xs->error = XS_DRIVER_STUFFUP;
248077961cf6Sbouyer done:
248177961cf6Sbouyer 	scsi_done(xs);
248277961cf6Sbouyer }
248377961cf6Sbouyer 
248477961cf6Sbouyer int
248577961cf6Sbouyer mfii_pd_scsi_probe(struct scsi_link *link)
248677961cf6Sbouyer {
248777961cf6Sbouyer 	struct mfii_softc *sc = link->adapter_softc;
248877961cf6Sbouyer 	struct mfi_pd_details mpd;
248977961cf6Sbouyer 	union mfi_mbox mbox;
249077961cf6Sbouyer 	int rv;
249177961cf6Sbouyer 
249277961cf6Sbouyer 	if (link->lun > 0)
249377961cf6Sbouyer 		return (0);
249477961cf6Sbouyer 
249577961cf6Sbouyer 	memset(&mbox, 0, sizeof(mbox));
249677961cf6Sbouyer 	mbox.s[0] = htole16(link->target);
249777961cf6Sbouyer 
249877961cf6Sbouyer 	rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, &mpd, sizeof(mpd),
249977961cf6Sbouyer 	    MFII_DATA_IN, true);
250077961cf6Sbouyer 	if (rv != 0)
250177961cf6Sbouyer 		return (EIO);
250277961cf6Sbouyer 
250377961cf6Sbouyer 	if (mpd.mpd_fw_state != htole16(MFI_PD_SYSTEM))
250477961cf6Sbouyer 		return (ENXIO);
250577961cf6Sbouyer 
250677961cf6Sbouyer 	return (0);
250777961cf6Sbouyer }
250877961cf6Sbouyer 
250977961cf6Sbouyer int
251077961cf6Sbouyer mfii_pd_scsi_cmd_cdb(struct mfii_softc *sc, struct mfii_ccb *ccb,
251177961cf6Sbouyer     struct scsipi_xfer *xs)
251277961cf6Sbouyer {
251377961cf6Sbouyer 	struct scsi_link *link = xs->sc_link;
251477961cf6Sbouyer 	struct mpii_msg_scsi_io *io = ccb->ccb_request;
251577961cf6Sbouyer 	struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
251677961cf6Sbouyer 	uint16_t dev_handle;
251777961cf6Sbouyer 
251877961cf6Sbouyer 	dev_handle = mfii_dev_handle(sc, link->target);
251977961cf6Sbouyer 	if (dev_handle == htole16(0xffff))
252077961cf6Sbouyer 		return (XS_SELTIMEOUT);
252177961cf6Sbouyer 
252277961cf6Sbouyer 	io->dev_handle = dev_handle;
252377961cf6Sbouyer 	io->function = 0;
252477961cf6Sbouyer 	io->sense_buffer_low_address = htole32(ccb->ccb_sense_dva);
252577961cf6Sbouyer 	io->sgl_flags = htole16(0x02); /* XXX */
252677961cf6Sbouyer 	io->sense_buffer_length = sizeof(xs->sense);
252777961cf6Sbouyer 	io->sgl_offset0 = (sizeof(*io) + sizeof(*ctx)) / 4;
252877961cf6Sbouyer 	io->data_length = htole32(xs->datalen);
252977961cf6Sbouyer 	io->io_flags = htole16(xs->cmdlen);
253077961cf6Sbouyer 	io->lun[0] = htobe16(link->lun);
253177961cf6Sbouyer 	switch (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
253277961cf6Sbouyer 	case XS_CTL_DATA_IN:
253377961cf6Sbouyer 		ccb->ccb_direction = MFII_DATA_IN;
253477961cf6Sbouyer 		io->direction = MPII_SCSIIO_DIR_READ;
253577961cf6Sbouyer 		break;
253677961cf6Sbouyer 	case XS_CTL_DATA_OUT:
253777961cf6Sbouyer 		ccb->ccb_direction = MFII_DATA_OUT;
253877961cf6Sbouyer 		io->direction = MPII_SCSIIO_DIR_WRITE;
253977961cf6Sbouyer 		break;
254077961cf6Sbouyer 	default:
254177961cf6Sbouyer 		ccb->ccb_direction = MFII_DATA_NONE;
254277961cf6Sbouyer 		io->direction = MPII_SCSIIO_DIR_NONE;
254377961cf6Sbouyer 		break;
254477961cf6Sbouyer 	}
254577961cf6Sbouyer 	memcpy(io->cdb, xs->cmd, xs->cmdlen);
254677961cf6Sbouyer 
254777961cf6Sbouyer 	ctx->virtual_disk_target_id = htole16(link->target);
254877961cf6Sbouyer 	ctx->raid_flags = MFII_RAID_CTX_IO_TYPE_SYSPD;
254977961cf6Sbouyer 	ctx->timeout_value = sc->sc_pd->pd_timeout;
255077961cf6Sbouyer 
255177961cf6Sbouyer 	if (mfii_load_ccb(sc, ccb, ctx + 1,
255277961cf6Sbouyer 	    ISSET(xs->xs_control, XS_CTL_NOSLEEP)) != 0)
255377961cf6Sbouyer 		return (XS_DRIVER_STUFFUP);
255477961cf6Sbouyer 
255577961cf6Sbouyer 	ctx->num_sge = (ccb->ccb_len == 0) ? 0 : ccb->ccb_dmamap64->dm_nsegs;
255677961cf6Sbouyer 	KASSERT(ccb->ccb_dma64);
255777961cf6Sbouyer 
255877961cf6Sbouyer 	ccb->ccb_req.flags = MFII_REQ_TYPE_HI_PRI;
255977961cf6Sbouyer 	ccb->ccb_req.smid = le16toh(ccb->ccb_smid);
256077961cf6Sbouyer 	ccb->ccb_req.dev_handle = dev_handle;
256177961cf6Sbouyer 
256277961cf6Sbouyer 	return (XS_NOERROR);
256377961cf6Sbouyer }
256477961cf6Sbouyer #endif
256577961cf6Sbouyer 
2566bfa22340Smaxv static int
mfii_load_ccb(struct mfii_softc * sc,struct mfii_ccb * ccb,void * sglp,int nosleep)256777961cf6Sbouyer mfii_load_ccb(struct mfii_softc *sc, struct mfii_ccb *ccb, void *sglp,
256877961cf6Sbouyer     int nosleep)
256977961cf6Sbouyer {
257077961cf6Sbouyer 	struct mpii_msg_request *req = ccb->ccb_request;
257177961cf6Sbouyer 	struct mfii_sge *sge = NULL, *nsge = sglp;
257277961cf6Sbouyer 	struct mfii_sge *ce = NULL;
257377961cf6Sbouyer 	bus_dmamap_t dmap = ccb->ccb_dmamap64;
257477961cf6Sbouyer 	u_int space;
257577961cf6Sbouyer 	int i;
257677961cf6Sbouyer 
257777961cf6Sbouyer 	int error;
257877961cf6Sbouyer 
257977961cf6Sbouyer 	if (ccb->ccb_len == 0)
258077961cf6Sbouyer 		return (0);
258177961cf6Sbouyer 
258277961cf6Sbouyer 	ccb->ccb_dma64 = true;
258377961cf6Sbouyer 	error = bus_dmamap_load(sc->sc_dmat64, dmap,
258477961cf6Sbouyer 	    ccb->ccb_data, ccb->ccb_len, NULL,
258577961cf6Sbouyer 	    nosleep ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
258677961cf6Sbouyer 	if (error) {
258777961cf6Sbouyer 		printf("%s: error %d loading dmamap\n", DEVNAME(sc), error);
258877961cf6Sbouyer 		return (1);
258977961cf6Sbouyer 	}
259077961cf6Sbouyer 
259177961cf6Sbouyer 	space = (MFII_REQUEST_SIZE - ((u_int8_t *)nsge - (u_int8_t *)req)) /
259277961cf6Sbouyer 	    sizeof(*nsge);
259377961cf6Sbouyer 	if (dmap->dm_nsegs > space) {
259477961cf6Sbouyer 		space--;
259577961cf6Sbouyer 
259677961cf6Sbouyer 		ccb->ccb_sgl_len = (dmap->dm_nsegs - space) * sizeof(*nsge);
259777961cf6Sbouyer 		memset(ccb->ccb_sgl, 0, ccb->ccb_sgl_len);
259877961cf6Sbouyer 
259977961cf6Sbouyer 		ce = nsge + space;
260077961cf6Sbouyer 		ce->sg_addr = htole64(ccb->ccb_sgl_dva);
260177961cf6Sbouyer 		ce->sg_len = htole32(ccb->ccb_sgl_len);
260277961cf6Sbouyer 		ce->sg_flags = sc->sc_iop->sge_flag_chain;
260377961cf6Sbouyer 
260477961cf6Sbouyer 		req->chain_offset = ((u_int8_t *)ce - (u_int8_t *)req) / 16;
260577961cf6Sbouyer 	}
260677961cf6Sbouyer 
260777961cf6Sbouyer 	for (i = 0; i < dmap->dm_nsegs; i++) {
260877961cf6Sbouyer 		if (nsge == ce)
260977961cf6Sbouyer 			nsge = ccb->ccb_sgl;
261077961cf6Sbouyer 
261177961cf6Sbouyer 		sge = nsge;
261277961cf6Sbouyer 
261377961cf6Sbouyer 		sge->sg_addr = htole64(dmap->dm_segs[i].ds_addr);
261477961cf6Sbouyer 		sge->sg_len = htole32(dmap->dm_segs[i].ds_len);
261577961cf6Sbouyer 		sge->sg_flags = MFII_SGE_ADDR_SYSTEM;
261677961cf6Sbouyer 
261777961cf6Sbouyer 		nsge = sge + 1;
261877961cf6Sbouyer 	}
261977961cf6Sbouyer 	sge->sg_flags |= sc->sc_iop->sge_flag_eol;
262077961cf6Sbouyer 
262177961cf6Sbouyer 	bus_dmamap_sync(sc->sc_dmat64, dmap, 0, dmap->dm_mapsize,
262277961cf6Sbouyer 	    ccb->ccb_direction == MFII_DATA_OUT ?
262377961cf6Sbouyer 	    BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
262477961cf6Sbouyer 
262577961cf6Sbouyer 	if (ccb->ccb_sgl_len > 0) {
262677961cf6Sbouyer 		bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_sgl),
262777961cf6Sbouyer 		    ccb->ccb_sgl_offset, ccb->ccb_sgl_len,
262877961cf6Sbouyer 		    BUS_DMASYNC_PREWRITE);
262977961cf6Sbouyer 	}
263077961cf6Sbouyer 
263177961cf6Sbouyer 	return (0);
263277961cf6Sbouyer }
263377961cf6Sbouyer 
2634bfa22340Smaxv static void
mfii_scsi_cmd_tmo(void * p)263577961cf6Sbouyer mfii_scsi_cmd_tmo(void *p)
263677961cf6Sbouyer {
263777961cf6Sbouyer 	struct mfii_ccb *ccb = p;
263877961cf6Sbouyer 	struct mfii_softc *sc = ccb->ccb_sc;
263977961cf6Sbouyer 	bool start_abort;
264077961cf6Sbouyer 
264177961cf6Sbouyer 	printf("%s: cmd timeout ccb %p\n", DEVNAME(sc), p);
264277961cf6Sbouyer 
264377961cf6Sbouyer 	mutex_enter(&sc->sc_abort_mtx);
264477961cf6Sbouyer 	start_abort = (SIMPLEQ_FIRST(&sc->sc_abort_list) == 0);
264577961cf6Sbouyer 	SIMPLEQ_INSERT_TAIL(&sc->sc_abort_list, ccb, ccb_link);
264677961cf6Sbouyer 	if (start_abort)
264777961cf6Sbouyer 		workqueue_enqueue(sc->sc_abort_wq, &sc->sc_abort_work, NULL);
264877961cf6Sbouyer 	mutex_exit(&sc->sc_abort_mtx);
264977961cf6Sbouyer }
265077961cf6Sbouyer 
2651bfa22340Smaxv static void
mfii_abort_task(struct work * wk,void * scp)265277961cf6Sbouyer mfii_abort_task(struct work *wk, void *scp)
265377961cf6Sbouyer {
265477961cf6Sbouyer 	struct mfii_softc *sc = scp;
265577961cf6Sbouyer 	struct mfii_ccb *list;
265677961cf6Sbouyer 
265777961cf6Sbouyer 	mutex_enter(&sc->sc_abort_mtx);
265877961cf6Sbouyer 	list = SIMPLEQ_FIRST(&sc->sc_abort_list);
265977961cf6Sbouyer 	SIMPLEQ_INIT(&sc->sc_abort_list);
266077961cf6Sbouyer 	mutex_exit(&sc->sc_abort_mtx);
266177961cf6Sbouyer 
266277961cf6Sbouyer 	while (list != NULL) {
266377961cf6Sbouyer 		struct mfii_ccb *ccb = list;
266477961cf6Sbouyer 		struct scsipi_xfer *xs = ccb->ccb_cookie;
266577961cf6Sbouyer 		struct scsipi_periph *periph = xs->xs_periph;
266677961cf6Sbouyer 		struct mfii_ccb *accb;
266777961cf6Sbouyer 
266877961cf6Sbouyer 		list = SIMPLEQ_NEXT(ccb, ccb_link);
266977961cf6Sbouyer 
267077961cf6Sbouyer 		if (!sc->sc_ld[periph->periph_target].ld_present) {
267177961cf6Sbouyer 			/* device is gone */
2672d38daeb6Sbouyer 			xs->error = XS_SELTIMEOUT;
267377961cf6Sbouyer 			scsipi_done(xs);
267477961cf6Sbouyer 			mfii_put_ccb(sc, ccb);
267577961cf6Sbouyer 			continue;
267677961cf6Sbouyer 		}
267777961cf6Sbouyer 
267877961cf6Sbouyer 		accb = mfii_get_ccb(sc);
267977961cf6Sbouyer 		mfii_scrub_ccb(accb);
268077961cf6Sbouyer 		mfii_abort(sc, accb, periph->periph_target, ccb->ccb_smid,
268177961cf6Sbouyer 		    MPII_SCSI_TASK_ABORT_TASK,
268277961cf6Sbouyer 		    htole32(MFII_TASK_MGMT_FLAGS_PD));
268377961cf6Sbouyer 
268477961cf6Sbouyer 		accb->ccb_cookie = ccb;
268577961cf6Sbouyer 		accb->ccb_done = mfii_scsi_cmd_abort_done;
268677961cf6Sbouyer 
268777961cf6Sbouyer 		mfii_start(sc, accb);
268877961cf6Sbouyer 	}
268977961cf6Sbouyer }
269077961cf6Sbouyer 
2691bfa22340Smaxv static void
mfii_abort(struct mfii_softc * sc,struct mfii_ccb * accb,uint16_t dev_handle,uint16_t smid,uint8_t type,uint32_t flags)269277961cf6Sbouyer mfii_abort(struct mfii_softc *sc, struct mfii_ccb *accb, uint16_t dev_handle,
269377961cf6Sbouyer     uint16_t smid, uint8_t type, uint32_t flags)
269477961cf6Sbouyer {
269577961cf6Sbouyer 	struct mfii_task_mgmt *msg;
269677961cf6Sbouyer 	struct mpii_msg_scsi_task_request *req;
269777961cf6Sbouyer 
269877961cf6Sbouyer 	msg = accb->ccb_request;
269977961cf6Sbouyer 	req = &msg->mpii_request;
270077961cf6Sbouyer 	req->dev_handle = dev_handle;
270177961cf6Sbouyer 	req->function = MPII_FUNCTION_SCSI_TASK_MGMT;
270277961cf6Sbouyer 	req->task_type = type;
270377961cf6Sbouyer 	req->task_mid = htole16( smid);
270477961cf6Sbouyer 	msg->flags = flags;
270577961cf6Sbouyer 
270677961cf6Sbouyer 	accb->ccb_req.flags = MFII_REQ_TYPE_HI_PRI;
270777961cf6Sbouyer 	accb->ccb_req.smid = le16toh(accb->ccb_smid);
270877961cf6Sbouyer }
270977961cf6Sbouyer 
2710bfa22340Smaxv static void
mfii_scsi_cmd_abort_done(struct mfii_softc * sc,struct mfii_ccb * accb)271177961cf6Sbouyer mfii_scsi_cmd_abort_done(struct mfii_softc *sc, struct mfii_ccb *accb)
271277961cf6Sbouyer {
271377961cf6Sbouyer 	struct mfii_ccb *ccb = accb->ccb_cookie;
271477961cf6Sbouyer 	struct scsipi_xfer *xs = ccb->ccb_cookie;
271577961cf6Sbouyer 
271677961cf6Sbouyer 	/* XXX check accb completion? */
271777961cf6Sbouyer 
271877961cf6Sbouyer 	mfii_put_ccb(sc, accb);
2719d38daeb6Sbouyer 	printf("%s: cmd aborted ccb %p\n", DEVNAME(sc), ccb);
272077961cf6Sbouyer 
272177961cf6Sbouyer 	xs->error = XS_TIMEOUT;
272277961cf6Sbouyer 	scsipi_done(xs);
272377961cf6Sbouyer 	mfii_put_ccb(sc, ccb);
272477961cf6Sbouyer }
272577961cf6Sbouyer 
2726bfa22340Smaxv static struct mfii_ccb *
mfii_get_ccb(struct mfii_softc * sc)272777961cf6Sbouyer mfii_get_ccb(struct mfii_softc *sc)
272877961cf6Sbouyer {
272977961cf6Sbouyer 	struct mfii_ccb *ccb;
273077961cf6Sbouyer 
273177961cf6Sbouyer 	mutex_enter(&sc->sc_ccb_mtx);
273277961cf6Sbouyer 	if (!sc->sc_running) {
273377961cf6Sbouyer 		ccb = NULL;
273477961cf6Sbouyer 	} else {
273577961cf6Sbouyer 		ccb = SIMPLEQ_FIRST(&sc->sc_ccb_freeq);
273677961cf6Sbouyer 		if (ccb != NULL)
273777961cf6Sbouyer 			SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_freeq, ccb_link);
273877961cf6Sbouyer 	}
273977961cf6Sbouyer 	mutex_exit(&sc->sc_ccb_mtx);
274077961cf6Sbouyer 	return (ccb);
274177961cf6Sbouyer }
274277961cf6Sbouyer 
2743bfa22340Smaxv static void
mfii_scrub_ccb(struct mfii_ccb * ccb)274477961cf6Sbouyer mfii_scrub_ccb(struct mfii_ccb *ccb)
274577961cf6Sbouyer {
274677961cf6Sbouyer 	ccb->ccb_cookie = NULL;
274777961cf6Sbouyer 	ccb->ccb_done = NULL;
274877961cf6Sbouyer 	ccb->ccb_flags = 0;
274977961cf6Sbouyer 	ccb->ccb_data = NULL;
275077961cf6Sbouyer 	ccb->ccb_direction = MFII_DATA_NONE;
275177961cf6Sbouyer 	ccb->ccb_dma64 = false;
275277961cf6Sbouyer 	ccb->ccb_len = 0;
275377961cf6Sbouyer 	ccb->ccb_sgl_len = 0;
275477961cf6Sbouyer 	memset(&ccb->ccb_req, 0, sizeof(ccb->ccb_req));
275577961cf6Sbouyer 	memset(ccb->ccb_request, 0, MFII_REQUEST_SIZE);
275677961cf6Sbouyer 	memset(ccb->ccb_mfi, 0, MFI_FRAME_SIZE);
275777961cf6Sbouyer }
275877961cf6Sbouyer 
2759bfa22340Smaxv static void
mfii_put_ccb(struct mfii_softc * sc,struct mfii_ccb * ccb)276077961cf6Sbouyer mfii_put_ccb(struct mfii_softc *sc, struct mfii_ccb *ccb)
276177961cf6Sbouyer {
276277961cf6Sbouyer 	mutex_enter(&sc->sc_ccb_mtx);
276377961cf6Sbouyer 	SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_freeq, ccb, ccb_link);
276477961cf6Sbouyer 	mutex_exit(&sc->sc_ccb_mtx);
276577961cf6Sbouyer }
276677961cf6Sbouyer 
2767bfa22340Smaxv static int
mfii_init_ccb(struct mfii_softc * sc)276877961cf6Sbouyer mfii_init_ccb(struct mfii_softc *sc)
276977961cf6Sbouyer {
277077961cf6Sbouyer 	struct mfii_ccb *ccb;
277177961cf6Sbouyer 	u_int8_t *request = MFII_DMA_KVA(sc->sc_requests);
277277961cf6Sbouyer 	u_int8_t *mfi = MFII_DMA_KVA(sc->sc_mfi);
277377961cf6Sbouyer 	u_int8_t *sense = MFII_DMA_KVA(sc->sc_sense);
277477961cf6Sbouyer 	u_int8_t *sgl = MFII_DMA_KVA(sc->sc_sgl);
277577961cf6Sbouyer 	u_int i;
277677961cf6Sbouyer 	int error;
277777961cf6Sbouyer 
277877961cf6Sbouyer 	sc->sc_ccb = malloc(sc->sc_max_cmds * sizeof(struct mfii_ccb),
277977961cf6Sbouyer 	    M_DEVBUF, M_WAITOK|M_ZERO);
278077961cf6Sbouyer 
278177961cf6Sbouyer 	for (i = 0; i < sc->sc_max_cmds; i++) {
278277961cf6Sbouyer 		ccb = &sc->sc_ccb[i];
278377961cf6Sbouyer 		ccb->ccb_sc = sc;
278477961cf6Sbouyer 
278577961cf6Sbouyer 		/* create a dma map for transfer */
278677961cf6Sbouyer 		error = bus_dmamap_create(sc->sc_dmat,
278777961cf6Sbouyer 		    MAXPHYS, sc->sc_max_sgl, MAXPHYS, 0,
278877961cf6Sbouyer 		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap32);
278977961cf6Sbouyer 		if (error) {
279077961cf6Sbouyer 			printf("%s: cannot create ccb dmamap32 (%d)\n",
279177961cf6Sbouyer 			    DEVNAME(sc), error);
279277961cf6Sbouyer 			goto destroy;
279377961cf6Sbouyer 		}
279477961cf6Sbouyer 		error = bus_dmamap_create(sc->sc_dmat64,
279577961cf6Sbouyer 		    MAXPHYS, sc->sc_max_sgl, MAXPHYS, 0,
279677961cf6Sbouyer 		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap64);
279777961cf6Sbouyer 		if (error) {
279877961cf6Sbouyer 			printf("%s: cannot create ccb dmamap64 (%d)\n",
279977961cf6Sbouyer 			    DEVNAME(sc), error);
280077961cf6Sbouyer 			goto destroy32;
280177961cf6Sbouyer 		}
280277961cf6Sbouyer 
280377961cf6Sbouyer 		/* select i + 1'th request. 0 is reserved for events */
280477961cf6Sbouyer 		ccb->ccb_smid = i + 1;
280577961cf6Sbouyer 		ccb->ccb_request_offset = MFII_REQUEST_SIZE * (i + 1);
280677961cf6Sbouyer 		ccb->ccb_request = request + ccb->ccb_request_offset;
280777961cf6Sbouyer 		ccb->ccb_request_dva = MFII_DMA_DVA(sc->sc_requests) +
280877961cf6Sbouyer 		    ccb->ccb_request_offset;
280977961cf6Sbouyer 
281077961cf6Sbouyer 		/* select i'th MFI command frame */
281177961cf6Sbouyer 		ccb->ccb_mfi_offset = MFI_FRAME_SIZE * i;
281277961cf6Sbouyer 		ccb->ccb_mfi = mfi + ccb->ccb_mfi_offset;
281377961cf6Sbouyer 		ccb->ccb_mfi_dva = MFII_DMA_DVA(sc->sc_mfi) +
281477961cf6Sbouyer 		    ccb->ccb_mfi_offset;
281577961cf6Sbouyer 
281677961cf6Sbouyer 		/* select i'th sense */
281777961cf6Sbouyer 		ccb->ccb_sense_offset = MFI_SENSE_SIZE * i;
281877961cf6Sbouyer 		ccb->ccb_sense = (struct mfi_sense *)(sense +
281977961cf6Sbouyer 		    ccb->ccb_sense_offset);
282077961cf6Sbouyer 		ccb->ccb_sense_dva = MFII_DMA_DVA(sc->sc_sense) +
282177961cf6Sbouyer 		    ccb->ccb_sense_offset;
282277961cf6Sbouyer 
282377961cf6Sbouyer 		/* select i'th sgl */
282477961cf6Sbouyer 		ccb->ccb_sgl_offset = sizeof(struct mfii_sge) *
282577961cf6Sbouyer 		    sc->sc_max_sgl * i;
282677961cf6Sbouyer 		ccb->ccb_sgl = (struct mfii_sge *)(sgl + ccb->ccb_sgl_offset);
282777961cf6Sbouyer 		ccb->ccb_sgl_dva = MFII_DMA_DVA(sc->sc_sgl) +
282877961cf6Sbouyer 		    ccb->ccb_sgl_offset;
282977961cf6Sbouyer 
283077961cf6Sbouyer 		mutex_init(&ccb->ccb_mtx, MUTEX_DEFAULT, IPL_BIO);
283177961cf6Sbouyer 		cv_init(&ccb->ccb_cv, "mfiiexec");
283277961cf6Sbouyer 
283377961cf6Sbouyer 		/* add ccb to queue */
283477961cf6Sbouyer 		mfii_put_ccb(sc, ccb);
283577961cf6Sbouyer 	}
283677961cf6Sbouyer 
283777961cf6Sbouyer 	return (0);
283877961cf6Sbouyer 
283977961cf6Sbouyer destroy32:
284077961cf6Sbouyer 	bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap32);
284177961cf6Sbouyer destroy:
284277961cf6Sbouyer 	/* free dma maps and ccb memory */
284377961cf6Sbouyer 	while ((ccb = mfii_get_ccb(sc)) != NULL) {
284477961cf6Sbouyer 		bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap32);
284577961cf6Sbouyer 		bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap64);
284677961cf6Sbouyer 	}
284777961cf6Sbouyer 
284877961cf6Sbouyer 	free(sc->sc_ccb, M_DEVBUF);
284977961cf6Sbouyer 
285077961cf6Sbouyer 	return (1);
285177961cf6Sbouyer }
285277961cf6Sbouyer 
285377961cf6Sbouyer #if NBIO > 0
2854bfa22340Smaxv static int
mfii_ioctl(device_t dev,u_long cmd,void * addr)285577961cf6Sbouyer mfii_ioctl(device_t dev, u_long cmd, void *addr)
285677961cf6Sbouyer {
285777961cf6Sbouyer 	struct mfii_softc	*sc = device_private(dev);
285877961cf6Sbouyer 	int error = 0;
285977961cf6Sbouyer 
286077961cf6Sbouyer 	DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl ", DEVNAME(sc));
286177961cf6Sbouyer 
286277961cf6Sbouyer 	mutex_enter(&sc->sc_lock);
286377961cf6Sbouyer 
286477961cf6Sbouyer 	switch (cmd) {
286577961cf6Sbouyer 	case BIOCINQ:
286677961cf6Sbouyer 		DNPRINTF(MFII_D_IOCTL, "inq\n");
286777961cf6Sbouyer 		error = mfii_ioctl_inq(sc, (struct bioc_inq *)addr);
286877961cf6Sbouyer 		break;
286977961cf6Sbouyer 
287077961cf6Sbouyer 	case BIOCVOL:
287177961cf6Sbouyer 		DNPRINTF(MFII_D_IOCTL, "vol\n");
287277961cf6Sbouyer 		error = mfii_ioctl_vol(sc, (struct bioc_vol *)addr);
287377961cf6Sbouyer 		break;
287477961cf6Sbouyer 
287577961cf6Sbouyer 	case BIOCDISK:
287677961cf6Sbouyer 		DNPRINTF(MFII_D_IOCTL, "disk\n");
287777961cf6Sbouyer 		error = mfii_ioctl_disk(sc, (struct bioc_disk *)addr);
287877961cf6Sbouyer 		break;
287977961cf6Sbouyer 
288077961cf6Sbouyer 	case BIOCALARM:
288177961cf6Sbouyer 		DNPRINTF(MFII_D_IOCTL, "alarm\n");
288277961cf6Sbouyer 		error = mfii_ioctl_alarm(sc, (struct bioc_alarm *)addr);
288377961cf6Sbouyer 		break;
288477961cf6Sbouyer 
288577961cf6Sbouyer 	case BIOCBLINK:
288677961cf6Sbouyer 		DNPRINTF(MFII_D_IOCTL, "blink\n");
288777961cf6Sbouyer 		error = mfii_ioctl_blink(sc, (struct bioc_blink *)addr);
288877961cf6Sbouyer 		break;
288977961cf6Sbouyer 
289077961cf6Sbouyer 	case BIOCSETSTATE:
289177961cf6Sbouyer 		DNPRINTF(MFII_D_IOCTL, "setstate\n");
289277961cf6Sbouyer 		error = mfii_ioctl_setstate(sc, (struct bioc_setstate *)addr);
289377961cf6Sbouyer 		break;
289477961cf6Sbouyer 
289577961cf6Sbouyer #if 0
289677961cf6Sbouyer 	case BIOCPATROL:
289777961cf6Sbouyer 		DNPRINTF(MFII_D_IOCTL, "patrol\n");
289877961cf6Sbouyer 		error = mfii_ioctl_patrol(sc, (struct bioc_patrol *)addr);
289977961cf6Sbouyer 		break;
290077961cf6Sbouyer #endif
290177961cf6Sbouyer 
290277961cf6Sbouyer 	default:
290377961cf6Sbouyer 		DNPRINTF(MFII_D_IOCTL, " invalid ioctl\n");
290477961cf6Sbouyer 		error = ENOTTY;
290577961cf6Sbouyer 	}
290677961cf6Sbouyer 
290777961cf6Sbouyer 	mutex_exit(&sc->sc_lock);
290877961cf6Sbouyer 
290977961cf6Sbouyer 	return (error);
291077961cf6Sbouyer }
291177961cf6Sbouyer 
2912bfa22340Smaxv static int
mfii_bio_getitall(struct mfii_softc * sc)291377961cf6Sbouyer mfii_bio_getitall(struct mfii_softc *sc)
291477961cf6Sbouyer {
291577961cf6Sbouyer 	int			i, d, rv = EINVAL;
291677961cf6Sbouyer 	size_t			size;
291777961cf6Sbouyer 	union mfi_mbox		mbox;
291877961cf6Sbouyer 	struct mfi_conf		*cfg = NULL;
291977961cf6Sbouyer 	struct mfi_ld_details	*ld_det = NULL;
292077961cf6Sbouyer 
292177961cf6Sbouyer 	/* get info */
292277961cf6Sbouyer 	if (mfii_get_info(sc)) {
292377961cf6Sbouyer 		DNPRINTF(MFII_D_IOCTL, "%s: mfii_get_info failed\n",
292477961cf6Sbouyer 		    DEVNAME(sc));
292577961cf6Sbouyer 		goto done;
292677961cf6Sbouyer 	}
292777961cf6Sbouyer 
292877961cf6Sbouyer 	/* send single element command to retrieve size for full structure */
292977961cf6Sbouyer 	cfg = malloc(sizeof *cfg, M_DEVBUF, M_NOWAIT | M_ZERO);
293077961cf6Sbouyer 	if (cfg == NULL)
293177961cf6Sbouyer 		goto done;
293277961cf6Sbouyer 	if (mfii_mgmt(sc, MR_DCMD_CONF_GET, NULL, cfg, sizeof(*cfg),
293377961cf6Sbouyer 	    MFII_DATA_IN, false)) {
293477961cf6Sbouyer 		free(cfg, M_DEVBUF);
293577961cf6Sbouyer 		goto done;
293677961cf6Sbouyer 	}
293777961cf6Sbouyer 
293877961cf6Sbouyer 	size = cfg->mfc_size;
293977961cf6Sbouyer 	free(cfg, M_DEVBUF);
294077961cf6Sbouyer 
294177961cf6Sbouyer 	/* memory for read config */
294277961cf6Sbouyer 	cfg = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
294377961cf6Sbouyer 	if (cfg == NULL)
294477961cf6Sbouyer 		goto done;
294577961cf6Sbouyer 	if (mfii_mgmt(sc, MR_DCMD_CONF_GET, NULL, cfg, size,
294677961cf6Sbouyer 	    MFII_DATA_IN, false)) {
294777961cf6Sbouyer 		free(cfg, M_DEVBUF);
294877961cf6Sbouyer 		goto done;
294977961cf6Sbouyer 	}
295077961cf6Sbouyer 
295177961cf6Sbouyer 	/* replace current pointer with new one */
295277961cf6Sbouyer 	if (sc->sc_cfg)
295377961cf6Sbouyer 		free(sc->sc_cfg, M_DEVBUF);
295477961cf6Sbouyer 	sc->sc_cfg = cfg;
295577961cf6Sbouyer 
295677961cf6Sbouyer 	/* get all ld info */
2957c6bee2b8Smsaitoh 	memset(&mbox, 0, sizeof(mbox));
2958c6bee2b8Smsaitoh 	if (sc->sc_max256vd)
2959c6bee2b8Smsaitoh 		mbox.b[0] = 1;
2960c6bee2b8Smsaitoh 	if (mfii_mgmt(sc, MR_DCMD_LD_GET_LIST, &mbox, &sc->sc_ld_list,
296177961cf6Sbouyer 	    sizeof(sc->sc_ld_list), MFII_DATA_IN, false))
296277961cf6Sbouyer 		goto done;
296377961cf6Sbouyer 
296477961cf6Sbouyer 	/* get memory for all ld structures */
296577961cf6Sbouyer 	size = cfg->mfc_no_ld * sizeof(struct mfi_ld_details);
296677961cf6Sbouyer 	if (sc->sc_ld_sz != size) {
296777961cf6Sbouyer 		if (sc->sc_ld_details)
296877961cf6Sbouyer 			free(sc->sc_ld_details, M_DEVBUF);
296977961cf6Sbouyer 
297077961cf6Sbouyer 		ld_det = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
297177961cf6Sbouyer 		if (ld_det == NULL)
297277961cf6Sbouyer 			goto done;
297377961cf6Sbouyer 		sc->sc_ld_sz = size;
297477961cf6Sbouyer 		sc->sc_ld_details = ld_det;
297577961cf6Sbouyer 	}
297677961cf6Sbouyer 
297777961cf6Sbouyer 	/* find used physical disks */
297877961cf6Sbouyer 	size = sizeof(struct mfi_ld_details);
297977961cf6Sbouyer 	for (i = 0, d = 0; i < cfg->mfc_no_ld; i++) {
298077961cf6Sbouyer 		memset(&mbox, 0, sizeof(mbox));
298177961cf6Sbouyer 		mbox.b[0] = sc->sc_ld_list.mll_list[i].mll_ld.mld_target;
298277961cf6Sbouyer 		if (mfii_mgmt(sc, MR_DCMD_LD_GET_INFO, &mbox,
298377961cf6Sbouyer 		    &sc->sc_ld_details[i], size, MFII_DATA_IN, false))
298477961cf6Sbouyer 			goto done;
298577961cf6Sbouyer 
298677961cf6Sbouyer 		d += sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_no_drv_per_span *
298777961cf6Sbouyer 		    sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_span_depth;
298877961cf6Sbouyer 	}
298977961cf6Sbouyer 	sc->sc_no_pd = d;
299077961cf6Sbouyer 
299177961cf6Sbouyer 	rv = 0;
299277961cf6Sbouyer done:
299377961cf6Sbouyer 	return (rv);
299477961cf6Sbouyer }
299577961cf6Sbouyer 
2996bfa22340Smaxv static int
mfii_ioctl_inq(struct mfii_softc * sc,struct bioc_inq * bi)299777961cf6Sbouyer mfii_ioctl_inq(struct mfii_softc *sc, struct bioc_inq *bi)
299877961cf6Sbouyer {
299977961cf6Sbouyer 	int			rv = EINVAL;
300077961cf6Sbouyer 	struct mfi_conf		*cfg = NULL;
300177961cf6Sbouyer 
300277961cf6Sbouyer 	DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_inq\n", DEVNAME(sc));
300377961cf6Sbouyer 
300477961cf6Sbouyer 	if (mfii_bio_getitall(sc)) {
300577961cf6Sbouyer 		DNPRINTF(MFII_D_IOCTL, "%s: mfii_bio_getitall failed\n",
300677961cf6Sbouyer 		    DEVNAME(sc));
300777961cf6Sbouyer 		goto done;
300877961cf6Sbouyer 	}
300977961cf6Sbouyer 
301077961cf6Sbouyer 	/* count unused disks as volumes */
301177961cf6Sbouyer 	if (sc->sc_cfg == NULL)
301277961cf6Sbouyer 		goto done;
301377961cf6Sbouyer 	cfg = sc->sc_cfg;
301477961cf6Sbouyer 
301577961cf6Sbouyer 	bi->bi_nodisk = sc->sc_info.mci_pd_disks_present;
301677961cf6Sbouyer 	bi->bi_novol = cfg->mfc_no_ld + cfg->mfc_no_hs;
301777961cf6Sbouyer #if notyet
301877961cf6Sbouyer 	bi->bi_novol = cfg->mfc_no_ld + cfg->mfc_no_hs +
301977961cf6Sbouyer 	    (bi->bi_nodisk - sc->sc_no_pd);
302077961cf6Sbouyer #endif
302177961cf6Sbouyer 	/* tell bio who we are */
302277961cf6Sbouyer 	strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev));
302377961cf6Sbouyer 
302477961cf6Sbouyer 	rv = 0;
302577961cf6Sbouyer done:
302677961cf6Sbouyer 	return (rv);
302777961cf6Sbouyer }
302877961cf6Sbouyer 
3029bfa22340Smaxv static int
mfii_ioctl_vol(struct mfii_softc * sc,struct bioc_vol * bv)303077961cf6Sbouyer mfii_ioctl_vol(struct mfii_softc *sc, struct bioc_vol *bv)
303177961cf6Sbouyer {
303277961cf6Sbouyer 	int			i, per, rv = EINVAL;
303377961cf6Sbouyer 
303477961cf6Sbouyer 	DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_vol %#x\n",
303577961cf6Sbouyer 	    DEVNAME(sc), bv->bv_volid);
303677961cf6Sbouyer 
303777961cf6Sbouyer 	/* we really could skip and expect that inq took care of it */
303877961cf6Sbouyer 	if (mfii_bio_getitall(sc)) {
303977961cf6Sbouyer 		DNPRINTF(MFII_D_IOCTL, "%s: mfii_bio_getitall failed\n",
304077961cf6Sbouyer 		    DEVNAME(sc));
304177961cf6Sbouyer 		goto done;
304277961cf6Sbouyer 	}
304377961cf6Sbouyer 
304477961cf6Sbouyer 	if (bv->bv_volid >= sc->sc_ld_list.mll_no_ld) {
304577961cf6Sbouyer 		/* go do hotspares & unused disks */
304677961cf6Sbouyer 		rv = mfii_bio_hs(sc, bv->bv_volid, MFI_MGMT_VD, bv);
304777961cf6Sbouyer 		goto done;
304877961cf6Sbouyer 	}
304977961cf6Sbouyer 
305077961cf6Sbouyer 	i = bv->bv_volid;
305177961cf6Sbouyer 	strlcpy(bv->bv_dev, sc->sc_ld_details[i].mld_cfg.mlc_prop.mlp_name,
305277961cf6Sbouyer 	    sizeof(bv->bv_dev));
305377961cf6Sbouyer 
305477961cf6Sbouyer 	switch (sc->sc_ld_list.mll_list[i].mll_state) {
305577961cf6Sbouyer 	case MFI_LD_OFFLINE:
305677961cf6Sbouyer 		bv->bv_status = BIOC_SVOFFLINE;
305777961cf6Sbouyer 		break;
305877961cf6Sbouyer 
305977961cf6Sbouyer 	case MFI_LD_PART_DEGRADED:
306077961cf6Sbouyer 	case MFI_LD_DEGRADED:
306177961cf6Sbouyer 		bv->bv_status = BIOC_SVDEGRADED;
306277961cf6Sbouyer 		break;
306377961cf6Sbouyer 
306477961cf6Sbouyer 	case MFI_LD_ONLINE:
306577961cf6Sbouyer 		bv->bv_status = BIOC_SVONLINE;
306677961cf6Sbouyer 		break;
306777961cf6Sbouyer 
306877961cf6Sbouyer 	default:
306977961cf6Sbouyer 		bv->bv_status = BIOC_SVINVALID;
307077961cf6Sbouyer 		DNPRINTF(MFII_D_IOCTL, "%s: invalid logical disk state %#x\n",
307177961cf6Sbouyer 		    DEVNAME(sc),
307277961cf6Sbouyer 		    sc->sc_ld_list.mll_list[i].mll_state);
307377961cf6Sbouyer 	}
307477961cf6Sbouyer 
307577961cf6Sbouyer 	/* additional status can modify MFI status */
307677961cf6Sbouyer 	switch (sc->sc_ld_details[i].mld_progress.mlp_in_prog) {
307777961cf6Sbouyer 	case MFI_LD_PROG_CC:
307877961cf6Sbouyer 		bv->bv_status = BIOC_SVSCRUB;
307977961cf6Sbouyer 		per = (int)sc->sc_ld_details[i].mld_progress.mlp_cc.mp_progress;
308077961cf6Sbouyer 		bv->bv_percent = (per * 100) / 0xffff;
308177961cf6Sbouyer 		bv->bv_seconds =
308277961cf6Sbouyer 		    sc->sc_ld_details[i].mld_progress.mlp_cc.mp_elapsed_seconds;
308377961cf6Sbouyer 		break;
308477961cf6Sbouyer 
308541b2270fSmsaitoh 	case MFI_LD_PROG_BGI:
308641b2270fSmsaitoh 		bv->bv_status = BIOC_SVSCRUB;
308741b2270fSmsaitoh 		per = (int)sc->sc_ld_details[i].mld_progress.mlp_bgi.mp_progress;
308841b2270fSmsaitoh 		bv->bv_percent = (per * 100) / 0xffff;
308941b2270fSmsaitoh 		bv->bv_seconds =
309041b2270fSmsaitoh 		    sc->sc_ld_details[i].mld_progress.mlp_bgi.mp_elapsed_seconds;
309141b2270fSmsaitoh 		break;
309241b2270fSmsaitoh 
309377961cf6Sbouyer 	case MFI_LD_PROG_FGI:
309477961cf6Sbouyer 	case MFI_LD_PROG_RECONSTRUCT:
309577961cf6Sbouyer 		/* nothing yet */
309677961cf6Sbouyer 		break;
309777961cf6Sbouyer 	}
309877961cf6Sbouyer 
309977961cf6Sbouyer #if 0
310077961cf6Sbouyer 	if (sc->sc_ld_details[i].mld_cfg.mlc_prop.mlp_cur_cache_policy & 0x01)
310177961cf6Sbouyer 		bv->bv_cache = BIOC_CVWRITEBACK;
310277961cf6Sbouyer 	else
310377961cf6Sbouyer 		bv->bv_cache = BIOC_CVWRITETHROUGH;
310477961cf6Sbouyer #endif
310577961cf6Sbouyer 
310677961cf6Sbouyer 	/*
310777961cf6Sbouyer 	 * The RAID levels are determined per the SNIA DDF spec, this is only
310877961cf6Sbouyer 	 * a subset that is valid for the MFI controller.
310977961cf6Sbouyer 	 */
311077961cf6Sbouyer 	bv->bv_level = sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_pri_raid;
311177961cf6Sbouyer 	if (sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_span_depth > 1)
311277961cf6Sbouyer 		bv->bv_level *= 10;
311377961cf6Sbouyer 
3114277d1243Smsaitoh 	bv->bv_nodisk =
3115277d1243Smsaitoh 	    sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_no_drv_per_span *
311677961cf6Sbouyer 	    sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_span_depth;
311777961cf6Sbouyer 
311877961cf6Sbouyer 	bv->bv_size = sc->sc_ld_details[i].mld_size * 512; /* bytes per block */
31198782b951Smsaitoh 	bv->bv_stripe_size =
31208782b951Smsaitoh 	    (512 << sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_stripe_size)
31218782b951Smsaitoh 	    / 1024; /* in KB */
312277961cf6Sbouyer 
312377961cf6Sbouyer 	rv = 0;
312477961cf6Sbouyer done:
312577961cf6Sbouyer 	return (rv);
312677961cf6Sbouyer }
312777961cf6Sbouyer 
3128bfa22340Smaxv static int
mfii_ioctl_disk(struct mfii_softc * sc,struct bioc_disk * bd)312977961cf6Sbouyer mfii_ioctl_disk(struct mfii_softc *sc, struct bioc_disk *bd)
313077961cf6Sbouyer {
313177961cf6Sbouyer 	struct mfi_conf		*cfg;
313277961cf6Sbouyer 	struct mfi_array	*ar;
313377961cf6Sbouyer 	struct mfi_ld_cfg	*ld;
313477961cf6Sbouyer 	struct mfi_pd_details	*pd;
313577961cf6Sbouyer 	struct mfi_pd_list	*pl;
313677961cf6Sbouyer 	struct scsipi_inquiry_data *inqbuf;
313777961cf6Sbouyer 	char			vend[8+16+4+1], *vendp;
313877961cf6Sbouyer 	int			i, rv = EINVAL;
313977961cf6Sbouyer 	int			arr, vol, disk, span;
314077961cf6Sbouyer 	union mfi_mbox		mbox;
314177961cf6Sbouyer 
314277961cf6Sbouyer 	DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_disk %#x\n",
314377961cf6Sbouyer 	    DEVNAME(sc), bd->bd_diskid);
314477961cf6Sbouyer 
314577961cf6Sbouyer 	/* we really could skip and expect that inq took care of it */
314677961cf6Sbouyer 	if (mfii_bio_getitall(sc)) {
314777961cf6Sbouyer 		DNPRINTF(MFII_D_IOCTL, "%s: mfii_bio_getitall failed\n",
314877961cf6Sbouyer 		    DEVNAME(sc));
314977961cf6Sbouyer 		return (rv);
315077961cf6Sbouyer 	}
315177961cf6Sbouyer 	cfg = sc->sc_cfg;
315277961cf6Sbouyer 
315377961cf6Sbouyer 	pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
315477961cf6Sbouyer 	pl = malloc(sizeof *pl, M_DEVBUF, M_WAITOK);
315577961cf6Sbouyer 
315677961cf6Sbouyer 	ar = cfg->mfc_array;
315777961cf6Sbouyer 	vol = bd->bd_volid;
315877961cf6Sbouyer 	if (vol >= cfg->mfc_no_ld) {
315977961cf6Sbouyer 		/* do hotspares */
316077961cf6Sbouyer 		rv = mfii_bio_hs(sc, bd->bd_volid, MFI_MGMT_SD, bd);
316177961cf6Sbouyer 		goto freeme;
316277961cf6Sbouyer 	}
316377961cf6Sbouyer 
316477961cf6Sbouyer 	/* calculate offset to ld structure */
316577961cf6Sbouyer 	ld = (struct mfi_ld_cfg *)(
316677961cf6Sbouyer 	    ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) +
316777961cf6Sbouyer 	    cfg->mfc_array_size * cfg->mfc_no_array);
316877961cf6Sbouyer 
316977961cf6Sbouyer 	/* use span 0 only when raid group is not spanned */
317077961cf6Sbouyer 	if (ld[vol].mlc_parm.mpa_span_depth > 1)
317177961cf6Sbouyer 		span = bd->bd_diskid / ld[vol].mlc_parm.mpa_no_drv_per_span;
317277961cf6Sbouyer 	else
317377961cf6Sbouyer 		span = 0;
317477961cf6Sbouyer 	arr = ld[vol].mlc_span[span].mls_index;
317577961cf6Sbouyer 
317677961cf6Sbouyer 	/* offset disk into pd list */
317777961cf6Sbouyer 	disk = bd->bd_diskid % ld[vol].mlc_parm.mpa_no_drv_per_span;
317877961cf6Sbouyer 
317977961cf6Sbouyer 	if (ar[arr].pd[disk].mar_pd.mfp_id == 0xffffU) {
318077961cf6Sbouyer 		/* disk is missing but succeed command */
318177961cf6Sbouyer 		bd->bd_status = BIOC_SDFAILED;
318277961cf6Sbouyer 		rv = 0;
318377961cf6Sbouyer 
318477961cf6Sbouyer 		/* try to find an unused disk for the target to rebuild */
318577961cf6Sbouyer 		if (mfii_mgmt(sc, MR_DCMD_PD_GET_LIST, NULL, pl, sizeof(*pl),
318677961cf6Sbouyer 		    MFII_DATA_IN, false))
318777961cf6Sbouyer 			goto freeme;
318877961cf6Sbouyer 
318977961cf6Sbouyer 		for (i = 0; i < pl->mpl_no_pd; i++) {
319077961cf6Sbouyer 			if (pl->mpl_address[i].mpa_scsi_type != 0)
319177961cf6Sbouyer 				continue;
319277961cf6Sbouyer 
319377961cf6Sbouyer 			memset(&mbox, 0, sizeof(mbox));
319477961cf6Sbouyer 			mbox.s[0] = pl->mpl_address[i].mpa_pd_id;
319577961cf6Sbouyer 			if (mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox,
319677961cf6Sbouyer 			    pd, sizeof(*pd), MFII_DATA_IN, false))
319777961cf6Sbouyer 				continue;
319877961cf6Sbouyer 
319977961cf6Sbouyer 			if (pd->mpd_fw_state == MFI_PD_UNCONFIG_GOOD ||
320077961cf6Sbouyer 			    pd->mpd_fw_state == MFI_PD_UNCONFIG_BAD)
320177961cf6Sbouyer 				break;
320277961cf6Sbouyer 		}
320377961cf6Sbouyer 
320477961cf6Sbouyer 		if (i == pl->mpl_no_pd)
320577961cf6Sbouyer 			goto freeme;
320677961cf6Sbouyer 	} else {
320777961cf6Sbouyer 		memset(&mbox, 0, sizeof(mbox));
320877961cf6Sbouyer 		mbox.s[0] = ar[arr].pd[disk].mar_pd.mfp_id;
320977961cf6Sbouyer 		if (mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
321077961cf6Sbouyer 		    MFII_DATA_IN, false)) {
321177961cf6Sbouyer 			bd->bd_status = BIOC_SDINVALID;
321277961cf6Sbouyer 			goto freeme;
321377961cf6Sbouyer 		}
321477961cf6Sbouyer 	}
321577961cf6Sbouyer 
321677961cf6Sbouyer 	/* get the remaining fields */
321777961cf6Sbouyer 	bd->bd_channel = pd->mpd_enc_idx;
321877961cf6Sbouyer 	bd->bd_target = pd->mpd_enc_slot;
321977961cf6Sbouyer 
322077961cf6Sbouyer 	/* get status */
322177961cf6Sbouyer 	switch (pd->mpd_fw_state){
322277961cf6Sbouyer 	case MFI_PD_UNCONFIG_GOOD:
322377961cf6Sbouyer 	case MFI_PD_UNCONFIG_BAD:
322477961cf6Sbouyer 		bd->bd_status = BIOC_SDUNUSED;
322577961cf6Sbouyer 		break;
322677961cf6Sbouyer 
322777961cf6Sbouyer 	case MFI_PD_HOTSPARE: /* XXX dedicated hotspare part of array? */
322877961cf6Sbouyer 		bd->bd_status = BIOC_SDHOTSPARE;
322977961cf6Sbouyer 		break;
323077961cf6Sbouyer 
323177961cf6Sbouyer 	case MFI_PD_OFFLINE:
323277961cf6Sbouyer 		bd->bd_status = BIOC_SDOFFLINE;
323377961cf6Sbouyer 		break;
323477961cf6Sbouyer 
323577961cf6Sbouyer 	case MFI_PD_FAILED:
323677961cf6Sbouyer 		bd->bd_status = BIOC_SDFAILED;
323777961cf6Sbouyer 		break;
323877961cf6Sbouyer 
323977961cf6Sbouyer 	case MFI_PD_REBUILD:
324077961cf6Sbouyer 		bd->bd_status = BIOC_SDREBUILD;
324177961cf6Sbouyer 		break;
324277961cf6Sbouyer 
324377961cf6Sbouyer 	case MFI_PD_ONLINE:
324477961cf6Sbouyer 		bd->bd_status = BIOC_SDONLINE;
324577961cf6Sbouyer 		break;
324677961cf6Sbouyer 
324777961cf6Sbouyer 	case MFI_PD_COPYBACK:
324877961cf6Sbouyer 	case MFI_PD_SYSTEM:
324977961cf6Sbouyer 	default:
325077961cf6Sbouyer 		bd->bd_status = BIOC_SDINVALID;
325177961cf6Sbouyer 		break;
325277961cf6Sbouyer 	}
325377961cf6Sbouyer 
325477961cf6Sbouyer 	bd->bd_size = pd->mpd_size * 512; /* bytes per block */
325577961cf6Sbouyer 
325677961cf6Sbouyer 	inqbuf = (struct scsipi_inquiry_data *)&pd->mpd_inq_data;
325777961cf6Sbouyer 	vendp = inqbuf->vendor;
325877961cf6Sbouyer 	memcpy(vend, vendp, sizeof vend - 1);
325977961cf6Sbouyer 	vend[sizeof vend - 1] = '\0';
326077961cf6Sbouyer 	strlcpy(bd->bd_vendor, vend, sizeof(bd->bd_vendor));
326177961cf6Sbouyer 
326277961cf6Sbouyer 	/* XXX find a way to retrieve serial nr from drive */
326377961cf6Sbouyer 	/* XXX find a way to get bd_procdev */
326477961cf6Sbouyer 
326577961cf6Sbouyer #if 0
326677961cf6Sbouyer 	mfp = &pd->mpd_progress;
326777961cf6Sbouyer 	if (mfp->mfp_in_prog & MFI_PD_PROG_PR) {
326877961cf6Sbouyer 		mp = &mfp->mfp_patrol_read;
326977961cf6Sbouyer 		bd->bd_patrol.bdp_percent = (mp->mp_progress * 100) / 0xffff;
327077961cf6Sbouyer 		bd->bd_patrol.bdp_seconds = mp->mp_elapsed_seconds;
327177961cf6Sbouyer 	}
327277961cf6Sbouyer #endif
327377961cf6Sbouyer 
327477961cf6Sbouyer 	rv = 0;
327577961cf6Sbouyer freeme:
327677961cf6Sbouyer 	free(pd, M_DEVBUF);
327777961cf6Sbouyer 	free(pl, M_DEVBUF);
327877961cf6Sbouyer 
327977961cf6Sbouyer 	return (rv);
328077961cf6Sbouyer }
328177961cf6Sbouyer 
3282bfa22340Smaxv static int
mfii_ioctl_alarm(struct mfii_softc * sc,struct bioc_alarm * ba)328377961cf6Sbouyer mfii_ioctl_alarm(struct mfii_softc *sc, struct bioc_alarm *ba)
328477961cf6Sbouyer {
328577961cf6Sbouyer 	uint32_t		opc;
328677961cf6Sbouyer 	int			rv = 0;
328777961cf6Sbouyer 	int8_t			ret;
328877961cf6Sbouyer 	mfii_direction_t dir = MFII_DATA_NONE;
328977961cf6Sbouyer 
329077961cf6Sbouyer 	switch (ba->ba_opcode) {
329177961cf6Sbouyer 	case BIOC_SADISABLE:
329277961cf6Sbouyer 		opc = MR_DCMD_SPEAKER_DISABLE;
329377961cf6Sbouyer 		break;
329477961cf6Sbouyer 
329577961cf6Sbouyer 	case BIOC_SAENABLE:
329677961cf6Sbouyer 		opc = MR_DCMD_SPEAKER_ENABLE;
329777961cf6Sbouyer 		break;
329877961cf6Sbouyer 
329977961cf6Sbouyer 	case BIOC_SASILENCE:
330077961cf6Sbouyer 		opc = MR_DCMD_SPEAKER_SILENCE;
330177961cf6Sbouyer 		break;
330277961cf6Sbouyer 
330377961cf6Sbouyer 	case BIOC_GASTATUS:
330477961cf6Sbouyer 		opc = MR_DCMD_SPEAKER_GET;
330577961cf6Sbouyer 		dir = MFII_DATA_IN;
330677961cf6Sbouyer 		break;
330777961cf6Sbouyer 
330877961cf6Sbouyer 	case BIOC_SATEST:
330977961cf6Sbouyer 		opc = MR_DCMD_SPEAKER_TEST;
331077961cf6Sbouyer 		break;
331177961cf6Sbouyer 
331277961cf6Sbouyer 	default:
3313277d1243Smsaitoh 		DNPRINTF(MFII_D_IOCTL,
3314277d1243Smsaitoh 		    "%s: mfii_ioctl_alarm biocalarm invalid opcode %x\n",
3315277d1243Smsaitoh 		    DEVNAME(sc), ba->ba_opcode);
331677961cf6Sbouyer 		return (EINVAL);
331777961cf6Sbouyer 	}
331877961cf6Sbouyer 
331977961cf6Sbouyer 	if (mfii_mgmt(sc, opc, NULL, &ret, sizeof(ret), dir, false))
332077961cf6Sbouyer 		rv = EINVAL;
332177961cf6Sbouyer 	else
332277961cf6Sbouyer 		if (ba->ba_opcode == BIOC_GASTATUS)
332377961cf6Sbouyer 			ba->ba_status = ret;
332477961cf6Sbouyer 		else
332577961cf6Sbouyer 			ba->ba_status = 0;
332677961cf6Sbouyer 
332777961cf6Sbouyer 	return (rv);
332877961cf6Sbouyer }
332977961cf6Sbouyer 
3330bfa22340Smaxv static int
mfii_ioctl_blink(struct mfii_softc * sc,struct bioc_blink * bb)333177961cf6Sbouyer mfii_ioctl_blink(struct mfii_softc *sc, struct bioc_blink *bb)
333277961cf6Sbouyer {
333377961cf6Sbouyer 	int			i, found, rv = EINVAL;
333477961cf6Sbouyer 	union mfi_mbox		mbox;
333577961cf6Sbouyer 	uint32_t		cmd;
333677961cf6Sbouyer 	struct mfi_pd_list	*pd;
333777961cf6Sbouyer 
333877961cf6Sbouyer 	DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_blink %x\n", DEVNAME(sc),
333977961cf6Sbouyer 	    bb->bb_status);
334077961cf6Sbouyer 
334177961cf6Sbouyer 	/* channel 0 means not in an enclosure so can't be blinked */
334277961cf6Sbouyer 	if (bb->bb_channel == 0)
334377961cf6Sbouyer 		return (EINVAL);
334477961cf6Sbouyer 
334577961cf6Sbouyer 	pd = malloc(sizeof(*pd), M_DEVBUF, M_WAITOK);
334677961cf6Sbouyer 
334777961cf6Sbouyer 	if (mfii_mgmt(sc, MR_DCMD_PD_GET_LIST, NULL, pd, sizeof(*pd),
334877961cf6Sbouyer 	    MFII_DATA_IN, false))
334977961cf6Sbouyer 		goto done;
335077961cf6Sbouyer 
335177961cf6Sbouyer 	for (i = 0, found = 0; i < pd->mpl_no_pd; i++)
335277961cf6Sbouyer 		if (bb->bb_channel == pd->mpl_address[i].mpa_enc_index &&
335377961cf6Sbouyer 		    bb->bb_target == pd->mpl_address[i].mpa_enc_slot) {
335477961cf6Sbouyer 			found = 1;
335577961cf6Sbouyer 			break;
335677961cf6Sbouyer 		}
335777961cf6Sbouyer 
335877961cf6Sbouyer 	if (!found)
335977961cf6Sbouyer 		goto done;
336077961cf6Sbouyer 
336177961cf6Sbouyer 	memset(&mbox, 0, sizeof(mbox));
336277961cf6Sbouyer 	mbox.s[0] = pd->mpl_address[i].mpa_pd_id;
336377961cf6Sbouyer 
336477961cf6Sbouyer 	switch (bb->bb_status) {
336577961cf6Sbouyer 	case BIOC_SBUNBLINK:
336677961cf6Sbouyer 		cmd = MR_DCMD_PD_UNBLINK;
336777961cf6Sbouyer 		break;
336877961cf6Sbouyer 
336977961cf6Sbouyer 	case BIOC_SBBLINK:
337077961cf6Sbouyer 		cmd = MR_DCMD_PD_BLINK;
337177961cf6Sbouyer 		break;
337277961cf6Sbouyer 
337377961cf6Sbouyer 	case BIOC_SBALARM:
337477961cf6Sbouyer 	default:
3375277d1243Smsaitoh 		DNPRINTF(MFII_D_IOCTL,
3376277d1243Smsaitoh 		    "%s: mfii_ioctl_blink biocblink invalid opcode %x\n",
3377277d1243Smsaitoh 		    DEVNAME(sc), bb->bb_status);
337877961cf6Sbouyer 		goto done;
337977961cf6Sbouyer 	}
338077961cf6Sbouyer 
338177961cf6Sbouyer 
338277961cf6Sbouyer 	if (mfii_mgmt(sc, cmd, &mbox, NULL, 0, MFII_DATA_NONE, false))
338377961cf6Sbouyer 		goto done;
338477961cf6Sbouyer 
338577961cf6Sbouyer 	rv = 0;
338677961cf6Sbouyer done:
338777961cf6Sbouyer 	free(pd, M_DEVBUF);
338877961cf6Sbouyer 	return (rv);
338977961cf6Sbouyer }
339077961cf6Sbouyer 
339177961cf6Sbouyer static int
mfii_makegood(struct mfii_softc * sc,uint16_t pd_id)339277961cf6Sbouyer mfii_makegood(struct mfii_softc *sc, uint16_t pd_id)
339377961cf6Sbouyer {
339477961cf6Sbouyer 	struct mfii_foreign_scan_info *fsi;
339577961cf6Sbouyer 	struct mfi_pd_details	*pd;
339677961cf6Sbouyer 	union mfi_mbox		mbox;
339777961cf6Sbouyer 	int			rv;
339877961cf6Sbouyer 
339977961cf6Sbouyer 	fsi = malloc(sizeof *fsi, M_DEVBUF, M_WAITOK);
340077961cf6Sbouyer 	pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
340177961cf6Sbouyer 
340277961cf6Sbouyer 	memset(&mbox, 0, sizeof mbox);
340377961cf6Sbouyer 	mbox.s[0] = pd_id;
340477961cf6Sbouyer 	rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
340577961cf6Sbouyer 	    MFII_DATA_IN, false);
340677961cf6Sbouyer 	if (rv != 0)
340777961cf6Sbouyer 		goto done;
340877961cf6Sbouyer 
340977961cf6Sbouyer 	if (pd->mpd_fw_state == MFI_PD_UNCONFIG_BAD) {
341077961cf6Sbouyer 		mbox.s[0] = pd_id;
341177961cf6Sbouyer 		mbox.s[1] = pd->mpd_pd.mfp_seq;
341277961cf6Sbouyer 		mbox.b[4] = MFI_PD_UNCONFIG_GOOD;
341377961cf6Sbouyer 		rv = mfii_mgmt(sc, MR_DCMD_PD_SET_STATE, &mbox, NULL, 0,
341477961cf6Sbouyer 		    MFII_DATA_NONE, false);
341577961cf6Sbouyer 		if (rv != 0)
341677961cf6Sbouyer 			goto done;
341777961cf6Sbouyer 	}
341877961cf6Sbouyer 
341977961cf6Sbouyer 	memset(&mbox, 0, sizeof mbox);
342077961cf6Sbouyer 	mbox.s[0] = pd_id;
342177961cf6Sbouyer 	rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
342277961cf6Sbouyer 	    MFII_DATA_IN, false);
342377961cf6Sbouyer 	if (rv != 0)
342477961cf6Sbouyer 		goto done;
342577961cf6Sbouyer 
342677961cf6Sbouyer 	if (pd->mpd_ddf_state & MFI_DDF_FOREIGN) {
342777961cf6Sbouyer 		rv = mfii_mgmt(sc, MR_DCMD_CFG_FOREIGN_SCAN, NULL,
342877961cf6Sbouyer 		    fsi, sizeof(*fsi), MFII_DATA_IN, false);
342977961cf6Sbouyer 		if (rv != 0)
343077961cf6Sbouyer 			goto done;
343177961cf6Sbouyer 
343277961cf6Sbouyer 		if (fsi->count > 0) {
343377961cf6Sbouyer 			rv = mfii_mgmt(sc, MR_DCMD_CFG_FOREIGN_CLEAR, NULL,
343477961cf6Sbouyer 			    NULL, 0, MFII_DATA_NONE, false);
343577961cf6Sbouyer 			if (rv != 0)
343677961cf6Sbouyer 				goto done;
343777961cf6Sbouyer 		}
343877961cf6Sbouyer 	}
343977961cf6Sbouyer 
344077961cf6Sbouyer 	memset(&mbox, 0, sizeof mbox);
344177961cf6Sbouyer 	mbox.s[0] = pd_id;
344277961cf6Sbouyer 	rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
344377961cf6Sbouyer 	    MFII_DATA_IN, false);
344477961cf6Sbouyer 	if (rv != 0)
344577961cf6Sbouyer 		goto done;
344677961cf6Sbouyer 
344777961cf6Sbouyer 	if (pd->mpd_fw_state != MFI_PD_UNCONFIG_GOOD ||
344877961cf6Sbouyer 	    pd->mpd_ddf_state & MFI_DDF_FOREIGN)
344977961cf6Sbouyer 		rv = ENXIO;
345077961cf6Sbouyer 
345177961cf6Sbouyer done:
345277961cf6Sbouyer 	free(fsi, M_DEVBUF);
345377961cf6Sbouyer 	free(pd, M_DEVBUF);
345477961cf6Sbouyer 
345577961cf6Sbouyer 	return (rv);
345677961cf6Sbouyer }
345777961cf6Sbouyer 
345877961cf6Sbouyer static int
mfii_makespare(struct mfii_softc * sc,uint16_t pd_id)345977961cf6Sbouyer mfii_makespare(struct mfii_softc *sc, uint16_t pd_id)
346077961cf6Sbouyer {
346177961cf6Sbouyer 	struct mfi_hotspare	*hs;
346277961cf6Sbouyer 	struct mfi_pd_details	*pd;
346377961cf6Sbouyer 	union mfi_mbox		mbox;
346477961cf6Sbouyer 	size_t			size;
346577961cf6Sbouyer 	int			rv = EINVAL;
346677961cf6Sbouyer 
346777961cf6Sbouyer 	/* we really could skip and expect that inq took care of it */
346877961cf6Sbouyer 	if (mfii_bio_getitall(sc)) {
346977961cf6Sbouyer 		DNPRINTF(MFII_D_IOCTL, "%s: mfii_bio_getitall failed\n",
347077961cf6Sbouyer 		    DEVNAME(sc));
347177961cf6Sbouyer 		return (rv);
347277961cf6Sbouyer 	}
347377961cf6Sbouyer 	size = sizeof *hs + sizeof(uint16_t) * sc->sc_cfg->mfc_no_array;
347477961cf6Sbouyer 
347577961cf6Sbouyer 	hs = malloc(size, M_DEVBUF, M_WAITOK);
347677961cf6Sbouyer 	pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
347777961cf6Sbouyer 
347877961cf6Sbouyer 	memset(&mbox, 0, sizeof mbox);
347977961cf6Sbouyer 	mbox.s[0] = pd_id;
348077961cf6Sbouyer 	rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
348177961cf6Sbouyer 	    MFII_DATA_IN, false);
348277961cf6Sbouyer 	if (rv != 0)
348377961cf6Sbouyer 		goto done;
348477961cf6Sbouyer 
348577961cf6Sbouyer 	memset(hs, 0, size);
348677961cf6Sbouyer 	hs->mhs_pd.mfp_id = pd->mpd_pd.mfp_id;
348777961cf6Sbouyer 	hs->mhs_pd.mfp_seq = pd->mpd_pd.mfp_seq;
348877961cf6Sbouyer 	rv = mfii_mgmt(sc, MR_DCMD_CFG_MAKE_SPARE, NULL, hs, size,
348977961cf6Sbouyer 	    MFII_DATA_OUT, false);
349077961cf6Sbouyer 
349177961cf6Sbouyer done:
349277961cf6Sbouyer 	free(hs, M_DEVBUF);
349377961cf6Sbouyer 	free(pd, M_DEVBUF);
349477961cf6Sbouyer 
349577961cf6Sbouyer 	return (rv);
349677961cf6Sbouyer }
349777961cf6Sbouyer 
3498bfa22340Smaxv static int
mfii_ioctl_setstate(struct mfii_softc * sc,struct bioc_setstate * bs)349977961cf6Sbouyer mfii_ioctl_setstate(struct mfii_softc *sc, struct bioc_setstate *bs)
350077961cf6Sbouyer {
350177961cf6Sbouyer 	struct mfi_pd_details	*pd;
350277961cf6Sbouyer 	struct mfi_pd_list	*pl;
350377961cf6Sbouyer 	int			i, found, rv = EINVAL;
350477961cf6Sbouyer 	union mfi_mbox		mbox;
350577961cf6Sbouyer 
350677961cf6Sbouyer 	DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_setstate %x\n", DEVNAME(sc),
350777961cf6Sbouyer 	    bs->bs_status);
350877961cf6Sbouyer 
350977961cf6Sbouyer 	pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
351077961cf6Sbouyer 	pl = malloc(sizeof *pl, M_DEVBUF, M_WAITOK);
351177961cf6Sbouyer 
351277961cf6Sbouyer 	if (mfii_mgmt(sc, MR_DCMD_PD_GET_LIST, NULL, pl, sizeof(*pl),
351377961cf6Sbouyer 	    MFII_DATA_IN, false))
351477961cf6Sbouyer 		goto done;
351577961cf6Sbouyer 
351677961cf6Sbouyer 	for (i = 0, found = 0; i < pl->mpl_no_pd; i++)
351777961cf6Sbouyer 		if (bs->bs_channel == pl->mpl_address[i].mpa_enc_index &&
351877961cf6Sbouyer 		    bs->bs_target == pl->mpl_address[i].mpa_enc_slot) {
351977961cf6Sbouyer 			found = 1;
352077961cf6Sbouyer 			break;
352177961cf6Sbouyer 		}
352277961cf6Sbouyer 
352377961cf6Sbouyer 	if (!found)
352477961cf6Sbouyer 		goto done;
352577961cf6Sbouyer 
352677961cf6Sbouyer 	memset(&mbox, 0, sizeof(mbox));
352777961cf6Sbouyer 	mbox.s[0] = pl->mpl_address[i].mpa_pd_id;
352877961cf6Sbouyer 
352977961cf6Sbouyer 	if (mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
353077961cf6Sbouyer 	    MFII_DATA_IN, false))
353177961cf6Sbouyer 		goto done;
353277961cf6Sbouyer 
353377961cf6Sbouyer 	mbox.s[0] = pl->mpl_address[i].mpa_pd_id;
353477961cf6Sbouyer 	mbox.s[1] = pd->mpd_pd.mfp_seq;
353577961cf6Sbouyer 
353677961cf6Sbouyer 	switch (bs->bs_status) {
353777961cf6Sbouyer 	case BIOC_SSONLINE:
353877961cf6Sbouyer 		mbox.b[4] = MFI_PD_ONLINE;
353977961cf6Sbouyer 		break;
354077961cf6Sbouyer 
354177961cf6Sbouyer 	case BIOC_SSOFFLINE:
354277961cf6Sbouyer 		mbox.b[4] = MFI_PD_OFFLINE;
354377961cf6Sbouyer 		break;
354477961cf6Sbouyer 
354577961cf6Sbouyer 	case BIOC_SSHOTSPARE:
354677961cf6Sbouyer 		mbox.b[4] = MFI_PD_HOTSPARE;
354777961cf6Sbouyer 		break;
354877961cf6Sbouyer 
354977961cf6Sbouyer 	case BIOC_SSREBUILD:
355077961cf6Sbouyer 		if (pd->mpd_fw_state != MFI_PD_OFFLINE) {
355177961cf6Sbouyer 			if ((rv = mfii_makegood(sc,
355277961cf6Sbouyer 			    pl->mpl_address[i].mpa_pd_id)))
355377961cf6Sbouyer 				goto done;
355477961cf6Sbouyer 
355577961cf6Sbouyer 			if ((rv = mfii_makespare(sc,
355677961cf6Sbouyer 			    pl->mpl_address[i].mpa_pd_id)))
355777961cf6Sbouyer 				goto done;
355877961cf6Sbouyer 
355977961cf6Sbouyer 			memset(&mbox, 0, sizeof(mbox));
356077961cf6Sbouyer 			mbox.s[0] = pl->mpl_address[i].mpa_pd_id;
356177961cf6Sbouyer 			rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox,
356277961cf6Sbouyer 			    pd, sizeof(*pd), MFII_DATA_IN, false);
356377961cf6Sbouyer 			if (rv != 0)
356477961cf6Sbouyer 				goto done;
356577961cf6Sbouyer 
356677961cf6Sbouyer 			/* rebuilding might be started by mfii_makespare() */
356777961cf6Sbouyer 			if (pd->mpd_fw_state == MFI_PD_REBUILD) {
356877961cf6Sbouyer 				rv = 0;
356977961cf6Sbouyer 				goto done;
357077961cf6Sbouyer 			}
357177961cf6Sbouyer 
357277961cf6Sbouyer 			mbox.s[0] = pl->mpl_address[i].mpa_pd_id;
357377961cf6Sbouyer 			mbox.s[1] = pd->mpd_pd.mfp_seq;
357477961cf6Sbouyer 		}
357577961cf6Sbouyer 		mbox.b[4] = MFI_PD_REBUILD;
357677961cf6Sbouyer 		break;
357777961cf6Sbouyer 
357877961cf6Sbouyer 	default:
357977961cf6Sbouyer 		DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_setstate invalid "
358077961cf6Sbouyer 		    "opcode %x\n", DEVNAME(sc), bs->bs_status);
358177961cf6Sbouyer 		goto done;
358277961cf6Sbouyer 	}
358377961cf6Sbouyer 
358477961cf6Sbouyer 
358577961cf6Sbouyer 	rv = mfii_mgmt(sc, MR_DCMD_PD_SET_STATE, &mbox, NULL, 0,
358677961cf6Sbouyer 	    MFII_DATA_NONE, false);
358777961cf6Sbouyer done:
358877961cf6Sbouyer 	free(pd, M_DEVBUF);
358977961cf6Sbouyer 	free(pl, M_DEVBUF);
359077961cf6Sbouyer 	return (rv);
359177961cf6Sbouyer }
359277961cf6Sbouyer 
359377961cf6Sbouyer #if 0
359477961cf6Sbouyer int
359577961cf6Sbouyer mfii_ioctl_patrol(struct mfii_softc *sc, struct bioc_patrol *bp)
359677961cf6Sbouyer {
359777961cf6Sbouyer 	uint32_t		opc;
359877961cf6Sbouyer 	int			rv = 0;
359977961cf6Sbouyer 	struct mfi_pr_properties prop;
360077961cf6Sbouyer 	struct mfi_pr_status	status;
360177961cf6Sbouyer 	uint32_t		time, exec_freq;
360277961cf6Sbouyer 
360377961cf6Sbouyer 	switch (bp->bp_opcode) {
360477961cf6Sbouyer 	case BIOC_SPSTOP:
360577961cf6Sbouyer 	case BIOC_SPSTART:
360677961cf6Sbouyer 		if (bp->bp_opcode == BIOC_SPSTART)
360777961cf6Sbouyer 			opc = MR_DCMD_PR_START;
360877961cf6Sbouyer 		else
360977961cf6Sbouyer 			opc = MR_DCMD_PR_STOP;
361077961cf6Sbouyer 		if (mfii_mgmt(sc, opc, NULL, NULL, 0, MFII_DATA_IN, false))
361177961cf6Sbouyer 			return (EINVAL);
361277961cf6Sbouyer 		break;
361377961cf6Sbouyer 
361477961cf6Sbouyer 	case BIOC_SPMANUAL:
361577961cf6Sbouyer 	case BIOC_SPDISABLE:
361677961cf6Sbouyer 	case BIOC_SPAUTO:
361777961cf6Sbouyer 		/* Get device's time. */
361877961cf6Sbouyer 		opc = MR_DCMD_TIME_SECS_GET;
361977961cf6Sbouyer 		if (mfii_mgmt(sc, opc, NULL, &time, sizeof(time),
362077961cf6Sbouyer 		    MFII_DATA_IN, false))
362177961cf6Sbouyer 			return (EINVAL);
362277961cf6Sbouyer 
362377961cf6Sbouyer 		opc = MR_DCMD_PR_GET_PROPERTIES;
362477961cf6Sbouyer 		if (mfii_mgmt(sc, opc, NULL, &prop, sizeof(prop),
362577961cf6Sbouyer 		    MFII_DATA_IN, false))
362677961cf6Sbouyer 			return (EINVAL);
362777961cf6Sbouyer 
362877961cf6Sbouyer 		switch (bp->bp_opcode) {
362977961cf6Sbouyer 		case BIOC_SPMANUAL:
363077961cf6Sbouyer 			prop.op_mode = MFI_PR_OPMODE_MANUAL;
363177961cf6Sbouyer 			break;
363277961cf6Sbouyer 		case BIOC_SPDISABLE:
363377961cf6Sbouyer 			prop.op_mode = MFI_PR_OPMODE_DISABLED;
363477961cf6Sbouyer 			break;
363577961cf6Sbouyer 		case BIOC_SPAUTO:
363677961cf6Sbouyer 			if (bp->bp_autoival != 0) {
363777961cf6Sbouyer 				if (bp->bp_autoival == -1)
363877961cf6Sbouyer 					/* continuously */
363977961cf6Sbouyer 					exec_freq = 0xffffffffU;
364077961cf6Sbouyer 				else if (bp->bp_autoival > 0)
364177961cf6Sbouyer 					exec_freq = bp->bp_autoival;
364277961cf6Sbouyer 				else
364377961cf6Sbouyer 					return (EINVAL);
364477961cf6Sbouyer 				prop.exec_freq = exec_freq;
364577961cf6Sbouyer 			}
364677961cf6Sbouyer 			if (bp->bp_autonext != 0) {
364777961cf6Sbouyer 				if (bp->bp_autonext < 0)
364877961cf6Sbouyer 					return (EINVAL);
364977961cf6Sbouyer 				else
3650277d1243Smsaitoh 					prop.next_exec =
3651277d1243Smsaitoh 					    time + bp->bp_autonext;
365277961cf6Sbouyer 			}
365377961cf6Sbouyer 			prop.op_mode = MFI_PR_OPMODE_AUTO;
365477961cf6Sbouyer 			break;
365577961cf6Sbouyer 		}
365677961cf6Sbouyer 
365777961cf6Sbouyer 		opc = MR_DCMD_PR_SET_PROPERTIES;
365877961cf6Sbouyer 		if (mfii_mgmt(sc, opc, NULL, &prop, sizeof(prop),
365977961cf6Sbouyer 		    MFII_DATA_OUT, false))
366077961cf6Sbouyer 			return (EINVAL);
366177961cf6Sbouyer 
366277961cf6Sbouyer 		break;
366377961cf6Sbouyer 
366477961cf6Sbouyer 	case BIOC_GPSTATUS:
366577961cf6Sbouyer 		opc = MR_DCMD_PR_GET_PROPERTIES;
366677961cf6Sbouyer 		if (mfii_mgmt(sc, opc, NULL, &prop, sizeof(prop),
366777961cf6Sbouyer 		    MFII_DATA_IN, false))
366877961cf6Sbouyer 			return (EINVAL);
366977961cf6Sbouyer 
367077961cf6Sbouyer 		opc = MR_DCMD_PR_GET_STATUS;
367177961cf6Sbouyer 		if (mfii_mgmt(sc, opc, NULL, &status, sizeof(status),
367277961cf6Sbouyer 		    MFII_DATA_IN, false))
367377961cf6Sbouyer 			return (EINVAL);
367477961cf6Sbouyer 
367577961cf6Sbouyer 		/* Get device's time. */
367677961cf6Sbouyer 		opc = MR_DCMD_TIME_SECS_GET;
367777961cf6Sbouyer 		if (mfii_mgmt(sc, opc, NULL, &time, sizeof(time),
367877961cf6Sbouyer 		    MFII_DATA_IN, false))
367977961cf6Sbouyer 			return (EINVAL);
368077961cf6Sbouyer 
368177961cf6Sbouyer 		switch (prop.op_mode) {
368277961cf6Sbouyer 		case MFI_PR_OPMODE_AUTO:
368377961cf6Sbouyer 			bp->bp_mode = BIOC_SPMAUTO;
368477961cf6Sbouyer 			bp->bp_autoival = prop.exec_freq;
368577961cf6Sbouyer 			bp->bp_autonext = prop.next_exec;
368677961cf6Sbouyer 			bp->bp_autonow = time;
368777961cf6Sbouyer 			break;
368877961cf6Sbouyer 		case MFI_PR_OPMODE_MANUAL:
368977961cf6Sbouyer 			bp->bp_mode = BIOC_SPMMANUAL;
369077961cf6Sbouyer 			break;
369177961cf6Sbouyer 		case MFI_PR_OPMODE_DISABLED:
369277961cf6Sbouyer 			bp->bp_mode = BIOC_SPMDISABLED;
369377961cf6Sbouyer 			break;
369477961cf6Sbouyer 		default:
369577961cf6Sbouyer 			printf("%s: unknown patrol mode %d\n",
369677961cf6Sbouyer 			    DEVNAME(sc), prop.op_mode);
369777961cf6Sbouyer 			break;
369877961cf6Sbouyer 		}
369977961cf6Sbouyer 
370077961cf6Sbouyer 		switch (status.state) {
370177961cf6Sbouyer 		case MFI_PR_STATE_STOPPED:
370277961cf6Sbouyer 			bp->bp_status = BIOC_SPSSTOPPED;
370377961cf6Sbouyer 			break;
370477961cf6Sbouyer 		case MFI_PR_STATE_READY:
370577961cf6Sbouyer 			bp->bp_status = BIOC_SPSREADY;
370677961cf6Sbouyer 			break;
370777961cf6Sbouyer 		case MFI_PR_STATE_ACTIVE:
370877961cf6Sbouyer 			bp->bp_status = BIOC_SPSACTIVE;
370977961cf6Sbouyer 			break;
371077961cf6Sbouyer 		case MFI_PR_STATE_ABORTED:
371177961cf6Sbouyer 			bp->bp_status = BIOC_SPSABORTED;
371277961cf6Sbouyer 			break;
371377961cf6Sbouyer 		default:
371477961cf6Sbouyer 			printf("%s: unknown patrol state %d\n",
371577961cf6Sbouyer 			    DEVNAME(sc), status.state);
371677961cf6Sbouyer 			break;
371777961cf6Sbouyer 		}
371877961cf6Sbouyer 
371977961cf6Sbouyer 		break;
372077961cf6Sbouyer 
372177961cf6Sbouyer 	default:
3722277d1243Smsaitoh 		DNPRINTF(MFII_D_IOCTL,
3723277d1243Smsaitoh 		    "%s: mfii_ioctl_patrol biocpatrol invalid opcode %x\n",
3724277d1243Smsaitoh 		    DEVNAME(sc), bp->bp_opcode);
372577961cf6Sbouyer 		return (EINVAL);
372677961cf6Sbouyer 	}
372777961cf6Sbouyer 
372877961cf6Sbouyer 	return (rv);
372977961cf6Sbouyer }
373077961cf6Sbouyer #endif
373177961cf6Sbouyer 
3732bfa22340Smaxv static int
mfii_bio_hs(struct mfii_softc * sc,int volid,int type,void * bio_hs)373377961cf6Sbouyer mfii_bio_hs(struct mfii_softc *sc, int volid, int type, void *bio_hs)
373477961cf6Sbouyer {
373577961cf6Sbouyer 	struct mfi_conf		*cfg;
373677961cf6Sbouyer 	struct mfi_hotspare	*hs;
373777961cf6Sbouyer 	struct mfi_pd_details	*pd;
373877961cf6Sbouyer 	struct bioc_disk	*sdhs;
373977961cf6Sbouyer 	struct bioc_vol		*vdhs;
374077961cf6Sbouyer 	struct scsipi_inquiry_data *inqbuf;
374177961cf6Sbouyer 	char			vend[8+16+4+1], *vendp;
374277961cf6Sbouyer 	int			i, rv = EINVAL;
374377961cf6Sbouyer 	uint32_t		size;
374477961cf6Sbouyer 	union mfi_mbox		mbox;
374577961cf6Sbouyer 
374677961cf6Sbouyer 	DNPRINTF(MFII_D_IOCTL, "%s: mfii_vol_hs %d\n", DEVNAME(sc), volid);
374777961cf6Sbouyer 
374877961cf6Sbouyer 	if (!bio_hs)
374977961cf6Sbouyer 		return (EINVAL);
375077961cf6Sbouyer 
375177961cf6Sbouyer 	pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
375277961cf6Sbouyer 
375377961cf6Sbouyer 	/* send single element command to retrieve size for full structure */
375477961cf6Sbouyer 	cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK);
375577961cf6Sbouyer 	if (mfii_mgmt(sc, MR_DCMD_CONF_GET, NULL, cfg, sizeof(*cfg),
375677961cf6Sbouyer 	    MFII_DATA_IN, false))
375777961cf6Sbouyer 		goto freeme;
375877961cf6Sbouyer 
375977961cf6Sbouyer 	size = cfg->mfc_size;
376077961cf6Sbouyer 	free(cfg, M_DEVBUF);
376177961cf6Sbouyer 
376277961cf6Sbouyer 	/* memory for read config */
376377961cf6Sbouyer 	cfg = malloc(size, M_DEVBUF, M_WAITOK|M_ZERO);
376477961cf6Sbouyer 	if (mfii_mgmt(sc, MR_DCMD_CONF_GET, NULL, cfg, size,
376577961cf6Sbouyer 	    MFII_DATA_IN, false))
376677961cf6Sbouyer 		goto freeme;
376777961cf6Sbouyer 
376877961cf6Sbouyer 	/* calculate offset to hs structure */
376977961cf6Sbouyer 	hs = (struct mfi_hotspare *)(
377077961cf6Sbouyer 	    ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) +
377177961cf6Sbouyer 	    cfg->mfc_array_size * cfg->mfc_no_array +
377277961cf6Sbouyer 	    cfg->mfc_ld_size * cfg->mfc_no_ld);
377377961cf6Sbouyer 
377477961cf6Sbouyer 	if (volid < cfg->mfc_no_ld)
377577961cf6Sbouyer 		goto freeme; /* not a hotspare */
377677961cf6Sbouyer 
377777961cf6Sbouyer 	if (volid > (cfg->mfc_no_ld + cfg->mfc_no_hs))
377877961cf6Sbouyer 		goto freeme; /* not a hotspare */
377977961cf6Sbouyer 
378077961cf6Sbouyer 	/* offset into hotspare structure */
378177961cf6Sbouyer 	i = volid - cfg->mfc_no_ld;
378277961cf6Sbouyer 
3783277d1243Smsaitoh 	DNPRINTF(MFII_D_IOCTL,
3784277d1243Smsaitoh 	    "%s: mfii_vol_hs i %d volid %d no_ld %d no_hs %d "
378577961cf6Sbouyer 	    "hs %p cfg %p id %02x\n", DEVNAME(sc), i, volid, cfg->mfc_no_ld,
378677961cf6Sbouyer 	    cfg->mfc_no_hs, hs, cfg, hs[i].mhs_pd.mfp_id);
378777961cf6Sbouyer 
378877961cf6Sbouyer 	/* get pd fields */
378977961cf6Sbouyer 	memset(&mbox, 0, sizeof(mbox));
379077961cf6Sbouyer 	mbox.s[0] = hs[i].mhs_pd.mfp_id;
379177961cf6Sbouyer 	if (mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
379277961cf6Sbouyer 	    MFII_DATA_IN, false)) {
379377961cf6Sbouyer 		DNPRINTF(MFII_D_IOCTL, "%s: mfii_vol_hs illegal PD\n",
379477961cf6Sbouyer 		    DEVNAME(sc));
379577961cf6Sbouyer 		goto freeme;
379677961cf6Sbouyer 	}
379777961cf6Sbouyer 
379877961cf6Sbouyer 	switch (type) {
379977961cf6Sbouyer 	case MFI_MGMT_VD:
380077961cf6Sbouyer 		vdhs = bio_hs;
380177961cf6Sbouyer 		vdhs->bv_status = BIOC_SVONLINE;
380277961cf6Sbouyer 		vdhs->bv_size = pd->mpd_size / 2 * 1024; /* XXX why? */
380377961cf6Sbouyer 		vdhs->bv_level = -1; /* hotspare */
380477961cf6Sbouyer 		vdhs->bv_nodisk = 1;
380577961cf6Sbouyer 		break;
380677961cf6Sbouyer 
380777961cf6Sbouyer 	case MFI_MGMT_SD:
380877961cf6Sbouyer 		sdhs = bio_hs;
380977961cf6Sbouyer 		sdhs->bd_status = BIOC_SDHOTSPARE;
381077961cf6Sbouyer 		sdhs->bd_size = pd->mpd_size / 2 * 1024; /* XXX why? */
381177961cf6Sbouyer 		sdhs->bd_channel = pd->mpd_enc_idx;
381277961cf6Sbouyer 		sdhs->bd_target = pd->mpd_enc_slot;
381377961cf6Sbouyer 		inqbuf = (struct scsipi_inquiry_data *)&pd->mpd_inq_data;
381477961cf6Sbouyer 		vendp = inqbuf->vendor;
381577961cf6Sbouyer 		memcpy(vend, vendp, sizeof vend - 1);
381677961cf6Sbouyer 		vend[sizeof vend - 1] = '\0';
381777961cf6Sbouyer 		strlcpy(sdhs->bd_vendor, vend, sizeof(sdhs->bd_vendor));
381877961cf6Sbouyer 		break;
381977961cf6Sbouyer 
382077961cf6Sbouyer 	default:
382177961cf6Sbouyer 		goto freeme;
382277961cf6Sbouyer 	}
382377961cf6Sbouyer 
382477961cf6Sbouyer 	DNPRINTF(MFII_D_IOCTL, "%s: mfii_vol_hs 6\n", DEVNAME(sc));
382577961cf6Sbouyer 	rv = 0;
382677961cf6Sbouyer freeme:
382777961cf6Sbouyer 	free(pd, M_DEVBUF);
382877961cf6Sbouyer 	free(cfg, M_DEVBUF);
382977961cf6Sbouyer 
383077961cf6Sbouyer 	return (rv);
383177961cf6Sbouyer }
383277961cf6Sbouyer 
383377961cf6Sbouyer #endif /* NBIO > 0 */
383477961cf6Sbouyer 
383577961cf6Sbouyer #define MFI_BBU_SENSORS 4
383677961cf6Sbouyer 
3837bfa22340Smaxv static void
mfii_bbu(struct mfii_softc * sc,envsys_data_t * edata)383877961cf6Sbouyer mfii_bbu(struct mfii_softc *sc, envsys_data_t *edata)
383977961cf6Sbouyer {
384077961cf6Sbouyer 	struct mfi_bbu_status bbu;
384177961cf6Sbouyer 	u_int32_t status;
384277961cf6Sbouyer 	u_int32_t mask;
384377961cf6Sbouyer 	u_int32_t soh_bad;
384477961cf6Sbouyer 	int rv;
384577961cf6Sbouyer 
384677961cf6Sbouyer 	mutex_enter(&sc->sc_lock);
384777961cf6Sbouyer 	rv = mfii_mgmt(sc, MR_DCMD_BBU_GET_STATUS, NULL, &bbu,
384877961cf6Sbouyer 	    sizeof(bbu), MFII_DATA_IN, false);
384977961cf6Sbouyer 	mutex_exit(&sc->sc_lock);
385077961cf6Sbouyer 	if (rv != 0) {
385177961cf6Sbouyer 		edata->state = ENVSYS_SINVALID;
385277961cf6Sbouyer 		edata->value_cur = 0;
385377961cf6Sbouyer 		return;
385477961cf6Sbouyer 	}
385577961cf6Sbouyer 
385677961cf6Sbouyer 	switch (bbu.battery_type) {
385777961cf6Sbouyer 	case MFI_BBU_TYPE_IBBU:
38586c40089cSmsaitoh 	case MFI_BBU_TYPE_IBBU09:
3859d8b90f07Smsaitoh 	case MFI_BBU_TYPE_CVPM02:
386077961cf6Sbouyer 		mask = MFI_BBU_STATE_BAD_IBBU;
386177961cf6Sbouyer 		soh_bad = 0;
386277961cf6Sbouyer 		break;
386377961cf6Sbouyer 	case MFI_BBU_TYPE_BBU:
386477961cf6Sbouyer 		mask = MFI_BBU_STATE_BAD_BBU;
386577961cf6Sbouyer 		soh_bad = (bbu.detail.bbu.is_SOH_good == 0);
386677961cf6Sbouyer 		break;
386777961cf6Sbouyer 
386877961cf6Sbouyer 	case MFI_BBU_TYPE_NONE:
386977961cf6Sbouyer 	default:
387077961cf6Sbouyer 		edata->state = ENVSYS_SCRITICAL;
387177961cf6Sbouyer 		edata->value_cur = 0;
387277961cf6Sbouyer 		return;
387377961cf6Sbouyer 	}
387477961cf6Sbouyer 
387577961cf6Sbouyer 	status = le32toh(bbu.fw_status) & mask;
387677961cf6Sbouyer 	switch (edata->sensor) {
387777961cf6Sbouyer 	case 0:
387877961cf6Sbouyer 		edata->value_cur = (status || soh_bad) ? 0 : 1;
387977961cf6Sbouyer 		edata->state =
388077961cf6Sbouyer 		    edata->value_cur ? ENVSYS_SVALID : ENVSYS_SCRITICAL;
388177961cf6Sbouyer 		return;
388277961cf6Sbouyer 	case 1:
388377961cf6Sbouyer 		edata->value_cur = le16toh(bbu.voltage) * 1000;
388477961cf6Sbouyer 		edata->state = ENVSYS_SVALID;
388577961cf6Sbouyer 		return;
388677961cf6Sbouyer 	case 2:
388777961cf6Sbouyer 		edata->value_cur = (int16_t)le16toh(bbu.current) * 1000;
388877961cf6Sbouyer 		edata->state = ENVSYS_SVALID;
388977961cf6Sbouyer 		return;
389077961cf6Sbouyer 	case 3:
3891277d1243Smsaitoh 		edata->value_cur =
3892277d1243Smsaitoh 		    le16toh(bbu.temperature) * 1000000 + 273150000;
389377961cf6Sbouyer 		edata->state = ENVSYS_SVALID;
389477961cf6Sbouyer 		return;
389577961cf6Sbouyer 	}
389677961cf6Sbouyer }
389777961cf6Sbouyer 
3898bfa22340Smaxv static void
mfii_refresh_ld_sensor(struct mfii_softc * sc,envsys_data_t * edata)389977961cf6Sbouyer mfii_refresh_ld_sensor(struct mfii_softc *sc, envsys_data_t *edata)
390077961cf6Sbouyer {
390177961cf6Sbouyer 	struct bioc_vol bv;
390277961cf6Sbouyer 	int error;
390377961cf6Sbouyer 
390477961cf6Sbouyer 	memset(&bv, 0, sizeof(bv));
390577961cf6Sbouyer 	bv.bv_volid = edata->sensor - MFI_BBU_SENSORS;
390677961cf6Sbouyer 	mutex_enter(&sc->sc_lock);
390777961cf6Sbouyer 	error = mfii_ioctl_vol(sc, &bv);
390877961cf6Sbouyer 	mutex_exit(&sc->sc_lock);
390977961cf6Sbouyer 	if (error)
391077961cf6Sbouyer 		bv.bv_status = BIOC_SVINVALID;
391177961cf6Sbouyer 	bio_vol_to_envsys(edata, &bv);
391277961cf6Sbouyer }
391377961cf6Sbouyer 
3914bfa22340Smaxv static void
mfii_init_ld_sensor(struct mfii_softc * sc,envsys_data_t * sensor,int i)391577961cf6Sbouyer mfii_init_ld_sensor(struct mfii_softc *sc, envsys_data_t *sensor, int i)
391677961cf6Sbouyer {
391777961cf6Sbouyer 	sensor->units = ENVSYS_DRIVE;
391877961cf6Sbouyer 	sensor->state = ENVSYS_SINVALID;
391977961cf6Sbouyer 	sensor->value_cur = ENVSYS_DRIVE_EMPTY;
392077961cf6Sbouyer 	/* Enable monitoring for drive state changes */
392177961cf6Sbouyer 	sensor->flags |= ENVSYS_FMONSTCHANGED;
392277961cf6Sbouyer 	snprintf(sensor->desc, sizeof(sensor->desc), "%s:%d", DEVNAME(sc), i);
392377961cf6Sbouyer }
392477961cf6Sbouyer 
392577961cf6Sbouyer static void
mfii_attach_sensor(struct mfii_softc * sc,envsys_data_t * s)392677961cf6Sbouyer mfii_attach_sensor(struct mfii_softc *sc, envsys_data_t *s)
392777961cf6Sbouyer {
392877961cf6Sbouyer 	if (sysmon_envsys_sensor_attach(sc->sc_sme, s))
392977961cf6Sbouyer 		aprint_error_dev(sc->sc_dev,
393077961cf6Sbouyer 		    "failed to attach sensor %s\n", s->desc);
393177961cf6Sbouyer }
393277961cf6Sbouyer 
3933bfa22340Smaxv static int
mfii_create_sensors(struct mfii_softc * sc)393477961cf6Sbouyer mfii_create_sensors(struct mfii_softc *sc)
393577961cf6Sbouyer {
393677961cf6Sbouyer 	int i, rv;
3937c6bee2b8Smsaitoh 	const int nsensors = MFI_BBU_SENSORS + MFII_MAX_LD_EXT;
393877961cf6Sbouyer 
393977961cf6Sbouyer 	sc->sc_sme = sysmon_envsys_create();
394077961cf6Sbouyer 	sc->sc_sensors = malloc(sizeof(envsys_data_t) * nsensors,
394170747dc1Schs 	    M_DEVBUF, M_WAITOK | M_ZERO);
394277961cf6Sbouyer 
394377961cf6Sbouyer 	/* BBU */
394477961cf6Sbouyer 	sc->sc_sensors[0].units = ENVSYS_INDICATOR;
394577961cf6Sbouyer 	sc->sc_sensors[0].state = ENVSYS_SINVALID;
394677961cf6Sbouyer 	sc->sc_sensors[0].value_cur = 0;
394777961cf6Sbouyer 	sc->sc_sensors[1].units = ENVSYS_SVOLTS_DC;
394877961cf6Sbouyer 	sc->sc_sensors[1].state = ENVSYS_SINVALID;
394977961cf6Sbouyer 	sc->sc_sensors[1].value_cur = 0;
395077961cf6Sbouyer 	sc->sc_sensors[2].units = ENVSYS_SAMPS;
395177961cf6Sbouyer 	sc->sc_sensors[2].state = ENVSYS_SINVALID;
395277961cf6Sbouyer 	sc->sc_sensors[2].value_cur = 0;
395377961cf6Sbouyer 	sc->sc_sensors[3].units = ENVSYS_STEMP;
395477961cf6Sbouyer 	sc->sc_sensors[3].state = ENVSYS_SINVALID;
395577961cf6Sbouyer 	sc->sc_sensors[3].value_cur = 0;
395677961cf6Sbouyer 
395777961cf6Sbouyer 	if (ISSET(le32toh(sc->sc_info.mci_hw_present), MFI_INFO_HW_BBU)) {
395877961cf6Sbouyer 		sc->sc_bbuok = true;
395977961cf6Sbouyer 		sc->sc_sensors[0].flags |= ENVSYS_FMONCRITICAL;
396077961cf6Sbouyer 		snprintf(sc->sc_sensors[0].desc, sizeof(sc->sc_sensors[0].desc),
396177961cf6Sbouyer 		    "%s BBU state", DEVNAME(sc));
396277961cf6Sbouyer 		snprintf(sc->sc_sensors[1].desc, sizeof(sc->sc_sensors[1].desc),
396377961cf6Sbouyer 		    "%s BBU voltage", DEVNAME(sc));
396477961cf6Sbouyer 		snprintf(sc->sc_sensors[2].desc, sizeof(sc->sc_sensors[2].desc),
396577961cf6Sbouyer 		    "%s BBU current", DEVNAME(sc));
396677961cf6Sbouyer 		snprintf(sc->sc_sensors[3].desc, sizeof(sc->sc_sensors[3].desc),
396777961cf6Sbouyer 		    "%s BBU temperature", DEVNAME(sc));
396877961cf6Sbouyer 		for (i = 0; i < MFI_BBU_SENSORS; i++) {
396977961cf6Sbouyer 			mfii_attach_sensor(sc, &sc->sc_sensors[i]);
397077961cf6Sbouyer 		}
397177961cf6Sbouyer 	}
397277961cf6Sbouyer 
397377961cf6Sbouyer 	for (i = 0; i < sc->sc_ld_list.mll_no_ld; i++) {
397477961cf6Sbouyer 		mfii_init_ld_sensor(sc, &sc->sc_sensors[i + MFI_BBU_SENSORS], i);
397577961cf6Sbouyer 		mfii_attach_sensor(sc, &sc->sc_sensors[i + MFI_BBU_SENSORS]);
397677961cf6Sbouyer 	}
397777961cf6Sbouyer 
397877961cf6Sbouyer 	sc->sc_sme->sme_name = DEVNAME(sc);
397977961cf6Sbouyer 	sc->sc_sme->sme_cookie = sc;
398077961cf6Sbouyer 	sc->sc_sme->sme_refresh = mfii_refresh_sensor;
398177961cf6Sbouyer 	rv = sysmon_envsys_register(sc->sc_sme);
398277961cf6Sbouyer 	if (rv) {
398377961cf6Sbouyer 		aprint_error_dev(sc->sc_dev,
398477961cf6Sbouyer 		    "unable to register with sysmon (rv = %d)\n", rv);
3985eba904eeSmsaitoh 		sysmon_envsys_destroy(sc->sc_sme);
3986eba904eeSmsaitoh 		sc->sc_sme = NULL;
398777961cf6Sbouyer 	}
398877961cf6Sbouyer 	return rv;
398977961cf6Sbouyer 
399077961cf6Sbouyer }
399177961cf6Sbouyer 
399277961cf6Sbouyer static int
mfii_destroy_sensors(struct mfii_softc * sc)399377961cf6Sbouyer mfii_destroy_sensors(struct mfii_softc *sc)
399477961cf6Sbouyer {
399577961cf6Sbouyer 	if (sc->sc_sme == NULL)
399677961cf6Sbouyer 		return 0;
399777961cf6Sbouyer 	sysmon_envsys_unregister(sc->sc_sme);
399877961cf6Sbouyer 	sc->sc_sme = NULL;
399977961cf6Sbouyer 	free(sc->sc_sensors, M_DEVBUF);
400077961cf6Sbouyer 	return 0;
400177961cf6Sbouyer }
400277961cf6Sbouyer 
4003bfa22340Smaxv static void
mfii_refresh_sensor(struct sysmon_envsys * sme,envsys_data_t * edata)400477961cf6Sbouyer mfii_refresh_sensor(struct sysmon_envsys *sme, envsys_data_t *edata)
400577961cf6Sbouyer {
400677961cf6Sbouyer 	struct mfii_softc	*sc = sme->sme_cookie;
400777961cf6Sbouyer 
4008c6bee2b8Smsaitoh 	if (edata->sensor >= MFI_BBU_SENSORS + MFII_MAX_LD_EXT)
400977961cf6Sbouyer 		return;
401077961cf6Sbouyer 
401177961cf6Sbouyer 	if (edata->sensor < MFI_BBU_SENSORS) {
401277961cf6Sbouyer 		if (sc->sc_bbuok)
401377961cf6Sbouyer 			mfii_bbu(sc, edata);
401477961cf6Sbouyer 	} else {
401577961cf6Sbouyer 		mfii_refresh_ld_sensor(sc, edata);
401677961cf6Sbouyer 	}
401777961cf6Sbouyer }
4018