changeset 12968:ed781b340472

FWARC/2010/185 PRI Changes for Direct Attached Disks 6903121 sun4v PI enumeration for directly attached disks 6940217 sun4vpi debug msg can dump core 6948399 libmdesc should export md_get_prop_data()
author Tom Pothier <Tom.Pothier@Sun.COM>
date Thu, 29 Jul 2010 13:03:36 -0400
parents 1e73c8f5a88b
children 9d6fa5bd011f
files usr/src/lib/fm/libmdesc/Makefile.com usr/src/lib/fm/libmdesc/common/mapfile-vers usr/src/lib/fm/topo/libtopo/common/hc.c usr/src/lib/fm/topo/libtopo/common/topo_hc.h usr/src/lib/fm/topo/modules/sun4v/sun4vpi/Makefile usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_bay.c usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_impl.h usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_subr.c usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_walker.c
diffstat 9 files changed, 817 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/lib/fm/libmdesc/Makefile.com	Thu Jul 29 08:59:51 2010 -0700
+++ b/usr/src/lib/fm/libmdesc/Makefile.com	Thu Jul 29 13:03:36 2010 -0400
@@ -19,8 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 LIBRARY = libmdesc.a
@@ -31,6 +30,7 @@
 	mdesc_findname.c \
 	mdesc_findnodeprop.c \
 	mdesc_getproparcs.c \
+	mdesc_getpropdata.c \
 	mdesc_getpropstr.c \
 	mdesc_getpropval.c \
 	mdesc_init_intern.c \
--- a/usr/src/lib/fm/libmdesc/common/mapfile-vers	Thu Jul 29 08:59:51 2010 -0700
+++ b/usr/src/lib/fm/libmdesc/common/mapfile-vers	Thu Jul 29 13:03:36 2010 -0400
@@ -44,6 +44,7 @@
 	md_find_node_prop;
 	md_fini;
 	md_get_prop_arcs;
+	md_get_prop_data;
 	md_get_prop_str;
 	md_get_prop_val;
 	md_init_intern;
--- a/usr/src/lib/fm/topo/libtopo/common/hc.c	Thu Jul 29 08:59:51 2010 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/hc.c	Thu Jul 29 13:03:36 2010 -0400
@@ -157,6 +157,7 @@
 	{ FAN, TOPO_STABILITY_PRIVATE },
 	{ FANBOARD, TOPO_STABILITY_PRIVATE },
 	{ FANMODULE, TOPO_STABILITY_PRIVATE },
+	{ HBA, TOPO_STABILITY_PRIVATE },
 	{ HOSTBRIDGE, TOPO_STABILITY_PRIVATE },
 	{ INTERCONNECT, TOPO_STABILITY_PRIVATE },
 	{ IOBOARD, TOPO_STABILITY_PRIVATE },
--- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h	Thu Jul 29 08:59:51 2010 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h	Thu Jul 29 13:03:36 2010 -0400
@@ -54,6 +54,7 @@
 #define	FAN		"fan"
 #define	FANBOARD	"fanboard"
 #define	FANMODULE	"fanmodule"
+#define	HBA		"hba"
 #define	HOSTBRIDGE	"hostbridge"
 #define	INTERCONNECT	"interconnect"
 #define	IOBOARD		"ioboard"
--- a/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/Makefile	Thu Jul 29 08:59:51 2010 -0700
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/Makefile	Thu Jul 29 13:03:36 2010 -0400
@@ -20,8 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 MODULE	= sun4vpi
@@ -31,7 +30,8 @@
 
 MODULESRCS =	pi_defer.c pi_ldom.c pi_walker.c pi_subr.c \
 		pi_cpu.c pi_mem.c pi_generic.c pi_pciexrc.c \
-		pi_hostbridge.c pi_niu.c pi_top.c sun4vpi.c pi_meth.c
+		pi_hostbridge.c pi_niu.c pi_top.c sun4vpi.c \
+		pi_meth.c pi_bay.c
 
 include ../../Makefile.plugin
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_bay.c	Thu Jul 29 13:03:36 2010 -0400
@@ -0,0 +1,496 @@
+/*
+ * 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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * Create a topology node for a PRI node of type 'bay'. Call the disk
+ * enumerator to enumerate any disks that may be attached.
+ */
+
+#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 <sys/pci.h>
+#include <sys/mdesc.h>
+#include "pi_impl.h"
+
+#define	_ENUM_NAME	"enum_bay"
+#define	HBA_DRV_NAME	"mpt_sas"
+#define	DEVICES		"/devices"
+
+#define	PI_BAY_AP	DDI_NT_SCSI_ATTACHMENT_POINT
+#define	PI_MAX_LUN	255
+
+static boolean_t MPxIO_ENABLED = B_FALSE;
+
+static const topo_pgroup_info_t io_pgroup = {
+	TOPO_PGROUP_IO,
+	TOPO_STABILITY_PRIVATE,
+	TOPO_STABILITY_PRIVATE,
+	1
+};
+
+static const topo_pgroup_info_t binding_pgroup = {
+	TOPO_PGROUP_BINDING,
+	TOPO_STABILITY_PRIVATE,
+	TOPO_STABILITY_PRIVATE,
+	1
+};
+
+
+/*
+ * Return the MPxIO occupant path bay property.
+ *
+ * The string must be freed with topo_mod_strfree().
+ */
+static char *
+pi_bay_ocpath(topo_mod_t *mod, di_node_t dnode)
+{
+
+	int		lun;
+	boolean_t	got_w;
+	char		buf[MAXPATHLEN];
+	char		*tgt_port = NULL;
+
+	/* 'target-port' property */
+	tgt_port = pi_get_target_port(mod, dnode);
+	if (tgt_port == NULL) {
+		topo_mod_dprintf(mod, "pi_bay_ocpath: failed to get "
+		    "'target-port' property\n");
+		return (NULL);
+	}
+
+	/* 'lun' property */
+	lun = pi_get_lun(mod, dnode);
+	if (lun < 0 || lun > PI_MAX_LUN) {
+		topo_mod_dprintf(mod, "pi_bay_ocpath: failed to get 'lun' "
+		    "property\n");
+		topo_mod_strfree(mod, tgt_port);
+		return (NULL);
+	}
+
+	/* 'target-port' leading 'w' is not consistent */
+	got_w = tgt_port[0] == 'w' ? B_TRUE : B_FALSE;
+
+	/*
+	 * Build occupatnt path:
+	 * 'devfs_path' + "/disk@w" + 'target-port' + "," + 'lun'
+	 */
+	(void) snprintf(buf, MAXPATHLEN, "%s%s%s,%x", di_devfs_path(dnode),
+	    (got_w ? "/disk@" : "/disk@w"), tgt_port, lun);
+
+	topo_mod_strfree(mod, tgt_port);
+	return (topo_mod_strdup(mod, buf));
+}
+
+
+/*
+ * Create bay "io" pgroup, create and add "ap_path" property.
+ * Create bay "binding" pgroup, create and add "oc_path" property.
+ */
+static int
+pi_bay_pgroups(topo_mod_t *mod, tnode_t *t_node, di_node_t cnode,
+    di_minor_t cminor)
+{
+	int	rv;
+	int	err;
+	char	*ap_path;
+	char	*oc_path;
+
+	/* Create "io" pgroup and attachment point. */
+	rv = topo_pgroup_create(t_node, &io_pgroup, &err);
+	if (rv != 0) {
+		topo_mod_dprintf(mod, "pi_bay_pgroups: failed to create "
+		    "\"io\" pgroup: %s\n", topo_mod_seterrno(mod, err));
+		return (err);
+	}
+
+	/*
+	 * Create the ap_path property:
+	 */
+	ap_path = topo_mod_alloc(mod, MAXPATHLEN);
+	if (ap_path == NULL) {
+		topo_mod_dprintf(mod, "pi_bay_pgroups: EMOD_NOMEM for "
+		    "ap_path\n");
+		return (topo_mod_seterrno(mod, EMOD_NOMEM));
+	}
+
+	/* attachment point path: "/devices" + minor node path */
+	(void) snprintf(ap_path, MAXPATHLEN, "%s%s", DEVICES,
+	    di_devfs_minor_path(cminor));
+	topo_mod_dprintf(mod, "pi_bay_pgroups: ap_path (%s)\n", ap_path);
+
+	/* add ap_path prop to io pgroup */
+	rv = topo_prop_set_string(t_node, TOPO_PGROUP_IO, TOPO_IO_AP_PATH,
+	    TOPO_PROP_IMMUTABLE, ap_path, &err);
+	if (rv != 0) {
+		topo_mod_dprintf(mod, "pi_bay_pgroups: failed to set "
+		    "ap-path: %s\n", topo_strerror(err));
+		topo_mod_free(mod, ap_path, MAXPATHLEN);
+		(void) topo_mod_seterrno(mod, err);
+		return (err);
+	}
+	topo_mod_free(mod, ap_path, MAXPATHLEN);
+
+	/* Create "binding" pgroup */
+	rv = topo_pgroup_create(t_node, &binding_pgroup, &err);
+	if (rv != 0) {
+		topo_mod_dprintf(mod, "pi_bay_pgroups: failed to "
+		    "create \"binding\" pgroup: %s\n", topo_strerror(err));
+		(void) topo_mod_seterrno(mod, err);
+		return (err);
+	}
+
+	/*
+	 * Create the oc_path property:
+	 */
+	if (MPxIO_ENABLED) {
+		oc_path = pi_bay_ocpath(mod, cnode);
+	} else {
+		oc_path = di_devfs_path(cnode);
+	}
+	if (oc_path == NULL) {
+		topo_mod_dprintf(mod, "pi_bay_pgroups: no occupant path\n");
+		return (-1);
+	}
+	topo_mod_dprintf(mod, "pi_bay_proups: oc_path (%s)\n", oc_path);
+
+	/* add oc_path to binding pgroup */
+	rv = topo_prop_set_string(t_node, TOPO_PGROUP_BINDING,
+	    TOPO_BINDING_OCCUPANT, TOPO_PROP_IMMUTABLE, oc_path, &err);
+	if (rv != 0) {
+		topo_mod_dprintf(mod, "pi_bay_pgroups: failed to set "
+		    "oc_path: %s\n", topo_strerror(err));
+		(void) topo_mod_seterrno(mod, err);
+		rv = err;
+	}
+
+	if (MPxIO_ENABLED) {
+		topo_mod_strfree(mod, oc_path);
+	} else {
+		di_devfs_path_free(oc_path);
+	}
+	return (rv);
+}
+
+
+/*
+ * Find the child devinfo node of the HBA that matches the PHY, capture the
+ * minor attachment point node.
+ */
+static void
+pi_bay_find_nodes(topo_mod_t *mod, di_node_t *nodep, di_node_t *sibp,
+    di_minor_t *minorp, int phy)
+{
+	di_node_t	sib = DI_NODE_NIL;
+	di_node_t	gsib = DI_NODE_NIL;
+	di_minor_t	minor = DI_MINOR_NIL;
+
+	/*
+	 * When MPxIO is enabled the child node of the HBA (iport) contains
+	 * the pathinfo property we're looking for; when MPxIO is disabled
+	 * the grand-child of the HBA (disk) contains the devinfo property
+	 * we're looking for.
+	 */
+	sib = di_child_node(*nodep);
+	while (sib != DI_NODE_NIL) {
+		/* match the PHY */
+		if (phy == pi_get_phynum(mod, sib)) {
+			while ((minor = di_minor_next(sib, minor)) !=
+			    DI_MINOR_NIL) {
+				/* scsi attachment point */
+				if (strncmp(di_minor_nodetype(minor),
+				    PI_BAY_AP,
+				    strlen(di_minor_nodetype(minor))) == 0) {
+					goto out;
+				}
+			}
+		} else {
+			/* look in grandchildren */
+			gsib = di_child_node(sib);
+			while (gsib != DI_NODE_NIL) {
+				/* match the PHY */
+				if (phy == pi_get_phynum(mod, gsib)) {
+					while ((minor = di_minor_next(sib,
+					    minor)) != DI_MINOR_NIL) {
+						/* scsi attachment point */
+						if (strncmp(
+						    di_minor_nodetype(minor),
+						    PI_BAY_AP,
+						    strlen(di_minor_nodetype(
+						    minor))) == 0) {
+							sib = gsib;
+							goto out;
+						}
+					}
+				}
+				gsib = di_sibling_node(gsib);
+			}
+		}
+		sib = di_sibling_node(sib);
+	}
+out:
+	if (sib == DI_NODE_NIL) {
+		*sibp = DI_NODE_NIL;
+	} else {
+		bcopy(&sib, sibp, sizeof (di_node_t));
+	}
+
+	if (minor == DI_MINOR_NIL) {
+		*minorp = DI_MINOR_NIL;
+	} else {
+		bcopy(&minor, minorp, sizeof (di_minor_t));
+	}
+}
+
+
+/*
+ * Decoreate "bay" node with required properties for disk enumerator.
+ */
+static int
+pi_bay_update_node(topo_mod_t *mod, tnode_t *t_node, uint8_t phy,
+    char *pri_path)
+{
+	int		rv;
+	char		*hba_path;
+	char		*mpxio_prop;
+	di_node_t	devtree;
+	di_node_t	dnode, sib;
+	di_minor_t	minor = DI_MINOR_NIL;
+
+	/*
+	 * The hba path and bay PHY come from the PRI; find the
+	 * driver node that coresponds to the PHY and it's minor
+	 * node name and create the occupant path/attachmeent_point
+	 * path
+	 */
+	devtree = di_init("/", DINFOFORCE | DINFOSUBTREE | DINFOMINOR |
+	    DINFOPROP | DINFOPATH);
+
+	for (dnode = di_drv_first_node(HBA_DRV_NAME, devtree);
+	    dnode != DI_NODE_NIL;
+	    dnode = di_drv_next_node(dnode)) {
+		/* find the dnode path that matches the pri path */
+		hba_path = pi_get_dipath(mod, dnode);
+		if (strcmp(pri_path, hba_path) == 0) {
+			/* found our dnode */
+			topo_mod_strfree(mod, hba_path);
+			break;
+		}
+		topo_mod_strfree(mod, hba_path);
+	}
+	if (dnode == DI_NODE_NIL) {
+		topo_mod_dprintf(mod, "pi_bay_update_node: failed to find "
+		    "devinfo path.\n");
+		return (-1);
+	}
+
+	/*
+	 * The "mpxio-disable" variable determines if MPxIO (multipathing)
+	 * is disabled (or enabled).
+	 */
+	if (di_prop_lookup_strings(DDI_DEV_T_ANY, dnode, "mpxio-disable",
+	    &mpxio_prop) < 0) {
+		/* no way to determine if MPxIO is enabled */
+		topo_mod_dprintf(mod,
+		    "pi_bay_update_node: no \"mpxio-disable\" property\n");
+		return (-1);
+	}
+
+	/* set MPxIO_ENABLED inverse to "mpxio-disable" */
+	topo_mod_dprintf(mod, "\"mpxio-disable\" = (%s)\n", mpxio_prop);
+	MPxIO_ENABLED = strncmp("no", mpxio_prop, strlen(mpxio_prop)) == 0 ?
+	    B_TRUE : B_FALSE;
+	topo_mod_dprintf(mod, "MPxIO_ENABLED: %s\n", MPxIO_ENABLED ? "TRUE" :
+	    "FALSE");
+
+	/*
+	 * Find the child node matching the PRI phy_number and determine the
+	 * minor attachment point.
+	 */
+	pi_bay_find_nodes(mod, &dnode, &sib, &minor, phy);
+	if (sib == DI_NODE_NIL || minor == DI_MINOR_NIL) {
+		topo_mod_dprintf(mod, "pi_bay_update_node: no disk on "
+		    "PHY %d.\n", phy);
+		return (-1);
+	}
+
+	/* add pgroups */
+	rv = pi_bay_pgroups(mod, t_node, sib, minor);
+	if (rv != 0) {
+		topo_mod_dprintf(mod, "pi_bay_update_node: failed to add "
+		    "pgroups.\n", _ENUM_NAME);
+		return (rv);
+	}
+	return (0);
+}
+
+/* ARGSUSED */
+int
+pi_enum_bay(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		i, rv;
+	int		min = 0, max = 0;
+	int		num_arcs;
+	int		nphy;
+	size_t		arcsize;
+	uint8_t		*phy = NULL;
+	char		*hba_pri_path;
+	mde_cookie_t	*arcp;
+
+	/* count how many PHYs the bay node has */
+	nphy = pi_get_priphy(mod, mdp, mde_node, phy);
+	if (nphy <= 0) {
+		topo_mod_dprintf(mod, "%s: node_0x%llx has no PHY\n",
+		    _ENUM_NAME, (uint64_t)mde_node);
+		return (-1);
+	}
+
+	phy = topo_mod_alloc(mod, (nphy * sizeof (uint8_t)));
+	if (phy == NULL) {
+		topo_mod_dprintf(mod, "%s: node_0x%llx ENOMEM\n",
+		    _ENUM_NAME, (uint64_t)mde_node);
+		return (-1);
+	}
+
+	/* get the PHY(s) for this bay node */
+	rv = pi_get_priphy(mod, mdp, mde_node, phy);
+	if (rv != nphy) {
+		topo_mod_dprintf(mod, "%s: node_0x%llx failed to get PHY\n",
+		    _ENUM_NAME, (uint64_t)mde_node);
+		return (-1);
+	}
+	topo_mod_dprintf(mod, "%s: node_0x%llx PHY: %d\n", _ENUM_NAME,
+	    mde_node, *phy);
+
+	/* determine how many parent (HBA) nodes */
+	num_arcs = md_get_prop_arcs(mdp, mde_node, MD_STR_BACK, NULL, 0);
+	if (num_arcs == 0) {
+		topo_mod_dprintf(mod, "%s: node_0x%llx has no \"back\" arcs\n",
+		    _ENUM_NAME, (uint64_t)mde_node);
+		return (-1); /* return partial here? */
+	}
+	topo_mod_dprintf(mod, "%s: node_0x%llx has %d \"back\" arcs\n",
+	    _ENUM_NAME, mde_node, num_arcs);
+
+	/* get the "back" nodes */
+	arcsize = sizeof (mde_cookie_t) * num_arcs;
+	arcp = topo_mod_zalloc(mod, arcsize);
+	if (arcp == NULL) {
+		topo_mod_dprintf(mod, "%s: no memory\n", _ENUM_NAME);
+		(void) topo_mod_seterrno(mod, EMOD_NOMEM);
+		return (-1);
+	}
+	num_arcs = md_get_prop_arcs(mdp, mde_node, MD_STR_BACK, arcp, arcsize);
+
+	/* make sure there are as many HBA nodes as PHYs */
+	if (num_arcs != nphy) {
+		topo_mod_dprintf(mod, "%s: %d PHYs for %d back arcs.\n",
+		    _ENUM_NAME, nphy, num_arcs);
+		return (-1);
+	}
+
+	/* create topo bay node for each HBA attached to this bay */
+	for (i = 0; i < num_arcs; i++) {
+		/* skip if topo-hc-skip = 1 */
+		if (pi_skip_node(mod, mdp, arcp[i])) {
+			topo_mod_dprintf(mod, "%s: skipping node_0x%llx\n",
+			    (uint64_t)arcp[i]);
+			continue;
+		}
+
+		/*
+		 * Create a generic "bay" node; decorate below.
+		 *
+		 * If we have more than one HBA the bay inst here will be
+		 * the same for both. This is okay since the paths will
+		 * be different for each HBA.
+		 */
+		rv = pi_enum_generic_impl(mod, mdp, mde_node, inst, t_parent,
+		    t_parent, hc_name, _ENUM_NAME, t_node, 0);
+		if (rv != 0 || *t_node == NULL) {
+			topo_mod_dprintf(mod,
+			    "%s: node_0x%llx failed to create topo node: %s\n",
+			    _ENUM_NAME, (uint64_t)mde_node,
+			    topo_strerror(topo_mod_errno(mod)));
+			return (rv);
+		}
+
+		/* must be an ses expander if no path property - skip */
+		rv = md_get_prop_str(mdp, arcp[i], MD_STR_PATH, &hba_pri_path);
+		if (rv != 0 || hba_pri_path == NULL ||
+		    strlen(hba_pri_path) == 0) {
+			topo_mod_dprintf(mod, "%s: node_0x%llx: no path "
+			    "property\n", _ENUM_NAME, (uint64_t)arcp[i]);
+			continue;
+		}
+
+		/* Decorate the bay tnode */
+		rv = pi_bay_update_node(mod, *t_node, phy[i], hba_pri_path);
+		if (rv != 0) {
+			topo_mod_dprintf(mod, "%s: failed to update "
+			    "node_0x%llx.\n", _ENUM_NAME, (uint64_t)mde_node);
+			continue;
+		}
+
+
+		/*
+		 * Call the disk enum passing in decorated bay tnode.
+		 */
+		if (topo_mod_load(mod, DISK, TOPO_VERSION) == NULL) {
+			topo_mod_dprintf(mod,
+			    "%s: Failed to load %s module: %s\n",
+			    _ENUM_NAME, DISK,
+			    topo_strerror(topo_mod_errno(mod)));
+			return (topo_mod_errno(mod));
+		}
+
+		rv = topo_node_range_create(mod, *t_node, DISK, min, max);
+		if (rv != 0) {
+			topo_mod_dprintf(mod,
+			    "%s: failed to create range: %s\n", _ENUM_NAME,
+			    topo_strerror(topo_mod_errno(mod)));
+			return (topo_mod_errno(mod));
+		}
+
+		rv = topo_mod_enumerate(mod, *t_node, DISK, DISK, min, max,
+		    NULL);
+		if (rv != 0) {
+			topo_mod_dprintf(mod,
+			    "%s: %s enumeration failed: %s\n", _ENUM_NAME,
+			    DISK, topo_strerror(topo_mod_errno(mod)));
+			return (topo_mod_errno(mod));
+		}
+	}
+
+	/* clean up */
+	topo_mod_free(mod, arcp, arcsize);
+	topo_mod_free(mod, phy, (nphy * sizeof (uint8_t)));
+	return (0);
+}
--- a/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_impl.h	Thu Jul 29 08:59:51 2010 -0700
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_impl.h	Thu Jul 29 13:03:36 2010 -0400
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _PI_IMPL_H
@@ -66,6 +65,7 @@
 #define	MD_STR_NAME		"name"
 #define	MD_STR_PART_NUMBER	"part_number"		/* FWARC/2008/300 */
 #define	MD_STR_PATH		"path"
+#define	MD_STR_PHY_NUMBER	"phy_number"		/* FWARC/2010/185 */
 #define	MD_STR_PLATFORM		"platform"
 #define	MD_STR_PRODUCT		"product"		/* FWARC/2009/390 */
 #define	MD_STR_REVISION_NUMBER	"rev_number"		/* FWARC/2008/300 */
@@ -107,6 +107,7 @@
 pi_enum_fn_t	pi_enum_niu;		/* Enumerate an NIU node */
 pi_enum_fn_t	pi_enum_hostbridge;	/* Enumerate a hostbridge node */
 pi_enum_fn_t	pi_enum_pciexrc;	/* Enumerate a PCIEX root complex */
+pi_enum_fn_t	pi_enum_bay;		/* Enumerate a bay PRI node */
 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,
@@ -145,18 +146,23 @@
 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);
+char   *pi_get_dipath(topo_mod_t *, di_node_t);
 char   *pi_get_productsn(topo_mod_t *, md_t *, mde_cookie_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_fru(topo_mod_t *, md_t *, mde_cookie_t, int *);
 int	pi_get_instance(topo_mod_t *, md_t *, mde_cookie_t, topo_instance_t *);
+char   *pi_get_label(topo_mod_t *, md_t *, mde_cookie_t);
+int	pi_get_lun(topo_mod_t *, di_node_t);
 char   *pi_get_part(topo_mod_t *, md_t *, mde_cookie_t);
 char   *pi_get_path(topo_mod_t *, md_t *, mde_cookie_t);
 char   *pi_get_productid(topo_mod_t *, md_t *);
+int	pi_get_priphy(topo_mod_t *, md_t *, mde_cookie_t, uint8_t *);
+int	pi_get_phynum(topo_mod_t *, di_node_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);
+char   *pi_get_target_port(topo_mod_t *, di_node_t);
+char   *pi_get_topo_hc_name(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 *,
--- a/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_subr.c	Thu Jul 29 08:59:51 2010 -0700
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_subr.c	Thu Jul 29 13:03:36 2010 -0400
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 
@@ -42,7 +41,11 @@
 
 #include "pi_impl.h"
 
-#define	MAX_PATH_DEPTH	(MAXPATHLEN / 256)	/* max pci path = 256 */
+/* max pci path = 256 */
+#define	MAX_PATH_DEPTH	(MAXPATHLEN / 256)
+
+/* max pci path + child + minor */
+#define	MAX_DIPATH_DEPTH	(MAX_PATH_DEPTH + 2)
 
 static const topo_pgroup_info_t sys_pgroup = {
 	TOPO_PGROUP_SYSTEM,
@@ -143,6 +146,77 @@
 	return (0);
 }
 
+
+/*
+ * Build a device path without device names (PRI like) from a devinfo
+ * node. Return the PRI like path.
+ *
+ * The string must be freed with topo_mod_strfree()
+ */
+char *
+pi_get_dipath(topo_mod_t *mod, di_node_t dnode)
+{
+	int	i, j, rv;
+	int	depth = 0;
+	char	*bus_addr[MAX_DIPATH_DEPTH] = { NULL };
+	char	*dev_path[MAX_DIPATH_DEPTH] = { NULL };
+	char	*path = NULL;
+	size_t	path_len = 0;
+
+	/* loop through collecting bus addresses */
+	do {
+		/* stop at '/' */
+		if (strcmp(di_devfs_path(dnode), "/") == 0) {
+			break;
+		}
+
+		if (depth < MAX_DIPATH_DEPTH) {
+			bus_addr[depth] = topo_mod_strdup(mod,
+			    di_bus_addr(dnode));
+			++depth;
+		} else {
+			topo_mod_dprintf(mod, "pi_get_dipath: path too "
+			    "long (%d)\n", depth);
+			return (NULL);
+		}
+	} while ((dnode = di_parent_node(dnode)) != DI_NODE_NIL);
+
+	/* prepend '/@' to each bus address */
+	for (i = (depth - 1), j = 0; i >= 0; --i, j++) {
+		int len = strlen(bus_addr[i]) + strlen("/@") + 1;
+		path_len += len;
+		dev_path[j] = (char *)topo_mod_alloc(mod, len);
+		rv = snprintf(dev_path[j], len, "/@%s", bus_addr[i]);
+		if (rv < 0) {
+			return (NULL);
+		}
+	}
+
+	/*
+	 * Build the path from the bus addresses.
+	 */
+	path_len -= (depth - 1); /* leave room for one null char */
+	path = (char *)topo_mod_alloc(mod, path_len);
+	path = strcpy(path, dev_path[0]);
+
+	for (i = 1; i < depth; i++) {
+		path = strncat(path, dev_path[i], strlen(dev_path[i]) + 1);
+	}
+
+	for (i = 0; i < depth; i++) {
+		if (bus_addr[i] != NULL) {
+			topo_mod_strfree(mod, bus_addr[i]);
+		}
+		if (dev_path[i] != NULL) {
+			topo_mod_strfree(mod, dev_path[i]);
+		}
+	}
+
+	topo_mod_dprintf(mod, "pi_get_dipath: path (%s)\n", path);
+	return (path);
+}
+
+
 /*
  * Get the product serial number (the ID as far as the topo authority is
  * concerned) either from the current node, if it is of type 'product', or
@@ -380,12 +454,23 @@
 	int	result;
 	int	is_fru;
 	char	*lp = NULL;
+	char	*hc_name = pi_get_topo_hc_name(mod, mdp, mde_node);
 
-	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 disk enumerator will set the "bay" node as a FRU and
+	 * expect the label from the PRI. The "fru" property can not
+	 * be set because hostconfig has no way to set the S/N, P/N,
+	 * etc.. in the PRI.
+	 */
+	if (strncmp(hc_name, BAY, strlen(BAY)) != 0) {
+		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 */
+			topo_mod_strfree(mod, hc_name);
+			return (NULL);
+		}
 	}
+	topo_mod_strfree(mod, hc_name);
 
 	/*
 	 * The node is a FRU.  Get the NAC name to use as a label.
@@ -402,6 +487,56 @@
 
 
 /*
+ * Return the "lun" property.
+ */
+int
+pi_get_lun(topo_mod_t *mod, di_node_t node)
+{
+	int		lun;
+	int		*buf;
+	unsigned char	*chbuf;
+	di_prop_t	di_prop = DI_PROP_NIL;
+	di_path_t	dpath = DI_PATH_NIL;
+	di_path_prop_t	di_path_prop = DI_PROP_NIL;
+
+	/* look for pathinfo property */
+	while ((dpath = di_path_phci_next_path(node, dpath)) != DI_PATH_NIL) {
+		while ((di_path_prop =
+		    di_path_prop_next(dpath, di_path_prop)) != DI_PROP_NIL) {
+			if (strcmp("lun",
+			    di_path_prop_name(di_path_prop)) == 0) {
+				(void) di_path_prop_ints(di_path_prop, &buf);
+				bcopy(buf, &lun, sizeof (int));
+				goto found;
+			}
+		}
+	}
+
+	/* look for devinfo property */
+	for (di_prop = di_prop_next(node, DI_PROP_NIL);
+	    di_prop != DI_PROP_NIL;
+	    di_prop = di_prop_next(node, di_prop)) {
+		if (strncmp("lun", di_prop_name(di_prop),
+		    strlen(di_prop_name(di_prop))) == 0) {
+			if (di_prop_bytes(di_prop, &chbuf) < sizeof (uint_t)) {
+				continue;
+			}
+			bcopy(chbuf, &lun, sizeof (uint_t));
+			goto found;
+		}
+	}
+
+	if (di_prop == DI_PROP_NIL && (dpath == DI_PATH_NIL ||
+	    di_path_prop == DI_PROP_NIL)) {
+		return (-1);
+	}
+found:
+	topo_mod_dprintf(mod, "pi_get_lun: lun = (%d)\n", lun);
+	return (lun);
+}
+
+
+/*
  * 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.
@@ -591,6 +726,88 @@
 
 
 /*
+ * If the phy pointer is NULL just return the number of 'phy_number' properties
+ * from the PRI; otherwise pass the 'phy_number' property values back to the
+ * caller.
+ *
+ * The caller is responsible for managing allocated memory.
+ */
+int
+pi_get_priphy(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node, uint8_t *phyp)
+{
+	int	result;
+	uint8_t	*phy_num;
+	int	nphy;
+
+	result = md_get_prop_data(mdp, mde_node, MD_STR_PHY_NUMBER,
+	    &phy_num, &nphy);
+	if (result != 0) {
+		/* no phy_number property */
+		topo_mod_dprintf(mod,
+		    "node_0x%llx has no phy_number property\n",
+		    (uint64_t)mde_node);
+		return (-1);
+	}
+
+	if (phyp != NULL) {
+		bcopy(phy_num, phyp, nphy);
+	}
+	return (nphy);
+}
+
+
+/*
+ * Return "phy-num" devinfo/pathinfo property.
+ */
+int
+pi_get_phynum(topo_mod_t *mod, di_node_t node)
+{
+	int		phy;
+	int		*buf;
+	unsigned char	*chbuf;
+	di_prop_t	di_prop = DI_PROP_NIL;
+	di_path_t	dpath = DI_PATH_NIL;
+	di_path_prop_t	di_path_prop = DI_PROP_NIL;
+
+
+	/* look for pathinfo property */
+	while ((dpath = di_path_phci_next_path(node, dpath)) != DI_PATH_NIL) {
+		while ((di_path_prop =
+		    di_path_prop_next(dpath, di_path_prop)) != DI_PROP_NIL) {
+			if (strcmp("phy-num",
+			    di_path_prop_name(di_path_prop)) == 0) {
+				(void) di_path_prop_ints(di_path_prop, &buf);
+				bcopy(buf, &phy, sizeof (int));
+				goto found;
+			}
+		}
+	}
+
+	/* look for devinfo property */
+	for (di_prop = di_prop_next(node, DI_PROP_NIL);
+	    di_prop != DI_PROP_NIL;
+	    di_prop = di_prop_next(node, di_prop)) {
+		if (strncmp("phy-num", di_prop_name(di_prop),
+		    strlen("phy-num")) == 0) {
+			if (di_prop_bytes(di_prop, &chbuf) < sizeof (uint_t)) {
+				continue;
+			}
+			bcopy(chbuf, &phy, sizeof (uint_t));
+			goto found;
+		}
+	}
+
+	if (di_prop == DI_PROP_NIL && (dpath == DI_PATH_NIL ||
+	    di_path_prop == DI_PROP_NIL)) {
+		return (-1);
+	}
+found:
+	topo_mod_dprintf(mod, "pi_get_phynum: phy = %d\n", phy);
+	return (phy);
+}
+
+
+/*
  * Return the revision string to the caller.
  *
  * The string must be freed with topo_mod_strfree()
@@ -675,7 +892,58 @@
 
 
 /*
- * Get the hc scheme name for the given node
+ * Return the "target-port" property.
+ *
+ * The string must be freed with topo_mod_strfree()
+ */
+char *
+pi_get_target_port(topo_mod_t *mod, di_node_t node)
+{
+	char		*tport;
+	di_prop_t	di_prop = DI_PROP_NIL;
+	di_path_t	dpath = DI_PATH_NIL;
+	di_path_prop_t	di_path_prop = DI_PROP_NIL;
+
+	/* look for pathinfo property */
+	while ((dpath = di_path_phci_next_path(node, dpath)) != DI_PATH_NIL) {
+		while ((di_path_prop =
+		    di_path_prop_next(dpath, di_path_prop)) != DI_PROP_NIL) {
+			if (strcmp("target-port",
+			    di_path_prop_name(di_path_prop)) == 0) {
+				(void) di_path_prop_strings(di_path_prop,
+				    &tport);
+				goto found;
+			}
+		}
+	}
+
+	/* look for devinfo property */
+	for (di_prop = di_prop_next(node, DI_PROP_NIL);
+	    di_prop != DI_PROP_NIL;
+	    di_prop = di_prop_next(node, di_prop)) {
+		if (strcmp("target-port", di_prop_name(di_prop)) == 0) {
+			if (di_prop_strings(di_prop, &tport) < 0) {
+				continue;
+			}
+			goto found;
+		}
+	}
+
+	if (di_prop == DI_PROP_NIL && (dpath == DI_PATH_NIL ||
+	    di_path_prop == DI_PROP_NIL)) {
+		return (NULL);
+	}
+found:
+	topo_mod_dprintf(mod, "pi_get_target_port: 'target-port' = (%s)\n",
+	    tport);
+	return (topo_mod_strdup(mod, tport));
+}
+
+
+/*
+ * Get the hc scheme name for the given node.
+ *
+ * The string must be freed with topo_mod_strfree()
  */
 char *
 pi_get_topo_hc_name(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
@@ -1131,18 +1399,23 @@
 	/*
 	 * We have bound the node.  Now decorate it with an appropriate
 	 * FRU and label (which may be inherited from the parent).
+	 *
+	 * The disk enumerator requires that 'bay' nodes not set their
+	 * fru property.
 	 */
-	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);
+	if (strncmp(hc_name, BAY, strlen(BAY)) != 0) {
+		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);
--- a/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_walker.c	Thu Jul 29 08:59:51 2010 -0700
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_walker.c	Thu Jul 29 13:03:36 2010 -0400
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -74,6 +73,7 @@
 	{pi_enum_hostbridge,	HOSTBRIDGE},
 	{pi_enum_pciexrc,	PCIEX_ROOT},
 	{pi_enum_niu,		NIU},
+	{pi_enum_bay,		BAY},
 	{NULL, NULL}
 };
 static nvlist_t *pi_enum_fns;
@@ -590,6 +590,14 @@
 			(void) nvlist_add_uint32(hc_range, PI_STR_MAX, max);
 
 		} else {
+			if (hc_name == NULL) {
+				topo_mod_dprintf(mod, "node_0x%llx has no "
+				    "topo_hc_name.", (uint64_t)arcp[arcidx]);
+				(void) topo_mod_seterrno(mod,
+				    EMOD_PARTIAL_ENUM);
+				return (MDE_WALK_ERROR);
+			}
+
 			topo_mod_dprintf(mod, "node_0x%llx type %s has no id. "
 			    "Excluding from range", (uint64_t)arcp[arcidx],
 			    hc_name);