summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorRob Johnston <rob.johnston@joyent.com>2018-08-22 10:47:22 -0700
committerRichard Lowe <richlowe@richlowe.net>2018-09-06 16:52:36 +0000
commit6d65bee7bcc62b2d9bdfde6610561ce76c92a908 (patch)
tree925c9ddea02e53bb558daf0c37e6cd1f2c7a7cdd /usr/src
parentd2df75e755ab7973e38d93f9937214d0062c20e0 (diff)
downloadillumos-joyent-6d65bee7bcc62b2d9bdfde6610561ce76c92a908.tar.gz
9459 Implement topo module to enumerate dimms from smbios
Reviewed by: Yuri Pankov <yuripv@yuripv.net> Reviewed by: Igor Kozhukhov <igor@dilos.org> Approved by: Richard Lowe <richlowe@richlowe.net>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/hc.c3
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/libtopo.h4
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/mapfile-vers2
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_hc.h22
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_mod.c10
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_mod.h4
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_mod.map2
-rw-r--r--usr/src/lib/fm/topo/maps/common/topology.dtd.143
-rw-r--r--usr/src/lib/fm/topo/maps/i86pc/i86pc-legacy-hc-topology.xml43
-rw-r--r--usr/src/lib/fm/topo/modules/common/Makefile3
-rw-r--r--usr/src/lib/fm/topo/modules/common/smbios/Makefile22
-rw-r--r--usr/src/lib/fm/topo/modules/common/smbios/smbios_enum.c487
-rw-r--r--usr/src/pkg/manifests/service-fault-management.mf2
13 files changed, 605 insertions, 42 deletions
diff --git a/usr/src/lib/fm/topo/libtopo/common/hc.c b/usr/src/lib/fm/topo/libtopo/common/hc.c
index df718d6490..b9001f0fd2 100644
--- a/usr/src/lib/fm/topo/libtopo/common/hc.c
+++ b/usr/src/lib/fm/topo/libtopo/common/hc.c
@@ -22,7 +22,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2017, Joyent, Inc.
+ * Copyright (c) 2018, Joyent, Inc.
*/
#include <stdio.h>
@@ -191,6 +191,7 @@ static const hcc_t hc_canon[] = {
{ SCSI_DEVICE, TOPO_STABILITY_PRIVATE },
{ SHELF, TOPO_STABILITY_PRIVATE },
{ SES_ENCLOSURE, TOPO_STABILITY_PRIVATE },
+ { SLOT, TOPO_STABILITY_PRIVATE },
{ SMP_DEVICE, TOPO_STABILITY_PRIVATE },
{ SP, TOPO_STABILITY_PRIVATE },
{ STRAND, TOPO_STABILITY_PRIVATE },
diff --git a/usr/src/lib/fm/topo/libtopo/common/libtopo.h b/usr/src/lib/fm/topo/libtopo/common/libtopo.h
index 53458e07ef..3c186010ec 100644
--- a/usr/src/lib/fm/topo/libtopo/common/libtopo.h
+++ b/usr/src/lib/fm/topo/libtopo/common/libtopo.h
@@ -1007,6 +1007,10 @@ typedef enum topo_led_type {
TOPO_LED_TYPE_PRESENT
} topo_led_type_t;
+typedef enum topo_slot_type {
+ TOPO_SLOT_TYPE_DIMM = 1
+} topo_slot_type_t;
+
#ifdef __cplusplus
}
diff --git a/usr/src/lib/fm/topo/libtopo/common/mapfile-vers b/usr/src/lib/fm/topo/libtopo/common/mapfile-vers
index ca10d4fad3..a894c61381 100644
--- a/usr/src/lib/fm/topo/libtopo/common/mapfile-vers
+++ b/usr/src/lib/fm/topo/libtopo/common/mapfile-vers
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2018, Joyent, Inc.
#
#
@@ -89,6 +90,7 @@ SYMBOL_VERSION SUNWprivate {
topo_method_unregister_all;
topo_mod_alloc;
topo_mod_auth;
+ topo_mod_clean_str;
topo_mod_clrdebug;
topo_mod_cpufmri;
topo_mod_devfmri;
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 8d4a4dd2a4..a136bd91b1 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
@@ -87,6 +87,7 @@ extern "C" {
#define SHELF "shelf"
#define SCSI_DEVICE "scsi-device"
#define SES_ENCLOSURE "ses-enclosure"
+#define SLOT "slot"
#define SMP_DEVICE "smp-device"
#define SP "sp"
#define SUBCHASSIS "subchassis"
@@ -194,6 +195,27 @@ extern "C" {
*/
#define TOPO_PROP_IPMI_ENTITY_LIST "entity-list"
+#define TOPO_PGROUP_SLOT "slot"
+#define TOPO_PROP_SLOT_TYPE "slot-type"
+
+#define TOPO_PGROUP_DIMM_SLOT "dimm-slot"
+#define TOPO_PROP_DIMM_SLOT_FORM "form-factor"
+#define TOPO_DIMM_SLOT_FORM_DIMM "DIMM"
+#define TOPO_DIMM_SLOT_FORM_SODIMM "SODIMM"
+#define TOPO_DIMM_SLOT_FORM_FBDIMM "FBDIMM"
+
+#define TOPO_PGROUP_DIMM_PROPS "dimm-properties"
+#define TOPO_PROP_DIMM_TYPE
+#define TOPO_DIMM_TYPE_UNKNOWN "UNKNOWN"
+#define TOPO_DIMM_TYPE_DDR "DDR"
+#define TOPO_DIMM_TYPE_DDR2 "DDR2"
+#define TOPO_DIMM_TYPE_DDR3 "DDR3"
+#define TOPO_DIMM_TYPE_DDR4 "DDR4"
+#define TOPO_DIMM_TYPE_LPDDR "LPDDR"
+#define TOPO_DIMM_TYPE_LPDDR2 "LPDDR2"
+#define TOPO_DIMM_TYPE_LPDDR3 "LPDDR3"
+#define TOPO_DIMM_TYPE_LPDDR4 "LPDDR4"
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_mod.c b/usr/src/lib/fm/topo/libtopo/common/topo_mod.c
index 253466aadc..72d40475f8 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc.
*/
/*
@@ -908,3 +909,12 @@ topo_mod_walk_init(topo_mod_t *mod, tnode_t *node, topo_mod_walk_cb_t cb_f,
return (wp);
}
+
+char *
+topo_mod_clean_str(topo_mod_t *mod, const char *str)
+{
+ if (str == NULL)
+ return (NULL);
+
+ return (topo_cleanup_auth_str(mod->tm_hdl, str));
+}
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_mod.h b/usr/src/lib/fm/topo/libtopo/common/topo_mod.h
index d9501d8b7d..482ba27511 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.h
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.h
@@ -22,6 +22,9 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc. All rights reserved.
+ */
#ifndef _TOPO_MOD_H
#define _TOPO_MOD_H
@@ -225,6 +228,7 @@ extern void topo_mod_setdebug(topo_mod_t *);
extern void topo_mod_dprintf(topo_mod_t *, const char *, ...);
extern const char *topo_mod_errmsg(topo_mod_t *);
extern int topo_mod_errno(topo_mod_t *);
+extern char *topo_mod_clean_str(topo_mod_t *, const char *);
/*
* Topo node utilities: callable from module enumeration, topo_mod_enumerate()
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_mod.map b/usr/src/lib/fm/topo/libtopo/common/topo_mod.map
index 82d22b87ee..1c50a7cf89 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.map
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.map
@@ -1,5 +1,6 @@
#
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2018, Joyent, Inc.
#
# CDDL HEADER START
#
@@ -64,6 +65,7 @@ SYMBOL_SCOPE {
topo_mod_nvl2str { TYPE = FUNCTION; FLAGS = extern };
topo_mod_str2nvl { TYPE = FUNCTION; FLAGS = extern };
topo_mod_auth { TYPE = FUNCTION; FLAGS = extern };
+ topo_mod_clean_str { TYPE = FUNCTION; FLAGS = extern };
topo_mod_walk_init { TYPE = FUNCTION; FLAGS = extern };
diff --git a/usr/src/lib/fm/topo/maps/common/topology.dtd.1 b/usr/src/lib/fm/topo/maps/common/topology.dtd.1
index ae749e6e46..e9ddab3663 100644
--- a/usr/src/lib/fm/topo/maps/common/topology.dtd.1
+++ b/usr/src/lib/fm/topo/maps/common/topology.dtd.1
@@ -3,6 +3,8 @@
Copyright 2009 Sun Microsystems, Inc. All rights reserved.
Use is subject to license terms.
+ Copyright (c) 2018, Joyent, Inc.
+
CDDL HEADER START
The contents of this file are subject to the terms of the
@@ -62,19 +64,19 @@
<!--
propval
- This element is for a singly valued property within a property group.
+ This element is for a singly valued property within a property group.
Its attributes are
name The name of this property.
type The data type for this property.
-
+
value The value for this property. Must match type
restriction of type attribute.
-
+
This is optional for array types
-
+
-->
<!ELEMENT propval (propitem*) >
@@ -89,14 +91,14 @@
<!--
propitem
- This element is an optional child element of propval and is used to
+ This element is an optional child element of propval and is used to
specify the values for array elements
Its attributes are
value The value for this property. Must match type
restriction of type attribute.
-
+
-->
<!ELEMENT propitem EMPTY >
@@ -172,14 +174,14 @@
<!--
argval
-
+
A propmethod argument. It has two attributes:
-
+
name The name of the argument.
type The data type of the argument.
value The value for this argument. Must match type
restriction of type attribute.
-
+
This attribute is optional for array types
-->
@@ -196,14 +198,14 @@
<!--
argitem
- This element is an optional child element of argval and is used to
+ This element is an optional child element of argval and is used to
specify the values for array elements
Its attributes are
value The value for this property. Must match type
restriction of type attribute.
-
+
-->
<!ELEMENT argitem EMPTY >
@@ -220,9 +222,9 @@
Its attributes are
- name Name of the method
- version Version of the method API
- propname Name of the property to create
+ name Name of the method
+ version Version of the method API
+ propname Name of the property to create
proptype Type of the property to create
mutable optional: default is false (0)
nonvolatile optional: default is false (0)
@@ -244,7 +246,7 @@
This element describes the enumeration method used to
populate a composition of topo nodes for a given range of topology
- nodes.
+ nodes.
Its attributes are
@@ -275,22 +277,23 @@
( fac-enum?, facility*, propgroup*, set*, enum-method*, dependents? ) >
<!ATTLIST node
- instance CDATA #REQUIRED >
+ instance CDATA #REQUIRED
+ static (false|true) "false" >
<!--
dependents
Ranges may have a number of "dependent" ranges, linked to
- the original range hierarchically as children or as a list, siblings.
+ the original range hierarchically as children or as a list, siblings.
Its attribute is:
grouping children | siblings
-->
-<!ELEMENT dependents
+<!ELEMENT dependents
(( range | xi:include )*, set*) >
-<!ATTLIST dependents
+<!ATTLIST dependents
grouping ( children | siblings ) #REQUIRED >
<!--
@@ -366,7 +369,7 @@
Its attributes are:
name topology name
- scheme ( hc | dev )
+ scheme (hc|dev)
-->
<!ELEMENT topology
diff --git a/usr/src/lib/fm/topo/maps/i86pc/i86pc-legacy-hc-topology.xml b/usr/src/lib/fm/topo/maps/i86pc/i86pc-legacy-hc-topology.xml
index fda43bca6c..b878f9599c 100644
--- a/usr/src/lib/fm/topo/maps/i86pc/i86pc-legacy-hc-topology.xml
+++ b/usr/src/lib/fm/topo/maps/i86pc/i86pc-legacy-hc-topology.xml
@@ -2,7 +2,7 @@
<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/topology.dtd.1">
<!--
Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
-Copyright (c) 2013, Joyent, Inc. All rights reserved.
+Copyright (c) 2018, Joyent, Inc. All rights reserved.
CDDL HEADER START
@@ -71,37 +71,40 @@ Copyright (c) 2013, Joyent, Inc. All rights reserved.
</propgroup>
</set>
</node>
-
+
<dependents grouping='children'>
<range name='chip' min='0' max='100'>
<enum-method name='chip' version='1' />
<propmap name='chip' />
</range>
+ <range name='slot' min='0' max='31'>
+ <enum-method name='smbios' version='1' />
+ </range>
<range name='hostbridge' min='0' max='254'>
<enum-method name='hostbridge' version='1' />
</range>
</dependents>
-
+
</range>
<range name='chassis' min='0' max='0'>
<propmap name='chassis' />
-
+
<dependents grouping='children'>
-
+
<set type='product'
setlist='Sun-Fire-X4100-Server|Sun-Fire-X4200-Server|Sun-Fire-X4100-M2|Sun-Fire-X4200-M2|Netra-X4200-M2|Sun-Fire-X4140|Sun-Fire-X4240|Sun-Fire-X4440'>
<range name='psu' min='0' max='100'>
- <enum-method name='ipmi' version='1' />
- <propmap name='psu' />
+ <enum-method name='ipmi' version='1' />
+ <propmap name='psu' />
</range>
<range name='fanmodule' min='0' max='100'>
- <propmap name='fan' />
+ <propmap name='fan' />
</range>
<set type='product' setlist='Sun-Fire-X4200-M2'>
- <range name='bay' min='0' max='3'>
+ <range name='bay' min='0' max='3'>
<propmap name='Sun-Fire-X4200-M2-disk' />
- </range>
+ </range>
</set>
<set type='product' setlist='Sun-Fire-X4200-Server'>
<range name='bay' min='0' max='3'>
@@ -122,23 +125,23 @@ Copyright (c) 2013, Joyent, Inc. All rights reserved.
<set type='product' setlist='Sun-Fire-X4500|Sun-Fire-X4540|SUN-FIRE-X4150|SUN-FIRE-X4250|SUN-FIRE-X4450'>
<range name='psu' min='0' max='100'>
- <propmap name='psu' />
+ <propmap name='psu' />
</range>
<range name='fanmodule' min='0' max='100'>
- <propmap name='fan' />
+ <propmap name='fan' />
</range>
<set type='product' setlist='Sun-Fire-X4500'>
- <range name='bay' min='0' max='47'>
+ <range name='bay' min='0' max='47'>
<propmap name='Sun-Fire-X4500-disk' />
- </range>
+ </range>
</set>
<set type='product' setlist='Sun-Fire-X4540'>
- <range name='bay' min='0' max='47'>
+ <range name='bay' min='0' max='47'>
<propmap name='Sun-Fire-X4540-disk' />
- </range>
+ </range>
</set>
</set>
-
+
<set type='product' setlist='Sun-Fire-X4600|Sun-Fire-X4600-M2'>
<range name='psu' min='0' max='100'>
<enum-method name='ipmi' version='1' />
@@ -166,13 +169,13 @@ Copyright (c) 2013, Joyent, Inc. All rights reserved.
<set type='product' setlist='default'>
<range name='psu' min='0' max='100'>
- <enum-method name='ipmi' version='1' />
+ <enum-method name='ipmi' version='1' />
</range>
<range name='fan' min='0' max='100'>
- <enum-method name='ipmi' version='1' />
+ <enum-method name='ipmi' version='1' />
</range>
<range name='bay' min='0' max='1024'>
- <enum-method name='ses' version='1' />
+ <enum-method name='ses' version='1' />
</range>
</set>
diff --git a/usr/src/lib/fm/topo/modules/common/Makefile b/usr/src/lib/fm/topo/modules/common/Makefile
index d725016aef..f7f47f5e06 100644
--- a/usr/src/lib/fm/topo/modules/common/Makefile
+++ b/usr/src/lib/fm/topo/modules/common/Makefile
@@ -22,7 +22,7 @@
#
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
-# Copyright (c) 2017, Joyent, Inc.
+# Copyright (c) 2018, Joyent, Inc.
#
SUBDIRS = \
@@ -32,6 +32,7 @@ SUBDIRS = \
ipmi \
nic \
ses \
+ smbios \
xfp
ses: disk
diff --git a/usr/src/lib/fm/topo/modules/common/smbios/Makefile b/usr/src/lib/fm/topo/modules/common/smbios/Makefile
new file mode 100644
index 0000000000..04590063c5
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/common/smbios/Makefile
@@ -0,0 +1,22 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2018, Joyent, Inc.
+#
+
+MODULE = smbios
+CLASS = common
+MODULESRCS = smbios_enum.c
+
+include ../../Makefile.plugin
+
+LDLIBS += -lsmbios
diff --git a/usr/src/lib/fm/topo/modules/common/smbios/smbios_enum.c b/usr/src/lib/fm/topo/modules/common/smbios/smbios_enum.c
new file mode 100644
index 0000000000..42c41697c4
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/common/smbios/smbios_enum.c
@@ -0,0 +1,487 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
+#include <assert.h>
+#include <fcntl.h>
+#include <fm/libtopo.h>
+#include <fm/topo_mod.h>
+#ifdef __x86
+#include <sys/mc.h>
+#endif
+#include <sys/fm/protocol.h>
+#include <string.h>
+#include <unistd.h>
+
+typedef struct smb_enum_data {
+ topo_mod_t *sme_mod;
+ tnode_t *sme_pnode;
+ tnode_t *sme_slotnode;
+ topo_instance_t sme_slot_inst;
+ topo_instance_t sme_slot_maxinst;
+ smbios_info_t *sme_smb_info;
+ char *sme_slot_form;
+} smb_enum_data_t;
+
+/*
+ * This function serves two purposes. It filters out memory devices that
+ * don't have a formfactor that represents a reasonably modern DIMM-like
+ * device (and hence not a device we're interested in enumerating). It also
+ * converts the numeric SMBIOS type representation to a more generic TOPO dimm
+ * type.
+ *
+ * Caller must free the returned string.
+ */
+static char *
+distill_dimm_form(topo_mod_t *mod, smbios_memdevice_t *smb_md)
+{
+ switch (smb_md->smbmd_form) {
+ case (SMB_MDFF_DIMM):
+ return (topo_mod_strdup(mod, TOPO_DIMM_SLOT_FORM_DIMM));
+ case (SMB_MDFF_SODIMM):
+ return (topo_mod_strdup(mod, TOPO_DIMM_SLOT_FORM_SODIMM));
+ case (SMB_MDFF_FBDIMM):
+ return (topo_mod_strdup(mod, TOPO_DIMM_SLOT_FORM_FBDIMM));
+ default:
+ topo_mod_dprintf(mod, "skipping device with form factor 0x%x",
+ smb_md->smbmd_form);
+ return (NULL);
+ }
+}
+
+static char *
+smbios2topotype(topo_mod_t *mod, uint8_t type)
+{
+ switch (type) {
+ case (SMB_MDT_DDR):
+ return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_DDR));
+ case (SMB_MDT_DDR2):
+ case (SMB_MDT_DDR2FBDIMM):
+ return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_DDR2));
+ case (SMB_MDT_DDR3):
+ return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_DDR3));
+ case (SMB_MDT_DDR4):
+ return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_DDR4));
+ case (SMB_MDT_LPDDR):
+ return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_LPDDR));
+ case (SMB_MDT_LPDDR2):
+ return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_LPDDR2));
+ case (SMB_MDT_LPDDR3):
+ return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_LPDDR3));
+ case (SMB_MDT_LPDDR4):
+ return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_LPDDR4));
+ default:
+ return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_UNKNOWN));
+ }
+}
+
+static boolean_t
+is_valid_string(const char *str)
+{
+ if (strcmp(str, SMB_DEFAULT1) != 0 && strcmp(str, SMB_DEFAULT2) != 0 &&
+ strlen(str) > 0)
+ return (B_TRUE);
+
+ return (B_FALSE);
+}
+
+static tnode_t *
+smbios_make_slot(smb_enum_data_t *smed, smbios_memdevice_t *smb_md)
+{
+ nvlist_t *auth, *fmri;
+ tnode_t *slotnode;
+ topo_mod_t *mod = smed->sme_mod;
+ topo_pgroup_info_t pgi;
+ int err;
+
+ if ((auth = topo_mod_auth(mod, smed->sme_pnode)) == NULL) {
+ topo_mod_dprintf(mod, "topo_mod_auth() failed: %s",
+ topo_mod_errmsg(mod));
+ /* errno set */
+ return (NULL);
+ }
+
+ if ((fmri = topo_mod_hcfmri(mod, smed->sme_pnode, FM_HC_SCHEME_VERSION,
+ SLOT, smed->sme_slot_inst, NULL, auth, NULL, NULL, NULL)) ==
+ NULL) {
+ nvlist_free(auth);
+ topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s",
+ topo_mod_errmsg(mod));
+ /* errno set */
+ return (NULL);
+ }
+ nvlist_free(auth);
+ if ((slotnode = topo_node_bind(mod, smed->sme_pnode, SLOT,
+ smed->sme_slot_inst, fmri)) == NULL) {
+ nvlist_free(fmri);
+ topo_mod_dprintf(mod, "topo_node_bind() failed: %s",
+ topo_mod_errmsg(mod));
+ /* errno set */
+ return (NULL);
+ }
+ nvlist_free(fmri);
+ fmri = NULL;
+
+ if (topo_node_label_set(slotnode, (char *)smb_md->smbmd_dloc, &err) !=
+ 0) {
+ topo_mod_dprintf(mod, "failed to set label on %s=%d: %s",
+ SLOT, smed->sme_slot_inst, topo_strerror(err));
+ (void) topo_mod_seterrno(mod, err);
+ return (NULL);
+ }
+ if (topo_node_fru(smed->sme_pnode, &fmri, NULL, &err) != 0 ||
+ topo_node_fru_set(slotnode, fmri, NULL, &err) != 0) {
+ topo_mod_dprintf(mod, "failed to set FRU on %s=%d: %s", SLOT,
+ smed->sme_slot_inst, topo_strerror(err));
+ nvlist_free(fmri);
+ (void) topo_mod_seterrno(mod, err);
+ return (NULL);
+ }
+ nvlist_free(fmri);
+
+ pgi.tpi_name = TOPO_PGROUP_SLOT;
+ pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
+ pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
+ pgi.tpi_version = TOPO_VERSION;
+ if (topo_pgroup_create(slotnode, &pgi, &err) != 0 ||
+ topo_prop_set_uint32(slotnode, TOPO_PGROUP_SLOT,
+ TOPO_PROP_SLOT_TYPE, TOPO_PROP_IMMUTABLE, TOPO_SLOT_TYPE_DIMM,
+ &err)) {
+ topo_mod_dprintf(mod, "failed to create slot properties: %s",
+ topo_strerror(err));
+ (void) topo_mod_seterrno(mod, err);
+ return (NULL);
+ }
+
+ pgi.tpi_name = TOPO_PGROUP_DIMM_SLOT;
+ pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
+ pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
+ pgi.tpi_version = TOPO_VERSION;
+ if (topo_pgroup_create(slotnode, &pgi, &err) != 0 ||
+ topo_prop_set_string(slotnode, TOPO_PGROUP_DIMM_SLOT,
+ TOPO_PROP_DIMM_SLOT_FORM, TOPO_PROP_IMMUTABLE, smed->sme_slot_form,
+ &err)) {
+ topo_mod_dprintf(mod, "failed to create slot properties: %s",
+ topo_strerror(err));
+ (void) topo_mod_seterrno(mod, err);
+ return (NULL);
+ }
+ return (slotnode);
+}
+
+static tnode_t *
+smbios_make_dimm(smb_enum_data_t *smed, smbios_memdevice_t *smb_md)
+{
+ nvlist_t *auth, *fmri;
+ smbios_info_t *smb_info = smed->sme_smb_info;
+ tnode_t *slotnode = smed->sme_slotnode;
+ tnode_t *dimmnode, *ret = NULL;
+ topo_mod_t *mod = smed->sme_mod;
+ topo_pgroup_info_t pgi;
+ const char *part = NULL, *rev = NULL, *serial = NULL;
+ char *type, *manuf = NULL, *prod = NULL, *asset = NULL, *loc = NULL;
+ int err, rc = 0;
+
+ if ((auth = topo_mod_auth(mod, slotnode)) == NULL) {
+ topo_mod_dprintf(mod, "topo_mod_auth() failed: %s",
+ topo_mod_errmsg(mod));
+ /* errno set */
+ return (NULL);
+ }
+
+ if (smed->sme_smb_info != NULL) {
+ if (is_valid_string(smb_info->smbi_part) == B_TRUE)
+ part = smb_info->smbi_part;
+ if (is_valid_string(smb_info->smbi_version) == B_TRUE)
+ rev = smb_info->smbi_version;
+ if (is_valid_string(smb_info->smbi_serial) == B_TRUE)
+ serial = smb_info->smbi_serial;
+ if (is_valid_string(smb_info->smbi_manufacturer) == B_TRUE)
+ manuf = topo_mod_clean_str(mod,
+ smb_info->smbi_manufacturer);
+ if (is_valid_string(smb_info->smbi_product) == B_TRUE)
+ prod = topo_mod_clean_str(mod, smb_info->smbi_product);
+ if (is_valid_string(smb_info->smbi_asset) == B_TRUE)
+ asset = topo_mod_clean_str(mod, smb_info->smbi_asset);
+ if (is_valid_string(smb_info->smbi_location) == B_TRUE)
+ loc = topo_mod_clean_str(mod, smb_info->smbi_location);
+ }
+
+ if ((fmri = topo_mod_hcfmri(mod, slotnode, FM_HC_SCHEME_VERSION,
+ DIMM, 0, NULL, auth, part, rev, serial)) == NULL) {
+ nvlist_free(auth);
+ topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s",
+ topo_mod_errmsg(mod));
+ /* errno set */
+ goto err;
+ }
+ nvlist_free(auth);
+
+ if (topo_node_range_create(mod, slotnode, DIMM, 0, 0) < 0 ||
+ (dimmnode = topo_node_bind(mod, slotnode, DIMM, 0, fmri)) ==
+ NULL) {
+ nvlist_free(fmri);
+ topo_mod_dprintf(mod, "failed to bind dimm node: %s",
+ topo_mod_errmsg(mod));
+ /* errno set */
+ goto err;
+ }
+
+ if (topo_node_fru_set(dimmnode, fmri, NULL, &err) != 0) {
+ topo_mod_dprintf(mod, "failed to set FRU on %s: %s",
+ DIMM, topo_strerror(err));
+ nvlist_free(fmri);
+ (void) topo_mod_seterrno(mod, err);
+ goto err;
+ }
+ nvlist_free(fmri);
+
+ if (topo_node_label_set(dimmnode, (char *)smb_md->smbmd_dloc, &err) !=
+ 0) {
+ topo_mod_dprintf(mod, "failed to set label on %s: %s",
+ DIMM, topo_strerror(err));
+ (void) topo_mod_seterrno(mod, err);
+ goto err;
+ }
+
+ pgi.tpi_name = TOPO_PGROUP_DIMM_PROPS;
+ pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
+ pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
+ pgi.tpi_version = TOPO_VERSION;
+ if (topo_pgroup_create(dimmnode, &pgi, &err) != 0) {
+ (void) topo_mod_seterrno(mod, err);
+ goto err;
+ }
+
+ rc += topo_prop_set_uint64(dimmnode, TOPO_PGROUP_DIMM_PROPS, "size",
+ TOPO_PROP_IMMUTABLE, smb_md->smbmd_size, &err);
+ if (rc == 0 && (type = smbios2topotype(mod, smb_md->smbmd_type)) !=
+ NULL) {
+ rc += topo_prop_set_string(dimmnode, TOPO_PGROUP_DIMM_PROPS,
+ "type", TOPO_PROP_IMMUTABLE, type, &err);
+ topo_mod_strfree(mod, type);
+ }
+ if (rc == 0 && smb_md->smbmd_set != 0 && smb_md->smbmd_set != 0xFF)
+ rc += topo_prop_set_uint32(dimmnode, TOPO_PGROUP_DIMM_PROPS,
+ "set", TOPO_PROP_IMMUTABLE, smb_md->smbmd_set, &err);
+ if (rc == 0 && smb_md->smbmd_rank != 0)
+ rc += topo_prop_set_uint32(dimmnode, TOPO_PGROUP_DIMM_PROPS,
+ "rank", TOPO_PROP_IMMUTABLE, smb_md->smbmd_rank, &err);
+ if (rc == 0 && smb_md->smbmd_clkspeed != 0)
+ rc += topo_prop_set_uint32(dimmnode, TOPO_PGROUP_DIMM_PROPS,
+ "configured-speed", TOPO_PROP_IMMUTABLE,
+ smb_md->smbmd_clkspeed, &err);
+ if (rc == 0 && smb_md->smbmd_speed != 0)
+ rc += topo_prop_set_uint32(dimmnode, TOPO_PGROUP_DIMM_PROPS,
+ "maximum-speed", TOPO_PROP_IMMUTABLE, smb_md->smbmd_speed,
+ &err);
+ if (rc == 0 && smb_md->smbmd_maxvolt != 0)
+ rc += topo_prop_set_double(dimmnode, TOPO_PGROUP_DIMM_PROPS,
+ "maximum-voltage", TOPO_PROP_IMMUTABLE,
+ (smb_md->smbmd_maxvolt / 1000), &err);
+ if (rc == 0 && smb_md->smbmd_minvolt != 0)
+ rc += topo_prop_set_double(dimmnode, TOPO_PGROUP_DIMM_PROPS,
+ "minimum-voltage", TOPO_PROP_IMMUTABLE,
+ (smb_md->smbmd_minvolt / 1000), &err);
+ if (rc == 0 && smb_md->smbmd_confvolt != 0)
+ rc += topo_prop_set_double(dimmnode, TOPO_PGROUP_DIMM_PROPS,
+ "configured-voltage", TOPO_PROP_IMMUTABLE,
+ (smb_md->smbmd_confvolt / 1000), &err);
+ if (rc == 0 && manuf != NULL)
+ rc += topo_prop_set_string(dimmnode, TOPO_PGROUP_DIMM_PROPS,
+ "manufacturer", TOPO_PROP_IMMUTABLE, manuf, &err);
+ if (rc == 0 && prod != NULL)
+ rc += topo_prop_set_string(dimmnode, TOPO_PGROUP_DIMM_PROPS,
+ "product", TOPO_PROP_IMMUTABLE, prod, &err);
+ if (rc == 0 && asset != NULL)
+ rc += topo_prop_set_string(dimmnode, TOPO_PGROUP_DIMM_PROPS,
+ "asset-tag", TOPO_PROP_IMMUTABLE, asset, &err);
+ if (rc == 0 && loc != NULL)
+ rc += topo_prop_set_string(dimmnode, TOPO_PGROUP_DIMM_PROPS,
+ "location", TOPO_PROP_IMMUTABLE, loc, &err);
+
+ if (rc != 0) {
+ topo_mod_dprintf(mod, "error setting properties on %s node",
+ DIMM);
+ (void) topo_mod_seterrno(mod, err);
+ goto err;
+ }
+ ret = dimmnode;
+err:
+ topo_mod_strfree(mod, manuf);
+ topo_mod_strfree(mod, prod);
+ topo_mod_strfree(mod, asset);
+ topo_mod_strfree(mod, loc);
+ return (ret);
+}
+
+static int
+smbios_enum_memory(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
+{
+ smbios_info_t smb_info;
+ smbios_memdevice_t smb_md;
+ smb_enum_data_t *smed = arg;
+ topo_mod_t *mod = smed->sme_mod;
+ tnode_t *slotnode;
+
+ if (sp->smbstr_type != SMB_TYPE_MEMDEVICE)
+ return (0);
+
+ if (smbios_info_memdevice(shp, sp->smbstr_id, &smb_md) != 0) {
+ topo_mod_dprintf(mod, "libsmbios error");
+ return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
+ }
+
+ /*
+ * SMB_TYPE_MEMDEVICE records can also be used to represent memory
+ * that come in non-DIMM form factors. If we encounter something like
+ * that, then we skip over it.
+ */
+ if ((smed->sme_slot_form = distill_dimm_form(mod, &smb_md)) == NULL)
+ return (0);
+
+ if ((slotnode = smbios_make_slot(smed, &smb_md)) == NULL) {
+ topo_mod_dprintf(mod, "failed to create %s node", SLOT);
+ topo_mod_strfree(mod, smed->sme_slot_form);
+ /* errno set */
+ return (-1);
+ }
+ topo_mod_strfree(mod, smed->sme_slot_form);
+ smed->sme_slotnode = slotnode;
+
+ /*
+ * A size of zero indicates that the DIMM slot is not populated, so
+ * we skip creating a child dimm node and return.
+ */
+ if (smb_md.smbmd_size == 0) {
+ smed->sme_slot_inst++;
+ return (0);
+ }
+
+ if (smbios_info_common(shp, sp->smbstr_id, &smb_info) == 0)
+ smed->sme_smb_info = &smb_info;
+
+ if (smbios_make_dimm(smed, &smb_md) == NULL) {
+ topo_mod_dprintf(mod, "failed to create %s node", DIMM);
+ /* errno set */
+ return (-1);
+ }
+ /*
+ * If we've exceeded our max inst then return non-zero to cause
+ * the walk to terminate.
+ */
+ if (++smed->sme_slot_inst > smed->sme_slot_maxinst)
+ return (1);
+
+ return (0);
+}
+
+/*
+ * A system with a functional memory controller driver will have one mc device
+ * node per chip instance, starting at instance 0. The driver provides an
+ * ioctl interface for retrieving a snapshot of the system's memory topology.
+ * If we're able to issue this ioctl on one of the mc device nodes then we'll
+ * return B_TRUE, indicating that this system has a minimally functional memory
+ * controller driver.
+ */
+static boolean_t
+has_mc_driver()
+{
+#ifdef __x86
+ int mc_fd;
+ mc_snapshot_info_t mcs;
+
+ if ((mc_fd = open("/dev/mc/mc0", O_RDONLY)) < 0)
+ return (B_FALSE);
+
+ if (ioctl(mc_fd, MC_IOC_SNAPSHOT_INFO, &mcs) < 0) {
+ (void) close(mc_fd);
+ return (B_FALSE);
+ }
+ (void) close(mc_fd);
+ return (B_TRUE);
+#else
+ return (B_TRUE);
+#endif
+}
+
+/*ARGSUSED*/
+static int
+smbios_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
+ topo_instance_t min, topo_instance_t max, void *arg, void *unused)
+{
+ smbios_hdl_t *smbh;
+ smb_enum_data_t smed = { 0 };
+
+ if ((smbh = topo_mod_smbios(mod)) == NULL) {
+ topo_mod_dprintf(mod, "failed to get libsmbios handle");
+ return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
+ }
+ smed.sme_mod = mod;
+ smed.sme_pnode = rnode;
+ smed.sme_slot_inst = min;
+ smed.sme_slot_maxinst = max;
+
+ /*
+ * Currently we only support enumerating dimm-slot and dimm nodes, but
+ * this module could be expanded in the future to enumerate other
+ * hardware components from SMBIOS.
+ */
+ if (strcmp(name, SLOT) == 0) {
+ /*
+ * If the system has a functional memory controller driver then
+ * we'll assume that it has responsibility for enumerating the
+ * memory topology.
+ */
+ if (has_mc_driver() == B_TRUE)
+ return (0);
+ if (smbios_iter(smbh, smbios_enum_memory, &smed) < 0)
+ /* errno set */
+ return (-1);
+ } else {
+ topo_mod_dprintf(mod, "smbios_enum() invoked for unsupported "
+ "node type: %s", name);
+ return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
+ }
+ return (0);
+}
+
+const topo_modops_t smbios_ops = { smbios_enum, NULL };
+
+const topo_modinfo_t smbios_info =
+ { "smbios", FM_FMRI_SCHEME_HC, TOPO_VERSION, &smbios_ops };
+
+/*ARGSUSED*/
+int
+_topo_init(topo_mod_t *mod, topo_version_t version)
+{
+ if (getenv("TOPOSMBIOSDEBUG") != NULL)
+ topo_mod_setdebug(mod);
+
+ if (topo_mod_register(mod, &smbios_info, TOPO_VERSION) != 0) {
+ topo_mod_dprintf(mod, "module registration failed: %s\n",
+ topo_mod_errmsg(mod));
+ /* errno set */
+ return (-1);
+ }
+
+ topo_mod_dprintf(mod, "SMBIOS enumerator initialized\n");
+ return (0);
+}
+
+void
+_topo_fini(topo_mod_t *mod)
+{
+ topo_mod_unregister(mod);
+}
diff --git a/usr/src/pkg/manifests/service-fault-management.mf b/usr/src/pkg/manifests/service-fault-management.mf
index f2176a6a36..cc529ac71b 100644
--- a/usr/src/pkg/manifests/service-fault-management.mf
+++ b/usr/src/pkg/manifests/service-fault-management.mf
@@ -21,6 +21,7 @@
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2018, Joyent, Inc.
#
#
@@ -570,6 +571,7 @@ file path=usr/lib/fm/topo/plugins/fac_prov_mptsas.so mode=0555
file path=usr/lib/fm/topo/plugins/ipmi.so mode=0555
file path=usr/lib/fm/topo/plugins/nic.so mode=0555
file path=usr/lib/fm/topo/plugins/ses.so mode=0555
+file path=usr/lib/fm/topo/plugins/smbios.so mode=0555
file path=usr/lib/fm/topo/plugins/xfp.so mode=0555
#
# Dictionaries, whether they are hardware-specific or not, are