blob: c1298764be943b330bc0959df07f29cdf912ddf9 [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>
Willy Tu4eca2512022-06-20 21:14:51 -070027#include <optional>
Willy Tude54f482021-01-26 15:59:09 -080028#include <phosphor-logging/log.hpp>
29#include <sdbusplus/bus/match.hpp>
30#include <string>
Willy Tu4eca2512022-06-20 21:14:51 -070031#include <unordered_set>
Willy Tude54f482021-01-26 15:59:09 -080032#include <vector>
33
34#pragma once
35
36static constexpr bool debug = false;
37
38struct CmpStrVersion
39{
40 bool operator()(std::string a, std::string b) const
41 {
42 return strverscmp(a.c_str(), b.c_str()) < 0;
43 }
44};
45
46using SensorSubTree = boost::container::flat_map<
47 std::string,
48 boost::container::flat_map<std::string, std::vector<std::string>>,
49 CmpStrVersion>;
50
51using SensorNumMap = boost::bimap<int, std::string>;
52
53static constexpr uint16_t maxSensorsPerLUN = 255;
54static constexpr uint16_t maxIPMISensors = (maxSensorsPerLUN * 3);
55static constexpr uint16_t lun1Sensor0 = 0x100;
56static constexpr uint16_t lun3Sensor0 = 0x300;
57static constexpr uint16_t invalidSensorNumber = 0xFFFF;
58static constexpr uint8_t reservedSensorNumber = 0xFF;
59
60namespace details
61{
Josh Lehana55c9532020-10-28 21:59:06 -070062// Enable/disable the logging of stats instrumentation
63static constexpr bool enableInstrumentation = false;
64
65class IPMIStatsEntry
66{
67 private:
68 int numReadings = 0;
69 int numMissings = 0;
70 int numStreakRead = 0;
71 int numStreakMiss = 0;
72 double minValue = 0.0;
73 double maxValue = 0.0;
74 std::string sensorName;
75
76 public:
77 const std::string& getName(void) const
78 {
79 return sensorName;
80 }
81
82 void updateName(std::string_view name)
83 {
84 sensorName = name;
85 }
86
87 // Returns true if this is the first successful reading
88 // This is so the caller can log the coefficients used
89 bool updateReading(double reading, int raw)
90 {
91 if constexpr (!enableInstrumentation)
92 {
93 return false;
94 }
95
96 bool first = ((numReadings == 0) && (numMissings == 0));
97
98 // Sensors can use "nan" to indicate unavailable reading
99 if (!(std::isfinite(reading)))
100 {
101 // Only show this if beginning a new streak
102 if (numStreakMiss == 0)
103 {
104 std::cerr << "IPMI sensor " << sensorName
105 << ": Missing reading, byte=" << raw
106 << ", Reading counts good=" << numReadings
107 << " miss=" << numMissings
108 << ", Prior good streak=" << numStreakRead << "\n";
109 }
110
111 numStreakRead = 0;
112 ++numMissings;
113 ++numStreakMiss;
114
115 return first;
116 }
117
118 // Only show this if beginning a new streak and not the first time
119 if ((numStreakRead == 0) && (numReadings != 0))
120 {
121 std::cerr << "IPMI sensor " << sensorName
122 << ": Recovered reading, value=" << reading
123 << " byte=" << raw
124 << ", Reading counts good=" << numReadings
125 << " 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,
Willy Tude54f482021-01-26 15:59:09 -0800319};
320
Scron Chang2b42d7e2021-07-06 15:45:47 +0800321enum class SensorEventTypeCodes : uint8_t
322{
323 unspecified = 0x00,
324 threshold = 0x01,
325 sensorSpecified = 0x6f
326};
327
328const static boost::container::flat_map<
329 const char*, std::pair<SensorTypeCodes, SensorEventTypeCodes>, CmpStr>
330 sensorTypes{
331 {{"temperature", std::make_pair(SensorTypeCodes::temperature,
332 SensorEventTypeCodes::threshold)},
333 {"voltage", std::make_pair(SensorTypeCodes::voltage,
334 SensorEventTypeCodes::threshold)},
335 {"current", std::make_pair(SensorTypeCodes::current,
336 SensorEventTypeCodes::threshold)},
337 {"fan_tach", std::make_pair(SensorTypeCodes::fan,
338 SensorEventTypeCodes::threshold)},
339 {"fan_pwm", std::make_pair(SensorTypeCodes::fan,
340 SensorEventTypeCodes::threshold)},
Joseph Fud7c26012022-03-03 15:13:00 +0800341 {"intrusion", std::make_pair(SensorTypeCodes::physical_security,
342 SensorEventTypeCodes::sensorSpecified)},
David Wang604e0c62021-11-17 11:06:54 +0800343 {"processor", std::make_pair(SensorTypeCodes::processor,
344 SensorEventTypeCodes::sensorSpecified)},
Scron Chang2b42d7e2021-07-06 15:45:47 +0800345 {"power", std::make_pair(SensorTypeCodes::other,
Scron Changb8e5b162021-07-06 15:46:43 +0800346 SensorEventTypeCodes::threshold)},
347 {"memory", std::make_pair(SensorTypeCodes::memory,
348 SensorEventTypeCodes::sensorSpecified)},
349 {"state", std::make_pair(SensorTypeCodes::power_unit,
350 SensorEventTypeCodes::sensorSpecified)},
351 {"buttons", std::make_pair(SensorTypeCodes::buttons,
352 SensorEventTypeCodes::sensorSpecified)},
353 {"watchdog", std::make_pair(SensorTypeCodes::watchdog2,
Duke Du363d8d52022-04-28 14:56:42 +0800354 SensorEventTypeCodes::sensorSpecified)},
355 {"entity", std::make_pair(SensorTypeCodes::entity,
356 SensorEventTypeCodes::sensorSpecified)}}};
Willy Tude54f482021-01-26 15:59:09 -0800357std::string getSensorTypeStringFromPath(const std::string& path);
358
359uint8_t getSensorTypeFromPath(const std::string& path);
360
361uint16_t getSensorNumberFromPath(const std::string& path);
362
363uint8_t getSensorEventTypeFromPath(const std::string& path);
364
365std::string getPathFromSensorNumber(uint16_t sensorNum);
366
367namespace ipmi
368{
369std::map<std::string, std::vector<std::string>>
370 getObjectInterfaces(const char* path);
371
372std::map<std::string, Value> getEntityManagerProperties(const char* path,
373 const char* interface);
374
Willy Tu4eca2512022-06-20 21:14:51 -0700375std::optional<std::unordered_set<std::string>>&
376 getIpmiDecoratorPaths(const std::optional<ipmi::Context::ptr>& ctx);
377
Willy Tude54f482021-01-26 15:59:09 -0800378const std::string* getSensorConfigurationInterface(
379 const std::map<std::string, std::vector<std::string>>&
380 sensorInterfacesResponse);
381
Willy Tu4eca2512022-06-20 21:14:51 -0700382void updateIpmiFromAssociation(
383 const std::string& path,
384 const std::unordered_set<std::string>& ipmiDecoratorPaths,
385 const DbusInterfaceMap& sensorMap, uint8_t& entityId,
386 uint8_t& entityInstance);
Willy Tude54f482021-01-26 15:59:09 -0800387} // namespace ipmi