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 { 393f7c5e40SJason 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: 7706aa21abSJosh Lehan const std::string& getName(void) const 7806aa21abSJosh Lehan { 7906aa21abSJosh Lehan return sensorName; 8006aa21abSJosh Lehan } 8106aa21abSJosh Lehan 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 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 12206aa21abSJosh Lehan << ": Recovered reading, value=" << reading 12306aa21abSJosh Lehan << " byte=" << raw 12406aa21abSJosh Lehan << ", Reading counts good=" << numReadings 12506aa21abSJosh Lehan << " miss=" << numMissings 12606aa21abSJosh Lehan << ", Prior miss streak=" << numStreakMiss << "\n"; 12706aa21abSJosh Lehan } 12806aa21abSJosh Lehan 12906aa21abSJosh Lehan // Initialize min/max if the first successful reading 13006aa21abSJosh Lehan if (numReadings == 0) 13106aa21abSJosh Lehan { 13206aa21abSJosh Lehan std::cerr << "IPMI sensor " << sensorName 13306aa21abSJosh Lehan << ": First reading, value=" << reading << " byte=" << raw 13406aa21abSJosh Lehan << "\n"; 13506aa21abSJosh Lehan 13606aa21abSJosh Lehan minValue = reading; 13706aa21abSJosh Lehan maxValue = reading; 13806aa21abSJosh Lehan } 13906aa21abSJosh Lehan 14006aa21abSJosh Lehan numStreakMiss = 0; 14106aa21abSJosh Lehan ++numReadings; 14206aa21abSJosh Lehan ++numStreakRead; 14306aa21abSJosh Lehan 14406aa21abSJosh Lehan // Only provide subsequent output if new min/max established 14506aa21abSJosh Lehan if (reading < minValue) 14606aa21abSJosh Lehan { 14706aa21abSJosh Lehan std::cerr << "IPMI sensor " << sensorName 14806aa21abSJosh Lehan << ": Lowest reading, value=" << reading 14906aa21abSJosh Lehan << " byte=" << raw << "\n"; 15006aa21abSJosh Lehan 15106aa21abSJosh Lehan minValue = reading; 15206aa21abSJosh Lehan } 15306aa21abSJosh Lehan 15406aa21abSJosh Lehan if (reading > maxValue) 15506aa21abSJosh Lehan { 15606aa21abSJosh Lehan std::cerr << "IPMI sensor " << sensorName 15706aa21abSJosh Lehan << ": Highest reading, value=" << reading 15806aa21abSJosh Lehan << " byte=" << raw << "\n"; 15906aa21abSJosh Lehan 16006aa21abSJosh Lehan maxValue = reading; 16106aa21abSJosh Lehan } 16206aa21abSJosh Lehan 16306aa21abSJosh Lehan return first; 16406aa21abSJosh Lehan } 16506aa21abSJosh Lehan }; 16606aa21abSJosh Lehan 16706aa21abSJosh Lehan class IPMIStatsTable 16806aa21abSJosh Lehan { 16906aa21abSJosh Lehan private: 17006aa21abSJosh Lehan std::vector<IPMIStatsEntry> entries; 17106aa21abSJosh Lehan 17206aa21abSJosh Lehan private: 17306aa21abSJosh Lehan void padEntries(size_t index) 17406aa21abSJosh Lehan { 17506aa21abSJosh Lehan char hexbuf[16]; 17606aa21abSJosh Lehan 17706aa21abSJosh Lehan // Pad vector until entries[index] becomes a valid index 17806aa21abSJosh Lehan while (entries.size() <= index) 17906aa21abSJosh Lehan { 18006aa21abSJosh Lehan // As name not known yet, use human-readable hex as name 18106aa21abSJosh Lehan IPMIStatsEntry newEntry; 18206aa21abSJosh Lehan sprintf(hexbuf, "0x%02zX", entries.size()); 18306aa21abSJosh Lehan newEntry.updateName(hexbuf); 18406aa21abSJosh Lehan 18506aa21abSJosh Lehan entries.push_back(std::move(newEntry)); 18606aa21abSJosh Lehan } 18706aa21abSJosh Lehan } 18806aa21abSJosh Lehan 18906aa21abSJosh Lehan public: 19006aa21abSJosh Lehan void wipeTable(void) 19106aa21abSJosh Lehan { 19206aa21abSJosh Lehan entries.clear(); 19306aa21abSJosh Lehan } 19406aa21abSJosh Lehan 19506aa21abSJosh Lehan const std::string& getName(size_t index) 19606aa21abSJosh Lehan { 19706aa21abSJosh Lehan padEntries(index); 19806aa21abSJosh Lehan return entries[index].getName(); 19906aa21abSJosh Lehan } 20006aa21abSJosh Lehan 20106aa21abSJosh Lehan void updateName(size_t index, std::string_view name) 20206aa21abSJosh Lehan { 20306aa21abSJosh Lehan padEntries(index); 20406aa21abSJosh Lehan entries[index].updateName(name); 20506aa21abSJosh Lehan } 20606aa21abSJosh Lehan 20706aa21abSJosh Lehan bool updateReading(size_t index, double reading, int raw) 20806aa21abSJosh Lehan { 20906aa21abSJosh Lehan padEntries(index); 21006aa21abSJosh Lehan return entries[index].updateReading(reading, raw); 21106aa21abSJosh Lehan } 21206aa21abSJosh Lehan }; 21306aa21abSJosh Lehan 21406aa21abSJosh Lehan // This object is global singleton, used from a variety of places 21506aa21abSJosh Lehan inline IPMIStatsTable sdrStatsTable; 21606aa21abSJosh Lehan 21717eadbfbSKuiying Wang inline static uint16_t getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree) 218a9423b6eSJason M. Bills { 219a9423b6eSJason M. Bills static std::shared_ptr<SensorSubTree> sensorTreePtr; 22017eadbfbSKuiying Wang static uint16_t sensorUpdatedIndex = 0; 2213f7c5e40SJason M. Bills sd_bus* bus = NULL; 2223f7c5e40SJason M. Bills int ret = sd_bus_default_system(&bus); 2233f7c5e40SJason M. Bills if (ret < 0) 2243f7c5e40SJason M. Bills { 2253f7c5e40SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>( 2263f7c5e40SJason M. Bills "Failed to connect to system bus", 2273f7c5e40SJason M. Bills phosphor::logging::entry("ERRNO=0x%X", -ret)); 2283f7c5e40SJason M. Bills sd_bus_unref(bus); 22917eadbfbSKuiying Wang return sensorUpdatedIndex; 2303f7c5e40SJason M. Bills } 231f944d2e5SPatrick Williams sdbusplus::bus_t dbus(bus); 232f944d2e5SPatrick Williams static sdbusplus::bus::match_t sensorAdded( 233a9423b6eSJason M. Bills dbus, 234a9423b6eSJason M. Bills "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/" 235a9423b6eSJason M. Bills "sensors/'", 236*dcff1506SVernon Mauery [](sdbusplus::message_t&) { sensorTreePtr.reset(); }); 237a9423b6eSJason M. Bills 238f944d2e5SPatrick Williams static sdbusplus::bus::match_t sensorRemoved( 239a9423b6eSJason M. Bills dbus, 240a9423b6eSJason M. Bills "type='signal',member='InterfacesRemoved',arg0path='/xyz/" 241a9423b6eSJason M. Bills "openbmc_project/sensors/'", 242*dcff1506SVernon Mauery [](sdbusplus::message_t&) { sensorTreePtr.reset(); }); 243a9423b6eSJason M. Bills 244a9423b6eSJason M. Bills if (sensorTreePtr) 245a9423b6eSJason M. Bills { 246a9423b6eSJason M. Bills subtree = sensorTreePtr; 24717eadbfbSKuiying Wang return sensorUpdatedIndex; 248a9423b6eSJason M. Bills } 249a9423b6eSJason M. Bills 250a9423b6eSJason M. Bills sensorTreePtr = std::make_shared<SensorSubTree>(); 251a9423b6eSJason M. Bills 252b37abfb2SPatrick Williams auto mapperCall = dbus.new_method_call("xyz.openbmc_project.ObjectMapper", 2533f7c5e40SJason M. Bills "/xyz/openbmc_project/object_mapper", 254b37abfb2SPatrick Williams "xyz.openbmc_project.ObjectMapper", 255b37abfb2SPatrick Williams "GetSubTree"); 25652341e85SJason M. Bills static constexpr const auto depth = 2; 2573f7c5e40SJason M. Bills static constexpr std::array<const char*, 3> interfaces = { 2583f7c5e40SJason M. Bills "xyz.openbmc_project.Sensor.Value", 2593f7c5e40SJason M. Bills "xyz.openbmc_project.Sensor.Threshold.Warning", 2603f7c5e40SJason M. Bills "xyz.openbmc_project.Sensor.Threshold.Critical"}; 2613f7c5e40SJason M. Bills mapperCall.append("/xyz/openbmc_project/sensors", depth, interfaces); 2623f7c5e40SJason M. Bills 2633f7c5e40SJason M. Bills try 2643f7c5e40SJason M. Bills { 2653f7c5e40SJason M. Bills auto mapperReply = dbus.call(mapperCall); 266a9423b6eSJason M. Bills mapperReply.read(*sensorTreePtr); 2673f7c5e40SJason M. Bills } 268bd51e6a9SPatrick Williams catch (const sdbusplus::exception_t& e) 2693f7c5e40SJason M. Bills { 27052341e85SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 27117eadbfbSKuiying Wang return sensorUpdatedIndex; 272a9423b6eSJason M. Bills } 273a9423b6eSJason M. Bills subtree = sensorTreePtr; 27417eadbfbSKuiying Wang sensorUpdatedIndex++; 27506aa21abSJosh Lehan // The SDR is being regenerated, wipe the old stats 27606aa21abSJosh Lehan sdrStatsTable.wipeTable(); 27717eadbfbSKuiying Wang return sensorUpdatedIndex; 278a9423b6eSJason M. Bills } 279a9423b6eSJason M. Bills 280a9423b6eSJason M. Bills inline static bool getSensorNumMap(std::shared_ptr<SensorNumMap>& sensorNumMap) 281a9423b6eSJason M. Bills { 282a9423b6eSJason M. Bills static std::shared_ptr<SensorNumMap> sensorNumMapPtr; 283a9423b6eSJason M. Bills bool sensorNumMapUpated = false; 28417eadbfbSKuiying Wang static uint16_t prevSensorUpdatedIndex = 0; 285a9423b6eSJason M. Bills std::shared_ptr<SensorSubTree> sensorTree; 28617eadbfbSKuiying Wang uint16_t curSensorUpdatedIndex = details::getSensorSubtree(sensorTree); 287a9423b6eSJason M. Bills if (!sensorTree) 288a9423b6eSJason M. Bills { 289a9423b6eSJason M. Bills return sensorNumMapUpated; 290a9423b6eSJason M. Bills } 291a9423b6eSJason M. Bills 29217eadbfbSKuiying Wang if ((curSensorUpdatedIndex == prevSensorUpdatedIndex) && sensorNumMapPtr) 293a9423b6eSJason M. Bills { 294a9423b6eSJason M. Bills sensorNumMap = sensorNumMapPtr; 295a9423b6eSJason M. Bills return sensorNumMapUpated; 296a9423b6eSJason M. Bills } 29717eadbfbSKuiying Wang prevSensorUpdatedIndex = curSensorUpdatedIndex; 298a9423b6eSJason M. Bills 299a9423b6eSJason M. Bills sensorNumMapPtr = std::make_shared<SensorNumMap>(); 300a9423b6eSJason M. Bills 301308c3a8bSJohnathan Mantey uint16_t sensorNum = 0; 302308c3a8bSJohnathan Mantey uint16_t sensorIndex = 0; 303a9423b6eSJason M. Bills for (const auto& sensor : *sensorTree) 304a9423b6eSJason M. Bills { 305a9423b6eSJason M. Bills sensorNumMapPtr->insert( 306308c3a8bSJohnathan Mantey SensorNumMap::value_type(sensorNum, sensor.first)); 307308c3a8bSJohnathan Mantey sensorIndex++; 308308c3a8bSJohnathan Mantey if (sensorIndex == maxSensorsPerLUN) 309308c3a8bSJohnathan Mantey { 310308c3a8bSJohnathan Mantey sensorIndex = lun1Sensor0; 311308c3a8bSJohnathan Mantey } 312308c3a8bSJohnathan Mantey else if (sensorIndex == (lun1Sensor0 | maxSensorsPerLUN)) 313308c3a8bSJohnathan Mantey { 314308c3a8bSJohnathan Mantey // Skip assigning LUN 0x2 any sensors 315308c3a8bSJohnathan Mantey sensorIndex = lun3Sensor0; 316308c3a8bSJohnathan Mantey } 317308c3a8bSJohnathan Mantey else if (sensorIndex == (lun3Sensor0 | maxSensorsPerLUN)) 318308c3a8bSJohnathan Mantey { 319308c3a8bSJohnathan Mantey // this is an error, too many IPMI sensors 320308c3a8bSJohnathan Mantey throw std::out_of_range("Maximum number of IPMI sensors exceeded."); 321308c3a8bSJohnathan Mantey } 322308c3a8bSJohnathan Mantey sensorNum = sensorIndex; 323a9423b6eSJason M. Bills } 324a9423b6eSJason M. Bills sensorNumMap = sensorNumMapPtr; 325a9423b6eSJason M. Bills sensorNumMapUpated = true; 326a9423b6eSJason M. Bills return sensorNumMapUpated; 327a9423b6eSJason M. Bills } 328a9423b6eSJason M. Bills } // namespace details 329a9423b6eSJason M. Bills 330a9423b6eSJason M. Bills inline static bool getSensorSubtree(SensorSubTree& subtree) 331a9423b6eSJason M. Bills { 332a9423b6eSJason M. Bills std::shared_ptr<SensorSubTree> sensorTree; 333a9423b6eSJason M. Bills details::getSensorSubtree(sensorTree); 334a9423b6eSJason M. Bills if (!sensorTree) 335a9423b6eSJason M. Bills { 3363f7c5e40SJason M. Bills return false; 3373f7c5e40SJason M. Bills } 338a9423b6eSJason M. Bills 339a9423b6eSJason M. Bills subtree = *sensorTree; 3403f7c5e40SJason M. Bills return true; 3413f7c5e40SJason M. Bills } 3423f7c5e40SJason M. Bills 3433f7c5e40SJason M. Bills struct CmpStr 3443f7c5e40SJason M. Bills { 3453f7c5e40SJason M. Bills bool operator()(const char* a, const char* b) const 3463f7c5e40SJason M. Bills { 3473f7c5e40SJason M. Bills return std::strcmp(a, b) < 0; 3483f7c5e40SJason M. Bills } 3493f7c5e40SJason M. Bills }; 3503f7c5e40SJason M. Bills 35152341e85SJason M. Bills enum class SensorTypeCodes : uint8_t 35252341e85SJason M. Bills { 35352341e85SJason M. Bills reserved = 0x0, 35452341e85SJason M. Bills temperature = 0x1, 35552341e85SJason M. Bills voltage = 0x2, 35652341e85SJason M. Bills current = 0x3, 35752341e85SJason M. Bills fan = 0x4, 35852341e85SJason M. Bills other = 0xB, 35952341e85SJason M. Bills }; 36052341e85SJason M. Bills 3613f7c5e40SJason M. Bills const static boost::container::flat_map<const char*, SensorTypeCodes, CmpStr> 3623f7c5e40SJason M. Bills sensorTypes{{{"temperature", SensorTypeCodes::temperature}, 3633f7c5e40SJason M. Bills {"voltage", SensorTypeCodes::voltage}, 3643f7c5e40SJason M. Bills {"current", SensorTypeCodes::current}, 3653f7c5e40SJason M. Bills {"fan_tach", SensorTypeCodes::fan}, 366f426f334SJames Feist {"fan_pwm", SensorTypeCodes::fan}, 3673f7c5e40SJason M. Bills {"power", SensorTypeCodes::other}}}; 3683f7c5e40SJason M. Bills 3693f7c5e40SJason M. Bills inline static std::string getSensorTypeStringFromPath(const std::string& path) 3703f7c5e40SJason M. Bills { 3713f7c5e40SJason M. Bills // get sensor type string from path, path is defined as 3723f7c5e40SJason M. Bills // /xyz/openbmc_project/sensors/<type>/label 3733f7c5e40SJason M. Bills size_t typeEnd = path.rfind("/"); 374360f593bSJason M. Bills if (typeEnd == std::string::npos) 3753f7c5e40SJason M. Bills { 3763f7c5e40SJason M. Bills return path; 3773f7c5e40SJason M. Bills } 378360f593bSJason M. Bills size_t typeStart = path.rfind("/", typeEnd - 1); 379360f593bSJason M. Bills if (typeStart == std::string::npos) 380360f593bSJason M. Bills { 381360f593bSJason M. Bills return path; 382360f593bSJason M. Bills } 383360f593bSJason M. Bills // Start at the character after the '/' 384360f593bSJason M. Bills typeStart++; 385360f593bSJason M. Bills return path.substr(typeStart, typeEnd - typeStart); 386360f593bSJason M. Bills } 3873f7c5e40SJason M. Bills 3883f7c5e40SJason M. Bills inline static uint8_t getSensorTypeFromPath(const std::string& path) 3893f7c5e40SJason M. Bills { 3903f7c5e40SJason M. Bills uint8_t sensorType = 0; 3913f7c5e40SJason M. Bills std::string type = getSensorTypeStringFromPath(path); 3923f7c5e40SJason M. Bills auto findSensor = sensorTypes.find(type.c_str()); 3933f7c5e40SJason M. Bills if (findSensor != sensorTypes.end()) 3943f7c5e40SJason M. Bills { 3953f7c5e40SJason M. Bills sensorType = static_cast<uint8_t>(findSensor->second); 3963f7c5e40SJason M. Bills } // else default 0x0 RESERVED 3973f7c5e40SJason M. Bills 3983f7c5e40SJason M. Bills return sensorType; 3993f7c5e40SJason M. Bills } 4003f7c5e40SJason M. Bills 401308c3a8bSJohnathan Mantey inline static uint16_t getSensorNumberFromPath(const std::string& path) 4023f7c5e40SJason M. Bills { 403a9423b6eSJason M. Bills std::shared_ptr<SensorNumMap> sensorNumMapPtr; 404a9423b6eSJason M. Bills details::getSensorNumMap(sensorNumMapPtr); 405a9423b6eSJason M. Bills if (!sensorNumMapPtr) 406a9423b6eSJason M. Bills { 407308c3a8bSJohnathan Mantey return invalidSensorNumber; 408a9423b6eSJason M. Bills } 4093f7c5e40SJason M. Bills 410a9423b6eSJason M. Bills try 4113f7c5e40SJason M. Bills { 412a9423b6eSJason M. Bills return sensorNumMapPtr->right.at(path); 413a9423b6eSJason M. Bills } 414bd51e6a9SPatrick Williams catch (const std::out_of_range& e) 4153f7c5e40SJason M. Bills { 416a9423b6eSJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 417308c3a8bSJohnathan Mantey return invalidSensorNumber; 4183f7c5e40SJason M. Bills } 4193f7c5e40SJason M. Bills } 4203f7c5e40SJason M. Bills 421*dcff1506SVernon Mauery inline static uint8_t getSensorEventTypeFromPath(const std::string& /* path */) 4223f7c5e40SJason M. Bills { 4233f7c5e40SJason M. Bills // TODO: Add support for additional reading types as needed 4243f7c5e40SJason M. Bills return 0x1; // reading type = threshold 4253f7c5e40SJason M. Bills } 4263f7c5e40SJason M. Bills 427308c3a8bSJohnathan Mantey inline static std::string getPathFromSensorNumber(uint16_t sensorNum) 4283f7c5e40SJason M. Bills { 429a9423b6eSJason M. Bills std::shared_ptr<SensorNumMap> sensorNumMapPtr; 430a9423b6eSJason M. Bills details::getSensorNumMap(sensorNumMapPtr); 431a9423b6eSJason M. Bills if (!sensorNumMapPtr) 4323f7c5e40SJason M. Bills { 433a9423b6eSJason M. Bills return std::string(); 4343f7c5e40SJason M. Bills } 4353f7c5e40SJason M. Bills 436a9423b6eSJason M. Bills try 4373f7c5e40SJason M. Bills { 438a9423b6eSJason M. Bills return sensorNumMapPtr->left.at(sensorNum); 439a9423b6eSJason M. Bills } 440bd51e6a9SPatrick Williams catch (const std::out_of_range& e) 4413f7c5e40SJason M. Bills { 442a9423b6eSJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 443a9423b6eSJason M. Bills return std::string(); 4443f7c5e40SJason M. Bills } 4453f7c5e40SJason M. Bills } 446262276f4SPatrick Venture 447262276f4SPatrick Venture namespace ipmi 448262276f4SPatrick Venture { 449262276f4SPatrick Venture 450262276f4SPatrick Venture static inline std::map<std::string, std::vector<std::string>> 451262276f4SPatrick Venture getObjectInterfaces(const char* path) 452262276f4SPatrick Venture { 453262276f4SPatrick Venture std::map<std::string, std::vector<std::string>> interfacesResponse; 454262276f4SPatrick Venture std::vector<std::string> interfaces; 455262276f4SPatrick Venture std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 456262276f4SPatrick Venture 457f944d2e5SPatrick Williams sdbusplus::message_t getObjectMessage = 458262276f4SPatrick Venture dbus->new_method_call("xyz.openbmc_project.ObjectMapper", 459262276f4SPatrick Venture "/xyz/openbmc_project/object_mapper", 460262276f4SPatrick Venture "xyz.openbmc_project.ObjectMapper", "GetObject"); 461262276f4SPatrick Venture getObjectMessage.append(path, interfaces); 462262276f4SPatrick Venture 463262276f4SPatrick Venture try 464262276f4SPatrick Venture { 465f944d2e5SPatrick Williams sdbusplus::message_t response = dbus->call(getObjectMessage); 466262276f4SPatrick Venture response.read(interfacesResponse); 467262276f4SPatrick Venture } 468262276f4SPatrick Venture catch (const std::exception& e) 469262276f4SPatrick Venture { 470262276f4SPatrick Venture phosphor::logging::log<phosphor::logging::level::ERR>( 471262276f4SPatrick Venture "Failed to GetObject", phosphor::logging::entry("PATH=%s", path), 472262276f4SPatrick Venture phosphor::logging::entry("WHAT=%s", e.what())); 473262276f4SPatrick Venture } 474262276f4SPatrick Venture 475262276f4SPatrick Venture return interfacesResponse; 476262276f4SPatrick Venture } 477262276f4SPatrick Venture 478262276f4SPatrick Venture static inline std::map<std::string, DbusVariant> 479262276f4SPatrick Venture getEntityManagerProperties(const char* path, const char* interface) 480262276f4SPatrick Venture { 481262276f4SPatrick Venture std::map<std::string, DbusVariant> properties; 482262276f4SPatrick Venture std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 483262276f4SPatrick Venture 484f944d2e5SPatrick Williams sdbusplus::message_t getProperties = 485262276f4SPatrick Venture dbus->new_method_call("xyz.openbmc_project.EntityManager", path, 486262276f4SPatrick Venture "org.freedesktop.DBus.Properties", "GetAll"); 487262276f4SPatrick Venture getProperties.append(interface); 488262276f4SPatrick Venture 489262276f4SPatrick Venture try 490262276f4SPatrick Venture { 491f944d2e5SPatrick Williams sdbusplus::message_t response = dbus->call(getProperties); 492262276f4SPatrick Venture response.read(properties); 493262276f4SPatrick Venture } 494262276f4SPatrick Venture catch (const std::exception& e) 495262276f4SPatrick Venture { 496262276f4SPatrick Venture phosphor::logging::log<phosphor::logging::level::ERR>( 497262276f4SPatrick Venture "Failed to GetAll", phosphor::logging::entry("PATH=%s", path), 498262276f4SPatrick Venture phosphor::logging::entry("INTF=%s", interface), 499262276f4SPatrick Venture phosphor::logging::entry("WHAT=%s", e.what())); 500262276f4SPatrick Venture } 501262276f4SPatrick Venture 502262276f4SPatrick Venture return properties; 503262276f4SPatrick Venture } 504262276f4SPatrick Venture 505262276f4SPatrick Venture static inline const std::string* getSensorConfigurationInterface( 506262276f4SPatrick Venture const std::map<std::string, std::vector<std::string>>& 507262276f4SPatrick Venture sensorInterfacesResponse) 508262276f4SPatrick Venture { 509262276f4SPatrick Venture auto entityManagerService = 510262276f4SPatrick Venture sensorInterfacesResponse.find("xyz.openbmc_project.EntityManager"); 511262276f4SPatrick Venture if (entityManagerService == sensorInterfacesResponse.end()) 512262276f4SPatrick Venture { 513262276f4SPatrick Venture return nullptr; 514262276f4SPatrick Venture } 515262276f4SPatrick Venture 516262276f4SPatrick Venture // Find the fan configuration first (fans can have multiple configuration 517262276f4SPatrick Venture // interfaces). 518262276f4SPatrick Venture for (const auto& entry : entityManagerService->second) 519262276f4SPatrick Venture { 520262276f4SPatrick Venture if (entry == "xyz.openbmc_project.Configuration.AspeedFan" || 521262276f4SPatrick Venture entry == "xyz.openbmc_project.Configuration.I2CFan" || 522262276f4SPatrick Venture entry == "xyz.openbmc_project.Configuration.NuvotonFan") 523262276f4SPatrick Venture { 524262276f4SPatrick Venture return &entry; 525262276f4SPatrick Venture } 526262276f4SPatrick Venture } 527262276f4SPatrick Venture 528262276f4SPatrick Venture for (const auto& entry : entityManagerService->second) 529262276f4SPatrick Venture { 530262276f4SPatrick Venture if (boost::algorithm::starts_with(entry, 531262276f4SPatrick Venture "xyz.openbmc_project.Configuration.")) 532262276f4SPatrick Venture { 533262276f4SPatrick Venture return &entry; 534262276f4SPatrick Venture } 535262276f4SPatrick Venture } 536262276f4SPatrick Venture 537262276f4SPatrick Venture return nullptr; 538262276f4SPatrick Venture } 539262276f4SPatrick Venture 540262276f4SPatrick Venture // Follow Association properties for Sensor back to the Board dbus object to 541262276f4SPatrick Venture // check for an EntityId and EntityInstance property. 542262276f4SPatrick Venture static inline void updateIpmiFromAssociation(const std::string& path, 543262276f4SPatrick Venture const SensorMap& sensorMap, 544262276f4SPatrick Venture uint8_t& entityId, 545262276f4SPatrick Venture uint8_t& entityInstance) 546262276f4SPatrick Venture { 547262276f4SPatrick Venture namespace fs = std::filesystem; 548262276f4SPatrick Venture 549262276f4SPatrick Venture auto sensorAssociationObject = 550262276f4SPatrick Venture sensorMap.find("xyz.openbmc_project.Association.Definitions"); 551262276f4SPatrick Venture if (sensorAssociationObject == sensorMap.end()) 552262276f4SPatrick Venture { 553262276f4SPatrick Venture if constexpr (debug) 554262276f4SPatrick Venture { 555262276f4SPatrick Venture std::fprintf(stderr, "path=%s, no association interface found\n", 556262276f4SPatrick Venture path.c_str()); 557262276f4SPatrick Venture } 558262276f4SPatrick Venture 559262276f4SPatrick Venture return; 560262276f4SPatrick Venture } 561262276f4SPatrick Venture 562262276f4SPatrick Venture auto associationObject = 563262276f4SPatrick Venture sensorAssociationObject->second.find("Associations"); 564262276f4SPatrick Venture if (associationObject == sensorAssociationObject->second.end()) 565262276f4SPatrick Venture { 566262276f4SPatrick Venture if constexpr (debug) 567262276f4SPatrick Venture { 568262276f4SPatrick Venture std::fprintf(stderr, "path=%s, no association records found\n", 569262276f4SPatrick Venture path.c_str()); 570262276f4SPatrick Venture } 571262276f4SPatrick Venture 572262276f4SPatrick Venture return; 573262276f4SPatrick Venture } 574262276f4SPatrick Venture 575262276f4SPatrick Venture std::vector<Association> associationValues = 576262276f4SPatrick Venture std::get<std::vector<Association>>(associationObject->second); 577262276f4SPatrick Venture 578262276f4SPatrick Venture // loop through the Associations looking for the right one: 579262276f4SPatrick Venture for (const auto& entry : associationValues) 580262276f4SPatrick Venture { 581262276f4SPatrick Venture // forward, reverse, endpoint 582262276f4SPatrick Venture const std::string& forward = std::get<0>(entry); 583262276f4SPatrick Venture const std::string& reverse = std::get<1>(entry); 584262276f4SPatrick Venture const std::string& endpoint = std::get<2>(entry); 585262276f4SPatrick Venture 586262276f4SPatrick Venture // We only currently concern ourselves with chassis+all_sensors. 587262276f4SPatrick Venture if (!(forward == "chassis" && reverse == "all_sensors")) 588262276f4SPatrick Venture { 589262276f4SPatrick Venture continue; 590262276f4SPatrick Venture } 591262276f4SPatrick Venture 592262276f4SPatrick Venture // the endpoint is the board entry provided by 593262276f4SPatrick Venture // Entity-Manager. so let's grab its properties if it has 594262276f4SPatrick Venture // the right interface. 595262276f4SPatrick Venture 596262276f4SPatrick Venture // just try grabbing the properties first. 597262276f4SPatrick Venture std::map<std::string, DbusVariant> ipmiProperties = 598262276f4SPatrick Venture getEntityManagerProperties( 599262276f4SPatrick Venture endpoint.c_str(), 600262276f4SPatrick Venture "xyz.openbmc_project.Inventory.Decorator.Ipmi"); 601262276f4SPatrick Venture 602262276f4SPatrick Venture auto entityIdProp = ipmiProperties.find("EntityId"); 603262276f4SPatrick Venture auto entityInstanceProp = ipmiProperties.find("EntityInstance"); 604262276f4SPatrick Venture if (entityIdProp != ipmiProperties.end()) 605262276f4SPatrick Venture { 606262276f4SPatrick Venture entityId = 607262276f4SPatrick Venture static_cast<uint8_t>(std::get<uint64_t>(entityIdProp->second)); 608262276f4SPatrick Venture } 609262276f4SPatrick Venture if (entityInstanceProp != ipmiProperties.end()) 610262276f4SPatrick Venture { 611262276f4SPatrick Venture entityInstance = static_cast<uint8_t>( 612262276f4SPatrick Venture std::get<uint64_t>(entityInstanceProp->second)); 613262276f4SPatrick Venture } 614262276f4SPatrick Venture 615262276f4SPatrick Venture // Now check the entity-manager entry for this sensor to see 616262276f4SPatrick Venture // if it has its own value and use that instead. 617262276f4SPatrick Venture // 618262276f4SPatrick Venture // In theory, checking this first saves us from checking 619262276f4SPatrick Venture // both, except in most use-cases identified, there won't be 620262276f4SPatrick Venture // a per sensor override, so we need to always check both. 621262276f4SPatrick Venture std::string sensorNameFromPath = fs::path(path).filename(); 622262276f4SPatrick Venture 623262276f4SPatrick Venture std::string sensorConfigPath = endpoint + "/" + sensorNameFromPath; 624262276f4SPatrick Venture 625262276f4SPatrick Venture // Download the interfaces for the sensor from 626262276f4SPatrick Venture // Entity-Manager to find the name of the configuration 627262276f4SPatrick Venture // interface. 628262276f4SPatrick Venture std::map<std::string, std::vector<std::string>> 629262276f4SPatrick Venture sensorInterfacesResponse = 630262276f4SPatrick Venture getObjectInterfaces(sensorConfigPath.c_str()); 631262276f4SPatrick Venture 632262276f4SPatrick Venture const std::string* configurationInterface = 633262276f4SPatrick Venture getSensorConfigurationInterface(sensorInterfacesResponse); 634262276f4SPatrick Venture 635262276f4SPatrick Venture // We didnt' find a configuration interface for this sensor, but we 636262276f4SPatrick Venture // followed the Association property to get here, so we're done 637262276f4SPatrick Venture // searching. 638262276f4SPatrick Venture if (!configurationInterface) 639262276f4SPatrick Venture { 640262276f4SPatrick Venture break; 641262276f4SPatrick Venture } 642262276f4SPatrick Venture 643262276f4SPatrick Venture // We found a configuration interface. 644262276f4SPatrick Venture std::map<std::string, DbusVariant> configurationProperties = 645262276f4SPatrick Venture getEntityManagerProperties(sensorConfigPath.c_str(), 646262276f4SPatrick Venture configurationInterface->c_str()); 647262276f4SPatrick Venture 648262276f4SPatrick Venture entityIdProp = configurationProperties.find("EntityId"); 649262276f4SPatrick Venture entityInstanceProp = configurationProperties.find("EntityInstance"); 650262276f4SPatrick Venture if (entityIdProp != configurationProperties.end()) 651262276f4SPatrick Venture { 652262276f4SPatrick Venture entityId = 653262276f4SPatrick Venture static_cast<uint8_t>(std::get<uint64_t>(entityIdProp->second)); 654262276f4SPatrick Venture } 655262276f4SPatrick Venture if (entityInstanceProp != configurationProperties.end()) 656262276f4SPatrick Venture { 657262276f4SPatrick Venture entityInstance = static_cast<uint8_t>( 658262276f4SPatrick Venture std::get<uint64_t>(entityInstanceProp->second)); 659262276f4SPatrick Venture } 660262276f4SPatrick Venture 661262276f4SPatrick Venture // stop searching Association records. 662262276f4SPatrick Venture break; 663262276f4SPatrick Venture } // end for Association vectors. 664262276f4SPatrick Venture 665262276f4SPatrick Venture if constexpr (debug) 666262276f4SPatrick Venture { 667262276f4SPatrick Venture std::fprintf(stderr, "path=%s, entityId=%d, entityInstance=%d\n", 668262276f4SPatrick Venture path.c_str(), entityId, entityInstance); 669262276f4SPatrick Venture } 670262276f4SPatrick Venture } 671262276f4SPatrick Venture 672262276f4SPatrick Venture } // namespace ipmi 673