view usr/src/lib/fm/topo/modules/common/shared/topo_sensor.c @ 25635:ce2b70e7aab0

[illumos-gate merge] commit 0a554e9f2c0d440dc40a97fae2d18f1d428ca786 13404 man page spelling errors commit 9f76c6ed5b6ee0cc0bf631daca15ac3dc5fc70c4 13400 zfs-tests: implicit conversion from 'enum dmu_objset_type' to 'enum lzc_dataset_type' commit ef96fc31fc4f4306719704352d5c3e33573c039f 13399 zfs: error: implicit conversion from 'boolean_t' to 'ds_hold_flags_t' commit 56870e8c76c2675bcef1fcee5d519585ce9c768e 13393 cheetah: case value '47616' not in enumerated type commit 8247326397b1a16f37e70cf13f5b7a4f50d06712 13403 zfs: symbol 'g_zfs' is multiply-defined commit 436b964b19ef06803ad9165542d80d9d731d6486 13402 zpool: symbol 'g_zfs' is multiply-defined commit 99308ed0417a2b8ab73c5856a8a5345ce2a7aea7 13396 PoolsExecption typo in resource pools javadoc commit 1575b751c16622553e958c1e5c45e59c86b15c6e 13392 px: case value '3' not in enumerated type commit 9b0429a10eec9313ec782d8421272aff70adbfdc 13339 Add support for Hygon Dhyana Family 18h processor commit d20422bd742384b77102bb3bd09e0dc4b7372e50 13351 loader: vbe_find_mode_xydm() is using wrong safety and iteration is buggy commit 174b8e455f9a6974e69fa4e28792580acde0892d 13311 uptime(1) dazed and confused for a minute after boot commit f816551bb187d104fbf2757703d7a5d2189a3a18 13401 eeprom: 'lv' may be used uninitialized in this function commit 5e96da73c99d9d17ff5a58b793fff2ab6dcadf25 13391 fm: build errors with gcc 7 on SPARC commit 58b55f701e285559e4799354996fd284238ed0d4 13398 libstand: xdrproc_t should return bool commit c6a28d7650029501a356f7b75b2a10a5c4430cef 13394 fhc: case value '4294967295' not in enumerated type commit 58d4b16fe601073f2408de78e3db7e9bfa9abfd2 13355 remove topo module warning gags commit 1473b8d60e902819558a8b0e8a257eb0d754c3c3 13388 ZFS list bookmark not working on zvols commit 4bba12ca5cd6f92aaf0d4c0d19d05528110bc095 13368 libbe_py should support temporary BE activation commit a92282e44f968185a6bba094d1e5fece2da819cf 13376 fm: variable may be used uninitialized commit 8b1df8bf71b7b62e7e4d46fe6b457d4d6447b2b8 13367 beadm activate -t should not promote new BE datasets commit 9704bf7fb82e71b685e194a967937ff03843e73a 13317 Decrease contention on dn_struct_rwlock commit 88a08813800ed7ba7c927986421cee437f7f2233 13363 ctfconvert could support more granular ignore for missing debug data commit 3dd4cd56e7843e01a8ab147a0d102cd4f6d732c1 13342 ctfconvert could encode _Float128 for 32-bit objects commit 73197b540cc5f0434c409b68ca9e1a514a6ce91b 13336 ctfconvert should be able to unconditionally attempt conversion commit dd4422524768709a579a2a93a10c78a88a6b0ecb 13280 CTF: provide option to truncate and continue Conflicts & other fixes (with help from Jason King <jbk@joyent.com>): usr/src/lib/fm/topo/modules/common/ipmi/ipmi_enum.c usr/src/lib/libctf/common/ctf_convert.c usr/src/lib/libctf/common/ctf_lib.c usr/src/lib/libctf/common/libctf.h usr/src/lib/libproc/common/Psymtab.c usr/src/man/man1/ld.so.1.1 usr/src/man/man4/process.4
author Dan McDonald <danmcd@joyent.com>
date Mon, 04 Jan 2021 14:49:49 -0500
parents 39e726bb90a9 a87c414f8206
children
line wrap: on
line source

/*
 * 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.
 * Copyright 2020 Oxide Computer Company
 */

/*
 * This file provides routines to interact with the kernel sensor framework.
 * Currently, modules that require interacting with a kernel sensor need to
 * build this file as part of the module. This takes care of all the work of
 * setting up and creating the sensor, given a path to that sensor.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <libnvpair.h>
#include <sys/sensors.h>
#include <sys/fm/protocol.h>
#include <fm/topo_mod.h>

#define	TOPO_METH_TOPO_SENSOR_SCALAR		"topo_sensor_scalar_reading"
#define	TOPO_METH_TOPO_SENSOR_SCALAR_DESC	"Kernel Sensor Scalar Reading"
#define	TOPO_METH_TOPO_SENSOR_SCALAR_VERSION	0

static int
topo_sensor_scalar_read(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
    nvlist_t *in, nvlist_t **out)
{
	int fd = -1, ret;
	nvlist_t *args, *nvl;
	char *path;
	sensor_ioctl_scalar_t scalar;
	double value;

	if (vers != TOPO_METH_TOPO_SENSOR_SCALAR_VERSION) {
		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
	}

	if (nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args) != 0 ||
	    nvlist_lookup_string(args, TOPO_IO_DEV_PATH, &path) != 0) {
		topo_mod_dprintf(mod, "failed to lookup sensor path from "
		    "property %s", TOPO_IO_DEV_PATH);
		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
	}

	if ((fd = open(path, O_RDONLY)) < 0) {
		topo_mod_dprintf(mod, "failed to open sensor path %s: %s",
		    path, strerror(errno));
		return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
	}

	(void) memset(&scalar, '\0', sizeof (scalar));
	if (ioctl(fd, SENSOR_IOCTL_SCALAR, &scalar) != 0) {
		topo_mod_dprintf(mod, "failed to read sensor %s: %s", path,
		    strerror(errno));
		ret = topo_mod_seterrno(mod, EMOD_UNKNOWN);
		goto out;
	}

	/*
	 * Check to see if we need to change the value to get it into an
	 * accurate reading. Positive granularities indicate that the sensor
	 * reading is in a fractional number of units and that each unit
	 * contains scalar.sis_gran steps. A negative number means that the
	 * sensor reading represents scalar.sis_gran units.
	 */
	value = (double)scalar.sis_value;
	if (scalar.sis_gran > 1) {
		value /= (double)scalar.sis_gran;
	} else if (scalar.sis_gran < -1) {
		value *= (double)labs(scalar.sis_gran);
	}

	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0) {
		topo_mod_dprintf(mod, "failed to allocate output nvl");
		ret = topo_mod_seterrno(mod, EMOD_NOMEM);
		goto out;
	}

	if (nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_SENSOR_READING) !=
	    0 ||
	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_DOUBLE) != 0 ||
	    nvlist_add_double(nvl, TOPO_PROP_VAL_VAL, value) != 0) {
		topo_mod_dprintf(mod, "failed to add members to output "
		    "sensor nvlist");
		nvlist_free(nvl);
		ret = topo_mod_seterrno(mod, EMOD_NOMEM);
		goto out;
	}

	*out = nvl;
	ret = 0;
out:
	if (fd >= 0) {
		(void) close(fd);
	}
	return (ret);
}

static const topo_method_t topo_sensor_scalar_fac_methods[] = {
	{ TOPO_METH_TOPO_SENSOR_SCALAR, TOPO_METH_TOPO_SENSOR_SCALAR_DESC,
		TOPO_METH_TOPO_SENSOR_SCALAR_VERSION, TOPO_STABILITY_INTERNAL,
		topo_sensor_scalar_read },
	{ NULL }
};

static topo_sensor_unit_t
topo_sensor_units(const sensor_ioctl_scalar_t *scalar)
{
	switch (scalar->sis_unit) {
	case SENSOR_UNIT_CELSIUS:
		return (TOPO_SENSOR_UNITS_DEGREES_C);
	case SENSOR_UNIT_FAHRENHEIT:
		return (TOPO_SENSOR_UNITS_DEGREES_F);
	case SENSOR_UNIT_KELVIN:
		return (TOPO_SENSOR_UNITS_DEGREES_K);
	case SENSOR_UNIT_VOLTS:
		return (TOPO_SENSOR_UNITS_VOLTS);
	case SENSOR_UNIT_AMPS:
		return (TOPO_SENSOR_UNITS_AMPS);
	default:
		return (TOPO_SENSOR_UNITS_UNSPECIFIED);
	}
}

int
topo_sensor_create_scalar_sensor(topo_mod_t *mod, tnode_t *pnode,
    const char *path, const char *fname)
{
	int fd, ret, err;
	sensor_ioctl_kind_t sik;
	sensor_ioctl_scalar_t scalar;
	uint32_t topo_type;
	tnode_t *fnode = NULL;
	topo_pgroup_info_t pgi;
	nvlist_t *reader_arg = NULL;

	topo_mod_dprintf(mod, "attempting to create sensor for %s at %s",
	    topo_node_name(pnode), path);

	(void) memset(&sik, '\0', sizeof (sik));
	(void) memset(&scalar, '\0', sizeof (scalar));

	if ((fd = open(path, O_RDONLY)) < 0) {
		topo_mod_dprintf(mod, "failed to open sensor path %s: %s",
		    path, strerror(errno));

		/*
		 * We always try to create sensors; however, they may not exist
		 * or be supported on the system in question.  Therefore ENOENT
		 * is totally acceptable.
		 */
		if (errno == ENOENT) {
			return (0);
		}
		return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
	}

	if (ioctl(fd, SENSOR_IOCTL_KIND, &sik) != 0) {
		topo_mod_dprintf(mod, "failed to verify sensor kind for sensor "
		    "%s: %s", path, strerror(errno));
		ret = topo_mod_seterrno(mod, EMOD_UNKNOWN);
		goto out;
	}

	switch (sik.sik_kind) {
	case SENSOR_KIND_TEMPERATURE:
		topo_type = TOPO_SENSOR_TYPE_TEMP;
		break;
	case SENSOR_KIND_VOLTAGE:
		topo_type = TOPO_SENSOR_TYPE_VOLTAGE;
		break;
	case SENSOR_KIND_CURRENT:
		topo_type = TOPO_SENSOR_TYPE_CURRENT;
		break;
	default:
		topo_mod_dprintf(mod, "unknown sensor kind for %s, found 0x%x",
		    path, sik.sik_kind);
		ret = topo_mod_seterrno(mod, EMOD_UNKNOWN);
		goto out;

	}

	if (ioctl(fd, SENSOR_IOCTL_SCALAR, &scalar) != 0) {
		topo_mod_dprintf(mod, "failed to read scalar sensor %s: %s",
		    path, strerror(errno));
		ret = topo_mod_seterrno(mod, EMOD_UNKNOWN);
		goto out;
	}

	(void) close(fd);
	fd = -1;

	if ((fnode = topo_node_facbind(mod, pnode, fname,
	    TOPO_FAC_TYPE_SENSOR)) == NULL) {
		topo_mod_dprintf(mod, "failed to bind sensor facility "
		    "node to %s: %d", path, topo_mod_errno(mod));
		ret = -1;
		goto out;
	}

	pgi.tpi_name = TOPO_PGROUP_FACILITY;
	pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
	pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
	pgi.tpi_version = 1;

	if (topo_pgroup_create(fnode, &pgi, &err) != 0) {
		topo_mod_dprintf(mod, "failed to create facility pgroup: %s",
		    topo_strerror(err));
		ret = topo_mod_seterrno(mod, err);
		goto out;
	}

	if (topo_prop_set_string(fnode, TOPO_PGROUP_FACILITY,
	    TOPO_SENSOR_CLASS, TOPO_PROP_IMMUTABLE,
	    TOPO_SENSOR_CLASS_THRESHOLD, &err) != 0 ||
	    topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY,
	    TOPO_FACILITY_TYPE, TOPO_PROP_IMMUTABLE, topo_type, &err) != 0 ||
	    topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY,
	    TOPO_SENSOR_UNITS, TOPO_PROP_IMMUTABLE, topo_sensor_units(&scalar),
	    &err) != 0) {
		topo_mod_dprintf(mod, "failed to set properties for sensor "
		    "%s: %s", path, topo_strerror(err));
		ret = topo_mod_seterrno(mod, err);
		goto out;

	}

	if (topo_method_register(mod, fnode, topo_sensor_scalar_fac_methods) <
	    0) {
		topo_mod_dprintf(mod, "failed to register reading methods on "
		    "%s", path);
		ret = -1;
		goto out;
	}

	if (topo_mod_nvalloc(mod, &reader_arg, NV_UNIQUE_NAME) != 0 ||
	    nvlist_add_string(reader_arg, TOPO_IO_DEV_PATH, path) != 0) {
		topo_mod_dprintf(mod, "Failed to set up reader argument nvl");
		ret = topo_mod_seterrno(mod, EMOD_NOMEM);
		goto out;
	}

	if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY,
	    TOPO_SENSOR_READING, TOPO_TYPE_DOUBLE, TOPO_METH_TOPO_SENSOR_SCALAR,
	    reader_arg, &err) != 0) {
		topo_mod_dprintf(mod, "failed to set argument for sensor %s: "
		    "%s", path, topo_strerror(err));
		ret = topo_mod_seterrno(mod, err);
		goto out;
	}

	topo_mod_dprintf(mod, "created sensor at %s", path);

	nvlist_free(reader_arg);
	return (0);
out:
	if (fd >= 0) {
		(void) close(fd);
	}

	topo_node_unbind(fnode);
	nvlist_free(reader_arg);
	return (ret);
}