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