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