xref: /openbmc/phosphor-host-ipmid/include/dbus-sdr/sdrutils.hpp (revision a55c953dd2bba16f2d43b186f920b18da4a3493f)
1de54f486SWilly Tu /*
2de54f486SWilly Tu // Copyright (c) 2018 Intel Corporation
3de54f486SWilly Tu //
4de54f486SWilly Tu // Licensed under the Apache License, Version 2.0 (the "License");
5de54f486SWilly Tu // you may not use this file except in compliance with the License.
6de54f486SWilly Tu // You may obtain a copy of the License at
7de54f486SWilly Tu //
8de54f486SWilly Tu //      http://www.apache.org/licenses/LICENSE-2.0
9de54f486SWilly Tu //
10de54f486SWilly Tu // Unless required by applicable law or agreed to in writing, software
11de54f486SWilly Tu // distributed under the License is distributed on an "AS IS" BASIS,
12de54f486SWilly Tu // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13de54f486SWilly Tu // See the License for the specific language governing permissions and
14de54f486SWilly Tu // limitations under the License.
15de54f486SWilly Tu */
16de54f486SWilly Tu 
17de54f486SWilly Tu #include <boost/algorithm/string.hpp>
18de54f486SWilly Tu #include <boost/bimap.hpp>
19de54f486SWilly Tu #include <boost/container/flat_map.hpp>
20de54f486SWilly Tu #include <cstdio>
21de54f486SWilly Tu #include <cstring>
22de54f486SWilly Tu #include <exception>
23de54f486SWilly Tu #include <filesystem>
24de54f486SWilly Tu #include <ipmid/api.hpp>
25de54f486SWilly Tu #include <ipmid/types.hpp>
26de54f486SWilly Tu #include <map>
27de54f486SWilly Tu #include <phosphor-logging/log.hpp>
28de54f486SWilly Tu #include <sdbusplus/bus/match.hpp>
29de54f486SWilly Tu #include <string>
30de54f486SWilly Tu #include <vector>
31de54f486SWilly Tu 
32de54f486SWilly Tu #pragma once
33de54f486SWilly Tu 
34de54f486SWilly Tu static constexpr bool debug = false;
35de54f486SWilly Tu 
36de54f486SWilly Tu struct CmpStrVersion
37de54f486SWilly Tu {
38de54f486SWilly Tu     bool operator()(std::string a, std::string b) const
39de54f486SWilly Tu     {
40de54f486SWilly Tu         return strverscmp(a.c_str(), b.c_str()) < 0;
41de54f486SWilly Tu     }
42de54f486SWilly Tu };
43de54f486SWilly Tu 
44de54f486SWilly Tu using SensorSubTree = boost::container::flat_map<
45de54f486SWilly Tu     std::string,
46de54f486SWilly Tu     boost::container::flat_map<std::string, std::vector<std::string>>,
47de54f486SWilly Tu     CmpStrVersion>;
48de54f486SWilly Tu 
49de54f486SWilly Tu using SensorNumMap = boost::bimap<int, std::string>;
50de54f486SWilly Tu 
51de54f486SWilly Tu static constexpr uint16_t maxSensorsPerLUN = 255;
52de54f486SWilly Tu static constexpr uint16_t maxIPMISensors = (maxSensorsPerLUN * 3);
53de54f486SWilly Tu static constexpr uint16_t lun1Sensor0 = 0x100;
54de54f486SWilly Tu static constexpr uint16_t lun3Sensor0 = 0x300;
55de54f486SWilly Tu static constexpr uint16_t invalidSensorNumber = 0xFFFF;
56de54f486SWilly Tu static constexpr uint8_t reservedSensorNumber = 0xFF;
57de54f486SWilly Tu 
58de54f486SWilly Tu namespace details
59de54f486SWilly Tu {
60*a55c953dSJosh Lehan // Enable/disable the logging of stats instrumentation
61*a55c953dSJosh Lehan static constexpr bool enableInstrumentation = false;
62*a55c953dSJosh Lehan 
63*a55c953dSJosh Lehan class IPMIStatsEntry
64*a55c953dSJosh Lehan {
65*a55c953dSJosh Lehan   private:
66*a55c953dSJosh Lehan     int numReadings = 0;
67*a55c953dSJosh Lehan     int numMissings = 0;
68*a55c953dSJosh Lehan     int numStreakRead = 0;
69*a55c953dSJosh Lehan     int numStreakMiss = 0;
70*a55c953dSJosh Lehan     double minValue = 0.0;
71*a55c953dSJosh Lehan     double maxValue = 0.0;
72*a55c953dSJosh Lehan     std::string sensorName;
73*a55c953dSJosh Lehan 
74*a55c953dSJosh Lehan   public:
75*a55c953dSJosh Lehan     const std::string& getName(void) const
76*a55c953dSJosh Lehan     {
77*a55c953dSJosh Lehan         return sensorName;
78*a55c953dSJosh Lehan     }
79*a55c953dSJosh Lehan 
80*a55c953dSJosh Lehan     void updateName(std::string_view name)
81*a55c953dSJosh Lehan     {
82*a55c953dSJosh Lehan         sensorName = name;
83*a55c953dSJosh Lehan     }
84*a55c953dSJosh Lehan 
85*a55c953dSJosh Lehan     // Returns true if this is the first successful reading
86*a55c953dSJosh Lehan     // This is so the caller can log the coefficients used
87*a55c953dSJosh Lehan     bool updateReading(double reading, int raw)
88*a55c953dSJosh Lehan     {
89*a55c953dSJosh Lehan         if constexpr (!enableInstrumentation)
90*a55c953dSJosh Lehan         {
91*a55c953dSJosh Lehan             return false;
92*a55c953dSJosh Lehan         }
93*a55c953dSJosh Lehan 
94*a55c953dSJosh Lehan         bool first = ((numReadings == 0) && (numMissings == 0));
95*a55c953dSJosh Lehan 
96*a55c953dSJosh Lehan         // Sensors can use "nan" to indicate unavailable reading
97*a55c953dSJosh Lehan         if (!(std::isfinite(reading)))
98*a55c953dSJosh Lehan         {
99*a55c953dSJosh Lehan             // Only show this if beginning a new streak
100*a55c953dSJosh Lehan             if (numStreakMiss == 0)
101*a55c953dSJosh Lehan             {
102*a55c953dSJosh Lehan                 std::cerr << "IPMI sensor " << sensorName
103*a55c953dSJosh Lehan                           << ": Missing reading, byte=" << raw
104*a55c953dSJosh Lehan                           << ", Reading counts good=" << numReadings
105*a55c953dSJosh Lehan                           << " miss=" << numMissings
106*a55c953dSJosh Lehan                           << ", Prior good streak=" << numStreakRead << "\n";
107*a55c953dSJosh Lehan             }
108*a55c953dSJosh Lehan 
109*a55c953dSJosh Lehan             numStreakRead = 0;
110*a55c953dSJosh Lehan             ++numMissings;
111*a55c953dSJosh Lehan             ++numStreakMiss;
112*a55c953dSJosh Lehan 
113*a55c953dSJosh Lehan             return first;
114*a55c953dSJosh Lehan         }
115*a55c953dSJosh Lehan 
116*a55c953dSJosh Lehan         // Only show this if beginning a new streak and not the first time
117*a55c953dSJosh Lehan         if ((numStreakRead == 0) && (numReadings != 0))
118*a55c953dSJosh Lehan         {
119*a55c953dSJosh Lehan             std::cerr << "IPMI sensor " << sensorName
120*a55c953dSJosh Lehan                       << ": Recovered reading, value=" << reading
121*a55c953dSJosh Lehan                       << " byte=" << raw
122*a55c953dSJosh Lehan                       << ", Reading counts good=" << numReadings
123*a55c953dSJosh Lehan                       << " miss=" << numMissings
124*a55c953dSJosh Lehan                       << ", Prior miss streak=" << numStreakMiss << "\n";
125*a55c953dSJosh Lehan         }
126*a55c953dSJosh Lehan 
127*a55c953dSJosh Lehan         // Initialize min/max if the first successful reading
128*a55c953dSJosh Lehan         if (numReadings == 0)
129*a55c953dSJosh Lehan         {
130*a55c953dSJosh Lehan             std::cerr << "IPMI sensor " << sensorName
131*a55c953dSJosh Lehan                       << ": First reading, value=" << reading << " byte=" << raw
132*a55c953dSJosh Lehan                       << "\n";
133*a55c953dSJosh Lehan 
134*a55c953dSJosh Lehan             minValue = reading;
135*a55c953dSJosh Lehan             maxValue = reading;
136*a55c953dSJosh Lehan         }
137*a55c953dSJosh Lehan 
138*a55c953dSJosh Lehan         numStreakMiss = 0;
139*a55c953dSJosh Lehan         ++numReadings;
140*a55c953dSJosh Lehan         ++numStreakRead;
141*a55c953dSJosh Lehan 
142*a55c953dSJosh Lehan         // Only provide subsequent output if new min/max established
143*a55c953dSJosh Lehan         if (reading < minValue)
144*a55c953dSJosh Lehan         {
145*a55c953dSJosh Lehan             std::cerr << "IPMI sensor " << sensorName
146*a55c953dSJosh Lehan                       << ": Lowest reading, value=" << reading
147*a55c953dSJosh Lehan                       << " byte=" << raw << "\n";
148*a55c953dSJosh Lehan 
149*a55c953dSJosh Lehan             minValue = reading;
150*a55c953dSJosh Lehan         }
151*a55c953dSJosh Lehan 
152*a55c953dSJosh Lehan         if (reading > maxValue)
153*a55c953dSJosh Lehan         {
154*a55c953dSJosh Lehan             std::cerr << "IPMI sensor " << sensorName
155*a55c953dSJosh Lehan                       << ": Highest reading, value=" << reading
156*a55c953dSJosh Lehan                       << " byte=" << raw << "\n";
157*a55c953dSJosh Lehan 
158*a55c953dSJosh Lehan             maxValue = reading;
159*a55c953dSJosh Lehan         }
160*a55c953dSJosh Lehan 
161*a55c953dSJosh Lehan         return first;
162*a55c953dSJosh Lehan     }
163*a55c953dSJosh Lehan };
164*a55c953dSJosh Lehan 
165*a55c953dSJosh Lehan class IPMIStatsTable
166*a55c953dSJosh Lehan {
167*a55c953dSJosh Lehan   private:
168*a55c953dSJosh Lehan     std::vector<IPMIStatsEntry> entries;
169*a55c953dSJosh Lehan 
170*a55c953dSJosh Lehan   private:
171*a55c953dSJosh Lehan     void padEntries(size_t index)
172*a55c953dSJosh Lehan     {
173*a55c953dSJosh Lehan         char hexbuf[16];
174*a55c953dSJosh Lehan 
175*a55c953dSJosh Lehan         // Pad vector until entries[index] becomes a valid index
176*a55c953dSJosh Lehan         while (entries.size() <= index)
177*a55c953dSJosh Lehan         {
178*a55c953dSJosh Lehan             // As name not known yet, use human-readable hex as name
179*a55c953dSJosh Lehan             IPMIStatsEntry newEntry;
180*a55c953dSJosh Lehan             sprintf(hexbuf, "0x%02zX", entries.size());
181*a55c953dSJosh Lehan             newEntry.updateName(hexbuf);
182*a55c953dSJosh Lehan 
183*a55c953dSJosh Lehan             entries.push_back(std::move(newEntry));
184*a55c953dSJosh Lehan         }
185*a55c953dSJosh Lehan     }
186*a55c953dSJosh Lehan 
187*a55c953dSJosh Lehan   public:
188*a55c953dSJosh Lehan     void wipeTable(void)
189*a55c953dSJosh Lehan     {
190*a55c953dSJosh Lehan         entries.clear();
191*a55c953dSJosh Lehan     }
192*a55c953dSJosh Lehan 
193*a55c953dSJosh Lehan     const std::string& getName(size_t index)
194*a55c953dSJosh Lehan     {
195*a55c953dSJosh Lehan         padEntries(index);
196*a55c953dSJosh Lehan         return entries[index].getName();
197*a55c953dSJosh Lehan     }
198*a55c953dSJosh Lehan 
199*a55c953dSJosh Lehan     void updateName(size_t index, std::string_view name)
200*a55c953dSJosh Lehan     {
201*a55c953dSJosh Lehan         padEntries(index);
202*a55c953dSJosh Lehan         entries[index].updateName(name);
203*a55c953dSJosh Lehan     }
204*a55c953dSJosh Lehan 
205*a55c953dSJosh Lehan     bool updateReading(size_t index, double reading, int raw)
206*a55c953dSJosh Lehan     {
207*a55c953dSJosh Lehan         padEntries(index);
208*a55c953dSJosh Lehan         return entries[index].updateReading(reading, raw);
209*a55c953dSJosh Lehan     }
210*a55c953dSJosh Lehan };
211*a55c953dSJosh Lehan 
212*a55c953dSJosh Lehan // This object is global singleton, used from a variety of places
213*a55c953dSJosh Lehan inline IPMIStatsTable sdrStatsTable;
214*a55c953dSJosh Lehan 
215a8b5b26dSKuiying Wang uint16_t getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree);
216de54f486SWilly Tu 
217de54f486SWilly Tu bool getSensorNumMap(std::shared_ptr<SensorNumMap>& sensorNumMap);
218de54f486SWilly Tu } // namespace details
219de54f486SWilly Tu 
220de54f486SWilly Tu bool getSensorSubtree(SensorSubTree& subtree);
221de54f486SWilly Tu 
222de54f486SWilly Tu struct CmpStr
223de54f486SWilly Tu {
224de54f486SWilly Tu     bool operator()(const char* a, const char* b) const
225de54f486SWilly Tu     {
226de54f486SWilly Tu         return std::strcmp(a, b) < 0;
227de54f486SWilly Tu     }
228de54f486SWilly Tu };
229de54f486SWilly Tu 
230de54f486SWilly Tu enum class SensorTypeCodes : uint8_t
231de54f486SWilly Tu {
232de54f486SWilly Tu     reserved = 0x0,
233de54f486SWilly Tu     temperature = 0x1,
234de54f486SWilly Tu     voltage = 0x2,
235de54f486SWilly Tu     current = 0x3,
236de54f486SWilly Tu     fan = 0x4,
237de54f486SWilly Tu     other = 0xB,
238de54f486SWilly Tu };
239de54f486SWilly Tu 
240de54f486SWilly Tu const static boost::container::flat_map<const char*, SensorTypeCodes, CmpStr>
241de54f486SWilly Tu     sensorTypes{{{"temperature", SensorTypeCodes::temperature},
242de54f486SWilly Tu                  {"voltage", SensorTypeCodes::voltage},
243de54f486SWilly Tu                  {"current", SensorTypeCodes::current},
244de54f486SWilly Tu                  {"fan_tach", SensorTypeCodes::fan},
245de54f486SWilly Tu                  {"fan_pwm", SensorTypeCodes::fan},
246de54f486SWilly Tu                  {"power", SensorTypeCodes::other}}};
247de54f486SWilly Tu 
248de54f486SWilly Tu std::string getSensorTypeStringFromPath(const std::string& path);
249de54f486SWilly Tu 
250de54f486SWilly Tu uint8_t getSensorTypeFromPath(const std::string& path);
251de54f486SWilly Tu 
252de54f486SWilly Tu uint16_t getSensorNumberFromPath(const std::string& path);
253de54f486SWilly Tu 
254de54f486SWilly Tu uint8_t getSensorEventTypeFromPath(const std::string& path);
255de54f486SWilly Tu 
256de54f486SWilly Tu std::string getPathFromSensorNumber(uint16_t sensorNum);
257de54f486SWilly Tu 
258de54f486SWilly Tu namespace ipmi
259de54f486SWilly Tu {
260de54f486SWilly Tu std::map<std::string, std::vector<std::string>>
261de54f486SWilly Tu     getObjectInterfaces(const char* path);
262de54f486SWilly Tu 
263de54f486SWilly Tu std::map<std::string, Value> getEntityManagerProperties(const char* path,
264de54f486SWilly Tu                                                         const char* interface);
265de54f486SWilly Tu 
266de54f486SWilly Tu const std::string* getSensorConfigurationInterface(
267de54f486SWilly Tu     const std::map<std::string, std::vector<std::string>>&
268de54f486SWilly Tu         sensorInterfacesResponse);
269de54f486SWilly Tu 
270de54f486SWilly Tu void updateIpmiFromAssociation(const std::string& path,
271de54f486SWilly Tu                                const DbusInterfaceMap& sensorMap,
272de54f486SWilly Tu                                uint8_t& entityId, uint8_t& entityInstance);
273de54f486SWilly Tu } // namespace ipmi
274