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