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