summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
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