usr/src/uts/common/sys/scsi/adapters/scsi_vhci.h
author Mark J. Nelson <Mark.J.Nelson@Sun.COM>
Wed, 06 Aug 2008 16:29:39 -0600
changeset 7298 b69e27387f74
parent 7201 0259de900d45
child 7654 82798d9a3db9
permissions -rw-r--r--
6733918 Teamware has retired, please welcome your new manager, Mercurial 4758439 some files use "current date" sccs keywords 6560843 asm sources should not rely on .file "%M%" for naming STT_FILE symbols 6560958 Solaris:: perl modules should not use SCCS keywords in version information 6729074 webrev doesn't deal well with remote ssh hg parents

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef	_SYS_SCSI_ADAPTERS_SCSI_VHCI_H
#define	_SYS_SCSI_ADAPTERS_SCSI_VHCI_H

/*
 * Multiplexed I/O SCSI vHCI global include
 */
#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  /* _BIT_FIELDS_LTOH */

#ifdef	_KERNEL

#ifdef	UNDEFINED
#undef	UNDEFINED
#endif
#define	UNDEFINED		-1

#define	VHCI_STATE_OPEN		0x00000001


#define	VH_SLEEP		0x0
#define	VH_NOSLEEP		0x1

/*
 * HBA interface macros
 */

#define	TRAN2HBAPRIVATE(tran)	((struct scsi_vhci *)(tran)->tran_hba_private)
#define	VHCI_INIT_WAIT_TIMEOUT	60000000
#define	VHCI_FOWATCH_INTERVAL	1000000		/* in usecs */
#define	VHCI_EXTFO_TIMEOUT	3*60		/* 3 minutes */

#define	SCBP_C(pkt)	((*(pkt)->pkt_scbp) & STATUS_MASK)

int vhci_do_scsi_cmd(struct scsi_pkt *);
/*PRINTFLIKE3*/
void vhci_log(int, dev_info_t *, const char *, ...);

/*
 * debugging stuff
 */

#ifdef	DEBUG

#ifndef VHCI_DEBUG_DEFAULT_VAL
#define	VHCI_DEBUG_DEFAULT_VAL		0
#endif	/* VHCI_DEBUG_DEFAULT_VAL */

extern int vhci_debug;

#include <sys/debug.h>

#define	VHCI_DEBUG(level, stmnt) \
	    if (vhci_debug >= (level)) vhci_log stmnt

#else	/* !DEBUG */

#define	VHCI_DEBUG(level, stmnt)

#endif	/* !DEBUG */



#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 *)((ap)->a_hba_tran->tran_tgt_private)
#define	ADDR2DIP(ap)	(dev_info_t *)((ap)->a_hba_tran->tran_sd->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);

/*
 * When a LUN is HELD it results in new IOs being returned to the target
 * driver layer with TRAN_BUSY.  Should be used while performing
 * operations that require prevention of any new IOs to the LUN and
 * the LUN should be HELD for the duration of such operations.
 * f can be VH_SLEEP or VH_NOSLEEP.
 * h is set to 1 to indicate LUN was successfully HELD.
 * h is set to 0 when f is VH_NOSLEEP and LUN is already HELD.
 *
 * Application examples:
 *
 * 1) SCSI-II RESERVE: HOLD LUN until it is quiesced and the load balancing
 * policy is switched to NONE before proceeding with RESERVE handling.
 *
 * 2) Failover: HOLD LUN before initiating failover.
 *
 * 3) When an externally initiated failover is detected, HOLD LUN until all
 * path states have been refreshed to reflect the new value.
 *
 */
#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)

/*
 * vhci_pkt states
 */
#define	VHCI_PKT_IDLE			0x01
#define	VHCI_PKT_ISSUED			0x02
#define	VHCI_PKT_ABORTING		0x04
#define	VHCI_PKT_STALE_BINDING		0x08
/*
 * Set the first time taskq is dispatched from scsi_start for
 * a packet.  To ensure vhci_scsi_start recognizes that the scsi_pkt
 * is being issued from the taskq and not target driver.
 */
#define	VHCI_PKT_THRU_TASKQ		0x20

#define	VHCI_PKT_TIMEOUT		30		/* seconds */
#define	VHCI_PKT_RETRY_CNT		2
#define	VHCI_POLL_TIMEOUT		60		/* seconds */

/*
 * define extended scsi cmd pkt
 */
#define	EXTCMDS_STATUS_SIZE		(sizeof (struct scsi_arq_status))

#define	CFLAG_NOWAIT		0x1000	/* don't sleep */
#define	CFLAG_DMA_PARTIAL	0x2000	/* Support Partial DMA */

/*
 * Maximum size of SCSI cdb in SCSI command
 */
#define	VHCI_SCSI_CDB_SIZE		16
#define	VHCI_SCSI_SCB_SIZE		(sizeof (struct scsi_arq_status))

/*
 * flag to determine failover support
 */
#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 {
	/* PGR register parameters start */
	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 /* _BIT_FIELDS_LTOH */

	uchar_t		reserved_1;
	uint16_t	ext_len;
	/* PGR register parameters end */

	/* Update VHCI_PROUT_SIZE if new fields are added here */

	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;	/* path pkt bound to */

	/*
	 * pHCI packet that does the actual work.
	 */
	struct scsi_pkt			*vpkt_hba_pkt;

	uint_t				vpkt_state;
	uint_t				vpkt_flags;

	/*
	 * copy of vhci_scsi_init_pkt args.  Used when we invoke
	 * scsi_init_pkt() of the pHCI corresponding to the path that we
	 * bind to
	 */
	int				vpkt_tgt_init_cdblen;
	int				vpkt_tgt_init_scblen;
	int				vpkt_tgt_init_pkt_flags;
	struct buf			*vpkt_tgt_init_bp;

	/*
	 * Pointer to original struct vhci_pkt for cmd send by ssd.
	 * Saved when the command is being retried internally.
	 */
	struct vhci_pkt			*vpkt_org_vpkt;
};

typedef struct scsi_vhci_lun {
	kmutex_t		svl_mutex;
	kcondvar_t		svl_cv;

	/*
	 * following three fields are under svl_mutex protection
	 */
	int			svl_transient;

	/*
	 * to prevent unnecessary failover when a device is
	 * is discovered across a passive path and active path
	 * is still comng up
	 */
	int			svl_waiting_for_activepath;
	time_t			svl_wfa_time;

	/*
	 * for RESERVE/RELEASE support
	 */
	client_lb_t		svl_lb_policy_save;

	/*
	 * Failover ops and ops name selected for the lun.
	 */
	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;

	/*
	 * currently active pathclass
	 */
	char			*svl_active_pclass;

	dev_info_t		*svl_dip;
	uint32_t		svl_flags;	/* protected by svl_mutex */

	/*
	 * When SCSI-II reservations are active we set the following pip
	 * to point to the path holding the reservation.  As long as
	 * the reservation is active this svl_resrv_pip is bound for the
	 * transport directly.  We bypass calling mdi_select_path to return
	 * a pip.
	 * The following pip is only valid when VLUN_RESERVE_ACTIVE_FLG
	 * is set.  This pip should not be accessed if this flag is reset.
	 */
	mdi_pathinfo_t	*svl_resrv_pip;

	/*
	 * following fields are for PGR support
	 */
	taskq_t			*svl_taskq;
	ksema_t			svl_pgr_sema;	/* PGR serialization */
	vhci_prin_readkeys_t	svl_prin;	/* PGR in data */
	vhci_prout_t		svl_prout;	/* PGR out data */
	uchar_t			svl_cdb[CDB_GROUP4];
	int			svl_time;	/* pkt_time */
	uint32_t		svl_bcount;	/* amount of data */
	int			svl_pgr_active; /* registrations active */
	mdi_pathinfo_t		*svl_first_path;

	/* external failover */
	int			svl_efo_update_path;
	struct	scsi_vhci_swarg	*svl_swarg;

	uint32_t		svl_support_lun_reset; /* Lun reset support */
	int			svl_not_supported;
	int			svl_xlf_capable; /* XLF implementation */
	int			svl_sector_size;
	int			svl_setcap_done;
	uint16_t		svl_fo_support;	 /* failover mode */
} scsi_vhci_lun_t;

#define	VLUN_TASK_D_ALIVE_FLG		0x01

/*
 * This flag is used to monitor the state of SCSI-II RESERVATION on the
 * lun.  A SCSI-II RESERVE cmd may be accepted by the target on the inactive
 * path.  This would then cause a subsequent IO to cause the paths to be
 * updated and be returned with a reservation conflict.  By monitoring this
 * flag, and sending a reset to the target when needed to clear the reservation,
 * one can avoid this conflict.
 */
#define	VLUN_RESERVE_ACTIVE_FLG		0x04

/*
 * This flag is set when a SCSI-II RESERVE cmd is received by scsi_vhci
 * and cleared when the pkt completes in vhci_intr.  It ensures that the
 * lun remains quiesced for the duration of this pkt.  This is different
 * from VHCI_HOLD_LUN as this pertains to IOs only.
 */
#define	VLUN_QUIESCED_FLG		0x08

/*
 * This flag is set to tell vhci_update_pathstates to call back
 * into vhci_mpapi_update_tpg_acc_state.
 */
#define	VLUN_UPDATE_TPG			0x10

/*
 * Various reset recovery depth.
 */

#define	VHCI_DEPTH_ALL		3
#define	VHCI_DEPTH_TARGET	2
#define	VHCI_DEPTH_LUN		1	/* For the sake completeness */
#define	TRUE			(1)
#define	FALSE			(0)

/*
 * this is stashed away in the client private area of
 * pathinfo
 */
typedef struct scsi_vhci_priv {
	kmutex_t		svp_mutex;
	kcondvar_t		svp_cv;
	struct scsi_vhci_lun	*svp_svl;

	/*
	 * scsi device associated with this
	 * pathinfo
	 */
	struct scsi_device	*svp_psd;

	/*
	 * number of outstanding commands on this
	 * path.  Protected by svp_mutex
	 */
	int			svp_cmds;

	/*
	 * following is used to prevent packets completing with the
	 * same error reason from flooding the screen
	 */
	uchar_t			svp_last_pkt_reason;

	/* external failover scsi_watch token */
	opaque_t		svp_sw_token;

	/* any cleanup operations for a newly found path. */
	int			svp_new_path;
} scsi_vhci_priv_t;

/*
 * argument to scsi_watch callback.  Used for processing
 * externally initiated failovers
 */
typedef struct scsi_vhci_swarg {
	scsi_vhci_priv_t	*svs_svp;
	time_t			svs_tos;	/* time of submission */
	mdi_pathinfo_t		*svs_pi;	/* pathinfo being "watched" */
	int			svs_release_lun;
	int			svs_done;
} scsi_vhci_swarg_t;

/*
 * scsi_vhci softstate
 *
 * vhci_mutex protects
 *	vhci_state
 * and	vhci_reset_notify list
 */
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;
	/*
	 * This taskq is for general vhci operations like reservations,
	 * auto-failback, etc.
	 */
	taskq_t				*vhci_taskq;
	/* Dedicate taskq to handle external failovers */
	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;
};

/*
 * vHCI flags for configuration settings, defined in scsi_vhci.conf
 */
#define	VHCI_CONF_FLAGS_AUTO_FAILBACK	0x0001	/* Enables auto failback */

typedef enum {
	SCSI_PATH_INACTIVE,
	SCSI_PATH_ACTIVE,
	SCSI_PATH_ACTIVE_NONOPT
} scsi_path_state_t;

#define	SCSI_MAXPCLASSLEN	25

#define	OPINFO_REV	1

/*
 * structure describing operational characteristics of
 * path
 */
struct scsi_path_opinfo {
	int			opinfo_rev;

	/*
	 * name of pathclass. Eg. "primary", "secondary"
	 */
	char			opinfo_path_attr[SCSI_MAXPCLASSLEN];

	/*
	 * path state: ACTIVE/PASSIVE
	 */
	scsi_path_state_t	opinfo_path_state;

	/*
	 * the best and worst case time estimates for
	 * failover operation to complete
	 */
	uint_t			opinfo_pswtch_best;
	uint_t			opinfo_pswtch_worst;

	/* XLF implementation */
	int			opinfo_xlf_capable;
	uint16_t		opinfo_preferred;
	uint16_t		opinfo_mode;

};


#define	SFO_REV		1

/*
 * vectors for device specific failover related operations
 */
struct scsi_failover_ops {
	int	sfo_rev;

	/*
	 * failover module name, begins with "f_"
	 */
	char	*sfo_name;

	/*
	 * devices supported by failover module
	 *
	 * NOTE: this is an aproximation, sfo_device_probe has the final say.
	 */
	char	**sfo_devices;

	/*
	 * initialize the failover module
	 */
	void	(*sfo_init)();

	/*
	 * identify device
	 */
	int	(*sfo_device_probe)(
			struct scsi_device	*sd,
			struct scsi_inquiry	*stdinq,
			void			**ctpriv);

	/*
	 * housekeeping (free memory etc alloc'ed during probe
	 */
	void	(*sfo_device_unprobe)(
			struct scsi_device	*sd,
			void			*ctpriv);

	/*
	 * bring a path ONLINE (ie make it ACTIVE)
	 */
	int	(*sfo_path_activate)(
			struct scsi_device	*sd,
			char			*pathclass,
			void			*ctpriv);

	/*
	 * inverse of above
	 */
	int	(*sfo_path_deactivate)(
			struct scsi_device	*sd,
			char			*pathclass,
			void			*ctpriv);

	/*
	 * returns operational characteristics of path
	 */
	int	(*sfo_path_get_opinfo)(
			struct scsi_device	*sd,
			struct scsi_path_opinfo *opinfo,
			void			*ctpriv);

	/*
	 * verify path is operational
	 */
	int	(*sfo_path_ping)(
			struct scsi_device	*sd,
			void			*ctpriv);

	/*
	 * analyze SENSE data to detect externally initiated
	 * failovers
	 */
	int	(*sfo_analyze_sense)(
			struct scsi_device		*sd,
			struct scsi_extended_sense	*sense,
			void				*ctpriv);

	/*
	 * return the next pathclass in order of preference
	 * eg. "secondary" comes after "primary"
	 */
	int	(*sfo_pathclass_next)(
			char			*cur,
			char			**nxt,
			void			*ctpriv);
};

/*
 * Names of (too) 'well-known' failover ops.
 *   NOTE: consumers of these names should look for a better way...
 */
#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)

/*
 * Macro to provide plumbing for basic failover module
 */
#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 *,			\
				struct scsi_extended_sense *, 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	/* lint */
#define	SCSI_FAILOVER_OP(sfo_name, local_name)				\
	_SCSI_FAILOVER_OP(sfo_name, local_name, scsi_vhci)
#endif	/* lint */

/*
 * Return values for sfo_device_probe
 */
#define	SFO_DEVICE_PROBE_VHCI	1	/* supported under scsi_vhci */
#define	SFO_DEVICE_PROBE_PHCI	0	/* not supported under scsi_vhci */

/* return values for sfo_analyze_sense() */
#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

/* vhci_intr action codes */
#define	JUST_RETURN			0
#define	BUSY_RETURN			1
#define	PKT_RETURN			2

#if	defined(_SYSCALL32)
/*
 * 32 bit variants of sv_path_info_prop_t and sv_path_info_t;
 * To be used only in the driver and NOT applications
 */
typedef struct sv_path_info_prop32 {
	uint32_t	buf_size;	/* user buffer size */
	caddr32_t	ret_buf_size;	/* actual buffer needed */
	caddr32_t	buf;		/* user space buffer */
} sv_path_info_prop32_t;

typedef struct sv_path_info32 {
	union {
		char	ret_ct[MAXPATHLEN];		/* client device */
		char	ret_phci[MAXPATHLEN];		/* pHCI device */
	} device;

	char			ret_addr[MAXNAMELEN];	/* device address */
	mdi_pathinfo_state_t	ret_state;		/* state information */
	uint32_t		ret_ext_state;		/* Extended State */
	sv_path_info_prop32_t	ret_prop;		/* path attributes */
} sv_path_info32_t;

typedef struct sv_iocdata32 {
	caddr32_t	client;		/* client dev devfs path name */
	caddr32_t	phci;		/* pHCI dev devfs path name */
	caddr32_t	addr;		/* device address */
	uint32_t	buf_elem;	/* number of path_info elems */
	caddr32_t	ret_buf;	/* addr of array of sv_path_info */
	caddr32_t	ret_elem;	/* count of above sv_path_info */
} sv_iocdata32_t;

typedef struct sv_switch_to_cntlr_iocdata32 {
	caddr32_t	client;	/* client device devfs path name */
	caddr32_t	class;	/* desired path class to be made active */
} sv_switch_to_cntlr_iocdata32_t;

#endif	/* _SYSCALL32 */

#endif	/* _KERNEL */

/*
 * Userland (Non Kernel) definitions start here.
 * Multiplexed I/O SCSI vHCI IOCTL Definitions
 */

/*
 * IOCTL structure for path properties
 */
typedef struct sv_path_info_prop {
	uint_t	buf_size;	/* user buffer size */
	uint_t	*ret_buf_size;	/* actual buffer needed */
	caddr_t	buf;		/* user space buffer */
} sv_path_info_prop_t;

/*
 * Max buffer size of getting path properties
 */
#define	SV_PROP_MAX_BUF_SIZE	4096

/*
 * String values for "path-class" property
 */
#define	PCLASS_PRIMARY		"primary"
#define	PCLASS_SECONDARY	"secondary"

#define	PCLASS_PREFERRED	1
#define	PCLASS_NONPREFERRED	0

/*
 * IOCTL structure for path information
 */
typedef struct sv_path_info {
	union {
		char	ret_ct[MAXPATHLEN];		/* client device */
		char	ret_phci[MAXPATHLEN];		/* pHCI device */
	} device;

	char			ret_addr[MAXNAMELEN];	/* device address */
	mdi_pathinfo_state_t	ret_state;		/* state information */
	uint32_t		ret_ext_state;		/* Extended State */
	sv_path_info_prop_t	ret_prop;		/* path attributes */
} sv_path_info_t;

/*
 * IOCTL argument structure
 */
typedef struct sv_iocdata {
	caddr_t		client;		/* client dev devfs path name */
	caddr_t		phci;		/* pHCI dev devfs path name */
	caddr_t		addr;		/* device address */
	uint_t		buf_elem;	/* number of path_info elems */
	sv_path_info_t	*ret_buf;	/* array of sv_path_info */
	uint_t		*ret_elem;	/* count of sv_path_info */
} sv_iocdata_t;

/*
 * IOCTL argument structure for switching controllers
 */
typedef struct sv_switch_to_cntlr_iocdata {
	caddr_t		client;	/* client device devfs path name */
	caddr_t		class;	/* desired path class to be made active */
} sv_switch_to_cntlr_iocdata_t;


/*
 * IOCTL definitions
 */
#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	/* _SYS_SCSI_ADAPTERS_SCSI_VHCI_H */