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