1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2020 Oxide Computer Company 14 */ 15 16 /* 17 * Construct sensors based on the ksensor framework for PCI devices. The kernel 18 * will create devices such that they show up 19 * /dev/sensors/temperature/pci/<bus>.<func>/<sensors>. This iterates and adds a 20 * sensor for the device based on the total number that exist for all of them. 21 */ 22 23 #include <sys/types.h> 24 #include <dirent.h> 25 #include <string.h> 26 #include <errno.h> 27 #include <fm/topo_mod.h> 28 #include <fm/topo_hc.h> 29 #include <pcibus.h> 30 #include <topo_sensor.h> 31 32 static const char *pci_sensor_types[] = { "current", "voltage", "temperature" }; 33 34 static int 35 pci_create_dev_scandir(topo_mod_t *mod, tnode_t *dev, const char *path) 36 { 37 int ret; 38 DIR *d; 39 struct dirent *ent; 40 41 d = opendir(path); 42 if (d == NULL) { 43 if (errno == ENOENT) { 44 return (0); 45 } 46 47 topo_mod_dprintf(mod, "failed to open %s: %s", path, 48 strerror(errno)); 49 return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM)); 50 } 51 52 while ((ent = readdir(d)) != NULL) { 53 char spath[PATH_MAX]; 54 55 if (strcmp(ent->d_name, ".") == 0 || 56 strcmp(ent->d_name, "..") == 0) { 57 continue; 58 } 59 60 if (snprintf(spath, sizeof (spath), "%s/%s", path, 61 ent->d_name) >= sizeof (spath)) { 62 topo_mod_dprintf(mod, "failed to construct sensor path " 63 "for %s/%s, path too long", path, ent->d_name); 64 ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM); 65 goto out; 66 } 67 68 topo_mod_dprintf(mod, "attempting to create sensor at %s", 69 spath); 70 if ((ret = topo_sensor_create_scalar_sensor(mod, dev, spath, 71 ent->d_name)) < 0) { 72 goto out; 73 } 74 } 75 76 ret = 0; 77 78 out: 79 (void) closedir(d); 80 return (ret); 81 } 82 83 int 84 pci_create_dev_sensors(topo_mod_t *mod, tnode_t *dev) 85 { 86 uint_t i; 87 char path[PATH_MAX]; 88 topo_instance_t binst, dinst; 89 tnode_t *parent = topo_node_parent(dev); 90 91 binst = topo_node_instance(parent); 92 dinst = topo_node_instance(dev); 93 94 for (i = 0; i < ARRAY_SIZE(pci_sensor_types); i++) { 95 int ret; 96 97 if (snprintf(path, sizeof (path), "/dev/sensors/%s/pci/%x.%x", 98 pci_sensor_types[i], binst, dinst) >= sizeof (path)) { 99 topo_mod_dprintf(mod, "failed to construct %s sensor " 100 "directory path, path too long", 101 pci_sensor_types[i]); 102 return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM)); 103 } 104 105 topo_mod_dprintf(mod, "searching for sensors in %s", path); 106 if ((ret = pci_create_dev_scandir(mod, dev, path)) != 0) { 107 return (ret); 108 } 109 } 110 111 return (0); 112 } 113