diff options
Diffstat (limited to 'usr/src/lib/fm/topo/modules/common')
5 files changed, 441 insertions, 20 deletions
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). |