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