blob: db462db42f61435abe7816716c261304ffa3b0dc [file] [log] [blame]
Willy Tude54f482021-01-26 15:59:09 -08001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#include <boost/algorithm/string.hpp>
18#include <boost/bimap.hpp>
19#include <boost/container/flat_map.hpp>
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050020#include <ipmid/api.hpp>
21#include <ipmid/types.hpp>
22#include <phosphor-logging/log.hpp>
23#include <sdbusplus/bus/match.hpp>
24
Willy Tude54f482021-01-26 15:59:09 -080025#include <cstdio>
26#include <cstring>
27#include <exception>
28#include <filesystem>
Willy Tude54f482021-01-26 15:59:09 -080029#include <map>
Willy Tu4eca2512022-06-20 21:14:51 -070030#include <optional>
Willy Tude54f482021-01-26 15:59:09 -080031#include <string>
Willy Tu4eca2512022-06-20 21:14:51 -070032#include <unordered_set>
Willy Tude54f482021-01-26 15:59:09 -080033#include <vector>
34
35#pragma once
36
37static constexpr bool debug = false;
38
39struct CmpStrVersion
40{
41 bool operator()(std::string a, std::string b) const
42 {
43 return strverscmp(a.c_str(), b.c_str()) < 0;
44 }
45};
46
47using SensorSubTree = boost::container::flat_map<
48 std::string,
49 boost::container::flat_map<std::string, std::vector<std::string>>,
50 CmpStrVersion>;
51
52using SensorNumMap = boost::bimap<int, std::string>;
53
54static constexpr uint16_t maxSensorsPerLUN = 255;
55static constexpr uint16_t maxIPMISensors = (maxSensorsPerLUN * 3);
56static constexpr uint16_t lun1Sensor0 = 0x100;
57static constexpr uint16_t lun3Sensor0 = 0x300;
58static constexpr uint16_t invalidSensorNumber = 0xFFFF;
59static constexpr uint8_t reservedSensorNumber = 0xFF;
60
61namespace details
62{
Josh Lehana55c9532020-10-28 21:59:06 -070063// Enable/disable the logging of stats instrumentation
64static constexpr bool enableInstrumentation = false;
65
66class IPMIStatsEntry
67{
68 private:
69 int numReadings = 0;
70 int numMissings = 0;
71 int numStreakRead = 0;
72 int numStreakMiss = 0;
73 double minValue = 0.0;
74 double maxValue = 0.0;
75 std::string sensorName;
76
77 public:
78 const std::string& getName(void) const
79 {
80 return sensorName;
81 }
82
83 void updateName(std::string_view name)
84 {
85 sensorName = name;
86 }
87
88 // Returns true if this is the first successful reading
89 // This is so the caller can log the coefficients used
90 bool updateReading(double reading, int raw)
91 {
92 if constexpr (!enableInstrumentation)
93 {
94 return false;
95 }
96
97 bool first = ((numReadings == 0) && (numMissings == 0));
98
99 // Sensors can use "nan" to indicate unavailable reading
100 if (!(std::isfinite(reading)))
101 {
102 // Only show this if beginning a new streak
103 if (numStreakMiss == 0)
104 {
105 std::cerr << "IPMI sensor " << sensorName
106 << ": Missing reading, byte=" << raw
107 << ", Reading counts good=" << numReadings
108 << " miss=" << numMissings
109 << ", Prior good streak=" << numStreakRead << "\n";
110 }
111
112 numStreakRead = 0;
113 ++numMissings;
114 ++numStreakMiss;
115
116 return first;
117 }
118
119 // Only show this if beginning a new streak and not the first time
120 if ((numStreakRead == 0) && (numReadings != 0))
121 {
122 std::cerr << "IPMI sensor " << sensorName
Patrick Williams1318a5e2024-08-16 15:19:54 -0400123 << ": Recovered reading, value=" << reading << " byte="
124 << raw << ", Reading counts good=" << numReadings
Josh Lehana55c9532020-10-28 21:59:06 -0700125 << " miss=" << numMissings
126 << ", Prior miss streak=" << numStreakMiss << "\n";
127 }
128
129 // Initialize min/max if the first successful reading
130 if (numReadings == 0)
131 {
132 std::cerr << "IPMI sensor " << sensorName
133 << ": First reading, value=" << reading << " byte=" << raw
134 << "\n";
135
136 minValue = reading;
137 maxValue = reading;
138 }
139
140 numStreakMiss = 0;
141 ++numReadings;
142 ++numStreakRead;
143
144 // Only provide subsequent output if new min/max established
145 if (reading < minValue)
146 {
147 std::cerr << "IPMI sensor " << sensorName
148 << ": Lowest reading, value=" << reading
149 << " byte=" << raw << "\n";
150
151 minValue = reading;
152 }
153
154 if (reading > maxValue)
155 {
156 std::cerr << "IPMI sensor " << sensorName
157 << ": Highest reading, value=" << reading
158 << " byte=" << raw << "\n";
159
160 maxValue = reading;
161 }
162
163 return first;
164 }
165};
166
167class IPMIStatsTable
168{
169 private:
170 std::vector<IPMIStatsEntry> entries;
171
172 private:
173 void padEntries(size_t index)
174 {
175 char hexbuf[16];
176
177 // Pad vector until entries[index] becomes a valid index
178 while (entries.size() <= index)
179 {
180 // As name not known yet, use human-readable hex as name
181 IPMIStatsEntry newEntry;
182 sprintf(hexbuf, "0x%02zX", entries.size());
183 newEntry.updateName(hexbuf);
184
185 entries.push_back(std::move(newEntry));
186 }
187 }
188
189 public:
190 void wipeTable(void)
191 {
192 entries.clear();
193 }
194
195 const std::string& getName(size_t index)
196 {
197 padEntries(index);
198 return entries[index].getName();
199 }
200
201 void updateName(size_t index, std::string_view name)
202 {
203 padEntries(index);
204 entries[index].updateName(name);
205 }
206
207 bool updateReading(size_t index, double reading, int raw)
208 {
209 padEntries(index);
210 return entries[index].updateReading(reading, raw);
211 }
212};
213
Jie Yangf0a89942021-07-29 15:30:25 -0700214class IPMIWriteEntry
215{
216 private:
217 bool writePermission = false;
218
219 public:
220 bool getWritePermission(void) const
221 {
222 return writePermission;
223 }
224
225 void setWritePermission(bool permission)
226 {
227 writePermission = permission;
228 }
229};
230
231class IPMIWriteTable
232{
233 private:
234 std::vector<IPMIWriteEntry> entries;
235
236 private:
237 void padEntries(size_t index)
238 {
239 // Pad vector until entries[index] becomes a valid index
240 if (entries.size() <= index)
241 {
242 entries.resize(index + 1);
243 }
244 }
245
246 public:
247 void wipeTable(void)
248 {
249 entries.clear();
250 }
251
252 bool getWritePermission(size_t index)
253 {
254 padEntries(index);
255 return entries[index].getWritePermission();
256 }
257
258 void setWritePermission(size_t index, bool permission)
259 {
260 padEntries(index);
261 entries[index].setWritePermission(permission);
262 }
263};
264
Hao Jiangd2afd052020-12-10 15:09:32 -0800265// Store information for threshold sensors and they are not used by VR
266// sensors. These objects are global singletons, used from a variety of places.
Josh Lehana55c9532020-10-28 21:59:06 -0700267inline IPMIStatsTable sdrStatsTable;
Jie Yangf0a89942021-07-29 15:30:25 -0700268inline IPMIWriteTable sdrWriteTable;
Josh Lehana55c9532020-10-28 21:59:06 -0700269
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800270/**
271 * Search ObjectMapper for sensors and update them to subtree.
272 *
273 * The function will search for sensors under either
274 * /xyz/openbmc_project/sensors or /xyz/openbmc_project/extsensors. It will
275 * optionally search VR typed sensors under /xyz/openbmc_project/vr
276 *
277 * @return the updated amount of times any of "sensors" or "extsensors" sensor
278 * paths updated successfully, previous amount if all failed. The "vr"
279 * sensor path is optional, and does not participate in the return value.
280 */
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800281uint16_t getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree);
Willy Tude54f482021-01-26 15:59:09 -0800282
283bool getSensorNumMap(std::shared_ptr<SensorNumMap>& sensorNumMap);
284} // namespace details
285
286bool getSensorSubtree(SensorSubTree& subtree);
287
Scron Chang2703b022021-07-06 15:47:45 +0800288#ifdef FEATURE_HYBRID_SENSORS
289ipmi::sensor::IdInfoMap::const_iterator
290 findStaticSensor(const std::string& path);
291#endif
292
Willy Tude54f482021-01-26 15:59:09 -0800293struct CmpStr
294{
295 bool operator()(const char* a, const char* b) const
296 {
297 return std::strcmp(a, b) < 0;
298 }
299};
300
Scron Chang2b42d7e2021-07-06 15:45:47 +0800301static constexpr size_t sensorTypeCodes = 0;
302static constexpr size_t sensorEventTypeCodes = 1;
303
Willy Tude54f482021-01-26 15:59:09 -0800304enum class SensorTypeCodes : uint8_t
305{
David Wang604e0c62021-11-17 11:06:54 +0800306 reserved = 0x00,
307 temperature = 0x01,
308 voltage = 0x02,
309 current = 0x03,
310 fan = 0x04,
Joseph Fud7c26012022-03-03 15:13:00 +0800311 physical_security = 0x5,
David Wang604e0c62021-11-17 11:06:54 +0800312 processor = 0x07,
Scron Changb8e5b162021-07-06 15:46:43 +0800313 power_unit = 0x09,
David Wang604e0c62021-11-17 11:06:54 +0800314 other = 0x0b,
315 memory = 0x0c,
Scron Changb8e5b162021-07-06 15:46:43 +0800316 buttons = 0x14,
317 watchdog2 = 0x23,
Duke Du363d8d52022-04-28 14:56:42 +0800318 entity = 0x25,
Johnathan Mantey34d19732024-07-17 07:59:54 -0700319 oemC0 = 0xc0,
Willy Tude54f482021-01-26 15:59:09 -0800320};
321
Scron Chang2b42d7e2021-07-06 15:45:47 +0800322enum class SensorEventTypeCodes : uint8_t
323{
324 unspecified = 0x00,
325 threshold = 0x01,
326 sensorSpecified = 0x6f
327};
328
Johnathan Mantey34d19732024-07-17 07:59:54 -0700329extern boost::container::flat_map<
Scron Chang2b42d7e2021-07-06 15:45:47 +0800330 const char*, std::pair<SensorTypeCodes, SensorEventTypeCodes>, CmpStr>
Johnathan Mantey34d19732024-07-17 07:59:54 -0700331 sensorTypes;
332
Willy Tude54f482021-01-26 15:59:09 -0800333std::string getSensorTypeStringFromPath(const std::string& path);
334
335uint8_t getSensorTypeFromPath(const std::string& path);
336
337uint16_t getSensorNumberFromPath(const std::string& path);
338
339uint8_t getSensorEventTypeFromPath(const std::string& path);
340
341std::string getPathFromSensorNumber(uint16_t sensorNum);
342
343namespace ipmi
344{
Alexander Hansen8fb5b892023-11-02 17:29:34 +0100345std::optional<std::map<std::string, std::vector<std::string>>>
Willy Tude54f482021-01-26 15:59:09 -0800346 getObjectInterfaces(const char* path);
347
Patrick Williams1318a5e2024-08-16 15:19:54 -0400348std::map<std::string, Value>
349 getEntityManagerProperties(const char* path, const char* interface);
Willy Tude54f482021-01-26 15:59:09 -0800350
Willy Tu4eca2512022-06-20 21:14:51 -0700351std::optional<std::unordered_set<std::string>>&
352 getIpmiDecoratorPaths(const std::optional<ipmi::Context::ptr>& ctx);
353
Willy Tude54f482021-01-26 15:59:09 -0800354const std::string* getSensorConfigurationInterface(
355 const std::map<std::string, std::vector<std::string>>&
356 sensorInterfacesResponse);
357
Willy Tu4eca2512022-06-20 21:14:51 -0700358void updateIpmiFromAssociation(
359 const std::string& path,
360 const std::unordered_set<std::string>& ipmiDecoratorPaths,
361 const DbusInterfaceMap& sensorMap, uint8_t& entityId,
362 uint8_t& entityInstance);
Willy Tude54f482021-01-26 15:59:09 -0800363} // namespace ipmi