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