blob: 6b544174f51392529b8456b77f886aa91dfb2f98 [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
Hao Jiangd2afd052020-12-10 15:09:32 -0800212// Store information for threshold sensors and they are not used by VR
213// sensors. These objects are global singletons, used from a variety of places.
Josh Lehana55c9532020-10-28 21:59:06 -0700214inline IPMIStatsTable sdrStatsTable;
215
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800216/**
217 * Search ObjectMapper for sensors and update them to subtree.
218 *
219 * The function will search for sensors under either
220 * /xyz/openbmc_project/sensors or /xyz/openbmc_project/extsensors. It will
221 * optionally search VR typed sensors under /xyz/openbmc_project/vr
222 *
223 * @return the updated amount of times any of "sensors" or "extsensors" sensor
224 * paths updated successfully, previous amount if all failed. The "vr"
225 * sensor path is optional, and does not participate in the return value.
226 */
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800227uint16_t getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree);
Willy Tude54f482021-01-26 15:59:09 -0800228
229bool getSensorNumMap(std::shared_ptr<SensorNumMap>& sensorNumMap);
230} // namespace details
231
232bool getSensorSubtree(SensorSubTree& subtree);
233
234struct CmpStr
235{
236 bool operator()(const char* a, const char* b) const
237 {
238 return std::strcmp(a, b) < 0;
239 }
240};
241
Scron Chang2b42d7e2021-07-06 15:45:47 +0800242static constexpr size_t sensorTypeCodes = 0;
243static constexpr size_t sensorEventTypeCodes = 1;
244
Willy Tude54f482021-01-26 15:59:09 -0800245enum class SensorTypeCodes : uint8_t
246{
247 reserved = 0x0,
248 temperature = 0x1,
249 voltage = 0x2,
250 current = 0x3,
251 fan = 0x4,
252 other = 0xB,
253};
254
Scron Chang2b42d7e2021-07-06 15:45:47 +0800255enum class SensorEventTypeCodes : uint8_t
256{
257 unspecified = 0x00,
258 threshold = 0x01,
259 sensorSpecified = 0x6f
260};
261
262const static boost::container::flat_map<
263 const char*, std::pair<SensorTypeCodes, SensorEventTypeCodes>, CmpStr>
264 sensorTypes{
265 {{"temperature", std::make_pair(SensorTypeCodes::temperature,
266 SensorEventTypeCodes::threshold)},
267 {"voltage", std::make_pair(SensorTypeCodes::voltage,
268 SensorEventTypeCodes::threshold)},
269 {"current", std::make_pair(SensorTypeCodes::current,
270 SensorEventTypeCodes::threshold)},
271 {"fan_tach", std::make_pair(SensorTypeCodes::fan,
272 SensorEventTypeCodes::threshold)},
273 {"fan_pwm", std::make_pair(SensorTypeCodes::fan,
274 SensorEventTypeCodes::threshold)},
275 {"power", std::make_pair(SensorTypeCodes::other,
276 SensorEventTypeCodes::threshold)}}};
Willy Tude54f482021-01-26 15:59:09 -0800277
278std::string getSensorTypeStringFromPath(const std::string& path);
279
280uint8_t getSensorTypeFromPath(const std::string& path);
281
282uint16_t getSensorNumberFromPath(const std::string& path);
283
284uint8_t getSensorEventTypeFromPath(const std::string& path);
285
286std::string getPathFromSensorNumber(uint16_t sensorNum);
287
288namespace ipmi
289{
290std::map<std::string, std::vector<std::string>>
291 getObjectInterfaces(const char* path);
292
293std::map<std::string, Value> getEntityManagerProperties(const char* path,
294 const char* interface);
295
296const std::string* getSensorConfigurationInterface(
297 const std::map<std::string, std::vector<std::string>>&
298 sensorInterfacesResponse);
299
300void updateIpmiFromAssociation(const std::string& path,
301 const DbusInterfaceMap& sensorMap,
302 uint8_t& entityId, uint8_t& entityInstance);
303} // namespace ipmi