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