diff options
author | hueston <none@none> | 2006-04-27 18:36:43 -0700 |
---|---|---|
committer | hueston <none@none> | 2006-04-27 18:36:43 -0700 |
commit | 0b6016e6ff70af39f99c9cc28e0c2207c8f5413c (patch) | |
tree | b49c60a8cc469f5a949c5fe22097ab6327bcd9b5 /usr/src | |
parent | f2f278521a1d65f81d30778b7bd252147b2d325f (diff) | |
download | illumos-joyent-0b6016e6ff70af39f99c9cc28e0c2207c8f5413c.tar.gz |
6393267 Need a libtopo enumerator for OPL
Diffstat (limited to 'usr/src')
15 files changed, 864 insertions, 39 deletions
diff --git a/usr/src/lib/fm/topo/files/Makefile b/usr/src/lib/fm/topo/files/Makefile index 8a76e32968..5286fba502 100644 --- a/usr/src/lib/fm/topo/files/Makefile +++ b/usr/src/lib/fm/topo/files/Makefile @@ -25,7 +25,13 @@ # # ident "%Z%%M% %I% %E% SMI" -sparc_SUBDIRS = sun4u sun4v SUNW,Sun-Fire SUNW,Sun-Fire-T200 SUNW,Sun-Fire-15000 +sparc_SUBDIRS = sun4u \ + sun4v \ + SUNW,Sun-Fire \ + SUNW,Sun-Fire-T200 \ + SUNW,Sun-Fire-15000 \ + SUNW,SPARC-Enterprise + i386_SUBDIRS = i86pc SUBDIRS = $($(MACH)_SUBDIRS) diff --git a/usr/src/lib/fm/topo/files/SUNW,SPARC-Enterprise/Makefile b/usr/src/lib/fm/topo/files/SUNW,SPARC-Enterprise/Makefile new file mode 100644 index 0000000000..678a1c9e2d --- /dev/null +++ b/usr/src/lib/fm/topo/files/SUNW,SPARC-Enterprise/Makefile @@ -0,0 +1,34 @@ +# +# 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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +PLATFORMS = SUNW,SPARC-Enterprise +CLASS = platform +DTDFILE = +TOPOFILE = hc-topology.xml +SRCDIR = ../SUNW,SPARC-Enterprise + +include ../Makefile.file diff --git a/usr/src/lib/fm/topo/files/SUNW,SPARC-Enterprise/hc-topology.xml b/usr/src/lib/fm/topo/files/SUNW,SPARC-Enterprise/hc-topology.xml new file mode 100644 index 0000000000..950e1b8fba --- /dev/null +++ b/usr/src/lib/fm/topo/files/SUNW,SPARC-Enterprise/hc-topology.xml @@ -0,0 +1,44 @@ +<?xml version="1.0"?> +<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/topology.dtd.1"> +<!-- + Copyright 2006 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + 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 + + ident "%Z%%M% %I% %E% SMI" +--> + +<topology name='SUNW,SPARC-Enterprise' scheme='hc'> + <range name='chassis' min='0' max='0'> + <node instance='0'> + <propgroup name='protocol'> + <propval name='FRU' type='fmri' + value='hc:///chassis=0' /> + </propgroup> + </node> + <dependents grouping='children'> + <range name='ioboard' min='0' max='15'> + <enum-method name='ioboard' version='1' + path='%r/usr/platform/SUNW,SPARC-Enterprise/lib/fm/topo/plugins' /> + </range> + </dependents> + </range> +</topology> diff --git a/usr/src/lib/fm/topo/libtopo/common/hc_canon.h b/usr/src/lib/fm/topo/libtopo/common/hc_canon.h index 4652fa4ede..732d64e081 100644 --- a/usr/src/lib/fm/topo/libtopo/common/hc_canon.h +++ b/usr/src/lib/fm/topo/libtopo/common/hc_canon.h @@ -49,6 +49,7 @@ static const char *Hc_canon[] = { "dimm", "hostbridge", "interconnect", + "chassis", "ioboard", "memory-controller", "motherboard", diff --git a/usr/src/lib/fm/topo/modules/Makefile b/usr/src/lib/fm/topo/modules/Makefile index 97ab5867d8..b4f7a58aae 100644 --- a/usr/src/lib/fm/topo/modules/Makefile +++ b/usr/src/lib/fm/topo/modules/Makefile @@ -25,7 +25,12 @@ # # ident "%Z%%M% %I% %E% SMI" -sparc_SUBDIRS = sun4u sun4v SUNW,Sun-Fire SUNW,Sun-Fire-15000 +sparc_SUBDIRS = sun4u \ + sun4v \ + SUNW,Sun-Fire \ + SUNW,Sun-Fire-15000 \ + SUNW,SPARC-Enterprise + i386_SUBDIRS = i86pc SUBDIRS = $($(MACH)_SUBDIRS) diff --git a/usr/src/lib/fm/topo/modules/SUNW,SPARC-Enterprise/Makefile b/usr/src/lib/fm/topo/modules/SUNW,SPARC-Enterprise/Makefile new file mode 100644 index 0000000000..122db7a134 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/SUNW,SPARC-Enterprise/Makefile @@ -0,0 +1,32 @@ +# +# 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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" + +SUBDIRS = ioboard + +.PARALLEL: $(SUBDIRS) + +include ../../../Makefile.subdirs diff --git a/usr/src/lib/fm/topo/modules/SUNW,SPARC-Enterprise/ioboard/Makefile b/usr/src/lib/fm/topo/modules/SUNW,SPARC-Enterprise/ioboard/Makefile new file mode 100644 index 0000000000..d1db6ad332 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/SUNW,SPARC-Enterprise/ioboard/Makefile @@ -0,0 +1,36 @@ +# +# 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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" + +CLASS = arch +ARCH = SUNW,SPARC-Enterprise + +MODULE = ioboard +MODULESRCS = opl_ioboard.c opl_hostbridge.c + +include ../../Makefile.plugin + +LDLIBS += -ldevinfo diff --git a/usr/src/lib/fm/topo/modules/SUNW,SPARC-Enterprise/ioboard/opl_hostbridge.c b/usr/src/lib/fm/topo/modules/SUNW,SPARC-Enterprise/ioboard/opl_hostbridge.c new file mode 100644 index 0000000000..ef272feb9c --- /dev/null +++ b/usr/src/lib/fm/topo/modules/SUNW,SPARC-Enterprise/ioboard/opl_hostbridge.c @@ -0,0 +1,251 @@ +/* + * 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 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <string.h> +#include <strings.h> +#include <libdevinfo.h> +#include <fm/topo_mod.h> +#include <sys/fm/protocol.h> +#include "opl_topo.h" + +/* + * Check the root complex device node for a slot-names property. + */ +const char * +opl_get_slot_name(di_node_t n) +{ + di_prom_prop_t pp = DI_PROM_PROP_NIL; + uchar_t *buf; + + for (pp = di_prom_prop_next(opl_promtree, n, pp); + pp != DI_PROM_PROP_NIL; + pp = di_prom_prop_next(opl_promtree, n, pp)) { + if (strcmp(di_prom_prop_name(pp), OPL_SLOT_NAMES) == 0) { + if (di_prom_prop_data(pp, &buf) <= sizeof (uint32_t)) + continue; + return ((const char *)&buf[4]); + } + } + return (NULL); +} + +static tnode_t * +opl_node_create(topo_mod_t *mp, tnode_t *parent, const char *name, int inst, + void *priv) +{ + int err; + tnode_t *node; + nvlist_t *fmri; + nvlist_t *args = NULL; + nvlist_t *pfmri = NULL; + topo_hdl_t *thp = topo_mod_handle(mp); + + if (parent == NULL || inst < 0) { + return (NULL); + } + + /* Get parent FMRI */ + (void) topo_node_resource(parent, &pfmri, &err); + if (pfmri != NULL) { + if (topo_mod_nvalloc(mp, &args, NV_UNIQUE_NAME) != 0 || + nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT, pfmri) + != 0) { + nvlist_free(pfmri); + nvlist_free(args); + (void) topo_mod_seterrno(mp, EMOD_FMRI_NVL); + return (NULL); + } + nvlist_free(pfmri); + } + + /* Create FMRI */ + if ((fmri = topo_fmri_create(thp, FM_FMRI_SCHEME_HC, name, inst, + args, &err)) == NULL) { + topo_mod_dprintf(mp, "create of tnode for %s failed: %s", + name, topo_strerror(topo_mod_errno(mp))); + (void) topo_mod_seterrno(mp, err); + nvlist_free(args); + return (NULL); + } + nvlist_free(args); + + /* Create and bind node */ + node = topo_node_bind(mp, parent, name, inst, fmri, priv); + if (node == NULL) { + nvlist_free(fmri); + topo_mod_dprintf(mp, "unable to bind root complex", + topo_strerror(topo_mod_errno(mp))); + return (NULL); /* mod_errno already set */ + } + nvlist_free(fmri); + return (node); +} + +/* + * Create a root complex node. + */ +static tnode_t * +opl_rc_node_create(topo_mod_t *mp, tnode_t *parent, di_node_t dnode, int inst, + void *priv) +{ + int err; + tnode_t *rcn; + topo_hdl_t *thp = topo_mod_handle(mp); + const char *slot_name; + + rcn = opl_node_create(mp, parent, PCIEXRC, inst, priv); + if (rcn == NULL) { + return (NULL); + } + + /* + * If this root complex connects to a slot, it will have a + * slot-names property. + */ + slot_name = opl_get_slot_name(dnode); + if (slot_name) { + char fru_str[64]; + nvlist_t *fru_fmri; + /* Add FRU fmri */ + snprintf(fru_str, sizeof (fru_str), "hc:///component=%s", + slot_name); + if (topo_fmri_str2nvl(thp, fru_str, &fru_fmri, &err) == 0) { + (void) topo_node_fru_set(rcn, fru_fmri, 0, &err); + nvlist_free(fru_fmri); + } + /* Add label */ + (void) topo_node_label_set(rcn, (char *)slot_name, &err); + } else { + /* Inherit parent FRU's label */ + (void) topo_node_fru_set(rcn, NULL, 0, &err); + (void) topo_node_label_set(rcn, NULL, &err); + } + /* Make room for children */ + topo_node_range_create(mp, rcn, PCIEX_BUS, 0, OPL_BUS_MAX); + return (rcn); +} + +/* + * Create a hostbridge node. + */ +static tnode_t * +opl_hb_node_create(topo_mod_t *mp, tnode_t *parent, int inst) +{ + int err; + tnode_t *hbn; + + hbn = opl_node_create(mp, parent, HOSTBRIDGE, inst, NULL); + if (hbn == NULL) { + return (NULL); + } + + /* Inherit parent FRU's label */ + (void) topo_node_fru_set(hbn, NULL, 0, &err); + (void) topo_node_label_set(hbn, NULL, &err); + + /* Make room for children */ + topo_node_range_create(mp, hbn, PCIEXRC, 0, OPL_RC_MAX); + + return (hbn); +} + +/* + * opl_hb_enum gets the ioboard instance passed in, and determines the + * hostbridge and root complex instances numbers based on the bus addresses. + */ +int +opl_hb_enum(topo_mod_t *mp, const ioboard_contents_t *iob, tnode_t *ion, + int brd) +{ + int hb; + int rc; + di_node_t p; + tnode_t *hbnode; + tnode_t *rcnode; + topo_mod_t *pcimod; + + /* Load the pcibus module. We'll need it later. */ + pcimod = topo_mod_load(mp, PCI_MOD_PATH); + if (pcimod == NULL) { + topo_mod_dprintf(mp, "can't load pcibus module", + topo_strerror(topo_mod_errno(mp))); + return (-1); + } + + /* For each hostbridge on an ioboard... */ + for (hb = 0; hb < OPL_HB_MAX; hb++) { + hbnode = NULL; + /* For each root complex in a hostbridge... */ + for (rc = 0; rc < OPL_RC_MAX; rc++) { + p = iob->rcs[hb][rc]; + /* If no root complex, continue */ + if (p == DI_NODE_NIL) { + continue; + } + + /* The root complex exists! */ + topo_mod_dprintf(mp, "declaring " + "/chassis=0/ioboard=%d/hostbridge=%d/pciexrc=%d\n", + brd, hb, rc); + + /* + * If we haven't created a hostbridge node yet, do it + * now. + */ + if (hbnode == NULL) { + hbnode = opl_hb_node_create(mp, ion, hb); + if (hbnode == NULL) { + topo_mod_dprintf(mp, + "unable to create hbnode: %s", + topo_strerror(topo_mod_errno(mp))); + return (-1); + } + + } + + /* Create the root complex node */ + rcnode = opl_rc_node_create(mp, hbnode, p, rc, p); + if (rcnode == NULL) { + topo_mod_dprintf(mp, + "unable to create rcnode: %s", + topo_strerror(topo_mod_errno(mp))); + return (-1); + } + + /* Enumerate pcibus nodes under the root complex */ + if (topo_mod_enumerate(pcimod, rcnode, + PCI_BUS, PCIEX_BUS, 0, 255) != 0) { + topo_mod_dprintf(mp, + "error enumerating pcibus", + topo_strerror(topo_mod_errno(mp))); + return (-1); + } + } + } + return (0); +} diff --git a/usr/src/lib/fm/topo/modules/SUNW,SPARC-Enterprise/ioboard/opl_ioboard.c b/usr/src/lib/fm/topo/modules/SUNW,SPARC-Enterprise/ioboard/opl_ioboard.c new file mode 100644 index 0000000000..c493e5b184 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/SUNW,SPARC-Enterprise/ioboard/opl_ioboard.c @@ -0,0 +1,298 @@ +/* + * 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 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * SUNW,OPL-Enterprise platform ioboard topology enumerator + */ +#include <string.h> +#include <strings.h> +#include <libdevinfo.h> +#include <fm/topo_mod.h> +#include <sys/fm/protocol.h> +#include "opl_topo.h" + +#define IOB_ENUMR_VERS 1 +#define FRUNAME "iou" +#define LABEL FRUNAME "#%d" +#define IOBDFRU "hc:///component=" LABEL + +static int opl_iob_enum(topo_mod_t *hdl, tnode_t *parent, const char *name, + topo_instance_t imin, topo_instance_t imax, void *notused); + +const topo_modinfo_t IobInfo = { + IOBOARD, + IOB_ENUMR_VERS, + opl_iob_enum, + NULL}; + +di_prom_handle_t opl_promtree = DI_PROM_HANDLE_NIL; +di_node_t opl_devtree; + +void +_topo_init(topo_mod_t *modhdl) +{ + /* + * Turn on module debugging output + */ + if (getenv("TOPOIOBDBG") != NULL) + topo_mod_setdebug(modhdl, TOPO_DBG_ALL); + topo_mod_dprintf(modhdl, "initializing ioboard enumerator\n"); + + topo_mod_register(modhdl, &IobInfo, NULL); +} + +void +_topo_fini(topo_mod_t *modhdl) +{ + topo_mod_unregister(modhdl); +} + +/* + * Checks to see if there's a physical board number property on this + * device node. + */ +static int +opl_get_physical_board(di_node_t n) +{ + di_prom_prop_t pp = DI_PROM_PROP_NIL; + uchar_t *buf; + int val; + + for (pp = di_prom_prop_next(opl_promtree, n, pp); + pp != DI_PROM_PROP_NIL; + pp = di_prom_prop_next(opl_promtree, n, pp)) { + if (strcmp(di_prom_prop_name(pp), OPL_PHYSICAL_BD) == 0) { + if (di_prom_prop_data(pp, &buf) < sizeof (val)) + continue; + bcopy(buf, &val, sizeof (val)); + return (val); + } + } + return (-1); +} + +/* + * Creates a map of logical boards to physical location. + */ +static void +opl_map_boards(int lsb_to_psb[OPL_IOB_MAX]) +{ + di_node_t n; + int i; + + /* Initialize all entries to no mapping */ + for (i = 0; i < OPL_IOB_MAX; i++) { + lsb_to_psb[i] = i; + } + /* + * Get LSB-to-PSB (logical-to-physical board) mapping by finding the + * memory controller driver per LSB. The MC driver will have a + * physical-board# property. + */ + for (n = di_drv_first_node(OPL_MC_DRV, opl_devtree); + n != DI_NODE_NIL; + n = di_drv_next_node(n)) { + char *ba = di_bus_addr(n); + int a = OPL_MC_STR2BA(ba); + int lsb = OPL_MC_LSB(a); + int psb; + + psb = opl_get_physical_board(n); + if (psb < 0 || psb >= OPL_IOB_MAX) { + /* psb mapping is out of range, skip */ + continue; + } + lsb_to_psb[lsb] = psb; + } +} + +/* + * Create the ioboard node. Add fru and label properties, and create room + * for child hostbridge nodes. + */ +static tnode_t * +opl_iob_node_create(topo_mod_t *mp, tnode_t *parent, int inst) +{ + int err; + tnode_t *ion; + nvlist_t *fmri; + nvlist_t *args = NULL; + nvlist_t *pfmri = NULL; + topo_hdl_t *thp = topo_mod_handle(mp); + char label[8]; + char fmri_str[32]; + + if (parent == NULL || inst < 0) { + return (NULL); + } + + /* Get parent FMRI */ + (void) topo_node_resource(parent, &pfmri, &err); + if (pfmri != NULL) { + if (topo_mod_nvalloc(mp, &args, NV_UNIQUE_NAME) != 0 || + nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT, pfmri) + != 0) { + nvlist_free(pfmri); + nvlist_free(args); + (void) topo_mod_seterrno(mp, EMOD_FMRI_NVL); + return (NULL); + } + nvlist_free(pfmri); + } + /* Create ioboard FMRI */ + if ((fmri = topo_fmri_create(thp, FM_FMRI_SCHEME_HC, IOBOARD, inst, + args, &err)) == NULL) { + topo_mod_dprintf(mp, "create of tnode for ioboard failed: %s", + topo_strerror(topo_mod_errno(mp))); + (void) topo_mod_seterrno(mp, err); + nvlist_free(args); + return (NULL); + } + nvlist_free(args); + /* Create node for this ioboard */ + ion = topo_node_bind(mp, parent, IOBOARD, inst, fmri, NULL); + if (ion == NULL) { + nvlist_free(fmri); + topo_mod_dprintf(mp, "unable to bind ioboard: %s", + topo_strerror(topo_mod_errno(mp))); + return (NULL); /* mod_errno already set */ + } + nvlist_free(fmri); + /* Create and add FRU fmri for this ioboard */ + snprintf(fmri_str, sizeof (fmri_str), IOBDFRU, inst); + if (topo_fmri_str2nvl(thp, fmri_str, &fmri, &err) == 0) { + (void) topo_node_fru_set(ion, fmri, 0, &err); + nvlist_free(fmri); + } + /* Add label for this ioboard */ + snprintf(label, sizeof (label), LABEL, inst); + (void) topo_node_label_set(ion, label, &err); + + /* Create range of hostbridges on this ioboard */ + if (topo_node_range_create(mp, ion, HOSTBRIDGE, 0, OPL_HB_MAX) != 0) { + topo_mod_dprintf(mp, "topo_node_range_create failed", + topo_strerror(topo_mod_errno(mp))); + return (NULL); + } + + return (ion); +} + +/*ARGSUSED*/ +static int +opl_iob_enum(topo_mod_t *mp, tnode_t *parent, const char *name, + topo_instance_t imin, topo_instance_t imax, void *notused) +{ + di_node_t pnode; + tnode_t *ion; + topo_instance_t inst; + int lsb_to_psb[OPL_IOB_MAX]; + ioboard_contents_t ioboard_list[OPL_IOB_MAX]; + int retval = 0; + + /* Validate the name is correct */ + if (strcmp(name, "ioboard") != 0) { + return (-1); + } + /* Initialize devinfo once for the module */ + if ((opl_promtree = di_prom_init()) == DI_PROM_HANDLE_NIL) { + (void) topo_mod_seterrno(mp, errno); + topo_mod_dprintf(mp, + "Ioboard enumerator: di_prom_handle_init failed.\n"); + return (-1); + } + /* Make sure we don't exceed OPL_IOB_MAX */ + if (imax >= OPL_IOB_MAX) { + imax = OPL_IOB_MAX; + } + + bzero(ioboard_list, sizeof (ioboard_list)); + + opl_devtree = di_init("/", DINFOCPYALL); + if (opl_devtree == DI_NODE_NIL) { + (void) topo_mod_seterrno(mp, errno); + topo_mod_dprintf(mp, "devinfo init failed."); + return (-1); + } + + /* + * Create a mapping from logical board numbers (which are part of + * the device node bus address) to physical board numbers, so we + * can create meaningful fru labels. + */ + opl_map_boards(lsb_to_psb); + + /* + * Figure out which boards are installed by finding hostbridges + * with matching bus addresses. + */ + for (pnode = di_drv_first_node(OPL_PX_DRV, opl_devtree); + pnode != DI_NODE_NIL; + pnode = di_drv_next_node(pnode)) { + int psb = -1; + char *ba = di_bus_addr(pnode); + int a = OPL_PX_STR2BA(ba); + int lsb = OPL_PX_LSB(a); + int hb = OPL_PX_HB(a); + int rc = OPL_PX_RC(a); + /* Map logical system board to physical system board */ + if (lsb >= 0 && lsb <= OPL_IOB_MAX) { + psb = lsb_to_psb[lsb]; + } + /* If valid psb, note that this board exists */ + if (psb >= 0 && psb < OPL_IOB_MAX) { + ioboard_list[psb].count++; + ioboard_list[psb].rcs[hb][rc] = pnode; + } + } + + /* + * Now enumerate each existing board Exit loop if retval is + * ever set to non-zero. + */ + for (inst = imin; inst <= imax && retval == 0; inst++) { + /* If this board doesn't contain any hostbridges, skip it */ + if (ioboard_list[inst].count == 0) { + continue; + } + /* Create node for this ioboard */ + ion = opl_iob_node_create(mp, parent, inst); + if (ion == NULL) { + topo_mod_dprintf(mp, + "enumeration of ioboard failed: %s", + topo_strerror(topo_mod_errno(mp))); + retval = -1; + break; + } + /* Enumerate hostbridges on this ioboard, sets errno */ + retval = opl_hb_enum(mp, &ioboard_list[inst], ion, inst); + } + di_fini(opl_devtree); + di_prom_fini(opl_promtree); + return (retval); +} diff --git a/usr/src/lib/fm/topo/modules/SUNW,SPARC-Enterprise/ioboard/opl_topo.h b/usr/src/lib/fm/topo/modules/SUNW,SPARC-Enterprise/ioboard/opl_topo.h new file mode 100644 index 0000000000..35a51b3d74 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/SUNW,SPARC-Enterprise/ioboard/opl_topo.h @@ -0,0 +1,97 @@ +/* + * 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 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _OPL_TOPO_H +#define _OPL_TOPO_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * OPL-specific enumerators. + */ +#define IOBOARD "ioboard" +#define HOSTBRIDGE "hostbridge" +#define PCIEXRC "pciexrc" +#define PCI_BUS "pcibus" +#define PCIEX_BUS "pciexbus" +#define PCI_MOD_PATH "/usr/platform/sun4u/lib/fm/topo/plugins/pcibus.so" + +/* + * OPL uses the Jupiter Bus Bindings (see FWARC/2005/076) which specifies + * the hostbridge port id (the part of the bus address before the comma) as + * [10:9] = 00 + * [8] = LSB_ID[4] = 0 + * [7:4] = LSB_ID[3:0] + * [3] = IO_Channel#[2] = 0 + * [2:1] = IO_Channel#[1:0] + * [0] = PCI Leaf Number (0=leaf-A, 1=leaf-B) + * where the LSB_ID is the logical system board, the IO_Channel is the + * hostbridge, and the PCI leaf is the root complex. The definitions + * allow up to 32 system boards, 8 hostbridges per system board, and + * two root complexes per hostbridge. + */ + +/* Common OPL limits */ +#define OPL_IOB_MAX 32 /* Max 32 IOBs per machine */ +#define OPL_HB_MAX 8 /* Max 8 hostbridges per IOB */ +#define OPL_RC_MAX 2 /* Max 2 root complexes per hostbridge */ +#define OPL_BUS_MAX 4 /* Max PCI-Ex buses under root complex */ + +/* Macros for manipulating px driver bus address. */ +#define OPL_PX_DRV "px" /* Oberon driver name */ +#define OPL_PX_STR2BA(s) strtol(s, NULL, 10) /* Convert ba string to int */ +#define OPL_PX_LSB(a) (((a) >> 4) & 0x1f) /* Extract board from ba */ +#define OPL_PX_HB(a) (((a) >> 1) & 0x07) /* Extract hb from ba */ +#define OPL_PX_RC(a) ((a) & 0x01) /* Extract rc from ba */ +#define OPL_SLOT_NAMES "slot-names" /* Slot name property */ + +/* Macros for manipulating mc-opl driver bus address. */ +#define OPL_MC_DRV "mc-opl" /* Driver name */ +#define OPL_MC_STR2BA(s) strtol(s, NULL, 16) /* Convert ba string to int */ +#define OPL_MC_LSB(a) (((a) >> 4) & 0x1f) /* Extract board from ba */ +#define OPL_PHYSICAL_BD "physical-board#" /* Physical board for the mc */ + +/* Structure listing devices on an ioboard */ +typedef struct { + int count; + di_node_t rcs[OPL_HB_MAX][OPL_RC_MAX]; +} ioboard_contents_t; + +/* Shared device tree root node */ +di_node_t opl_devtree; +di_prom_handle_t opl_promtree; +int opl_hb_enum(topo_mod_t *mp, const ioboard_contents_t *iob, + tnode_t *parent, int brd); + +#ifdef __cplusplus +} +#endif + +#endif /* _OPL_TOPO_H */ diff --git a/usr/src/lib/fm/topo/modules/common/did.c b/usr/src/lib/fm/topo/modules/common/did.c index 4a8a39bfdd..45a2a81cae 100644 --- a/usr/src/lib/fm/topo/modules/common/did.c +++ b/usr/src/lib/fm/topo/modules/common/did.c @@ -118,6 +118,8 @@ di_physlotinfo_get(topo_mod_t *mp, di_node_t src, uint_t excap, int *slotnum, char **slotnm) { char *slotbuf; + int sz; + uchar_t *buf; *slotnum = -1; (void) di_uintprop_get(src, DI_PHYSPROP, (uint_t *)slotnum); @@ -137,12 +139,20 @@ di_physlotinfo_get(topo_mod_t *mp, di_node_t src, uint_t excap, return (0); /* - * Make generic description string "SLOT <num>", allow up 10 - * digits for number + * For PCI-Express, there is only one downstream device, so check for + * a slot-names property, and if it exists, ignore the slotmask value + * and use the string as the label. */ - slotbuf = alloca(16); - (void) snprintf(slotbuf, 16, "SLOT %d", *slotnum); - + if (di_bytes_get(src, DI_SLOTPROP, &sz, &buf) == 0 && sz > 4) { + slotbuf = (char *)&buf[4]; + } else { + /* + * Make generic description string "SLOT <num>", allow up to + * 10 digits for number + */ + slotbuf = alloca(16); + (void) snprintf(slotbuf, 16, "SLOT %d", *slotnum); + } if ((*slotnm = topo_mod_strdup(mp, slotbuf)) == NULL) return (-1); @@ -506,19 +516,15 @@ pciex_cap_get(did_hash_t *dhash, di_node_t dn) } int -did_inherit(tnode_t *parent, tnode_t *child) +did_inherit(did_t *pdp, did_t *dp) { - did_t *pdp, *dp; - /* * If the child already has a label, we're done. */ - dp = topo_node_private(child); assert(dp != NULL); if (did_numlabels(dp) > 0) return (0); - pdp = topo_node_private(parent); assert(pdp != NULL); /* diff --git a/usr/src/lib/fm/topo/modules/common/did.h b/usr/src/lib/fm/topo/modules/common/did.h index bc4150b5f1..d0da891076 100644 --- a/usr/src/lib/fm/topo/modules/common/did.h +++ b/usr/src/lib/fm/topo/modules/common/did.h @@ -50,7 +50,7 @@ extern int did_board(did_t *); extern int did_bridge(did_t *); extern int did_rc(did_t *); extern int did_physslot(did_t *); -extern int did_inherit(tnode_t *, tnode_t *); +extern int did_inherit(did_t *, did_t *); extern int did_excap(did_t *); extern int did_bdf(did_t *); diff --git a/usr/src/lib/fm/topo/modules/common/hostbridge.c b/usr/src/lib/fm/topo/modules/common/hostbridge.c index e7a47c6c46..007fefebd5 100644 --- a/usr/src/lib/fm/topo/modules/common/hostbridge.c +++ b/usr/src/lib/fm/topo/modules/common/hostbridge.c @@ -232,12 +232,6 @@ static void hb_release(topo_mod_t *mp, tnode_t *node) { topo_method_unregister_all(mp, node); - - /* - * node private data (did_t) for this node is destroyed in - * did_hash_destroy() - */ - } static tnode_t * @@ -311,7 +305,7 @@ pcihostbridge_declare(tnode_t *parent, di_node_t din, topo_instance_t i) if ((pd = did_find(Didhash, din)) == NULL) return (NULL); - if ((ntn = hb_tnode_create(parent, HOSTBRIDGE, i, pd)) == NULL) + if ((ntn = hb_tnode_create(parent, HOSTBRIDGE, i, din)) == NULL) return (NULL); if (did_props_set(ntn, pd, HB_common_props, HB_propcnt) < 0) { topo_node_unbind(ntn); @@ -335,7 +329,7 @@ pciexhostbridge_declare(tnode_t *parent, di_node_t din, topo_instance_t hi) if ((pd = did_find(Didhash, din)) == NULL) return (NULL); - if ((ntn = hb_tnode_create(parent, HOSTBRIDGE, hi, pd)) == NULL) + if ((ntn = hb_tnode_create(parent, HOSTBRIDGE, hi, din)) == NULL) return (NULL); if (did_props_set(ntn, pd, ExHB_common_props, ExHB_propcnt) < 0) { topo_node_unbind(ntn); @@ -360,7 +354,7 @@ pciexrc_declare(tnode_t *parent, di_node_t din, topo_instance_t ri) if ((pd = did_find(Didhash, din)) == NULL) return (NULL); did_markrc(pd); - if ((ntn = hb_tnode_create(parent, PCIEX_ROOT, ri, pd)) == NULL) + if ((ntn = hb_tnode_create(parent, PCIEX_ROOT, ri, din)) == NULL) return (NULL); if (did_props_set(ntn, pd, RC_common_props, RC_propcnt) < 0) { topo_node_unbind(ntn); diff --git a/usr/src/lib/fm/topo/modules/common/pcibus.c b/usr/src/lib/fm/topo/modules/common/pcibus.c index 8ef1212a70..ac6608fda8 100644 --- a/usr/src/lib/fm/topo/modules/common/pcibus.c +++ b/usr/src/lib/fm/topo/modules/common/pcibus.c @@ -156,13 +156,10 @@ pci_tnode_create(tnode_t *parent, static int hostbridge_asdevice(tnode_t *bus) { - did_t *pd; di_node_t di; tnode_t *dev32; - pd = topo_node_private(bus); - assert(pd != NULL); - di = did_dinode(pd); + di = topo_node_private(bus); assert(di != DI_NODE_NIL); if ((dev32 = pcidev_declare(bus, di, 32)) == NULL) @@ -180,7 +177,7 @@ pciexfn_declare(tnode_t *parent, di_node_t dn, topo_instance_t i) if ((pd = did_find(Didhash, dn)) == NULL) return (NULL); - if ((ntn = pci_tnode_create(parent, PCIEX_FUNCTION, i, pd)) == NULL) + if ((ntn = pci_tnode_create(parent, PCIEX_FUNCTION, i, dn)) == NULL) return (NULL); if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) { topo_node_unbind(ntn); @@ -208,7 +205,7 @@ pciexdev_declare(tnode_t *parent, di_node_t dn, topo_instance_t i) if ((pd = did_find(Didhash, dn)) == NULL) return (NULL); - if ((ntn = pci_tnode_create(parent, PCIEX_DEVICE, i, pd)) == NULL) + if ((ntn = pci_tnode_create(parent, PCIEX_DEVICE, i, dn)) == NULL) return (NULL); if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) { topo_node_unbind(ntn); @@ -233,7 +230,7 @@ pciexbus_declare(tnode_t *parent, di_node_t dn, topo_instance_t i) if ((pd = did_find(Didhash, dn)) == NULL) return (NULL); - if ((ntn = pci_tnode_create(parent, PCIEX_BUS, i, pd)) == NULL) + if ((ntn = pci_tnode_create(parent, PCIEX_BUS, i, dn)) == NULL) return (NULL); if (did_props_set(ntn, pd, Bus_common_props, Bus_propcnt) < 0) { topo_node_range_destroy(ntn, PCI_DEVICE); @@ -259,7 +256,7 @@ pcifn_declare(tnode_t *parent, di_node_t dn, topo_instance_t i) if ((pd = did_find(Didhash, dn)) == NULL) return (NULL); - if ((ntn = pci_tnode_create(parent, PCI_FUNCTION, i, pd)) == NULL) + if ((ntn = pci_tnode_create(parent, PCI_FUNCTION, i, dn)) == NULL) return (NULL); if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) { topo_node_unbind(ntn); @@ -278,19 +275,25 @@ pcifn_declare(tnode_t *parent, di_node_t dn, topo_instance_t i) tnode_t * pcidev_declare(tnode_t *parent, di_node_t dn, topo_instance_t i) { + di_node_t pdn; did_t *pd; tnode_t *ntn; + did_t *ppd; + if ((pdn = topo_node_private(parent)) == DI_NODE_NIL) + return (NULL); + if ((ppd = did_find(Didhash, pdn)) == NULL) + return (NULL); if ((pd = did_find(Didhash, dn)) == NULL) return (NULL); - if ((ntn = pci_tnode_create(parent, PCI_DEVICE, i, pd)) == NULL) + if ((ntn = pci_tnode_create(parent, PCI_DEVICE, i, dn)) == NULL) return (NULL); /* * If our devinfo node is lacking certain information of its * own, we may need/want to inherit the information available * from our parent node's private data. */ - did_inherit(parent, ntn); + did_inherit(ppd, pd); if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) { topo_node_unbind(ntn); return (NULL); @@ -315,7 +318,7 @@ pcibus_declare(tnode_t *parent, di_node_t dn, topo_instance_t i) if ((pd = did_find(Didhash, dn)) == NULL) return (NULL); - if ((ntn = pci_tnode_create(parent, PCI_BUS, i, pd)) == NULL) + if ((ntn = pci_tnode_create(parent, PCI_BUS, i, dn)) == NULL) return (NULL); /* * If our devinfo node is lacking certain information of its @@ -454,15 +457,24 @@ pci_children_instantiate(tnode_t *parent, di_node_t pn, /*ARGSUSED*/ static int -pci_enum(topo_mod_t *ignored, tnode_t *troot, const char *name, +pci_enum(topo_mod_t *mp, tnode_t *troot, const char *name, topo_instance_t min, topo_instance_t max, void *notused) { did_t *hbdid, *didp; char *pname; + di_node_t parent_dinode; + int rc; + int retval; topo_mod_dprintf(PciHdl, "Enumerating pci!\n"); - if (strcmp(name, PCI_BUS) != 0 && strcmp(name, PCIEX_BUS) != 0) { + if (strcmp(name, PCI_BUS) == 0) { + /* PCI Bus, so no root complex */ + rc = NO_RC; + } else if (strcmp(name, PCIEX_BUS) == 0) { + /* PCI-Express; root complex is hostbridge's instance */ + rc = topo_node_instance(troot); + } else { topo_mod_dprintf(PciHdl, "Currently only know how to enumerate %s or %s not %s.\n", PCI_BUS, PCIEX_BUS, name); @@ -478,14 +490,16 @@ pci_enum(topo_mod_t *ignored, tnode_t *troot, const char *name, HOSTBRIDGE, PCIEX_ROOT); return (0); } - if ((hbdid = topo_node_private(troot)) == NULL) { + if ((parent_dinode = topo_node_private(troot)) == DI_NODE_NIL) { topo_mod_dprintf(PciHdl, "Parent %s node missing private data.\n" "Unable to proceed with %s enumeration.\n", pname, name); return (0); } - Didhash = did_hash(hbdid); + Didhash = did_hash_init(mp); + hbdid = did_create(Didhash, parent_dinode, 0, 0, rc, TRUST_BDF); + /* * If we're looking for a specific bus-instance, find the right * did_t in the chain, otherwise, there should be only one did_t. @@ -504,15 +518,18 @@ pci_enum(topo_mod_t *ignored, tnode_t *troot, const char *name, topo_mod_dprintf(PciHdl, "Parent %s node missing private data related\n" "to %s instance %d.\n", pname, name, min); + did_hash_fini(Didhash); return (0); } } else { assert(did_link_get(hbdid) == NULL); didp = hbdid; } - return (pci_children_instantiate(troot, did_dinode(didp), + retval = pci_children_instantiate(troot, did_dinode(didp), did_board(didp), did_bridge(didp), did_rc(didp), - (min == max) ? min : TRUST_BDF, 0)); + (min == max) ? min : TRUST_BDF, 0); + did_hash_fini(Didhash); + return (retval); } /*ARGSUSED*/ diff --git a/usr/src/pkgdefs/SUNWfmd/prototype_sparc b/usr/src/pkgdefs/SUNWfmd/prototype_sparc index 96dbb9de5d..937d81313a 100644 --- a/usr/src/pkgdefs/SUNWfmd/prototype_sparc +++ b/usr/src/pkgdefs/SUNWfmd/prototype_sparc @@ -117,6 +117,10 @@ d none usr/platform/SUNW,SPARC-Enterprise/lib/fm/fmd 755 root bin d none usr/platform/SUNW,SPARC-Enterprise/lib/fm/fmd/plugins 755 root bin f none usr/platform/SUNW,SPARC-Enterprise/lib/fm/fmd/plugins/event-transport.so 555 root bin f none usr/platform/SUNW,SPARC-Enterprise/lib/fm/fmd/plugins/event-transport.conf 644 root bin +d none usr/platform/SUNW,SPARC-Enterprise/lib/fm/topo 755 root bin +f none usr/platform/SUNW,SPARC-Enterprise/lib/fm/topo/hc-topology.xml 444 root bin +d none usr/platform/SUNW,SPARC-Enterprise/lib/fm/topo/plugins 755 root bin +f none usr/platform/SUNW,SPARC-Enterprise/lib/fm/topo/plugins/ioboard.so 555 root bin d none usr/platform/SUNW,Sun-Fire 755 root sys d none usr/platform/SUNW,Sun-Fire/lib 755 root bin d none usr/platform/SUNW,Sun-Fire/lib/fm 755 root bin |