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