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