blob: 7a001a6f6850463cab7f32621cf2a8989647e205 [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
123 << ": Recovered reading, value=" << reading
124 << " byte=" << raw
125 << ", Reading counts good=" << numReadings
126 << " miss=" << numMissings
127 << ", Prior miss streak=" << numStreakMiss << "\n";
128 }
129
130 // Initialize min/max if the first successful reading
131 if (numReadings == 0)
132 {
133 std::cerr << "IPMI sensor " << sensorName
134 << ": First reading, value=" << reading << " byte=" << raw
135 << "\n";
136
137 minValue = reading;
138 maxValue = reading;
139 }
140
141 numStreakMiss = 0;
142 ++numReadings;
143 ++numStreakRead;
144
145 // Only provide subsequent output if new min/max established
146 if (reading < minValue)
147 {
148 std::cerr << "IPMI sensor " << sensorName
149 << ": Lowest reading, value=" << reading
150 << " byte=" << raw << "\n";
151
152 minValue = reading;
153 }
154
155 if (reading > maxValue)
156 {
157 std::cerr << "IPMI sensor " << sensorName
158 << ": Highest reading, value=" << reading
159 << " byte=" << raw << "\n";
160
161 maxValue = reading;
162 }
163
164 return first;
165 }
166};
167
168class IPMIStatsTable
169{
170 private:
171 std::vector<IPMIStatsEntry> entries;
172
173 private:
174 void padEntries(size_t index)
175 {
176 char hexbuf[16];
177
178 // Pad vector until entries[index] becomes a valid index
179 while (entries.size() <= index)
180 {
181 // As name not known yet, use human-readable hex as name
182 IPMIStatsEntry newEntry;
183 sprintf(hexbuf, "0x%02zX", entries.size());
184 newEntry.updateName(hexbuf);
185
186 entries.push_back(std::move(newEntry));
187 }
188 }
189
190 public:
191 void wipeTable(void)
192 {
193 entries.clear();
194 }
195
196 const std::string& getName(size_t index)
197 {
198 padEntries(index);
199 return entries[index].getName();
200 }
201
202 void updateName(size_t index, std::string_view name)
203 {
204 padEntries(index);
205 entries[index].updateName(name);
206 }
207
208 bool updateReading(size_t index, double reading, int raw)
209 {
210 padEntries(index);
211 return entries[index].updateReading(reading, raw);
212 }
213};
214
Jie Yangf0a89942021-07-29 15:30:25 -0700215class IPMIWriteEntry
216{
217 private:
218 bool writePermission = false;
219
220 public:
221 bool getWritePermission(void) const
222 {
223 return writePermission;
224 }
225
226 void setWritePermission(bool permission)
227 {
228 writePermission = permission;
229 }
230};
231
232class IPMIWriteTable
233{
234 private:
235 std::vector<IPMIWriteEntry> entries;
236
237 private:
238 void padEntries(size_t index)
239 {
240 // Pad vector until entries[index] becomes a valid index
241 if (entries.size() <= index)
242 {
243 entries.resize(index + 1);
244 }
245 }
246
247 public:
248 void wipeTable(void)
249 {
250 entries.clear();
251 }
252
253 bool getWritePermission(size_t index)
254 {
255 padEntries(index);
256 return entries[index].getWritePermission();
257 }
258
259 void setWritePermission(size_t index, bool permission)
260 {
261 padEntries(index);
262 entries[index].setWritePermission(permission);
263 }
264};
265
Hao Jiangd2afd052020-12-10 15:09:32 -0800266// Store information for threshold sensors and they are not used by VR
267// sensors. These objects are global singletons, used from a variety of places.
Josh Lehana55c9532020-10-28 21:59:06 -0700268inline IPMIStatsTable sdrStatsTable;
Jie Yangf0a89942021-07-29 15:30:25 -0700269inline IPMIWriteTable sdrWriteTable;
Josh Lehana55c9532020-10-28 21:59:06 -0700270
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800271/**
272 * Search ObjectMapper for sensors and update them to subtree.
273 *
274 * The function will search for sensors under either
275 * /xyz/openbmc_project/sensors or /xyz/openbmc_project/extsensors. It will
276 * optionally search VR typed sensors under /xyz/openbmc_project/vr
277 *
278 * @return the updated amount of times any of "sensors" or "extsensors" sensor
279 * paths updated successfully, previous amount if all failed. The "vr"
280 * sensor path is optional, and does not participate in the return value.
281 */
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800282uint16_t getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree);
Willy Tude54f482021-01-26 15:59:09 -0800283
284bool getSensorNumMap(std::shared_ptr<SensorNumMap>& sensorNumMap);
285} // namespace details
286
287bool getSensorSubtree(SensorSubTree& subtree);
288
Scron Chang2703b022021-07-06 15:47:45 +0800289#ifdef FEATURE_HYBRID_SENSORS
290ipmi::sensor::IdInfoMap::const_iterator
291 findStaticSensor(const std::string& path);
292#endif
293
Willy Tude54f482021-01-26 15:59:09 -0800294struct CmpStr
295{
296 bool operator()(const char* a, const char* b) const
297 {
298 return std::strcmp(a, b) < 0;
299 }
300};
301
Scron Chang2b42d7e2021-07-06 15:45:47 +0800302static constexpr size_t sensorTypeCodes = 0;
303static constexpr size_t sensorEventTypeCodes = 1;
304
Willy Tude54f482021-01-26 15:59:09 -0800305enum class SensorTypeCodes : uint8_t
306{
David Wang604e0c62021-11-17 11:06:54 +0800307 reserved = 0x00,
308 temperature = 0x01,
309 voltage = 0x02,
310 current = 0x03,
311 fan = 0x04,
Joseph Fud7c26012022-03-03 15:13:00 +0800312 physical_security = 0x5,
David Wang604e0c62021-11-17 11:06:54 +0800313 processor = 0x07,
Scron Changb8e5b162021-07-06 15:46:43 +0800314 power_unit = 0x09,
David Wang604e0c62021-11-17 11:06:54 +0800315 other = 0x0b,
316 memory = 0x0c,
Scron Changb8e5b162021-07-06 15:46:43 +0800317 buttons = 0x14,
318 watchdog2 = 0x23,
Duke Du363d8d52022-04-28 14:56:42 +0800319 entity = 0x25,
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
329const static boost::container::flat_map<
330 const char*, std::pair<SensorTypeCodes, SensorEventTypeCodes>, CmpStr>
331 sensorTypes{
332 {{"temperature", std::make_pair(SensorTypeCodes::temperature,
333 SensorEventTypeCodes::threshold)},
334 {"voltage", std::make_pair(SensorTypeCodes::voltage,
335 SensorEventTypeCodes::threshold)},
336 {"current", std::make_pair(SensorTypeCodes::current,
337 SensorEventTypeCodes::threshold)},
338 {"fan_tach", std::make_pair(SensorTypeCodes::fan,
339 SensorEventTypeCodes::threshold)},
340 {"fan_pwm", std::make_pair(SensorTypeCodes::fan,
341 SensorEventTypeCodes::threshold)},
Joseph Fud7c26012022-03-03 15:13:00 +0800342 {"intrusion", std::make_pair(SensorTypeCodes::physical_security,
343 SensorEventTypeCodes::sensorSpecified)},
David Wang604e0c62021-11-17 11:06:54 +0800344 {"processor", std::make_pair(SensorTypeCodes::processor,
345 SensorEventTypeCodes::sensorSpecified)},
Scron Chang2b42d7e2021-07-06 15:45:47 +0800346 {"power", std::make_pair(SensorTypeCodes::other,
Scron Changb8e5b162021-07-06 15:46:43 +0800347 SensorEventTypeCodes::threshold)},
348 {"memory", std::make_pair(SensorTypeCodes::memory,
349 SensorEventTypeCodes::sensorSpecified)},
350 {"state", std::make_pair(SensorTypeCodes::power_unit,
351 SensorEventTypeCodes::sensorSpecified)},
352 {"buttons", std::make_pair(SensorTypeCodes::buttons,
353 SensorEventTypeCodes::sensorSpecified)},
354 {"watchdog", std::make_pair(SensorTypeCodes::watchdog2,
Duke Du363d8d52022-04-28 14:56:42 +0800355 SensorEventTypeCodes::sensorSpecified)},
356 {"entity", std::make_pair(SensorTypeCodes::entity,
357 SensorEventTypeCodes::sensorSpecified)}}};
Willy Tude54f482021-01-26 15:59:09 -0800358std::string getSensorTypeStringFromPath(const std::string& path);
359
360uint8_t getSensorTypeFromPath(const std::string& path);
361
362uint16_t getSensorNumberFromPath(const std::string& path);
363
364uint8_t getSensorEventTypeFromPath(const std::string& path);
365
366std::string getPathFromSensorNumber(uint16_t sensorNum);
367
368namespace ipmi
369{
370std::map<std::string, std::vector<std::string>>
371 getObjectInterfaces(const char* path);
372
373std::map<std::string, Value> getEntityManagerProperties(const char* path,
374 const char* interface);
375
Willy Tu4eca2512022-06-20 21:14:51 -0700376std::optional<std::unordered_set<std::string>>&
377 getIpmiDecoratorPaths(const std::optional<ipmi::Context::ptr>& ctx);
378
Willy Tude54f482021-01-26 15:59:09 -0800379const std::string* getSensorConfigurationInterface(
380 const std::map<std::string, std::vector<std::string>>&
381 sensorInterfacesResponse);
382
Willy Tu4eca2512022-06-20 21:14:51 -0700383void updateIpmiFromAssociation(
384 const std::string& path,
385 const std::unordered_set<std::string>& ipmiDecoratorPaths,
386 const DbusInterfaceMap& sensorMap, uint8_t& entityId,
387 uint8_t& entityInstance);
Willy Tude54f482021-01-26 15:59:09 -0800388} // namespace ipmi