changeset 12632:2e5ce9dbe1f9

6943556 need to enumerate fanboard, fanmodule, powerboard, and powermodules in storage enclosure
author Hyon Kim <Hyon.Kim@Sun.COM>
date Wed, 16 Jun 2010 07:19:49 -0700
parents 7312bbaa193c
children 9f2cda0ed938
files usr/src/lib/fm/topo/libtopo/common/hc.c usr/src/lib/fm/topo/libtopo/common/topo_hc.h usr/src/lib/fm/topo/modules/common/ses/ses.c usr/src/lib/scsi/libses/common/libses.h usr/src/lib/scsi/plugins/ses/SUN/common/sun.h usr/src/lib/scsi/plugins/ses/libses/Makefile.com usr/src/lib/scsi/plugins/ses/libses/common/mkelemtype.sh usr/src/lib/scsi/plugins/ses/ses2/common/ses2.h
diffstat 8 files changed, 604 insertions(+), 64 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/lib/fm/topo/libtopo/common/hc.c	Wed Jun 16 16:07:57 2010 +0200
+++ b/usr/src/lib/fm/topo/libtopo/common/hc.c	Wed Jun 16 07:19:49 2010 -0700
@@ -155,6 +155,7 @@
 	{ DRAM, TOPO_STABILITY_PRIVATE },
 	{ DRAMCHANNEL, TOPO_STABILITY_PRIVATE },
 	{ FAN, TOPO_STABILITY_PRIVATE },
+	{ FANBOARD, TOPO_STABILITY_PRIVATE },
 	{ FANMODULE, TOPO_STABILITY_PRIVATE },
 	{ HOSTBRIDGE, TOPO_STABILITY_PRIVATE },
 	{ INTERCONNECT, TOPO_STABILITY_PRIVATE },
@@ -176,6 +177,7 @@
 	{ PCIEX_ROOT, TOPO_STABILITY_PRIVATE },
 	{ PCIEX_SWUP, TOPO_STABILITY_PRIVATE },
 	{ PCIEX_SWDWN, TOPO_STABILITY_PRIVATE },
+	{ POWERBOARD, TOPO_STABILITY_PRIVATE },
 	{ POWERMODULE, TOPO_STABILITY_PRIVATE },
 	{ PSU, TOPO_STABILITY_PRIVATE },
 	{ RANK, TOPO_STABILITY_PRIVATE },
--- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h	Wed Jun 16 16:07:57 2010 +0200
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h	Wed Jun 16 07:19:49 2010 -0700
@@ -52,6 +52,7 @@
 #define	DRAM		"dram"
 #define	DRAMCHANNEL	"dram-channel"
 #define	FAN		"fan"
+#define	FANBOARD	"fanboard"
 #define	FANMODULE	"fanmodule"
 #define	HOSTBRIDGE	"hostbridge"
 #define	INTERCONNECT	"interconnect"
@@ -73,6 +74,7 @@
 #define	PCIEX_ROOT	"pciexrc"
 #define	PCIEX_SWUP	"pciexswu"
 #define	PCIEX_SWDWN	"pciexswd"
+#define	POWERBOARD	"powerboard"
 #define	POWERMODULE	"powermodule"
 #define	PSU		"psu"
 #define	RANK		"rank"
--- a/usr/src/lib/fm/topo/modules/common/ses/ses.c	Wed Jun 16 16:07:57 2010 +0200
+++ b/usr/src/lib/fm/topo/modules/common/ses/ses.c	Wed Jun 16 07:19:49 2010 -0700
@@ -46,6 +46,7 @@
 #include <sys/contract/device.h>
 #include <libsysevent.h>
 #include <sys/sysevent/eventdefs.h>
+#include <scsi/plugins/ses/vendor/sun.h>
 
 #include "disk.h"
 #include "ses.h"
@@ -60,6 +61,8 @@
 #define	SES_STATUS_UNAVAIL(s)	\
 	((s) == SES_ESC_UNSUPPORTED || (s) >= SES_ESC_NOT_INSTALLED)
 
+#define	HR_SECOND   1000000000
+
 /*
  * Because multiple SES targets can be part of a single chassis, we construct
  * our own hierarchy that takes this into account.  These SES targets may refer
@@ -109,13 +112,13 @@
 } ses_enum_data_t;
 
 typedef struct sas_connector_phy_data {
-	uint64_t    index;
-	uint64_t    phy_mask;
+	uint64_t    scpd_index;
+	uint64_t    scpd_pm;
 } sas_connector_phy_data_t;
 
 typedef struct sas_connector_type {
-	uint64_t    type;
-	char	    *name;
+	uint64_t    sct_type;
+	char	    *sct_name;
 } sas_connector_type_t;
 
 static const sas_connector_type_t sas_connector_type_list[] = {
@@ -157,6 +160,45 @@
 #define	SAS_CONNECTOR_TYPE_RESERVED \
 	"Connector type reserved by SES-2 standard"
 
+typedef struct phys_enum_type {
+	uint64_t    pet_type;
+	char	    *pet_nodename;
+	char	    *pet_defaultlabel;
+	boolean_t   pet_dorange;
+} phys_enum_type_t;
+
+static const phys_enum_type_t phys_enum_type_list[] = {
+	{   SES_ET_ARRAY_DEVICE, BAY, "BAY", B_TRUE  },
+	{   SES_ET_COOLING, FAN, "FAN", B_TRUE  },
+	{   SES_ET_DEVICE, BAY, "BAY", B_TRUE  },
+	{   SES_ET_ESC_ELECTRONICS, CONTROLLER, "CONTROLLER", B_TRUE  },
+	{   SES_ET_POWER_SUPPLY, PSU, "PSU", B_TRUE  },
+	{   SES_ET_SUNW_FANBOARD, FANBOARD, "FANBOARD", B_TRUE  },
+	{   SES_ET_SUNW_FANMODULE, FANMODULE, "FANMODULE", B_TRUE  },
+	{   SES_ET_SUNW_POWERBOARD, POWERBOARD, "POWERBOARD", B_TRUE  },
+	{   SES_ET_SUNW_POWERMODULE, POWERMODULE, "POWERMODULE", B_TRUE  }
+};
+
+#define	N_PHYS_ENUM_TYPES (sizeof (phys_enum_type_list) / \
+	sizeof (phys_enum_type_list[0]))
+
+/*
+ * Structure for the hierarchical tree for element nodes.
+ */
+typedef struct ses_phys_tree {
+    ses_node_t	*spt_snode;
+    ses_enum_node_t	*spt_senumnode;
+    boolean_t	spt_isfru;
+    uint64_t	spt_eonlyindex;
+    uint64_t	spt_cindex;
+    uint64_t	spt_pindex;
+    uint64_t	spt_maxinst;
+    struct ses_phys_tree    *spt_parent;
+    struct ses_phys_tree    *spt_child;
+    struct ses_phys_tree    *spt_sibling;
+    tnode_t	*spt_tnode;
+} ses_phys_tree_t;
+
 typedef enum {
 	SES_NEW_CHASSIS		= 0x1,
 	SES_NEW_SUBCHASSIS	= 0x2,
@@ -164,6 +206,7 @@
 	SES_DUP_SUBCHASSIS	= 0x8
 } ses_chassis_type_e;
 
+
 static const topo_pgroup_info_t storage_pgroup = {
 	TOPO_PGROUP_STORAGE,
 	TOPO_STABILITY_PRIVATE,
@@ -1258,8 +1301,9 @@
  * Callback to create a basic node (bay, psu, fan, or controller and expander).
  */
 static int
-ses_create_generic(ses_enum_data_t *sdp, ses_enum_node_t *snp,
-    tnode_t *pnode, const char *nodename, const char *labelname, tnode_t **node)
+ses_create_generic(ses_enum_data_t *sdp, ses_enum_node_t *snp, tnode_t *pnode,
+    tnode_t *frutn, const char *nodename, const char *labelname,
+    tnode_t **node)
 {
 	ses_node_t *np = snp->sen_node;
 	ses_node_t *parent;
@@ -1267,7 +1311,7 @@
 	topo_mod_t *mod = sdp->sed_mod;
 	nvlist_t *props, *aprops;
 	nvlist_t *auth = NULL, *fmri = NULL;
-	tnode_t *tn = NULL, *frutn = NULL;
+	tnode_t *tn = NULL;
 	char label[128];
 	int err;
 	char *part = NULL, *serial = NULL, *revision = NULL;
@@ -1348,16 +1392,6 @@
 	if (topo_node_label_set(tn, desc, &err) != 0)
 		goto error;
 
-	/*
-	 * For an expander node, set the FRU to its parent(controller).
-	 * For a connector node, set the FRU to its grand parent(controller).
-	 */
-	if (strcmp(nodename, SASEXPANDER) == 0) {
-		frutn = pnode;
-	} else if (strcmp(nodename, RECEPTACLE) == 0) {
-		frutn = topo_node_parent(pnode);
-	}
-
 	if (ses_set_standard_props(mod, frutn, tn, NULL, ses_node_id(np),
 	    snp->sen_target->set_devpath) != 0)
 		goto error;
@@ -1506,7 +1540,7 @@
 	}
 
 	/* update the ses property group with SES target info */
-	if ((topo_pgroup_create(tnode, &ses_pgroup, &err) == NULL) &&
+	if ((topo_pgroup_create(tnode, &ses_pgroup, &err) != 0) &&
 	    (err != ETOPO_PROP_DEFD)) {
 		/* SES prop group doesn't exist but failed to be created. */
 		topo_mod_dprintf(mod, "ses_set_expander_props: "
@@ -1717,14 +1751,14 @@
 		} else {
 			found = B_FALSE;
 			for (i = 0; ; i++) {
-				if (sas_connector_type_list[i].type ==
+				if (sas_connector_type_list[i].sct_type ==
 				    SAS_CONNECTOR_TYPE_CODE_NOT_DEFINED) {
 					break;
 				}
-				if (sas_connector_type_list[i].type ==
+				if (sas_connector_type_list[i].sct_type ==
 				    conntype) {
 					conntype_str =
-					    sas_connector_type_list[i].name;
+					    sas_connector_type_list[i].sct_name;
 					found = B_TRUE;
 					break;
 				}
@@ -1869,7 +1903,7 @@
 		 * element - binding to parent node and
 		 * allocating FMRI...
 		 */
-		if (ses_create_generic(sdp, xsnp, pnode, SASEXPANDER,
+		if (ses_create_generic(sdp, xsnp, pnode, pnode, SASEXPANDER,
 		    "SAS-EXPANDER", &exptn) != 0)
 			continue;
 		/*
@@ -1905,7 +1939,7 @@
 			if (cidxlist[i] != -1) {
 				/* connector index is valid. */
 				for (j = 0; j < count; j++) {
-					if (connectors[j].index ==
+					if (connectors[j].scpd_index ==
 					    cidxlist[i]) {
 						/*
 						 * Just update phy mask.
@@ -1913,8 +1947,8 @@
 						 * index lists(cidxlist index)
 						 * is set.
 						 */
-						connectors[j].phy_mask =
-						    connectors[j].phy_mask |
+						connectors[j].scpd_pm =
+						    connectors[j].scpd_pm |
 						    (1ULL << i);
 						break;
 					}
@@ -1925,9 +1959,10 @@
 				 */
 				if (j == count) {
 					/* add a new index and phy mask. */
-					connectors[count].index = cidxlist[i];
-					connectors[count].phy_mask =
-					    connectors[count].phy_mask |
+					connectors[count].scpd_index =
+					    cidxlist[i];
+					connectors[count].scpd_pm =
+					    connectors[count].scpd_pm |
 					    (1ULL << i);
 					count++;
 				}
@@ -1988,7 +2023,7 @@
 					    SES_PROP_ELEMENT_ONLY_INDEX,
 					    &conindex) == 0) {
 						if (conindex ==
-						    connectors[i].index) {
+						    connectors[i].scpd_index) {
 							found = B_TRUE;
 							break;
 						}
@@ -2000,13 +2035,14 @@
 			if (found) {
 				/* Create generic props. */
 				if (ses_create_generic(sdp, consnp, exptn,
+				    topo_node_parent(exptn),
 				    RECEPTACLE, "RECEPTACLE", &contn) !=
 				    0) {
 					continue;
 				}
 				/* Create connector specific props. */
 				if (ses_set_connector_props(sdp, consnp,
-				    contn, connectors[i].phy_mask) != 0) {
+				    contn, connectors[i].scpd_pm) != 0) {
 					continue;
 				}
 			}
@@ -2090,7 +2126,14 @@
 	for (snp = topo_list_next(&cp->sec_nodes); snp != NULL;
 	    snp = topo_list_next(snp)) {
 		if (snp->sen_type == type) {
-			if (ses_create_generic(sdp, snp, pnode,
+			/*
+			 * With flat layout of ses nodes there is no
+			 * way to find out the direct FRU for a node.
+			 * Passing NULL for fru topo node.  Note that
+			 * ses_create_children_from_phys_tree() provides
+			 * the actual direct FRU for a node.
+			 */
+			if (ses_create_generic(sdp, snp, pnode, NULL,
 			    nodename, defaultlabel, &tn) != 0)
 				return (-1);
 			/*
@@ -2251,6 +2294,407 @@
 }
 
 /*
+ * Function we use to insert a node.
+ */
+static int
+ses_phys_tree_insert(topo_mod_t *mod, ses_phys_tree_t **sproot,
+    ses_phys_tree_t *child)
+{
+	uint64_t ppindex, eindex, pindex;
+	ses_phys_tree_t *node_ptr;
+	int ret = 0;
+
+	assert(sproot != NULL);
+	assert(child != NULL);
+
+	if (*sproot == NULL) {
+		*sproot = child;
+		return (0);
+	}
+
+	pindex = child->spt_pindex;
+	ppindex = (*sproot)->spt_pindex;
+	eindex = (*sproot)->spt_eonlyindex;
+
+	/*
+	 * If the element only index of the root is same as the physical
+	 * parent index of a node to be added, add the node as a child of
+	 * the current root.
+	 */
+	if (eindex == pindex) {
+		(void) ses_phys_tree_insert(mod, &(*sproot)->spt_child, child);
+		child->spt_parent = *sproot;
+	} else if (ppindex == pindex) {
+		/*
+		 * if the physical parent of the current root and the child
+		 * is same, then this should be a sibling node.
+		 * Siblings can be different element types and arrange
+		 * them by group.
+		 */
+		if ((*sproot)->spt_senumnode->sen_type ==
+		    child->spt_senumnode->sen_type) {
+			child->spt_sibling = *sproot;
+			*sproot = child;
+		} else {
+			/* add a node in front of matching element type. */
+			node_ptr = *sproot;
+			while (node_ptr->spt_sibling != NULL) {
+				if (node_ptr->spt_sibling->
+				    spt_senumnode->sen_type ==
+				    child->spt_senumnode->sen_type) {
+					child->spt_sibling =
+					    node_ptr->spt_sibling;
+					node_ptr->spt_sibling = child;
+					break;
+				}
+				node_ptr = node_ptr->spt_sibling;
+			}
+			/* no matching.  Add the child at the end. */
+			if (node_ptr->spt_sibling == NULL) {
+				node_ptr->spt_sibling = child;
+			}
+		}
+		child->spt_parent = (*sproot)->spt_parent;
+	} else {
+		/*
+		 * The root and the node is not directly related.
+		 * Try to insert to the child sub-tree first and then try to
+		 * insert to the sibling sub-trees.  If fails for both
+		 * the caller will retry insertion later.
+		 */
+		if ((*sproot)->spt_child) {
+			ret = ses_phys_tree_insert(mod, &(*sproot)->spt_child,
+			    child);
+		}
+		if ((*sproot)->spt_child == NULL || ret != 0) {
+			if ((*sproot)->spt_sibling) {
+				ret = ses_phys_tree_insert(mod,
+				    &(*sproot)->spt_sibling, child);
+			} else {
+				ret = 1;
+			}
+		}
+		return (ret);
+	}
+	return (0);
+}
+
+/*
+ * Construct tree view of ses elements through parent phyiscal element index.
+ * The root of tree is already constructed using the enclosure element.
+ */
+static int
+ses_construct_phys_tree(ses_enum_data_t *sdp, ses_enum_chassis_t *cp,
+    ses_phys_tree_t *sproot)
+{
+	ses_enum_node_t *snp;
+	ses_phys_tree_t	*child;
+	ses_phys_tree_t	*u_watch = NULL;
+	ses_phys_tree_t	*u_head = NULL;
+	ses_phys_tree_t	*u_tail = NULL;
+	int u_inserted = 0, u_left = 0;
+	nvlist_t *props;
+	topo_mod_t *mod = sdp->sed_mod;
+
+	for (snp = topo_list_next(&cp->sec_nodes); snp != NULL;
+	    snp = topo_list_next(snp)) {
+		if ((child = topo_mod_zalloc(mod,
+		    sizeof (ses_phys_tree_t))) == NULL) {
+			topo_mod_dprintf(mod,
+			    "failed to allocate root.");
+			return (-1);
+		}
+		child->spt_snode = snp->sen_node;
+		props = ses_node_props(snp->sen_node);
+		if (nvlist_lookup_uint64(props,
+		    LIBSES_PROP_PHYS_PARENT, &child->spt_pindex) != 0) {
+			/*
+			 * the prop should exist. continue to see if
+			 * we can build a partial tree with other elements.
+			 */
+			topo_mod_dprintf(mod,
+			    "ses_construct_phys_tree(): Failed to find prop %s "
+			    "on ses element type %d and instance %d "
+			    "(CSN %s).", LIBSES_PROP_PHYS_PARENT,
+			    snp->sen_type, snp->sen_instance, cp->sec_csn);
+			topo_mod_free(mod, child, sizeof (ses_phys_tree_t));
+			continue;
+		} else {
+			if (nvlist_lookup_boolean_value(props,
+			    LIBSES_PROP_FRU, &child->spt_isfru) != 0) {
+				topo_mod_dprintf(mod,
+				    "ses_construct_phys_tree(): Failed to "
+				    "find prop %s on ses element type %d "
+				    "and instance %d (CSN %s).",
+				    LIBSES_PROP_FRU,
+				    snp->sen_type, snp->sen_instance,
+				    cp->sec_csn);
+				/*
+				 * Ignore if the prop doesn't exist.
+				 * Note that the enclosure itself should be
+				 * a FRU so if no FRU found the enclosure FRU
+				 * can be a direct FRU.
+				 */
+			}
+			verify(nvlist_lookup_uint64(props,
+			    SES_PROP_ELEMENT_ONLY_INDEX,
+			    &child->spt_eonlyindex) == 0);
+			verify(nvlist_lookup_uint64(props,
+			    SES_PROP_ELEMENT_CLASS_INDEX,
+			    &child->spt_cindex) == 0);
+		}
+		child->spt_senumnode = snp;
+		if (ses_phys_tree_insert(mod, &sproot, child) != 0) {
+			/* collect unresolved element to process later. */
+			if (u_head == NULL) {
+				u_head = child;
+				u_tail = child;
+			} else {
+				child->spt_sibling = u_head;
+				u_head = child;
+			}
+		}
+	}
+
+	/*
+	 * The parent of a child node may not be inserted yet.
+	 * Trying to insert the child until no child is left or
+	 * no child is not added further.  For the latter
+	 * the hierarchical relationship between elements
+	 * should be checked through SUNW,FRUID page.
+	 * u_watch is a watch dog to check the prgress of unresolved
+	 * node.
+	 */
+	u_watch = u_tail;
+	while (u_head) {
+		child = u_head;
+		u_head = u_head->spt_sibling;
+		if (u_head == NULL)
+			u_tail = NULL;
+		child->spt_sibling = NULL;
+		if (ses_phys_tree_insert(mod, &sproot, child) != 0) {
+			u_tail->spt_sibling = child;
+			u_tail = child;
+			if (child == u_watch) {
+				/*
+				 * We just scanned one round for the
+				 * unresolved list. Check to see whether we
+				 * have nodes inserted, if none, we should
+				 * break in case of an indefinite loop.
+				 */
+				if (u_inserted == 0) {
+					/*
+					 * Indicate there is unhandled node.
+					 * Chain free the whole unsolved
+					 * list here.
+					 */
+					u_left++;
+					break;
+				} else {
+					u_inserted = 0;
+					u_watch = u_tail;
+				}
+			}
+		} else {
+			/*
+			 * We just inserted one rpnode, increment the
+			 * unsolved_inserted counter. We will utilize this
+			 * counter to detect an indefinite insertion loop.
+			 */
+			u_inserted++;
+		}
+	}
+
+	/* check if there is left out unresolved nodes. */
+	if (u_left) {
+		topo_mod_dprintf(mod, "ses_construct_phys_tree(): "
+		    "Failed to construct physical view of the following "
+		    "ses elements of Chassis CSN %s.", cp->sec_csn);
+		while (u_head) {
+			u_tail = u_head->spt_sibling;
+			topo_mod_dprintf(mod,
+			    "\telement type (%d) and instance (%d)",
+			    u_head->spt_senumnode->sen_type,
+			    u_head->spt_senumnode->sen_instance);
+			topo_mod_free(mod, u_head, sizeof (ses_phys_tree_t));
+			u_head = u_tail;
+		}
+		return (-1);
+	}
+
+	return (0);
+}
+
+/*
+ * Free the whole phys tree.
+ */
+static void ses_phys_tree_free(topo_mod_t *mod, ses_phys_tree_t *sproot)
+{
+	if (sproot == NULL)
+		return;
+
+	/* Free child tree. */
+	if (sproot->spt_child) {
+		ses_phys_tree_free(mod, sproot->spt_child);
+	}
+
+	/* Free sibling trees. */
+	if (sproot->spt_sibling) {
+		ses_phys_tree_free(mod, sproot->spt_sibling);
+	}
+
+	/* Free root node itself. */
+	topo_mod_free(mod, sproot, sizeof (ses_phys_tree_t));
+}
+
+/*
+ * Parses phys_enum_type table to get the index of the given type.
+ */
+static boolean_t
+is_type_enumerated(ses_phys_tree_t *node, int *index)
+{
+	int i;
+
+	for (i = 0; i < N_PHYS_ENUM_TYPES; i++) {
+		if (node->spt_senumnode->sen_type ==
+		    phys_enum_type_list[i].pet_type) {
+			*index = i;
+			return (B_TRUE);
+		}
+	}
+	return (B_FALSE);
+}
+
+/*
+ * Recusrive routine for top-down enumeration of the tree.
+ */
+static int
+ses_enumerate_node(ses_enum_data_t *sdp, tnode_t *pnode, ses_enum_chassis_t *cp,
+    ses_phys_tree_t *parent, int mrange[])
+{
+	topo_mod_t *mod = sdp->sed_mod;
+	ses_phys_tree_t *child = NULL;
+	int i, ret = 0, ret_ch;
+	uint64_t prevtype = SES_ET_UNSPECIFIED;
+	ses_phys_tree_t *dirfru = NULL;
+	tnode_t *tn = NULL, *frutn = NULL;
+
+	if (parent == NULL) {
+		return (0);
+	}
+
+	for (child = parent->spt_child; child != NULL;
+	    child = child->spt_sibling) {
+		if (is_type_enumerated(child, &i)) {
+			if (prevtype != phys_enum_type_list[i].pet_type) {
+				/* check if range needs to be created. */
+				if (phys_enum_type_list[i].pet_dorange &&
+				    topo_node_range_create(mod, pnode,
+				    phys_enum_type_list[i].pet_nodename, 0,
+				    mrange[i]) != 0) {
+					topo_mod_dprintf(mod,
+					    "topo_node_create_range() failed: "
+					    "%s", topo_mod_errmsg(mod));
+					return (-1);
+				}
+				prevtype = phys_enum_type_list[i].pet_type;
+			}
+
+			if (!(child->spt_isfru)) {
+				for (dirfru = parent; dirfru != NULL;
+				    dirfru = dirfru->spt_parent) {
+					if (dirfru->spt_isfru) {
+						break;
+					}
+				}
+				/* found direct FRU node. */
+				if (dirfru) {
+					frutn = dirfru->spt_tnode;
+				} else {
+					frutn = NULL;
+				}
+			} else {
+				frutn = NULL;
+			}
+
+			if (ses_create_generic(sdp, child->spt_senumnode,
+			    pnode, frutn, phys_enum_type_list[i].pet_nodename,
+			    phys_enum_type_list[i].pet_defaultlabel, &tn) != 0)
+				return (-1);
+
+			child->spt_tnode = tn;
+			/*
+			 * For some SES element there may be protocol specific
+			 * information to process.   Here we are processing
+			 * the association between enclosure controller and
+			 * SAS expanders.
+			 */
+			if (phys_enum_type_list[i].pet_type ==
+			    SES_ET_ESC_ELECTRONICS) {
+				/* create SAS expander node */
+				if (ses_create_protocol_specific(sdp,
+				    child->spt_senumnode, tn,
+				    phys_enum_type_list[i].pet_type,
+				    cp, phys_enum_type_list[i].pet_dorange) !=
+				    0) {
+					return (-1);
+				}
+			}
+		} else {
+			continue;
+		}
+		ret_ch = ses_enumerate_node(sdp, tn, cp, child, mrange);
+		if (ret_ch)
+			ret = ret_ch; /* there was an error and set the ret. */
+	}
+
+	return (ret);
+}
+
+/*
+ * Instantiate types of nodes that are specified in the hierarchy
+ * element type list.
+ */
+static int
+ses_create_children_from_phys_tree(ses_enum_data_t *sdp, tnode_t *pnode,
+    ses_enum_chassis_t *cp, ses_phys_tree_t *phys_tree)
+{
+	topo_mod_t *mod = sdp->sed_mod;
+	int mrange[N_PHYS_ENUM_TYPES] = { 0 };
+	ses_enum_node_t *snp;
+	int i, ret;
+
+	/*
+	 * First get max range for each type of element to be enumerated.
+	 */
+	for (i = 0; i < N_PHYS_ENUM_TYPES; i++) {
+		if (phys_enum_type_list[i].pet_dorange) {
+			for (snp = topo_list_next(&cp->sec_nodes); snp != NULL;
+			    snp = topo_list_next(snp)) {
+				if (snp->sen_type ==
+				    phys_enum_type_list[i].pet_type) {
+					if (snp->sen_instance > mrange[i])
+						mrange[i] =
+						    snp->sen_instance;
+				}
+			}
+		}
+	}
+
+	topo_mod_dprintf(mod, "%s: creating nodes from FRU hierarchy tree.",
+	    cp->sec_csn);
+
+	if ((ret = ses_enumerate_node(sdp, pnode, cp, phys_tree, mrange)) !=
+	    0) {
+		topo_mod_dprintf(mod,
+		    "ses_create_children_from_phys_tree() failed: ");
+		return (ret);
+	}
+
+	return (0);
+}
+
+/*
  * Instantiate a new chassis instance in the topology.
  */
 static int
@@ -2271,7 +2715,11 @@
 	ses_enum_target_t *stp;
 	ses_enum_chassis_t *scp;
 	int i, err;
-	uint64_t sc_count = 0;
+	uint64_t sc_count = 0, pindex;
+	ses_phys_tree_t	*sproot = NULL;
+	hrtime_t start;
+	hrtime_t end;
+	double duration;
 
 	/*
 	 * Ignore any internal enclosures.
@@ -2398,22 +2846,95 @@
 		goto error;
 	}
 
-	/*
-	 * Create the nodes for power supplies, fans, controllers and devices.
-	 * Note that SAS exopander nodes and connector nodes are handled
-	 * through protocol specific processing of controllers.
-	 */
-	if (ses_create_children(sdp, tn, SES_ET_POWER_SUPPLY,
-	    PSU, "PSU", cp, B_TRUE) != 0 ||
-	    ses_create_children(sdp, tn, SES_ET_COOLING,
-	    FAN, "FAN", cp, B_TRUE) != 0 ||
-	    ses_create_children(sdp, tn, SES_ET_ESC_ELECTRONICS,
-	    CONTROLLER, "CONTROLLER", cp, B_TRUE) != 0 ||
-	    ses_create_children(sdp, tn, SES_ET_DEVICE,
-	    BAY, "BAY", cp, B_TRUE) != 0 ||
-	    ses_create_children(sdp, tn, SES_ET_ARRAY_DEVICE,
-	    BAY, "BAY", cp, B_TRUE) != 0)
-		goto error;
+	if (nvlist_lookup_uint64(props,
+	    LIBSES_PROP_PHYS_PARENT, &pindex) == 0) {
+		start = gethrtime(); /* to mearusre performance */
+		/*
+		 * The enclosure is supported through SUNW,FRUID.
+		 * Need to enumerate the nodes through hierarchical order.
+		 */
+		if ((sproot = topo_mod_zalloc(mod,
+		    sizeof (ses_phys_tree_t))) == NULL) {
+			topo_mod_dprintf(mod,
+			    "failed to allocate root: %s\n",
+			    topo_strerror(err));
+			goto error;
+		}
+		sproot->spt_pindex = pindex;
+		if (nvlist_lookup_boolean_value(props,
+		    LIBSES_PROP_FRU, &sproot->spt_isfru) != 0) {
+			topo_mod_dprintf(mod,
+			    "ses_create_chassis(): Failed to find prop %s "
+			    "on enclosure element (CSN %s).",
+			    LIBSES_PROP_FRU, cp->sec_csn);
+			/* an enclosure should be a FRU. continue to process. */
+			sproot->spt_isfru = B_TRUE;
+		}
+		if (nvlist_lookup_uint64(props,
+		    SES_PROP_ELEMENT_ONLY_INDEX,
+		    &sproot->spt_eonlyindex) != 0) {
+			topo_mod_dprintf(mod,
+			    "ses_create_chassis(): Failed to find prop %s "
+			    "on enclosure element (CSN %s).",
+			    LIBSES_PROP_PHYS_PARENT, cp->sec_csn);
+			topo_mod_free(mod, sproot, sizeof (ses_phys_tree_t));
+			goto error;
+		}
+		if (sproot->spt_pindex != sproot->spt_eonlyindex) {
+			topo_mod_dprintf(mod, "ses_create_chassis(): "
+			    "Enclosure element(CSN %s) should have "
+			    "itself as the parent to be the root node "
+			    "of FRU hierarchical tree.)", cp->sec_csn);
+			topo_mod_free(mod, sproot, sizeof (ses_phys_tree_t));
+			goto error;
+		} else {
+			sproot->spt_snode = cp->sec_enclosure;
+			sproot->spt_tnode = tn;
+			/* construct a tree. */
+			if (ses_construct_phys_tree(sdp, cp, sproot) != 0) {
+				topo_mod_dprintf(mod, "ses_create_chassis(): "
+				    "Failed to construct FRU hierarchical "
+				    "tree on enclosure (CSN %s.)",
+				    cp->sec_csn);
+			}
+
+			/* enumerate elements from the tree. */
+			if (ses_create_children_from_phys_tree(sdp, tn, cp,
+			    sproot) != 0) {
+				topo_mod_dprintf(mod, "ses_create_chassis(): "
+				    "Failed to create children topo nodes out "
+				    "of FRU hierarchical tree on enclosure "
+				    "(CSN %s).", cp->sec_csn);
+			}
+			/* destroy the phys tree. */
+			ses_phys_tree_free(mod, sproot);
+		}
+
+		end = gethrtime();
+		duration = end - start;
+		duration /= HR_SECOND;
+		topo_mod_dprintf(mod,
+		    "FRU boundary tree based enumeration: %.6f seconds",
+		    duration);
+	} else {
+		/*
+		 * Create the nodes for power supplies, fans, controllers and
+		 * devices.  Note that SAS exopander nodes and connector nodes
+		 * are handled through protocol specific processing of
+		 * controllers.
+		 */
+		if (ses_create_children(sdp, tn, SES_ET_POWER_SUPPLY,
+		    PSU, "PSU", cp, B_TRUE) != 0 ||
+		    ses_create_children(sdp, tn, SES_ET_COOLING,
+		    FAN, "FAN", cp, B_TRUE) != 0 ||
+		    ses_create_children(sdp, tn, SES_ET_ESC_ELECTRONICS,
+		    CONTROLLER, "CONTROLLER", cp, B_TRUE) != 0 ||
+		    ses_create_children(sdp, tn, SES_ET_DEVICE,
+		    BAY, "BAY", cp, B_TRUE) != 0 ||
+		    ses_create_children(sdp, tn, SES_ET_ARRAY_DEVICE,
+		    BAY, "BAY", cp, B_TRUE) != 0)
+			goto error;
+	}
 
 	if (cp->sec_maxinstance >= 0 &&
 	    (topo_node_range_create(mod, tn, SUBCHASSIS, 0,
@@ -2761,7 +3282,11 @@
 		    &type) == 0);
 		if (type != SES_ET_DEVICE &&
 		    type != SES_ET_ARRAY_DEVICE &&
+		    type != SES_ET_SUNW_FANBOARD &&
+		    type != SES_ET_SUNW_FANMODULE &&
 		    type != SES_ET_COOLING &&
+		    type != SES_ET_SUNW_POWERBOARD &&
+		    type != SES_ET_SUNW_POWERMODULE &&
 		    type != SES_ET_POWER_SUPPLY &&
 		    type != SES_ET_ESC_ELECTRONICS &&
 		    type != SES_ET_SAS_EXPANDER &&
--- a/usr/src/lib/scsi/libses/common/libses.h	Wed Jun 16 16:07:57 2010 +0200
+++ b/usr/src/lib/scsi/libses/common/libses.h	Wed Jun 16 07:19:49 2010 -0700
@@ -20,15 +20,12 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	_LIBSES_H
 #define	_LIBSES_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -45,6 +42,12 @@
 
 #define	LIBSES_VERSION	1
 
+/*
+ * element type prop can be created by any plugin.  The ses2 plugin created
+ * SES-2 defined element types and SUN plugin defines vendor specific types.
+ */
+#define	SES_PROP_ELEMENT_TYPE	"ses-element-type"
+
 typedef enum ses_node_type {
 	SES_NODE_NONE = 0x0,
 	SES_NODE_TARGET = 0x1,
--- a/usr/src/lib/scsi/plugins/ses/SUN/common/sun.h	Wed Jun 16 16:07:57 2010 +0200
+++ b/usr/src/lib/scsi/plugins/ses/SUN/common/sun.h	Wed Jun 16 07:19:49 2010 -0700
@@ -35,6 +35,13 @@
  */
 #define	SUN_DIAGPAGE_FRUID	SES2_DIAGPAGE_VENDOR_0
 
+typedef enum sun_element_type {
+	SES_ET_SUNW_FANMODULE = 0x90,
+	SES_ET_SUNW_POWERBOARD = 0x94,
+	SES_ET_SUNW_POWERMODULE = 0x95,
+	SES_ET_SUNW_FANBOARD = 0x96
+} sun_element_type;
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/lib/scsi/plugins/ses/libses/Makefile.com	Wed Jun 16 16:07:57 2010 +0200
+++ b/usr/src/lib/scsi/plugins/ses/libses/Makefile.com	Wed Jun 16 07:19:49 2010 -0700
@@ -32,8 +32,9 @@
 include ../../Makefile.lib
 
 SES2HDR =	$(ROOTPLUGINHDRDIR)/ses/framework/ses2.h
+SUNPLUGINHDR =	$(ROOTPLUGINHDRDIR)/ses/vendor/sun.h
 
 CLEANFILES +=	../common/libses_elemtype.c
 
-../common/libses_elemtype.c: ../common/mkelemtype.sh $(SES2HDR)
-	sh ../common/mkelemtype.sh < $(SES2HDR) > $@
+../common/libses_elemtype.c: ../common/mkelemtype.sh $(SES2HDR) $(SUNPLUGINHDR)
+	sh ../common/mkelemtype.sh $(SES2HDR) $(SUNPLUGINHDR) > $@
--- a/usr/src/lib/scsi/plugins/ses/libses/common/mkelemtype.sh	Wed Jun 16 16:07:57 2010 +0200
+++ b/usr/src/lib/scsi/plugins/ses/libses/common/mkelemtype.sh	Wed Jun 16 07:19:49 2010 -0700
@@ -21,31 +21,32 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
 
 echo "/*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident\t\"@(#)mkelemtype.sh\t1.1\t07/01/19 SMI\"
-
 #include <sys/types.h>
 #include <string.h>
 #include <scsi/libses.h>
+#include <scsi/plugins/ses/vendor/sun.h>
 
 static const struct {
-\tses2_element_type_t se_type;\t/* element type */
+\tint se_type;\t/* element type */
 \tconst char *se_name;\t\t/* element type name */
 } _ses_elemtypestr[] = {"
 
 pattern='^	\(SES_ET_\([A-Z0-9_]*\)\).*'
 replace='	{ \1, "\2" },'
+pattern2=', "SUNW_'
+replace2=', "'
 
-( sed -n "s/$pattern/$replace/p" ) || exit 1
+( for file in $*
+  do 
+    cat $file | sed -n "s/$pattern/$replace/p" | sed "s/$pattern2/$replace2/"
+  done ) || exit 1
 
 echo "\
 };\n\
--- a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2.h	Wed Jun 16 16:07:57 2010 +0200
+++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2.h	Wed Jun 16 07:19:49 2010 -0700
@@ -33,7 +33,6 @@
 /*
  * Node properties
  */
-#define	SES_PROP_ELEMENT_TYPE		"ses-element-type"
 typedef enum ses2_element_type {
 	SES_ET_UNSPECIFIED = 0,
 	SES_ET_DEVICE = 0x1,