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