summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorrs135747 <none@none>2005-11-11 16:52:37 -0800
committerrs135747 <none@none>2005-11-11 16:52:37 -0800
commit8c4f8890c870d3bd16cbcaeed2dc4679d5e076b5 (patch)
treeab4d0d1191a3708b22742d4e5260a35150b9bb23 /usr/src
parenta940d195c7af8690a5b0f1a1f638857f3cc91248 (diff)
downloadillumos-joyent-8c4f8890c870d3bd16cbcaeed2dc4679d5e076b5.tar.gz
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
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/devfsadm/devfsadm.c6
-rw-r--r--usr/src/lib/libdevinfo/devinfo.c98
-rw-r--r--usr/src/lib/libdevinfo/libdevinfo.h6
-rw-r--r--usr/src/lib/libdevinfo/spec/devinfo.spec24
-rw-r--r--usr/src/pkgdefs/etc/exception_list_i3867
-rw-r--r--usr/src/pkgdefs/etc/exception_list_sparc7
-rw-r--r--usr/src/uts/common/Makefile.files1
-rw-r--r--usr/src/uts/common/io/devinfo.c116
-rw-r--r--usr/src/uts/common/io/scsi/impl/scsi_hba.c34
-rw-r--r--usr/src/uts/common/os/sunmdi.c189
-rw-r--r--usr/src/uts/common/sys/Makefile4
-rw-r--r--usr/src/uts/common/sys/devinfo_impl.h26
-rw-r--r--usr/src/uts/common/sys/scsi/adapters/mpapi_impl.h428
-rw-r--r--usr/src/uts/common/sys/scsi/adapters/mpapi_scsi_vhci.h161
-rw-r--r--usr/src/uts/common/sys/scsi/adapters/scsi_vhci.h11
-rw-r--r--usr/src/uts/common/sys/scsi/impl/services.h31
-rw-r--r--usr/src/uts/common/sys/scsi/impl/transport.h10
-rw-r--r--usr/src/uts/common/sys/sunddi.h19
-rw-r--r--usr/src/uts/common/sys/sunmdi.h17
-rw-r--r--usr/src/uts/intel/os/device_policy1
-rw-r--r--usr/src/uts/intel/os/minor_perm1
-rw-r--r--usr/src/uts/sparc/os/device_policy1
-rw-r--r--usr/src/uts/sparc/os/minor_perm1
23 files changed, 1180 insertions, 19 deletions
diff --git a/usr/src/cmd/devfsadm/devfsadm.c b/usr/src/cmd/devfsadm/devfsadm.c
index 6317c86aec..0df0f12abd 100644
--- a/usr/src/cmd/devfsadm/devfsadm.c
+++ b/usr/src/cmd/devfsadm/devfsadm.c
@@ -945,11 +945,15 @@ process_deferred_links(struct dca_impl *dcip, int flags)
* 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: ";
diff --git a/usr/src/lib/libdevinfo/devinfo.c b/usr/src/lib/libdevinfo/devinfo.c
index 991fa7d833..ee33c2d518 100644
--- a/usr/src/lib/libdevinfo/devinfo.c
+++ b/usr/src/lib/libdevinfo/devinfo.c
@@ -2088,6 +2088,104 @@ int di_path_prop_lookup_strings(di_path_t path, const char *prop_name,
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
diff --git a/usr/src/lib/libdevinfo/libdevinfo.h b/usr/src/lib/libdevinfo/libdevinfo.h
index b277ff4ae5..195eee4e55 100644
--- a/usr/src/lib/libdevinfo/libdevinfo.h
+++ b/usr/src/lib/libdevinfo/libdevinfo.h
@@ -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_sibling_node(di_node_t node);
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
diff --git a/usr/src/lib/libdevinfo/spec/devinfo.spec b/usr/src/lib/libdevinfo/spec/devinfo.spec
index 66a4de49d8..cbf95569e3 100644
--- a/usr/src/lib/libdevinfo/spec/devinfo.spec
+++ b/usr/src/lib/libdevinfo/spec/devinfo.spec
@@ -949,3 +949,27 @@ declaration int devfs_rm_minor_perm(char *drv, \
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
diff --git a/usr/src/pkgdefs/etc/exception_list_i386 b/usr/src/pkgdefs/etc/exception_list_i386
index 845ab53571..37252fc182 100644
--- a/usr/src/pkgdefs/etc/exception_list_i386
+++ b/usr/src/pkgdefs/etc/exception_list_i386
@@ -743,3 +743,10 @@ usr/lib/llib-lzpool.ln i386
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
diff --git a/usr/src/pkgdefs/etc/exception_list_sparc b/usr/src/pkgdefs/etc/exception_list_sparc
index 500564a3eb..eb70a2b112 100644
--- a/usr/src/pkgdefs/etc/exception_list_sparc
+++ b/usr/src/pkgdefs/etc/exception_list_sparc
@@ -810,3 +810,10 @@ usr/lib/llib-lzpool sparc
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
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 2b952a3b5a..fdb7a58762 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -1176,6 +1176,7 @@ SCSI_VHCI_OBJS += scsi_vhci.o \
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
diff --git a/usr/src/uts/common/io/devinfo.c b/usr/src/uts/common/io/devinfo.c
index 20ef0add5c..3533f193fe 100644
--- a/usr/src/uts/common/io/devinfo.c
+++ b/usr/src/uts/common/io/devinfo.c
@@ -270,6 +270,11 @@ static uint_t di_chunk = 32; /* I/O chunk size in pages */
#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 snapshot_is_cacheable(struct di_state *st);
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 @@ di_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
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 @@ di_snapshot(struct di_state *st)
*/
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 @@ di_snapshot(struct di_state *st)
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 @@ di_snapshot_and_clean(struct di_state *st)
}
/*
+ * 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 @@ di_copynode(struct di_stack *dsp, struct di_state *st)
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 @@ path:
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 @@ path:
}
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 @@ chunk_write(struct vnode *vp, offset_t off, caddr_t buf, size_t len)
}
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)
diff --git a/usr/src/uts/common/io/scsi/impl/scsi_hba.c b/usr/src/uts/common/io/scsi/impl/scsi_hba.c
index 8974f1e144..0d7c21afd6 100644
--- a/usr/src/uts/common/io/scsi/impl/scsi_hba.c
+++ b/usr/src/uts/common/io/scsi/impl/scsi_hba.c
@@ -278,8 +278,10 @@ scsi_hba_attach_setup(
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 @@ scsi_hba_attach_setup(
* 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 @@ scsi_hba_attach_setup(
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 @@ scsi_hba_tran_alloc(
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);
}
diff --git a/usr/src/uts/common/os/sunmdi.c b/usr/src/uts/common/os/sunmdi.c
index dc2a0024a2..bdc0ebcd43 100644
--- a/usr/src/uts/common/os/sunmdi.c
+++ b/usr/src/uts/common/os/sunmdi.c
@@ -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_rele_client(mdi_client_t *, int);
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 @@ mdi_vhci_unregister(dev_info_t *vdip, int flags)
}
/*
- * 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 @@ mdi_phci_register(char *class, dev_info_t *pdip, int flags)
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 @@ mdi_phci_unregister(dev_info_t *pdip, int flags)
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 @@ i_mdi_pi_alloc(mdi_phci_t *ph, char *paddr, mdi_client_t *ct)
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 @@ i_mdi_pi_alloc(mdi_phci_t *ph, char *paddr, mdi_client_t *ct)
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 @@ mdi_pi_free(mdi_pathinfo_t *pip, int flags)
/*
* 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 @@ mdi_pi_free(mdi_pathinfo_t *pip, int flags)
* 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 @@ i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *pip, mdi_client_t *ct)
{
int ct_circular;
int ph_circular;
+ int se_flag;
+ int kmem_flag;
/*
* remove any per-path kstats
@@ -2836,6 +2852,12 @@ i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *pip, mdi_client_t *ct)
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 @@ mdi_clean_vhcache(void)
}
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"));
+}
diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile
index 39ba2202d6..24704620bd 100644
--- a/usr/src/uts/common/sys/Makefile
+++ b/usr/src/uts/common/sys/Makefile
@@ -788,7 +788,9 @@ SCSICADHDRS= \
mptvar.h
SCSIVHCIHDRS= \
- scsi_vhci.h
+ scsi_vhci.h \
+ mpapi_impl.h \
+ mpapi_scsi_vhci.h
FCHDRS= \
fc_transport.h \
diff --git a/usr/src/uts/common/sys/devinfo_impl.h b/usr/src/uts/common/sys/devinfo_impl.h
index 1e0f3a7fb9..6bf4255cf6 100644
--- a/usr/src/uts/common/sys/devinfo_impl.h
+++ b/usr/src/uts/common/sys/devinfo_impl.h
@@ -98,14 +98,16 @@ extern "C" {
#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 @@ extern "C" {
#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 @@ struct di_all {
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 @@ struct di_node { /* useful info to export for each tree node */
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. */
};
/*
diff --git a/usr/src/uts/common/sys/scsi/adapters/mpapi_impl.h b/usr/src/uts/common/sys/scsi/adapters/mpapi_impl.h
new file mode 100644
index 0000000000..7ecdc063bf
--- /dev/null
+++ b/usr/src/uts/common/sys/scsi/adapters/mpapi_impl.h
@@ -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 */
diff --git a/usr/src/uts/common/sys/scsi/adapters/mpapi_scsi_vhci.h b/usr/src/uts/common/sys/scsi/adapters/mpapi_scsi_vhci.h
new file mode 100644
index 0000000000..08af5735b4
--- /dev/null
+++ b/usr/src/uts/common/sys/scsi/adapters/mpapi_scsi_vhci.h
@@ -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 */
diff --git a/usr/src/uts/common/sys/scsi/adapters/scsi_vhci.h b/usr/src/uts/common/sys/scsi/adapters/scsi_vhci.h
index eb7d0ad65a..b2b5346873 100644
--- a/usr/src/uts/common/sys/scsi/adapters/scsi_vhci.h
+++ b/usr/src/uts/common/sys/scsi/adapters/scsi_vhci.h
@@ -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 @@ extern int vhci_debug;
#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 @@ struct scsi_vhci {
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 @@ typedef struct sv_switch_to_cntlr_iocdata {
#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
}
diff --git a/usr/src/uts/common/sys/scsi/impl/services.h b/usr/src/uts/common/sys/scsi/impl/services.h
index f2324e9b8b..9f48d0aabf 100644
--- a/usr/src/uts/common/sys/scsi/impl/services.h
+++ b/usr/src/uts/common/sys/scsi/impl/services.h
@@ -144,9 +144,36 @@ extern char *sense_keys[NUM_SENSE_KEYS + NUM_IMPL_SENSE_KEYS];
#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...
diff --git a/usr/src/uts/common/sys/scsi/impl/transport.h b/usr/src/uts/common/sys/scsi/impl/transport.h
index 92b6c0ef92..034b3f9453 100644
--- a/usr/src/uts/common/sys/scsi/impl/transport.h
+++ b/usr/src/uts/common/sys/scsi/impl/transport.h
@@ -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 @@ struct scsi_hba_tran {
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 @@ extern void scsi_hba_nodename_compatible_free(
*/
#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
diff --git a/usr/src/uts/common/sys/sunddi.h b/usr/src/uts/common/sys/sunddi.h
index 0bc48cbd84..1f287da483 100644
--- a/usr/src/uts/common/sys/sunddi.h
+++ b/usr/src/uts/common/sys/sunddi.h
@@ -222,6 +222,7 @@ extern "C" {
* 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 @@ extern "C" {
#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 @@ extern "C" {
#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
diff --git a/usr/src/uts/common/sys/sunmdi.h b/usr/src/uts/common/sys/sunmdi.h
index 0c4efcb3e3..97fe1ea59a 100644
--- a/usr/src/uts/common/sys/sunmdi.h
+++ b/usr/src/uts/common/sys/sunmdi.h
@@ -241,6 +241,23 @@ void mdi_pi_set_phci_private(mdi_pathinfo_t *, caddr_t);
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
diff --git a/usr/src/uts/intel/os/device_policy b/usr/src/uts/intel/os/device_policy
index 3e667aa25f..c2f9733153 100644
--- a/usr/src/uts/intel/os/device_policy
+++ b/usr/src/uts/intel/os/device_policy
@@ -73,6 +73,7 @@ vni read_priv_set=net_rawaccess write_priv_set=net_rawaccess
#
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.
#
diff --git a/usr/src/uts/intel/os/minor_perm b/usr/src/uts/intel/os/minor_perm
index d60196d570..4d7aa42b6c 100644
--- a/usr/src/uts/intel/os/minor_perm
+++ b/usr/src/uts/intel/os/minor_perm
@@ -115,3 +115,4 @@ aggr:* 0666 root sys
smbios:smbios 0444 root sys
zfs:* 0600 root sys
zfs:zfs 0666 root sys
+scsi_vhci:* 0666 root sys
diff --git a/usr/src/uts/sparc/os/device_policy b/usr/src/uts/sparc/os/device_policy
index 45f3294cf9..a6d7e1de52 100644
--- a/usr/src/uts/sparc/os/device_policy
+++ b/usr/src/uts/sparc/os/device_policy
@@ -78,6 +78,7 @@ vni read_priv_set=net_rawaccess write_priv_set=net_rawaccess
#
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.
#
diff --git a/usr/src/uts/sparc/os/minor_perm b/usr/src/uts/sparc/os/minor_perm
index e46f3718ff..07c11962eb 100644
--- a/usr/src/uts/sparc/os/minor_perm
+++ b/usr/src/uts/sparc/os/minor_perm
@@ -164,3 +164,4 @@ aggr:* 0666 root sys
ntwdt:* 0644 root sys
zfs:* 0600 root sys
zfs:zfs 0666 root sys
+scsi_vhci:* 0666 root sys