summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Pothier <Tom.Pothier@Sun.COM>2010-07-29 13:03:36 -0400
committerTom Pothier <Tom.Pothier@Sun.COM>2010-07-29 13:03:36 -0400
commitfc33347812f84907261f6fd501e2409da108b8d8 (patch)
tree2af1c6c7532a015b5874432626b87036ed47d299
parent4c56998a4a895e2885b4848d6753357edccb6436 (diff)
downloadillumos-joyent-fc33347812f84907261f6fd501e2409da108b8d8.tar.gz
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()
-rw-r--r--usr/src/lib/fm/libmdesc/Makefile.com4
-rw-r--r--usr/src/lib/fm/libmdesc/common/mapfile-vers1
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/hc.c1
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_hc.h1
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/sun4vpi/Makefile6
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_bay.c496
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_impl.h16
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_subr.c311
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_walker.c12
9 files changed, 817 insertions, 31 deletions
diff --git a/usr/src/lib/fm/libmdesc/Makefile.com b/usr/src/lib/fm/libmdesc/Makefile.com
index a282a11a85..7d3f814c59 100644
--- a/usr/src/lib/fm/libmdesc/Makefile.com
+++ b/usr/src/lib/fm/libmdesc/Makefile.com
@@ -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 @@ LIBSRCS = \
mdesc_findname.c \
mdesc_findnodeprop.c \
mdesc_getproparcs.c \
+ mdesc_getpropdata.c \
mdesc_getpropstr.c \
mdesc_getpropval.c \
mdesc_init_intern.c \
diff --git a/usr/src/lib/fm/libmdesc/common/mapfile-vers b/usr/src/lib/fm/libmdesc/common/mapfile-vers
index 794766921e..3ba3cfd4fc 100644
--- a/usr/src/lib/fm/libmdesc/common/mapfile-vers
+++ b/usr/src/lib/fm/libmdesc/common/mapfile-vers
@@ -44,6 +44,7 @@ SYMBOL_VERSION SUNWprivate {
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;
diff --git a/usr/src/lib/fm/topo/libtopo/common/hc.c b/usr/src/lib/fm/topo/libtopo/common/hc.c
index fce1a159e5..2bec088639 100644
--- a/usr/src/lib/fm/topo/libtopo/common/hc.c
+++ b/usr/src/lib/fm/topo/libtopo/common/hc.c
@@ -157,6 +157,7 @@ static const hcc_t hc_canon[] = {
{ 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 },
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
index 13df1c0157..1c3a92f804 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
@@ -54,6 +54,7 @@ extern "C" {
#define FAN "fan"
#define FANBOARD "fanboard"
#define FANMODULE "fanmodule"
+#define HBA "hba"
#define HOSTBRIDGE "hostbridge"
#define INTERCONNECT "interconnect"
#define IOBOARD "ioboard"
diff --git a/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/Makefile b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/Makefile
index 44132ff40d..455c3219c2 100644
--- a/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/Makefile
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/Makefile
@@ -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 @@ TOPODIR = ../../../libtopo/common
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
diff --git a/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_bay.c b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_bay.c
new file mode 100644
index 0000000000..a655fb09fc
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_bay.c
@@ -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);
+}
diff --git a/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_impl.h b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_impl.h
index b42f55f6eb..bcc5353017 100644
--- a/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_impl.h
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_impl.h
@@ -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 @@ extern "C" {
#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_generic; /* Enumerate a generic PRI node */
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 @@ void pi_walker_fini(topo_mod_t *);
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 *,
diff --git a/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_subr.c b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_subr.c
index e15f304582..b31eb28683 100644
--- a/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_subr.c
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_subr.c
@@ -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 @@ pi_skip_node(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
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 @@ pi_get_label(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
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 @@ pi_get_label(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
/*
+ * 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 @@ pi_get_productid(topo_mod_t *mod, md_t *mdp)
/*
+ * 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 @@ pi_get_serverid(topo_mod_t *mod)
/*
- * 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 @@ pi_node_bind(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
/*
* 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);
diff --git a/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_walker.c b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_walker.c
index 707c17083d..c762e5e5c0 100644
--- a/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_walker.c
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_walker.c
@@ -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 @@ static pi_enum_functions_t pi_enum_fns_builtin[] = {
{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 @@ pi_walker_node_range(topo_mod_t *mod, md_t *mdp, tnode_t *t_parent,
(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);