blob: c4b7cfaa6bbf90940fd1cc0aba9b969f9f4103c6 [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>
20#include <cstdio>
21#include <cstring>
22#include <exception>
23#include <filesystem>
24#include <ipmid/api.hpp>
25#include <ipmid/types.hpp>
26#include <map>
27#include <phosphor-logging/log.hpp>
28#include <sdbusplus/bus/match.hpp>
29#include <string>
30#include <vector>
31
32#pragma once
33
34static constexpr bool debug = false;
35
36struct CmpStrVersion
37{
38 bool operator()(std::string a, std::string b) const
39 {
40 return strverscmp(a.c_str(), b.c_str()) < 0;
41 }
42};
43
44using SensorSubTree = boost::container::flat_map<
45 std::string,
46 boost::container::flat_map<std::string, std::vector<std::string>>,
47 CmpStrVersion>;
48
49using SensorNumMap = boost::bimap<int, std::string>;
50
51static constexpr uint16_t maxSensorsPerLUN = 255;
52static constexpr uint16_t maxIPMISensors = (maxSensorsPerLUN * 3);
53static constexpr uint16_t lun1Sensor0 = 0x100;
54static constexpr uint16_t lun3Sensor0 = 0x300;
55static constexpr uint16_t invalidSensorNumber = 0xFFFF;
56static constexpr uint8_t reservedSensorNumber = 0xFF;
57
58namespace details
59{
Josh Lehana55c9532020-10-28 21:59:06 -070060// Enable/disable the logging of stats instrumentation
61static constexpr bool enableInstrumentation = false;
62
63class IPMIStatsEntry
64{
65 private:
66 int numReadings = 0;
67 int numMissings = 0;
68 int numStreakRead = 0;
69 int numStreakMiss = 0;
70 double minValue = 0.0;
71 double maxValue = 0.0;
72 std::string sensorName;
73
74 public:
75 const std::string& getName(void) const
76 {
77 return sensorName;
78 }
79
80 void updateName(std::string_view name)
81 {
82 sensorName = name;
83 }
84
85 // Returns true if this is the first successful reading
86 // This is so the caller can log the coefficients used
87 bool updateReading(double reading, int raw)
88 {
89 if constexpr (!enableInstrumentation)
90 {
91 return false;
92 }
93
94 bool first = ((numReadings == 0) && (numMissings == 0));
95
96 // Sensors can use "nan" to indicate unavailable reading
97 if (!(std::isfinite(reading)))
98 {
99 // Only show this if beginning a new streak
100 if (numStreakMiss == 0)
101 {
102 std::cerr << "IPMI sensor " << sensorName
103 << ": Missing reading, byte=" << raw
104 << ", Reading counts good=" << numReadings
105 << " miss=" << numMissings
106 << ", Prior good streak=" << numStreakRead << "\n";
107 }
108
109 numStreakRead = 0;
110 ++numMissings;
111 ++numStreakMiss;
112
113 return first;
114 }
115
116 // Only show this if beginning a new streak and not the first time
117 if ((numStreakRead == 0) && (numReadings != 0))
118 {
119 std::cerr << "IPMI sensor " << sensorName
120 << ": Recovered reading, value=" << reading
121 << " byte=" << raw
122 << ", Reading counts good=" << numReadings
123 << " miss=" << numMissings
124 << ", Prior miss streak=" << numStreakMiss << "\n";
125 }
126
127 // Initialize min/max if the first successful reading
128 if (numReadings == 0)
129 {
130 std::cerr << "IPMI sensor " << sensorName
131 << ": First reading, value=" << reading << " byte=" << raw
132 << "\n";
133
134 minValue = reading;
135 maxValue = reading;
136 }
137
138 numStreakMiss = 0;
139 ++numReadings;
140 ++numStreakRead;
141
142 // Only provide subsequent output if new min/max established
143 if (reading < minValue)
144 {
145 std::cerr << "IPMI sensor " << sensorName
146 << ": Lowest reading, value=" << reading
147 << " byte=" << raw << "\n";
148
149 minValue = reading;
150 }
151
152 if (reading > maxValue)
153 {
154 std::cerr << "IPMI sensor " << sensorName
155 << ": Highest reading, value=" << reading
156 << " byte=" << raw << "\n";
157
158 maxValue = reading;
159 }
160
161 return first;
162 }
163};
164
165class IPMIStatsTable
166{
167 private:
168 std::vector<IPMIStatsEntry> entries;
169
170 private:
171 void padEntries(size_t index)
172 {
173 char hexbuf[16];
174
175 // Pad vector until entries[index] becomes a valid index
176 while (entries.size() <= index)
177 {
178 // As name not known yet, use human-readable hex as name
179 IPMIStatsEntry newEntry;
180 sprintf(hexbuf, "0x%02zX", entries.size());
181 newEntry.updateName(hexbuf);
182
183 entries.push_back(std::move(newEntry));
184 }
185 }
186
187 public:
188 void wipeTable(void)
189 {
190 entries.clear();
191 }
192
193 const std::string& getName(size_t index)
194 {
195 padEntries(index);
196 return entries[index].getName();
197 }
198
199 void updateName(size_t index, std::string_view name)
200 {
201 padEntries(index);
202 entries[index].updateName(name);
203 }
204
205 bool updateReading(size_t index, double reading, int raw)
206 {
207 padEntries(index);
208 return entries[index].updateReading(reading, raw);
209 }
210};
211
Jie Yangf0a89942021-07-29 15:30:25 -0700212class IPMIWriteEntry
213{
214 private:
215 bool writePermission = false;
216
217 public:
218 bool getWritePermission(void) const
219 {
220 return writePermission;
221 }
222
223 void setWritePermission(bool permission)
224 {
225 writePermission = permission;
226 }
227};
228
229class IPMIWriteTable
230{
231 private:
232 std::vector<IPMIWriteEntry> entries;
233
234 private:
235 void padEntries(size_t index)
236 {
237 // Pad vector until entries[index] becomes a valid index
238 if (entries.size() <= index)
239 {
240 entries.resize(index + 1);
241 }
242 }
243
244 public:
245 void wipeTable(void)
246 {
247 entries.clear();
248 }
249
250 bool getWritePermission(size_t index)
251 {
252 padEntries(index);
253 return entries[index].getWritePermission();
254 }
255
256 void setWritePermission(size_t index, bool permission)
257 {
258 padEntries(index);
259 entries[index].setWritePermission(permission);
260 }
261};
262
Hao Jiangd2afd052020-12-10 15:09:32 -0800263// Store information for threshold sensors and they are not used by VR
264// sensors. These objects are global singletons, used from a variety of places.
Josh Lehana55c9532020-10-28 21:59:06 -0700265inline IPMIStatsTable sdrStatsTable;
Jie Yangf0a89942021-07-29 15:30:25 -0700266inline IPMIWriteTable sdrWriteTable;
Josh Lehana55c9532020-10-28 21:59:06 -0700267
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800268/**
269 * Search ObjectMapper for sensors and update them to subtree.
270 *
271 * The function will search for sensors under either
272 * /xyz/openbmc_project/sensors or /xyz/openbmc_project/extsensors. It will
273 * optionally search VR typed sensors under /xyz/openbmc_project/vr
274 *
275 * @return the updated amount of times any of "sensors" or "extsensors" sensor
276 * paths updated successfully, previous amount if all failed. The "vr"
277 * sensor path is optional, and does not participate in the return value.
278 */
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800279uint16_t getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree);
Willy Tude54f482021-01-26 15:59:09 -0800280
281bool getSensorNumMap(std::shared_ptr<SensorNumMap>& sensorNumMap);
282} // namespace details
283
284bool getSensorSubtree(SensorSubTree& subtree);
285
Scron Chang2703b022021-07-06 15:47:45 +0800286#ifdef FEATURE_HYBRID_SENSORS
287ipmi::sensor::IdInfoMap::const_iterator
288 findStaticSensor(const std::string& path);
289#endif
290
Willy Tude54f482021-01-26 15:59:09 -0800291struct CmpStr
292{
293 bool operator()(const char* a, const char* b) const
294 {
295 return std::strcmp(a, b) < 0;
296 }
297};
298
Scron Chang2b42d7e2021-07-06 15:45:47 +0800299static constexpr size_t sensorTypeCodes = 0;
300static constexpr size_t sensorEventTypeCodes = 1;
301
Willy Tude54f482021-01-26 15:59:09 -0800302enum class SensorTypeCodes : uint8_t
303{
David Wang604e0c62021-11-17 11:06:54 +0800304 reserved = 0x00,
305 temperature = 0x01,
306 voltage = 0x02,
307 current = 0x03,
308 fan = 0x04,
Joseph Fud7c26012022-03-03 15:13:00 +0800309 physical_security = 0x5,
David Wang604e0c62021-11-17 11:06:54 +0800310 processor = 0x07,
Scron Changb8e5b162021-07-06 15:46:43 +0800311 power_unit = 0x09,
David Wang604e0c62021-11-17 11:06:54 +0800312 other = 0x0b,
313 memory = 0x0c,
Scron Changb8e5b162021-07-06 15:46:43 +0800314 buttons = 0x14,
315 watchdog2 = 0x23,
Duke Du363d8d52022-04-28 14:56:42 +0800316 entity = 0x25,
Willy Tude54f482021-01-26 15:59:09 -0800317};
318
Scron Chang2b42d7e2021-07-06 15:45:47 +0800319enum class SensorEventTypeCodes : uint8_t
320{
321 unspecified = 0x00,
322 threshold = 0x01,
323 sensorSpecified = 0x6f
324};
325
326const static boost::container::flat_map<
327 const char*, std::pair<SensorTypeCodes, SensorEventTypeCodes>, CmpStr>
328 sensorTypes{
329 {{"temperature", std::make_pair(SensorTypeCodes::temperature,
330 SensorEventTypeCodes::threshold)},
331 {"voltage", std::make_pair(SensorTypeCodes::voltage,
332 SensorEventTypeCodes::threshold)},
333 {"current", std::make_pair(SensorTypeCodes::current,
334 SensorEventTypeCodes::threshold)},
335 {"fan_tach", std::make_pair(SensorTypeCodes::fan,
336 SensorEventTypeCodes::threshold)},
337 {"fan_pwm", std::make_pair(SensorTypeCodes::fan,
338 SensorEventTypeCodes::threshold)},
Joseph Fud7c26012022-03-03 15:13:00 +0800339 {"intrusion", std::make_pair(SensorTypeCodes::physical_security,
340 SensorEventTypeCodes::sensorSpecified)},
David Wang604e0c62021-11-17 11:06:54 +0800341 {"processor", std::make_pair(SensorTypeCodes::processor,
342 SensorEventTypeCodes::sensorSpecified)},
Scron Chang2b42d7e2021-07-06 15:45:47 +0800343 {"power", std::make_pair(SensorTypeCodes::other,
Scron Changb8e5b162021-07-06 15:46:43 +0800344 SensorEventTypeCodes::threshold)},
345 {"memory", std::make_pair(SensorTypeCodes::memory,
346 SensorEventTypeCodes::sensorSpecified)},
347 {"state", std::make_pair(SensorTypeCodes::power_unit,
348 SensorEventTypeCodes::sensorSpecified)},
349 {"buttons", std::make_pair(SensorTypeCodes::buttons,
350 SensorEventTypeCodes::sensorSpecified)},
351 {"watchdog", std::make_pair(SensorTypeCodes::watchdog2,
Duke Du363d8d52022-04-28 14:56:42 +0800352 SensorEventTypeCodes::sensorSpecified)},
353 {"entity", std::make_pair(SensorTypeCodes::entity,
354 SensorEventTypeCodes::sensorSpecified)}}};
Willy Tude54f482021-01-26 15:59:09 -0800355std::string getSensorTypeStringFromPath(const std::string& path);
356
357uint8_t getSensorTypeFromPath(const std::string& path);
358
359uint16_t getSensorNumberFromPath(const std::string& path);
360
361uint8_t getSensorEventTypeFromPath(const std::string& path);
362
363std::string getPathFromSensorNumber(uint16_t sensorNum);
364
365namespace ipmi
366{
367std::map<std::string, std::vector<std::string>>
368 getObjectInterfaces(const char* path);
369
370std::map<std::string, Value> getEntityManagerProperties(const char* path,
371 const char* interface);
372
373const std::string* getSensorConfigurationInterface(
374 const std::map<std::string, std::vector<std::string>>&
375 sensorInterfacesResponse);
376
377void updateIpmiFromAssociation(const std::string& path,
378 const DbusInterfaceMap& sensorMap,
379 uint8_t& entityId, uint8_t& entityInstance);
380} // namespace ipmi