xref: /illumos-gate/usr/src/lib/fm/topo/modules/common/pcibus/pci_sensor.c (revision bdc3270f393f51a419684e0fd3d7112e9b269773)
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 int
33 pci_create_dev_sensors(topo_mod_t *mod, tnode_t *dev)
34 {
35 	int ret;
36 	DIR *d;
37 	char path[PATH_MAX];
38 	topo_instance_t binst, dinst;
39 	struct dirent *ent;
40 	tnode_t *parent = topo_node_parent(dev);
41 
42 	binst = topo_node_instance(parent);
43 	dinst = topo_node_instance(dev);
44 
45 	if (snprintf(path, sizeof (path), "/dev/sensors/temperature/pci/%x.%x",
46 	    binst, dinst) >= sizeof (path)) {
47 		topo_mod_dprintf(mod, "failed to construct temp sensor "
48 		    "directory path, path too long");
49 		return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM));
50 	}
51 
52 	topo_mod_dprintf(mod, "searching for sensors in %s", path);
53 
54 	d = opendir(path);
55 	if (d == NULL) {
56 		if (errno == ENOENT) {
57 			return (0);
58 		}
59 
60 		topo_mod_dprintf(mod, "failed to open %s: %s", path,
61 		    strerror(errno));
62 		return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM));
63 	}
64 
65 	while ((ent = readdir(d)) != NULL) {
66 		char spath[PATH_MAX];
67 
68 		if (strcmp(ent->d_name, ".") == 0 ||
69 		    strcmp(ent->d_name, "..") == 0) {
70 			continue;
71 		}
72 
73 		if (snprintf(spath, sizeof (spath), "%s/%s", path,
74 		    ent->d_name) >= sizeof (spath)) {
75 			topo_mod_dprintf(mod, "failed to construct temp sensor "
76 			    "path for %s/%s, path too long", path, ent->d_name);
77 			ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
78 			goto out;
79 		}
80 
81 		topo_mod_dprintf(mod, "attempting to create sensor at %s",
82 		    spath);
83 		if ((ret = topo_sensor_create_temp_sensor(mod, dev, spath,
84 		    ent->d_name)) < 0) {
85 			goto out;
86 		}
87 
88 	}
89 	ret = 0;
90 
91 out:
92 	(void) closedir(d);
93 
94 	return (ret);
95 }
96