FWARC 2008/300 Sun4v FMA Platform Independent FMA Topology Enumeration
PSARC 2008/392 FMA new canonical hc names for sun4v_pi enumerator
PSARC 2008/440 sun4v Platform Independent Topology Enumerator - libmdesc extensions
6628827 Need platform independent topo enumeration for sun4v platforms
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/mdesc/mdesc_getproparcs.c Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,122 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/mdesc.h>
+#include <sys/mdesc_impl.h>
+
+static int md_find_node_arcs(md_impl_t *, mde_cookie_t, mde_str_cookie_t, int,
+ mde_cookie_t *, size_t);
+
+
+/*
+ * Return an array containing the node indexes for the arcs in
+ * the given node. The array is allocated using the allocator
+ * defined at machine description initialization time and the
+ * number of arcs found returned.
+ *
+ * Input Description
+ * ------------------- ----------------------------------------
+ * md_t * Pointer to md session
+ * mde_cookie_t Node containing arcs
+ * char * Arc name to count (e.g. "fwd" or "back")
+ * mde_cookie_t * Buffer to store indexes, or NULL
+ * size_t Size of buffer
+ *
+ * Output Description
+ * ------------------- ----------------------------------------
+ * int Count of arcs in node
+ */
+int
+md_get_prop_arcs(md_t *ptr, mde_cookie_t node, char *namep, mde_cookie_t *arcp,
+ size_t arcsize)
+{
+ int result;
+ mde_str_cookie_t prop_name;
+ md_impl_t *mdp;
+
+ mdp = (md_impl_t *)ptr;
+
+ if (node == MDE_INVAL_ELEM_COOKIE) {
+ return (-1);
+ }
+
+ prop_name = md_find_name(ptr, namep);
+ if (prop_name == MDE_INVAL_STR_COOKIE) {
+ return (-1);
+ }
+
+ result = md_find_node_arcs(mdp, node, prop_name, MDET_PROP_ARC, arcp,
+ arcsize);
+
+ return (result);
+}
+
+
+/*
+ * Find the number of arcs in the node of the requested prop_name. If storage
+ * is given in arcp, store the first arcsize number of node indexes.
+ */
+static int
+md_find_node_arcs(md_impl_t *mdp, mde_cookie_t node,
+ mde_str_cookie_t prop_name, int tag_type, mde_cookie_t *arcp,
+ size_t arcsize)
+{
+ int result;
+ md_element_t *mdep;
+ int idx;
+
+ /* Get the private node information from session data */
+ idx = (int)node;
+ mdep = &(mdp->mdep[idx]);
+
+ /* Make sure the cookie is in fact a node */
+ if (MDE_TAG(mdep) != MDET_NODE) {
+ return (-1);
+ }
+
+ /*
+ * Walk the elements in the node and find all the arcs of the
+ * requested type, and store them in an array.
+ */
+ result = 0;
+ for (idx++, mdep++; MDE_TAG(mdep) != MDET_NODE_END; idx++, mdep++) {
+ if ((MDE_TAG(mdep) == tag_type) &&
+ (MDE_NAME(mdep) == prop_name)) {
+ if (arcp != NULL && result < arcsize) {
+ arcp[result] =
+ (mde_cookie_t)MDE_PROP_INDEX(mdep);
+ }
+
+ /* Increment the count of arcs found */
+ result++;
+ }
+ }
+
+ /* Return the total count of arcs in the node */
+ return (result);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/mdesc/mdesc_walkdag.c Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,204 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef _KERNEL
+#include <sys/systm.h>
+#else
+#include <string.h>
+#include <strings.h>
+#endif
+
+#include <sys/mdesc.h>
+#include <sys/mdesc_impl.h>
+
+static int
+mdl_walk_dag(md_impl_t *, mde_cookie_t, mde_cookie_t, mde_str_cookie_t,
+ mde_str_cookie_t, uint8_t *, md_walk_fn_t, void *, int);
+
+
+/*
+ * Walk the machine description directed graph from a starting
+ * node searching for nodes of a given node name and using a
+ * given arc type. Call a callback function for each node found.
+ * Each node will be visited only once.
+ *
+ * Input Description
+ * ------------------- ----------------------------------------
+ * md_t * Pointer to md session
+ * mde_cookie_t Index of the starting node
+ * mde_str_cookie_t Node name cookie of the nodes to call
+ * the walk function
+ * mde_str_cookie_t Arc name cookie of the path to follow
+ * md_walk_fn_t The function to call for each node
+ * void * Private data to pass to the walker function
+ *
+ */
+int
+md_walk_dag(md_t *ptr, mde_cookie_t startnode,
+ mde_str_cookie_t node_name_cookie, mde_str_cookie_t arc_name_cookie,
+ md_walk_fn_t func, void *private)
+{
+ int res;
+ uint8_t *seenp;
+ md_impl_t *mdp;
+ mde_cookie_t start;
+
+ mdp = (md_impl_t *)ptr;
+ if (mdp == NULL) {
+ return (-1);
+ }
+
+ /*
+ * Possible the caller was lazy and didn't check the
+ * validitiy of either the node name or the arc name
+ * on calling ... in which case fail to find any
+ * nodes.
+ * This is distinct, from a fail (-1) since we return
+ * that nothing was found.
+ */
+ if (node_name_cookie == MDE_INVAL_STR_COOKIE ||
+ arc_name_cookie == MDE_INVAL_STR_COOKIE) {
+ return (0);
+ }
+
+ /*
+ * if we want to start at the top, start at index 0
+ */
+ start = startnode;
+ if (start == MDE_INVAL_ELEM_COOKIE) {
+ start = 0;
+ }
+
+ /*
+ * Scan from the start point until the first node.
+ */
+ while (start < mdp->element_count &&
+ MDE_TAG(&mdp->mdep[start]) == MDET_NULL) {
+ start++;
+ }
+
+ /*
+ * This was a bogus start point if no node found
+ */
+ if (MDE_TAG(&mdp->mdep[start]) != MDET_NODE) {
+ return (-1); /* illegal start node specified */
+ }
+
+ /*
+ * Allocate a recursion detection structure so we only visit
+ * each node once.
+ */
+ seenp = (uint8_t *)mdp->allocp(mdp->element_count);
+ if (seenp == NULL) {
+ return (-1);
+ }
+ (void) memset(seenp, 0, mdp->element_count);
+
+ /*
+ * Now build the list of requested nodes.
+ */
+ res = mdl_walk_dag(mdp, MDE_INVAL_ELEM_COOKIE, start,
+ node_name_cookie, arc_name_cookie, seenp, func, private, 0);
+
+ mdp->freep(seenp, mdp->element_count);
+
+ return (res >= 0 ? 0 : res);
+}
+
+
+static int
+mdl_walk_dag(md_impl_t *mdp, mde_cookie_t parentidx, mde_cookie_t nodeidx,
+ mde_str_cookie_t node_name_cookie, mde_str_cookie_t arc_name_cookie,
+ uint8_t *seenp, md_walk_fn_t func, void *private, int level)
+{
+ int result;
+ md_element_t *mdep;
+
+ /* Get the node element from the session */
+ mdep = &(mdp->mdep[nodeidx]);
+
+ /* see if cookie is infact a node */
+ if (MDE_TAG(mdep) != MDET_NODE) {
+ return (MDE_WALK_ERROR);
+ }
+
+ /* have we been here before ? */
+ if (seenp[nodeidx]) {
+ return (MDE_WALK_NEXT);
+ }
+ seenp[nodeidx] = 1;
+
+#ifdef DEBUG_LIBMDESC
+ {
+ int x;
+ for (x = 0; x < level; x++) {
+ printf("-");
+ }
+ printf("%d (%s)\n", nodeidx,
+ (char *)(mdp->datap + MDE_NAME(mdep)));
+ }
+#endif
+
+ /* is this node of the type we seek ? */
+ if (MDE_NAME(mdep) == node_name_cookie) {
+ /*
+ * Yes. Call the callback function.
+ */
+ result = (func)((md_t *)mdp, parentidx, nodeidx, private);
+ if (result != MDE_WALK_NEXT) {
+ return (result);
+ }
+ }
+
+ /*
+ * Simply walk the elements in the node.
+ * if we find a matching arc, then recursively call
+ * the subordinate looking for a match
+ */
+ result = MDE_WALK_NEXT;
+ for (mdep++; MDE_TAG(mdep) != MDET_NODE_END; mdep++) {
+ if (MDE_TAG(mdep) == MDET_PROP_ARC &&
+ MDE_NAME(mdep) == arc_name_cookie) {
+ /*
+ * The current node becomes the parent node, and the
+ * arc index is the new current node.
+ */
+ result = mdl_walk_dag(mdp, nodeidx, mdep->d.prop_idx,
+ node_name_cookie, arc_name_cookie, seenp, func,
+ private, level+1);
+ if (result != MDE_WALK_NEXT) {
+ /* The walk is complete or terminated. */
+ return (result);
+ }
+ }
+ }
+
+ return (result);
+}
--- a/usr/src/lib/fm/libmdesc/Makefile.com Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/lib/fm/libmdesc/Makefile.com Mon Jul 28 15:46:04 2008 -0700
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -32,11 +32,13 @@
mdesc_fini.c \
mdesc_findname.c \
mdesc_findnodeprop.c \
+ mdesc_getproparcs.c \
mdesc_getpropstr.c \
mdesc_getpropval.c \
mdesc_init_intern.c \
mdesc_nodecount.c \
- mdesc_scandag.c
+ mdesc_scandag.c \
+ mdesc_walkdag.c
OBJECTS = $(LIBSRCS:%.c=%.o)
--- a/usr/src/lib/fm/libmdesc/common/mapfile-vers Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/lib/fm/libmdesc/common/mapfile-vers Mon Jul 28 15:46:04 2008 -0700
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -30,11 +30,13 @@
md_find_name;
md_find_node_prop;
md_fini;
+ md_get_prop_arcs;
md_get_prop_str;
md_get_prop_val;
md_init_intern;
md_node_count;
md_scan_dag;
+ md_walk_dag;
local:
*;
};
--- a/usr/src/lib/fm/topo/libtopo/common/hc.c Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/hc.c Mon Jul 28 15:46:04 2008 -0700
@@ -107,18 +107,22 @@
{ HC, FM_FMRI_SCHEME_HC, HC_VERSION, &hc_ops };
static const hcc_t hc_canon[] = {
+ { BANK, TOPO_STABILITY_PRIVATE },
{ BAY, TOPO_STABILITY_PRIVATE },
+ { BLADE, TOPO_STABILITY_PRIVATE },
{ BRANCH, TOPO_STABILITY_PRIVATE },
{ CMP, TOPO_STABILITY_PRIVATE },
{ CENTERPLANE, TOPO_STABILITY_PRIVATE },
{ CHASSIS, TOPO_STABILITY_PRIVATE },
{ CHIP, TOPO_STABILITY_PRIVATE },
{ CHIP_SELECT, TOPO_STABILITY_PRIVATE },
+ { CORE, TOPO_STABILITY_PRIVATE },
{ CONTROLLER, TOPO_STABILITY_PRIVATE },
{ CPU, TOPO_STABILITY_PRIVATE },
{ CPUBOARD, TOPO_STABILITY_PRIVATE },
{ DIMM, TOPO_STABILITY_PRIVATE },
{ DISK, TOPO_STABILITY_PRIVATE },
+ { DRAM, TOPO_STABILITY_PRIVATE },
{ DRAMCHANNEL, TOPO_STABILITY_PRIVATE },
{ FAN, TOPO_STABILITY_PRIVATE },
{ FANMODULE, TOPO_STABILITY_PRIVATE },
@@ -126,7 +130,9 @@
{ INTERCONNECT, TOPO_STABILITY_PRIVATE },
{ IOBOARD, TOPO_STABILITY_PRIVATE },
{ MEMBOARD, TOPO_STABILITY_PRIVATE },
+ { MEMORYBUFFER, TOPO_STABILITY_PRIVATE },
{ MEMORYCONTROL, TOPO_STABILITY_PRIVATE },
+ { MICROCORE, TOPO_STABILITY_PRIVATE },
{ MOTHERBOARD, TOPO_STABILITY_PRIVATE },
{ NIU, TOPO_STABILITY_PRIVATE },
{ NIUFN, TOPO_STABILITY_PRIVATE },
@@ -142,6 +148,8 @@
{ POWERMODULE, TOPO_STABILITY_PRIVATE },
{ PSU, TOPO_STABILITY_PRIVATE },
{ RANK, TOPO_STABILITY_PRIVATE },
+ { RISER, TOPO_STABILITY_PRIVATE },
+ { SHELF, TOPO_STABILITY_PRIVATE },
{ SES_ENCLOSURE, TOPO_STABILITY_PRIVATE },
{ SYSTEMBOARD, TOPO_STABILITY_PRIVATE },
{ XAUI, TOPO_STABILITY_PRIVATE },
--- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h Mon Jul 28 15:46:04 2008 -0700
@@ -36,18 +36,22 @@
/*
* Allowable hardware component names for hc FMRIs
*/
+#define BANK "bank"
#define BAY "bay"
+#define BLADE "blade"
#define BRANCH "branch"
#define CMP "CMP"
#define CENTERPLANE "centerplane"
#define CHASSIS "chassis"
#define CHIP "chip"
#define CHIP_SELECT "chip-select"
+#define CORE "core"
#define CONTROLLER "controller"
#define CPU "cpu"
#define CPUBOARD "cpuboard"
#define DIMM "dimm"
#define DISK "disk"
+#define DRAM "dram"
#define DRAMCHANNEL "dram-channel"
#define FAN "fan"
#define FANMODULE "fanmodule"
@@ -55,7 +59,9 @@
#define INTERCONNECT "interconnect"
#define IOBOARD "ioboard"
#define MEMBOARD "memboard"
+#define MEMORYBUFFER "memory-buffer"
#define MEMORYCONTROL "memory-controller"
+#define MICROCORE "micro-core"
#define MOTHERBOARD "motherboard"
#define NIU "niu"
#define NIUFN "niufn"
@@ -71,6 +77,8 @@
#define POWERMODULE "powermodule"
#define PSU "psu"
#define RANK "rank"
+#define RISER "riser"
+#define SHELF "shelf"
#define SES_ENCLOSURE "ses-enclosure"
#define SYSTEMBOARD "systemboard"
#define XAUI "xaui"
--- a/usr/src/lib/fm/topo/maps/sun4v/sun4v-hc-topology.xml Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/lib/fm/topo/maps/sun4v/sun4v-hc-topology.xml Mon Jul 28 15:46:04 2008 -0700
@@ -27,16 +27,8 @@
-->
<topology name='sun4v' scheme='hc'>
- <range name='motherboard' min='0' max='0'>
- <enum-method name='motherboard' version='1'/>
- <dependents grouping='children'>
- <range name='chip' min='0' max='32'>
- <enum-method name='chip' version='1' />
- </range>
- <range name='hostbridge' min='0' max='254'>
- <enum-method name='hostbridge' version='1' />
- </range>
- </dependents>
+ <range name='chassis' min='0' max='0'>
+ <enum-method name='sun4vpi' version='1' />
</range>
<range name='ses-enclosure' min='0' max='1024'>
<enum-method name='ses' version='1' />
--- a/usr/src/lib/fm/topo/modules/sun4v/Makefile Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/lib/fm/topo/modules/sun4v/Makefile Mon Jul 28 15:46:04 2008 -0700
@@ -34,6 +34,7 @@
niu \
platform-cpu \
platform-mem \
+ sun4vpi \
xaui \
zambezi
--- a/usr/src/lib/fm/topo/modules/sun4v/pcibus/Makefile Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/lib/fm/topo/modules/sun4v/pcibus/Makefile Mon Jul 28 15:46:04 2008 -0700
@@ -20,7 +20,7 @@
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -29,3 +29,4 @@
ARCH = sun4v
include ../../sun4/pcibus/Makefile.pci
+LDLIBS += -ldevinfo
--- a/usr/src/lib/fm/topo/modules/sun4v/pcibus/pci_sun4v.c Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/lib/fm/topo/modules/sun4v/pcibus/pci_sun4v.c Mon Jul 28 15:46:04 2008 -0700
@@ -29,6 +29,10 @@
#include <fm/topo_mod.h>
#include <sys/fm/protocol.h>
#include <string.h>
+#include <alloca.h>
+#include <libdevinfo.h>
+#include <did_props.h>
+
/*
* Including the following file gives us definitions of the three
* global arrays used to adjust labels, Slot_Rewrites, Physlot_Names,
@@ -36,15 +40,62 @@
* routines for pci.
*/
#include "pci_sun4v.h"
+#include "pci_sun4.h"
-#include "pci_sun4.h"
+#define PI_PROP_CHASSIS_LOCATION_NAME "chassis-location-name"
+
+typedef struct _pci_fru {
+ tnode_t *node;
+ char *location;
+ int locsiz;
+} _pci_fru_t;
+
+
+static int platform_pci_fru_location(topo_mod_t *, tnode_t *, uchar_t *, int);
+static int platform_pci_fru_cb(topo_mod_t *, tnode_t *, void *);
+
int
platform_pci_label(topo_mod_t *mod, tnode_t *node, nvlist_t *in,
nvlist_t **out)
{
- return (pci_label_cmn(mod, node, in, out));
+ int result;
+ int err;
+ int locsiz = 0;
+ uchar_t *loc = NULL;
+ char *nac = NULL;
+
+ topo_mod_dprintf(mod, "entering platform_pci_label\n");
+
+ *out = NULL;
+ result = di_bytes_get(mod, topo_node_getspecific(node),
+ PI_PROP_CHASSIS_LOCATION_NAME, &locsiz, &loc);
+ if (result == -1 || locsiz < 0) {
+ topo_mod_dprintf(mod, "platform_pci_label: %s not found (%s)\n",
+ PI_PROP_CHASSIS_LOCATION_NAME, strerror(errno));
+
+ /* Invoke the generic label generator for this node */
+ return (pci_label_cmn(mod, node, in, out));
+ }
+
+ /*
+ * We have crossed a FRU boundary. Use the value in the
+ * chassis-location-name property as the node label.
+ */
+ nac = alloca(locsiz+1);
+ (void) memset(nac, 0, locsiz+1);
+ (void) memcpy(nac, loc, locsiz);
+ result = topo_node_label_set(node, nac, &err);
+ if (result < 0) {
+ if (err != ETOPO_PROP_NOENT) {
+ return (topo_mod_seterrno(mod, err));
+ }
+ }
+
+ return (0);
}
+
+
int
platform_pci_fru(topo_mod_t *mod, tnode_t *node, nvlist_t *in,
nvlist_t **out)
@@ -56,6 +107,8 @@
char *nm, *plat, *pp, **cp;
const char *label;
int found_t1plat = 0;
+ uchar_t *loc;
+ int locsiz;
topo_mod_dprintf(mod, "entering platform_pci_fru\n");
@@ -119,7 +172,94 @@
*out = rnvl;
}
return (0);
+ } else if (di_bytes_get(mod, topo_node_getspecific(node),
+ PI_PROP_CHASSIS_LOCATION_NAME, &locsiz, &loc) == 0 && locsiz > 0) {
+ /*
+ * We have crossed a FRU boundary and need to find the parent
+ * node with this location and set our FMRI to that value.
+ */
+ return (platform_pci_fru_location(mod, node, loc, locsiz));
} else {
return (pci_fru_compute(mod, node, in, out));
}
}
+
+
+static int
+platform_pci_fru_location(topo_mod_t *mod, tnode_t *node, uchar_t *loc,
+ int locsiz)
+{
+ int err;
+ tnode_t *parent;
+ tnode_t *top;
+ topo_walk_t *wp;
+ _pci_fru_t walkdata;
+
+ topo_mod_dprintf(mod, "entering platform_pci_fru_location\n");
+
+ /* Find the root node */
+ top = node;
+ while ((parent = topo_node_parent(top)) != NULL) {
+ top = parent;
+ }
+ walkdata.node = node;
+ walkdata.locsiz = locsiz;
+ walkdata.location = alloca(locsiz+1);
+ (void) memset(walkdata.location, 0, locsiz+1);
+ (void) memcpy(walkdata.location, loc, locsiz);
+
+ /* Create a walker starting at the root node */
+ wp = topo_mod_walk_init(mod, top, platform_pci_fru_cb, &walkdata, &err);
+ if (wp == NULL) {
+ return (topo_mod_seterrno(mod, err));
+ }
+
+ /*
+ * Walk the tree breadth first to hopefully avoid visiting too many
+ * nodes while searching for the node with the appropriate FMRI.
+ */
+ (void) topo_walk_step(wp, TOPO_WALK_SIBLING);
+ topo_walk_fini(wp);
+
+ return (0);
+}
+
+
+static int
+platform_pci_fru_cb(topo_mod_t *mod, tnode_t *node, void *private)
+{
+ int err;
+ _pci_fru_t *walkdata = (_pci_fru_t *)private;
+ nvlist_t *fmri;
+ char *location;
+ int result, rc;
+
+ if (node == walkdata->node) {
+ /* This is the starting node. Do not check the location */
+ return (TOPO_WALK_NEXT);
+ }
+
+ if (topo_node_label(node, &location, &err) != 0) {
+ /* This node has no location property. Continue the walk */
+ return (TOPO_WALK_NEXT);
+ }
+
+ result = TOPO_WALK_NEXT;
+ if (strncmp(location, walkdata->location, walkdata->locsiz) == 0) {
+ /*
+ * We have a match. Set the node's FRU FMRI to this nodes
+ * FRU FMRI
+ */
+ rc = topo_node_fru(node, &fmri, NULL, &err);
+ if (rc == 0) {
+ rc = topo_node_fru_set(walkdata->node, fmri, 0, &err);
+ nvlist_free(fmri);
+ }
+ if (rc != 0) {
+ result = TOPO_WALK_TERMINATE;
+ topo_mod_seterrno(mod, err);
+ }
+ }
+ topo_mod_strfree(mod, location);
+ return (result);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/Makefile Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,46 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+MODULE = sun4vpi
+ARCH = sun4v
+CLASS = arch
+TOPODIR = ../../../libtopo/common
+
+MODULESRCS = pi_defer.c pi_ldom.c pi_walker.c pi_subr.c \
+ pi_cpu.c pi_generic.c pi_pciexrc.c pi_niu.c pi_top.c \
+ sun4vpi.c
+
+include ../../Makefile.plugin
+
+LDLIBS += -ldevinfo -lmdesc -lldom -luutil
+
+CPPFLAGS += -I. -I$(ROOT)/usr/platform/sun4v/include -I$(TOPODIR)
+
+%.o: ../../../../../common/mdesc/%.c
+ $(COMPILE.c) $<
+ $(CTFCONVERT_O)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_cpu.c Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,165 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Enumerate a CPU node
+ */
+#include <sys/types.h>
+#include <strings.h>
+#include <sys/fm/protocol.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include "pi_impl.h"
+
+#define _ENUM_NAME "enum_cpu"
+
+typedef struct cpuwalk_s {
+ topo_mod_t *mod;
+ char *serial;
+} cpuwalk_t;
+
+static int pi_enum_cpu_serial(topo_mod_t *, md_t *, mde_cookie_t, char **);
+static int pi_enum_cpu_serial_cb(md_t *, mde_cookie_t, mde_cookie_t, void *);
+
+int
+pi_enum_cpu(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+ topo_instance_t inst, tnode_t *t_parent, const char *hc_name,
+ tnode_t **t_node)
+{
+ int result;
+ int err;
+ int cpumask;
+ nvlist_t *asru = NULL;
+ char *serial = NULL;
+
+ *t_node = NULL;
+
+ /*
+ * Create the basic topology node for the CPU using the generic
+ * enumerator.
+ */
+ result = pi_enum_generic_impl(mod, mdp, mde_node, inst, t_parent,
+ t_parent, hc_name, _ENUM_NAME, t_node);
+ if (result != 0) {
+ /* Error messages are printed by the generic routine */
+ return (result);
+ }
+
+ /*
+ * Get the parameters required to create an FMRI. The cpumask is
+ * on the chip itself and while it may be part of an ereport
+ * payload is unavailable here, so we set it to zero.
+ */
+ cpumask = 0;
+
+ /*
+ * Find the serial number, which is on the "chip" node, not the
+ * "cpu" node.
+ */
+ result = pi_enum_cpu_serial(mod, mdp, mde_node, &serial);
+ if (result != 0 || serial == NULL) {
+ topo_mod_dprintf(mod, "%s node_0x%llx failed to find serial "
+ "number.\n", _ENUM_NAME, (uint64_t)mde_node);
+ return (result);
+ }
+
+ /* Create a CPU scheme FMRI and set it as the ASRU for the CPU node */
+ asru = topo_mod_cpufmri(mod, FM_CPU_SCHEME_VERSION, inst, cpumask,
+ serial);
+ topo_mod_strfree(mod, serial);
+ if (asru == NULL) {
+ topo_mod_dprintf(mod,
+ "%s node_0x%llx failed to compute cpu scheme ASRU: %s\n",
+ _ENUM_NAME, (uint64_t)mde_node,
+ topo_strerror(topo_mod_errno(mod)));
+ return (-1);
+ }
+
+ /* Set the ASRU on the node without flags (the 0) */
+ result = topo_node_asru_set(*t_node, asru, 0, &err);
+ nvlist_free(asru);
+ if (result != 0) {
+ topo_mod_dprintf(mod,
+ "%s node_0x%llx failed to set ASRU: %s\n", _ENUM_NAME,
+ (uint64_t)mde_node, topo_strerror(err));
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+static int
+pi_enum_cpu_serial(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+ char **serial)
+{
+ int result;
+ cpuwalk_t args;
+ mde_str_cookie_t component_cookie;
+ mde_str_cookie_t back_cookie;
+
+ args.mod = mod;
+ args.serial = NULL;
+
+ /*
+ * Search backwards through the PRI graph, starting at the current
+ * strand (aka cpu) mde_node, and find the MD_STR_CHIP node. This
+ * node has the serial number for the cpu.
+ */
+ component_cookie = md_find_name(mdp, MD_STR_COMPONENT);
+ back_cookie = md_find_name(mdp, MD_STR_BACK);
+
+ result = md_walk_dag(mdp, mde_node, component_cookie, back_cookie,
+ pi_enum_cpu_serial_cb, (void *)&args);
+ *serial = args.serial;
+
+ return (result);
+}
+
+
+/*ARGSUSED*/
+static int
+pi_enum_cpu_serial_cb(md_t *mdp, mde_cookie_t mde_parent,
+ mde_cookie_t mde_node, void *private)
+{
+ char *hc_name;
+ cpuwalk_t *args = (cpuwalk_t *)private;
+
+ if (args == NULL) {
+ return (MDE_WALK_ERROR);
+ }
+ args->serial = NULL;
+
+ hc_name = pi_get_topo_hc_name(args->mod, mdp, mde_node);
+ if (hc_name != NULL && strcmp(hc_name, MD_STR_CHIP) == 0) {
+ args->serial = pi_get_serial(args->mod, mdp, mde_node);
+ }
+ topo_mod_strfree(args->mod, hc_name);
+
+ return ((args->serial == NULL ? MDE_WALK_NEXT : MDE_WALK_DONE));
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_defer.c Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,238 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Some topology creation routines may need to defer completing enumeration
+ * until after the entire PRI graph has been visited. This file includes
+ * the interfaces necessary to permit these routines to do this in a general
+ * way.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <strings.h>
+#include <string.h>
+#include <libuutil.h>
+#include <libnvpair.h>
+#include <sys/mdesc.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include "pi_impl.h"
+
+static uu_list_pool_t *defer_pool;
+static uu_list_t *defer_list;
+
+struct pi_defernode_s {
+ uu_list_node_t defer_node;
+
+ mde_cookie_t mde_node; /* MDE node index */
+ tnode_t *t_parent; /* Parent topology node */
+ tnode_t *t_node; /* Topo node associated with MDE node */
+ void *private; /* Private data for defer routine */
+
+ pi_deferenum_fn_t *func; /* Defered enumeration routine */
+};
+typedef struct pi_defernode_s pi_defernode_t;
+
+/* Routines to handle the list of topology parents and mde_nodes */
+static int pi_deferlist_create(topo_mod_t *);
+static int pi_deferlist_compare(const void *, const void *, void *);
+
+
+/*
+ * Add a new routine to the list of deferred enumeration routines
+ */
+int
+pi_defer_add(topo_mod_t *mod, mde_cookie_t mde_node, tnode_t *t_parent,
+ tnode_t *t_node, pi_deferenum_fn_t func, void *private)
+{
+ int result;
+ uu_list_index_t idx;
+ pi_defernode_t *dnp;
+
+ if (defer_list == NULL) {
+ result = pi_deferlist_create(mod);
+ if (result != 0) {
+ return (result);
+ }
+ }
+
+ /*
+ * Create a data structure to store information about the node for
+ * which to defer enumeration. The defer_pool is created by the
+ * list creation routine, above.
+ */
+ dnp = topo_mod_zalloc(mod, sizeof (pi_defernode_t));
+ if (dnp == NULL) {
+ topo_mod_seterrno(mod, EMOD_NOMEM);
+ return (-1);
+ }
+ uu_list_node_init(dnp, &(dnp->defer_node), defer_pool);
+
+ dnp->mde_node = mde_node;
+ dnp->t_parent = t_parent;
+ dnp->t_node = t_node;
+ dnp->private = private;
+ dnp->func = func;
+
+ (void) uu_list_find(defer_list, dnp, NULL, &idx);
+ uu_list_insert(defer_list, dnp, idx);
+
+ return (0);
+}
+
+
+/*
+ * Execute the list of deferred enumeration routines, destroying the list as
+ * we go.
+ */
+int
+pi_defer_exec(topo_mod_t *mod, md_t *mdp)
+{
+ int result;
+
+ void *dvp;
+ pi_defernode_t *dp;
+ topo_instance_t inst;
+ mde_cookie_t mde_node;
+ tnode_t *t_parent;
+ tnode_t *t_node;
+ void *private;
+ char *hc_name;
+
+ pi_deferenum_fn_t *func;
+
+ topo_mod_dprintf(mod, "beginning deferred enumerator execution\n");
+ if (defer_list == NULL) {
+ topo_mod_dprintf(mod, "no deferred enumerators. done.\n");
+ return (0);
+ }
+
+ while ((dvp = uu_list_first(defer_list)) != NULL) {
+ /* Extract the necessary information from the defernode_t */
+ dp = (pi_defernode_t *)dvp;
+ mde_node = dp->mde_node;
+ t_parent = dp->t_parent;
+ t_node = dp->t_node;
+ private = dp->private;
+ func = dp->func;
+
+ /*
+ * Remove the element from the list. Once we are done calling
+ * the routine we do not need it any more.
+ */
+ uu_list_remove(defer_list, dvp);
+ uu_list_node_fini(dp, &(dp->defer_node), defer_pool);
+ topo_mod_free(mod, dp, sizeof (pi_defernode_t));
+
+ /* Get the instance value from the mde node */
+ if (pi_get_instance(mod, mdp, mde_node, &inst) != 0) {
+ topo_mod_dprintf(mod, "deferred node_0x%llx invalid\n",
+ (uint64_t)mde_node);
+
+ /* Move on to the next node */
+ topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+ continue;
+ }
+
+ /* Get the hc name from the mde node */
+ hc_name = pi_get_topo_hc_name(mod, mdp, mde_node);
+ if (hc_name == NULL) {
+ topo_mod_dprintf(mod,
+ "deferred node_0x%llx has invalid NULL hc_name\n",
+ (uint64_t)mde_node);
+
+ /* Move on to the next node */
+ topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+ continue;
+ }
+ topo_mod_dprintf(mod,
+ "calling deferred enumerator for node_0x%llx\n",
+ (uint64_t)mde_node);
+
+ /* Call the deferred enumeration function */
+ result = (func)(mod, mdp, mde_node, inst, t_parent, hc_name,
+ t_node, private);
+ if (result != 0) {
+ topo_mod_dprintf(mod,
+ "deferred enumeration for node_0x%llx failed\n",
+ (uint64_t)mde_node);
+ topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+ }
+
+ /* Clean up from the deferred call */
+ topo_mod_strfree(mod, hc_name);
+ }
+ topo_mod_dprintf(mod, "deferred enumeration completed.\n");
+
+ uu_list_destroy(defer_list);
+ uu_list_pool_destroy(defer_pool);
+
+ return (0);
+}
+
+
+static int
+pi_deferlist_create(topo_mod_t *mod)
+{
+ /* Initialize the uutil list structure */
+ defer_pool = uu_list_pool_create("pi_defer_pool",
+ sizeof (pi_defernode_t), offsetof(pi_defernode_t, defer_node),
+ pi_deferlist_compare, 0);
+ if (defer_pool == NULL) {
+ topo_mod_seterrno(mod, EMOD_NOMEM);
+ return (-1);
+ }
+ defer_list = uu_list_create(defer_pool, NULL, 0);
+ if (defer_list == NULL) {
+ uu_list_pool_destroy(defer_pool);
+ topo_mod_seterrno(mod, EMOD_NOMEM);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+/* ARGSUSED */
+static int
+pi_deferlist_compare(const void *l_arg, const void *r_arg, void *private)
+{
+ pi_defernode_t *lp = (pi_defernode_t *)l_arg;
+ pi_defernode_t *rp = (pi_defernode_t *)r_arg;
+
+ if (lp->func != rp->func) {
+ return (1);
+ }
+ if (lp->t_parent != rp->t_parent) {
+ return (-1);
+ }
+ return (0);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_generic.c Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,111 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Create a generic topology node for a given PRI node.
+ */
+#include <sys/types.h>
+#include <strings.h>
+#include <sys/fm/protocol.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include "pi_impl.h"
+
+#define _ENUM_NAME "enum_generic"
+
+int
+pi_enum_generic(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+ topo_instance_t inst, tnode_t *t_parent, const char *hc_name,
+ tnode_t **t_node)
+{
+ int result;
+
+ /*
+ * For a generic node that is not a top-level node, we use the
+ * same parent topology node to generate the FMRI as well as
+ * to bind the new node.
+ */
+ result = pi_enum_generic_impl(mod, mdp, mde_node, inst, t_parent,
+ t_parent, hc_name, _ENUM_NAME, t_node);
+
+ return (result);
+}
+
+
+/*
+ * Create a generic topo node based on the PRI information in the machine
+ * description information.
+ */
+int
+pi_enum_generic_impl(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+ topo_instance_t inst, tnode_t *t_bindparent, tnode_t *t_fmriparent,
+ const char *hc_name, const char *enum_name, tnode_t **t_node)
+{
+ nvlist_t *fmri;
+ nvlist_t *auth;
+
+ topo_mod_dprintf(mod, "%s adding entry for node_0x%llx type %s\n",
+ enum_name, (uint64_t)mde_node, hc_name);
+
+ if (t_bindparent == NULL) {
+ topo_mod_dprintf(mod,
+ "%s called with NULL parent for node_0x%llx type %s\n",
+ enum_name, (uint64_t)mde_node, hc_name);
+ return (-1);
+ }
+
+ /* Create the FMRI for this node */
+ auth = topo_mod_auth(mod, t_bindparent);
+ fmri = topo_mod_hcfmri(mod, t_fmriparent, FM_HC_SCHEME_VERSION, hc_name,
+ inst, NULL, auth, NULL, NULL, NULL);
+ if (fmri == NULL) {
+ topo_mod_dprintf(mod,
+ "%s failed to create fmri node_0x%llx: %s\n", enum_name,
+ (uint64_t)mde_node, topo_strerror(topo_mod_errno(mod)));
+ nvlist_free(auth);
+ return (-1);
+ }
+
+ /* Bind this node to the parent */
+ *t_node = pi_node_bind(mod, mdp, mde_node, t_bindparent, hc_name, inst,
+ fmri);
+ nvlist_free(fmri);
+ nvlist_free(auth);
+ if (*t_node == NULL) {
+ topo_mod_dprintf(mod,
+ "%s failed to bind node_0x%llx instance %d: %s\n",
+ enum_name, (uint64_t)mde_node, (uint32_t)inst,
+ topo_strerror(topo_mod_errno(mod)));
+ return (-1);
+ }
+
+ topo_mod_dprintf(mod, "%s added node_0x%llx type %s\n",
+ enum_name, (uint64_t)mde_node, hc_name);
+
+ return (0);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_impl.h Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,165 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PI_IMPL_H
+#define _PI_IMPL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SUN4V Platform Independent Enumerator private interfaces
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <pthread.h>
+#include <libuutil.h>
+#include <sys/mdesc.h>
+#include <sys/fm/ldom.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+
+/* Definitions used when registering the enumerator with libtopo */
+#define SUN4VPI_DESC "SUN4V Platform independent topology enumerator"
+#define SUN4VPI_SCHEME "hc"
+#define SUN4VPI_VERSION TOPO_VERSION
+
+/* Definitions used when working with PRI machine description nodes */
+#define MD_STR_BACK "back"
+#define MD_STR_CFG_HANDLE "cfg-handle" /* FWARC/2008/300 */
+#define MD_STR_CHIP "chip"
+#define MD_STR_COMPONENT "component" /* FWARC/2006/700 */
+#define MD_STR_CHASSIS "chassis"
+#define MD_STR_COMPONENTS "components" /* FWARC/2006/700 */
+#define MD_STR_DASH_NUMBER "dash_number" /* FWARC/2006/700 */
+#define MD_STR_FRU "fru" /* FWARC/2006/700 */
+#define MD_STR_FWD "fwd"
+#define MD_STR_ID "id" /* FWARC/2008/300 */
+#define MD_STR_NAC "nac" /* FWARC/2008/300 */
+#define MD_STR_NAME "name"
+#define MD_STR_PART_NUMBER "part_number" /* FWARC/2008/300 */
+#define MD_STR_PLATFORM "platform"
+#define MD_STR_REVISION_NUMBER "rev_number" /* FWARC/2008/300 */
+#define MD_STR_SERIAL_NUMBER "serial_number" /* FWARC/2008/300 */
+#define MD_STR_TOPO_HC_NAME "topo-hc-name" /* FWARC/2008/300 */
+#define MD_STR_TOPO_SKIP "topo-skip" /* FWARC/2008/300 */
+#define MD_STR_TYPE "type"
+
+
+/*
+ * The enumerator needs to pass some state in to the function that walks
+ * the PRI graph. This structure contains the necessary information.
+ */
+struct pi_enum_s {
+ topo_mod_t *mod; /* Topo module handle */
+
+ ldom_hdl_t *ldomp; /* LDOM connection handle */
+ uint64_t *ldom_bufp; /* LDOM connection data */
+ ssize_t ldom_bufsize; /* LDOM connection data size */
+
+ md_t *mdp; /* Machine Description handle */
+ int md_nodes; /* Number of md nodes */
+
+ void *wp; /* Walker private data */
+};
+typedef struct pi_enum_s pi_enum_t;
+
+
+/*
+ * Some node types require custom functions to create their topology nodes.
+ * This function prototype defines the interface to these functions.
+ */
+typedef int pi_enum_fn_t(topo_mod_t *, md_t *, mde_cookie_t, topo_instance_t,
+ tnode_t *, const char *, tnode_t **);
+
+pi_enum_fn_t pi_enum_cpu; /* Enumerate a CPU node */
+pi_enum_fn_t pi_enum_generic; /* Enumerate a generic PRI node */
+pi_enum_fn_t pi_enum_niu; /* Enumerate an NIU node */
+pi_enum_fn_t pi_enum_pciexrc; /* Enumerate a PCIEX root complex */
+pi_enum_fn_t pi_enum_top; /* Enumerate a top-level PRI node */
+
+int pi_enum_generic_impl(topo_mod_t *, md_t *, mde_cookie_t, topo_instance_t,
+ tnode_t *, tnode_t *, const char *, const char *, tnode_t **);
+
+
+/*
+ * Some enumeration functions may need to defer execution until after the
+ * entire PRI graph has been walked for some nodes. This interface is
+ * provided to allow for the registration of routines to execute after the
+ * entire graph has been walked (for example, to execute sub-enumerators).
+ */
+typedef int pi_deferenum_fn_t(topo_mod_t *, md_t *, mde_cookie_t,
+ topo_instance_t, tnode_t *, const char *, tnode_t *, void *);
+
+int pi_defer_add(topo_mod_t *, mde_cookie_t, tnode_t *, tnode_t *,
+ pi_deferenum_fn_t, void *);
+int pi_defer_exec(topo_mod_t *, md_t *);
+
+
+/* Functions to handle LDOM PRI sessions */
+int pi_ldompri_open(topo_mod_t *, pi_enum_t *);
+void pi_ldompri_close(topo_mod_t *, pi_enum_t *);
+
+
+/* Walk the PRI and create a topology starting at a particular PRI node */
+int pi_walker(pi_enum_t *, tnode_t *, const char *, mde_cookie_t,
+ mde_str_cookie_t, mde_str_cookie_t);
+int pi_walker_init(topo_mod_t *);
+void pi_walker_fini(topo_mod_t *);
+
+/* PRI machine description node data access routines */
+int pi_find_mdenodes(topo_mod_t *, md_t *, mde_cookie_t, char *, char *,
+ mde_cookie_t **, size_t *);
+int pi_skip_node(topo_mod_t *, md_t *, mde_cookie_t);
+int pi_get_cfg_handle(topo_mod_t *, md_t *, mde_cookie_t, uint64_t *);
+char *pi_get_chassisid(topo_mod_t *, md_t *, mde_cookie_t);
+char *pi_get_topo_hc_name(topo_mod_t *, md_t *, mde_cookie_t);
+int pi_get_instance(topo_mod_t *, md_t *, mde_cookie_t, topo_instance_t *);
+char *pi_get_part(topo_mod_t *, md_t *, mde_cookie_t);
+char *pi_get_productid(topo_mod_t *, md_t *);
+char *pi_get_revision(topo_mod_t *, md_t *, mde_cookie_t);
+char *pi_get_serial(topo_mod_t *, md_t *, mde_cookie_t);
+char *pi_get_serverid(topo_mod_t *);
+int pi_get_fru(topo_mod_t *, md_t *, mde_cookie_t, int *);
+char *pi_get_label(topo_mod_t *, md_t *, mde_cookie_t);
+
+int pi_set_auth(topo_mod_t *, md_t *, mde_cookie_t, tnode_t *, tnode_t *);
+int pi_set_frufmri(topo_mod_t *, md_t *, mde_cookie_t, const char *,
+ topo_instance_t, tnode_t *, tnode_t *);
+int pi_set_label(topo_mod_t *, md_t *, mde_cookie_t, tnode_t *);
+int pi_set_system(topo_mod_t *, tnode_t *);
+
+tnode_t *pi_node_bind(topo_mod_t *, md_t *, mde_cookie_t, tnode_t *,
+ const char *, topo_instance_t, nvlist_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PI_IMPL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_ldom.c Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,139 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Open connections to the LDOM and Machine Description libraries used during
+ * enumeration.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/mdesc.h>
+#include <sys/fm/ldom.h>
+#include <sys/systeminfo.h>
+
+#include "pi_impl.h"
+
+static topo_mod_t *Pi_mod;
+
+static void pi_free(void *, size_t);
+static void * pi_alloc(size_t);
+
+/*
+ * Initialize a connection to the LDOM machine description interface.
+ */
+int
+pi_ldompri_open(topo_mod_t *mod, pi_enum_t *pip)
+{
+ if (mod == NULL || pip == NULL) {
+ return (-1);
+ }
+
+ /*
+ * Store the module pointer for this session. This file-global
+ * is used by the allocators called by libldom and libmdesc.
+ */
+ Pi_mod = mod;
+
+ /* Initialize the LDOM connection */
+ pip->ldomp = ldom_init(pi_alloc, pi_free);
+ if (pip->ldomp == NULL) {
+ topo_mod_dprintf(mod,
+ "sun4vpi failed to initialize LDOM layer.\n");
+ Pi_mod = NULL;
+ return (-1);
+ }
+
+ /* Initialize the machine description layer for this ldom instance */
+ pip->ldom_bufsize = ldom_get_core_md(pip->ldomp, &(pip->ldom_bufp));
+ if (pip->ldom_bufsize < 1) {
+ topo_mod_dprintf(mod, "ldom_get_core_md error: bufsize = %d\n",
+ pip->ldom_bufsize);
+ ldom_fini(pip->ldomp);
+ Pi_mod = NULL;
+ return (-1);
+ }
+
+ /* Initialize the machine description internal layer */
+ pip->mdp = md_init_intern(pip->ldom_bufp, pi_alloc, pi_free);
+ if (pip->mdp == NULL ||
+ (pip->md_nodes = md_node_count(pip->mdp)) < 1) {
+ topo_mod_dprintf(mod, "md_init_intern error\n");
+ pi_free(pip->ldom_bufp, pip->ldom_bufsize);
+ ldom_fini(pip->ldomp);
+ Pi_mod = NULL;
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+/* ARGSUSED */
+void
+pi_ldompri_close(topo_mod_t *mod, pi_enum_t *pip)
+{
+ if (pip == NULL) {
+ return;
+ }
+
+ /* Close the machine description connection */
+ (void) md_fini(pip->mdp);
+
+ /* Close the connection to the LDOM layer */
+ ldom_fini(pip->ldomp);
+
+ /* Free the ldom connection data */
+ pi_free(pip->ldom_bufp, pip->ldom_bufsize);
+
+ /* Reset the file-global module pointer */
+ Pi_mod = NULL;
+}
+
+
+static void *
+pi_alloc(size_t size)
+{
+ if (Pi_mod == NULL) {
+ /* Cannot allocate memory without a module pointer */
+ return (NULL);
+ }
+ return (topo_mod_alloc(Pi_mod, size));
+}
+
+
+static void
+pi_free(void *buf, size_t size)
+{
+ if (Pi_mod == NULL) {
+ /* Cannot free memory without a module pointer */
+ return;
+ }
+ topo_mod_free(Pi_mod, buf, size);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_niu.c Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,79 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Create a topology node for a PRI node of type 'niu'
+ */
+#include <sys/types.h>
+#include <strings.h>
+#include <sys/fm/protocol.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include "pi_impl.h"
+
+#define _ENUM_NAME "enum_niu"
+
+
+/* ARGSUSED */
+int
+pi_enum_niu(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+ topo_instance_t inst, tnode_t *t_parent, const char *hc_name,
+ tnode_t **t_node)
+{
+ int result;
+
+ *t_node = NULL;
+
+ topo_mod_dprintf(mod,
+ "%s node_0x%llx enumeration starting\n", _ENUM_NAME,
+ (uint64_t)mde_node);
+
+ /* Make sure our dependent modules are loaded */
+ if (topo_mod_load(mod, NIU, TOPO_VERSION) == NULL) {
+ topo_mod_dprintf(mod, "%s could not load %s module: %s\n",
+ _ENUM_NAME, NIU, topo_strerror(topo_mod_errno(mod)));
+ return (-1);
+ }
+
+ /*
+ * Invoke the niu enumerator for this node.
+ */
+ result = topo_mod_enumerate(mod, t_parent, NIU, hc_name, inst, inst,
+ NULL);
+ if (result != 0) {
+ topo_mod_dprintf(mod,
+ "%s node_0x%llx enumeration failed: %s\n", _ENUM_NAME,
+ (uint64_t)mde_node, topo_strerror(topo_mod_errno(mod)));
+ return (-1);
+ }
+
+ topo_mod_dprintf(mod, "%s added node_0x%llx type %s\n",
+ _ENUM_NAME, (uint64_t)mde_node, hc_name);
+
+ return (0);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_pciexrc.c Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,387 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Create a topology node for a PRI node of type 'pciexrc'
+ */
+#include <sys/types.h>
+#include <strings.h>
+#include <sys/fm/protocol.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include <libdevinfo.h>
+#include "pi_impl.h"
+
+#define TOPO_PGROUP_PCIEX "pciex"
+#define TOPO_PCIEX_DRIVER "px"
+#define PCIEX_MAX_DEVICE 255
+
+#define _ENUM_NAME "enum_pciexrc"
+
+static const topo_pgroup_info_t io_pgroup =
+ { TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
+
+static const topo_pgroup_info_t pci_pgroup =
+ { TOPO_PGROUP_PCI, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
+
+static int pi_enum_pciexrc_finddev(topo_mod_t *, md_t *, mde_cookie_t,
+ tnode_t *);
+static int pi_enum_pciexrc_update(topo_mod_t *, md_t *, mde_cookie_t,
+ tnode_t *, tnode_t *);
+
+static int pi_enum_pciexrc_defer(topo_mod_t *, md_t *, mde_cookie_t,
+ topo_instance_t, tnode_t *, const char *, tnode_t *, void *);
+
+
+/*
+ * Create a pciexrc topo by calling the pciexrc enumerator for this instance.
+ */
+int
+pi_enum_pciexrc(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+ topo_instance_t inst, tnode_t *t_parent, const char *hc_name,
+ tnode_t **t_node)
+{
+ int result;
+
+ topo_mod_dprintf(mod, "%s called for node_0x%llx type %s\n",
+ _ENUM_NAME, (uint64_t)mde_node, hc_name);
+
+ *t_node = NULL;
+
+ /*
+ * Create the root complex topo node. Use the generic enumerator to
+ * do this, and then we will add more attributes below.
+ */
+ result = pi_enum_generic_impl(mod, mdp, mde_node, inst, t_parent,
+ t_parent, hc_name, _ENUM_NAME, t_node);
+ if (result != 0 || *t_node == NULL) {
+ topo_mod_dprintf(mod,
+ "%s node_0x%llx failed to create topo node: %s\n",
+ _ENUM_NAME, topo_strerror(topo_mod_errno(mod)));
+ return (result);
+ }
+
+ /* Update the topo node with more specific information */
+ result = pi_enum_pciexrc_update(mod, mdp, mde_node, t_parent, *t_node);
+ if (result != 0) {
+ topo_mod_dprintf(mod,
+ "%s node_0x%llx failed to create node properites: %s\n",
+ _ENUM_NAME, topo_strerror(topo_mod_errno(mod)));
+ return (result);
+ }
+
+ result = pi_enum_pciexrc_finddev(mod, mdp, mde_node, *t_node);
+ if (result == 0) {
+ /*
+ * The node exists in this domain. We will call the PCIBUS
+ * enumerator after the entire PRI graph has been walked so
+ * that all the possible FRU nodes are available for bus's
+ * that span multiple FRU boundaries.
+ */
+ result = pi_defer_add(mod, mde_node, t_parent, *t_node,
+ pi_enum_pciexrc_defer, NULL);
+ if (result != 0) {
+ /* We cannot defer the call, so we need to do it now */
+ result = pi_enum_pciexrc_defer(mod, mdp, mde_node, inst,
+ t_parent, hc_name, *t_node, NULL);
+ }
+ } else {
+ /*
+ * It is OK if the node does not exist for further PCIBUS
+ * enumeration. We can return success having created the
+ * root complex node itself.
+ */
+ result = 0;
+ }
+ topo_mod_dprintf(mod, "%s added node_0x%llx type %s\n",
+ _ENUM_NAME, (uint64_t)mde_node, hc_name);
+
+ return (result);
+}
+
+
+/* ARGSUSED */
+static int
+pi_enum_pciexrc_defer(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+ topo_instance_t inst, tnode_t *t_parent, const char *hc_name,
+ tnode_t *t_node, void *private)
+{
+ int result;
+ topo_instance_t min;
+ topo_instance_t max;
+
+ topo_mod_dprintf(mod,
+ "%s node_0x%llx deferred enumeration starting\n", _ENUM_NAME,
+ (uint64_t)mde_node);
+
+ /* Make sure our dependent modules are loaded */
+ if (topo_mod_load(mod, PCI_BUS, TOPO_VERSION) == NULL) {
+ topo_mod_dprintf(mod, "%s could not load %s module: %s\n",
+ _ENUM_NAME, PCI_BUS, topo_strerror(topo_mod_errno(mod)));
+ return (-1);
+ }
+
+ /* Create a node range for children of this bus */
+ min = 0;
+ max = PCIEX_MAX_DEVICE;
+ result = topo_node_range_create(mod, t_node, PCI_BUS, min, max);
+ if (result != 0) {
+ topo_mod_dprintf(mod,
+ "%s node_0x%llx failed to create node range: %s\n",
+ _ENUM_NAME, topo_strerror(topo_mod_errno(mod)));
+ return (-1);
+ }
+
+ /*
+ * Invoke the pcibus enumerator for this node.
+ */
+ result = topo_mod_enumerate(mod, t_node, PCI_BUS, PCIEX_BUS,
+ min, max, NULL);
+ if (result != 0) {
+ topo_mod_dprintf(mod,
+ "%s node_0x%llx enumeration failed: %s\n", _ENUM_NAME,
+ (uint64_t)mde_node, topo_strerror(topo_mod_errno(mod)));
+ }
+
+ topo_mod_dprintf(mod, "%s added node_0x%llx type %s\n",
+ _ENUM_NAME, (uint64_t)mde_node, hc_name);
+
+ return (result);
+}
+
+
+/*
+ * Update a PCIEXRC topo node with node-specific information
+ *
+ * The following is mostly a duplicate of code contained in:
+ * usr/src/lib/fm/topo/modules/sun4v/cpuboard/
+ * cpuboard_hostbridge.c:cpuboard_rc_node_create
+ */
+static int
+pi_enum_pciexrc_update(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+ tnode_t *t_parent, tnode_t *t_node)
+{
+ int result;
+ int err;
+ char dnpath[MAXPATHLEN];
+ uint64_t cfg_handle;
+ nvlist_t *modfmri;
+ nvlist_t *devfmri;
+
+ if (t_parent == NULL || t_node == NULL) {
+ topo_mod_dprintf(mod, "%s node_0x%llx has no parent\n",
+ _ENUM_NAME, (uint64_t)mde_node);
+ return (-1);
+ }
+
+ /*
+ * Calculate the device path for this root complex node.
+ */
+ result = pi_get_cfg_handle(mod, mdp, mde_node, &cfg_handle);
+ if (result != 0) {
+ topo_mod_dprintf(mod, "node_0x%llx has no cfg-handle\n",
+ (uint64_t)mde_node);
+ return (result);
+ }
+ (void) snprintf(dnpath, sizeof (dnpath), "/pci@%llx", cfg_handle);
+
+ /*
+ * Set the ASRU for this node using the dev scheme
+ */
+ devfmri = topo_mod_devfmri(mod, FM_DEV_SCHEME_VERSION, dnpath, NULL);
+ if (devfmri == NULL) {
+ topo_mod_dprintf(mod, "%s node_0x%llx fmri creation failed\n",
+ _ENUM_NAME, (uint64_t)mde_node);
+ return (-1);
+ }
+
+ result = topo_node_asru_set(t_node, devfmri, 0, &err);
+ nvlist_free(devfmri);
+ if (result != 0) {
+ topo_mod_dprintf(mod, "%s node_0x%llx failed to set ASRU\n",
+ _ENUM_NAME, (uint64_t)mde_node);
+ topo_mod_seterrno(mod, err);
+ return (-1);
+ }
+
+ /*
+ * Set PCIEXRC properties for root complex nodes
+ */
+ result = topo_pgroup_create(t_node, &io_pgroup, &err);
+ if (result < 0) {
+ topo_mod_dprintf(mod,
+ "%s node_0x%llx topo_pgroup_create for io pgroup failed\n",
+ _ENUM_NAME, (uint64_t)mde_node);
+ topo_mod_seterrno(mod, err);
+ return (result);
+ }
+ result = topo_pgroup_create(t_node, &pci_pgroup, &err);
+ if (result < 0) {
+ topo_mod_dprintf(mod,
+ "%s node_0x%llx topo_pgroup_create for pci pgroup failed\n",
+ _ENUM_NAME, (uint64_t)mde_node);
+ topo_mod_seterrno(mod, err);
+ return (result);
+ }
+
+ result = topo_prop_set_string(t_node, TOPO_PGROUP_IO, TOPO_IO_DEV,
+ TOPO_PROP_IMMUTABLE, dnpath, &err);
+ if (result != 0) {
+ topo_mod_dprintf(mod,
+ "%s node_0x%llx failed to set DEV property\n",
+ _ENUM_NAME, (uint64_t)mde_node);
+ topo_mod_seterrno(mod, err);
+ return (result);
+ }
+
+ /* device type is always "pciex" */
+ result = topo_prop_set_string(t_node, TOPO_PGROUP_IO, TOPO_IO_DEVTYPE,
+ TOPO_PROP_IMMUTABLE, TOPO_PGROUP_PCIEX, &err);
+ if (result < 0) {
+ topo_mod_dprintf(mod,
+ "%s node_0x%llx failed to set DEVTYPE property\n",
+ _ENUM_NAME, (uint64_t)mde_node);
+ topo_mod_seterrno(mod, err);
+ return (result);
+ }
+
+ /*
+ * driver is always "px"
+ */
+ result = topo_prop_set_string(t_node, TOPO_PGROUP_IO, TOPO_IO_DRIVER,
+ TOPO_PROP_IMMUTABLE, TOPO_PCIEX_DRIVER, &err);
+ if (result < 0) {
+ topo_mod_dprintf(mod,
+ "%s node_0x%llx failed to set DRIVER property\n",
+ _ENUM_NAME, (uint64_t)mde_node);
+ topo_mod_seterrno(mod, err);
+ return (result);
+ }
+
+ modfmri = topo_mod_modfmri(mod, FM_MOD_SCHEME_VERSION,
+ TOPO_PCIEX_DRIVER);
+ if (modfmri == NULL) {
+ topo_mod_dprintf(mod,
+ "%s node_0x%llx failed to create module fmri\n",
+ _ENUM_NAME, (uint64_t)mde_node);
+ topo_mod_seterrno(mod, err);
+ return (result);
+ }
+ result = topo_prop_set_fmri(t_node, TOPO_PGROUP_IO, TOPO_IO_MODULE,
+ TOPO_PROP_IMMUTABLE, modfmri, &err);
+ nvlist_free(modfmri);
+ if (result < 0) {
+ topo_mod_dprintf(mod,
+ "%s node_0x%llx failed to set MODULE property\n",
+ _ENUM_NAME, (uint64_t)mde_node);
+ topo_mod_seterrno(mod, err);
+ return (result);
+ }
+
+ /* This is a PCIEX root complex */
+ result = topo_prop_set_string(t_node, TOPO_PGROUP_PCI, TOPO_PCI_EXCAP,
+ TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err);
+ if (result < 0) {
+ topo_mod_dprintf(mod,
+ "%s node_0x%llx failed to set EXCAP property\n",
+ _ENUM_NAME, (uint64_t)mde_node);
+ topo_mod_seterrno(mod, err);
+ return (result);
+ }
+
+ /* Create a node range for the children of this root complex */
+ topo_node_range_create(mod, t_node, PCIEX_BUS, 0, PCIEX_MAX_DEVICE);
+
+ return (0);
+}
+
+
+static int
+pi_enum_pciexrc_finddev(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+ tnode_t *t_node)
+{
+ int result;
+ di_node_t devtree;
+ di_node_t dnode;
+ uint64_t cfg_handle;
+
+ /* Initialize the device information structure for this module */
+ devtree = topo_mod_devinfo(mod);
+ if (devtree == DI_NODE_NIL) {
+ topo_mod_dprintf(mod, "devinfo init failed\n");
+ return (-1);
+ }
+
+ /*
+ * Find the PRI node cfg-handle. This will be used to associate the
+ * PRI node with the device node
+ */
+ result = pi_get_cfg_handle(mod, mdp, mde_node, &cfg_handle);
+ if (result != 0) {
+ topo_mod_dprintf(mod, "node_0x%llx has no cfg-handle\n",
+ (uint64_t)mde_node);
+ return (result);
+ }
+ topo_mod_dprintf(mod, "node_0x%llx has cfg-handle = /pci@%llx\n",
+ (uint64_t)mde_node, cfg_handle);
+
+ /*
+ * Scan the device node list and find the node associated with
+ * the given PRI node. Equality is defined as the PRI cfg-handle
+ * equalling the device node bus address.
+ */
+ dnode = di_drv_first_node(TOPO_PCIEX_DRIVER, devtree);
+ while (dnode != DI_NODE_NIL) {
+ uint64_t bus_addr;
+ char *addr;
+
+ addr = di_bus_addr(dnode);
+ if (addr != NULL) {
+ bus_addr = strtoull(addr, NULL, 16);
+ if (bus_addr == cfg_handle) {
+ /* We have found the matching dnode */
+ break;
+ }
+ }
+
+ /* We have not found the matching dnode yet */
+ dnode = di_drv_next_node(dnode);
+ }
+ if (dnode != DI_NODE_NIL) {
+ topo_mod_dprintf(mod, "%s node_0x%llx found bus 0x%llx\n",
+ _ENUM_NAME, (uint64_t)mde_node, cfg_handle);
+
+ /*
+ * Associate this dnode with the topo node. The PCI
+ * enumerator requires this information.
+ */
+ topo_node_setspecific(t_node, (void *)dnode);
+ }
+
+ return (0);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_subr.c Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,963 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Subroutines used by various components of the Sun4v PI enumerator
+ */
+
+#include <sys/types.h>
+#include <sys/systeminfo.h>
+#include <sys/utsname.h>
+#include <strings.h>
+#include <sys/fm/protocol.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include <sys/mdesc.h>
+#include <libnvpair.h>
+
+#include "pi_impl.h"
+
+static const topo_pgroup_info_t sys_pgroup = {
+ TOPO_PGROUP_SYSTEM,
+ TOPO_STABILITY_PRIVATE,
+ TOPO_STABILITY_PRIVATE,
+ 1
+};
+
+static const topo_pgroup_info_t auth_pgroup = {
+ FM_FMRI_AUTHORITY,
+ TOPO_STABILITY_PRIVATE,
+ TOPO_STABILITY_PRIVATE,
+ 1
+};
+
+
+/*
+ * Search the PRI for MDE nodes using md_scan_dag. Using this routine
+ * consolodates similar searches used in a few places within the sun4vpi
+ * enumerator.
+ *
+ * The routine returns the number of nodes found, or -1. If the node array
+ * is non-NULL on return, then it must be freed:
+ * topo_mod_free(mod, nodes, nsize);
+ *
+ */
+int
+pi_find_mdenodes(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_start,
+ char *type_str, char *arc_str, mde_cookie_t **nodes, size_t *nsize)
+{
+ int result;
+ int total_mdenodes;
+
+ mde_str_cookie_t start_cookie;
+ mde_str_cookie_t arc_cookie;
+
+ /* Prepare to scan the PRI using the start string and given arc */
+ total_mdenodes = md_node_count(mdp);
+ start_cookie = md_find_name(mdp, type_str);
+ arc_cookie = md_find_name(mdp, arc_str);
+
+ /* Allocate an array to hold the results of the scan */
+ *nsize = sizeof (mde_cookie_t) * total_mdenodes;
+ *nodes = topo_mod_zalloc(mod, *nsize);
+ if (*nodes == NULL) {
+ /* We have no memory. Set an error code and return failure */
+ *nsize = 0;
+ topo_mod_seterrno(mod, EMOD_NOMEM);
+ return (-1);
+ }
+
+ result = md_scan_dag(mdp, mde_start, start_cookie, arc_cookie, *nodes);
+ if (result <= 0) {
+ /* No nodes found. Free the node array before returning */
+ topo_mod_free(mod, *nodes, *nsize);
+ *nodes = NULL;
+ *nsize = 0;
+ }
+
+ return (result);
+}
+
+
+/*
+ * Determine if this node should be skipped by finding the topo-skip property.
+ */
+int
+pi_skip_node(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
+{
+ int result;
+ uint64_t skip;
+
+ if (mod == NULL || mdp == NULL) {
+ /*
+ * These parameters are required. Tell the caller to skip
+ * all nodes.
+ */
+ return (1);
+ }
+
+ skip = 0; /* do not skip by default */
+ result = md_get_prop_val(mdp, mde_node, MD_STR_TOPO_SKIP, &skip);
+ if (result != 0) {
+ /*
+ * There is no topo-skip property. Assume we are not skipping
+ * the mde node.
+ */
+ skip = 0;
+ }
+
+ /*
+ * If skip is present and non-zero we want to skip this node. We
+ * return 1 to indicate this.
+ */
+ if (skip != 0) {
+ return (1);
+ }
+ return (0);
+}
+
+
+/*
+ * Get the cfg-handle property value from the given PRI node
+ */
+int
+pi_get_cfg_handle(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+ uint64_t *cfg_handle)
+{
+ int result;
+
+ if (cfg_handle == NULL) {
+ return (-1);
+ }
+
+ result = md_get_prop_val(mdp, mde_node, MD_STR_CFG_HANDLE, cfg_handle);
+ if (result != 0) {
+ topo_mod_dprintf(mod,
+ "failed to get property %s from node_0x%llx\n",
+ MD_STR_CFG_HANDLE, (uint64_t)mde_node);
+ }
+ return (result);
+}
+
+
+/*
+ * Get the chassis serial number (the ID as far as the topo authority is
+ * concerned) either from the current node, if it is of type 'chassis', or
+ * search for a chassis node in the PRI.
+ *
+ * The string must be freed with topo_mod_strfree()
+ */
+char *
+pi_get_chassisid(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
+{
+ int result;
+ int idx;
+ int num_nodes;
+ char *id = NULL;
+ char *hc_name = NULL;
+ size_t chassis_size;
+ mde_cookie_t *chassis_nodes = NULL;
+
+ topo_mod_dprintf(mod, "pi_get_chassis: enter\n");
+
+ hc_name = pi_get_topo_hc_name(mod, mdp, mde_node);
+ if (hc_name != NULL && strcmp(hc_name, MD_STR_CHASSIS) == 0) {
+ topo_mod_strfree(mod, hc_name);
+
+ /*
+ * This is a chassis node. We need only search for the serial
+ * number property on this node to return the ID.
+ */
+ result = md_get_prop_str(mdp, mde_node, MD_STR_SERIAL_NUMBER,
+ &id);
+ if (result != 0 || id == NULL || strlen(id) == 0) {
+ return (NULL);
+ }
+ topo_mod_dprintf(mod, "pi_get_chassis: chassis-id = %s\n", id);
+ return (topo_mod_strdup(mod, id));
+ }
+
+ /*
+ * Search the PRI for nodes of type MD_STR_COMPONENT and find the
+ * first element with topo-hc-type of MD_STR_CHASSIS. This node
+ * will contain the MD_STR_SERIAL_NUMBER property to use as the
+ * chassis-id.
+ */
+ num_nodes = pi_find_mdenodes(mod, mdp, MDE_INVAL_ELEM_COOKIE,
+ MD_STR_COMPONENT, MD_STR_FWD, &chassis_nodes, &chassis_size);
+ if (num_nodes <= 0 || chassis_nodes == NULL) {
+ /* We did not find any chassis nodes */
+ return (NULL);
+ }
+ topo_mod_dprintf(mod, "pi_get_chassisid: found %d %s nodes\n",
+ num_nodes, MD_STR_COMPONENT);
+
+ idx = 0;
+ while (id == NULL && idx < num_nodes) {
+ hc_name = pi_get_topo_hc_name(mod, mdp, chassis_nodes[idx]);
+ if (hc_name != NULL && strcmp(hc_name, MD_STR_CHASSIS) == 0) {
+ /*
+ * This is a chassis node. Get the serial number
+ * property from the node.
+ */
+ result = md_get_prop_str(mdp, chassis_nodes[idx],
+ MD_STR_SERIAL_NUMBER, &id);
+ if (result != 0) {
+ topo_mod_dprintf(mod, "pi_get_chassisid: "
+ "failed to read %s from node_0x%llx\n",
+ MD_STR_SERIAL_NUMBER,
+ (uint64_t)chassis_nodes[idx]);
+ }
+ }
+ topo_mod_strfree(mod, hc_name);
+
+ /* Search the next node, if necessary */
+ idx++;
+ }
+ topo_mod_free(mod, chassis_nodes, chassis_size);
+
+ /* Everything is freed up and it's time to return the platform-id */
+ if (result != 0 || id == NULL || strlen(id) == 0) {
+ return (NULL);
+ }
+ topo_mod_dprintf(mod, "pi_get_chassis: chassis-id %s\n", id);
+
+ return (topo_mod_strdup(mod, id));
+}
+
+
+/*
+ * Determine if the node is a FRU by checking for the existance and non-zero
+ * value of the 'fru' property on the mde node.
+ */
+int
+pi_get_fru(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node, int *is_fru)
+{
+ int result;
+ uint64_t fru;
+
+ if (mod == NULL || mdp == NULL || is_fru == NULL) {
+ return (-1);
+ }
+ fru = 0;
+ *is_fru = 0;
+
+ result = md_get_prop_val(mdp, mde_node, MD_STR_FRU, &fru);
+ if (result != 0) {
+ /* The node is not a FRU. */
+ return (-1);
+ }
+ if (fru != 0) {
+ *is_fru = 1;
+ }
+ return (0);
+}
+
+
+/*
+ * Get the id property value from the given PRI node
+ */
+int
+pi_get_instance(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+ topo_instance_t *ip)
+{
+ int result;
+ uint64_t id;
+
+ id = 0;
+ result = md_get_prop_val(mdp, mde_node, MD_STR_ID, &id);
+ if (result != 0) {
+ /*
+ * There is no id property.
+ */
+ topo_mod_dprintf(mod, "node_0x%llx has no id property\n",
+ (uint64_t)mde_node);
+ return (-1);
+ }
+ *ip = id;
+
+ return (0);
+}
+
+
+/*
+ * If the given MDE node is a FRU return the 'nac' property, if it exists,
+ * to use as the label.
+ *
+ * The string must be freed with topo_mod_strfree()
+ */
+char *
+pi_get_label(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
+{
+ int result;
+ int is_fru;
+ char *lp = NULL;
+
+ result = pi_get_fru(mod, mdp, mde_node, &is_fru);
+ if (result != 0 || is_fru == 0) {
+ /* This node is not a FRU. It has no label */
+ return (NULL);
+ }
+
+ /*
+ * The node is a FRU. Get the NAC name to use as a label.
+ */
+ result = md_get_prop_str(mdp, mde_node, MD_STR_NAC, &lp);
+ if (result != 0 || lp == NULL || strlen(lp) == 0) {
+ /* No NAC label. Return NULL */
+ return (NULL);
+ }
+
+ /* Return a copy of the label */
+ return (topo_mod_strdup(mod, lp));
+}
+
+
+/*
+ * Return the complete part number string to the caller. The complete part
+ * number is made up of the part number attribute concatenated with the dash
+ * number attribute of the mde node.
+ *
+ * The string must be freed with topo_mod_strfree()
+ */
+char *
+pi_get_part(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
+{
+ int result;
+ size_t bufsize;
+ char *buf = NULL;
+ char *part = NULL;
+ char *dash = NULL;
+
+ result = md_get_prop_str(mdp, mde_node, MD_STR_PART_NUMBER, &part);
+ if (result != 0) {
+ part = NULL;
+ }
+ result = md_get_prop_str(mdp, mde_node, MD_STR_DASH_NUMBER, &dash);
+ if (result != 0) {
+ dash = NULL;
+ }
+ bufsize = 1 + (part ? strlen(part) : 0) + (dash ? strlen(dash) : 0);
+ if (bufsize == 1) {
+ return (NULL);
+ }
+
+ /* Construct the part number from the part and dash values */
+ buf = topo_mod_alloc(mod, bufsize);
+ if (buf != NULL) {
+ (void) snprintf(buf, bufsize, "%s%s", (part ? part : ""),
+ (dash ? dash : ""));
+ }
+
+ return (buf);
+}
+
+
+/*
+ * Get the product ID from the 'platform' node in the PRI
+ *
+ * The string must be freed with topo_mod_strfree()
+ */
+char *
+pi_get_productid(topo_mod_t *mod, md_t *mdp)
+{
+ int result;
+ char *id = NULL;
+ size_t platform_size;
+ mde_cookie_t *platform_nodes = NULL;
+
+ topo_mod_dprintf(mod, "pi_get_product: enter\n");
+
+ /*
+ * Search the PRI for nodes of type MD_STR_PLATFORM, which contains
+ * the product-id in it's MD_STR_NAME property.
+ */
+ result = pi_find_mdenodes(mod, mdp, MDE_INVAL_ELEM_COOKIE,
+ MD_STR_PLATFORM, MD_STR_FWD, &platform_nodes, &platform_size);
+ if (result <= 0 || platform_nodes == NULL) {
+ /* We did not find any platform nodes */
+ return (NULL);
+ }
+ topo_mod_dprintf(mod, "pi_get_productid: found %d platform nodes\n",
+ result);
+
+ /*
+ * There should only be 1 platform node, so we will always
+ * use the first if we find any at all.
+ */
+ result = md_get_prop_str(mdp, platform_nodes[0], MD_STR_NAME, &id);
+ topo_mod_free(mod, platform_nodes, platform_size);
+
+ /* Everything is freed up and it's time to return the platform-id */
+ if (result != 0 || id == NULL || strlen(id) == 0) {
+ return (NULL);
+ }
+ topo_mod_dprintf(mod, "pi_get_product: returning %s\n", id);
+
+ return (topo_mod_strdup(mod, id));
+}
+
+
+/*
+ * Return the revision string to the caller.
+ *
+ * The string must be freed with topo_mod_strfree()
+ */
+char *
+pi_get_revision(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
+{
+ int result;
+ char *rp = NULL;
+
+ result = md_get_prop_str(mdp, mde_node, MD_STR_REVISION_NUMBER, &rp);
+ if (result != 0 || rp == NULL || strlen(rp) == 0) {
+ return (NULL);
+ }
+
+ return (topo_mod_strdup(mod, rp));
+}
+
+
+/*
+ * Return the serial number string to the caller.
+ *
+ * The string must be freed with topo_mod_strfree()
+ */
+char *
+pi_get_serial(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
+{
+ int result;
+ uint64_t sn;
+ char *sp = NULL;
+ char buf[MAXNAMELEN];
+
+ result = md_get_prop_str(mdp, mde_node, MD_STR_SERIAL_NUMBER, &sp);
+ if (result != 0 || sp == NULL || strlen(sp) == 0) {
+ /* Is this a uint64_t type serial number? */
+ result = md_get_prop_val(mdp, mde_node, MD_STR_SERIAL_NUMBER,
+ &sn);
+ if (result != 0) {
+ /* No. We have failed to find a serial number */
+ return (NULL);
+ }
+ topo_mod_dprintf(mod, "pi_get_serial: node_0x%llx numeric "
+ "serial number %llx\n", (uint64_t)mde_node, sn);
+
+ /* Convert the acquired value to a string */
+ result = snprintf(buf, sizeof (buf), "%llu", sn);
+ if (result < 0) {
+ return (NULL);
+ }
+ sp = buf;
+ }
+ topo_mod_dprintf(mod, "pi_get_serial: node_0x%llx = %s\n",
+ (uint64_t)mde_node, (sp == NULL ? "NULL" : sp));
+
+ return (topo_mod_strdup(mod, sp));
+}
+
+
+/*
+ * Get the server hostname (the ID as far as the topo authority is
+ * concerned) from sysinfo and return a copy to the caller.
+ *
+ * The string must be freed with topo_mod_strfree()
+ */
+char *
+pi_get_serverid(topo_mod_t *mod)
+{
+ int result;
+ char hostname[MAXNAMELEN];
+
+ topo_mod_dprintf(mod, "pi_get_serverid: enter\n");
+
+ result = sysinfo(SI_HOSTNAME, hostname, sizeof (hostname));
+ /* Everything is freed up and it's time to return the platform-id */
+ if (result == -1) {
+ return (NULL);
+ }
+ topo_mod_dprintf(mod, "pi_get_serverid: hostname = %s\n", hostname);
+
+ return (topo_mod_strdup(mod, hostname));
+}
+
+
+/*
+ * Get the hc scheme name for the given node
+ */
+char *
+pi_get_topo_hc_name(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
+{
+ int result;
+ char *hc_name;
+
+ /*
+ * Request the hc name from the node.
+ */
+ hc_name = NULL;
+ result = md_get_prop_str(mdp, mde_node, MD_STR_TOPO_HC_NAME, &hc_name);
+ if (result != 0 || hc_name == NULL) {
+ topo_mod_dprintf(mod,
+ "failed to get property %s from node_0x%llx\n",
+ MD_STR_TOPO_HC_NAME, (uint64_t)mde_node);
+ return (NULL);
+ }
+
+ /* Return a copy of the type string */
+ return (topo_mod_strdup(mod, hc_name));
+}
+
+
+/*
+ * Calculate the authority information for a node. Inherit the data if
+ * possible, but always create an appropriate property group.
+ */
+int
+pi_set_auth(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+ tnode_t *t_parent, tnode_t *t_node)
+{
+ int result;
+ int err;
+ nvlist_t *auth;
+ char *val = NULL;
+ char *prod = NULL;
+ char *csn = NULL;
+ char *server = NULL;
+
+ if (mod == NULL || mdp == NULL || t_parent == NULL || t_node == NULL) {
+ return (-1);
+ }
+
+ result = topo_pgroup_create(t_node, &auth_pgroup, &err);
+ if (result != 0 && err != ETOPO_PROP_DEFD) {
+ /*
+ * We failed to create the property group and it was not
+ * already defined. Set the err code and return failure.
+ */
+ topo_mod_seterrno(mod, err);
+ return (-1);
+ }
+
+ /* Get the authority information already available from the parent */
+ auth = topo_mod_auth(mod, t_parent);
+
+ /*
+ * Set the authority data, inheriting it if possible, but creating it
+ * if necessary.
+ */
+ result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY,
+ FM_FMRI_AUTH_PRODUCT, &err);
+ if (result != 0 && err != ETOPO_PROP_DEFD) {
+ val = NULL;
+ result = nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT,
+ &val);
+ if (result != 0 || val == NULL) {
+ /*
+ * No product information in the parent node or auth
+ * list. Find the product information in the PRI.
+ */
+ prod = pi_get_productid(mod, mdp);
+ if (prod == NULL) {
+ topo_mod_dprintf(mod, "pi_set_auth: product "
+ "name not found for node_0x%llx\n",
+ (uint64_t)mde_node);
+ }
+ } else {
+ /*
+ * Dup the string. If we cannot find it in the auth
+ * nvlist we will need to free it, so this lets us
+ * have a single code path.
+ */
+ prod = topo_mod_strdup(mod, val);
+ }
+
+ /*
+ * We continue even if the product information is not available
+ * to enumerate as much as possible.
+ */
+ if (prod != NULL) {
+ result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY,
+ FM_FMRI_AUTH_PRODUCT, TOPO_PROP_IMMUTABLE, prod,
+ &err);
+ if (result != 0) {
+ /* Preserve the error and continue */
+ topo_mod_seterrno(mod, err);
+ topo_mod_dprintf(mod, "pi_set_auth: failed to "
+ "set property %s (%d) : %s\n",
+ FM_FMRI_AUTH_CHASSIS, err,
+ topo_strerror(err));
+ }
+ topo_mod_strfree(mod, prod);
+ }
+ }
+
+ result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY,
+ FM_FMRI_AUTH_CHASSIS, &err);
+ if (result != 0 && err != ETOPO_PROP_DEFD) {
+ val = NULL;
+ result = nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS,
+ &val);
+ if (result != 0 || val == NULL) {
+ /*
+ * No product information in the parent node or auth
+ * list. Find the product information in the PRI.
+ */
+ csn = pi_get_chassisid(mod, mdp, mde_node);
+ if (csn == NULL) {
+ topo_mod_dprintf(mod, "pi_set_auth: csn "
+ "name not found for node_0x%llx\n",
+ (uint64_t)mde_node);
+ }
+ } else {
+ /*
+ * Dup the string. If we cannot find it in the auth
+ * nvlist we will need to free it, so this lets us
+ * have a single code path.
+ */
+ csn = topo_mod_strdup(mod, val);
+ }
+
+ /*
+ * We continue even if the product information is not available
+ * to enumerate as much as possible.
+ */
+ if (csn != NULL) {
+ result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY,
+ FM_FMRI_AUTH_CHASSIS, TOPO_PROP_IMMUTABLE, csn,
+ &err);
+ if (result != 0) {
+ /* Preserve the error and continue */
+ topo_mod_seterrno(mod, err);
+ topo_mod_dprintf(mod, "pi_set_auth: failed to "
+ "set property %s (%d) : %s\n",
+ FM_FMRI_AUTH_CHASSIS, err,
+ topo_strerror(err));
+ }
+ topo_mod_strfree(mod, csn);
+ }
+ }
+
+ result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY,
+ FM_FMRI_AUTH_SERVER, &err);
+ if (result != 0 && err != ETOPO_PROP_DEFD) {
+ val = NULL;
+ result = nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER,
+ &val);
+ if (result != 0 || val == NULL) {
+ /*
+ * No product information in the parent node or auth
+ * list. Find the product information in the PRI.
+ */
+ server = pi_get_serverid(mod);
+ if (server == NULL) {
+ topo_mod_dprintf(mod, "pi_set_auth: server "
+ "name not found for node_0x%llx\n",
+ (uint64_t)mde_node);
+ }
+ } else {
+ /*
+ * Dup the string. If we cannot find it in the auth
+ * nvlist we will need to free it, so this lets us
+ * have a single code path.
+ */
+ server = topo_mod_strdup(mod, val);
+ }
+
+ /*
+ * We continue even if the product information is not available
+ * to enumerate as much as possible.
+ */
+ if (server != NULL) {
+ result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY,
+ FM_FMRI_AUTH_SERVER, TOPO_PROP_IMMUTABLE, server,
+ &err);
+ if (result != 0) {
+ /* Preserve the error and continue */
+ topo_mod_seterrno(mod, err);
+ topo_mod_dprintf(mod, "pi_set_auth: failed to "
+ "set property %s (%d) : %s\n",
+ FM_FMRI_AUTH_SERVER, err,
+ topo_strerror(err));
+ }
+ topo_mod_strfree(mod, server);
+ }
+ }
+
+ nvlist_free(auth);
+
+ return (0);
+}
+
+
+/*
+ * Calculate a generic FRU for the given node. If the node is not a FRU,
+ * then inherit the FRU data from the nodes parent.
+ */
+int
+pi_set_frufmri(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+ const char *name, topo_instance_t inst, tnode_t *t_parent, tnode_t *t_node)
+{
+ int result;
+ int err;
+ int is_fru;
+ char *part;
+ char *rev;
+ char *serial;
+ nvlist_t *auth = NULL;
+ nvlist_t *frufmri = NULL;
+
+ if (t_node == NULL || mod == NULL || mdp == NULL) {
+ return (-1);
+ }
+
+ /*
+ * Determine if this node is a FRU
+ */
+ result = pi_get_fru(mod, mdp, mde_node, &is_fru);
+ if (result != 0 || is_fru == 0) {
+ /* This node is not a FRU. Inherit from parent and return */
+ topo_node_fru_set(t_node, NULL, 0, &result);
+ return (0);
+ }
+
+ /*
+ * This node is a FRU. Create an FMRI.
+ */
+ part = pi_get_part(mod, mdp, mde_node);
+ rev = pi_get_revision(mod, mdp, mde_node);
+ serial = pi_get_serial(mod, mdp, mde_node);
+ auth = topo_mod_auth(mod, t_parent);
+ frufmri = topo_mod_hcfmri(mod, t_parent, FM_HC_SCHEME_VERSION, name,
+ inst, NULL, auth, part, rev, serial);
+ if (frufmri == NULL) {
+ topo_mod_dprintf(mod, "failed to create FRU: %s\n",
+ topo_strerror(topo_mod_errno(mod)));
+ }
+ nvlist_free(auth);
+ topo_mod_strfree(mod, part);
+ topo_mod_strfree(mod, rev);
+ topo_mod_strfree(mod, serial);
+
+ /* Set the FRU, whether NULL or not */
+ result = topo_node_fru_set(t_node, frufmri, 0, &err);
+ if (result != 0) {
+ topo_mod_seterrno(mod, err);
+ }
+ nvlist_free(frufmri);
+
+ return (result);
+}
+
+
+int
+pi_set_label(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node, tnode_t *t_node)
+{
+ int result;
+ int err;
+ char *label;
+
+ if (mod == NULL || mdp == NULL) {
+ return (-1);
+ }
+
+ /*
+ * Get the label, if any, from the mde node and apply it as the label
+ * for this topology node. Note that a NULL label will inherit the
+ * label from topology node's parent.
+ */
+ label = pi_get_label(mod, mdp, mde_node);
+ result = topo_node_label_set(t_node, label, &err);
+ topo_mod_strfree(mod, label);
+ if (result != 0) {
+ topo_mod_seterrno(mod, err);
+ topo_mod_dprintf(mod, "pi_set_label: failed with label %s "
+ "on node_0x%llx: %s\n", (label == NULL ? "NULL" : label),
+ (uint64_t)mde_node, topo_strerror(err));
+ }
+
+ return (result);
+}
+
+
+/*
+ * Calculate the system information for a node. Inherit the data if
+ * possible, but always create an appropriate property group.
+ */
+int
+pi_set_system(topo_mod_t *mod, tnode_t *t_node)
+{
+ int result;
+ int err;
+ struct utsname uts;
+ char isa[MAXNAMELEN];
+
+ if (mod == NULL || t_node == NULL) {
+ return (-1);
+ }
+
+ result = topo_pgroup_create(t_node, &sys_pgroup, &err);
+ if (result != 0 && err != ETOPO_PROP_DEFD) {
+ /*
+ * We failed to create the property group and it was not
+ * already defined. Set the err code and return failure.
+ */
+ topo_mod_seterrno(mod, err);
+ return (-1);
+ }
+
+ result = topo_prop_inherit(t_node, TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA,
+ &err);
+ if (result != 0 && err != ETOPO_PROP_DEFD) {
+ isa[0] = '\0';
+ result = sysinfo(SI_ARCHITECTURE, isa, sizeof (isa));
+ if (result == -1) {
+ /* Preserve the error and continue */
+ topo_mod_dprintf(mod, "pi_set_system: failed to "
+ "read SI_ARCHITECTURE: %d\n", errno);
+ }
+ if (strnlen(isa, MAXNAMELEN) > 0) {
+ result = topo_prop_set_string(t_node,
+ TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA,
+ TOPO_PROP_IMMUTABLE, isa, &err);
+ if (result != 0) {
+ /* Preserve the error and continue */
+ topo_mod_seterrno(mod, err);
+ topo_mod_dprintf(mod, "pi_set_auth: failed to "
+ "set property %s (%d) : %s\n",
+ TOPO_PROP_ISA, err, topo_strerror(err));
+ }
+ }
+ }
+
+ result = topo_prop_inherit(t_node, TOPO_PGROUP_SYSTEM,
+ TOPO_PROP_MACHINE, &err);
+ if (result != 0 && err != ETOPO_PROP_DEFD) {
+ result = uname(&uts);
+ if (result == -1) {
+ /* Preserve the error and continue */
+ topo_mod_seterrno(mod, errno);
+ topo_mod_dprintf(mod, "pi_set_system: failed to "
+ "read uname: %d\n", errno);
+ }
+ if (strnlen(uts.machine, sizeof (uts.machine)) > 0) {
+ result = topo_prop_set_string(t_node,
+ TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE,
+ TOPO_PROP_IMMUTABLE, uts.machine, &err);
+ if (result != 0) {
+ /* Preserve the error and continue */
+ topo_mod_seterrno(mod, err);
+ topo_mod_dprintf(mod, "pi_set_auth: failed to "
+ "set property %s (%d) : %s\n",
+ TOPO_PROP_MACHINE, err, topo_strerror(err));
+ }
+ }
+ }
+
+ return (0);
+}
+
+
+tnode_t *
+pi_node_bind(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+ tnode_t *t_parent, const char *hc_name, topo_instance_t inst,
+ nvlist_t *fmri)
+{
+ int result;
+ tnode_t *t_node;
+
+ if (t_parent == NULL) {
+ topo_mod_dprintf(mod,
+ "cannot bind for node_0x%llx instance %d type %s\n",
+ (uint64_t)mde_node, inst, hc_name);
+ return (NULL);
+ }
+
+ /* Bind this node to the parent */
+ t_node = topo_node_bind(mod, t_parent, hc_name, inst, fmri);
+ if (t_node == NULL) {
+ topo_mod_dprintf(mod,
+ "failed to bind node_0x%llx instance %d: %s\n",
+ (uint64_t)mde_node, (uint32_t)inst,
+ topo_strerror(topo_mod_errno(mod)));
+ return (NULL);
+ }
+ topo_mod_dprintf(mod, "bound node_0x%llx instance %d type %s\n",
+ (uint64_t)mde_node, inst, hc_name);
+
+ /*
+ * We have bound the node. Now decorate it with an appropriate
+ * FRU and label (which may be inherited from the parent).
+ */
+ result = pi_set_frufmri(mod, mdp, mde_node, hc_name, inst, t_parent,
+ t_node);
+ if (result != 0) {
+ /*
+ * Though we have failed to set the FRU FMRI we still continue.
+ * The module errno is set by the called routine, so we report
+ * the problem and move on.
+ */
+ topo_mod_dprintf(mod,
+ "failed to set FRU FMRI for node_0x%llx\n",
+ (uint64_t)mde_node);
+ }
+
+ result = pi_set_label(mod, mdp, mde_node, t_node);
+ if (result != 0) {
+ /*
+ * Though we have failed to set the label, we still continue.
+ * The module errno is set by the called routine, so we report
+ * the problem and move on.
+ */
+ topo_mod_dprintf(mod, "failed to set label for node_0x%llx\n",
+ (uint64_t)mde_node);
+ }
+
+ result = pi_set_auth(mod, mdp, mde_node, t_parent, t_node);
+ if (result != 0) {
+ /*
+ * Though we have failed to set the authority, we still
+ * continue. The module errno is set by the called routine, so
+ * we report the problem and move on.
+ */
+ topo_mod_dprintf(mod, "failed to set authority for "
+ "node_0x%llx\n", (uint64_t)mde_node);
+ }
+
+ result = pi_set_system(mod, t_node);
+ if (result != 0) {
+ /*
+ * Though we have failed to set the system group, we still
+ * continue. The module errno is set by the called routine, so
+ * we report the problem and move on.
+ */
+ topo_mod_dprintf(mod, "failed to set system for node_0x%llx\n",
+ (uint64_t)mde_node);
+ }
+
+ return (t_node);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_top.c Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,63 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Create a topology node for a top level PRI node, one that is a child
+ * of the 'components' node.
+ */
+#include <sys/types.h>
+#include <strings.h>
+#include <sys/fm/protocol.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include "pi_impl.h"
+
+#define _ENUM_NAME "enum_top"
+
+/*
+ * This enumerator is the same as the generic enumerator, except that when
+ * the FMRI is created, the parent node must be NULL. This is true for all
+ * top level nodes.
+ */
+int
+pi_enum_top(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+ topo_instance_t inst, tnode_t *t_parent, const char *hc_name,
+ tnode_t **t_node)
+{
+ int result;
+
+ /*
+ * This is a top-level topology node and there is no resource data
+ * from which to generate an FMRI. We use a NULL value for the FMRI
+ * parent when creating the FMRI for this node so that the underlying
+ * libtopo method does not fail.
+ */
+ result = pi_enum_generic_impl(mod, mdp, mde_node, inst, t_parent,
+ NULL, hc_name, _ENUM_NAME, t_node);
+ return (result);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_walker.c Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,754 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Walk the LDOM PRI component nodes and create appropriate topology nodes
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <strings.h>
+#include <string.h>
+#include <libuutil.h>
+#include <libnvpair.h>
+#include <sys/mdesc.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include "pi_impl.h"
+
+#define PI_STR_MIN "instance_min"
+#define PI_STR_MAX "instance_max"
+
+/*
+ * Allow for custom topo node creation routines based on topo-hc-name.
+ */
+struct pi_enum_functions_s {
+ pi_enum_fn_t *func;
+ char *hc_name; /* topo-hc-name */
+};
+typedef struct pi_enum_functions_s pi_enum_functions_t;
+
+/*
+ * List of custom enumerators for PRI nodes that require them. The most
+ * common nodes are listed first.
+ */
+static pi_enum_functions_t pi_enum_fns_builtin[] = {
+ {pi_enum_cpu, CPU},
+ {pi_enum_pciexrc, PCIEX_ROOT},
+ {pi_enum_niu, NIU},
+ {NULL, NULL}
+};
+static nvlist_t *pi_enum_fns;
+
+
+/*
+ * In order to create a topology node from a PRI MDE node we need to know the
+ * topology parent node that should be used. So, after creating a topology
+ * node from an MDE node, we associate children of the MDE node with the new
+ * topology node. Thus, when the children are visited we can know the
+ * appropriate parent topology node to use.
+ *
+ * We take advantage of the libtopo threading model here, which guarantees a
+ * single thread and a single invocation at a time for an enumerator. This
+ * makes using a file-global safe.
+ */
+static uu_list_pool_t *walker_pool;
+static uu_list_t *walker_list;
+
+struct pi_walkernode_s {
+ uu_list_node_t walker_node;
+ tnode_t *t_parent; /* Parent topology node */
+ mde_cookie_t mde_node; /* Child MDE node index */
+};
+typedef struct pi_walkernode_s pi_walkernode_t;
+
+
+/* The routine called for each node in the PRI while walking the graph */
+static int pi_walker_node(md_t *, mde_cookie_t, mde_cookie_t, void *);
+
+/*
+ * Create a sub-range for a given PRI node and associate the given topology
+ * node with the children.
+ */
+static int pi_walker_node_range(topo_mod_t *, md_t *, tnode_t *, mde_cookie_t);
+static int pi_walker_node_create(topo_mod_t *, md_t *, mde_cookie_t, tnode_t *,
+ topo_instance_t, tnode_t **);
+
+/* Routines to handle the list of topology parents and mde_nodes */
+static int pi_walkerlist_compare(const void *, const void *, void *);
+static int pi_walkerlist_create(topo_mod_t *);
+static void pi_walkerlist_destroy(topo_mod_t *);
+static int pi_walkerlist_add(topo_mod_t *, tnode_t *, mde_cookie_t);
+static int pi_walkerlist_addtype(topo_mod_t *, nvlist_t *, char *, uint32_t,
+ uint32_t);
+static int pi_walkerlist_find(topo_mod_t *, mde_cookie_t, tnode_t **);
+
+
+int
+pi_walker_init(topo_mod_t *mod)
+{
+ int result;
+ pi_enum_functions_t *fp;
+
+ result = topo_mod_nvalloc(mod, &pi_enum_fns, NV_UNIQUE_NAME);
+ if (result != 0) {
+ topo_mod_dprintf(mod, "pi_walker_init failed\n");
+ return (-1);
+ }
+
+ /* Add the builtin functions to the list */
+ fp = pi_enum_fns_builtin;
+ while (fp != NULL && fp->hc_name != NULL) {
+ uint64_t faddr;
+
+ faddr = (uint64_t)(uintptr_t)*(fp->func);
+ result = nvlist_add_uint64(pi_enum_fns, fp->hc_name, faddr);
+ if (result != 0) {
+ topo_mod_dprintf(mod, "pi_walker_init failed\n");
+ nvlist_free(pi_enum_fns);
+ return (-1);
+ }
+ fp++;
+ }
+
+ return (0);
+}
+
+
+void
+pi_walker_fini(topo_mod_t *mod)
+{
+ topo_mod_dprintf(mod, "pi_walker_fini: enter\n");
+ nvlist_free(pi_enum_fns);
+}
+
+
+/*
+ * Begin to walk the machine description array starting at the given PRI node.
+ */
+int
+pi_walker(pi_enum_t *pip, tnode_t *t_parent, const char *hc_name,
+ mde_cookie_t mde_node, mde_str_cookie_t component_cookie,
+ mde_str_cookie_t arc_cookie)
+{
+ int result;
+ hrtime_t starttime;
+ hrtime_t endtime;
+ topo_mod_t *mod;
+
+ if (pip == NULL) {
+ return (-1);
+ }
+ mod = pip->mod;
+
+ starttime = gethrtime();
+ topo_mod_dprintf(mod, "walker starting at node_0x%llx\n",
+ mde_node);
+
+ /*
+ * Create a list to store topology nodes and their associated machine
+ * description index. This allows the code to know the parent of a
+ * node when creating topology entries.
+ */
+ result = pi_walkerlist_create(mod);
+ if (result != 0) {
+ topo_mod_dprintf(mod, "walker could not create list\n");
+ return (result);
+ }
+
+ /* Create a walker node for the parent of the start node */
+ result = pi_walkerlist_add(mod, t_parent, mde_node);
+ if (result != 0) {
+ pi_walkerlist_destroy(mod);
+ topo_mod_dprintf(mod, "walker could not add to list\n");
+ topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
+ return (result);
+ }
+
+ /*
+ * This is a top-level node. Make sure we call the top level
+ * enumerator if there is not already a custom enumerator registered.
+ */
+ if (! nvlist_exists(pi_enum_fns, hc_name)) {
+ uint64_t faddr;
+
+ /*
+ * There is no enumerator function registered for this
+ * hc name. Automatically register the top level node
+ * enumerator function.
+ */
+ faddr = (uint64_t)(uintptr_t)pi_enum_top;
+ result = nvlist_add_uint64(pi_enum_fns, hc_name, faddr);
+ if (result != 0) {
+ pi_walkerlist_destroy(mod);
+ topo_mod_dprintf(mod,
+ "walker could not register enumerator for type "
+ "%s\n", hc_name);
+ topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
+ return (-1);
+ }
+ topo_mod_dprintf(mod,
+ "walker registered pi_enum_top enumerator for type %s\n",
+ hc_name);
+ }
+
+ /* Walk the machine description list starting at the given node */
+ result = md_walk_dag(pip->mdp, mde_node, component_cookie, arc_cookie,
+ pi_walker_node, (void *)pip);
+ switch (result) {
+ case 0:
+ /* Successful completion */
+ /* DO NOTHING */
+ break;
+
+ case MDE_WALK_ERROR:
+ /*
+ * Store that we have a partial enumeration and return
+ * that we have encountered an error.
+ */
+ topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+ result = -1;
+ break;
+
+ default:
+ /*
+ * This should not happen. We want to always produce
+ * as complete a topology as possible, even in the face
+ * of errors, however, so set an error and continue.
+ */
+ topo_mod_dprintf(mod,
+ "walker encountered invalid result: %d. "
+ "Continuing\n", result);
+ topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
+ result = 0;
+ break;
+ }
+
+ /* Destroy the walker list, which is no longer necessary */
+ pi_walkerlist_destroy(mod);
+
+ topo_mod_dprintf(mod, "walker done with node_0x%llx\n", mde_node);
+
+ endtime = gethrtime();
+ topo_mod_dprintf(mod, "walker scan time %lld ms\n",
+ (endtime-starttime)/MICROSEC);
+
+ return (result);
+}
+
+
+/*
+ * Visited once for each node in the machine description. Creates a topo
+ * node for the machine description node and associates it with it's parent,
+ * by calling an appropriate creation routine for the node type.
+ *
+ * Output:
+ * This routine returns MDE_WALK_NEXT, MDE_WALK_DONE or MDE_WALK_ERROR
+ * only.
+ */
+static int
+pi_walker_node(md_t *mdp, mde_cookie_t parent_mde_node, mde_cookie_t mde_node,
+ void *private)
+{
+ int result;
+ pi_enum_t *pip = (pi_enum_t *)private;
+ uint64_t skip; /* flag in md to skip this node */
+ tnode_t *t_parent; /* topo parent to this md node */
+ tnode_t *t_node; /* topo parent to this md node */
+ topo_instance_t inst;
+
+ topo_mod_t *mod;
+
+ /* Make sure we have our private data */
+ if (pip == NULL) {
+ return (MDE_WALK_ERROR);
+ }
+ mod = pip->mod;
+
+ topo_mod_dprintf(pip->mod,
+ "walker processing node_0x%llx parent node 0x%llx\n",
+ (uint64_t)mde_node, (uint64_t)parent_mde_node);
+
+ /* Should we skip this node ? */
+ skip = pi_skip_node(mod, pip->mdp, mde_node);
+ if (skip) {
+ /* Skip this node and continue to the next node */
+ topo_mod_dprintf(mod, "walker skipping node_0x%llx\n",
+ (uint64_t)mde_node);
+ return (MDE_WALK_NEXT);
+ }
+
+ result = pi_get_instance(mod, mdp, mde_node, &inst);
+ if (result != 0) {
+ /*
+ * No ID available to place this mde node in the topology so
+ * we cannot create a topology node.
+ */
+ topo_mod_dprintf(mod, "walker skipping node_0x%llx: "
+ "no instance\n", (uint64_t)mde_node);
+ topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+ return (MDE_WALK_NEXT);
+ }
+
+ /*
+ * Find the parent topo node for this machine description node.
+ *
+ * If found, the element will also be removed from the list and the
+ * memory used to keep track of it released. We will only visit an
+ * MDE node once and so the memory is no longer needed.
+ */
+ t_parent = NULL;
+ result = pi_walkerlist_find(mod, mde_node, &t_parent);
+ if (result != 0 || t_parent == NULL) {
+ /*
+ * No parent was found or a NULL parent encountered. We
+ * cannot create a new topology node without a parent (
+ * even for top level nodes). We associate children of
+ * this MDE node with a NULL parent to silently skip the
+ * remainder of this MDE branch.
+ */
+ topo_mod_dprintf(mod, "no topo parent found for node_0x%llx\n",
+ mde_node);
+ result = pi_walker_node_range(mod, mdp, NULL, mde_node);
+ topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+
+ return (result);
+ }
+
+ /*
+ * We have the mde node instance and parent information.
+ * Attempt to create a topology node for this mde node.
+ */
+ t_node = NULL;
+ result = pi_walker_node_create(mod, mdp, mde_node, t_parent, inst,
+ &t_node);
+ if (result != MDE_WALK_NEXT || t_node == NULL) {
+ /*
+ * We have failed to create a new topology node based on
+ * the current MDE node. We set partial enumeration and
+ * return without associating the children of this MDE
+ * node with a topology parent. This will propgate the
+ * creation error down this MDE branch.
+ */
+ topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+ return (result);
+ }
+
+ /*
+ * Associate the new topology node with any children of this mde node.
+ */
+ result = pi_walker_node_range(mod, mdp, t_node, mde_node);
+
+ topo_mod_dprintf(mod, "walker completed node_0x%llx result = %d\n",
+ (uint64_t)mde_node, result);
+
+ return (result);
+}
+
+
+static int
+pi_walker_node_create(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+ tnode_t *t_parent, topo_instance_t inst, tnode_t **t_node)
+{
+ int result;
+ char *hc_name;
+ uint64_t faddr;
+ pi_enum_fn_t *func;
+
+ if (t_parent == NULL) {
+ /*
+ * A parent topology node is required even for top-level
+ * nodes.
+ */
+ return (MDE_WALK_NEXT);
+ }
+
+ /*
+ * Find the topo-hc-name for this node which is used to find
+ * the specific creation function
+ */
+ hc_name = pi_get_topo_hc_name(mod, mdp, mde_node);
+ if (hc_name == NULL) {
+ /* Cannot get the hc-name */
+ topo_mod_dprintf(mod,
+ "failed to find hc-name for node_0x%llx\n", mde_node);
+ return (MDE_WALK_NEXT);
+ }
+
+ /* Determine the topology node creation routine to use */
+ func = pi_enum_generic;
+ faddr = 0;
+ result = nvlist_lookup_uint64(pi_enum_fns, hc_name, &faddr);
+ if (result == 0) {
+ /*
+ * A function is registered for this node. Convert the
+ * address to a pointer to function
+ */
+ func = (pi_enum_fn_t *)(uintptr_t)faddr;
+ }
+
+ /*
+ * Create a topology node for this mde node by calling the identified
+ * enumeration function
+ */
+ *t_node = NULL;
+ result = (func)(mod, mdp, mde_node, inst, t_parent, hc_name, t_node);
+ if (result != 0) {
+ topo_mod_dprintf(mod,
+ "failed to create topo entry for node_0x%llx type %s\n",
+ (uint64_t)mde_node, hc_name);
+ }
+ topo_mod_strfree(mod, hc_name);
+
+ return (MDE_WALK_NEXT);
+}
+
+
+/*
+ * Scan the children of a given MDE node and find all the sets of topo-hc-name
+ * types and their instance ranges. From this information we create topology
+ * node ranges on the given parent so that when the children are visited and a
+ * topology node is created, the range exists and the creation will succeed.
+ */
+static int
+pi_walker_node_range(topo_mod_t *mod, md_t *mdp, tnode_t *t_parent,
+ mde_cookie_t mde_node)
+{
+ int result;
+ int rc;
+ int num_arcs;
+ nvlist_t *typelist;
+ nvpair_t *nvp;
+ mde_cookie_t *arcp;
+ size_t arcsize;
+ int arcidx;
+ char *hc_name;
+ nvlist_t *hc_range;
+ topo_instance_t inst;
+ uint32_t min;
+ uint32_t max;
+
+ if (t_parent == NULL) {
+ topo_mod_dprintf(mod,
+ "walker failed to create node range with a NULL parent\n");
+ return (MDE_WALK_NEXT);
+ }
+
+ /* Determine how many children the given node has */
+ num_arcs = md_get_prop_arcs(mdp, mde_node, MD_STR_FWD, NULL, 0);
+ if (num_arcs == 0) {
+ /* This node has no children */
+ return (MDE_WALK_NEXT);
+ }
+ topo_mod_dprintf(mod, "node_0x%llx has %d children\n",
+ (uint64_t)mde_node, num_arcs);
+
+ /* Get the indexes for all the child nodes and put them in an array */
+ arcsize = sizeof (mde_cookie_t) * num_arcs;
+ arcp = topo_mod_zalloc(mod, arcsize);
+ if (arcp == NULL) {
+ topo_mod_dprintf(mod, "out of memory\n");
+ topo_mod_seterrno(mod, EMOD_NOMEM);
+ return (MDE_WALK_ERROR);
+ }
+ num_arcs = md_get_prop_arcs(mdp, mde_node, MD_STR_FWD, arcp, arcsize);
+
+ /*
+ * The children of the given node may have multiple types.
+ * Potentially, each child may have a different type and we need to
+ * create a topo node range for each one.
+ *
+ * We loop through the children and collect the type information for
+ * each one and associate the child with the given parent topo node.
+ */
+ result = topo_mod_nvalloc(mod, &typelist, NV_UNIQUE_NAME);
+ if (result != 0) {
+ topo_mod_free(mod, arcp, arcsize);
+ topo_mod_seterrno(mod, EMOD_NOMEM);
+ return (MDE_WALK_ERROR);
+ }
+
+ arcidx = 0;
+ for (arcidx = 0; arcidx < num_arcs; arcidx++) {
+ /* Should this node be skipped? */
+ if (pi_skip_node(mod, mdp, arcp[arcidx])) {
+ /* Skip this node */
+ topo_mod_dprintf(mod, "skipping node_0x%llx\n",
+ (uint64_t)arcp[arcidx]);
+ continue;
+ }
+
+ /* Get the type of this node */
+ hc_name = pi_get_topo_hc_name(mod, mdp, arcp[arcidx]);
+ rc = pi_get_instance(mod, mdp, arcp[arcidx], &inst);
+ if (rc == 0 && hc_name != NULL) {
+ /* Increment the count of nodes with this type */
+ hc_range = NULL;
+ rc = nvlist_lookup_nvlist(typelist, hc_name, &hc_range);
+ if (rc != 0) {
+ /*
+ * We have not visited this type yet. Create
+ * a new range based on this nodes instance
+ * information.
+ */
+ result = pi_walkerlist_addtype(mod, typelist,
+ hc_name, (uint32_t)inst, (uint32_t)inst);
+ if (result != 0) {
+ /*
+ * This error can only if there was a
+ * memory failure of some kind. Stop
+ * the walk or it will just get worse.
+ */
+ nvlist_free(typelist);
+ topo_mod_strfree(mod, hc_name);
+ topo_mod_free(mod, arcp, arcsize);
+ topo_mod_seterrno(mod,
+ EMOD_PARTIAL_ENUM);
+ return (MDE_WALK_ERROR);
+ }
+
+ /*
+ * We know the list exists now or the above
+ * would have failed. Just look it up.
+ */
+ (void) nvlist_lookup_nvlist(typelist, hc_name,
+ &hc_range);
+ }
+
+ /* Re-calculate the range minimums and maximums */
+ (void) nvlist_lookup_uint32(hc_range, PI_STR_MIN, &min);
+ (void) nvlist_lookup_uint32(hc_range, PI_STR_MAX, &max);
+ min = MIN(min, (uint32_t)inst);
+ max = MAX(max, (uint32_t)inst);
+ (void) nvlist_add_uint32(hc_range, PI_STR_MIN, min);
+ (void) nvlist_add_uint32(hc_range, PI_STR_MAX, max);
+
+ } else {
+ topo_mod_dprintf(mod, "node_0x%llx type %s has no id. "
+ "Excluding from range", (uint64_t)arcp[arcidx],
+ hc_name);
+ }
+ topo_mod_strfree(mod, hc_name);
+
+ /*
+ * Associate this node with the given topo parent even if it
+ * has no instance. We do this so that later an error with
+ * the PRI node will be reported instead of an internal
+ * error about not being able to find the parent of a node
+ */
+ rc = pi_walkerlist_add(mod, t_parent, arcp[arcidx]);
+ if (rc != 0) {
+ topo_mod_dprintf(mod,
+ "could not add node_0x%llx to walker list\n",
+ (uint64_t)arcp[arcidx]);
+ }
+ }
+
+ /*
+ * We have associated all the child nodes with the given topo parent
+ * in the walker list. Now we need to create topo ranges for each
+ * set of child types under the parent.
+ */
+ nvp = nvlist_next_nvpair(typelist, NULL);
+ while (nvp != NULL) {
+ /* Get the type name and count from the list element */
+ hc_name = nvpair_name(nvp);
+ (void) nvpair_value_nvlist(nvp, &hc_range);
+ (void) nvlist_lookup_uint32(hc_range, PI_STR_MIN, &min);
+ (void) nvlist_lookup_uint32(hc_range, PI_STR_MAX, &max);
+
+ /*
+ * We have the number of children with this type.
+ * Create an appropriate range.
+ */
+ topo_mod_dprintf(mod,
+ "creating instance range %d to %d of type %s\n",
+ min, max, hc_name);
+ rc = topo_node_range_create(mod, t_parent, hc_name,
+ (topo_instance_t)min, (topo_instance_t)max);
+ if (rc != 0) {
+ topo_mod_dprintf(mod,
+ "failed to created node range %d to %d for "
+ "nodes of type %s\n", min, max, hc_name);
+ }
+
+ /* Check the next node */
+ nvp = nvlist_next_nvpair(typelist, nvp);
+ }
+ topo_mod_free(mod, arcp, arcsize);
+ nvlist_free(typelist);
+
+ return (MDE_WALK_NEXT);
+}
+
+
+static int
+pi_walkerlist_addtype(topo_mod_t *mod, nvlist_t *typelist, char *hc_name,
+ uint32_t min, uint32_t max)
+{
+ int result;
+ nvlist_t *nvl;
+
+ result = topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME);
+ if (result != 0) {
+ return (result);
+ }
+
+ /* Create min and max elements in this list */
+ if (nvlist_add_uint32(nvl, PI_STR_MIN, min) != 0 ||
+ nvlist_add_uint32(nvl, PI_STR_MAX, max) != 0 ||
+ nvlist_add_nvlist(typelist, hc_name, nvl) != 0) {
+ nvlist_free(nvl);
+ return (-1);
+ }
+ nvlist_free(nvl);
+
+ return (0);
+}
+
+
+/* ARGSUSED */
+static int
+pi_walkerlist_compare(const void *left, const void *right, void *private)
+{
+ pi_walkernode_t *lp = (pi_walkernode_t *)left;
+ pi_walkernode_t *rp = (pi_walkernode_t *)right;
+
+ if (lp->mde_node > rp->mde_node) {
+ return (1);
+ }
+ if (lp->mde_node < rp->mde_node) {
+ return (-1);
+ }
+ return (0);
+}
+
+
+static int
+pi_walkerlist_create(topo_mod_t *mod)
+{
+ /* Initialize the uutil list structure */
+ walker_pool = uu_list_pool_create("pi_walker_pool",
+ sizeof (pi_walkernode_t), offsetof(pi_walkernode_t, walker_node),
+ pi_walkerlist_compare, NULL);
+ if (walker_pool == NULL) {
+ topo_mod_seterrno(mod, EMOD_NOMEM);
+ return (-1);
+ }
+ walker_list = uu_list_create(walker_pool, NULL, 0);
+ if (walker_list == NULL) {
+ uu_list_pool_destroy(walker_pool);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+static void
+pi_walkerlist_destroy(topo_mod_t *mod)
+{
+ void *wvp;
+ pi_walkernode_t *wp;
+
+ /* Destroy our list of items */
+ while ((wvp = uu_list_first(walker_list)) != NULL) {
+ /*
+ * First, we empty the list of elements and free each one.
+ * We do not free the data elements as they are libtopo nodes
+ * and will be freed by libtopo
+ */
+ wp = (pi_walkernode_t *)wvp;
+ uu_list_remove(walker_list, wvp);
+ uu_list_node_fini(wp, &(wp->walker_node), walker_pool);
+
+ topo_mod_free(mod, wvp, sizeof (pi_walkernode_t));
+ }
+ uu_list_destroy(walker_list);
+ uu_list_pool_destroy(walker_pool);
+}
+
+
+static int
+pi_walkerlist_add(topo_mod_t *mod, tnode_t *t_parent, mde_cookie_t mde_node)
+{
+ uu_list_index_t idx;
+ pi_walkernode_t *wnp;
+
+ wnp = topo_mod_zalloc(mod, sizeof (pi_walkernode_t));
+ if (wnp == NULL) {
+ topo_mod_dprintf(mod, "failed to add node_0x%llx parent %p\n",
+ (uint64_t)mde_node, t_parent);
+ return (-1);
+ }
+ uu_list_node_init(wnp, &(wnp->walker_node), walker_pool);
+
+ wnp->t_parent = t_parent;
+ wnp->mde_node = mde_node;
+
+ (void) uu_list_find(walker_list, wnp, NULL, &idx);
+ uu_list_insert(walker_list, wnp, idx);
+
+ return (0);
+}
+
+
+/*
+ * Find the parent topo node for this machine description node.
+ *
+ * Nodes are removed from the list as they are found. They are only
+ * visited once and this eliminates the need for a separate routine
+ * that walks the list to free elements later.
+ */
+static int
+pi_walkerlist_find(topo_mod_t *mod, mde_cookie_t mde_node, tnode_t **tpp)
+{
+ pi_walkernode_t *result;
+
+ uu_list_index_t idx;
+ pi_walkernode_t search_criteria;
+
+ search_criteria.mde_node = mde_node;
+ search_criteria.t_parent = NULL;
+
+ *tpp = NULL;
+ result = uu_list_find(walker_list, &search_criteria, NULL, &idx);
+ if (result == NULL) {
+ return (-1);
+ }
+ *tpp = result->t_parent;
+
+ /* Remove this element from the list */
+ uu_list_remove(walker_list, result);
+ uu_list_node_fini(result, &(result->walker_node), walker_pool);
+ topo_mod_free(mod, result, sizeof (pi_walkernode_t));
+
+ return (0);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/sun4vpi.c Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,289 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Main entry points for SUN4V Platform Independent topology enumerator
+ */
+#include <sys/types.h>
+#include <strings.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include <sys/systeminfo.h>
+#include <pi_impl.h>
+
+/*
+ * Entry point called by libtopo when enumeration is required
+ */
+static topo_enum_f pi_enum; /* libtopo enumeration entry point */
+
+
+/*
+ * Declare the operations vector and information structure used during
+ * module registration
+ */
+static topo_modops_t pi_ops = {pi_enum, NULL};
+static topo_modinfo_t pi_modinfo = {
+ SUN4VPI_DESC, SUN4VPI_SCHEME, SUN4VPI_VERSION, &pi_ops
+};
+
+static int pi_enum_components(pi_enum_t *, tnode_t *, const char *,
+ mde_cookie_t, mde_str_cookie_t, mde_str_cookie_t);
+
+
+/*
+ * Called by libtopo when the topo module is loaded.
+ */
+void
+_topo_init(topo_mod_t *mod, topo_version_t version)
+{
+ int result;
+ char isa[MAXNAMELEN];
+
+ if (getenv("TOPOSUN4VPIDBG") != NULL) {
+ /* Debugging is requested for this module */
+ topo_mod_setdebug(mod);
+ }
+ topo_mod_dprintf(mod, "sun4vpi module initializing.\n");
+
+ if (version != TOPO_VERSION) {
+ topo_mod_seterrno(mod, EMOD_VER_NEW);
+ topo_mod_dprintf(mod, "incompatible topo version %d\n",
+ version);
+ return;
+ }
+
+ /* Verify that this is a SUN4V architecture machine */
+ (void) sysinfo(SI_MACHINE, isa, MAXNAMELEN);
+ if (strncmp(isa, "sun4v", MAXNAMELEN) != 0) {
+ topo_mod_dprintf(mod, "not sun4v architecture: %s\n", isa);
+ return;
+ }
+
+ result = topo_mod_register(mod, &pi_modinfo, TOPO_VERSION);
+ if (result < 0) {
+ topo_mod_dprintf(mod, "registration failed: %s\n",
+ topo_mod_errmsg(mod));
+
+ /* module errno already set */
+ return;
+ }
+ topo_mod_dprintf(mod, "module ready.\n");
+}
+
+
+/*
+ * Clean up any data used by the module before it is unloaded.
+ */
+void
+_topo_fini(topo_mod_t *mod)
+{
+ topo_mod_dprintf(mod, "module finishing.\n");
+
+ /* Unregister from libtopo */
+ topo_mod_unregister(mod);
+}
+
+
+/*
+ * Enumeration entry point for the SUN4V topology enumerator
+ */
+/* ARGSUSED */
+static int
+pi_enum(topo_mod_t *mod, tnode_t *t_parent, const char *name,
+ topo_instance_t min, topo_instance_t max, void *pi_private, void *data)
+{
+ int result;
+ int idx;
+ int num_components;
+ size_t csize;
+ hrtime_t starttime;
+
+ pi_enum_t pi;
+
+ mde_cookie_t *components;
+ mde_str_cookie_t arc_cookie;
+ mde_str_cookie_t component_cookie;
+
+ /* Begin enumeration */
+ starttime = gethrtime();
+ topo_mod_dprintf(mod, "enumeration starting.\n");
+
+ /* Initialize the walker */
+ result = pi_walker_init(mod);
+ if (result != 0) {
+ topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
+ return (-1);
+ }
+
+ /* Open a connection to the LDOM PRI */
+ bzero(&pi, sizeof (pi_enum_t));
+ result = pi_ldompri_open(mod, &pi);
+ if (result != 0) {
+ pi_walker_fini(mod);
+ topo_mod_dprintf(mod, "could not open LDOM PRI\n");
+ topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
+ return (-1);
+ }
+ pi.mod = mod;
+
+ /*
+ * Find the top of the components graph in the PRI using the machine
+ * description library.
+ */
+ num_components = pi_find_mdenodes(mod, pi.mdp, MDE_INVAL_ELEM_COOKIE,
+ MD_STR_COMPONENTS, MD_STR_FWD, &components, &csize);
+ if (num_components < 0 || components == NULL) {
+ /* No nodes were found */
+ pi_walker_fini(mod);
+ topo_mod_dprintf(mod, "could not find components in PRI\n");
+ topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
+ return (-1);
+ }
+
+ /*
+ * There should be a single components node. But scan all of the
+ * results just in case a future machine has multiple hierarchies
+ * for some unknown reason.
+ *
+ * We continue to walk components nodes until they are all exhausted
+ * and do not stop if a node cannot be enumerated. Instead, we
+ * enumerate what we can and return a partial-enumeration error if
+ * there is a problem.
+ */
+ topo_mod_dprintf(mod, "enumerating %d components hierarchies\n",
+ num_components);
+
+ component_cookie = md_find_name(pi.mdp, MD_STR_COMPONENT);
+ arc_cookie = md_find_name(pi.mdp, MD_STR_FWD);
+ result = 0;
+ for (idx = 0; idx < num_components; idx++) {
+ int skip;
+
+ /*
+ * We have found a component hierarchy to process. First,
+ * make sure we are not supposed to skip the graph.
+ */
+ skip = pi_skip_node(mod, pi.mdp, components[idx]);
+ if (skip == 0) {
+ /*
+ * We have found a components node. Find the top-
+ * level nodes and create a topology tree from them.
+ */
+ result = pi_enum_components(&pi, t_parent, name,
+ components[idx], component_cookie, arc_cookie);
+ }
+ }
+ topo_mod_free(mod, components, csize);
+
+ /* Close our connection to the PRI */
+ pi_ldompri_close(mod, &pi);
+
+ /* Clean up after the walker */
+ pi_walker_fini(mod);
+
+ /* Complete enumeration */
+ topo_mod_dprintf(mod, "enumeration complete in %lld ms.\n",
+ ((gethrtime() - starttime)/MICROSEC));
+
+ /* All done */
+ return (result);
+}
+
+
+/*
+ * This routined is called once for each mde node of type 'components'. It
+ * initiates enumeration of the graph starting with with this node.
+ */
+static int
+pi_enum_components(pi_enum_t *pip, tnode_t *t_parent, const char *hc_name,
+ mde_cookie_t mde_node, mde_str_cookie_t component_cookie,
+ mde_str_cookie_t arc_cookie)
+{
+ int result;
+
+ int num_arcs;
+ mde_cookie_t *arcp;
+ size_t arcsize;
+ int arcidx;
+
+ topo_mod_t *mod = pip->mod;
+ md_t *mdp = pip->mdp;
+
+ if (t_parent == NULL) {
+ topo_mod_dprintf(mod,
+ "walker failed to create node range with a NULL parent\n");
+ topo_mod_seterrno(mod, EMOD_METHOD_INVAL);
+ return (-1);
+ }
+
+ /* Determine how many children the given node has */
+ num_arcs = md_get_prop_arcs(mdp, mde_node, MD_STR_FWD, NULL, 0);
+ if (num_arcs == 0) {
+ /*
+ * This components node has no children and is not a topo
+ * node itself, so set partial enumeration and return.
+ */
+ topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+ return (0);
+ }
+ topo_mod_dprintf(mod, "node_0x%llx has %d children\n",
+ (uint64_t)mde_node, num_arcs);
+
+ /* Get the indexes for all the child nodes and put them in an array */
+ arcsize = sizeof (mde_cookie_t) * num_arcs;
+ arcp = topo_mod_zalloc(mod, arcsize);
+ if (arcp == NULL) {
+ topo_mod_dprintf(mod, "out of memory\n");
+ topo_mod_seterrno(mod, EMOD_NOMEM);
+ return (-1);
+ }
+ num_arcs = md_get_prop_arcs(mdp, mde_node, MD_STR_FWD, arcp,
+ arcsize);
+
+ result = 0;
+ for (arcidx = 0; arcidx < num_arcs; arcidx++) {
+ /*
+ * Initiate walking the PRI graph starting with the current
+ * child of the components node.
+ */
+ result = pi_walker(pip, t_parent, hc_name,
+ arcp[arcidx], component_cookie, arc_cookie);
+ if (result != 0) {
+ topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+ }
+ }
+ topo_mod_free(mod, arcp, arcsize);
+
+ /*
+ * We have now walked the entire PRI graph. Execute any deferred
+ * enumeration routines that need all the nodes to be available.
+ */
+ result = pi_defer_exec(mod, mdp);
+
+ return (result);
+}
--- a/usr/src/pkgdefs/SUNWfmd/prototype_sparc Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/pkgdefs/SUNWfmd/prototype_sparc Mon Jul 28 15:46:04 2008 -0700
@@ -145,6 +145,7 @@
f none usr/platform/sun4v/lib/fm/topo/plugins/platform-mem.so 555 root bin
f none usr/platform/sun4v/lib/fm/topo/plugins/motherboard.so 555 root bin
f none usr/platform/sun4v/lib/fm/topo/plugins/niu.so 555 root bin
+f none usr/platform/sun4v/lib/fm/topo/plugins/sun4vpi.so 555 root bin
f none usr/platform/sun4v/lib/fm/topo/plugins/xaui.so 555 root bin
f none usr/platform/sun4v/lib/fm/topo/plugins/zambezi.so 555 root bin
d none usr/platform/SUNW,SPARC-Enterprise 755 root sys
--- a/usr/src/uts/common/sys/mdesc.h Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/uts/common/sys/mdesc.h Mon Jul 28 15:46:04 2008 -0700
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -114,6 +114,33 @@
/*
+ * Walk callback function return codes
+ */
+#define MDE_WALK_ERROR -1 /* Terminate walk with error */
+#define MDE_WALK_NEXT 0 /* Continue to next node */
+#define MDE_WALK_DONE 1 /* Terminate walk with success */
+
+/*
+ * The function prototype for a walker callback function.
+ * The machine description session, parent node, current node,
+ * and private data are given to the callback.
+ *
+ * The parent node is given to the callback to provide context
+ * on how the walker arrived at this location. While the node
+ * may have many parents, it will be visited only once, this
+ * provides context on how the walker arrived at the node.
+ *
+ * Input Description
+ * ------------------- ----------------------------------------
+ * md_t * Pointer to md session
+ * mde_cookie_t Index of parent node to provide context
+ * mde_cookie_t The current node in the walk
+ * void * Private data for the walking function
+ */
+typedef int md_walk_fn_t(md_t *, mde_cookie_t, mde_cookie_t, void *);
+
+
+/*
* External Interface
*/
@@ -139,6 +166,13 @@
mde_str_cookie_t,
mde_cookie_t *);
+extern int md_walk_dag(md_t *,
+ mde_cookie_t,
+ mde_str_cookie_t,
+ mde_str_cookie_t,
+ md_walk_fn_t,
+ void *);
+
extern int md_get_prop_val(md_t *,
mde_cookie_t,
char *,
@@ -155,6 +189,13 @@
uint8_t **,
int *);
+extern int md_get_prop_arcs(md_t *,
+ mde_cookie_t,
+ char *,
+ mde_cookie_t *,
+ size_t);
+
+
extern md_diff_cookie_t md_diff_init(md_t *,
mde_cookie_t,
md_t *,