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