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