summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/fm/topo/modules/common/pcibus/did.c127
-rw-r--r--usr/src/lib/fm/topo/modules/common/pcibus/pcibus_labels.c6
2 files changed, 98 insertions, 35 deletions
diff --git a/usr/src/lib/fm/topo/modules/common/pcibus/did.c b/usr/src/lib/fm/topo/modules/common/pcibus/did.c
index 59ba171c75..a15d722eb1 100644
--- a/usr/src/lib/fm/topo/modules/common/pcibus/did.c
+++ b/usr/src/lib/fm/topo/modules/common/pcibus/did.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
/*
@@ -104,11 +105,37 @@ di_devtype_get(topo_mod_t *mp, di_node_t src, char **devtype)
typedef struct smbios_slot_cb {
int cb_slotnum;
+ int cb_bdf;
const char *cb_label;
} smbios_slot_cb_t;
static int
-di_smbios_find_slot(smbios_hdl_t *shp, const smbios_struct_t *strp, void *data)
+di_smbios_find_slot_by_bdf(smbios_hdl_t *shp, const smbios_struct_t *strp,
+ void *data)
+{
+ smbios_slot_cb_t *cbp = data;
+ smbios_slot_t slot;
+ int bus, df;
+
+ bus = (cbp->cb_bdf & 0xFF00) >> 8;
+ df = cbp->cb_bdf & 0xFF;
+
+ if (strp->smbstr_type != SMB_TYPE_SLOT ||
+ smbios_info_slot(shp, strp->smbstr_id, &slot) != 0)
+ return (0);
+
+ if (slot.smbl_bus == bus && slot.smbl_df == df) {
+ cbp->cb_label = slot.smbl_name;
+ cbp->cb_slotnum = slot.smbl_id;
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+di_smbios_find_slot_by_id(smbios_hdl_t *shp, const smbios_struct_t *strp,
+ void *data)
{
smbios_slot_cb_t *cbp = data;
smbios_slot_t slot;
@@ -126,9 +153,10 @@ di_smbios_find_slot(smbios_hdl_t *shp, const smbios_struct_t *strp, void *data)
}
static int
-di_physlotinfo_get(topo_mod_t *mp, di_node_t src, int *slotnum, char **slotname)
+di_physlotinfo_get(topo_mod_t *mp, di_node_t src, int bdf, int *slotnum,
+ char **slotname)
{
- char *slotbuf;
+ char *slotbuf = NULL;
int sz;
uchar_t *buf;
smbios_hdl_t *shp;
@@ -154,55 +182,90 @@ di_physlotinfo_get(topo_mod_t *mp, di_node_t src, int *slotnum, char **slotname)
(void) sscanf((char *)&buf[4], "Slot%d", slotnum);
}
- if (*slotnum == -1)
- return (0);
-
/*
- * Order of preference
- * 1) take slotnum and look up in SMBIOS table
- * 2) use slot-names
- * 3) fabricate name based on slotnum
+ * If the system supports SMBIOS (virtual certainty on X86) then we will
+ * source the label from the Type 9 (Slot) records. If we're unable
+ * to correlate the device with a slot record (as would happen with
+ * onboard PCIe devices), we return without setting slotname, which will
+ * ultimately result in the node inheriting the FRU label from its
+ * parent node.
+ *
+ * In the absence of any SMBIOS support (i.e. SPARC) then we will use
+ * the slot-names property, if available. Otherwise we'll fall back
+ * to fabricating a label based on the slot number.
*/
if ((shp = topo_mod_smbios(mp)) != NULL) {
/*
* The PCI spec describes slot number 0 as reserved for
- * internal PCI devices. Not all platforms respect
- * this, so we have to treat slot 0 as a valid device.
- * But other platforms use 0 to identify an internal
- * device. We deal with this by letting SMBIOS be the
- * final decision maker. If SMBIOS is supported, but
- * the given slot number is not represented in the
- * SMBIOS tables, then ignore the slot entirely.
+ * internal PCI devices. Unfortunately, not all platforms
+ * respect this. For that reason, we prefer to lookup the slot
+ * record using the device's BDF. However, SMBIOS
+ * implementations prior to 2.6 don't encode the BDF in the
+ * slot record. In that case we resort to looking up the
+ * slot record using the slot number.
*/
smbios_slot_cb_t cbdata;
+ smbios_version_t smbv;
+ boolean_t bdf_supp = B_TRUE;
cbdata.cb_slotnum = *slotnum;
+ cbdata.cb_bdf = bdf;
cbdata.cb_label = NULL;
- if (smbios_iter(shp, di_smbios_find_slot, &cbdata) <= 0)
+
+ /*
+ * The bus and device/fn payload members of the SMBIOS slot
+ * record were added in SMBIOS 2.6.
+ */
+ smbios_info_smbios_version(shp, &smbv);
+ if (smbv.smbv_major < 2 ||
+ (smbv.smbv_major == 2 && smbv.smbv_minor < 6)) {
+ bdf_supp = B_FALSE;
+ }
+
+ /*
+ * If the SMBIOS implementation is too old to look up the slot
+ * records by BDF and we weren't able to derive a slotnum then
+ * there is nothing we can do here.
+ */
+ if (!bdf_supp && *slotnum == -1)
+ return (0);
+
+ if (bdf_supp)
+ (void) smbios_iter(shp, di_smbios_find_slot_by_bdf,
+ &cbdata);
+ else
+ (void) smbios_iter(shp, di_smbios_find_slot_by_id,
+ &cbdata);
+
+ if (cbdata.cb_label == NULL)
return (0);
+
slotbuf = (char *)cbdata.cb_label;
- topo_mod_dprintf(mp, "%s: node=%p: using smbios name\n",
- __func__, src);
- } else if (got_slotprop == B_TRUE) {
+ topo_mod_dprintf(mp, "%s: di_node=%p: using smbios name: %s\n",
+ __func__, src, slotbuf);
+ } else if (got_slotprop) {
slotbuf = (char *)&buf[4];
- topo_mod_dprintf(mp, "%s: node=%p: found %s property\n",
- __func__, src, DI_SLOTPROP);
+ topo_mod_dprintf(mp, "%s: di_node=%p: using %s property: %s\n",
+ __func__, src, DI_SLOTPROP, slotbuf);
} else {
/*
* Make generic description string "SLOT <num>", allow up to
- * 10 digits for number
+ * 10 digits for number. Bail, if we weren't able to derive
+ * a slotnum.
*/
+ if (*slotnum == -1)
+ return (0);
+
slotbuf = alloca(16);
(void) snprintf(slotbuf, 16, "SLOT %d", *slotnum);
- topo_mod_dprintf(mp, "%s: node=%p: using generic slot name\n",
- __func__, src);
+ topo_mod_dprintf(mp, "%s: di_node=%p: using fabricated slot "
+ "name: %s\n", __func__, src, slotbuf);
}
- if ((*slotname = topo_mod_strdup(mp, slotbuf)) == NULL)
- return (-1);
-
- topo_mod_dprintf(mp, "%s: node=%p: slotname=%s\n",
- __func__, src, *slotname);
+ if ((*slotname = topo_mod_strdup(mp, slotbuf)) == NULL) {
+ /* topo errno set */
+ return (-1);
+ }
return (0);
}
@@ -325,7 +388,7 @@ did_create(topo_mod_t *mp, di_node_t src,
/*
* This is a pciex node.
*/
- if (di_physlotinfo_get(mp, src, &np->dp_physlot,
+ if (di_physlotinfo_get(mp, src, np->dp_bdf, &np->dp_physlot,
&np->dp_physlot_name) < 0) {
if (np->dp_devtype != NULL)
topo_mod_strfree(mp, np->dp_devtype);
diff --git a/usr/src/lib/fm/topo/modules/common/pcibus/pcibus_labels.c b/usr/src/lib/fm/topo/modules/common/pcibus/pcibus_labels.c
index a7e59ec300..1a767312a1 100644
--- a/usr/src/lib/fm/topo/modules/common/pcibus/pcibus_labels.c
+++ b/usr/src/lib/fm/topo/modules/common/pcibus/pcibus_labels.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#include <alloca.h>
@@ -245,7 +246,7 @@ pci_slot_label_lookup(topo_mod_t *mod, tnode_t *node, did_t *dp, did_t *pdp)
* of a slot while the child contains the label.
*
* Note that this algorithm only applies to nodes which have
- * a physcal slot number. (i.e. PCIE devices or PCI/PCIX
+ * a physical slot number. (i.e. PCIE devices or PCI/PCIX
* devices off of a PCIE to PCIX switch)
*/
if (did_physlot(pdp) >= 0) {
@@ -258,7 +259,6 @@ pci_slot_label_lookup(topo_mod_t *mod, tnode_t *node, did_t *dp, did_t *pdp)
* Get this device's physical slot name.
*/
l = (char *)did_physlot_name(pdp, d);
-
anode = topo_node_parent(node);
/*
@@ -386,7 +386,7 @@ pci_slot_label_lookup(topo_mod_t *mod, tnode_t *node, did_t *dp, did_t *pdp)
*/
if ((l = (char *)pci_label_physlot_lookup(mod, pp, pdp))
== NULL) {
- if ((l = (char *)did_physlot_name(pdp, d)) != NULL) {
+ if ((l = (char *)did_physlot_name(dp, d)) != NULL) {
l = (char *)
pci_label_slotname_lookup(mod, pp, l, dp);
}