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