PSARC 2004/626 SNIA Multipath Management API support for scsi_vhci
authorrs135747
Fri, 11 Nov 2005 16:52:37 -0800
changeset 893 76977629f0d7
parent 892 3d350db28f2a
child 894 87e5bdcca365
PSARC 2004/626 SNIA Multipath Management API support for scsi_vhci PSARC 2005/646 MDI/PHCI/libdevinfo Extensions for SNIA MPAPI support 6271075 Provide libdevinfo interface that allows to get to phci nodes from vhci 6274924 DINFOCACHE snapshot needs to be invalidated when pathinfo is created or removed 6326490 Need to provide interconnect-type prop 6326499 MDI needs to provide vhci/phci/client device traversal interfaces. 6326502 MDI needs to generate sysevent for phci registration/unregistration 6326564 Provide SNIA MP API support 6326937 scsi_vhci(MPxIO) needs to provide Explicit Mode support for TPGS devices
usr/src/cmd/devfsadm/devfsadm.c
usr/src/lib/libdevinfo/devinfo.c
usr/src/lib/libdevinfo/libdevinfo.h
usr/src/lib/libdevinfo/spec/devinfo.spec
usr/src/pkgdefs/etc/exception_list_i386
usr/src/pkgdefs/etc/exception_list_sparc
usr/src/uts/common/Makefile.files
usr/src/uts/common/io/devinfo.c
usr/src/uts/common/io/scsi/impl/scsi_hba.c
usr/src/uts/common/os/sunmdi.c
usr/src/uts/common/sys/Makefile
usr/src/uts/common/sys/devinfo_impl.h
usr/src/uts/common/sys/scsi/adapters/mpapi_impl.h
usr/src/uts/common/sys/scsi/adapters/mpapi_scsi_vhci.h
usr/src/uts/common/sys/scsi/adapters/scsi_vhci.h
usr/src/uts/common/sys/scsi/impl/services.h
usr/src/uts/common/sys/scsi/impl/transport.h
usr/src/uts/common/sys/sunddi.h
usr/src/uts/common/sys/sunmdi.h
usr/src/uts/intel/os/device_policy
usr/src/uts/intel/os/minor_perm
usr/src/uts/sparc/os/device_policy
usr/src/uts/sparc/os/minor_perm
--- a/usr/src/cmd/devfsadm/devfsadm.c	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/cmd/devfsadm/devfsadm.c	Fri Nov 11 16:52:37 2005 -0800
@@ -945,11 +945,15 @@
  * Called in non-daemon mode to take a snap shot of the devinfo tree.
  * Then it calls the appropriate functions to build /devices and /dev.
  * It also flushes path_to_inst.
+ * DINFOCACHE snapshot needs to be updated when devfsadm is run.
+ * This will only happen if the flags that devfsadm uses matches the flags
+ * that DINFOCACHE uses and that is why flags is set to
+ * DI_CACHE_SNAPSHOT_FLAGS.
  */
 void
 process_devinfo_tree()
 {
-	uint_t		flags = DINFOCPYALL;
+	uint_t		flags = DI_CACHE_SNAPSHOT_FLAGS;
 	struct dca_impl	dci;
 	char		name[MAXNAMELEN];
 	char		*fcn = "process_devinfo_tree: ";
--- a/usr/src/lib/libdevinfo/devinfo.c	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/lib/libdevinfo/devinfo.c	Fri Nov 11 16:52:37 2005 -0800
@@ -2088,6 +2088,104 @@
 	return (di_path_prop_strings(prop, prop_data));
 }
 
+/*
+ * Consolidation private interfaces for traversing vhci nodes.
+ */
+di_node_t
+di_vhci_first_node(di_node_t root)
+{
+	struct di_all *dap;
+	caddr_t		pa;		/* starting address of map */
+
+	DPRINTF((DI_INFO, "Get first vhci node\n"));
+
+	if (root == DI_NODE_NIL) {
+		errno = EINVAL;
+		return (DI_NODE_NIL);
+	}
+
+	pa = (caddr_t)root - DI_NODE(root)->self;
+	dap = DI_ALL(pa);
+
+	if (dap->top_vhci_devinfo == NULL) {
+		errno = ENXIO;
+		return (DI_NODE_NIL);
+	}
+
+	return (DI_NODE(pa + dap->top_vhci_devinfo));
+}
+
+di_node_t
+di_vhci_next_node(di_node_t node)
+{
+	caddr_t		pa;		/* starting address of map */
+
+	if (node == DI_NODE_NIL) {
+		errno = EINVAL;
+		return (DI_NODE_NIL);
+	}
+
+	DPRINTF((DI_TRACE, "next vhci node on the snap shot:"
+	    " current=%s\n", di_node_name(node)));
+
+	if (DI_NODE(node)->next_vhci == NULL) {
+		errno = ENXIO;
+		return (DI_NODE_NIL);
+	}
+
+	pa = (caddr_t)node - DI_NODE(node)->self;
+
+	return (DI_NODE(pa + DI_NODE(node)->next_vhci));
+}
+
+/*
+ * Consolidation private interfaces for traversing phci nodes.
+ */
+di_node_t
+di_phci_first_node(di_node_t vhci_node)
+{
+	caddr_t		pa;		/* starting address of map */
+
+	DPRINTF((DI_INFO, "Get first phci node:\n"
+	    " current=%s", di_node_name(vhci_node)));
+
+	if (vhci_node == DI_NODE_NIL) {
+		errno = EINVAL;
+		return (DI_NODE_NIL);
+	}
+
+	pa = (caddr_t)vhci_node - DI_NODE(vhci_node)->self;
+
+	if (DI_NODE(vhci_node)->top_phci == NULL) {
+		errno = ENXIO;
+		return (DI_NODE_NIL);
+	}
+
+	return (DI_NODE(pa + DI_NODE(vhci_node)->top_phci));
+}
+
+di_node_t
+di_phci_next_node(di_node_t node)
+{
+	caddr_t		pa;		/* starting address of map */
+
+	if (node == DI_NODE_NIL) {
+		errno = EINVAL;
+		return (DI_NODE_NIL);
+	}
+
+	DPRINTF((DI_TRACE, "next phci node on the snap shot:"
+	    " current=%s\n", di_node_name(node)));
+
+	if (DI_NODE(node)->next_phci == NULL) {
+		errno = ENXIO;
+		return (DI_NODE_NIL);
+	}
+
+	pa = (caddr_t)node - DI_NODE(node)->self;
+
+	return (DI_NODE(pa + DI_NODE(node)->next_phci));
+}
 
 /*
  * Consolidation private interfaces for private data
--- a/usr/src/lib/libdevinfo/libdevinfo.h	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/lib/libdevinfo/libdevinfo.h	Fri Nov 11 16:52:37 2005 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -142,6 +142,10 @@
 extern di_node_t di_child_node(di_node_t node);
 extern di_node_t di_drv_first_node(const char *drv_name, di_node_t root);
 extern di_node_t di_drv_next_node(di_node_t node);
+extern di_node_t di_vhci_first_node(di_node_t root);
+extern di_node_t di_vhci_next_node(di_node_t node);
+extern di_node_t di_phci_first_node(di_node_t vhci_node);
+extern di_node_t di_phci_next_node(di_node_t node);
 
 /*
  * tree walking assistants
--- a/usr/src/lib/libdevinfo/spec/devinfo.spec	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/lib/libdevinfo/spec/devinfo.spec	Fri Nov 11 16:52:37 2005 -0800
@@ -949,3 +949,27 @@
 			void (*cb)(minorperm_err_t, int))
 version		SUNWprivate_1.1
 end
+
+function	di_vhci_first_node
+include		<libdevinfo.h>
+declaration	di_node_t di_vhci_first_node(di_node_t root)
+version		SUNWprivate_1.1
+end
+
+function	di_vhci_next_node
+include		<libdevinfo.h>
+declaration	di_node_t di_vhci_next_node(di_node_t vhci_node)
+version		SUNWprivate_1.1
+end
+
+function	di_phci_first_node
+include		<libdevinfo.h>
+declaration	di_node_t di_phci_first_node(di_node_t vhci_node)
+version		SUNWprivate_1.1
+end
+
+function	di_phci_next_node
+include		<libdevinfo.h>
+declaration	di_node_t di_phci_next_node(di_node_t phci_node)
+version		SUNWprivate_1.1
+end
--- a/usr/src/pkgdefs/etc/exception_list_i386	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/pkgdefs/etc/exception_list_i386	Fri Nov 11 16:52:37 2005 -0800
@@ -743,3 +743,10 @@
 usr/lib/amd64/llib-lzfs.ln		i386
 usr/lib/amd64/llib-lzfs_jni.ln		i386
 usr/lib/amd64/llib-lzpool.ln		i386
+
+#
+# These files are installed in the proto area for Solaris scsi_vhci driver
+# (for MPAPI support) and should not be shipped
+#
+usr/include/sys/scsi/adapters/mpapi_impl.h	i386
+usr/include/sys/scsi/adapters/mpapi_scsi_vhci.h	i386
--- a/usr/src/pkgdefs/etc/exception_list_sparc	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/pkgdefs/etc/exception_list_sparc	Fri Nov 11 16:52:37 2005 -0800
@@ -810,3 +810,10 @@
 usr/lib/sparcv9/llib-lzfs.ln		sparc
 usr/lib/sparcv9/llib-lzfs_jni.ln	sparc
 usr/lib/sparcv9/llib-lzpool.ln		sparc
+
+#
+# These files are installed in the proto area for Solaris scsi_vhci driver
+# (for MPAPI support) and should not be shipped
+#
+usr/include/sys/scsi/adapters/mpapi_impl.h	sparc
+usr/include/sys/scsi/adapters/mpapi_scsi_vhci.h	sparc
--- a/usr/src/uts/common/Makefile.files	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/uts/common/Makefile.files	Fri Nov 11 16:52:37 2005 -0800
@@ -1176,6 +1176,7 @@
 			lsi_asymmetric_fops.o	\
 			std_asymmetric_fops.o	\
 			emc_asymmetric_fops.o	\
+			mpapi_impl.o		\
 			proprietary_vhci_util.o
 
 STRPLUMB_OBJS += strplumb.o octet.o
--- a/usr/src/uts/common/io/devinfo.c	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/uts/common/io/devinfo.c	Fri Nov 11 16:52:37 2005 -0800
@@ -270,6 +270,11 @@
 #define	CACHE_DEBUG(args)	\
 	{ if (di_cache_debug != DI_QUIET) di_cache_print args; }
 
+static struct phci_walk_arg {
+	di_off_t	off;
+	struct di_state	*st;
+} phci_walk_arg_t;
+
 static int di_open(dev_t *, int, int, cred_t *);
 static int di_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
 static int di_close(dev_t, int, int, cred_t *);
@@ -306,6 +311,8 @@
 static int di_cache_lookup(struct di_state *st);
 static int di_cache_update(struct di_state *st);
 static void di_cache_print(di_cache_debug_t msglevel, char *fmt, ...);
+int build_vhci_list(dev_info_t *vh_devinfo, void *arg);
+int build_phci_list(dev_info_t *ph_devinfo, void *arg);
 
 static struct cb_ops di_cb_ops = {
 	di_open,		/* open */
@@ -715,6 +722,7 @@
 	all->devcnt = devcnt;
 	all->command = st->command;
 	all->version = DI_SNAPSHOT_VERSION;
+	all->top_vhci_devinfo = 0;	/* filled up by build_vhci_list. */
 
 	/*
 	 * Note the endianness in case we need to transport snapshot
@@ -1321,6 +1329,10 @@
 	 */
 	off = di_copytree(DEVI(rootnode), &all->top_devinfo, st);
 
+	if (DINFOPATH & st->command) {
+		mdi_walk_vhcis(build_vhci_list, st);
+	}
+
 	ddi_release_devi(rootnode);
 
 	/*
@@ -1367,7 +1379,7 @@
 static di_off_t
 di_snapshot_and_clean(struct di_state *st)
 {
-	di_off_t off;
+	di_off_t	off;
 
 	modunload_disable();
 	off = di_snapshot(st);
@@ -1388,6 +1400,95 @@
 }
 
 /*
+ * construct vhci linkage in the snapshot.
+ */
+int
+build_vhci_list(dev_info_t *vh_devinfo, void *arg)
+{
+	struct di_all *all;
+	struct di_node *me;
+	struct di_state *st;
+	di_off_t off;
+	struct phci_walk_arg pwa;
+
+	dcmn_err3((CE_CONT, "build_vhci list\n"));
+
+	dcmn_err3((CE_CONT, "vhci node %s, instance #%d\n",
+		DEVI(vh_devinfo)->devi_node_name,
+		DEVI(vh_devinfo)->devi_instance));
+
+	st = (struct di_state *)arg;
+	if (di_dip_find(st, vh_devinfo, &off) != 0) {
+		dcmn_err((CE_WARN, "di_dip_find error for the given node\n"));
+		return (DDI_WALK_TERMINATE);
+	}
+
+	dcmn_err3((CE_CONT, "st->mem_size: %d vh_devinfo off: 0x%x\n",
+		st->mem_size, off));
+
+	all = (struct di_all *)di_mem_addr(st, 0);
+	if (all->top_vhci_devinfo == 0) {
+		all->top_vhci_devinfo = off;
+	} else {
+		me = (struct di_node *)di_mem_addr(st, all->top_vhci_devinfo);
+
+		while (me->next_vhci != 0) {
+			me = (struct di_node *)di_mem_addr(st, me->next_vhci);
+		}
+
+		me->next_vhci = off;
+	}
+
+	pwa.off = off;
+	pwa.st = st;
+	mdi_vhci_walk_phcis(vh_devinfo, build_phci_list, &pwa);
+
+	return (DDI_WALK_CONTINUE);
+}
+
+/*
+ * construct phci linkage for the given vhci in the snapshot.
+ */
+int
+build_phci_list(dev_info_t *ph_devinfo, void *arg)
+{
+	struct di_node *vh_di_node;
+	struct di_node *me;
+	struct phci_walk_arg *pwa;
+	di_off_t off;
+
+	pwa = (struct phci_walk_arg *)arg;
+
+	dcmn_err3((CE_CONT, "build_phci list for vhci at offset: 0x%x\n",
+		pwa->off));
+
+	vh_di_node = (struct di_node *)di_mem_addr(pwa->st, pwa->off);
+
+	if (di_dip_find(pwa->st, ph_devinfo, &off) != 0) {
+		dcmn_err((CE_WARN, "di_dip_find error for the given node\n"));
+		return (DDI_WALK_TERMINATE);
+	}
+
+	dcmn_err3((CE_CONT, "phci node %s, instance #%d, at offset 0x%x\n",
+		DEVI(ph_devinfo)->devi_node_name,
+		DEVI(ph_devinfo)->devi_instance, off));
+
+	if (vh_di_node->top_phci == 0) {
+		vh_di_node->top_phci = off;
+		return (DDI_WALK_CONTINUE);
+	}
+
+	me = (struct di_node *)di_mem_addr(pwa->st, vh_di_node->top_phci);
+
+	while (me->next_phci != 0) {
+		me = (struct di_node *)di_mem_addr(pwa->st, me->next_phci);
+	}
+	me->next_phci = off;
+
+	return (DDI_WALK_CONTINUE);
+}
+
+/*
  * Assumes all devinfo nodes in device tree have been snapshotted
  */
 static void
@@ -1607,6 +1708,10 @@
 	me->attributes = node->devi_node_attributes;
 	me->state = node->devi_state;
 	me->node_state = node->devi_node_state;
+	me->next_vhci = 0;		/* Filled up by build_vhci_list. */
+	me->top_phci = 0;		/* Filled up by build_phci_list. */
+	me->next_phci = 0;		/* Filled up by build_phci_list. */
+	me->multipath_component = MULTIPATH_COMPONENT_NONE; /* set default. */
 	me->user_private_data = NULL;
 
 	/*
@@ -1738,7 +1843,12 @@
 		goto property;
 	}
 
+	if (MDI_VHCI(node)) {
+		me->multipath_component = MULTIPATH_COMPONENT_VHCI;
+	}
+
 	if (MDI_CLIENT(node)) {
+		me->multipath_component = MULTIPATH_COMPONENT_CLIENT;
 		me->multipath_client = DI_ALIGN(off);
 		off = di_getpath_data((dev_info_t *)node, &me->multipath_client,
 		    me->self, st, 1);
@@ -1749,6 +1859,7 @@
 	}
 
 	if (MDI_PHCI(node)) {
+		me->multipath_component = MULTIPATH_COMPONENT_PHCI;
 		me->multipath_phci = DI_ALIGN(off);
 		off = di_getpath_data((dev_info_t *)node, &me->multipath_phci,
 		    me->self, st, 0);
@@ -3369,6 +3480,9 @@
 }
 
 extern int modrootloaded;
+extern void mdi_walk_vhcis(int (*)(dev_info_t *, void *), void *);
+extern void mdi_vhci_walk_phcis(dev_info_t *,
+	int (*)(dev_info_t *, void *), void *);
 
 static void
 di_cache_write(struct di_cache *cache)
--- a/usr/src/uts/common/io/scsi/impl/scsi_hba.c	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/uts/common/io/scsi/impl/scsi_hba.c	Fri Nov 11 16:52:37 2005 -0800
@@ -278,8 +278,10 @@
 	int			value;
 	int			len;
 	char			*prop_name;
+	const char		*prop_value;
 	char			*errmsg =
 		"scsi_hba_attach: cannot create property '%s' for %s%d\n";
+	static const char	*interconnect[] = INTERCONNECT_TYPE_ASCII;
 
 	/*
 	 * Link this instance into the scsi_hba_list
@@ -307,7 +309,8 @@
 	 * later by scsi_hba_bus_ctl(), and scsi_hba_map().
 	 */
 	hba_tran->tran_hba_dip = dip;
-	hba_tran->tran_hba_flags = flags;
+	hba_tran->tran_hba_flags &= SCSI_HBA_TRAN_ALLOC;
+	hba_tran->tran_hba_flags |= (flags & ~SCSI_HBA_TRAN_ALLOC);
 
 	/*
 	 * Note: we only need dma_attr_minxfer and dma_attr_burstsizes
@@ -385,6 +388,24 @@
 				ddi_get_name(dip), ddi_get_instance(dip));
 		}
 	}
+	if ((hba_tran->tran_hba_flags & SCSI_HBA_TRAN_ALLOC) &&
+	    (hba_tran->tran_interconnect_type > 0) &&
+	    (hba_tran->tran_interconnect_type < INTERCONNECT_MAX)) {
+		prop_name = "initiator-interconnect-type";
+		len = 0;
+		if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN, 0, prop_name,
+				NULL, &len) == DDI_PROP_NOT_FOUND) {
+			value = hba_tran->tran_interconnect_type;
+			prop_value = interconnect[value];
+			if (ddi_prop_update_string(DDI_MAJOR_T_UNKNOWN, dip,
+			    prop_name, (char *)prop_value)
+			    != DDI_PROP_SUCCESS) {
+				cmn_err(CE_CONT, errmsg, prop_name,
+					ddi_get_name(dip),
+					ddi_get_instance(dip));
+			}
+		}
+	}
 
 	ddi_set_driver_private(dip, hba_tran);
 
@@ -846,8 +867,15 @@
 	dev_info_t		*dip,
 	int			flags)
 {
-	return (kmem_zalloc(sizeof (scsi_hba_tran_t),
-		(flags & SCSI_HBA_CANSLEEP) ? KM_SLEEP : KM_NOSLEEP));
+	scsi_hba_tran_t		*hba_tran;
+
+	hba_tran = kmem_zalloc(sizeof (scsi_hba_tran_t),
+		(flags & SCSI_HBA_CANSLEEP) ? KM_SLEEP : KM_NOSLEEP);
+
+	hba_tran->tran_interconnect_type = INTERCONNECT_PARALLEL;
+	hba_tran->tran_hba_flags |= SCSI_HBA_TRAN_ALLOC;
+
+	return (hba_tran);
 }
 
 
--- a/usr/src/uts/common/os/sunmdi.c	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/uts/common/os/sunmdi.c	Fri Nov 11 16:52:37 2005 -0800
@@ -65,6 +65,8 @@
 #include <sys/epm.h>
 #include <sys/sunpm.h>
 #include <sys/modhash.h>
+#include <sys/disp.h>
+#include <sys/autoconf.h>
 
 #ifdef	DEBUG
 #include <sys/debug.h>
@@ -181,6 +183,7 @@
 static void		i_mdi_pm_reset_client(mdi_client_t *);
 static void		i_mdi_pm_hold_all_phci(mdi_client_t *);
 static int		i_mdi_power_all_phci(mdi_client_t *);
+static void		i_mdi_log_sysevent(dev_info_t *, char *, char *);
 
 
 /*
@@ -448,7 +451,7 @@
 	}
 
 	/*
-	 * Check the pHCI and client count. All the pHCIs and clients
+	 * Check the vHCI, pHCI and client count. All the pHCIs and clients
 	 * should have been unregistered, before a vHCI can be
 	 * unregistered.
 	 */
@@ -616,6 +619,7 @@
 	vh->vh_phci_tail = ph;
 	vh->vh_phci_count++;
 	mutex_exit(&mdi_mutex);
+	i_mdi_log_sysevent(pdip, class, ESC_DDI_INITIATOR_REGISTER);
 	return (MDI_SUCCESS);
 }
 
@@ -678,6 +682,8 @@
 
 	mutex_exit(&mdi_mutex);
 
+	i_mdi_log_sysevent(pdip, ph->ph_vhci->vh_class,
+	    ESC_DDI_INITIATOR_UNREGISTER);
 	vhcache_phci_remove(vh->vh_config, ph);
 	cv_destroy(&ph->ph_unstable_cv);
 	cv_destroy(&ph->ph_powerchange_cv);
@@ -2567,6 +2573,8 @@
 	mdi_pathinfo_t	*pip;
 	int		ct_circular;
 	int		ph_circular;
+	int		se_flag;
+	int		kmem_flag;
 
 	pip = kmem_zalloc(sizeof (struct mdi_pathinfo), KM_SLEEP);
 	mutex_init(&MDI_PI(pip)->pi_mutex, NULL, MUTEX_DEFAULT, NULL);
@@ -2612,6 +2620,12 @@
 	ndi_devi_exit(ph->ph_dip, ph_circular);
 	ndi_devi_exit(ct->ct_dip, ct_circular);
 
+	/* determine interrupt context */
+	se_flag = (servicing_interrupt()) ? SE_NOSLEEP : SE_SLEEP;
+	kmem_flag = (se_flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
+
+	i_ddi_di_cache_invalidate(kmem_flag);
+
 	return (pip);
 }
 
@@ -2731,7 +2745,7 @@
 		/*
 		 * Give a chance for pending I/Os to complete.
 		 */
-		MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip, "!i_mdi_pi_free: "
+		MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip, "!mdi_pi_free: "
 		    "%d cmds still pending on path: %p\n",
 		    MDI_PI(pip)->pi_ref_cnt, pip));
 		if (cv_timedwait(&MDI_PI(pip)->pi_ref_cv,
@@ -2742,11 +2756,11 @@
 			 * being signaled.
 			 */
 			MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip,
-			    "!i_mdi_pi_free: "
+			    "!mdi_pi_free: "
 			    "Timeout reached on path %p without the cond\n",
 			    pip));
 			MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip,
-			    "!i_mdi_pi_free: "
+			    "!mdi_pi_free: "
 			    "%d cmds still pending on path: %p\n",
 			    MDI_PI(pip)->pi_ref_cnt, pip));
 			MDI_PI_UNLOCK(pip);
@@ -2821,6 +2835,8 @@
 {
 	int	ct_circular;
 	int	ph_circular;
+	int	se_flag;
+	int	kmem_flag;
 
 	/*
 	 * remove any per-path kstats
@@ -2836,6 +2852,12 @@
 	ndi_devi_exit(ph->ph_dip, ph_circular);
 	ndi_devi_exit(ct->ct_dip, ct_circular);
 
+	/* determine interrupt context */
+	se_flag = (servicing_interrupt()) ? SE_NOSLEEP : SE_SLEEP;
+	kmem_flag = (se_flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
+
+	i_ddi_di_cache_invalidate(kmem_flag);
+
 	mutex_destroy(&MDI_PI(pip)->pi_mutex);
 	cv_destroy(&MDI_PI(pip)->pi_state_cv);
 	cv_destroy(&MDI_PI(pip)->pi_ref_cv);
@@ -8362,3 +8384,162 @@
 	}
 	mutex_exit(&mdi_mutex);
 }
+
+/*
+ * mdi_vhci_walk_clients():
+ *		Walker routine to traverse client dev_info nodes
+ * ddi_walk_devs(ddi_get_child(vdip), f, arg) returns the entire tree
+ * below the client, including nexus devices, which we dont want.
+ * So we just traverse the immediate siblings, starting from 1st client.
+ */
+void
+mdi_vhci_walk_clients(dev_info_t *vdip,
+    int (*f)(dev_info_t *, void *), void *arg)
+{
+	dev_info_t	*cdip;
+	mdi_client_t	*ct;
+
+	mutex_enter(&mdi_mutex);
+
+	cdip = ddi_get_child(vdip);
+
+	while (cdip) {
+		ct = i_devi_get_client(cdip);
+		MDI_CLIENT_LOCK(ct);
+
+		switch ((*f)(cdip, arg)) {
+		case DDI_WALK_CONTINUE:
+			cdip = ddi_get_next_sibling(cdip);
+			MDI_CLIENT_UNLOCK(ct);
+			break;
+
+		default:
+			MDI_CLIENT_UNLOCK(ct);
+			mutex_exit(&mdi_mutex);
+			return;
+		}
+	}
+
+	mutex_exit(&mdi_mutex);
+}
+
+/*
+ * mdi_vhci_walk_phcis():
+ *		Walker routine to traverse phci dev_info nodes
+ */
+void
+mdi_vhci_walk_phcis(dev_info_t *vdip,
+    int (*f)(dev_info_t *, void *), void *arg)
+{
+	mdi_vhci_t	*vh = NULL;
+	mdi_phci_t	*ph = NULL;
+
+	mutex_enter(&mdi_mutex);
+
+	vh = i_devi_get_vhci(vdip);
+	ph = vh->vh_phci_head;
+
+	while (ph) {
+		MDI_PHCI_LOCK(ph);
+
+		switch ((*f)(ph->ph_dip, arg)) {
+		case DDI_WALK_CONTINUE:
+			MDI_PHCI_UNLOCK(ph);
+			ph = ph->ph_next;
+			break;
+
+		default:
+			MDI_PHCI_UNLOCK(ph);
+			mutex_exit(&mdi_mutex);
+			return;
+		}
+	}
+
+	mutex_exit(&mdi_mutex);
+}
+
+
+/*
+ * mdi_walk_vhcis():
+ *		Walker routine to traverse vhci dev_info nodes
+ */
+void
+mdi_walk_vhcis(int (*f)(dev_info_t *, void *), void *arg)
+{
+	mdi_vhci_t	*vh = NULL;
+
+	mutex_enter(&mdi_mutex);
+	/*
+	 * Scan for already registered vhci
+	 */
+	for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) {
+		vh->vh_refcnt++;
+		mutex_exit(&mdi_mutex);
+		if (((*f)(vh->vh_dip, arg)) != DDI_WALK_CONTINUE) {
+			mutex_enter(&mdi_mutex);
+			vh->vh_refcnt--;
+			break;
+		} else {
+			mutex_enter(&mdi_mutex);
+			vh->vh_refcnt--;
+		}
+	}
+
+	mutex_exit(&mdi_mutex);
+}
+
+/*
+ * i_mdi_log_sysevent():
+ *		Logs events for pickup by syseventd
+ */
+static void
+i_mdi_log_sysevent(dev_info_t *dip, char *ph_vh_class, char *subclass)
+{
+	char		*path_name;
+	nvlist_t	*attr_list;
+
+	if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
+	    KM_SLEEP) != DDI_SUCCESS) {
+		goto alloc_failed;
+	}
+
+	path_name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+	(void) ddi_pathname(dip, path_name);
+
+	if (nvlist_add_string(attr_list, DDI_DRIVER_NAME,
+	    ddi_driver_name(dip)) != DDI_SUCCESS) {
+		goto error;
+	}
+
+	if (nvlist_add_int32(attr_list, DDI_DRIVER_MAJOR,
+	    (int32_t)ddi_driver_major(dip)) != DDI_SUCCESS) {
+		goto error;
+	}
+
+	if (nvlist_add_int32(attr_list, DDI_INSTANCE,
+	    (int32_t)ddi_get_instance(dip)) != DDI_SUCCESS) {
+		goto error;
+	}
+
+	if (nvlist_add_string(attr_list, DDI_PATHNAME,
+	    path_name) != DDI_SUCCESS) {
+		goto error;
+	}
+
+	if (nvlist_add_string(attr_list, DDI_CLASS,
+	    ph_vh_class) != DDI_SUCCESS) {
+		goto error;
+	}
+
+	(void) ddi_log_sysevent(dip, DDI_VENDOR_SUNW, EC_DDI, subclass,
+	    attr_list, NULL, DDI_SLEEP);
+
+error:
+	kmem_free(path_name, MAXPATHLEN);
+	nvlist_free(attr_list);
+	return;
+
+alloc_failed:
+	MDI_DEBUG(1, (CE_WARN, dip,
+	    "!i_mdi_log_sysevent: Unable to send sysevent"));
+}
--- a/usr/src/uts/common/sys/Makefile	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/uts/common/sys/Makefile	Fri Nov 11 16:52:37 2005 -0800
@@ -788,7 +788,9 @@
 	mptvar.h
 
 SCSIVHCIHDRS=		\
-	scsi_vhci.h
+	scsi_vhci.h	\
+	mpapi_impl.h	\
+	mpapi_scsi_vhci.h
 
 FCHDRS=			\
 	fc_transport.h	\
--- a/usr/src/uts/common/sys/devinfo_impl.h	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/uts/common/sys/devinfo_impl.h	Fri Nov 11 16:52:37 2005 -0800
@@ -98,14 +98,16 @@
 #define	MAX_TREE_DEPTH	64
 #define	MAX_PTR_IN_PRV	5
 #define	DI_SNAPSHOT_VERSION_0	0	/* reserved */
-#define	DI_SNAPSHOT_VERSION	DI_SNAPSHOT_VERSION_0	/* current version */
+#define	DI_SNAPSHOT_VERSION_1	1	/* reserved */
+#define	DI_SNAPSHOT_VERSION	DI_SNAPSHOT_VERSION_1	/* current version */
 #define	DI_PRIVDATA_VERSION_0	10	/* Start from 10 so caller must set */
 #define	DI_BIG_ENDIAN		0	/* reserved */
 #define	DI_LITTLE_ENDIAN	1	/* reserved */
 
 #define	DI_CACHE_MAGIC		0xdfcac6ed	/* magic # for cache */
 #define	DI_CACHE_PERMS		(0444)
-#define	DI_CACHE_SNAPSHOT_FLAGS	(DINFOFORCE|DINFOSUBTREE|DINFOMINOR|DINFOPROP)
+#define	DI_CACHE_SNAPSHOT_FLAGS	\
+	(DINFOFORCE|DINFOSUBTREE|DINFOMINOR|DINFOPROP|DINFOPATH)
 
 #define	DI_NODE(addr)		((struct di_node *)((void *)(addr)))
 #define	DI_MINOR(addr)		((struct di_minor *)((void *)(addr)))
@@ -126,6 +128,15 @@
 #define	DIPATH(addr)		DI_PATH(addr)
 #define	DIPATHPROP(addr)	DI_PATHPROP(addr)
 
+/*
+ * multipath component definitions:  Follows the registered component of
+ * the mpxio system.
+ */
+#define	MULTIPATH_COMPONENT_NONE	0
+#define	MULTIPATH_COMPONENT_VHCI	0x1
+#define	MULTIPATH_COMPONENT_PHCI	0x2
+#define	MULTIPATH_COMPONENT_CLIENT	0x4
+
 typedef int32_t di_off_t;
 
 /*
@@ -140,6 +151,7 @@
 	uint32_t	cache_checksum;	/* snapshot checksum */
 	uint64_t	snapshot_time;	/* snapshot timestamp */
 	di_off_t	top_devinfo;
+	di_off_t	top_vhci_devinfo;
 	di_off_t	devnames;
 	di_off_t	ppdata_format;	/* parent priv data format array */
 	di_off_t	dpdata_format;	/* driver priv data format array */
@@ -256,7 +268,15 @@
 	di_off_t tgt_links;
 	di_off_t src_links;
 
-	uint64_t	user_private_data;
+	uint32_t di_pad1;	/* 4 byte padding for 32bit x86 app. */
+	uint64_t user_private_data;
+	/*
+	 * offset to link vhci/phci nodes.
+	 */
+	di_off_t next_vhci;
+	di_off_t top_phci;
+	di_off_t next_phci;
+	uint32_t multipath_component;	/* stores MDI_COMPONENT_* value. */
 };
 
 /*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/scsi/adapters/mpapi_impl.h	Fri Nov 11 16:52:37 2005 -0800
@@ -0,0 +1,428 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_SCSI_ADAPTERS_MPAPI_IMPL_H
+#define	_SYS_SCSI_ADAPTERS_MPAPI_IMPL_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/sunmdi.h>
+#include <sys/sunddi.h>
+#include <sys/mdi_impldefs.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 */
+
+/*
+ * All the structures (except mp_iocdata_t) are 64-bit aligned (padded,
+ * where necessary) to facilitate the use of the same structure for
+ * handling ioctl calls made by both 32-bit and 64-bit applications.
+ * There are no pointers to other structures inside these structures
+ * as copyout to user land may not produce desired result.
+ * The caddr_t structure is kept at the end due to the undeterminstic
+ * size it could accrue to its parent structure.
+ */
+
+/* Structure for MP_PLUGIN_PROPERTIES */
+
+typedef struct mp_driver_prop {
+	char		driverVersion[256];
+	uint32_t	supportedLoadBalanceTypes;
+	boolean_t	canSetTPGAccess;
+	boolean_t	canOverridePaths;
+	boolean_t	exposesPathDeviceFiles;
+	char		deviceFileNamespace[256];
+	uint32_t	onlySupportsSpecifiedProducts;
+	uint32_t	maximumWeight;
+	uint32_t	failbackPollingRateMax;
+	uint32_t	currentFailbackPollingRate;
+	uint32_t	autoFailbackSupport;
+	uint32_t	autoFailbackEnabled;
+	uint32_t	defaultLoadBalanceType;
+	uint32_t	probingPollingRateMax;
+	uint32_t	currentProbingPollingRate;
+	uint32_t	autoProbingSupport;
+	uint32_t	autoProbingEnabled;
+	uint32_t	proprietaryPropSize;
+	caddr_t		proprietaryProp;
+} mp_driver_prop_t;
+
+
+/* Size of "proprietaryProp" field */
+
+#define	MP_MAX_PROP_BUF_SIZE				1024
+
+
+/* Constants for autoFailbackSupport */
+
+/*
+ * Both MP_DRVR_AUTO_FAILBACK_SUPPORT and
+ * MP_DRVR_AUTO_FAILBACK_SUPPORT_LU
+ * can be supported at the same time.
+ */
+
+#define	MP_DRVR_AUTO_FAILBACK_SUPPORT_NONE		0
+#define	MP_DRVR_AUTO_FAILBACK_SUPPORT			(1<<0)
+#define	MP_DRVR_AUTO_FAILBACK_SUPPORT_LU		(1<<1)
+
+
+/* Constants for defaultLoadBalanceType */
+
+#define	MP_DRVR_LOAD_BALANCE_TYPE_UNKNOWN		0
+#define	MP_DRVR_LOAD_BALANCE_TYPE_ROUNDROBIN		(1<<0)
+#define	MP_DRVR_LOAD_BALANCE_TYPE_LEASTBLOCKS		(1<<1)
+#define	MP_DRVR_LOAD_BALANCE_TYPE_LEASTIO		(1<<2)
+#define	MP_DRVR_LOAD_BALANCE_TYPE_DEVICE_PRODUCT	(1<<3)
+#define	MP_DRVR_LOAD_BALANCE_TYPE_LBA_REGION		(1<<4)
+#define	MP_DRVR_LOAD_BALANCE_TYPE_PROPRIETARY1		(1<<16)
+#define	MP_DRVR_LOAD_BALANCE_TYPE_PROPRIETARY2		(1<<17)
+
+
+/* Constants for autoProbingSupport */
+
+/*
+ * Both MP_DRVR_AUTO_PROBING_SUPPORT and
+ * MP_DRVR_AUTO_PROBING_SUPPORT_LU
+ * can be supported at the same time.
+ */
+
+#define	MP_DRVR_AUTO_PROBING_SUPPORT_NONE		0
+#define	MP_DRVR_AUTO_PROBING_SUPPORT			(1<<0)
+#define	MP_DRVR_AUTO_PROBING_SUPPORT_LU			(1<<1)
+
+
+/* Structures for MP_DEVICE_PRODUCT_PROPERTIES */
+
+typedef struct mp_vendor_prod_info {
+	char	vendor[8];
+	char	product[16];
+	char	revision[4];
+	char	reserved[4]; /* padding for 64bit alignment */
+} mp_vendor_prod_info_t;
+
+typedef struct mp_dev_prod_prop {
+	struct mp_vendor_prod_info	prodInfo;
+	uint32_t			supportedLoadBalanceTypes;
+	uint32_t			reserved; /* 64bit alignment padding */
+	uint64_t			id;
+} mp_dev_prod_prop_t;
+
+
+/* Structure for MP_MULTIPATH_LOGICAL_UNIT_PROPERTIES */
+
+typedef struct mp_logical_unit_prop {
+	struct mp_vendor_prod_info	prodInfo;
+	char				name[256];  /* guid */
+	uint32_t			nameType;
+	uint32_t			luGroupID;
+	char				deviceFileName[256];
+	uint64_t			id;
+	boolean_t			asymmetric;
+	uint32_t			currentLoadBalanceType;
+	boolean_t			autoFailbackEnabled;
+	uint32_t			failbackPollingRateMax;
+	uint32_t			currentFailBackPollingRate;
+	uint32_t			autoProbingEnabled;
+	uint32_t			probingPollingRateMax;
+	uint32_t			currentProbingPollingRate;
+	uint64_t			overridePathID;
+	boolean_t			overridePathInUse;
+	uint32_t			proprietaryPropSize;
+	caddr_t				proprietaryProp;
+} mp_logical_unit_prop_t;
+
+
+/* Constants for nameType */
+
+#define	MP_DRVR_NAME_TYPE_UNKNOWN		0
+#define	MP_DRVR_NAME_TYPE_VPD83_TYPE1		1
+#define	MP_DRVR_NAME_TYPE_VPD83_TYPE2		2
+#define	MP_DRVR_NAME_TYPE_VPD83_TYPE3		3
+#define	MP_DRVR_NAME_TYPE_DEVICE_SPECIFIC	4
+
+
+/* Structure for MP_INITIATOR_PORT_PROPERTIES */
+
+typedef struct mp_init_port_prop {
+	char		portID[256];
+	char		osDeviceFile[256];
+	uint32_t	portType;
+	uint32_t	reserved; /* padding for 64bit alignment */
+	uint64_t	id;
+} mp_init_port_prop_t;
+
+
+/* Constants for portType */
+
+#define	MP_DRVR_TRANSPORT_TYPE_UNKNOWN	0
+#define	MP_DRVR_TRANSPORT_TYPE_FC	2
+#define	MP_DRVR_TRANSPORT_TYPE_SPI	3
+#define	MP_DRVR_TRANSPORT_TYPE_ISCSI	4
+#define	MP_DRVR_TRANSPORT_TYPE_IFB	5
+
+
+/* Structure for MP_TARGET_PORT_PROPERTIES */
+
+typedef struct mp_target_port_prop {
+	char		portName[256];
+	uint32_t	relativePortID;
+	uint32_t	reserved; /* padding for 64bit alignment */
+	uint64_t	id;
+} mp_target_port_prop_t;
+
+
+/* Structure for MP_TARGET_PORT_GROUP_PROPERTIES */
+
+typedef struct mp_tpg_prop {
+	uint32_t	accessState;
+	boolean_t	explicitFailover;
+	uint32_t	tpgId; /* T10 defined id in report/set TPG */
+	boolean_t	preferredLuPath;
+	boolean_t	supportsLuAssignment;
+	uint32_t	reserved; /* padding for 64bit alignment */
+	uint64_t	id;
+} mp_tpg_prop_t;
+
+
+/* Constants for accessState */
+
+#define	MP_DRVR_ACCESS_STATE_ACTIVE_OPTIMIZED		0
+#define	MP_DRVR_ACCESS_STATE_ACTIVE_NONOPTIMIZED	0x1
+#define	MP_DRVR_ACCESS_STATE_STANDBY			0x2
+#define	MP_DRVR_ACCESS_STATE_UNAVAILABLE		0x3
+#define	MP_DRVR_ACCESS_STATE_TRANSITIONING		0xf
+#define	MP_DRVR_ACCESS_STATE_ACTIVE			0x10
+
+
+/* Structure for MP_PATH_LOGICAL_UNIT_PROPERTIES */
+
+typedef struct mp_path_prop {
+	uint32_t			weight;
+	uint32_t			pathState;
+	boolean_t			disabled;
+	uint32_t			reserved; /* 64bit alignment padding */
+	uint64_t			id;
+	struct mp_init_port_prop	initPort;
+	struct mp_target_port_prop	targetPort;
+	struct mp_logical_unit_prop	logicalUnit;
+} mp_path_prop_t;
+
+
+/* Constants for pathState */
+
+#define	MP_DRVR_PATH_STATE_ACTIVE		0
+#define	MP_DRVR_PATH_STATE_PASSIVE		1
+#define	MP_DRVR_PATH_STATE_PATH_ERR		2
+#define	MP_DRVR_PATH_STATE_LU_ERR		3
+#define	MP_DRVR_PATH_STATE_RESERVED		4
+#define	MP_DRVR_PATH_STATE_REMOVED		5
+#define	MP_DRVR_PATH_STATE_TRANSITIONING	6
+#define	MP_DRVR_PATH_STATE_UNKNOWN		7
+
+
+/* Structure for MP_PROPRIETARY_LOAD_BALANCE_PROPERTIES */
+
+typedef struct mp_proprietary_loadbalance_prop {
+	char		name[256];
+	char		vendorName[256];
+	uint64_t	id;
+	uint32_t	typeIndex;
+	uint32_t	proprietaryPropSize;
+	caddr_t		proprietaryProp;
+} mp_proprietary_loadbalance_prop_t;
+
+
+/*
+ * Structure used as input to
+ * MP_ASSIGN_LU_TO_TPG subcmd.
+ */
+
+typedef struct mp_lu_tpg_pair {
+	uint64_t	luId;
+	uint64_t	tpgId;
+} mp_lu_tpg_pair_t;
+
+
+/*
+ * Structure used as input to
+ * MP_SET_TPG_ACCESS_STATE subcmd.
+ */
+
+typedef struct mp_set_tpg_state_req {
+	struct mp_lu_tpg_pair	luTpgPair;
+	uint32_t		desiredState;
+	uint32_t		reserved; /* padding for 64bit boundary */
+} mp_set_tpg_state_req_t;
+
+
+/*
+ * Structure for ioctl data
+ */
+typedef struct mp_iocdata {
+	uint16_t	mp_xfer;	/* direction */
+	uint16_t	mp_cmd;		/* sub command */
+	uint16_t	mp_flags;	/* flags */
+	uint16_t	mp_cmd_flags;	/* command specific flags */
+	size_t		mp_ilen;	/* Input buffer length */
+	caddr_t		mp_ibuf;	/* Input buffer */
+	size_t		mp_olen;	/* Output buffer length */
+	caddr_t		mp_obuf;	/* Output buffer */
+	size_t		mp_alen;	/* Auxiliary buffer length */
+	caddr_t		mp_abuf;	/* Auxiliary buffer */
+	int		mp_errno;	/* MPAPI driver internal error code */
+} mp_iocdata_t;
+
+
+#ifdef _KERNEL
+
+#if defined(_SYSCALL32)
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack(4)
+#endif
+
+/*
+ * Structure for 32-bit ioctl data
+ */
+
+typedef struct mp_iocdata32 {
+	uint16_t	mp_xfer;	/* direction */
+	uint16_t	mp_cmd;		/* sub command */
+	uint16_t	mp_flags;	/* flags */
+	uint16_t	mp_cmd_flags;	/* command specific flags */
+	uint32_t	mp_ilen;	/* Input buffer length */
+	caddr32_t	mp_ibuf;	/* Input buffer */
+	uint32_t	mp_olen;	/* Output buffer length */
+	caddr32_t	mp_obuf;	/* Output buffer */
+	uint32_t	mp_alen;	/* Auxiliary buffer length */
+	caddr32_t	mp_abuf;	/* Auxiliary buffer */
+	int32_t		mp_errno;	/* MPAPI driver internal error code */
+} mp_iocdata32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack()
+#endif
+
+#endif  /* _SYSCALL32 */
+
+#endif /* _KERNEL */
+
+
+/* Constants for MP_XFER */
+
+#define	MP_XFER_NONE	0x00
+#define	MP_XFER_READ	0x01
+#define	MP_XFER_WRITE	0x02
+#define	MP_XFER_RW	(MP_XFER_READ | MP_XFER_WRITE)
+
+
+/* Constants for MP_OBJECT_TYPE */
+
+#define	MP_OBJECT_TYPE_UNKNOWN			0
+#define	MP_OBJECT_TYPE_PLUGIN			1
+#define	MP_OBJECT_TYPE_INITIATOR_PORT		2
+#define	MP_OBJECT_TYPE_TARGET_PORT		3
+#define	MP_OBJECT_TYPE_MULTIPATH_LU		4
+#define	MP_OBJECT_TYPE_PATH_LU			5
+#define	MP_OBJECT_TYPE_DEVICE_PRODUCT		6
+#define	MP_OBJECT_TYPE_TARGET_PORT_GROUP	7
+#define	MP_OBJECT_TYPE_PROPRIETARY_LOAD_BALANCE	8
+#define	MP_OBJECT_TYPE_LAST_ENTRY 	MP_OBJECT_TYPE_PROPRIETARY_LOAD_BALANCE
+#define	MP_MAX_OBJECT_TYPE	(MP_OBJECT_TYPE_LAST_ENTRY + 1)
+
+
+/* Constants for MP_CMD */
+
+#define	MPAPI_CTL				('m'<<8)
+#define	MP_CMD					(MPAPI_CTL | 2005)
+#define	MP_SUB_CMD				('M'<<8)
+
+#define	MP_API_SUBCMD_MIN			(MP_SUB_CMD + 0x01)
+#define	MP_GET_DRIVER_PROP			(MP_SUB_CMD + 0x01)
+#define	MP_GET_DEV_PROD_LIST			(MP_SUB_CMD + 0x02)
+#define	MP_GET_DEV_PROD_PROP			(MP_SUB_CMD + 0x03)
+#define	MP_GET_LU_LIST				(MP_SUB_CMD + 0x04)
+#define	MP_GET_LU_LIST_FROM_TPG			(MP_SUB_CMD + 0x05)
+#define	MP_GET_LU_PROP				(MP_SUB_CMD + 0x06)
+#define	MP_GET_PATH_LIST_FOR_MP_LU		(MP_SUB_CMD + 0x07)
+#define	MP_GET_PATH_LIST_FOR_INIT_PORT		(MP_SUB_CMD + 0x08)
+#define	MP_GET_PATH_LIST_FOR_TARGET_PORT	(MP_SUB_CMD + 0x09)
+#define	MP_GET_PATH_PROP			(MP_SUB_CMD + 0x0a)
+#define	MP_GET_INIT_PORT_LIST			(MP_SUB_CMD + 0x0b)
+#define	MP_GET_INIT_PORT_PROP			(MP_SUB_CMD + 0x0c)
+#define	MP_GET_TARGET_PORT_PROP			(MP_SUB_CMD + 0x0d)
+#define	MP_GET_TPG_LIST				(MP_SUB_CMD + 0x0e)
+#define	MP_GET_TPG_PROP				(MP_SUB_CMD + 0x0f)
+#define	MP_GET_TPG_LIST_FOR_LU			(MP_SUB_CMD + 0x10)
+#define	MP_GET_TARGET_PORT_LIST_FOR_TPG		(MP_SUB_CMD + 0x11)
+#define	MP_SET_TPG_ACCESS_STATE			(MP_SUB_CMD + 0x12)
+#define	MP_ENABLE_AUTO_FAILBACK			(MP_SUB_CMD + 0x13)
+#define	MP_DISABLE_AUTO_FAILBACK 		(MP_SUB_CMD + 0x14)
+#define	MP_ENABLE_PATH				(MP_SUB_CMD + 0x15)
+#define	MP_DISABLE_PATH				(MP_SUB_CMD + 0x16)
+#define	MP_GET_PROPRIETARY_LOADBALANCE_LIST	(MP_SUB_CMD + 0x17)
+#define	MP_GET_PROPRIETARY_LOADBALANCE_PROP	(MP_SUB_CMD + 0x18)
+#define	MP_ASSIGN_LU_TO_TPG			(MP_SUB_CMD + 0x19)
+#define	MP_API_SUBCMD_MAX			(MP_ASSIGN_LU_TO_TPG)
+
+
+/*
+ * Typical MP API ioctl interface specific Return Values
+ */
+
+#define	MP_IOCTL_ERROR_START			0x5533
+#define	MP_MORE_DATA				(MP_IOCTL_ERROR_START + 1)
+#define	MP_DRVR_INVALID_ID			(MP_IOCTL_ERROR_START + 2)
+#define	MP_DRVR_ID_OBSOLETE			(MP_IOCTL_ERROR_START + 3)
+#define	MP_DRVR_ACCESS_SYMMETRIC		(MP_IOCTL_ERROR_START + 4)
+#define	MP_DRVR_PATH_UNAVAILABLE		(MP_IOCTL_ERROR_START + 5)
+#define	MP_DRVR_IDS_NOT_ASSOCIATED		(MP_IOCTL_ERROR_START + 6)
+#define	MP_DRVR_ILLEGAL_ACCESS_STATE_REQUEST	(MP_IOCTL_ERROR_START + 7)
+
+/*
+ * Macros for OID operations
+ */
+#define	MP_ID_SHIFT4MAJOR		32
+#define	MP_GET_MAJOR_FROM_ID(id)	((id) >> MP_ID_SHIFT4MAJOR)
+#define	MP_GET_INST_FROM_ID(id)		((id) & 0x00000000ffffffff)
+#define	MP_STORE_INST_TO_ID(inst, id)	(((uint64_t)(inst)) | id)
+#define	MP_STORE_MAJOR_TO_ID(major, id)	\
+	((((uint64_t)(major)) << MP_ID_SHIFT4MAJOR) | id)
+
+/*
+ * Event Class and Sub-Class definitions
+ */
+#define	EC_SUN_MP			"EC_sun_mp"
+
+#define	ESC_SUN_MP_LU_CHANGE		"ESC_sun_mp_lu_change"
+
+#define	ESC_SUN_MP_PATH_CHANGE		"ESC_sun_mp_path_change"
+#define	ESC_SUN_MP_PATH_ADD		"ESC_sun_mp_path_add"
+#define	ESC_SUN_MP_PATH_REMOVE		"ESC_sun_mp_path_remove"
+
+#define	ESC_SUN_MP_INIT_PORT_CHANGE	"ESC_sun_mp_init_port_change"
+
+#define	ESC_SUN_MP_TPG_CHANGE		"ESC_sun_mp_tpg_change"
+#define	ESC_SUN_MP_TPG_ADD		"ESC_sun_mp_tpg_add"
+#define	ESC_SUN_MP_TPG_REMOVE		"ESC_sun_mp_tpg_remove"
+
+#define	ESC_SUN_MP_TARGET_PORT_CHANGE	"ESC_sun_mp_target_port_change"
+#define	ESC_SUN_MP_TARGET_PORT_ADD	"ESC_sun_mp_target_port_add"
+#define	ESC_SUN_MP_TARGET_PORT_REMOVE	"ESC_sun_mp_target_port_remove"
+
+#define	ESC_SUN_MP_DEV_PROD_CHANGE	"ESC_sun_mp_dev_prod_change"
+#define	ESC_SUN_MP_DEV_PROD_ADD		"ESC_sun_mp_dev_prod_add"
+#define	ESC_SUN_MP_DEV_PROD_REMOVE	"ESC_sun_mp_dev_prod_remove"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SCSI_ADAPTERS_MPAPI_IMPL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/scsi/adapters/mpapi_scsi_vhci.h	Fri Nov 11 16:52:37 2005 -0800
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_SCSI_ADAPTERS_MPAPI_SCSI_VHCI_H
+#define	_SYS_SCSI_ADAPTERS_MPAPI_SCSI_VHCI_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#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 */
+
+
+#include <sys/scsi/adapters/mpapi_impl.h>
+
+/* Structure for MP_OID (kernel level only) */
+
+typedef struct mp_oid {
+#if defined(_BIT_FIELDS_HTOL)
+	uint32_t	tstamp;
+	uint32_t	type:8,
+			seq_id:24;
+#else
+	uint32_t	seq_id:24,
+			type:8;
+	uint32_t	tstamp;
+#endif
+} mp_oid_t;
+
+typedef union mpoid {
+	uint64_t	raw_oid;	/* raw oid */
+	mp_oid_t	disc_oid;	/* discrete oid */
+} mpoid_t;
+
+
+/*
+ * MP API item - A generic one to use in a list setup
+ * in a common way for all types of elements of
+ * Object type items required for mpapi.
+ */
+
+typedef	struct mpapi_item {
+	mpoid_t			oid;
+	void			*idata; /* item data */
+}mpapi_item_t;
+
+typedef	struct mpapi_item_list {
+	mpapi_item_t		*item;
+	struct mpapi_item_list	*next;
+}mpapi_item_list_t;
+
+/*
+ * MP API item header definition.
+ */
+
+typedef struct mpapi_list_header {
+	mpapi_item_list_t	*head;
+	mpapi_item_list_t	*tail;
+}mpapi_list_header_t;
+
+/*
+ * Structure to maintain mp api initiator data.
+ */
+typedef struct mpapi_initiator_data {
+	void			*resp; /* phci */
+	mpapi_list_header_t	*path_list;
+	int			valid;
+	mp_init_port_prop_t	prop;
+} mpapi_initiator_data_t;
+
+/*
+ * Structure to maintain mp api lu data.
+ */
+typedef struct mpapi_lu_data {
+	void			*resp; /* vlun */
+	mpapi_list_header_t	*path_list;
+	mpapi_list_header_t	*tpg_list;
+	int			valid;
+	mp_logical_unit_prop_t	prop;
+} mpapi_lu_data_t;
+
+/*
+ * Structure to maintain mp api path data.
+ */
+typedef struct mpapi_path_data {
+	void			*resp; /* pip */
+	char			*path_name;
+	int			valid;
+	mp_path_prop_t		prop;
+} mpapi_path_data_t;
+
+/*
+ * Structure to maintain mp api tpg data.
+ */
+typedef struct mpapi_tpg_data {
+	void			*resp; /* target port prop, but non-unique */
+	mpapi_list_header_t	*tport_list;
+	mpapi_list_header_t	*lu_list; /* mpath lu or lun list */
+	int			valid;
+	mp_tpg_prop_t		prop;
+} mpapi_tpg_data_t;
+
+/*
+ * Structure to maintain mp api tport data.
+ */
+typedef struct mpapi_tport_data {
+	void			*resp; /* target port prop */
+	mpapi_list_header_t	*path_list;
+	int			valid;
+	mp_target_port_prop_t	prop;
+} mpapi_tport_data_t;
+
+
+/* Structure for mpapi private data */
+
+typedef struct mpapi_priv {
+
+	/*
+	 * Will be initialized with the lbolt value(lower
+	 * 32 bits) at the time of initialization. This will
+	 * enable detection of stale OIDs used by the
+	 * upper layers.
+	 */
+	uint32_t		tstamp;
+	/*
+	 * The Seq number space is unique within an Object
+	 * type - that is there can be a seq# 2 in Object type
+	 * 'initiator Port' and also a seq#2 in object type
+	 * 'Path LU'. Even though the seq space collides,
+	 * the unique type field(Object type) will make them
+	 * distinct.
+	 * The following field will indicate what the next
+	 * sequence number that can be used for a particular
+	 * type of Object type - Object type will be used to
+	 * index into the array element.
+	 */
+	uint32_t		oid_seq[MP_MAX_OBJECT_TYPE];
+
+	/*
+	 * One list for each type of object.
+	 */
+	mpapi_list_header_t	*obj_hdr_list[MP_MAX_OBJECT_TYPE];
+
+	/*
+	 * Still to do..   LBA
+	 */
+
+
+} mpapi_priv_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SCSI_ADAPTERS_MPAPI_SCSI_VHCI_H */
--- a/usr/src/uts/common/sys/scsi/adapters/scsi_vhci.h	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/uts/common/sys/scsi/adapters/scsi_vhci.h	Fri Nov 11 16:52:37 2005 -0800
@@ -36,6 +36,8 @@
 #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" {
@@ -215,6 +217,13 @@
 
 #define	SCSI_OPTIONS_VHCI(n)	((n) & SCSI_OPTIONS_VHCI_MASK)
 
+typedef struct vhci_dev_vidpid_entry {
+	char	vid[10];
+	int	vid_len;
+	char	pid[20];
+	int	pid_len;
+} vhci_dev_vidpid_entry_t;
+
 struct	scsi_vhci_swarg;
 
 typedef struct vhci_prin_readkeys {
@@ -459,6 +468,7 @@
 	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;
 };
 
 /*
@@ -724,6 +734,7 @@
 
 #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)
 
 #ifdef	__cplusplus
 }
--- a/usr/src/uts/common/sys/scsi/impl/services.h	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/uts/common/sys/scsi/impl/services.h	Fri Nov 11 16:52:37 2005 -0800
@@ -144,9 +144,36 @@
 #define	INTERCONNECT_ISCSI		8
 #define	INTERCONNECT_IBSRP		9
 #define	INTERCONNECT_SATA		10
+#define	INTERCONNECT_MAX		11	/* Change this appropriately, */
+						/* as new one(s) are added.   */
+						/* Is always the last & max.  */
+
+/*					INTERCONNECT TYPE STRINGS */
+#define	INTERCONNECT_PARALLEL_STR	"SPI"
+#define	INTERCONNECT_FIBRE_STR		"FIBRE"
+#define	INTERCONNECT_1394_STR		"1394"
+#define	INTERCONNECT_SSA_STR		""
+#define	INTERCONNECT_FABRIC_STR		"FABRIC"
+#define	INTERCONNECT_USB_STR		"USB"
+#define	INTERCONNECT_ATAPI_STR		"ATAPI"
+#define	INTERCONNECT_ISCSI_STR		"iSCSI"
+#define	INTERCONNECT_IBSRP_STR		"IB"
+#define	INTERCONNECT_SATA_STR		"SATA"
+
 #define	INTERCONNECT_TYPE_ASCII		{				\
-		"", "SPI", "FC", "1394", "", "FC", "USB",		\
-		"ATAPI", "iSCSI", "IB", "SATA", NULL }
+					"",				\
+					INTERCONNECT_PARALLEL_STR,	\
+					INTERCONNECT_FIBRE_STR,		\
+					INTERCONNECT_1394_STR,		\
+					INTERCONNECT_SSA_STR,		\
+					INTERCONNECT_FABRIC_STR,	\
+					INTERCONNECT_USB_STR,		\
+					INTERCONNECT_ATAPI_STR,		\
+					INTERCONNECT_ISCSI_STR,		\
+					INTERCONNECT_IBSRP_STR,		\
+					INTERCONNECT_SATA_STR,		\
+					NULL				\
+					};
 
 /*
  * Compatibility...
--- a/usr/src/uts/common/sys/scsi/impl/transport.h	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/uts/common/sys/scsi/impl/transport.h	Fri Nov 11 16:52:37 2005 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -253,6 +253,12 @@
 				pm_bus_power_op_t	op,
 				void			*arg,
 				void			*result);
+
+	/*
+	 * Inter-Connect type of trasnport as defined in
+	 * usr/src/uts/common/sys/scsi/impl/services.h
+	 */
+	int		tran_interconnect_type;
 };
 
 #ifdef __lock_lint
@@ -371,6 +377,8 @@
  */
 #define	SCSI_HBA_TRAN_CLONE	0x01		/* clone scsi_hba_tran_t */
 						/* structure per target */
+#define	SCSI_HBA_TRAN_ALLOC	0x02		/* set if scsi_hba_tran_alloc */
+						/* is called */
 
 /*
  * Flags for scsi_hba allocation functions
--- a/usr/src/uts/common/sys/sunddi.h	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/uts/common/sys/sunddi.h	Fri Nov 11 16:52:37 2005 -0800
@@ -222,6 +222,7 @@
  * DDI event definitions
  */
 #define	EC_DEVFS	"EC_devfs"	/* Event class devfs */
+#define	EC_DDI		"EC_ddi"	/* Event class ddi */
 
 /* Class devfs subclasses */
 #define	ESC_DEVFS_MINOR_CREATE	"ESC_devfs_minor_create"
@@ -232,14 +233,17 @@
 #define	ESC_DEVFS_BRANCH_ADD	"ESC_devfs_branch_add"
 #define	ESC_DEVFS_BRANCH_REMOVE	"ESC_devfs_branch_remove"
 
+/* Class ddi subclasses */
+#define	ESC_DDI_INITIATOR_REGISTER	"ESC_ddi_initiator_register"
+#define	ESC_DDI_INITIATOR_UNREGISTER	"ESC_ddi_initiator_unregister"
+
 /* DDI/NDI event publisher */
 #define	EP_DDI	SUNW_KERN_PUB"ddi"
 
 /*
  * devfs event class attributes
  *
- * The following attributes are private to EC_DEVFS
- * event data.
+ * The following attributes are private to EC_DEVFS event data.
  */
 #define	DEVFS_DRIVER_NAME	"di.driver"
 #define	DEVFS_INSTANCE		"di.instance"
@@ -253,6 +257,17 @@
 #define	DEVFS_MINOR_MINORNUM	"mi.minorno"
 
 /*
+ * ddi event class payload
+ *
+ * The following attributes are private to EC_DDI event data.
+ */
+#define	DDI_DRIVER_NAME		"ddi.driver"
+#define	DDI_DRIVER_MAJOR	"ddi.major"
+#define	DDI_INSTANCE		"ddi.instance"
+#define	DDI_PATHNAME		"ddi.path"
+#define	DDI_CLASS		"ddi.class"
+
+/*
  * Fault-related definitions
  *
  * The specific numeric values have been chosen to be ordered, but
--- a/usr/src/uts/common/sys/sunmdi.h	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/uts/common/sys/sunmdi.h	Fri Nov 11 16:52:37 2005 -0800
@@ -241,6 +241,23 @@
 int mdi_vhci_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t, void *,
     dev_info_t **, char *);
 
+/*
+ * mdi_vhci node walker function
+ */
+void mdi_walk_vhcis(int (*f)(dev_info_t *, void *), void *arg);
+
+/*
+ * mdi_phci node walker function
+ */
+void mdi_vhci_walk_phcis(dev_info_t *, int (*f)(dev_info_t *, void *),
+    void *arg);
+
+/*
+ * mdi_client node walker function
+ */
+void mdi_vhci_walk_clients(dev_info_t *, int (*f)(dev_info_t *, void *),
+    void *arg);
+
 #endif /* _KERNEL */
 
 #ifdef	__cplusplus
--- a/usr/src/uts/intel/os/device_policy	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/uts/intel/os/device_policy	Fri Nov 11 16:52:37 2005 -0800
@@ -73,6 +73,7 @@
 #
 md:admin					write_priv_set=sys_config
 fssnap:ctl	read_priv_set=sys_config	write_priv_set=sys_config
+scsi_vhci:devctl				write_priv_set=sys_devices
 #
 # Other devices that require a privilege to open.
 #
--- a/usr/src/uts/intel/os/minor_perm	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/uts/intel/os/minor_perm	Fri Nov 11 16:52:37 2005 -0800
@@ -115,3 +115,4 @@
 smbios:smbios 0444 root sys
 zfs:* 0600 root sys
 zfs:zfs 0666 root sys
+scsi_vhci:* 0666 root sys
--- a/usr/src/uts/sparc/os/device_policy	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/uts/sparc/os/device_policy	Fri Nov 11 16:52:37 2005 -0800
@@ -78,6 +78,7 @@
 #
 md:admin					write_priv_set=sys_config
 fssnap:ctl	read_priv_set=sys_config	write_priv_set=sys_config
+scsi_vhci:devctl				write_priv_set=sys_devices
 #
 # Other devices that require a privilege to open.
 #
--- a/usr/src/uts/sparc/os/minor_perm	Fri Nov 11 16:30:15 2005 -0800
+++ b/usr/src/uts/sparc/os/minor_perm	Fri Nov 11 16:52:37 2005 -0800
@@ -164,3 +164,4 @@
 ntwdt:* 0644 root sys
 zfs:* 0600 root sys
 zfs:zfs 0666 root sys
+scsi_vhci:* 0666 root sys