diff options
author | Jordan Paige Hendricks <jordan.hendricks@joyent.com> | 2018-12-03 18:33:15 +0000 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2019-08-28 17:49:57 +0000 |
commit | e2f631f93662311389118b220daa637b16a612ac (patch) | |
tree | 2bccd93efda69ae4f2a2fb199ff19291988be7e9 | |
parent | c5806743f70246f7f708e57514b9103a6291d629 (diff) | |
download | illumos-joyent-e2f631f93662311389118b220daa637b16a612ac.tar.gz |
11576 Want support for ahci LED entries in topo
Reviewed by: Rob Johnston <rob.johnston@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: C Fraire <cfraire@me.com>
Approved by: Gordon Ross <gwr@nexenta.com>
7 files changed, 336 insertions, 2 deletions
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 748b27c945..4c3a96ccb3 100644 --- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h +++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h @@ -137,6 +137,7 @@ extern "C" { #define TOPO_BINDING_DEVCTL "devctl" #define TOPO_BINDING_ENCLOSURE "enclosure" #define TOPO_BINDING_SLOT "slot" +#define TOPO_BINDING_PORT "port" #define TOPO_PGROUP_STORAGE "storage" #define TOPO_STORAGE_INITIATOR_PORT "initiator-port" diff --git a/usr/src/lib/fm/topo/maps/SMCI,SSG-2029P-ACR24L/SSG-2029P-ACR24L-disk-hc-topology.xmlgenksh b/usr/src/lib/fm/topo/maps/SMCI,SSG-2029P-ACR24L/SSG-2029P-ACR24L-disk-hc-topology.xmlgenksh index 327c41c53b..7ff945eaa0 100755 --- a/usr/src/lib/fm/topo/maps/SMCI,SSG-2029P-ACR24L/SSG-2029P-ACR24L-disk-hc-topology.xmlgenksh +++ b/usr/src/lib/fm/topo/maps/SMCI,SSG-2029P-ACR24L/SSG-2029P-ACR24L-disk-hc-topology.xmlgenksh @@ -78,8 +78,28 @@ function do_sata_node (( target = bay + 4 )) hpath="/pci@0,0/pci15d9,981@11,5" tpath="/disk@${target},0" + devctl="/devices/pci@0,0/pci15d9,981@11,5:devctl" cat <<EOF <node instance='$bay_inst'> + <facility name='fail' type='indicator' provider='fac_prov_ahci' > + <propgroup name='facility' version='1' name-stability='Private' + data-stability='Private' > + <propval name='type' type='uint32' value='0' /> + <propmethod name='ahci_led_mode' version='0' propname='mode' + proptype='uint32' mutable='1'> + </propmethod> + </propgroup> + </facility> + <facility name='ident' type='indicator' provider='fac_prov_ahci' > + <propgroup name='facility' version='1' name-stability='Private' + data-stability='Private' > + <propval name='type' type='uint32' value='1' /> + <propmethod name='ahci_led_mode' version='0' propname='mode' + proptype='uint32' mutable='1'> + </propmethod> + </propgroup> + </facility> + <propgroup name='protocol' version='1' name-stability='Private' data-stability='Private'> <propval name='label' type='string' value='Rear Disk $bay' /> @@ -92,6 +112,9 @@ function do_sata_node data-stability='Private'> <propval name='occupant-path' type='string' value='$hpath$tpath' /> + <propval name='devctl' type='string' + value='$devctl' /> + <propval name='port' type='uint32' value='$target' /> </propgroup> </node> EOF diff --git a/usr/src/lib/fm/topo/modules/common/Makefile b/usr/src/lib/fm/topo/modules/common/Makefile index 275ff96f9a..3dd59a2fc2 100644 --- a/usr/src/lib/fm/topo/modules/common/Makefile +++ b/usr/src/lib/fm/topo/modules/common/Makefile @@ -27,6 +27,7 @@ SUBDIRS = \ disk \ + fac_prov_ahci \ fac_prov_ipmi \ fac_prov_mptsas \ ipmi \ diff --git a/usr/src/lib/fm/topo/modules/common/fac_prov_ahci/Makefile b/usr/src/lib/fm/topo/modules/common/fac_prov_ahci/Makefile new file mode 100644 index 0000000000..3837005aa3 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/fac_prov_ahci/Makefile @@ -0,0 +1,23 @@ +# +# 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 2018, Joyent, Inc. +# + +MODULE = fac_prov_ahci +CLASS = common + +MODULESRCS = fac_prov_ahci.c + +include ../../Makefile.plugin + +CPPFLAGS += -I$(SRC)/uts/common diff --git a/usr/src/lib/fm/topo/modules/common/fac_prov_ahci/fac_prov_ahci.c b/usr/src/lib/fm/topo/modules/common/fac_prov_ahci/fac_prov_ahci.c new file mode 100644 index 0000000000..cd47bc6a23 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/fac_prov_ahci/fac_prov_ahci.c @@ -0,0 +1,286 @@ +/* + * 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 <unistd.h> +#include <stropts.h> +#include <fcntl.h> +#include <libnvpair.h> +#include <string.h> +#include <strings.h> +#include <sys/fm/protocol.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <fm/libtopo.h> +#include <fm/topo_mod.h> +#include <libgen.h> + +#include "sys/sata/adapters/ahci/ahciem.h" + +#define TOPO_METH_AHCI_LED_MODE_VERSION 0 + +/* + * This enum is used to more clearly demonstrate the mapping between libtopo's + * concept of LED types and the types represented in AHCI. + */ +typedef enum { + AHCI_FAC_IDENT, + AHCI_FAC_FAULT +} ahci_fac_led_t; + +static int fac_prov_ahci_enum(topo_mod_t *, tnode_t *, const char *, + topo_instance_t, topo_instance_t, void *, void *); + +/* + * ahci facility provider methods + */ +static int ahci_led_mode(topo_mod_t *, tnode_t *, topo_version_t, + nvlist_t *, nvlist_t **); + +static const topo_modops_t ahci_ops = { fac_prov_ahci_enum, NULL }; + +static const topo_modinfo_t ahci_info = + { "ahci facility provider", FM_FMRI_SCHEME_HC, TOPO_VERSION, + &ahci_ops }; + +static const topo_method_t ahci_fac_methods[] = { + { "ahci_led_mode", TOPO_PROP_METH_DESC, + TOPO_METH_AHCI_LED_MODE_VERSION, + TOPO_STABILITY_INTERNAL, ahci_led_mode }, + { NULL } +}; + +int +_topo_init(topo_mod_t *mod, topo_version_t version) +{ + if (getenv("TOPOFACAHCIDEBUG") != NULL) + topo_mod_setdebug(mod); + + return (topo_mod_register(mod, &ahci_info, TOPO_VERSION)); +} + +void +_topo_fini(topo_mod_t *mod) +{ + topo_mod_unregister(mod); +} + +/* + * Get or set the LED state for a given LED of type (facility node type, port). + * This function returns -1 on error. + */ +static int +do_led_control(topo_mod_t *mod, const char *devctl, uint32_t port, + ahci_fac_led_t fac_type, uint32_t *ledmode, boolean_t set) +{ + int fd = -1, ret = -1; + + if ((fd = open(devctl, (set ? O_RDWR : O_RDONLY))) == -1) { + topo_mod_dprintf(mod, "devctl open failed: %s", + strerror(errno)); + goto out; + } + + if (set) { + ahci_ioc_em_set_t ahci_set; + uint32_t led_status = *ledmode; + uint_t op, leds; + + switch (fac_type) { + case AHCI_FAC_IDENT: + leds = AHCI_EM_LED_IDENT_ENABLE; + break; + case AHCI_FAC_FAULT: + leds = AHCI_EM_LED_FAULT_ENABLE; + break; + default: + topo_mod_dprintf(mod, "invalid facility node type: %d", + fac_type); + goto out; + } + + if (led_status) { + op = AHCI_EM_IOC_SET_OP_ADD; + } else { + op = AHCI_EM_IOC_SET_OP_REM; + } + + bzero(&ahci_set, sizeof (ahci_set)); + ahci_set.aiems_port = port; + ahci_set.aiems_op = op; + ahci_set.aiems_leds = leds; + + if (ioctl(fd, AHCI_EM_IOC_SET, &ahci_set) == -1) { + topo_mod_dprintf(mod, "ioctl failed: %s", + strerror(errno)); + goto out; + } + } else { + uint_t led_set = 0; + ahci_ioc_em_get_t ahci_get; + + bzero(&ahci_get, sizeof (ahci_get)); + if (ioctl(fd, AHCI_EM_IOC_GET, &ahci_get) == -1) { + topo_mod_dprintf(mod, "led control ioctl failed: %s", + strerror(errno)); + goto out; + } + + switch (fac_type) { + case AHCI_FAC_IDENT: + led_set = ahci_get.aiemg_status[port] & + AHCI_EM_LED_IDENT_ENABLE; + break; + case AHCI_FAC_FAULT: + led_set = ahci_get.aiemg_status[port] & + AHCI_EM_LED_FAULT_ENABLE; + break; + default: + topo_mod_dprintf(mod, "invalid facility node type: %d", + fac_type); + goto out; + } + + *ledmode = (led_set != 0) ? + TOPO_LED_STATE_ON : TOPO_LED_STATE_OFF; + } + ret = 0; + +out: + if (fd >= 0) { + (void) close(fd); + } + return (ret); +} + +static int +ahci_led_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers, + nvlist_t *in, nvlist_t **nvout) +{ + int err, ret = 0; + tnode_t *pnode = topo_node_parent(node); + uint32_t type, ledmode = 0, ahci_port; + nvlist_t *pargs, *nvl; + char *devctl = NULL; + boolean_t set; + ahci_fac_led_t fac_type; + + if (vers > TOPO_METH_AHCI_LED_MODE_VERSION) { + return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); + } + + if (topo_prop_get_uint32(node, TOPO_PGROUP_FACILITY, TOPO_FACILITY_TYPE, + &type, &err) != 0) { + topo_mod_dprintf(mod, "%s: Failed to lookup %s property " + "(%s)", __func__, TOPO_FACILITY_TYPE, topo_strerror(err)); + return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); + } + + /* + * While the AHCI specification includes bits for locate, fault, and + * activity LEDs, we generally only need to account for locate and fault + * LEDs, as activity LEDs are typically disabled in hardware. + */ + switch (type) { + case (TOPO_LED_TYPE_SERVICE): + fac_type = AHCI_FAC_FAULT; + break; + case (TOPO_LED_TYPE_LOCATE): + fac_type = AHCI_FAC_IDENT; + break; + default: + topo_mod_dprintf(mod, "%s: Invalid LED type: 0x%x\n", __func__, + type); + ret = topo_mod_seterrno(mod, EMOD_NVL_INVAL); + return (ret); + } + + if (topo_prop_get_string(pnode, TOPO_PGROUP_BINDING, + TOPO_BINDING_DEVCTL, &devctl, &err) != 0 || + topo_prop_get_uint32(pnode, TOPO_PGROUP_BINDING, + TOPO_BINDING_PORT, &ahci_port, &err) != 0) { + topo_mod_dprintf(mod, "%s: Facility was missing ahci binding " + "properties\n", __func__); + ret = topo_mod_seterrno(mod, EMOD_NVL_INVAL); + goto out; + } + + if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) && + nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) { + /* + * Set the LED mode. + */ + set = B_TRUE; + + if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL, + &ledmode)) != 0) { + topo_mod_dprintf(mod, "%s: Failed to lookup %s nvpair " + "(%s)\n", __func__, TOPO_PROP_VAL_VAL, + strerror(ret)); + ret = topo_mod_seterrno(mod, EMOD_NVL_INVAL); + goto out; + + } + topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__, + ledmode ? "ON" : "OFF"); + } else { + /* + * Get the LED mode + */ + set = B_FALSE; + topo_mod_dprintf(mod, "%s: Getting LED mode\n", __func__); + } + ret = do_led_control(mod, devctl, ahci_port, fac_type, &ledmode, set); + + if (ret == -1) { + topo_mod_dprintf(mod, "%s: do_led_control failed", __func__); + ret = topo_mod_seterrno(mod, EMOD_UNKNOWN); + goto out; + } + + if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || + nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 || + nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 || + nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) { + topo_mod_dprintf(mod, "%s: Failed to allocate 'out' nvlist\n", + __func__); + nvlist_free(nvl); + ret = topo_mod_seterrno(mod, EMOD_NOMEM); + goto out; + } + *nvout = nvl; + +out: + topo_mod_strfree(mod, devctl); + return (ret); +} + +static int +fac_prov_ahci_enum(topo_mod_t *mod, tnode_t *rnode, const char *name, + topo_instance_t min, topo_instance_t max, void *arg, void *unused) +{ + + if (topo_node_flags(rnode) == TOPO_NODE_FACILITY) { + if (topo_method_register(mod, rnode, ahci_fac_methods) != 0) { + topo_mod_dprintf(mod, "%s: topo_method_register() " + "failed: %s", __func__, topo_mod_errmsg(mod)); + return (-1); + } + return (0); + } + + topo_mod_dprintf(mod, "%s: unexpected node flags 0x%x", __func__, + topo_node_flags(rnode)); + return (-1); +} diff --git a/usr/src/pkg/manifests/service-fault-management.mf b/usr/src/pkg/manifests/service-fault-management.mf index a6e616605d..5127927e5b 100644 --- a/usr/src/pkg/manifests/service-fault-management.mf +++ b/usr/src/pkg/manifests/service-fault-management.mf @@ -506,6 +506,7 @@ file path=usr/lib/fm/libtopo.so.1 variant.opensolaris.zone=__NODEFAULT # file path=usr/lib/fm/topo/maps/xfp-hc-topology.xml mode=0444 file path=usr/lib/fm/topo/plugins/disk.so mode=0555 +file path=usr/lib/fm/topo/plugins/fac_prov_ahci.so mode=0555 file path=usr/lib/fm/topo/plugins/fac_prov_ipmi.so mode=0555 file path=usr/lib/fm/topo/plugins/fac_prov_mptsas.so mode=0555 file path=usr/lib/fm/topo/plugins/ipmi.so mode=0555 diff --git a/usr/src/uts/common/io/sata/adapters/ahci/ahci.c b/usr/src/uts/common/io/sata/adapters/ahci/ahci.c index 918f95ff67..bdb95413f2 100644 --- a/usr/src/uts/common/io/sata/adapters/ahci/ahci.c +++ b/usr/src/uts/common/io/sata/adapters/ahci/ahci.c @@ -10552,8 +10552,7 @@ ahci_em_led_task(void *arg) mutex_enter(&led->aelta_ctl->ahcictl_mutex); if (ret) { - led->aelta_ctl->ahcictl_em_state[led->aelta_port] = - led->aelta_state; + led->aelta_ctl->ahcictl_em_state[led->aelta_port] = state; led->aelta_ret = 0; } else { led->aelta_ret = EIO; |