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