diff --git a/manifest b/manifest
index b4e6354e9180..4b243cf6b0cb 100644
--- a/manifest
+++ b/manifest
@@ -10566,6 +10566,9 @@ f usr/platform/i86pc/lib/fm/topo/maps/SSG-2028R-ACR24L-disk-hc-topology.xml 0444
f usr/platform/i86pc/lib/fm/topo/maps/SSG-2028R-ACR24L-hc-topology.xml 0444 root sys
f usr/platform/i86pc/lib/fm/topo/maps/SSG-2028R-ACR24L-slot-hc-topology.xml 0444 root sys
f usr/platform/i86pc/lib/fm/topo/maps/SSG-2028R-ACR24L-usb.usbtopo 0444 root sys
+f usr/platform/i86pc/lib/fm/topo/maps/SYS-2028U-E1CNRT+-chassis-hc-topology.xml 0444 root sys
+f usr/platform/i86pc/lib/fm/topo/maps/SYS-2028U-E1CNRT+-hc-topology.xml 0444 root sys
+f usr/platform/i86pc/lib/fm/topo/maps/SYS-2028U-E1CNRT+-usb.usbtopo 0444 root sys
f usr/platform/i86pc/lib/fm/topo/maps/SSG-2029P-ACR24L-chassis-hc-topology.xml 0444 root sys
f usr/platform/i86pc/lib/fm/topo/maps/SSG-2029P-ACR24L-disk-hc-topology.xml 0444 root sys
f usr/platform/i86pc/lib/fm/topo/maps/SSG-2029P-ACR24L-hc-topology.xml 0444 root sys
diff --git a/usr/src/lib/fm/topo/libtopo/common/hc.c b/usr/src/lib/fm/topo/libtopo/common/hc.c
index 3101d12d56dd..c6afe0afbcc9 100644
--- a/usr/src/lib/fm/topo/libtopo/common/hc.c
+++ b/usr/src/lib/fm/topo/libtopo/common/hc.c
@@ -179,6 +179,7 @@ static const hcc_t hc_canon[] = {
{ MOTHERBOARD, TOPO_STABILITY_PRIVATE },
{ NIU, TOPO_STABILITY_PRIVATE },
{ NIUFN, TOPO_STABILITY_PRIVATE },
+ { NVME, TOPO_STABILITY_PRIVATE },
{ PCI_BUS, TOPO_STABILITY_PRIVATE },
{ PCI_DEVICE, TOPO_STABILITY_PRIVATE },
{ PCI_FUNCTION, TOPO_STABILITY_PRIVATE },
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
index 8f245c1cf079..e217b1f76144 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
@@ -68,6 +68,7 @@ extern "C" {
#define MOTHERBOARD "motherboard"
#define NIU "niu"
#define NIUFN "niufn"
+#define NVME "nvme"
#define PCI_BUS "pcibus"
#define PCI_DEVICE "pcidev"
#define PCI_FUNCTION "pcifn"
@@ -138,6 +139,7 @@ extern "C" {
#define TOPO_BINDING_ENCLOSURE "enclosure"
#define TOPO_BINDING_SLOT "slot"
#define TOPO_BINDING_PORT "port"
+#define TOPO_BINDING_PARENT_DEV "parent-device"
#define TOPO_PGROUP_STORAGE "storage"
#define TOPO_STORAGE_INITIATOR_PORT "initiator-port"
@@ -290,6 +292,9 @@ extern "C" {
#define TOPO_PROP_UFM_SLOT_MODE "ufm-slot-mode"
#define TOPO_PROP_UFM_SLOT_ACTIVE "ufm-slot-active"
+#define TOPO_PGROUP_NVME "nvme-properties"
+#define TOPO_PROP_NVME_VER "nvme-version"
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_xml.c b/usr/src/lib/fm/topo/libtopo/common/topo_xml.c
index 58743077bd32..1ec31af7bac8 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_xml.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_xml.c
@@ -1346,14 +1346,14 @@ pad_process(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn,
*rpad = new;
}
- if (new->tpad_dcnt > 0)
- if (dependents_create(mp, rd->rd_finfo, new, pxn, ptn) < 0)
- return (-1);
-
if (new->tpad_pgcnt > 0)
if (pgroups_create(mp, new, ptn) < 0)
return (-1);
+ if (new->tpad_dcnt > 0)
+ if (dependents_create(mp, rd->rd_finfo, new, pxn, ptn) < 0)
+ return (-1);
+
return (0);
}
diff --git a/usr/src/lib/fm/topo/maps/Makefile b/usr/src/lib/fm/topo/maps/Makefile
index 04fc0d4b7da2..182034e6bc39 100644
--- a/usr/src/lib/fm/topo/maps/Makefile
+++ b/usr/src/lib/fm/topo/maps/Makefile
@@ -22,7 +22,7 @@
#
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
# Copyright 2019 Peter Tribble.
#
@@ -54,6 +54,7 @@ i386_SUBDIRS = i86pc \
Joyent,Joyent-Compute-Platform-330x \
Joyent,Joyent-Storage-Platform-7001 \
SMCI,SSG-2028R-ACR24L \
+ SMCI,SYS-2028U-E1CNRT+ \
SMCI,SSG-6049P-E1CR36L \
SMCI,SSG-2029P-ACR24L
diff --git a/usr/src/lib/fm/topo/maps/SMCI,SYS-2028U-E1CNRT+/Makefile b/usr/src/lib/fm/topo/maps/SMCI,SYS-2028U-E1CNRT+/Makefile
new file mode 100644
index 000000000000..885062cae978
--- /dev/null
+++ b/usr/src/lib/fm/topo/maps/SMCI,SYS-2028U-E1CNRT+/Makefile
@@ -0,0 +1,29 @@
+#
+# 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 2019 Joyent, Inc.
+#
+ARCH = i86pc
+CLASS = arch
+DTDFILE = topology.dtd.1
+
+TOPOFILE = \
+ SYS-2028U-E1CNRT+-hc-topology.xml \
+ SYS-2028U-E1CNRT+-chassis-hc-topology.xml \
+ SYS-2028U-E1CNRT+-usb.usbtopo
+
+SRCDIR = ../SMCI,SYS-2028U-E1CNRT+
+
+PLATFORM = SYS-2028U-E1CNRT+
+
+include ../Makefile.map
+
diff --git a/usr/src/lib/fm/topo/maps/SMCI,SYS-2028U-E1CNRT+/SYS-2028U-E1CNRT+-chassis-hc-topology.xml b/usr/src/lib/fm/topo/maps/SMCI,SYS-2028U-E1CNRT+/SYS-2028U-E1CNRT+-chassis-hc-topology.xml
new file mode 100644
index 000000000000..fde29e13f6d0
--- /dev/null
+++ b/usr/src/lib/fm/topo/maps/SMCI,SYS-2028U-E1CNRT+/SYS-2028U-E1CNRT+-chassis-hc-topology.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/usr/src/lib/fm/topo/maps/SMCI,SYS-2028U-E1CNRT+/SYS-2028U-E1CNRT+-hc-topology.xml b/usr/src/lib/fm/topo/maps/SMCI,SYS-2028U-E1CNRT+/SYS-2028U-E1CNRT+-hc-topology.xml
new file mode 100644
index 000000000000..9554c607eecb
--- /dev/null
+++ b/usr/src/lib/fm/topo/maps/SMCI,SYS-2028U-E1CNRT+/SYS-2028U-E1CNRT+-hc-topology.xml
@@ -0,0 +1,161 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/usr/src/lib/fm/topo/maps/SMCI,SYS-2028U-E1CNRT+/SYS-2028U-E1CNRT+-usb.usbtopo b/usr/src/lib/fm/topo/maps/SMCI,SYS-2028U-E1CNRT+/SYS-2028U-E1CNRT+-usb.usbtopo
new file mode 100644
index 000000000000..bdbbbe4f44b4
--- /dev/null
+++ b/usr/src/lib/fm/topo/maps/SMCI,SYS-2028U-E1CNRT+/SYS-2028U-E1CNRT+-usb.usbtopo
@@ -0,0 +1,50 @@
+#
+# 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 2019 Joyent, Inc.
+#
+
+#
+# This file describes the USB topology for the SuperMicro
+# SYS-2028U-E1CNRT+ product. While the system board contains headers for up
+# to 5 USB 3.0 ports, this particular plaform only wires up two of them.
+# Both ports are accessible from the rear of the chassis.
+#
+# For more information on the format see topo_usb_file.c.
+#
+
+enable-acpi-match
+port
+ label
+ Rear Upper USB
+ chassis
+ external
+ port-type
+ 0x3
+ acpi-path
+ \_SB_.PC00.XHCI.RHUB.HS02
+ acpi-path
+ \_SB_.PC00.XHCI.RHUB.SS02
+end-port
+
+port
+ label
+ Rear Lower USB
+ chassis
+ external
+ port-type
+ 0x3
+ acpi-path
+ \_SB_.PC00.XHCI.RHUB.HS01
+ acpi-path
+ \_SB_.PC00.XHCI.RHUB.SS01
+end-port
diff --git a/usr/src/lib/fm/topo/modules/common/disk/Makefile b/usr/src/lib/fm/topo/modules/common/disk/Makefile
index 8e8935be6582..c04f4620be7c 100644
--- a/usr/src/lib/fm/topo/modules/common/disk/Makefile
+++ b/usr/src/lib/fm/topo/modules/common/disk/Makefile
@@ -22,13 +22,13 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
#
MODULE = disk
CLASS = common
-MODULESRCS = disk.c disk_common.c disk_mptsas.c
+MODULESRCS = disk.c disk_common.c disk_mptsas.c disk_nvme.c
include ../../Makefile.plugin
diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk.c b/usr/src/lib/fm/topo/modules/common/disk/disk.c
index c16fa28aaece..378e2b242144 100644
--- a/usr/src/lib/fm/topo/modules/common/disk/disk.c
+++ b/usr/src/lib/fm/topo/modules/common/disk/disk.c
@@ -22,7 +22,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
- * Copyright (c) 2018, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#include
@@ -53,7 +53,7 @@ disk_declare_driver(topo_mod_t *mod, tnode_t *baynode, topo_list_t *dlistp,
{
int err;
- if (strcmp("mpt_sas", driver) == 0) {
+ if (strcmp(MPTSAS_DRV, driver) == 0) {
char *sas_address = NULL;
tnode_t *child = NULL;
@@ -66,6 +66,11 @@ disk_declare_driver(topo_mod_t *mod, tnode_t *baynode, topo_list_t *dlistp,
topo_mod_strfree(mod, sas_address);
return (err);
+ } else if (strcmp(NVME_DRV, driver) == 0) {
+ if (disk_nvme_enum_disk(mod, baynode) != 0)
+ return (-1);
+
+ return (0);
}
topo_mod_dprintf(mod, "unknown disk driver '%s'\n", driver);
@@ -82,9 +87,10 @@ disk_enum(topo_mod_t *mod, tnode_t *baynode,
int err;
topo_list_t *dlistp = topo_mod_getspecific(mod);
- if (strcmp(name, DISK) != 0) {
+ if (strcmp(name, DISK) != 0 && strcmp(name, NVME) != 0) {
topo_mod_dprintf(mod, "disk_enum: "
- "only know how to enumerate %s components.\n", DISK);
+ "only know how to enumerate %s and %s components.", DISK,
+ NVME);
return (-1);
}
@@ -102,7 +108,13 @@ disk_enum(topo_mod_t *mod, tnode_t *baynode,
topo_strerror(err));
return (-1);
}
- if (topo_node_fru_set(baynode, fmri, 0, &err) != 0) {
+ /*
+ * If the disk enumerator module has been run from an XML map
+ * and the parent bay node was already created by an enumerator
+ * module (e.g. ses), then the FRU will already be set.
+ */
+ if (topo_node_fru_set(baynode, fmri, 0, &err) != 0 &&
+ err != ETOPO_PROP_DEFD) {
topo_mod_dprintf(mod, "disk_enum: "
"topo_node_fru error %s\n", topo_strerror(err));
nvlist_free(fmri);
@@ -134,7 +146,8 @@ disk_enum(topo_mod_t *mod, tnode_t *baynode,
if (topo_prop_get_string(baynode, TOPO_PGROUP_BINDING,
TOPO_BINDING_OCCUPANT, &device, &err) != 0) {
topo_mod_dprintf(mod, "disk_enum: "
- "binding error %s\n", topo_strerror(err));
+ "failed to lookup prop %s/%s: %s\n", TOPO_PGROUP_BINDING,
+ TOPO_BINDING_OCCUPANT, topo_strerror(err));
return (-1);
}
diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk.h b/usr/src/lib/fm/topo/modules/common/disk/disk.h
index 02aa7efc87d4..85965250f5e6 100644
--- a/usr/src/lib/fm/topo/modules/common/disk/disk.h
+++ b/usr/src/lib/fm/topo/modules/common/disk/disk.h
@@ -23,12 +23,13 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
- * Copyright (c) 2018, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _DISK_H
#define _DISK_H
+#include
#include
#include
@@ -42,6 +43,18 @@ extern "C" {
/* Max. number of devices for thumper */
#define DEVID_MAX 48
+/*
+ * Given a /devices path for a whole disk, appending this extension gives the
+ * path to a raw device that can be opened.
+ */
+#if defined(__i386) || defined(__amd64)
+#define PHYS_EXTN ":q,raw"
+#elif defined(__sparc) || defined(__sparcv9)
+#define PHYS_EXTN ":c,raw"
+#else
+#error Unknown architecture
+#endif
+
/* Properties added to the "storage" pgroup: */
#define TOPO_PGROUP_STORAGE "storage"
#define TOPO_STORAGE_LOGICAL_DISK_NAME "logical-disk"
@@ -52,21 +65,26 @@ extern "C" {
#define TOPO_STORAGE_CAPACITY "capacity-in-bytes"
#define TOPO_STORAGE_RPM "speed-in-rpm"
-/*
- * Properties for binding group: The binding group required in platform
- * specific xml that describes 'bay' nodes containing internal disks.
- */
-#define TOPO_PGROUP_BINDING "binding"
-#define TOPO_BINDING_OCCUPANT "occupant-path"
-#define TOPO_BINDING_DRIVER "driver"
-
-/*
- * The binding group required in platform specific xml that describes 'bay'
- * nodes containing disks attached to an HBA using the 'mpt_sas' driver.
- */
-#define TOPO_BINDING_DEVCTL "devctl"
-#define TOPO_BINDING_ENCLOSURE "enclosure"
-#define TOPO_BINDING_SLOT "slot"
+static const topo_pgroup_info_t io_pgroup = {
+ TOPO_PGROUP_IO,
+ TOPO_STABILITY_PRIVATE,
+ TOPO_STABILITY_PRIVATE,
+ 1
+};
+
+static const topo_pgroup_info_t disk_auth_pgroup = {
+ FM_FMRI_AUTHORITY,
+ TOPO_STABILITY_PRIVATE,
+ TOPO_STABILITY_PRIVATE,
+ 1
+};
+
+static const topo_pgroup_info_t storage_pgroup = {
+ TOPO_PGROUP_STORAGE,
+ TOPO_STABILITY_PRIVATE,
+ TOPO_STABILITY_PRIVATE,
+ 1
+};
/*
* device node information.
diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk_common.c b/usr/src/lib/fm/topo/modules/common/disk/disk_common.c
index ef4d638f94b7..d048daabd84a 100644
--- a/usr/src/lib/fm/topo/modules/common/disk/disk_common.c
+++ b/usr/src/lib/fm/topo/modules/common/disk/disk_common.c
@@ -61,18 +61,6 @@ typedef struct disk_cbdata {
dev_di_node_t *dcb_dnode; /* for di_devlink_walk only */
} disk_cbdata_t;
-/*
- * Given a /devices path for a whole disk, appending this extension gives the
- * path to a raw device that can be opened.
- */
-#if defined(__i386) || defined(__amd64)
-#define PHYS_EXTN ":q,raw"
-#elif defined(__sparc) || defined(__sparcv9)
-#define PHYS_EXTN ":c,raw"
-#else
-#error Unknown architecture
-#endif
-
/*
* Methods for disks. This is used by the disk-transport module to
* generate ereports based off SCSI disk status.
@@ -101,27 +89,6 @@ static const topo_method_t disk_fac_methods[] = {
{ NULL }
};
-static const topo_pgroup_info_t io_pgroup = {
- TOPO_PGROUP_IO,
- TOPO_STABILITY_PRIVATE,
- TOPO_STABILITY_PRIVATE,
- 1
-};
-
-static const topo_pgroup_info_t disk_auth_pgroup = {
- FM_FMRI_AUTHORITY,
- TOPO_STABILITY_PRIVATE,
- TOPO_STABILITY_PRIVATE,
- 1
-};
-
-static const topo_pgroup_info_t storage_pgroup = {
- TOPO_PGROUP_STORAGE,
- TOPO_STABILITY_PRIVATE,
- TOPO_STABILITY_PRIVATE,
- 1
-};
-
/*
* Set the properties of the disk node, from dev_di_node_t data.
* Properties include:
diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk_drivers.h b/usr/src/lib/fm/topo/modules/common/disk/disk_drivers.h
index 6851e2fe279b..91aa97963648 100644
--- a/usr/src/lib/fm/topo/modules/common/disk/disk_drivers.h
+++ b/usr/src/lib/fm/topo/modules/common/disk/disk_drivers.h
@@ -9,7 +9,7 @@
* http://www.illumos.org/license/CDDL.
*/
/*
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _DISK_DRIVERS_H
@@ -22,7 +22,11 @@
extern "C" {
#endif
+#define MPTSAS_DRV "mpt_sas"
+#define NVME_DRV "nvme"
+
int disk_mptsas_find_disk(topo_mod_t *, tnode_t *, char **);
+int disk_nvme_enum_disk(topo_mod_t *, tnode_t *);
#ifdef __cplusplus
}
diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk_nvme.c b/usr/src/lib/fm/topo/modules/common/disk/disk_nvme.c
new file mode 100644
index 000000000000..851c0678acb1
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/common/disk/disk_nvme.c
@@ -0,0 +1,589 @@
+/*
+ * 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 2019 Joyent, Inc.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include "disk.h"
+#include "disk_drivers.h"
+
+struct nvme_enum_info {
+ topo_mod_t *nei_mod;
+ di_node_t nei_dinode;
+ nvme_identify_ctrl_t *nei_idctl;
+ nvme_version_t nei_vers;
+ tnode_t *nei_bay;
+ tnode_t *nei_nvme;
+ nvlist_t *nei_nvme_fmri;
+ const char *nei_nvme_path;
+ int nei_fd;
+};
+
+struct devlink_arg {
+ topo_mod_t *dla_mod;
+ char *dla_logical_disk;
+};
+
+static int
+devlink_cb(di_devlink_t dl, void *arg)
+{
+ struct devlink_arg *dlarg = (struct devlink_arg *)arg;
+ topo_mod_t *mod = dlarg->dla_mod;
+ const char *devpath;
+ char *slice, *ctds;
+
+ if ((devpath = di_devlink_path(dl)) == NULL ||
+ (dlarg->dla_logical_disk = topo_mod_strdup(mod, devpath)) ==
+ NULL) {
+ return (DI_WALK_TERMINATE);
+ }
+
+ /* trim the slice off the public name */
+ if (((ctds = strrchr(dlarg->dla_logical_disk, '/')) != NULL) &&
+ ((slice = strchr(ctds, 's')) != NULL))
+ *slice = '\0';
+
+ return (DI_WALK_TERMINATE);
+}
+
+static char *
+get_logical_disk(topo_mod_t *mod, char *devpath)
+{
+ di_devlink_handle_t devhdl;
+ struct devlink_arg dlarg = { 0 };
+ char *minorpath = NULL;
+
+ if (asprintf(&minorpath, "%s:a", devpath) < 0) {
+ return (NULL);
+ }
+
+ if ((devhdl = di_devlink_init(NULL, 0)) == DI_NODE_NIL) {
+ topo_mod_dprintf(mod, "%s: di_devlink_init failed", __func__);
+ return (NULL);
+ }
+
+ dlarg.dla_mod = mod;
+
+ (void) di_devlink_walk(devhdl, "^dsk/", minorpath, DI_PRIMARY_LINK,
+ &dlarg, devlink_cb);
+
+ (void) di_devlink_fini(&devhdl);
+ free(minorpath);
+
+ return (dlarg.dla_logical_disk);
+}
+
+static int
+make_disk_node(struct nvme_enum_info *nvme_info, di_node_t dinode,
+ topo_instance_t inst)
+{
+ topo_mod_t *mod = nvme_info->nei_mod;
+ nvlist_t *auth = NULL, *fmri = NULL;
+ tnode_t *disk;
+ char *rev = NULL, *model = NULL, *serial = NULL, *path;
+ char *logical_disk = NULL, *devid, *manuf, *ctd = NULL;
+ char *cap_bytes_str = NULL, full_path[MAXPATHLEN + 1];
+ const char **ppaths = NULL;
+ struct dk_minfo minfo;
+ uint64_t cap_bytes;
+ int fd = -1, err, ret = -1, r;
+
+ if ((path = di_devfs_path(dinode)) == NULL) {
+ topo_mod_dprintf(mod, "%s: failed to get dev path", __func__);
+ (void) topo_mod_seterrno(mod, EMOD_UNKNOWN);
+ return (ret);
+ }
+
+ topo_mod_dprintf(mod, "%s: found nvme namespace: %s", __func__, path);
+
+ /*
+ * Issue the DKIOCGMEDIAINFO ioctl to get the capacity
+ */
+ (void) snprintf(full_path, MAXPATHLEN, "/devices%s%s", path,
+ PHYS_EXTN);
+ if ((fd = open(full_path, O_RDWR)) < 0 ||
+ ioctl(fd, DKIOCGMEDIAINFO, &minfo) < 0) {
+ topo_mod_dprintf(mod, "failed to get blkdev capacity (%s)",
+ strerror(errno));
+ (void) topo_mod_seterrno(mod, EMOD_UNKNOWN);
+ goto error;
+ }
+
+ cap_bytes = minfo.dki_lbsize * minfo.dki_capacity;
+
+ if (asprintf(&cap_bytes_str, "%" PRIu64, cap_bytes) < 0) {
+ topo_mod_dprintf(mod, "%s: failed to alloc string", __func__);
+ (void) topo_mod_seterrno(mod, EMOD_NOMEM);
+ goto error;
+ }
+
+ /*
+ * Gather the FRU identity information from the devinfo properties
+ */
+ if (di_prop_lookup_strings(DDI_DEV_T_ANY, dinode, DEVID_PROP_NAME,
+ &devid) == -1 ||
+ di_prop_lookup_strings(DDI_DEV_T_ANY, dinode, INQUIRY_VENDOR_ID,
+ &manuf) == -1 ||
+ di_prop_lookup_strings(DDI_DEV_T_ANY, dinode, INQUIRY_PRODUCT_ID,
+ &model) == -1 ||
+ di_prop_lookup_strings(DDI_DEV_T_ANY, dinode, INQUIRY_REVISION_ID,
+ &rev) == -1 ||
+ di_prop_lookup_strings(DDI_DEV_T_ANY, dinode, INQUIRY_SERIAL_NO,
+ &serial) == -1) {
+ topo_mod_dprintf(mod, "%s: failed to lookup devinfo props on "
+ "%s", __func__, path);
+ (void) topo_mod_seterrno(mod, EMOD_UNKNOWN);
+ goto error;
+ }
+
+ model = topo_mod_clean_str(mod, model);
+ rev = topo_mod_clean_str(mod, rev);
+ serial = topo_mod_clean_str(mod, serial);
+
+ /*
+ * Lookup the /dev/dsk/c#t#d# disk device name from the blkdev path
+ */
+ if ((logical_disk = get_logical_disk(mod, path)) == NULL) {
+ topo_mod_dprintf(mod, "failed to find logical disk");
+ (void) topo_mod_seterrno(mod, EMOD_UNKNOWN);
+ goto error;
+ }
+
+ /*
+ * If we were able to look up the logical disk path for this namespace
+ * then set ctd to be that pathname, minus the "/dev/dsk/" portion.
+ */
+ if ((ctd = strrchr(logical_disk, '/')) != NULL) {
+ ctd = ctd + 1;
+ } else {
+ topo_mod_dprintf(mod, "malformed logical disk path: %s",
+ logical_disk);
+ (void) topo_mod_seterrno(mod, EMOD_UNKNOWN);
+ goto error;
+ }
+
+ /*
+ * Build the FMRI and then bind the disk node to the parent nvme node.
+ */
+ auth = topo_mod_auth(mod, nvme_info->nei_nvme);
+ fmri = topo_mod_hcfmri(mod, nvme_info->nei_nvme, FM_HC_SCHEME_VERSION,
+ DISK, inst, NULL, auth, model, rev, serial);
+
+ if (fmri == NULL) {
+ /* errno set */
+ topo_mod_dprintf(mod, "%s: hcfmri failed for %s=%u/%s=0/%s=%u",
+ __func__, BAY, topo_node_instance(nvme_info->nei_bay),
+ NVME, DISK, inst);
+ goto error;
+ }
+ if ((disk = topo_node_bind(mod, nvme_info->nei_nvme, DISK, inst,
+ fmri)) == NULL) {
+ /* errno set */
+ topo_mod_dprintf(mod, "%s: bind failed for %s=%u/%s=0/%s=%u",
+ __func__, BAY, topo_node_instance(nvme_info->nei_bay),
+ NVME, DISK, inst);
+ goto error;
+ }
+
+ /* Create authority and system prop groups */
+ topo_pgroup_hcset(disk, auth);
+
+ /*
+ * As the "disk" in this case is simply a logical construct
+ * representing an NVMe namespace, we set the FRU to be the parent
+ * node, which will be the NVMe controller.
+ */
+ if (topo_node_fru_set(disk, nvme_info->nei_nvme_fmri, 0, &err) != 0) {
+ topo_mod_dprintf(mod, "%s: failed to set FRU: %s", __func__,
+ topo_strerror(err));
+ (void) topo_mod_seterrno(mod, err);
+ goto error;
+ }
+
+ if ((ppaths = topo_mod_zalloc(mod, sizeof (char *))) == NULL) {
+ (void) topo_mod_seterrno(mod, EMOD_NOMEM);
+ goto error;
+ }
+ ppaths[0] = path;
+
+ /*
+ * Create the "storage" and "io" property groups and then fill them
+ * with the standard set of properties for "disk" nodes.
+ */
+ if (topo_pgroup_create(disk, &io_pgroup, &err) != 0 ||
+ topo_pgroup_create(disk, &storage_pgroup, &err) != 0) {
+ topo_mod_dprintf(mod, "%s: failed to create propgroups: %s",
+ __func__, topo_strerror(err));
+ (void) topo_mod_seterrno(mod, err);
+ goto error;
+ }
+
+ r = topo_prop_set_string(disk, TOPO_PGROUP_IO, TOPO_IO_DEV_PATH,
+ TOPO_PROP_IMMUTABLE, path, &err);
+
+ r += topo_prop_set_string_array(disk, TOPO_PGROUP_IO,
+ TOPO_IO_PHYS_PATH, TOPO_PROP_IMMUTABLE, ppaths, 1, &err);
+
+ r += topo_prop_set_string(disk, TOPO_PGROUP_IO, TOPO_IO_DEVID,
+ TOPO_PROP_IMMUTABLE, devid, &err);
+
+ r += topo_prop_set_string(disk, TOPO_PGROUP_STORAGE,
+ TOPO_STORAGE_MANUFACTURER, TOPO_PROP_IMMUTABLE, manuf, &err);
+
+ r += topo_prop_set_string(disk, TOPO_PGROUP_STORAGE,
+ TOPO_STORAGE_CAPACITY, TOPO_PROP_IMMUTABLE, cap_bytes_str,
+ &err);
+
+ r += topo_prop_set_string(disk, TOPO_PGROUP_STORAGE,
+ TOPO_STORAGE_SERIAL_NUM, TOPO_PROP_IMMUTABLE, serial, &err);
+
+ r += topo_prop_set_string(disk, TOPO_PGROUP_STORAGE,
+ TOPO_STORAGE_MODEL, TOPO_PROP_IMMUTABLE, model, &err);
+
+ r += topo_prop_set_string(disk, TOPO_PGROUP_STORAGE,
+ TOPO_STORAGE_FIRMWARE_REV, TOPO_PROP_IMMUTABLE, rev, &err);
+
+ r += topo_prop_set_string(disk, TOPO_PGROUP_STORAGE,
+ TOPO_STORAGE_LOGICAL_DISK_NAME, TOPO_PROP_IMMUTABLE, ctd, &err);
+
+ if (r != 0) {
+ topo_mod_dprintf(mod, "%s: failed to create properties: %s",
+ __func__, topo_strerror(err));
+ (void) topo_mod_seterrno(mod, EMOD_UNKNOWN);
+ goto error;
+ }
+
+ ret = 0;
+
+error:
+ free(cap_bytes_str);
+ if (fd > 0)
+ (void) close(fd);
+ if (ppaths != NULL)
+ topo_mod_free(mod, ppaths, sizeof (char *));
+ di_devfs_path_free(path);
+ nvlist_free(auth);
+ nvlist_free(fmri);
+ topo_mod_strfree(mod, rev);
+ topo_mod_strfree(mod, model);
+ topo_mod_strfree(mod, serial);
+ topo_mod_strfree(mod, logical_disk);
+ return (ret);
+}
+
+static const topo_pgroup_info_t nvme_pgroup = {
+ TOPO_PGROUP_NVME,
+ TOPO_STABILITY_PRIVATE,
+ TOPO_STABILITY_PRIVATE,
+ 1
+};
+
+#define NVME_MODEL_SZ 40
+#define NVME_SERIAL_SZ 20
+
+static int
+make_nvme_node(struct nvme_enum_info *nvme_info)
+{
+ topo_mod_t *mod = nvme_info->nei_mod;
+ nvlist_t *auth = NULL, *fmri = NULL;
+ tnode_t *nvme;
+ char raw_rev[NVME_FWVER_SZ + 1], raw_model[NVME_MODEL_SZ + 1];
+ char raw_serial[NVME_SERIAL_SZ + 1];
+ char *rev = NULL, *model = NULL, *serial = NULL, *vers = NULL;
+ int err = 0, ret = -1;
+ di_node_t cn;
+ uint_t i;
+
+ /*
+ * The raw strings returned by the IDENTIFY CONTROLLER command are
+ * not NUL-terminated, so we fix that up.
+ */
+ (void) strncpy(raw_rev, nvme_info->nei_idctl->id_fwrev, NVME_FWVER_SZ);
+ raw_rev[NVME_FWVER_SZ] = '\0';
+ (void) strncpy(raw_model, nvme_info->nei_idctl->id_model,
+ NVME_MODEL_SZ);
+ raw_model[NVME_MODEL_SZ] = '\0';
+ (void) strncpy(raw_serial, nvme_info->nei_idctl->id_serial,
+ NVME_SERIAL_SZ);
+ raw_serial[NVME_SERIAL_SZ] = '\0';
+
+ /*
+ * Next we pass the strings through a function that sanitizes them of
+ * any characters that can't be used in an FMRI string.
+ */
+ rev = topo_mod_clean_str(mod, raw_rev);
+ model = topo_mod_clean_str(mod, raw_model);
+ serial = topo_mod_clean_str(mod, raw_serial);
+
+ auth = topo_mod_auth(mod, nvme_info->nei_bay);
+ fmri = topo_mod_hcfmri(mod, nvme_info->nei_bay, FM_HC_SCHEME_VERSION,
+ NVME, 0, NULL, auth, model, rev, serial);
+
+ if (fmri == NULL) {
+ /* errno set */
+ topo_mod_dprintf(mod, "%s: hcfmri failed for %s=%u/%s=0",
+ __func__, BAY, topo_node_instance(nvme_info->nei_bay),
+ NVME);
+ goto error;
+ }
+
+ /*
+ * Create a new topo node to represent the NVMe controller and bind it
+ * to the parent bay node.
+ */
+ if ((nvme = topo_node_bind(mod, nvme_info->nei_bay, NVME, 0, fmri)) ==
+ NULL) {
+ /* errno set */
+ topo_mod_dprintf(mod, "%s: bind failed for %s=%u/%s=0",
+ __func__, BAY, topo_node_instance(nvme_info->nei_bay),
+ NVME);
+ goto error;
+ }
+ nvme_info->nei_nvme = nvme;
+ nvme_info->nei_nvme_fmri = fmri;
+
+ /* Create authority and system prop groups */
+ topo_pgroup_hcset(nvme, auth);
+
+ if (topo_node_fru_set(nvme, fmri, 0, &err) != 0) {
+ topo_mod_dprintf(mod, "%s: failed to set FRU: %s", __func__,
+ topo_strerror(err));
+ (void) topo_mod_seterrno(mod, err);
+ goto error;
+ }
+ if (topo_pgroup_create(nvme, &nvme_pgroup, &err) != 0) {
+ topo_mod_dprintf(mod, "%s: failed to create %s pgroup: %s",
+ __func__, TOPO_PGROUP_NVME, topo_strerror(err));
+ (void) topo_mod_seterrno(mod, err);
+ goto error;
+ }
+
+ if (asprintf(&vers, "%u.%u", nvme_info->nei_vers.v_major,
+ nvme_info->nei_vers.v_minor) < 0) {
+ topo_mod_dprintf(mod, "%s: failed to alloc string", __func__);
+ (void) topo_mod_seterrno(mod, EMOD_NOMEM);
+ goto error;
+ }
+ if (topo_prop_set_string(nvme, TOPO_PGROUP_NVME, TOPO_PROP_NVME_VER,
+ TOPO_PROP_IMMUTABLE, vers, &err) != 0) {
+ (void) topo_mod_seterrno(mod, err);
+ goto error;
+ }
+
+ if (topo_pgroup_create(nvme, &io_pgroup, &err) != 0) {
+ topo_mod_dprintf(mod, "%s: failed to create %s pgroup: %s",
+ __func__, TOPO_PGROUP_IO, topo_strerror(err));
+ (void) topo_mod_seterrno(mod, err);
+ goto error;
+ }
+ if (topo_prop_set_string(nvme, TOPO_PGROUP_IO, TOPO_IO_DEV_PATH,
+ TOPO_PROP_IMMUTABLE, nvme_info->nei_nvme_path, &err) != 0) {
+ (void) topo_mod_seterrno(mod, err);
+ goto error;
+ }
+
+ /*
+ * Create a child disk node for each namespace.
+ */
+ if (topo_node_range_create(mod, nvme, DISK, 0,
+ (nvme_info->nei_idctl->id_nn - 1)) < 0) {
+ /* errno set */
+ topo_mod_dprintf(mod, "%s: error creating %s range", __func__,
+ DISK);
+ goto error;
+ }
+
+ for (i = 0, cn = di_child_node(nvme_info->nei_dinode);
+ cn != DI_NODE_NIL;
+ i++, cn = di_sibling_node(cn)) {
+
+ if (make_disk_node(nvme_info, cn, i) != 0) {
+ /* errno set */
+ goto error;
+ }
+ }
+ ret = 0;
+
+error:
+ free(vers);
+ nvlist_free(auth);
+ nvlist_free(fmri);
+ topo_mod_strfree(mod, rev);
+ topo_mod_strfree(mod, model);
+ topo_mod_strfree(mod, serial);
+ return (ret);
+}
+
+struct diwalk_arg {
+ topo_mod_t *diwk_mod;
+ tnode_t *diwk_bay;
+};
+
+/*
+ * This function gathers identity information from the NVMe controller and
+ * stores it in a struct. This struct is passed to make_nvme_node(), which
+ * does the actual topo node creation.
+ */
+static int
+discover_nvme_ctl(di_node_t node, di_minor_t minor, void *arg)
+{
+ struct diwalk_arg *wkarg = (struct diwalk_arg *)arg;
+ topo_mod_t *mod = wkarg->diwk_mod;
+ char *path, *devctl = NULL;
+ nvme_ioctl_t nioc = { 0 };
+ nvme_identify_ctrl_t *idctl = NULL;
+ struct nvme_enum_info nvme_info = { 0 };
+ int fd = -1, ret = DI_WALK_TERMINATE;
+
+ if ((path = di_devfs_minor_path(minor)) == NULL) {
+ topo_mod_dprintf(mod, "failed to get minor path");
+ (void) topo_mod_seterrno(mod, EMOD_UNKNOWN);
+ return (ret);
+ }
+
+ topo_mod_dprintf(mod, "%s=%u: found nvme controller: %s", BAY,
+ topo_node_instance(wkarg->diwk_bay), path);
+
+ if (asprintf(&devctl, "/devices%s", path) < 0) {
+ topo_mod_dprintf(mod, "failed to alloc string");
+ (void) topo_mod_seterrno(mod, EMOD_NOMEM);
+ goto error;
+ }
+
+ if ((fd = open(devctl, O_RDWR)) < 0) {
+ topo_mod_dprintf(mod, "failed to open %s", devctl);
+ (void) topo_mod_seterrno(mod, EMOD_UNKNOWN);
+ goto error;
+ }
+ if ((idctl = topo_mod_zalloc(mod, NVME_IDENTIFY_BUFSIZE)) == NULL) {
+ topo_mod_dprintf(mod, "zalloc failed");
+ (void) topo_mod_seterrno(mod, EMOD_NOMEM);
+ goto error;
+ }
+ nioc.n_len = NVME_IDENTIFY_BUFSIZE;
+ nioc.n_buf = (uintptr_t)idctl;
+
+ if (ioctl(fd, NVME_IOC_IDENTIFY_CTRL, &nioc) != 0) {
+ topo_mod_dprintf(mod, "NVME_IOC_IDENTIFY_CTRL ioctl "
+ "failed: %s", strerror(errno));
+ (void) topo_mod_seterrno(mod, EMOD_UNKNOWN);
+ goto error;
+ }
+
+ nioc.n_len = sizeof (nvme_version_t);
+ nioc.n_buf = (uintptr_t)&nvme_info.nei_vers;
+
+ if (ioctl(fd, NVME_IOC_VERSION, &nioc) != 0) {
+ topo_mod_dprintf(mod, "NVME_IOC_VERSION ioctl failed: %s",
+ strerror(errno));
+ (void) topo_mod_seterrno(mod, EMOD_UNKNOWN);
+ goto error;
+ }
+
+ nvme_info.nei_mod = mod;
+ nvme_info.nei_nvme_path = path;
+ nvme_info.nei_dinode = node;
+ nvme_info.nei_idctl = idctl;
+ nvme_info.nei_bay = wkarg->diwk_bay;
+ nvme_info.nei_fd = fd;
+
+ if (make_nvme_node(&nvme_info) != 0)
+ /* errno set */
+ goto error;
+
+ ret = DI_WALK_CONTINUE;
+
+error:
+ if (fd > 0)
+ (void) close(fd);
+ di_devfs_path_free(path);
+ free(devctl);
+ if (idctl != NULL)
+ topo_mod_free(mod, idctl, NVME_IDENTIFY_BUFSIZE);
+ return (ret);
+}
+
+int
+disk_nvme_enum_disk(topo_mod_t *mod, tnode_t *baynode)
+{
+ char *parent = NULL;
+ int err;
+ di_node_t devtree;
+ di_node_t dnode;
+ struct diwalk_arg wkarg = { 0 };
+ int ret = -1;
+
+ /*
+ * Lookup a property containing the devfs path of the parent PCIe
+ * device of the NVMe device we're attempting to enumerate. This
+ * property is hard-coded in per-platform topo XML maps that are
+ * delivered with the OS. This hard-coded path allows topo to map a
+ * given NVMe controller to a physical location (bay or slot) on the
+ * platform, when generating the topo snapshot.
+ */
+ if (topo_prop_get_string(baynode, TOPO_PGROUP_BINDING,
+ TOPO_BINDING_PARENT_DEV, &parent, &err) != 0) {
+ topo_mod_dprintf(mod, "bay node was missing nvme binding "
+ "properties\n");
+ goto out;
+ }
+ if ((devtree = topo_mod_devinfo(mod)) == DI_NODE_NIL) {
+ topo_mod_dprintf(mod, "failed to get devinfo snapshot");
+ goto out;
+ }
+
+ /*
+ * Walk the devinfo tree looking NVMe devices. For each NVMe device,
+ * check if the devfs path of the parent matches the one specified in
+ * TOPO_BINDING_PARENT_DEV.
+ */
+ wkarg.diwk_mod = mod;
+ wkarg.diwk_bay = baynode;
+ dnode = di_drv_first_node(NVME_DRV, devtree);
+ while (dnode != DI_NODE_NIL) {
+ char *path;
+
+ if ((path = di_devfs_path(di_parent_node(dnode))) == NULL) {
+ topo_mod_dprintf(mod, "failed to get dev path");
+ goto out;
+ }
+ if (strcmp(parent, path) == 0) {
+ if (di_walk_minor(dnode, DDI_NT_NVME_NEXUS, 0,
+ &wkarg, discover_nvme_ctl) < 0) {
+ di_devfs_path_free(path);
+ goto out;
+ }
+ }
+ di_devfs_path_free(path);
+ dnode = di_drv_next_node(dnode);
+ }
+ ret = 0;
+
+out:
+ topo_mod_strfree(mod, parent);
+ return (ret);
+}
diff --git a/usr/src/lib/fm/topo/modules/common/ses/ses.c b/usr/src/lib/fm/topo/modules/common/ses/ses.c
index 627780b4472e..003814d2599c 100644
--- a/usr/src/lib/fm/topo/modules/common/ses/ses.c
+++ b/usr/src/lib/fm/topo/modules/common/ses/ses.c
@@ -23,7 +23,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012 Milan Jurik. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2019, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#include
@@ -226,14 +226,6 @@ typedef enum {
SES_DUP_SUBCHASSIS = 0x8
} ses_chassis_type_e;
-
-static const topo_pgroup_info_t storage_pgroup = {
- TOPO_PGROUP_STORAGE,
- TOPO_STABILITY_PRIVATE,
- TOPO_STABILITY_PRIVATE,
- 1
-};
-
static const topo_pgroup_info_t smp_pgroup = {
TOPO_PGROUP_SMP,
TOPO_STABILITY_PRIVATE,