Home | History | Annotate | Line # | Download | only in pci
mfii.c revision 1.4.2.3
      1  1.4.2.3    martin /* $NetBSD: mfii.c,v 1.4.2.3 2020/04/08 14:08:09 martin Exp $ */
      2  1.4.2.2  christos /* $OpenBSD: mfii.c,v 1.58 2018/08/14 05:22:21 jmatthew Exp $ */
      3  1.4.2.2  christos 
      4  1.4.2.2  christos /*
      5  1.4.2.2  christos  * Copyright (c) 2018 Manuel Bouyer <Manuel.Bouyer (at) lip6.fr>
      6  1.4.2.2  christos  * Copyright (c) 2012 David Gwynne <dlg (at) openbsd.org>
      7  1.4.2.2  christos  *
      8  1.4.2.2  christos  * Permission to use, copy, modify, and distribute this software for any
      9  1.4.2.2  christos  * purpose with or without fee is hereby granted, provided that the above
     10  1.4.2.2  christos  * copyright notice and this permission notice appear in all copies.
     11  1.4.2.2  christos  *
     12  1.4.2.2  christos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     13  1.4.2.2  christos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     14  1.4.2.2  christos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     15  1.4.2.2  christos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     16  1.4.2.2  christos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     17  1.4.2.2  christos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     18  1.4.2.2  christos  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     19  1.4.2.2  christos  */
     20  1.4.2.2  christos 
     21  1.4.2.2  christos #include <sys/cdefs.h>
     22  1.4.2.3    martin __KERNEL_RCSID(0, "$NetBSD: mfii.c,v 1.4.2.3 2020/04/08 14:08:09 martin Exp $");
     23  1.4.2.2  christos 
     24  1.4.2.2  christos #include "bio.h"
     25  1.4.2.2  christos 
     26  1.4.2.2  christos #include <sys/atomic.h>
     27  1.4.2.2  christos #include <sys/param.h>
     28  1.4.2.2  christos #include <sys/systm.h>
     29  1.4.2.2  christos #include <sys/buf.h>
     30  1.4.2.2  christos #include <sys/ioctl.h>
     31  1.4.2.2  christos #include <sys/device.h>
     32  1.4.2.2  christos #include <sys/kernel.h>
     33  1.4.2.2  christos #include <sys/proc.h>
     34  1.4.2.2  christos #include <sys/cpu.h>
     35  1.4.2.2  christos #include <sys/conf.h>
     36  1.4.2.2  christos #include <sys/kauth.h>
     37  1.4.2.2  christos #include <sys/workqueue.h>
     38  1.4.2.2  christos #include <sys/malloc.h>
     39  1.4.2.2  christos 
     40  1.4.2.2  christos #include <uvm/uvm_param.h>
     41  1.4.2.2  christos 
     42  1.4.2.2  christos #include <dev/pci/pcidevs.h>
     43  1.4.2.2  christos #include <dev/pci/pcivar.h>
     44  1.4.2.2  christos 
     45  1.4.2.2  christos #include <sys/bus.h>
     46  1.4.2.2  christos 
     47  1.4.2.2  christos #include <dev/sysmon/sysmonvar.h>
     48  1.4.2.2  christos #include <sys/envsys.h>
     49  1.4.2.2  christos 
     50  1.4.2.2  christos #include <dev/scsipi/scsipi_all.h>
     51  1.4.2.2  christos #include <dev/scsipi/scsi_all.h>
     52  1.4.2.2  christos #include <dev/scsipi/scsi_spc.h>
     53  1.4.2.2  christos #include <dev/scsipi/scsipi_disk.h>
     54  1.4.2.2  christos #include <dev/scsipi/scsi_disk.h>
     55  1.4.2.2  christos #include <dev/scsipi/scsiconf.h>
     56  1.4.2.2  christos 
     57  1.4.2.2  christos #if NBIO > 0
     58  1.4.2.2  christos #include <dev/biovar.h>
     59  1.4.2.2  christos #endif /* NBIO > 0 */
     60  1.4.2.2  christos 
     61  1.4.2.2  christos #include <dev/ic/mfireg.h>
     62  1.4.2.2  christos #include <dev/pci/mpiireg.h>
     63  1.4.2.2  christos 
     64  1.4.2.2  christos #define	MFII_BAR		0x14
     65  1.4.2.2  christos #define MFII_BAR_35		0x10
     66  1.4.2.2  christos #define	MFII_PCI_MEMSIZE	0x2000 /* 8k */
     67  1.4.2.2  christos 
     68  1.4.2.2  christos #define MFII_OSTS_INTR_VALID	0x00000009
     69  1.4.2.2  christos #define MFII_RPI		0x6c /* reply post host index */
     70  1.4.2.2  christos #define MFII_OSP2		0xb4 /* outbound scratch pad 2 */
     71  1.4.2.2  christos #define MFII_OSP3		0xb8 /* outbound scratch pad 3 */
     72  1.4.2.2  christos 
     73  1.4.2.2  christos #define MFII_REQ_TYPE_SCSI	MPII_REQ_DESCR_SCSI_IO
     74  1.4.2.2  christos #define MFII_REQ_TYPE_LDIO	(0x7 << 1)
     75  1.4.2.2  christos #define MFII_REQ_TYPE_MFA	(0x1 << 1)
     76  1.4.2.2  christos #define MFII_REQ_TYPE_NO_LOCK	(0x2 << 1)
     77  1.4.2.2  christos #define MFII_REQ_TYPE_HI_PRI	(0x6 << 1)
     78  1.4.2.2  christos 
     79  1.4.2.2  christos #define MFII_REQ_MFA(_a)	htole64((_a) | MFII_REQ_TYPE_MFA)
     80  1.4.2.2  christos 
     81  1.4.2.2  christos #define MFII_FUNCTION_PASSTHRU_IO			(0xf0)
     82  1.4.2.2  christos #define MFII_FUNCTION_LDIO_REQUEST			(0xf1)
     83  1.4.2.2  christos 
     84  1.4.2.2  christos #define MFII_MAX_CHAIN_UNIT	0x00400000
     85  1.4.2.2  christos #define MFII_MAX_CHAIN_MASK	0x000003E0
     86  1.4.2.2  christos #define MFII_MAX_CHAIN_SHIFT	5
     87  1.4.2.2  christos 
     88  1.4.2.2  christos #define MFII_256K_IO		128
     89  1.4.2.2  christos #define MFII_1MB_IO		(MFII_256K_IO * 4)
     90  1.4.2.2  christos 
     91  1.4.2.2  christos #define MFII_CHAIN_FRAME_MIN	1024
     92  1.4.2.2  christos 
     93  1.4.2.2  christos struct mfii_request_descr {
     94  1.4.2.2  christos 	u_int8_t	flags;
     95  1.4.2.2  christos 	u_int8_t	msix_index;
     96  1.4.2.2  christos 	u_int16_t	smid;
     97  1.4.2.2  christos 
     98  1.4.2.2  christos 	u_int16_t	lmid;
     99  1.4.2.2  christos 	u_int16_t	dev_handle;
    100  1.4.2.2  christos } __packed;
    101  1.4.2.2  christos 
    102  1.4.2.2  christos #define MFII_RAID_CTX_IO_TYPE_SYSPD	(0x1 << 4)
    103  1.4.2.2  christos #define MFII_RAID_CTX_TYPE_CUDA		(0x2 << 4)
    104  1.4.2.2  christos 
    105  1.4.2.2  christos struct mfii_raid_context {
    106  1.4.2.2  christos 	u_int8_t	type_nseg;
    107  1.4.2.2  christos 	u_int8_t	_reserved1;
    108  1.4.2.2  christos 	u_int16_t	timeout_value;
    109  1.4.2.2  christos 
    110  1.4.2.2  christos 	u_int16_t	reg_lock_flags;
    111  1.4.2.2  christos #define MFII_RAID_CTX_RL_FLAGS_SEQNO_EN	(0x08)
    112  1.4.2.2  christos #define MFII_RAID_CTX_RL_FLAGS_CPU0	(0x00)
    113  1.4.2.2  christos #define MFII_RAID_CTX_RL_FLAGS_CPU1	(0x10)
    114  1.4.2.2  christos #define MFII_RAID_CTX_RL_FLAGS_CUDA	(0x80)
    115  1.4.2.2  christos 
    116  1.4.2.2  christos #define MFII_RAID_CTX_ROUTING_FLAGS_SQN	(1 << 4)
    117  1.4.2.2  christos #define MFII_RAID_CTX_ROUTING_FLAGS_CPU0 0
    118  1.4.2.2  christos 	u_int16_t	virtual_disk_target_id;
    119  1.4.2.2  christos 
    120  1.4.2.2  christos 	u_int64_t	reg_lock_row_lba;
    121  1.4.2.2  christos 
    122  1.4.2.2  christos 	u_int32_t	reg_lock_length;
    123  1.4.2.2  christos 
    124  1.4.2.2  christos 	u_int16_t	next_lm_id;
    125  1.4.2.2  christos 	u_int8_t	ex_status;
    126  1.4.2.2  christos 	u_int8_t	status;
    127  1.4.2.2  christos 
    128  1.4.2.2  christos 	u_int8_t	raid_flags;
    129  1.4.2.2  christos 	u_int8_t	num_sge;
    130  1.4.2.2  christos 	u_int16_t	config_seq_num;
    131  1.4.2.2  christos 
    132  1.4.2.2  christos 	u_int8_t	span_arm;
    133  1.4.2.2  christos 	u_int8_t	_reserved3[3];
    134  1.4.2.2  christos } __packed;
    135  1.4.2.2  christos 
    136  1.4.2.2  christos struct mfii_sge {
    137  1.4.2.2  christos 	u_int64_t	sg_addr;
    138  1.4.2.2  christos 	u_int32_t	sg_len;
    139  1.4.2.2  christos 	u_int16_t	_reserved;
    140  1.4.2.2  christos 	u_int8_t	sg_next_chain_offset;
    141  1.4.2.2  christos 	u_int8_t	sg_flags;
    142  1.4.2.2  christos } __packed;
    143  1.4.2.2  christos 
    144  1.4.2.2  christos #define MFII_SGE_ADDR_MASK		(0x03)
    145  1.4.2.2  christos #define MFII_SGE_ADDR_SYSTEM		(0x00)
    146  1.4.2.2  christos #define MFII_SGE_ADDR_IOCDDR		(0x01)
    147  1.4.2.2  christos #define MFII_SGE_ADDR_IOCPLB		(0x02)
    148  1.4.2.2  christos #define MFII_SGE_ADDR_IOCPLBNTA		(0x03)
    149  1.4.2.2  christos #define MFII_SGE_END_OF_LIST		(0x40)
    150  1.4.2.2  christos #define MFII_SGE_CHAIN_ELEMENT		(0x80)
    151  1.4.2.2  christos 
    152  1.4.2.2  christos #define MFII_REQUEST_SIZE	256
    153  1.4.2.2  christos 
    154  1.4.2.2  christos #define MR_DCMD_LD_MAP_GET_INFO			0x0300e101
    155  1.4.2.2  christos 
    156  1.4.2.2  christos #define MFII_MAX_ROW		32
    157  1.4.2.2  christos #define MFII_MAX_ARRAY		128
    158  1.4.2.2  christos 
    159  1.4.2.2  christos struct mfii_array_map {
    160  1.4.2.2  christos 	uint16_t		mam_pd[MFII_MAX_ROW];
    161  1.4.2.2  christos } __packed;
    162  1.4.2.2  christos 
    163  1.4.2.2  christos struct mfii_dev_handle {
    164  1.4.2.2  christos 	uint16_t		mdh_cur_handle;
    165  1.4.2.2  christos 	uint8_t			mdh_valid;
    166  1.4.2.2  christos 	uint8_t			mdh_reserved;
    167  1.4.2.2  christos 	uint16_t		mdh_handle[2];
    168  1.4.2.2  christos } __packed;
    169  1.4.2.2  christos 
    170  1.4.2.2  christos struct mfii_ld_map {
    171  1.4.2.2  christos 	uint32_t		mlm_total_size;
    172  1.4.2.2  christos 	uint32_t		mlm_reserved1[5];
    173  1.4.2.2  christos 	uint32_t		mlm_num_lds;
    174  1.4.2.2  christos 	uint32_t		mlm_reserved2;
    175  1.4.2.2  christos 	uint8_t			mlm_tgtid_to_ld[2 * MFI_MAX_LD];
    176  1.4.2.2  christos 	uint8_t			mlm_pd_timeout;
    177  1.4.2.2  christos 	uint8_t			mlm_reserved3[7];
    178  1.4.2.2  christos 	struct mfii_array_map	mlm_am[MFII_MAX_ARRAY];
    179  1.4.2.2  christos 	struct mfii_dev_handle	mlm_dev_handle[MFI_MAX_PD];
    180  1.4.2.2  christos } __packed;
    181  1.4.2.2  christos 
    182  1.4.2.2  christos struct mfii_task_mgmt {
    183  1.4.2.2  christos 	union {
    184  1.4.2.2  christos 		uint8_t			request[128];
    185  1.4.2.2  christos 		struct mpii_msg_scsi_task_request
    186  1.4.2.2  christos 					mpii_request;
    187  1.4.2.2  christos 	} __packed __aligned(8);
    188  1.4.2.2  christos 
    189  1.4.2.2  christos 	union {
    190  1.4.2.2  christos 		uint8_t			reply[128];
    191  1.4.2.2  christos 		uint32_t		flags;
    192  1.4.2.2  christos #define MFII_TASK_MGMT_FLAGS_LD				(1 << 0)
    193  1.4.2.2  christos #define MFII_TASK_MGMT_FLAGS_PD				(1 << 1)
    194  1.4.2.2  christos 		struct mpii_msg_scsi_task_reply
    195  1.4.2.2  christos 					mpii_reply;
    196  1.4.2.2  christos 	} __packed __aligned(8);
    197  1.4.2.2  christos } __packed __aligned(8);
    198  1.4.2.2  christos 
    199  1.4.2.2  christos /* We currently don't know the full details of the following struct */
    200  1.4.2.2  christos struct mfii_foreign_scan_cfg {
    201  1.4.2.2  christos         char data[24];
    202  1.4.2.2  christos } __packed;
    203  1.4.2.2  christos 
    204  1.4.2.2  christos struct mfii_foreign_scan_info {
    205  1.4.2.2  christos 	uint32_t count; /* Number of foreign configs found */
    206  1.4.2.2  christos 	struct mfii_foreign_scan_cfg cfgs[8];
    207  1.4.2.2  christos } __packed;
    208  1.4.2.2  christos 
    209  1.4.2.2  christos struct mfii_dmamem {
    210  1.4.2.2  christos 	bus_dmamap_t		mdm_map;
    211  1.4.2.2  christos 	bus_dma_segment_t	mdm_seg;
    212  1.4.2.2  christos 	size_t			mdm_size;
    213  1.4.2.2  christos 	void *			mdm_kva;
    214  1.4.2.2  christos };
    215  1.4.2.2  christos #define MFII_DMA_MAP(_mdm)	((_mdm)->mdm_map)
    216  1.4.2.2  christos #define MFII_DMA_LEN(_mdm)	((_mdm)->mdm_size)
    217  1.4.2.2  christos #define MFII_DMA_DVA(_mdm)	((u_int64_t)(_mdm)->mdm_map->dm_segs[0].ds_addr)
    218  1.4.2.2  christos #define MFII_DMA_KVA(_mdm)	((void *)(_mdm)->mdm_kva)
    219  1.4.2.2  christos 
    220  1.4.2.2  christos struct mfii_softc;
    221  1.4.2.2  christos 
    222  1.4.2.2  christos typedef enum mfii_direction {
    223  1.4.2.2  christos 	MFII_DATA_NONE = 0,
    224  1.4.2.2  christos 	MFII_DATA_IN,
    225  1.4.2.2  christos 	MFII_DATA_OUT
    226  1.4.2.2  christos } mfii_direction_t;
    227  1.4.2.2  christos 
    228  1.4.2.2  christos struct mfii_ccb {
    229  1.4.2.2  christos 	struct mfii_softc	*ccb_sc;
    230  1.4.2.2  christos 	void			*ccb_request;
    231  1.4.2.2  christos 	u_int64_t		ccb_request_dva;
    232  1.4.2.2  christos 	bus_addr_t		ccb_request_offset;
    233  1.4.2.2  christos 
    234  1.4.2.2  christos 	void			*ccb_mfi;
    235  1.4.2.2  christos 	u_int64_t		ccb_mfi_dva;
    236  1.4.2.2  christos 	bus_addr_t		ccb_mfi_offset;
    237  1.4.2.2  christos 
    238  1.4.2.2  christos 	struct mfi_sense	*ccb_sense;
    239  1.4.2.2  christos 	u_int64_t		ccb_sense_dva;
    240  1.4.2.2  christos 	bus_addr_t		ccb_sense_offset;
    241  1.4.2.2  christos 
    242  1.4.2.2  christos 	struct mfii_sge		*ccb_sgl;
    243  1.4.2.2  christos 	u_int64_t		ccb_sgl_dva;
    244  1.4.2.2  christos 	bus_addr_t		ccb_sgl_offset;
    245  1.4.2.2  christos 	u_int			ccb_sgl_len;
    246  1.4.2.2  christos 
    247  1.4.2.2  christos 	struct mfii_request_descr ccb_req;
    248  1.4.2.2  christos 
    249  1.4.2.2  christos 	bus_dmamap_t		ccb_dmamap64;
    250  1.4.2.2  christos 	bus_dmamap_t		ccb_dmamap32;
    251  1.4.2.2  christos 	bool			ccb_dma64;
    252  1.4.2.2  christos 
    253  1.4.2.2  christos 	/* data for sgl */
    254  1.4.2.2  christos 	void			*ccb_data;
    255  1.4.2.2  christos 	size_t			ccb_len;
    256  1.4.2.2  christos 
    257  1.4.2.2  christos 	mfii_direction_t	ccb_direction;
    258  1.4.2.2  christos 
    259  1.4.2.2  christos 	void			*ccb_cookie;
    260  1.4.2.2  christos 	kmutex_t		ccb_mtx;
    261  1.4.2.2  christos 	kcondvar_t		ccb_cv;
    262  1.4.2.2  christos 	void			(*ccb_done)(struct mfii_softc *,
    263  1.4.2.2  christos 				    struct mfii_ccb *);
    264  1.4.2.2  christos 
    265  1.4.2.2  christos 	u_int32_t		ccb_flags;
    266  1.4.2.2  christos #define MFI_CCB_F_ERR			(1<<0)
    267  1.4.2.2  christos 	u_int			ccb_smid;
    268  1.4.2.2  christos 	SIMPLEQ_ENTRY(mfii_ccb)	ccb_link;
    269  1.4.2.2  christos };
    270  1.4.2.2  christos SIMPLEQ_HEAD(mfii_ccb_list, mfii_ccb);
    271  1.4.2.2  christos 
    272  1.4.2.2  christos struct mfii_iop {
    273  1.4.2.2  christos 	int bar;
    274  1.4.2.2  christos 	int num_sge_loc;
    275  1.4.2.2  christos #define MFII_IOP_NUM_SGE_LOC_ORIG	0
    276  1.4.2.2  christos #define MFII_IOP_NUM_SGE_LOC_35		1
    277  1.4.2.2  christos 	u_int16_t ldio_ctx_reg_lock_flags;
    278  1.4.2.2  christos 	u_int8_t ldio_req_type;
    279  1.4.2.2  christos 	u_int8_t ldio_ctx_type_nseg;
    280  1.4.2.2  christos 	u_int8_t sge_flag_chain;
    281  1.4.2.2  christos 	u_int8_t sge_flag_eol;
    282  1.4.2.2  christos };
    283  1.4.2.2  christos 
    284  1.4.2.2  christos struct mfii_softc {
    285  1.4.2.2  christos 	device_t		sc_dev;
    286  1.4.2.2  christos 	struct scsipi_channel   sc_chan;
    287  1.4.2.2  christos 	struct scsipi_adapter   sc_adapt;
    288  1.4.2.2  christos 
    289  1.4.2.2  christos 	const struct mfii_iop	*sc_iop;
    290  1.4.2.2  christos 
    291  1.4.2.2  christos 	pci_chipset_tag_t	sc_pc;
    292  1.4.2.2  christos 	pcitag_t		sc_tag;
    293  1.4.2.2  christos 
    294  1.4.2.2  christos 	bus_space_tag_t		sc_iot;
    295  1.4.2.2  christos 	bus_space_handle_t	sc_ioh;
    296  1.4.2.2  christos 	bus_size_t		sc_ios;
    297  1.4.2.2  christos 	bus_dma_tag_t		sc_dmat;
    298  1.4.2.2  christos 	bus_dma_tag_t		sc_dmat64;
    299  1.4.2.2  christos 	bool			sc_64bit_dma;
    300  1.4.2.2  christos 
    301  1.4.2.2  christos 	void			*sc_ih;
    302  1.4.2.2  christos 
    303  1.4.2.2  christos 	kmutex_t		sc_ccb_mtx;
    304  1.4.2.2  christos 	kmutex_t		sc_post_mtx;
    305  1.4.2.2  christos 
    306  1.4.2.2  christos 	u_int			sc_max_fw_cmds;
    307  1.4.2.2  christos 	u_int			sc_max_cmds;
    308  1.4.2.2  christos 	u_int			sc_max_sgl;
    309  1.4.2.2  christos 
    310  1.4.2.2  christos 	u_int			sc_reply_postq_depth;
    311  1.4.2.2  christos 	u_int			sc_reply_postq_index;
    312  1.4.2.2  christos 	kmutex_t		sc_reply_postq_mtx;
    313  1.4.2.2  christos 	struct mfii_dmamem	*sc_reply_postq;
    314  1.4.2.2  christos 
    315  1.4.2.2  christos 	struct mfii_dmamem	*sc_requests;
    316  1.4.2.2  christos 	struct mfii_dmamem	*sc_mfi;
    317  1.4.2.2  christos 	struct mfii_dmamem	*sc_sense;
    318  1.4.2.2  christos 	struct mfii_dmamem	*sc_sgl;
    319  1.4.2.2  christos 
    320  1.4.2.2  christos 	struct mfii_ccb		*sc_ccb;
    321  1.4.2.2  christos 	struct mfii_ccb_list	sc_ccb_freeq;
    322  1.4.2.2  christos 
    323  1.4.2.2  christos 	struct mfii_ccb		*sc_aen_ccb;
    324  1.4.2.2  christos 	struct workqueue	*sc_aen_wq;
    325  1.4.2.2  christos 	struct work		sc_aen_work;
    326  1.4.2.2  christos 
    327  1.4.2.2  christos 	kmutex_t		sc_abort_mtx;
    328  1.4.2.2  christos 	struct mfii_ccb_list	sc_abort_list;
    329  1.4.2.2  christos 	struct workqueue	*sc_abort_wq;
    330  1.4.2.2  christos 	struct work		sc_abort_work;
    331  1.4.2.2  christos 
    332  1.4.2.2  christos 	/* save some useful information for logical drives that is missing
    333  1.4.2.2  christos 	 * in sc_ld_list
    334  1.4.2.2  christos 	 */
    335  1.4.2.2  christos 	struct {
    336  1.4.2.2  christos 		bool		ld_present;
    337  1.4.2.2  christos 		char		ld_dev[16];	/* device name sd? */
    338  1.4.2.2  christos 	}			sc_ld[MFI_MAX_LD];
    339  1.4.2.2  christos 	int			sc_target_lds[MFI_MAX_LD];
    340  1.4.2.2  christos 
    341  1.4.2.2  christos 	/* bio */
    342  1.4.2.2  christos 	struct mfi_conf	 *sc_cfg;
    343  1.4.2.2  christos 	struct mfi_ctrl_info    sc_info;
    344  1.4.2.2  christos 	struct mfi_ld_list	sc_ld_list;
    345  1.4.2.2  christos 	struct mfi_ld_details	*sc_ld_details; /* array to all logical disks */
    346  1.4.2.2  christos 	int			sc_no_pd; /* used physical disks */
    347  1.4.2.2  christos 	int			sc_ld_sz; /* sizeof sc_ld_details */
    348  1.4.2.2  christos 
    349  1.4.2.2  christos 	/* mgmt lock */
    350  1.4.2.2  christos 	kmutex_t		sc_lock;
    351  1.4.2.2  christos 	bool			sc_running;
    352  1.4.2.2  christos 
    353  1.4.2.2  christos 	/* sensors */
    354  1.4.2.2  christos 	struct sysmon_envsys	*sc_sme;
    355  1.4.2.2  christos 	envsys_data_t		*sc_sensors;
    356  1.4.2.2  christos 	bool			sc_bbuok;
    357  1.4.2.2  christos 
    358  1.4.2.2  christos 	device_t		sc_child;
    359  1.4.2.2  christos };
    360  1.4.2.2  christos 
    361  1.4.2.2  christos // #define MFII_DEBUG
    362  1.4.2.2  christos #ifdef MFII_DEBUG
    363  1.4.2.2  christos #define DPRINTF(x...)		do { if (mfii_debug) printf(x); } while(0)
    364  1.4.2.2  christos #define DNPRINTF(n,x...)	do { if (mfii_debug & n) printf(x); } while(0)
    365  1.4.2.2  christos #define	MFII_D_CMD		0x0001
    366  1.4.2.2  christos #define	MFII_D_INTR		0x0002
    367  1.4.2.2  christos #define	MFII_D_MISC		0x0004
    368  1.4.2.2  christos #define	MFII_D_DMA		0x0008
    369  1.4.2.2  christos #define	MFII_D_IOCTL		0x0010
    370  1.4.2.2  christos #define	MFII_D_RW		0x0020
    371  1.4.2.2  christos #define	MFII_D_MEM		0x0040
    372  1.4.2.2  christos #define	MFII_D_CCB		0x0080
    373  1.4.2.2  christos uint32_t	mfii_debug = 0
    374  1.4.2.2  christos /*		    | MFII_D_CMD */
    375  1.4.2.2  christos /*		    | MFII_D_INTR */
    376  1.4.2.2  christos 	    	    | MFII_D_MISC
    377  1.4.2.2  christos /*		    | MFII_D_DMA */
    378  1.4.2.2  christos /*		    | MFII_D_IOCTL */
    379  1.4.2.2  christos /*		    | MFII_D_RW */
    380  1.4.2.2  christos /*		    | MFII_D_MEM */
    381  1.4.2.2  christos /*		    | MFII_D_CCB */
    382  1.4.2.2  christos 		;
    383  1.4.2.2  christos #else
    384  1.4.2.2  christos #define DPRINTF(x...)
    385  1.4.2.2  christos #define DNPRINTF(n,x...)
    386  1.4.2.2  christos #endif
    387  1.4.2.2  christos 
    388  1.4.2.3    martin static int	mfii_match(device_t, cfdata_t, void *);
    389  1.4.2.3    martin static void	mfii_attach(device_t, device_t, void *);
    390  1.4.2.3    martin static int	mfii_detach(device_t, int);
    391  1.4.2.3    martin static int	mfii_rescan(device_t, const char *, const int *);
    392  1.4.2.3    martin static void	mfii_childdetached(device_t, device_t);
    393  1.4.2.2  christos static bool	mfii_suspend(device_t, const pmf_qual_t *);
    394  1.4.2.2  christos static bool	mfii_resume(device_t, const pmf_qual_t *);
    395  1.4.2.2  christos static bool	mfii_shutdown(device_t, int);
    396  1.4.2.2  christos 
    397  1.4.2.2  christos 
    398  1.4.2.2  christos CFATTACH_DECL3_NEW(mfii, sizeof(struct mfii_softc),
    399  1.4.2.2  christos     mfii_match, mfii_attach, mfii_detach, NULL, mfii_rescan,
    400  1.4.2.2  christos 	mfii_childdetached, DVF_DETACH_SHUTDOWN);
    401  1.4.2.2  christos 
    402  1.4.2.3    martin static void	mfii_scsipi_request(struct scsipi_channel *,
    403  1.4.2.2  christos 			scsipi_adapter_req_t, void *);
    404  1.4.2.3    martin static void	mfii_scsi_cmd_done(struct mfii_softc *, struct mfii_ccb *);
    405  1.4.2.2  christos 
    406  1.4.2.2  christos #define DEVNAME(_sc)		(device_xname((_sc)->sc_dev))
    407  1.4.2.2  christos 
    408  1.4.2.2  christos static u_int32_t	mfii_read(struct mfii_softc *, bus_size_t);
    409  1.4.2.2  christos static void		mfii_write(struct mfii_softc *, bus_size_t, u_int32_t);
    410  1.4.2.2  christos 
    411  1.4.2.3    martin static struct mfii_dmamem *	mfii_dmamem_alloc(struct mfii_softc *, size_t);
    412  1.4.2.3    martin static void		mfii_dmamem_free(struct mfii_softc *,
    413  1.4.2.2  christos 			    struct mfii_dmamem *);
    414  1.4.2.2  christos 
    415  1.4.2.3    martin static struct mfii_ccb *	mfii_get_ccb(struct mfii_softc *);
    416  1.4.2.3    martin static void		mfii_put_ccb(struct mfii_softc *, struct mfii_ccb *);
    417  1.4.2.3    martin static int		mfii_init_ccb(struct mfii_softc *);
    418  1.4.2.3    martin static void		mfii_scrub_ccb(struct mfii_ccb *);
    419  1.4.2.3    martin 
    420  1.4.2.3    martin static int		mfii_transition_firmware(struct mfii_softc *);
    421  1.4.2.3    martin static int		mfii_initialise_firmware(struct mfii_softc *);
    422  1.4.2.3    martin static int		mfii_get_info(struct mfii_softc *);
    423  1.4.2.3    martin 
    424  1.4.2.3    martin static void		mfii_start(struct mfii_softc *, struct mfii_ccb *);
    425  1.4.2.3    martin static void		mfii_done(struct mfii_softc *, struct mfii_ccb *);
    426  1.4.2.3    martin static int		mfii_poll(struct mfii_softc *, struct mfii_ccb *);
    427  1.4.2.3    martin static void		mfii_poll_done(struct mfii_softc *, struct mfii_ccb *);
    428  1.4.2.3    martin static int		mfii_exec(struct mfii_softc *, struct mfii_ccb *);
    429  1.4.2.3    martin static void		mfii_exec_done(struct mfii_softc *, struct mfii_ccb *);
    430  1.4.2.3    martin static int		mfii_my_intr(struct mfii_softc *);
    431  1.4.2.3    martin static int		mfii_intr(void *);
    432  1.4.2.3    martin static void		mfii_postq(struct mfii_softc *);
    433  1.4.2.2  christos 
    434  1.4.2.3    martin static int		mfii_load_ccb(struct mfii_softc *, struct mfii_ccb *,
    435  1.4.2.2  christos 			    void *, int);
    436  1.4.2.3    martin static int		mfii_load_mfa(struct mfii_softc *, struct mfii_ccb *,
    437  1.4.2.2  christos 			    void *, int);
    438  1.4.2.2  christos 
    439  1.4.2.3    martin static int		mfii_mfa_poll(struct mfii_softc *, struct mfii_ccb *);
    440  1.4.2.2  christos 
    441  1.4.2.3    martin static int		mfii_mgmt(struct mfii_softc *, uint32_t,
    442  1.4.2.2  christos 			    const union mfi_mbox *, void *, size_t,
    443  1.4.2.2  christos 			    mfii_direction_t, bool);
    444  1.4.2.3    martin static int		mfii_do_mgmt(struct mfii_softc *, struct mfii_ccb *,
    445  1.4.2.2  christos 			    uint32_t, const union mfi_mbox *, void *, size_t,
    446  1.4.2.2  christos 			    mfii_direction_t, bool);
    447  1.4.2.3    martin static void		mfii_empty_done(struct mfii_softc *, struct mfii_ccb *);
    448  1.4.2.2  christos 
    449  1.4.2.3    martin static int		mfii_scsi_cmd_io(struct mfii_softc *,
    450  1.4.2.2  christos 			    struct mfii_ccb *, struct scsipi_xfer *);
    451  1.4.2.3    martin static int		mfii_scsi_cmd_cdb(struct mfii_softc *,
    452  1.4.2.2  christos 			    struct mfii_ccb *, struct scsipi_xfer *);
    453  1.4.2.3    martin static void		mfii_scsi_cmd_tmo(void *);
    454  1.4.2.2  christos 
    455  1.4.2.3    martin static void		mfii_abort_task(struct work *, void *);
    456  1.4.2.3    martin static void		mfii_abort(struct mfii_softc *, struct mfii_ccb *,
    457  1.4.2.2  christos 			    uint16_t, uint16_t, uint8_t, uint32_t);
    458  1.4.2.3    martin static void		mfii_scsi_cmd_abort_done(struct mfii_softc *,
    459  1.4.2.2  christos 			    struct mfii_ccb *);
    460  1.4.2.2  christos 
    461  1.4.2.3    martin static int		mfii_aen_register(struct mfii_softc *);
    462  1.4.2.3    martin static void		mfii_aen_start(struct mfii_softc *, struct mfii_ccb *,
    463  1.4.2.2  christos 			    struct mfii_dmamem *, uint32_t);
    464  1.4.2.3    martin static void		mfii_aen_done(struct mfii_softc *, struct mfii_ccb *);
    465  1.4.2.3    martin static void		mfii_aen(struct work *, void *);
    466  1.4.2.3    martin static void		mfii_aen_unregister(struct mfii_softc *);
    467  1.4.2.2  christos 
    468  1.4.2.3    martin static void		mfii_aen_pd_insert(struct mfii_softc *,
    469  1.4.2.2  christos 			    const struct mfi_evtarg_pd_address *);
    470  1.4.2.3    martin static void		mfii_aen_pd_remove(struct mfii_softc *,
    471  1.4.2.2  christos 			    const struct mfi_evtarg_pd_address *);
    472  1.4.2.3    martin static void		mfii_aen_pd_state_change(struct mfii_softc *,
    473  1.4.2.2  christos 			    const struct mfi_evtarg_pd_state *);
    474  1.4.2.3    martin static void		mfii_aen_ld_update(struct mfii_softc *);
    475  1.4.2.2  christos 
    476  1.4.2.2  christos #if NBIO > 0
    477  1.4.2.3    martin static int	mfii_ioctl(device_t, u_long, void *);
    478  1.4.2.3    martin static int	mfii_ioctl_inq(struct mfii_softc *, struct bioc_inq *);
    479  1.4.2.3    martin static int	mfii_ioctl_vol(struct mfii_softc *, struct bioc_vol *);
    480  1.4.2.3    martin static int	mfii_ioctl_disk(struct mfii_softc *, struct bioc_disk *);
    481  1.4.2.3    martin static int	mfii_ioctl_alarm(struct mfii_softc *, struct bioc_alarm *);
    482  1.4.2.3    martin static int	mfii_ioctl_blink(struct mfii_softc *sc, struct bioc_blink *);
    483  1.4.2.3    martin static int	mfii_ioctl_setstate(struct mfii_softc *,
    484  1.4.2.2  christos 		    struct bioc_setstate *);
    485  1.4.2.3    martin static int	mfii_bio_hs(struct mfii_softc *, int, int, void *);
    486  1.4.2.3    martin static int	mfii_bio_getitall(struct mfii_softc *);
    487  1.4.2.2  christos #endif /* NBIO > 0 */
    488  1.4.2.2  christos 
    489  1.4.2.2  christos #if 0
    490  1.4.2.2  christos static const char *mfi_bbu_indicators[] = {
    491  1.4.2.2  christos 	"pack missing",
    492  1.4.2.2  christos 	"voltage low",
    493  1.4.2.2  christos 	"temp high",
    494  1.4.2.2  christos 	"charge active",
    495  1.4.2.2  christos 	"discharge active",
    496  1.4.2.2  christos 	"learn cycle req'd",
    497  1.4.2.2  christos 	"learn cycle active",
    498  1.4.2.2  christos 	"learn cycle failed",
    499  1.4.2.2  christos 	"learn cycle timeout",
    500  1.4.2.2  christos 	"I2C errors",
    501  1.4.2.2  christos 	"replace pack",
    502  1.4.2.2  christos 	"low capacity",
    503  1.4.2.2  christos 	"periodic learn req'd"
    504  1.4.2.2  christos };
    505  1.4.2.2  christos #endif
    506  1.4.2.2  christos 
    507  1.4.2.3    martin static void	mfii_init_ld_sensor(struct mfii_softc *, envsys_data_t *, int);
    508  1.4.2.3    martin static void	mfii_refresh_ld_sensor(struct mfii_softc *, envsys_data_t *);
    509  1.4.2.2  christos static void	mfii_attach_sensor(struct mfii_softc *, envsys_data_t *);
    510  1.4.2.3    martin static int	mfii_create_sensors(struct mfii_softc *);
    511  1.4.2.2  christos static int	mfii_destroy_sensors(struct mfii_softc *);
    512  1.4.2.3    martin static void	mfii_refresh_sensor(struct sysmon_envsys *, envsys_data_t *);
    513  1.4.2.3    martin static void	mfii_bbu(struct mfii_softc *, envsys_data_t *);
    514  1.4.2.2  christos 
    515  1.4.2.2  christos /*
    516  1.4.2.2  christos  * mfii boards support asynchronous (and non-polled) completion of
    517  1.4.2.2  christos  * dcmds by proxying them through a passthru mpii command that points
    518  1.4.2.2  christos  * at a dcmd frame. since the passthru command is submitted like
    519  1.4.2.2  christos  * the scsi commands using an SMID in the request descriptor,
    520  1.4.2.2  christos  * ccb_request memory * must contain the passthru command because
    521  1.4.2.2  christos  * that is what the SMID refers to. this means ccb_request cannot
    522  1.4.2.2  christos  * contain the dcmd. rather than allocating separate dma memory to
    523  1.4.2.2  christos  * hold the dcmd, we reuse the sense memory buffer for it.
    524  1.4.2.2  christos  */
    525  1.4.2.2  christos 
    526  1.4.2.3    martin static void	mfii_dcmd_start(struct mfii_softc *, struct mfii_ccb *);
    527  1.4.2.2  christos 
    528  1.4.2.2  christos static inline void
    529  1.4.2.2  christos mfii_dcmd_scrub(struct mfii_ccb *ccb)
    530  1.4.2.2  christos {
    531  1.4.2.2  christos 	memset(ccb->ccb_sense, 0, sizeof(*ccb->ccb_sense));
    532  1.4.2.2  christos }
    533  1.4.2.2  christos 
    534  1.4.2.2  christos static inline struct mfi_dcmd_frame *
    535  1.4.2.2  christos mfii_dcmd_frame(struct mfii_ccb *ccb)
    536  1.4.2.2  christos {
    537  1.4.2.2  christos 	CTASSERT(sizeof(struct mfi_dcmd_frame) <= sizeof(*ccb->ccb_sense));
    538  1.4.2.2  christos 	return ((struct mfi_dcmd_frame *)ccb->ccb_sense);
    539  1.4.2.2  christos }
    540  1.4.2.2  christos 
    541  1.4.2.2  christos static inline void
    542  1.4.2.2  christos mfii_dcmd_sync(struct mfii_softc *sc, struct mfii_ccb *ccb, int flags)
    543  1.4.2.2  christos {
    544  1.4.2.2  christos 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_sense),
    545  1.4.2.2  christos 	    ccb->ccb_sense_offset, sizeof(*ccb->ccb_sense), flags);
    546  1.4.2.2  christos }
    547  1.4.2.2  christos 
    548  1.4.2.2  christos #define mfii_fw_state(_sc) mfii_read((_sc), MFI_OSP)
    549  1.4.2.2  christos 
    550  1.4.2.3    martin static const struct mfii_iop mfii_iop_thunderbolt = {
    551  1.4.2.2  christos 	MFII_BAR,
    552  1.4.2.2  christos 	MFII_IOP_NUM_SGE_LOC_ORIG,
    553  1.4.2.2  christos 	0,
    554  1.4.2.2  christos 	MFII_REQ_TYPE_LDIO,
    555  1.4.2.2  christos 	0,
    556  1.4.2.2  christos 	MFII_SGE_CHAIN_ELEMENT | MFII_SGE_ADDR_IOCPLBNTA,
    557  1.4.2.2  christos 	0
    558  1.4.2.2  christos };
    559  1.4.2.2  christos 
    560  1.4.2.2  christos /*
    561  1.4.2.2  christos  * a lot of these values depend on us not implementing fastpath yet.
    562  1.4.2.2  christos  */
    563  1.4.2.3    martin static const struct mfii_iop mfii_iop_25 = {
    564  1.4.2.2  christos 	MFII_BAR,
    565  1.4.2.2  christos 	MFII_IOP_NUM_SGE_LOC_ORIG,
    566  1.4.2.2  christos 	MFII_RAID_CTX_RL_FLAGS_CPU0, /* | MFII_RAID_CTX_RL_FLAGS_SEQNO_EN */
    567  1.4.2.2  christos 	MFII_REQ_TYPE_NO_LOCK,
    568  1.4.2.2  christos 	MFII_RAID_CTX_TYPE_CUDA | 0x1,
    569  1.4.2.2  christos 	MFII_SGE_CHAIN_ELEMENT,
    570  1.4.2.2  christos 	MFII_SGE_END_OF_LIST
    571  1.4.2.2  christos };
    572  1.4.2.2  christos 
    573  1.4.2.3    martin static const struct mfii_iop mfii_iop_35 = {
    574  1.4.2.2  christos 	MFII_BAR_35,
    575  1.4.2.2  christos 	MFII_IOP_NUM_SGE_LOC_35,
    576  1.4.2.2  christos 	MFII_RAID_CTX_ROUTING_FLAGS_CPU0, /* | MFII_RAID_CTX_ROUTING_FLAGS_SQN */
    577  1.4.2.2  christos 	MFII_REQ_TYPE_NO_LOCK,
    578  1.4.2.2  christos 	MFII_RAID_CTX_TYPE_CUDA | 0x1,
    579  1.4.2.2  christos 	MFII_SGE_CHAIN_ELEMENT,
    580  1.4.2.2  christos 	MFII_SGE_END_OF_LIST
    581  1.4.2.2  christos };
    582  1.4.2.2  christos 
    583  1.4.2.2  christos struct mfii_device {
    584  1.4.2.2  christos 	pcireg_t		mpd_vendor;
    585  1.4.2.2  christos 	pcireg_t		mpd_product;
    586  1.4.2.2  christos 	const struct mfii_iop	*mpd_iop;
    587  1.4.2.2  christos };
    588  1.4.2.2  christos 
    589  1.4.2.3    martin static const struct mfii_device mfii_devices[] = {
    590  1.4.2.2  christos 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_2208,
    591  1.4.2.2  christos 	    &mfii_iop_thunderbolt },
    592  1.4.2.2  christos 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3008,
    593  1.4.2.2  christos 	    &mfii_iop_25 },
    594  1.4.2.2  christos 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3108,
    595  1.4.2.2  christos 	    &mfii_iop_25 },
    596  1.4.2.2  christos 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3404,
    597  1.4.2.2  christos 	    &mfii_iop_35 },
    598  1.4.2.2  christos 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3504,
    599  1.4.2.2  christos 	    &mfii_iop_35 },
    600  1.4.2.2  christos 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3408,
    601  1.4.2.2  christos 	    &mfii_iop_35 },
    602  1.4.2.2  christos 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3508,
    603  1.4.2.2  christos 	    &mfii_iop_35 },
    604  1.4.2.2  christos 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3416,
    605  1.4.2.2  christos 	    &mfii_iop_35 },
    606  1.4.2.2  christos 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3516,
    607  1.4.2.2  christos 	    &mfii_iop_35 }
    608  1.4.2.2  christos };
    609  1.4.2.2  christos 
    610  1.4.2.3    martin static const struct mfii_iop *mfii_find_iop(struct pci_attach_args *);
    611  1.4.2.2  christos 
    612  1.4.2.3    martin static const struct mfii_iop *
    613  1.4.2.2  christos mfii_find_iop(struct pci_attach_args *pa)
    614  1.4.2.2  christos {
    615  1.4.2.2  christos 	const struct mfii_device *mpd;
    616  1.4.2.2  christos 	int i;
    617  1.4.2.2  christos 
    618  1.4.2.2  christos 	for (i = 0; i < __arraycount(mfii_devices); i++) {
    619  1.4.2.2  christos 		mpd = &mfii_devices[i];
    620  1.4.2.2  christos 
    621  1.4.2.2  christos 		if (mpd->mpd_vendor == PCI_VENDOR(pa->pa_id) &&
    622  1.4.2.2  christos 		    mpd->mpd_product == PCI_PRODUCT(pa->pa_id))
    623  1.4.2.2  christos 			return (mpd->mpd_iop);
    624  1.4.2.2  christos 	}
    625  1.4.2.2  christos 
    626  1.4.2.2  christos 	return (NULL);
    627  1.4.2.2  christos }
    628  1.4.2.2  christos 
    629  1.4.2.3    martin static int
    630  1.4.2.2  christos mfii_match(device_t parent, cfdata_t match, void *aux)
    631  1.4.2.2  christos {
    632  1.4.2.2  christos 	return ((mfii_find_iop(aux) != NULL) ? 2 : 0);
    633  1.4.2.2  christos }
    634  1.4.2.2  christos 
    635  1.4.2.3    martin static void
    636  1.4.2.2  christos mfii_attach(device_t parent, device_t self, void *aux)
    637  1.4.2.2  christos {
    638  1.4.2.2  christos 	struct mfii_softc *sc = device_private(self);
    639  1.4.2.2  christos 	struct pci_attach_args *pa = aux;
    640  1.4.2.2  christos 	pcireg_t memtype;
    641  1.4.2.2  christos 	pci_intr_handle_t ih;
    642  1.4.2.2  christos 	char intrbuf[PCI_INTRSTR_LEN];
    643  1.4.2.2  christos 	const char *intrstr;
    644  1.4.2.2  christos 	u_int32_t status, scpad2, scpad3;
    645  1.4.2.2  christos 	int chain_frame_sz, nsge_in_io, nsge_in_chain, i;
    646  1.4.2.2  christos 	struct scsipi_adapter *adapt = &sc->sc_adapt;
    647  1.4.2.2  christos 	struct scsipi_channel *chan = &sc->sc_chan;
    648  1.4.2.2  christos 
    649  1.4.2.2  christos 	/* init sc */
    650  1.4.2.2  christos 	sc->sc_dev = self;
    651  1.4.2.2  christos 	sc->sc_iop = mfii_find_iop(aux);
    652  1.4.2.2  christos 	sc->sc_dmat = pa->pa_dmat;
    653  1.4.2.2  christos 	if (pci_dma64_available(pa)) {
    654  1.4.2.2  christos 		sc->sc_dmat64 = pa->pa_dmat64;
    655  1.4.2.2  christos 		sc->sc_64bit_dma = 1;
    656  1.4.2.2  christos 	} else {
    657  1.4.2.2  christos 		sc->sc_dmat64 = pa->pa_dmat;
    658  1.4.2.2  christos 		sc->sc_64bit_dma = 0;
    659  1.4.2.2  christos 	}
    660  1.4.2.2  christos 	SIMPLEQ_INIT(&sc->sc_ccb_freeq);
    661  1.4.2.2  christos 	mutex_init(&sc->sc_ccb_mtx, MUTEX_DEFAULT, IPL_BIO);
    662  1.4.2.2  christos 	mutex_init(&sc->sc_post_mtx, MUTEX_DEFAULT, IPL_BIO);
    663  1.4.2.2  christos 	mutex_init(&sc->sc_reply_postq_mtx, MUTEX_DEFAULT, IPL_BIO);
    664  1.4.2.2  christos 
    665  1.4.2.2  christos 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
    666  1.4.2.2  christos 
    667  1.4.2.2  christos 	sc->sc_aen_ccb = NULL;
    668  1.4.2.2  christos 	snprintf(intrbuf, sizeof(intrbuf) - 1, "%saen", device_xname(self));
    669  1.4.2.2  christos 	workqueue_create(&sc->sc_aen_wq, intrbuf, mfii_aen, sc,
    670  1.4.2.2  christos 	    PRI_BIO, IPL_BIO, WQ_MPSAFE);
    671  1.4.2.2  christos 
    672  1.4.2.2  christos 	snprintf(intrbuf, sizeof(intrbuf) - 1, "%sabrt", device_xname(self));
    673  1.4.2.2  christos 	workqueue_create(&sc->sc_abort_wq, intrbuf, mfii_abort_task,
    674  1.4.2.2  christos 	    sc, PRI_BIO, IPL_BIO, WQ_MPSAFE);
    675  1.4.2.2  christos 
    676  1.4.2.2  christos 	mutex_init(&sc->sc_abort_mtx, MUTEX_DEFAULT, IPL_BIO);
    677  1.4.2.2  christos 	SIMPLEQ_INIT(&sc->sc_abort_list);
    678  1.4.2.2  christos 
    679  1.4.2.2  christos 	/* wire up the bus shizz */
    680  1.4.2.2  christos 	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, sc->sc_iop->bar);
    681  1.4.2.2  christos 	memtype |= PCI_MAPREG_MEM_TYPE_32BIT;
    682  1.4.2.2  christos 	if (pci_mapreg_map(pa, sc->sc_iop->bar, memtype, 0,
    683  1.4.2.2  christos 	    &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_ios)) {
    684  1.4.2.2  christos 		aprint_error(": unable to map registers\n");
    685  1.4.2.2  christos 		return;
    686  1.4.2.2  christos 	}
    687  1.4.2.2  christos 
    688  1.4.2.2  christos 	/* disable interrupts */
    689  1.4.2.2  christos 	mfii_write(sc, MFI_OMSK, 0xffffffff);
    690  1.4.2.2  christos 
    691  1.4.2.2  christos 	if (pci_intr_map(pa, &ih) != 0) {
    692  1.4.2.2  christos 		aprint_error(": unable to map interrupt\n");
    693  1.4.2.2  christos 		goto pci_unmap;
    694  1.4.2.2  christos 	}
    695  1.4.2.2  christos 	intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf));
    696  1.4.2.2  christos 	pci_intr_setattr(pa->pa_pc, &ih, PCI_INTR_MPSAFE, true);
    697  1.4.2.2  christos 
    698  1.4.2.2  christos 	/* lets get started */
    699  1.4.2.2  christos 	if (mfii_transition_firmware(sc))
    700  1.4.2.2  christos 		goto pci_unmap;
    701  1.4.2.2  christos 	sc->sc_running = true;
    702  1.4.2.2  christos 
    703  1.4.2.2  christos 	/* determine max_cmds (refer to the Linux megaraid_sas driver) */
    704  1.4.2.2  christos 	scpad3 = mfii_read(sc, MFII_OSP3);
    705  1.4.2.2  christos 	status = mfii_fw_state(sc);
    706  1.4.2.2  christos 	sc->sc_max_fw_cmds = scpad3 & MFI_STATE_MAXCMD_MASK;
    707  1.4.2.2  christos 	if (sc->sc_max_fw_cmds == 0)
    708  1.4.2.2  christos 		sc->sc_max_fw_cmds = status & MFI_STATE_MAXCMD_MASK;
    709  1.4.2.2  christos 	/*
    710  1.4.2.2  christos 	 * reduce max_cmds by 1 to ensure that the reply queue depth does not
    711  1.4.2.2  christos 	 * exceed FW supplied max_fw_cmds.
    712  1.4.2.2  christos 	 */
    713  1.4.2.2  christos 	sc->sc_max_cmds = uimin(sc->sc_max_fw_cmds, 1024) - 1;
    714  1.4.2.2  christos 
    715  1.4.2.2  christos 	/* determine max_sgl (refer to the Linux megaraid_sas driver) */
    716  1.4.2.2  christos 	scpad2 = mfii_read(sc, MFII_OSP2);
    717  1.4.2.2  christos 	chain_frame_sz =
    718  1.4.2.2  christos 		((scpad2 & MFII_MAX_CHAIN_MASK) >> MFII_MAX_CHAIN_SHIFT) *
    719  1.4.2.2  christos 		((scpad2 & MFII_MAX_CHAIN_UNIT) ? MFII_1MB_IO : MFII_256K_IO);
    720  1.4.2.2  christos 	if (chain_frame_sz < MFII_CHAIN_FRAME_MIN)
    721  1.4.2.2  christos 		chain_frame_sz = MFII_CHAIN_FRAME_MIN;
    722  1.4.2.2  christos 
    723  1.4.2.2  christos 	nsge_in_io = (MFII_REQUEST_SIZE -
    724  1.4.2.2  christos 		sizeof(struct mpii_msg_scsi_io) -
    725  1.4.2.2  christos 		sizeof(struct mfii_raid_context)) / sizeof(struct mfii_sge);
    726  1.4.2.2  christos 	nsge_in_chain = chain_frame_sz / sizeof(struct mfii_sge);
    727  1.4.2.2  christos 
    728  1.4.2.2  christos 	/* round down to nearest power of two */
    729  1.4.2.2  christos 	sc->sc_max_sgl = 1;
    730  1.4.2.2  christos 	while ((sc->sc_max_sgl << 1) <= (nsge_in_io + nsge_in_chain))
    731  1.4.2.2  christos 		sc->sc_max_sgl <<= 1;
    732  1.4.2.2  christos 
    733  1.4.2.2  christos 	DNPRINTF(MFII_D_MISC, "%s: OSP 0x%08x, OSP2 0x%08x, OSP3 0x%08x\n",
    734  1.4.2.2  christos 	    DEVNAME(sc), status, scpad2, scpad3);
    735  1.4.2.2  christos 	DNPRINTF(MFII_D_MISC, "%s: max_fw_cmds %d, max_cmds %d\n",
    736  1.4.2.2  christos 	    DEVNAME(sc), sc->sc_max_fw_cmds, sc->sc_max_cmds);
    737  1.4.2.2  christos 	DNPRINTF(MFII_D_MISC, "%s: nsge_in_io %d, nsge_in_chain %d, "
    738  1.4.2.2  christos 	    "max_sgl %d\n", DEVNAME(sc), nsge_in_io, nsge_in_chain,
    739  1.4.2.2  christos 	    sc->sc_max_sgl);
    740  1.4.2.2  christos 
    741  1.4.2.2  christos 	/* sense memory */
    742  1.4.2.2  christos 	CTASSERT(sizeof(struct mfi_sense) == MFI_SENSE_SIZE);
    743  1.4.2.2  christos 	sc->sc_sense = mfii_dmamem_alloc(sc, sc->sc_max_cmds * MFI_SENSE_SIZE);
    744  1.4.2.2  christos 	if (sc->sc_sense == NULL) {
    745  1.4.2.2  christos 		aprint_error(": unable to allocate sense memory\n");
    746  1.4.2.2  christos 		goto pci_unmap;
    747  1.4.2.2  christos 	}
    748  1.4.2.2  christos 
    749  1.4.2.2  christos 	/* reply post queue */
    750  1.4.2.2  christos 	sc->sc_reply_postq_depth = roundup(sc->sc_max_fw_cmds, 16);
    751  1.4.2.2  christos 
    752  1.4.2.2  christos 	sc->sc_reply_postq = mfii_dmamem_alloc(sc,
    753  1.4.2.2  christos 	    sc->sc_reply_postq_depth * sizeof(struct mpii_reply_descr));
    754  1.4.2.2  christos 	if (sc->sc_reply_postq == NULL)
    755  1.4.2.2  christos 		goto free_sense;
    756  1.4.2.2  christos 
    757  1.4.2.2  christos 	memset(MFII_DMA_KVA(sc->sc_reply_postq), 0xff,
    758  1.4.2.2  christos 	    MFII_DMA_LEN(sc->sc_reply_postq));
    759  1.4.2.2  christos 
    760  1.4.2.2  christos 	/* MPII request frame array */
    761  1.4.2.2  christos 	sc->sc_requests = mfii_dmamem_alloc(sc,
    762  1.4.2.2  christos 	    MFII_REQUEST_SIZE * (sc->sc_max_cmds + 1));
    763  1.4.2.2  christos 	if (sc->sc_requests == NULL)
    764  1.4.2.2  christos 		goto free_reply_postq;
    765  1.4.2.2  christos 
    766  1.4.2.2  christos 	/* MFI command frame array */
    767  1.4.2.2  christos 	sc->sc_mfi = mfii_dmamem_alloc(sc, sc->sc_max_cmds * MFI_FRAME_SIZE);
    768  1.4.2.2  christos 	if (sc->sc_mfi == NULL)
    769  1.4.2.2  christos 		goto free_requests;
    770  1.4.2.2  christos 
    771  1.4.2.2  christos 	/* MPII SGL array */
    772  1.4.2.2  christos 	sc->sc_sgl = mfii_dmamem_alloc(sc, sc->sc_max_cmds *
    773  1.4.2.2  christos 	    sizeof(struct mfii_sge) * sc->sc_max_sgl);
    774  1.4.2.2  christos 	if (sc->sc_sgl == NULL)
    775  1.4.2.2  christos 		goto free_mfi;
    776  1.4.2.2  christos 
    777  1.4.2.2  christos 	if (mfii_init_ccb(sc) != 0) {
    778  1.4.2.2  christos 		aprint_error(": could not init ccb list\n");
    779  1.4.2.2  christos 		goto free_sgl;
    780  1.4.2.2  christos 	}
    781  1.4.2.2  christos 
    782  1.4.2.2  christos 	/* kickstart firmware with all addresses and pointers */
    783  1.4.2.2  christos 	if (mfii_initialise_firmware(sc) != 0) {
    784  1.4.2.2  christos 		aprint_error(": could not initialize firmware\n");
    785  1.4.2.2  christos 		goto free_sgl;
    786  1.4.2.2  christos 	}
    787  1.4.2.2  christos 
    788  1.4.2.2  christos 	mutex_enter(&sc->sc_lock);
    789  1.4.2.2  christos 	if (mfii_get_info(sc) != 0) {
    790  1.4.2.2  christos 		mutex_exit(&sc->sc_lock);
    791  1.4.2.2  christos 		aprint_error(": could not retrieve controller information\n");
    792  1.4.2.2  christos 		goto free_sgl;
    793  1.4.2.2  christos 	}
    794  1.4.2.2  christos 	mutex_exit(&sc->sc_lock);
    795  1.4.2.2  christos 
    796  1.4.2.2  christos 	aprint_normal(": \"%s\", firmware %s",
    797  1.4.2.2  christos 	    sc->sc_info.mci_product_name, sc->sc_info.mci_package_version);
    798  1.4.2.2  christos 	if (le16toh(sc->sc_info.mci_memory_size) > 0) {
    799  1.4.2.2  christos 		aprint_normal(", %uMB cache",
    800  1.4.2.2  christos 		    le16toh(sc->sc_info.mci_memory_size));
    801  1.4.2.2  christos 	}
    802  1.4.2.2  christos 	aprint_normal("\n");
    803  1.4.2.2  christos 	aprint_naive("\n");
    804  1.4.2.2  christos 
    805  1.4.2.2  christos 	sc->sc_ih = pci_intr_establish_xname(sc->sc_pc, ih, IPL_BIO,
    806  1.4.2.2  christos 	    mfii_intr, sc, DEVNAME(sc));
    807  1.4.2.2  christos 	if (sc->sc_ih == NULL) {
    808  1.4.2.2  christos 		aprint_error_dev(self, "can't establish interrupt");
    809  1.4.2.2  christos 		if (intrstr)
    810  1.4.2.2  christos 			aprint_error(" at %s", intrstr);
    811  1.4.2.2  christos 		aprint_error("\n");
    812  1.4.2.2  christos 		goto free_sgl;
    813  1.4.2.2  christos 	}
    814  1.4.2.2  christos 	aprint_normal_dev(self, "interrupting at %s\n", intrstr);
    815  1.4.2.2  christos 
    816  1.4.2.2  christos 	for (i = 0; i < sc->sc_info.mci_lds_present; i++)
    817  1.4.2.2  christos 		sc->sc_ld[i].ld_present = 1;
    818  1.4.2.2  christos 
    819  1.4.2.2  christos 	memset(adapt, 0, sizeof(*adapt));
    820  1.4.2.2  christos 	adapt->adapt_dev = sc->sc_dev;
    821  1.4.2.2  christos 	adapt->adapt_nchannels = 1;
    822  1.4.2.2  christos 	/* keep a few commands for management */
    823  1.4.2.2  christos 	if (sc->sc_max_cmds > 4)
    824  1.4.2.2  christos 		adapt->adapt_openings = sc->sc_max_cmds - 4;
    825  1.4.2.2  christos 	else
    826  1.4.2.2  christos 		adapt->adapt_openings = sc->sc_max_cmds;
    827  1.4.2.2  christos 	adapt->adapt_max_periph = adapt->adapt_openings;
    828  1.4.2.2  christos 	adapt->adapt_request = mfii_scsipi_request;
    829  1.4.2.2  christos 	adapt->adapt_minphys = minphys;
    830  1.4.2.2  christos 	adapt->adapt_flags = SCSIPI_ADAPT_MPSAFE;
    831  1.4.2.2  christos 
    832  1.4.2.2  christos 	memset(chan, 0, sizeof(*chan));
    833  1.4.2.2  christos 	chan->chan_adapter = adapt;
    834  1.4.2.2  christos 	chan->chan_bustype = &scsi_sas_bustype;
    835  1.4.2.2  christos 	chan->chan_channel = 0;
    836  1.4.2.2  christos 	chan->chan_flags = 0;
    837  1.4.2.2  christos 	chan->chan_nluns = 8;
    838  1.4.2.2  christos 	chan->chan_ntargets = sc->sc_info.mci_max_lds;
    839  1.4.2.2  christos 	chan->chan_id = sc->sc_info.mci_max_lds;
    840  1.4.2.2  christos 
    841  1.4.2.2  christos 	mfii_rescan(sc->sc_dev, "scsi", NULL);
    842  1.4.2.2  christos 
    843  1.4.2.2  christos 	if (mfii_aen_register(sc) != 0) {
    844  1.4.2.2  christos 		/* error printed by mfii_aen_register */
    845  1.4.2.2  christos 		goto intr_disestablish;
    846  1.4.2.2  christos 	}
    847  1.4.2.2  christos 
    848  1.4.2.2  christos 	mutex_enter(&sc->sc_lock);
    849  1.4.2.2  christos 	if (mfii_mgmt(sc, MR_DCMD_LD_GET_LIST, NULL, &sc->sc_ld_list,
    850  1.4.2.2  christos 	    sizeof(sc->sc_ld_list), MFII_DATA_IN, true) != 0) {
    851  1.4.2.2  christos 		mutex_exit(&sc->sc_lock);
    852  1.4.2.2  christos 		aprint_error_dev(self,
    853  1.4.2.2  christos 		    "getting list of logical disks failed\n");
    854  1.4.2.2  christos 		goto intr_disestablish;
    855  1.4.2.2  christos 	}
    856  1.4.2.2  christos 	mutex_exit(&sc->sc_lock);
    857  1.4.2.2  christos 	memset(sc->sc_target_lds, -1, sizeof(sc->sc_target_lds));
    858  1.4.2.2  christos 	for (i = 0; i < sc->sc_ld_list.mll_no_ld; i++) {
    859  1.4.2.2  christos 		int target = sc->sc_ld_list.mll_list[i].mll_ld.mld_target;
    860  1.4.2.2  christos 		sc->sc_target_lds[target] = i;
    861  1.4.2.2  christos 	}
    862  1.4.2.2  christos 
    863  1.4.2.2  christos 	/* enable interrupts */
    864  1.4.2.2  christos 	mfii_write(sc, MFI_OSTS, 0xffffffff);
    865  1.4.2.2  christos 	mfii_write(sc, MFI_OMSK, ~MFII_OSTS_INTR_VALID);
    866  1.4.2.2  christos 
    867  1.4.2.2  christos #if NBIO > 0
    868  1.4.2.2  christos 	if (bio_register(sc->sc_dev, mfii_ioctl) != 0)
    869  1.4.2.2  christos 		panic("%s: controller registration failed", DEVNAME(sc));
    870  1.4.2.2  christos #endif /* NBIO > 0 */
    871  1.4.2.2  christos 
    872  1.4.2.2  christos 	if (mfii_create_sensors(sc) != 0)
    873  1.4.2.2  christos 		aprint_error_dev(self, "unable to create sensors\n");
    874  1.4.2.2  christos 
    875  1.4.2.2  christos 	if (!pmf_device_register1(sc->sc_dev, mfii_suspend, mfii_resume,
    876  1.4.2.2  christos 	    mfii_shutdown))
    877  1.4.2.2  christos 		aprint_error_dev(self, "couldn't establish power handler\n");
    878  1.4.2.2  christos 	return;
    879  1.4.2.2  christos intr_disestablish:
    880  1.4.2.2  christos 	pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
    881  1.4.2.2  christos free_sgl:
    882  1.4.2.2  christos 	mfii_dmamem_free(sc, sc->sc_sgl);
    883  1.4.2.2  christos free_mfi:
    884  1.4.2.2  christos 	mfii_dmamem_free(sc, sc->sc_mfi);
    885  1.4.2.2  christos free_requests:
    886  1.4.2.2  christos 	mfii_dmamem_free(sc, sc->sc_requests);
    887  1.4.2.2  christos free_reply_postq:
    888  1.4.2.2  christos 	mfii_dmamem_free(sc, sc->sc_reply_postq);
    889  1.4.2.2  christos free_sense:
    890  1.4.2.2  christos 	mfii_dmamem_free(sc, sc->sc_sense);
    891  1.4.2.2  christos pci_unmap:
    892  1.4.2.2  christos 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
    893  1.4.2.2  christos }
    894  1.4.2.2  christos 
    895  1.4.2.2  christos #if 0
    896  1.4.2.2  christos struct srp_gc mfii_dev_handles_gc =
    897  1.4.2.2  christos     SRP_GC_INITIALIZER(mfii_dev_handles_dtor, NULL);
    898  1.4.2.2  christos 
    899  1.4.2.2  christos static inline uint16_t
    900  1.4.2.2  christos mfii_dev_handle(struct mfii_softc *sc, uint16_t target)
    901  1.4.2.2  christos {
    902  1.4.2.2  christos 	struct srp_ref sr;
    903  1.4.2.2  christos 	uint16_t *map, handle;
    904  1.4.2.2  christos 
    905  1.4.2.2  christos 	map = srp_enter(&sr, &sc->sc_pd->pd_dev_handles);
    906  1.4.2.2  christos 	handle = map[target];
    907  1.4.2.2  christos 	srp_leave(&sr);
    908  1.4.2.2  christos 
    909  1.4.2.2  christos 	return (handle);
    910  1.4.2.2  christos }
    911  1.4.2.2  christos 
    912  1.4.2.3    martin static int
    913  1.4.2.2  christos mfii_dev_handles_update(struct mfii_softc *sc)
    914  1.4.2.2  christos {
    915  1.4.2.2  christos 	struct mfii_ld_map *lm;
    916  1.4.2.2  christos 	uint16_t *dev_handles = NULL;
    917  1.4.2.2  christos 	int i;
    918  1.4.2.2  christos 	int rv = 0;
    919  1.4.2.2  christos 
    920  1.4.2.2  christos 	lm = malloc(sizeof(*lm), M_TEMP, M_WAITOK|M_ZERO);
    921  1.4.2.2  christos 
    922  1.4.2.2  christos 	rv = mfii_mgmt(sc, MR_DCMD_LD_MAP_GET_INFO, NULL, lm, sizeof(*lm),
    923  1.4.2.2  christos 	    MFII_DATA_IN, false);
    924  1.4.2.2  christos 
    925  1.4.2.2  christos 	if (rv != 0) {
    926  1.4.2.2  christos 		rv = EIO;
    927  1.4.2.2  christos 		goto free_lm;
    928  1.4.2.2  christos 	}
    929  1.4.2.2  christos 
    930  1.4.2.2  christos 	dev_handles = mallocarray(MFI_MAX_PD, sizeof(*dev_handles),
    931  1.4.2.2  christos 	    M_DEVBUF, M_WAITOK);
    932  1.4.2.2  christos 
    933  1.4.2.2  christos 	for (i = 0; i < MFI_MAX_PD; i++)
    934  1.4.2.2  christos 		dev_handles[i] = lm->mlm_dev_handle[i].mdh_cur_handle;
    935  1.4.2.2  christos 
    936  1.4.2.2  christos 	/* commit the updated info */
    937  1.4.2.2  christos 	sc->sc_pd->pd_timeout = lm->mlm_pd_timeout;
    938  1.4.2.2  christos 	srp_update_locked(&mfii_dev_handles_gc,
    939  1.4.2.2  christos 	    &sc->sc_pd->pd_dev_handles, dev_handles);
    940  1.4.2.2  christos 
    941  1.4.2.2  christos free_lm:
    942  1.4.2.2  christos 	free(lm, M_TEMP, sizeof(*lm));
    943  1.4.2.2  christos 
    944  1.4.2.2  christos 	return (rv);
    945  1.4.2.2  christos }
    946  1.4.2.2  christos 
    947  1.4.2.3    martin static void
    948  1.4.2.2  christos mfii_dev_handles_dtor(void *null, void *v)
    949  1.4.2.2  christos {
    950  1.4.2.2  christos 	uint16_t *dev_handles = v;
    951  1.4.2.2  christos 
    952  1.4.2.2  christos 	free(dev_handles, M_DEVBUF, sizeof(*dev_handles) * MFI_MAX_PD);
    953  1.4.2.2  christos }
    954  1.4.2.2  christos #endif /* 0 */
    955  1.4.2.2  christos 
    956  1.4.2.3    martin static int
    957  1.4.2.2  christos mfii_detach(device_t self, int flags)
    958  1.4.2.2  christos {
    959  1.4.2.2  christos 	struct mfii_softc *sc = device_private(self);
    960  1.4.2.2  christos 	int error;
    961  1.4.2.2  christos 
    962  1.4.2.2  christos 	if (sc->sc_ih == NULL)
    963  1.4.2.2  christos 		return (0);
    964  1.4.2.2  christos 
    965  1.4.2.2  christos 	if ((error = config_detach_children(sc->sc_dev, flags)) != 0)
    966  1.4.2.2  christos 		return error;
    967  1.4.2.2  christos 
    968  1.4.2.2  christos 	mfii_destroy_sensors(sc);
    969  1.4.2.2  christos #if NBIO > 0
    970  1.4.2.2  christos 	bio_unregister(sc->sc_dev);
    971  1.4.2.2  christos #endif
    972  1.4.2.2  christos 	mfii_shutdown(sc->sc_dev, 0);
    973  1.4.2.2  christos 	mfii_write(sc, MFI_OMSK, 0xffffffff);
    974  1.4.2.2  christos 
    975  1.4.2.2  christos 	mfii_aen_unregister(sc);
    976  1.4.2.2  christos 	pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
    977  1.4.2.2  christos 	mfii_dmamem_free(sc, sc->sc_sgl);
    978  1.4.2.2  christos 	mfii_dmamem_free(sc, sc->sc_mfi);
    979  1.4.2.2  christos 	mfii_dmamem_free(sc, sc->sc_requests);
    980  1.4.2.2  christos 	mfii_dmamem_free(sc, sc->sc_reply_postq);
    981  1.4.2.2  christos 	mfii_dmamem_free(sc, sc->sc_sense);
    982  1.4.2.2  christos 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
    983  1.4.2.2  christos 
    984  1.4.2.2  christos 	return (0);
    985  1.4.2.2  christos }
    986  1.4.2.2  christos 
    987  1.4.2.3    martin static int
    988  1.4.2.2  christos mfii_rescan(device_t self, const char *ifattr, const int *locators)
    989  1.4.2.2  christos {
    990  1.4.2.2  christos 	struct mfii_softc *sc = device_private(self);
    991  1.4.2.2  christos 	if (sc->sc_child != NULL)
    992  1.4.2.2  christos 		return 0;
    993  1.4.2.2  christos 
    994  1.4.2.2  christos 	sc->sc_child = config_found_sm_loc(self, ifattr, locators, &sc->sc_chan,
    995  1.4.2.2  christos 	    scsiprint, NULL);
    996  1.4.2.2  christos 	return 0;
    997  1.4.2.2  christos }
    998  1.4.2.2  christos 
    999  1.4.2.3    martin static void
   1000  1.4.2.2  christos mfii_childdetached(device_t self, device_t child)
   1001  1.4.2.2  christos {
   1002  1.4.2.2  christos 	struct mfii_softc *sc = device_private(self);
   1003  1.4.2.2  christos 
   1004  1.4.2.2  christos 	KASSERT(self == sc->sc_dev);
   1005  1.4.2.2  christos 	KASSERT(child == sc->sc_child);
   1006  1.4.2.2  christos 
   1007  1.4.2.2  christos 	if (child == sc->sc_child)
   1008  1.4.2.2  christos 		sc->sc_child = NULL;
   1009  1.4.2.2  christos }
   1010  1.4.2.2  christos 
   1011  1.4.2.2  christos static bool
   1012  1.4.2.2  christos mfii_suspend(device_t dev, const pmf_qual_t *q)
   1013  1.4.2.2  christos {
   1014  1.4.2.2  christos 	/* XXX to be implemented */
   1015  1.4.2.2  christos 	return false;
   1016  1.4.2.2  christos }
   1017  1.4.2.2  christos 
   1018  1.4.2.2  christos static bool
   1019  1.4.2.2  christos mfii_resume(device_t dev, const pmf_qual_t *q)
   1020  1.4.2.2  christos {
   1021  1.4.2.2  christos 	/* XXX to be implemented */
   1022  1.4.2.2  christos 	return false;
   1023  1.4.2.2  christos }
   1024  1.4.2.2  christos 
   1025  1.4.2.2  christos static bool
   1026  1.4.2.2  christos mfii_shutdown(device_t dev, int how)
   1027  1.4.2.2  christos {
   1028  1.4.2.2  christos 	struct mfii_softc	*sc = device_private(dev);
   1029  1.4.2.2  christos 	struct mfii_ccb *ccb;
   1030  1.4.2.2  christos 	union mfi_mbox		mbox;
   1031  1.4.2.2  christos 	bool rv = true;;
   1032  1.4.2.2  christos 
   1033  1.4.2.2  christos 	memset(&mbox, 0, sizeof(mbox));
   1034  1.4.2.2  christos 
   1035  1.4.2.2  christos 	mutex_enter(&sc->sc_lock);
   1036  1.4.2.2  christos 	DNPRINTF(MFI_D_MISC, "%s: mfii_shutdown\n", DEVNAME(sc));
   1037  1.4.2.2  christos 	ccb = mfii_get_ccb(sc);
   1038  1.4.2.2  christos 	if (ccb == NULL)
   1039  1.4.2.2  christos 		return false;
   1040  1.4.2.2  christos 	mutex_enter(&sc->sc_ccb_mtx);
   1041  1.4.2.2  christos 	if (sc->sc_running) {
   1042  1.4.2.2  christos 		sc->sc_running = 0; /* prevent new commands */
   1043  1.4.2.2  christos 		mutex_exit(&sc->sc_ccb_mtx);
   1044  1.4.2.2  christos #if 0 /* XXX why does this hang ? */
   1045  1.4.2.2  christos 		mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
   1046  1.4.2.2  christos 		mfii_scrub_ccb(ccb);
   1047  1.4.2.2  christos 		if (mfii_do_mgmt(sc, ccb, MR_DCMD_CTRL_CACHE_FLUSH, &mbox,
   1048  1.4.2.2  christos 		    NULL, 0, MFII_DATA_NONE, true)) {
   1049  1.4.2.2  christos 			aprint_error_dev(dev, "shutdown: cache flush failed\n");
   1050  1.4.2.2  christos 			rv = false;
   1051  1.4.2.2  christos 			goto fail;
   1052  1.4.2.2  christos 		}
   1053  1.4.2.2  christos 		printf("ok1\n");
   1054  1.4.2.2  christos #endif
   1055  1.4.2.2  christos 		mbox.b[0] = 0;
   1056  1.4.2.2  christos 		mfii_scrub_ccb(ccb);
   1057  1.4.2.2  christos 		if (mfii_do_mgmt(sc, ccb, MR_DCMD_CTRL_SHUTDOWN, &mbox,
   1058  1.4.2.2  christos 		    NULL, 0, MFII_DATA_NONE, true)) {
   1059  1.4.2.2  christos 			aprint_error_dev(dev, "shutdown: "
   1060  1.4.2.2  christos 			    "firmware shutdown failed\n");
   1061  1.4.2.2  christos 		    	rv = false;
   1062  1.4.2.2  christos 			goto fail;
   1063  1.4.2.2  christos 		}
   1064  1.4.2.2  christos 	} else {
   1065  1.4.2.2  christos 		mutex_exit(&sc->sc_ccb_mtx);
   1066  1.4.2.2  christos 	}
   1067  1.4.2.2  christos fail:
   1068  1.4.2.2  christos 	mfii_put_ccb(sc, ccb);
   1069  1.4.2.2  christos 	mutex_exit(&sc->sc_lock);
   1070  1.4.2.2  christos 	return rv;
   1071  1.4.2.2  christos }
   1072  1.4.2.2  christos 
   1073  1.4.2.2  christos static u_int32_t
   1074  1.4.2.2  christos mfii_read(struct mfii_softc *sc, bus_size_t r)
   1075  1.4.2.2  christos {
   1076  1.4.2.2  christos 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
   1077  1.4.2.2  christos 	    BUS_SPACE_BARRIER_READ);
   1078  1.4.2.2  christos 	return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, r));
   1079  1.4.2.2  christos }
   1080  1.4.2.2  christos 
   1081  1.4.2.2  christos static void
   1082  1.4.2.2  christos mfii_write(struct mfii_softc *sc, bus_size_t r, u_int32_t v)
   1083  1.4.2.2  christos {
   1084  1.4.2.2  christos 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v);
   1085  1.4.2.2  christos 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
   1086  1.4.2.2  christos 	    BUS_SPACE_BARRIER_WRITE);
   1087  1.4.2.2  christos }
   1088  1.4.2.2  christos 
   1089  1.4.2.3    martin static struct mfii_dmamem *
   1090  1.4.2.2  christos mfii_dmamem_alloc(struct mfii_softc *sc, size_t size)
   1091  1.4.2.2  christos {
   1092  1.4.2.2  christos 	struct mfii_dmamem *m;
   1093  1.4.2.2  christos 	int nsegs;
   1094  1.4.2.2  christos 
   1095  1.4.2.2  christos 	m = malloc(sizeof(*m), M_DEVBUF, M_NOWAIT | M_ZERO);
   1096  1.4.2.2  christos 	if (m == NULL)
   1097  1.4.2.2  christos 		return (NULL);
   1098  1.4.2.2  christos 
   1099  1.4.2.2  christos 	m->mdm_size = size;
   1100  1.4.2.2  christos 
   1101  1.4.2.2  christos 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
   1102  1.4.2.2  christos 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &m->mdm_map) != 0)
   1103  1.4.2.2  christos 		goto mdmfree;
   1104  1.4.2.2  christos 
   1105  1.4.2.2  christos 	if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &m->mdm_seg, 1,
   1106  1.4.2.2  christos 	    &nsegs, BUS_DMA_NOWAIT) != 0)
   1107  1.4.2.2  christos 		goto destroy;
   1108  1.4.2.2  christos 
   1109  1.4.2.2  christos 	if (bus_dmamem_map(sc->sc_dmat, &m->mdm_seg, nsegs, size, &m->mdm_kva,
   1110  1.4.2.2  christos 	    BUS_DMA_NOWAIT) != 0)
   1111  1.4.2.2  christos 		goto free;
   1112  1.4.2.2  christos 
   1113  1.4.2.2  christos 	if (bus_dmamap_load(sc->sc_dmat, m->mdm_map, m->mdm_kva, size, NULL,
   1114  1.4.2.2  christos 	    BUS_DMA_NOWAIT) != 0)
   1115  1.4.2.2  christos 		goto unmap;
   1116  1.4.2.2  christos 
   1117  1.4.2.2  christos 	memset(m->mdm_kva, 0, size);
   1118  1.4.2.2  christos 	return (m);
   1119  1.4.2.2  christos 
   1120  1.4.2.2  christos unmap:
   1121  1.4.2.2  christos 	bus_dmamem_unmap(sc->sc_dmat, m->mdm_kva, m->mdm_size);
   1122  1.4.2.2  christos free:
   1123  1.4.2.2  christos 	bus_dmamem_free(sc->sc_dmat, &m->mdm_seg, 1);
   1124  1.4.2.2  christos destroy:
   1125  1.4.2.2  christos 	bus_dmamap_destroy(sc->sc_dmat, m->mdm_map);
   1126  1.4.2.2  christos mdmfree:
   1127  1.4.2.2  christos 	free(m, M_DEVBUF);
   1128  1.4.2.2  christos 
   1129  1.4.2.2  christos 	return (NULL);
   1130  1.4.2.2  christos }
   1131  1.4.2.2  christos 
   1132  1.4.2.3    martin static void
   1133  1.4.2.2  christos mfii_dmamem_free(struct mfii_softc *sc, struct mfii_dmamem *m)
   1134  1.4.2.2  christos {
   1135  1.4.2.2  christos 	bus_dmamap_unload(sc->sc_dmat, m->mdm_map);
   1136  1.4.2.2  christos 	bus_dmamem_unmap(sc->sc_dmat, m->mdm_kva, m->mdm_size);
   1137  1.4.2.2  christos 	bus_dmamem_free(sc->sc_dmat, &m->mdm_seg, 1);
   1138  1.4.2.2  christos 	bus_dmamap_destroy(sc->sc_dmat, m->mdm_map);
   1139  1.4.2.2  christos 	free(m, M_DEVBUF);
   1140  1.4.2.2  christos }
   1141  1.4.2.2  christos 
   1142  1.4.2.3    martin static void
   1143  1.4.2.2  christos mfii_dcmd_start(struct mfii_softc *sc, struct mfii_ccb *ccb)
   1144  1.4.2.2  christos {
   1145  1.4.2.2  christos 	struct mpii_msg_scsi_io *io = ccb->ccb_request;
   1146  1.4.2.2  christos 	struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
   1147  1.4.2.2  christos 	struct mfii_sge *sge = (struct mfii_sge *)(ctx + 1);
   1148  1.4.2.2  christos 
   1149  1.4.2.2  christos 	io->function = MFII_FUNCTION_PASSTHRU_IO;
   1150  1.4.2.2  christos 	io->sgl_offset0 = (uint32_t *)sge - (uint32_t *)io;
   1151  1.4.2.2  christos 	io->chain_offset = io->sgl_offset0 / 4;
   1152  1.4.2.2  christos 
   1153  1.4.2.2  christos 	sge->sg_addr = htole64(ccb->ccb_sense_dva);
   1154  1.4.2.2  christos 	sge->sg_len = htole32(sizeof(*ccb->ccb_sense));
   1155  1.4.2.2  christos 	sge->sg_flags = MFII_SGE_CHAIN_ELEMENT | MFII_SGE_ADDR_IOCPLBNTA;
   1156  1.4.2.2  christos 
   1157  1.4.2.2  christos 	ccb->ccb_req.flags = MFII_REQ_TYPE_SCSI;
   1158  1.4.2.2  christos 	ccb->ccb_req.smid = le16toh(ccb->ccb_smid);
   1159  1.4.2.2  christos 
   1160  1.4.2.2  christos 	mfii_start(sc, ccb);
   1161  1.4.2.2  christos }
   1162  1.4.2.2  christos 
   1163  1.4.2.3    martin static int
   1164  1.4.2.2  christos mfii_aen_register(struct mfii_softc *sc)
   1165  1.4.2.2  christos {
   1166  1.4.2.2  christos 	struct mfi_evt_log_info mel;
   1167  1.4.2.2  christos 	struct mfii_ccb *ccb;
   1168  1.4.2.2  christos 	struct mfii_dmamem *mdm;
   1169  1.4.2.2  christos 	int rv;
   1170  1.4.2.2  christos 
   1171  1.4.2.2  christos 	ccb = mfii_get_ccb(sc);
   1172  1.4.2.2  christos 	if (ccb == NULL) {
   1173  1.4.2.2  christos 		printf("%s: unable to allocate ccb for aen\n", DEVNAME(sc));
   1174  1.4.2.2  christos 		return (ENOMEM);
   1175  1.4.2.2  christos 	}
   1176  1.4.2.2  christos 
   1177  1.4.2.2  christos 	memset(&mel, 0, sizeof(mel));
   1178  1.4.2.2  christos 	mfii_scrub_ccb(ccb);
   1179  1.4.2.2  christos 
   1180  1.4.2.2  christos 	rv = mfii_do_mgmt(sc, ccb, MR_DCMD_CTRL_EVENT_GET_INFO, NULL,
   1181  1.4.2.2  christos 	    &mel, sizeof(mel), MFII_DATA_IN, true);
   1182  1.4.2.2  christos 	if (rv != 0) {
   1183  1.4.2.2  christos 		mfii_put_ccb(sc, ccb);
   1184  1.4.2.2  christos 		aprint_error_dev(sc->sc_dev, "unable to get event info\n");
   1185  1.4.2.2  christos 		return (EIO);
   1186  1.4.2.2  christos 	}
   1187  1.4.2.2  christos 
   1188  1.4.2.2  christos 	mdm = mfii_dmamem_alloc(sc, sizeof(struct mfi_evt_detail));
   1189  1.4.2.2  christos 	if (mdm == NULL) {
   1190  1.4.2.2  christos 		mfii_put_ccb(sc, ccb);
   1191  1.4.2.2  christos 		aprint_error_dev(sc->sc_dev, "unable to allocate event data\n");
   1192  1.4.2.2  christos 		return (ENOMEM);
   1193  1.4.2.2  christos 	}
   1194  1.4.2.2  christos 
   1195  1.4.2.2  christos 	/* replay all the events from boot */
   1196  1.4.2.2  christos 	mfii_aen_start(sc, ccb, mdm, le32toh(mel.mel_boot_seq_num));
   1197  1.4.2.2  christos 
   1198  1.4.2.2  christos 	return (0);
   1199  1.4.2.2  christos }
   1200  1.4.2.2  christos 
   1201  1.4.2.3    martin static void
   1202  1.4.2.2  christos mfii_aen_start(struct mfii_softc *sc, struct mfii_ccb *ccb,
   1203  1.4.2.2  christos     struct mfii_dmamem *mdm, uint32_t seq)
   1204  1.4.2.2  christos {
   1205  1.4.2.2  christos 	struct mfi_dcmd_frame *dcmd = mfii_dcmd_frame(ccb);
   1206  1.4.2.2  christos 	struct mfi_frame_header *hdr = &dcmd->mdf_header;
   1207  1.4.2.2  christos 	union mfi_sgl *sgl = &dcmd->mdf_sgl;
   1208  1.4.2.2  christos 	union mfi_evt_class_locale mec;
   1209  1.4.2.2  christos 
   1210  1.4.2.2  christos 	mfii_scrub_ccb(ccb);
   1211  1.4.2.2  christos 	mfii_dcmd_scrub(ccb);
   1212  1.4.2.2  christos 	memset(MFII_DMA_KVA(mdm), 0, MFII_DMA_LEN(mdm));
   1213  1.4.2.2  christos 
   1214  1.4.2.2  christos 	ccb->ccb_cookie = mdm;
   1215  1.4.2.2  christos 	ccb->ccb_done = mfii_aen_done;
   1216  1.4.2.2  christos 	sc->sc_aen_ccb = ccb;
   1217  1.4.2.2  christos 
   1218  1.4.2.2  christos 	mec.mec_members.class = MFI_EVT_CLASS_DEBUG;
   1219  1.4.2.2  christos 	mec.mec_members.reserved = 0;
   1220  1.4.2.2  christos 	mec.mec_members.locale = htole16(MFI_EVT_LOCALE_ALL);
   1221  1.4.2.2  christos 
   1222  1.4.2.2  christos 	hdr->mfh_cmd = MFI_CMD_DCMD;
   1223  1.4.2.2  christos 	hdr->mfh_sg_count = 1;
   1224  1.4.2.2  christos 	hdr->mfh_flags = htole16(MFI_FRAME_DIR_READ | MFI_FRAME_SGL64);
   1225  1.4.2.2  christos 	hdr->mfh_data_len = htole32(MFII_DMA_LEN(mdm));
   1226  1.4.2.2  christos 	dcmd->mdf_opcode = htole32(MR_DCMD_CTRL_EVENT_WAIT);
   1227  1.4.2.2  christos 	dcmd->mdf_mbox.w[0] = htole32(seq);
   1228  1.4.2.2  christos 	dcmd->mdf_mbox.w[1] = htole32(mec.mec_word);
   1229  1.4.2.2  christos 	sgl->sg64[0].addr = htole64(MFII_DMA_DVA(mdm));
   1230  1.4.2.2  christos 	sgl->sg64[0].len = htole32(MFII_DMA_LEN(mdm));
   1231  1.4.2.2  christos 
   1232  1.4.2.2  christos 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(mdm),
   1233  1.4.2.2  christos 	    0, MFII_DMA_LEN(mdm), BUS_DMASYNC_PREREAD);
   1234  1.4.2.2  christos 
   1235  1.4.2.2  christos 	mfii_dcmd_sync(sc, ccb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
   1236  1.4.2.2  christos 	mfii_dcmd_start(sc, ccb);
   1237  1.4.2.2  christos }
   1238  1.4.2.2  christos 
   1239  1.4.2.3    martin static void
   1240  1.4.2.2  christos mfii_aen_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
   1241  1.4.2.2  christos {
   1242  1.4.2.2  christos 	KASSERT(sc->sc_aen_ccb == ccb);
   1243  1.4.2.2  christos 
   1244  1.4.2.2  christos 	/*
   1245  1.4.2.2  christos 	 * defer to a thread with KERNEL_LOCK so we can run autoconf
   1246  1.4.2.2  christos 	 * We shouldn't have more than one AEN command pending at a time,
   1247  1.4.2.2  christos 	 * so no need to lock
   1248  1.4.2.2  christos 	 */
   1249  1.4.2.2  christos 	if (sc->sc_running)
   1250  1.4.2.2  christos 		workqueue_enqueue(sc->sc_aen_wq, &sc->sc_aen_work, NULL);
   1251  1.4.2.2  christos }
   1252  1.4.2.2  christos 
   1253  1.4.2.3    martin static void
   1254  1.4.2.2  christos mfii_aen(struct work *wk, void *arg)
   1255  1.4.2.2  christos {
   1256  1.4.2.2  christos 	struct mfii_softc *sc = arg;
   1257  1.4.2.2  christos 	struct mfii_ccb *ccb = sc->sc_aen_ccb;
   1258  1.4.2.2  christos 	struct mfii_dmamem *mdm = ccb->ccb_cookie;
   1259  1.4.2.2  christos 	const struct mfi_evt_detail *med = MFII_DMA_KVA(mdm);
   1260  1.4.2.2  christos 
   1261  1.4.2.2  christos 	mfii_dcmd_sync(sc, ccb,
   1262  1.4.2.2  christos 	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
   1263  1.4.2.2  christos 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(mdm),
   1264  1.4.2.2  christos 	    0, MFII_DMA_LEN(mdm), BUS_DMASYNC_POSTREAD);
   1265  1.4.2.2  christos 
   1266  1.4.2.2  christos 	DNPRINTF(MFII_D_MISC, "%s: %u %08x %02x %s\n", DEVNAME(sc),
   1267  1.4.2.2  christos 	    le32toh(med->med_seq_num), le32toh(med->med_code),
   1268  1.4.2.2  christos 	    med->med_arg_type, med->med_description);
   1269  1.4.2.2  christos 
   1270  1.4.2.2  christos 	switch (le32toh(med->med_code)) {
   1271  1.4.2.2  christos 	case MR_EVT_PD_INSERTED_EXT:
   1272  1.4.2.2  christos 		if (med->med_arg_type != MR_EVT_ARGS_PD_ADDRESS)
   1273  1.4.2.2  christos 			break;
   1274  1.4.2.2  christos 
   1275  1.4.2.2  christos 		mfii_aen_pd_insert(sc, &med->args.pd_address);
   1276  1.4.2.2  christos 		break;
   1277  1.4.2.2  christos  	case MR_EVT_PD_REMOVED_EXT:
   1278  1.4.2.2  christos 		if (med->med_arg_type != MR_EVT_ARGS_PD_ADDRESS)
   1279  1.4.2.2  christos 			break;
   1280  1.4.2.2  christos 
   1281  1.4.2.2  christos 		mfii_aen_pd_remove(sc, &med->args.pd_address);
   1282  1.4.2.2  christos 		break;
   1283  1.4.2.2  christos 
   1284  1.4.2.2  christos 	case MR_EVT_PD_STATE_CHANGE:
   1285  1.4.2.2  christos 		if (med->med_arg_type != MR_EVT_ARGS_PD_STATE)
   1286  1.4.2.2  christos 			break;
   1287  1.4.2.2  christos 
   1288  1.4.2.2  christos 		mfii_aen_pd_state_change(sc, &med->args.pd_state);
   1289  1.4.2.2  christos 		break;
   1290  1.4.2.2  christos 
   1291  1.4.2.2  christos 	case MR_EVT_LD_CREATED:
   1292  1.4.2.2  christos 	case MR_EVT_LD_DELETED:
   1293  1.4.2.2  christos 		mfii_aen_ld_update(sc);
   1294  1.4.2.2  christos 		break;
   1295  1.4.2.2  christos 
   1296  1.4.2.2  christos 	default:
   1297  1.4.2.2  christos 		break;
   1298  1.4.2.2  christos 	}
   1299  1.4.2.2  christos 
   1300  1.4.2.2  christos 	mfii_aen_start(sc, ccb, mdm, le32toh(med->med_seq_num) + 1);
   1301  1.4.2.2  christos }
   1302  1.4.2.2  christos 
   1303  1.4.2.3    martin static void
   1304  1.4.2.2  christos mfii_aen_pd_insert(struct mfii_softc *sc,
   1305  1.4.2.2  christos     const struct mfi_evtarg_pd_address *pd)
   1306  1.4.2.2  christos {
   1307  1.4.2.2  christos 	printf("%s: physical disk inserted id %d enclosure %d\n", DEVNAME(sc),
   1308  1.4.2.2  christos 	    le16toh(pd->device_id), le16toh(pd->encl_id));
   1309  1.4.2.2  christos }
   1310  1.4.2.2  christos 
   1311  1.4.2.3    martin static void
   1312  1.4.2.2  christos mfii_aen_pd_remove(struct mfii_softc *sc,
   1313  1.4.2.2  christos     const struct mfi_evtarg_pd_address *pd)
   1314  1.4.2.2  christos {
   1315  1.4.2.2  christos 	printf("%s: physical disk removed id %d enclosure %d\n", DEVNAME(sc),
   1316  1.4.2.2  christos 	    le16toh(pd->device_id), le16toh(pd->encl_id));
   1317  1.4.2.2  christos }
   1318  1.4.2.2  christos 
   1319  1.4.2.3    martin static void
   1320  1.4.2.2  christos mfii_aen_pd_state_change(struct mfii_softc *sc,
   1321  1.4.2.2  christos     const struct mfi_evtarg_pd_state *state)
   1322  1.4.2.2  christos {
   1323  1.4.2.2  christos 	return;
   1324  1.4.2.2  christos }
   1325  1.4.2.2  christos 
   1326  1.4.2.3    martin static void
   1327  1.4.2.2  christos mfii_aen_ld_update(struct mfii_softc *sc)
   1328  1.4.2.2  christos {
   1329  1.4.2.2  christos 	int i, target, old, nld;
   1330  1.4.2.2  christos 	int newlds[MFI_MAX_LD];
   1331  1.4.2.2  christos 
   1332  1.4.2.2  christos 	mutex_enter(&sc->sc_lock);
   1333  1.4.2.2  christos 	if (mfii_mgmt(sc, MR_DCMD_LD_GET_LIST, NULL, &sc->sc_ld_list,
   1334  1.4.2.2  christos 	    sizeof(sc->sc_ld_list), MFII_DATA_IN, false) != 0) {
   1335  1.4.2.2  christos 		mutex_exit(&sc->sc_lock);
   1336  1.4.2.2  christos 		DNPRINTF(MFII_D_MISC, "%s: getting list of logical disks failed\n",
   1337  1.4.2.2  christos 		    DEVNAME(sc));
   1338  1.4.2.2  christos 		return;
   1339  1.4.2.2  christos 	}
   1340  1.4.2.2  christos 	mutex_exit(&sc->sc_lock);
   1341  1.4.2.2  christos 
   1342  1.4.2.2  christos 	memset(newlds, -1, sizeof(newlds));
   1343  1.4.2.2  christos 
   1344  1.4.2.2  christos 	for (i = 0; i < sc->sc_ld_list.mll_no_ld; i++) {
   1345  1.4.2.2  christos 		target = sc->sc_ld_list.mll_list[i].mll_ld.mld_target;
   1346  1.4.2.2  christos 		DNPRINTF(MFII_D_MISC, "%s: target %d: state %d\n",
   1347  1.4.2.2  christos 		    DEVNAME(sc), target, sc->sc_ld_list.mll_list[i].mll_state);
   1348  1.4.2.2  christos 		newlds[target] = i;
   1349  1.4.2.2  christos 	}
   1350  1.4.2.2  christos 
   1351  1.4.2.2  christos 	for (i = 0; i < MFI_MAX_LD; i++) {
   1352  1.4.2.2  christos 		old = sc->sc_target_lds[i];
   1353  1.4.2.2  christos 		nld = newlds[i];
   1354  1.4.2.2  christos 
   1355  1.4.2.2  christos 		if (old == -1 && nld != -1) {
   1356  1.4.2.2  christos 			printf("%s: logical drive %d added (target %d)\n",
   1357  1.4.2.2  christos 			    DEVNAME(sc), i, nld);
   1358  1.4.2.2  christos 
   1359  1.4.2.2  christos 			// XXX scsi_probe_target(sc->sc_scsibus, i);
   1360  1.4.2.2  christos 
   1361  1.4.2.2  christos 			mfii_init_ld_sensor(sc, &sc->sc_sensors[i], i);
   1362  1.4.2.2  christos 			mfii_attach_sensor(sc, &sc->sc_sensors[i]);
   1363  1.4.2.2  christos 		} else if (nld == -1 && old != -1) {
   1364  1.4.2.2  christos 			printf("%s: logical drive %d removed (target %d)\n",
   1365  1.4.2.2  christos 			    DEVNAME(sc), i, old);
   1366  1.4.2.2  christos 
   1367  1.4.2.2  christos 			scsipi_target_detach(&sc->sc_chan, i, 0, DETACH_FORCE);
   1368  1.4.2.2  christos 			sysmon_envsys_sensor_detach(sc->sc_sme,
   1369  1.4.2.2  christos 			    &sc->sc_sensors[i]);
   1370  1.4.2.2  christos 		}
   1371  1.4.2.2  christos 	}
   1372  1.4.2.2  christos 
   1373  1.4.2.2  christos 	memcpy(sc->sc_target_lds, newlds, sizeof(sc->sc_target_lds));
   1374  1.4.2.2  christos }
   1375  1.4.2.2  christos 
   1376  1.4.2.3    martin static void
   1377  1.4.2.2  christos mfii_aen_unregister(struct mfii_softc *sc)
   1378  1.4.2.2  christos {
   1379  1.4.2.2  christos 	/* XXX */
   1380  1.4.2.2  christos }
   1381  1.4.2.2  christos 
   1382  1.4.2.3    martin static int
   1383  1.4.2.2  christos mfii_transition_firmware(struct mfii_softc *sc)
   1384  1.4.2.2  christos {
   1385  1.4.2.2  christos 	int32_t			fw_state, cur_state;
   1386  1.4.2.2  christos 	int			max_wait, i;
   1387  1.4.2.2  christos 
   1388  1.4.2.2  christos 	fw_state = mfii_fw_state(sc) & MFI_STATE_MASK;
   1389  1.4.2.2  christos 
   1390  1.4.2.2  christos 	while (fw_state != MFI_STATE_READY) {
   1391  1.4.2.2  christos 		cur_state = fw_state;
   1392  1.4.2.2  christos 		switch (fw_state) {
   1393  1.4.2.2  christos 		case MFI_STATE_FAULT:
   1394  1.4.2.2  christos 			printf("%s: firmware fault\n", DEVNAME(sc));
   1395  1.4.2.2  christos 			return (1);
   1396  1.4.2.2  christos 		case MFI_STATE_WAIT_HANDSHAKE:
   1397  1.4.2.2  christos 			mfii_write(sc, MFI_SKINNY_IDB,
   1398  1.4.2.2  christos 			    MFI_INIT_CLEAR_HANDSHAKE);
   1399  1.4.2.2  christos 			max_wait = 2;
   1400  1.4.2.2  christos 			break;
   1401  1.4.2.2  christos 		case MFI_STATE_OPERATIONAL:
   1402  1.4.2.2  christos 			mfii_write(sc, MFI_SKINNY_IDB, MFI_INIT_READY);
   1403  1.4.2.2  christos 			max_wait = 10;
   1404  1.4.2.2  christos 			break;
   1405  1.4.2.2  christos 		case MFI_STATE_UNDEFINED:
   1406  1.4.2.2  christos 		case MFI_STATE_BB_INIT:
   1407  1.4.2.2  christos 			max_wait = 2;
   1408  1.4.2.2  christos 			break;
   1409  1.4.2.2  christos 		case MFI_STATE_FW_INIT:
   1410  1.4.2.2  christos 		case MFI_STATE_DEVICE_SCAN:
   1411  1.4.2.2  christos 		case MFI_STATE_FLUSH_CACHE:
   1412  1.4.2.2  christos 			max_wait = 20;
   1413  1.4.2.2  christos 			break;
   1414  1.4.2.2  christos 		default:
   1415  1.4.2.2  christos 			printf("%s: unknown firmware state %d\n",
   1416  1.4.2.2  christos 			    DEVNAME(sc), fw_state);
   1417  1.4.2.2  christos 			return (1);
   1418  1.4.2.2  christos 		}
   1419  1.4.2.2  christos 		for (i = 0; i < (max_wait * 10); i++) {
   1420  1.4.2.2  christos 			fw_state = mfii_fw_state(sc) & MFI_STATE_MASK;
   1421  1.4.2.2  christos 			if (fw_state == cur_state)
   1422  1.4.2.2  christos 				DELAY(100000);
   1423  1.4.2.2  christos 			else
   1424  1.4.2.2  christos 				break;
   1425  1.4.2.2  christos 		}
   1426  1.4.2.2  christos 		if (fw_state == cur_state) {
   1427  1.4.2.2  christos 			printf("%s: firmware stuck in state %#x\n",
   1428  1.4.2.2  christos 			    DEVNAME(sc), fw_state);
   1429  1.4.2.2  christos 			return (1);
   1430  1.4.2.2  christos 		}
   1431  1.4.2.2  christos 	}
   1432  1.4.2.2  christos 
   1433  1.4.2.2  christos 	return (0);
   1434  1.4.2.2  christos }
   1435  1.4.2.2  christos 
   1436  1.4.2.3    martin static int
   1437  1.4.2.2  christos mfii_get_info(struct mfii_softc *sc)
   1438  1.4.2.2  christos {
   1439  1.4.2.2  christos 	int i, rv;
   1440  1.4.2.2  christos 
   1441  1.4.2.2  christos 	rv = mfii_mgmt(sc, MR_DCMD_CTRL_GET_INFO, NULL, &sc->sc_info,
   1442  1.4.2.2  christos 	    sizeof(sc->sc_info), MFII_DATA_IN, true);
   1443  1.4.2.2  christos 
   1444  1.4.2.2  christos 	if (rv != 0)
   1445  1.4.2.2  christos 		return (rv);
   1446  1.4.2.2  christos 
   1447  1.4.2.2  christos 	for (i = 0; i < sc->sc_info.mci_image_component_count; i++) {
   1448  1.4.2.2  christos 		DPRINTF("%s: active FW %s Version %s date %s time %s\n",
   1449  1.4.2.2  christos 		    DEVNAME(sc),
   1450  1.4.2.2  christos 		    sc->sc_info.mci_image_component[i].mic_name,
   1451  1.4.2.2  christos 		    sc->sc_info.mci_image_component[i].mic_version,
   1452  1.4.2.2  christos 		    sc->sc_info.mci_image_component[i].mic_build_date,
   1453  1.4.2.2  christos 		    sc->sc_info.mci_image_component[i].mic_build_time);
   1454  1.4.2.2  christos 	}
   1455  1.4.2.2  christos 
   1456  1.4.2.2  christos 	for (i = 0; i < sc->sc_info.mci_pending_image_component_count; i++) {
   1457  1.4.2.2  christos 		DPRINTF("%s: pending FW %s Version %s date %s time %s\n",
   1458  1.4.2.2  christos 		    DEVNAME(sc),
   1459  1.4.2.2  christos 		    sc->sc_info.mci_pending_image_component[i].mic_name,
   1460  1.4.2.2  christos 		    sc->sc_info.mci_pending_image_component[i].mic_version,
   1461  1.4.2.2  christos 		    sc->sc_info.mci_pending_image_component[i].mic_build_date,
   1462  1.4.2.2  christos 		    sc->sc_info.mci_pending_image_component[i].mic_build_time);
   1463  1.4.2.2  christos 	}
   1464  1.4.2.2  christos 
   1465  1.4.2.2  christos 	DPRINTF("%s: max_arms %d max_spans %d max_arrs %d max_lds %d name %s\n",
   1466  1.4.2.2  christos 	    DEVNAME(sc),
   1467  1.4.2.2  christos 	    sc->sc_info.mci_max_arms,
   1468  1.4.2.2  christos 	    sc->sc_info.mci_max_spans,
   1469  1.4.2.2  christos 	    sc->sc_info.mci_max_arrays,
   1470  1.4.2.2  christos 	    sc->sc_info.mci_max_lds,
   1471  1.4.2.2  christos 	    sc->sc_info.mci_product_name);
   1472  1.4.2.2  christos 
   1473  1.4.2.2  christos 	DPRINTF("%s: serial %s present %#x fw time %d max_cmds %d max_sg %d\n",
   1474  1.4.2.2  christos 	    DEVNAME(sc),
   1475  1.4.2.2  christos 	    sc->sc_info.mci_serial_number,
   1476  1.4.2.2  christos 	    sc->sc_info.mci_hw_present,
   1477  1.4.2.2  christos 	    sc->sc_info.mci_current_fw_time,
   1478  1.4.2.2  christos 	    sc->sc_info.mci_max_cmds,
   1479  1.4.2.2  christos 	    sc->sc_info.mci_max_sg_elements);
   1480  1.4.2.2  christos 
   1481  1.4.2.2  christos 	DPRINTF("%s: max_rq %d lds_pres %d lds_deg %d lds_off %d pd_pres %d\n",
   1482  1.4.2.2  christos 	    DEVNAME(sc),
   1483  1.4.2.2  christos 	    sc->sc_info.mci_max_request_size,
   1484  1.4.2.2  christos 	    sc->sc_info.mci_lds_present,
   1485  1.4.2.2  christos 	    sc->sc_info.mci_lds_degraded,
   1486  1.4.2.2  christos 	    sc->sc_info.mci_lds_offline,
   1487  1.4.2.2  christos 	    sc->sc_info.mci_pd_present);
   1488  1.4.2.2  christos 
   1489  1.4.2.2  christos 	DPRINTF("%s: pd_dsk_prs %d pd_dsk_pred_fail %d pd_dsk_fail %d\n",
   1490  1.4.2.2  christos 	    DEVNAME(sc),
   1491  1.4.2.2  christos 	    sc->sc_info.mci_pd_disks_present,
   1492  1.4.2.2  christos 	    sc->sc_info.mci_pd_disks_pred_failure,
   1493  1.4.2.2  christos 	    sc->sc_info.mci_pd_disks_failed);
   1494  1.4.2.2  christos 
   1495  1.4.2.2  christos 	DPRINTF("%s: nvram %d mem %d flash %d\n",
   1496  1.4.2.2  christos 	    DEVNAME(sc),
   1497  1.4.2.2  christos 	    sc->sc_info.mci_nvram_size,
   1498  1.4.2.2  christos 	    sc->sc_info.mci_memory_size,
   1499  1.4.2.2  christos 	    sc->sc_info.mci_flash_size);
   1500  1.4.2.2  christos 
   1501  1.4.2.2  christos 	DPRINTF("%s: ram_cor %d ram_uncor %d clus_all %d clus_act %d\n",
   1502  1.4.2.2  christos 	    DEVNAME(sc),
   1503  1.4.2.2  christos 	    sc->sc_info.mci_ram_correctable_errors,
   1504  1.4.2.2  christos 	    sc->sc_info.mci_ram_uncorrectable_errors,
   1505  1.4.2.2  christos 	    sc->sc_info.mci_cluster_allowed,
   1506  1.4.2.2  christos 	    sc->sc_info.mci_cluster_active);
   1507  1.4.2.2  christos 
   1508  1.4.2.2  christos 	DPRINTF("%s: max_strps_io %d raid_lvl %#x adapt_ops %#x ld_ops %#x\n",
   1509  1.4.2.2  christos 	    DEVNAME(sc),
   1510  1.4.2.2  christos 	    sc->sc_info.mci_max_strips_per_io,
   1511  1.4.2.2  christos 	    sc->sc_info.mci_raid_levels,
   1512  1.4.2.2  christos 	    sc->sc_info.mci_adapter_ops,
   1513  1.4.2.2  christos 	    sc->sc_info.mci_ld_ops);
   1514  1.4.2.2  christos 
   1515  1.4.2.2  christos 	DPRINTF("%s: strp_sz_min %d strp_sz_max %d pd_ops %#x pd_mix %#x\n",
   1516  1.4.2.2  christos 	    DEVNAME(sc),
   1517  1.4.2.2  christos 	    sc->sc_info.mci_stripe_sz_ops.min,
   1518  1.4.2.2  christos 	    sc->sc_info.mci_stripe_sz_ops.max,
   1519  1.4.2.2  christos 	    sc->sc_info.mci_pd_ops,
   1520  1.4.2.2  christos 	    sc->sc_info.mci_pd_mix_support);
   1521  1.4.2.2  christos 
   1522  1.4.2.2  christos 	DPRINTF("%s: ecc_bucket %d pckg_prop %s\n",
   1523  1.4.2.2  christos 	    DEVNAME(sc),
   1524  1.4.2.2  christos 	    sc->sc_info.mci_ecc_bucket_count,
   1525  1.4.2.2  christos 	    sc->sc_info.mci_package_version);
   1526  1.4.2.2  christos 
   1527  1.4.2.2  christos 	DPRINTF("%s: sq_nm %d prd_fail_poll %d intr_thrtl %d intr_thrtl_to %d\n",
   1528  1.4.2.2  christos 	    DEVNAME(sc),
   1529  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_seq_num,
   1530  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_pred_fail_poll_interval,
   1531  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_intr_throttle_cnt,
   1532  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_intr_throttle_timeout);
   1533  1.4.2.2  christos 
   1534  1.4.2.2  christos 	DPRINTF("%s: rbld_rate %d patr_rd_rate %d bgi_rate %d cc_rate %d\n",
   1535  1.4.2.2  christos 	    DEVNAME(sc),
   1536  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_rebuild_rate,
   1537  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_patrol_read_rate,
   1538  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_bgi_rate,
   1539  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_cc_rate);
   1540  1.4.2.2  christos 
   1541  1.4.2.2  christos 	DPRINTF("%s: rc_rate %d ch_flsh %d spin_cnt %d spin_dly %d clus_en %d\n",
   1542  1.4.2.2  christos 	    DEVNAME(sc),
   1543  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_recon_rate,
   1544  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_cache_flush_interval,
   1545  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_spinup_drv_cnt,
   1546  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_spinup_delay,
   1547  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_cluster_enable);
   1548  1.4.2.2  christos 
   1549  1.4.2.2  christos 	DPRINTF("%s: coerc %d alarm %d dis_auto_rbld %d dis_bat_wrn %d ecc %d\n",
   1550  1.4.2.2  christos 	    DEVNAME(sc),
   1551  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_coercion_mode,
   1552  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_alarm_enable,
   1553  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_disable_auto_rebuild,
   1554  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_disable_battery_warn,
   1555  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_ecc_bucket_size);
   1556  1.4.2.2  christos 
   1557  1.4.2.2  christos 	DPRINTF("%s: ecc_leak %d rest_hs %d exp_encl_dev %d\n",
   1558  1.4.2.2  christos 	    DEVNAME(sc),
   1559  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_ecc_bucket_leak_rate,
   1560  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_restore_hotspare_on_insertion,
   1561  1.4.2.2  christos 	    sc->sc_info.mci_properties.mcp_expose_encl_devices);
   1562  1.4.2.2  christos 
   1563  1.4.2.2  christos 	DPRINTF("%s: vendor %#x device %#x subvendor %#x subdevice %#x\n",
   1564  1.4.2.2  christos 	    DEVNAME(sc),
   1565  1.4.2.2  christos 	    sc->sc_info.mci_pci.mip_vendor,
   1566  1.4.2.2  christos 	    sc->sc_info.mci_pci.mip_device,
   1567  1.4.2.2  christos 	    sc->sc_info.mci_pci.mip_subvendor,
   1568  1.4.2.2  christos 	    sc->sc_info.mci_pci.mip_subdevice);
   1569  1.4.2.2  christos 
   1570  1.4.2.2  christos 	DPRINTF("%s: type %#x port_count %d port_addr ",
   1571  1.4.2.2  christos 	    DEVNAME(sc),
   1572  1.4.2.2  christos 	    sc->sc_info.mci_host.mih_type,
   1573  1.4.2.2  christos 	    sc->sc_info.mci_host.mih_port_count);
   1574  1.4.2.2  christos 
   1575  1.4.2.2  christos 	for (i = 0; i < 8; i++)
   1576  1.4.2.2  christos 		DPRINTF("%.0" PRIx64 " ", sc->sc_info.mci_host.mih_port_addr[i]);
   1577  1.4.2.2  christos 	DPRINTF("\n");
   1578  1.4.2.2  christos 
   1579  1.4.2.2  christos 	DPRINTF("%s: type %.x port_count %d port_addr ",
   1580  1.4.2.2  christos 	    DEVNAME(sc),
   1581  1.4.2.2  christos 	    sc->sc_info.mci_device.mid_type,
   1582  1.4.2.2  christos 	    sc->sc_info.mci_device.mid_port_count);
   1583  1.4.2.2  christos 
   1584  1.4.2.2  christos 	for (i = 0; i < 8; i++)
   1585  1.4.2.2  christos 		DPRINTF("%.0" PRIx64 " ", sc->sc_info.mci_device.mid_port_addr[i]);
   1586  1.4.2.2  christos 	DPRINTF("\n");
   1587  1.4.2.2  christos 
   1588  1.4.2.2  christos 	return (0);
   1589  1.4.2.2  christos }
   1590  1.4.2.2  christos 
   1591  1.4.2.3    martin static int
   1592  1.4.2.2  christos mfii_mfa_poll(struct mfii_softc *sc, struct mfii_ccb *ccb)
   1593  1.4.2.2  christos {
   1594  1.4.2.2  christos 	struct mfi_frame_header	*hdr = ccb->ccb_request;
   1595  1.4.2.2  christos 	u_int64_t r;
   1596  1.4.2.2  christos 	int to = 0, rv = 0;
   1597  1.4.2.2  christos 
   1598  1.4.2.2  christos #ifdef DIAGNOSTIC
   1599  1.4.2.2  christos 	if (ccb->ccb_cookie != NULL || ccb->ccb_done != NULL)
   1600  1.4.2.2  christos 		panic("mfii_mfa_poll called with cookie or done set");
   1601  1.4.2.2  christos #endif
   1602  1.4.2.2  christos 
   1603  1.4.2.2  christos 	hdr->mfh_context = ccb->ccb_smid;
   1604  1.4.2.2  christos 	hdr->mfh_cmd_status = MFI_STAT_INVALID_STATUS;
   1605  1.4.2.2  christos 	hdr->mfh_flags |= htole16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
   1606  1.4.2.2  christos 
   1607  1.4.2.2  christos 	r = MFII_REQ_MFA(ccb->ccb_request_dva);
   1608  1.4.2.2  christos 	memcpy(&ccb->ccb_req, &r, sizeof(ccb->ccb_req));
   1609  1.4.2.2  christos 
   1610  1.4.2.2  christos 	mfii_start(sc, ccb);
   1611  1.4.2.2  christos 
   1612  1.4.2.2  christos 	for (;;) {
   1613  1.4.2.2  christos 		bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_requests),
   1614  1.4.2.2  christos 		    ccb->ccb_request_offset, MFII_REQUEST_SIZE,
   1615  1.4.2.2  christos 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
   1616  1.4.2.2  christos 
   1617  1.4.2.2  christos 		if (hdr->mfh_cmd_status != MFI_STAT_INVALID_STATUS)
   1618  1.4.2.2  christos 			break;
   1619  1.4.2.2  christos 
   1620  1.4.2.2  christos 		if (to++ > 5000) { /* XXX 5 seconds busywait sucks */
   1621  1.4.2.2  christos 			printf("%s: timeout on ccb %d\n", DEVNAME(sc),
   1622  1.4.2.2  christos 			    ccb->ccb_smid);
   1623  1.4.2.2  christos 			ccb->ccb_flags |= MFI_CCB_F_ERR;
   1624  1.4.2.2  christos 			rv = 1;
   1625  1.4.2.2  christos 			break;
   1626  1.4.2.2  christos 		}
   1627  1.4.2.2  christos 
   1628  1.4.2.2  christos 		bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_requests),
   1629  1.4.2.2  christos 		    ccb->ccb_request_offset, MFII_REQUEST_SIZE,
   1630  1.4.2.2  christos 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
   1631  1.4.2.2  christos 
   1632  1.4.2.2  christos 		delay(1000);
   1633  1.4.2.2  christos 	}
   1634  1.4.2.2  christos 
   1635  1.4.2.2  christos 	if (ccb->ccb_len > 0) {
   1636  1.4.2.2  christos 		bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap32,
   1637  1.4.2.2  christos 		    0, ccb->ccb_dmamap32->dm_mapsize,
   1638  1.4.2.2  christos 		    (ccb->ccb_direction == MFII_DATA_IN) ?
   1639  1.4.2.2  christos 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
   1640  1.4.2.2  christos 
   1641  1.4.2.2  christos 		bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap32);
   1642  1.4.2.2  christos 	}
   1643  1.4.2.2  christos 
   1644  1.4.2.2  christos 	return (rv);
   1645  1.4.2.2  christos }
   1646  1.4.2.2  christos 
   1647  1.4.2.3    martin static int
   1648  1.4.2.2  christos mfii_poll(struct mfii_softc *sc, struct mfii_ccb *ccb)
   1649  1.4.2.2  christos {
   1650  1.4.2.2  christos 	void (*done)(struct mfii_softc *, struct mfii_ccb *);
   1651  1.4.2.2  christos 	void *cookie;
   1652  1.4.2.2  christos 	int rv = 1;
   1653  1.4.2.2  christos 
   1654  1.4.2.2  christos 	done = ccb->ccb_done;
   1655  1.4.2.2  christos 	cookie = ccb->ccb_cookie;
   1656  1.4.2.2  christos 
   1657  1.4.2.2  christos 	ccb->ccb_done = mfii_poll_done;
   1658  1.4.2.2  christos 	ccb->ccb_cookie = &rv;
   1659  1.4.2.2  christos 
   1660  1.4.2.2  christos 	mfii_start(sc, ccb);
   1661  1.4.2.2  christos 
   1662  1.4.2.2  christos 	do {
   1663  1.4.2.2  christos 		delay(10);
   1664  1.4.2.2  christos 		mfii_postq(sc);
   1665  1.4.2.2  christos 	} while (rv == 1);
   1666  1.4.2.2  christos 
   1667  1.4.2.2  christos 	ccb->ccb_cookie = cookie;
   1668  1.4.2.2  christos 	done(sc, ccb);
   1669  1.4.2.2  christos 
   1670  1.4.2.2  christos 	return (0);
   1671  1.4.2.2  christos }
   1672  1.4.2.2  christos 
   1673  1.4.2.3    martin static void
   1674  1.4.2.2  christos mfii_poll_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
   1675  1.4.2.2  christos {
   1676  1.4.2.2  christos 	int *rv = ccb->ccb_cookie;
   1677  1.4.2.2  christos 
   1678  1.4.2.2  christos 	*rv = 0;
   1679  1.4.2.2  christos }
   1680  1.4.2.2  christos 
   1681  1.4.2.3    martin static int
   1682  1.4.2.2  christos mfii_exec(struct mfii_softc *sc, struct mfii_ccb *ccb)
   1683  1.4.2.2  christos {
   1684  1.4.2.2  christos #ifdef DIAGNOSTIC
   1685  1.4.2.2  christos 	if (ccb->ccb_cookie != NULL || ccb->ccb_done != NULL)
   1686  1.4.2.2  christos 		panic("mfii_exec called with cookie or done set");
   1687  1.4.2.2  christos #endif
   1688  1.4.2.2  christos 
   1689  1.4.2.2  christos 	ccb->ccb_cookie = ccb;
   1690  1.4.2.2  christos 	ccb->ccb_done = mfii_exec_done;
   1691  1.4.2.2  christos 
   1692  1.4.2.2  christos 	mfii_start(sc, ccb);
   1693  1.4.2.2  christos 
   1694  1.4.2.2  christos 	mutex_enter(&ccb->ccb_mtx);
   1695  1.4.2.2  christos 	while (ccb->ccb_cookie != NULL)
   1696  1.4.2.2  christos 		cv_wait(&ccb->ccb_cv, &ccb->ccb_mtx);
   1697  1.4.2.2  christos 	mutex_exit(&ccb->ccb_mtx);
   1698  1.4.2.2  christos 
   1699  1.4.2.2  christos 	return (0);
   1700  1.4.2.2  christos }
   1701  1.4.2.2  christos 
   1702  1.4.2.3    martin static void
   1703  1.4.2.2  christos mfii_exec_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
   1704  1.4.2.2  christos {
   1705  1.4.2.2  christos 	mutex_enter(&ccb->ccb_mtx);
   1706  1.4.2.2  christos 	ccb->ccb_cookie = NULL;
   1707  1.4.2.2  christos 	cv_signal(&ccb->ccb_cv);
   1708  1.4.2.2  christos 	mutex_exit(&ccb->ccb_mtx);
   1709  1.4.2.2  christos }
   1710  1.4.2.2  christos 
   1711  1.4.2.3    martin static int
   1712  1.4.2.2  christos mfii_mgmt(struct mfii_softc *sc, uint32_t opc, const union mfi_mbox *mbox,
   1713  1.4.2.2  christos     void *buf, size_t len, mfii_direction_t dir, bool poll)
   1714  1.4.2.2  christos {
   1715  1.4.2.2  christos 	struct mfii_ccb *ccb;
   1716  1.4.2.2  christos 	int rv;
   1717  1.4.2.2  christos 
   1718  1.4.2.2  christos 	KASSERT(mutex_owned(&sc->sc_lock));
   1719  1.4.2.2  christos 	if (!sc->sc_running)
   1720  1.4.2.2  christos 		return EAGAIN;
   1721  1.4.2.2  christos 
   1722  1.4.2.2  christos 	ccb = mfii_get_ccb(sc);
   1723  1.4.2.2  christos 	if (ccb == NULL)
   1724  1.4.2.2  christos 		return (ENOMEM);
   1725  1.4.2.2  christos 
   1726  1.4.2.2  christos 	mfii_scrub_ccb(ccb);
   1727  1.4.2.2  christos 	rv = mfii_do_mgmt(sc, ccb, opc, mbox, buf, len, dir, poll);
   1728  1.4.2.2  christos 	mfii_put_ccb(sc, ccb);
   1729  1.4.2.2  christos 
   1730  1.4.2.2  christos 	return (rv);
   1731  1.4.2.2  christos }
   1732  1.4.2.2  christos 
   1733  1.4.2.3    martin static int
   1734  1.4.2.2  christos mfii_do_mgmt(struct mfii_softc *sc, struct mfii_ccb *ccb, uint32_t opc,
   1735  1.4.2.2  christos     const union mfi_mbox *mbox, void *buf, size_t len, mfii_direction_t dir,
   1736  1.4.2.2  christos     bool poll)
   1737  1.4.2.2  christos {
   1738  1.4.2.2  christos 	struct mpii_msg_scsi_io *io = ccb->ccb_request;
   1739  1.4.2.2  christos 	struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
   1740  1.4.2.2  christos 	struct mfii_sge *sge = (struct mfii_sge *)(ctx + 1);
   1741  1.4.2.2  christos 	struct mfi_dcmd_frame *dcmd = ccb->ccb_mfi;
   1742  1.4.2.2  christos 	struct mfi_frame_header *hdr = &dcmd->mdf_header;
   1743  1.4.2.2  christos 	int rv = EIO;
   1744  1.4.2.2  christos 
   1745  1.4.2.2  christos 	if (cold)
   1746  1.4.2.2  christos 		poll = true;
   1747  1.4.2.2  christos 
   1748  1.4.2.2  christos 	ccb->ccb_data = buf;
   1749  1.4.2.2  christos 	ccb->ccb_len = len;
   1750  1.4.2.2  christos 	ccb->ccb_direction = dir;
   1751  1.4.2.2  christos 	switch (dir) {
   1752  1.4.2.2  christos 	case MFII_DATA_IN:
   1753  1.4.2.2  christos 		hdr->mfh_flags = htole16(MFI_FRAME_DIR_READ);
   1754  1.4.2.2  christos 		break;
   1755  1.4.2.2  christos 	case MFII_DATA_OUT:
   1756  1.4.2.2  christos 		hdr->mfh_flags = htole16(MFI_FRAME_DIR_WRITE);
   1757  1.4.2.2  christos 		break;
   1758  1.4.2.2  christos 	case MFII_DATA_NONE:
   1759  1.4.2.2  christos 		hdr->mfh_flags = htole16(MFI_FRAME_DIR_NONE);
   1760  1.4.2.2  christos 		break;
   1761  1.4.2.2  christos 	}
   1762  1.4.2.2  christos 
   1763  1.4.2.2  christos 	if (mfii_load_mfa(sc, ccb, &dcmd->mdf_sgl, poll) != 0) {
   1764  1.4.2.2  christos 		rv = ENOMEM;
   1765  1.4.2.2  christos 		goto done;
   1766  1.4.2.2  christos 	}
   1767  1.4.2.2  christos 
   1768  1.4.2.2  christos 	hdr->mfh_cmd = MFI_CMD_DCMD;
   1769  1.4.2.2  christos 	hdr->mfh_context = ccb->ccb_smid;
   1770  1.4.2.2  christos 	hdr->mfh_data_len = htole32(len);
   1771  1.4.2.2  christos 	hdr->mfh_sg_count = ccb->ccb_dmamap32->dm_nsegs;
   1772  1.4.2.2  christos 	KASSERT(!ccb->ccb_dma64);
   1773  1.4.2.2  christos 
   1774  1.4.2.2  christos 	dcmd->mdf_opcode = opc;
   1775  1.4.2.2  christos 	/* handle special opcodes */
   1776  1.4.2.2  christos 	if (mbox != NULL)
   1777  1.4.2.2  christos 		memcpy(&dcmd->mdf_mbox, mbox, sizeof(dcmd->mdf_mbox));
   1778  1.4.2.2  christos 
   1779  1.4.2.2  christos 	io->function = MFII_FUNCTION_PASSTHRU_IO;
   1780  1.4.2.2  christos 	io->sgl_offset0 = ((u_int8_t *)sge - (u_int8_t *)io) / 4;
   1781  1.4.2.2  christos 	io->chain_offset = ((u_int8_t *)sge - (u_int8_t *)io) / 16;
   1782  1.4.2.2  christos 
   1783  1.4.2.2  christos 	sge->sg_addr = htole64(ccb->ccb_mfi_dva);
   1784  1.4.2.2  christos 	sge->sg_len = htole32(MFI_FRAME_SIZE);
   1785  1.4.2.2  christos 	sge->sg_flags = MFII_SGE_CHAIN_ELEMENT | MFII_SGE_ADDR_IOCPLBNTA;
   1786  1.4.2.2  christos 
   1787  1.4.2.2  christos 	ccb->ccb_req.flags = MFII_REQ_TYPE_SCSI;
   1788  1.4.2.2  christos 	ccb->ccb_req.smid = le16toh(ccb->ccb_smid);
   1789  1.4.2.2  christos 
   1790  1.4.2.2  christos 	if (poll) {
   1791  1.4.2.2  christos 		ccb->ccb_done = mfii_empty_done;
   1792  1.4.2.2  christos 		mfii_poll(sc, ccb);
   1793  1.4.2.2  christos 	} else
   1794  1.4.2.2  christos 		mfii_exec(sc, ccb);
   1795  1.4.2.2  christos 
   1796  1.4.2.2  christos 	if (hdr->mfh_cmd_status == MFI_STAT_OK) {
   1797  1.4.2.2  christos 		rv = 0;
   1798  1.4.2.2  christos 	}
   1799  1.4.2.2  christos 
   1800  1.4.2.2  christos done:
   1801  1.4.2.2  christos 	return (rv);
   1802  1.4.2.2  christos }
   1803  1.4.2.2  christos 
   1804  1.4.2.3    martin static void
   1805  1.4.2.2  christos mfii_empty_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
   1806  1.4.2.2  christos {
   1807  1.4.2.2  christos 	return;
   1808  1.4.2.2  christos }
   1809  1.4.2.2  christos 
   1810  1.4.2.3    martin static int
   1811  1.4.2.2  christos mfii_load_mfa(struct mfii_softc *sc, struct mfii_ccb *ccb,
   1812  1.4.2.2  christos     void *sglp, int nosleep)
   1813  1.4.2.2  christos {
   1814  1.4.2.2  christos 	union mfi_sgl *sgl = sglp;
   1815  1.4.2.2  christos 	bus_dmamap_t dmap = ccb->ccb_dmamap32;
   1816  1.4.2.2  christos 	int error;
   1817  1.4.2.2  christos 	int i;
   1818  1.4.2.2  christos 
   1819  1.4.2.2  christos 	KASSERT(!ccb->ccb_dma64);
   1820  1.4.2.2  christos 	if (ccb->ccb_len == 0)
   1821  1.4.2.2  christos 		return (0);
   1822  1.4.2.2  christos 
   1823  1.4.2.2  christos 	error = bus_dmamap_load(sc->sc_dmat, dmap,
   1824  1.4.2.2  christos 	    ccb->ccb_data, ccb->ccb_len, NULL,
   1825  1.4.2.2  christos 	    nosleep ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
   1826  1.4.2.2  christos 	if (error) {
   1827  1.4.2.2  christos 		printf("%s: error %d loading dmamap\n", DEVNAME(sc), error);
   1828  1.4.2.2  christos 		return (1);
   1829  1.4.2.2  christos 	}
   1830  1.4.2.2  christos 
   1831  1.4.2.2  christos 	for (i = 0; i < dmap->dm_nsegs; i++) {
   1832  1.4.2.2  christos 		sgl->sg32[i].addr = htole32(dmap->dm_segs[i].ds_addr);
   1833  1.4.2.2  christos 		sgl->sg32[i].len = htole32(dmap->dm_segs[i].ds_len);
   1834  1.4.2.2  christos 	}
   1835  1.4.2.2  christos 
   1836  1.4.2.2  christos 	bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
   1837  1.4.2.2  christos 	    ccb->ccb_direction == MFII_DATA_OUT ?
   1838  1.4.2.2  christos 	    BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
   1839  1.4.2.2  christos 
   1840  1.4.2.2  christos 	return (0);
   1841  1.4.2.2  christos }
   1842  1.4.2.2  christos 
   1843  1.4.2.3    martin static void
   1844  1.4.2.2  christos mfii_start(struct mfii_softc *sc, struct mfii_ccb *ccb)
   1845  1.4.2.2  christos {
   1846  1.4.2.2  christos 	u_long *r = (u_long *)&ccb->ccb_req;
   1847  1.4.2.2  christos 
   1848  1.4.2.2  christos 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_requests),
   1849  1.4.2.2  christos 	    ccb->ccb_request_offset, MFII_REQUEST_SIZE,
   1850  1.4.2.2  christos 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
   1851  1.4.2.2  christos 
   1852  1.4.2.2  christos #if defined(__LP64__) && 0
   1853  1.4.2.2  christos 	bus_space_write_8(sc->sc_iot, sc->sc_ioh, MFI_IQPL, *r);
   1854  1.4.2.2  christos #else
   1855  1.4.2.2  christos 	mutex_enter(&sc->sc_post_mtx);
   1856  1.4.2.2  christos 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MFI_IQPL, r[0]);
   1857  1.4.2.2  christos 	bus_space_barrier(sc->sc_iot, sc->sc_ioh,
   1858  1.4.2.2  christos 	    MFI_IQPL, 8, BUS_SPACE_BARRIER_WRITE);
   1859  1.4.2.2  christos 
   1860  1.4.2.2  christos 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MFI_IQPH, r[1]);
   1861  1.4.2.2  christos 	bus_space_barrier(sc->sc_iot, sc->sc_ioh,
   1862  1.4.2.2  christos 	    MFI_IQPH, 8, BUS_SPACE_BARRIER_WRITE);
   1863  1.4.2.2  christos 	mutex_exit(&sc->sc_post_mtx);
   1864  1.4.2.2  christos #endif
   1865  1.4.2.2  christos }
   1866  1.4.2.2  christos 
   1867  1.4.2.3    martin static void
   1868  1.4.2.2  christos mfii_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
   1869  1.4.2.2  christos {
   1870  1.4.2.2  christos 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_requests),
   1871  1.4.2.2  christos 	    ccb->ccb_request_offset, MFII_REQUEST_SIZE,
   1872  1.4.2.2  christos 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
   1873  1.4.2.2  christos 
   1874  1.4.2.2  christos 	if (ccb->ccb_sgl_len > 0) {
   1875  1.4.2.2  christos 		bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_sgl),
   1876  1.4.2.2  christos 		    ccb->ccb_sgl_offset, ccb->ccb_sgl_len,
   1877  1.4.2.2  christos 		    BUS_DMASYNC_POSTWRITE);
   1878  1.4.2.2  christos 	}
   1879  1.4.2.2  christos 
   1880  1.4.2.2  christos 	if (ccb->ccb_dma64) {
   1881  1.4.2.2  christos 		KASSERT(ccb->ccb_len > 0);
   1882  1.4.2.2  christos 		bus_dmamap_sync(sc->sc_dmat64, ccb->ccb_dmamap64,
   1883  1.4.2.2  christos 		    0, ccb->ccb_dmamap64->dm_mapsize,
   1884  1.4.2.2  christos 		    (ccb->ccb_direction == MFII_DATA_IN) ?
   1885  1.4.2.2  christos 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
   1886  1.4.2.2  christos 
   1887  1.4.2.2  christos 		bus_dmamap_unload(sc->sc_dmat64, ccb->ccb_dmamap64);
   1888  1.4.2.2  christos 	} else if (ccb->ccb_len > 0) {
   1889  1.4.2.2  christos 		bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap32,
   1890  1.4.2.2  christos 		    0, ccb->ccb_dmamap32->dm_mapsize,
   1891  1.4.2.2  christos 		    (ccb->ccb_direction == MFII_DATA_IN) ?
   1892  1.4.2.2  christos 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
   1893  1.4.2.2  christos 
   1894  1.4.2.2  christos 		bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap32);
   1895  1.4.2.2  christos 	}
   1896  1.4.2.2  christos 
   1897  1.4.2.2  christos 	ccb->ccb_done(sc, ccb);
   1898  1.4.2.2  christos }
   1899  1.4.2.2  christos 
   1900  1.4.2.3    martin static int
   1901  1.4.2.2  christos mfii_initialise_firmware(struct mfii_softc *sc)
   1902  1.4.2.2  christos {
   1903  1.4.2.2  christos 	struct mpii_msg_iocinit_request *iiq;
   1904  1.4.2.2  christos 	struct mfii_dmamem *m;
   1905  1.4.2.2  christos 	struct mfii_ccb *ccb;
   1906  1.4.2.2  christos 	struct mfi_init_frame *init;
   1907  1.4.2.2  christos 	int rv;
   1908  1.4.2.2  christos 
   1909  1.4.2.2  christos 	m = mfii_dmamem_alloc(sc, sizeof(*iiq));
   1910  1.4.2.2  christos 	if (m == NULL)
   1911  1.4.2.2  christos 		return (1);
   1912  1.4.2.2  christos 
   1913  1.4.2.2  christos 	iiq = MFII_DMA_KVA(m);
   1914  1.4.2.2  christos 	memset(iiq, 0, sizeof(*iiq));
   1915  1.4.2.2  christos 
   1916  1.4.2.2  christos 	iiq->function = MPII_FUNCTION_IOC_INIT;
   1917  1.4.2.2  christos 	iiq->whoinit = MPII_WHOINIT_HOST_DRIVER;
   1918  1.4.2.2  christos 
   1919  1.4.2.2  christos 	iiq->msg_version_maj = 0x02;
   1920  1.4.2.2  christos 	iiq->msg_version_min = 0x00;
   1921  1.4.2.2  christos 	iiq->hdr_version_unit = 0x10;
   1922  1.4.2.2  christos 	iiq->hdr_version_dev = 0x0;
   1923  1.4.2.2  christos 
   1924  1.4.2.2  christos 	iiq->system_request_frame_size = htole16(MFII_REQUEST_SIZE / 4);
   1925  1.4.2.2  christos 
   1926  1.4.2.2  christos 	iiq->reply_descriptor_post_queue_depth =
   1927  1.4.2.2  christos 	    htole16(sc->sc_reply_postq_depth);
   1928  1.4.2.2  christos 	iiq->reply_free_queue_depth = htole16(0);
   1929  1.4.2.2  christos 
   1930  1.4.2.2  christos 	iiq->sense_buffer_address_high = htole32(
   1931  1.4.2.2  christos 	    MFII_DMA_DVA(sc->sc_sense) >> 32);
   1932  1.4.2.2  christos 
   1933  1.4.2.2  christos 	iiq->reply_descriptor_post_queue_address_lo =
   1934  1.4.2.2  christos 	    htole32(MFII_DMA_DVA(sc->sc_reply_postq));
   1935  1.4.2.2  christos 	iiq->reply_descriptor_post_queue_address_hi =
   1936  1.4.2.2  christos 	    htole32(MFII_DMA_DVA(sc->sc_reply_postq) >> 32);
   1937  1.4.2.2  christos 
   1938  1.4.2.2  christos 	iiq->system_request_frame_base_address_lo =
   1939  1.4.2.2  christos 	    htole32(MFII_DMA_DVA(sc->sc_requests));
   1940  1.4.2.2  christos 	iiq->system_request_frame_base_address_hi =
   1941  1.4.2.2  christos 	    htole32(MFII_DMA_DVA(sc->sc_requests) >> 32);
   1942  1.4.2.2  christos 
   1943  1.4.2.2  christos 	iiq->timestamp = htole64(time_uptime);
   1944  1.4.2.2  christos 
   1945  1.4.2.2  christos 	ccb = mfii_get_ccb(sc);
   1946  1.4.2.2  christos 	if (ccb == NULL) {
   1947  1.4.2.2  christos 		/* shouldn't ever run out of ccbs during attach */
   1948  1.4.2.2  christos 		return (1);
   1949  1.4.2.2  christos 	}
   1950  1.4.2.2  christos 	mfii_scrub_ccb(ccb);
   1951  1.4.2.2  christos 	init = ccb->ccb_request;
   1952  1.4.2.2  christos 
   1953  1.4.2.2  christos 	init->mif_header.mfh_cmd = MFI_CMD_INIT;
   1954  1.4.2.2  christos 	init->mif_header.mfh_data_len = htole32(sizeof(*iiq));
   1955  1.4.2.2  christos 	init->mif_qinfo_new_addr_lo = htole32(MFII_DMA_DVA(m));
   1956  1.4.2.2  christos 	init->mif_qinfo_new_addr_hi = htole32((uint64_t)MFII_DMA_DVA(m) >> 32);
   1957  1.4.2.2  christos 
   1958  1.4.2.2  christos 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_reply_postq),
   1959  1.4.2.2  christos 	    0, MFII_DMA_LEN(sc->sc_reply_postq),
   1960  1.4.2.2  christos 	    BUS_DMASYNC_PREREAD);
   1961  1.4.2.2  christos 
   1962  1.4.2.2  christos 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(m),
   1963  1.4.2.2  christos 	    0, sizeof(*iiq), BUS_DMASYNC_PREREAD);
   1964  1.4.2.2  christos 
   1965  1.4.2.2  christos 	rv = mfii_mfa_poll(sc, ccb);
   1966  1.4.2.2  christos 
   1967  1.4.2.2  christos 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(m),
   1968  1.4.2.2  christos 	    0, sizeof(*iiq), BUS_DMASYNC_POSTREAD);
   1969  1.4.2.2  christos 
   1970  1.4.2.2  christos 	mfii_put_ccb(sc, ccb);
   1971  1.4.2.2  christos 	mfii_dmamem_free(sc, m);
   1972  1.4.2.2  christos 
   1973  1.4.2.2  christos 	return (rv);
   1974  1.4.2.2  christos }
   1975  1.4.2.2  christos 
   1976  1.4.2.3    martin static int
   1977  1.4.2.2  christos mfii_my_intr(struct mfii_softc *sc)
   1978  1.4.2.2  christos {
   1979  1.4.2.2  christos 	u_int32_t status;
   1980  1.4.2.2  christos 
   1981  1.4.2.2  christos 	status = mfii_read(sc, MFI_OSTS);
   1982  1.4.2.2  christos 
   1983  1.4.2.2  christos 	DNPRINTF(MFII_D_INTR, "%s: intr status 0x%x\n", DEVNAME(sc), status);
   1984  1.4.2.2  christos 	if (ISSET(status, 0x1)) {
   1985  1.4.2.2  christos 		mfii_write(sc, MFI_OSTS, status);
   1986  1.4.2.2  christos 		return (1);
   1987  1.4.2.2  christos 	}
   1988  1.4.2.2  christos 
   1989  1.4.2.2  christos 	return (ISSET(status, MFII_OSTS_INTR_VALID) ? 1 : 0);
   1990  1.4.2.2  christos }
   1991  1.4.2.2  christos 
   1992  1.4.2.3    martin static int
   1993  1.4.2.2  christos mfii_intr(void *arg)
   1994  1.4.2.2  christos {
   1995  1.4.2.2  christos 	struct mfii_softc *sc = arg;
   1996  1.4.2.2  christos 
   1997  1.4.2.2  christos 	if (!mfii_my_intr(sc))
   1998  1.4.2.2  christos 		return (0);
   1999  1.4.2.2  christos 
   2000  1.4.2.2  christos 	mfii_postq(sc);
   2001  1.4.2.2  christos 
   2002  1.4.2.2  christos 	return (1);
   2003  1.4.2.2  christos }
   2004  1.4.2.2  christos 
   2005  1.4.2.3    martin static void
   2006  1.4.2.2  christos mfii_postq(struct mfii_softc *sc)
   2007  1.4.2.2  christos {
   2008  1.4.2.2  christos 	struct mfii_ccb_list ccbs = SIMPLEQ_HEAD_INITIALIZER(ccbs);
   2009  1.4.2.2  christos 	struct mpii_reply_descr *postq = MFII_DMA_KVA(sc->sc_reply_postq);
   2010  1.4.2.2  christos 	struct mpii_reply_descr *rdp;
   2011  1.4.2.2  christos 	struct mfii_ccb *ccb;
   2012  1.4.2.2  christos 	int rpi = 0;
   2013  1.4.2.2  christos 
   2014  1.4.2.2  christos 	mutex_enter(&sc->sc_reply_postq_mtx);
   2015  1.4.2.2  christos 
   2016  1.4.2.2  christos 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_reply_postq),
   2017  1.4.2.2  christos 	    0, MFII_DMA_LEN(sc->sc_reply_postq),
   2018  1.4.2.2  christos 	    BUS_DMASYNC_POSTREAD);
   2019  1.4.2.2  christos 
   2020  1.4.2.2  christos 	for (;;) {
   2021  1.4.2.2  christos 		rdp = &postq[sc->sc_reply_postq_index];
   2022  1.4.2.2  christos 		DNPRINTF(MFII_D_INTR, "%s: mfii_postq index %d flags 0x%x data 0x%x\n",
   2023  1.4.2.2  christos 		    DEVNAME(sc), sc->sc_reply_postq_index, rdp->reply_flags,
   2024  1.4.2.2  christos 			rdp->data == 0xffffffff);
   2025  1.4.2.2  christos 		if ((rdp->reply_flags & MPII_REPLY_DESCR_TYPE_MASK) ==
   2026  1.4.2.2  christos 		    MPII_REPLY_DESCR_UNUSED)
   2027  1.4.2.2  christos 			break;
   2028  1.4.2.2  christos 		if (rdp->data == 0xffffffff) {
   2029  1.4.2.2  christos 			/*
   2030  1.4.2.2  christos 			 * ioc is still writing to the reply post queue
   2031  1.4.2.2  christos 			 * race condition - bail!
   2032  1.4.2.2  christos 			 */
   2033  1.4.2.2  christos 			break;
   2034  1.4.2.2  christos 		}
   2035  1.4.2.2  christos 
   2036  1.4.2.2  christos 		ccb = &sc->sc_ccb[le16toh(rdp->smid) - 1];
   2037  1.4.2.2  christos 		SIMPLEQ_INSERT_TAIL(&ccbs, ccb, ccb_link);
   2038  1.4.2.2  christos 		memset(rdp, 0xff, sizeof(*rdp));
   2039  1.4.2.2  christos 
   2040  1.4.2.2  christos 		sc->sc_reply_postq_index++;
   2041  1.4.2.2  christos 		sc->sc_reply_postq_index %= sc->sc_reply_postq_depth;
   2042  1.4.2.2  christos 		rpi = 1;
   2043  1.4.2.2  christos 	}
   2044  1.4.2.2  christos 
   2045  1.4.2.2  christos 	bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_reply_postq),
   2046  1.4.2.2  christos 	    0, MFII_DMA_LEN(sc->sc_reply_postq),
   2047  1.4.2.2  christos 	    BUS_DMASYNC_PREREAD);
   2048  1.4.2.2  christos 
   2049  1.4.2.2  christos 	if (rpi)
   2050  1.4.2.2  christos 		mfii_write(sc, MFII_RPI, sc->sc_reply_postq_index);
   2051  1.4.2.2  christos 
   2052  1.4.2.2  christos 	mutex_exit(&sc->sc_reply_postq_mtx);
   2053  1.4.2.2  christos 
   2054  1.4.2.2  christos 	while ((ccb = SIMPLEQ_FIRST(&ccbs)) != NULL) {
   2055  1.4.2.2  christos 		SIMPLEQ_REMOVE_HEAD(&ccbs, ccb_link);
   2056  1.4.2.2  christos 		mfii_done(sc, ccb);
   2057  1.4.2.2  christos 	}
   2058  1.4.2.2  christos }
   2059  1.4.2.2  christos 
   2060  1.4.2.3    martin static void
   2061  1.4.2.2  christos mfii_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
   2062  1.4.2.2  christos     void *arg)
   2063  1.4.2.2  christos {
   2064  1.4.2.2  christos 	struct scsipi_periph    *periph;
   2065  1.4.2.2  christos 	struct scsipi_xfer	*xs;
   2066  1.4.2.2  christos 	struct scsipi_adapter   *adapt = chan->chan_adapter;
   2067  1.4.2.2  christos 	struct mfii_softc	*sc = device_private(adapt->adapt_dev);
   2068  1.4.2.2  christos 	struct mfii_ccb *ccb;
   2069  1.4.2.2  christos 	int timeout;
   2070  1.4.2.2  christos 	int target;
   2071  1.4.2.2  christos 
   2072  1.4.2.2  christos 	switch(req) {
   2073  1.4.2.2  christos 		case ADAPTER_REQ_GROW_RESOURCES:
   2074  1.4.2.2  christos 		/* Not supported. */
   2075  1.4.2.2  christos 		return;
   2076  1.4.2.2  christos 	case ADAPTER_REQ_SET_XFER_MODE:
   2077  1.4.2.2  christos 	{
   2078  1.4.2.2  christos 		struct scsipi_xfer_mode *xm = arg;
   2079  1.4.2.2  christos 		xm->xm_mode = PERIPH_CAP_TQING;
   2080  1.4.2.2  christos 		xm->xm_period = 0;
   2081  1.4.2.2  christos 		xm->xm_offset = 0;
   2082  1.4.2.2  christos 		scsipi_async_event(&sc->sc_chan, ASYNC_EVENT_XFER_MODE, xm);
   2083  1.4.2.2  christos 		return;
   2084  1.4.2.2  christos 	}
   2085  1.4.2.2  christos 	case ADAPTER_REQ_RUN_XFER:
   2086  1.4.2.2  christos 		break;
   2087  1.4.2.2  christos 	}
   2088  1.4.2.2  christos 
   2089  1.4.2.2  christos 	xs = arg;
   2090  1.4.2.2  christos 	periph = xs->xs_periph;
   2091  1.4.2.2  christos 	target = periph->periph_target;
   2092  1.4.2.2  christos 
   2093  1.4.2.2  christos 	if (target >= MFI_MAX_LD || !sc->sc_ld[target].ld_present ||
   2094  1.4.2.2  christos 	    periph->periph_lun != 0) {
   2095  1.4.2.2  christos 		xs->error = XS_SELTIMEOUT;
   2096  1.4.2.2  christos 		scsipi_done(xs);
   2097  1.4.2.2  christos 		return;
   2098  1.4.2.2  christos 	}
   2099  1.4.2.2  christos 
   2100  1.4.2.2  christos 	if ((xs->cmd->opcode == SCSI_SYNCHRONIZE_CACHE_10 ||
   2101  1.4.2.2  christos 	    xs->cmd->opcode == SCSI_SYNCHRONIZE_CACHE_16) && sc->sc_bbuok) {
   2102  1.4.2.2  christos 		/* the cache is stable storage, don't flush */
   2103  1.4.2.2  christos 		xs->error = XS_NOERROR;
   2104  1.4.2.2  christos 		xs->status = SCSI_OK;
   2105  1.4.2.2  christos 		xs->resid = 0;
   2106  1.4.2.2  christos 		scsipi_done(xs);
   2107  1.4.2.2  christos 		return;
   2108  1.4.2.2  christos 	}
   2109  1.4.2.2  christos 
   2110  1.4.2.2  christos 	ccb = mfii_get_ccb(sc);
   2111  1.4.2.2  christos 	if (ccb == NULL) {
   2112  1.4.2.2  christos 		xs->error = XS_RESOURCE_SHORTAGE;
   2113  1.4.2.2  christos 		scsipi_done(xs);
   2114  1.4.2.2  christos 		return;
   2115  1.4.2.2  christos 	}
   2116  1.4.2.2  christos 	mfii_scrub_ccb(ccb);
   2117  1.4.2.2  christos 	ccb->ccb_cookie = xs;
   2118  1.4.2.2  christos 	ccb->ccb_done = mfii_scsi_cmd_done;
   2119  1.4.2.2  christos 	ccb->ccb_data = xs->data;
   2120  1.4.2.2  christos 	ccb->ccb_len = xs->datalen;
   2121  1.4.2.2  christos 
   2122  1.4.2.2  christos 	timeout = mstohz(xs->timeout);
   2123  1.4.2.2  christos 	if (timeout == 0)
   2124  1.4.2.2  christos 		timeout = 1;
   2125  1.4.2.2  christos 	callout_reset(&xs->xs_callout, timeout, mfii_scsi_cmd_tmo, ccb);
   2126  1.4.2.2  christos 
   2127  1.4.2.2  christos 	switch (xs->cmd->opcode) {
   2128  1.4.2.2  christos 	case SCSI_READ_6_COMMAND:
   2129  1.4.2.2  christos 	case READ_10:
   2130  1.4.2.2  christos 	case READ_12:
   2131  1.4.2.2  christos 	case READ_16:
   2132  1.4.2.2  christos 	case SCSI_WRITE_6_COMMAND:
   2133  1.4.2.2  christos 	case WRITE_10:
   2134  1.4.2.2  christos 	case WRITE_12:
   2135  1.4.2.2  christos 	case WRITE_16:
   2136  1.4.2.2  christos 		if (mfii_scsi_cmd_io(sc, ccb, xs) != 0)
   2137  1.4.2.2  christos 			goto stuffup;
   2138  1.4.2.2  christos 		break;
   2139  1.4.2.2  christos 
   2140  1.4.2.2  christos 	default:
   2141  1.4.2.2  christos 		if (mfii_scsi_cmd_cdb(sc, ccb, xs) != 0)
   2142  1.4.2.2  christos 			goto stuffup;
   2143  1.4.2.2  christos 		break;
   2144  1.4.2.2  christos 	}
   2145  1.4.2.2  christos 
   2146  1.4.2.2  christos 	xs->error = XS_NOERROR;
   2147  1.4.2.2  christos 	xs->resid = 0;
   2148  1.4.2.2  christos 
   2149  1.4.2.2  christos 	DNPRINTF(MFII_D_CMD, "%s: start io %d cmd %d\n", DEVNAME(sc), target,
   2150  1.4.2.2  christos 	    xs->cmd->opcode);
   2151  1.4.2.2  christos 
   2152  1.4.2.2  christos 	if (xs->xs_control & XS_CTL_POLL) {
   2153  1.4.2.2  christos 		if (mfii_poll(sc, ccb) != 0)
   2154  1.4.2.2  christos 			goto stuffup;
   2155  1.4.2.2  christos 		return;
   2156  1.4.2.2  christos 	}
   2157  1.4.2.2  christos 
   2158  1.4.2.2  christos 	mfii_start(sc, ccb);
   2159  1.4.2.2  christos 
   2160  1.4.2.2  christos 	return;
   2161  1.4.2.2  christos 
   2162  1.4.2.2  christos stuffup:
   2163  1.4.2.2  christos 	xs->error = XS_DRIVER_STUFFUP;
   2164  1.4.2.2  christos 	scsipi_done(xs);
   2165  1.4.2.2  christos 	mfii_put_ccb(sc, ccb);
   2166  1.4.2.2  christos }
   2167  1.4.2.2  christos 
   2168  1.4.2.3    martin static void
   2169  1.4.2.2  christos mfii_scsi_cmd_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
   2170  1.4.2.2  christos {
   2171  1.4.2.2  christos 	struct scsipi_xfer *xs = ccb->ccb_cookie;
   2172  1.4.2.2  christos 	struct mpii_msg_scsi_io *io = ccb->ccb_request;
   2173  1.4.2.2  christos 	struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
   2174  1.4.2.2  christos 
   2175  1.4.2.2  christos 	if (callout_stop(&xs->xs_callout) != 0)
   2176  1.4.2.2  christos 		return;
   2177  1.4.2.2  christos 
   2178  1.4.2.2  christos 	switch (ctx->status) {
   2179  1.4.2.2  christos 	case MFI_STAT_OK:
   2180  1.4.2.2  christos 		break;
   2181  1.4.2.2  christos 
   2182  1.4.2.2  christos 	case MFI_STAT_SCSI_DONE_WITH_ERROR:
   2183  1.4.2.2  christos 		xs->error = XS_SENSE;
   2184  1.4.2.2  christos 		memset(&xs->sense, 0, sizeof(xs->sense));
   2185  1.4.2.2  christos 		memcpy(&xs->sense, ccb->ccb_sense, sizeof(xs->sense));
   2186  1.4.2.2  christos 		break;
   2187  1.4.2.2  christos 
   2188  1.4.2.2  christos 	case MFI_STAT_LD_OFFLINE:
   2189  1.4.2.2  christos 	case MFI_STAT_DEVICE_NOT_FOUND:
   2190  1.4.2.2  christos 		xs->error = XS_SELTIMEOUT;
   2191  1.4.2.2  christos 		break;
   2192  1.4.2.2  christos 
   2193  1.4.2.2  christos 	default:
   2194  1.4.2.2  christos 		xs->error = XS_DRIVER_STUFFUP;
   2195  1.4.2.2  christos 		break;
   2196  1.4.2.2  christos 	}
   2197  1.4.2.2  christos 
   2198  1.4.2.2  christos 	scsipi_done(xs);
   2199  1.4.2.2  christos 	mfii_put_ccb(sc, ccb);
   2200  1.4.2.2  christos }
   2201  1.4.2.2  christos 
   2202  1.4.2.3    martin static int
   2203  1.4.2.2  christos mfii_scsi_cmd_io(struct mfii_softc *sc, struct mfii_ccb *ccb,
   2204  1.4.2.2  christos     struct scsipi_xfer *xs)
   2205  1.4.2.2  christos {
   2206  1.4.2.2  christos 	struct scsipi_periph *periph = xs->xs_periph;
   2207  1.4.2.2  christos 	struct mpii_msg_scsi_io *io = ccb->ccb_request;
   2208  1.4.2.2  christos 	struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
   2209  1.4.2.2  christos 	int segs;
   2210  1.4.2.2  christos 
   2211  1.4.2.2  christos 	io->dev_handle = htole16(periph->periph_target);
   2212  1.4.2.2  christos 	io->function = MFII_FUNCTION_LDIO_REQUEST;
   2213  1.4.2.2  christos 	io->sense_buffer_low_address = htole32(ccb->ccb_sense_dva);
   2214  1.4.2.2  christos 	io->sgl_flags = htole16(0x02); /* XXX */
   2215  1.4.2.2  christos 	io->sense_buffer_length = sizeof(xs->sense);
   2216  1.4.2.2  christos 	io->sgl_offset0 = (sizeof(*io) + sizeof(*ctx)) / 4;
   2217  1.4.2.2  christos 	io->data_length = htole32(xs->datalen);
   2218  1.4.2.2  christos 	io->io_flags = htole16(xs->cmdlen);
   2219  1.4.2.2  christos 	switch (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
   2220  1.4.2.2  christos 	case XS_CTL_DATA_IN:
   2221  1.4.2.2  christos 		ccb->ccb_direction = MFII_DATA_IN;
   2222  1.4.2.2  christos 		io->direction = MPII_SCSIIO_DIR_READ;
   2223  1.4.2.2  christos 		break;
   2224  1.4.2.2  christos 	case XS_CTL_DATA_OUT:
   2225  1.4.2.2  christos 		ccb->ccb_direction = MFII_DATA_OUT;
   2226  1.4.2.2  christos 		io->direction = MPII_SCSIIO_DIR_WRITE;
   2227  1.4.2.2  christos 		break;
   2228  1.4.2.2  christos 	default:
   2229  1.4.2.2  christos 		ccb->ccb_direction = MFII_DATA_NONE;
   2230  1.4.2.2  christos 		io->direction = MPII_SCSIIO_DIR_NONE;
   2231  1.4.2.2  christos 		break;
   2232  1.4.2.2  christos 	}
   2233  1.4.2.2  christos 	memcpy(io->cdb, xs->cmd, xs->cmdlen);
   2234  1.4.2.2  christos 
   2235  1.4.2.2  christos 	ctx->type_nseg = sc->sc_iop->ldio_ctx_type_nseg;
   2236  1.4.2.2  christos 	ctx->timeout_value = htole16(0x14); /* XXX */
   2237  1.4.2.2  christos 	ctx->reg_lock_flags = htole16(sc->sc_iop->ldio_ctx_reg_lock_flags);
   2238  1.4.2.2  christos 	ctx->virtual_disk_target_id = htole16(periph->periph_target);
   2239  1.4.2.2  christos 
   2240  1.4.2.2  christos 	if (mfii_load_ccb(sc, ccb, ctx + 1,
   2241  1.4.2.2  christos 	    ISSET(xs->xs_control, XS_CTL_NOSLEEP)) != 0)
   2242  1.4.2.2  christos 		return (1);
   2243  1.4.2.2  christos 
   2244  1.4.2.2  christos 	KASSERT(ccb->ccb_len == 0 || ccb->ccb_dma64);
   2245  1.4.2.2  christos 	segs = (ccb->ccb_len == 0) ? 0 : ccb->ccb_dmamap64->dm_nsegs;
   2246  1.4.2.2  christos 	switch (sc->sc_iop->num_sge_loc) {
   2247  1.4.2.2  christos 	case MFII_IOP_NUM_SGE_LOC_ORIG:
   2248  1.4.2.2  christos 		ctx->num_sge = segs;
   2249  1.4.2.2  christos 		break;
   2250  1.4.2.2  christos 	case MFII_IOP_NUM_SGE_LOC_35:
   2251  1.4.2.2  christos 		/* 12 bit field, but we're only using the lower 8 */
   2252  1.4.2.2  christos 		ctx->span_arm = segs;
   2253  1.4.2.2  christos 		break;
   2254  1.4.2.2  christos 	}
   2255  1.4.2.2  christos 
   2256  1.4.2.2  christos 	ccb->ccb_req.flags = sc->sc_iop->ldio_req_type;
   2257  1.4.2.2  christos 	ccb->ccb_req.smid = le16toh(ccb->ccb_smid);
   2258  1.4.2.2  christos 
   2259  1.4.2.2  christos 	return (0);
   2260  1.4.2.2  christos }
   2261  1.4.2.2  christos 
   2262  1.4.2.3    martin static int
   2263  1.4.2.2  christos mfii_scsi_cmd_cdb(struct mfii_softc *sc, struct mfii_ccb *ccb,
   2264  1.4.2.2  christos     struct scsipi_xfer *xs)
   2265  1.4.2.2  christos {
   2266  1.4.2.2  christos 	struct scsipi_periph *periph = xs->xs_periph;
   2267  1.4.2.2  christos 	struct mpii_msg_scsi_io *io = ccb->ccb_request;
   2268  1.4.2.2  christos 	struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
   2269  1.4.2.2  christos 
   2270  1.4.2.2  christos 	io->dev_handle = htole16(periph->periph_target);
   2271  1.4.2.2  christos 	io->function = MFII_FUNCTION_LDIO_REQUEST;
   2272  1.4.2.2  christos 	io->sense_buffer_low_address = htole32(ccb->ccb_sense_dva);
   2273  1.4.2.2  christos 	io->sgl_flags = htole16(0x02); /* XXX */
   2274  1.4.2.2  christos 	io->sense_buffer_length = sizeof(xs->sense);
   2275  1.4.2.2  christos 	io->sgl_offset0 = (sizeof(*io) + sizeof(*ctx)) / 4;
   2276  1.4.2.2  christos 	io->data_length = htole32(xs->datalen);
   2277  1.4.2.2  christos 	io->io_flags = htole16(xs->cmdlen);
   2278  1.4.2.2  christos 	io->lun[0] = htobe16(periph->periph_lun);
   2279  1.4.2.2  christos 	switch (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
   2280  1.4.2.2  christos 	case XS_CTL_DATA_IN:
   2281  1.4.2.2  christos 		ccb->ccb_direction = MFII_DATA_IN;
   2282  1.4.2.2  christos 		io->direction = MPII_SCSIIO_DIR_READ;
   2283  1.4.2.2  christos 		break;
   2284  1.4.2.2  christos 	case XS_CTL_DATA_OUT:
   2285  1.4.2.2  christos 		ccb->ccb_direction = MFII_DATA_OUT;
   2286  1.4.2.2  christos 		io->direction = MPII_SCSIIO_DIR_WRITE;
   2287  1.4.2.2  christos 		break;
   2288  1.4.2.2  christos 	default:
   2289  1.4.2.2  christos 		ccb->ccb_direction = MFII_DATA_NONE;
   2290  1.4.2.2  christos 		io->direction = MPII_SCSIIO_DIR_NONE;
   2291  1.4.2.2  christos 		break;
   2292  1.4.2.2  christos 	}
   2293  1.4.2.2  christos 	memcpy(io->cdb, xs->cmd, xs->cmdlen);
   2294  1.4.2.2  christos 
   2295  1.4.2.2  christos 	ctx->virtual_disk_target_id = htole16(periph->periph_target);
   2296  1.4.2.2  christos 
   2297  1.4.2.2  christos 	if (mfii_load_ccb(sc, ccb, ctx + 1,
   2298  1.4.2.2  christos 	    ISSET(xs->xs_control, XS_CTL_NOSLEEP)) != 0)
   2299  1.4.2.2  christos 		return (1);
   2300  1.4.2.2  christos 
   2301  1.4.2.2  christos 	ctx->num_sge = (ccb->ccb_len == 0) ? 0 : ccb->ccb_dmamap64->dm_nsegs;
   2302  1.4.2.2  christos 	KASSERT(ccb->ccb_len == 0 || ccb->ccb_dma64);
   2303  1.4.2.2  christos 
   2304  1.4.2.2  christos 	ccb->ccb_req.flags = MFII_REQ_TYPE_SCSI;
   2305  1.4.2.2  christos 	ccb->ccb_req.smid = le16toh(ccb->ccb_smid);
   2306  1.4.2.2  christos 
   2307  1.4.2.2  christos 	return (0);
   2308  1.4.2.2  christos }
   2309  1.4.2.2  christos 
   2310  1.4.2.2  christos #if 0
   2311  1.4.2.2  christos void
   2312  1.4.2.2  christos mfii_pd_scsi_cmd(struct scsipi_xfer *xs)
   2313  1.4.2.2  christos {
   2314  1.4.2.2  christos 	struct scsi_link *link = xs->sc_link;
   2315  1.4.2.2  christos 	struct mfii_softc *sc = link->adapter_softc;
   2316  1.4.2.2  christos 	struct mfii_ccb *ccb = xs->io;
   2317  1.4.2.2  christos 
   2318  1.4.2.2  christos 	mfii_scrub_ccb(ccb);
   2319  1.4.2.2  christos 	ccb->ccb_cookie = xs;
   2320  1.4.2.2  christos 	ccb->ccb_done = mfii_scsi_cmd_done;
   2321  1.4.2.2  christos 	ccb->ccb_data = xs->data;
   2322  1.4.2.2  christos 	ccb->ccb_len = xs->datalen;
   2323  1.4.2.2  christos 
   2324  1.4.2.2  christos 	// XXX timeout_set(&xs->stimeout, mfii_scsi_cmd_tmo, xs);
   2325  1.4.2.2  christos 
   2326  1.4.2.2  christos 	xs->error = mfii_pd_scsi_cmd_cdb(sc, xs);
   2327  1.4.2.2  christos 	if (xs->error != XS_NOERROR)
   2328  1.4.2.2  christos 		goto done;
   2329  1.4.2.2  christos 
   2330  1.4.2.2  christos 	xs->resid = 0;
   2331  1.4.2.2  christos 
   2332  1.4.2.2  christos 	if (ISSET(xs->xs_control, XS_CTL_POLL)) {
   2333  1.4.2.2  christos 		if (mfii_poll(sc, ccb) != 0)
   2334  1.4.2.2  christos 			goto stuffup;
   2335  1.4.2.2  christos 		return;
   2336  1.4.2.2  christos 	}
   2337  1.4.2.2  christos 
   2338  1.4.2.2  christos 	// XXX timeout_add_msec(&xs->stimeout, xs->timeout);
   2339  1.4.2.2  christos 	mfii_start(sc, ccb);
   2340  1.4.2.2  christos 
   2341  1.4.2.2  christos 	return;
   2342  1.4.2.2  christos 
   2343  1.4.2.2  christos stuffup:
   2344  1.4.2.2  christos 	xs->error = XS_DRIVER_STUFFUP;
   2345  1.4.2.2  christos done:
   2346  1.4.2.2  christos 	scsi_done(xs);
   2347  1.4.2.2  christos }
   2348  1.4.2.2  christos 
   2349  1.4.2.2  christos int
   2350  1.4.2.2  christos mfii_pd_scsi_probe(struct scsi_link *link)
   2351  1.4.2.2  christos {
   2352  1.4.2.2  christos 	struct mfii_softc *sc = link->adapter_softc;
   2353  1.4.2.2  christos 	struct mfi_pd_details mpd;
   2354  1.4.2.2  christos 	union mfi_mbox mbox;
   2355  1.4.2.2  christos 	int rv;
   2356  1.4.2.2  christos 
   2357  1.4.2.2  christos 	if (link->lun > 0)
   2358  1.4.2.2  christos 		return (0);
   2359  1.4.2.2  christos 
   2360  1.4.2.2  christos 	memset(&mbox, 0, sizeof(mbox));
   2361  1.4.2.2  christos 	mbox.s[0] = htole16(link->target);
   2362  1.4.2.2  christos 
   2363  1.4.2.2  christos 	rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, &mpd, sizeof(mpd),
   2364  1.4.2.2  christos 	    MFII_DATA_IN, true);
   2365  1.4.2.2  christos 	if (rv != 0)
   2366  1.4.2.2  christos 		return (EIO);
   2367  1.4.2.2  christos 
   2368  1.4.2.2  christos 	if (mpd.mpd_fw_state != htole16(MFI_PD_SYSTEM))
   2369  1.4.2.2  christos 		return (ENXIO);
   2370  1.4.2.2  christos 
   2371  1.4.2.2  christos 	return (0);
   2372  1.4.2.2  christos }
   2373  1.4.2.2  christos 
   2374  1.4.2.2  christos int
   2375  1.4.2.2  christos mfii_pd_scsi_cmd_cdb(struct mfii_softc *sc, struct mfii_ccb *ccb,
   2376  1.4.2.2  christos     struct scsipi_xfer *xs)
   2377  1.4.2.2  christos {
   2378  1.4.2.2  christos 	struct scsi_link *link = xs->sc_link;
   2379  1.4.2.2  christos 	struct mpii_msg_scsi_io *io = ccb->ccb_request;
   2380  1.4.2.2  christos 	struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
   2381  1.4.2.2  christos 	uint16_t dev_handle;
   2382  1.4.2.2  christos 
   2383  1.4.2.2  christos 	dev_handle = mfii_dev_handle(sc, link->target);
   2384  1.4.2.2  christos 	if (dev_handle == htole16(0xffff))
   2385  1.4.2.2  christos 		return (XS_SELTIMEOUT);
   2386  1.4.2.2  christos 
   2387  1.4.2.2  christos 	io->dev_handle = dev_handle;
   2388  1.4.2.2  christos 	io->function = 0;
   2389  1.4.2.2  christos 	io->sense_buffer_low_address = htole32(ccb->ccb_sense_dva);
   2390  1.4.2.2  christos 	io->sgl_flags = htole16(0x02); /* XXX */
   2391  1.4.2.2  christos 	io->sense_buffer_length = sizeof(xs->sense);
   2392  1.4.2.2  christos 	io->sgl_offset0 = (sizeof(*io) + sizeof(*ctx)) / 4;
   2393  1.4.2.2  christos 	io->data_length = htole32(xs->datalen);
   2394  1.4.2.2  christos 	io->io_flags = htole16(xs->cmdlen);
   2395  1.4.2.2  christos 	io->lun[0] = htobe16(link->lun);
   2396  1.4.2.2  christos 	switch (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
   2397  1.4.2.2  christos 	case XS_CTL_DATA_IN:
   2398  1.4.2.2  christos 		ccb->ccb_direction = MFII_DATA_IN;
   2399  1.4.2.2  christos 		io->direction = MPII_SCSIIO_DIR_READ;
   2400  1.4.2.2  christos 		break;
   2401  1.4.2.2  christos 	case XS_CTL_DATA_OUT:
   2402  1.4.2.2  christos 		ccb->ccb_direction = MFII_DATA_OUT;
   2403  1.4.2.2  christos 		io->direction = MPII_SCSIIO_DIR_WRITE;
   2404  1.4.2.2  christos 		break;
   2405  1.4.2.2  christos 	default:
   2406  1.4.2.2  christos 		ccb->ccb_direction = MFII_DATA_NONE;
   2407  1.4.2.2  christos 		io->direction = MPII_SCSIIO_DIR_NONE;
   2408  1.4.2.2  christos 		break;
   2409  1.4.2.2  christos 	}
   2410  1.4.2.2  christos 	memcpy(io->cdb, xs->cmd, xs->cmdlen);
   2411  1.4.2.2  christos 
   2412  1.4.2.2  christos 	ctx->virtual_disk_target_id = htole16(link->target);
   2413  1.4.2.2  christos 	ctx->raid_flags = MFII_RAID_CTX_IO_TYPE_SYSPD;
   2414  1.4.2.2  christos 	ctx->timeout_value = sc->sc_pd->pd_timeout;
   2415  1.4.2.2  christos 
   2416  1.4.2.2  christos 	if (mfii_load_ccb(sc, ccb, ctx + 1,
   2417  1.4.2.2  christos 	    ISSET(xs->xs_control, XS_CTL_NOSLEEP)) != 0)
   2418  1.4.2.2  christos 		return (XS_DRIVER_STUFFUP);
   2419  1.4.2.2  christos 
   2420  1.4.2.2  christos 	ctx->num_sge = (ccb->ccb_len == 0) ? 0 : ccb->ccb_dmamap64->dm_nsegs;
   2421  1.4.2.2  christos 	KASSERT(ccb->ccb_dma64);
   2422  1.4.2.2  christos 
   2423  1.4.2.2  christos 	ccb->ccb_req.flags = MFII_REQ_TYPE_HI_PRI;
   2424  1.4.2.2  christos 	ccb->ccb_req.smid = le16toh(ccb->ccb_smid);
   2425  1.4.2.2  christos 	ccb->ccb_req.dev_handle = dev_handle;
   2426  1.4.2.2  christos 
   2427  1.4.2.2  christos 	return (XS_NOERROR);
   2428  1.4.2.2  christos }
   2429  1.4.2.2  christos #endif
   2430  1.4.2.2  christos 
   2431  1.4.2.3    martin static int
   2432  1.4.2.2  christos mfii_load_ccb(struct mfii_softc *sc, struct mfii_ccb *ccb, void *sglp,
   2433  1.4.2.2  christos     int nosleep)
   2434  1.4.2.2  christos {
   2435  1.4.2.2  christos 	struct mpii_msg_request *req = ccb->ccb_request;
   2436  1.4.2.2  christos 	struct mfii_sge *sge = NULL, *nsge = sglp;
   2437  1.4.2.2  christos 	struct mfii_sge *ce = NULL;
   2438  1.4.2.2  christos 	bus_dmamap_t dmap = ccb->ccb_dmamap64;
   2439  1.4.2.2  christos 	u_int space;
   2440  1.4.2.2  christos 	int i;
   2441  1.4.2.2  christos 
   2442  1.4.2.2  christos 	int error;
   2443  1.4.2.2  christos 
   2444  1.4.2.2  christos 	if (ccb->ccb_len == 0)
   2445  1.4.2.2  christos 		return (0);
   2446  1.4.2.2  christos 
   2447  1.4.2.2  christos 	ccb->ccb_dma64 = true;
   2448  1.4.2.2  christos 	error = bus_dmamap_load(sc->sc_dmat64, dmap,
   2449  1.4.2.2  christos 	    ccb->ccb_data, ccb->ccb_len, NULL,
   2450  1.4.2.2  christos 	    nosleep ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
   2451  1.4.2.2  christos 	if (error) {
   2452  1.4.2.2  christos 		printf("%s: error %d loading dmamap\n", DEVNAME(sc), error);
   2453  1.4.2.2  christos 		return (1);
   2454  1.4.2.2  christos 	}
   2455  1.4.2.2  christos 
   2456  1.4.2.2  christos 	space = (MFII_REQUEST_SIZE - ((u_int8_t *)nsge - (u_int8_t *)req)) /
   2457  1.4.2.2  christos 	    sizeof(*nsge);
   2458  1.4.2.2  christos 	if (dmap->dm_nsegs > space) {
   2459  1.4.2.2  christos 		space--;
   2460  1.4.2.2  christos 
   2461  1.4.2.2  christos 		ccb->ccb_sgl_len = (dmap->dm_nsegs - space) * sizeof(*nsge);
   2462  1.4.2.2  christos 		memset(ccb->ccb_sgl, 0, ccb->ccb_sgl_len);
   2463  1.4.2.2  christos 
   2464  1.4.2.2  christos 		ce = nsge + space;
   2465  1.4.2.2  christos 		ce->sg_addr = htole64(ccb->ccb_sgl_dva);
   2466  1.4.2.2  christos 		ce->sg_len = htole32(ccb->ccb_sgl_len);
   2467  1.4.2.2  christos 		ce->sg_flags = sc->sc_iop->sge_flag_chain;
   2468  1.4.2.2  christos 
   2469  1.4.2.2  christos 		req->chain_offset = ((u_int8_t *)ce - (u_int8_t *)req) / 16;
   2470  1.4.2.2  christos 	}
   2471  1.4.2.2  christos 
   2472  1.4.2.2  christos 	for (i = 0; i < dmap->dm_nsegs; i++) {
   2473  1.4.2.2  christos 		if (nsge == ce)
   2474  1.4.2.2  christos 			nsge = ccb->ccb_sgl;
   2475  1.4.2.2  christos 
   2476  1.4.2.2  christos 		sge = nsge;
   2477  1.4.2.2  christos 
   2478  1.4.2.2  christos 		sge->sg_addr = htole64(dmap->dm_segs[i].ds_addr);
   2479  1.4.2.2  christos 		sge->sg_len = htole32(dmap->dm_segs[i].ds_len);
   2480  1.4.2.2  christos 		sge->sg_flags = MFII_SGE_ADDR_SYSTEM;
   2481  1.4.2.2  christos 
   2482  1.4.2.2  christos 		nsge = sge + 1;
   2483  1.4.2.2  christos 	}
   2484  1.4.2.2  christos 	sge->sg_flags |= sc->sc_iop->sge_flag_eol;
   2485  1.4.2.2  christos 
   2486  1.4.2.2  christos 	bus_dmamap_sync(sc->sc_dmat64, dmap, 0, dmap->dm_mapsize,
   2487  1.4.2.2  christos 	    ccb->ccb_direction == MFII_DATA_OUT ?
   2488  1.4.2.2  christos 	    BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
   2489  1.4.2.2  christos 
   2490  1.4.2.2  christos 	if (ccb->ccb_sgl_len > 0) {
   2491  1.4.2.2  christos 		bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_sgl),
   2492  1.4.2.2  christos 		    ccb->ccb_sgl_offset, ccb->ccb_sgl_len,
   2493  1.4.2.2  christos 		    BUS_DMASYNC_PREWRITE);
   2494  1.4.2.2  christos 	}
   2495  1.4.2.2  christos 
   2496  1.4.2.2  christos 	return (0);
   2497  1.4.2.2  christos }
   2498  1.4.2.2  christos 
   2499  1.4.2.3    martin static void
   2500  1.4.2.2  christos mfii_scsi_cmd_tmo(void *p)
   2501  1.4.2.2  christos {
   2502  1.4.2.2  christos 	struct mfii_ccb *ccb = p;
   2503  1.4.2.2  christos 	struct mfii_softc *sc = ccb->ccb_sc;
   2504  1.4.2.2  christos 	bool start_abort;
   2505  1.4.2.2  christos 
   2506  1.4.2.2  christos 	printf("%s: cmd timeout ccb %p\n", DEVNAME(sc), p);
   2507  1.4.2.2  christos 
   2508  1.4.2.2  christos 	mutex_enter(&sc->sc_abort_mtx);
   2509  1.4.2.2  christos 	start_abort = (SIMPLEQ_FIRST(&sc->sc_abort_list) == 0);
   2510  1.4.2.2  christos 	SIMPLEQ_INSERT_TAIL(&sc->sc_abort_list, ccb, ccb_link);
   2511  1.4.2.2  christos 	if (start_abort)
   2512  1.4.2.2  christos 		workqueue_enqueue(sc->sc_abort_wq, &sc->sc_abort_work, NULL);
   2513  1.4.2.2  christos 	mutex_exit(&sc->sc_abort_mtx);
   2514  1.4.2.2  christos }
   2515  1.4.2.2  christos 
   2516  1.4.2.3    martin static void
   2517  1.4.2.2  christos mfii_abort_task(struct work *wk, void *scp)
   2518  1.4.2.2  christos {
   2519  1.4.2.2  christos 	struct mfii_softc *sc = scp;
   2520  1.4.2.2  christos 	struct mfii_ccb *list;
   2521  1.4.2.2  christos 
   2522  1.4.2.2  christos 	mutex_enter(&sc->sc_abort_mtx);
   2523  1.4.2.2  christos 	list = SIMPLEQ_FIRST(&sc->sc_abort_list);
   2524  1.4.2.2  christos 	SIMPLEQ_INIT(&sc->sc_abort_list);
   2525  1.4.2.2  christos 	mutex_exit(&sc->sc_abort_mtx);
   2526  1.4.2.2  christos 
   2527  1.4.2.2  christos 	while (list != NULL) {
   2528  1.4.2.2  christos 		struct mfii_ccb *ccb = list;
   2529  1.4.2.2  christos 		struct scsipi_xfer *xs = ccb->ccb_cookie;
   2530  1.4.2.2  christos 		struct scsipi_periph *periph = xs->xs_periph;
   2531  1.4.2.2  christos 		struct mfii_ccb *accb;
   2532  1.4.2.2  christos 
   2533  1.4.2.2  christos 		list = SIMPLEQ_NEXT(ccb, ccb_link);
   2534  1.4.2.2  christos 
   2535  1.4.2.2  christos 		if (!sc->sc_ld[periph->periph_target].ld_present) {
   2536  1.4.2.2  christos 			/* device is gone */
   2537  1.4.2.2  christos 			xs->error = XS_SELTIMEOUT;
   2538  1.4.2.2  christos 			scsipi_done(xs);
   2539  1.4.2.2  christos 			mfii_put_ccb(sc, ccb);
   2540  1.4.2.2  christos 			continue;
   2541  1.4.2.2  christos 		}
   2542  1.4.2.2  christos 
   2543  1.4.2.2  christos 		accb = mfii_get_ccb(sc);
   2544  1.4.2.2  christos 		mfii_scrub_ccb(accb);
   2545  1.4.2.2  christos 		mfii_abort(sc, accb, periph->periph_target, ccb->ccb_smid,
   2546  1.4.2.2  christos 		    MPII_SCSI_TASK_ABORT_TASK,
   2547  1.4.2.2  christos 		    htole32(MFII_TASK_MGMT_FLAGS_PD));
   2548  1.4.2.2  christos 
   2549  1.4.2.2  christos 		accb->ccb_cookie = ccb;
   2550  1.4.2.2  christos 		accb->ccb_done = mfii_scsi_cmd_abort_done;
   2551  1.4.2.2  christos 
   2552  1.4.2.2  christos 		mfii_start(sc, accb);
   2553  1.4.2.2  christos 	}
   2554  1.4.2.2  christos }
   2555  1.4.2.2  christos 
   2556  1.4.2.3    martin static void
   2557  1.4.2.2  christos mfii_abort(struct mfii_softc *sc, struct mfii_ccb *accb, uint16_t dev_handle,
   2558  1.4.2.2  christos     uint16_t smid, uint8_t type, uint32_t flags)
   2559  1.4.2.2  christos {
   2560  1.4.2.2  christos 	struct mfii_task_mgmt *msg;
   2561  1.4.2.2  christos 	struct mpii_msg_scsi_task_request *req;
   2562  1.4.2.2  christos 
   2563  1.4.2.2  christos 	msg = accb->ccb_request;
   2564  1.4.2.2  christos 	req = &msg->mpii_request;
   2565  1.4.2.2  christos 	req->dev_handle = dev_handle;
   2566  1.4.2.2  christos 	req->function = MPII_FUNCTION_SCSI_TASK_MGMT;
   2567  1.4.2.2  christos 	req->task_type = type;
   2568  1.4.2.2  christos 	req->task_mid = htole16( smid);
   2569  1.4.2.2  christos 	msg->flags = flags;
   2570  1.4.2.2  christos 
   2571  1.4.2.2  christos 	accb->ccb_req.flags = MFII_REQ_TYPE_HI_PRI;
   2572  1.4.2.2  christos 	accb->ccb_req.smid = le16toh(accb->ccb_smid);
   2573  1.4.2.2  christos }
   2574  1.4.2.2  christos 
   2575  1.4.2.3    martin static void
   2576  1.4.2.2  christos mfii_scsi_cmd_abort_done(struct mfii_softc *sc, struct mfii_ccb *accb)
   2577  1.4.2.2  christos {
   2578  1.4.2.2  christos 	struct mfii_ccb *ccb = accb->ccb_cookie;
   2579  1.4.2.2  christos 	struct scsipi_xfer *xs = ccb->ccb_cookie;
   2580  1.4.2.2  christos 
   2581  1.4.2.2  christos 	/* XXX check accb completion? */
   2582  1.4.2.2  christos 
   2583  1.4.2.2  christos 	mfii_put_ccb(sc, accb);
   2584  1.4.2.2  christos 	printf("%s: cmd aborted ccb %p\n", DEVNAME(sc), ccb);
   2585  1.4.2.2  christos 
   2586  1.4.2.2  christos 	xs->error = XS_TIMEOUT;
   2587  1.4.2.2  christos 	scsipi_done(xs);
   2588  1.4.2.2  christos 	mfii_put_ccb(sc, ccb);
   2589  1.4.2.2  christos }
   2590  1.4.2.2  christos 
   2591  1.4.2.3    martin static struct mfii_ccb *
   2592  1.4.2.2  christos mfii_get_ccb(struct mfii_softc *sc)
   2593  1.4.2.2  christos {
   2594  1.4.2.2  christos 	struct mfii_ccb *ccb;
   2595  1.4.2.2  christos 
   2596  1.4.2.2  christos 	mutex_enter(&sc->sc_ccb_mtx);
   2597  1.4.2.2  christos 	if (!sc->sc_running) {
   2598  1.4.2.2  christos 		ccb = NULL;
   2599  1.4.2.2  christos 	} else {
   2600  1.4.2.2  christos 		ccb = SIMPLEQ_FIRST(&sc->sc_ccb_freeq);
   2601  1.4.2.2  christos 		if (ccb != NULL)
   2602  1.4.2.2  christos 			SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_freeq, ccb_link);
   2603  1.4.2.2  christos 	}
   2604  1.4.2.2  christos 	mutex_exit(&sc->sc_ccb_mtx);
   2605  1.4.2.2  christos 	return (ccb);
   2606  1.4.2.2  christos }
   2607  1.4.2.2  christos 
   2608  1.4.2.3    martin static void
   2609  1.4.2.2  christos mfii_scrub_ccb(struct mfii_ccb *ccb)
   2610  1.4.2.2  christos {
   2611  1.4.2.2  christos 	ccb->ccb_cookie = NULL;
   2612  1.4.2.2  christos 	ccb->ccb_done = NULL;
   2613  1.4.2.2  christos 	ccb->ccb_flags = 0;
   2614  1.4.2.2  christos 	ccb->ccb_data = NULL;
   2615  1.4.2.2  christos 	ccb->ccb_direction = MFII_DATA_NONE;
   2616  1.4.2.2  christos 	ccb->ccb_dma64 = false;
   2617  1.4.2.2  christos 	ccb->ccb_len = 0;
   2618  1.4.2.2  christos 	ccb->ccb_sgl_len = 0;
   2619  1.4.2.2  christos 	memset(&ccb->ccb_req, 0, sizeof(ccb->ccb_req));
   2620  1.4.2.2  christos 	memset(ccb->ccb_request, 0, MFII_REQUEST_SIZE);
   2621  1.4.2.2  christos 	memset(ccb->ccb_mfi, 0, MFI_FRAME_SIZE);
   2622  1.4.2.2  christos }
   2623  1.4.2.2  christos 
   2624  1.4.2.3    martin static void
   2625  1.4.2.2  christos mfii_put_ccb(struct mfii_softc *sc, struct mfii_ccb *ccb)
   2626  1.4.2.2  christos {
   2627  1.4.2.2  christos 	mutex_enter(&sc->sc_ccb_mtx);
   2628  1.4.2.2  christos 	SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_freeq, ccb, ccb_link);
   2629  1.4.2.2  christos 	mutex_exit(&sc->sc_ccb_mtx);
   2630  1.4.2.2  christos }
   2631  1.4.2.2  christos 
   2632  1.4.2.3    martin static int
   2633  1.4.2.2  christos mfii_init_ccb(struct mfii_softc *sc)
   2634  1.4.2.2  christos {
   2635  1.4.2.2  christos 	struct mfii_ccb *ccb;
   2636  1.4.2.2  christos 	u_int8_t *request = MFII_DMA_KVA(sc->sc_requests);
   2637  1.4.2.2  christos 	u_int8_t *mfi = MFII_DMA_KVA(sc->sc_mfi);
   2638  1.4.2.2  christos 	u_int8_t *sense = MFII_DMA_KVA(sc->sc_sense);
   2639  1.4.2.2  christos 	u_int8_t *sgl = MFII_DMA_KVA(sc->sc_sgl);
   2640  1.4.2.2  christos 	u_int i;
   2641  1.4.2.2  christos 	int error;
   2642  1.4.2.2  christos 
   2643  1.4.2.2  christos 	sc->sc_ccb = malloc(sc->sc_max_cmds * sizeof(struct mfii_ccb),
   2644  1.4.2.2  christos 	    M_DEVBUF, M_WAITOK|M_ZERO);
   2645  1.4.2.2  christos 
   2646  1.4.2.2  christos 	for (i = 0; i < sc->sc_max_cmds; i++) {
   2647  1.4.2.2  christos 		ccb = &sc->sc_ccb[i];
   2648  1.4.2.2  christos 		ccb->ccb_sc = sc;
   2649  1.4.2.2  christos 
   2650  1.4.2.2  christos 		/* create a dma map for transfer */
   2651  1.4.2.2  christos 		error = bus_dmamap_create(sc->sc_dmat,
   2652  1.4.2.2  christos 		    MAXPHYS, sc->sc_max_sgl, MAXPHYS, 0,
   2653  1.4.2.2  christos 		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap32);
   2654  1.4.2.2  christos 		if (error) {
   2655  1.4.2.2  christos 			printf("%s: cannot create ccb dmamap32 (%d)\n",
   2656  1.4.2.2  christos 			    DEVNAME(sc), error);
   2657  1.4.2.2  christos 			goto destroy;
   2658  1.4.2.2  christos 		}
   2659  1.4.2.2  christos 		error = bus_dmamap_create(sc->sc_dmat64,
   2660  1.4.2.2  christos 		    MAXPHYS, sc->sc_max_sgl, MAXPHYS, 0,
   2661  1.4.2.2  christos 		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap64);
   2662  1.4.2.2  christos 		if (error) {
   2663  1.4.2.2  christos 			printf("%s: cannot create ccb dmamap64 (%d)\n",
   2664  1.4.2.2  christos 			    DEVNAME(sc), error);
   2665  1.4.2.2  christos 			goto destroy32;
   2666  1.4.2.2  christos 		}
   2667  1.4.2.2  christos 
   2668  1.4.2.2  christos 		/* select i + 1'th request. 0 is reserved for events */
   2669  1.4.2.2  christos 		ccb->ccb_smid = i + 1;
   2670  1.4.2.2  christos 		ccb->ccb_request_offset = MFII_REQUEST_SIZE * (i + 1);
   2671  1.4.2.2  christos 		ccb->ccb_request = request + ccb->ccb_request_offset;
   2672  1.4.2.2  christos 		ccb->ccb_request_dva = MFII_DMA_DVA(sc->sc_requests) +
   2673  1.4.2.2  christos 		    ccb->ccb_request_offset;
   2674  1.4.2.2  christos 
   2675  1.4.2.2  christos 		/* select i'th MFI command frame */
   2676  1.4.2.2  christos 		ccb->ccb_mfi_offset = MFI_FRAME_SIZE * i;
   2677  1.4.2.2  christos 		ccb->ccb_mfi = mfi + ccb->ccb_mfi_offset;
   2678  1.4.2.2  christos 		ccb->ccb_mfi_dva = MFII_DMA_DVA(sc->sc_mfi) +
   2679  1.4.2.2  christos 		    ccb->ccb_mfi_offset;
   2680  1.4.2.2  christos 
   2681  1.4.2.2  christos 		/* select i'th sense */
   2682  1.4.2.2  christos 		ccb->ccb_sense_offset = MFI_SENSE_SIZE * i;
   2683  1.4.2.2  christos 		ccb->ccb_sense = (struct mfi_sense *)(sense +
   2684  1.4.2.2  christos 		    ccb->ccb_sense_offset);
   2685  1.4.2.2  christos 		ccb->ccb_sense_dva = MFII_DMA_DVA(sc->sc_sense) +
   2686  1.4.2.2  christos 		    ccb->ccb_sense_offset;
   2687  1.4.2.2  christos 
   2688  1.4.2.2  christos 		/* select i'th sgl */
   2689  1.4.2.2  christos 		ccb->ccb_sgl_offset = sizeof(struct mfii_sge) *
   2690  1.4.2.2  christos 		    sc->sc_max_sgl * i;
   2691  1.4.2.2  christos 		ccb->ccb_sgl = (struct mfii_sge *)(sgl + ccb->ccb_sgl_offset);
   2692  1.4.2.2  christos 		ccb->ccb_sgl_dva = MFII_DMA_DVA(sc->sc_sgl) +
   2693  1.4.2.2  christos 		    ccb->ccb_sgl_offset;
   2694  1.4.2.2  christos 
   2695  1.4.2.2  christos 		mutex_init(&ccb->ccb_mtx, MUTEX_DEFAULT, IPL_BIO);
   2696  1.4.2.2  christos 		cv_init(&ccb->ccb_cv, "mfiiexec");
   2697  1.4.2.2  christos 
   2698  1.4.2.2  christos 		/* add ccb to queue */
   2699  1.4.2.2  christos 		mfii_put_ccb(sc, ccb);
   2700  1.4.2.2  christos 	}
   2701  1.4.2.2  christos 
   2702  1.4.2.2  christos 	return (0);
   2703  1.4.2.2  christos 
   2704  1.4.2.2  christos destroy32:
   2705  1.4.2.2  christos 	bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap32);
   2706  1.4.2.2  christos destroy:
   2707  1.4.2.2  christos 	/* free dma maps and ccb memory */
   2708  1.4.2.2  christos 	while ((ccb = mfii_get_ccb(sc)) != NULL) {
   2709  1.4.2.2  christos 		bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap32);
   2710  1.4.2.2  christos 		bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap64);
   2711  1.4.2.2  christos 	}
   2712  1.4.2.2  christos 
   2713  1.4.2.2  christos 	free(sc->sc_ccb, M_DEVBUF);
   2714  1.4.2.2  christos 
   2715  1.4.2.2  christos 	return (1);
   2716  1.4.2.2  christos }
   2717  1.4.2.2  christos 
   2718  1.4.2.2  christos #if NBIO > 0
   2719  1.4.2.3    martin static int
   2720  1.4.2.2  christos mfii_ioctl(device_t dev, u_long cmd, void *addr)
   2721  1.4.2.2  christos {
   2722  1.4.2.2  christos 	struct mfii_softc	*sc = device_private(dev);
   2723  1.4.2.2  christos 	int error = 0;
   2724  1.4.2.2  christos 
   2725  1.4.2.2  christos 	DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl ", DEVNAME(sc));
   2726  1.4.2.2  christos 
   2727  1.4.2.2  christos 	mutex_enter(&sc->sc_lock);
   2728  1.4.2.2  christos 
   2729  1.4.2.2  christos 	switch (cmd) {
   2730  1.4.2.2  christos 	case BIOCINQ:
   2731  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "inq\n");
   2732  1.4.2.2  christos 		error = mfii_ioctl_inq(sc, (struct bioc_inq *)addr);
   2733  1.4.2.2  christos 		break;
   2734  1.4.2.2  christos 
   2735  1.4.2.2  christos 	case BIOCVOL:
   2736  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "vol\n");
   2737  1.4.2.2  christos 		error = mfii_ioctl_vol(sc, (struct bioc_vol *)addr);
   2738  1.4.2.2  christos 		break;
   2739  1.4.2.2  christos 
   2740  1.4.2.2  christos 	case BIOCDISK:
   2741  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "disk\n");
   2742  1.4.2.2  christos 		error = mfii_ioctl_disk(sc, (struct bioc_disk *)addr);
   2743  1.4.2.2  christos 		break;
   2744  1.4.2.2  christos 
   2745  1.4.2.2  christos 	case BIOCALARM:
   2746  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "alarm\n");
   2747  1.4.2.2  christos 		error = mfii_ioctl_alarm(sc, (struct bioc_alarm *)addr);
   2748  1.4.2.2  christos 		break;
   2749  1.4.2.2  christos 
   2750  1.4.2.2  christos 	case BIOCBLINK:
   2751  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "blink\n");
   2752  1.4.2.2  christos 		error = mfii_ioctl_blink(sc, (struct bioc_blink *)addr);
   2753  1.4.2.2  christos 		break;
   2754  1.4.2.2  christos 
   2755  1.4.2.2  christos 	case BIOCSETSTATE:
   2756  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "setstate\n");
   2757  1.4.2.2  christos 		error = mfii_ioctl_setstate(sc, (struct bioc_setstate *)addr);
   2758  1.4.2.2  christos 		break;
   2759  1.4.2.2  christos 
   2760  1.4.2.2  christos #if 0
   2761  1.4.2.2  christos 	case BIOCPATROL:
   2762  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "patrol\n");
   2763  1.4.2.2  christos 		error = mfii_ioctl_patrol(sc, (struct bioc_patrol *)addr);
   2764  1.4.2.2  christos 		break;
   2765  1.4.2.2  christos #endif
   2766  1.4.2.2  christos 
   2767  1.4.2.2  christos 	default:
   2768  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, " invalid ioctl\n");
   2769  1.4.2.2  christos 		error = ENOTTY;
   2770  1.4.2.2  christos 	}
   2771  1.4.2.2  christos 
   2772  1.4.2.2  christos 	mutex_exit(&sc->sc_lock);
   2773  1.4.2.2  christos 
   2774  1.4.2.2  christos 	return (error);
   2775  1.4.2.2  christos }
   2776  1.4.2.2  christos 
   2777  1.4.2.3    martin static int
   2778  1.4.2.2  christos mfii_bio_getitall(struct mfii_softc *sc)
   2779  1.4.2.2  christos {
   2780  1.4.2.2  christos 	int			i, d, rv = EINVAL;
   2781  1.4.2.2  christos 	size_t			size;
   2782  1.4.2.2  christos 	union mfi_mbox		mbox;
   2783  1.4.2.2  christos 	struct mfi_conf		*cfg = NULL;
   2784  1.4.2.2  christos 	struct mfi_ld_details	*ld_det = NULL;
   2785  1.4.2.2  christos 
   2786  1.4.2.2  christos 	/* get info */
   2787  1.4.2.2  christos 	if (mfii_get_info(sc)) {
   2788  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "%s: mfii_get_info failed\n",
   2789  1.4.2.2  christos 		    DEVNAME(sc));
   2790  1.4.2.2  christos 		goto done;
   2791  1.4.2.2  christos 	}
   2792  1.4.2.2  christos 
   2793  1.4.2.2  christos 	/* send single element command to retrieve size for full structure */
   2794  1.4.2.2  christos 	cfg = malloc(sizeof *cfg, M_DEVBUF, M_NOWAIT | M_ZERO);
   2795  1.4.2.2  christos 	if (cfg == NULL)
   2796  1.4.2.2  christos 		goto done;
   2797  1.4.2.2  christos 	if (mfii_mgmt(sc, MR_DCMD_CONF_GET, NULL, cfg, sizeof(*cfg),
   2798  1.4.2.2  christos 	    MFII_DATA_IN, false)) {
   2799  1.4.2.2  christos 		free(cfg, M_DEVBUF);
   2800  1.4.2.2  christos 		goto done;
   2801  1.4.2.2  christos 	}
   2802  1.4.2.2  christos 
   2803  1.4.2.2  christos 	size = cfg->mfc_size;
   2804  1.4.2.2  christos 	free(cfg, M_DEVBUF);
   2805  1.4.2.2  christos 
   2806  1.4.2.2  christos 	/* memory for read config */
   2807  1.4.2.2  christos 	cfg = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
   2808  1.4.2.2  christos 	if (cfg == NULL)
   2809  1.4.2.2  christos 		goto done;
   2810  1.4.2.2  christos 	if (mfii_mgmt(sc, MR_DCMD_CONF_GET, NULL, cfg, size,
   2811  1.4.2.2  christos 	    MFII_DATA_IN, false)) {
   2812  1.4.2.2  christos 		free(cfg, M_DEVBUF);
   2813  1.4.2.2  christos 		goto done;
   2814  1.4.2.2  christos 	}
   2815  1.4.2.2  christos 
   2816  1.4.2.2  christos 	/* replace current pointer with new one */
   2817  1.4.2.2  christos 	if (sc->sc_cfg)
   2818  1.4.2.2  christos 		free(sc->sc_cfg, M_DEVBUF);
   2819  1.4.2.2  christos 	sc->sc_cfg = cfg;
   2820  1.4.2.2  christos 
   2821  1.4.2.2  christos 	/* get all ld info */
   2822  1.4.2.2  christos 	if (mfii_mgmt(sc, MR_DCMD_LD_GET_LIST, NULL, &sc->sc_ld_list,
   2823  1.4.2.2  christos 	    sizeof(sc->sc_ld_list), MFII_DATA_IN, false))
   2824  1.4.2.2  christos 		goto done;
   2825  1.4.2.2  christos 
   2826  1.4.2.2  christos 	/* get memory for all ld structures */
   2827  1.4.2.2  christos 	size = cfg->mfc_no_ld * sizeof(struct mfi_ld_details);
   2828  1.4.2.2  christos 	if (sc->sc_ld_sz != size) {
   2829  1.4.2.2  christos 		if (sc->sc_ld_details)
   2830  1.4.2.2  christos 			free(sc->sc_ld_details, M_DEVBUF);
   2831  1.4.2.2  christos 
   2832  1.4.2.2  christos 		ld_det = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
   2833  1.4.2.2  christos 		if (ld_det == NULL)
   2834  1.4.2.2  christos 			goto done;
   2835  1.4.2.2  christos 		sc->sc_ld_sz = size;
   2836  1.4.2.2  christos 		sc->sc_ld_details = ld_det;
   2837  1.4.2.2  christos 	}
   2838  1.4.2.2  christos 
   2839  1.4.2.2  christos 	/* find used physical disks */
   2840  1.4.2.2  christos 	size = sizeof(struct mfi_ld_details);
   2841  1.4.2.2  christos 	for (i = 0, d = 0; i < cfg->mfc_no_ld; i++) {
   2842  1.4.2.2  christos 		memset(&mbox, 0, sizeof(mbox));
   2843  1.4.2.2  christos 		mbox.b[0] = sc->sc_ld_list.mll_list[i].mll_ld.mld_target;
   2844  1.4.2.2  christos 		if (mfii_mgmt(sc, MR_DCMD_LD_GET_INFO, &mbox,
   2845  1.4.2.2  christos 		    &sc->sc_ld_details[i], size, MFII_DATA_IN, false))
   2846  1.4.2.2  christos 			goto done;
   2847  1.4.2.2  christos 
   2848  1.4.2.2  christos 		d += sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_no_drv_per_span *
   2849  1.4.2.2  christos 		    sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_span_depth;
   2850  1.4.2.2  christos 	}
   2851  1.4.2.2  christos 	sc->sc_no_pd = d;
   2852  1.4.2.2  christos 
   2853  1.4.2.2  christos 	rv = 0;
   2854  1.4.2.2  christos done:
   2855  1.4.2.2  christos 	return (rv);
   2856  1.4.2.2  christos }
   2857  1.4.2.2  christos 
   2858  1.4.2.3    martin static int
   2859  1.4.2.2  christos mfii_ioctl_inq(struct mfii_softc *sc, struct bioc_inq *bi)
   2860  1.4.2.2  christos {
   2861  1.4.2.2  christos 	int			rv = EINVAL;
   2862  1.4.2.2  christos 	struct mfi_conf		*cfg = NULL;
   2863  1.4.2.2  christos 
   2864  1.4.2.2  christos 	DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_inq\n", DEVNAME(sc));
   2865  1.4.2.2  christos 
   2866  1.4.2.2  christos 	if (mfii_bio_getitall(sc)) {
   2867  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "%s: mfii_bio_getitall failed\n",
   2868  1.4.2.2  christos 		    DEVNAME(sc));
   2869  1.4.2.2  christos 		goto done;
   2870  1.4.2.2  christos 	}
   2871  1.4.2.2  christos 
   2872  1.4.2.2  christos 	/* count unused disks as volumes */
   2873  1.4.2.2  christos 	if (sc->sc_cfg == NULL)
   2874  1.4.2.2  christos 		goto done;
   2875  1.4.2.2  christos 	cfg = sc->sc_cfg;
   2876  1.4.2.2  christos 
   2877  1.4.2.2  christos 	bi->bi_nodisk = sc->sc_info.mci_pd_disks_present;
   2878  1.4.2.2  christos 	bi->bi_novol = cfg->mfc_no_ld + cfg->mfc_no_hs;
   2879  1.4.2.2  christos #if notyet
   2880  1.4.2.2  christos 	bi->bi_novol = cfg->mfc_no_ld + cfg->mfc_no_hs +
   2881  1.4.2.2  christos 	    (bi->bi_nodisk - sc->sc_no_pd);
   2882  1.4.2.2  christos #endif
   2883  1.4.2.2  christos 	/* tell bio who we are */
   2884  1.4.2.2  christos 	strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev));
   2885  1.4.2.2  christos 
   2886  1.4.2.2  christos 	rv = 0;
   2887  1.4.2.2  christos done:
   2888  1.4.2.2  christos 	return (rv);
   2889  1.4.2.2  christos }
   2890  1.4.2.2  christos 
   2891  1.4.2.3    martin static int
   2892  1.4.2.2  christos mfii_ioctl_vol(struct mfii_softc *sc, struct bioc_vol *bv)
   2893  1.4.2.2  christos {
   2894  1.4.2.2  christos 	int			i, per, rv = EINVAL;
   2895  1.4.2.2  christos 
   2896  1.4.2.2  christos 	DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_vol %#x\n",
   2897  1.4.2.2  christos 	    DEVNAME(sc), bv->bv_volid);
   2898  1.4.2.2  christos 
   2899  1.4.2.2  christos 	/* we really could skip and expect that inq took care of it */
   2900  1.4.2.2  christos 	if (mfii_bio_getitall(sc)) {
   2901  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "%s: mfii_bio_getitall failed\n",
   2902  1.4.2.2  christos 		    DEVNAME(sc));
   2903  1.4.2.2  christos 		goto done;
   2904  1.4.2.2  christos 	}
   2905  1.4.2.2  christos 
   2906  1.4.2.2  christos 	if (bv->bv_volid >= sc->sc_ld_list.mll_no_ld) {
   2907  1.4.2.2  christos 		/* go do hotspares & unused disks */
   2908  1.4.2.2  christos 		rv = mfii_bio_hs(sc, bv->bv_volid, MFI_MGMT_VD, bv);
   2909  1.4.2.2  christos 		goto done;
   2910  1.4.2.2  christos 	}
   2911  1.4.2.2  christos 
   2912  1.4.2.2  christos 	i = bv->bv_volid;
   2913  1.4.2.2  christos 	strlcpy(bv->bv_dev, sc->sc_ld_details[i].mld_cfg.mlc_prop.mlp_name,
   2914  1.4.2.2  christos 	    sizeof(bv->bv_dev));
   2915  1.4.2.2  christos 
   2916  1.4.2.2  christos 	switch(sc->sc_ld_list.mll_list[i].mll_state) {
   2917  1.4.2.2  christos 	case MFI_LD_OFFLINE:
   2918  1.4.2.2  christos 		bv->bv_status = BIOC_SVOFFLINE;
   2919  1.4.2.2  christos 		break;
   2920  1.4.2.2  christos 
   2921  1.4.2.2  christos 	case MFI_LD_PART_DEGRADED:
   2922  1.4.2.2  christos 	case MFI_LD_DEGRADED:
   2923  1.4.2.2  christos 		bv->bv_status = BIOC_SVDEGRADED;
   2924  1.4.2.2  christos 		break;
   2925  1.4.2.2  christos 
   2926  1.4.2.2  christos 	case MFI_LD_ONLINE:
   2927  1.4.2.2  christos 		bv->bv_status = BIOC_SVONLINE;
   2928  1.4.2.2  christos 		break;
   2929  1.4.2.2  christos 
   2930  1.4.2.2  christos 	default:
   2931  1.4.2.2  christos 		bv->bv_status = BIOC_SVINVALID;
   2932  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "%s: invalid logical disk state %#x\n",
   2933  1.4.2.2  christos 		    DEVNAME(sc),
   2934  1.4.2.2  christos 		    sc->sc_ld_list.mll_list[i].mll_state);
   2935  1.4.2.2  christos 	}
   2936  1.4.2.2  christos 
   2937  1.4.2.2  christos 	/* additional status can modify MFI status */
   2938  1.4.2.2  christos 	switch (sc->sc_ld_details[i].mld_progress.mlp_in_prog) {
   2939  1.4.2.2  christos 	case MFI_LD_PROG_CC:
   2940  1.4.2.2  christos 	case MFI_LD_PROG_BGI:
   2941  1.4.2.2  christos 		bv->bv_status = BIOC_SVSCRUB;
   2942  1.4.2.2  christos 		per = (int)sc->sc_ld_details[i].mld_progress.mlp_cc.mp_progress;
   2943  1.4.2.2  christos 		bv->bv_percent = (per * 100) / 0xffff;
   2944  1.4.2.2  christos 		bv->bv_seconds =
   2945  1.4.2.2  christos 		    sc->sc_ld_details[i].mld_progress.mlp_cc.mp_elapsed_seconds;
   2946  1.4.2.2  christos 		break;
   2947  1.4.2.2  christos 
   2948  1.4.2.2  christos 	case MFI_LD_PROG_FGI:
   2949  1.4.2.2  christos 	case MFI_LD_PROG_RECONSTRUCT:
   2950  1.4.2.2  christos 		/* nothing yet */
   2951  1.4.2.2  christos 		break;
   2952  1.4.2.2  christos 	}
   2953  1.4.2.2  christos 
   2954  1.4.2.2  christos #if 0
   2955  1.4.2.2  christos 	if (sc->sc_ld_details[i].mld_cfg.mlc_prop.mlp_cur_cache_policy & 0x01)
   2956  1.4.2.2  christos 		bv->bv_cache = BIOC_CVWRITEBACK;
   2957  1.4.2.2  christos 	else
   2958  1.4.2.2  christos 		bv->bv_cache = BIOC_CVWRITETHROUGH;
   2959  1.4.2.2  christos #endif
   2960  1.4.2.2  christos 
   2961  1.4.2.2  christos 	/*
   2962  1.4.2.2  christos 	 * The RAID levels are determined per the SNIA DDF spec, this is only
   2963  1.4.2.2  christos 	 * a subset that is valid for the MFI controller.
   2964  1.4.2.2  christos 	 */
   2965  1.4.2.2  christos 	bv->bv_level = sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_pri_raid;
   2966  1.4.2.2  christos 	if (sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_span_depth > 1)
   2967  1.4.2.2  christos 		bv->bv_level *= 10;
   2968  1.4.2.2  christos 
   2969  1.4.2.2  christos 	bv->bv_nodisk = sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_no_drv_per_span *
   2970  1.4.2.2  christos 	    sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_span_depth;
   2971  1.4.2.2  christos 
   2972  1.4.2.2  christos 	bv->bv_size = sc->sc_ld_details[i].mld_size * 512; /* bytes per block */
   2973  1.4.2.2  christos 
   2974  1.4.2.2  christos 	rv = 0;
   2975  1.4.2.2  christos done:
   2976  1.4.2.2  christos 	return (rv);
   2977  1.4.2.2  christos }
   2978  1.4.2.2  christos 
   2979  1.4.2.3    martin static int
   2980  1.4.2.2  christos mfii_ioctl_disk(struct mfii_softc *sc, struct bioc_disk *bd)
   2981  1.4.2.2  christos {
   2982  1.4.2.2  christos 	struct mfi_conf		*cfg;
   2983  1.4.2.2  christos 	struct mfi_array	*ar;
   2984  1.4.2.2  christos 	struct mfi_ld_cfg	*ld;
   2985  1.4.2.2  christos 	struct mfi_pd_details	*pd;
   2986  1.4.2.2  christos 	struct mfi_pd_list	*pl;
   2987  1.4.2.2  christos 	struct scsipi_inquiry_data *inqbuf;
   2988  1.4.2.2  christos 	char			vend[8+16+4+1], *vendp;
   2989  1.4.2.2  christos 	int			i, rv = EINVAL;
   2990  1.4.2.2  christos 	int			arr, vol, disk, span;
   2991  1.4.2.2  christos 	union mfi_mbox		mbox;
   2992  1.4.2.2  christos 
   2993  1.4.2.2  christos 	DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_disk %#x\n",
   2994  1.4.2.2  christos 	    DEVNAME(sc), bd->bd_diskid);
   2995  1.4.2.2  christos 
   2996  1.4.2.2  christos 	/* we really could skip and expect that inq took care of it */
   2997  1.4.2.2  christos 	if (mfii_bio_getitall(sc)) {
   2998  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "%s: mfii_bio_getitall failed\n",
   2999  1.4.2.2  christos 		    DEVNAME(sc));
   3000  1.4.2.2  christos 		return (rv);
   3001  1.4.2.2  christos 	}
   3002  1.4.2.2  christos 	cfg = sc->sc_cfg;
   3003  1.4.2.2  christos 
   3004  1.4.2.2  christos 	pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
   3005  1.4.2.2  christos 	pl = malloc(sizeof *pl, M_DEVBUF, M_WAITOK);
   3006  1.4.2.2  christos 
   3007  1.4.2.2  christos 	ar = cfg->mfc_array;
   3008  1.4.2.2  christos 	vol = bd->bd_volid;
   3009  1.4.2.2  christos 	if (vol >= cfg->mfc_no_ld) {
   3010  1.4.2.2  christos 		/* do hotspares */
   3011  1.4.2.2  christos 		rv = mfii_bio_hs(sc, bd->bd_volid, MFI_MGMT_SD, bd);
   3012  1.4.2.2  christos 		goto freeme;
   3013  1.4.2.2  christos 	}
   3014  1.4.2.2  christos 
   3015  1.4.2.2  christos 	/* calculate offset to ld structure */
   3016  1.4.2.2  christos 	ld = (struct mfi_ld_cfg *)(
   3017  1.4.2.2  christos 	    ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) +
   3018  1.4.2.2  christos 	    cfg->mfc_array_size * cfg->mfc_no_array);
   3019  1.4.2.2  christos 
   3020  1.4.2.2  christos 	/* use span 0 only when raid group is not spanned */
   3021  1.4.2.2  christos 	if (ld[vol].mlc_parm.mpa_span_depth > 1)
   3022  1.4.2.2  christos 		span = bd->bd_diskid / ld[vol].mlc_parm.mpa_no_drv_per_span;
   3023  1.4.2.2  christos 	else
   3024  1.4.2.2  christos 		span = 0;
   3025  1.4.2.2  christos 	arr = ld[vol].mlc_span[span].mls_index;
   3026  1.4.2.2  christos 
   3027  1.4.2.2  christos 	/* offset disk into pd list */
   3028  1.4.2.2  christos 	disk = bd->bd_diskid % ld[vol].mlc_parm.mpa_no_drv_per_span;
   3029  1.4.2.2  christos 
   3030  1.4.2.2  christos 	if (ar[arr].pd[disk].mar_pd.mfp_id == 0xffffU) {
   3031  1.4.2.2  christos 		/* disk is missing but succeed command */
   3032  1.4.2.2  christos 		bd->bd_status = BIOC_SDFAILED;
   3033  1.4.2.2  christos 		rv = 0;
   3034  1.4.2.2  christos 
   3035  1.4.2.2  christos 		/* try to find an unused disk for the target to rebuild */
   3036  1.4.2.2  christos 		if (mfii_mgmt(sc, MR_DCMD_PD_GET_LIST, NULL, pl, sizeof(*pl),
   3037  1.4.2.2  christos 		    MFII_DATA_IN, false))
   3038  1.4.2.2  christos 			goto freeme;
   3039  1.4.2.2  christos 
   3040  1.4.2.2  christos 		for (i = 0; i < pl->mpl_no_pd; i++) {
   3041  1.4.2.2  christos 			if (pl->mpl_address[i].mpa_scsi_type != 0)
   3042  1.4.2.2  christos 				continue;
   3043  1.4.2.2  christos 
   3044  1.4.2.2  christos 			memset(&mbox, 0, sizeof(mbox));
   3045  1.4.2.2  christos 			mbox.s[0] = pl->mpl_address[i].mpa_pd_id;
   3046  1.4.2.2  christos 			if (mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox,
   3047  1.4.2.2  christos 			    pd, sizeof(*pd), MFII_DATA_IN, false))
   3048  1.4.2.2  christos 				continue;
   3049  1.4.2.2  christos 
   3050  1.4.2.2  christos 			if (pd->mpd_fw_state == MFI_PD_UNCONFIG_GOOD ||
   3051  1.4.2.2  christos 			    pd->mpd_fw_state == MFI_PD_UNCONFIG_BAD)
   3052  1.4.2.2  christos 				break;
   3053  1.4.2.2  christos 		}
   3054  1.4.2.2  christos 
   3055  1.4.2.2  christos 		if (i == pl->mpl_no_pd)
   3056  1.4.2.2  christos 			goto freeme;
   3057  1.4.2.2  christos 	} else {
   3058  1.4.2.2  christos 		memset(&mbox, 0, sizeof(mbox));
   3059  1.4.2.2  christos 		mbox.s[0] = ar[arr].pd[disk].mar_pd.mfp_id;
   3060  1.4.2.2  christos 		if (mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
   3061  1.4.2.2  christos 		    MFII_DATA_IN, false)) {
   3062  1.4.2.2  christos 			bd->bd_status = BIOC_SDINVALID;
   3063  1.4.2.2  christos 			goto freeme;
   3064  1.4.2.2  christos 		}
   3065  1.4.2.2  christos 	}
   3066  1.4.2.2  christos 
   3067  1.4.2.2  christos 	/* get the remaining fields */
   3068  1.4.2.2  christos 	bd->bd_channel = pd->mpd_enc_idx;
   3069  1.4.2.2  christos 	bd->bd_target = pd->mpd_enc_slot;
   3070  1.4.2.2  christos 
   3071  1.4.2.2  christos 	/* get status */
   3072  1.4.2.2  christos 	switch (pd->mpd_fw_state){
   3073  1.4.2.2  christos 	case MFI_PD_UNCONFIG_GOOD:
   3074  1.4.2.2  christos 	case MFI_PD_UNCONFIG_BAD:
   3075  1.4.2.2  christos 		bd->bd_status = BIOC_SDUNUSED;
   3076  1.4.2.2  christos 		break;
   3077  1.4.2.2  christos 
   3078  1.4.2.2  christos 	case MFI_PD_HOTSPARE: /* XXX dedicated hotspare part of array? */
   3079  1.4.2.2  christos 		bd->bd_status = BIOC_SDHOTSPARE;
   3080  1.4.2.2  christos 		break;
   3081  1.4.2.2  christos 
   3082  1.4.2.2  christos 	case MFI_PD_OFFLINE:
   3083  1.4.2.2  christos 		bd->bd_status = BIOC_SDOFFLINE;
   3084  1.4.2.2  christos 		break;
   3085  1.4.2.2  christos 
   3086  1.4.2.2  christos 	case MFI_PD_FAILED:
   3087  1.4.2.2  christos 		bd->bd_status = BIOC_SDFAILED;
   3088  1.4.2.2  christos 		break;
   3089  1.4.2.2  christos 
   3090  1.4.2.2  christos 	case MFI_PD_REBUILD:
   3091  1.4.2.2  christos 		bd->bd_status = BIOC_SDREBUILD;
   3092  1.4.2.2  christos 		break;
   3093  1.4.2.2  christos 
   3094  1.4.2.2  christos 	case MFI_PD_ONLINE:
   3095  1.4.2.2  christos 		bd->bd_status = BIOC_SDONLINE;
   3096  1.4.2.2  christos 		break;
   3097  1.4.2.2  christos 
   3098  1.4.2.2  christos 	case MFI_PD_COPYBACK:
   3099  1.4.2.2  christos 	case MFI_PD_SYSTEM:
   3100  1.4.2.2  christos 	default:
   3101  1.4.2.2  christos 		bd->bd_status = BIOC_SDINVALID;
   3102  1.4.2.2  christos 		break;
   3103  1.4.2.2  christos 	}
   3104  1.4.2.2  christos 
   3105  1.4.2.2  christos 	bd->bd_size = pd->mpd_size * 512; /* bytes per block */
   3106  1.4.2.2  christos 
   3107  1.4.2.2  christos 	inqbuf = (struct scsipi_inquiry_data *)&pd->mpd_inq_data;
   3108  1.4.2.2  christos 	vendp = inqbuf->vendor;
   3109  1.4.2.2  christos 	memcpy(vend, vendp, sizeof vend - 1);
   3110  1.4.2.2  christos 	vend[sizeof vend - 1] = '\0';
   3111  1.4.2.2  christos 	strlcpy(bd->bd_vendor, vend, sizeof(bd->bd_vendor));
   3112  1.4.2.2  christos 
   3113  1.4.2.2  christos 	/* XXX find a way to retrieve serial nr from drive */
   3114  1.4.2.2  christos 	/* XXX find a way to get bd_procdev */
   3115  1.4.2.2  christos 
   3116  1.4.2.2  christos #if 0
   3117  1.4.2.2  christos 	mfp = &pd->mpd_progress;
   3118  1.4.2.2  christos 	if (mfp->mfp_in_prog & MFI_PD_PROG_PR) {
   3119  1.4.2.2  christos 		mp = &mfp->mfp_patrol_read;
   3120  1.4.2.2  christos 		bd->bd_patrol.bdp_percent = (mp->mp_progress * 100) / 0xffff;
   3121  1.4.2.2  christos 		bd->bd_patrol.bdp_seconds = mp->mp_elapsed_seconds;
   3122  1.4.2.2  christos 	}
   3123  1.4.2.2  christos #endif
   3124  1.4.2.2  christos 
   3125  1.4.2.2  christos 	rv = 0;
   3126  1.4.2.2  christos freeme:
   3127  1.4.2.2  christos 	free(pd, M_DEVBUF);
   3128  1.4.2.2  christos 	free(pl, M_DEVBUF);
   3129  1.4.2.2  christos 
   3130  1.4.2.2  christos 	return (rv);
   3131  1.4.2.2  christos }
   3132  1.4.2.2  christos 
   3133  1.4.2.3    martin static int
   3134  1.4.2.2  christos mfii_ioctl_alarm(struct mfii_softc *sc, struct bioc_alarm *ba)
   3135  1.4.2.2  christos {
   3136  1.4.2.2  christos 	uint32_t		opc;
   3137  1.4.2.2  christos 	int			rv = 0;
   3138  1.4.2.2  christos 	int8_t			ret;
   3139  1.4.2.2  christos 	mfii_direction_t dir = MFII_DATA_NONE;
   3140  1.4.2.2  christos 
   3141  1.4.2.2  christos 	switch(ba->ba_opcode) {
   3142  1.4.2.2  christos 	case BIOC_SADISABLE:
   3143  1.4.2.2  christos 		opc = MR_DCMD_SPEAKER_DISABLE;
   3144  1.4.2.2  christos 		break;
   3145  1.4.2.2  christos 
   3146  1.4.2.2  christos 	case BIOC_SAENABLE:
   3147  1.4.2.2  christos 		opc = MR_DCMD_SPEAKER_ENABLE;
   3148  1.4.2.2  christos 		break;
   3149  1.4.2.2  christos 
   3150  1.4.2.2  christos 	case BIOC_SASILENCE:
   3151  1.4.2.2  christos 		opc = MR_DCMD_SPEAKER_SILENCE;
   3152  1.4.2.2  christos 		break;
   3153  1.4.2.2  christos 
   3154  1.4.2.2  christos 	case BIOC_GASTATUS:
   3155  1.4.2.2  christos 		opc = MR_DCMD_SPEAKER_GET;
   3156  1.4.2.2  christos 		dir = MFII_DATA_IN;
   3157  1.4.2.2  christos 		break;
   3158  1.4.2.2  christos 
   3159  1.4.2.2  christos 	case BIOC_SATEST:
   3160  1.4.2.2  christos 		opc = MR_DCMD_SPEAKER_TEST;
   3161  1.4.2.2  christos 		break;
   3162  1.4.2.2  christos 
   3163  1.4.2.2  christos 	default:
   3164  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_alarm biocalarm invalid "
   3165  1.4.2.2  christos 		    "opcode %x\n", DEVNAME(sc), ba->ba_opcode);
   3166  1.4.2.2  christos 		return (EINVAL);
   3167  1.4.2.2  christos 	}
   3168  1.4.2.2  christos 
   3169  1.4.2.2  christos 	if (mfii_mgmt(sc, opc, NULL, &ret, sizeof(ret), dir, false))
   3170  1.4.2.2  christos 		rv = EINVAL;
   3171  1.4.2.2  christos 	else
   3172  1.4.2.2  christos 		if (ba->ba_opcode == BIOC_GASTATUS)
   3173  1.4.2.2  christos 			ba->ba_status = ret;
   3174  1.4.2.2  christos 		else
   3175  1.4.2.2  christos 			ba->ba_status = 0;
   3176  1.4.2.2  christos 
   3177  1.4.2.2  christos 	return (rv);
   3178  1.4.2.2  christos }
   3179  1.4.2.2  christos 
   3180  1.4.2.3    martin static int
   3181  1.4.2.2  christos mfii_ioctl_blink(struct mfii_softc *sc, struct bioc_blink *bb)
   3182  1.4.2.2  christos {
   3183  1.4.2.2  christos 	int			i, found, rv = EINVAL;
   3184  1.4.2.2  christos 	union mfi_mbox		mbox;
   3185  1.4.2.2  christos 	uint32_t		cmd;
   3186  1.4.2.2  christos 	struct mfi_pd_list	*pd;
   3187  1.4.2.2  christos 
   3188  1.4.2.2  christos 	DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_blink %x\n", DEVNAME(sc),
   3189  1.4.2.2  christos 	    bb->bb_status);
   3190  1.4.2.2  christos 
   3191  1.4.2.2  christos 	/* channel 0 means not in an enclosure so can't be blinked */
   3192  1.4.2.2  christos 	if (bb->bb_channel == 0)
   3193  1.4.2.2  christos 		return (EINVAL);
   3194  1.4.2.2  christos 
   3195  1.4.2.2  christos 	pd = malloc(sizeof(*pd), M_DEVBUF, M_WAITOK);
   3196  1.4.2.2  christos 
   3197  1.4.2.2  christos 	if (mfii_mgmt(sc, MR_DCMD_PD_GET_LIST, NULL, pd, sizeof(*pd),
   3198  1.4.2.2  christos 	    MFII_DATA_IN, false))
   3199  1.4.2.2  christos 		goto done;
   3200  1.4.2.2  christos 
   3201  1.4.2.2  christos 	for (i = 0, found = 0; i < pd->mpl_no_pd; i++)
   3202  1.4.2.2  christos 		if (bb->bb_channel == pd->mpl_address[i].mpa_enc_index &&
   3203  1.4.2.2  christos 		    bb->bb_target == pd->mpl_address[i].mpa_enc_slot) {
   3204  1.4.2.2  christos 			found = 1;
   3205  1.4.2.2  christos 			break;
   3206  1.4.2.2  christos 		}
   3207  1.4.2.2  christos 
   3208  1.4.2.2  christos 	if (!found)
   3209  1.4.2.2  christos 		goto done;
   3210  1.4.2.2  christos 
   3211  1.4.2.2  christos 	memset(&mbox, 0, sizeof(mbox));
   3212  1.4.2.2  christos 	mbox.s[0] = pd->mpl_address[i].mpa_pd_id;
   3213  1.4.2.2  christos 
   3214  1.4.2.2  christos 	switch (bb->bb_status) {
   3215  1.4.2.2  christos 	case BIOC_SBUNBLINK:
   3216  1.4.2.2  christos 		cmd = MR_DCMD_PD_UNBLINK;
   3217  1.4.2.2  christos 		break;
   3218  1.4.2.2  christos 
   3219  1.4.2.2  christos 	case BIOC_SBBLINK:
   3220  1.4.2.2  christos 		cmd = MR_DCMD_PD_BLINK;
   3221  1.4.2.2  christos 		break;
   3222  1.4.2.2  christos 
   3223  1.4.2.2  christos 	case BIOC_SBALARM:
   3224  1.4.2.2  christos 	default:
   3225  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_blink biocblink invalid "
   3226  1.4.2.2  christos 		    "opcode %x\n", DEVNAME(sc), bb->bb_status);
   3227  1.4.2.2  christos 		goto done;
   3228  1.4.2.2  christos 	}
   3229  1.4.2.2  christos 
   3230  1.4.2.2  christos 
   3231  1.4.2.2  christos 	if (mfii_mgmt(sc, cmd, &mbox, NULL, 0, MFII_DATA_NONE, false))
   3232  1.4.2.2  christos 		goto done;
   3233  1.4.2.2  christos 
   3234  1.4.2.2  christos 	rv = 0;
   3235  1.4.2.2  christos done:
   3236  1.4.2.2  christos 	free(pd, M_DEVBUF);
   3237  1.4.2.2  christos 	return (rv);
   3238  1.4.2.2  christos }
   3239  1.4.2.2  christos 
   3240  1.4.2.2  christos static int
   3241  1.4.2.2  christos mfii_makegood(struct mfii_softc *sc, uint16_t pd_id)
   3242  1.4.2.2  christos {
   3243  1.4.2.2  christos 	struct mfii_foreign_scan_info *fsi;
   3244  1.4.2.2  christos 	struct mfi_pd_details	*pd;
   3245  1.4.2.2  christos 	union mfi_mbox		mbox;
   3246  1.4.2.2  christos 	int			rv;
   3247  1.4.2.2  christos 
   3248  1.4.2.2  christos 	fsi = malloc(sizeof *fsi, M_DEVBUF, M_WAITOK);
   3249  1.4.2.2  christos 	pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
   3250  1.4.2.2  christos 
   3251  1.4.2.2  christos 	memset(&mbox, 0, sizeof mbox);
   3252  1.4.2.2  christos 	mbox.s[0] = pd_id;
   3253  1.4.2.2  christos 	rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
   3254  1.4.2.2  christos 	    MFII_DATA_IN, false);
   3255  1.4.2.2  christos 	if (rv != 0)
   3256  1.4.2.2  christos 		goto done;
   3257  1.4.2.2  christos 
   3258  1.4.2.2  christos 	if (pd->mpd_fw_state == MFI_PD_UNCONFIG_BAD) {
   3259  1.4.2.2  christos 		mbox.s[0] = pd_id;
   3260  1.4.2.2  christos 		mbox.s[1] = pd->mpd_pd.mfp_seq;
   3261  1.4.2.2  christos 		mbox.b[4] = MFI_PD_UNCONFIG_GOOD;
   3262  1.4.2.2  christos 		rv = mfii_mgmt(sc, MR_DCMD_PD_SET_STATE, &mbox, NULL, 0,
   3263  1.4.2.2  christos 		    MFII_DATA_NONE, false);
   3264  1.4.2.2  christos 		if (rv != 0)
   3265  1.4.2.2  christos 			goto done;
   3266  1.4.2.2  christos 	}
   3267  1.4.2.2  christos 
   3268  1.4.2.2  christos 	memset(&mbox, 0, sizeof mbox);
   3269  1.4.2.2  christos 	mbox.s[0] = pd_id;
   3270  1.4.2.2  christos 	rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
   3271  1.4.2.2  christos 	    MFII_DATA_IN, false);
   3272  1.4.2.2  christos 	if (rv != 0)
   3273  1.4.2.2  christos 		goto done;
   3274  1.4.2.2  christos 
   3275  1.4.2.2  christos 	if (pd->mpd_ddf_state & MFI_DDF_FOREIGN) {
   3276  1.4.2.2  christos 		rv = mfii_mgmt(sc, MR_DCMD_CFG_FOREIGN_SCAN, NULL,
   3277  1.4.2.2  christos 		    fsi, sizeof(*fsi), MFII_DATA_IN, false);
   3278  1.4.2.2  christos 		if (rv != 0)
   3279  1.4.2.2  christos 			goto done;
   3280  1.4.2.2  christos 
   3281  1.4.2.2  christos 		if (fsi->count > 0) {
   3282  1.4.2.2  christos 			rv = mfii_mgmt(sc, MR_DCMD_CFG_FOREIGN_CLEAR, NULL,
   3283  1.4.2.2  christos 			    NULL, 0, MFII_DATA_NONE, false);
   3284  1.4.2.2  christos 			if (rv != 0)
   3285  1.4.2.2  christos 				goto done;
   3286  1.4.2.2  christos 		}
   3287  1.4.2.2  christos 	}
   3288  1.4.2.2  christos 
   3289  1.4.2.2  christos 	memset(&mbox, 0, sizeof mbox);
   3290  1.4.2.2  christos 	mbox.s[0] = pd_id;
   3291  1.4.2.2  christos 	rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
   3292  1.4.2.2  christos 	    MFII_DATA_IN, false);
   3293  1.4.2.2  christos 	if (rv != 0)
   3294  1.4.2.2  christos 		goto done;
   3295  1.4.2.2  christos 
   3296  1.4.2.2  christos 	if (pd->mpd_fw_state != MFI_PD_UNCONFIG_GOOD ||
   3297  1.4.2.2  christos 	    pd->mpd_ddf_state & MFI_DDF_FOREIGN)
   3298  1.4.2.2  christos 		rv = ENXIO;
   3299  1.4.2.2  christos 
   3300  1.4.2.2  christos done:
   3301  1.4.2.2  christos 	free(fsi, M_DEVBUF);
   3302  1.4.2.2  christos 	free(pd, M_DEVBUF);
   3303  1.4.2.2  christos 
   3304  1.4.2.2  christos 	return (rv);
   3305  1.4.2.2  christos }
   3306  1.4.2.2  christos 
   3307  1.4.2.2  christos static int
   3308  1.4.2.2  christos mfii_makespare(struct mfii_softc *sc, uint16_t pd_id)
   3309  1.4.2.2  christos {
   3310  1.4.2.2  christos 	struct mfi_hotspare	*hs;
   3311  1.4.2.2  christos 	struct mfi_pd_details	*pd;
   3312  1.4.2.2  christos 	union mfi_mbox		mbox;
   3313  1.4.2.2  christos 	size_t			size;
   3314  1.4.2.2  christos 	int			rv = EINVAL;
   3315  1.4.2.2  christos 
   3316  1.4.2.2  christos 	/* we really could skip and expect that inq took care of it */
   3317  1.4.2.2  christos 	if (mfii_bio_getitall(sc)) {
   3318  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "%s: mfii_bio_getitall failed\n",
   3319  1.4.2.2  christos 		    DEVNAME(sc));
   3320  1.4.2.2  christos 		return (rv);
   3321  1.4.2.2  christos 	}
   3322  1.4.2.2  christos 	size = sizeof *hs + sizeof(uint16_t) * sc->sc_cfg->mfc_no_array;
   3323  1.4.2.2  christos 
   3324  1.4.2.2  christos 	hs = malloc(size, M_DEVBUF, M_WAITOK);
   3325  1.4.2.2  christos 	pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
   3326  1.4.2.2  christos 
   3327  1.4.2.2  christos 	memset(&mbox, 0, sizeof mbox);
   3328  1.4.2.2  christos 	mbox.s[0] = pd_id;
   3329  1.4.2.2  christos 	rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
   3330  1.4.2.2  christos 	    MFII_DATA_IN, false);
   3331  1.4.2.2  christos 	if (rv != 0)
   3332  1.4.2.2  christos 		goto done;
   3333  1.4.2.2  christos 
   3334  1.4.2.2  christos 	memset(hs, 0, size);
   3335  1.4.2.2  christos 	hs->mhs_pd.mfp_id = pd->mpd_pd.mfp_id;
   3336  1.4.2.2  christos 	hs->mhs_pd.mfp_seq = pd->mpd_pd.mfp_seq;
   3337  1.4.2.2  christos 	rv = mfii_mgmt(sc, MR_DCMD_CFG_MAKE_SPARE, NULL, hs, size,
   3338  1.4.2.2  christos 	    MFII_DATA_OUT, false);
   3339  1.4.2.2  christos 
   3340  1.4.2.2  christos done:
   3341  1.4.2.2  christos 	free(hs, M_DEVBUF);
   3342  1.4.2.2  christos 	free(pd, M_DEVBUF);
   3343  1.4.2.2  christos 
   3344  1.4.2.2  christos 	return (rv);
   3345  1.4.2.2  christos }
   3346  1.4.2.2  christos 
   3347  1.4.2.3    martin static int
   3348  1.4.2.2  christos mfii_ioctl_setstate(struct mfii_softc *sc, struct bioc_setstate *bs)
   3349  1.4.2.2  christos {
   3350  1.4.2.2  christos 	struct mfi_pd_details	*pd;
   3351  1.4.2.2  christos 	struct mfi_pd_list	*pl;
   3352  1.4.2.2  christos 	int			i, found, rv = EINVAL;
   3353  1.4.2.2  christos 	union mfi_mbox		mbox;
   3354  1.4.2.2  christos 
   3355  1.4.2.2  christos 	DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_setstate %x\n", DEVNAME(sc),
   3356  1.4.2.2  christos 	    bs->bs_status);
   3357  1.4.2.2  christos 
   3358  1.4.2.2  christos 	pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
   3359  1.4.2.2  christos 	pl = malloc(sizeof *pl, M_DEVBUF, M_WAITOK);
   3360  1.4.2.2  christos 
   3361  1.4.2.2  christos 	if (mfii_mgmt(sc, MR_DCMD_PD_GET_LIST, NULL, pl, sizeof(*pl),
   3362  1.4.2.2  christos 	    MFII_DATA_IN, false))
   3363  1.4.2.2  christos 		goto done;
   3364  1.4.2.2  christos 
   3365  1.4.2.2  christos 	for (i = 0, found = 0; i < pl->mpl_no_pd; i++)
   3366  1.4.2.2  christos 		if (bs->bs_channel == pl->mpl_address[i].mpa_enc_index &&
   3367  1.4.2.2  christos 		    bs->bs_target == pl->mpl_address[i].mpa_enc_slot) {
   3368  1.4.2.2  christos 			found = 1;
   3369  1.4.2.2  christos 			break;
   3370  1.4.2.2  christos 		}
   3371  1.4.2.2  christos 
   3372  1.4.2.2  christos 	if (!found)
   3373  1.4.2.2  christos 		goto done;
   3374  1.4.2.2  christos 
   3375  1.4.2.2  christos 	memset(&mbox, 0, sizeof(mbox));
   3376  1.4.2.2  christos 	mbox.s[0] = pl->mpl_address[i].mpa_pd_id;
   3377  1.4.2.2  christos 
   3378  1.4.2.2  christos 	if (mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
   3379  1.4.2.2  christos 	    MFII_DATA_IN, false))
   3380  1.4.2.2  christos 		goto done;
   3381  1.4.2.2  christos 
   3382  1.4.2.2  christos 	mbox.s[0] = pl->mpl_address[i].mpa_pd_id;
   3383  1.4.2.2  christos 	mbox.s[1] = pd->mpd_pd.mfp_seq;
   3384  1.4.2.2  christos 
   3385  1.4.2.2  christos 	switch (bs->bs_status) {
   3386  1.4.2.2  christos 	case BIOC_SSONLINE:
   3387  1.4.2.2  christos 		mbox.b[4] = MFI_PD_ONLINE;
   3388  1.4.2.2  christos 		break;
   3389  1.4.2.2  christos 
   3390  1.4.2.2  christos 	case BIOC_SSOFFLINE:
   3391  1.4.2.2  christos 		mbox.b[4] = MFI_PD_OFFLINE;
   3392  1.4.2.2  christos 		break;
   3393  1.4.2.2  christos 
   3394  1.4.2.2  christos 	case BIOC_SSHOTSPARE:
   3395  1.4.2.2  christos 		mbox.b[4] = MFI_PD_HOTSPARE;
   3396  1.4.2.2  christos 		break;
   3397  1.4.2.2  christos 
   3398  1.4.2.2  christos 	case BIOC_SSREBUILD:
   3399  1.4.2.2  christos 		if (pd->mpd_fw_state != MFI_PD_OFFLINE) {
   3400  1.4.2.2  christos 			if ((rv = mfii_makegood(sc,
   3401  1.4.2.2  christos 			    pl->mpl_address[i].mpa_pd_id)))
   3402  1.4.2.2  christos 				goto done;
   3403  1.4.2.2  christos 
   3404  1.4.2.2  christos 			if ((rv = mfii_makespare(sc,
   3405  1.4.2.2  christos 			    pl->mpl_address[i].mpa_pd_id)))
   3406  1.4.2.2  christos 				goto done;
   3407  1.4.2.2  christos 
   3408  1.4.2.2  christos 			memset(&mbox, 0, sizeof(mbox));
   3409  1.4.2.2  christos 			mbox.s[0] = pl->mpl_address[i].mpa_pd_id;
   3410  1.4.2.2  christos 			rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox,
   3411  1.4.2.2  christos 			    pd, sizeof(*pd), MFII_DATA_IN, false);
   3412  1.4.2.2  christos 			if (rv != 0)
   3413  1.4.2.2  christos 				goto done;
   3414  1.4.2.2  christos 
   3415  1.4.2.2  christos 			/* rebuilding might be started by mfii_makespare() */
   3416  1.4.2.2  christos 			if (pd->mpd_fw_state == MFI_PD_REBUILD) {
   3417  1.4.2.2  christos 				rv = 0;
   3418  1.4.2.2  christos 				goto done;
   3419  1.4.2.2  christos 			}
   3420  1.4.2.2  christos 
   3421  1.4.2.2  christos 			mbox.s[0] = pl->mpl_address[i].mpa_pd_id;
   3422  1.4.2.2  christos 			mbox.s[1] = pd->mpd_pd.mfp_seq;
   3423  1.4.2.2  christos 		}
   3424  1.4.2.2  christos 		mbox.b[4] = MFI_PD_REBUILD;
   3425  1.4.2.2  christos 		break;
   3426  1.4.2.2  christos 
   3427  1.4.2.2  christos 	default:
   3428  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_setstate invalid "
   3429  1.4.2.2  christos 		    "opcode %x\n", DEVNAME(sc), bs->bs_status);
   3430  1.4.2.2  christos 		goto done;
   3431  1.4.2.2  christos 	}
   3432  1.4.2.2  christos 
   3433  1.4.2.2  christos 
   3434  1.4.2.2  christos 	rv = mfii_mgmt(sc, MR_DCMD_PD_SET_STATE, &mbox, NULL, 0,
   3435  1.4.2.2  christos 	    MFII_DATA_NONE, false);
   3436  1.4.2.2  christos done:
   3437  1.4.2.2  christos 	free(pd, M_DEVBUF);
   3438  1.4.2.2  christos 	free(pl, M_DEVBUF);
   3439  1.4.2.2  christos 	return (rv);
   3440  1.4.2.2  christos }
   3441  1.4.2.2  christos 
   3442  1.4.2.2  christos #if 0
   3443  1.4.2.2  christos int
   3444  1.4.2.2  christos mfii_ioctl_patrol(struct mfii_softc *sc, struct bioc_patrol *bp)
   3445  1.4.2.2  christos {
   3446  1.4.2.2  christos 	uint32_t		opc;
   3447  1.4.2.2  christos 	int			rv = 0;
   3448  1.4.2.2  christos 	struct mfi_pr_properties prop;
   3449  1.4.2.2  christos 	struct mfi_pr_status	status;
   3450  1.4.2.2  christos 	uint32_t		time, exec_freq;
   3451  1.4.2.2  christos 
   3452  1.4.2.2  christos 	switch (bp->bp_opcode) {
   3453  1.4.2.2  christos 	case BIOC_SPSTOP:
   3454  1.4.2.2  christos 	case BIOC_SPSTART:
   3455  1.4.2.2  christos 		if (bp->bp_opcode == BIOC_SPSTART)
   3456  1.4.2.2  christos 			opc = MR_DCMD_PR_START;
   3457  1.4.2.2  christos 		else
   3458  1.4.2.2  christos 			opc = MR_DCMD_PR_STOP;
   3459  1.4.2.2  christos 		if (mfii_mgmt(sc, opc, NULL, NULL, 0, MFII_DATA_IN, false))
   3460  1.4.2.2  christos 			return (EINVAL);
   3461  1.4.2.2  christos 		break;
   3462  1.4.2.2  christos 
   3463  1.4.2.2  christos 	case BIOC_SPMANUAL:
   3464  1.4.2.2  christos 	case BIOC_SPDISABLE:
   3465  1.4.2.2  christos 	case BIOC_SPAUTO:
   3466  1.4.2.2  christos 		/* Get device's time. */
   3467  1.4.2.2  christos 		opc = MR_DCMD_TIME_SECS_GET;
   3468  1.4.2.2  christos 		if (mfii_mgmt(sc, opc, NULL, &time, sizeof(time),
   3469  1.4.2.2  christos 		    MFII_DATA_IN, false))
   3470  1.4.2.2  christos 			return (EINVAL);
   3471  1.4.2.2  christos 
   3472  1.4.2.2  christos 		opc = MR_DCMD_PR_GET_PROPERTIES;
   3473  1.4.2.2  christos 		if (mfii_mgmt(sc, opc, NULL, &prop, sizeof(prop),
   3474  1.4.2.2  christos 		    MFII_DATA_IN, false))
   3475  1.4.2.2  christos 			return (EINVAL);
   3476  1.4.2.2  christos 
   3477  1.4.2.2  christos 		switch (bp->bp_opcode) {
   3478  1.4.2.2  christos 		case BIOC_SPMANUAL:
   3479  1.4.2.2  christos 			prop.op_mode = MFI_PR_OPMODE_MANUAL;
   3480  1.4.2.2  christos 			break;
   3481  1.4.2.2  christos 		case BIOC_SPDISABLE:
   3482  1.4.2.2  christos 			prop.op_mode = MFI_PR_OPMODE_DISABLED;
   3483  1.4.2.2  christos 			break;
   3484  1.4.2.2  christos 		case BIOC_SPAUTO:
   3485  1.4.2.2  christos 			if (bp->bp_autoival != 0) {
   3486  1.4.2.2  christos 				if (bp->bp_autoival == -1)
   3487  1.4.2.2  christos 					/* continuously */
   3488  1.4.2.2  christos 					exec_freq = 0xffffffffU;
   3489  1.4.2.2  christos 				else if (bp->bp_autoival > 0)
   3490  1.4.2.2  christos 					exec_freq = bp->bp_autoival;
   3491  1.4.2.2  christos 				else
   3492  1.4.2.2  christos 					return (EINVAL);
   3493  1.4.2.2  christos 				prop.exec_freq = exec_freq;
   3494  1.4.2.2  christos 			}
   3495  1.4.2.2  christos 			if (bp->bp_autonext != 0) {
   3496  1.4.2.2  christos 				if (bp->bp_autonext < 0)
   3497  1.4.2.2  christos 					return (EINVAL);
   3498  1.4.2.2  christos 				else
   3499  1.4.2.2  christos 					prop.next_exec = time + bp->bp_autonext;
   3500  1.4.2.2  christos 			}
   3501  1.4.2.2  christos 			prop.op_mode = MFI_PR_OPMODE_AUTO;
   3502  1.4.2.2  christos 			break;
   3503  1.4.2.2  christos 		}
   3504  1.4.2.2  christos 
   3505  1.4.2.2  christos 		opc = MR_DCMD_PR_SET_PROPERTIES;
   3506  1.4.2.2  christos 		if (mfii_mgmt(sc, opc, NULL, &prop, sizeof(prop),
   3507  1.4.2.2  christos 		    MFII_DATA_OUT, false))
   3508  1.4.2.2  christos 			return (EINVAL);
   3509  1.4.2.2  christos 
   3510  1.4.2.2  christos 		break;
   3511  1.4.2.2  christos 
   3512  1.4.2.2  christos 	case BIOC_GPSTATUS:
   3513  1.4.2.2  christos 		opc = MR_DCMD_PR_GET_PROPERTIES;
   3514  1.4.2.2  christos 		if (mfii_mgmt(sc, opc, NULL, &prop, sizeof(prop),
   3515  1.4.2.2  christos 		    MFII_DATA_IN, false))
   3516  1.4.2.2  christos 			return (EINVAL);
   3517  1.4.2.2  christos 
   3518  1.4.2.2  christos 		opc = MR_DCMD_PR_GET_STATUS;
   3519  1.4.2.2  christos 		if (mfii_mgmt(sc, opc, NULL, &status, sizeof(status),
   3520  1.4.2.2  christos 		    MFII_DATA_IN, false))
   3521  1.4.2.2  christos 			return (EINVAL);
   3522  1.4.2.2  christos 
   3523  1.4.2.2  christos 		/* Get device's time. */
   3524  1.4.2.2  christos 		opc = MR_DCMD_TIME_SECS_GET;
   3525  1.4.2.2  christos 		if (mfii_mgmt(sc, opc, NULL, &time, sizeof(time),
   3526  1.4.2.2  christos 		    MFII_DATA_IN, false))
   3527  1.4.2.2  christos 			return (EINVAL);
   3528  1.4.2.2  christos 
   3529  1.4.2.2  christos 		switch (prop.op_mode) {
   3530  1.4.2.2  christos 		case MFI_PR_OPMODE_AUTO:
   3531  1.4.2.2  christos 			bp->bp_mode = BIOC_SPMAUTO;
   3532  1.4.2.2  christos 			bp->bp_autoival = prop.exec_freq;
   3533  1.4.2.2  christos 			bp->bp_autonext = prop.next_exec;
   3534  1.4.2.2  christos 			bp->bp_autonow = time;
   3535  1.4.2.2  christos 			break;
   3536  1.4.2.2  christos 		case MFI_PR_OPMODE_MANUAL:
   3537  1.4.2.2  christos 			bp->bp_mode = BIOC_SPMMANUAL;
   3538  1.4.2.2  christos 			break;
   3539  1.4.2.2  christos 		case MFI_PR_OPMODE_DISABLED:
   3540  1.4.2.2  christos 			bp->bp_mode = BIOC_SPMDISABLED;
   3541  1.4.2.2  christos 			break;
   3542  1.4.2.2  christos 		default:
   3543  1.4.2.2  christos 			printf("%s: unknown patrol mode %d\n",
   3544  1.4.2.2  christos 			    DEVNAME(sc), prop.op_mode);
   3545  1.4.2.2  christos 			break;
   3546  1.4.2.2  christos 		}
   3547  1.4.2.2  christos 
   3548  1.4.2.2  christos 		switch (status.state) {
   3549  1.4.2.2  christos 		case MFI_PR_STATE_STOPPED:
   3550  1.4.2.2  christos 			bp->bp_status = BIOC_SPSSTOPPED;
   3551  1.4.2.2  christos 			break;
   3552  1.4.2.2  christos 		case MFI_PR_STATE_READY:
   3553  1.4.2.2  christos 			bp->bp_status = BIOC_SPSREADY;
   3554  1.4.2.2  christos 			break;
   3555  1.4.2.2  christos 		case MFI_PR_STATE_ACTIVE:
   3556  1.4.2.2  christos 			bp->bp_status = BIOC_SPSACTIVE;
   3557  1.4.2.2  christos 			break;
   3558  1.4.2.2  christos 		case MFI_PR_STATE_ABORTED:
   3559  1.4.2.2  christos 			bp->bp_status = BIOC_SPSABORTED;
   3560  1.4.2.2  christos 			break;
   3561  1.4.2.2  christos 		default:
   3562  1.4.2.2  christos 			printf("%s: unknown patrol state %d\n",
   3563  1.4.2.2  christos 			    DEVNAME(sc), status.state);
   3564  1.4.2.2  christos 			break;
   3565  1.4.2.2  christos 		}
   3566  1.4.2.2  christos 
   3567  1.4.2.2  christos 		break;
   3568  1.4.2.2  christos 
   3569  1.4.2.2  christos 	default:
   3570  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_patrol biocpatrol invalid "
   3571  1.4.2.2  christos 		    "opcode %x\n", DEVNAME(sc), bp->bp_opcode);
   3572  1.4.2.2  christos 		return (EINVAL);
   3573  1.4.2.2  christos 	}
   3574  1.4.2.2  christos 
   3575  1.4.2.2  christos 	return (rv);
   3576  1.4.2.2  christos }
   3577  1.4.2.2  christos #endif
   3578  1.4.2.2  christos 
   3579  1.4.2.3    martin static int
   3580  1.4.2.2  christos mfii_bio_hs(struct mfii_softc *sc, int volid, int type, void *bio_hs)
   3581  1.4.2.2  christos {
   3582  1.4.2.2  christos 	struct mfi_conf		*cfg;
   3583  1.4.2.2  christos 	struct mfi_hotspare	*hs;
   3584  1.4.2.2  christos 	struct mfi_pd_details	*pd;
   3585  1.4.2.2  christos 	struct bioc_disk	*sdhs;
   3586  1.4.2.2  christos 	struct bioc_vol		*vdhs;
   3587  1.4.2.2  christos 	struct scsipi_inquiry_data *inqbuf;
   3588  1.4.2.2  christos 	char			vend[8+16+4+1], *vendp;
   3589  1.4.2.2  christos 	int			i, rv = EINVAL;
   3590  1.4.2.2  christos 	uint32_t		size;
   3591  1.4.2.2  christos 	union mfi_mbox		mbox;
   3592  1.4.2.2  christos 
   3593  1.4.2.2  christos 	DNPRINTF(MFII_D_IOCTL, "%s: mfii_vol_hs %d\n", DEVNAME(sc), volid);
   3594  1.4.2.2  christos 
   3595  1.4.2.2  christos 	if (!bio_hs)
   3596  1.4.2.2  christos 		return (EINVAL);
   3597  1.4.2.2  christos 
   3598  1.4.2.2  christos 	pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
   3599  1.4.2.2  christos 
   3600  1.4.2.2  christos 	/* send single element command to retrieve size for full structure */
   3601  1.4.2.2  christos 	cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK);
   3602  1.4.2.2  christos 	if (mfii_mgmt(sc, MR_DCMD_CONF_GET, NULL, cfg, sizeof(*cfg),
   3603  1.4.2.2  christos 	    MFII_DATA_IN, false))
   3604  1.4.2.2  christos 		goto freeme;
   3605  1.4.2.2  christos 
   3606  1.4.2.2  christos 	size = cfg->mfc_size;
   3607  1.4.2.2  christos 	free(cfg, M_DEVBUF);
   3608  1.4.2.2  christos 
   3609  1.4.2.2  christos 	/* memory for read config */
   3610  1.4.2.2  christos 	cfg = malloc(size, M_DEVBUF, M_WAITOK|M_ZERO);
   3611  1.4.2.2  christos 	if (mfii_mgmt(sc, MR_DCMD_CONF_GET, NULL, cfg, size,
   3612  1.4.2.2  christos 	    MFII_DATA_IN, false))
   3613  1.4.2.2  christos 		goto freeme;
   3614  1.4.2.2  christos 
   3615  1.4.2.2  christos 	/* calculate offset to hs structure */
   3616  1.4.2.2  christos 	hs = (struct mfi_hotspare *)(
   3617  1.4.2.2  christos 	    ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) +
   3618  1.4.2.2  christos 	    cfg->mfc_array_size * cfg->mfc_no_array +
   3619  1.4.2.2  christos 	    cfg->mfc_ld_size * cfg->mfc_no_ld);
   3620  1.4.2.2  christos 
   3621  1.4.2.2  christos 	if (volid < cfg->mfc_no_ld)
   3622  1.4.2.2  christos 		goto freeme; /* not a hotspare */
   3623  1.4.2.2  christos 
   3624  1.4.2.2  christos 	if (volid > (cfg->mfc_no_ld + cfg->mfc_no_hs))
   3625  1.4.2.2  christos 		goto freeme; /* not a hotspare */
   3626  1.4.2.2  christos 
   3627  1.4.2.2  christos 	/* offset into hotspare structure */
   3628  1.4.2.2  christos 	i = volid - cfg->mfc_no_ld;
   3629  1.4.2.2  christos 
   3630  1.4.2.2  christos 	DNPRINTF(MFII_D_IOCTL, "%s: mfii_vol_hs i %d volid %d no_ld %d no_hs %d "
   3631  1.4.2.2  christos 	    "hs %p cfg %p id %02x\n", DEVNAME(sc), i, volid, cfg->mfc_no_ld,
   3632  1.4.2.2  christos 	    cfg->mfc_no_hs, hs, cfg, hs[i].mhs_pd.mfp_id);
   3633  1.4.2.2  christos 
   3634  1.4.2.2  christos 	/* get pd fields */
   3635  1.4.2.2  christos 	memset(&mbox, 0, sizeof(mbox));
   3636  1.4.2.2  christos 	mbox.s[0] = hs[i].mhs_pd.mfp_id;
   3637  1.4.2.2  christos 	if (mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
   3638  1.4.2.2  christos 	    MFII_DATA_IN, false)) {
   3639  1.4.2.2  christos 		DNPRINTF(MFII_D_IOCTL, "%s: mfii_vol_hs illegal PD\n",
   3640  1.4.2.2  christos 		    DEVNAME(sc));
   3641  1.4.2.2  christos 		goto freeme;
   3642  1.4.2.2  christos 	}
   3643  1.4.2.2  christos 
   3644  1.4.2.2  christos 	switch (type) {
   3645  1.4.2.2  christos 	case MFI_MGMT_VD:
   3646  1.4.2.2  christos 		vdhs = bio_hs;
   3647  1.4.2.2  christos 		vdhs->bv_status = BIOC_SVONLINE;
   3648  1.4.2.2  christos 		vdhs->bv_size = pd->mpd_size / 2 * 1024; /* XXX why? */
   3649  1.4.2.2  christos 		vdhs->bv_level = -1; /* hotspare */
   3650  1.4.2.2  christos 		vdhs->bv_nodisk = 1;
   3651  1.4.2.2  christos 		break;
   3652  1.4.2.2  christos 
   3653  1.4.2.2  christos 	case MFI_MGMT_SD:
   3654  1.4.2.2  christos 		sdhs = bio_hs;
   3655  1.4.2.2  christos 		sdhs->bd_status = BIOC_SDHOTSPARE;
   3656  1.4.2.2  christos 		sdhs->bd_size = pd->mpd_size / 2 * 1024; /* XXX why? */
   3657  1.4.2.2  christos 		sdhs->bd_channel = pd->mpd_enc_idx;
   3658  1.4.2.2  christos 		sdhs->bd_target = pd->mpd_enc_slot;
   3659  1.4.2.2  christos 		inqbuf = (struct scsipi_inquiry_data *)&pd->mpd_inq_data;
   3660  1.4.2.2  christos 		vendp = inqbuf->vendor;
   3661  1.4.2.2  christos 		memcpy(vend, vendp, sizeof vend - 1);
   3662  1.4.2.2  christos 		vend[sizeof vend - 1] = '\0';
   3663  1.4.2.2  christos 		strlcpy(sdhs->bd_vendor, vend, sizeof(sdhs->bd_vendor));
   3664  1.4.2.2  christos 		break;
   3665  1.4.2.2  christos 
   3666  1.4.2.2  christos 	default:
   3667  1.4.2.2  christos 		goto freeme;
   3668  1.4.2.2  christos 	}
   3669  1.4.2.2  christos 
   3670  1.4.2.2  christos 	DNPRINTF(MFII_D_IOCTL, "%s: mfii_vol_hs 6\n", DEVNAME(sc));
   3671  1.4.2.2  christos 	rv = 0;
   3672  1.4.2.2  christos freeme:
   3673  1.4.2.2  christos 	free(pd, M_DEVBUF);
   3674  1.4.2.2  christos 	free(cfg, M_DEVBUF);
   3675  1.4.2.2  christos 
   3676  1.4.2.2  christos 	return (rv);
   3677  1.4.2.2  christos }
   3678  1.4.2.2  christos 
   3679  1.4.2.2  christos #endif /* NBIO > 0 */
   3680  1.4.2.2  christos 
   3681  1.4.2.2  christos #define MFI_BBU_SENSORS 4
   3682  1.4.2.2  christos 
   3683  1.4.2.3    martin static void
   3684  1.4.2.2  christos mfii_bbu(struct mfii_softc *sc, envsys_data_t *edata)
   3685  1.4.2.2  christos {
   3686  1.4.2.2  christos 	struct mfi_bbu_status bbu;
   3687  1.4.2.2  christos 	u_int32_t status;
   3688  1.4.2.2  christos 	u_int32_t mask;
   3689  1.4.2.2  christos 	u_int32_t soh_bad;
   3690  1.4.2.2  christos 	int rv;
   3691  1.4.2.2  christos 
   3692  1.4.2.2  christos 	mutex_enter(&sc->sc_lock);
   3693  1.4.2.2  christos 	rv = mfii_mgmt(sc, MR_DCMD_BBU_GET_STATUS, NULL, &bbu,
   3694  1.4.2.2  christos 	    sizeof(bbu), MFII_DATA_IN, false);
   3695  1.4.2.2  christos 	mutex_exit(&sc->sc_lock);
   3696  1.4.2.2  christos 	if (rv != 0) {
   3697  1.4.2.2  christos 		edata->state = ENVSYS_SINVALID;
   3698  1.4.2.2  christos 		edata->value_cur = 0;
   3699  1.4.2.2  christos 		return;
   3700  1.4.2.2  christos 	}
   3701  1.4.2.2  christos 
   3702  1.4.2.2  christos 	switch (bbu.battery_type) {
   3703  1.4.2.2  christos 	case MFI_BBU_TYPE_IBBU:
   3704  1.4.2.2  christos 		mask = MFI_BBU_STATE_BAD_IBBU;
   3705  1.4.2.2  christos 		soh_bad = 0;
   3706  1.4.2.2  christos 		break;
   3707  1.4.2.2  christos 	case MFI_BBU_TYPE_BBU:
   3708  1.4.2.2  christos 		mask = MFI_BBU_STATE_BAD_BBU;
   3709  1.4.2.2  christos 		soh_bad = (bbu.detail.bbu.is_SOH_good == 0);
   3710  1.4.2.2  christos 		break;
   3711  1.4.2.2  christos 
   3712  1.4.2.2  christos 	case MFI_BBU_TYPE_NONE:
   3713  1.4.2.2  christos 	default:
   3714  1.4.2.2  christos 		edata->state = ENVSYS_SCRITICAL;
   3715  1.4.2.2  christos 		edata->value_cur = 0;
   3716  1.4.2.2  christos 		return;
   3717  1.4.2.2  christos 	}
   3718  1.4.2.2  christos 
   3719  1.4.2.2  christos 	status = le32toh(bbu.fw_status) & mask;
   3720  1.4.2.2  christos 	switch(edata->sensor) {
   3721  1.4.2.2  christos 	case 0:
   3722  1.4.2.2  christos 		edata->value_cur = (status || soh_bad) ? 0 : 1;
   3723  1.4.2.2  christos 		edata->state =
   3724  1.4.2.2  christos 		    edata->value_cur ? ENVSYS_SVALID : ENVSYS_SCRITICAL;
   3725  1.4.2.2  christos 		return;
   3726  1.4.2.2  christos 	case 1:
   3727  1.4.2.2  christos 		edata->value_cur = le16toh(bbu.voltage) * 1000;
   3728  1.4.2.2  christos 		edata->state = ENVSYS_SVALID;
   3729  1.4.2.2  christos 		return;
   3730  1.4.2.2  christos 	case 2:
   3731  1.4.2.2  christos 		edata->value_cur = (int16_t)le16toh(bbu.current) * 1000;
   3732  1.4.2.2  christos 		edata->state = ENVSYS_SVALID;
   3733  1.4.2.2  christos 		return;
   3734  1.4.2.2  christos 	case 3:
   3735  1.4.2.2  christos 		edata->value_cur = le16toh(bbu.temperature) * 1000000 + 273150000;
   3736  1.4.2.2  christos 		edata->state = ENVSYS_SVALID;
   3737  1.4.2.2  christos 		return;
   3738  1.4.2.2  christos 	}
   3739  1.4.2.2  christos }
   3740  1.4.2.2  christos 
   3741  1.4.2.3    martin static void
   3742  1.4.2.2  christos mfii_refresh_ld_sensor(struct mfii_softc *sc, envsys_data_t *edata)
   3743  1.4.2.2  christos {
   3744  1.4.2.2  christos 	struct bioc_vol bv;
   3745  1.4.2.2  christos 	int error;
   3746  1.4.2.2  christos 
   3747  1.4.2.2  christos 	memset(&bv, 0, sizeof(bv));
   3748  1.4.2.2  christos 	bv.bv_volid = edata->sensor - MFI_BBU_SENSORS;
   3749  1.4.2.2  christos 	mutex_enter(&sc->sc_lock);
   3750  1.4.2.2  christos 	error = mfii_ioctl_vol(sc, &bv);
   3751  1.4.2.2  christos 	mutex_exit(&sc->sc_lock);
   3752  1.4.2.2  christos 	if (error)
   3753  1.4.2.2  christos 		bv.bv_status = BIOC_SVINVALID;
   3754  1.4.2.2  christos 	bio_vol_to_envsys(edata, &bv);
   3755  1.4.2.2  christos }
   3756  1.4.2.2  christos 
   3757  1.4.2.3    martin static void
   3758  1.4.2.2  christos mfii_init_ld_sensor(struct mfii_softc *sc, envsys_data_t *sensor, int i)
   3759  1.4.2.2  christos {
   3760  1.4.2.2  christos 	sensor->units = ENVSYS_DRIVE;
   3761  1.4.2.2  christos 	sensor->state = ENVSYS_SINVALID;
   3762  1.4.2.2  christos 	sensor->value_cur = ENVSYS_DRIVE_EMPTY;
   3763  1.4.2.2  christos 	/* Enable monitoring for drive state changes */
   3764  1.4.2.2  christos 	sensor->flags |= ENVSYS_FMONSTCHANGED;
   3765  1.4.2.2  christos 	snprintf(sensor->desc, sizeof(sensor->desc), "%s:%d", DEVNAME(sc), i);
   3766  1.4.2.2  christos }
   3767  1.4.2.2  christos 
   3768  1.4.2.2  christos static void
   3769  1.4.2.2  christos mfii_attach_sensor(struct mfii_softc *sc, envsys_data_t *s)
   3770  1.4.2.2  christos {
   3771  1.4.2.2  christos 	if (sysmon_envsys_sensor_attach(sc->sc_sme, s))
   3772  1.4.2.2  christos 		aprint_error_dev(sc->sc_dev,
   3773  1.4.2.2  christos 		    "failed to attach sensor %s\n", s->desc);
   3774  1.4.2.2  christos }
   3775  1.4.2.2  christos 
   3776  1.4.2.3    martin static int
   3777  1.4.2.2  christos mfii_create_sensors(struct mfii_softc *sc)
   3778  1.4.2.2  christos {
   3779  1.4.2.2  christos 	int i, rv;
   3780  1.4.2.2  christos 	const int nsensors = MFI_BBU_SENSORS + MFI_MAX_LD;
   3781  1.4.2.2  christos 
   3782  1.4.2.2  christos 	sc->sc_sme = sysmon_envsys_create();
   3783  1.4.2.2  christos 	sc->sc_sensors = malloc(sizeof(envsys_data_t) * nsensors,
   3784  1.4.2.2  christos 	    M_DEVBUF, M_NOWAIT | M_ZERO);
   3785  1.4.2.2  christos 
   3786  1.4.2.2  christos 	if (sc->sc_sensors == NULL) {
   3787  1.4.2.2  christos 		aprint_error_dev(sc->sc_dev, "can't allocate envsys_data_t\n");
   3788  1.4.2.2  christos 		return ENOMEM;
   3789  1.4.2.2  christos 	}
   3790  1.4.2.2  christos 	/* BBU */
   3791  1.4.2.2  christos 	sc->sc_sensors[0].units = ENVSYS_INDICATOR;
   3792  1.4.2.2  christos 	sc->sc_sensors[0].state = ENVSYS_SINVALID;
   3793  1.4.2.2  christos 	sc->sc_sensors[0].value_cur = 0;
   3794  1.4.2.2  christos 	sc->sc_sensors[1].units = ENVSYS_SVOLTS_DC;
   3795  1.4.2.2  christos 	sc->sc_sensors[1].state = ENVSYS_SINVALID;
   3796  1.4.2.2  christos 	sc->sc_sensors[1].value_cur = 0;
   3797  1.4.2.2  christos 	sc->sc_sensors[2].units = ENVSYS_SAMPS;
   3798  1.4.2.2  christos 	sc->sc_sensors[2].state = ENVSYS_SINVALID;
   3799  1.4.2.2  christos 	sc->sc_sensors[2].value_cur = 0;
   3800  1.4.2.2  christos 	sc->sc_sensors[3].units = ENVSYS_STEMP;
   3801  1.4.2.2  christos 	sc->sc_sensors[3].state = ENVSYS_SINVALID;
   3802  1.4.2.2  christos 	sc->sc_sensors[3].value_cur = 0;
   3803  1.4.2.2  christos 
   3804  1.4.2.2  christos 	if (ISSET(le32toh(sc->sc_info.mci_hw_present), MFI_INFO_HW_BBU)) {
   3805  1.4.2.2  christos 		sc->sc_bbuok = true;
   3806  1.4.2.2  christos 		sc->sc_sensors[0].flags |= ENVSYS_FMONCRITICAL;
   3807  1.4.2.2  christos 		snprintf(sc->sc_sensors[0].desc, sizeof(sc->sc_sensors[0].desc),
   3808  1.4.2.2  christos 		    "%s BBU state", DEVNAME(sc));
   3809  1.4.2.2  christos 		snprintf(sc->sc_sensors[1].desc, sizeof(sc->sc_sensors[1].desc),
   3810  1.4.2.2  christos 		    "%s BBU voltage", DEVNAME(sc));
   3811  1.4.2.2  christos 		snprintf(sc->sc_sensors[2].desc, sizeof(sc->sc_sensors[2].desc),
   3812  1.4.2.2  christos 		    "%s BBU current", DEVNAME(sc));
   3813  1.4.2.2  christos 		snprintf(sc->sc_sensors[3].desc, sizeof(sc->sc_sensors[3].desc),
   3814  1.4.2.2  christos 		    "%s BBU temperature", DEVNAME(sc));
   3815  1.4.2.2  christos 		for (i = 0; i < MFI_BBU_SENSORS; i++) {
   3816  1.4.2.2  christos 			mfii_attach_sensor(sc, &sc->sc_sensors[i]);
   3817  1.4.2.2  christos 		}
   3818  1.4.2.2  christos 	}
   3819  1.4.2.2  christos 
   3820  1.4.2.2  christos 	for (i = 0; i < sc->sc_ld_list.mll_no_ld; i++) {
   3821  1.4.2.2  christos 		mfii_init_ld_sensor(sc, &sc->sc_sensors[i + MFI_BBU_SENSORS], i);
   3822  1.4.2.2  christos 		mfii_attach_sensor(sc, &sc->sc_sensors[i + MFI_BBU_SENSORS]);
   3823  1.4.2.2  christos 	}
   3824  1.4.2.2  christos 
   3825  1.4.2.2  christos 	sc->sc_sme->sme_name = DEVNAME(sc);
   3826  1.4.2.2  christos 	sc->sc_sme->sme_cookie = sc;
   3827  1.4.2.2  christos 	sc->sc_sme->sme_refresh = mfii_refresh_sensor;
   3828  1.4.2.2  christos 	rv = sysmon_envsys_register(sc->sc_sme);
   3829  1.4.2.2  christos 	if (rv) {
   3830  1.4.2.2  christos 		aprint_error_dev(sc->sc_dev,
   3831  1.4.2.2  christos 		    "unable to register with sysmon (rv = %d)\n", rv);
   3832  1.4.2.2  christos 	}
   3833  1.4.2.2  christos 	return rv;
   3834  1.4.2.2  christos 
   3835  1.4.2.2  christos }
   3836  1.4.2.2  christos 
   3837  1.4.2.2  christos static int
   3838  1.4.2.2  christos mfii_destroy_sensors(struct mfii_softc *sc)
   3839  1.4.2.2  christos {
   3840  1.4.2.2  christos 	if (sc->sc_sme == NULL)
   3841  1.4.2.2  christos 		return 0;
   3842  1.4.2.2  christos 	sysmon_envsys_unregister(sc->sc_sme);
   3843  1.4.2.2  christos 	sc->sc_sme = NULL;
   3844  1.4.2.2  christos 	free(sc->sc_sensors, M_DEVBUF);
   3845  1.4.2.2  christos 	return 0;
   3846  1.4.2.2  christos }
   3847  1.4.2.2  christos 
   3848  1.4.2.3    martin static void
   3849  1.4.2.2  christos mfii_refresh_sensor(struct sysmon_envsys *sme, envsys_data_t *edata)
   3850  1.4.2.2  christos {
   3851  1.4.2.2  christos 	struct mfii_softc	*sc = sme->sme_cookie;
   3852  1.4.2.2  christos 
   3853  1.4.2.2  christos 	if (edata->sensor >= MFI_BBU_SENSORS + MFI_MAX_LD)
   3854  1.4.2.2  christos 		return;
   3855  1.4.2.2  christos 
   3856  1.4.2.2  christos 	if (edata->sensor < MFI_BBU_SENSORS) {
   3857  1.4.2.2  christos 		if (sc->sc_bbuok)
   3858  1.4.2.2  christos 			mfii_bbu(sc, edata);
   3859  1.4.2.2  christos 	} else {
   3860  1.4.2.2  christos 		mfii_refresh_ld_sensor(sc, edata);
   3861  1.4.2.2  christos 	}
   3862  1.4.2.2  christos }
   3863