Mercurial > illumos > illumos-gate
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);