1 /* 2 // Copyright (c) 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 #pragma once 17 18 #include "bmcweb_config.h" 19 20 #include "app.hpp" 21 #include "dbus_singleton.hpp" 22 #include "dbus_utility.hpp" 23 #include "generated/enums/computer_system.hpp" 24 #include "generated/enums/resource.hpp" 25 #include "hypervisor_system.hpp" 26 #include "led.hpp" 27 #include "query.hpp" 28 #include "redfish_util.hpp" 29 #include "registries/privilege_registry.hpp" 30 #include "utils/dbus_utils.hpp" 31 #include "utils/json_utils.hpp" 32 #include "utils/pcie_util.hpp" 33 #include "utils/sw_utils.hpp" 34 #include "utils/time_utils.hpp" 35 36 #include <boost/asio/error.hpp> 37 #include <boost/container/flat_map.hpp> 38 #include <boost/system/error_code.hpp> 39 #include <boost/system/linux_error.hpp> 40 #include <boost/url/format.hpp> 41 #include <sdbusplus/asio/property.hpp> 42 #include <sdbusplus/message.hpp> 43 #include <sdbusplus/unpack_properties.hpp> 44 45 #include <array> 46 #include <memory> 47 #include <string> 48 #include <string_view> 49 #include <utility> 50 #include <variant> 51 #include <vector> 52 53 namespace redfish 54 { 55 56 const static std::array<std::pair<std::string_view, std::string_view>, 2> 57 protocolToDBusForSystems{ 58 {{"SSH", "obmc-console-ssh"}, {"IPMI", "phosphor-ipmi-net"}}}; 59 60 /** 61 * @brief Updates the Functional State of DIMMs 62 * 63 * @param[in] asyncResp Shared pointer for completing asynchronous calls 64 * @param[in] dimmState Dimm's Functional state, true/false 65 * 66 * @return None. 67 */ 68 inline void 69 updateDimmProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 70 bool isDimmFunctional) 71 { 72 BMCWEB_LOG_DEBUG("Dimm Functional: {}", isDimmFunctional); 73 74 // Set it as Enabled if at least one DIMM is functional 75 // Update STATE only if previous State was DISABLED and current Dimm is 76 // ENABLED. 77 const nlohmann::json& prevMemSummary = 78 asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"]; 79 if (prevMemSummary == "Disabled") 80 { 81 if (isDimmFunctional) 82 { 83 asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 84 "Enabled"; 85 } 86 } 87 } 88 89 /* 90 * @brief Update "ProcessorSummary" "Status" "State" based on 91 * CPU Functional State 92 * 93 * @param[in] asyncResp Shared pointer for completing asynchronous calls 94 * @param[in] cpuFunctionalState is CPU functional true/false 95 * 96 * @return None. 97 */ 98 inline void modifyCpuFunctionalState( 99 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, bool isCpuFunctional) 100 { 101 BMCWEB_LOG_DEBUG("Cpu Functional: {}", isCpuFunctional); 102 103 const nlohmann::json& prevProcState = 104 asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"]; 105 106 // Set it as Enabled if at least one CPU is functional 107 // Update STATE only if previous State was Non_Functional and current CPU is 108 // Functional. 109 if (prevProcState == "Disabled") 110 { 111 if (isCpuFunctional) 112 { 113 asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 114 "Enabled"; 115 } 116 } 117 } 118 119 /* 120 * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState 121 * 122 * @param[in] asyncResp Shared pointer for completing asynchronous calls 123 * @param[in] cpuPresenceState CPU present or not 124 * 125 * @return None. 126 */ 127 inline void 128 modifyCpuPresenceState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 129 bool isCpuPresent) 130 { 131 BMCWEB_LOG_DEBUG("Cpu Present: {}", isCpuPresent); 132 133 if (isCpuPresent) 134 { 135 nlohmann::json& procCount = 136 asyncResp->res.jsonValue["ProcessorSummary"]["Count"]; 137 auto* procCountPtr = 138 procCount.get_ptr<nlohmann::json::number_integer_t*>(); 139 if (procCountPtr != nullptr) 140 { 141 // shouldn't be possible to be nullptr 142 *procCountPtr += 1; 143 } 144 } 145 } 146 147 inline void getProcessorProperties( 148 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 149 const std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>& 150 properties) 151 { 152 BMCWEB_LOG_DEBUG("Got {} Cpu properties.", properties.size()); 153 154 // TODO: Get Model 155 156 const uint16_t* coreCount = nullptr; 157 158 const bool success = sdbusplus::unpackPropertiesNoThrow( 159 dbus_utils::UnpackErrorPrinter(), properties, "CoreCount", coreCount); 160 161 if (!success) 162 { 163 messages::internalError(asyncResp->res); 164 return; 165 } 166 167 if (coreCount != nullptr) 168 { 169 nlohmann::json& coreCountJson = 170 asyncResp->res.jsonValue["ProcessorSummary"]["CoreCount"]; 171 uint64_t* coreCountJsonPtr = coreCountJson.get_ptr<uint64_t*>(); 172 173 if (coreCountJsonPtr == nullptr) 174 { 175 coreCountJson = *coreCount; 176 } 177 else 178 { 179 *coreCountJsonPtr += *coreCount; 180 } 181 } 182 } 183 184 /* 185 * @brief Get ProcessorSummary fields 186 * 187 * @param[in] asyncResp Shared pointer for completing asynchronous calls 188 * @param[in] service dbus service for Cpu Information 189 * @param[in] path dbus path for Cpu 190 * 191 * @return None. 192 */ 193 inline void 194 getProcessorSummary(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 195 const std::string& service, const std::string& path) 196 { 197 auto getCpuPresenceState = [asyncResp](const boost::system::error_code& ec3, 198 const bool cpuPresenceCheck) { 199 if (ec3) 200 { 201 BMCWEB_LOG_ERROR("DBUS response error {}", ec3); 202 return; 203 } 204 modifyCpuPresenceState(asyncResp, cpuPresenceCheck); 205 }; 206 207 // Get the Presence of CPU 208 sdbusplus::asio::getProperty<bool>( 209 *crow::connections::systemBus, service, path, 210 "xyz.openbmc_project.Inventory.Item", "Present", 211 std::move(getCpuPresenceState)); 212 213 sdbusplus::asio::getAllProperties( 214 *crow::connections::systemBus, service, path, 215 "xyz.openbmc_project.Inventory.Item.Cpu", 216 [asyncResp, service, 217 path](const boost::system::error_code& ec2, 218 const dbus::utility::DBusPropertiesMap& properties) { 219 if (ec2) 220 { 221 BMCWEB_LOG_ERROR("DBUS response error {}", ec2); 222 messages::internalError(asyncResp->res); 223 return; 224 } 225 getProcessorProperties(asyncResp, properties); 226 }); 227 } 228 229 /* 230 * @brief processMemoryProperties fields 231 * 232 * @param[in] asyncResp Shared pointer for completing asynchronous calls 233 * @param[in] DBUS properties for memory 234 * 235 * @return None. 236 */ 237 inline void 238 processMemoryProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 239 const dbus::utility::DBusPropertiesMap& properties) 240 { 241 BMCWEB_LOG_DEBUG("Got {} Dimm properties.", properties.size()); 242 243 if (properties.empty()) 244 { 245 return; 246 } 247 248 const size_t* memorySizeInKB = nullptr; 249 250 const bool success = sdbusplus::unpackPropertiesNoThrow( 251 dbus_utils::UnpackErrorPrinter(), properties, "MemorySizeInKB", 252 memorySizeInKB); 253 254 if (!success) 255 { 256 messages::internalError(asyncResp->res); 257 return; 258 } 259 260 if (memorySizeInKB != nullptr) 261 { 262 nlohmann::json& totalMemory = 263 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"]; 264 const double* preValue = totalMemory.get_ptr<const double*>(); 265 if (preValue == nullptr) 266 { 267 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = 268 static_cast<double>(*memorySizeInKB) / (1024 * 1024); 269 } 270 else 271 { 272 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = 273 static_cast<double>(*memorySizeInKB) / (1024 * 1024) + 274 *preValue; 275 } 276 } 277 } 278 279 /* 280 * @brief Get getMemorySummary fields 281 * 282 * @param[in] asyncResp Shared pointer for completing asynchronous calls 283 * @param[in] service dbus service for memory Information 284 * @param[in] path dbus path for memory 285 * 286 * @return None. 287 */ 288 inline void 289 getMemorySummary(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 290 const std::string& service, const std::string& path) 291 { 292 sdbusplus::asio::getAllProperties( 293 *crow::connections::systemBus, service, path, 294 "xyz.openbmc_project.Inventory.Item.Dimm", 295 [asyncResp, service, 296 path](const boost::system::error_code& ec2, 297 const dbus::utility::DBusPropertiesMap& properties) { 298 if (ec2) 299 { 300 BMCWEB_LOG_ERROR("DBUS response error {}", ec2); 301 messages::internalError(asyncResp->res); 302 return; 303 } 304 processMemoryProperties(asyncResp, properties); 305 }); 306 } 307 308 inline void afterGetUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 309 const boost::system::error_code& ec, 310 const dbus::utility::DBusPropertiesMap& properties) 311 { 312 if (ec) 313 { 314 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 315 messages::internalError(asyncResp->res); 316 return; 317 } 318 BMCWEB_LOG_DEBUG("Got {} UUID properties.", properties.size()); 319 320 const std::string* uUID = nullptr; 321 322 const bool success = sdbusplus::unpackPropertiesNoThrow( 323 dbus_utils::UnpackErrorPrinter(), properties, "UUID", uUID); 324 325 if (!success) 326 { 327 messages::internalError(asyncResp->res); 328 return; 329 } 330 331 if (uUID != nullptr) 332 { 333 std::string valueStr = *uUID; 334 if (valueStr.size() == 32) 335 { 336 valueStr.insert(8, 1, '-'); 337 valueStr.insert(13, 1, '-'); 338 valueStr.insert(18, 1, '-'); 339 valueStr.insert(23, 1, '-'); 340 } 341 BMCWEB_LOG_DEBUG("UUID = {}", valueStr); 342 asyncResp->res.jsonValue["UUID"] = valueStr; 343 } 344 } 345 346 inline void 347 afterGetInventory(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 348 const boost::system::error_code& ec, 349 const dbus::utility::DBusPropertiesMap& propertiesList) 350 { 351 if (ec) 352 { 353 // doesn't have to include this 354 // interface 355 return; 356 } 357 BMCWEB_LOG_DEBUG("Got {} properties for system", propertiesList.size()); 358 359 const std::string* partNumber = nullptr; 360 const std::string* serialNumber = nullptr; 361 const std::string* manufacturer = nullptr; 362 const std::string* model = nullptr; 363 const std::string* subModel = nullptr; 364 365 const bool success = sdbusplus::unpackPropertiesNoThrow( 366 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 367 partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer, 368 "Model", model, "SubModel", subModel); 369 370 if (!success) 371 { 372 messages::internalError(asyncResp->res); 373 return; 374 } 375 376 if (partNumber != nullptr) 377 { 378 asyncResp->res.jsonValue["PartNumber"] = *partNumber; 379 } 380 381 if (serialNumber != nullptr) 382 { 383 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 384 } 385 386 if (manufacturer != nullptr) 387 { 388 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 389 } 390 391 if (model != nullptr) 392 { 393 asyncResp->res.jsonValue["Model"] = *model; 394 } 395 396 if (subModel != nullptr) 397 { 398 asyncResp->res.jsonValue["SubModel"] = *subModel; 399 } 400 401 // Grab the bios version 402 sw_util::populateSoftwareInformation(asyncResp, sw_util::biosPurpose, 403 "BiosVersion", false); 404 } 405 406 inline void 407 afterGetAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 408 const boost::system::error_code& ec, 409 const std::string& value) 410 { 411 if (ec) 412 { 413 // doesn't have to include this 414 // interface 415 return; 416 } 417 418 asyncResp->res.jsonValue["AssetTag"] = value; 419 } 420 421 inline void afterSystemGetSubTree( 422 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 423 const boost::system::error_code& ec, 424 const dbus::utility::MapperGetSubTreeResponse& subtree) 425 { 426 if (ec) 427 { 428 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 429 messages::internalError(asyncResp->res); 430 return; 431 } 432 // Iterate over all retrieved ObjectPaths. 433 for (const std::pair< 434 std::string, 435 std::vector<std::pair<std::string, std::vector<std::string>>>>& 436 object : subtree) 437 { 438 const std::string& path = object.first; 439 BMCWEB_LOG_DEBUG("Got path: {}", path); 440 const std::vector<std::pair<std::string, std::vector<std::string>>>& 441 connectionNames = object.second; 442 if (connectionNames.empty()) 443 { 444 continue; 445 } 446 447 // This is not system, so check if it's cpu, dimm, UUID or 448 // BiosVer 449 for (const auto& connection : connectionNames) 450 { 451 for (const auto& interfaceName : connection.second) 452 { 453 if (interfaceName == "xyz.openbmc_project.Inventory.Item.Dimm") 454 { 455 BMCWEB_LOG_DEBUG("Found Dimm, now get its properties."); 456 457 getMemorySummary(asyncResp, connection.first, path); 458 } 459 else if (interfaceName == 460 "xyz.openbmc_project.Inventory.Item.Cpu") 461 { 462 BMCWEB_LOG_DEBUG("Found Cpu, now get its properties."); 463 464 getProcessorSummary(asyncResp, connection.first, path); 465 } 466 else if (interfaceName == "xyz.openbmc_project.Common.UUID") 467 { 468 BMCWEB_LOG_DEBUG("Found UUID, now get its properties."); 469 470 sdbusplus::asio::getAllProperties( 471 *crow::connections::systemBus, connection.first, path, 472 "xyz.openbmc_project.Common.UUID", 473 [asyncResp](const boost::system::error_code& ec3, 474 const dbus::utility::DBusPropertiesMap& 475 properties) { 476 afterGetUUID(asyncResp, ec3, properties); 477 }); 478 } 479 else if (interfaceName == 480 "xyz.openbmc_project.Inventory.Item.System") 481 { 482 sdbusplus::asio::getAllProperties( 483 *crow::connections::systemBus, connection.first, path, 484 "xyz.openbmc_project.Inventory.Decorator.Asset", 485 [asyncResp](const boost::system::error_code& ec3, 486 const dbus::utility::DBusPropertiesMap& 487 properties) { 488 afterGetInventory(asyncResp, ec3, properties); 489 }); 490 491 sdbusplus::asio::getProperty<std::string>( 492 *crow::connections::systemBus, connection.first, path, 493 "xyz.openbmc_project.Inventory.Decorator." 494 "AssetTag", 495 "AssetTag", 496 std::bind_front(afterGetAssetTag, asyncResp)); 497 } 498 } 499 } 500 } 501 } 502 503 /* 504 * @brief Retrieves computer system properties over dbus 505 * 506 * @param[in] asyncResp Shared pointer for completing asynchronous calls 507 * 508 * @return None. 509 */ 510 inline void 511 getComputerSystem(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 512 { 513 BMCWEB_LOG_DEBUG("Get available system components."); 514 constexpr std::array<std::string_view, 5> interfaces = { 515 "xyz.openbmc_project.Inventory.Decorator.Asset", 516 "xyz.openbmc_project.Inventory.Item.Cpu", 517 "xyz.openbmc_project.Inventory.Item.Dimm", 518 "xyz.openbmc_project.Inventory.Item.System", 519 "xyz.openbmc_project.Common.UUID", 520 }; 521 dbus::utility::getSubTree( 522 "/xyz/openbmc_project/inventory", 0, interfaces, 523 std::bind_front(afterSystemGetSubTree, asyncResp)); 524 } 525 526 /** 527 * @brief Retrieves host state properties over dbus 528 * 529 * @param[in] asyncResp Shared pointer for completing asynchronous calls. 530 * 531 * @return None. 532 */ 533 inline void getHostState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 534 { 535 BMCWEB_LOG_DEBUG("Get host information."); 536 sdbusplus::asio::getProperty<std::string>( 537 *crow::connections::systemBus, "xyz.openbmc_project.State.Host", 538 "/xyz/openbmc_project/state/host0", "xyz.openbmc_project.State.Host", 539 "CurrentHostState", 540 [asyncResp](const boost::system::error_code& ec, 541 const std::string& hostState) { 542 if (ec) 543 { 544 if (ec == boost::system::errc::host_unreachable) 545 { 546 // Service not available, no error, just don't return 547 // host state info 548 BMCWEB_LOG_DEBUG("Service not available {}", ec); 549 return; 550 } 551 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 552 messages::internalError(asyncResp->res); 553 return; 554 } 555 556 BMCWEB_LOG_DEBUG("Host state: {}", hostState); 557 // Verify Host State 558 if (hostState == "xyz.openbmc_project.State.Host.HostState.Running") 559 { 560 asyncResp->res.jsonValue["PowerState"] = "On"; 561 asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 562 } 563 else if (hostState == 564 "xyz.openbmc_project.State.Host.HostState.Quiesced") 565 { 566 asyncResp->res.jsonValue["PowerState"] = "On"; 567 asyncResp->res.jsonValue["Status"]["State"] = "Quiesced"; 568 } 569 else if (hostState == 570 "xyz.openbmc_project.State.Host.HostState.DiagnosticMode") 571 { 572 asyncResp->res.jsonValue["PowerState"] = "On"; 573 asyncResp->res.jsonValue["Status"]["State"] = "InTest"; 574 } 575 else if ( 576 hostState == 577 "xyz.openbmc_project.State.Host.HostState.TransitioningToRunning") 578 { 579 asyncResp->res.jsonValue["PowerState"] = "PoweringOn"; 580 asyncResp->res.jsonValue["Status"]["State"] = "Starting"; 581 } 582 else if (hostState == 583 "xyz.openbmc_project.State.Host.HostState.TransitioningToOff") 584 { 585 asyncResp->res.jsonValue["PowerState"] = "PoweringOff"; 586 asyncResp->res.jsonValue["Status"]["State"] = "Disabled"; 587 } 588 else 589 { 590 asyncResp->res.jsonValue["PowerState"] = "Off"; 591 asyncResp->res.jsonValue["Status"]["State"] = "Disabled"; 592 } 593 }); 594 } 595 596 /** 597 * @brief Translates boot source DBUS property value to redfish. 598 * 599 * @param[in] dbusSource The boot source in DBUS speak. 600 * 601 * @return Returns as a string, the boot source in Redfish terms. If translation 602 * cannot be done, returns an empty string. 603 */ 604 inline std::string dbusToRfBootSource(const std::string& dbusSource) 605 { 606 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default") 607 { 608 return "None"; 609 } 610 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Disk") 611 { 612 return "Hdd"; 613 } 614 if (dbusSource == 615 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia") 616 { 617 return "Cd"; 618 } 619 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Network") 620 { 621 return "Pxe"; 622 } 623 if (dbusSource == 624 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia") 625 { 626 return "Usb"; 627 } 628 return ""; 629 } 630 631 /** 632 * @brief Translates boot type DBUS property value to redfish. 633 * 634 * @param[in] dbusType The boot type in DBUS speak. 635 * 636 * @return Returns as a string, the boot type in Redfish terms. If translation 637 * cannot be done, returns an empty string. 638 */ 639 inline std::string dbusToRfBootType(const std::string& dbusType) 640 { 641 if (dbusType == "xyz.openbmc_project.Control.Boot.Type.Types.Legacy") 642 { 643 return "Legacy"; 644 } 645 if (dbusType == "xyz.openbmc_project.Control.Boot.Type.Types.EFI") 646 { 647 return "UEFI"; 648 } 649 return ""; 650 } 651 652 /** 653 * @brief Translates boot mode DBUS property value to redfish. 654 * 655 * @param[in] dbusMode The boot mode in DBUS speak. 656 * 657 * @return Returns as a string, the boot mode in Redfish terms. If translation 658 * cannot be done, returns an empty string. 659 */ 660 inline std::string dbusToRfBootMode(const std::string& dbusMode) 661 { 662 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 663 { 664 return "None"; 665 } 666 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe") 667 { 668 return "Diags"; 669 } 670 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup") 671 { 672 return "BiosSetup"; 673 } 674 return ""; 675 } 676 677 /** 678 * @brief Translates boot progress DBUS property value to redfish. 679 * 680 * @param[in] dbusBootProgress The boot progress in DBUS speak. 681 * 682 * @return Returns as a string, the boot progress in Redfish terms. If 683 * translation cannot be done, returns "None". 684 */ 685 inline std::string dbusToRfBootProgress(const std::string& dbusBootProgress) 686 { 687 // Now convert the D-Bus BootProgress to the appropriate Redfish 688 // enum 689 std::string rfBpLastState = "None"; 690 if (dbusBootProgress == "xyz.openbmc_project.State.Boot.Progress." 691 "ProgressStages.Unspecified") 692 { 693 rfBpLastState = "None"; 694 } 695 else if (dbusBootProgress == 696 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 697 "PrimaryProcInit") 698 { 699 rfBpLastState = "PrimaryProcessorInitializationStarted"; 700 } 701 else if (dbusBootProgress == 702 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 703 "BusInit") 704 { 705 rfBpLastState = "BusInitializationStarted"; 706 } 707 else if (dbusBootProgress == 708 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 709 "MemoryInit") 710 { 711 rfBpLastState = "MemoryInitializationStarted"; 712 } 713 else if (dbusBootProgress == 714 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 715 "SecondaryProcInit") 716 { 717 rfBpLastState = "SecondaryProcessorInitializationStarted"; 718 } 719 else if (dbusBootProgress == 720 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 721 "PCIInit") 722 { 723 rfBpLastState = "PCIResourceConfigStarted"; 724 } 725 else if (dbusBootProgress == 726 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 727 "SystemSetup") 728 { 729 rfBpLastState = "SetupEntered"; 730 } 731 else if (dbusBootProgress == 732 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 733 "SystemInitComplete") 734 { 735 rfBpLastState = "SystemHardwareInitializationComplete"; 736 } 737 else if (dbusBootProgress == 738 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 739 "OSStart") 740 { 741 rfBpLastState = "OSBootStarted"; 742 } 743 else if (dbusBootProgress == 744 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 745 "OSRunning") 746 { 747 rfBpLastState = "OSRunning"; 748 } 749 else 750 { 751 BMCWEB_LOG_DEBUG("Unsupported D-Bus BootProgress {}", dbusBootProgress); 752 // Just return the default 753 } 754 return rfBpLastState; 755 } 756 757 /** 758 * @brief Translates boot source from Redfish to the DBus boot paths. 759 * 760 * @param[in] rfSource The boot source in Redfish. 761 * @param[out] bootSource The DBus source 762 * @param[out] bootMode the DBus boot mode 763 * 764 * @return Integer error code. 765 */ 766 inline int 767 assignBootParameters(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 768 const std::string& rfSource, std::string& bootSource, 769 std::string& bootMode) 770 { 771 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 772 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 773 774 if (rfSource == "None") 775 { 776 return 0; 777 } 778 if (rfSource == "Pxe") 779 { 780 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network"; 781 } 782 else if (rfSource == "Hdd") 783 { 784 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk"; 785 } 786 else if (rfSource == "Diags") 787 { 788 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe"; 789 } 790 else if (rfSource == "Cd") 791 { 792 bootSource = 793 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia"; 794 } 795 else if (rfSource == "BiosSetup") 796 { 797 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup"; 798 } 799 else if (rfSource == "Usb") 800 { 801 bootSource = 802 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia"; 803 } 804 else 805 { 806 BMCWEB_LOG_DEBUG( 807 "Invalid property value for BootSourceOverrideTarget: {}", 808 bootSource); 809 messages::propertyValueNotInList(asyncResp->res, rfSource, 810 "BootSourceTargetOverride"); 811 return -1; 812 } 813 return 0; 814 } 815 816 /** 817 * @brief Retrieves boot progress of the system 818 * 819 * @param[in] asyncResp Shared pointer for generating response message. 820 * 821 * @return None. 822 */ 823 inline void getBootProgress(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 824 { 825 sdbusplus::asio::getProperty<std::string>( 826 *crow::connections::systemBus, "xyz.openbmc_project.State.Host", 827 "/xyz/openbmc_project/state/host0", 828 "xyz.openbmc_project.State.Boot.Progress", "BootProgress", 829 [asyncResp](const boost::system::error_code& ec, 830 const std::string& bootProgressStr) { 831 if (ec) 832 { 833 // BootProgress is an optional object so just do nothing if 834 // not found 835 return; 836 } 837 838 BMCWEB_LOG_DEBUG("Boot Progress: {}", bootProgressStr); 839 840 asyncResp->res.jsonValue["BootProgress"]["LastState"] = 841 dbusToRfBootProgress(bootProgressStr); 842 }); 843 } 844 845 /** 846 * @brief Retrieves boot progress Last Update of the system 847 * 848 * @param[in] asyncResp Shared pointer for generating response message. 849 * 850 * @return None. 851 */ 852 inline void getBootProgressLastStateTime( 853 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 854 { 855 sdbusplus::asio::getProperty<uint64_t>( 856 *crow::connections::systemBus, "xyz.openbmc_project.State.Host", 857 "/xyz/openbmc_project/state/host0", 858 "xyz.openbmc_project.State.Boot.Progress", "BootProgressLastUpdate", 859 [asyncResp](const boost::system::error_code& ec, 860 const uint64_t lastStateTime) { 861 if (ec) 862 { 863 BMCWEB_LOG_DEBUG("D-BUS response error {}", ec); 864 return; 865 } 866 867 // BootProgressLastUpdate is the last time the BootProgress property 868 // was updated. The time is the Epoch time, number of microseconds 869 // since 1 Jan 1970 00::00::00 UTC." 870 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/ 871 // yaml/xyz/openbmc_project/State/Boot/Progress.interface.yaml#L11 872 873 // Convert to ISO 8601 standard 874 asyncResp->res.jsonValue["BootProgress"]["LastStateTime"] = 875 redfish::time_utils::getDateTimeUintUs(lastStateTime); 876 }); 877 } 878 879 /** 880 * @brief Retrieves boot override type over DBUS and fills out the response 881 * 882 * @param[in] asyncResp Shared pointer for generating response message. 883 * 884 * @return None. 885 */ 886 887 inline void 888 getBootOverrideType(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 889 { 890 sdbusplus::asio::getProperty<std::string>( 891 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 892 "/xyz/openbmc_project/control/host0/boot", 893 "xyz.openbmc_project.Control.Boot.Type", "BootType", 894 [asyncResp](const boost::system::error_code& ec, 895 const std::string& bootType) { 896 if (ec) 897 { 898 // not an error, don't have to have the interface 899 return; 900 } 901 902 BMCWEB_LOG_DEBUG("Boot type: {}", bootType); 903 904 asyncResp->res 905 .jsonValue["Boot"] 906 ["BootSourceOverrideMode@Redfish.AllowableValues"] = 907 nlohmann::json::array_t({"Legacy", "UEFI"}); 908 909 auto rfType = dbusToRfBootType(bootType); 910 if (rfType.empty()) 911 { 912 messages::internalError(asyncResp->res); 913 return; 914 } 915 916 asyncResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = rfType; 917 }); 918 } 919 920 /** 921 * @brief Retrieves boot override mode over DBUS and fills out the response 922 * 923 * @param[in] asyncResp Shared pointer for generating response message. 924 * 925 * @return None. 926 */ 927 928 inline void 929 getBootOverrideMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 930 { 931 sdbusplus::asio::getProperty<std::string>( 932 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 933 "/xyz/openbmc_project/control/host0/boot", 934 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 935 [asyncResp](const boost::system::error_code& ec, 936 const std::string& bootModeStr) { 937 if (ec) 938 { 939 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 940 messages::internalError(asyncResp->res); 941 return; 942 } 943 944 BMCWEB_LOG_DEBUG("Boot mode: {}", bootModeStr); 945 946 nlohmann::json::array_t allowed; 947 allowed.emplace_back("None"); 948 allowed.emplace_back("Pxe"); 949 allowed.emplace_back("Hdd"); 950 allowed.emplace_back("Cd"); 951 allowed.emplace_back("Diags"); 952 allowed.emplace_back("BiosSetup"); 953 allowed.emplace_back("Usb"); 954 955 asyncResp->res 956 .jsonValue["Boot"] 957 ["BootSourceOverrideTarget@Redfish.AllowableValues"] = 958 std::move(allowed); 959 if (bootModeStr != 960 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 961 { 962 auto rfMode = dbusToRfBootMode(bootModeStr); 963 if (!rfMode.empty()) 964 { 965 asyncResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 966 rfMode; 967 } 968 } 969 }); 970 } 971 972 /** 973 * @brief Retrieves boot override source over DBUS 974 * 975 * @param[in] asyncResp Shared pointer for generating response message. 976 * 977 * @return None. 978 */ 979 980 inline void 981 getBootOverrideSource(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 982 { 983 sdbusplus::asio::getProperty<std::string>( 984 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 985 "/xyz/openbmc_project/control/host0/boot", 986 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 987 [asyncResp](const boost::system::error_code& ec, 988 const std::string& bootSourceStr) { 989 if (ec) 990 { 991 if (ec.value() == boost::asio::error::host_unreachable) 992 { 993 return; 994 } 995 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 996 messages::internalError(asyncResp->res); 997 return; 998 } 999 1000 BMCWEB_LOG_DEBUG("Boot source: {}", bootSourceStr); 1001 1002 auto rfSource = dbusToRfBootSource(bootSourceStr); 1003 if (!rfSource.empty()) 1004 { 1005 asyncResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 1006 rfSource; 1007 } 1008 1009 // Get BootMode as BootSourceOverrideTarget is constructed 1010 // from both BootSource and BootMode 1011 getBootOverrideMode(asyncResp); 1012 }); 1013 } 1014 1015 /** 1016 * @brief This functions abstracts all the logic behind getting a 1017 * "BootSourceOverrideEnabled" property from an overall boot override enable 1018 * state 1019 * 1020 * @param[in] asyncResp Shared pointer for generating response message. 1021 * 1022 * @return None. 1023 */ 1024 1025 inline void processBootOverrideEnable( 1026 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1027 const bool bootOverrideEnableSetting) 1028 { 1029 if (!bootOverrideEnableSetting) 1030 { 1031 asyncResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 1032 "Disabled"; 1033 return; 1034 } 1035 1036 // If boot source override is enabled, we need to check 'one_time' 1037 // property to set a correct value for the "BootSourceOverrideEnabled" 1038 sdbusplus::asio::getProperty<bool>( 1039 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 1040 "/xyz/openbmc_project/control/host0/boot/one_time", 1041 "xyz.openbmc_project.Object.Enable", "Enabled", 1042 [asyncResp](const boost::system::error_code& ec, bool oneTimeSetting) { 1043 if (ec) 1044 { 1045 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 1046 messages::internalError(asyncResp->res); 1047 return; 1048 } 1049 1050 if (oneTimeSetting) 1051 { 1052 asyncResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 1053 "Once"; 1054 } 1055 else 1056 { 1057 asyncResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 1058 "Continuous"; 1059 } 1060 }); 1061 } 1062 1063 /** 1064 * @brief Retrieves boot override enable over DBUS 1065 * 1066 * @param[in] asyncResp Shared pointer for generating response message. 1067 * 1068 * @return None. 1069 */ 1070 1071 inline void 1072 getBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1073 { 1074 sdbusplus::asio::getProperty<bool>( 1075 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 1076 "/xyz/openbmc_project/control/host0/boot", 1077 "xyz.openbmc_project.Object.Enable", "Enabled", 1078 [asyncResp](const boost::system::error_code& ec, 1079 const bool bootOverrideEnable) { 1080 if (ec) 1081 { 1082 if (ec.value() == boost::asio::error::host_unreachable) 1083 { 1084 return; 1085 } 1086 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 1087 messages::internalError(asyncResp->res); 1088 return; 1089 } 1090 1091 processBootOverrideEnable(asyncResp, bootOverrideEnable); 1092 }); 1093 } 1094 1095 /** 1096 * @brief Retrieves boot source override properties 1097 * 1098 * @param[in] asyncResp Shared pointer for generating response message. 1099 * 1100 * @return None. 1101 */ 1102 inline void 1103 getBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1104 { 1105 BMCWEB_LOG_DEBUG("Get boot information."); 1106 1107 getBootOverrideSource(asyncResp); 1108 getBootOverrideType(asyncResp); 1109 getBootOverrideEnable(asyncResp); 1110 } 1111 1112 /** 1113 * @brief Retrieves the Last Reset Time 1114 * 1115 * "Reset" is an overloaded term in Redfish, "Reset" includes power on 1116 * and power off. Even though this is the "system" Redfish object look at the 1117 * chassis D-Bus interface for the LastStateChangeTime since this has the 1118 * last power operation time. 1119 * 1120 * @param[in] asyncResp Shared pointer for generating response message. 1121 * 1122 * @return None. 1123 */ 1124 inline void 1125 getLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1126 { 1127 BMCWEB_LOG_DEBUG("Getting System Last Reset Time"); 1128 1129 sdbusplus::asio::getProperty<uint64_t>( 1130 *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis", 1131 "/xyz/openbmc_project/state/chassis0", 1132 "xyz.openbmc_project.State.Chassis", "LastStateChangeTime", 1133 [asyncResp](const boost::system::error_code& ec, 1134 uint64_t lastResetTime) { 1135 if (ec) 1136 { 1137 BMCWEB_LOG_DEBUG("D-BUS response error {}", ec); 1138 return; 1139 } 1140 1141 // LastStateChangeTime is epoch time, in milliseconds 1142 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19 1143 uint64_t lastResetTimeStamp = lastResetTime / 1000; 1144 1145 // Convert to ISO 8601 standard 1146 asyncResp->res.jsonValue["LastResetTime"] = 1147 redfish::time_utils::getDateTimeUint(lastResetTimeStamp); 1148 }); 1149 } 1150 1151 /** 1152 * @brief Retrieves the number of automatic boot Retry attempts allowed/left. 1153 * 1154 * The total number of automatic reboot retries allowed "RetryAttempts" and its 1155 * corresponding property "AttemptsLeft" that keeps track of the amount of 1156 * automatic retry attempts left are hosted in phosphor-state-manager through 1157 * dbus. 1158 * 1159 * @param[in] asyncResp Shared pointer for generating response message. 1160 * 1161 * @return None. 1162 */ 1163 inline void getAutomaticRebootAttempts( 1164 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1165 { 1166 BMCWEB_LOG_DEBUG("Get Automatic Retry policy"); 1167 1168 sdbusplus::asio::getAllProperties( 1169 *crow::connections::systemBus, "xyz.openbmc_project.State.Host", 1170 "/xyz/openbmc_project/state/host0", 1171 "xyz.openbmc_project.Control.Boot.RebootAttempts", 1172 [asyncResp{asyncResp}]( 1173 const boost::system::error_code& ec, 1174 const dbus::utility::DBusPropertiesMap& propertiesList) { 1175 if (ec) 1176 { 1177 if (ec.value() != EBADR) 1178 { 1179 BMCWEB_LOG_ERROR("D-Bus responses error: {}", ec); 1180 messages::internalError(asyncResp->res); 1181 } 1182 return; 1183 } 1184 1185 const uint32_t* attemptsLeft = nullptr; 1186 const uint32_t* retryAttempts = nullptr; 1187 1188 const bool success = sdbusplus::unpackPropertiesNoThrow( 1189 dbus_utils::UnpackErrorPrinter(), propertiesList, "AttemptsLeft", 1190 attemptsLeft, "RetryAttempts", retryAttempts); 1191 1192 if (!success) 1193 { 1194 messages::internalError(asyncResp->res); 1195 return; 1196 } 1197 1198 if (attemptsLeft != nullptr) 1199 { 1200 asyncResp->res 1201 .jsonValue["Boot"]["RemainingAutomaticRetryAttempts"] = 1202 *attemptsLeft; 1203 } 1204 1205 if (retryAttempts != nullptr) 1206 { 1207 asyncResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 1208 *retryAttempts; 1209 } 1210 }); 1211 } 1212 1213 /** 1214 * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot. 1215 * 1216 * @param[in] asyncResp Shared pointer for generating response message. 1217 * 1218 * @return None. 1219 */ 1220 inline void 1221 getAutomaticRetryPolicy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1222 { 1223 BMCWEB_LOG_DEBUG("Get Automatic Retry policy"); 1224 1225 sdbusplus::asio::getProperty<bool>( 1226 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 1227 "/xyz/openbmc_project/control/host0/auto_reboot", 1228 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", 1229 [asyncResp](const boost::system::error_code& ec, 1230 bool autoRebootEnabled) { 1231 if (ec) 1232 { 1233 if (ec.value() != EBADR) 1234 { 1235 BMCWEB_LOG_ERROR("D-Bus responses error: {}", ec); 1236 messages::internalError(asyncResp->res); 1237 } 1238 return; 1239 } 1240 1241 BMCWEB_LOG_DEBUG("Auto Reboot: {}", autoRebootEnabled); 1242 if (autoRebootEnabled) 1243 { 1244 asyncResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1245 "RetryAttempts"; 1246 } 1247 else 1248 { 1249 asyncResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1250 "Disabled"; 1251 } 1252 getAutomaticRebootAttempts(asyncResp); 1253 1254 // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways, 1255 // and RetryAttempts. OpenBMC only supports Disabled and 1256 // RetryAttempts. 1257 nlohmann::json::array_t allowed; 1258 allowed.emplace_back("Disabled"); 1259 allowed.emplace_back("RetryAttempts"); 1260 asyncResp->res 1261 .jsonValue["Boot"]["AutomaticRetryConfig@Redfish.AllowableValues"] = 1262 std::move(allowed); 1263 }); 1264 } 1265 1266 /** 1267 * @brief Sets RetryAttempts 1268 * 1269 * @param[in] asyncResp Shared pointer for generating response message. 1270 * @param[in] retryAttempts "AutomaticRetryAttempts" from request. 1271 * 1272 *@return None. 1273 */ 1274 1275 inline void setAutomaticRetryAttempts( 1276 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1277 const uint32_t retryAttempts) 1278 { 1279 BMCWEB_LOG_DEBUG("Set Automatic Retry Attempts."); 1280 setDbusProperty( 1281 asyncResp, "xyz.openbmc_project.State.Host", 1282 sdbusplus::message::object_path("/xyz/openbmc_project/state/host0"), 1283 "xyz.openbmc_project.Control.Boot.RebootAttempts", "RetryAttempts", 1284 "Boot/AutomaticRetryAttempts", retryAttempts); 1285 } 1286 1287 inline computer_system::PowerRestorePolicyTypes 1288 redfishPowerRestorePolicyFromDbus(std::string_view value) 1289 { 1290 if (value == 1291 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn") 1292 { 1293 return computer_system::PowerRestorePolicyTypes::AlwaysOn; 1294 } 1295 if (value == 1296 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff") 1297 { 1298 return computer_system::PowerRestorePolicyTypes::AlwaysOff; 1299 } 1300 if (value == 1301 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore") 1302 { 1303 return computer_system::PowerRestorePolicyTypes::LastState; 1304 } 1305 if (value == "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.None") 1306 { 1307 return computer_system::PowerRestorePolicyTypes::AlwaysOff; 1308 } 1309 return computer_system::PowerRestorePolicyTypes::Invalid; 1310 } 1311 /** 1312 * @brief Retrieves power restore policy over DBUS. 1313 * 1314 * @param[in] asyncResp Shared pointer for generating response message. 1315 * 1316 * @return None. 1317 */ 1318 inline void 1319 getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1320 { 1321 BMCWEB_LOG_DEBUG("Get power restore policy"); 1322 1323 sdbusplus::asio::getProperty<std::string>( 1324 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 1325 "/xyz/openbmc_project/control/host0/power_restore_policy", 1326 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1327 [asyncResp](const boost::system::error_code& ec, 1328 const std::string& policy) { 1329 if (ec) 1330 { 1331 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 1332 return; 1333 } 1334 computer_system::PowerRestorePolicyTypes restore = 1335 redfishPowerRestorePolicyFromDbus(policy); 1336 if (restore == computer_system::PowerRestorePolicyTypes::Invalid) 1337 { 1338 messages::internalError(asyncResp->res); 1339 return; 1340 } 1341 1342 asyncResp->res.jsonValue["PowerRestorePolicy"] = restore; 1343 }); 1344 } 1345 1346 /** 1347 * @brief Stop Boot On Fault over DBUS. 1348 * 1349 * @param[in] asyncResp Shared pointer for generating response message. 1350 * 1351 * @return None. 1352 */ 1353 inline void 1354 getStopBootOnFault(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1355 { 1356 BMCWEB_LOG_DEBUG("Get Stop Boot On Fault"); 1357 1358 sdbusplus::asio::getProperty<bool>( 1359 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 1360 "/xyz/openbmc_project/logging/settings", 1361 "xyz.openbmc_project.Logging.Settings", "QuiesceOnHwError", 1362 [asyncResp](const boost::system::error_code& ec, bool value) { 1363 if (ec) 1364 { 1365 if (ec.value() != EBADR) 1366 { 1367 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 1368 messages::internalError(asyncResp->res); 1369 } 1370 return; 1371 } 1372 1373 if (value) 1374 { 1375 asyncResp->res.jsonValue["Boot"]["StopBootOnFault"] = "AnyFault"; 1376 } 1377 else 1378 { 1379 asyncResp->res.jsonValue["Boot"]["StopBootOnFault"] = "Never"; 1380 } 1381 }); 1382 } 1383 1384 /** 1385 * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not 1386 * TPM is required for booting the host. 1387 * 1388 * @param[in] asyncResp Shared pointer for generating response message. 1389 * 1390 * @return None. 1391 */ 1392 inline void getTrustedModuleRequiredToBoot( 1393 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1394 { 1395 BMCWEB_LOG_DEBUG("Get TPM required to boot."); 1396 constexpr std::array<std::string_view, 1> interfaces = { 1397 "xyz.openbmc_project.Control.TPM.Policy"}; 1398 dbus::utility::getSubTree( 1399 "/", 0, interfaces, 1400 [asyncResp](const boost::system::error_code& ec, 1401 const dbus::utility::MapperGetSubTreeResponse& subtree) { 1402 if (ec) 1403 { 1404 BMCWEB_LOG_DEBUG("DBUS response error on TPM.Policy GetSubTree{}", 1405 ec); 1406 // This is an optional D-Bus object so just return if 1407 // error occurs 1408 return; 1409 } 1410 if (subtree.empty()) 1411 { 1412 // As noted above, this is an optional interface so just return 1413 // if there is no instance found 1414 return; 1415 } 1416 1417 /* When there is more than one TPMEnable object... */ 1418 if (subtree.size() > 1) 1419 { 1420 BMCWEB_LOG_DEBUG( 1421 "DBUS response has more than 1 TPM Enable object:{}", 1422 subtree.size()); 1423 // Throw an internal Error and return 1424 messages::internalError(asyncResp->res); 1425 return; 1426 } 1427 1428 // Make sure the Dbus response map has a service and objectPath 1429 // field 1430 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1431 { 1432 BMCWEB_LOG_DEBUG("TPM.Policy mapper error!"); 1433 messages::internalError(asyncResp->res); 1434 return; 1435 } 1436 1437 const std::string& path = subtree[0].first; 1438 const std::string& serv = subtree[0].second.begin()->first; 1439 1440 // Valid TPM Enable object found, now reading the current value 1441 sdbusplus::asio::getProperty<bool>( 1442 *crow::connections::systemBus, serv, path, 1443 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable", 1444 [asyncResp](const boost::system::error_code& ec2, 1445 bool tpmRequired) { 1446 if (ec2) 1447 { 1448 BMCWEB_LOG_ERROR("D-BUS response error on TPM.Policy Get{}", 1449 ec2); 1450 messages::internalError(asyncResp->res); 1451 return; 1452 } 1453 1454 if (tpmRequired) 1455 { 1456 asyncResp->res 1457 .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = 1458 "Required"; 1459 } 1460 else 1461 { 1462 asyncResp->res 1463 .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = 1464 "Disabled"; 1465 } 1466 }); 1467 }); 1468 } 1469 1470 /** 1471 * @brief Set TrustedModuleRequiredToBoot property. Determines whether or not 1472 * TPM is required for booting the host. 1473 * 1474 * @param[in] asyncResp Shared pointer for generating response message. 1475 * @param[in] tpmRequired Value to set TPM Required To Boot property to. 1476 * 1477 * @return None. 1478 */ 1479 inline void setTrustedModuleRequiredToBoot( 1480 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const bool tpmRequired) 1481 { 1482 BMCWEB_LOG_DEBUG("Set TrustedModuleRequiredToBoot."); 1483 constexpr std::array<std::string_view, 1> interfaces = { 1484 "xyz.openbmc_project.Control.TPM.Policy"}; 1485 dbus::utility::getSubTree( 1486 "/", 0, interfaces, 1487 [asyncResp, 1488 tpmRequired](const boost::system::error_code& ec, 1489 const dbus::utility::MapperGetSubTreeResponse& subtree) { 1490 if (ec) 1491 { 1492 BMCWEB_LOG_ERROR("DBUS response error on TPM.Policy GetSubTree{}", 1493 ec); 1494 messages::internalError(asyncResp->res); 1495 return; 1496 } 1497 if (subtree.empty()) 1498 { 1499 messages::propertyValueNotInList(asyncResp->res, "ComputerSystem", 1500 "TrustedModuleRequiredToBoot"); 1501 return; 1502 } 1503 1504 /* When there is more than one TPMEnable object... */ 1505 if (subtree.size() > 1) 1506 { 1507 BMCWEB_LOG_DEBUG( 1508 "DBUS response has more than 1 TPM Enable object:{}", 1509 subtree.size()); 1510 // Throw an internal Error and return 1511 messages::internalError(asyncResp->res); 1512 return; 1513 } 1514 1515 // Make sure the Dbus response map has a service and objectPath 1516 // field 1517 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1518 { 1519 BMCWEB_LOG_DEBUG("TPM.Policy mapper error!"); 1520 messages::internalError(asyncResp->res); 1521 return; 1522 } 1523 1524 const std::string& path = subtree[0].first; 1525 const std::string& serv = subtree[0].second.begin()->first; 1526 1527 if (serv.empty()) 1528 { 1529 BMCWEB_LOG_DEBUG("TPM.Policy service mapper error!"); 1530 messages::internalError(asyncResp->res); 1531 return; 1532 } 1533 1534 // Valid TPM Enable object found, now setting the value 1535 setDbusProperty(asyncResp, serv, path, 1536 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable", 1537 "Boot/TrustedModuleRequiredToBoot", tpmRequired); 1538 }); 1539 } 1540 1541 /** 1542 * @brief Sets boot properties into DBUS object(s). 1543 * 1544 * @param[in] asyncResp Shared pointer for generating response message. 1545 * @param[in] bootType The boot type to set. 1546 * @return Integer error code. 1547 */ 1548 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1549 const std::optional<std::string>& bootType) 1550 { 1551 std::string bootTypeStr; 1552 1553 if (!bootType) 1554 { 1555 return; 1556 } 1557 1558 // Source target specified 1559 BMCWEB_LOG_DEBUG("Boot type: {}", *bootType); 1560 // Figure out which DBUS interface and property to use 1561 if (*bootType == "Legacy") 1562 { 1563 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy"; 1564 } 1565 else if (*bootType == "UEFI") 1566 { 1567 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI"; 1568 } 1569 else 1570 { 1571 BMCWEB_LOG_DEBUG("Invalid property value for " 1572 "BootSourceOverrideMode: {}", 1573 *bootType); 1574 messages::propertyValueNotInList(asyncResp->res, *bootType, 1575 "BootSourceOverrideMode"); 1576 return; 1577 } 1578 1579 // Act on validated parameters 1580 BMCWEB_LOG_DEBUG("DBUS boot type: {}", bootTypeStr); 1581 1582 setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", 1583 sdbusplus::message::object_path( 1584 "/xyz/openbmc_project/control/host0/boot"), 1585 "xyz.openbmc_project.Control.Boot.Type", "BootType", 1586 "Boot/BootSourceOverrideMode", bootTypeStr); 1587 } 1588 1589 /** 1590 * @brief Sets boot properties into DBUS object(s). 1591 * 1592 * @param[in] asyncResp Shared pointer for generating response 1593 * message. 1594 * @param[in] bootType The boot type to set. 1595 * @return Integer error code. 1596 */ 1597 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1598 const std::optional<std::string>& bootEnable) 1599 { 1600 if (!bootEnable) 1601 { 1602 return; 1603 } 1604 // Source target specified 1605 BMCWEB_LOG_DEBUG("Boot enable: {}", *bootEnable); 1606 1607 bool bootOverrideEnable = false; 1608 bool bootOverridePersistent = false; 1609 // Figure out which DBUS interface and property to use 1610 if (*bootEnable == "Disabled") 1611 { 1612 bootOverrideEnable = false; 1613 } 1614 else if (*bootEnable == "Once") 1615 { 1616 bootOverrideEnable = true; 1617 bootOverridePersistent = false; 1618 } 1619 else if (*bootEnable == "Continuous") 1620 { 1621 bootOverrideEnable = true; 1622 bootOverridePersistent = true; 1623 } 1624 else 1625 { 1626 BMCWEB_LOG_DEBUG( 1627 "Invalid property value for BootSourceOverrideEnabled: {}", 1628 *bootEnable); 1629 messages::propertyValueNotInList(asyncResp->res, *bootEnable, 1630 "BootSourceOverrideEnabled"); 1631 return; 1632 } 1633 1634 // Act on validated parameters 1635 BMCWEB_LOG_DEBUG("DBUS boot override enable: {}", bootOverrideEnable); 1636 1637 setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", 1638 sdbusplus::message::object_path( 1639 "/xyz/openbmc_project/control/host0/boot"), 1640 "xyz.openbmc_project.Object.Enable", "Enabled", 1641 "Boot/BootSourceOverrideEnabled", bootOverrideEnable); 1642 1643 if (!bootOverrideEnable) 1644 { 1645 return; 1646 } 1647 1648 // In case boot override is enabled we need to set correct value for the 1649 // 'one_time' enable DBus interface 1650 BMCWEB_LOG_DEBUG("DBUS boot override persistent: {}", 1651 bootOverridePersistent); 1652 1653 setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", 1654 sdbusplus::message::object_path( 1655 "/xyz/openbmc_project/control/host0/boot/one_time"), 1656 "xyz.openbmc_project.Object.Enable", "Enabled", 1657 "Boot/BootSourceOverrideEnabled", !bootOverridePersistent); 1658 } 1659 1660 /** 1661 * @brief Sets boot properties into DBUS object(s). 1662 * 1663 * @param[in] asyncResp Shared pointer for generating response message. 1664 * @param[in] bootSource The boot source to set. 1665 * 1666 * @return Integer error code. 1667 */ 1668 inline void 1669 setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1670 const std::optional<std::string>& bootSource) 1671 { 1672 std::string bootSourceStr; 1673 std::string bootModeStr; 1674 1675 if (!bootSource) 1676 { 1677 return; 1678 } 1679 1680 // Source target specified 1681 BMCWEB_LOG_DEBUG("Boot source: {}", *bootSource); 1682 // Figure out which DBUS interface and property to use 1683 if (assignBootParameters(asyncResp, *bootSource, bootSourceStr, 1684 bootModeStr) != 0) 1685 { 1686 BMCWEB_LOG_DEBUG( 1687 "Invalid property value for BootSourceOverrideTarget: {}", 1688 *bootSource); 1689 messages::propertyValueNotInList(asyncResp->res, *bootSource, 1690 "BootSourceTargetOverride"); 1691 return; 1692 } 1693 1694 // Act on validated parameters 1695 BMCWEB_LOG_DEBUG("DBUS boot source: {}", bootSourceStr); 1696 BMCWEB_LOG_DEBUG("DBUS boot mode: {}", bootModeStr); 1697 1698 setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", 1699 sdbusplus::message::object_path( 1700 "/xyz/openbmc_project/control/host0/boot"), 1701 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 1702 "Boot/BootSourceOverrideTarget", bootSourceStr); 1703 setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", 1704 sdbusplus::message::object_path( 1705 "/xyz/openbmc_project/control/host0/boot"), 1706 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 1707 "Boot/BootSourceOverrideTarget", bootModeStr); 1708 } 1709 1710 /** 1711 * @brief Sets Boot source override properties. 1712 * 1713 * @param[in] asyncResp Shared pointer for generating response message. 1714 * @param[in] bootSource The boot source from incoming RF request. 1715 * @param[in] bootType The boot type from incoming RF request. 1716 * @param[in] bootEnable The boot override enable from incoming RF request. 1717 * 1718 * @return Integer error code. 1719 */ 1720 1721 inline void 1722 setBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1723 const std::optional<std::string>& bootSource, 1724 const std::optional<std::string>& bootType, 1725 const std::optional<std::string>& bootEnable) 1726 { 1727 BMCWEB_LOG_DEBUG("Set boot information."); 1728 1729 setBootModeOrSource(asyncResp, bootSource); 1730 setBootType(asyncResp, bootType); 1731 setBootEnable(asyncResp, bootEnable); 1732 } 1733 1734 /** 1735 * @brief Sets AssetTag 1736 * 1737 * @param[in] asyncResp Shared pointer for generating response message. 1738 * @param[in] assetTag "AssetTag" from request. 1739 * 1740 * @return None. 1741 */ 1742 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1743 const std::string& assetTag) 1744 { 1745 constexpr std::array<std::string_view, 1> interfaces = { 1746 "xyz.openbmc_project.Inventory.Item.System"}; 1747 dbus::utility::getSubTree( 1748 "/xyz/openbmc_project/inventory", 0, interfaces, 1749 [asyncResp, 1750 assetTag](const boost::system::error_code& ec, 1751 const dbus::utility::MapperGetSubTreeResponse& subtree) { 1752 if (ec) 1753 { 1754 BMCWEB_LOG_DEBUG("D-Bus response error on GetSubTree {}", ec); 1755 messages::internalError(asyncResp->res); 1756 return; 1757 } 1758 if (subtree.empty()) 1759 { 1760 BMCWEB_LOG_DEBUG("Can't find system D-Bus object!"); 1761 messages::internalError(asyncResp->res); 1762 return; 1763 } 1764 // Assume only 1 system D-Bus object 1765 // Throw an error if there is more than 1 1766 if (subtree.size() > 1) 1767 { 1768 BMCWEB_LOG_DEBUG("Found more than 1 system D-Bus object!"); 1769 messages::internalError(asyncResp->res); 1770 return; 1771 } 1772 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1773 { 1774 BMCWEB_LOG_DEBUG("Asset Tag Set mapper error!"); 1775 messages::internalError(asyncResp->res); 1776 return; 1777 } 1778 1779 const std::string& path = subtree[0].first; 1780 const std::string& service = subtree[0].second.begin()->first; 1781 1782 if (service.empty()) 1783 { 1784 BMCWEB_LOG_DEBUG("Asset Tag Set service mapper error!"); 1785 messages::internalError(asyncResp->res); 1786 return; 1787 } 1788 1789 setDbusProperty(asyncResp, service, path, 1790 "xyz.openbmc_project.Inventory.Decorator.AssetTag", 1791 "AssetTag", "AssetTag", assetTag); 1792 }); 1793 } 1794 1795 /** 1796 * @brief Validate the specified stopBootOnFault is valid and return the 1797 * stopBootOnFault name associated with that string 1798 * 1799 * @param[in] stopBootOnFaultString String representing the desired 1800 * stopBootOnFault 1801 * 1802 * @return stopBootOnFault value or empty if incoming value is not valid 1803 */ 1804 inline std::optional<bool> 1805 validstopBootOnFault(const std::string& stopBootOnFaultString) 1806 { 1807 if (stopBootOnFaultString == "AnyFault") 1808 { 1809 return true; 1810 } 1811 1812 if (stopBootOnFaultString == "Never") 1813 { 1814 return false; 1815 } 1816 1817 return std::nullopt; 1818 } 1819 1820 /** 1821 * @brief Sets stopBootOnFault 1822 * 1823 * @param[in] asyncResp Shared pointer for generating response message. 1824 * @param[in] stopBootOnFault "StopBootOnFault" from request. 1825 * 1826 * @return None. 1827 */ 1828 inline void 1829 setStopBootOnFault(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1830 const std::string& stopBootOnFault) 1831 { 1832 BMCWEB_LOG_DEBUG("Set Stop Boot On Fault."); 1833 1834 std::optional<bool> stopBootEnabled = validstopBootOnFault(stopBootOnFault); 1835 if (!stopBootEnabled) 1836 { 1837 BMCWEB_LOG_DEBUG("Invalid property value for StopBootOnFault: {}", 1838 stopBootOnFault); 1839 messages::propertyValueNotInList(asyncResp->res, stopBootOnFault, 1840 "StopBootOnFault"); 1841 return; 1842 } 1843 1844 setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", 1845 sdbusplus::message::object_path( 1846 "/xyz/openbmc_project/logging/settings"), 1847 "xyz.openbmc_project.Logging.Settings", "QuiesceOnHwError", 1848 "Boot/StopBootOnFault", *stopBootEnabled); 1849 } 1850 1851 /** 1852 * @brief Sets automaticRetry (Auto Reboot) 1853 * 1854 * @param[in] asyncResp Shared pointer for generating response message. 1855 * @param[in] automaticRetryConfig "AutomaticRetryConfig" from request. 1856 * 1857 * @return None. 1858 */ 1859 inline void 1860 setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1861 const std::string& automaticRetryConfig) 1862 { 1863 BMCWEB_LOG_DEBUG("Set Automatic Retry."); 1864 1865 // OpenBMC only supports "Disabled" and "RetryAttempts". 1866 bool autoRebootEnabled = false; 1867 1868 if (automaticRetryConfig == "Disabled") 1869 { 1870 autoRebootEnabled = false; 1871 } 1872 else if (automaticRetryConfig == "RetryAttempts") 1873 { 1874 autoRebootEnabled = true; 1875 } 1876 else 1877 { 1878 BMCWEB_LOG_DEBUG("Invalid property value for AutomaticRetryConfig: {}", 1879 automaticRetryConfig); 1880 messages::propertyValueNotInList(asyncResp->res, automaticRetryConfig, 1881 "AutomaticRetryConfig"); 1882 return; 1883 } 1884 1885 setDbusProperty(asyncResp, "xyz.openbmc_project.Settings", 1886 sdbusplus::message::object_path( 1887 "/xyz/openbmc_project/control/host0/auto_reboot"), 1888 "xyz.openbmc_project.Control.Boot.RebootPolicy", 1889 "AutoReboot", "Boot/AutomaticRetryConfig", 1890 autoRebootEnabled); 1891 } 1892 1893 inline std::string dbusPowerRestorePolicyFromRedfish(std::string_view policy) 1894 { 1895 if (policy == "AlwaysOn") 1896 { 1897 return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn"; 1898 } 1899 if (policy == "AlwaysOff") 1900 { 1901 return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff"; 1902 } 1903 if (policy == "LastState") 1904 { 1905 return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore"; 1906 } 1907 return ""; 1908 } 1909 1910 /** 1911 * @brief Sets power restore policy properties. 1912 * 1913 * @param[in] asyncResp Shared pointer for generating response message. 1914 * @param[in] policy power restore policy properties from request. 1915 * 1916 * @return None. 1917 */ 1918 inline void 1919 setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1920 std::string_view policy) 1921 { 1922 BMCWEB_LOG_DEBUG("Set power restore policy."); 1923 1924 std::string powerRestorePolicy = dbusPowerRestorePolicyFromRedfish(policy); 1925 1926 if (powerRestorePolicy.empty()) 1927 { 1928 messages::propertyValueNotInList(asyncResp->res, policy, 1929 "PowerRestorePolicy"); 1930 return; 1931 } 1932 1933 setDbusProperty( 1934 asyncResp, "xyz.openbmc_project.Settings", 1935 sdbusplus::message::object_path( 1936 "/xyz/openbmc_project/control/host0/power_restore_policy"), 1937 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1938 "PowerRestorePolicy", powerRestorePolicy); 1939 } 1940 1941 /** 1942 * @brief Retrieves provisioning status 1943 * 1944 * @param[in] asyncResp Shared pointer for completing asynchronous 1945 * calls. 1946 * 1947 * @return None. 1948 */ 1949 inline void 1950 getProvisioningStatus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1951 { 1952 BMCWEB_LOG_DEBUG("Get OEM information."); 1953 sdbusplus::asio::getAllProperties( 1954 *crow::connections::systemBus, "xyz.openbmc_project.PFR.Manager", 1955 "/xyz/openbmc_project/pfr", "xyz.openbmc_project.PFR.Attributes", 1956 [asyncResp](const boost::system::error_code& ec, 1957 const dbus::utility::DBusPropertiesMap& propertiesList) { 1958 nlohmann::json& oemPFR = 1959 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 1960 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] = 1961 "#OemComputerSystem.OpenBmc"; 1962 oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning"; 1963 1964 if (ec) 1965 { 1966 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 1967 // not an error, don't have to have the interface 1968 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1969 return; 1970 } 1971 1972 const bool* provState = nullptr; 1973 const bool* lockState = nullptr; 1974 1975 const bool success = sdbusplus::unpackPropertiesNoThrow( 1976 dbus_utils::UnpackErrorPrinter(), propertiesList, "UfmProvisioned", 1977 provState, "UfmLocked", lockState); 1978 1979 if (!success) 1980 { 1981 messages::internalError(asyncResp->res); 1982 return; 1983 } 1984 1985 if ((provState == nullptr) || (lockState == nullptr)) 1986 { 1987 BMCWEB_LOG_DEBUG("Unable to get PFR attributes."); 1988 messages::internalError(asyncResp->res); 1989 return; 1990 } 1991 1992 if (*provState) 1993 { 1994 if (*lockState) 1995 { 1996 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 1997 } 1998 else 1999 { 2000 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 2001 } 2002 } 2003 else 2004 { 2005 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 2006 } 2007 }); 2008 } 2009 2010 /** 2011 * @brief Translate the PowerMode string to enum value 2012 * 2013 * @param[in] modeString PowerMode string to be translated 2014 * 2015 * @return PowerMode enum 2016 */ 2017 inline computer_system::PowerMode 2018 translatePowerModeString(const std::string& modeString) 2019 { 2020 using PowerMode = computer_system::PowerMode; 2021 2022 if (modeString == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static") 2023 { 2024 return PowerMode::Static; 2025 } 2026 if (modeString == 2027 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance") 2028 { 2029 return PowerMode::MaximumPerformance; 2030 } 2031 if (modeString == 2032 "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving") 2033 { 2034 return PowerMode::PowerSaving; 2035 } 2036 if (modeString == 2037 "xyz.openbmc_project.Control.Power.Mode.PowerMode.BalancedPerformance") 2038 { 2039 return PowerMode::BalancedPerformance; 2040 } 2041 if (modeString == 2042 "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPerformance") 2043 { 2044 return PowerMode::EfficiencyFavorPerformance; 2045 } 2046 if (modeString == 2047 "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPower") 2048 { 2049 return PowerMode::EfficiencyFavorPower; 2050 } 2051 if (modeString == "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM") 2052 { 2053 return PowerMode::OEM; 2054 } 2055 // Any other values would be invalid 2056 BMCWEB_LOG_ERROR("PowerMode value was not valid: {}", modeString); 2057 return PowerMode::Invalid; 2058 } 2059 2060 inline void 2061 afterGetPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2062 const boost::system::error_code& ec, 2063 const dbus::utility::DBusPropertiesMap& properties) 2064 { 2065 if (ec) 2066 { 2067 BMCWEB_LOG_ERROR("DBUS response error on PowerMode GetAll: {}", ec); 2068 messages::internalError(asyncResp->res); 2069 return; 2070 } 2071 2072 std::string powerMode; 2073 const std::vector<std::string>* allowedModes = nullptr; 2074 const bool success = sdbusplus::unpackPropertiesNoThrow( 2075 dbus_utils::UnpackErrorPrinter(), properties, "PowerMode", powerMode, 2076 "AllowedPowerModes", allowedModes); 2077 2078 if (!success) 2079 { 2080 messages::internalError(asyncResp->res); 2081 return; 2082 } 2083 2084 nlohmann::json::array_t modeList; 2085 if (allowedModes == nullptr) 2086 { 2087 modeList.emplace_back("Static"); 2088 modeList.emplace_back("MaximumPerformance"); 2089 modeList.emplace_back("PowerSaving"); 2090 } 2091 else 2092 { 2093 for (const auto& aMode : *allowedModes) 2094 { 2095 computer_system::PowerMode modeValue = 2096 translatePowerModeString(aMode); 2097 if (modeValue == computer_system::PowerMode::Invalid) 2098 { 2099 messages::internalError(asyncResp->res); 2100 continue; 2101 } 2102 modeList.emplace_back(modeValue); 2103 } 2104 } 2105 asyncResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = modeList; 2106 2107 BMCWEB_LOG_DEBUG("Current power mode: {}", powerMode); 2108 const computer_system::PowerMode modeValue = 2109 translatePowerModeString(powerMode); 2110 if (modeValue == computer_system::PowerMode::Invalid) 2111 { 2112 messages::internalError(asyncResp->res); 2113 return; 2114 } 2115 asyncResp->res.jsonValue["PowerMode"] = modeValue; 2116 } 2117 /** 2118 * @brief Retrieves system power mode 2119 * 2120 * @param[in] asyncResp Shared pointer for generating response message. 2121 * 2122 * @return None. 2123 */ 2124 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2125 { 2126 BMCWEB_LOG_DEBUG("Get power mode."); 2127 2128 // Get Power Mode object path: 2129 constexpr std::array<std::string_view, 1> interfaces = { 2130 "xyz.openbmc_project.Control.Power.Mode"}; 2131 dbus::utility::getSubTree( 2132 "/", 0, interfaces, 2133 [asyncResp](const boost::system::error_code& ec, 2134 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2135 if (ec) 2136 { 2137 BMCWEB_LOG_DEBUG("DBUS response error on Power.Mode GetSubTree {}", 2138 ec); 2139 // This is an optional D-Bus object so just return if 2140 // error occurs 2141 return; 2142 } 2143 if (subtree.empty()) 2144 { 2145 // As noted above, this is an optional interface so just return 2146 // if there is no instance found 2147 return; 2148 } 2149 if (subtree.size() > 1) 2150 { 2151 // More then one PowerMode object is not supported and is an 2152 // error 2153 BMCWEB_LOG_DEBUG( 2154 "Found more than 1 system D-Bus Power.Mode objects: {}", 2155 subtree.size()); 2156 messages::internalError(asyncResp->res); 2157 return; 2158 } 2159 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2160 { 2161 BMCWEB_LOG_DEBUG("Power.Mode mapper error!"); 2162 messages::internalError(asyncResp->res); 2163 return; 2164 } 2165 const std::string& path = subtree[0].first; 2166 const std::string& service = subtree[0].second.begin()->first; 2167 if (service.empty()) 2168 { 2169 BMCWEB_LOG_DEBUG("Power.Mode service mapper error!"); 2170 messages::internalError(asyncResp->res); 2171 return; 2172 } 2173 2174 // Valid Power Mode object found, now read the mode properties 2175 sdbusplus::asio::getAllProperties( 2176 *crow::connections::systemBus, service, path, 2177 "xyz.openbmc_project.Control.Power.Mode", 2178 [asyncResp](const boost::system::error_code& ec2, 2179 const dbus::utility::DBusPropertiesMap& properties) { 2180 afterGetPowerMode(asyncResp, ec2, properties); 2181 }); 2182 }); 2183 } 2184 2185 /** 2186 * @brief Validate the specified mode is valid and return the PowerMode 2187 * name associated with that string 2188 * 2189 * @param[in] asyncResp Shared pointer for generating response message. 2190 * @param[in] modeValue String representing the desired PowerMode 2191 * 2192 * @return PowerMode value or empty string if mode is not valid 2193 */ 2194 inline std::string 2195 validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2196 const nlohmann::json& modeValue) 2197 { 2198 using PowerMode = computer_system::PowerMode; 2199 std::string mode; 2200 2201 if (modeValue == PowerMode::Static) 2202 { 2203 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static"; 2204 } 2205 else if (modeValue == PowerMode::MaximumPerformance) 2206 { 2207 mode = 2208 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance"; 2209 } 2210 else if (modeValue == PowerMode::PowerSaving) 2211 { 2212 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving"; 2213 } 2214 else if (modeValue == PowerMode::BalancedPerformance) 2215 { 2216 mode = 2217 "xyz.openbmc_project.Control.Power.Mode.PowerMode.BalancedPerformance"; 2218 } 2219 else if (modeValue == PowerMode::EfficiencyFavorPerformance) 2220 { 2221 mode = 2222 "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPerformance"; 2223 } 2224 else if (modeValue == PowerMode::EfficiencyFavorPower) 2225 { 2226 mode = 2227 "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPower"; 2228 } 2229 else 2230 { 2231 messages::propertyValueNotInList(asyncResp->res, modeValue.dump(), 2232 "PowerMode"); 2233 } 2234 return mode; 2235 } 2236 2237 /** 2238 * @brief Sets system power mode. 2239 * 2240 * @param[in] asyncResp Shared pointer for generating response message. 2241 * @param[in] pmode System power mode from request. 2242 * 2243 * @return None. 2244 */ 2245 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2246 const std::string& pmode) 2247 { 2248 BMCWEB_LOG_DEBUG("Set power mode."); 2249 2250 std::string powerMode = validatePowerMode(asyncResp, pmode); 2251 if (powerMode.empty()) 2252 { 2253 return; 2254 } 2255 2256 // Get Power Mode object path: 2257 constexpr std::array<std::string_view, 1> interfaces = { 2258 "xyz.openbmc_project.Control.Power.Mode"}; 2259 dbus::utility::getSubTree( 2260 "/", 0, interfaces, 2261 [asyncResp, 2262 powerMode](const boost::system::error_code& ec, 2263 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2264 if (ec) 2265 { 2266 BMCWEB_LOG_ERROR("DBUS response error on Power.Mode GetSubTree {}", 2267 ec); 2268 // This is an optional D-Bus object, but user attempted to patch 2269 messages::internalError(asyncResp->res); 2270 return; 2271 } 2272 if (subtree.empty()) 2273 { 2274 // This is an optional D-Bus object, but user attempted to patch 2275 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 2276 "PowerMode"); 2277 return; 2278 } 2279 if (subtree.size() > 1) 2280 { 2281 // More then one PowerMode object is not supported and is an 2282 // error 2283 BMCWEB_LOG_DEBUG( 2284 "Found more than 1 system D-Bus Power.Mode objects: {}", 2285 subtree.size()); 2286 messages::internalError(asyncResp->res); 2287 return; 2288 } 2289 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2290 { 2291 BMCWEB_LOG_DEBUG("Power.Mode mapper error!"); 2292 messages::internalError(asyncResp->res); 2293 return; 2294 } 2295 const std::string& path = subtree[0].first; 2296 const std::string& service = subtree[0].second.begin()->first; 2297 if (service.empty()) 2298 { 2299 BMCWEB_LOG_DEBUG("Power.Mode service mapper error!"); 2300 messages::internalError(asyncResp->res); 2301 return; 2302 } 2303 2304 BMCWEB_LOG_DEBUG("Setting power mode({}) -> {}", powerMode, path); 2305 2306 // Set the Power Mode property 2307 setDbusProperty(asyncResp, service, path, 2308 "xyz.openbmc_project.Control.Power.Mode", "PowerMode", 2309 "PowerMode", powerMode); 2310 }); 2311 } 2312 2313 /** 2314 * @brief Translates watchdog timeout action DBUS property value to redfish. 2315 * 2316 * @param[in] dbusAction The watchdog timeout action in D-BUS. 2317 * 2318 * @return Returns as a string, the timeout action in Redfish terms. If 2319 * translation cannot be done, returns an empty string. 2320 */ 2321 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction) 2322 { 2323 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 2324 { 2325 return "None"; 2326 } 2327 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset") 2328 { 2329 return "ResetSystem"; 2330 } 2331 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 2332 { 2333 return "PowerDown"; 2334 } 2335 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 2336 { 2337 return "PowerCycle"; 2338 } 2339 2340 return ""; 2341 } 2342 2343 /** 2344 *@brief Translates timeout action from Redfish to DBUS property value. 2345 * 2346 *@param[in] rfAction The timeout action in Redfish. 2347 * 2348 *@return Returns as a string, the time_out action as expected by DBUS. 2349 *If translation cannot be done, returns an empty string. 2350 */ 2351 2352 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 2353 { 2354 if (rfAction == "None") 2355 { 2356 return "xyz.openbmc_project.State.Watchdog.Action.None"; 2357 } 2358 if (rfAction == "PowerCycle") 2359 { 2360 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 2361 } 2362 if (rfAction == "PowerDown") 2363 { 2364 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 2365 } 2366 if (rfAction == "ResetSystem") 2367 { 2368 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 2369 } 2370 2371 return ""; 2372 } 2373 2374 /** 2375 * @brief Retrieves host watchdog timer properties over DBUS 2376 * 2377 * @param[in] asyncResp Shared pointer for completing asynchronous calls. 2378 * 2379 * @return None. 2380 */ 2381 inline void 2382 getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2383 { 2384 BMCWEB_LOG_DEBUG("Get host watchodg"); 2385 sdbusplus::asio::getAllProperties( 2386 *crow::connections::systemBus, "xyz.openbmc_project.Watchdog", 2387 "/xyz/openbmc_project/watchdog/host0", 2388 "xyz.openbmc_project.State.Watchdog", 2389 [asyncResp](const boost::system::error_code& ec, 2390 const dbus::utility::DBusPropertiesMap& properties) { 2391 if (ec) 2392 { 2393 // watchdog service is stopped 2394 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 2395 return; 2396 } 2397 2398 BMCWEB_LOG_DEBUG("Got {} wdt prop.", properties.size()); 2399 2400 nlohmann::json& hostWatchdogTimer = 2401 asyncResp->res.jsonValue["HostWatchdogTimer"]; 2402 2403 // watchdog service is running/enabled 2404 hostWatchdogTimer["Status"]["State"] = "Enabled"; 2405 2406 const bool* enabled = nullptr; 2407 const std::string* expireAction = nullptr; 2408 2409 const bool success = sdbusplus::unpackPropertiesNoThrow( 2410 dbus_utils::UnpackErrorPrinter(), properties, "Enabled", enabled, 2411 "ExpireAction", expireAction); 2412 2413 if (!success) 2414 { 2415 messages::internalError(asyncResp->res); 2416 return; 2417 } 2418 2419 if (enabled != nullptr) 2420 { 2421 hostWatchdogTimer["FunctionEnabled"] = *enabled; 2422 } 2423 2424 if (expireAction != nullptr) 2425 { 2426 std::string action = dbusToRfWatchdogAction(*expireAction); 2427 if (action.empty()) 2428 { 2429 messages::internalError(asyncResp->res); 2430 return; 2431 } 2432 hostWatchdogTimer["TimeoutAction"] = action; 2433 } 2434 }); 2435 } 2436 2437 /** 2438 * @brief Sets Host WatchDog Timer properties. 2439 * 2440 * @param[in] asyncResp Shared pointer for generating response message. 2441 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 2442 * RF request. 2443 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 2444 * 2445 * @return None. 2446 */ 2447 inline void 2448 setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2449 const std::optional<bool> wdtEnable, 2450 const std::optional<std::string>& wdtTimeOutAction) 2451 { 2452 BMCWEB_LOG_DEBUG("Set host watchdog"); 2453 2454 if (wdtTimeOutAction) 2455 { 2456 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 2457 // check if TimeOut Action is Valid 2458 if (wdtTimeOutActStr.empty()) 2459 { 2460 BMCWEB_LOG_DEBUG("Unsupported value for TimeoutAction: {}", 2461 *wdtTimeOutAction); 2462 messages::propertyValueNotInList(asyncResp->res, *wdtTimeOutAction, 2463 "TimeoutAction"); 2464 return; 2465 } 2466 2467 setDbusProperty(asyncResp, "xyz.openbmc_project.Watchdog", 2468 sdbusplus::message::object_path( 2469 "/xyz/openbmc_project/watchdog/host0"), 2470 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 2471 "HostWatchdogTimer/TimeoutAction", wdtTimeOutActStr); 2472 } 2473 2474 if (wdtEnable) 2475 { 2476 setDbusProperty(asyncResp, "xyz.openbmc_project.Watchdog", 2477 sdbusplus::message::object_path( 2478 "/xyz/openbmc_project/watchdog/host0"), 2479 "xyz.openbmc_project.State.Watchdog", "Enabled", 2480 "HostWatchdogTimer/FunctionEnabled", *wdtEnable); 2481 } 2482 } 2483 2484 /** 2485 * @brief Parse the Idle Power Saver properties into json 2486 * 2487 * @param[in] asyncResp Shared pointer for completing asynchronous calls. 2488 * @param[in] properties IPS property data from DBus. 2489 * 2490 * @return true if successful 2491 */ 2492 inline bool 2493 parseIpsProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2494 const dbus::utility::DBusPropertiesMap& properties) 2495 { 2496 const bool* enabled = nullptr; 2497 const uint8_t* enterUtilizationPercent = nullptr; 2498 const uint64_t* enterDwellTime = nullptr; 2499 const uint8_t* exitUtilizationPercent = nullptr; 2500 const uint64_t* exitDwellTime = nullptr; 2501 2502 const bool success = sdbusplus::unpackPropertiesNoThrow( 2503 dbus_utils::UnpackErrorPrinter(), properties, "Enabled", enabled, 2504 "EnterUtilizationPercent", enterUtilizationPercent, "EnterDwellTime", 2505 enterDwellTime, "ExitUtilizationPercent", exitUtilizationPercent, 2506 "ExitDwellTime", exitDwellTime); 2507 2508 if (!success) 2509 { 2510 return false; 2511 } 2512 2513 if (enabled != nullptr) 2514 { 2515 asyncResp->res.jsonValue["IdlePowerSaver"]["Enabled"] = *enabled; 2516 } 2517 2518 if (enterUtilizationPercent != nullptr) 2519 { 2520 asyncResp->res.jsonValue["IdlePowerSaver"]["EnterUtilizationPercent"] = 2521 *enterUtilizationPercent; 2522 } 2523 2524 if (enterDwellTime != nullptr) 2525 { 2526 const std::chrono::duration<uint64_t, std::milli> ms(*enterDwellTime); 2527 asyncResp->res.jsonValue["IdlePowerSaver"]["EnterDwellTimeSeconds"] = 2528 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) 2529 .count(); 2530 } 2531 2532 if (exitUtilizationPercent != nullptr) 2533 { 2534 asyncResp->res.jsonValue["IdlePowerSaver"]["ExitUtilizationPercent"] = 2535 *exitUtilizationPercent; 2536 } 2537 2538 if (exitDwellTime != nullptr) 2539 { 2540 const std::chrono::duration<uint64_t, std::milli> ms(*exitDwellTime); 2541 asyncResp->res.jsonValue["IdlePowerSaver"]["ExitDwellTimeSeconds"] = 2542 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) 2543 .count(); 2544 } 2545 2546 return true; 2547 } 2548 2549 /** 2550 * @brief Retrieves host watchdog timer properties over DBUS 2551 * 2552 * @param[in] asyncResp Shared pointer for completing asynchronous calls. 2553 * 2554 * @return None. 2555 */ 2556 inline void 2557 getIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2558 { 2559 BMCWEB_LOG_DEBUG("Get idle power saver parameters"); 2560 2561 // Get IdlePowerSaver object path: 2562 constexpr std::array<std::string_view, 1> interfaces = { 2563 "xyz.openbmc_project.Control.Power.IdlePowerSaver"}; 2564 dbus::utility::getSubTree( 2565 "/", 0, interfaces, 2566 [asyncResp](const boost::system::error_code& ec, 2567 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2568 if (ec) 2569 { 2570 BMCWEB_LOG_ERROR( 2571 "DBUS response error on Power.IdlePowerSaver GetSubTree {}", 2572 ec); 2573 messages::internalError(asyncResp->res); 2574 return; 2575 } 2576 if (subtree.empty()) 2577 { 2578 // This is an optional interface so just return 2579 // if there is no instance found 2580 BMCWEB_LOG_DEBUG("No instances found"); 2581 return; 2582 } 2583 if (subtree.size() > 1) 2584 { 2585 // More then one PowerIdlePowerSaver object is not supported and 2586 // is an error 2587 BMCWEB_LOG_DEBUG("Found more than 1 system D-Bus " 2588 "Power.IdlePowerSaver objects: {}", 2589 subtree.size()); 2590 messages::internalError(asyncResp->res); 2591 return; 2592 } 2593 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2594 { 2595 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver mapper error!"); 2596 messages::internalError(asyncResp->res); 2597 return; 2598 } 2599 const std::string& path = subtree[0].first; 2600 const std::string& service = subtree[0].second.begin()->first; 2601 if (service.empty()) 2602 { 2603 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver service mapper error!"); 2604 messages::internalError(asyncResp->res); 2605 return; 2606 } 2607 2608 // Valid IdlePowerSaver object found, now read the current values 2609 sdbusplus::asio::getAllProperties( 2610 *crow::connections::systemBus, service, path, 2611 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2612 [asyncResp](const boost::system::error_code& ec2, 2613 const dbus::utility::DBusPropertiesMap& properties) { 2614 if (ec2) 2615 { 2616 BMCWEB_LOG_ERROR( 2617 "DBUS response error on IdlePowerSaver GetAll: {}", ec2); 2618 messages::internalError(asyncResp->res); 2619 return; 2620 } 2621 2622 if (!parseIpsProperties(asyncResp, properties)) 2623 { 2624 messages::internalError(asyncResp->res); 2625 return; 2626 } 2627 }); 2628 }); 2629 2630 BMCWEB_LOG_DEBUG("EXIT: Get idle power saver parameters"); 2631 } 2632 2633 /** 2634 * @brief Sets Idle Power Saver properties. 2635 * 2636 * @param[in] asyncResp Shared pointer for generating response message. 2637 * @param[in] ipsEnable The IPS Enable value (true/false) from incoming 2638 * RF request. 2639 * @param[in] ipsEnterUtil The utilization limit to enter idle state. 2640 * @param[in] ipsEnterTime The time the utilization must be below ipsEnterUtil 2641 * before entering idle state. 2642 * @param[in] ipsExitUtil The utilization limit when exiting idle state. 2643 * @param[in] ipsExitTime The time the utilization must be above ipsExutUtil 2644 * before exiting idle state 2645 * 2646 * @return None. 2647 */ 2648 inline void 2649 setIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2650 const std::optional<bool> ipsEnable, 2651 const std::optional<uint8_t> ipsEnterUtil, 2652 const std::optional<uint64_t> ipsEnterTime, 2653 const std::optional<uint8_t> ipsExitUtil, 2654 const std::optional<uint64_t> ipsExitTime) 2655 { 2656 BMCWEB_LOG_DEBUG("Set idle power saver properties"); 2657 2658 // Get IdlePowerSaver object path: 2659 constexpr std::array<std::string_view, 1> interfaces = { 2660 "xyz.openbmc_project.Control.Power.IdlePowerSaver"}; 2661 dbus::utility::getSubTree( 2662 "/", 0, interfaces, 2663 [asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime, ipsExitUtil, 2664 ipsExitTime](const boost::system::error_code& ec, 2665 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2666 if (ec) 2667 { 2668 BMCWEB_LOG_ERROR( 2669 "DBUS response error on Power.IdlePowerSaver GetSubTree {}", 2670 ec); 2671 messages::internalError(asyncResp->res); 2672 return; 2673 } 2674 if (subtree.empty()) 2675 { 2676 // This is an optional D-Bus object, but user attempted to patch 2677 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 2678 "IdlePowerSaver"); 2679 return; 2680 } 2681 if (subtree.size() > 1) 2682 { 2683 // More then one PowerIdlePowerSaver object is not supported and 2684 // is an error 2685 BMCWEB_LOG_DEBUG( 2686 "Found more than 1 system D-Bus Power.IdlePowerSaver objects: {}", 2687 subtree.size()); 2688 messages::internalError(asyncResp->res); 2689 return; 2690 } 2691 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2692 { 2693 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver mapper error!"); 2694 messages::internalError(asyncResp->res); 2695 return; 2696 } 2697 const std::string& path = subtree[0].first; 2698 const std::string& service = subtree[0].second.begin()->first; 2699 if (service.empty()) 2700 { 2701 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver service mapper error!"); 2702 messages::internalError(asyncResp->res); 2703 return; 2704 } 2705 2706 // Valid Power IdlePowerSaver object found, now set any values that 2707 // need to be updated 2708 2709 if (ipsEnable) 2710 { 2711 setDbusProperty(asyncResp, service, path, 2712 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2713 "Enabled", "IdlePowerSaver/Enabled", *ipsEnable); 2714 } 2715 if (ipsEnterUtil) 2716 { 2717 setDbusProperty(asyncResp, service, path, 2718 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2719 "EnterUtilizationPercent", 2720 "IdlePowerSaver/EnterUtilizationPercent", 2721 *ipsEnterUtil); 2722 } 2723 if (ipsEnterTime) 2724 { 2725 // Convert from seconds into milliseconds for DBus 2726 const uint64_t timeMilliseconds = *ipsEnterTime * 1000; 2727 setDbusProperty(asyncResp, service, path, 2728 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2729 "EnterDwellTime", 2730 "IdlePowerSaver/EnterDwellTimeSeconds", 2731 timeMilliseconds); 2732 } 2733 if (ipsExitUtil) 2734 { 2735 setDbusProperty(asyncResp, service, path, 2736 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2737 "ExitUtilizationPercent", 2738 "IdlePowerSaver/ExitUtilizationPercent", 2739 *ipsExitUtil); 2740 } 2741 if (ipsExitTime) 2742 { 2743 // Convert from seconds into milliseconds for DBus 2744 const uint64_t timeMilliseconds = *ipsExitTime * 1000; 2745 setDbusProperty(asyncResp, service, path, 2746 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2747 "ExitDwellTime", 2748 "IdlePowerSaver/ExitDwellTimeSeconds", 2749 timeMilliseconds); 2750 } 2751 }); 2752 2753 BMCWEB_LOG_DEBUG("EXIT: Set idle power saver parameters"); 2754 } 2755 2756 inline void handleComputerSystemCollectionHead( 2757 crow::App& app, const crow::Request& req, 2758 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2759 { 2760 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2761 { 2762 return; 2763 } 2764 asyncResp->res.addHeader( 2765 boost::beast::http::field::link, 2766 "</redfish/v1/JsonSchemas/ComputerSystemCollection/ComputerSystemCollection.json>; rel=describedby"); 2767 } 2768 2769 inline void handleComputerSystemCollectionGet( 2770 crow::App& app, const crow::Request& req, 2771 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2772 { 2773 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2774 { 2775 return; 2776 } 2777 2778 asyncResp->res.addHeader( 2779 boost::beast::http::field::link, 2780 "</redfish/v1/JsonSchemas/ComputerSystemCollection.json>; rel=describedby"); 2781 asyncResp->res.jsonValue["@odata.type"] = 2782 "#ComputerSystemCollection.ComputerSystemCollection"; 2783 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 2784 asyncResp->res.jsonValue["Name"] = "Computer System Collection"; 2785 2786 nlohmann::json& ifaceArray = asyncResp->res.jsonValue["Members"]; 2787 ifaceArray = nlohmann::json::array(); 2788 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 2789 { 2790 asyncResp->res.jsonValue["Members@odata.count"] = 0; 2791 // Option currently returns no systems. TBD 2792 return; 2793 } 2794 asyncResp->res.jsonValue["Members@odata.count"] = 1; 2795 nlohmann::json::object_t system; 2796 system["@odata.id"] = boost::urls::format("/redfish/v1/Systems/{}", 2797 BMCWEB_REDFISH_SYSTEM_URI_NAME); 2798 ifaceArray.emplace_back(std::move(system)); 2799 sdbusplus::asio::getProperty<std::string>( 2800 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 2801 "/xyz/openbmc_project/network/hypervisor", 2802 "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 2803 [asyncResp](const boost::system::error_code& ec2, 2804 const std::string& /*hostName*/) { 2805 if (ec2) 2806 { 2807 return; 2808 } 2809 auto val = asyncResp->res.jsonValue.find("Members@odata.count"); 2810 if (val == asyncResp->res.jsonValue.end()) 2811 { 2812 BMCWEB_LOG_CRITICAL("Count wasn't found??"); 2813 return; 2814 } 2815 uint64_t* count = val->get_ptr<uint64_t*>(); 2816 if (count == nullptr) 2817 { 2818 BMCWEB_LOG_CRITICAL("Count wasn't found??"); 2819 return; 2820 } 2821 *count = *count + 1; 2822 BMCWEB_LOG_DEBUG("Hypervisor is available"); 2823 nlohmann::json& ifaceArray2 = asyncResp->res.jsonValue["Members"]; 2824 nlohmann::json::object_t hypervisor; 2825 hypervisor["@odata.id"] = "/redfish/v1/Systems/hypervisor"; 2826 ifaceArray2.emplace_back(std::move(hypervisor)); 2827 }); 2828 } 2829 2830 /** 2831 * Function transceives data with dbus directly. 2832 */ 2833 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2834 { 2835 constexpr const char* serviceName = "xyz.openbmc_project.Control.Host.NMI"; 2836 constexpr const char* objectPath = "/xyz/openbmc_project/control/host0/nmi"; 2837 constexpr const char* interfaceName = 2838 "xyz.openbmc_project.Control.Host.NMI"; 2839 constexpr const char* method = "NMI"; 2840 2841 crow::connections::systemBus->async_method_call( 2842 [asyncResp](const boost::system::error_code& ec) { 2843 if (ec) 2844 { 2845 BMCWEB_LOG_ERROR(" Bad D-Bus request error: {}", ec); 2846 messages::internalError(asyncResp->res); 2847 return; 2848 } 2849 messages::success(asyncResp->res); 2850 }, 2851 serviceName, objectPath, interfaceName, method); 2852 } 2853 2854 inline void handleComputerSystemResetActionPost( 2855 crow::App& app, const crow::Request& req, 2856 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2857 const std::string& systemName) 2858 { 2859 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2860 { 2861 return; 2862 } 2863 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 2864 { 2865 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 2866 systemName); 2867 return; 2868 } 2869 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 2870 { 2871 // Option currently returns no systems. TBD 2872 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 2873 systemName); 2874 return; 2875 } 2876 std::string resetType; 2877 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType)) 2878 { 2879 return; 2880 } 2881 2882 // Get the command and host vs. chassis 2883 std::string command; 2884 bool hostCommand = true; 2885 if ((resetType == "On") || (resetType == "ForceOn")) 2886 { 2887 command = "xyz.openbmc_project.State.Host.Transition.On"; 2888 hostCommand = true; 2889 } 2890 else if (resetType == "ForceOff") 2891 { 2892 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 2893 hostCommand = false; 2894 } 2895 else if (resetType == "ForceRestart") 2896 { 2897 command = "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 2898 hostCommand = true; 2899 } 2900 else if (resetType == "GracefulShutdown") 2901 { 2902 command = "xyz.openbmc_project.State.Host.Transition.Off"; 2903 hostCommand = true; 2904 } 2905 else if (resetType == "GracefulRestart") 2906 { 2907 command = 2908 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot"; 2909 hostCommand = true; 2910 } 2911 else if (resetType == "PowerCycle") 2912 { 2913 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 2914 hostCommand = true; 2915 } 2916 else if (resetType == "Nmi") 2917 { 2918 doNMI(asyncResp); 2919 return; 2920 } 2921 else 2922 { 2923 messages::actionParameterUnknown(asyncResp->res, "Reset", resetType); 2924 return; 2925 } 2926 sdbusplus::message::object_path statePath("/xyz/openbmc_project/state"); 2927 2928 if (hostCommand) 2929 { 2930 setDbusProperty(asyncResp, "xyz.openbmc_project.State.Host", 2931 statePath / "host0", "xyz.openbmc_project.State.Host", 2932 "RequestedHostTransition", "Reset", command); 2933 } 2934 else 2935 { 2936 setDbusProperty(asyncResp, "xyz.openbmc_project.State.Chassis", 2937 statePath / "chassis0", 2938 "xyz.openbmc_project.State.Chassis", 2939 "RequestedPowerTransition", "Reset", command); 2940 } 2941 } 2942 2943 inline void handleComputerSystemHead( 2944 App& app, const crow::Request& req, 2945 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2946 const std::string& /*systemName*/) 2947 { 2948 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2949 { 2950 return; 2951 } 2952 2953 asyncResp->res.addHeader( 2954 boost::beast::http::field::link, 2955 "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby"); 2956 } 2957 2958 inline void afterPortRequest( 2959 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2960 const boost::system::error_code& ec, 2961 const std::vector<std::tuple<std::string, std::string, bool>>& socketData) 2962 { 2963 if (ec) 2964 { 2965 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 2966 messages::internalError(asyncResp->res); 2967 return; 2968 } 2969 for (const auto& data : socketData) 2970 { 2971 const std::string& socketPath = get<0>(data); 2972 const std::string& protocolName = get<1>(data); 2973 bool isProtocolEnabled = get<2>(data); 2974 nlohmann::json& dataJson = asyncResp->res.jsonValue["SerialConsole"]; 2975 dataJson[protocolName]["ServiceEnabled"] = isProtocolEnabled; 2976 // need to retrieve port number for 2977 // obmc-console-ssh service 2978 if (protocolName == "SSH") 2979 { 2980 getPortNumber(socketPath, [asyncResp, protocolName]( 2981 const boost::system::error_code& ec1, 2982 int portNumber) { 2983 if (ec1) 2984 { 2985 BMCWEB_LOG_ERROR("DBUS response error {}", ec1); 2986 messages::internalError(asyncResp->res); 2987 return; 2988 } 2989 nlohmann::json& dataJson1 = 2990 asyncResp->res.jsonValue["SerialConsole"]; 2991 dataJson1[protocolName]["Port"] = portNumber; 2992 }); 2993 } 2994 } 2995 } 2996 2997 inline void 2998 handleComputerSystemGet(crow::App& app, const crow::Request& req, 2999 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3000 const std::string& systemName) 3001 { 3002 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3003 { 3004 return; 3005 } 3006 3007 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 3008 { 3009 // Option currently returns no systems. TBD 3010 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3011 systemName); 3012 return; 3013 } 3014 3015 if (systemName == "hypervisor") 3016 { 3017 handleHypervisorSystemGet(asyncResp); 3018 return; 3019 } 3020 3021 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 3022 { 3023 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3024 systemName); 3025 return; 3026 } 3027 asyncResp->res.addHeader( 3028 boost::beast::http::field::link, 3029 "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby"); 3030 asyncResp->res.jsonValue["@odata.type"] = 3031 "#ComputerSystem.v1_22_0.ComputerSystem"; 3032 asyncResp->res.jsonValue["Name"] = BMCWEB_REDFISH_SYSTEM_URI_NAME; 3033 asyncResp->res.jsonValue["Id"] = BMCWEB_REDFISH_SYSTEM_URI_NAME; 3034 asyncResp->res.jsonValue["SystemType"] = "Physical"; 3035 asyncResp->res.jsonValue["Description"] = "Computer System"; 3036 asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0; 3037 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = 3038 double(0); 3039 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 3040 "/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME); 3041 3042 asyncResp->res.jsonValue["Processors"]["@odata.id"] = boost::urls::format( 3043 "/redfish/v1/Systems/{}/Processors", BMCWEB_REDFISH_SYSTEM_URI_NAME); 3044 asyncResp->res.jsonValue["Memory"]["@odata.id"] = boost::urls::format( 3045 "/redfish/v1/Systems/{}/Memory", BMCWEB_REDFISH_SYSTEM_URI_NAME); 3046 asyncResp->res.jsonValue["Storage"]["@odata.id"] = boost::urls::format( 3047 "/redfish/v1/Systems/{}/Storage", BMCWEB_REDFISH_SYSTEM_URI_NAME); 3048 asyncResp->res.jsonValue["FabricAdapters"]["@odata.id"] = 3049 boost::urls::format("/redfish/v1/Systems/{}/FabricAdapters", 3050 BMCWEB_REDFISH_SYSTEM_URI_NAME); 3051 3052 asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"]["target"] = 3053 boost::urls::format( 3054 "/redfish/v1/Systems/{}/Actions/ComputerSystem.Reset", 3055 BMCWEB_REDFISH_SYSTEM_URI_NAME); 3056 asyncResp->res 3057 .jsonValue["Actions"]["#ComputerSystem.Reset"]["@Redfish.ActionInfo"] = 3058 boost::urls::format("/redfish/v1/Systems/{}/ResetActionInfo", 3059 BMCWEB_REDFISH_SYSTEM_URI_NAME); 3060 3061 asyncResp->res.jsonValue["LogServices"]["@odata.id"] = boost::urls::format( 3062 "/redfish/v1/Systems/{}/LogServices", BMCWEB_REDFISH_SYSTEM_URI_NAME); 3063 asyncResp->res.jsonValue["Bios"]["@odata.id"] = boost::urls::format( 3064 "/redfish/v1/Systems/{}/Bios", BMCWEB_REDFISH_SYSTEM_URI_NAME); 3065 3066 nlohmann::json::array_t managedBy; 3067 nlohmann::json& manager = managedBy.emplace_back(); 3068 manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}", 3069 BMCWEB_REDFISH_MANAGER_URI_NAME); 3070 asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy); 3071 asyncResp->res.jsonValue["Status"]["Health"] = "OK"; 3072 asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 3073 3074 // Fill in SerialConsole info 3075 asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15; 3076 asyncResp->res.jsonValue["SerialConsole"]["IPMI"]["ServiceEnabled"] = true; 3077 3078 asyncResp->res.jsonValue["SerialConsole"]["SSH"]["ServiceEnabled"] = true; 3079 asyncResp->res.jsonValue["SerialConsole"]["SSH"]["Port"] = 2200; 3080 asyncResp->res.jsonValue["SerialConsole"]["SSH"]["HotKeySequenceDisplay"] = 3081 "Press ~. to exit console"; 3082 getPortStatusAndPath(std::span{protocolToDBusForSystems}, 3083 std::bind_front(afterPortRequest, asyncResp)); 3084 3085 if constexpr (BMCWEB_KVM) 3086 { 3087 // Fill in GraphicalConsole info 3088 asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true; 3089 asyncResp->res.jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = 3090 4; 3091 asyncResp->res.jsonValue["GraphicalConsole"]["ConnectTypesSupported"] = 3092 nlohmann::json::array_t({"KVMIP"}); 3093 } 3094 3095 getMainChassisId(asyncResp, 3096 [](const std::string& chassisId, 3097 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { 3098 nlohmann::json::array_t chassisArray; 3099 nlohmann::json& chassis = chassisArray.emplace_back(); 3100 chassis["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}", 3101 chassisId); 3102 aRsp->res.jsonValue["Links"]["Chassis"] = std::move(chassisArray); 3103 }); 3104 3105 getSystemLocationIndicatorActive(asyncResp); 3106 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 3107 getIndicatorLedState(asyncResp); 3108 getComputerSystem(asyncResp); 3109 getHostState(asyncResp); 3110 getBootProperties(asyncResp); 3111 getBootProgress(asyncResp); 3112 getBootProgressLastStateTime(asyncResp); 3113 pcie_util::getPCIeDeviceList(asyncResp, 3114 nlohmann::json::json_pointer("/PCIeDevices")); 3115 getHostWatchdogTimer(asyncResp); 3116 getPowerRestorePolicy(asyncResp); 3117 getStopBootOnFault(asyncResp); 3118 getAutomaticRetryPolicy(asyncResp); 3119 getLastResetTime(asyncResp); 3120 if constexpr (BMCWEB_REDFISH_PROVISIONING_FEATURE) 3121 { 3122 getProvisioningStatus(asyncResp); 3123 } 3124 getTrustedModuleRequiredToBoot(asyncResp); 3125 getPowerMode(asyncResp); 3126 getIdlePowerSaver(asyncResp); 3127 } 3128 3129 inline void handleComputerSystemPatch( 3130 crow::App& app, const crow::Request& req, 3131 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3132 const std::string& systemName) 3133 { 3134 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3135 { 3136 return; 3137 } 3138 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 3139 { 3140 // Option currently returns no systems. TBD 3141 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3142 systemName); 3143 return; 3144 } 3145 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 3146 { 3147 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3148 systemName); 3149 return; 3150 } 3151 3152 asyncResp->res.addHeader( 3153 boost::beast::http::field::link, 3154 "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby"); 3155 3156 std::optional<bool> locationIndicatorActive; 3157 std::optional<std::string> indicatorLed; 3158 std::optional<std::string> assetTag; 3159 std::optional<std::string> powerRestorePolicy; 3160 std::optional<std::string> powerMode; 3161 std::optional<bool> wdtEnable; 3162 std::optional<std::string> wdtTimeOutAction; 3163 std::optional<std::string> bootSource; 3164 std::optional<std::string> bootType; 3165 std::optional<std::string> bootEnable; 3166 std::optional<std::string> bootAutomaticRetry; 3167 std::optional<uint32_t> bootAutomaticRetryAttempts; 3168 std::optional<bool> bootTrustedModuleRequired; 3169 std::optional<std::string> stopBootOnFault; 3170 std::optional<bool> ipsEnable; 3171 std::optional<uint8_t> ipsEnterUtil; 3172 std::optional<uint64_t> ipsEnterTime; 3173 std::optional<uint8_t> ipsExitUtil; 3174 std::optional<uint64_t> ipsExitTime; 3175 3176 // clang-format off 3177 if (!json_util::readJsonPatch( 3178 req, asyncResp->res, 3179 "IndicatorLED", indicatorLed, 3180 "LocationIndicatorActive", locationIndicatorActive, 3181 "AssetTag", assetTag, 3182 "PowerRestorePolicy", powerRestorePolicy, 3183 "PowerMode", powerMode, 3184 "HostWatchdogTimer/FunctionEnabled", wdtEnable, 3185 "HostWatchdogTimer/TimeoutAction", wdtTimeOutAction, 3186 "Boot/BootSourceOverrideTarget", bootSource, 3187 "Boot/BootSourceOverrideMode", bootType, 3188 "Boot/BootSourceOverrideEnabled", bootEnable, 3189 "Boot/AutomaticRetryConfig", bootAutomaticRetry, 3190 "Boot/AutomaticRetryAttempts", bootAutomaticRetryAttempts, 3191 "Boot/TrustedModuleRequiredToBoot", bootTrustedModuleRequired, 3192 "Boot/StopBootOnFault", stopBootOnFault, 3193 "IdlePowerSaver/Enabled", ipsEnable, 3194 "IdlePowerSaver/EnterUtilizationPercent", ipsEnterUtil, 3195 "IdlePowerSaver/EnterDwellTimeSeconds", ipsEnterTime, 3196 "IdlePowerSaver/ExitUtilizationPercent", ipsExitUtil, 3197 "IdlePowerSaver/ExitDwellTimeSeconds", ipsExitTime)) 3198 { 3199 return; 3200 } 3201 // clang-format on 3202 3203 asyncResp->res.result(boost::beast::http::status::no_content); 3204 3205 if (assetTag) 3206 { 3207 setAssetTag(asyncResp, *assetTag); 3208 } 3209 3210 if (wdtEnable || wdtTimeOutAction) 3211 { 3212 setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction); 3213 } 3214 3215 if (bootSource || bootType || bootEnable) 3216 { 3217 setBootProperties(asyncResp, bootSource, bootType, bootEnable); 3218 } 3219 if (bootAutomaticRetry) 3220 { 3221 setAutomaticRetry(asyncResp, *bootAutomaticRetry); 3222 } 3223 3224 if (bootAutomaticRetryAttempts) 3225 { 3226 setAutomaticRetryAttempts(asyncResp, 3227 bootAutomaticRetryAttempts.value()); 3228 } 3229 3230 if (bootTrustedModuleRequired) 3231 { 3232 setTrustedModuleRequiredToBoot(asyncResp, *bootTrustedModuleRequired); 3233 } 3234 3235 if (stopBootOnFault) 3236 { 3237 setStopBootOnFault(asyncResp, *stopBootOnFault); 3238 } 3239 3240 if (locationIndicatorActive) 3241 { 3242 setSystemLocationIndicatorActive(asyncResp, *locationIndicatorActive); 3243 } 3244 3245 // TODO (Gunnar): Remove IndicatorLED after enough time has 3246 // passed 3247 if (indicatorLed) 3248 { 3249 setIndicatorLedState(asyncResp, *indicatorLed); 3250 asyncResp->res.addHeader(boost::beast::http::field::warning, 3251 "299 - \"IndicatorLED is deprecated. Use " 3252 "LocationIndicatorActive instead.\""); 3253 } 3254 3255 if (powerRestorePolicy) 3256 { 3257 setPowerRestorePolicy(asyncResp, *powerRestorePolicy); 3258 } 3259 3260 if (powerMode) 3261 { 3262 setPowerMode(asyncResp, *powerMode); 3263 } 3264 3265 if (ipsEnable || ipsEnterUtil || ipsEnterTime || ipsExitUtil || ipsExitTime) 3266 { 3267 setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime, 3268 ipsExitUtil, ipsExitTime); 3269 } 3270 } 3271 3272 inline void handleSystemCollectionResetActionHead( 3273 crow::App& app, const crow::Request& req, 3274 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3275 const std::string& /*systemName*/) 3276 { 3277 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3278 { 3279 return; 3280 } 3281 asyncResp->res.addHeader( 3282 boost::beast::http::field::link, 3283 "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby"); 3284 } 3285 3286 /** 3287 * @brief Translates allowed host transitions to redfish string 3288 * 3289 * @param[in] dbusAllowedHostTran The allowed host transition on dbus 3290 * @param[out] allowableValues The translated host transition(s) 3291 * 3292 * @return Emplaces correpsonding Redfish translated value(s) in 3293 * allowableValues. If translation not possible, does nothing to 3294 * allowableValues. 3295 */ 3296 inline void 3297 dbusToRfAllowedHostTransitions(const std::string& dbusAllowedHostTran, 3298 nlohmann::json::array_t& allowableValues) 3299 { 3300 if (dbusAllowedHostTran == "xyz.openbmc_project.State.Host.Transition.On") 3301 { 3302 allowableValues.emplace_back(resource::ResetType::On); 3303 allowableValues.emplace_back(resource::ResetType::ForceOn); 3304 } 3305 else if (dbusAllowedHostTran == 3306 "xyz.openbmc_project.State.Host.Transition.Off") 3307 { 3308 allowableValues.emplace_back(resource::ResetType::GracefulShutdown); 3309 } 3310 else if (dbusAllowedHostTran == 3311 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot") 3312 { 3313 allowableValues.emplace_back(resource::ResetType::GracefulRestart); 3314 } 3315 else if (dbusAllowedHostTran == 3316 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot") 3317 { 3318 allowableValues.emplace_back(resource::ResetType::ForceRestart); 3319 } 3320 else 3321 { 3322 BMCWEB_LOG_WARNING("Unsupported host tran {}", dbusAllowedHostTran); 3323 } 3324 } 3325 3326 inline void afterGetAllowedHostTransitions( 3327 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3328 const boost::system::error_code& ec, 3329 const std::vector<std::string>& allowedHostTransitions) 3330 { 3331 nlohmann::json::array_t allowableValues; 3332 3333 // Supported on all systems currently 3334 allowableValues.emplace_back(resource::ResetType::ForceOff); 3335 allowableValues.emplace_back(resource::ResetType::PowerCycle); 3336 allowableValues.emplace_back(resource::ResetType::Nmi); 3337 3338 if (ec) 3339 { 3340 if ((ec.value() == 3341 boost::system::linux_error::bad_request_descriptor) || 3342 (ec.value() == boost::asio::error::basic_errors::host_unreachable)) 3343 { 3344 // Property not implemented so just return defaults 3345 BMCWEB_LOG_DEBUG("Property not available {}", ec); 3346 allowableValues.emplace_back(resource::ResetType::On); 3347 allowableValues.emplace_back(resource::ResetType::ForceOn); 3348 allowableValues.emplace_back(resource::ResetType::ForceRestart); 3349 allowableValues.emplace_back(resource::ResetType::GracefulRestart); 3350 allowableValues.emplace_back(resource::ResetType::GracefulShutdown); 3351 } 3352 else 3353 { 3354 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 3355 messages::internalError(asyncResp->res); 3356 return; 3357 } 3358 } 3359 else 3360 { 3361 for (const std::string& transition : allowedHostTransitions) 3362 { 3363 BMCWEB_LOG_DEBUG("Found allowed host tran {}", transition); 3364 dbusToRfAllowedHostTransitions(transition, allowableValues); 3365 } 3366 } 3367 3368 nlohmann::json::object_t parameter; 3369 parameter["Name"] = "ResetType"; 3370 parameter["Required"] = true; 3371 parameter["DataType"] = "String"; 3372 parameter["AllowableValues"] = std::move(allowableValues); 3373 nlohmann::json::array_t parameters; 3374 parameters.emplace_back(std::move(parameter)); 3375 asyncResp->res.jsonValue["Parameters"] = std::move(parameters); 3376 } 3377 3378 inline void handleSystemCollectionResetActionGet( 3379 crow::App& app, const crow::Request& req, 3380 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3381 const std::string& systemName) 3382 { 3383 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3384 { 3385 return; 3386 } 3387 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 3388 { 3389 // Option currently returns no systems. TBD 3390 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3391 systemName); 3392 return; 3393 } 3394 3395 if (systemName == "hypervisor") 3396 { 3397 handleHypervisorResetActionGet(asyncResp); 3398 return; 3399 } 3400 3401 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 3402 { 3403 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3404 systemName); 3405 return; 3406 } 3407 3408 asyncResp->res.addHeader( 3409 boost::beast::http::field::link, 3410 "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby"); 3411 3412 asyncResp->res.jsonValue["@odata.id"] = 3413 boost::urls::format("/redfish/v1/Systems/{}/ResetActionInfo", 3414 BMCWEB_REDFISH_SYSTEM_URI_NAME); 3415 asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo"; 3416 asyncResp->res.jsonValue["Name"] = "Reset Action Info"; 3417 asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; 3418 3419 // Look to see if system defines AllowedHostTransitions 3420 sdbusplus::asio::getProperty<std::vector<std::string>>( 3421 *crow::connections::systemBus, "xyz.openbmc_project.State.Host", 3422 "/xyz/openbmc_project/state/host0", "xyz.openbmc_project.State.Host", 3423 "AllowedHostTransitions", 3424 [asyncResp](const boost::system::error_code& ec, 3425 const std::vector<std::string>& allowedHostTransitions) { 3426 afterGetAllowedHostTransitions(asyncResp, ec, allowedHostTransitions); 3427 }); 3428 } 3429 /** 3430 * SystemResetActionInfo derived class for delivering Computer Systems 3431 * ResetType AllowableValues using ResetInfo schema. 3432 */ 3433 inline void requestRoutesSystems(App& app) 3434 { 3435 BMCWEB_ROUTE(app, "/redfish/v1/Systems/") 3436 .privileges(redfish::privileges::headComputerSystemCollection) 3437 .methods(boost::beast::http::verb::head)( 3438 std::bind_front(handleComputerSystemCollectionHead, std::ref(app))); 3439 3440 BMCWEB_ROUTE(app, "/redfish/v1/Systems/") 3441 .privileges(redfish::privileges::getComputerSystemCollection) 3442 .methods(boost::beast::http::verb::get)( 3443 std::bind_front(handleComputerSystemCollectionGet, std::ref(app))); 3444 3445 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/") 3446 .privileges(redfish::privileges::headComputerSystem) 3447 .methods(boost::beast::http::verb::head)( 3448 std::bind_front(handleComputerSystemHead, std::ref(app))); 3449 3450 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/") 3451 .privileges(redfish::privileges::getComputerSystem) 3452 .methods(boost::beast::http::verb::get)( 3453 std::bind_front(handleComputerSystemGet, std::ref(app))); 3454 3455 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/") 3456 .privileges(redfish::privileges::patchComputerSystem) 3457 .methods(boost::beast::http::verb::patch)( 3458 std::bind_front(handleComputerSystemPatch, std::ref(app))); 3459 3460 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Actions/ComputerSystem.Reset/") 3461 .privileges(redfish::privileges::postComputerSystem) 3462 .methods(boost::beast::http::verb::post)(std::bind_front( 3463 handleComputerSystemResetActionPost, std::ref(app))); 3464 3465 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/ResetActionInfo/") 3466 .privileges(redfish::privileges::headActionInfo) 3467 .methods(boost::beast::http::verb::head)(std::bind_front( 3468 handleSystemCollectionResetActionHead, std::ref(app))); 3469 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/ResetActionInfo/") 3470 .privileges(redfish::privileges::getActionInfo) 3471 .methods(boost::beast::http::verb::get)(std::bind_front( 3472 handleSystemCollectionResetActionGet, std::ref(app))); 3473 } 3474 } // namespace redfish 3475