summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Paige Hendricks <jordan.hendricks@joyent.com>2018-12-03 18:33:15 +0000
committerRobert Mustacchi <rm@joyent.com>2019-08-28 17:49:57 +0000
commite2f631f93662311389118b220daa637b16a612ac (patch)
tree2bccd93efda69ae4f2a2fb199ff19291988be7e9
parentc5806743f70246f7f708e57514b9103a6291d629 (diff)
downloadillumos-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>
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_hc.h1
-rwxr-xr-xusr/src/lib/fm/topo/maps/SMCI,SSG-2029P-ACR24L/SSG-2029P-ACR24L-disk-hc-topology.xmlgenksh23
-rw-r--r--usr/src/lib/fm/topo/modules/common/Makefile1
-rw-r--r--usr/src/lib/fm/topo/modules/common/fac_prov_ahci/Makefile23
-rw-r--r--usr/src/lib/fm/topo/modules/common/fac_prov_ahci/fac_prov_ahci.c286
-rw-r--r--usr/src/pkg/manifests/service-fault-management.mf1
-rw-r--r--usr/src/uts/common/io/sata/adapters/ahci/ahci.c3
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;