13f7c5e40SJason M. Bills /*
23f7c5e40SJason M. Bills // Copyright (c) 2018 Intel Corporation
33f7c5e40SJason M. Bills //
43f7c5e40SJason M. Bills // Licensed under the Apache License, Version 2.0 (the "License");
53f7c5e40SJason M. Bills // you may not use this file except in compliance with the License.
63f7c5e40SJason M. Bills // You may obtain a copy of the License at
73f7c5e40SJason M. Bills //
83f7c5e40SJason M. Bills // http://www.apache.org/licenses/LICENSE-2.0
93f7c5e40SJason M. Bills //
103f7c5e40SJason M. Bills // Unless required by applicable law or agreed to in writing, software
113f7c5e40SJason M. Bills // distributed under the License is distributed on an "AS IS" BASIS,
123f7c5e40SJason M. Bills // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133f7c5e40SJason M. Bills // See the License for the specific language governing permissions and
143f7c5e40SJason M. Bills // limitations under the License.
153f7c5e40SJason M. Bills */
163f7c5e40SJason M. Bills
17262276f4SPatrick Venture #include "commandutils.hpp"
18c2a07d4bSPatrick Venture #include "types.hpp"
19262276f4SPatrick Venture
203f7c5e40SJason M. Bills #include <boost/algorithm/string.hpp>
21a9423b6eSJason M. Bills #include <boost/bimap.hpp>
223f7c5e40SJason M. Bills #include <boost/container/flat_map.hpp>
23fcd2d3a9SJames Feist #include <phosphor-logging/log.hpp>
24fcd2d3a9SJames Feist #include <sdbusplus/bus/match.hpp>
25fcd2d3a9SJames Feist
26262276f4SPatrick Venture #include <cstdio>
273f7c5e40SJason M. Bills #include <cstring>
28262276f4SPatrick Venture #include <exception>
29262276f4SPatrick Venture #include <filesystem>
30262276f4SPatrick Venture #include <map>
31262276f4SPatrick Venture #include <string>
3206aa21abSJosh Lehan #include <string_view>
33262276f4SPatrick Venture #include <vector>
343f7c5e40SJason M. Bills
353f7c5e40SJason M. Bills #pragma once
363f7c5e40SJason M. Bills
373f7c5e40SJason M. Bills struct CmpStrVersion
383f7c5e40SJason M. Bills {
operator ()CmpStrVersion393f7c5e40SJason M. Bills bool operator()(std::string a, std::string b) const
403f7c5e40SJason M. Bills {
413f7c5e40SJason M. Bills return strverscmp(a.c_str(), b.c_str()) < 0;
423f7c5e40SJason M. Bills }
433f7c5e40SJason M. Bills };
443f7c5e40SJason M. Bills
453f7c5e40SJason M. Bills using SensorSubTree = boost::container::flat_map<
463f7c5e40SJason M. Bills std::string,
473f7c5e40SJason M. Bills boost::container::flat_map<std::string, std::vector<std::string>>,
483f7c5e40SJason M. Bills CmpStrVersion>;
493f7c5e40SJason M. Bills
50a9423b6eSJason M. Bills using SensorNumMap = boost::bimap<int, std::string>;
51a9423b6eSJason M. Bills
52308c3a8bSJohnathan Mantey static constexpr uint16_t maxSensorsPerLUN = 255;
53308c3a8bSJohnathan Mantey static constexpr uint16_t maxIPMISensors = (maxSensorsPerLUN * 3);
54308c3a8bSJohnathan Mantey static constexpr uint16_t lun1Sensor0 = 0x100;
55308c3a8bSJohnathan Mantey static constexpr uint16_t lun3Sensor0 = 0x300;
56308c3a8bSJohnathan Mantey static constexpr uint16_t invalidSensorNumber = 0xFFFF;
57308c3a8bSJohnathan Mantey static constexpr uint8_t reservedSensorNumber = 0xFF;
58308c3a8bSJohnathan Mantey
59a9423b6eSJason M. Bills namespace details
603f7c5e40SJason M. Bills {
6106aa21abSJosh Lehan
6206aa21abSJosh Lehan // Enable/disable the logging of stats instrumentation
6306aa21abSJosh Lehan static constexpr bool enableInstrumentation = false;
6406aa21abSJosh Lehan
6506aa21abSJosh Lehan class IPMIStatsEntry
6606aa21abSJosh Lehan {
6706aa21abSJosh Lehan private:
6806aa21abSJosh Lehan int numReadings = 0;
6906aa21abSJosh Lehan int numMissings = 0;
7006aa21abSJosh Lehan int numStreakRead = 0;
7106aa21abSJosh Lehan int numStreakMiss = 0;
7206aa21abSJosh Lehan double minValue = 0.0;
7306aa21abSJosh Lehan double maxValue = 0.0;
7406aa21abSJosh Lehan std::string sensorName;
7506aa21abSJosh Lehan
7606aa21abSJosh Lehan public:
getName(void) const7706aa21abSJosh Lehan const std::string& getName(void) const
7806aa21abSJosh Lehan {
7906aa21abSJosh Lehan return sensorName;
8006aa21abSJosh Lehan }
8106aa21abSJosh Lehan
updateName(std::string_view name)8206aa21abSJosh Lehan void updateName(std::string_view name)
8306aa21abSJosh Lehan {
8406aa21abSJosh Lehan sensorName = name;
8506aa21abSJosh Lehan }
8606aa21abSJosh Lehan
8706aa21abSJosh Lehan // Returns true if this is the first successful reading
8806aa21abSJosh Lehan // This is so the caller can log the coefficients used
updateReading(double reading,int raw)8906aa21abSJosh Lehan bool updateReading(double reading, int raw)
9006aa21abSJosh Lehan {
9106aa21abSJosh Lehan if constexpr (!enableInstrumentation)
9206aa21abSJosh Lehan {
9306aa21abSJosh Lehan return false;
9406aa21abSJosh Lehan }
9506aa21abSJosh Lehan
9606aa21abSJosh Lehan bool first = ((numReadings == 0) && (numMissings == 0));
9706aa21abSJosh Lehan
9806aa21abSJosh Lehan // Sensors can use "nan" to indicate unavailable reading
9906aa21abSJosh Lehan if (!(std::isfinite(reading)))
10006aa21abSJosh Lehan {
10106aa21abSJosh Lehan // Only show this if beginning a new streak
10206aa21abSJosh Lehan if (numStreakMiss == 0)
10306aa21abSJosh Lehan {
10406aa21abSJosh Lehan std::cerr << "IPMI sensor " << sensorName
10506aa21abSJosh Lehan << ": Missing reading, byte=" << raw
10606aa21abSJosh Lehan << ", Reading counts good=" << numReadings
10706aa21abSJosh Lehan << " miss=" << numMissings
10806aa21abSJosh Lehan << ", Prior good streak=" << numStreakRead << "\n";
10906aa21abSJosh Lehan }
11006aa21abSJosh Lehan
11106aa21abSJosh Lehan numStreakRead = 0;
11206aa21abSJosh Lehan ++numMissings;
11306aa21abSJosh Lehan ++numStreakMiss;
11406aa21abSJosh Lehan
11506aa21abSJosh Lehan return first;
11606aa21abSJosh Lehan }
11706aa21abSJosh Lehan
11806aa21abSJosh Lehan // Only show this if beginning a new streak and not the first time
11906aa21abSJosh Lehan if ((numStreakRead == 0) && (numReadings != 0))
12006aa21abSJosh Lehan {
12106aa21abSJosh Lehan std::cerr << "IPMI sensor " << sensorName
122*1bcced08SPatrick Williams << ": Recovered reading, value=" << reading << " byte="
123*1bcced08SPatrick Williams << raw << ", Reading counts good=" << numReadings
12406aa21abSJosh Lehan << " miss=" << numMissings
12506aa21abSJosh Lehan << ", Prior miss streak=" << numStreakMiss << "\n";
12606aa21abSJosh Lehan }
12706aa21abSJosh Lehan
12806aa21abSJosh Lehan // Initialize min/max if the first successful reading
12906aa21abSJosh Lehan if (numReadings == 0)
13006aa21abSJosh Lehan {
13106aa21abSJosh Lehan std::cerr << "IPMI sensor " << sensorName
13206aa21abSJosh Lehan << ": First reading, value=" << reading << " byte=" << raw
13306aa21abSJosh Lehan << "\n";
13406aa21abSJosh Lehan
13506aa21abSJosh Lehan minValue = reading;
13606aa21abSJosh Lehan maxValue = reading;
13706aa21abSJosh Lehan }
13806aa21abSJosh Lehan
13906aa21abSJosh Lehan numStreakMiss = 0;
14006aa21abSJosh Lehan ++numReadings;
14106aa21abSJosh Lehan ++numStreakRead;
14206aa21abSJosh Lehan
14306aa21abSJosh Lehan // Only provide subsequent output if new min/max established
14406aa21abSJosh Lehan if (reading < minValue)
14506aa21abSJosh Lehan {
14606aa21abSJosh Lehan std::cerr << "IPMI sensor " << sensorName
14706aa21abSJosh Lehan << ": Lowest reading, value=" << reading
14806aa21abSJosh Lehan << " byte=" << raw << "\n";
14906aa21abSJosh Lehan
15006aa21abSJosh Lehan minValue = reading;
15106aa21abSJosh Lehan }
15206aa21abSJosh Lehan
15306aa21abSJosh Lehan if (reading > maxValue)
15406aa21abSJosh Lehan {
15506aa21abSJosh Lehan std::cerr << "IPMI sensor " << sensorName
15606aa21abSJosh Lehan << ": Highest reading, value=" << reading
15706aa21abSJosh Lehan << " byte=" << raw << "\n";
15806aa21abSJosh Lehan
15906aa21abSJosh Lehan maxValue = reading;
16006aa21abSJosh Lehan }
16106aa21abSJosh Lehan
16206aa21abSJosh Lehan return first;
16306aa21abSJosh Lehan }
16406aa21abSJosh Lehan };
16506aa21abSJosh Lehan
16606aa21abSJosh Lehan class IPMIStatsTable
16706aa21abSJosh Lehan {
16806aa21abSJosh Lehan private:
16906aa21abSJosh Lehan std::vector<IPMIStatsEntry> entries;
17006aa21abSJosh Lehan
17106aa21abSJosh Lehan private:
padEntries(size_t index)17206aa21abSJosh Lehan void padEntries(size_t index)
17306aa21abSJosh Lehan {
17406aa21abSJosh Lehan char hexbuf[16];
17506aa21abSJosh Lehan
17606aa21abSJosh Lehan // Pad vector until entries[index] becomes a valid index
17706aa21abSJosh Lehan while (entries.size() <= index)
17806aa21abSJosh Lehan {
17906aa21abSJosh Lehan // As name not known yet, use human-readable hex as name
18006aa21abSJosh Lehan IPMIStatsEntry newEntry;
18106aa21abSJosh Lehan sprintf(hexbuf, "0x%02zX", entries.size());
18206aa21abSJosh Lehan newEntry.updateName(hexbuf);
18306aa21abSJosh Lehan
18406aa21abSJosh Lehan entries.push_back(std::move(newEntry));
18506aa21abSJosh Lehan }
18606aa21abSJosh Lehan }
18706aa21abSJosh Lehan
18806aa21abSJosh Lehan public:
wipeTable(void)18906aa21abSJosh Lehan void wipeTable(void)
19006aa21abSJosh Lehan {
19106aa21abSJosh Lehan entries.clear();
19206aa21abSJosh Lehan }
19306aa21abSJosh Lehan
getName(size_t index)19406aa21abSJosh Lehan const std::string& getName(size_t index)
19506aa21abSJosh Lehan {
19606aa21abSJosh Lehan padEntries(index);
19706aa21abSJosh Lehan return entries[index].getName();
19806aa21abSJosh Lehan }
19906aa21abSJosh Lehan
updateName(size_t index,std::string_view name)20006aa21abSJosh Lehan void updateName(size_t index, std::string_view name)
20106aa21abSJosh Lehan {
20206aa21abSJosh Lehan padEntries(index);
20306aa21abSJosh Lehan entries[index].updateName(name);
20406aa21abSJosh Lehan }
20506aa21abSJosh Lehan
updateReading(size_t index,double reading,int raw)20606aa21abSJosh Lehan bool updateReading(size_t index, double reading, int raw)
20706aa21abSJosh Lehan {
20806aa21abSJosh Lehan padEntries(index);
20906aa21abSJosh Lehan return entries[index].updateReading(reading, raw);
21006aa21abSJosh Lehan }
21106aa21abSJosh Lehan };
21206aa21abSJosh Lehan
21306aa21abSJosh Lehan // This object is global singleton, used from a variety of places
21406aa21abSJosh Lehan inline IPMIStatsTable sdrStatsTable;
21506aa21abSJosh Lehan
getSensorSubtree(std::shared_ptr<SensorSubTree> & subtree)21617eadbfbSKuiying Wang inline static uint16_t getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree)
217a9423b6eSJason M. Bills {
218a9423b6eSJason M. Bills static std::shared_ptr<SensorSubTree> sensorTreePtr;
21917eadbfbSKuiying Wang static uint16_t sensorUpdatedIndex = 0;
2203f7c5e40SJason M. Bills sd_bus* bus = NULL;
2213f7c5e40SJason M. Bills int ret = sd_bus_default_system(&bus);
2223f7c5e40SJason M. Bills if (ret < 0)
2233f7c5e40SJason M. Bills {
2243f7c5e40SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(
2253f7c5e40SJason M. Bills "Failed to connect to system bus",
2263f7c5e40SJason M. Bills phosphor::logging::entry("ERRNO=0x%X", -ret));
2273f7c5e40SJason M. Bills sd_bus_unref(bus);
22817eadbfbSKuiying Wang return sensorUpdatedIndex;
2293f7c5e40SJason M. Bills }
230f944d2e5SPatrick Williams sdbusplus::bus_t dbus(bus);
231f944d2e5SPatrick Williams static sdbusplus::bus::match_t sensorAdded(
232a9423b6eSJason M. Bills dbus,
233a9423b6eSJason M. Bills "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
234a9423b6eSJason M. Bills "sensors/'",
235dcff1506SVernon Mauery [](sdbusplus::message_t&) { sensorTreePtr.reset(); });
236a9423b6eSJason M. Bills
237f944d2e5SPatrick Williams static sdbusplus::bus::match_t sensorRemoved(
238a9423b6eSJason M. Bills dbus,
239a9423b6eSJason M. Bills "type='signal',member='InterfacesRemoved',arg0path='/xyz/"
240a9423b6eSJason M. Bills "openbmc_project/sensors/'",
241dcff1506SVernon Mauery [](sdbusplus::message_t&) { sensorTreePtr.reset(); });
242a9423b6eSJason M. Bills
243a9423b6eSJason M. Bills if (sensorTreePtr)
244a9423b6eSJason M. Bills {
245a9423b6eSJason M. Bills subtree = sensorTreePtr;
24617eadbfbSKuiying Wang return sensorUpdatedIndex;
247a9423b6eSJason M. Bills }
248a9423b6eSJason M. Bills
249a9423b6eSJason M. Bills sensorTreePtr = std::make_shared<SensorSubTree>();
250a9423b6eSJason M. Bills
251*1bcced08SPatrick Williams auto mapperCall =
252*1bcced08SPatrick Williams dbus.new_method_call("xyz.openbmc_project.ObjectMapper",
2533f7c5e40SJason M. Bills "/xyz/openbmc_project/object_mapper",
254*1bcced08SPatrick Williams "xyz.openbmc_project.ObjectMapper", "GetSubTree");
25552341e85SJason M. Bills static constexpr const auto depth = 2;
2563f7c5e40SJason M. Bills static constexpr std::array<const char*, 3> interfaces = {
2573f7c5e40SJason M. Bills "xyz.openbmc_project.Sensor.Value",
2583f7c5e40SJason M. Bills "xyz.openbmc_project.Sensor.Threshold.Warning",
2593f7c5e40SJason M. Bills "xyz.openbmc_project.Sensor.Threshold.Critical"};
2603f7c5e40SJason M. Bills mapperCall.append("/xyz/openbmc_project/sensors", depth, interfaces);
2613f7c5e40SJason M. Bills
2623f7c5e40SJason M. Bills try
2633f7c5e40SJason M. Bills {
2643f7c5e40SJason M. Bills auto mapperReply = dbus.call(mapperCall);
265a9423b6eSJason M. Bills mapperReply.read(*sensorTreePtr);
2663f7c5e40SJason M. Bills }
267bd51e6a9SPatrick Williams catch (const sdbusplus::exception_t& e)
2683f7c5e40SJason M. Bills {
26952341e85SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
27017eadbfbSKuiying Wang return sensorUpdatedIndex;
271a9423b6eSJason M. Bills }
272a9423b6eSJason M. Bills subtree = sensorTreePtr;
27317eadbfbSKuiying Wang sensorUpdatedIndex++;
27406aa21abSJosh Lehan // The SDR is being regenerated, wipe the old stats
27506aa21abSJosh Lehan sdrStatsTable.wipeTable();
27617eadbfbSKuiying Wang return sensorUpdatedIndex;
277a9423b6eSJason M. Bills }
278a9423b6eSJason M. Bills
getSensorNumMap(std::shared_ptr<SensorNumMap> & sensorNumMap)279a9423b6eSJason M. Bills inline static bool getSensorNumMap(std::shared_ptr<SensorNumMap>& sensorNumMap)
280a9423b6eSJason M. Bills {
281a9423b6eSJason M. Bills static std::shared_ptr<SensorNumMap> sensorNumMapPtr;
282a9423b6eSJason M. Bills bool sensorNumMapUpated = false;
28317eadbfbSKuiying Wang static uint16_t prevSensorUpdatedIndex = 0;
284a9423b6eSJason M. Bills std::shared_ptr<SensorSubTree> sensorTree;
28517eadbfbSKuiying Wang uint16_t curSensorUpdatedIndex = details::getSensorSubtree(sensorTree);
286a9423b6eSJason M. Bills if (!sensorTree)
287a9423b6eSJason M. Bills {
288a9423b6eSJason M. Bills return sensorNumMapUpated;
289a9423b6eSJason M. Bills }
290a9423b6eSJason M. Bills
29117eadbfbSKuiying Wang if ((curSensorUpdatedIndex == prevSensorUpdatedIndex) && sensorNumMapPtr)
292a9423b6eSJason M. Bills {
293a9423b6eSJason M. Bills sensorNumMap = sensorNumMapPtr;
294a9423b6eSJason M. Bills return sensorNumMapUpated;
295a9423b6eSJason M. Bills }
29617eadbfbSKuiying Wang prevSensorUpdatedIndex = curSensorUpdatedIndex;
297a9423b6eSJason M. Bills
298a9423b6eSJason M. Bills sensorNumMapPtr = std::make_shared<SensorNumMap>();
299a9423b6eSJason M. Bills
300308c3a8bSJohnathan Mantey uint16_t sensorNum = 0;
301308c3a8bSJohnathan Mantey uint16_t sensorIndex = 0;
302a9423b6eSJason M. Bills for (const auto& sensor : *sensorTree)
303a9423b6eSJason M. Bills {
304a9423b6eSJason M. Bills sensorNumMapPtr->insert(
305308c3a8bSJohnathan Mantey SensorNumMap::value_type(sensorNum, sensor.first));
306308c3a8bSJohnathan Mantey sensorIndex++;
307308c3a8bSJohnathan Mantey if (sensorIndex == maxSensorsPerLUN)
308308c3a8bSJohnathan Mantey {
309308c3a8bSJohnathan Mantey sensorIndex = lun1Sensor0;
310308c3a8bSJohnathan Mantey }
311308c3a8bSJohnathan Mantey else if (sensorIndex == (lun1Sensor0 | maxSensorsPerLUN))
312308c3a8bSJohnathan Mantey {
313308c3a8bSJohnathan Mantey // Skip assigning LUN 0x2 any sensors
314308c3a8bSJohnathan Mantey sensorIndex = lun3Sensor0;
315308c3a8bSJohnathan Mantey }
316308c3a8bSJohnathan Mantey else if (sensorIndex == (lun3Sensor0 | maxSensorsPerLUN))
317308c3a8bSJohnathan Mantey {
318308c3a8bSJohnathan Mantey // this is an error, too many IPMI sensors
319308c3a8bSJohnathan Mantey throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
320308c3a8bSJohnathan Mantey }
321308c3a8bSJohnathan Mantey sensorNum = sensorIndex;
322a9423b6eSJason M. Bills }
323a9423b6eSJason M. Bills sensorNumMap = sensorNumMapPtr;
324a9423b6eSJason M. Bills sensorNumMapUpated = true;
325a9423b6eSJason M. Bills return sensorNumMapUpated;
326a9423b6eSJason M. Bills }
327a9423b6eSJason M. Bills } // namespace details
328a9423b6eSJason M. Bills
getSensorSubtree(SensorSubTree & subtree)329a9423b6eSJason M. Bills inline static bool getSensorSubtree(SensorSubTree& subtree)
330a9423b6eSJason M. Bills {
331a9423b6eSJason M. Bills std::shared_ptr<SensorSubTree> sensorTree;
332a9423b6eSJason M. Bills details::getSensorSubtree(sensorTree);
333a9423b6eSJason M. Bills if (!sensorTree)
334a9423b6eSJason M. Bills {
3353f7c5e40SJason M. Bills return false;
3363f7c5e40SJason M. Bills }
337a9423b6eSJason M. Bills
338a9423b6eSJason M. Bills subtree = *sensorTree;
3393f7c5e40SJason M. Bills return true;
3403f7c5e40SJason M. Bills }
3413f7c5e40SJason M. Bills
3423f7c5e40SJason M. Bills struct CmpStr
3433f7c5e40SJason M. Bills {
operator ()CmpStr3443f7c5e40SJason M. Bills bool operator()(const char* a, const char* b) const
3453f7c5e40SJason M. Bills {
3463f7c5e40SJason M. Bills return std::strcmp(a, b) < 0;
3473f7c5e40SJason M. Bills }
3483f7c5e40SJason M. Bills };
3493f7c5e40SJason M. Bills
35052341e85SJason M. Bills enum class SensorTypeCodes : uint8_t
35152341e85SJason M. Bills {
35252341e85SJason M. Bills reserved = 0x0,
35352341e85SJason M. Bills temperature = 0x1,
35452341e85SJason M. Bills voltage = 0x2,
35552341e85SJason M. Bills current = 0x3,
35652341e85SJason M. Bills fan = 0x4,
35752341e85SJason M. Bills other = 0xB,
35852341e85SJason M. Bills };
35952341e85SJason M. Bills
3603f7c5e40SJason M. Bills const static boost::container::flat_map<const char*, SensorTypeCodes, CmpStr>
3613f7c5e40SJason M. Bills sensorTypes{{{"temperature", SensorTypeCodes::temperature},
3623f7c5e40SJason M. Bills {"voltage", SensorTypeCodes::voltage},
3633f7c5e40SJason M. Bills {"current", SensorTypeCodes::current},
3643f7c5e40SJason M. Bills {"fan_tach", SensorTypeCodes::fan},
365f426f334SJames Feist {"fan_pwm", SensorTypeCodes::fan},
3663f7c5e40SJason M. Bills {"power", SensorTypeCodes::other}}};
3673f7c5e40SJason M. Bills
getSensorTypeStringFromPath(const std::string & path)3683f7c5e40SJason M. Bills inline static std::string getSensorTypeStringFromPath(const std::string& path)
3693f7c5e40SJason M. Bills {
3703f7c5e40SJason M. Bills // get sensor type string from path, path is defined as
3713f7c5e40SJason M. Bills // /xyz/openbmc_project/sensors/<type>/label
3723f7c5e40SJason M. Bills size_t typeEnd = path.rfind("/");
373360f593bSJason M. Bills if (typeEnd == std::string::npos)
3743f7c5e40SJason M. Bills {
3753f7c5e40SJason M. Bills return path;
3763f7c5e40SJason M. Bills }
377360f593bSJason M. Bills size_t typeStart = path.rfind("/", typeEnd - 1);
378360f593bSJason M. Bills if (typeStart == std::string::npos)
379360f593bSJason M. Bills {
380360f593bSJason M. Bills return path;
381360f593bSJason M. Bills }
382360f593bSJason M. Bills // Start at the character after the '/'
383360f593bSJason M. Bills typeStart++;
384360f593bSJason M. Bills return path.substr(typeStart, typeEnd - typeStart);
385360f593bSJason M. Bills }
3863f7c5e40SJason M. Bills
getSensorTypeFromPath(const std::string & path)3873f7c5e40SJason M. Bills inline static uint8_t getSensorTypeFromPath(const std::string& path)
3883f7c5e40SJason M. Bills {
3893f7c5e40SJason M. Bills uint8_t sensorType = 0;
3903f7c5e40SJason M. Bills std::string type = getSensorTypeStringFromPath(path);
3913f7c5e40SJason M. Bills auto findSensor = sensorTypes.find(type.c_str());
3923f7c5e40SJason M. Bills if (findSensor != sensorTypes.end())
3933f7c5e40SJason M. Bills {
3943f7c5e40SJason M. Bills sensorType = static_cast<uint8_t>(findSensor->second);
3953f7c5e40SJason M. Bills } // else default 0x0 RESERVED
3963f7c5e40SJason M. Bills
3973f7c5e40SJason M. Bills return sensorType;
3983f7c5e40SJason M. Bills }
3993f7c5e40SJason M. Bills
getSensorNumberFromPath(const std::string & path)400308c3a8bSJohnathan Mantey inline static uint16_t getSensorNumberFromPath(const std::string& path)
4013f7c5e40SJason M. Bills {
402a9423b6eSJason M. Bills std::shared_ptr<SensorNumMap> sensorNumMapPtr;
403a9423b6eSJason M. Bills details::getSensorNumMap(sensorNumMapPtr);
404a9423b6eSJason M. Bills if (!sensorNumMapPtr)
405a9423b6eSJason M. Bills {
406308c3a8bSJohnathan Mantey return invalidSensorNumber;
407a9423b6eSJason M. Bills }
4083f7c5e40SJason M. Bills
409a9423b6eSJason M. Bills try
4103f7c5e40SJason M. Bills {
411a9423b6eSJason M. Bills return sensorNumMapPtr->right.at(path);
412a9423b6eSJason M. Bills }
413bd51e6a9SPatrick Williams catch (const std::out_of_range& e)
4143f7c5e40SJason M. Bills {
415a9423b6eSJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
416308c3a8bSJohnathan Mantey return invalidSensorNumber;
4173f7c5e40SJason M. Bills }
4183f7c5e40SJason M. Bills }
4193f7c5e40SJason M. Bills
getSensorEventTypeFromPath(const std::string &)420dcff1506SVernon Mauery inline static uint8_t getSensorEventTypeFromPath(const std::string& /* path */)
4213f7c5e40SJason M. Bills {
4223f7c5e40SJason M. Bills // TODO: Add support for additional reading types as needed
4233f7c5e40SJason M. Bills return 0x1; // reading type = threshold
4243f7c5e40SJason M. Bills }
4253f7c5e40SJason M. Bills
getPathFromSensorNumber(uint16_t sensorNum)426308c3a8bSJohnathan Mantey inline static std::string getPathFromSensorNumber(uint16_t sensorNum)
4273f7c5e40SJason M. Bills {
428a9423b6eSJason M. Bills std::shared_ptr<SensorNumMap> sensorNumMapPtr;
429a9423b6eSJason M. Bills details::getSensorNumMap(sensorNumMapPtr);
430a9423b6eSJason M. Bills if (!sensorNumMapPtr)
4313f7c5e40SJason M. Bills {
432a9423b6eSJason M. Bills return std::string();
4333f7c5e40SJason M. Bills }
4343f7c5e40SJason M. Bills
435a9423b6eSJason M. Bills try
4363f7c5e40SJason M. Bills {
437a9423b6eSJason M. Bills return sensorNumMapPtr->left.at(sensorNum);
438a9423b6eSJason M. Bills }
439bd51e6a9SPatrick Williams catch (const std::out_of_range& e)
4403f7c5e40SJason M. Bills {
441a9423b6eSJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
442a9423b6eSJason M. Bills return std::string();
4433f7c5e40SJason M. Bills }
4443f7c5e40SJason M. Bills }
445262276f4SPatrick Venture
446262276f4SPatrick Venture namespace ipmi
447262276f4SPatrick Venture {
448262276f4SPatrick Venture
449262276f4SPatrick Venture static inline std::map<std::string, std::vector<std::string>>
getObjectInterfaces(const char * path)450262276f4SPatrick Venture getObjectInterfaces(const char* path)
451262276f4SPatrick Venture {
452262276f4SPatrick Venture std::map<std::string, std::vector<std::string>> interfacesResponse;
453262276f4SPatrick Venture std::vector<std::string> interfaces;
454262276f4SPatrick Venture std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
455262276f4SPatrick Venture
456f944d2e5SPatrick Williams sdbusplus::message_t getObjectMessage =
457262276f4SPatrick Venture dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
458262276f4SPatrick Venture "/xyz/openbmc_project/object_mapper",
459262276f4SPatrick Venture "xyz.openbmc_project.ObjectMapper", "GetObject");
460262276f4SPatrick Venture getObjectMessage.append(path, interfaces);
461262276f4SPatrick Venture
462262276f4SPatrick Venture try
463262276f4SPatrick Venture {
464f944d2e5SPatrick Williams sdbusplus::message_t response = dbus->call(getObjectMessage);
465262276f4SPatrick Venture response.read(interfacesResponse);
466262276f4SPatrick Venture }
467262276f4SPatrick Venture catch (const std::exception& e)
468262276f4SPatrick Venture {
469262276f4SPatrick Venture phosphor::logging::log<phosphor::logging::level::ERR>(
470262276f4SPatrick Venture "Failed to GetObject", phosphor::logging::entry("PATH=%s", path),
471262276f4SPatrick Venture phosphor::logging::entry("WHAT=%s", e.what()));
472262276f4SPatrick Venture }
473262276f4SPatrick Venture
474262276f4SPatrick Venture return interfacesResponse;
475262276f4SPatrick Venture }
476262276f4SPatrick Venture
477262276f4SPatrick Venture static inline std::map<std::string, DbusVariant>
getEntityManagerProperties(const char * path,const char * interface)478262276f4SPatrick Venture getEntityManagerProperties(const char* path, const char* interface)
479262276f4SPatrick Venture {
480262276f4SPatrick Venture std::map<std::string, DbusVariant> properties;
481262276f4SPatrick Venture std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
482262276f4SPatrick Venture
483f944d2e5SPatrick Williams sdbusplus::message_t getProperties =
484262276f4SPatrick Venture dbus->new_method_call("xyz.openbmc_project.EntityManager", path,
485262276f4SPatrick Venture "org.freedesktop.DBus.Properties", "GetAll");
486262276f4SPatrick Venture getProperties.append(interface);
487262276f4SPatrick Venture
488262276f4SPatrick Venture try
489262276f4SPatrick Venture {
490f944d2e5SPatrick Williams sdbusplus::message_t response = dbus->call(getProperties);
491262276f4SPatrick Venture response.read(properties);
492262276f4SPatrick Venture }
493262276f4SPatrick Venture catch (const std::exception& e)
494262276f4SPatrick Venture {
495262276f4SPatrick Venture phosphor::logging::log<phosphor::logging::level::ERR>(
496262276f4SPatrick Venture "Failed to GetAll", phosphor::logging::entry("PATH=%s", path),
497262276f4SPatrick Venture phosphor::logging::entry("INTF=%s", interface),
498262276f4SPatrick Venture phosphor::logging::entry("WHAT=%s", e.what()));
499262276f4SPatrick Venture }
500262276f4SPatrick Venture
501262276f4SPatrick Venture return properties;
502262276f4SPatrick Venture }
503262276f4SPatrick Venture
getSensorConfigurationInterface(const std::map<std::string,std::vector<std::string>> & sensorInterfacesResponse)504262276f4SPatrick Venture static inline const std::string* getSensorConfigurationInterface(
505262276f4SPatrick Venture const std::map<std::string, std::vector<std::string>>&
506262276f4SPatrick Venture sensorInterfacesResponse)
507262276f4SPatrick Venture {
508262276f4SPatrick Venture auto entityManagerService =
509262276f4SPatrick Venture sensorInterfacesResponse.find("xyz.openbmc_project.EntityManager");
510262276f4SPatrick Venture if (entityManagerService == sensorInterfacesResponse.end())
511262276f4SPatrick Venture {
512262276f4SPatrick Venture return nullptr;
513262276f4SPatrick Venture }
514262276f4SPatrick Venture
515262276f4SPatrick Venture // Find the fan configuration first (fans can have multiple configuration
516262276f4SPatrick Venture // interfaces).
517262276f4SPatrick Venture for (const auto& entry : entityManagerService->second)
518262276f4SPatrick Venture {
519262276f4SPatrick Venture if (entry == "xyz.openbmc_project.Configuration.AspeedFan" ||
520262276f4SPatrick Venture entry == "xyz.openbmc_project.Configuration.I2CFan" ||
521262276f4SPatrick Venture entry == "xyz.openbmc_project.Configuration.NuvotonFan")
522262276f4SPatrick Venture {
523262276f4SPatrick Venture return &entry;
524262276f4SPatrick Venture }
525262276f4SPatrick Venture }
526262276f4SPatrick Venture
527262276f4SPatrick Venture for (const auto& entry : entityManagerService->second)
528262276f4SPatrick Venture {
529262276f4SPatrick Venture if (boost::algorithm::starts_with(entry,
530262276f4SPatrick Venture "xyz.openbmc_project.Configuration."))
531262276f4SPatrick Venture {
532262276f4SPatrick Venture return &entry;
533262276f4SPatrick Venture }
534262276f4SPatrick Venture }
535262276f4SPatrick Venture
536262276f4SPatrick Venture return nullptr;
537262276f4SPatrick Venture }
538262276f4SPatrick Venture
539262276f4SPatrick Venture // Follow Association properties for Sensor back to the Board dbus object to
540262276f4SPatrick Venture // check for an EntityId and EntityInstance property.
updateIpmiFromAssociation(const std::string & path,const SensorMap & sensorMap,uint8_t & entityId,uint8_t & entityInstance)541*1bcced08SPatrick Williams static inline void updateIpmiFromAssociation(
542*1bcced08SPatrick Williams const std::string& path, const SensorMap& sensorMap, uint8_t& entityId,
543262276f4SPatrick Venture uint8_t& entityInstance)
544262276f4SPatrick Venture {
545262276f4SPatrick Venture namespace fs = std::filesystem;
546262276f4SPatrick Venture
547262276f4SPatrick Venture auto sensorAssociationObject =
548262276f4SPatrick Venture sensorMap.find("xyz.openbmc_project.Association.Definitions");
549262276f4SPatrick Venture if (sensorAssociationObject == sensorMap.end())
550262276f4SPatrick Venture {
551262276f4SPatrick Venture if constexpr (debug)
552262276f4SPatrick Venture {
553262276f4SPatrick Venture std::fprintf(stderr, "path=%s, no association interface found\n",
554262276f4SPatrick Venture path.c_str());
555262276f4SPatrick Venture }
556262276f4SPatrick Venture
557262276f4SPatrick Venture return;
558262276f4SPatrick Venture }
559262276f4SPatrick Venture
560262276f4SPatrick Venture auto associationObject =
561262276f4SPatrick Venture sensorAssociationObject->second.find("Associations");
562262276f4SPatrick Venture if (associationObject == sensorAssociationObject->second.end())
563262276f4SPatrick Venture {
564262276f4SPatrick Venture if constexpr (debug)
565262276f4SPatrick Venture {
566262276f4SPatrick Venture std::fprintf(stderr, "path=%s, no association records found\n",
567262276f4SPatrick Venture path.c_str());
568262276f4SPatrick Venture }
569262276f4SPatrick Venture
570262276f4SPatrick Venture return;
571262276f4SPatrick Venture }
572262276f4SPatrick Venture
573262276f4SPatrick Venture std::vector<Association> associationValues =
574262276f4SPatrick Venture std::get<std::vector<Association>>(associationObject->second);
575262276f4SPatrick Venture
576262276f4SPatrick Venture // loop through the Associations looking for the right one:
577262276f4SPatrick Venture for (const auto& entry : associationValues)
578262276f4SPatrick Venture {
579262276f4SPatrick Venture // forward, reverse, endpoint
580262276f4SPatrick Venture const std::string& forward = std::get<0>(entry);
581262276f4SPatrick Venture const std::string& reverse = std::get<1>(entry);
582262276f4SPatrick Venture const std::string& endpoint = std::get<2>(entry);
583262276f4SPatrick Venture
584262276f4SPatrick Venture // We only currently concern ourselves with chassis+all_sensors.
585262276f4SPatrick Venture if (!(forward == "chassis" && reverse == "all_sensors"))
586262276f4SPatrick Venture {
587262276f4SPatrick Venture continue;
588262276f4SPatrick Venture }
589262276f4SPatrick Venture
590262276f4SPatrick Venture // the endpoint is the board entry provided by
591262276f4SPatrick Venture // Entity-Manager. so let's grab its properties if it has
592262276f4SPatrick Venture // the right interface.
593262276f4SPatrick Venture
594262276f4SPatrick Venture // just try grabbing the properties first.
595262276f4SPatrick Venture std::map<std::string, DbusVariant> ipmiProperties =
596262276f4SPatrick Venture getEntityManagerProperties(
597262276f4SPatrick Venture endpoint.c_str(),
598262276f4SPatrick Venture "xyz.openbmc_project.Inventory.Decorator.Ipmi");
599262276f4SPatrick Venture
600262276f4SPatrick Venture auto entityIdProp = ipmiProperties.find("EntityId");
601262276f4SPatrick Venture auto entityInstanceProp = ipmiProperties.find("EntityInstance");
602262276f4SPatrick Venture if (entityIdProp != ipmiProperties.end())
603262276f4SPatrick Venture {
604262276f4SPatrick Venture entityId =
605262276f4SPatrick Venture static_cast<uint8_t>(std::get<uint64_t>(entityIdProp->second));
606262276f4SPatrick Venture }
607262276f4SPatrick Venture if (entityInstanceProp != ipmiProperties.end())
608262276f4SPatrick Venture {
609262276f4SPatrick Venture entityInstance = static_cast<uint8_t>(
610262276f4SPatrick Venture std::get<uint64_t>(entityInstanceProp->second));
611262276f4SPatrick Venture }
612262276f4SPatrick Venture
613262276f4SPatrick Venture // Now check the entity-manager entry for this sensor to see
614262276f4SPatrick Venture // if it has its own value and use that instead.
615262276f4SPatrick Venture //
616262276f4SPatrick Venture // In theory, checking this first saves us from checking
617262276f4SPatrick Venture // both, except in most use-cases identified, there won't be
618262276f4SPatrick Venture // a per sensor override, so we need to always check both.
619262276f4SPatrick Venture std::string sensorNameFromPath = fs::path(path).filename();
620262276f4SPatrick Venture
621262276f4SPatrick Venture std::string sensorConfigPath = endpoint + "/" + sensorNameFromPath;
622262276f4SPatrick Venture
623262276f4SPatrick Venture // Download the interfaces for the sensor from
624262276f4SPatrick Venture // Entity-Manager to find the name of the configuration
625262276f4SPatrick Venture // interface.
626262276f4SPatrick Venture std::map<std::string, std::vector<std::string>>
627262276f4SPatrick Venture sensorInterfacesResponse =
628262276f4SPatrick Venture getObjectInterfaces(sensorConfigPath.c_str());
629262276f4SPatrick Venture
630262276f4SPatrick Venture const std::string* configurationInterface =
631262276f4SPatrick Venture getSensorConfigurationInterface(sensorInterfacesResponse);
632262276f4SPatrick Venture
633262276f4SPatrick Venture // We didnt' find a configuration interface for this sensor, but we
634262276f4SPatrick Venture // followed the Association property to get here, so we're done
635262276f4SPatrick Venture // searching.
636262276f4SPatrick Venture if (!configurationInterface)
637262276f4SPatrick Venture {
638262276f4SPatrick Venture break;
639262276f4SPatrick Venture }
640262276f4SPatrick Venture
641262276f4SPatrick Venture // We found a configuration interface.
642262276f4SPatrick Venture std::map<std::string, DbusVariant> configurationProperties =
643262276f4SPatrick Venture getEntityManagerProperties(sensorConfigPath.c_str(),
644262276f4SPatrick Venture configurationInterface->c_str());
645262276f4SPatrick Venture
646262276f4SPatrick Venture entityIdProp = configurationProperties.find("EntityId");
647262276f4SPatrick Venture entityInstanceProp = configurationProperties.find("EntityInstance");
648262276f4SPatrick Venture if (entityIdProp != configurationProperties.end())
649262276f4SPatrick Venture {
650262276f4SPatrick Venture entityId =
651262276f4SPatrick Venture static_cast<uint8_t>(std::get<uint64_t>(entityIdProp->second));
652262276f4SPatrick Venture }
653262276f4SPatrick Venture if (entityInstanceProp != configurationProperties.end())
654262276f4SPatrick Venture {
655262276f4SPatrick Venture entityInstance = static_cast<uint8_t>(
656262276f4SPatrick Venture std::get<uint64_t>(entityInstanceProp->second));
657262276f4SPatrick Venture }
658262276f4SPatrick Venture
659262276f4SPatrick Venture // stop searching Association records.
660262276f4SPatrick Venture break;
661262276f4SPatrick Venture } // end for Association vectors.
662262276f4SPatrick Venture
663262276f4SPatrick Venture if constexpr (debug)
664262276f4SPatrick Venture {
665262276f4SPatrick Venture std::fprintf(stderr, "path=%s, entityId=%d, entityInstance=%d\n",
666262276f4SPatrick Venture path.c_str(), entityId, entityInstance);
667262276f4SPatrick Venture }
668262276f4SPatrick Venture }
669262276f4SPatrick Venture
670262276f4SPatrick Venture } // namespace ipmi
671