diff options
Diffstat (limited to 'usr/src/lib/fm')
16 files changed, 543 insertions, 27 deletions
diff --git a/usr/src/lib/fm/libfmd_adm/common/fmd_adm.c b/usr/src/lib/fm/libfmd_adm/common/fmd_adm.c index 3c1c189c8d..d102735eb7 100644 --- a/usr/src/lib/fm/libfmd_adm/common/fmd_adm.c +++ b/usr/src/lib/fm/libfmd_adm/common/fmd_adm.c @@ -24,6 +24,10 @@ * Use is subject to license terms. */ +/* + * Copyright 2019 Joyent, Inc. + */ + #include <strings.h> #include <stdlib.h> #include <netdir.h> @@ -1027,7 +1031,7 @@ fmd_adm_xprt_iter(fmd_adm_t *ap, fmd_adm_xprt_f *func, void *arg) } for (i = 0; i < rxl.rxl_len; i++) - func(rxl.rxl_buf.rxl_buf_val[i], arg); + (void) func(rxl.rxl_buf.rxl_buf_val[i], arg); xdr_free(xdr_fmd_rpc_xprtlist, (char *)&rxl); return (0); diff --git a/usr/src/lib/fm/libfmd_snmp/Makefile.com b/usr/src/lib/fm/libfmd_snmp/Makefile.com index 99dd888363..e0abeeef0d 100644 --- a/usr/src/lib/fm/libfmd_snmp/Makefile.com +++ b/usr/src/lib/fm/libfmd_snmp/Makefile.com @@ -53,7 +53,7 @@ $(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG CFLAGS += $(CCVERBOSE) $(C_BIGPICFLAGS) CFLAGS64 += $(CCVERBOSE) $(C_BIGPICFLAGS) -SNMPLIBS = -lnetsnmp -lnetsnmpagent +SNMPLIBS = -lnetsnmp -lnetsnmpagent -lnetsnmphelpers NATIVE_LIBS += libnetsnmp.so libnetsnmpagent.so LDLIBS += $(MACH_LDLIBS) diff --git a/usr/src/lib/fm/topo/libtopo/common/libtopo.h b/usr/src/lib/fm/topo/libtopo/common/libtopo.h index c8dcdb9cd4..93884718c6 100644 --- a/usr/src/lib/fm/topo/libtopo/common/libtopo.h +++ b/usr/src/lib/fm/topo/libtopo/common/libtopo.h @@ -410,6 +410,8 @@ extern void topo_hdl_free(topo_hdl_t *, void *, size_t); extern int topo_hdl_nvalloc(topo_hdl_t *, nvlist_t **, uint_t); extern int topo_hdl_nvdup(topo_hdl_t *, nvlist_t *, nvlist_t **); extern char *topo_hdl_strdup(topo_hdl_t *, const char *); +extern char *topo_hdl_strsplit(topo_hdl_t *, const char *, const char *, + char **); /* * Interfaces for interacting with directed graph topologies diff --git a/usr/src/lib/fm/topo/libtopo/common/mapfile-vers b/usr/src/lib/fm/topo/libtopo/common/mapfile-vers index 5d1b53f1f6..ca33084ff2 100644 --- a/usr/src/lib/fm/topo/libtopo/common/mapfile-vers +++ b/usr/src/lib/fm/topo/libtopo/common/mapfile-vers @@ -86,6 +86,7 @@ SYMBOL_VERSION SUNWprivate { topo_hdl_strdup; topo_hdl_strfree; topo_hdl_strfreev; + topo_hdl_strsplit; topo_hdl_zalloc; topo_led_state_name; topo_led_type_name; @@ -101,6 +102,8 @@ SYMBOL_VERSION SUNWprivate { topo_mod_alloc; topo_mod_auth; topo_mod_clean_str; + topo_mod_create_ufm; + topo_mod_create_ufm_slot; topo_mod_clrdebug; topo_mod_cpufmri; topo_mod_create_ufm; @@ -137,6 +140,7 @@ SYMBOL_VERSION SUNWprivate { topo_mod_strdup; topo_mod_strfree; topo_mod_strfreev; + topo_mod_strsplit; topo_mod_unload; topo_mod_unregister; topo_mod_walk_init; 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 593f8946fb..1e5589b78c 100644 --- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h +++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h @@ -236,6 +236,27 @@ extern "C" { */ #define TOPO_PROP_IPMI_ENTITY_LIST "entity-list" +/* + * These properties can be used to describe the network configuration of a + * given hardware components. They're currently used to describe the + * network config on the service processor (sp) + */ +#define TOPO_PGROUP_NETCFG "network-config" +#define TOPO_PROP_NETCFG_MACADDR "mac-address" +#define TOPO_PROP_NETCFG_VLAN_ID "vlan-id" +#define TOPO_PROP_NETCFG_IPV4_ADDR "ipv4-address" +#define TOPO_PROP_NETCFG_IPV4_SUBNET "ipv4-subnet" +#define TOPO_PROP_NETCFG_IPV4_GATEWAY "ipv4-gateway" +#define TOPO_PROP_NETCFG_IPV4_TYPE "ipv4-config-type" +#define TOPO_PROP_NETCFG_IPV6_ADDR "ipv6-address" +#define TOPO_PROP_NETCFG_IPV6_ROUTES "ipv6-routes" +#define TOPO_PROP_NETCFG_IPV6_TYPE "ipv6-config-type" + +/* Possible values for TOPO_PROP_NETCFG_TYPE */ +#define TOPO_NETCFG_TYPE_UNKNOWN "unknown" +#define TOPO_NETCFG_TYPE_STATIC "static" +#define TOPO_NETCFG_TYPE_DHCP "dhcp" + #define TOPO_PGROUP_SLOT "slot" #define TOPO_PROP_SLOT_TYPE "slot-type" 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 4e2ec816fc..772c51bb0a 100644 --- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.h +++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.h @@ -222,6 +222,8 @@ extern void topo_mod_free(topo_mod_t *, void *, size_t); extern char *topo_mod_strdup(topo_mod_t *, const char *); extern void topo_mod_strfree(topo_mod_t *, char *); extern void topo_mod_strfreev(topo_mod_t *, char **, uint_t); +extern char *topo_mod_strsplit(topo_mod_t *, const char *, const char *, + char **); extern int topo_mod_nvalloc(topo_mod_t *, nvlist_t **, uint_t); extern int topo_mod_nvdup(topo_mod_t *, nvlist_t *, nvlist_t **); diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_string.c b/usr/src/lib/fm/topo/libtopo/common/topo_string.c index 53a6280647..bca2bdc66a 100644 --- a/usr/src/lib/fm/topo/libtopo/common/topo_string.c +++ b/usr/src/lib/fm/topo/libtopo/common/topo_string.c @@ -66,6 +66,58 @@ topo_hdl_strfreev(topo_hdl_t *thp, char **strarr, uint_t nelem) } char * +topo_hdl_strsplit(topo_hdl_t *hdl, const char *input, const char *sep, + char **lastp) +{ + size_t seplen = strlen(sep); + const char *scanstart; + char *token; + char *ret; + + if (input != NULL) { + /* + * Start scanning at beginning of input: + */ + scanstart = input; + } else if (*lastp == NULL) { + /* + * If we have already finished scanning, return NULL. + */ + return (NULL); + } else { + /* + * Otherwise, start scanning where we left off: + */ + scanstart = *lastp; + } + + token = strstr(scanstart, sep); + if (token != NULL) { + /* + * We still have a separator, so advance the next-start + * pointer past it: + */ + *lastp = token + seplen; + /* + * Copy out this element. The buffer must fit the string + * exactly, so that topo_hdl_strfree() can determine its + * size with strlen(). + */ + ret = topo_hdl_alloc(hdl, token - scanstart + 1); + (void) strncpy(ret, scanstart, token - scanstart); + ret[token - scanstart] = '\0'; + } else { + /* + * We have no separator, so this is the last element: + */ + *lastp = NULL; + ret = topo_hdl_strdup(hdl, scanstart); + } + + return (ret); +} + +char * topo_mod_strdup(topo_mod_t *mod, const char *s) { return (topo_hdl_strdup(mod->tm_hdl, s)); @@ -83,6 +135,13 @@ topo_mod_strfreev(topo_mod_t *mod, char **strarr, uint_t nelem) topo_hdl_strfreev(mod->tm_hdl, strarr, nelem); } +char * +topo_mod_strsplit(topo_mod_t *mod, const char *input, const char *sep, + char **lastp) +{ + return (topo_hdl_strsplit(mod->tm_hdl, input, sep, lastp)); +} + const char * topo_strbasename(const char *s) { diff --git a/usr/src/lib/fm/topo/maps/Joyent,Joyent-Compute-Platform-1101/Joyent-Compute-Platform-1101-disk-hc-topology.xmlgenksh b/usr/src/lib/fm/topo/maps/Joyent,Joyent-Compute-Platform-1101/Joyent-Compute-Platform-1101-disk-hc-topology.xmlgenksh index 874bad142f..874bad142f 100644..100755 --- a/usr/src/lib/fm/topo/maps/Joyent,Joyent-Compute-Platform-1101/Joyent-Compute-Platform-1101-disk-hc-topology.xmlgenksh +++ b/usr/src/lib/fm/topo/maps/Joyent,Joyent-Compute-Platform-1101/Joyent-Compute-Platform-1101-disk-hc-topology.xmlgenksh diff --git a/usr/src/lib/fm/topo/maps/Joyent,Joyent-Storage-Platform-7001/Joyent-Storage-Platform-7001-slot-hc-topology.xml b/usr/src/lib/fm/topo/maps/Joyent,Joyent-Storage-Platform-7001/Joyent-Storage-Platform-7001-slot-hc-topology.xml index 6b16063427..9362ae3e8d 100644 --- a/usr/src/lib/fm/topo/maps/Joyent,Joyent-Storage-Platform-7001/Joyent-Storage-Platform-7001-slot-hc-topology.xml +++ b/usr/src/lib/fm/topo/maps/Joyent,Joyent-Storage-Platform-7001/Joyent-Storage-Platform-7001-slot-hc-topology.xml @@ -11,7 +11,7 @@ source. A copy of the CDDL is also available via the Internet at http://www.illumos.org/license/CDDL. - Copyright (c) 2018, Joyent, Inc. + Copyright (c) 2019, Joyent, Inc. --> @@ -201,7 +201,7 @@ <propgroup name='ipmi' version='1' name-stability='Private' data-stability='Private' > <propval name='entity-list' type='string_array' > - <propitem value='P2-DIMMF1 Temp' /> + <propitem value='P2-DIMMF2 Temp' /> </propval> </propgroup> </node> diff --git a/usr/src/lib/fm/topo/maps/SMCI,SSG-2028R-ACR24L/SSG-2028R-ACR24L-slot-hc-topology.xml b/usr/src/lib/fm/topo/maps/SMCI,SSG-2028R-ACR24L/SSG-2028R-ACR24L-slot-hc-topology.xml index 6b16063427..9362ae3e8d 100644 --- a/usr/src/lib/fm/topo/maps/SMCI,SSG-2028R-ACR24L/SSG-2028R-ACR24L-slot-hc-topology.xml +++ b/usr/src/lib/fm/topo/maps/SMCI,SSG-2028R-ACR24L/SSG-2028R-ACR24L-slot-hc-topology.xml @@ -11,7 +11,7 @@ source. A copy of the CDDL is also available via the Internet at http://www.illumos.org/license/CDDL. - Copyright (c) 2018, Joyent, Inc. + Copyright (c) 2019, Joyent, Inc. --> @@ -201,7 +201,7 @@ <propgroup name='ipmi' version='1' name-stability='Private' data-stability='Private' > <propval name='entity-list' type='string_array' > - <propitem value='P2-DIMMF1 Temp' /> + <propitem value='P2-DIMMF2 Temp' /> </propval> </propgroup> </node> 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 0ddcd1e0d8..f6b0a39e9e 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 @@ -83,6 +83,9 @@ Copyright 2019 Joyent, Inc. <range name='hostbridge' min='0' max='254'> <enum-method name='hostbridge' version='1' /> </range> + <range name='sp' min='0' max='0'> + <enum-method name='ipmi' version='1' /> + </range> <range name='usb-mobo' min='0' max='100'> <enum-method name='usb' version='1' /> </range> @@ -161,7 +164,7 @@ Copyright 2019 Joyent, Inc. </range> </set> - <set type='product' setlist='Joyent-Compute-Platform-1101|Joyent-Compute-Platform-1102'> + <set type='product' setlist='Joyent-Compute-Platform-1101|Joyent-Compute-Platform-1102|Joyent-Compute-Platform-2101|Joyent-Compute-Platform-2102'> <range name='psu' min='0' max='1'> <enum-method name='ipmi' version='1' /> </range> diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk_mptsas.c b/usr/src/lib/fm/topo/modules/common/disk/disk_mptsas.c index db853c6695..beae89f9f1 100644 --- a/usr/src/lib/fm/topo/modules/common/disk/disk_mptsas.c +++ b/usr/src/lib/fm/topo/modules/common/disk/disk_mptsas.c @@ -32,11 +32,18 @@ #include "disk.h" #include "disk_drivers.h" +/* + * Request the SAS address of the disk (if any) attached to this mpt_sas + * instance at (Enclosure Number, Slot Number). The function returns + * -1 on error and sets errno to ENOENT _only_ if the /devices node + * (*devctl) does not exist. + */ static int get_sas_address(topo_mod_t *mod, char *devctl, uint32_t enclosure, uint32_t slot, char **sas_address) { - int fd, err, i; + int ret = -1, en = ENXIO; + int fd, i; mptsas_get_disk_info_t gdi; mptsas_disk_info_t *di; size_t disz; @@ -44,16 +51,19 @@ get_sas_address(topo_mod_t *mod, char *devctl, uint32_t enclosure, bzero(&gdi, sizeof (gdi)); if ((fd = open(devctl, O_RDWR)) == -1) { + en = errno; topo_mod_dprintf(mod, "could not open '%s' for ioctl: %s\n", devctl, strerror(errno)); + errno = en; return (-1); } if (ioctl(fd, MPTIOCTL_GET_DISK_INFO, &gdi) == -1) { + if (errno != ENOENT) + en = errno; topo_mod_dprintf(mod, "ioctl 1 on '%s' failed: %s\n", devctl, strerror(errno)); - (void) close(fd); - return (-1); + goto out; } gdi.DiskInfoArraySize = disz = sizeof (mptsas_disk_info_t) * @@ -61,19 +71,19 @@ get_sas_address(topo_mod_t *mod, char *devctl, uint32_t enclosure, gdi.PtrDiskInfoArray = di = topo_mod_alloc(mod, disz); if (di == NULL) { topo_mod_dprintf(mod, "memory allocation failed\n"); - (void) close(fd); - return (-1); + en = ENOMEM; + goto out; } if (ioctl(fd, MPTIOCTL_GET_DISK_INFO, &gdi) == -1) { + if (errno != ENOENT) + en = errno; topo_mod_dprintf(mod, "ioctl 2 on '%s' failed: %s\n", devctl, strerror(errno)); topo_mod_free(mod, di, disz); - (void) close(fd); - return (-1); + goto out; } - err = -1; for (i = 0; i < gdi.DiskCount; i++) { if (di[i].Enclosure == enclosure && di[i].Slot == slot) { char sas[17]; /* 16 hex digits and NUL */ @@ -81,14 +91,16 @@ get_sas_address(topo_mod_t *mod, char *devctl, uint32_t enclosure, topo_mod_dprintf(mod, "found mpt_sas disk (%d/%d) " "with adddress %s\n", enclosure, slot, sas); *sas_address = topo_mod_strdup(mod, sas); - err = 0; + en = ret = 0; break; } } topo_mod_free(mod, di, disz); +out: (void) close(fd); - return (err); + errno = en; + return (ret); } int @@ -97,6 +109,8 @@ disk_mptsas_find_disk(topo_mod_t *mod, tnode_t *baynode, char **sas_address) char *devctl = NULL; uint32_t enclosure, slot; int err; + char *elem, *lastp; + int ret = -1; /* * Get the required properties from the node. These come from @@ -115,6 +129,35 @@ disk_mptsas_find_disk(topo_mod_t *mod, tnode_t *baynode, char **sas_address) return (-1); } - return (get_sas_address(mod, devctl, enclosure, slot, sas_address)); + /* + * devctl is a (potentially) pipe-separated list of different device + * paths to try. + */ + if ((elem = topo_mod_strsplit(mod, devctl, "|", &lastp)) != NULL) { + boolean_t done = B_FALSE; + do { + topo_mod_dprintf(mod, "trying mpt_sas instance at %s\n", + elem); + + ret = get_sas_address(mod, elem, enclosure, + slot, sas_address); + + /* + * Only try further devctl paths from the list if this + * one was not found: + */ + if (ret == 0 || errno != ENOENT) { + done = B_TRUE; + } else { + topo_mod_dprintf(mod, "instance not found\n"); + } + + topo_mod_strfree(mod, elem); + + } while (!done && (elem = topo_mod_strsplit(mod, NULL, "|", + &lastp)) != NULL); + } + topo_mod_strfree(mod, devctl); + return (ret); } diff --git a/usr/src/lib/fm/topo/modules/common/fac_prov_mptsas/fac_prov_mptsas.c b/usr/src/lib/fm/topo/modules/common/fac_prov_mptsas/fac_prov_mptsas.c index a49a131811..115e3b801d 100644 --- a/usr/src/lib/fm/topo/modules/common/fac_prov_mptsas/fac_prov_mptsas.c +++ b/usr/src/lib/fm/topo/modules/common/fac_prov_mptsas/fac_prov_mptsas.c @@ -72,6 +72,12 @@ _topo_fini(topo_mod_t *mod) topo_mod_unregister(mod); } +/* + * Get or set LED state for a particular target attached to an mpt_sas + * instance at (Enclosure Number, Slot Number). The function returns + * -1 on error and sets errno to ENOENT _only_ if the /devices node + * (*devctl) does not exist. + */ static int do_led_control(topo_mod_t *mod, char *devctl, uint16_t enclosure, uint16_t slot, uint8_t led, uint32_t *ledmode, boolean_t set) @@ -88,8 +94,10 @@ do_led_control(topo_mod_t *mod, char *devctl, uint16_t enclosure, lc.LedStatus = *ledmode; if ((fd = open(devctl, (set ? O_RDWR : O_RDONLY))) == -1) { + int en = errno; topo_mod_dprintf(mod, "devctl open failed: %s", strerror(errno)); + errno = en; return (-1); } @@ -103,9 +111,11 @@ do_led_control(topo_mod_t *mod, char *devctl, uint16_t enclosure, */ lc.LedStatus = 0; } else { + int en = errno; topo_mod_dprintf(mod, "led control ioctl failed: %s", strerror(errno)); (void) close(fd); + errno = en; return (-1); } } @@ -113,6 +123,7 @@ do_led_control(topo_mod_t *mod, char *devctl, uint16_t enclosure, *ledmode = lc.LedStatus ? TOPO_LED_STATE_ON : TOPO_LED_STATE_OFF; (void) close(fd); + errno = 0; return (0); } @@ -127,7 +138,8 @@ mptsas_led_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers, char *driver = NULL, *devctl = NULL; uint32_t enclosure, slot; uint8_t mptsas_led; - boolean_t set; + boolean_t set, done; + char *elem, *lastp; if (vers > TOPO_METH_MPTSAS_LED_MODE_VERSION) return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); @@ -197,8 +209,41 @@ mptsas_led_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers, topo_mod_dprintf(mod, "%s: Getting LED mode\n", __func__); } - if (do_led_control(mod, devctl, enclosure, slot, mptsas_led, &ledmode, - set) != 0) { + /* + * devctl is a (potentially) pipe-separated list of different device + * paths to try. + */ + if ((elem = topo_mod_strsplit(mod, devctl, "|", &lastp)) == NULL) { + topo_mod_dprintf(mod, "%s: could not parse devctl list", + __func__); + ret = topo_mod_seterrno(mod, EMOD_UNKNOWN); + goto out; + } + done = B_FALSE; + do { + topo_mod_dprintf(mod, "%s: trying mpt_sas instance at %s\n", + __func__, elem); + + ret = do_led_control(mod, elem, enclosure, slot, + mptsas_led, &ledmode, set); + + /* + * Only try further devctl paths from the list if this one + * was not found: + */ + if (ret == 0 || errno != ENOENT) { + done = B_TRUE; + } else { + topo_mod_dprintf(mod, "%s: instance not found\n", + __func__); + } + + topo_mod_strfree(mod, elem); + + } while (!done && (elem = topo_mod_strsplit(mod, NULL, "|", + &lastp)) != NULL); + + if (ret != 0) { topo_mod_dprintf(mod, "%s: do_led_control failed", __func__); ret = topo_mod_seterrno(mod, EMOD_UNKNOWN); goto out; diff --git a/usr/src/lib/fm/topo/modules/common/ipmi/Makefile b/usr/src/lib/fm/topo/modules/common/ipmi/Makefile index b6f2839c42..4a0bf39401 100644 --- a/usr/src/lib/fm/topo/modules/common/ipmi/Makefile +++ b/usr/src/lib/fm/topo/modules/common/ipmi/Makefile @@ -22,7 +22,8 @@ # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" +# Copyright (c) 2018, Joyent, Inc. +# MODULE = ipmi CLASS = common @@ -31,4 +32,4 @@ MODULESRCS = ipmi_enum.c ipmi_methods.c include ../../Makefile.plugin -LDLIBS += -lipmi +LDLIBS += -lipmi -lnsl diff --git a/usr/src/lib/fm/topo/modules/common/ipmi/ipmi_enum.c b/usr/src/lib/fm/topo/modules/common/ipmi/ipmi_enum.c index e0a768462d..96149ccc2e 100644 --- a/usr/src/lib/fm/topo/modules/common/ipmi/ipmi_enum.c +++ b/usr/src/lib/fm/topo/modules/common/ipmi/ipmi_enum.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2017, Joyent, Inc. + * Copyright 2019 Joyent, Inc. * Copyright 2019 by Western Digital Corporation */ @@ -30,6 +30,9 @@ #include <fm/topo_mod.h> #include <sys/fm/protocol.h> #include <string.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <sys/socket.h> #define TOPO_PGROUP_IPMI "ipmi" #define TOPO_PROP_IPMI_ENTITY_REF "entity_ref" @@ -599,6 +602,278 @@ ipmi_check_entity(ipmi_handle_t *ihp, ipmi_entity_t *ep, void *data) return (0); } +static const char * +ipmi2toposrc(uint8_t ipmi_ip_src) +{ + char *cfgtype; + + switch (ipmi_ip_src) { + case (IPMI_LAN_SRC_STATIC): + case (IPMI_LAN_SRC_BIOS): + cfgtype = TOPO_NETCFG_TYPE_STATIC; + break; + case (IPMI_LAN_SRC_DHCP): + cfgtype = TOPO_NETCFG_TYPE_DHCP; + break; + default: + cfgtype = TOPO_NETCFG_TYPE_UNKNOWN; + break; + } + return (cfgtype); +} + +/* + * Channel related IPMI commands reserve 4 bits for the channel number. + */ +#define IPMI_MAX_CHANNEL 0xf + +static int +ipmi_enum_sp(topo_mod_t *mod, tnode_t *pnode) +{ + ipmi_handle_t *ihp; + ipmi_channel_info_t *chinfo; + ipmi_lan_config_t lancfg = { 0 }; + boolean_t found_lan = B_TRUE; + char ipv4_addr[INET_ADDRSTRLEN], subnet[INET_ADDRSTRLEN]; + char gateway[INET_ADDRSTRLEN], macaddr[18]; + char ipv6_addr[INET6_ADDRSTRLEN]; + char **ipv6_routes = NULL; + const char *sp_rev, *ipv4_cfgtype, *ipv6_cfgtype; + nvlist_t *auth, *fmri; + tnode_t *sp_node; + topo_pgroup_info_t pgi; + topo_ufm_slot_info_t slotinfo = { 0 }; + int err, ch, i, ret = -1; + + if ((ihp = topo_mod_ipmi_hold(mod)) == NULL) + return (0); + + /* + * If we're able to successfully get the service processor version by + * issuing a GET_DEVICE_ID IPMI command over the KCS interface, then we + * can say with certainty that a service processor exists. If not, + * then either the SP is unresponsive or one isn't present. In either + * case, we bail. + */ + if ((sp_rev = ipmi_firmware_version(ihp)) == NULL) { + topo_mod_dprintf(mod, "failed to query SP"); + topo_mod_ipmi_rele(mod); + return (0); + } + + if ((auth = topo_mod_auth(mod, pnode)) == NULL) { + topo_mod_dprintf(mod, "topo_mod_auth() failed: %s", + topo_mod_errmsg(mod)); + /* errno set */ + goto out; + } + if ((fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, + SP, 0, NULL, auth, NULL, sp_rev, NULL)) == NULL) { + nvlist_free(auth); + topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s", + topo_mod_errmsg(mod)); + /* errno set */ + goto out; + } + nvlist_free(auth); + + if ((sp_node = topo_node_bind(mod, pnode, SP, 0, fmri)) == NULL) { + nvlist_free(fmri); + topo_mod_dprintf(mod, "topo_node_bind() failed: %s", + topo_mod_errmsg(mod)); + /* errno set */ + goto out; + } + nvlist_free(fmri); + fmri = NULL; + + if (topo_node_label_set(sp_node, "service-processor", &err) != 0) { + topo_mod_dprintf(mod, "failed to set label on %s=%d: %s", SP, + 0, topo_strerror(err)); + (void) topo_mod_seterrno(mod, err); + goto out; + } + + if (topo_node_fru(pnode, &fmri, NULL, &err) != 0 || + topo_node_fru_set(sp_node, fmri, 0, &err) != 0) { + topo_mod_dprintf(mod, "failed to set FRU on %s=%d: %s", SP, 0, + topo_strerror(err)); + nvlist_free(fmri); + (void) topo_mod_seterrno(mod, err); + goto out; + } + nvlist_free(fmri); + + /* + * Create UFM node to capture the SP LOM version + */ + slotinfo.usi_version = sp_rev; + slotinfo.usi_active = B_TRUE; + slotinfo.usi_mode = TOPO_UFM_SLOT_MODE_NONE; + if (topo_node_range_create(mod, sp_node, UFM, 0, 0) != 0 || + topo_mod_create_ufm(mod, sp_node, + "Baseboard Management Controller firmware", &slotinfo) == NULL) { + topo_mod_dprintf(mod, "failed to create %s node", UFM); + goto out; + } + + /* + * Iterate through the channels to find the LAN channel. + */ + for (ch = 0; ch <= IPMI_MAX_CHANNEL; ch++) { + if ((chinfo = ipmi_get_channel_info(ihp, ch)) != NULL && + chinfo->ici_medium == IPMI_MEDIUM_8023LAN) { + found_lan = B_TRUE; + break; + } + } + /* + * If we found a LAN channel, look up its configuration so that we can + * expose it via node properties. + */ + if (found_lan != B_TRUE || + ipmi_lan_get_config(ihp, ch, &lancfg) != 0) { + (void) fprintf(stderr, "failed to get LAN config\n"); + (void) topo_mod_seterrno(mod, EMOD_UNKNOWN); + goto out; + } + + pgi.tpi_name = TOPO_PGROUP_NETCFG; + pgi.tpi_namestab = TOPO_STABILITY_PRIVATE; + pgi.tpi_datastab = TOPO_STABILITY_PRIVATE; + pgi.tpi_version = TOPO_VERSION; + + if (topo_pgroup_create(sp_node, &pgi, &err) != 0) { + (void) topo_mod_seterrno(mod, err); + goto out; + } + + /* Set MAC address property */ + (void) sprintf(macaddr, "%02x:%02x:%02x:%02x:%02x:%02x", + lancfg.ilc_macaddr[0], lancfg.ilc_macaddr[1], + lancfg.ilc_macaddr[2], lancfg.ilc_macaddr[3], + lancfg.ilc_macaddr[4], lancfg.ilc_macaddr[5]); + macaddr[17] = '\0'; + + if (topo_prop_set_string(sp_node, TOPO_PGROUP_NETCFG, + TOPO_PROP_NETCFG_MACADDR, TOPO_PROP_IMMUTABLE, macaddr, + &err) != 0) { + topo_mod_dprintf(mod, "failed to set properties on %s=%d: %s", + SP, 0, topo_strerror(err)); + (void) topo_mod_seterrno(mod, err); + goto out; + } + + /* Set VLAN ID property, if VLAN is enabled */ + if (lancfg.ilc_vlan_enabled == B_TRUE && + topo_prop_set_uint32(sp_node, TOPO_PGROUP_NETCFG, + TOPO_PROP_NETCFG_VLAN_ID, TOPO_PROP_IMMUTABLE, lancfg.ilc_vlan_id, + &err) != 0) { + topo_mod_dprintf(mod, "failed to set properties on %s=%d: %s", + SP, 0, topo_strerror(err)); + (void) topo_mod_seterrno(mod, err); + goto out; + } + + /* Set IPv4 configuration properties if IPv4 is enabled */ + if (lancfg.ilc_ipv4_enabled == B_TRUE && + (inet_ntop(AF_INET, &lancfg.ilc_ipaddr, ipv4_addr, + sizeof (ipv4_addr)) == NULL || + inet_ntop(AF_INET, &lancfg.ilc_subnet, subnet, + sizeof (subnet)) == NULL || + inet_ntop(AF_INET, &lancfg.ilc_gateway_addr, gateway, + sizeof (gateway)) == NULL)) { + (void) fprintf(stderr, "failed to convert IP addresses: %s\n", + strerror(errno)); + (void) topo_mod_seterrno(mod, EMOD_UNKNOWN); + goto out; + } + ipv4_cfgtype = ipmi2toposrc(lancfg.ilc_ipaddr_source); + if (lancfg.ilc_ipv4_enabled == B_TRUE && + (topo_prop_set_string(sp_node, TOPO_PGROUP_NETCFG, + TOPO_PROP_NETCFG_IPV4_ADDR, TOPO_PROP_IMMUTABLE, ipv4_addr, + &err) != 0 || + topo_prop_set_string(sp_node, TOPO_PGROUP_NETCFG, + TOPO_PROP_NETCFG_IPV4_SUBNET, TOPO_PROP_IMMUTABLE, subnet, + &err) != 0 || + topo_prop_set_string(sp_node, TOPO_PGROUP_NETCFG, + TOPO_PROP_NETCFG_IPV4_GATEWAY, TOPO_PROP_IMMUTABLE, gateway, + &err) != 0 || + topo_prop_set_string(sp_node, TOPO_PGROUP_NETCFG, + TOPO_PROP_NETCFG_IPV4_TYPE, TOPO_PROP_IMMUTABLE, ipv4_cfgtype, + &err) != 0)) { + topo_mod_dprintf(mod, "failed to set properties on %s=%d: %s", + SP, 0, topo_strerror(err)); + (void) topo_mod_seterrno(mod, err); + goto out; + } + + /* Set IPv6 configuration properties if IPv6 is enabled */ + if (lancfg.ilc_ipv6_enabled == B_TRUE) { + ipv6_cfgtype = ipmi2toposrc(lancfg.ilc_ipv6_source); + + if (inet_ntop(AF_INET6, &lancfg.ilc_ipv6_addr, ipv6_addr, + sizeof (ipv6_addr)) == NULL) { + (void) fprintf(stderr, "failed to convert IPv6 " + "address: %s\n", strerror(errno)); + (void) topo_mod_seterrno(mod, EMOD_UNKNOWN); + goto out; + } + + /* allocate and populate ipv6-routes string array */ + if ((ipv6_routes = topo_mod_zalloc(mod, + lancfg.ilc_ipv6_nroutes * sizeof (char *))) == NULL) { + /* errno set */ + goto out; + } + for (i = 0; i < lancfg.ilc_ipv6_nroutes; i++) { + if ((ipv6_routes[i] = topo_mod_alloc(mod, + INET6_ADDRSTRLEN)) == NULL) { + /* errno set */ + goto out; + } + } + for (i = 0; i < lancfg.ilc_ipv6_nroutes; i++) { + if (inet_ntop(AF_INET6, &lancfg.ilc_ipv6_routes[i], + ipv6_routes[i], sizeof (ipv6_routes[i])) == NULL) { + (void) fprintf(stderr, "failed to convert " + "IPv6 addresses: %s\n", strerror(errno)); + (void) topo_mod_seterrno(mod, EMOD_UNKNOWN); + goto out; + } + } + } + if (lancfg.ilc_ipv6_enabled == B_TRUE && + (topo_prop_set_string(sp_node, TOPO_PGROUP_NETCFG, + TOPO_PROP_NETCFG_IPV6_ADDR, TOPO_PROP_IMMUTABLE, ipv6_addr, + &err) != 0 || + topo_prop_set_string_array(sp_node, TOPO_PGROUP_NETCFG, + TOPO_PROP_NETCFG_IPV6_ROUTES, TOPO_PROP_IMMUTABLE, + (const char **)ipv6_routes, lancfg.ilc_ipv6_nroutes, &err) != 0 || + topo_prop_set_string(sp_node, TOPO_PGROUP_NETCFG, + TOPO_PROP_NETCFG_IPV6_TYPE, TOPO_PROP_IMMUTABLE, ipv6_cfgtype, + &err) != 0)) { + topo_mod_dprintf(mod, "failed to set properties on %s=%d: %s", + SP, 0, topo_strerror(err)); + (void) topo_mod_seterrno(mod, err); + goto out; + } + ret = 0; +out: + if (lancfg.ilc_ipv6_nroutes > 0 && ipv6_routes != NULL) { + for (i = 0; i < lancfg.ilc_ipv6_nroutes; i++) { + if (ipv6_routes[i] != NULL) { + topo_mod_free(mod, ipv6_routes[i], + INET6_ADDRSTRLEN); + } + } + topo_mod_free(mod, ipv6_routes, + lancfg.ilc_ipv6_nroutes * sizeof (char *)); + } + topo_mod_ipmi_rele(mod); + return (ret); +} + /* * libtopo enumeration point. This simply iterates over entities looking for * the appropriate type. @@ -613,10 +888,11 @@ ipmi_enum(topo_mod_t *mod, tnode_t *rnode, const char *name, int ret; /* - * If the node being passed in ISN'T the chassis node, then we're being - * asked to post-process a statically defined node. + * If the node being passed in ISN'T the chassis or motherboard node, + * then we're being asked to post-process a statically defined node. */ - if (strcmp(topo_node_name(rnode), CHASSIS) != 0) { + if (strcmp(topo_node_name(rnode), CHASSIS) != 0 && + strcmp(topo_node_name(rnode), MOTHERBOARD) != 0) { if (ipmi_post_process(mod, rnode) != 0) { topo_mod_dprintf(mod, "post processing of node %s=%d " "failed!", topo_node_name(rnode), @@ -626,6 +902,19 @@ ipmi_enum(topo_mod_t *mod, tnode_t *rnode, const char *name, return (0); } + /* + * For service processor enumeration we vector off into a special code + * path. + */ + if (strcmp(name, SP) == 0) { + if (ipmi_enum_sp(mod, rnode) != 0) { + topo_mod_dprintf(mod, "failed to enumerate the " + "service-processor"); + return (-1); + } + return (0); + } + if (strcmp(name, POWERMODULE) == 0) { data.ed_entity = IPMI_ET_POWER_DOMAIN; } else if (strcmp(name, PSU) == 0) { 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 8d74b8aeb8..0273009bbe 100644 --- a/usr/src/lib/fm/topo/modules/common/ses/ses.c +++ b/usr/src/lib/fm/topo/modules/common/ses/ses.c @@ -340,6 +340,34 @@ static ses_open_fail_list_t *ses_sofh; static pthread_mutex_t ses_sofmt; static void ses_ct_print(char *ptr); +/* + * Static list of enclosure manufacturers/models that we will skip enumerating. + * To skip all models from a particular vendor, set the seb_model field to "*". + */ +typedef struct ses_enc_blacklist { + const char *seb_manuf; + const char *seb_model; +} ses_enc_blacklist_t; + +static const ses_enc_blacklist_t enc_blacklist[] = { + { "LSI", "VirtualSES" } +}; + +#define N_ENC_BLACKLIST (sizeof (enc_blacklist) / \ + sizeof (enc_blacklist[0])) + +static boolean_t +ses_is_blacklisted(ses_enc_blacklist_t *seb) +{ + for (uint_t i = 0; i < N_ENC_BLACKLIST; i++) { + if (strcmp(seb->seb_manuf, enc_blacklist[i].seb_manuf) == 0 && + (strcmp(enc_blacklist[i].seb_model, "*") == 0 || + strcmp(seb->seb_model, enc_blacklist[i].seb_model) == 0)) + return (B_TRUE); + } + return (B_FALSE); +} + static void ses_recheck_dir() { @@ -3298,9 +3326,24 @@ ses_enum_gather(ses_node_t *np, void *data) uint64_t prevstatus, status; boolean_t report; uint64_t subchassis = NO_SUBCHASSIS; + ses_enc_blacklist_t seb; if (ses_node_type(np) == SES_NODE_ENCLOSURE) { /* + * Compare the enclosure identity against the entries in the SES + * enclosure blacklist and ignore it, if found. + */ + verify(nvlist_lookup_string(props, SES_EN_PROP_VID, + (char **)&seb.seb_manuf) == 0); + verify(nvlist_lookup_string(props, SES_EN_PROP_PID, + (char **)&seb.seb_model) == 0); + if (ses_is_blacklisted(&seb) == B_TRUE) { + topo_mod_dprintf(mod, "Skipping enclosure %s-%s: is " + "blacklisted", seb.seb_manuf, seb.seb_model); + return (SES_WALK_ACTION_TERMINATE); + } + + /* * If we have already identified the chassis for this target, * then this is a secondary enclosure and we should ignore it, * along with the rest of the tree (since this is depth-first). |