| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1 | /* | 
 | 2 | // Copyright (c) 2017 2018 Intel Corporation | 
 | 3 | // | 
 | 4 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 5 | // you may not use this file except in compliance with the License. | 
 | 6 | // You may obtain a copy of the License at | 
 | 7 | // | 
 | 8 | //      http://www.apache.org/licenses/LICENSE-2.0 | 
 | 9 | // | 
 | 10 | // Unless required by applicable law or agreed to in writing, software | 
 | 11 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 13 | // See the License for the specific language governing permissions and | 
 | 14 | // limitations under the License. | 
 | 15 | */ | 
 | 16 |  | 
| Alexander Hansen | c2c26f9 | 2023-07-17 09:38:43 +0200 | [diff] [blame] | 17 | #include "config.h" | 
 | 18 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 19 | #include "dbus-sdr/sensorcommands.hpp" | 
 | 20 |  | 
 | 21 | #include "dbus-sdr/sdrutils.hpp" | 
 | 22 | #include "dbus-sdr/sensorutils.hpp" | 
 | 23 | #include "dbus-sdr/storagecommands.hpp" | 
 | 24 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 25 | #include <boost/algorithm/string.hpp> | 
 | 26 | #include <boost/container/flat_map.hpp> | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 27 | #include <ipmid/api.hpp> | 
| Vernon Mauery | 9cf0838 | 2023-04-28 14:00:11 -0700 | [diff] [blame] | 28 | #include <ipmid/entity_map_json.hpp> | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 29 | #include <ipmid/types.hpp> | 
 | 30 | #include <ipmid/utils.hpp> | 
 | 31 | #include <phosphor-logging/log.hpp> | 
 | 32 | #include <sdbusplus/bus.hpp> | 
 | 33 | #include <user_channel/channel_layer.hpp> | 
 | 34 |  | 
 | 35 | #include <algorithm> | 
 | 36 | #include <array> | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 37 | #include <chrono> | 
 | 38 | #include <cmath> | 
 | 39 | #include <cstring> | 
| Willy Tu | 62e3ca8 | 2024-01-31 17:28:34 +0000 | [diff] [blame] | 40 | #include <format> | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 41 | #include <iostream> | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 42 | #include <map> | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 43 | #include <optional> | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 44 | #include <stdexcept> | 
 | 45 | #include <string> | 
 | 46 | #include <utility> | 
 | 47 | #include <variant> | 
 | 48 |  | 
| Scron Chang | 2703b02 | 2021-07-06 15:47:45 +0800 | [diff] [blame] | 49 | #ifdef FEATURE_HYBRID_SENSORS | 
 | 50 |  | 
 | 51 | #include "sensordatahandler.hpp" | 
 | 52 | namespace ipmi | 
 | 53 | { | 
 | 54 | namespace sensor | 
 | 55 | { | 
 | 56 | extern const IdInfoMap sensors; | 
 | 57 | } // namespace sensor | 
 | 58 | } // namespace ipmi | 
 | 59 | #endif | 
| adarshgrami | 042e9db | 2022-09-15 10:34:34 +0530 | [diff] [blame] | 60 | namespace ipmi | 
 | 61 | { | 
 | 62 | namespace dcmi | 
 | 63 | { | 
 | 64 | // Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec | 
 | 65 | static const std::map<uint8_t, uint8_t> validEntityId{ | 
 | 66 |     {0x40, 0x37}, {0x37, 0x40}, {0x41, 0x03}, | 
 | 67 |     {0x03, 0x41}, {0x42, 0x07}, {0x07, 0x42}}; | 
 | 68 | constexpr uint8_t temperatureSensorType = 0x01; | 
 | 69 | constexpr uint8_t maxRecords = 8; | 
 | 70 | } // namespace dcmi | 
 | 71 | } // namespace ipmi | 
| JeffLin | d950f41 | 2021-10-20 18:49:34 +0800 | [diff] [blame] | 72 | constexpr std::array<const char*, 7> suffixes = { | 
 | 73 |     "_Output_Voltage", "_Input_Voltage", "_Output_Current", "_Input_Current", | 
 | 74 |     "_Output_Power",   "_Input_Power",   "_Temperature"}; | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 75 | namespace ipmi | 
 | 76 | { | 
| Hao Jiang | d48c921 | 2021-02-03 15:45:06 -0800 | [diff] [blame] | 77 |  | 
 | 78 | using phosphor::logging::entry; | 
 | 79 | using phosphor::logging::level; | 
 | 80 | using phosphor::logging::log; | 
 | 81 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 82 | static constexpr int sensorMapUpdatePeriod = 10; | 
| Alex Qiu | 9ab2f94 | 2020-07-15 17:56:21 -0700 | [diff] [blame] | 83 | static constexpr int sensorMapSdrUpdatePeriod = 60; | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 84 |  | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 85 | // BMC I2C address is generally at 0x20 | 
 | 86 | static constexpr uint8_t bmcI2CAddr = 0x20; | 
 | 87 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 88 | constexpr size_t maxSDRTotalSize = | 
 | 89 |     76; // Largest SDR Record Size (type 01) + SDR Overheader Size | 
 | 90 | constexpr static const uint32_t noTimestamp = 0xFFFFFFFF; | 
 | 91 |  | 
 | 92 | static uint16_t sdrReservationID; | 
 | 93 | static uint32_t sdrLastAdd = noTimestamp; | 
 | 94 | static uint32_t sdrLastRemove = noTimestamp; | 
 | 95 | static constexpr size_t lastRecordIndex = 0xFFFF; | 
| Johnathan Mantey | 6619ae4 | 2021-08-06 11:21:10 -0700 | [diff] [blame] | 96 |  | 
 | 97 | // The IPMI spec defines four Logical Units (LUN), each capable of supporting | 
 | 98 | // 255 sensors. The 256 values assigned to LUN 2 are special and are not used | 
 | 99 | // for general purpose sensors. Each LUN reserves location 0xFF. The maximum | 
| Harvey Wu | 7589306 | 2023-03-22 17:17:31 +0800 | [diff] [blame] | 100 | // number of IPMI sensors are LUN 0 + LUN 1 + LUN 3, less the reserved | 
| Johnathan Mantey | 6619ae4 | 2021-08-06 11:21:10 -0700 | [diff] [blame] | 101 | // location. | 
 | 102 | static constexpr size_t maxIPMISensors = ((3 * 256) - (3 * 1)); | 
 | 103 |  | 
| Harvey Wu | 7589306 | 2023-03-22 17:17:31 +0800 | [diff] [blame] | 104 | static constexpr uint8_t lun0 = 0x0; | 
 | 105 | static constexpr uint8_t lun1 = 0x1; | 
 | 106 | static constexpr uint8_t lun3 = 0x3; | 
 | 107 |  | 
| Johnathan Mantey | 6619ae4 | 2021-08-06 11:21:10 -0700 | [diff] [blame] | 108 | static constexpr size_t lun0MaxSensorNum = 0xfe; | 
 | 109 | static constexpr size_t lun1MaxSensorNum = 0x1fe; | 
 | 110 | static constexpr size_t lun3MaxSensorNum = 0x3fe; | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 111 | static constexpr int GENERAL_ERROR = -1; | 
 | 112 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 113 | static boost::container::flat_map<std::string, ObjectValueTree> SensorCache; | 
 | 114 |  | 
 | 115 | // Specify the comparison required to sort and find char* map objects | 
 | 116 | struct CmpStr | 
 | 117 | { | 
 | 118 |     bool operator()(const char* a, const char* b) const | 
 | 119 |     { | 
 | 120 |         return std::strcmp(a, b) < 0; | 
 | 121 |     } | 
 | 122 | }; | 
 | 123 | const static boost::container::flat_map<const char*, SensorUnits, CmpStr> | 
 | 124 |     sensorUnits{{{"temperature", SensorUnits::degreesC}, | 
 | 125 |                  {"voltage", SensorUnits::volts}, | 
 | 126 |                  {"current", SensorUnits::amps}, | 
 | 127 |                  {"fan_tach", SensorUnits::rpm}, | 
| Johnathan Mantey | 7b03727 | 2024-06-17 12:12:40 -0700 | [diff] [blame] | 128 |                  {"power", SensorUnits::watts}, | 
 | 129 |                  {"energy", SensorUnits::joules}}}; | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 130 |  | 
 | 131 | void registerSensorFunctions() __attribute__((constructor)); | 
 | 132 |  | 
| Patrick Williams | 5d82f47 | 2022-07-22 19:26:53 -0500 | [diff] [blame] | 133 | static sdbusplus::bus::match_t sensorAdded( | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 134 |     *getSdBus(), | 
 | 135 |     "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/" | 
 | 136 |     "sensors/'", | 
| Patrick Williams | 5d82f47 | 2022-07-22 19:26:53 -0500 | [diff] [blame] | 137 |     [](sdbusplus::message_t&) { | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 138 |     getSensorTree().clear(); | 
 | 139 |     getIpmiDecoratorPaths(/*ctx=*/std::nullopt).reset(); | 
 | 140 |     sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>( | 
 | 141 |                      std::chrono::system_clock::now().time_since_epoch()) | 
 | 142 |                      .count(); | 
| Patrick Williams | 369824e | 2023-10-20 11:18:23 -0500 | [diff] [blame] | 143 | }); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 144 |  | 
| Patrick Williams | 5d82f47 | 2022-07-22 19:26:53 -0500 | [diff] [blame] | 145 | static sdbusplus::bus::match_t sensorRemoved( | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 146 |     *getSdBus(), | 
 | 147 |     "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/" | 
 | 148 |     "sensors/'", | 
| Patrick Williams | 5d82f47 | 2022-07-22 19:26:53 -0500 | [diff] [blame] | 149 |     [](sdbusplus::message_t&) { | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 150 |     getSensorTree().clear(); | 
 | 151 |     getIpmiDecoratorPaths(/*ctx=*/std::nullopt).reset(); | 
 | 152 |     sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>( | 
 | 153 |                         std::chrono::system_clock::now().time_since_epoch()) | 
 | 154 |                         .count(); | 
| Patrick Williams | 369824e | 2023-10-20 11:18:23 -0500 | [diff] [blame] | 155 | }); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 156 |  | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 157 | ipmi_ret_t getSensorConnection(ipmi::Context::ptr ctx, uint8_t sensnum, | 
 | 158 |                                std::string& connection, std::string& path, | 
 | 159 |                                std::vector<std::string>* interfaces) | 
 | 160 | { | 
 | 161 |     auto& sensorTree = getSensorTree(); | 
 | 162 |     if (!getSensorSubtree(sensorTree) && sensorTree.empty()) | 
 | 163 |     { | 
 | 164 |         return IPMI_CC_RESPONSE_ERROR; | 
 | 165 |     } | 
 | 166 |  | 
 | 167 |     if (ctx == nullptr) | 
 | 168 |     { | 
 | 169 |         return IPMI_CC_RESPONSE_ERROR; | 
 | 170 |     } | 
 | 171 |  | 
 | 172 |     path = getPathFromSensorNumber((ctx->lun << 8) | sensnum); | 
 | 173 |     if (path.empty()) | 
 | 174 |     { | 
 | 175 |         return IPMI_CC_INVALID_FIELD_REQUEST; | 
 | 176 |     } | 
 | 177 |  | 
 | 178 |     for (const auto& sensor : sensorTree) | 
 | 179 |     { | 
 | 180 |         if (path == sensor.first) | 
 | 181 |         { | 
 | 182 |             connection = sensor.second.begin()->first; | 
 | 183 |             if (interfaces) | 
 | 184 |                 *interfaces = sensor.second.begin()->second; | 
 | 185 |             break; | 
 | 186 |         } | 
 | 187 |     } | 
 | 188 |  | 
 | 189 |     return 0; | 
 | 190 | } | 
 | 191 |  | 
 | 192 | SensorSubTree& getSensorTree() | 
 | 193 | { | 
 | 194 |     static SensorSubTree sensorTree; | 
 | 195 |     return sensorTree; | 
 | 196 | } | 
 | 197 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 198 | // this keeps track of deassertions for sensor event status command. A | 
 | 199 | // deasertion can only happen if an assertion was seen first. | 
 | 200 | static boost::container::flat_map< | 
 | 201 |     std::string, boost::container::flat_map<std::string, std::optional<bool>>> | 
 | 202 |     thresholdDeassertMap; | 
 | 203 |  | 
| Patrick Williams | 5d82f47 | 2022-07-22 19:26:53 -0500 | [diff] [blame] | 204 | static sdbusplus::bus::match_t thresholdChanged( | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 205 |     *getSdBus(), | 
 | 206 |     "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus." | 
 | 207 |     "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'", | 
| Patrick Williams | 5d82f47 | 2022-07-22 19:26:53 -0500 | [diff] [blame] | 208 |     [](sdbusplus::message_t& m) { | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 209 |     boost::container::flat_map<std::string, std::variant<bool, double>> values; | 
 | 210 |     m.read(std::string(), values); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 211 |  | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 212 |     auto findAssert = std::find_if(values.begin(), values.end(), | 
 | 213 |                                    [](const auto& pair) { | 
 | 214 |         return pair.first.find("Alarm") != std::string::npos; | 
 | 215 |     }); | 
 | 216 |     if (findAssert != values.end()) | 
 | 217 |     { | 
 | 218 |         auto ptr = std::get_if<bool>(&(findAssert->second)); | 
 | 219 |         if (ptr == nullptr) | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 220 |         { | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 221 |             phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 222 |                 "thresholdChanged: Assert non bool"); | 
 | 223 |             return; | 
 | 224 |         } | 
 | 225 |         if (*ptr) | 
 | 226 |         { | 
 | 227 |             phosphor::logging::log<phosphor::logging::level::INFO>( | 
 | 228 |                 "thresholdChanged: Assert", | 
 | 229 |                 phosphor::logging::entry("SENSOR=%s", m.get_path())); | 
 | 230 |             thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr; | 
 | 231 |         } | 
 | 232 |         else | 
 | 233 |         { | 
 | 234 |             auto& value = thresholdDeassertMap[m.get_path()][findAssert->first]; | 
 | 235 |             if (value) | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 236 |             { | 
 | 237 |                 phosphor::logging::log<phosphor::logging::level::INFO>( | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 238 |                     "thresholdChanged: deassert", | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 239 |                     phosphor::logging::entry("SENSOR=%s", m.get_path())); | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 240 |                 value = *ptr; | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 241 |             } | 
 | 242 |         } | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 243 |     } | 
| Patrick Williams | 369824e | 2023-10-20 11:18:23 -0500 | [diff] [blame] | 244 | }); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 245 |  | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 246 | namespace sensor | 
 | 247 | { | 
 | 248 | static constexpr const char* vrInterface = | 
 | 249 |     "xyz.openbmc_project.Control.VoltageRegulatorMode"; | 
 | 250 | static constexpr const char* sensorInterface = | 
 | 251 |     "xyz.openbmc_project.Sensor.Value"; | 
 | 252 | } // namespace sensor | 
 | 253 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 254 | static void getSensorMaxMin(const DbusInterfaceMap& sensorMap, double& max, | 
 | 255 |                             double& min) | 
 | 256 | { | 
 | 257 |     max = 127; | 
 | 258 |     min = -128; | 
 | 259 |  | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 260 |     auto sensorObject = sensorMap.find(sensor::sensorInterface); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 261 |     auto critical = | 
 | 262 |         sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical"); | 
 | 263 |     auto warning = | 
 | 264 |         sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning"); | 
 | 265 |  | 
 | 266 |     if (sensorObject != sensorMap.end()) | 
 | 267 |     { | 
 | 268 |         auto maxMap = sensorObject->second.find("MaxValue"); | 
 | 269 |         auto minMap = sensorObject->second.find("MinValue"); | 
 | 270 |  | 
 | 271 |         if (maxMap != sensorObject->second.end()) | 
 | 272 |         { | 
 | 273 |             max = std::visit(VariantToDoubleVisitor(), maxMap->second); | 
 | 274 |         } | 
 | 275 |         if (minMap != sensorObject->second.end()) | 
 | 276 |         { | 
 | 277 |             min = std::visit(VariantToDoubleVisitor(), minMap->second); | 
 | 278 |         } | 
 | 279 |     } | 
 | 280 |     if (critical != sensorMap.end()) | 
 | 281 |     { | 
 | 282 |         auto lower = critical->second.find("CriticalLow"); | 
 | 283 |         auto upper = critical->second.find("CriticalHigh"); | 
 | 284 |         if (lower != critical->second.end()) | 
 | 285 |         { | 
 | 286 |             double value = std::visit(VariantToDoubleVisitor(), lower->second); | 
| Konstantin Aladyshev | 8265af2 | 2021-12-16 18:18:10 +0300 | [diff] [blame] | 287 |             if (std::isfinite(value)) | 
 | 288 |             { | 
| Johnathan Mantey | 92217f0 | 2024-06-20 12:43:01 -0700 | [diff] [blame] | 289 |                 min = std::fmin(value, min); | 
| Konstantin Aladyshev | 8265af2 | 2021-12-16 18:18:10 +0300 | [diff] [blame] | 290 |             } | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 291 |         } | 
 | 292 |         if (upper != critical->second.end()) | 
 | 293 |         { | 
 | 294 |             double value = std::visit(VariantToDoubleVisitor(), upper->second); | 
| Konstantin Aladyshev | 8265af2 | 2021-12-16 18:18:10 +0300 | [diff] [blame] | 295 |             if (std::isfinite(value)) | 
 | 296 |             { | 
| Johnathan Mantey | 92217f0 | 2024-06-20 12:43:01 -0700 | [diff] [blame] | 297 |                 max = std::fmax(value, max); | 
| Konstantin Aladyshev | 8265af2 | 2021-12-16 18:18:10 +0300 | [diff] [blame] | 298 |             } | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 299 |         } | 
 | 300 |     } | 
 | 301 |     if (warning != sensorMap.end()) | 
 | 302 |     { | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 303 |         auto lower = warning->second.find("WarningLow"); | 
 | 304 |         auto upper = warning->second.find("WarningHigh"); | 
 | 305 |         if (lower != warning->second.end()) | 
 | 306 |         { | 
 | 307 |             double value = std::visit(VariantToDoubleVisitor(), lower->second); | 
| Konstantin Aladyshev | 8265af2 | 2021-12-16 18:18:10 +0300 | [diff] [blame] | 308 |             if (std::isfinite(value)) | 
 | 309 |             { | 
| Johnathan Mantey | 92217f0 | 2024-06-20 12:43:01 -0700 | [diff] [blame] | 310 |                 min = std::fmin(value, min); | 
| Konstantin Aladyshev | 8265af2 | 2021-12-16 18:18:10 +0300 | [diff] [blame] | 311 |             } | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 312 |         } | 
 | 313 |         if (upper != warning->second.end()) | 
 | 314 |         { | 
 | 315 |             double value = std::visit(VariantToDoubleVisitor(), upper->second); | 
| Konstantin Aladyshev | 8265af2 | 2021-12-16 18:18:10 +0300 | [diff] [blame] | 316 |             if (std::isfinite(value)) | 
 | 317 |             { | 
| Johnathan Mantey | 92217f0 | 2024-06-20 12:43:01 -0700 | [diff] [blame] | 318 |                 max = std::fmax(value, max); | 
| Konstantin Aladyshev | 8265af2 | 2021-12-16 18:18:10 +0300 | [diff] [blame] | 319 |             } | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 320 |         } | 
 | 321 |     } | 
 | 322 | } | 
 | 323 |  | 
 | 324 | static bool getSensorMap(ipmi::Context::ptr ctx, std::string sensorConnection, | 
| Alex Qiu | 9ab2f94 | 2020-07-15 17:56:21 -0700 | [diff] [blame] | 325 |                          std::string sensorPath, DbusInterfaceMap& sensorMap, | 
 | 326 |                          int updatePeriod = sensorMapUpdatePeriod) | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 327 | { | 
| Scron Chang | 2703b02 | 2021-07-06 15:47:45 +0800 | [diff] [blame] | 328 | #ifdef FEATURE_HYBRID_SENSORS | 
 | 329 |     if (auto sensor = findStaticSensor(sensorPath); | 
 | 330 |         sensor != ipmi::sensor::sensors.end() && | 
 | 331 |         getSensorEventTypeFromPath(sensorPath) != | 
 | 332 |             static_cast<uint8_t>(SensorEventTypeCodes::threshold)) | 
 | 333 |     { | 
 | 334 |         // If the incoming sensor is a discrete sensor, it might fail in | 
 | 335 |         // getManagedObjects(), return true, and use its own getFunc to get | 
 | 336 |         // value. | 
 | 337 |         return true; | 
 | 338 |     } | 
 | 339 | #endif | 
 | 340 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 341 |     static boost::container::flat_map< | 
 | 342 |         std::string, std::chrono::time_point<std::chrono::steady_clock>> | 
 | 343 |         updateTimeMap; | 
 | 344 |  | 
 | 345 |     auto updateFind = updateTimeMap.find(sensorConnection); | 
 | 346 |     auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>(); | 
 | 347 |     if (updateFind != updateTimeMap.end()) | 
 | 348 |     { | 
 | 349 |         lastUpdate = updateFind->second; | 
 | 350 |     } | 
 | 351 |  | 
 | 352 |     auto now = std::chrono::steady_clock::now(); | 
 | 353 |  | 
 | 354 |     if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate) | 
| Alex Qiu | 9ab2f94 | 2020-07-15 17:56:21 -0700 | [diff] [blame] | 355 |             .count() > updatePeriod) | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 356 |     { | 
| Sui Chen | c2cb1bc | 2023-01-10 02:52:06 -0800 | [diff] [blame] | 357 |         bool found = false; | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 358 |  | 
| Sui Chen | c2cb1bc | 2023-01-10 02:52:06 -0800 | [diff] [blame] | 359 |         // Object managers for different kinds of OpenBMC DBus interfaces. | 
 | 360 |         // Documented in the phosphor-dbus-interfaces repository. | 
 | 361 |         const char* paths[] = { | 
 | 362 |             "/xyz/openbmc_project/sensors", | 
 | 363 |             "/xyz/openbmc_project/vr", | 
 | 364 |         }; | 
 | 365 |         constexpr size_t num_paths = sizeof(paths) / sizeof(paths[0]); | 
 | 366 |         ObjectValueTree allManagedObjects; | 
 | 367 |  | 
 | 368 |         for (size_t i = 0; i < num_paths; i++) | 
 | 369 |         { | 
 | 370 |             ObjectValueTree managedObjects; | 
 | 371 |             boost::system::error_code ec = getManagedObjects( | 
 | 372 |                 ctx, sensorConnection.c_str(), paths[i], managedObjects); | 
 | 373 |             if (ec) | 
 | 374 |             { | 
| Sui Chen | c2cb1bc | 2023-01-10 02:52:06 -0800 | [diff] [blame] | 375 |                 continue; | 
 | 376 |             } | 
 | 377 |             allManagedObjects.merge(managedObjects); | 
 | 378 |             found = true; | 
 | 379 |         } | 
 | 380 |  | 
 | 381 |         if (!found) | 
 | 382 |         { | 
| Tom Tung | 6615d47 | 2023-05-31 18:48:12 +0800 | [diff] [blame] | 383 |             phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 384 |                 "GetMangagedObjects for getSensorMap failed", | 
 | 385 |                 phosphor::logging::entry("SERVICE=%s", | 
 | 386 |                                          sensorConnection.c_str())); | 
 | 387 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 388 |             return false; | 
 | 389 |         } | 
 | 390 |  | 
| Sui Chen | c2cb1bc | 2023-01-10 02:52:06 -0800 | [diff] [blame] | 391 |         SensorCache[sensorConnection] = allManagedObjects; | 
| Alex Qiu | 9ab2f94 | 2020-07-15 17:56:21 -0700 | [diff] [blame] | 392 |         // Update time after finish building the map which allow the | 
 | 393 |         // data to be cached for updatePeriod plus the build time. | 
 | 394 |         updateTimeMap[sensorConnection] = std::chrono::steady_clock::now(); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 395 |     } | 
 | 396 |     auto connection = SensorCache.find(sensorConnection); | 
 | 397 |     if (connection == SensorCache.end()) | 
 | 398 |     { | 
 | 399 |         return false; | 
 | 400 |     } | 
 | 401 |     auto path = connection->second.find(sensorPath); | 
 | 402 |     if (path == connection->second.end()) | 
 | 403 |     { | 
 | 404 |         return false; | 
 | 405 |     } | 
 | 406 |     sensorMap = path->second; | 
 | 407 |  | 
 | 408 |     return true; | 
 | 409 | } | 
 | 410 |  | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 411 | namespace sensor | 
 | 412 | { | 
| Hao Jiang | d48c921 | 2021-02-03 15:45:06 -0800 | [diff] [blame] | 413 | // Read VR profiles from sensor(daemon) interface | 
 | 414 | static std::optional<std::vector<std::string>> | 
 | 415 |     getSupportedVrProfiles(const ipmi::DbusInterfaceMap::mapped_type& object) | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 416 | { | 
 | 417 |     // get VR mode profiles from Supported Interface | 
| Hao Jiang | d48c921 | 2021-02-03 15:45:06 -0800 | [diff] [blame] | 418 |     auto supportedProperty = object.find("Supported"); | 
 | 419 |     if (supportedProperty == object.end() || | 
 | 420 |         object.find("Selected") == object.end()) | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 421 |     { | 
 | 422 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 423 |             "Missing the required Supported and Selected properties"); | 
 | 424 |         return std::nullopt; | 
 | 425 |     } | 
 | 426 |  | 
 | 427 |     const auto profilesPtr = | 
 | 428 |         std::get_if<std::vector<std::string>>(&supportedProperty->second); | 
 | 429 |  | 
 | 430 |     if (profilesPtr == nullptr) | 
 | 431 |     { | 
 | 432 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 433 |             "property is not array of string"); | 
 | 434 |         return std::nullopt; | 
 | 435 |     } | 
| Hao Jiang | d48c921 | 2021-02-03 15:45:06 -0800 | [diff] [blame] | 436 |     return *profilesPtr; | 
 | 437 | } | 
 | 438 |  | 
 | 439 | // Calculate VR Mode from input IPMI discrete event bytes | 
 | 440 | static std::optional<std::string> | 
 | 441 |     calculateVRMode(uint15_t assertOffset, | 
 | 442 |                     const ipmi::DbusInterfaceMap::mapped_type& VRObject) | 
 | 443 | { | 
 | 444 |     // get VR mode profiles from Supported Interface | 
 | 445 |     auto profiles = getSupportedVrProfiles(VRObject); | 
 | 446 |     if (!profiles) | 
 | 447 |     { | 
 | 448 |         return std::nullopt; | 
 | 449 |     } | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 450 |  | 
 | 451 |     // interpret IPMI cmd bits into profiles' index | 
 | 452 |     long unsigned int index = 0; | 
 | 453 |     // only one bit should be set and the highest bit should not be used. | 
 | 454 |     if (assertOffset == 0 || assertOffset == (1u << 15) || | 
 | 455 |         (assertOffset & (assertOffset - 1))) | 
 | 456 |     { | 
 | 457 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 458 |             "IPMI cmd format incorrect", | 
 | 459 |  | 
 | 460 |             phosphor::logging::entry("BYTES=%#02x", | 
 | 461 |                                      static_cast<uint16_t>(assertOffset))); | 
 | 462 |         return std::nullopt; | 
 | 463 |     } | 
 | 464 |  | 
 | 465 |     while (assertOffset != 1) | 
 | 466 |     { | 
 | 467 |         assertOffset >>= 1; | 
 | 468 |         index++; | 
 | 469 |     } | 
 | 470 |  | 
| Hao Jiang | d48c921 | 2021-02-03 15:45:06 -0800 | [diff] [blame] | 471 |     if (index >= profiles->size()) | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 472 |     { | 
 | 473 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 474 |             "profile index out of boundary"); | 
 | 475 |         return std::nullopt; | 
 | 476 |     } | 
 | 477 |  | 
| Hao Jiang | d48c921 | 2021-02-03 15:45:06 -0800 | [diff] [blame] | 478 |     return profiles->at(index); | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 479 | } | 
 | 480 |  | 
 | 481 | // Calculate sensor value from IPMI reading byte | 
 | 482 | static std::optional<double> | 
 | 483 |     calculateValue(uint8_t reading, const ipmi::DbusInterfaceMap& sensorMap, | 
 | 484 |                    const ipmi::DbusInterfaceMap::mapped_type& valueObject) | 
 | 485 | { | 
 | 486 |     if (valueObject.find("Value") == valueObject.end()) | 
 | 487 |     { | 
 | 488 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 489 |             "Missing the required Value property"); | 
 | 490 |         return std::nullopt; | 
 | 491 |     } | 
 | 492 |  | 
 | 493 |     double max = 0; | 
 | 494 |     double min = 0; | 
 | 495 |     getSensorMaxMin(sensorMap, max, min); | 
 | 496 |  | 
 | 497 |     int16_t mValue = 0; | 
 | 498 |     int16_t bValue = 0; | 
 | 499 |     int8_t rExp = 0; | 
 | 500 |     int8_t bExp = 0; | 
 | 501 |     bool bSigned = false; | 
 | 502 |  | 
 | 503 |     if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned)) | 
 | 504 |     { | 
 | 505 |         return std::nullopt; | 
 | 506 |     } | 
 | 507 |  | 
 | 508 |     double value = bSigned ? ((int8_t)reading) : reading; | 
 | 509 |  | 
 | 510 |     value *= ((double)mValue); | 
 | 511 |     value += ((double)bValue) * std::pow(10.0, bExp); | 
 | 512 |     value *= std::pow(10.0, rExp); | 
 | 513 |  | 
 | 514 |     return value; | 
 | 515 | } | 
 | 516 |  | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 517 | // Extract file name from sensor path as the sensors SDR ID. Simplify the name | 
 | 518 | // if it is too long. | 
 | 519 | std::string parseSdrIdFromPath(const std::string& path) | 
 | 520 | { | 
 | 521 |     std::string name; | 
 | 522 |     size_t nameStart = path.rfind("/"); | 
 | 523 |     if (nameStart != std::string::npos) | 
 | 524 |     { | 
 | 525 |         name = path.substr(nameStart + 1, std::string::npos - nameStart); | 
 | 526 |     } | 
 | 527 |  | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 528 |     if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH) | 
 | 529 |     { | 
| Alexander Hansen | c2c26f9 | 2023-07-17 09:38:43 +0200 | [diff] [blame] | 530 | #ifdef SHORTNAME_REMOVE_SUFFIX | 
| JeffLin | d950f41 | 2021-10-20 18:49:34 +0800 | [diff] [blame] | 531 |         for (const auto& suffix : suffixes) | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 532 |         { | 
| JeffLin | d950f41 | 2021-10-20 18:49:34 +0800 | [diff] [blame] | 533 |             if (boost::ends_with(name, suffix)) | 
 | 534 |             { | 
 | 535 |                 boost::replace_all(name, suffix, ""); | 
 | 536 |                 break; | 
 | 537 |             } | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 538 |         } | 
| Alexander Hansen | c2c26f9 | 2023-07-17 09:38:43 +0200 | [diff] [blame] | 539 | #endif | 
 | 540 | #ifdef SHORTNAME_REPLACE_WORDS | 
 | 541 |         constexpr std::array<std::pair<const char*, const char*>, 2> | 
 | 542 |             replaceWords = {std::make_pair("Output", "Out"), | 
 | 543 |                             std::make_pair("Input", "In")}; | 
 | 544 |         for (const auto& [find, replace] : replaceWords) | 
| Duke Du | 97014f5 | 2021-12-16 17:21:01 +0800 | [diff] [blame] | 545 |         { | 
| Alexander Hansen | c2c26f9 | 2023-07-17 09:38:43 +0200 | [diff] [blame] | 546 |             boost::replace_all(name, find, replace); | 
| Duke Du | 97014f5 | 2021-12-16 17:21:01 +0800 | [diff] [blame] | 547 |         } | 
| Alexander Hansen | c2c26f9 | 2023-07-17 09:38:43 +0200 | [diff] [blame] | 548 | #endif | 
 | 549 |  | 
 | 550 |         // as a backup and if nothing else is configured | 
 | 551 |         name.resize(FULL_RECORD_ID_STR_MAX_LENGTH); | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 552 |     } | 
 | 553 |     return name; | 
 | 554 | } | 
 | 555 |  | 
| Hao Jiang | d48c921 | 2021-02-03 15:45:06 -0800 | [diff] [blame] | 556 | bool getVrEventStatus(ipmi::Context::ptr ctx, const std::string& connection, | 
 | 557 |                       const std::string& path, | 
 | 558 |                       const ipmi::DbusInterfaceMap::mapped_type& object, | 
 | 559 |                       std::bitset<16>& assertions) | 
 | 560 | { | 
 | 561 |     auto profiles = sensor::getSupportedVrProfiles(object); | 
 | 562 |     if (!profiles) | 
 | 563 |     { | 
 | 564 |         return false; | 
 | 565 |     } | 
| Willy Tu | 8366f0b | 2022-04-29 05:00:17 -0700 | [diff] [blame] | 566 |     std::string mode; | 
| Hao Jiang | d48c921 | 2021-02-03 15:45:06 -0800 | [diff] [blame] | 567 |  | 
 | 568 |     auto ec = getDbusProperty(ctx, connection, path, sensor::vrInterface, | 
| Willy Tu | 8366f0b | 2022-04-29 05:00:17 -0700 | [diff] [blame] | 569 |                               "Selected", mode); | 
| Hao Jiang | d48c921 | 2021-02-03 15:45:06 -0800 | [diff] [blame] | 570 |     if (ec) | 
 | 571 |     { | 
 | 572 |         log<level::ERR>("Failed to get property", | 
 | 573 |                         entry("PROPERTY=%s", "Selected"), | 
 | 574 |                         entry("PATH=%s", path.c_str()), | 
 | 575 |                         entry("INTERFACE=%s", sensor::sensorInterface), | 
 | 576 |                         entry("WHAT=%s", ec.message().c_str())); | 
 | 577 |         return false; | 
 | 578 |     } | 
 | 579 |  | 
| Willy Tu | 8366f0b | 2022-04-29 05:00:17 -0700 | [diff] [blame] | 580 |     auto itr = std::find(profiles->begin(), profiles->end(), mode); | 
| Hao Jiang | d48c921 | 2021-02-03 15:45:06 -0800 | [diff] [blame] | 581 |     if (itr == profiles->end()) | 
 | 582 |     { | 
 | 583 |         using namespace phosphor::logging; | 
 | 584 |         log<level::ERR>("VR mode doesn't match any of its profiles", | 
 | 585 |                         entry("PATH=%s", path.c_str())); | 
 | 586 |         return false; | 
 | 587 |     } | 
 | 588 |     std::size_t index = | 
 | 589 |         static_cast<std::size_t>(std::distance(profiles->begin(), itr)); | 
 | 590 |  | 
| Willy Tu | bef102a | 2022-06-09 15:36:09 -0700 | [diff] [blame] | 591 |     // map index to response event assertion bit. | 
 | 592 |     if (index < 16) | 
| Hao Jiang | d48c921 | 2021-02-03 15:45:06 -0800 | [diff] [blame] | 593 |     { | 
| Willy Tu | bef102a | 2022-06-09 15:36:09 -0700 | [diff] [blame] | 594 |         assertions.set(index); | 
| Hao Jiang | d48c921 | 2021-02-03 15:45:06 -0800 | [diff] [blame] | 595 |     } | 
 | 596 |     else | 
 | 597 |     { | 
 | 598 |         log<level::ERR>("VR profile index reaches max assertion bit", | 
 | 599 |                         entry("PATH=%s", path.c_str()), | 
 | 600 |                         entry("INDEX=%uz", index)); | 
 | 601 |         return false; | 
 | 602 |     } | 
 | 603 |     if constexpr (debug) | 
 | 604 |     { | 
 | 605 |         std::cerr << "VR sensor " << sensor::parseSdrIdFromPath(path) | 
| Willy Tu | 8366f0b | 2022-04-29 05:00:17 -0700 | [diff] [blame] | 606 |                   << " mode is: [" << index << "] " << mode << std::endl; | 
| Hao Jiang | d48c921 | 2021-02-03 15:45:06 -0800 | [diff] [blame] | 607 |     } | 
 | 608 |     return true; | 
 | 609 | } | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 610 |  | 
 | 611 | /* | 
 | 612 |  * Handle every Sensor Data Record besides Type 01 | 
 | 613 |  * | 
 | 614 |  * The D-Bus sensors work well for generating Type 01 SDRs. | 
 | 615 |  * After the Type 01 sensors are processed the remaining sensor types require | 
 | 616 |  * special handling. Each BMC vendor is going to have their own requirements for | 
 | 617 |  * insertion of non-Type 01 records. | 
 | 618 |  * Manage non-Type 01 records: | 
 | 619 |  * | 
 | 620 |  * Create a new file: dbus-sdr/sensorcommands_oem.cpp | 
 | 621 |  * Populate it with the two weakly linked functions below, without adding the | 
 | 622 |  * 'weak' attribute definition prior to the function definition. | 
 | 623 |  *    getOtherSensorsCount(...) | 
 | 624 |  *    getOtherSensorsDataRecord(...) | 
 | 625 |  *    Example contents are provided in the weak definitions below | 
 | 626 |  *    Enable 'sensors-oem' in your phosphor-ipmi-host bbappend file | 
 | 627 |  *      'EXTRA_OEMESON:append = " -Dsensors-oem=enabled"' | 
 | 628 |  * The contents of the sensorcommands_oem.cpp file will then override the code | 
 | 629 |  * provided below. | 
 | 630 |  */ | 
 | 631 |  | 
 | 632 | size_t getOtherSensorsCount(ipmi::Context::ptr ctx) __attribute__((weak)); | 
 | 633 | size_t getOtherSensorsCount(ipmi::Context::ptr ctx) | 
 | 634 | { | 
 | 635 |     size_t fruCount = 0; | 
 | 636 |  | 
 | 637 |     ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount); | 
 | 638 |     if (ret != ipmi::ccSuccess) | 
 | 639 |     { | 
 | 640 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 641 |             "getOtherSensorsCount: getFruSdrCount error"); | 
 | 642 |         return std::numeric_limits<size_t>::max(); | 
 | 643 |     } | 
 | 644 |  | 
 | 645 |     const auto& entityRecords = | 
 | 646 |         ipmi::sensor::EntityInfoMapContainer::getContainer() | 
 | 647 |             ->getIpmiEntityRecords(); | 
 | 648 |     size_t entityCount = entityRecords.size(); | 
 | 649 |  | 
 | 650 |     return fruCount + ipmi::storage::type12Count + entityCount; | 
 | 651 | } | 
 | 652 |  | 
 | 653 | int getOtherSensorsDataRecord(ipmi::Context::ptr ctx, uint16_t recordID, | 
 | 654 |                               std::vector<uint8_t>& recordData) | 
 | 655 |     __attribute__((weak)); | 
 | 656 | int getOtherSensorsDataRecord(ipmi::Context::ptr ctx, uint16_t recordID, | 
 | 657 |                               std::vector<uint8_t>& recordData) | 
 | 658 | { | 
 | 659 |     size_t otherCount{ipmi::sensor::getOtherSensorsCount(ctx)}; | 
 | 660 |     if (otherCount == std::numeric_limits<size_t>::max()) | 
 | 661 |     { | 
 | 662 |         return GENERAL_ERROR; | 
 | 663 |     } | 
 | 664 |     const auto& entityRecords = | 
 | 665 |         ipmi::sensor::EntityInfoMapContainer::getContainer() | 
 | 666 |             ->getIpmiEntityRecords(); | 
 | 667 |  | 
 | 668 |     size_t sdrIndex(recordID - ipmi::getNumberOfSensors()); | 
 | 669 |     size_t entityCount{entityRecords.size()}; | 
 | 670 |     size_t fruCount{otherCount - ipmi::storage::type12Count - entityCount}; | 
 | 671 |  | 
 | 672 |     if (sdrIndex > otherCount) | 
 | 673 |     { | 
 | 674 |         return std::numeric_limits<int>::min(); | 
 | 675 |     } | 
 | 676 |     else if (sdrIndex >= fruCount + ipmi::storage::type12Count) | 
 | 677 |     { | 
 | 678 |         // handle type 8 entity map records | 
 | 679 |         ipmi::sensor::EntityInfoMap::const_iterator entity = | 
 | 680 |             entityRecords.find(static_cast<uint8_t>( | 
 | 681 |                 sdrIndex - fruCount - ipmi::storage::type12Count)); | 
 | 682 |  | 
 | 683 |         if (entity == entityRecords.end()) | 
 | 684 |         { | 
 | 685 |             return GENERAL_ERROR; | 
 | 686 |         } | 
 | 687 |         recordData = ipmi::storage::getType8SDRs(entity, recordID); | 
 | 688 |     } | 
 | 689 |     else if (sdrIndex >= fruCount) | 
 | 690 |     { | 
 | 691 |         // handle type 12 hardcoded records | 
 | 692 |         size_t type12Index = sdrIndex - fruCount; | 
 | 693 |         if (type12Index >= ipmi::storage::type12Count) | 
 | 694 |         { | 
 | 695 |             phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 696 |                 "getSensorDataRecord: type12Index error"); | 
 | 697 |             return GENERAL_ERROR; | 
 | 698 |         } | 
 | 699 |         recordData = ipmi::storage::getType12SDRs(type12Index, recordID); | 
 | 700 |     } | 
 | 701 |     else | 
 | 702 |     { | 
 | 703 |         // handle fru records | 
 | 704 |         get_sdr::SensorDataFruRecord data; | 
 | 705 |         if (ipmi::Cc ret = ipmi::storage::getFruSdrs(ctx, sdrIndex, data); | 
 | 706 |             ret != IPMI_CC_OK) | 
 | 707 |         { | 
 | 708 |             return GENERAL_ERROR; | 
 | 709 |         } | 
 | 710 |         data.header.record_id_msb = recordID >> 8; | 
 | 711 |         data.header.record_id_lsb = recordID & 0xFF; | 
 | 712 |         recordData.insert(recordData.end(), reinterpret_cast<uint8_t*>(&data), | 
 | 713 |                           reinterpret_cast<uint8_t*>(&data) + sizeof(data)); | 
 | 714 |     } | 
 | 715 |  | 
 | 716 |     return 0; | 
 | 717 | } | 
 | 718 |  | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 719 | } // namespace sensor | 
 | 720 |  | 
| Chalapathi Venkataramashetty | 6f43f4a | 2021-06-20 19:50:33 +0000 | [diff] [blame] | 721 | ipmi::RspType<> ipmiSenPlatformEvent(ipmi::Context::ptr ctx, | 
 | 722 |                                      ipmi::message::Payload& p) | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 723 | { | 
| Chalapathi Venkataramashetty | 6f43f4a | 2021-06-20 19:50:33 +0000 | [diff] [blame] | 724 |     constexpr const uint8_t validEnvmRev = 0x04; | 
 | 725 |     constexpr const uint8_t lastSensorType = 0x2C; | 
 | 726 |     constexpr const uint8_t oemReserved = 0xC0; | 
 | 727 |  | 
| Sujoy Ray | 3ab2c2b | 2021-11-01 13:17:27 -0700 | [diff] [blame] | 728 |     uint8_t sysgeneratorID = 0; | 
| Chalapathi Venkataramashetty | 6f43f4a | 2021-06-20 19:50:33 +0000 | [diff] [blame] | 729 |     uint8_t evmRev = 0; | 
 | 730 |     uint8_t sensorType = 0; | 
 | 731 |     uint8_t sensorNum = 0; | 
 | 732 |     uint8_t eventType = 0; | 
 | 733 |     uint8_t eventData1 = 0; | 
 | 734 |     std::optional<uint8_t> eventData2 = 0; | 
 | 735 |     std::optional<uint8_t> eventData3 = 0; | 
| Sujoy Ray | 3ab2c2b | 2021-11-01 13:17:27 -0700 | [diff] [blame] | 736 |     [[maybe_unused]] uint16_t generatorID = 0; | 
| Chalapathi Venkataramashetty | 6f43f4a | 2021-06-20 19:50:33 +0000 | [diff] [blame] | 737 |     ipmi::ChannelInfo chInfo; | 
 | 738 |  | 
 | 739 |     if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess) | 
 | 740 |     { | 
 | 741 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 742 |             "Failed to get Channel Info", | 
 | 743 |             phosphor::logging::entry("CHANNEL=%d", ctx->channel)); | 
 | 744 |         return ipmi::responseUnspecifiedError(); | 
 | 745 |     } | 
 | 746 |  | 
 | 747 |     if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) == | 
 | 748 |         ipmi::EChannelMediumType::systemInterface) | 
 | 749 |     { | 
| Sujoy Ray | 3ab2c2b | 2021-11-01 13:17:27 -0700 | [diff] [blame] | 750 |         p.unpack(sysgeneratorID, evmRev, sensorType, sensorNum, eventType, | 
| Chalapathi Venkataramashetty | 6f43f4a | 2021-06-20 19:50:33 +0000 | [diff] [blame] | 751 |                  eventData1, eventData2, eventData3); | 
| Johnathan Mantey | a440cd4 | 2024-06-20 13:21:48 -0700 | [diff] [blame^] | 752 |         constexpr const uint8_t isSoftwareID = 0x01; | 
 | 753 |         if (!(sysgeneratorID & isSoftwareID)) | 
 | 754 |         { | 
 | 755 |             return ipmi::responseInvalidFieldRequest(); | 
 | 756 |         } | 
| Sujoy Ray | 3ab2c2b | 2021-11-01 13:17:27 -0700 | [diff] [blame] | 757 |         // Refer to IPMI Spec Table 32: SEL Event Records | 
 | 758 |         generatorID = (ctx->channel << 12) // Channel | 
 | 759 |                       | (0x0 << 10)        // Reserved | 
 | 760 |                       | (0x0 << 8)         // 0x0 for sys-soft ID | 
| Johnathan Mantey | a440cd4 | 2024-06-20 13:21:48 -0700 | [diff] [blame^] | 761 |                       | sysgeneratorID; | 
| Chalapathi Venkataramashetty | 6f43f4a | 2021-06-20 19:50:33 +0000 | [diff] [blame] | 762 |     } | 
 | 763 |     else | 
 | 764 |     { | 
| Chalapathi Venkataramashetty | 6f43f4a | 2021-06-20 19:50:33 +0000 | [diff] [blame] | 765 |         p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1, | 
 | 766 |                  eventData2, eventData3); | 
| Sujoy Ray | 3ab2c2b | 2021-11-01 13:17:27 -0700 | [diff] [blame] | 767 |         // Refer to IPMI Spec Table 32: SEL Event Records | 
 | 768 |         generatorID = (ctx->channel << 12)      // Channel | 
 | 769 |                       | (0x0 << 10)             // Reserved | 
 | 770 |                       | ((ctx->lun & 0x3) << 8) // Lun | 
 | 771 |                       | (ctx->rqSA << 1); | 
| Chalapathi Venkataramashetty | 6f43f4a | 2021-06-20 19:50:33 +0000 | [diff] [blame] | 772 |     } | 
 | 773 |  | 
 | 774 |     if (!p.fullyUnpacked()) | 
 | 775 |     { | 
 | 776 |         return ipmi::responseReqDataLenInvalid(); | 
 | 777 |     } | 
 | 778 |  | 
 | 779 |     // Check for valid evmRev and Sensor Type(per Table 42 of spec) | 
 | 780 |     if (evmRev != validEnvmRev) | 
 | 781 |     { | 
 | 782 |         return ipmi::responseInvalidFieldRequest(); | 
 | 783 |     } | 
 | 784 |     if ((sensorType > lastSensorType) && (sensorType < oemReserved)) | 
 | 785 |     { | 
 | 786 |         return ipmi::responseInvalidFieldRequest(); | 
 | 787 |     } | 
 | 788 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 789 |     return ipmi::responseSuccess(); | 
 | 790 | } | 
 | 791 |  | 
| Willy Tu | dbafbce | 2021-03-29 00:37:05 -0700 | [diff] [blame] | 792 | ipmi::RspType<> ipmiSetSensorReading(ipmi::Context::ptr ctx, | 
| Willy Tu | 11d6889 | 2022-01-20 10:37:34 -0800 | [diff] [blame] | 793 |                                      uint8_t sensorNumber, uint8_t, | 
| Willy Tu | dbafbce | 2021-03-29 00:37:05 -0700 | [diff] [blame] | 794 |                                      uint8_t reading, uint15_t assertOffset, | 
| Willy Tu | 11d6889 | 2022-01-20 10:37:34 -0800 | [diff] [blame] | 795 |                                      bool, uint15_t, bool, uint8_t, uint8_t, | 
 | 796 |                                      uint8_t) | 
| Willy Tu | dbafbce | 2021-03-29 00:37:05 -0700 | [diff] [blame] | 797 | { | 
 | 798 |     std::string connection; | 
 | 799 |     std::string path; | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 800 |     std::vector<std::string> interfaces; | 
 | 801 |  | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 802 |     ipmi::Cc status = getSensorConnection(ctx, sensorNumber, connection, path, | 
 | 803 |                                           &interfaces); | 
| Willy Tu | dbafbce | 2021-03-29 00:37:05 -0700 | [diff] [blame] | 804 |     if (status) | 
 | 805 |     { | 
 | 806 |         return ipmi::response(status); | 
 | 807 |     } | 
 | 808 |  | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 809 |     // we can tell the sensor type by its interface type | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 810 |     if (std::find(interfaces.begin(), interfaces.end(), | 
 | 811 |                   sensor::sensorInterface) != interfaces.end()) | 
| Willy Tu | dbafbce | 2021-03-29 00:37:05 -0700 | [diff] [blame] | 812 |     { | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 813 |         DbusInterfaceMap sensorMap; | 
 | 814 |         if (!getSensorMap(ctx, connection, path, sensorMap)) | 
 | 815 |         { | 
 | 816 |             return ipmi::responseResponseError(); | 
 | 817 |         } | 
 | 818 |         auto sensorObject = sensorMap.find(sensor::sensorInterface); | 
| Harvey Wu | f61c086 | 2021-09-15 08:48:40 +0800 | [diff] [blame] | 819 |         if (sensorObject == sensorMap.end()) | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 820 |         { | 
 | 821 |             return ipmi::responseResponseError(); | 
 | 822 |         } | 
 | 823 |  | 
| Jie Yang | f0a8994 | 2021-07-29 15:30:25 -0700 | [diff] [blame] | 824 |         // Only allow external SetSensor if write permission granted | 
| Harvey.Wu | 0e7a8af | 2022-06-10 16:46:46 +0800 | [diff] [blame] | 825 |         if (!details::sdrWriteTable.getWritePermission((ctx->lun << 8) | | 
 | 826 |                                                        sensorNumber)) | 
| Jie Yang | f0a8994 | 2021-07-29 15:30:25 -0700 | [diff] [blame] | 827 |         { | 
 | 828 |             return ipmi::responseResponseError(); | 
 | 829 |         } | 
 | 830 |  | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 831 |         auto value = sensor::calculateValue(reading, sensorMap, | 
 | 832 |                                             sensorObject->second); | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 833 |         if (!value) | 
 | 834 |         { | 
 | 835 |             return ipmi::responseResponseError(); | 
 | 836 |         } | 
 | 837 |  | 
 | 838 |         if constexpr (debug) | 
 | 839 |         { | 
 | 840 |             phosphor::logging::log<phosphor::logging::level::INFO>( | 
 | 841 |                 "IPMI SET_SENSOR", | 
 | 842 |                 phosphor::logging::entry("SENSOR_NUM=%d", sensorNumber), | 
 | 843 |                 phosphor::logging::entry("BYTE=%u", (unsigned int)reading), | 
 | 844 |                 phosphor::logging::entry("VALUE=%f", *value)); | 
 | 845 |         } | 
 | 846 |  | 
 | 847 |         boost::system::error_code ec = | 
 | 848 |             setDbusProperty(ctx, connection, path, sensor::sensorInterface, | 
 | 849 |                             "Value", ipmi::Value(*value)); | 
 | 850 |  | 
 | 851 |         // setDbusProperty intended to resolve dbus exception/rc within the | 
| Patrick Williams | ef1259b | 2021-09-02 09:12:33 -0500 | [diff] [blame] | 852 |         // function but failed to achieve that. Catch exception in the ipmi | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 853 |         // callback functions for now (e.g. ipmiSetSensorReading). | 
 | 854 |         if (ec) | 
 | 855 |         { | 
 | 856 |             using namespace phosphor::logging; | 
 | 857 |             log<level::ERR>("Failed to set property", | 
 | 858 |                             entry("PROPERTY=%s", "Value"), | 
 | 859 |                             entry("PATH=%s", path.c_str()), | 
 | 860 |                             entry("INTERFACE=%s", sensor::sensorInterface), | 
 | 861 |                             entry("WHAT=%s", ec.message().c_str())); | 
 | 862 |             return ipmi::responseResponseError(); | 
 | 863 |         } | 
 | 864 |         return ipmi::responseSuccess(); | 
| Willy Tu | dbafbce | 2021-03-29 00:37:05 -0700 | [diff] [blame] | 865 |     } | 
 | 866 |  | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 867 |     if (std::find(interfaces.begin(), interfaces.end(), sensor::vrInterface) != | 
 | 868 |         interfaces.end()) | 
| Willy Tu | dbafbce | 2021-03-29 00:37:05 -0700 | [diff] [blame] | 869 |     { | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 870 |         DbusInterfaceMap sensorMap; | 
 | 871 |         if (!getSensorMap(ctx, connection, path, sensorMap)) | 
 | 872 |         { | 
 | 873 |             return ipmi::responseResponseError(); | 
 | 874 |         } | 
 | 875 |         auto sensorObject = sensorMap.find(sensor::vrInterface); | 
| Harvey Wu | f61c086 | 2021-09-15 08:48:40 +0800 | [diff] [blame] | 876 |         if (sensorObject == sensorMap.end()) | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 877 |         { | 
 | 878 |             return ipmi::responseResponseError(); | 
 | 879 |         } | 
 | 880 |  | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 881 |         // VR sensors are treated as a special case and we will not check the | 
 | 882 |         // write permission for VR sensors, since they always deemed writable | 
 | 883 |         // and permission table are not applied to VR sensors. | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 884 |         auto vrMode = sensor::calculateVRMode(assertOffset, | 
 | 885 |                                               sensorObject->second); | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 886 |         if (!vrMode) | 
 | 887 |         { | 
 | 888 |             return ipmi::responseResponseError(); | 
 | 889 |         } | 
 | 890 |         boost::system::error_code ec = setDbusProperty( | 
 | 891 |             ctx, connection, path, sensor::vrInterface, "Selected", *vrMode); | 
 | 892 |         // setDbusProperty intended to resolve dbus exception/rc within the | 
| Patrick Williams | ef1259b | 2021-09-02 09:12:33 -0500 | [diff] [blame] | 893 |         // function but failed to achieve that. Catch exception in the ipmi | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 894 |         // callback functions for now (e.g. ipmiSetSensorReading). | 
 | 895 |         if (ec) | 
 | 896 |         { | 
 | 897 |             using namespace phosphor::logging; | 
 | 898 |             log<level::ERR>("Failed to set property", | 
 | 899 |                             entry("PROPERTY=%s", "Selected"), | 
 | 900 |                             entry("PATH=%s", path.c_str()), | 
 | 901 |                             entry("INTERFACE=%s", sensor::sensorInterface), | 
 | 902 |                             entry("WHAT=%s", ec.message().c_str())); | 
 | 903 |             return ipmi::responseResponseError(); | 
 | 904 |         } | 
 | 905 |         return ipmi::responseSuccess(); | 
| Willy Tu | dbafbce | 2021-03-29 00:37:05 -0700 | [diff] [blame] | 906 |     } | 
 | 907 |  | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 908 |     phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 909 |         "unknown sensor type", | 
 | 910 |         phosphor::logging::entry("PATH=%s", path.c_str())); | 
 | 911 |     return ipmi::responseResponseError(); | 
| Willy Tu | dbafbce | 2021-03-29 00:37:05 -0700 | [diff] [blame] | 912 | } | 
 | 913 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 914 | ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>> | 
 | 915 |     ipmiSenGetSensorReading(ipmi::Context::ptr ctx, uint8_t sensnum) | 
 | 916 | { | 
 | 917 |     std::string connection; | 
 | 918 |     std::string path; | 
 | 919 |  | 
| Chalapathi Venkataramashetty | 8c2f3c4 | 2021-06-13 19:51:17 +0000 | [diff] [blame] | 920 |     if (sensnum == reservedSensorNumber) | 
 | 921 |     { | 
 | 922 |         return ipmi::responseInvalidFieldRequest(); | 
 | 923 |     } | 
 | 924 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 925 |     auto status = getSensorConnection(ctx, sensnum, connection, path); | 
 | 926 |     if (status) | 
 | 927 |     { | 
 | 928 |         return ipmi::response(status); | 
 | 929 |     } | 
 | 930 |  | 
| Scron Chang | 2703b02 | 2021-07-06 15:47:45 +0800 | [diff] [blame] | 931 | #ifdef FEATURE_HYBRID_SENSORS | 
 | 932 |     if (auto sensor = findStaticSensor(path); | 
 | 933 |         sensor != ipmi::sensor::sensors.end() && | 
 | 934 |         getSensorEventTypeFromPath(path) != | 
 | 935 |             static_cast<uint8_t>(SensorEventTypeCodes::threshold)) | 
 | 936 |     { | 
 | 937 |         if (ipmi::sensor::Mutability::Read != | 
 | 938 |             (sensor->second.mutability & ipmi::sensor::Mutability::Read)) | 
 | 939 |         { | 
 | 940 |             return ipmi::responseIllegalCommand(); | 
 | 941 |         } | 
 | 942 |  | 
 | 943 |         uint8_t operation; | 
 | 944 |         try | 
 | 945 |         { | 
 | 946 |             ipmi::sensor::GetSensorResponse getResponse = | 
 | 947 |                 sensor->second.getFunc(sensor->second); | 
 | 948 |  | 
 | 949 |             if (getResponse.readingOrStateUnavailable) | 
 | 950 |             { | 
 | 951 |                 operation |= static_cast<uint8_t>( | 
 | 952 |                     IPMISensorReadingByte2::readingStateUnavailable); | 
 | 953 |             } | 
 | 954 |             if (getResponse.scanningEnabled) | 
 | 955 |             { | 
 | 956 |                 operation |= static_cast<uint8_t>( | 
 | 957 |                     IPMISensorReadingByte2::sensorScanningEnable); | 
 | 958 |             } | 
 | 959 |             if (getResponse.allEventMessagesEnabled) | 
 | 960 |             { | 
 | 961 |                 operation |= static_cast<uint8_t>( | 
 | 962 |                     IPMISensorReadingByte2::eventMessagesEnable); | 
 | 963 |             } | 
 | 964 |             return ipmi::responseSuccess( | 
 | 965 |                 getResponse.reading, operation, | 
 | 966 |                 getResponse.thresholdLevelsStates, | 
 | 967 |                 getResponse.discreteReadingSensorStates); | 
 | 968 |         } | 
 | 969 |         catch (const std::exception& e) | 
 | 970 |         { | 
 | 971 |             operation |= static_cast<uint8_t>( | 
 | 972 |                 IPMISensorReadingByte2::readingStateUnavailable); | 
 | 973 |             return ipmi::responseSuccess(0, operation, 0, std::nullopt); | 
 | 974 |         } | 
 | 975 |     } | 
 | 976 | #endif | 
 | 977 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 978 |     DbusInterfaceMap sensorMap; | 
 | 979 |     if (!getSensorMap(ctx, connection, path, sensorMap)) | 
 | 980 |     { | 
 | 981 |         return ipmi::responseResponseError(); | 
 | 982 |     } | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 983 |     auto sensorObject = sensorMap.find(sensor::sensorInterface); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 984 |  | 
 | 985 |     if (sensorObject == sensorMap.end() || | 
 | 986 |         sensorObject->second.find("Value") == sensorObject->second.end()) | 
 | 987 |     { | 
 | 988 |         return ipmi::responseResponseError(); | 
 | 989 |     } | 
 | 990 |     auto& valueVariant = sensorObject->second["Value"]; | 
 | 991 |     double reading = std::visit(VariantToDoubleVisitor(), valueVariant); | 
 | 992 |  | 
 | 993 |     double max = 0; | 
 | 994 |     double min = 0; | 
 | 995 |     getSensorMaxMin(sensorMap, max, min); | 
 | 996 |  | 
 | 997 |     int16_t mValue = 0; | 
 | 998 |     int16_t bValue = 0; | 
 | 999 |     int8_t rExp = 0; | 
 | 1000 |     int8_t bExp = 0; | 
 | 1001 |     bool bSigned = false; | 
 | 1002 |  | 
 | 1003 |     if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned)) | 
 | 1004 |     { | 
 | 1005 |         return ipmi::responseResponseError(); | 
 | 1006 |     } | 
 | 1007 |  | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 1008 |     uint8_t value = scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, | 
 | 1009 |                                              bExp, bSigned); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1010 |     uint8_t operation = | 
 | 1011 |         static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable); | 
 | 1012 |     operation |= | 
 | 1013 |         static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable); | 
 | 1014 |     bool notReading = std::isnan(reading); | 
 | 1015 |  | 
 | 1016 |     if (!notReading) | 
 | 1017 |     { | 
 | 1018 |         auto availableObject = | 
 | 1019 |             sensorMap.find("xyz.openbmc_project.State.Decorator.Availability"); | 
 | 1020 |         if (availableObject != sensorMap.end()) | 
 | 1021 |         { | 
 | 1022 |             auto findAvailable = availableObject->second.find("Available"); | 
 | 1023 |             if (findAvailable != availableObject->second.end()) | 
 | 1024 |             { | 
 | 1025 |                 bool* available = std::get_if<bool>(&(findAvailable->second)); | 
 | 1026 |                 if (available && !(*available)) | 
 | 1027 |                 { | 
 | 1028 |                     notReading = true; | 
 | 1029 |                 } | 
 | 1030 |             } | 
 | 1031 |         } | 
 | 1032 |     } | 
 | 1033 |  | 
 | 1034 |     if (notReading) | 
 | 1035 |     { | 
 | 1036 |         operation |= static_cast<uint8_t>( | 
 | 1037 |             IPMISensorReadingByte2::readingStateUnavailable); | 
 | 1038 |     } | 
 | 1039 |  | 
| Josh Lehan | a55c953 | 2020-10-28 21:59:06 -0700 | [diff] [blame] | 1040 |     if constexpr (details::enableInstrumentation) | 
 | 1041 |     { | 
 | 1042 |         int byteValue; | 
 | 1043 |         if (bSigned) | 
 | 1044 |         { | 
 | 1045 |             byteValue = static_cast<int>(static_cast<int8_t>(value)); | 
 | 1046 |         } | 
 | 1047 |         else | 
 | 1048 |         { | 
 | 1049 |             byteValue = static_cast<int>(static_cast<uint8_t>(value)); | 
 | 1050 |         } | 
 | 1051 |  | 
 | 1052 |         // Keep stats on the reading just obtained, even if it is "NaN" | 
| Harvey.Wu | 0e7a8af | 2022-06-10 16:46:46 +0800 | [diff] [blame] | 1053 |         if (details::sdrStatsTable.updateReading((ctx->lun << 8) | sensnum, | 
 | 1054 |                                                  reading, byteValue)) | 
| Josh Lehan | a55c953 | 2020-10-28 21:59:06 -0700 | [diff] [blame] | 1055 |         { | 
 | 1056 |             // This is the first reading, show the coefficients | 
 | 1057 |             double step = (max - min) / 255.0; | 
 | 1058 |             std::cerr << "IPMI sensor " | 
| Harvey.Wu | 0e7a8af | 2022-06-10 16:46:46 +0800 | [diff] [blame] | 1059 |                       << details::sdrStatsTable.getName((ctx->lun << 8) | | 
 | 1060 |                                                         sensnum) | 
| Josh Lehan | a55c953 | 2020-10-28 21:59:06 -0700 | [diff] [blame] | 1061 |                       << ": Range min=" << min << " max=" << max | 
 | 1062 |                       << ", step=" << step | 
 | 1063 |                       << ", Coefficients mValue=" << static_cast<int>(mValue) | 
 | 1064 |                       << " rExp=" << static_cast<int>(rExp) | 
 | 1065 |                       << " bValue=" << static_cast<int>(bValue) | 
 | 1066 |                       << " bExp=" << static_cast<int>(bExp) | 
 | 1067 |                       << " bSigned=" << static_cast<int>(bSigned) << "\n"; | 
 | 1068 |         } | 
 | 1069 |     } | 
 | 1070 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1071 |     uint8_t thresholds = 0; | 
 | 1072 |  | 
 | 1073 |     auto warningObject = | 
 | 1074 |         sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning"); | 
 | 1075 |     if (warningObject != sensorMap.end()) | 
 | 1076 |     { | 
 | 1077 |         auto alarmHigh = warningObject->second.find("WarningAlarmHigh"); | 
 | 1078 |         auto alarmLow = warningObject->second.find("WarningAlarmLow"); | 
 | 1079 |         if (alarmHigh != warningObject->second.end()) | 
 | 1080 |         { | 
 | 1081 |             if (std::get<bool>(alarmHigh->second)) | 
 | 1082 |             { | 
 | 1083 |                 thresholds |= static_cast<uint8_t>( | 
 | 1084 |                     IPMISensorReadingByte3::upperNonCritical); | 
 | 1085 |             } | 
 | 1086 |         } | 
 | 1087 |         if (alarmLow != warningObject->second.end()) | 
 | 1088 |         { | 
 | 1089 |             if (std::get<bool>(alarmLow->second)) | 
 | 1090 |             { | 
 | 1091 |                 thresholds |= static_cast<uint8_t>( | 
 | 1092 |                     IPMISensorReadingByte3::lowerNonCritical); | 
 | 1093 |             } | 
 | 1094 |         } | 
 | 1095 |     } | 
 | 1096 |  | 
 | 1097 |     auto criticalObject = | 
 | 1098 |         sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical"); | 
 | 1099 |     if (criticalObject != sensorMap.end()) | 
 | 1100 |     { | 
 | 1101 |         auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh"); | 
 | 1102 |         auto alarmLow = criticalObject->second.find("CriticalAlarmLow"); | 
 | 1103 |         if (alarmHigh != criticalObject->second.end()) | 
 | 1104 |         { | 
 | 1105 |             if (std::get<bool>(alarmHigh->second)) | 
 | 1106 |             { | 
 | 1107 |                 thresholds |= | 
 | 1108 |                     static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical); | 
 | 1109 |             } | 
 | 1110 |         } | 
 | 1111 |         if (alarmLow != criticalObject->second.end()) | 
 | 1112 |         { | 
 | 1113 |             if (std::get<bool>(alarmLow->second)) | 
 | 1114 |             { | 
 | 1115 |                 thresholds |= | 
 | 1116 |                     static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical); | 
 | 1117 |             } | 
 | 1118 |         } | 
 | 1119 |     } | 
 | 1120 |  | 
 | 1121 |     // no discrete as of today so optional byte is never returned | 
 | 1122 |     return ipmi::responseSuccess(value, operation, thresholds, std::nullopt); | 
 | 1123 | } | 
 | 1124 |  | 
 | 1125 | /** @brief implements the Set Sensor threshold command | 
 | 1126 |  *  @param sensorNumber        - sensor number | 
 | 1127 |  *  @param lowerNonCriticalThreshMask | 
 | 1128 |  *  @param lowerCriticalThreshMask | 
 | 1129 |  *  @param lowerNonRecovThreshMask | 
 | 1130 |  *  @param upperNonCriticalThreshMask | 
 | 1131 |  *  @param upperCriticalThreshMask | 
 | 1132 |  *  @param upperNonRecovThreshMask | 
 | 1133 |  *  @param reserved | 
 | 1134 |  *  @param lowerNonCritical    - lower non-critical threshold | 
 | 1135 |  *  @param lowerCritical       - Lower critical threshold | 
 | 1136 |  *  @param lowerNonRecoverable - Lower non recovarable threshold | 
 | 1137 |  *  @param upperNonCritical    - Upper non-critical threshold | 
 | 1138 |  *  @param upperCritical       - Upper critical | 
 | 1139 |  *  @param upperNonRecoverable - Upper Non-recoverable | 
 | 1140 |  * | 
 | 1141 |  *  @returns IPMI completion code | 
 | 1142 |  */ | 
 | 1143 | ipmi::RspType<> ipmiSenSetSensorThresholds( | 
 | 1144 |     ipmi::Context::ptr ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask, | 
 | 1145 |     bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask, | 
 | 1146 |     bool upperNonCriticalThreshMask, bool upperCriticalThreshMask, | 
 | 1147 |     bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical, | 
| Willy Tu | 11d6889 | 2022-01-20 10:37:34 -0800 | [diff] [blame] | 1148 |     uint8_t lowerCritical, [[maybe_unused]] uint8_t lowerNonRecoverable, | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1149 |     uint8_t upperNonCritical, uint8_t upperCritical, | 
| Willy Tu | 11d6889 | 2022-01-20 10:37:34 -0800 | [diff] [blame] | 1150 |     [[maybe_unused]] uint8_t upperNonRecoverable) | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1151 | { | 
| Chalapathi Venkataramashetty | 8c2f3c4 | 2021-06-13 19:51:17 +0000 | [diff] [blame] | 1152 |     if (sensorNum == reservedSensorNumber || reserved) | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1153 |     { | 
 | 1154 |         return ipmi::responseInvalidFieldRequest(); | 
 | 1155 |     } | 
 | 1156 |  | 
 | 1157 |     // lower nc and upper nc not suppported on any sensor | 
 | 1158 |     if (lowerNonRecovThreshMask || upperNonRecovThreshMask) | 
 | 1159 |     { | 
 | 1160 |         return ipmi::responseInvalidFieldRequest(); | 
 | 1161 |     } | 
 | 1162 |  | 
 | 1163 |     // if none of the threshold mask are set, nothing to do | 
 | 1164 |     if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask | | 
 | 1165 |           lowerNonRecovThreshMask | upperNonCriticalThreshMask | | 
 | 1166 |           upperCriticalThreshMask | upperNonRecovThreshMask)) | 
 | 1167 |     { | 
 | 1168 |         return ipmi::responseSuccess(); | 
 | 1169 |     } | 
 | 1170 |  | 
 | 1171 |     std::string connection; | 
 | 1172 |     std::string path; | 
 | 1173 |  | 
 | 1174 |     ipmi::Cc status = getSensorConnection(ctx, sensorNum, connection, path); | 
 | 1175 |     if (status) | 
 | 1176 |     { | 
 | 1177 |         return ipmi::response(status); | 
 | 1178 |     } | 
 | 1179 |     DbusInterfaceMap sensorMap; | 
 | 1180 |     if (!getSensorMap(ctx, connection, path, sensorMap)) | 
 | 1181 |     { | 
 | 1182 |         return ipmi::responseResponseError(); | 
 | 1183 |     } | 
 | 1184 |  | 
 | 1185 |     double max = 0; | 
 | 1186 |     double min = 0; | 
 | 1187 |     getSensorMaxMin(sensorMap, max, min); | 
 | 1188 |  | 
 | 1189 |     int16_t mValue = 0; | 
 | 1190 |     int16_t bValue = 0; | 
 | 1191 |     int8_t rExp = 0; | 
 | 1192 |     int8_t bExp = 0; | 
 | 1193 |     bool bSigned = false; | 
 | 1194 |  | 
 | 1195 |     if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned)) | 
 | 1196 |     { | 
 | 1197 |         return ipmi::responseResponseError(); | 
 | 1198 |     } | 
 | 1199 |  | 
 | 1200 |     // store a vector of property name, value to set, and interface | 
 | 1201 |     std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet; | 
 | 1202 |  | 
 | 1203 |     // define the indexes of the tuple | 
 | 1204 |     constexpr uint8_t propertyName = 0; | 
 | 1205 |     constexpr uint8_t thresholdValue = 1; | 
 | 1206 |     constexpr uint8_t interface = 2; | 
 | 1207 |     // verifiy all needed fields are present | 
 | 1208 |     if (lowerCriticalThreshMask || upperCriticalThreshMask) | 
 | 1209 |     { | 
 | 1210 |         auto findThreshold = | 
 | 1211 |             sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical"); | 
 | 1212 |         if (findThreshold == sensorMap.end()) | 
 | 1213 |         { | 
 | 1214 |             return ipmi::responseInvalidFieldRequest(); | 
 | 1215 |         } | 
 | 1216 |         if (lowerCriticalThreshMask) | 
 | 1217 |         { | 
 | 1218 |             auto findLower = findThreshold->second.find("CriticalLow"); | 
 | 1219 |             if (findLower == findThreshold->second.end()) | 
 | 1220 |             { | 
 | 1221 |                 return ipmi::responseInvalidFieldRequest(); | 
 | 1222 |             } | 
 | 1223 |             thresholdsToSet.emplace_back("CriticalLow", lowerCritical, | 
 | 1224 |                                          findThreshold->first); | 
 | 1225 |         } | 
 | 1226 |         if (upperCriticalThreshMask) | 
 | 1227 |         { | 
 | 1228 |             auto findUpper = findThreshold->second.find("CriticalHigh"); | 
 | 1229 |             if (findUpper == findThreshold->second.end()) | 
 | 1230 |             { | 
 | 1231 |                 return ipmi::responseInvalidFieldRequest(); | 
 | 1232 |             } | 
 | 1233 |             thresholdsToSet.emplace_back("CriticalHigh", upperCritical, | 
 | 1234 |                                          findThreshold->first); | 
 | 1235 |         } | 
 | 1236 |     } | 
 | 1237 |     if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask) | 
 | 1238 |     { | 
 | 1239 |         auto findThreshold = | 
 | 1240 |             sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning"); | 
 | 1241 |         if (findThreshold == sensorMap.end()) | 
 | 1242 |         { | 
 | 1243 |             return ipmi::responseInvalidFieldRequest(); | 
 | 1244 |         } | 
 | 1245 |         if (lowerNonCriticalThreshMask) | 
 | 1246 |         { | 
 | 1247 |             auto findLower = findThreshold->second.find("WarningLow"); | 
 | 1248 |             if (findLower == findThreshold->second.end()) | 
 | 1249 |             { | 
 | 1250 |                 return ipmi::responseInvalidFieldRequest(); | 
 | 1251 |             } | 
 | 1252 |             thresholdsToSet.emplace_back("WarningLow", lowerNonCritical, | 
 | 1253 |                                          findThreshold->first); | 
 | 1254 |         } | 
 | 1255 |         if (upperNonCriticalThreshMask) | 
 | 1256 |         { | 
 | 1257 |             auto findUpper = findThreshold->second.find("WarningHigh"); | 
 | 1258 |             if (findUpper == findThreshold->second.end()) | 
 | 1259 |             { | 
 | 1260 |                 return ipmi::responseInvalidFieldRequest(); | 
 | 1261 |             } | 
 | 1262 |             thresholdsToSet.emplace_back("WarningHigh", upperNonCritical, | 
 | 1263 |                                          findThreshold->first); | 
 | 1264 |         } | 
 | 1265 |     } | 
 | 1266 |     for (const auto& property : thresholdsToSet) | 
 | 1267 |     { | 
 | 1268 |         // from section 36.3 in the IPMI Spec, assume all linear | 
 | 1269 |         double valueToSet = ((mValue * std::get<thresholdValue>(property)) + | 
 | 1270 |                              (bValue * std::pow(10.0, bExp))) * | 
 | 1271 |                             std::pow(10.0, rExp); | 
 | 1272 |         setDbusProperty( | 
 | 1273 |             *getSdBus(), connection, path, std::get<interface>(property), | 
 | 1274 |             std::get<propertyName>(property), ipmi::Value(valueToSet)); | 
 | 1275 |     } | 
 | 1276 |     return ipmi::responseSuccess(); | 
 | 1277 | } | 
 | 1278 |  | 
 | 1279 | IPMIThresholds getIPMIThresholds(const DbusInterfaceMap& sensorMap) | 
 | 1280 | { | 
 | 1281 |     IPMIThresholds resp; | 
 | 1282 |     auto warningInterface = | 
 | 1283 |         sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning"); | 
 | 1284 |     auto criticalInterface = | 
 | 1285 |         sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical"); | 
 | 1286 |  | 
 | 1287 |     if ((warningInterface != sensorMap.end()) || | 
 | 1288 |         (criticalInterface != sensorMap.end())) | 
 | 1289 |     { | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 1290 |         auto sensorPair = sensorMap.find(sensor::sensorInterface); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1291 |  | 
 | 1292 |         if (sensorPair == sensorMap.end()) | 
 | 1293 |         { | 
 | 1294 |             // should not have been able to find a sensor not implementing | 
 | 1295 |             // the sensor object | 
 | 1296 |             throw std::runtime_error("Invalid sensor map"); | 
 | 1297 |         } | 
 | 1298 |  | 
 | 1299 |         double max = 0; | 
 | 1300 |         double min = 0; | 
 | 1301 |         getSensorMaxMin(sensorMap, max, min); | 
 | 1302 |  | 
 | 1303 |         int16_t mValue = 0; | 
 | 1304 |         int16_t bValue = 0; | 
 | 1305 |         int8_t rExp = 0; | 
 | 1306 |         int8_t bExp = 0; | 
 | 1307 |         bool bSigned = false; | 
 | 1308 |  | 
 | 1309 |         if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned)) | 
 | 1310 |         { | 
 | 1311 |             throw std::runtime_error("Invalid sensor atrributes"); | 
 | 1312 |         } | 
 | 1313 |         if (warningInterface != sensorMap.end()) | 
 | 1314 |         { | 
 | 1315 |             auto& warningMap = warningInterface->second; | 
 | 1316 |  | 
 | 1317 |             auto warningHigh = warningMap.find("WarningHigh"); | 
 | 1318 |             auto warningLow = warningMap.find("WarningLow"); | 
 | 1319 |  | 
 | 1320 |             if (warningHigh != warningMap.end()) | 
 | 1321 |             { | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 1322 |                 double value = std::visit(VariantToDoubleVisitor(), | 
 | 1323 |                                           warningHigh->second); | 
| Konstantin Aladyshev | 8265af2 | 2021-12-16 18:18:10 +0300 | [diff] [blame] | 1324 |                 if (std::isfinite(value)) | 
 | 1325 |                 { | 
 | 1326 |                     resp.warningHigh = scaleIPMIValueFromDouble( | 
 | 1327 |                         value, mValue, rExp, bValue, bExp, bSigned); | 
 | 1328 |                 } | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1329 |             } | 
 | 1330 |             if (warningLow != warningMap.end()) | 
 | 1331 |             { | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 1332 |                 double value = std::visit(VariantToDoubleVisitor(), | 
 | 1333 |                                           warningLow->second); | 
| Konstantin Aladyshev | 8265af2 | 2021-12-16 18:18:10 +0300 | [diff] [blame] | 1334 |                 if (std::isfinite(value)) | 
 | 1335 |                 { | 
 | 1336 |                     resp.warningLow = scaleIPMIValueFromDouble( | 
 | 1337 |                         value, mValue, rExp, bValue, bExp, bSigned); | 
 | 1338 |                 } | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1339 |             } | 
 | 1340 |         } | 
 | 1341 |         if (criticalInterface != sensorMap.end()) | 
 | 1342 |         { | 
 | 1343 |             auto& criticalMap = criticalInterface->second; | 
 | 1344 |  | 
 | 1345 |             auto criticalHigh = criticalMap.find("CriticalHigh"); | 
 | 1346 |             auto criticalLow = criticalMap.find("CriticalLow"); | 
 | 1347 |  | 
 | 1348 |             if (criticalHigh != criticalMap.end()) | 
 | 1349 |             { | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 1350 |                 double value = std::visit(VariantToDoubleVisitor(), | 
 | 1351 |                                           criticalHigh->second); | 
| Konstantin Aladyshev | 8265af2 | 2021-12-16 18:18:10 +0300 | [diff] [blame] | 1352 |                 if (std::isfinite(value)) | 
 | 1353 |                 { | 
 | 1354 |                     resp.criticalHigh = scaleIPMIValueFromDouble( | 
 | 1355 |                         value, mValue, rExp, bValue, bExp, bSigned); | 
 | 1356 |                 } | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1357 |             } | 
 | 1358 |             if (criticalLow != criticalMap.end()) | 
 | 1359 |             { | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 1360 |                 double value = std::visit(VariantToDoubleVisitor(), | 
 | 1361 |                                           criticalLow->second); | 
| Konstantin Aladyshev | 8265af2 | 2021-12-16 18:18:10 +0300 | [diff] [blame] | 1362 |                 if (std::isfinite(value)) | 
 | 1363 |                 { | 
 | 1364 |                     resp.criticalLow = scaleIPMIValueFromDouble( | 
 | 1365 |                         value, mValue, rExp, bValue, bExp, bSigned); | 
 | 1366 |                 } | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1367 |             } | 
 | 1368 |         } | 
 | 1369 |     } | 
 | 1370 |     return resp; | 
 | 1371 | } | 
 | 1372 |  | 
 | 1373 | ipmi::RspType<uint8_t, // readable | 
 | 1374 |               uint8_t, // lowerNCrit | 
 | 1375 |               uint8_t, // lowerCrit | 
 | 1376 |               uint8_t, // lowerNrecoverable | 
 | 1377 |               uint8_t, // upperNC | 
 | 1378 |               uint8_t, // upperCrit | 
 | 1379 |               uint8_t> // upperNRecoverable | 
 | 1380 |     ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber) | 
 | 1381 | { | 
 | 1382 |     std::string connection; | 
 | 1383 |     std::string path; | 
 | 1384 |  | 
| Chalapathi Venkataramashetty | 8c2f3c4 | 2021-06-13 19:51:17 +0000 | [diff] [blame] | 1385 |     if (sensorNumber == reservedSensorNumber) | 
 | 1386 |     { | 
 | 1387 |         return ipmi::responseInvalidFieldRequest(); | 
 | 1388 |     } | 
 | 1389 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1390 |     auto status = getSensorConnection(ctx, sensorNumber, connection, path); | 
 | 1391 |     if (status) | 
 | 1392 |     { | 
 | 1393 |         return ipmi::response(status); | 
 | 1394 |     } | 
 | 1395 |  | 
 | 1396 |     DbusInterfaceMap sensorMap; | 
 | 1397 |     if (!getSensorMap(ctx, connection, path, sensorMap)) | 
 | 1398 |     { | 
 | 1399 |         return ipmi::responseResponseError(); | 
 | 1400 |     } | 
 | 1401 |  | 
 | 1402 |     IPMIThresholds thresholdData; | 
 | 1403 |     try | 
 | 1404 |     { | 
 | 1405 |         thresholdData = getIPMIThresholds(sensorMap); | 
 | 1406 |     } | 
| Patrick Williams | a2ad2da | 2021-10-06 12:21:46 -0500 | [diff] [blame] | 1407 |     catch (const std::exception&) | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1408 |     { | 
 | 1409 |         return ipmi::responseResponseError(); | 
 | 1410 |     } | 
 | 1411 |  | 
 | 1412 |     uint8_t readable = 0; | 
 | 1413 |     uint8_t lowerNC = 0; | 
 | 1414 |     uint8_t lowerCritical = 0; | 
 | 1415 |     uint8_t lowerNonRecoverable = 0; | 
 | 1416 |     uint8_t upperNC = 0; | 
 | 1417 |     uint8_t upperCritical = 0; | 
 | 1418 |     uint8_t upperNonRecoverable = 0; | 
 | 1419 |  | 
 | 1420 |     if (thresholdData.warningHigh) | 
 | 1421 |     { | 
 | 1422 |         readable |= | 
 | 1423 |             1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical); | 
 | 1424 |         upperNC = *thresholdData.warningHigh; | 
 | 1425 |     } | 
 | 1426 |     if (thresholdData.warningLow) | 
 | 1427 |     { | 
 | 1428 |         readable |= | 
 | 1429 |             1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical); | 
 | 1430 |         lowerNC = *thresholdData.warningLow; | 
 | 1431 |     } | 
 | 1432 |  | 
 | 1433 |     if (thresholdData.criticalHigh) | 
 | 1434 |     { | 
 | 1435 |         readable |= | 
 | 1436 |             1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical); | 
 | 1437 |         upperCritical = *thresholdData.criticalHigh; | 
 | 1438 |     } | 
 | 1439 |     if (thresholdData.criticalLow) | 
 | 1440 |     { | 
 | 1441 |         readable |= | 
 | 1442 |             1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical); | 
 | 1443 |         lowerCritical = *thresholdData.criticalLow; | 
 | 1444 |     } | 
 | 1445 |  | 
 | 1446 |     return ipmi::responseSuccess(readable, lowerNC, lowerCritical, | 
 | 1447 |                                  lowerNonRecoverable, upperNC, upperCritical, | 
 | 1448 |                                  upperNonRecoverable); | 
 | 1449 | } | 
 | 1450 |  | 
 | 1451 | /** @brief implements the get Sensor event enable command | 
 | 1452 |  *  @param sensorNumber - sensor number | 
 | 1453 |  * | 
 | 1454 |  *  @returns IPMI completion code plus response data | 
 | 1455 |  *   - enabled               - Sensor Event messages | 
 | 1456 |  *   - assertionEnabledLsb   - Assertion event messages | 
 | 1457 |  *   - assertionEnabledMsb   - Assertion event messages | 
 | 1458 |  *   - deassertionEnabledLsb - Deassertion event messages | 
 | 1459 |  *   - deassertionEnabledMsb - Deassertion event messages | 
 | 1460 |  */ | 
 | 1461 |  | 
 | 1462 | ipmi::RspType<uint8_t, // enabled | 
 | 1463 |               uint8_t, // assertionEnabledLsb | 
 | 1464 |               uint8_t, // assertionEnabledMsb | 
 | 1465 |               uint8_t, // deassertionEnabledLsb | 
 | 1466 |               uint8_t> // deassertionEnabledMsb | 
 | 1467 |     ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum) | 
 | 1468 | { | 
 | 1469 |     std::string connection; | 
 | 1470 |     std::string path; | 
 | 1471 |  | 
 | 1472 |     uint8_t enabled = 0; | 
 | 1473 |     uint8_t assertionEnabledLsb = 0; | 
 | 1474 |     uint8_t assertionEnabledMsb = 0; | 
 | 1475 |     uint8_t deassertionEnabledLsb = 0; | 
 | 1476 |     uint8_t deassertionEnabledMsb = 0; | 
 | 1477 |  | 
| Chalapathi Venkataramashetty | 8c2f3c4 | 2021-06-13 19:51:17 +0000 | [diff] [blame] | 1478 |     if (sensorNum == reservedSensorNumber) | 
 | 1479 |     { | 
 | 1480 |         return ipmi::responseInvalidFieldRequest(); | 
 | 1481 |     } | 
 | 1482 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1483 |     auto status = getSensorConnection(ctx, sensorNum, connection, path); | 
 | 1484 |     if (status) | 
 | 1485 |     { | 
 | 1486 |         return ipmi::response(status); | 
 | 1487 |     } | 
 | 1488 |  | 
| Scron Chang | 2703b02 | 2021-07-06 15:47:45 +0800 | [diff] [blame] | 1489 | #ifdef FEATURE_HYBRID_SENSORS | 
 | 1490 |     if (auto sensor = findStaticSensor(path); | 
 | 1491 |         sensor != ipmi::sensor::sensors.end() && | 
 | 1492 |         getSensorEventTypeFromPath(path) != | 
 | 1493 |             static_cast<uint8_t>(SensorEventTypeCodes::threshold)) | 
 | 1494 |     { | 
 | 1495 |         enabled = static_cast<uint8_t>( | 
 | 1496 |             IPMISensorEventEnableByte2::sensorScanningEnable); | 
 | 1497 |         uint16_t assertionEnabled = 0; | 
 | 1498 |         for (auto& offsetValMap : sensor->second.propertyInterfaces.begin() | 
 | 1499 |                                       ->second.begin() | 
 | 1500 |                                       ->second.second) | 
 | 1501 |         { | 
 | 1502 |             assertionEnabled |= (1 << offsetValMap.first); | 
 | 1503 |         } | 
 | 1504 |         assertionEnabledLsb = static_cast<uint8_t>((assertionEnabled & 0xFF)); | 
 | 1505 |         assertionEnabledMsb = | 
 | 1506 |             static_cast<uint8_t>(((assertionEnabled >> 8) & 0xFF)); | 
 | 1507 |  | 
 | 1508 |         return ipmi::responseSuccess(enabled, assertionEnabledLsb, | 
 | 1509 |                                      assertionEnabledMsb, deassertionEnabledLsb, | 
 | 1510 |                                      deassertionEnabledMsb); | 
 | 1511 |     } | 
 | 1512 | #endif | 
 | 1513 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1514 |     DbusInterfaceMap sensorMap; | 
 | 1515 |     if (!getSensorMap(ctx, connection, path, sensorMap)) | 
 | 1516 |     { | 
 | 1517 |         return ipmi::responseResponseError(); | 
 | 1518 |     } | 
 | 1519 |  | 
 | 1520 |     auto warningInterface = | 
 | 1521 |         sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning"); | 
 | 1522 |     auto criticalInterface = | 
 | 1523 |         sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical"); | 
 | 1524 |     if ((warningInterface != sensorMap.end()) || | 
 | 1525 |         (criticalInterface != sensorMap.end())) | 
 | 1526 |     { | 
 | 1527 |         enabled = static_cast<uint8_t>( | 
 | 1528 |             IPMISensorEventEnableByte2::sensorScanningEnable); | 
 | 1529 |         if (warningInterface != sensorMap.end()) | 
 | 1530 |         { | 
 | 1531 |             auto& warningMap = warningInterface->second; | 
 | 1532 |  | 
 | 1533 |             auto warningHigh = warningMap.find("WarningHigh"); | 
 | 1534 |             auto warningLow = warningMap.find("WarningLow"); | 
 | 1535 |             if (warningHigh != warningMap.end()) | 
 | 1536 |             { | 
| Johnathan Mantey | 92217f0 | 2024-06-20 12:43:01 -0700 | [diff] [blame] | 1537 |                 double value = std::visit(VariantToDoubleVisitor(), | 
 | 1538 |                                           warningHigh->second); | 
 | 1539 |                 if (std::isfinite(value)) | 
 | 1540 |                 { | 
 | 1541 |                     assertionEnabledLsb |= static_cast<uint8_t>( | 
 | 1542 |                         IPMISensorEventEnableThresholds:: | 
 | 1543 |                             upperNonCriticalGoingHigh); | 
 | 1544 |                     deassertionEnabledLsb |= static_cast<uint8_t>( | 
 | 1545 |                         IPMISensorEventEnableThresholds:: | 
 | 1546 |                             upperNonCriticalGoingLow); | 
 | 1547 |                 } | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1548 |             } | 
 | 1549 |             if (warningLow != warningMap.end()) | 
 | 1550 |             { | 
| Johnathan Mantey | 92217f0 | 2024-06-20 12:43:01 -0700 | [diff] [blame] | 1551 |                 double value = std::visit(VariantToDoubleVisitor(), | 
 | 1552 |                                           warningLow->second); | 
 | 1553 |                 if (std::isfinite(value)) | 
 | 1554 |                 { | 
 | 1555 |                     assertionEnabledLsb |= static_cast<uint8_t>( | 
 | 1556 |                         IPMISensorEventEnableThresholds:: | 
 | 1557 |                             lowerNonCriticalGoingLow); | 
 | 1558 |                     deassertionEnabledLsb |= static_cast<uint8_t>( | 
 | 1559 |                         IPMISensorEventEnableThresholds:: | 
 | 1560 |                             lowerNonCriticalGoingHigh); | 
 | 1561 |                 } | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1562 |             } | 
 | 1563 |         } | 
 | 1564 |         if (criticalInterface != sensorMap.end()) | 
 | 1565 |         { | 
 | 1566 |             auto& criticalMap = criticalInterface->second; | 
 | 1567 |  | 
 | 1568 |             auto criticalHigh = criticalMap.find("CriticalHigh"); | 
 | 1569 |             auto criticalLow = criticalMap.find("CriticalLow"); | 
 | 1570 |  | 
 | 1571 |             if (criticalHigh != criticalMap.end()) | 
 | 1572 |             { | 
| Johnathan Mantey | 92217f0 | 2024-06-20 12:43:01 -0700 | [diff] [blame] | 1573 |                 double value = std::visit(VariantToDoubleVisitor(), | 
 | 1574 |                                           criticalHigh->second); | 
 | 1575 |                 if (std::isfinite(value)) | 
 | 1576 |                 { | 
 | 1577 |                     assertionEnabledMsb |= static_cast<uint8_t>( | 
 | 1578 |                         IPMISensorEventEnableThresholds:: | 
 | 1579 |                             upperCriticalGoingHigh); | 
 | 1580 |                     deassertionEnabledMsb |= static_cast<uint8_t>( | 
 | 1581 |                         IPMISensorEventEnableThresholds::upperCriticalGoingLow); | 
 | 1582 |                 } | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1583 |             } | 
 | 1584 |             if (criticalLow != criticalMap.end()) | 
 | 1585 |             { | 
| Johnathan Mantey | 92217f0 | 2024-06-20 12:43:01 -0700 | [diff] [blame] | 1586 |                 double value = std::visit(VariantToDoubleVisitor(), | 
 | 1587 |                                           criticalLow->second); | 
 | 1588 |                 if (std::isfinite(value)) | 
 | 1589 |                 { | 
 | 1590 |                     assertionEnabledLsb |= static_cast<uint8_t>( | 
 | 1591 |                         IPMISensorEventEnableThresholds::lowerCriticalGoingLow); | 
 | 1592 |                     deassertionEnabledLsb |= static_cast<uint8_t>( | 
 | 1593 |                         IPMISensorEventEnableThresholds:: | 
 | 1594 |                             lowerCriticalGoingHigh); | 
 | 1595 |                 } | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1596 |             } | 
 | 1597 |         } | 
 | 1598 |     } | 
 | 1599 |  | 
 | 1600 |     return ipmi::responseSuccess(enabled, assertionEnabledLsb, | 
 | 1601 |                                  assertionEnabledMsb, deassertionEnabledLsb, | 
 | 1602 |                                  deassertionEnabledMsb); | 
 | 1603 | } | 
 | 1604 |  | 
 | 1605 | /** @brief implements the get Sensor event status command | 
 | 1606 |  *  @param sensorNumber - sensor number, FFh = reserved | 
 | 1607 |  * | 
 | 1608 |  *  @returns IPMI completion code plus response data | 
 | 1609 |  *   - sensorEventStatus - Sensor Event messages state | 
 | 1610 |  *   - assertions        - Assertion event messages | 
 | 1611 |  *   - deassertions      - Deassertion event messages | 
 | 1612 |  */ | 
 | 1613 | ipmi::RspType<uint8_t,         // sensorEventStatus | 
 | 1614 |               std::bitset<16>, // assertions | 
 | 1615 |               std::bitset<16>  // deassertion | 
 | 1616 |               > | 
 | 1617 |     ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum) | 
 | 1618 | { | 
 | 1619 |     if (sensorNum == reservedSensorNumber) | 
 | 1620 |     { | 
 | 1621 |         return ipmi::responseInvalidFieldRequest(); | 
 | 1622 |     } | 
 | 1623 |  | 
 | 1624 |     std::string connection; | 
 | 1625 |     std::string path; | 
 | 1626 |     auto status = getSensorConnection(ctx, sensorNum, connection, path); | 
 | 1627 |     if (status) | 
 | 1628 |     { | 
 | 1629 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 1630 |             "ipmiSenGetSensorEventStatus: Sensor connection Error", | 
 | 1631 |             phosphor::logging::entry("SENSOR=%d", sensorNum)); | 
 | 1632 |         return ipmi::response(status); | 
 | 1633 |     } | 
 | 1634 |  | 
| Scron Chang | 2703b02 | 2021-07-06 15:47:45 +0800 | [diff] [blame] | 1635 | #ifdef FEATURE_HYBRID_SENSORS | 
 | 1636 |     if (auto sensor = findStaticSensor(path); | 
 | 1637 |         sensor != ipmi::sensor::sensors.end() && | 
 | 1638 |         getSensorEventTypeFromPath(path) != | 
 | 1639 |             static_cast<uint8_t>(SensorEventTypeCodes::threshold)) | 
 | 1640 |     { | 
 | 1641 |         auto response = ipmi::sensor::get::mapDbusToAssertion( | 
 | 1642 |             sensor->second, path, sensor->second.sensorInterface); | 
 | 1643 |         std::bitset<16> assertions; | 
 | 1644 |         // deassertions are not used. | 
 | 1645 |         std::bitset<16> deassertions = 0; | 
 | 1646 |         uint8_t sensorEventStatus; | 
 | 1647 |         if (response.readingOrStateUnavailable) | 
 | 1648 |         { | 
 | 1649 |             sensorEventStatus |= static_cast<uint8_t>( | 
 | 1650 |                 IPMISensorReadingByte2::readingStateUnavailable); | 
 | 1651 |         } | 
 | 1652 |         if (response.scanningEnabled) | 
 | 1653 |         { | 
 | 1654 |             sensorEventStatus |= static_cast<uint8_t>( | 
 | 1655 |                 IPMISensorReadingByte2::sensorScanningEnable); | 
 | 1656 |         } | 
 | 1657 |         if (response.allEventMessagesEnabled) | 
 | 1658 |         { | 
 | 1659 |             sensorEventStatus |= static_cast<uint8_t>( | 
 | 1660 |                 IPMISensorReadingByte2::eventMessagesEnable); | 
 | 1661 |         } | 
 | 1662 |         assertions |= response.discreteReadingSensorStates << 8; | 
 | 1663 |         assertions |= response.thresholdLevelsStates; | 
 | 1664 |         return ipmi::responseSuccess(sensorEventStatus, assertions, | 
 | 1665 |                                      deassertions); | 
 | 1666 |     } | 
 | 1667 | #endif | 
 | 1668 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1669 |     DbusInterfaceMap sensorMap; | 
 | 1670 |     if (!getSensorMap(ctx, connection, path, sensorMap)) | 
 | 1671 |     { | 
 | 1672 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 1673 |             "ipmiSenGetSensorEventStatus: Sensor Mapping Error", | 
 | 1674 |             phosphor::logging::entry("SENSOR=%s", path.c_str())); | 
 | 1675 |         return ipmi::responseResponseError(); | 
 | 1676 |     } | 
| Hao Jiang | d48c921 | 2021-02-03 15:45:06 -0800 | [diff] [blame] | 1677 |  | 
 | 1678 |     uint8_t sensorEventStatus = | 
 | 1679 |         static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable); | 
 | 1680 |     std::bitset<16> assertions = 0; | 
 | 1681 |     std::bitset<16> deassertions = 0; | 
 | 1682 |  | 
 | 1683 |     // handle VR typed sensor | 
 | 1684 |     auto vrInterface = sensorMap.find(sensor::vrInterface); | 
 | 1685 |     if (vrInterface != sensorMap.end()) | 
 | 1686 |     { | 
 | 1687 |         if (!sensor::getVrEventStatus(ctx, connection, path, | 
 | 1688 |                                       vrInterface->second, assertions)) | 
 | 1689 |         { | 
 | 1690 |             return ipmi::responseResponseError(); | 
 | 1691 |         } | 
 | 1692 |  | 
 | 1693 |         // both Event Message and Sensor Scanning are disable for VR. | 
 | 1694 |         sensorEventStatus = 0; | 
 | 1695 |         return ipmi::responseSuccess(sensorEventStatus, assertions, | 
 | 1696 |                                      deassertions); | 
 | 1697 |     } | 
 | 1698 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1699 |     auto warningInterface = | 
 | 1700 |         sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning"); | 
 | 1701 |     auto criticalInterface = | 
 | 1702 |         sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical"); | 
 | 1703 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1704 |     std::optional<bool> criticalDeassertHigh = | 
 | 1705 |         thresholdDeassertMap[path]["CriticalAlarmHigh"]; | 
 | 1706 |     std::optional<bool> criticalDeassertLow = | 
 | 1707 |         thresholdDeassertMap[path]["CriticalAlarmLow"]; | 
 | 1708 |     std::optional<bool> warningDeassertHigh = | 
 | 1709 |         thresholdDeassertMap[path]["WarningAlarmHigh"]; | 
 | 1710 |     std::optional<bool> warningDeassertLow = | 
 | 1711 |         thresholdDeassertMap[path]["WarningAlarmLow"]; | 
 | 1712 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1713 |     if (criticalDeassertHigh && !*criticalDeassertHigh) | 
 | 1714 |     { | 
 | 1715 |         deassertions.set(static_cast<size_t>( | 
 | 1716 |             IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh)); | 
 | 1717 |     } | 
 | 1718 |     if (criticalDeassertLow && !*criticalDeassertLow) | 
 | 1719 |     { | 
 | 1720 |         deassertions.set(static_cast<size_t>( | 
 | 1721 |             IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow)); | 
 | 1722 |     } | 
 | 1723 |     if (warningDeassertHigh && !*warningDeassertHigh) | 
 | 1724 |     { | 
 | 1725 |         deassertions.set(static_cast<size_t>( | 
 | 1726 |             IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh)); | 
 | 1727 |     } | 
 | 1728 |     if (warningDeassertLow && !*warningDeassertLow) | 
 | 1729 |     { | 
 | 1730 |         deassertions.set(static_cast<size_t>( | 
 | 1731 |             IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh)); | 
 | 1732 |     } | 
 | 1733 |     if ((warningInterface != sensorMap.end()) || | 
 | 1734 |         (criticalInterface != sensorMap.end())) | 
 | 1735 |     { | 
 | 1736 |         sensorEventStatus = static_cast<size_t>( | 
 | 1737 |             IPMISensorEventEnableByte2::eventMessagesEnable); | 
 | 1738 |         if (warningInterface != sensorMap.end()) | 
 | 1739 |         { | 
 | 1740 |             auto& warningMap = warningInterface->second; | 
 | 1741 |  | 
 | 1742 |             auto warningHigh = warningMap.find("WarningAlarmHigh"); | 
 | 1743 |             auto warningLow = warningMap.find("WarningAlarmLow"); | 
 | 1744 |             auto warningHighAlarm = false; | 
 | 1745 |             auto warningLowAlarm = false; | 
 | 1746 |  | 
 | 1747 |             if (warningHigh != warningMap.end()) | 
 | 1748 |             { | 
 | 1749 |                 warningHighAlarm = std::get<bool>(warningHigh->second); | 
 | 1750 |             } | 
 | 1751 |             if (warningLow != warningMap.end()) | 
 | 1752 |             { | 
 | 1753 |                 warningLowAlarm = std::get<bool>(warningLow->second); | 
 | 1754 |             } | 
 | 1755 |             if (warningHighAlarm) | 
 | 1756 |             { | 
 | 1757 |                 assertions.set( | 
 | 1758 |                     static_cast<size_t>(IPMIGetSensorEventEnableThresholds:: | 
 | 1759 |                                             upperNonCriticalGoingHigh)); | 
 | 1760 |             } | 
 | 1761 |             if (warningLowAlarm) | 
 | 1762 |             { | 
 | 1763 |                 assertions.set( | 
 | 1764 |                     static_cast<size_t>(IPMIGetSensorEventEnableThresholds:: | 
 | 1765 |                                             lowerNonCriticalGoingLow)); | 
 | 1766 |             } | 
 | 1767 |         } | 
 | 1768 |         if (criticalInterface != sensorMap.end()) | 
 | 1769 |         { | 
 | 1770 |             auto& criticalMap = criticalInterface->second; | 
 | 1771 |  | 
 | 1772 |             auto criticalHigh = criticalMap.find("CriticalAlarmHigh"); | 
 | 1773 |             auto criticalLow = criticalMap.find("CriticalAlarmLow"); | 
 | 1774 |             auto criticalHighAlarm = false; | 
 | 1775 |             auto criticalLowAlarm = false; | 
 | 1776 |  | 
 | 1777 |             if (criticalHigh != criticalMap.end()) | 
 | 1778 |             { | 
 | 1779 |                 criticalHighAlarm = std::get<bool>(criticalHigh->second); | 
 | 1780 |             } | 
 | 1781 |             if (criticalLow != criticalMap.end()) | 
 | 1782 |             { | 
 | 1783 |                 criticalLowAlarm = std::get<bool>(criticalLow->second); | 
 | 1784 |             } | 
 | 1785 |             if (criticalHighAlarm) | 
 | 1786 |             { | 
 | 1787 |                 assertions.set( | 
 | 1788 |                     static_cast<size_t>(IPMIGetSensorEventEnableThresholds:: | 
 | 1789 |                                             upperCriticalGoingHigh)); | 
 | 1790 |             } | 
 | 1791 |             if (criticalLowAlarm) | 
 | 1792 |             { | 
 | 1793 |                 assertions.set(static_cast<size_t>( | 
 | 1794 |                     IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow)); | 
 | 1795 |             } | 
 | 1796 |         } | 
 | 1797 |     } | 
 | 1798 |  | 
 | 1799 |     return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions); | 
 | 1800 | } | 
 | 1801 |  | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 1802 | // Construct a type 1 SDR for threshold sensor. | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 1803 | void constructSensorSdrHeaderKey(uint16_t sensorNum, uint16_t recordID, | 
 | 1804 |                                  get_sdr::SensorDataFullRecord& record) | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 1805 | { | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 1806 |     get_sdr::header::set_record_id( | 
 | 1807 |         recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record)); | 
 | 1808 |  | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 1809 |     uint8_t sensornumber = static_cast<uint8_t>(sensorNum); | 
 | 1810 |     uint8_t lun = static_cast<uint8_t>(sensorNum >> 8); | 
 | 1811 |  | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 1812 |     record.header.sdr_version = ipmiSdrVersion; | 
 | 1813 |     record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD; | 
 | 1814 |     record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) - | 
 | 1815 |                                   sizeof(get_sdr::SensorDataRecordHeader); | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 1816 |     record.key.owner_id = bmcI2CAddr; | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 1817 |     record.key.owner_lun = lun; | 
 | 1818 |     record.key.sensor_number = sensornumber; | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 1819 | } | 
| Willy Tu | 4eca251 | 2022-06-20 21:14:51 -0700 | [diff] [blame] | 1820 | bool constructSensorSdr( | 
 | 1821 |     ipmi::Context::ptr ctx, | 
 | 1822 |     const std::unordered_set<std::string>& ipmiDecoratorPaths, | 
 | 1823 |     uint16_t sensorNum, uint16_t recordID, const std::string& service, | 
 | 1824 |     const std::string& path, get_sdr::SensorDataFullRecord& record) | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 1825 | { | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 1826 |     constructSensorSdrHeaderKey(sensorNum, recordID, record); | 
 | 1827 |  | 
 | 1828 |     DbusInterfaceMap sensorMap; | 
 | 1829 |     if (!getSensorMap(ctx, service, path, sensorMap, sensorMapSdrUpdatePeriod)) | 
 | 1830 |     { | 
 | 1831 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 1832 |             "Failed to update sensor map for threshold sensor", | 
 | 1833 |             phosphor::logging::entry("SERVICE=%s", service.c_str()), | 
 | 1834 |             phosphor::logging::entry("PATH=%s", path.c_str())); | 
 | 1835 |         return false; | 
 | 1836 |     } | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 1837 |  | 
 | 1838 |     record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis | 
 | 1839 |     record.body.sensor_type = getSensorTypeFromPath(path); | 
 | 1840 |     std::string type = getSensorTypeStringFromPath(path); | 
 | 1841 |     auto typeCstr = type.c_str(); | 
 | 1842 |     auto findUnits = sensorUnits.find(typeCstr); | 
 | 1843 |     if (findUnits != sensorUnits.end()) | 
 | 1844 |     { | 
 | 1845 |         record.body.sensor_units_2_base = | 
 | 1846 |             static_cast<uint8_t>(findUnits->second); | 
 | 1847 |     } // else default 0x0 unspecified | 
 | 1848 |  | 
 | 1849 |     record.body.event_reading_type = getSensorEventTypeFromPath(path); | 
 | 1850 |  | 
| Hao Jiang | d2afd05 | 2020-12-10 15:09:32 -0800 | [diff] [blame] | 1851 |     auto sensorObject = sensorMap.find(sensor::sensorInterface); | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 1852 |     if (sensorObject == sensorMap.end()) | 
 | 1853 |     { | 
 | 1854 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 1855 |             "constructSensorSdr: sensorObject error"); | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 1856 |         return false; | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 1857 |     } | 
 | 1858 |  | 
 | 1859 |     uint8_t entityId = 0; | 
 | 1860 |     uint8_t entityInstance = 0x01; | 
 | 1861 |  | 
 | 1862 |     // follow the association chain to get the parent board's entityid and | 
 | 1863 |     // entityInstance | 
| Willy Tu | 4eca251 | 2022-06-20 21:14:51 -0700 | [diff] [blame] | 1864 |     updateIpmiFromAssociation(path, ipmiDecoratorPaths, sensorMap, entityId, | 
 | 1865 |                               entityInstance); | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 1866 |  | 
 | 1867 |     record.body.entity_id = entityId; | 
 | 1868 |     record.body.entity_instance = entityInstance; | 
 | 1869 |  | 
| Shakeeb Pasha | 9388972 | 2021-10-14 10:20:13 +0530 | [diff] [blame] | 1870 |     double max = 0; | 
 | 1871 |     double min = 0; | 
 | 1872 |     getSensorMaxMin(sensorMap, max, min); | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 1873 |  | 
 | 1874 |     int16_t mValue = 0; | 
 | 1875 |     int8_t rExp = 0; | 
 | 1876 |     int16_t bValue = 0; | 
 | 1877 |     int8_t bExp = 0; | 
 | 1878 |     bool bSigned = false; | 
 | 1879 |  | 
 | 1880 |     if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned)) | 
 | 1881 |     { | 
 | 1882 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 1883 |             "constructSensorSdr: getSensorAttributes error"); | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 1884 |         return false; | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 1885 |     } | 
 | 1886 |  | 
 | 1887 |     // The record.body is a struct SensorDataFullRecordBody | 
 | 1888 |     // from sensorhandler.hpp in phosphor-ipmi-host. | 
 | 1889 |     // The meaning of these bits appears to come from | 
 | 1890 |     // table 43.1 of the IPMI spec. | 
 | 1891 |     // The above 5 sensor attributes are stuffed in as follows: | 
 | 1892 |     // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned | 
 | 1893 |     // Byte 22-24 are for other purposes | 
 | 1894 |     // Byte 25 = MMMMMMMM = LSB of M | 
 | 1895 |     // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance | 
 | 1896 |     // Byte 27 = BBBBBBBB = LSB of B | 
 | 1897 |     // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy | 
 | 1898 |     // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy | 
 | 1899 |     // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed) | 
 | 1900 |  | 
 | 1901 |     // apply M, B, and exponents, M and B are 10 bit values, exponents are 4 | 
 | 1902 |     record.body.m_lsb = mValue & 0xFF; | 
 | 1903 |  | 
 | 1904 |     uint8_t mBitSign = (mValue < 0) ? 1 : 0; | 
 | 1905 |     uint8_t mBitNine = (mValue & 0x0100) >> 8; | 
 | 1906 |  | 
 | 1907 |     // move the smallest bit of the MSB into place (bit 9) | 
 | 1908 |     // the MSbs are bits 7:8 in m_msb_and_tolerance | 
 | 1909 |     record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6); | 
 | 1910 |  | 
 | 1911 |     record.body.b_lsb = bValue & 0xFF; | 
 | 1912 |  | 
 | 1913 |     uint8_t bBitSign = (bValue < 0) ? 1 : 0; | 
 | 1914 |     uint8_t bBitNine = (bValue & 0x0100) >> 8; | 
 | 1915 |  | 
 | 1916 |     // move the smallest bit of the MSB into place (bit 9) | 
 | 1917 |     // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb | 
 | 1918 |     record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6); | 
 | 1919 |  | 
 | 1920 |     uint8_t rExpSign = (rExp < 0) ? 1 : 0; | 
 | 1921 |     uint8_t rExpBits = rExp & 0x07; | 
 | 1922 |  | 
 | 1923 |     uint8_t bExpSign = (bExp < 0) ? 1 : 0; | 
 | 1924 |     uint8_t bExpBits = bExp & 0x07; | 
 | 1925 |  | 
 | 1926 |     // move rExp and bExp into place | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 1927 |     record.body.r_b_exponents = (rExpSign << 7) | (rExpBits << 4) | | 
 | 1928 |                                 (bExpSign << 3) | bExpBits; | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 1929 |  | 
 | 1930 |     // Set the analog reading byte interpretation accordingly | 
 | 1931 |     record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7; | 
 | 1932 |  | 
 | 1933 |     // TODO(): Perhaps care about Tolerance, Accuracy, and so on | 
 | 1934 |     // These seem redundant, but derivable from the above 5 attributes | 
 | 1935 |     // Original comment said "todo fill out rest of units" | 
 | 1936 |  | 
 | 1937 |     // populate sensor name from path | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 1938 |     auto name = sensor::parseSdrIdFromPath(path); | 
| Paul Fertser | 5113698 | 2022-08-18 12:36:41 +0000 | [diff] [blame] | 1939 |     get_sdr::body::set_id_strlen(name.size(), &record.body); | 
 | 1940 |     get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1" | 
| Patrick Williams | 2f0a6d0 | 2023-08-17 12:54:08 -0500 | [diff] [blame] | 1941 |     std::memcpy(record.body.id_string, name.c_str(), | 
 | 1942 |                 std::min(name.length() + 1, sizeof(record.body.id_string))); | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 1943 |  | 
| Josh Lehan | a55c953 | 2020-10-28 21:59:06 -0700 | [diff] [blame] | 1944 |     // Remember the sensor name, as determined for this sensor number | 
| Harvey.Wu | 0e7a8af | 2022-06-10 16:46:46 +0800 | [diff] [blame] | 1945 |     details::sdrStatsTable.updateName(sensorNum, name); | 
| Josh Lehan | a55c953 | 2020-10-28 21:59:06 -0700 | [diff] [blame] | 1946 |  | 
| Jie Yang | f0a8994 | 2021-07-29 15:30:25 -0700 | [diff] [blame] | 1947 |     bool sensorSettable = false; | 
 | 1948 |     auto mutability = | 
 | 1949 |         sensorMap.find("xyz.openbmc_project.Sensor.ValueMutability"); | 
 | 1950 |     if (mutability != sensorMap.end()) | 
 | 1951 |     { | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 1952 |         sensorSettable = mappedVariant<bool>(mutability->second, "Mutable", | 
 | 1953 |                                              false); | 
| Jie Yang | f0a8994 | 2021-07-29 15:30:25 -0700 | [diff] [blame] | 1954 |     } | 
 | 1955 |     get_sdr::body::init_settable_state(sensorSettable, &record.body); | 
 | 1956 |  | 
 | 1957 |     // Grant write permission to sensors deemed externally settable | 
| Harvey.Wu | 0e7a8af | 2022-06-10 16:46:46 +0800 | [diff] [blame] | 1958 |     details::sdrWriteTable.setWritePermission(sensorNum, sensorSettable); | 
| Willy Tu | 530e277 | 2021-07-02 14:42:06 -0700 | [diff] [blame] | 1959 |  | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 1960 |     IPMIThresholds thresholdData; | 
 | 1961 |     try | 
 | 1962 |     { | 
 | 1963 |         thresholdData = getIPMIThresholds(sensorMap); | 
 | 1964 |     } | 
| Patrick Williams | a2ad2da | 2021-10-06 12:21:46 -0500 | [diff] [blame] | 1965 |     catch (const std::exception&) | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 1966 |     { | 
 | 1967 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 1968 |             "constructSensorSdr: getIPMIThresholds error"); | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 1969 |         return false; | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 1970 |     } | 
 | 1971 |  | 
 | 1972 |     if (thresholdData.criticalHigh) | 
 | 1973 |     { | 
 | 1974 |         record.body.upper_critical_threshold = *thresholdData.criticalHigh; | 
 | 1975 |         record.body.supported_deassertions[1] |= static_cast<uint8_t>( | 
 | 1976 |             IPMISensorEventEnableThresholds::criticalThreshold); | 
 | 1977 |         record.body.supported_deassertions[1] |= static_cast<uint8_t>( | 
 | 1978 |             IPMISensorEventEnableThresholds::upperCriticalGoingHigh); | 
 | 1979 |         record.body.supported_assertions[1] |= static_cast<uint8_t>( | 
 | 1980 |             IPMISensorEventEnableThresholds::upperCriticalGoingHigh); | 
 | 1981 |         record.body.discrete_reading_setting_mask[0] |= | 
 | 1982 |             static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical); | 
 | 1983 |     } | 
 | 1984 |     if (thresholdData.warningHigh) | 
 | 1985 |     { | 
 | 1986 |         record.body.upper_noncritical_threshold = *thresholdData.warningHigh; | 
 | 1987 |         record.body.supported_deassertions[1] |= static_cast<uint8_t>( | 
 | 1988 |             IPMISensorEventEnableThresholds::nonCriticalThreshold); | 
 | 1989 |         record.body.supported_deassertions[0] |= static_cast<uint8_t>( | 
 | 1990 |             IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh); | 
 | 1991 |         record.body.supported_assertions[0] |= static_cast<uint8_t>( | 
 | 1992 |             IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh); | 
 | 1993 |         record.body.discrete_reading_setting_mask[0] |= | 
 | 1994 |             static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical); | 
 | 1995 |     } | 
 | 1996 |     if (thresholdData.criticalLow) | 
 | 1997 |     { | 
 | 1998 |         record.body.lower_critical_threshold = *thresholdData.criticalLow; | 
 | 1999 |         record.body.supported_assertions[1] |= static_cast<uint8_t>( | 
 | 2000 |             IPMISensorEventEnableThresholds::criticalThreshold); | 
 | 2001 |         record.body.supported_deassertions[0] |= static_cast<uint8_t>( | 
 | 2002 |             IPMISensorEventEnableThresholds::lowerCriticalGoingLow); | 
 | 2003 |         record.body.supported_assertions[0] |= static_cast<uint8_t>( | 
 | 2004 |             IPMISensorEventEnableThresholds::lowerCriticalGoingLow); | 
 | 2005 |         record.body.discrete_reading_setting_mask[0] |= | 
 | 2006 |             static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical); | 
 | 2007 |     } | 
 | 2008 |     if (thresholdData.warningLow) | 
 | 2009 |     { | 
 | 2010 |         record.body.lower_noncritical_threshold = *thresholdData.warningLow; | 
 | 2011 |         record.body.supported_assertions[1] |= static_cast<uint8_t>( | 
 | 2012 |             IPMISensorEventEnableThresholds::nonCriticalThreshold); | 
 | 2013 |         record.body.supported_deassertions[0] |= static_cast<uint8_t>( | 
 | 2014 |             IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow); | 
 | 2015 |         record.body.supported_assertions[0] |= static_cast<uint8_t>( | 
 | 2016 |             IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow); | 
 | 2017 |         record.body.discrete_reading_setting_mask[0] |= | 
 | 2018 |             static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical); | 
 | 2019 |     } | 
 | 2020 |  | 
 | 2021 |     // everything that is readable is setable | 
 | 2022 |     record.body.discrete_reading_setting_mask[1] = | 
 | 2023 |         record.body.discrete_reading_setting_mask[0]; | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 2024 |     return true; | 
 | 2025 | } | 
 | 2026 |  | 
| Scron Chang | 2703b02 | 2021-07-06 15:47:45 +0800 | [diff] [blame] | 2027 | #ifdef FEATURE_HYBRID_SENSORS | 
 | 2028 | // Construct a type 1 SDR for discrete Sensor typed sensor. | 
| Willy Tu | 11d6889 | 2022-01-20 10:37:34 -0800 | [diff] [blame] | 2029 | void constructStaticSensorSdr(ipmi::Context::ptr, uint16_t sensorNum, | 
| Scron Chang | 2703b02 | 2021-07-06 15:47:45 +0800 | [diff] [blame] | 2030 |                               uint16_t recordID, | 
 | 2031 |                               ipmi::sensor::IdInfoMap::const_iterator sensor, | 
 | 2032 |                               get_sdr::SensorDataFullRecord& record) | 
 | 2033 | { | 
 | 2034 |     constructSensorSdrHeaderKey(sensorNum, recordID, record); | 
 | 2035 |  | 
 | 2036 |     record.body.entity_id = sensor->second.entityType; | 
 | 2037 |     record.body.sensor_type = sensor->second.sensorType; | 
 | 2038 |     record.body.event_reading_type = sensor->second.sensorReadingType; | 
 | 2039 |     record.body.entity_instance = sensor->second.instance; | 
 | 2040 |     if (ipmi::sensor::Mutability::Write == | 
 | 2041 |         (sensor->second.mutability & ipmi::sensor::Mutability::Write)) | 
 | 2042 |     { | 
 | 2043 |         get_sdr::body::init_settable_state(true, &(record.body)); | 
 | 2044 |     } | 
 | 2045 |  | 
 | 2046 |     auto id_string = sensor->second.sensorName; | 
 | 2047 |  | 
 | 2048 |     if (id_string.empty()) | 
 | 2049 |     { | 
 | 2050 |         id_string = sensor->second.sensorNameFunc(sensor->second); | 
 | 2051 |     } | 
 | 2052 |  | 
 | 2053 |     if (id_string.length() > FULL_RECORD_ID_STR_MAX_LENGTH) | 
 | 2054 |     { | 
 | 2055 |         get_sdr::body::set_id_strlen(FULL_RECORD_ID_STR_MAX_LENGTH, | 
 | 2056 |                                      &(record.body)); | 
 | 2057 |     } | 
 | 2058 |     else | 
 | 2059 |     { | 
 | 2060 |         get_sdr::body::set_id_strlen(id_string.length(), &(record.body)); | 
 | 2061 |     } | 
| Paul Fertser | 5113698 | 2022-08-18 12:36:41 +0000 | [diff] [blame] | 2062 |     get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1" | 
| Scron Chang | 2703b02 | 2021-07-06 15:47:45 +0800 | [diff] [blame] | 2063 |     std::strncpy(record.body.id_string, id_string.c_str(), | 
 | 2064 |                  get_sdr::body::get_id_strlen(&(record.body))); | 
 | 2065 | } | 
 | 2066 | #endif | 
 | 2067 |  | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 2068 | // Construct type 3 SDR header and key (for VR and other discrete sensors) | 
 | 2069 | void constructEventSdrHeaderKey(uint16_t sensorNum, uint16_t recordID, | 
 | 2070 |                                 get_sdr::SensorDataEventRecord& record) | 
| Willy Tu | 61992ad | 2021-03-29 15:33:20 -0700 | [diff] [blame] | 2071 | { | 
 | 2072 |     uint8_t sensornumber = static_cast<uint8_t>(sensorNum); | 
 | 2073 |     uint8_t lun = static_cast<uint8_t>(sensorNum >> 8); | 
 | 2074 |  | 
 | 2075 |     get_sdr::header::set_record_id( | 
 | 2076 |         recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record)); | 
 | 2077 |  | 
 | 2078 |     record.header.sdr_version = ipmiSdrVersion; | 
 | 2079 |     record.header.record_type = get_sdr::SENSOR_DATA_EVENT_RECORD; | 
 | 2080 |     record.header.record_length = sizeof(get_sdr::SensorDataEventRecord) - | 
 | 2081 |                                   sizeof(get_sdr::SensorDataRecordHeader); | 
 | 2082 |     record.key.owner_id = bmcI2CAddr; | 
 | 2083 |     record.key.owner_lun = lun; | 
 | 2084 |     record.key.sensor_number = sensornumber; | 
 | 2085 |  | 
 | 2086 |     record.body.entity_id = 0x00; | 
 | 2087 |     record.body.entity_instance = 0x01; | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 2088 | } | 
| Willy Tu | 61992ad | 2021-03-29 15:33:20 -0700 | [diff] [blame] | 2089 |  | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 2090 | // Construct a type 3 SDR for VR typed sensor(daemon). | 
| Willy Tu | 4eca251 | 2022-06-20 21:14:51 -0700 | [diff] [blame] | 2091 | bool constructVrSdr(ipmi::Context::ptr ctx, | 
 | 2092 |                     const std::unordered_set<std::string>& ipmiDecoratorPaths, | 
 | 2093 |                     uint16_t sensorNum, uint16_t recordID, | 
 | 2094 |                     const std::string& service, const std::string& path, | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 2095 |                     get_sdr::SensorDataEventRecord& record) | 
 | 2096 | { | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 2097 |     constructEventSdrHeaderKey(sensorNum, recordID, record); | 
 | 2098 |  | 
 | 2099 |     DbusInterfaceMap sensorMap; | 
 | 2100 |     if (!getSensorMap(ctx, service, path, sensorMap, sensorMapSdrUpdatePeriod)) | 
 | 2101 |     { | 
 | 2102 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 2103 |             "Failed to update sensor map for VR sensor", | 
 | 2104 |             phosphor::logging::entry("SERVICE=%s", service.c_str()), | 
 | 2105 |             phosphor::logging::entry("PATH=%s", path.c_str())); | 
 | 2106 |         return false; | 
 | 2107 |     } | 
| Willy Tu | 61992ad | 2021-03-29 15:33:20 -0700 | [diff] [blame] | 2108 |     // follow the association chain to get the parent board's entityid and | 
 | 2109 |     // entityInstance | 
| Willy Tu | 4eca251 | 2022-06-20 21:14:51 -0700 | [diff] [blame] | 2110 |     updateIpmiFromAssociation(path, ipmiDecoratorPaths, sensorMap, | 
 | 2111 |                               record.body.entity_id, | 
| Willy Tu | 61992ad | 2021-03-29 15:33:20 -0700 | [diff] [blame] | 2112 |                               record.body.entity_instance); | 
 | 2113 |  | 
 | 2114 |     // Sensor type is hardcoded as a module/board type instead of parsing from | 
 | 2115 |     // sensor path. This is because VR control is allocated in an independent | 
 | 2116 |     // path(/xyz/openbmc_project/vr/profile/...) which is not categorized by | 
 | 2117 |     // types. | 
 | 2118 |     static constexpr const uint8_t module_board_type = 0x15; | 
 | 2119 |     record.body.sensor_type = module_board_type; | 
 | 2120 |     record.body.event_reading_type = 0x00; | 
 | 2121 |  | 
 | 2122 |     record.body.sensor_record_sharing_1 = 0x00; | 
 | 2123 |     record.body.sensor_record_sharing_2 = 0x00; | 
 | 2124 |  | 
 | 2125 |     // populate sensor name from path | 
 | 2126 |     auto name = sensor::parseSdrIdFromPath(path); | 
 | 2127 |     int nameSize = std::min(name.size(), sizeof(record.body.id_string)); | 
| Paul Fertser | 5113698 | 2022-08-18 12:36:41 +0000 | [diff] [blame] | 2128 |     get_sdr::body::set_id_strlen(nameSize, &record.body); | 
 | 2129 |     get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1" | 
| Willy Tu | 61992ad | 2021-03-29 15:33:20 -0700 | [diff] [blame] | 2130 |     std::memset(record.body.id_string, 0x00, sizeof(record.body.id_string)); | 
 | 2131 |     std::memcpy(record.body.id_string, name.c_str(), nameSize); | 
 | 2132 |  | 
 | 2133 |     // Remember the sensor name, as determined for this sensor number | 
| Harvey.Wu | 0e7a8af | 2022-06-10 16:46:46 +0800 | [diff] [blame] | 2134 |     details::sdrStatsTable.updateName(sensorNum, name); | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 2135 |  | 
 | 2136 |     return true; | 
| Willy Tu | 61992ad | 2021-03-29 15:33:20 -0700 | [diff] [blame] | 2137 | } | 
 | 2138 |  | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 2139 | uint16_t getNumberOfSensors() | 
| Johnathan Mantey | 6619ae4 | 2021-08-06 11:21:10 -0700 | [diff] [blame] | 2140 | { | 
 | 2141 |     return std::min(getSensorTree().size(), maxIPMISensors); | 
 | 2142 | } | 
 | 2143 |  | 
| Willy Tu | 4eca251 | 2022-06-20 21:14:51 -0700 | [diff] [blame] | 2144 | static int getSensorDataRecord( | 
 | 2145 |     ipmi::Context::ptr ctx, | 
 | 2146 |     const std::unordered_set<std::string>& ipmiDecoratorPaths, | 
 | 2147 |     std::vector<uint8_t>& recordData, uint16_t recordID, | 
 | 2148 |     uint8_t readBytes = std::numeric_limits<uint8_t>::max()) | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 2149 | { | 
| selvaganapathi | 7b2e550 | 2023-02-14 07:10:47 +0530 | [diff] [blame] | 2150 |     recordData.clear(); | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 2151 |     size_t lastRecord = ipmi::getNumberOfSensors() + | 
 | 2152 |                         ipmi::sensor::getOtherSensorsCount(ctx) - 1; | 
 | 2153 |     uint16_t nextRecord(recordID + 1); | 
 | 2154 |  | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 2155 |     if (recordID == lastRecordIndex) | 
 | 2156 |     { | 
 | 2157 |         recordID = lastRecord; | 
 | 2158 |     } | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 2159 |     if (recordID == lastRecord) | 
 | 2160 |     { | 
 | 2161 |         nextRecord = lastRecordIndex; | 
 | 2162 |     } | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 2163 |     if (recordID > lastRecord) | 
 | 2164 |     { | 
 | 2165 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 2166 |             "getSensorDataRecord: recordID > lastRecord error"); | 
 | 2167 |         return GENERAL_ERROR; | 
 | 2168 |     } | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 2169 |     if (recordID >= ipmi::getNumberOfSensors()) | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 2170 |     { | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 2171 |         if (auto err = ipmi::sensor::getOtherSensorsDataRecord(ctx, recordID, | 
 | 2172 |                                                                recordData); | 
 | 2173 |             err < 0) | 
| Harvey Wu | 05d17c0 | 2021-09-15 08:46:59 +0800 | [diff] [blame] | 2174 |         { | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 2175 |             // phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 2176 |             //     "getSensorDataRecord: Error getting custom record"); | 
 | 2177 |             return lastRecordIndex; | 
| Harvey Wu | 05d17c0 | 2021-09-15 08:46:59 +0800 | [diff] [blame] | 2178 |         } | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 2179 |         return nextRecord; | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 2180 |     } | 
 | 2181 |  | 
| Johnathan Mantey | 6619ae4 | 2021-08-06 11:21:10 -0700 | [diff] [blame] | 2182 |     // Perform a incremental scan of the SDR Record ID's and translate the | 
 | 2183 |     // first 765 SDR records (i.e. maxIPMISensors) into IPMI Sensor | 
 | 2184 |     // Numbers. The IPMI sensor numbers are not linear, and have a reserved | 
 | 2185 |     // gap at 0xff. This code creates 254 sensors per LUN, excepting LUN 2 | 
 | 2186 |     // which has special meaning. | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 2187 |     std::string connection; | 
 | 2188 |     std::string path; | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 2189 |     std::vector<std::string> interfaces; | 
| Johnathan Mantey | ce98277 | 2021-07-28 15:08:30 -0700 | [diff] [blame] | 2190 |     uint16_t sensNumFromRecID{recordID}; | 
| Johnathan Mantey | 6619ae4 | 2021-08-06 11:21:10 -0700 | [diff] [blame] | 2191 |     if ((recordID > lun0MaxSensorNum) && (recordID < lun1MaxSensorNum)) | 
| Johnathan Mantey | ce98277 | 2021-07-28 15:08:30 -0700 | [diff] [blame] | 2192 |     { | 
| Johnathan Mantey | 6619ae4 | 2021-08-06 11:21:10 -0700 | [diff] [blame] | 2193 |         // LUN 0 has one reserved sensor number. Compensate here by adding one | 
 | 2194 |         // to the record ID | 
 | 2195 |         sensNumFromRecID = recordID + 1; | 
| Harvey Wu | 7589306 | 2023-03-22 17:17:31 +0800 | [diff] [blame] | 2196 |         ctx->lun = lun1; | 
| Johnathan Mantey | ce98277 | 2021-07-28 15:08:30 -0700 | [diff] [blame] | 2197 |     } | 
| Johnathan Mantey | 6619ae4 | 2021-08-06 11:21:10 -0700 | [diff] [blame] | 2198 |     else if ((recordID >= lun1MaxSensorNum) && (recordID < maxIPMISensors)) | 
| Johnathan Mantey | ce98277 | 2021-07-28 15:08:30 -0700 | [diff] [blame] | 2199 |     { | 
| Johnathan Mantey | 6619ae4 | 2021-08-06 11:21:10 -0700 | [diff] [blame] | 2200 |         // LUN 0, 1 have a reserved sensor number. Compensate here by adding 2 | 
 | 2201 |         // to the record ID. Skip all 256 sensors in LUN 2, as it has special | 
 | 2202 |         // rules governing its use. | 
 | 2203 |         sensNumFromRecID = recordID + (maxSensorsPerLUN + 1) + 2; | 
| Harvey Wu | 7589306 | 2023-03-22 17:17:31 +0800 | [diff] [blame] | 2204 |         ctx->lun = lun3; | 
| Johnathan Mantey | ce98277 | 2021-07-28 15:08:30 -0700 | [diff] [blame] | 2205 |     } | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 2206 |  | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 2207 |     auto status = getSensorConnection(ctx, | 
 | 2208 |                                       static_cast<uint8_t>(sensNumFromRecID), | 
 | 2209 |                                       connection, path, &interfaces); | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 2210 |     if (status) | 
 | 2211 |     { | 
 | 2212 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 2213 |             "getSensorDataRecord: getSensorConnection error"); | 
 | 2214 |         return GENERAL_ERROR; | 
 | 2215 |     } | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 2216 |     uint16_t sensorNum = getSensorNumberFromPath(path); | 
| Johnathan Mantey | 6619ae4 | 2021-08-06 11:21:10 -0700 | [diff] [blame] | 2217 |     // Return an error on LUN 2 assingments, and any sensor number beyond the | 
 | 2218 |     // range of LUN 3 | 
 | 2219 |     if (((sensorNum > lun1MaxSensorNum) && (sensorNum <= maxIPMISensors)) || | 
 | 2220 |         (sensorNum > lun3MaxSensorNum)) | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 2221 |     { | 
 | 2222 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 2223 |             "getSensorDataRecord: invalidSensorNumber"); | 
 | 2224 |         return GENERAL_ERROR; | 
 | 2225 |     } | 
| Johnathan Mantey | ce98277 | 2021-07-28 15:08:30 -0700 | [diff] [blame] | 2226 |     uint8_t sensornumber = static_cast<uint8_t>(sensorNum); | 
 | 2227 |     uint8_t lun = static_cast<uint8_t>(sensorNum >> 8); | 
 | 2228 |  | 
| Johnathan Mantey | 6619ae4 | 2021-08-06 11:21:10 -0700 | [diff] [blame] | 2229 |     if ((sensornumber != static_cast<uint8_t>(sensNumFromRecID)) && | 
 | 2230 |         (lun != ctx->lun)) | 
| Johnathan Mantey | ce98277 | 2021-07-28 15:08:30 -0700 | [diff] [blame] | 2231 |     { | 
 | 2232 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 2233 |             "getSensorDataRecord: sensor record mismatch"); | 
 | 2234 |         return GENERAL_ERROR; | 
 | 2235 |     } | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 2236 |  | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 2237 |     // Construct full record (SDR type 1) for the threshold sensors | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 2238 |     if (std::find(interfaces.begin(), interfaces.end(), | 
 | 2239 |                   sensor::sensorInterface) != interfaces.end()) | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 2240 |     { | 
| Willy Tu | 11d6889 | 2022-01-20 10:37:34 -0800 | [diff] [blame] | 2241 |         get_sdr::SensorDataFullRecord record = {}; | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 2242 |  | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 2243 |         // If the request doesn't read SDR body, construct only header and key | 
 | 2244 |         // part to avoid additional DBus transaction. | 
 | 2245 |         if (readBytes <= sizeof(record.header) + sizeof(record.key)) | 
 | 2246 |         { | 
 | 2247 |             constructSensorSdrHeaderKey(sensorNum, recordID, record); | 
 | 2248 |         } | 
| Willy Tu | 4eca251 | 2022-06-20 21:14:51 -0700 | [diff] [blame] | 2249 |         else if (!constructSensorSdr(ctx, ipmiDecoratorPaths, sensorNum, | 
 | 2250 |                                      recordID, connection, path, record)) | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 2251 |         { | 
 | 2252 |             return GENERAL_ERROR; | 
 | 2253 |         } | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 2254 |  | 
| selvaganapathi | 7b2e550 | 2023-02-14 07:10:47 +0530 | [diff] [blame] | 2255 |         recordData.insert(recordData.end(), reinterpret_cast<uint8_t*>(&record), | 
 | 2256 |                           reinterpret_cast<uint8_t*>(&record) + sizeof(record)); | 
| Willy Tu | 61992ad | 2021-03-29 15:33:20 -0700 | [diff] [blame] | 2257 |  | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 2258 |         return nextRecord; | 
| Willy Tu | 38e7a2b | 2021-03-29 15:09:56 -0700 | [diff] [blame] | 2259 |     } | 
| Willy Tu | 61992ad | 2021-03-29 15:33:20 -0700 | [diff] [blame] | 2260 |  | 
| Scron Chang | 2703b02 | 2021-07-06 15:47:45 +0800 | [diff] [blame] | 2261 | #ifdef FEATURE_HYBRID_SENSORS | 
 | 2262 |     if (auto sensor = findStaticSensor(path); | 
 | 2263 |         sensor != ipmi::sensor::sensors.end() && | 
 | 2264 |         getSensorEventTypeFromPath(path) != | 
 | 2265 |             static_cast<uint8_t>(SensorEventTypeCodes::threshold)) | 
 | 2266 |     { | 
| Willy Tu | 11d6889 | 2022-01-20 10:37:34 -0800 | [diff] [blame] | 2267 |         get_sdr::SensorDataFullRecord record = {}; | 
| Scron Chang | 2703b02 | 2021-07-06 15:47:45 +0800 | [diff] [blame] | 2268 |  | 
 | 2269 |         // If the request doesn't read SDR body, construct only header and key | 
 | 2270 |         // part to avoid additional DBus transaction. | 
 | 2271 |         if (readBytes <= sizeof(record.header) + sizeof(record.key)) | 
 | 2272 |         { | 
 | 2273 |             constructSensorSdrHeaderKey(sensorNum, recordID, record); | 
 | 2274 |         } | 
 | 2275 |         else | 
 | 2276 |         { | 
 | 2277 |             constructStaticSensorSdr(ctx, sensorNum, recordID, sensor, record); | 
 | 2278 |         } | 
 | 2279 |  | 
| selvaganapathi | 7b2e550 | 2023-02-14 07:10:47 +0530 | [diff] [blame] | 2280 |         recordData.insert(recordData.end(), reinterpret_cast<uint8_t*>(&record), | 
 | 2281 |                           reinterpret_cast<uint8_t*>(&record) + sizeof(record)); | 
| Scron Chang | 2703b02 | 2021-07-06 15:47:45 +0800 | [diff] [blame] | 2282 |  | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 2283 |         return nextRecord; | 
| Scron Chang | 2703b02 | 2021-07-06 15:47:45 +0800 | [diff] [blame] | 2284 |     } | 
 | 2285 | #endif | 
 | 2286 |  | 
| Willy Tu | 61992ad | 2021-03-29 15:33:20 -0700 | [diff] [blame] | 2287 |     // Contruct SDR type 3 record for VR sensor (daemon) | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 2288 |     if (std::find(interfaces.begin(), interfaces.end(), sensor::vrInterface) != | 
 | 2289 |         interfaces.end()) | 
| Willy Tu | 61992ad | 2021-03-29 15:33:20 -0700 | [diff] [blame] | 2290 |     { | 
| Willy Tu | 11d6889 | 2022-01-20 10:37:34 -0800 | [diff] [blame] | 2291 |         get_sdr::SensorDataEventRecord record = {}; | 
| Willy Tu | 61992ad | 2021-03-29 15:33:20 -0700 | [diff] [blame] | 2292 |  | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 2293 |         // If the request doesn't read SDR body, construct only header and key | 
 | 2294 |         // part to avoid additional DBus transaction. | 
 | 2295 |         if (readBytes <= sizeof(record.header) + sizeof(record.key)) | 
 | 2296 |         { | 
 | 2297 |             constructEventSdrHeaderKey(sensorNum, recordID, record); | 
 | 2298 |         } | 
| Willy Tu | 4eca251 | 2022-06-20 21:14:51 -0700 | [diff] [blame] | 2299 |         else if (!constructVrSdr(ctx, ipmiDecoratorPaths, sensorNum, recordID, | 
 | 2300 |                                  connection, path, record)) | 
| Hao Jiang | e39d4d8 | 2021-04-16 17:02:40 -0700 | [diff] [blame] | 2301 |         { | 
 | 2302 |             return GENERAL_ERROR; | 
 | 2303 |         } | 
| selvaganapathi | 7b2e550 | 2023-02-14 07:10:47 +0530 | [diff] [blame] | 2304 |         recordData.insert(recordData.end(), reinterpret_cast<uint8_t*>(&record), | 
 | 2305 |                           reinterpret_cast<uint8_t*>(&record) + sizeof(record)); | 
| Willy Tu | 61992ad | 2021-03-29 15:33:20 -0700 | [diff] [blame] | 2306 |     } | 
 | 2307 |  | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 2308 |     return nextRecord; | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2309 | } | 
 | 2310 |  | 
 | 2311 | /** @brief implements the get SDR Info command | 
 | 2312 |  *  @param count - Operation | 
 | 2313 |  * | 
 | 2314 |  *  @returns IPMI completion code plus response data | 
 | 2315 |  *   - sdrCount - sensor/SDR count | 
 | 2316 |  *   - lunsAndDynamicPopulation - static/Dynamic sensor population flag | 
 | 2317 |  */ | 
 | 2318 | static ipmi::RspType<uint8_t, // respcount | 
 | 2319 |                      uint8_t, // dynamic population flags | 
 | 2320 |                      uint32_t // last time a sensor was added | 
 | 2321 |                      > | 
 | 2322 |     ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx, | 
 | 2323 |                                std::optional<uint8_t> count) | 
 | 2324 | { | 
 | 2325 |     auto& sensorTree = getSensorTree(); | 
 | 2326 |     uint8_t sdrCount = 0; | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 2327 |     uint16_t recordID = 0; | 
 | 2328 |     std::vector<uint8_t> record; | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2329 |     // Sensors are dynamically allocated, and there is at least one LUN | 
 | 2330 |     uint8_t lunsAndDynamicPopulation = 0x80; | 
 | 2331 |     constexpr uint8_t getSdrCount = 0x01; | 
 | 2332 |     constexpr uint8_t getSensorCount = 0x00; | 
 | 2333 |  | 
 | 2334 |     if (!getSensorSubtree(sensorTree) || sensorTree.empty()) | 
 | 2335 |     { | 
 | 2336 |         return ipmi::responseResponseError(); | 
 | 2337 |     } | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 2338 |     uint16_t numSensors = ipmi::getNumberOfSensors(); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2339 |     if (count.value_or(0) == getSdrCount) | 
 | 2340 |     { | 
| Willy Tu | 4eca251 | 2022-06-20 21:14:51 -0700 | [diff] [blame] | 2341 |         auto& ipmiDecoratorPaths = getIpmiDecoratorPaths(ctx); | 
 | 2342 |  | 
| Harvey Wu | 7589306 | 2023-03-22 17:17:31 +0800 | [diff] [blame] | 2343 |         if (ctx->lun == lun1) | 
| Harvey Wu | a347627 | 2023-03-22 10:09:38 +0800 | [diff] [blame] | 2344 |         { | 
 | 2345 |             recordID += maxSensorsPerLUN; | 
 | 2346 |         } | 
| Harvey Wu | 7589306 | 2023-03-22 17:17:31 +0800 | [diff] [blame] | 2347 |         else if (ctx->lun == lun3) | 
| Harvey Wu | a347627 | 2023-03-22 10:09:38 +0800 | [diff] [blame] | 2348 |         { | 
 | 2349 |             recordID += maxSensorsPerLUN * 2; | 
 | 2350 |         } | 
 | 2351 |  | 
| Harvey Wu | 7589306 | 2023-03-22 17:17:31 +0800 | [diff] [blame] | 2352 |         // Count the number of Type 1h, Type 2h, Type 11h, Type 12h SDR entries | 
 | 2353 |         // assigned to the LUN | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 2354 |         while (getSensorDataRecord(ctx, | 
 | 2355 |                                    ipmiDecoratorPaths.value_or( | 
 | 2356 |                                        std::unordered_set<std::string>()), | 
 | 2357 |                                    record, recordID++) >= 0) | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2358 |         { | 
 | 2359 |             get_sdr::SensorDataRecordHeader* hdr = | 
 | 2360 |                 reinterpret_cast<get_sdr::SensorDataRecordHeader*>( | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 2361 |                     record.data()); | 
| selvaganapathi | 7b2e550 | 2023-02-14 07:10:47 +0530 | [diff] [blame] | 2362 |             if (!hdr) | 
 | 2363 |             { | 
 | 2364 |                 continue; | 
 | 2365 |             } | 
 | 2366 |  | 
 | 2367 |             if (hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD) | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2368 |             { | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 2369 |                 get_sdr::SensorDataFullRecord* recordData = | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2370 |                     reinterpret_cast<get_sdr::SensorDataFullRecord*>( | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 2371 |                         record.data()); | 
 | 2372 |                 if (ctx->lun == recordData->key.owner_lun) | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2373 |                 { | 
 | 2374 |                     sdrCount++; | 
 | 2375 |                 } | 
 | 2376 |             } | 
| selvaganapathi | 7b2e550 | 2023-02-14 07:10:47 +0530 | [diff] [blame] | 2377 |             else if (hdr->record_type == get_sdr::SENSOR_DATA_COMPACT_RECORD) | 
 | 2378 |             { | 
 | 2379 |                 get_sdr::SensorDataCompactRecord* recordData = | 
 | 2380 |                     reinterpret_cast<get_sdr::SensorDataCompactRecord*>( | 
 | 2381 |                         record.data()); | 
 | 2382 |                 if (ctx->lun == recordData->key.owner_lun) | 
 | 2383 |                 { | 
 | 2384 |                     sdrCount++; | 
 | 2385 |                 } | 
 | 2386 |             } | 
| Harvey Wu | a347627 | 2023-03-22 10:09:38 +0800 | [diff] [blame] | 2387 |             else if (hdr->record_type == get_sdr::SENSOR_DATA_FRU_RECORD || | 
 | 2388 |                      hdr->record_type == get_sdr::SENSOR_DATA_MGMT_CTRL_LOCATOR) | 
| selvaganapathi | 7b2e550 | 2023-02-14 07:10:47 +0530 | [diff] [blame] | 2389 |             { | 
 | 2390 |                 sdrCount++; | 
 | 2391 |             } | 
| Harvey Wu | a347627 | 2023-03-22 10:09:38 +0800 | [diff] [blame] | 2392 |  | 
 | 2393 |             // Because response count data is 1 byte, so sdrCount need to avoid | 
 | 2394 |             // overflow. | 
 | 2395 |             if (sdrCount == maxSensorsPerLUN) | 
 | 2396 |             { | 
 | 2397 |                 break; | 
 | 2398 |             } | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2399 |         } | 
 | 2400 |     } | 
 | 2401 |     else if (count.value_or(0) == getSensorCount) | 
 | 2402 |     { | 
 | 2403 |         // Return the number of sensors attached to the LUN | 
| Harvey Wu | 7589306 | 2023-03-22 17:17:31 +0800 | [diff] [blame] | 2404 |         if ((ctx->lun == lun0) && (numSensors > 0)) | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2405 |         { | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 2406 |             sdrCount = (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN | 
 | 2407 |                                                        : numSensors; | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2408 |         } | 
| Harvey Wu | 7589306 | 2023-03-22 17:17:31 +0800 | [diff] [blame] | 2409 |         else if ((ctx->lun == lun1) && (numSensors > maxSensorsPerLUN)) | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2410 |         { | 
 | 2411 |             sdrCount = (numSensors > (2 * maxSensorsPerLUN)) | 
 | 2412 |                            ? maxSensorsPerLUN | 
 | 2413 |                            : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN; | 
 | 2414 |         } | 
| Harvey Wu | 7589306 | 2023-03-22 17:17:31 +0800 | [diff] [blame] | 2415 |         else if (ctx->lun == lun3) | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2416 |         { | 
 | 2417 |             if (numSensors <= maxIPMISensors) | 
 | 2418 |             { | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 2419 |                 sdrCount = (numSensors - (2 * maxSensorsPerLUN)) & | 
 | 2420 |                            maxSensorsPerLUN; | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2421 |             } | 
 | 2422 |             else | 
 | 2423 |             { | 
 | 2424 |                 // error | 
 | 2425 |                 throw std::out_of_range( | 
 | 2426 |                     "Maximum number of IPMI sensors exceeded."); | 
 | 2427 |             } | 
 | 2428 |         } | 
 | 2429 |     } | 
 | 2430 |     else | 
 | 2431 |     { | 
 | 2432 |         return ipmi::responseInvalidFieldRequest(); | 
 | 2433 |     } | 
 | 2434 |  | 
 | 2435 |     // Get Sensor count. This returns the number of sensors | 
 | 2436 |     if (numSensors > 0) | 
 | 2437 |     { | 
 | 2438 |         lunsAndDynamicPopulation |= 1; | 
 | 2439 |     } | 
 | 2440 |     if (numSensors > maxSensorsPerLUN) | 
 | 2441 |     { | 
 | 2442 |         lunsAndDynamicPopulation |= 2; | 
 | 2443 |     } | 
 | 2444 |     if (numSensors >= (maxSensorsPerLUN * 2)) | 
 | 2445 |     { | 
 | 2446 |         lunsAndDynamicPopulation |= 8; | 
 | 2447 |     } | 
 | 2448 |     if (numSensors > maxIPMISensors) | 
 | 2449 |     { | 
 | 2450 |         // error | 
 | 2451 |         throw std::out_of_range("Maximum number of IPMI sensors exceeded."); | 
 | 2452 |     } | 
 | 2453 |  | 
 | 2454 |     return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation, | 
 | 2455 |                                  sdrLastAdd); | 
 | 2456 | } | 
 | 2457 |  | 
 | 2458 | /* end sensor commands */ | 
 | 2459 |  | 
 | 2460 | /* storage commands */ | 
 | 2461 |  | 
 | 2462 | ipmi::RspType<uint8_t,  // sdr version | 
 | 2463 |               uint16_t, // record count | 
 | 2464 |               uint16_t, // free space | 
 | 2465 |               uint32_t, // most recent addition | 
 | 2466 |               uint32_t, // most recent erase | 
 | 2467 |               uint8_t   // operationSupport | 
 | 2468 |               > | 
 | 2469 |     ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx) | 
 | 2470 | { | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2471 |     constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF; | 
| Johnathan Mantey | 31c1ecd | 2024-06-20 11:10:41 -0700 | [diff] [blame] | 2472 |     uint16_t recordCount = ipmi::getNumberOfSensors() + | 
 | 2473 |                            ipmi::sensor::getOtherSensorsCount(ctx); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2474 |  | 
 | 2475 |     uint8_t operationSupport = static_cast<uint8_t>( | 
 | 2476 |         SdrRepositoryInfoOps::overflow); // write not supported | 
 | 2477 |  | 
 | 2478 |     operationSupport |= | 
 | 2479 |         static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported); | 
 | 2480 |     operationSupport |= static_cast<uint8_t>( | 
 | 2481 |         SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported); | 
 | 2482 |     return ipmi::responseSuccess(ipmiSdrVersion, recordCount, | 
 | 2483 |                                  unspecifiedFreeSpace, sdrLastAdd, | 
 | 2484 |                                  sdrLastRemove, operationSupport); | 
 | 2485 | } | 
 | 2486 |  | 
 | 2487 | /** @brief implements the get SDR allocation info command | 
 | 2488 |  * | 
 | 2489 |  *  @returns IPMI completion code plus response data | 
 | 2490 |  *   - allocUnits    - Number of possible allocation units | 
 | 2491 |  *   - allocUnitSize - Allocation unit size in bytes. | 
 | 2492 |  *   - allocUnitFree - Number of free allocation units | 
 | 2493 |  *   - allocUnitLargestFree - Largest free block in allocation units | 
 | 2494 |  *   - maxRecordSize    - Maximum record size in allocation units. | 
 | 2495 |  */ | 
 | 2496 | ipmi::RspType<uint16_t, // allocUnits | 
 | 2497 |               uint16_t, // allocUnitSize | 
 | 2498 |               uint16_t, // allocUnitFree | 
 | 2499 |               uint16_t, // allocUnitLargestFree | 
 | 2500 |               uint8_t   // maxRecordSize | 
 | 2501 |               > | 
 | 2502 |     ipmiStorageGetSDRAllocationInfo() | 
 | 2503 | { | 
 | 2504 |     // 0000h unspecified number of alloc units | 
 | 2505 |     constexpr uint16_t allocUnits = 0; | 
 | 2506 |  | 
 | 2507 |     constexpr uint16_t allocUnitFree = 0; | 
 | 2508 |     constexpr uint16_t allocUnitLargestFree = 0; | 
 | 2509 |     // only allow one block at a time | 
 | 2510 |     constexpr uint8_t maxRecordSize = 1; | 
 | 2511 |  | 
 | 2512 |     return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree, | 
 | 2513 |                                  allocUnitLargestFree, maxRecordSize); | 
 | 2514 | } | 
 | 2515 |  | 
 | 2516 | /** @brief implements the reserve SDR command | 
 | 2517 |  *  @returns IPMI completion code plus response data | 
 | 2518 |  *   - sdrReservationID | 
 | 2519 |  */ | 
 | 2520 | ipmi::RspType<uint16_t> ipmiStorageReserveSDR() | 
 | 2521 | { | 
 | 2522 |     sdrReservationID++; | 
 | 2523 |     if (sdrReservationID == 0) | 
 | 2524 |     { | 
 | 2525 |         sdrReservationID++; | 
 | 2526 |     } | 
 | 2527 |  | 
 | 2528 |     return ipmi::responseSuccess(sdrReservationID); | 
 | 2529 | } | 
 | 2530 |  | 
 | 2531 | ipmi::RspType<uint16_t,            // next record ID | 
 | 2532 |               std::vector<uint8_t> // payload | 
 | 2533 |               > | 
 | 2534 |     ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID, | 
 | 2535 |                       uint16_t recordID, uint8_t offset, uint8_t bytesToRead) | 
 | 2536 | { | 
 | 2537 |     // reservation required for partial reads with non zero offset into | 
 | 2538 |     // record | 
 | 2539 |     if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset) | 
 | 2540 |     { | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 2541 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 2542 |             "ipmiStorageGetSDR: responseInvalidReservationId"); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2543 |         return ipmi::responseInvalidReservationId(); | 
 | 2544 |     } | 
| Harvey Wu | 05d17c0 | 2021-09-15 08:46:59 +0800 | [diff] [blame] | 2545 |  | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 2546 |     auto& sensorTree = getSensorTree(); | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 2547 |     if (!getSensorSubtree(sensorTree) && sensorTree.empty()) | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2548 |     { | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 2549 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 2550 |             "ipmiStorageGetSDR: getSensorSubtree error"); | 
 | 2551 |         return ipmi::responseResponseError(); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2552 |     } | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 2553 |  | 
| Willy Tu | 4eca251 | 2022-06-20 21:14:51 -0700 | [diff] [blame] | 2554 |     auto& ipmiDecoratorPaths = getIpmiDecoratorPaths(ctx); | 
 | 2555 |  | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 2556 |     std::vector<uint8_t> record; | 
| Johnathan Mantey | 777cfaf | 2024-06-13 10:45:47 -0700 | [diff] [blame] | 2557 |     int nextRecordId = getSensorDataRecord( | 
 | 2558 |         ctx, ipmiDecoratorPaths.value_or(std::unordered_set<std::string>()), | 
 | 2559 |         record, recordID, offset + bytesToRead); | 
 | 2560 |  | 
 | 2561 |     if (nextRecordId < 0) | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2562 |     { | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 2563 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 2564 |             "ipmiStorageGetSDR: fail to get SDR"); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2565 |         return ipmi::responseInvalidFieldRequest(); | 
 | 2566 |     } | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2567 |     get_sdr::SensorDataRecordHeader* hdr = | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 2568 |         reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data()); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2569 |     if (!hdr) | 
 | 2570 |     { | 
 | 2571 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 2572 |             "ipmiStorageGetSDR: record header is null"); | 
 | 2573 |         return ipmi::responseSuccess(nextRecordId, record); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2574 |     } | 
 | 2575 |  | 
| Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 2576 |     size_t sdrLength = sizeof(get_sdr::SensorDataRecordHeader) + | 
 | 2577 |                        hdr->record_length; | 
| Vernon Mauery | 6dbea08 | 2023-07-21 11:43:00 -0700 | [diff] [blame] | 2578 |     if (offset >= sdrLength) | 
 | 2579 |     { | 
 | 2580 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 2581 |             "ipmiStorageGetSDR: offset is outside the record"); | 
 | 2582 |         return ipmi::responseParmOutOfRange(); | 
 | 2583 |     } | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2584 |     if (sdrLength < (offset + bytesToRead)) | 
 | 2585 |     { | 
 | 2586 |         bytesToRead = sdrLength - offset; | 
 | 2587 |     } | 
 | 2588 |  | 
 | 2589 |     uint8_t* respStart = reinterpret_cast<uint8_t*>(hdr) + offset; | 
 | 2590 |     if (!respStart) | 
 | 2591 |     { | 
 | 2592 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 2593 |             "ipmiStorageGetSDR: record is null"); | 
 | 2594 |         return ipmi::responseSuccess(nextRecordId, record); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2595 |     } | 
 | 2596 |  | 
 | 2597 |     std::vector<uint8_t> recordData(respStart, respStart + bytesToRead); | 
| Kuiying Wang | a8b5b26 | 2021-02-06 23:38:22 +0800 | [diff] [blame] | 2598 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2599 |     return ipmi::responseSuccess(nextRecordId, recordData); | 
 | 2600 | } | 
| adarshgrami | 042e9db | 2022-09-15 10:34:34 +0530 | [diff] [blame] | 2601 | namespace dcmi | 
 | 2602 | { | 
 | 2603 |  | 
| Thang Tran | b1416ef | 2023-08-02 13:57:09 +0700 | [diff] [blame] | 2604 | std::tuple<uint8_t,                // Total of instance sensors | 
 | 2605 |            std::vector<sensorInfo> // The list of sensors | 
 | 2606 |            > | 
 | 2607 |     getSensorsByEntityId(ipmi::Context::ptr ctx, uint8_t entityId, | 
 | 2608 |                          uint8_t entityInstance, uint8_t instanceStart) | 
 | 2609 | { | 
 | 2610 |     std::vector<sensorInfo> sensorList; | 
 | 2611 |     uint8_t totalInstSensor = 0; | 
 | 2612 |     auto match = ipmi::dcmi::validEntityId.find(entityId); | 
 | 2613 |  | 
 | 2614 |     if (match == ipmi::dcmi::validEntityId.end()) | 
 | 2615 |     { | 
 | 2616 |         return std::make_tuple(totalInstSensor, sensorList); | 
 | 2617 |     } | 
 | 2618 |  | 
 | 2619 |     auto& sensorTree = getSensorTree(); | 
 | 2620 |     if (!getSensorSubtree(sensorTree) && sensorTree.empty()) | 
 | 2621 |     { | 
 | 2622 |         return std::make_tuple(totalInstSensor, sensorList); | 
 | 2623 |     } | 
 | 2624 |  | 
 | 2625 |     auto& ipmiDecoratorPaths = getIpmiDecoratorPaths(ctx); | 
 | 2626 |  | 
| Willy Tu | 62e3ca8 | 2024-01-31 17:28:34 +0000 | [diff] [blame] | 2627 |     size_t invalidSensorNumberErrCount = 0; | 
| Thang Tran | b1416ef | 2023-08-02 13:57:09 +0700 | [diff] [blame] | 2628 |     for (const auto& sensor : sensorTree) | 
 | 2629 |     { | 
 | 2630 |         const std::string& sensorObjPath = sensor.first; | 
 | 2631 |         const auto& sensorTypeValue = getSensorTypeFromPath(sensorObjPath); | 
 | 2632 |  | 
 | 2633 |         /* | 
 | 2634 |          * In the DCMI specification, it only supports the sensor type is 0x01 | 
 | 2635 |          * (temperature type) for both Get Sensor Info and Get Temperature | 
 | 2636 |          * Readings commands. | 
 | 2637 |          */ | 
 | 2638 |         if (sensorTypeValue != ipmi::dcmi::temperatureSensorType) | 
 | 2639 |         { | 
 | 2640 |             continue; | 
 | 2641 |         } | 
 | 2642 |  | 
 | 2643 |         const auto& connection = sensor.second.begin()->first; | 
 | 2644 |         DbusInterfaceMap sensorMap; | 
 | 2645 |  | 
 | 2646 |         if (!getSensorMap(ctx, connection, sensorObjPath, sensorMap, | 
 | 2647 |                           sensorMapSdrUpdatePeriod)) | 
 | 2648 |         { | 
 | 2649 |             phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 2650 |                 "Failed to update sensor map for threshold sensor", | 
 | 2651 |                 phosphor::logging::entry("SERVICE=%s", connection.c_str()), | 
 | 2652 |                 phosphor::logging::entry("PATH=%s", sensorObjPath.c_str())); | 
 | 2653 |             continue; | 
 | 2654 |         } | 
 | 2655 |  | 
 | 2656 |         uint8_t entityIdValue = 0; | 
 | 2657 |         uint8_t entityInstanceValue = 0; | 
 | 2658 |  | 
 | 2659 |         /* | 
 | 2660 |          * Get the Entity ID, Entity Instance information which are configured | 
 | 2661 |          * in the Entity-Manger. | 
 | 2662 |          */ | 
 | 2663 |         updateIpmiFromAssociation( | 
 | 2664 |             sensorObjPath, | 
 | 2665 |             ipmiDecoratorPaths.value_or(std::unordered_set<std::string>()), | 
 | 2666 |             sensorMap, entityIdValue, entityInstanceValue); | 
 | 2667 |  | 
 | 2668 |         if (entityIdValue == match->first || entityIdValue == match->second) | 
 | 2669 |         { | 
 | 2670 |             totalInstSensor++; | 
 | 2671 |  | 
 | 2672 |             /* | 
 | 2673 |              * When Entity Instance parameter is not 0, we only get the first | 
 | 2674 |              * sensor whose Entity Instance number is equal input Entity | 
 | 2675 |              * Instance parameter. | 
 | 2676 |              */ | 
 | 2677 |             if (entityInstance) | 
 | 2678 |             { | 
 | 2679 |                 if (!sensorList.empty()) | 
 | 2680 |                 { | 
 | 2681 |                     continue; | 
 | 2682 |                 } | 
 | 2683 |  | 
 | 2684 |                 if (entityInstanceValue == entityInstance) | 
 | 2685 |                 { | 
 | 2686 |                     auto recordId = getSensorNumberFromPath(sensorObjPath); | 
| Willy Tu | 62e3ca8 | 2024-01-31 17:28:34 +0000 | [diff] [blame] | 2687 |                     if (recordId == invalidSensorNumber) | 
| Thang Tran | b1416ef | 2023-08-02 13:57:09 +0700 | [diff] [blame] | 2688 |                     { | 
| Willy Tu | 62e3ca8 | 2024-01-31 17:28:34 +0000 | [diff] [blame] | 2689 |                         ++invalidSensorNumberErrCount; | 
 | 2690 |                         continue; | 
| Thang Tran | b1416ef | 2023-08-02 13:57:09 +0700 | [diff] [blame] | 2691 |                     } | 
| Thang Tran | b1416ef | 2023-08-02 13:57:09 +0700 | [diff] [blame] | 2692 |                     sensorList.emplace_back(sensorObjPath, sensorTypeValue, | 
 | 2693 |                                             recordId, entityIdValue, | 
 | 2694 |                                             entityInstanceValue); | 
 | 2695 |                 } | 
 | 2696 |             } | 
| Willy Tu | 62e3ca8 | 2024-01-31 17:28:34 +0000 | [diff] [blame] | 2697 |             else if (entityInstanceValue >= instanceStart) | 
 | 2698 |             { | 
 | 2699 |                 auto recordId = getSensorNumberFromPath(sensorObjPath); | 
 | 2700 |                 if (recordId == invalidSensorNumber) | 
 | 2701 |                 { | 
 | 2702 |                     ++invalidSensorNumberErrCount; | 
 | 2703 |                     continue; | 
 | 2704 |                 } | 
 | 2705 |                 sensorList.emplace_back(sensorObjPath, sensorTypeValue, | 
 | 2706 |                                         recordId, entityIdValue, | 
 | 2707 |                                         entityInstanceValue); | 
 | 2708 |             } | 
| Thang Tran | b1416ef | 2023-08-02 13:57:09 +0700 | [diff] [blame] | 2709 |         } | 
 | 2710 |     } | 
| Willy Tu | 62e3ca8 | 2024-01-31 17:28:34 +0000 | [diff] [blame] | 2711 |     if (invalidSensorNumberErrCount != 0) | 
 | 2712 |     { | 
 | 2713 |         phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 2714 |             std::format( | 
 | 2715 |                 "getSensorNumberFromPath returned invalidSensorNumber {} times", | 
 | 2716 |                 invalidSensorNumberErrCount) | 
 | 2717 |                 .data()); | 
 | 2718 |     } | 
| Thang Tran | b1416ef | 2023-08-02 13:57:09 +0700 | [diff] [blame] | 2719 |  | 
 | 2720 |     auto cmpFunc = [](sensorInfo first, sensorInfo second) { | 
 | 2721 |         return first.entityInstance <= second.entityInstance; | 
 | 2722 |     }; | 
 | 2723 |  | 
 | 2724 |     sort(sensorList.begin(), sensorList.end(), cmpFunc); | 
 | 2725 |  | 
 | 2726 |     return std::make_tuple(totalInstSensor, sensorList); | 
 | 2727 | } | 
 | 2728 |  | 
| Thang Tran | 3dad826 | 2023-08-17 15:20:56 +0700 | [diff] [blame] | 2729 | std::tuple<bool,    // Reading result | 
 | 2730 |            uint7_t, // Temp value | 
 | 2731 |            bool>    // Sign bit | 
 | 2732 |     readTemp(ipmi::Context::ptr ctx, const std::string& objectPath) | 
 | 2733 | { | 
 | 2734 |     std::string service{}; | 
 | 2735 |     boost::system::error_code ec = | 
 | 2736 |         ipmi::getService(ctx, sensor::sensorInterface, objectPath, service); | 
 | 2737 |     if (ec.value()) | 
 | 2738 |     { | 
 | 2739 |         return std::make_tuple(false, 0, false); | 
 | 2740 |     } | 
 | 2741 |  | 
 | 2742 |     ipmi::PropertyMap properties{}; | 
 | 2743 |     ec = ipmi::getAllDbusProperties(ctx, service, objectPath, | 
 | 2744 |                                     sensor::sensorInterface, properties); | 
 | 2745 |     if (ec.value()) | 
 | 2746 |     { | 
 | 2747 |         return std::make_tuple(false, 0, false); | 
 | 2748 |     } | 
 | 2749 |  | 
 | 2750 |     auto scaleIt = properties.find("Scale"); | 
 | 2751 |     double scaleVal = 0.0; | 
 | 2752 |     if (scaleIt != properties.end()) | 
 | 2753 |     { | 
 | 2754 |         scaleVal = std::visit(ipmi::VariantToDoubleVisitor(), scaleIt->second); | 
 | 2755 |     } | 
 | 2756 |  | 
 | 2757 |     auto tempValIt = properties.find("Value"); | 
 | 2758 |     double tempVal = 0.0; | 
 | 2759 |     if (tempValIt == properties.end()) | 
 | 2760 |     { | 
 | 2761 |         return std::make_tuple(false, 0, false); | 
 | 2762 |     } | 
 | 2763 |  | 
 | 2764 |     const double maxTemp = 127; | 
 | 2765 |     double absTempVal = 0.0; | 
 | 2766 |     bool signBit = false; | 
 | 2767 |  | 
 | 2768 |     tempVal = std::visit(ipmi::VariantToDoubleVisitor(), tempValIt->second); | 
 | 2769 |     tempVal = std::pow(10, scaleVal) * tempVal; | 
 | 2770 |     absTempVal = std::abs(tempVal); | 
 | 2771 |     absTempVal = std::min(absTempVal, maxTemp); | 
 | 2772 |     signBit = (tempVal < 0) ? true : false; | 
 | 2773 |  | 
 | 2774 |     return std::make_tuple(true, static_cast<uint7_t>(absTempVal), signBit); | 
 | 2775 | } | 
 | 2776 |  | 
| adarshgrami | 042e9db | 2022-09-15 10:34:34 +0530 | [diff] [blame] | 2777 | ipmi::RspType<uint8_t,              // No of instances for requested id | 
 | 2778 |               uint8_t,              // No of record ids in the response | 
 | 2779 |               std::vector<uint16_t> // SDR Record ID corresponding to the Entity | 
 | 2780 |                                     // IDs | 
 | 2781 |               > | 
 | 2782 |     getSensorInfo(ipmi::Context::ptr ctx, uint8_t sensorType, uint8_t entityId, | 
| Thang Tran | b1416ef | 2023-08-02 13:57:09 +0700 | [diff] [blame] | 2783 |                   uint8_t entityInstance, uint8_t instanceStart) | 
| adarshgrami | 042e9db | 2022-09-15 10:34:34 +0530 | [diff] [blame] | 2784 | { | 
 | 2785 |     auto match = ipmi::dcmi::validEntityId.find(entityId); | 
 | 2786 |     if (match == ipmi::dcmi::validEntityId.end()) | 
 | 2787 |     { | 
 | 2788 |         log<level::ERR>("Unknown Entity ID", entry("ENTITY_ID=%d", entityId)); | 
 | 2789 |  | 
 | 2790 |         return ipmi::responseInvalidFieldRequest(); | 
 | 2791 |     } | 
 | 2792 |  | 
 | 2793 |     if (sensorType != ipmi::dcmi::temperatureSensorType) | 
 | 2794 |     { | 
 | 2795 |         log<level::ERR>("Invalid sensor type", | 
 | 2796 |                         entry("SENSOR_TYPE=%d", sensorType)); | 
 | 2797 |  | 
 | 2798 |         return ipmi::responseInvalidFieldRequest(); | 
 | 2799 |     } | 
| adarshgrami | 042e9db | 2022-09-15 10:34:34 +0530 | [diff] [blame] | 2800 |  | 
 | 2801 |     std::vector<uint16_t> sensorRec{}; | 
| Thang Tran | b1416ef | 2023-08-02 13:57:09 +0700 | [diff] [blame] | 2802 |     const auto& [totalSensorInst, sensorList] = | 
 | 2803 |         getSensorsByEntityId(ctx, entityId, entityInstance, instanceStart); | 
| adarshgrami | 042e9db | 2022-09-15 10:34:34 +0530 | [diff] [blame] | 2804 |  | 
| Thang Tran | b1416ef | 2023-08-02 13:57:09 +0700 | [diff] [blame] | 2805 |     if (sensorList.empty()) | 
| adarshgrami | 042e9db | 2022-09-15 10:34:34 +0530 | [diff] [blame] | 2806 |     { | 
| Thang Tran | b1416ef | 2023-08-02 13:57:09 +0700 | [diff] [blame] | 2807 |         return ipmi::responseSuccess(totalSensorInst, 0, sensorRec); | 
 | 2808 |     } | 
| adarshgrami | 042e9db | 2022-09-15 10:34:34 +0530 | [diff] [blame] | 2809 |  | 
| Thang Tran | b1416ef | 2023-08-02 13:57:09 +0700 | [diff] [blame] | 2810 |     /* | 
 | 2811 |      * As DCMI specification, the maximum number of Record Ids of response data | 
 | 2812 |      * is 1 if Entity Instance paramter is not 0. Else the maximum number of | 
 | 2813 |      * Record Ids of response data is 8. Therefore, not all of sensors are shown | 
 | 2814 |      * in response data. | 
 | 2815 |      */ | 
 | 2816 |     uint8_t numOfRec = (entityInstance != 0) ? 1 : ipmi::dcmi::maxRecords; | 
 | 2817 |  | 
 | 2818 |     for (const auto& sensor : sensorList) | 
 | 2819 |     { | 
 | 2820 |         sensorRec.emplace_back(sensor.recordId); | 
 | 2821 |         if (sensorRec.size() >= numOfRec) | 
| adarshgrami | 042e9db | 2022-09-15 10:34:34 +0530 | [diff] [blame] | 2822 |         { | 
| Thang Tran | b1416ef | 2023-08-02 13:57:09 +0700 | [diff] [blame] | 2823 |             break; | 
| adarshgrami | 042e9db | 2022-09-15 10:34:34 +0530 | [diff] [blame] | 2824 |         } | 
 | 2825 |     } | 
| Thang Tran | b1416ef | 2023-08-02 13:57:09 +0700 | [diff] [blame] | 2826 |  | 
 | 2827 |     return ipmi::responseSuccess( | 
 | 2828 |         totalSensorInst, static_cast<uint8_t>(sensorRec.size()), sensorRec); | 
| adarshgrami | 042e9db | 2022-09-15 10:34:34 +0530 | [diff] [blame] | 2829 | } | 
| Thang Tran | 3dad826 | 2023-08-17 15:20:56 +0700 | [diff] [blame] | 2830 |  | 
 | 2831 | ipmi::RspType<uint8_t,                // No of instances for requested id | 
 | 2832 |               uint8_t,                // No of record ids in the response | 
 | 2833 |               std::vector<            // Temperature Data | 
 | 2834 |                   std::tuple<uint7_t, // Temperature value | 
 | 2835 |                              bool,    // Sign bit | 
 | 2836 |                              uint8_t  // Entity Instance of sensor | 
 | 2837 |                              >>> | 
 | 2838 |     getTempReadings(ipmi::Context::ptr ctx, uint8_t sensorType, | 
 | 2839 |                     uint8_t entityId, uint8_t entityInstance, | 
 | 2840 |                     uint8_t instanceStart) | 
 | 2841 | { | 
 | 2842 |     auto match = ipmi::dcmi::validEntityId.find(entityId); | 
 | 2843 |     if (match == ipmi::dcmi::validEntityId.end()) | 
 | 2844 |     { | 
 | 2845 |         log<level::ERR>("Unknown Entity ID", entry("ENTITY_ID=%d", entityId)); | 
 | 2846 |  | 
 | 2847 |         return ipmi::responseInvalidFieldRequest(); | 
 | 2848 |     } | 
 | 2849 |  | 
 | 2850 |     if (sensorType != ipmi::dcmi::temperatureSensorType) | 
 | 2851 |     { | 
 | 2852 |         log<level::ERR>("Invalid sensor type", | 
 | 2853 |                         entry("SENSOR_TYPE=%d", sensorType)); | 
 | 2854 |  | 
 | 2855 |         return ipmi::responseInvalidFieldRequest(); | 
 | 2856 |     } | 
 | 2857 |  | 
 | 2858 |     std::vector<std::tuple<uint7_t, bool, uint8_t>> tempReadingVal{}; | 
 | 2859 |     const auto& [totalSensorInst, sensorList] = | 
 | 2860 |         getSensorsByEntityId(ctx, entityId, entityInstance, instanceStart); | 
 | 2861 |  | 
 | 2862 |     if (sensorList.empty()) | 
 | 2863 |     { | 
 | 2864 |         return ipmi::responseSuccess(totalSensorInst, 0, tempReadingVal); | 
 | 2865 |     } | 
 | 2866 |  | 
 | 2867 |     /* | 
 | 2868 |      * As DCMI specification, the maximum number of Record Ids of response data | 
 | 2869 |      * is 1 if Entity Instance paramter is not 0. Else the maximum number of | 
 | 2870 |      * Record Ids of response data is 8. Therefore, not all of sensors are shown | 
 | 2871 |      * in response data. | 
 | 2872 |      */ | 
 | 2873 |     uint8_t numOfRec = (entityInstance != 0) ? 1 : ipmi::dcmi::maxRecords; | 
 | 2874 |  | 
 | 2875 |     for (const auto& sensor : sensorList) | 
 | 2876 |     { | 
 | 2877 |         const auto& [readResult, tempVal, | 
 | 2878 |                      signBit] = readTemp(ctx, sensor.objectPath); | 
 | 2879 |  | 
 | 2880 |         if (readResult) | 
 | 2881 |         { | 
 | 2882 |             tempReadingVal.emplace_back( | 
 | 2883 |                 std::make_tuple(tempVal, signBit, sensor.entityInstance)); | 
 | 2884 |  | 
 | 2885 |             if (tempReadingVal.size() >= numOfRec) | 
 | 2886 |             { | 
 | 2887 |                 break; | 
 | 2888 |             } | 
 | 2889 |         } | 
 | 2890 |     } | 
 | 2891 |  | 
 | 2892 |     return ipmi::responseSuccess(totalSensorInst, | 
 | 2893 |                                  static_cast<uint8_t>(tempReadingVal.size()), | 
 | 2894 |                                  tempReadingVal); | 
 | 2895 | } | 
 | 2896 |  | 
| adarshgrami | 042e9db | 2022-09-15 10:34:34 +0530 | [diff] [blame] | 2897 | } // namespace dcmi | 
 | 2898 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2899 | /* end storage commands */ | 
 | 2900 |  | 
 | 2901 | void registerSensorFunctions() | 
 | 2902 | { | 
 | 2903 |     // <Platform Event> | 
 | 2904 |     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor, | 
 | 2905 |                           ipmi::sensor_event::cmdPlatformEvent, | 
 | 2906 |                           ipmi::Privilege::Operator, ipmiSenPlatformEvent); | 
 | 2907 |  | 
| Willy Tu | dbafbce | 2021-03-29 00:37:05 -0700 | [diff] [blame] | 2908 |     // <Set Sensor Reading and Event Status> | 
 | 2909 |     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor, | 
 | 2910 |                           ipmi::sensor_event::cmdSetSensorReadingAndEvtSts, | 
 | 2911 |                           ipmi::Privilege::Operator, ipmiSetSensorReading); | 
| Willy Tu | dbafbce | 2021-03-29 00:37:05 -0700 | [diff] [blame] | 2912 |  | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2913 |     // <Get Sensor Reading> | 
 | 2914 |     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor, | 
 | 2915 |                           ipmi::sensor_event::cmdGetSensorReading, | 
 | 2916 |                           ipmi::Privilege::User, ipmiSenGetSensorReading); | 
 | 2917 |  | 
 | 2918 |     // <Get Sensor Threshold> | 
 | 2919 |     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor, | 
 | 2920 |                           ipmi::sensor_event::cmdGetSensorThreshold, | 
 | 2921 |                           ipmi::Privilege::User, ipmiSenGetSensorThresholds); | 
 | 2922 |  | 
 | 2923 |     // <Set Sensor Threshold> | 
 | 2924 |     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor, | 
 | 2925 |                           ipmi::sensor_event::cmdSetSensorThreshold, | 
 | 2926 |                           ipmi::Privilege::Operator, | 
 | 2927 |                           ipmiSenSetSensorThresholds); | 
 | 2928 |  | 
 | 2929 |     // <Get Sensor Event Enable> | 
 | 2930 |     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor, | 
 | 2931 |                           ipmi::sensor_event::cmdGetSensorEventEnable, | 
 | 2932 |                           ipmi::Privilege::User, ipmiSenGetSensorEventEnable); | 
 | 2933 |  | 
 | 2934 |     // <Get Sensor Event Status> | 
 | 2935 |     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor, | 
 | 2936 |                           ipmi::sensor_event::cmdGetSensorEventStatus, | 
 | 2937 |                           ipmi::Privilege::User, ipmiSenGetSensorEventStatus); | 
 | 2938 |  | 
 | 2939 |     // register all storage commands for both Sensor and Storage command | 
 | 2940 |     // versions | 
 | 2941 |  | 
 | 2942 |     // <Get SDR Repository Info> | 
 | 2943 |     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, | 
 | 2944 |                           ipmi::storage::cmdGetSdrRepositoryInfo, | 
 | 2945 |                           ipmi::Privilege::User, | 
 | 2946 |                           ipmiStorageGetSDRRepositoryInfo); | 
 | 2947 |  | 
 | 2948 |     // <Get Device SDR Info> | 
 | 2949 |     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor, | 
 | 2950 |                           ipmi::sensor_event::cmdGetDeviceSdrInfo, | 
 | 2951 |                           ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo); | 
 | 2952 |  | 
 | 2953 |     // <Get SDR Allocation Info> | 
 | 2954 |     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, | 
 | 2955 |                           ipmi::storage::cmdGetSdrRepositoryAllocInfo, | 
 | 2956 |                           ipmi::Privilege::User, | 
 | 2957 |                           ipmiStorageGetSDRAllocationInfo); | 
 | 2958 |  | 
 | 2959 |     // <Reserve SDR Repo> | 
 | 2960 |     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor, | 
 | 2961 |                           ipmi::sensor_event::cmdReserveDeviceSdrRepository, | 
 | 2962 |                           ipmi::Privilege::User, ipmiStorageReserveSDR); | 
 | 2963 |  | 
 | 2964 |     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, | 
 | 2965 |                           ipmi::storage::cmdReserveSdrRepository, | 
 | 2966 |                           ipmi::Privilege::User, ipmiStorageReserveSDR); | 
 | 2967 |  | 
 | 2968 |     // <Get Sdr> | 
 | 2969 |     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor, | 
 | 2970 |                           ipmi::sensor_event::cmdGetDeviceSdr, | 
 | 2971 |                           ipmi::Privilege::User, ipmiStorageGetSDR); | 
 | 2972 |  | 
 | 2973 |     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, | 
 | 2974 |                           ipmi::storage::cmdGetSdr, ipmi::Privilege::User, | 
 | 2975 |                           ipmiStorageGetSDR); | 
| adarshgrami | 042e9db | 2022-09-15 10:34:34 +0530 | [diff] [blame] | 2976 |     // <Get DCMI Sensor Info> | 
 | 2977 |     ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI, | 
 | 2978 |                                ipmi::dcmi::cmdGetDcmiSensorInfo, | 
| Chau Ly | d74df5f | 2023-05-25 10:33:00 +0000 | [diff] [blame] | 2979 |                                ipmi::Privilege::Operator, | 
| adarshgrami | 042e9db | 2022-09-15 10:34:34 +0530 | [diff] [blame] | 2980 |                                ipmi::dcmi::getSensorInfo); | 
| Thang Tran | 3dad826 | 2023-08-17 15:20:56 +0700 | [diff] [blame] | 2981 |     // <Get Temperature Readings> | 
 | 2982 |     ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI, | 
 | 2983 |                                ipmi::dcmi::cmdGetTemperatureReadings, | 
 | 2984 |                                ipmi::Privilege::User, | 
 | 2985 |                                ipmi::dcmi::getTempReadings); | 
| Willy Tu | de54f48 | 2021-01-26 15:59:09 -0800 | [diff] [blame] | 2986 | } | 
 | 2987 | } // namespace ipmi |