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>
20fbc6c9d7SPatrick Williams #include <ipmid/api.hpp>
21fbc6c9d7SPatrick Williams #include <ipmid/types.hpp>
22fbc6c9d7SPatrick Williams #include <phosphor-logging/log.hpp>
23fbc6c9d7SPatrick Williams #include <sdbusplus/bus/match.hpp>
24fbc6c9d7SPatrick Williams 
25de54f486SWilly Tu #include <cstdio>
26de54f486SWilly Tu #include <cstring>
27de54f486SWilly Tu #include <exception>
28de54f486SWilly Tu #include <filesystem>
29de54f486SWilly Tu #include <map>
304eca2510SWilly Tu #include <optional>
31de54f486SWilly Tu #include <string>
324eca2510SWilly Tu #include <unordered_set>
33de54f486SWilly Tu #include <vector>
34de54f486SWilly Tu 
35de54f486SWilly Tu #pragma once
36de54f486SWilly Tu 
37de54f486SWilly Tu static constexpr bool debug = false;
38de54f486SWilly Tu 
39de54f486SWilly Tu struct CmpStrVersion
40de54f486SWilly Tu {
operator ()CmpStrVersion41de54f486SWilly Tu     bool operator()(std::string a, std::string b) const
42de54f486SWilly Tu     {
43de54f486SWilly Tu         return strverscmp(a.c_str(), b.c_str()) < 0;
44de54f486SWilly Tu     }
45de54f486SWilly Tu };
46de54f486SWilly Tu 
47de54f486SWilly Tu using SensorSubTree = boost::container::flat_map<
48de54f486SWilly Tu     std::string,
49de54f486SWilly Tu     boost::container::flat_map<std::string, std::vector<std::string>>,
50de54f486SWilly Tu     CmpStrVersion>;
51de54f486SWilly Tu 
52de54f486SWilly Tu using SensorNumMap = boost::bimap<int, std::string>;
53de54f486SWilly Tu 
54de54f486SWilly Tu static constexpr uint16_t maxSensorsPerLUN = 255;
55de54f486SWilly Tu static constexpr uint16_t maxIPMISensors = (maxSensorsPerLUN * 3);
56de54f486SWilly Tu static constexpr uint16_t lun1Sensor0 = 0x100;
57de54f486SWilly Tu static constexpr uint16_t lun3Sensor0 = 0x300;
58de54f486SWilly Tu static constexpr uint16_t invalidSensorNumber = 0xFFFF;
59de54f486SWilly Tu static constexpr uint8_t reservedSensorNumber = 0xFF;
60de54f486SWilly Tu 
61de54f486SWilly Tu namespace details
62de54f486SWilly Tu {
63a55c953dSJosh Lehan // Enable/disable the logging of stats instrumentation
64a55c953dSJosh Lehan static constexpr bool enableInstrumentation = false;
65a55c953dSJosh Lehan 
66a55c953dSJosh Lehan class IPMIStatsEntry
67a55c953dSJosh Lehan {
68a55c953dSJosh Lehan   private:
69a55c953dSJosh Lehan     int numReadings = 0;
70a55c953dSJosh Lehan     int numMissings = 0;
71a55c953dSJosh Lehan     int numStreakRead = 0;
72a55c953dSJosh Lehan     int numStreakMiss = 0;
73a55c953dSJosh Lehan     double minValue = 0.0;
74a55c953dSJosh Lehan     double maxValue = 0.0;
75a55c953dSJosh Lehan     std::string sensorName;
76a55c953dSJosh Lehan 
77a55c953dSJosh Lehan   public:
getName(void) const78a55c953dSJosh Lehan     const std::string& getName(void) const
79a55c953dSJosh Lehan     {
80a55c953dSJosh Lehan         return sensorName;
81a55c953dSJosh Lehan     }
82a55c953dSJosh Lehan 
updateName(std::string_view name)83a55c953dSJosh Lehan     void updateName(std::string_view name)
84a55c953dSJosh Lehan     {
85a55c953dSJosh Lehan         sensorName = name;
86a55c953dSJosh Lehan     }
87a55c953dSJosh Lehan 
88a55c953dSJosh Lehan     // Returns true if this is the first successful reading
89a55c953dSJosh Lehan     // This is so the caller can log the coefficients used
updateReading(double reading,int raw)90a55c953dSJosh Lehan     bool updateReading(double reading, int raw)
91a55c953dSJosh Lehan     {
92a55c953dSJosh Lehan         if constexpr (!enableInstrumentation)
93a55c953dSJosh Lehan         {
94a55c953dSJosh Lehan             return false;
95a55c953dSJosh Lehan         }
96a55c953dSJosh Lehan 
97a55c953dSJosh Lehan         bool first = ((numReadings == 0) && (numMissings == 0));
98a55c953dSJosh Lehan 
99a55c953dSJosh Lehan         // Sensors can use "nan" to indicate unavailable reading
100a55c953dSJosh Lehan         if (!(std::isfinite(reading)))
101a55c953dSJosh Lehan         {
102a55c953dSJosh Lehan             // Only show this if beginning a new streak
103a55c953dSJosh Lehan             if (numStreakMiss == 0)
104a55c953dSJosh Lehan             {
105a55c953dSJosh Lehan                 std::cerr << "IPMI sensor " << sensorName
106a55c953dSJosh Lehan                           << ": Missing reading, byte=" << raw
107a55c953dSJosh Lehan                           << ", Reading counts good=" << numReadings
108a55c953dSJosh Lehan                           << " miss=" << numMissings
109a55c953dSJosh Lehan                           << ", Prior good streak=" << numStreakRead << "\n";
110a55c953dSJosh Lehan             }
111a55c953dSJosh Lehan 
112a55c953dSJosh Lehan             numStreakRead = 0;
113a55c953dSJosh Lehan             ++numMissings;
114a55c953dSJosh Lehan             ++numStreakMiss;
115a55c953dSJosh Lehan 
116a55c953dSJosh Lehan             return first;
117a55c953dSJosh Lehan         }
118a55c953dSJosh Lehan 
119a55c953dSJosh Lehan         // Only show this if beginning a new streak and not the first time
120a55c953dSJosh Lehan         if ((numStreakRead == 0) && (numReadings != 0))
121a55c953dSJosh Lehan         {
122a55c953dSJosh Lehan             std::cerr << "IPMI sensor " << sensorName
123*1318a5edSPatrick Williams                       << ": Recovered reading, value=" << reading << " byte="
124*1318a5edSPatrick Williams                       << raw << ", Reading counts good=" << numReadings
125a55c953dSJosh Lehan                       << " miss=" << numMissings
126a55c953dSJosh Lehan                       << ", Prior miss streak=" << numStreakMiss << "\n";
127a55c953dSJosh Lehan         }
128a55c953dSJosh Lehan 
129a55c953dSJosh Lehan         // Initialize min/max if the first successful reading
130a55c953dSJosh Lehan         if (numReadings == 0)
131a55c953dSJosh Lehan         {
132a55c953dSJosh Lehan             std::cerr << "IPMI sensor " << sensorName
133a55c953dSJosh Lehan                       << ": First reading, value=" << reading << " byte=" << raw
134a55c953dSJosh Lehan                       << "\n";
135a55c953dSJosh Lehan 
136a55c953dSJosh Lehan             minValue = reading;
137a55c953dSJosh Lehan             maxValue = reading;
138a55c953dSJosh Lehan         }
139a55c953dSJosh Lehan 
140a55c953dSJosh Lehan         numStreakMiss = 0;
141a55c953dSJosh Lehan         ++numReadings;
142a55c953dSJosh Lehan         ++numStreakRead;
143a55c953dSJosh Lehan 
144a55c953dSJosh Lehan         // Only provide subsequent output if new min/max established
145a55c953dSJosh Lehan         if (reading < minValue)
146a55c953dSJosh Lehan         {
147a55c953dSJosh Lehan             std::cerr << "IPMI sensor " << sensorName
148a55c953dSJosh Lehan                       << ": Lowest reading, value=" << reading
149a55c953dSJosh Lehan                       << " byte=" << raw << "\n";
150a55c953dSJosh Lehan 
151a55c953dSJosh Lehan             minValue = reading;
152a55c953dSJosh Lehan         }
153a55c953dSJosh Lehan 
154a55c953dSJosh Lehan         if (reading > maxValue)
155a55c953dSJosh Lehan         {
156a55c953dSJosh Lehan             std::cerr << "IPMI sensor " << sensorName
157a55c953dSJosh Lehan                       << ": Highest reading, value=" << reading
158a55c953dSJosh Lehan                       << " byte=" << raw << "\n";
159a55c953dSJosh Lehan 
160a55c953dSJosh Lehan             maxValue = reading;
161a55c953dSJosh Lehan         }
162a55c953dSJosh Lehan 
163a55c953dSJosh Lehan         return first;
164a55c953dSJosh Lehan     }
165a55c953dSJosh Lehan };
166a55c953dSJosh Lehan 
167a55c953dSJosh Lehan class IPMIStatsTable
168a55c953dSJosh Lehan {
169a55c953dSJosh Lehan   private:
170a55c953dSJosh Lehan     std::vector<IPMIStatsEntry> entries;
171a55c953dSJosh Lehan 
172a55c953dSJosh Lehan   private:
padEntries(size_t index)173a55c953dSJosh Lehan     void padEntries(size_t index)
174a55c953dSJosh Lehan     {
175a55c953dSJosh Lehan         char hexbuf[16];
176a55c953dSJosh Lehan 
177a55c953dSJosh Lehan         // Pad vector until entries[index] becomes a valid index
178a55c953dSJosh Lehan         while (entries.size() <= index)
179a55c953dSJosh Lehan         {
180a55c953dSJosh Lehan             // As name not known yet, use human-readable hex as name
181a55c953dSJosh Lehan             IPMIStatsEntry newEntry;
182a55c953dSJosh Lehan             sprintf(hexbuf, "0x%02zX", entries.size());
183a55c953dSJosh Lehan             newEntry.updateName(hexbuf);
184a55c953dSJosh Lehan 
185a55c953dSJosh Lehan             entries.push_back(std::move(newEntry));
186a55c953dSJosh Lehan         }
187a55c953dSJosh Lehan     }
188a55c953dSJosh Lehan 
189a55c953dSJosh Lehan   public:
wipeTable(void)190a55c953dSJosh Lehan     void wipeTable(void)
191a55c953dSJosh Lehan     {
192a55c953dSJosh Lehan         entries.clear();
193a55c953dSJosh Lehan     }
194a55c953dSJosh Lehan 
getName(size_t index)195a55c953dSJosh Lehan     const std::string& getName(size_t index)
196a55c953dSJosh Lehan     {
197a55c953dSJosh Lehan         padEntries(index);
198a55c953dSJosh Lehan         return entries[index].getName();
199a55c953dSJosh Lehan     }
200a55c953dSJosh Lehan 
updateName(size_t index,std::string_view name)201a55c953dSJosh Lehan     void updateName(size_t index, std::string_view name)
202a55c953dSJosh Lehan     {
203a55c953dSJosh Lehan         padEntries(index);
204a55c953dSJosh Lehan         entries[index].updateName(name);
205a55c953dSJosh Lehan     }
206a55c953dSJosh Lehan 
updateReading(size_t index,double reading,int raw)207a55c953dSJosh Lehan     bool updateReading(size_t index, double reading, int raw)
208a55c953dSJosh Lehan     {
209a55c953dSJosh Lehan         padEntries(index);
210a55c953dSJosh Lehan         return entries[index].updateReading(reading, raw);
211a55c953dSJosh Lehan     }
212a55c953dSJosh Lehan };
213a55c953dSJosh Lehan 
214f0a89946SJie Yang class IPMIWriteEntry
215f0a89946SJie Yang {
216f0a89946SJie Yang   private:
217f0a89946SJie Yang     bool writePermission = false;
218f0a89946SJie Yang 
219f0a89946SJie Yang   public:
getWritePermission(void) const220f0a89946SJie Yang     bool getWritePermission(void) const
221f0a89946SJie Yang     {
222f0a89946SJie Yang         return writePermission;
223f0a89946SJie Yang     }
224f0a89946SJie Yang 
setWritePermission(bool permission)225f0a89946SJie Yang     void setWritePermission(bool permission)
226f0a89946SJie Yang     {
227f0a89946SJie Yang         writePermission = permission;
228f0a89946SJie Yang     }
229f0a89946SJie Yang };
230f0a89946SJie Yang 
231f0a89946SJie Yang class IPMIWriteTable
232f0a89946SJie Yang {
233f0a89946SJie Yang   private:
234f0a89946SJie Yang     std::vector<IPMIWriteEntry> entries;
235f0a89946SJie Yang 
236f0a89946SJie Yang   private:
padEntries(size_t index)237f0a89946SJie Yang     void padEntries(size_t index)
238f0a89946SJie Yang     {
239f0a89946SJie Yang         // Pad vector until entries[index] becomes a valid index
240f0a89946SJie Yang         if (entries.size() <= index)
241f0a89946SJie Yang         {
242f0a89946SJie Yang             entries.resize(index + 1);
243f0a89946SJie Yang         }
244f0a89946SJie Yang     }
245f0a89946SJie Yang 
246f0a89946SJie Yang   public:
wipeTable(void)247f0a89946SJie Yang     void wipeTable(void)
248f0a89946SJie Yang     {
249f0a89946SJie Yang         entries.clear();
250f0a89946SJie Yang     }
251f0a89946SJie Yang 
getWritePermission(size_t index)252f0a89946SJie Yang     bool getWritePermission(size_t index)
253f0a89946SJie Yang     {
254f0a89946SJie Yang         padEntries(index);
255f0a89946SJie Yang         return entries[index].getWritePermission();
256f0a89946SJie Yang     }
257f0a89946SJie Yang 
setWritePermission(size_t index,bool permission)258f0a89946SJie Yang     void setWritePermission(size_t index, bool permission)
259f0a89946SJie Yang     {
260f0a89946SJie Yang         padEntries(index);
261f0a89946SJie Yang         entries[index].setWritePermission(permission);
262f0a89946SJie Yang     }
263f0a89946SJie Yang };
264f0a89946SJie Yang 
265d2afd054SHao Jiang // Store information for threshold sensors and they are not used by VR
266d2afd054SHao Jiang // sensors. These objects are global singletons, used from a variety of places.
267a55c953dSJosh Lehan inline IPMIStatsTable sdrStatsTable;
268f0a89946SJie Yang inline IPMIWriteTable sdrWriteTable;
269a55c953dSJosh Lehan 
2709a5b51e3SHao Jiang /**
2719a5b51e3SHao Jiang  * Search ObjectMapper for sensors and update them to subtree.
2729a5b51e3SHao Jiang  *
2739a5b51e3SHao Jiang  * The function will search for sensors under either
2749a5b51e3SHao Jiang  * /xyz/openbmc_project/sensors or /xyz/openbmc_project/extsensors. It will
2759a5b51e3SHao Jiang  * optionally search VR typed sensors under /xyz/openbmc_project/vr
2769a5b51e3SHao Jiang  *
2779a5b51e3SHao Jiang  * @return the updated amount of times any of "sensors" or "extsensors" sensor
2789a5b51e3SHao Jiang  * paths updated successfully, previous amount if all failed. The "vr"
2799a5b51e3SHao Jiang  * sensor path is optional, and does not participate in the return value.
2809a5b51e3SHao Jiang  */
281a8b5b26dSKuiying Wang uint16_t getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree);
282de54f486SWilly Tu 
283de54f486SWilly Tu bool getSensorNumMap(std::shared_ptr<SensorNumMap>& sensorNumMap);
284de54f486SWilly Tu } // namespace details
285de54f486SWilly Tu 
286de54f486SWilly Tu bool getSensorSubtree(SensorSubTree& subtree);
287de54f486SWilly Tu 
2882703b029SScron Chang #ifdef FEATURE_HYBRID_SENSORS
2892703b029SScron Chang ipmi::sensor::IdInfoMap::const_iterator
2902703b029SScron Chang     findStaticSensor(const std::string& path);
2912703b029SScron Chang #endif
2922703b029SScron Chang 
293de54f486SWilly Tu struct CmpStr
294de54f486SWilly Tu {
operator ()CmpStr295de54f486SWilly Tu     bool operator()(const char* a, const char* b) const
296de54f486SWilly Tu     {
297de54f486SWilly Tu         return std::strcmp(a, b) < 0;
298de54f486SWilly Tu     }
299de54f486SWilly Tu };
300de54f486SWilly Tu 
3012b42d7eeSScron Chang static constexpr size_t sensorTypeCodes = 0;
3022b42d7eeSScron Chang static constexpr size_t sensorEventTypeCodes = 1;
3032b42d7eeSScron Chang 
304de54f486SWilly Tu enum class SensorTypeCodes : uint8_t
305de54f486SWilly Tu {
306604e0c67SDavid Wang     reserved = 0x00,
307604e0c67SDavid Wang     temperature = 0x01,
308604e0c67SDavid Wang     voltage = 0x02,
309604e0c67SDavid Wang     current = 0x03,
310604e0c67SDavid Wang     fan = 0x04,
311d7c26017SJoseph Fu     physical_security = 0x5,
312604e0c67SDavid Wang     processor = 0x07,
313b8e5b164SScron Chang     power_unit = 0x09,
314604e0c67SDavid Wang     other = 0x0b,
315604e0c67SDavid Wang     memory = 0x0c,
316b8e5b164SScron Chang     buttons = 0x14,
317b8e5b164SScron Chang     watchdog2 = 0x23,
318363d8d52SDuke Du     entity = 0x25,
31934d19736SJohnathan Mantey     oemC0 = 0xc0,
320de54f486SWilly Tu };
321de54f486SWilly Tu 
3222b42d7eeSScron Chang enum class SensorEventTypeCodes : uint8_t
3232b42d7eeSScron Chang {
3242b42d7eeSScron Chang     unspecified = 0x00,
3252b42d7eeSScron Chang     threshold = 0x01,
3262b42d7eeSScron Chang     sensorSpecified = 0x6f
3272b42d7eeSScron Chang };
3282b42d7eeSScron Chang 
32934d19736SJohnathan Mantey extern boost::container::flat_map<
3302b42d7eeSScron Chang     const char*, std::pair<SensorTypeCodes, SensorEventTypeCodes>, CmpStr>
33134d19736SJohnathan Mantey     sensorTypes;
33234d19736SJohnathan Mantey 
333de54f486SWilly Tu std::string getSensorTypeStringFromPath(const std::string& path);
334de54f486SWilly Tu 
335de54f486SWilly Tu uint8_t getSensorTypeFromPath(const std::string& path);
336de54f486SWilly Tu 
337de54f486SWilly Tu uint16_t getSensorNumberFromPath(const std::string& path);
338de54f486SWilly Tu 
339de54f486SWilly Tu uint8_t getSensorEventTypeFromPath(const std::string& path);
340de54f486SWilly Tu 
341de54f486SWilly Tu std::string getPathFromSensorNumber(uint16_t sensorNum);
342de54f486SWilly Tu 
343de54f486SWilly Tu namespace ipmi
344de54f486SWilly Tu {
3458fb5b89aSAlexander Hansen std::optional<std::map<std::string, std::vector<std::string>>>
346de54f486SWilly Tu     getObjectInterfaces(const char* path);
347de54f486SWilly Tu 
348*1318a5edSPatrick Williams std::map<std::string, Value>
349*1318a5edSPatrick Williams     getEntityManagerProperties(const char* path, const char* interface);
350de54f486SWilly Tu 
3514eca2510SWilly Tu std::optional<std::unordered_set<std::string>>&
3524eca2510SWilly Tu     getIpmiDecoratorPaths(const std::optional<ipmi::Context::ptr>& ctx);
3534eca2510SWilly Tu 
354de54f486SWilly Tu const std::string* getSensorConfigurationInterface(
355de54f486SWilly Tu     const std::map<std::string, std::vector<std::string>>&
356de54f486SWilly Tu         sensorInterfacesResponse);
357de54f486SWilly Tu 
3584eca2510SWilly Tu void updateIpmiFromAssociation(
3594eca2510SWilly Tu     const std::string& path,
3604eca2510SWilly Tu     const std::unordered_set<std::string>& ipmiDecoratorPaths,
3614eca2510SWilly Tu     const DbusInterfaceMap& sensorMap, uint8_t& entityId,
3624eca2510SWilly Tu     uint8_t& entityInstance);
363de54f486SWilly Tu } // namespace ipmi
364