#ifndef _SYS_SCSI_ADAPTERS_SCSI_VHCI_H
#define _SYS_SCSI_ADAPTERS_SCSI_VHCI_H
#include <sys/note.h>
#include <sys/taskq.h>
#include <sys/mhd.h>
#include <sys/sunmdi.h>
#include <sys/mdi_impldefs.h>
#include <sys/scsi/adapters/mpapi_impl.h>
#include <sys/scsi/adapters/mpapi_scsi_vhci.h>
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(_BIT_FIELDS_LTOH) && !defined(_BIT_FIELDS_HTOL)
#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
#endif
#ifdef _KERNEL
#ifdef UNDEFINED
#undef UNDEFINED
#endif
#define UNDEFINED -1
#define VHCI_STATE_OPEN 0x00000001
#define VH_SLEEP 0x0
#define VH_NOSLEEP 0x1
#define TRAN2HBAPRIVATE(tran) ((struct scsi_vhci *)(tran)->tran_hba_private)
#define VHCI_INIT_WAIT_TIMEOUT 60000000
#define VHCI_FOWATCH_INTERVAL 1000000
#define VHCI_EXTFO_TIMEOUT (3 * 60 * NANOSEC)
#define SCBP_C(pkt) ((*(pkt)->pkt_scbp) & STATUS_MASK)
int vhci_do_scsi_cmd(struct scsi_pkt *);
void vhci_log(int, dev_info_t *, const char *, ...);
size_t vhci_get_blocksize(dev_info_t *);
#ifdef DEBUG
#ifndef VHCI_DEBUG_DEFAULT_VAL
#define VHCI_DEBUG_DEFAULT_VAL 0
#endif
extern int vhci_debug;
#include <sys/debug.h>
#define VHCI_DEBUG(level, stmnt) \
if (vhci_debug >= (level)) vhci_log stmnt
#else
#define VHCI_DEBUG(level, stmnt)
#endif
#define VHCI_PKT_PRIV_SIZE 2
#define ADDR2VHCI(ap) ((struct scsi_vhci *) \
((ap)->a_hba_tran->tran_hba_private))
#define ADDR2VLUN(ap) (scsi_vhci_lun_t *) \
(scsi_device_hba_private_get(scsi_address_device(ap)))
#define ADDR2DIP(ap) ((dev_info_t *)(scsi_address_device(ap)->sd_dev))
#define HBAPKT2VHCIPKT(pkt) (pkt->pkt_private)
#define TGTPKT2VHCIPKT(pkt) (pkt->pkt_ha_private)
#define VHCIPKT2HBAPKT(pkt) (pkt->pkt_hba_pkt)
#define VHCIPKT2TGTPKT(pkt) (pkt->pkt_tgt_pkt)
#define VHCI_DECR_PATH_CMDCOUNT(svp) { \
mutex_enter(&(svp)->svp_mutex); \
(svp)->svp_cmds--; \
if ((svp)->svp_cmds == 0) \
cv_broadcast(&(svp)->svp_cv); \
mutex_exit(&(svp)->svp_mutex); \
}
#define VHCI_INCR_PATH_CMDCOUNT(svp) { \
mutex_enter(&(svp)->svp_mutex); \
(svp)->svp_cmds++; \
mutex_exit(&(svp)->svp_mutex); \
}
#define VHCI_HOLD_LUN(vlun, f, h) { \
int sleep = (f); \
mutex_enter(&(vlun)->svl_mutex); \
if ((vlun)->svl_transient == 1) { \
if (sleep == VH_SLEEP) { \
while ((vlun)->svl_transient == 1) \
cv_wait(&(vlun)->svl_cv, &(vlun)->svl_mutex); \
(vlun)->svl_transient = 1; \
(h) = 1; \
} else { \
(h) = 0; \
} \
} else { \
(vlun)->svl_transient = 1; \
(h) = 1; \
} \
sleep = (h); \
mutex_exit(&(vlun)->svl_mutex); \
}
#define VHCI_RELEASE_LUN(vlun) { \
mutex_enter(&(vlun)->svl_mutex); \
(vlun)->svl_transient = 0; \
cv_broadcast(&(vlun)->svl_cv); \
mutex_exit(&(vlun)->svl_mutex); \
}
#define VHCI_LUN_IS_HELD(vlun) ((vlun)->svl_transient == 1)
#define VHCI_PKT_IDLE 0x01
#define VHCI_PKT_ISSUED 0x02
#define VHCI_PKT_ABORTING 0x04
#define VHCI_PKT_STALE_BINDING 0x08
#define VHCI_PKT_THRU_TASKQ 0x20
#define VHCI_PKT_IN_FAILOVER 0x40
#define VHCI_PKT_TIMEOUT 30
#define VHCI_PKT_RETRY_CNT 2
#define VHCI_POLL_TIMEOUT 60
#define EXTCMDS_STATUS_SIZE (sizeof (struct scsi_arq_status))
#define CFLAG_NOWAIT 0x1000
#define CFLAG_DMA_PARTIAL 0x2000
#define VHCI_SCSI_CDB_SIZE 16
#define VHCI_SCSI_SCB_SIZE (sizeof (struct scsi_arq_status))
#define VHCI_SCSI_OSD_CDB_SIZE 224
#define VHCI_SCSI_OSD_PKT_FLAGS 0x100000
#define SCSI_NO_FAILOVER 0x0
#define SCSI_IMPLICIT_FAILOVER 0x1
#define SCSI_EXPLICIT_FAILOVER 0x2
#define SCSI_BOTH_FAILOVER \
(SCSI_IMPLICIT_FAILOVER | SCSI_EXPLICIT_FAILOVER)
struct scsi_vhci_swarg;
#define VHCI_NUM_RESV_KEYS 8
typedef struct vhci_prin_readkeys {
uint32_t generation;
uint32_t length;
mhioc_resv_key_t keylist[VHCI_NUM_RESV_KEYS];
} vhci_prin_readkeys_t;
#define VHCI_PROUT_SIZE \
((sizeof (vhci_prout_t) - 2 * (MHIOC_RESV_KEY_SIZE) * sizeof (char)))
typedef struct vhci_prout {
uchar_t res_key[MHIOC_RESV_KEY_SIZE];
uchar_t service_key[MHIOC_RESV_KEY_SIZE];
uint32_t scope_address;
#if defined(_BIT_FIELDS_LTOH)
uchar_t aptpl:1,
reserved:7;
#else
uchar_t reserved:7,
aptpl:1;
#endif
uchar_t reserved_1;
uint16_t ext_len;
uchar_t active_res_key[MHIOC_RESV_KEY_SIZE];
uchar_t active_service_key[MHIOC_RESV_KEY_SIZE];
} vhci_prout_t;
#define VHCI_PROUT_REGISTER 0x0
#define VHCI_PROUT_RESERVE 0x1
#define VHCI_PROUT_RELEASE 0x2
#define VHCI_PROUT_CLEAR 0x3
#define VHCI_PROUT_PREEMPT 0x4
#define VHCI_PROUT_P_AND_A 0x5
#define VHCI_PROUT_R_AND_IGNORE 0x6
struct vhci_pkt {
struct scsi_pkt *vpkt_tgt_pkt;
mdi_pathinfo_t *vpkt_path;
struct scsi_pkt *vpkt_hba_pkt;
uint_t vpkt_state;
uint_t vpkt_flags;
int vpkt_tgt_init_cdblen;
int vpkt_tgt_init_scblen;
int vpkt_tgt_init_pkt_flags;
struct buf *vpkt_tgt_init_bp;
struct vhci_pkt *vpkt_org_vpkt;
};
typedef struct scsi_vhci_lun {
kmutex_t svl_mutex;
kcondvar_t svl_cv;
int svl_transient;
int svl_waiting_for_activepath;
hrtime_t svl_wfa_time;
int svl_failover_status;
client_lb_t svl_lb_policy_save;
struct scsi_failover_ops *svl_fops;
char *svl_fops_name;
void *svl_fops_ctpriv;
struct scsi_vhci_lun *svl_hash_next;
char *svl_lun_wwn;
char *svl_active_pclass;
dev_info_t *svl_dip;
uint32_t svl_flags;
mdi_pathinfo_t *svl_resrv_pip;
taskq_t *svl_taskq;
ksema_t svl_pgr_sema;
vhci_prin_readkeys_t svl_prin;
vhci_prout_t svl_prout;
uchar_t svl_cdb[CDB_GROUP4];
int svl_time;
uint32_t svl_bcount;
int svl_pgr_active;
mdi_pathinfo_t *svl_first_path;
int svl_efo_update_path;
struct scsi_vhci_swarg *svl_swarg;
uint32_t svl_support_lun_reset;
int svl_not_supported;
int svl_xlf_capable;
int svl_sector_size;
int svl_setcap_done;
uint16_t svl_fo_support;
} scsi_vhci_lun_t;
#define VLUN_TASK_D_ALIVE_FLG 0x01
#define VLUN_RESERVE_ACTIVE_FLG 0x04
#define VLUN_QUIESCED_FLG 0x08
#define VLUN_UPDATE_TPG 0x10
#define VHCI_DEPTH_ALL 3
#define VHCI_DEPTH_TARGET 2
#define VHCI_DEPTH_LUN 1
#define TRUE (1)
#define FALSE (0)
typedef struct scsi_vhci_priv {
kmutex_t svp_mutex;
kcondvar_t svp_cv;
struct scsi_vhci_lun *svp_svl;
struct scsi_device *svp_psd;
int svp_cmds;
uchar_t svp_last_pkt_reason;
opaque_t svp_sw_token;
int svp_new_path;
} scsi_vhci_priv_t;
typedef struct scsi_vhci_swarg {
scsi_vhci_priv_t *svs_svp;
hrtime_t svs_tos;
mdi_pathinfo_t *svs_pi;
int svs_release_lun;
int svs_done;
} scsi_vhci_swarg_t;
struct scsi_vhci {
kmutex_t vhci_mutex;
dev_info_t *vhci_dip;
struct scsi_hba_tran *vhci_tran;
uint32_t vhci_state;
uint32_t vhci_instance;
kstat_t vhci_kstat;
taskq_t *vhci_taskq;
taskq_t *vhci_update_pathstates_taskq;
struct scsi_reset_notify_entry *vhci_reset_notify_listf;
uint16_t vhci_conf_flags;
mpapi_priv_t *mp_priv;
};
#define VHCI_CONF_FLAGS_AUTO_FAILBACK 0x0001
typedef enum {
SCSI_PATH_INACTIVE,
SCSI_PATH_ACTIVE,
SCSI_PATH_ACTIVE_NONOPT
} scsi_path_state_t;
#define SCSI_MAXPCLASSLEN 25
#define OPINFO_REV 1
struct scsi_path_opinfo {
int opinfo_rev;
char opinfo_path_attr[SCSI_MAXPCLASSLEN];
scsi_path_state_t opinfo_path_state;
uint_t opinfo_pswtch_best;
uint_t opinfo_pswtch_worst;
int opinfo_xlf_capable;
uint16_t opinfo_preferred;
uint16_t opinfo_mode;
};
#define SFO_REV 1
struct scsi_failover_ops {
int sfo_rev;
char *sfo_name;
char **sfo_devices;
void (*sfo_init)();
int (*sfo_device_probe)(
struct scsi_device *sd,
struct scsi_inquiry *stdinq,
void **ctpriv);
void (*sfo_device_unprobe)(
struct scsi_device *sd,
void *ctpriv);
int (*sfo_path_activate)(
struct scsi_device *sd,
char *pathclass,
void *ctpriv);
int (*sfo_path_deactivate)(
struct scsi_device *sd,
char *pathclass,
void *ctpriv);
int (*sfo_path_get_opinfo)(
struct scsi_device *sd,
struct scsi_path_opinfo *opinfo,
void *ctpriv);
int (*sfo_path_ping)(
struct scsi_device *sd,
void *ctpriv);
int (*sfo_analyze_sense)(
struct scsi_device *sd,
uint8_t *sense,
void *ctpriv);
int (*sfo_pathclass_next)(
char *cur,
char **nxt,
void *ctpriv);
};
#define SFO_NAME_SYM "f_sym"
#define SFO_NAME_TPGS "f_tpgs"
#define SCSI_FAILOVER_IS_ASYM(svl) \
((svl) ? ((svl)->svl_fo_support != SCSI_NO_FAILOVER) : 0)
#define SCSI_FAILOVER_IS_TPGS(sfo) \
((sfo) ? (strcmp((sfo)->sfo_name, SFO_NAME_TPGS) == 0) : 0)
#define _SCSI_FAILOVER_OP(sfo_name, local_name, ops_name) \
static struct modlmisc modlmisc = { \
&mod_miscops, sfo_name \
}; \
static struct modlinkage modlinkage = { \
MODREV_1, (void *)&modlmisc, NULL \
}; \
int _init() \
{ \
return (mod_install(&modlinkage)); \
} \
int _fini() \
{ \
return (mod_remove(&modlinkage)); \
} \
int _info(struct modinfo *modinfop) \
{ \
return (mod_info(&modlinkage, modinfop)); \
} \
static int local_name##_device_probe( \
struct scsi_device *, \
struct scsi_inquiry *, void **); \
static void local_name##_device_unprobe( \
struct scsi_device *, void *); \
static int local_name##_path_activate( \
struct scsi_device *, char *, void *); \
static int local_name##_path_deactivate( \
struct scsi_device *, char *, void *); \
static int local_name##_path_get_opinfo( \
struct scsi_device *, \
struct scsi_path_opinfo *, void *); \
static int local_name##_path_ping( \
struct scsi_device *, void *); \
static int local_name##_analyze_sense( \
struct scsi_device *, \
uint8_t *, void *); \
static int local_name##_pathclass_next( \
char *, char **, void *); \
struct scsi_failover_ops ops_name##_failover_ops = { \
SFO_REV, \
sfo_name, \
local_name##_dev_table, \
NULL, \
local_name##_device_probe, \
local_name##_device_unprobe, \
local_name##_path_activate, \
local_name##_path_deactivate, \
local_name##_path_get_opinfo, \
local_name##_path_ping, \
local_name##_analyze_sense, \
local_name##_pathclass_next \
}
#ifdef lint
#define SCSI_FAILOVER_OP(sfo_name, local_name) \
_SCSI_FAILOVER_OP(sfo_name, local_name, local_name)
#else
#define SCSI_FAILOVER_OP(sfo_name, local_name) \
_SCSI_FAILOVER_OP(sfo_name, local_name, scsi_vhci)
#endif
#define SFO_DEVICE_PROBE_VHCI 1
#define SFO_DEVICE_PROBE_PHCI 0
#define SCSI_SENSE_NOFAILOVER 0
#define SCSI_SENSE_FAILOVER_INPROG 1
#define SCSI_SENSE_ACT2INACT 2
#define SCSI_SENSE_INACT2ACT 3
#define SCSI_SENSE_INACTIVE 4
#define SCSI_SENSE_UNKNOWN 5
#define SCSI_SENSE_STATE_CHANGED 6
#define SCSI_SENSE_NOT_READY 7
#define JUST_RETURN 0
#define BUSY_RETURN 1
#define PKT_RETURN 2
#if defined(_SYSCALL32)
typedef struct sv_path_info_prop32 {
uint32_t buf_size;
caddr32_t ret_buf_size;
caddr32_t buf;
} sv_path_info_prop32_t;
typedef struct sv_path_info32 {
union {
char ret_ct[MAXPATHLEN];
char ret_phci[MAXPATHLEN];
} device;
char ret_addr[MAXNAMELEN];
mdi_pathinfo_state_t ret_state;
uint32_t ret_ext_state;
sv_path_info_prop32_t ret_prop;
} sv_path_info32_t;
typedef struct sv_iocdata32 {
caddr32_t client;
caddr32_t phci;
caddr32_t addr;
uint32_t buf_elem;
caddr32_t ret_buf;
caddr32_t ret_elem;
} sv_iocdata32_t;
typedef struct sv_switch_to_cntlr_iocdata32 {
caddr32_t client;
caddr32_t class;
} sv_switch_to_cntlr_iocdata32_t;
#endif
#endif
typedef struct sv_path_info_prop {
uint_t buf_size;
uint_t *ret_buf_size;
caddr_t buf;
} sv_path_info_prop_t;
#define SV_PROP_MAX_BUF_SIZE 4096
#define PCLASS_PRIMARY "primary"
#define PCLASS_SECONDARY "secondary"
#define PCLASS_PREFERRED 1
#define PCLASS_NONPREFERRED 0
typedef struct sv_path_info {
union {
char ret_ct[MAXPATHLEN];
char ret_phci[MAXPATHLEN];
} device;
char ret_addr[MAXNAMELEN];
mdi_pathinfo_state_t ret_state;
uint32_t ret_ext_state;
sv_path_info_prop_t ret_prop;
} sv_path_info_t;
typedef struct sv_iocdata {
caddr_t client;
caddr_t phci;
caddr_t addr;
uint_t buf_elem;
sv_path_info_t *ret_buf;
uint_t *ret_elem;
} sv_iocdata_t;
typedef struct sv_switch_to_cntlr_iocdata {
caddr_t client;
caddr_t class;
} sv_switch_to_cntlr_iocdata_t;
#define SCSI_VHCI_CTL ('X' << 8)
#define SCSI_VHCI_CTL_CMD (SCSI_VHCI_CTL | ('S' << 8) | 'P')
#define SCSI_VHCI_CTL_SUB_CMD ('x' << 8)
#define SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO (SCSI_VHCI_CTL_SUB_CMD + 0x01)
#define SCSI_VHCI_GET_PHCI_MULTIPATH_INFO (SCSI_VHCI_CTL_SUB_CMD + 0x02)
#define SCSI_VHCI_GET_CLIENT_NAME (SCSI_VHCI_CTL_SUB_CMD + 0x03)
#define SCSI_VHCI_PATH_ONLINE (SCSI_VHCI_CTL_SUB_CMD + 0x04)
#define SCSI_VHCI_PATH_OFFLINE (SCSI_VHCI_CTL_SUB_CMD + 0x05)
#define SCSI_VHCI_PATH_STANDBY (SCSI_VHCI_CTL_SUB_CMD + 0x06)
#define SCSI_VHCI_PATH_TEST (SCSI_VHCI_CTL_SUB_CMD + 0x07)
#define SCSI_VHCI_SWITCH_TO_CNTLR (SCSI_VHCI_CTL_SUB_CMD + 0x08)
#ifdef DEBUG
#define SCSI_VHCI_GET_PHCI_LIST (SCSI_VHCI_CTL_SUB_CMD + 0x09)
#define SCSI_VHCI_CONFIGURE_PHCI (SCSI_VHCI_CTL_SUB_CMD + 0x0A)
#define SCSI_VHCI_UNCONFIGURE_PHCI (SCSI_VHCI_CTL_SUB_CMD + 0x0B)
#endif
#define SCSI_VHCI_PATH_DISABLE (SCSI_VHCI_CTL_SUB_CMD + 0x0C)
#define SCSI_VHCI_PATH_ENABLE (SCSI_VHCI_CTL_SUB_CMD + 0x0D)
#define SCSI_VHCI_MPAPI (SCSI_VHCI_CTL_SUB_CMD + 0x0E)
#define SCSI_VHCI_GET_TARGET_LONGNAME (SCSI_VHCI_CTL_SUB_CMD + 0x0F)
#ifdef __cplusplus
}
#endif
#endif