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 ec.value() != boost::asio::error::host_unreachable) 1186 { 1187 // Service not available, no error, just don't return 1188 // RebootAttempts information 1189 BMCWEB_LOG_ERROR("D-Bus responses error: {}", ec); 1190 messages::internalError(asyncResp->res); 1191 } 1192 return; 1193 } 1194 1195 const uint32_t* attemptsLeft = nullptr; 1196 const uint32_t* retryAttempts = nullptr; 1197 1198 const bool success = sdbusplus::unpackPropertiesNoThrow( 1199 dbus_utils::UnpackErrorPrinter(), propertiesList, 1200 "AttemptsLeft", attemptsLeft, "RetryAttempts", retryAttempts); 1201 1202 if (!success) 1203 { 1204 messages::internalError(asyncResp->res); 1205 return; 1206 } 1207 1208 if (attemptsLeft != nullptr) 1209 { 1210 asyncResp->res 1211 .jsonValue["Boot"]["RemainingAutomaticRetryAttempts"] = 1212 *attemptsLeft; 1213 } 1214 1215 if (retryAttempts != nullptr) 1216 { 1217 asyncResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 1218 *retryAttempts; 1219 } 1220 }); 1221 } 1222 1223 /** 1224 * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot. 1225 * 1226 * @param[in] asyncResp Shared pointer for generating response message. 1227 * 1228 * @return None. 1229 */ 1230 inline void getAutomaticRetryPolicy( 1231 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1232 { 1233 BMCWEB_LOG_DEBUG("Get Automatic Retry policy"); 1234 1235 dbus::utility::getProperty<bool>( 1236 "xyz.openbmc_project.Settings", 1237 "/xyz/openbmc_project/control/host0/auto_reboot", 1238 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", 1239 [asyncResp](const boost::system::error_code& ec, 1240 bool autoRebootEnabled) { 1241 if (ec) 1242 { 1243 // Service not available, no error, just don't return 1244 // AutoReboot information 1245 if (ec.value() != EBADR && 1246 ec.value() != boost::asio::error::host_unreachable) 1247 { 1248 BMCWEB_LOG_ERROR("D-Bus responses error: {}", ec); 1249 messages::internalError(asyncResp->res); 1250 } 1251 return; 1252 } 1253 1254 BMCWEB_LOG_DEBUG("Auto Reboot: {}", autoRebootEnabled); 1255 if (autoRebootEnabled) 1256 { 1257 asyncResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1258 "RetryAttempts"; 1259 } 1260 else 1261 { 1262 asyncResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1263 "Disabled"; 1264 } 1265 getAutomaticRebootAttempts(asyncResp); 1266 1267 // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways, 1268 // and RetryAttempts. OpenBMC only supports Disabled and 1269 // RetryAttempts. 1270 nlohmann::json::array_t allowed; 1271 allowed.emplace_back("Disabled"); 1272 allowed.emplace_back("RetryAttempts"); 1273 asyncResp->res 1274 .jsonValue["Boot"] 1275 ["AutomaticRetryConfig@Redfish.AllowableValues"] = 1276 std::move(allowed); 1277 }); 1278 } 1279 1280 /** 1281 * @brief Sets RetryAttempts 1282 * 1283 * @param[in] asyncResp Shared pointer for generating response message. 1284 * @param[in] retryAttempts "AutomaticRetryAttempts" from request. 1285 * 1286 *@return None. 1287 */ 1288 1289 inline void setAutomaticRetryAttempts( 1290 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1291 const uint32_t retryAttempts) 1292 { 1293 BMCWEB_LOG_DEBUG("Set Automatic Retry Attempts."); 1294 setDbusProperty( 1295 asyncResp, "Boot/AutomaticRetryAttempts", 1296 "xyz.openbmc_project.State.Host", 1297 sdbusplus::message::object_path("/xyz/openbmc_project/state/host0"), 1298 "xyz.openbmc_project.Control.Boot.RebootAttempts", "RetryAttempts", 1299 retryAttempts); 1300 } 1301 1302 inline computer_system::PowerRestorePolicyTypes 1303 redfishPowerRestorePolicyFromDbus(std::string_view value) 1304 { 1305 if (value == 1306 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn") 1307 { 1308 return computer_system::PowerRestorePolicyTypes::AlwaysOn; 1309 } 1310 if (value == 1311 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff") 1312 { 1313 return computer_system::PowerRestorePolicyTypes::AlwaysOff; 1314 } 1315 if (value == 1316 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore") 1317 { 1318 return computer_system::PowerRestorePolicyTypes::LastState; 1319 } 1320 if (value == "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.None") 1321 { 1322 return computer_system::PowerRestorePolicyTypes::AlwaysOff; 1323 } 1324 return computer_system::PowerRestorePolicyTypes::Invalid; 1325 } 1326 /** 1327 * @brief Retrieves power restore policy over DBUS. 1328 * 1329 * @param[in] asyncResp Shared pointer for generating response message. 1330 * 1331 * @return None. 1332 */ 1333 inline void getPowerRestorePolicy( 1334 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1335 { 1336 BMCWEB_LOG_DEBUG("Get power restore policy"); 1337 1338 dbus::utility::getProperty<std::string>( 1339 "xyz.openbmc_project.Settings", 1340 "/xyz/openbmc_project/control/host0/power_restore_policy", 1341 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1342 [asyncResp](const boost::system::error_code& ec, 1343 const std::string& policy) { 1344 if (ec) 1345 { 1346 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 1347 return; 1348 } 1349 computer_system::PowerRestorePolicyTypes restore = 1350 redfishPowerRestorePolicyFromDbus(policy); 1351 if (restore == computer_system::PowerRestorePolicyTypes::Invalid) 1352 { 1353 messages::internalError(asyncResp->res); 1354 return; 1355 } 1356 1357 asyncResp->res.jsonValue["PowerRestorePolicy"] = restore; 1358 }); 1359 } 1360 1361 /** 1362 * @brief Stop Boot On Fault over DBUS. 1363 * 1364 * @param[in] asyncResp Shared pointer for generating response message. 1365 * 1366 * @return None. 1367 */ 1368 inline void getStopBootOnFault( 1369 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1370 { 1371 BMCWEB_LOG_DEBUG("Get Stop Boot On Fault"); 1372 1373 dbus::utility::getProperty<bool>( 1374 "xyz.openbmc_project.Settings", "/xyz/openbmc_project/logging/settings", 1375 "xyz.openbmc_project.Logging.Settings", "QuiesceOnHwError", 1376 [asyncResp](const boost::system::error_code& ec, bool value) { 1377 if (ec) 1378 { 1379 // Service not available, no error, just don't return 1380 // StopBootOnFault information 1381 if (ec.value() != EBADR || 1382 ec.value() != boost::asio::error::host_unreachable) 1383 { 1384 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 1385 messages::internalError(asyncResp->res); 1386 } 1387 return; 1388 } 1389 1390 if (value) 1391 { 1392 asyncResp->res.jsonValue["Boot"]["StopBootOnFault"] = 1393 computer_system::StopBootOnFault::AnyFault; 1394 } 1395 else 1396 { 1397 asyncResp->res.jsonValue["Boot"]["StopBootOnFault"] = 1398 computer_system::StopBootOnFault::Never; 1399 } 1400 }); 1401 } 1402 1403 /** 1404 * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not 1405 * TPM is required for booting the host. 1406 * 1407 * @param[in] asyncResp Shared pointer for generating response message. 1408 * 1409 * @return None. 1410 */ 1411 inline void getTrustedModuleRequiredToBoot( 1412 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1413 { 1414 BMCWEB_LOG_DEBUG("Get TPM required to boot."); 1415 constexpr std::array<std::string_view, 1> interfaces = { 1416 "xyz.openbmc_project.Control.TPM.Policy"}; 1417 dbus::utility::getSubTree( 1418 "/", 0, interfaces, 1419 [asyncResp](const boost::system::error_code& ec, 1420 const dbus::utility::MapperGetSubTreeResponse& subtree) { 1421 if (ec) 1422 { 1423 BMCWEB_LOG_DEBUG( 1424 "DBUS response error on TPM.Policy GetSubTree{}", ec); 1425 // This is an optional D-Bus object so just return if 1426 // error occurs 1427 return; 1428 } 1429 if (subtree.empty()) 1430 { 1431 // As noted above, this is an optional interface so just return 1432 // if there is no instance found 1433 return; 1434 } 1435 1436 /* When there is more than one TPMEnable object... */ 1437 if (subtree.size() > 1) 1438 { 1439 BMCWEB_LOG_DEBUG( 1440 "DBUS response has more than 1 TPM Enable object:{}", 1441 subtree.size()); 1442 // Throw an internal Error and return 1443 messages::internalError(asyncResp->res); 1444 return; 1445 } 1446 1447 // Make sure the Dbus response map has a service and objectPath 1448 // field 1449 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1450 { 1451 BMCWEB_LOG_DEBUG("TPM.Policy mapper error!"); 1452 messages::internalError(asyncResp->res); 1453 return; 1454 } 1455 1456 const std::string& path = subtree[0].first; 1457 const std::string& serv = subtree[0].second.begin()->first; 1458 1459 // Valid TPM Enable object found, now reading the current value 1460 dbus::utility::getProperty<bool>( 1461 serv, path, "xyz.openbmc_project.Control.TPM.Policy", 1462 "TPMEnable", 1463 [asyncResp](const boost::system::error_code& ec2, 1464 bool tpmRequired) { 1465 if (ec2) 1466 { 1467 BMCWEB_LOG_ERROR( 1468 "D-BUS response error on TPM.Policy Get{}", ec2); 1469 messages::internalError(asyncResp->res); 1470 return; 1471 } 1472 1473 if (tpmRequired) 1474 { 1475 asyncResp->res 1476 .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = 1477 "Required"; 1478 } 1479 else 1480 { 1481 asyncResp->res 1482 .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = 1483 "Disabled"; 1484 } 1485 }); 1486 }); 1487 } 1488 1489 /** 1490 * @brief Set TrustedModuleRequiredToBoot property. Determines whether or not 1491 * TPM is required for booting the host. 1492 * 1493 * @param[in] asyncResp Shared pointer for generating response message. 1494 * @param[in] tpmRequired Value to set TPM Required To Boot property to. 1495 * 1496 * @return None. 1497 */ 1498 inline void setTrustedModuleRequiredToBoot( 1499 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const bool tpmRequired) 1500 { 1501 BMCWEB_LOG_DEBUG("Set TrustedModuleRequiredToBoot."); 1502 constexpr std::array<std::string_view, 1> interfaces = { 1503 "xyz.openbmc_project.Control.TPM.Policy"}; 1504 dbus::utility::getSubTree( 1505 "/", 0, interfaces, 1506 [asyncResp, 1507 tpmRequired](const boost::system::error_code& ec, 1508 const dbus::utility::MapperGetSubTreeResponse& subtree) { 1509 if (ec) 1510 { 1511 BMCWEB_LOG_ERROR( 1512 "DBUS response error on TPM.Policy GetSubTree{}", ec); 1513 messages::internalError(asyncResp->res); 1514 return; 1515 } 1516 if (subtree.empty()) 1517 { 1518 messages::propertyValueNotInList(asyncResp->res, 1519 "ComputerSystem", 1520 "TrustedModuleRequiredToBoot"); 1521 return; 1522 } 1523 1524 /* When there is more than one TPMEnable object... */ 1525 if (subtree.size() > 1) 1526 { 1527 BMCWEB_LOG_DEBUG( 1528 "DBUS response has more than 1 TPM Enable object:{}", 1529 subtree.size()); 1530 // Throw an internal Error and return 1531 messages::internalError(asyncResp->res); 1532 return; 1533 } 1534 1535 // Make sure the Dbus response map has a service and objectPath 1536 // field 1537 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1538 { 1539 BMCWEB_LOG_DEBUG("TPM.Policy mapper error!"); 1540 messages::internalError(asyncResp->res); 1541 return; 1542 } 1543 1544 const std::string& path = subtree[0].first; 1545 const std::string& serv = subtree[0].second.begin()->first; 1546 1547 if (serv.empty()) 1548 { 1549 BMCWEB_LOG_DEBUG("TPM.Policy service mapper error!"); 1550 messages::internalError(asyncResp->res); 1551 return; 1552 } 1553 1554 // Valid TPM Enable object found, now setting the value 1555 setDbusProperty(asyncResp, "Boot/TrustedModuleRequiredToBoot", serv, 1556 path, "xyz.openbmc_project.Control.TPM.Policy", 1557 "TPMEnable", tpmRequired); 1558 }); 1559 } 1560 1561 /** 1562 * @brief Sets boot properties into DBUS object(s). 1563 * 1564 * @param[in] asyncResp Shared pointer for generating response message. 1565 * @param[in] bootType The boot type to set. 1566 * @return Integer error code. 1567 */ 1568 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1569 const std::optional<std::string>& bootType) 1570 { 1571 std::string bootTypeStr; 1572 1573 if (!bootType) 1574 { 1575 return; 1576 } 1577 1578 // Source target specified 1579 BMCWEB_LOG_DEBUG("Boot type: {}", *bootType); 1580 // Figure out which DBUS interface and property to use 1581 if (*bootType == "Legacy") 1582 { 1583 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy"; 1584 } 1585 else if (*bootType == "UEFI") 1586 { 1587 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI"; 1588 } 1589 else 1590 { 1591 BMCWEB_LOG_DEBUG("Invalid property value for " 1592 "BootSourceOverrideMode: {}", 1593 *bootType); 1594 messages::propertyValueNotInList(asyncResp->res, *bootType, 1595 "BootSourceOverrideMode"); 1596 return; 1597 } 1598 1599 // Act on validated parameters 1600 BMCWEB_LOG_DEBUG("DBUS boot type: {}", bootTypeStr); 1601 1602 setDbusProperty(asyncResp, "Boot/BootSourceOverrideMode", 1603 "xyz.openbmc_project.Settings", 1604 sdbusplus::message::object_path( 1605 "/xyz/openbmc_project/control/host0/boot"), 1606 "xyz.openbmc_project.Control.Boot.Type", "BootType", 1607 bootTypeStr); 1608 } 1609 1610 /** 1611 * @brief Sets boot properties into DBUS object(s). 1612 * 1613 * @param[in] asyncResp Shared pointer for generating response 1614 * message. 1615 * @param[in] bootType The boot type to set. 1616 * @return Integer error code. 1617 */ 1618 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1619 const std::optional<std::string>& bootEnable) 1620 { 1621 if (!bootEnable) 1622 { 1623 return; 1624 } 1625 // Source target specified 1626 BMCWEB_LOG_DEBUG("Boot enable: {}", *bootEnable); 1627 1628 bool bootOverrideEnable = false; 1629 bool bootOverridePersistent = false; 1630 // Figure out which DBUS interface and property to use 1631 if (*bootEnable == "Disabled") 1632 { 1633 bootOverrideEnable = false; 1634 } 1635 else if (*bootEnable == "Once") 1636 { 1637 bootOverrideEnable = true; 1638 bootOverridePersistent = false; 1639 } 1640 else if (*bootEnable == "Continuous") 1641 { 1642 bootOverrideEnable = true; 1643 bootOverridePersistent = true; 1644 } 1645 else 1646 { 1647 BMCWEB_LOG_DEBUG( 1648 "Invalid property value for BootSourceOverrideEnabled: {}", 1649 *bootEnable); 1650 messages::propertyValueNotInList(asyncResp->res, *bootEnable, 1651 "BootSourceOverrideEnabled"); 1652 return; 1653 } 1654 1655 // Act on validated parameters 1656 BMCWEB_LOG_DEBUG("DBUS boot override enable: {}", bootOverrideEnable); 1657 1658 setDbusProperty(asyncResp, "Boot/BootSourceOverrideEnabled", 1659 "xyz.openbmc_project.Settings", 1660 sdbusplus::message::object_path( 1661 "/xyz/openbmc_project/control/host0/boot"), 1662 "xyz.openbmc_project.Object.Enable", "Enabled", 1663 bootOverrideEnable); 1664 1665 if (!bootOverrideEnable) 1666 { 1667 return; 1668 } 1669 1670 // In case boot override is enabled we need to set correct value for the 1671 // 'one_time' enable DBus interface 1672 BMCWEB_LOG_DEBUG("DBUS boot override persistent: {}", 1673 bootOverridePersistent); 1674 1675 setDbusProperty(asyncResp, "Boot/BootSourceOverrideEnabled", 1676 "xyz.openbmc_project.Settings", 1677 sdbusplus::message::object_path( 1678 "/xyz/openbmc_project/control/host0/boot/one_time"), 1679 "xyz.openbmc_project.Object.Enable", "Enabled", 1680 !bootOverridePersistent); 1681 } 1682 1683 /** 1684 * @brief Sets boot properties into DBUS object(s). 1685 * 1686 * @param[in] asyncResp Shared pointer for generating response message. 1687 * @param[in] bootSource The boot source to set. 1688 * 1689 * @return Integer error code. 1690 */ 1691 inline void setBootModeOrSource( 1692 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1693 const std::optional<std::string>& bootSource) 1694 { 1695 std::string bootSourceStr; 1696 std::string bootModeStr; 1697 1698 if (!bootSource) 1699 { 1700 return; 1701 } 1702 1703 // Source target specified 1704 BMCWEB_LOG_DEBUG("Boot source: {}", *bootSource); 1705 // Figure out which DBUS interface and property to use 1706 if (assignBootParameters(asyncResp, *bootSource, bootSourceStr, 1707 bootModeStr) != 0) 1708 { 1709 BMCWEB_LOG_DEBUG( 1710 "Invalid property value for BootSourceOverrideTarget: {}", 1711 *bootSource); 1712 messages::propertyValueNotInList(asyncResp->res, *bootSource, 1713 "BootSourceTargetOverride"); 1714 return; 1715 } 1716 1717 // Act on validated parameters 1718 BMCWEB_LOG_DEBUG("DBUS boot source: {}", bootSourceStr); 1719 BMCWEB_LOG_DEBUG("DBUS boot mode: {}", bootModeStr); 1720 1721 setDbusProperty(asyncResp, "Boot/BootSourceOverrideTarget", 1722 "xyz.openbmc_project.Settings", 1723 sdbusplus::message::object_path( 1724 "/xyz/openbmc_project/control/host0/boot"), 1725 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 1726 bootSourceStr); 1727 setDbusProperty(asyncResp, "Boot/BootSourceOverrideTarget", 1728 "xyz.openbmc_project.Settings", 1729 sdbusplus::message::object_path( 1730 "/xyz/openbmc_project/control/host0/boot"), 1731 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 1732 bootModeStr); 1733 } 1734 1735 /** 1736 * @brief Sets Boot source override properties. 1737 * 1738 * @param[in] asyncResp Shared pointer for generating response message. 1739 * @param[in] bootSource The boot source from incoming RF request. 1740 * @param[in] bootType The boot type from incoming RF request. 1741 * @param[in] bootEnable The boot override enable from incoming RF request. 1742 * 1743 * @return Integer error code. 1744 */ 1745 1746 inline void setBootProperties( 1747 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1748 const std::optional<std::string>& bootSource, 1749 const std::optional<std::string>& bootType, 1750 const std::optional<std::string>& bootEnable) 1751 { 1752 BMCWEB_LOG_DEBUG("Set boot information."); 1753 1754 setBootModeOrSource(asyncResp, bootSource); 1755 setBootType(asyncResp, bootType); 1756 setBootEnable(asyncResp, bootEnable); 1757 } 1758 1759 /** 1760 * @brief Sets AssetTag 1761 * 1762 * @param[in] asyncResp Shared pointer for generating response message. 1763 * @param[in] assetTag "AssetTag" from request. 1764 * 1765 * @return None. 1766 */ 1767 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1768 const std::string& assetTag) 1769 { 1770 constexpr std::array<std::string_view, 1> interfaces = { 1771 "xyz.openbmc_project.Inventory.Item.System"}; 1772 dbus::utility::getSubTree( 1773 "/xyz/openbmc_project/inventory", 0, interfaces, 1774 [asyncResp, 1775 assetTag](const boost::system::error_code& ec, 1776 const dbus::utility::MapperGetSubTreeResponse& subtree) { 1777 if (ec) 1778 { 1779 BMCWEB_LOG_DEBUG("D-Bus response error on GetSubTree {}", ec); 1780 messages::internalError(asyncResp->res); 1781 return; 1782 } 1783 if (subtree.empty()) 1784 { 1785 BMCWEB_LOG_DEBUG("Can't find system D-Bus object!"); 1786 messages::internalError(asyncResp->res); 1787 return; 1788 } 1789 // Assume only 1 system D-Bus object 1790 // Throw an error if there is more than 1 1791 if (subtree.size() > 1) 1792 { 1793 BMCWEB_LOG_DEBUG("Found more than 1 system D-Bus object!"); 1794 messages::internalError(asyncResp->res); 1795 return; 1796 } 1797 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1798 { 1799 BMCWEB_LOG_DEBUG("Asset Tag Set mapper error!"); 1800 messages::internalError(asyncResp->res); 1801 return; 1802 } 1803 1804 const std::string& path = subtree[0].first; 1805 const std::string& service = subtree[0].second.begin()->first; 1806 1807 if (service.empty()) 1808 { 1809 BMCWEB_LOG_DEBUG("Asset Tag Set service mapper error!"); 1810 messages::internalError(asyncResp->res); 1811 return; 1812 } 1813 1814 setDbusProperty(asyncResp, "AssetTag", service, path, 1815 "xyz.openbmc_project.Inventory.Decorator.AssetTag", 1816 "AssetTag", assetTag); 1817 }); 1818 } 1819 1820 /** 1821 * @brief Validate the specified stopBootOnFault is valid and return the 1822 * stopBootOnFault name associated with that string 1823 * 1824 * @param[in] stopBootOnFaultString String representing the desired 1825 * stopBootOnFault 1826 * 1827 * @return stopBootOnFault value or empty if incoming value is not valid 1828 */ 1829 inline std::optional<bool> validstopBootOnFault( 1830 const std::string& stopBootOnFaultString) 1831 { 1832 if (stopBootOnFaultString == "AnyFault") 1833 { 1834 return true; 1835 } 1836 1837 if (stopBootOnFaultString == "Never") 1838 { 1839 return false; 1840 } 1841 1842 return std::nullopt; 1843 } 1844 1845 /** 1846 * @brief Sets stopBootOnFault 1847 * 1848 * @param[in] asyncResp Shared pointer for generating response message. 1849 * @param[in] stopBootOnFault "StopBootOnFault" from request. 1850 * 1851 * @return None. 1852 */ 1853 inline void setStopBootOnFault( 1854 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1855 const std::string& stopBootOnFault) 1856 { 1857 BMCWEB_LOG_DEBUG("Set Stop Boot On Fault."); 1858 1859 std::optional<bool> stopBootEnabled = validstopBootOnFault(stopBootOnFault); 1860 if (!stopBootEnabled) 1861 { 1862 BMCWEB_LOG_DEBUG("Invalid property value for StopBootOnFault: {}", 1863 stopBootOnFault); 1864 messages::propertyValueNotInList(asyncResp->res, stopBootOnFault, 1865 "StopBootOnFault"); 1866 return; 1867 } 1868 1869 setDbusProperty(asyncResp, "Boot/StopBootOnFault", 1870 "xyz.openbmc_project.Settings", 1871 sdbusplus::message::object_path( 1872 "/xyz/openbmc_project/logging/settings"), 1873 "xyz.openbmc_project.Logging.Settings", "QuiesceOnHwError", 1874 *stopBootEnabled); 1875 } 1876 1877 /** 1878 * @brief Sets automaticRetry (Auto Reboot) 1879 * 1880 * @param[in] asyncResp Shared pointer for generating response message. 1881 * @param[in] automaticRetryConfig "AutomaticRetryConfig" from request. 1882 * 1883 * @return None. 1884 */ 1885 inline void setAutomaticRetry( 1886 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1887 const std::string& automaticRetryConfig) 1888 { 1889 BMCWEB_LOG_DEBUG("Set Automatic Retry."); 1890 1891 // OpenBMC only supports "Disabled" and "RetryAttempts". 1892 bool autoRebootEnabled = false; 1893 1894 if (automaticRetryConfig == "Disabled") 1895 { 1896 autoRebootEnabled = false; 1897 } 1898 else if (automaticRetryConfig == "RetryAttempts") 1899 { 1900 autoRebootEnabled = true; 1901 } 1902 else 1903 { 1904 BMCWEB_LOG_DEBUG("Invalid property value for AutomaticRetryConfig: {}", 1905 automaticRetryConfig); 1906 messages::propertyValueNotInList(asyncResp->res, automaticRetryConfig, 1907 "AutomaticRetryConfig"); 1908 return; 1909 } 1910 1911 setDbusProperty(asyncResp, "Boot/AutomaticRetryConfig", 1912 "xyz.openbmc_project.Settings", 1913 sdbusplus::message::object_path( 1914 "/xyz/openbmc_project/control/host0/auto_reboot"), 1915 "xyz.openbmc_project.Control.Boot.RebootPolicy", 1916 "AutoReboot", autoRebootEnabled); 1917 } 1918 1919 inline std::string dbusPowerRestorePolicyFromRedfish(std::string_view policy) 1920 { 1921 if (policy == "AlwaysOn") 1922 { 1923 return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn"; 1924 } 1925 if (policy == "AlwaysOff") 1926 { 1927 return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff"; 1928 } 1929 if (policy == "LastState") 1930 { 1931 return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore"; 1932 } 1933 return ""; 1934 } 1935 1936 /** 1937 * @brief Sets power restore policy properties. 1938 * 1939 * @param[in] asyncResp Shared pointer for generating response message. 1940 * @param[in] policy power restore policy properties from request. 1941 * 1942 * @return None. 1943 */ 1944 inline void setPowerRestorePolicy( 1945 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1946 std::string_view policy) 1947 { 1948 BMCWEB_LOG_DEBUG("Set power restore policy."); 1949 1950 std::string powerRestorePolicy = dbusPowerRestorePolicyFromRedfish(policy); 1951 1952 if (powerRestorePolicy.empty()) 1953 { 1954 messages::propertyValueNotInList(asyncResp->res, policy, 1955 "PowerRestorePolicy"); 1956 return; 1957 } 1958 1959 setDbusProperty( 1960 asyncResp, "PowerRestorePolicy", "xyz.openbmc_project.Settings", 1961 sdbusplus::message::object_path( 1962 "/xyz/openbmc_project/control/host0/power_restore_policy"), 1963 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1964 powerRestorePolicy); 1965 } 1966 1967 /** 1968 * @brief Retrieves provisioning status 1969 * 1970 * @param[in] asyncResp Shared pointer for completing asynchronous 1971 * calls. 1972 * 1973 * @return None. 1974 */ 1975 inline void getProvisioningStatus( 1976 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1977 { 1978 BMCWEB_LOG_DEBUG("Get OEM information."); 1979 dbus::utility::getAllProperties( 1980 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 1981 "xyz.openbmc_project.PFR.Attributes", 1982 [asyncResp](const boost::system::error_code& ec, 1983 const dbus::utility::DBusPropertiesMap& propertiesList) { 1984 nlohmann::json& oemPFR = 1985 asyncResp->res 1986 .jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 1987 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] = 1988 "#OpenBMCComputerSystem.v1_0_0.OpenBmc"; 1989 oemPFR["@odata.type"] = 1990 "#OpenBMCComputerSystem.FirmwareProvisioning"; 1991 1992 if (ec) 1993 { 1994 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 1995 // not an error, don't have to have the interface 1996 oemPFR["ProvisioningStatus"] = open_bmc_computer_system:: 1997 FirmwareProvisioningStatus::NotProvisioned; 1998 return; 1999 } 2000 2001 const bool* provState = nullptr; 2002 const bool* lockState = nullptr; 2003 2004 const bool success = sdbusplus::unpackPropertiesNoThrow( 2005 dbus_utils::UnpackErrorPrinter(), propertiesList, 2006 "UfmProvisioned", provState, "UfmLocked", lockState); 2007 2008 if (!success) 2009 { 2010 messages::internalError(asyncResp->res); 2011 return; 2012 } 2013 2014 if ((provState == nullptr) || (lockState == nullptr)) 2015 { 2016 BMCWEB_LOG_DEBUG("Unable to get PFR attributes."); 2017 messages::internalError(asyncResp->res); 2018 return; 2019 } 2020 2021 if (*provState) 2022 { 2023 if (*lockState) 2024 { 2025 oemPFR["ProvisioningStatus"] = open_bmc_computer_system:: 2026 FirmwareProvisioningStatus::ProvisionedAndLocked; 2027 } 2028 else 2029 { 2030 oemPFR["ProvisioningStatus"] = open_bmc_computer_system:: 2031 FirmwareProvisioningStatus::ProvisionedButNotLocked; 2032 } 2033 } 2034 else 2035 { 2036 oemPFR["ProvisioningStatus"] = open_bmc_computer_system:: 2037 FirmwareProvisioningStatus::NotProvisioned; 2038 } 2039 }); 2040 } 2041 2042 /** 2043 * @brief Translate the PowerMode string to enum value 2044 * 2045 * @param[in] modeString PowerMode string to be translated 2046 * 2047 * @return PowerMode enum 2048 */ 2049 inline computer_system::PowerMode translatePowerModeString( 2050 const std::string& modeString) 2051 { 2052 using PowerMode = computer_system::PowerMode; 2053 2054 if (modeString == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static") 2055 { 2056 return PowerMode::Static; 2057 } 2058 if (modeString == 2059 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance") 2060 { 2061 return PowerMode::MaximumPerformance; 2062 } 2063 if (modeString == 2064 "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving") 2065 { 2066 return PowerMode::PowerSaving; 2067 } 2068 if (modeString == 2069 "xyz.openbmc_project.Control.Power.Mode.PowerMode.BalancedPerformance") 2070 { 2071 return PowerMode::BalancedPerformance; 2072 } 2073 if (modeString == 2074 "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPerformance") 2075 { 2076 return PowerMode::EfficiencyFavorPerformance; 2077 } 2078 if (modeString == 2079 "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPower") 2080 { 2081 return PowerMode::EfficiencyFavorPower; 2082 } 2083 if (modeString == "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM") 2084 { 2085 return PowerMode::OEM; 2086 } 2087 // Any other values would be invalid 2088 BMCWEB_LOG_ERROR("PowerMode value was not valid: {}", modeString); 2089 return PowerMode::Invalid; 2090 } 2091 2092 inline void afterGetPowerMode( 2093 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2094 const boost::system::error_code& ec, 2095 const dbus::utility::DBusPropertiesMap& properties) 2096 { 2097 if (ec) 2098 { 2099 BMCWEB_LOG_ERROR("DBUS response error on PowerMode GetAll: {}", ec); 2100 messages::internalError(asyncResp->res); 2101 return; 2102 } 2103 2104 std::string powerMode; 2105 const std::vector<std::string>* allowedModes = nullptr; 2106 const bool success = sdbusplus::unpackPropertiesNoThrow( 2107 dbus_utils::UnpackErrorPrinter(), properties, "PowerMode", powerMode, 2108 "AllowedPowerModes", allowedModes); 2109 2110 if (!success) 2111 { 2112 messages::internalError(asyncResp->res); 2113 return; 2114 } 2115 2116 nlohmann::json::array_t modeList; 2117 if (allowedModes == nullptr) 2118 { 2119 modeList.emplace_back("Static"); 2120 modeList.emplace_back("MaximumPerformance"); 2121 modeList.emplace_back("PowerSaving"); 2122 } 2123 else 2124 { 2125 for (const auto& aMode : *allowedModes) 2126 { 2127 computer_system::PowerMode modeValue = 2128 translatePowerModeString(aMode); 2129 if (modeValue == computer_system::PowerMode::Invalid) 2130 { 2131 messages::internalError(asyncResp->res); 2132 continue; 2133 } 2134 modeList.emplace_back(modeValue); 2135 } 2136 } 2137 asyncResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = modeList; 2138 2139 BMCWEB_LOG_DEBUG("Current power mode: {}", powerMode); 2140 const computer_system::PowerMode modeValue = 2141 translatePowerModeString(powerMode); 2142 if (modeValue == computer_system::PowerMode::Invalid) 2143 { 2144 messages::internalError(asyncResp->res); 2145 return; 2146 } 2147 asyncResp->res.jsonValue["PowerMode"] = modeValue; 2148 } 2149 /** 2150 * @brief Retrieves system power mode 2151 * 2152 * @param[in] asyncResp Shared pointer for generating response message. 2153 * 2154 * @return None. 2155 */ 2156 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2157 { 2158 BMCWEB_LOG_DEBUG("Get power mode."); 2159 2160 // Get Power Mode object path: 2161 constexpr std::array<std::string_view, 1> interfaces = { 2162 "xyz.openbmc_project.Control.Power.Mode"}; 2163 dbus::utility::getSubTree( 2164 "/", 0, interfaces, 2165 [asyncResp](const boost::system::error_code& ec, 2166 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2167 if (ec) 2168 { 2169 BMCWEB_LOG_DEBUG( 2170 "DBUS response error on Power.Mode GetSubTree {}", ec); 2171 // This is an optional D-Bus object so just return if 2172 // error occurs 2173 return; 2174 } 2175 if (subtree.empty()) 2176 { 2177 // As noted above, this is an optional interface so just return 2178 // if there is no instance found 2179 return; 2180 } 2181 if (subtree.size() > 1) 2182 { 2183 // More then one PowerMode object is not supported and is an 2184 // error 2185 BMCWEB_LOG_DEBUG( 2186 "Found more than 1 system D-Bus Power.Mode objects: {}", 2187 subtree.size()); 2188 messages::internalError(asyncResp->res); 2189 return; 2190 } 2191 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2192 { 2193 BMCWEB_LOG_DEBUG("Power.Mode mapper error!"); 2194 messages::internalError(asyncResp->res); 2195 return; 2196 } 2197 const std::string& path = subtree[0].first; 2198 const std::string& service = subtree[0].second.begin()->first; 2199 if (service.empty()) 2200 { 2201 BMCWEB_LOG_DEBUG("Power.Mode service mapper error!"); 2202 messages::internalError(asyncResp->res); 2203 return; 2204 } 2205 2206 // Valid Power Mode object found, now read the mode properties 2207 dbus::utility::getAllProperties( 2208 *crow::connections::systemBus, service, path, 2209 "xyz.openbmc_project.Control.Power.Mode", 2210 [asyncResp]( 2211 const boost::system::error_code& ec2, 2212 const dbus::utility::DBusPropertiesMap& properties) { 2213 afterGetPowerMode(asyncResp, ec2, properties); 2214 }); 2215 }); 2216 } 2217 2218 /** 2219 * @brief Validate the specified mode is valid and return the PowerMode 2220 * name associated with that string 2221 * 2222 * @param[in] asyncResp Shared pointer for generating response message. 2223 * @param[in] modeValue String representing the desired PowerMode 2224 * 2225 * @return PowerMode value or empty string if mode is not valid 2226 */ 2227 inline std::string validatePowerMode( 2228 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2229 const nlohmann::json& modeValue) 2230 { 2231 using PowerMode = computer_system::PowerMode; 2232 std::string mode; 2233 2234 if (modeValue == PowerMode::Static) 2235 { 2236 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static"; 2237 } 2238 else if (modeValue == PowerMode::MaximumPerformance) 2239 { 2240 mode = 2241 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance"; 2242 } 2243 else if (modeValue == PowerMode::PowerSaving) 2244 { 2245 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving"; 2246 } 2247 else if (modeValue == PowerMode::BalancedPerformance) 2248 { 2249 mode = 2250 "xyz.openbmc_project.Control.Power.Mode.PowerMode.BalancedPerformance"; 2251 } 2252 else if (modeValue == PowerMode::EfficiencyFavorPerformance) 2253 { 2254 mode = 2255 "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPerformance"; 2256 } 2257 else if (modeValue == PowerMode::EfficiencyFavorPower) 2258 { 2259 mode = 2260 "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPower"; 2261 } 2262 else 2263 { 2264 messages::propertyValueNotInList(asyncResp->res, modeValue.dump(), 2265 "PowerMode"); 2266 } 2267 return mode; 2268 } 2269 2270 /** 2271 * @brief Sets system power mode. 2272 * 2273 * @param[in] asyncResp Shared pointer for generating response message. 2274 * @param[in] pmode System power mode from request. 2275 * 2276 * @return None. 2277 */ 2278 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2279 const std::string& pmode) 2280 { 2281 BMCWEB_LOG_DEBUG("Set power mode."); 2282 2283 std::string powerMode = validatePowerMode(asyncResp, pmode); 2284 if (powerMode.empty()) 2285 { 2286 return; 2287 } 2288 2289 // Get Power Mode object path: 2290 constexpr std::array<std::string_view, 1> interfaces = { 2291 "xyz.openbmc_project.Control.Power.Mode"}; 2292 dbus::utility::getSubTree( 2293 "/", 0, interfaces, 2294 [asyncResp, 2295 powerMode](const boost::system::error_code& ec, 2296 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2297 if (ec) 2298 { 2299 BMCWEB_LOG_ERROR( 2300 "DBUS response error on Power.Mode GetSubTree {}", ec); 2301 // This is an optional D-Bus object, but user attempted to patch 2302 messages::internalError(asyncResp->res); 2303 return; 2304 } 2305 if (subtree.empty()) 2306 { 2307 // This is an optional D-Bus object, but user attempted to patch 2308 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 2309 "PowerMode"); 2310 return; 2311 } 2312 if (subtree.size() > 1) 2313 { 2314 // More then one PowerMode object is not supported and is an 2315 // error 2316 BMCWEB_LOG_DEBUG( 2317 "Found more than 1 system D-Bus Power.Mode objects: {}", 2318 subtree.size()); 2319 messages::internalError(asyncResp->res); 2320 return; 2321 } 2322 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2323 { 2324 BMCWEB_LOG_DEBUG("Power.Mode mapper error!"); 2325 messages::internalError(asyncResp->res); 2326 return; 2327 } 2328 const std::string& path = subtree[0].first; 2329 const std::string& service = subtree[0].second.begin()->first; 2330 if (service.empty()) 2331 { 2332 BMCWEB_LOG_DEBUG("Power.Mode service mapper error!"); 2333 messages::internalError(asyncResp->res); 2334 return; 2335 } 2336 2337 BMCWEB_LOG_DEBUG("Setting power mode({}) -> {}", powerMode, path); 2338 2339 // Set the Power Mode property 2340 setDbusProperty(asyncResp, "PowerMode", service, path, 2341 "xyz.openbmc_project.Control.Power.Mode", 2342 "PowerMode", powerMode); 2343 }); 2344 } 2345 2346 /** 2347 * @brief Translates watchdog timeout action DBUS property value to redfish. 2348 * 2349 * @param[in] dbusAction The watchdog timeout action in D-BUS. 2350 * 2351 * @return Returns as a string, the timeout action in Redfish terms. If 2352 * translation cannot be done, returns an empty string. 2353 */ 2354 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction) 2355 { 2356 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 2357 { 2358 return "None"; 2359 } 2360 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset") 2361 { 2362 return "ResetSystem"; 2363 } 2364 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 2365 { 2366 return "PowerDown"; 2367 } 2368 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 2369 { 2370 return "PowerCycle"; 2371 } 2372 2373 return ""; 2374 } 2375 2376 /** 2377 *@brief Translates timeout action from Redfish to DBUS property value. 2378 * 2379 *@param[in] rfAction The timeout action in Redfish. 2380 * 2381 *@return Returns as a string, the time_out action as expected by DBUS. 2382 *If translation cannot be done, returns an empty string. 2383 */ 2384 2385 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 2386 { 2387 if (rfAction == "None") 2388 { 2389 return "xyz.openbmc_project.State.Watchdog.Action.None"; 2390 } 2391 if (rfAction == "PowerCycle") 2392 { 2393 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 2394 } 2395 if (rfAction == "PowerDown") 2396 { 2397 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 2398 } 2399 if (rfAction == "ResetSystem") 2400 { 2401 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 2402 } 2403 2404 return ""; 2405 } 2406 2407 /** 2408 * @brief Retrieves host watchdog timer properties over DBUS 2409 * 2410 * @param[in] asyncResp Shared pointer for completing asynchronous calls. 2411 * 2412 * @return None. 2413 */ 2414 inline void getHostWatchdogTimer( 2415 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2416 { 2417 BMCWEB_LOG_DEBUG("Get host watchodg"); 2418 dbus::utility::getAllProperties( 2419 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 2420 "xyz.openbmc_project.State.Watchdog", 2421 [asyncResp](const boost::system::error_code& ec, 2422 const dbus::utility::DBusPropertiesMap& properties) { 2423 if (ec) 2424 { 2425 // watchdog service is stopped 2426 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 2427 return; 2428 } 2429 2430 BMCWEB_LOG_DEBUG("Got {} wdt prop.", properties.size()); 2431 2432 nlohmann::json& hostWatchdogTimer = 2433 asyncResp->res.jsonValue["HostWatchdogTimer"]; 2434 2435 // watchdog service is running/enabled 2436 hostWatchdogTimer["Status"]["State"] = resource::State::Enabled; 2437 2438 const bool* enabled = nullptr; 2439 const std::string* expireAction = nullptr; 2440 2441 const bool success = sdbusplus::unpackPropertiesNoThrow( 2442 dbus_utils::UnpackErrorPrinter(), properties, "Enabled", 2443 enabled, "ExpireAction", expireAction); 2444 2445 if (!success) 2446 { 2447 messages::internalError(asyncResp->res); 2448 return; 2449 } 2450 2451 if (enabled != nullptr) 2452 { 2453 hostWatchdogTimer["FunctionEnabled"] = *enabled; 2454 } 2455 2456 if (expireAction != nullptr) 2457 { 2458 std::string action = dbusToRfWatchdogAction(*expireAction); 2459 if (action.empty()) 2460 { 2461 messages::internalError(asyncResp->res); 2462 return; 2463 } 2464 hostWatchdogTimer["TimeoutAction"] = action; 2465 } 2466 }); 2467 } 2468 2469 /** 2470 * @brief Sets Host WatchDog Timer properties. 2471 * 2472 * @param[in] asyncResp Shared pointer for generating response message. 2473 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 2474 * RF request. 2475 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 2476 * 2477 * @return None. 2478 */ 2479 inline void setWDTProperties( 2480 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2481 const std::optional<bool> wdtEnable, 2482 const std::optional<std::string>& wdtTimeOutAction) 2483 { 2484 BMCWEB_LOG_DEBUG("Set host watchdog"); 2485 2486 if (wdtTimeOutAction) 2487 { 2488 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 2489 // check if TimeOut Action is Valid 2490 if (wdtTimeOutActStr.empty()) 2491 { 2492 BMCWEB_LOG_DEBUG("Unsupported value for TimeoutAction: {}", 2493 *wdtTimeOutAction); 2494 messages::propertyValueNotInList(asyncResp->res, *wdtTimeOutAction, 2495 "TimeoutAction"); 2496 return; 2497 } 2498 2499 setDbusProperty(asyncResp, "HostWatchdogTimer/TimeoutAction", 2500 "xyz.openbmc_project.Watchdog", 2501 sdbusplus::message::object_path( 2502 "/xyz/openbmc_project/watchdog/host0"), 2503 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 2504 wdtTimeOutActStr); 2505 } 2506 2507 if (wdtEnable) 2508 { 2509 setDbusProperty(asyncResp, "HostWatchdogTimer/FunctionEnabled", 2510 "xyz.openbmc_project.Watchdog", 2511 sdbusplus::message::object_path( 2512 "/xyz/openbmc_project/watchdog/host0"), 2513 "xyz.openbmc_project.State.Watchdog", "Enabled", 2514 *wdtEnable); 2515 } 2516 } 2517 2518 /** 2519 * @brief Parse the Idle Power Saver properties into json 2520 * 2521 * @param[in] asyncResp Shared pointer for completing asynchronous calls. 2522 * @param[in] properties IPS property data from DBus. 2523 * 2524 * @return true if successful 2525 */ 2526 inline bool parseIpsProperties( 2527 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2528 const dbus::utility::DBusPropertiesMap& properties) 2529 { 2530 const bool* enabled = nullptr; 2531 const uint8_t* enterUtilizationPercent = nullptr; 2532 const uint64_t* enterDwellTime = nullptr; 2533 const uint8_t* exitUtilizationPercent = nullptr; 2534 const uint64_t* exitDwellTime = nullptr; 2535 2536 const bool success = sdbusplus::unpackPropertiesNoThrow( 2537 dbus_utils::UnpackErrorPrinter(), properties, "Enabled", enabled, 2538 "EnterUtilizationPercent", enterUtilizationPercent, "EnterDwellTime", 2539 enterDwellTime, "ExitUtilizationPercent", exitUtilizationPercent, 2540 "ExitDwellTime", exitDwellTime); 2541 2542 if (!success) 2543 { 2544 return false; 2545 } 2546 2547 if (enabled != nullptr) 2548 { 2549 asyncResp->res.jsonValue["IdlePowerSaver"]["Enabled"] = *enabled; 2550 } 2551 2552 if (enterUtilizationPercent != nullptr) 2553 { 2554 asyncResp->res.jsonValue["IdlePowerSaver"]["EnterUtilizationPercent"] = 2555 *enterUtilizationPercent; 2556 } 2557 2558 if (enterDwellTime != nullptr) 2559 { 2560 const std::chrono::duration<uint64_t, std::milli> ms(*enterDwellTime); 2561 asyncResp->res.jsonValue["IdlePowerSaver"]["EnterDwellTimeSeconds"] = 2562 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) 2563 .count(); 2564 } 2565 2566 if (exitUtilizationPercent != nullptr) 2567 { 2568 asyncResp->res.jsonValue["IdlePowerSaver"]["ExitUtilizationPercent"] = 2569 *exitUtilizationPercent; 2570 } 2571 2572 if (exitDwellTime != nullptr) 2573 { 2574 const std::chrono::duration<uint64_t, std::milli> ms(*exitDwellTime); 2575 asyncResp->res.jsonValue["IdlePowerSaver"]["ExitDwellTimeSeconds"] = 2576 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) 2577 .count(); 2578 } 2579 2580 return true; 2581 } 2582 2583 /** 2584 * @brief Retrieves host watchdog timer properties over DBUS 2585 * 2586 * @param[in] asyncResp Shared pointer for completing asynchronous calls. 2587 * 2588 * @return None. 2589 */ 2590 inline void getIdlePowerSaver( 2591 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2592 { 2593 BMCWEB_LOG_DEBUG("Get idle power saver parameters"); 2594 2595 // Get IdlePowerSaver object path: 2596 constexpr std::array<std::string_view, 1> interfaces = { 2597 "xyz.openbmc_project.Control.Power.IdlePowerSaver"}; 2598 dbus::utility::getSubTree( 2599 "/", 0, interfaces, 2600 [asyncResp](const boost::system::error_code& ec, 2601 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2602 if (ec) 2603 { 2604 BMCWEB_LOG_ERROR( 2605 "DBUS response error on Power.IdlePowerSaver GetSubTree {}", 2606 ec); 2607 messages::internalError(asyncResp->res); 2608 return; 2609 } 2610 if (subtree.empty()) 2611 { 2612 // This is an optional interface so just return 2613 // if there is no instance found 2614 BMCWEB_LOG_DEBUG("No instances found"); 2615 return; 2616 } 2617 if (subtree.size() > 1) 2618 { 2619 // More then one PowerIdlePowerSaver object is not supported and 2620 // is an error 2621 BMCWEB_LOG_DEBUG("Found more than 1 system D-Bus " 2622 "Power.IdlePowerSaver objects: {}", 2623 subtree.size()); 2624 messages::internalError(asyncResp->res); 2625 return; 2626 } 2627 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2628 { 2629 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver mapper error!"); 2630 messages::internalError(asyncResp->res); 2631 return; 2632 } 2633 const std::string& path = subtree[0].first; 2634 const std::string& service = subtree[0].second.begin()->first; 2635 if (service.empty()) 2636 { 2637 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver service mapper error!"); 2638 messages::internalError(asyncResp->res); 2639 return; 2640 } 2641 2642 // Valid IdlePowerSaver object found, now read the current values 2643 dbus::utility::getAllProperties( 2644 *crow::connections::systemBus, service, path, 2645 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2646 [asyncResp]( 2647 const boost::system::error_code& ec2, 2648 const dbus::utility::DBusPropertiesMap& properties) { 2649 if (ec2) 2650 { 2651 BMCWEB_LOG_ERROR( 2652 "DBUS response error on IdlePowerSaver GetAll: {}", 2653 ec2); 2654 messages::internalError(asyncResp->res); 2655 return; 2656 } 2657 2658 if (!parseIpsProperties(asyncResp, properties)) 2659 { 2660 messages::internalError(asyncResp->res); 2661 return; 2662 } 2663 }); 2664 }); 2665 2666 BMCWEB_LOG_DEBUG("EXIT: Get idle power saver parameters"); 2667 } 2668 2669 /** 2670 * @brief Sets Idle Power Saver properties. 2671 * 2672 * @param[in] asyncResp Shared pointer for generating response message. 2673 * @param[in] ipsEnable The IPS Enable value (true/false) from incoming 2674 * RF request. 2675 * @param[in] ipsEnterUtil The utilization limit to enter idle state. 2676 * @param[in] ipsEnterTime The time the utilization must be below ipsEnterUtil 2677 * before entering idle state. 2678 * @param[in] ipsExitUtil The utilization limit when exiting idle state. 2679 * @param[in] ipsExitTime The time the utilization must be above ipsExutUtil 2680 * before exiting idle state 2681 * 2682 * @return None. 2683 */ 2684 inline void setIdlePowerSaver( 2685 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2686 const std::optional<bool> ipsEnable, 2687 const std::optional<uint8_t> ipsEnterUtil, 2688 const std::optional<uint64_t> ipsEnterTime, 2689 const std::optional<uint8_t> ipsExitUtil, 2690 const std::optional<uint64_t> ipsExitTime) 2691 { 2692 BMCWEB_LOG_DEBUG("Set idle power saver properties"); 2693 2694 // Get IdlePowerSaver object path: 2695 constexpr std::array<std::string_view, 1> interfaces = { 2696 "xyz.openbmc_project.Control.Power.IdlePowerSaver"}; 2697 dbus::utility::getSubTree( 2698 "/", 0, interfaces, 2699 [asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime, ipsExitUtil, 2700 ipsExitTime](const boost::system::error_code& ec, 2701 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2702 if (ec) 2703 { 2704 BMCWEB_LOG_ERROR( 2705 "DBUS response error on Power.IdlePowerSaver GetSubTree {}", 2706 ec); 2707 messages::internalError(asyncResp->res); 2708 return; 2709 } 2710 if (subtree.empty()) 2711 { 2712 // This is an optional D-Bus object, but user attempted to patch 2713 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 2714 "IdlePowerSaver"); 2715 return; 2716 } 2717 if (subtree.size() > 1) 2718 { 2719 // More then one PowerIdlePowerSaver object is not supported and 2720 // is an error 2721 BMCWEB_LOG_DEBUG( 2722 "Found more than 1 system D-Bus Power.IdlePowerSaver objects: {}", 2723 subtree.size()); 2724 messages::internalError(asyncResp->res); 2725 return; 2726 } 2727 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2728 { 2729 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver mapper error!"); 2730 messages::internalError(asyncResp->res); 2731 return; 2732 } 2733 const std::string& path = subtree[0].first; 2734 const std::string& service = subtree[0].second.begin()->first; 2735 if (service.empty()) 2736 { 2737 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver service mapper error!"); 2738 messages::internalError(asyncResp->res); 2739 return; 2740 } 2741 2742 // Valid Power IdlePowerSaver object found, now set any values that 2743 // need to be updated 2744 2745 if (ipsEnable) 2746 { 2747 setDbusProperty( 2748 asyncResp, "IdlePowerSaver/Enabled", service, path, 2749 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2750 "Enabled", *ipsEnable); 2751 } 2752 if (ipsEnterUtil) 2753 { 2754 setDbusProperty( 2755 asyncResp, "IdlePowerSaver/EnterUtilizationPercent", 2756 service, path, 2757 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2758 "EnterUtilizationPercent", *ipsEnterUtil); 2759 } 2760 if (ipsEnterTime) 2761 { 2762 // Convert from seconds into milliseconds for DBus 2763 const uint64_t timeMilliseconds = *ipsEnterTime * 1000; 2764 setDbusProperty( 2765 asyncResp, "IdlePowerSaver/EnterDwellTimeSeconds", service, 2766 path, "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2767 "EnterDwellTime", timeMilliseconds); 2768 } 2769 if (ipsExitUtil) 2770 { 2771 setDbusProperty( 2772 asyncResp, "IdlePowerSaver/ExitUtilizationPercent", service, 2773 path, "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2774 "ExitUtilizationPercent", *ipsExitUtil); 2775 } 2776 if (ipsExitTime) 2777 { 2778 // Convert from seconds into milliseconds for DBus 2779 const uint64_t timeMilliseconds = *ipsExitTime * 1000; 2780 setDbusProperty( 2781 asyncResp, "IdlePowerSaver/ExitDwellTimeSeconds", service, 2782 path, "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2783 "ExitDwellTime", timeMilliseconds); 2784 } 2785 }); 2786 2787 BMCWEB_LOG_DEBUG("EXIT: Set idle power saver parameters"); 2788 } 2789 2790 inline void handleComputerSystemCollectionHead( 2791 crow::App& app, const crow::Request& req, 2792 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2793 { 2794 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2795 { 2796 return; 2797 } 2798 asyncResp->res.addHeader( 2799 boost::beast::http::field::link, 2800 "</redfish/v1/JsonSchemas/ComputerSystemCollection/ComputerSystemCollection.json>; rel=describedby"); 2801 } 2802 2803 inline void handleComputerSystemCollectionGet( 2804 crow::App& app, const crow::Request& req, 2805 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2806 { 2807 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2808 { 2809 return; 2810 } 2811 2812 asyncResp->res.addHeader( 2813 boost::beast::http::field::link, 2814 "</redfish/v1/JsonSchemas/ComputerSystemCollection.json>; rel=describedby"); 2815 asyncResp->res.jsonValue["@odata.type"] = 2816 "#ComputerSystemCollection.ComputerSystemCollection"; 2817 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 2818 asyncResp->res.jsonValue["Name"] = "Computer System Collection"; 2819 2820 getSystemCollectionMembers(asyncResp); 2821 } 2822 2823 /** 2824 * Function transceives data with dbus directly. 2825 */ 2826 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2827 { 2828 constexpr const char* serviceName = "xyz.openbmc_project.Control.Host.NMI"; 2829 constexpr const char* objectPath = "/xyz/openbmc_project/control/host0/nmi"; 2830 constexpr const char* interfaceName = 2831 "xyz.openbmc_project.Control.Host.NMI"; 2832 constexpr const char* method = "NMI"; 2833 2834 dbus::utility::async_method_call( 2835 asyncResp, 2836 [asyncResp](const boost::system::error_code& ec) { 2837 if (ec) 2838 { 2839 BMCWEB_LOG_ERROR(" Bad D-Bus request error: {}", ec); 2840 messages::internalError(asyncResp->res); 2841 return; 2842 } 2843 messages::success(asyncResp->res); 2844 }, 2845 serviceName, objectPath, interfaceName, method); 2846 } 2847 2848 inline void handleComputerSystemResetActionPost( 2849 crow::App& app, const crow::Request& req, 2850 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2851 const std::string& systemName) 2852 { 2853 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2854 { 2855 return; 2856 } 2857 2858 if constexpr (BMCWEB_HYPERVISOR_COMPUTER_SYSTEM) 2859 { 2860 if (systemName == "hypervisor") 2861 { 2862 handleHypervisorSystemResetPost(req, asyncResp); 2863 return; 2864 } 2865 } 2866 2867 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 2868 { 2869 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 2870 systemName); 2871 return; 2872 } 2873 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 2874 { 2875 // Option currently returns no systems. TBD 2876 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 2877 systemName); 2878 return; 2879 } 2880 std::string resetType; 2881 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType)) 2882 { 2883 return; 2884 } 2885 2886 // Get the command and host vs. chassis 2887 std::string command; 2888 bool hostCommand = true; 2889 if ((resetType == "On") || (resetType == "ForceOn")) 2890 { 2891 command = "xyz.openbmc_project.State.Host.Transition.On"; 2892 hostCommand = true; 2893 } 2894 else if (resetType == "ForceOff") 2895 { 2896 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 2897 hostCommand = false; 2898 } 2899 else if (resetType == "ForceRestart") 2900 { 2901 command = "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 2902 hostCommand = true; 2903 } 2904 else if (resetType == "GracefulShutdown") 2905 { 2906 command = "xyz.openbmc_project.State.Host.Transition.Off"; 2907 hostCommand = true; 2908 } 2909 else if (resetType == "GracefulRestart") 2910 { 2911 command = 2912 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot"; 2913 hostCommand = true; 2914 } 2915 else if (resetType == "PowerCycle") 2916 { 2917 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 2918 hostCommand = true; 2919 } 2920 else if (resetType == "Nmi") 2921 { 2922 doNMI(asyncResp); 2923 return; 2924 } 2925 else 2926 { 2927 messages::actionParameterUnknown(asyncResp->res, "Reset", resetType); 2928 return; 2929 } 2930 sdbusplus::message::object_path statePath("/xyz/openbmc_project/state"); 2931 2932 if (hostCommand) 2933 { 2934 setDbusProperty(asyncResp, "Reset", "xyz.openbmc_project.State.Host", 2935 statePath / "host0", "xyz.openbmc_project.State.Host", 2936 "RequestedHostTransition", command); 2937 } 2938 else 2939 { 2940 setDbusProperty(asyncResp, "Reset", "xyz.openbmc_project.State.Chassis", 2941 statePath / "chassis0", 2942 "xyz.openbmc_project.State.Chassis", 2943 "RequestedPowerTransition", command); 2944 } 2945 } 2946 2947 inline void handleComputerSystemHead( 2948 App& app, const crow::Request& req, 2949 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2950 const std::string& /*systemName*/) 2951 { 2952 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2953 { 2954 return; 2955 } 2956 2957 asyncResp->res.addHeader( 2958 boost::beast::http::field::link, 2959 "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby"); 2960 } 2961 2962 inline void afterPortRequest( 2963 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2964 const boost::system::error_code& ec, 2965 const std::vector<std::tuple<std::string, std::string, bool>>& socketData) 2966 { 2967 if (ec) 2968 { 2969 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 2970 messages::internalError(asyncResp->res); 2971 return; 2972 } 2973 for (const auto& data : socketData) 2974 { 2975 const std::string& socketPath = get<0>(data); 2976 const std::string& protocolName = get<1>(data); 2977 bool isProtocolEnabled = get<2>(data); 2978 nlohmann::json& dataJson = asyncResp->res.jsonValue["SerialConsole"]; 2979 dataJson[protocolName]["ServiceEnabled"] = isProtocolEnabled; 2980 // need to retrieve port number for 2981 // obmc-console-ssh service 2982 if (protocolName == "SSH") 2983 { 2984 getPortNumber(socketPath, [asyncResp, protocolName]( 2985 const boost::system::error_code& ec1, 2986 int portNumber) { 2987 if (ec1) 2988 { 2989 BMCWEB_LOG_ERROR("DBUS response error {}", ec1); 2990 messages::internalError(asyncResp->res); 2991 return; 2992 } 2993 nlohmann::json& dataJson1 = 2994 asyncResp->res.jsonValue["SerialConsole"]; 2995 dataJson1[protocolName]["Port"] = portNumber; 2996 }); 2997 } 2998 } 2999 } 3000 3001 inline void handleComputerSystemGet( 3002 crow::App& app, const crow::Request& req, 3003 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3004 const std::string& systemName) 3005 { 3006 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3007 { 3008 return; 3009 } 3010 3011 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 3012 { 3013 // Option currently returns no systems. TBD 3014 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3015 systemName); 3016 return; 3017 } 3018 3019 if constexpr (BMCWEB_HYPERVISOR_COMPUTER_SYSTEM) 3020 { 3021 if (systemName == "hypervisor") 3022 { 3023 handleHypervisorSystemGet(asyncResp); 3024 return; 3025 } 3026 } 3027 3028 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 3029 { 3030 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3031 systemName); 3032 return; 3033 } 3034 asyncResp->res.addHeader( 3035 boost::beast::http::field::link, 3036 "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby"); 3037 asyncResp->res.jsonValue["@odata.type"] = 3038 "#ComputerSystem.v1_22_0.ComputerSystem"; 3039 asyncResp->res.jsonValue["Name"] = BMCWEB_REDFISH_SYSTEM_URI_NAME; 3040 asyncResp->res.jsonValue["Id"] = BMCWEB_REDFISH_SYSTEM_URI_NAME; 3041 asyncResp->res.jsonValue["SystemType"] = 3042 computer_system::SystemType::Physical; 3043 asyncResp->res.jsonValue["Description"] = "Computer System"; 3044 asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0; 3045 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = 3046 double(0); 3047 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 3048 "/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME); 3049 3050 asyncResp->res.jsonValue["Processors"]["@odata.id"] = boost::urls::format( 3051 "/redfish/v1/Systems/{}/Processors", BMCWEB_REDFISH_SYSTEM_URI_NAME); 3052 asyncResp->res.jsonValue["Memory"]["@odata.id"] = boost::urls::format( 3053 "/redfish/v1/Systems/{}/Memory", BMCWEB_REDFISH_SYSTEM_URI_NAME); 3054 asyncResp->res.jsonValue["Storage"]["@odata.id"] = boost::urls::format( 3055 "/redfish/v1/Systems/{}/Storage", BMCWEB_REDFISH_SYSTEM_URI_NAME); 3056 asyncResp->res.jsonValue["FabricAdapters"]["@odata.id"] = 3057 boost::urls::format("/redfish/v1/Systems/{}/FabricAdapters", 3058 BMCWEB_REDFISH_SYSTEM_URI_NAME); 3059 3060 asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"]["target"] = 3061 boost::urls::format( 3062 "/redfish/v1/Systems/{}/Actions/ComputerSystem.Reset", 3063 BMCWEB_REDFISH_SYSTEM_URI_NAME); 3064 asyncResp->res 3065 .jsonValue["Actions"]["#ComputerSystem.Reset"]["@Redfish.ActionInfo"] = 3066 boost::urls::format("/redfish/v1/Systems/{}/ResetActionInfo", 3067 BMCWEB_REDFISH_SYSTEM_URI_NAME); 3068 3069 asyncResp->res.jsonValue["LogServices"]["@odata.id"] = boost::urls::format( 3070 "/redfish/v1/Systems/{}/LogServices", BMCWEB_REDFISH_SYSTEM_URI_NAME); 3071 asyncResp->res.jsonValue["Bios"]["@odata.id"] = boost::urls::format( 3072 "/redfish/v1/Systems/{}/Bios", BMCWEB_REDFISH_SYSTEM_URI_NAME); 3073 3074 nlohmann::json::array_t managedBy; 3075 nlohmann::json& manager = managedBy.emplace_back(); 3076 manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}", 3077 BMCWEB_REDFISH_MANAGER_URI_NAME); 3078 asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy); 3079 asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK; 3080 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 3081 3082 // Fill in SerialConsole info 3083 asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15; 3084 asyncResp->res.jsonValue["SerialConsole"]["IPMI"]["ServiceEnabled"] = true; 3085 3086 asyncResp->res.jsonValue["SerialConsole"]["SSH"]["ServiceEnabled"] = true; 3087 asyncResp->res.jsonValue["SerialConsole"]["SSH"]["Port"] = 2200; 3088 asyncResp->res.jsonValue["SerialConsole"]["SSH"]["HotKeySequenceDisplay"] = 3089 "Press ~. to exit console"; 3090 getPortStatusAndPath(std::span{protocolToDBusForSystems}, 3091 std::bind_front(afterPortRequest, asyncResp)); 3092 3093 if constexpr (BMCWEB_KVM) 3094 { 3095 // Fill in GraphicalConsole info 3096 asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true; 3097 asyncResp->res.jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = 3098 4; 3099 asyncResp->res.jsonValue["GraphicalConsole"]["ConnectTypesSupported"] = 3100 nlohmann::json::array_t({"KVMIP"}); 3101 } 3102 3103 getMainChassisId( 3104 asyncResp, [](const std::string& chassisId, 3105 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { 3106 nlohmann::json::array_t chassisArray; 3107 nlohmann::json& chassis = chassisArray.emplace_back(); 3108 chassis["@odata.id"] = 3109 boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 3110 aRsp->res.jsonValue["Links"]["Chassis"] = std::move(chassisArray); 3111 }); 3112 3113 getSystemLocationIndicatorActive(asyncResp); 3114 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 3115 getIndicatorLedState(asyncResp); 3116 getComputerSystem(asyncResp); 3117 getHostState(asyncResp); 3118 getBootProperties(asyncResp); 3119 getBootProgress(asyncResp); 3120 getBootProgressLastStateTime(asyncResp); 3121 pcie_util::getPCIeDeviceList(asyncResp, 3122 nlohmann::json::json_pointer("/PCIeDevices")); 3123 getHostWatchdogTimer(asyncResp); 3124 getPowerRestorePolicy(asyncResp); 3125 getStopBootOnFault(asyncResp); 3126 getAutomaticRetryPolicy(asyncResp); 3127 getLastResetTime(asyncResp); 3128 if constexpr (BMCWEB_REDFISH_PROVISIONING_FEATURE) 3129 { 3130 getProvisioningStatus(asyncResp); 3131 } 3132 getTrustedModuleRequiredToBoot(asyncResp); 3133 getPowerMode(asyncResp); 3134 getIdlePowerSaver(asyncResp); 3135 } 3136 3137 inline void handleComputerSystemPatch( 3138 crow::App& app, const crow::Request& req, 3139 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3140 const std::string& systemName) 3141 { 3142 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3143 { 3144 return; 3145 } 3146 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 3147 { 3148 // Option currently returns no systems. TBD 3149 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3150 systemName); 3151 return; 3152 } 3153 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 3154 { 3155 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3156 systemName); 3157 return; 3158 } 3159 3160 asyncResp->res.addHeader( 3161 boost::beast::http::field::link, 3162 "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby"); 3163 3164 std::optional<bool> locationIndicatorActive; 3165 std::optional<std::string> indicatorLed; 3166 std::optional<std::string> assetTag; 3167 std::optional<std::string> powerRestorePolicy; 3168 std::optional<std::string> powerMode; 3169 std::optional<bool> wdtEnable; 3170 std::optional<std::string> wdtTimeOutAction; 3171 std::optional<std::string> bootSource; 3172 std::optional<std::string> bootType; 3173 std::optional<std::string> bootEnable; 3174 std::optional<std::string> bootAutomaticRetry; 3175 std::optional<uint32_t> bootAutomaticRetryAttempts; 3176 std::optional<bool> bootTrustedModuleRequired; 3177 std::optional<std::string> stopBootOnFault; 3178 std::optional<bool> ipsEnable; 3179 std::optional<uint8_t> ipsEnterUtil; 3180 std::optional<uint64_t> ipsEnterTime; 3181 std::optional<uint8_t> ipsExitUtil; 3182 std::optional<uint64_t> ipsExitTime; 3183 3184 if (!json_util::readJsonPatch( // 3185 req, asyncResp->res, // 3186 "AssetTag", assetTag, // 3187 "Boot/AutomaticRetryAttempts", bootAutomaticRetryAttempts, // 3188 "Boot/AutomaticRetryConfig", bootAutomaticRetry, // 3189 "Boot/BootSourceOverrideEnabled", bootEnable, // 3190 "Boot/BootSourceOverrideMode", bootType, // 3191 "Boot/BootSourceOverrideTarget", bootSource, // 3192 "Boot/StopBootOnFault", stopBootOnFault, // 3193 "Boot/TrustedModuleRequiredToBoot", bootTrustedModuleRequired, // 3194 "HostWatchdogTimer/FunctionEnabled", wdtEnable, // 3195 "HostWatchdogTimer/TimeoutAction", wdtTimeOutAction, // 3196 "IdlePowerSaver/Enabled", ipsEnable, // 3197 "IdlePowerSaver/EnterDwellTimeSeconds", ipsEnterTime, // 3198 "IdlePowerSaver/EnterUtilizationPercent", ipsEnterUtil, // 3199 "IdlePowerSaver/ExitDwellTimeSeconds", ipsExitTime, // 3200 "IdlePowerSaver/ExitUtilizationPercent", ipsExitUtil, // 3201 "IndicatorLED", indicatorLed, // 3202 "LocationIndicatorActive", locationIndicatorActive, // 3203 "PowerMode", powerMode, // 3204 "PowerRestorePolicy", powerRestorePolicy // 3205 )) 3206 { 3207 return; 3208 } 3209 3210 asyncResp->res.result(boost::beast::http::status::no_content); 3211 3212 if (assetTag) 3213 { 3214 setAssetTag(asyncResp, *assetTag); 3215 } 3216 3217 if (wdtEnable || wdtTimeOutAction) 3218 { 3219 setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction); 3220 } 3221 3222 if (bootSource || bootType || bootEnable) 3223 { 3224 setBootProperties(asyncResp, bootSource, bootType, bootEnable); 3225 } 3226 if (bootAutomaticRetry) 3227 { 3228 setAutomaticRetry(asyncResp, *bootAutomaticRetry); 3229 } 3230 3231 if (bootAutomaticRetryAttempts) 3232 { 3233 setAutomaticRetryAttempts(asyncResp, 3234 bootAutomaticRetryAttempts.value()); 3235 } 3236 3237 if (bootTrustedModuleRequired) 3238 { 3239 setTrustedModuleRequiredToBoot(asyncResp, *bootTrustedModuleRequired); 3240 } 3241 3242 if (stopBootOnFault) 3243 { 3244 setStopBootOnFault(asyncResp, *stopBootOnFault); 3245 } 3246 3247 if (locationIndicatorActive) 3248 { 3249 setSystemLocationIndicatorActive(asyncResp, *locationIndicatorActive); 3250 } 3251 3252 // TODO (Gunnar): Remove IndicatorLED after enough time has 3253 // passed 3254 if (indicatorLed) 3255 { 3256 setIndicatorLedState(asyncResp, *indicatorLed); 3257 asyncResp->res.addHeader(boost::beast::http::field::warning, 3258 "299 - \"IndicatorLED is deprecated. Use " 3259 "LocationIndicatorActive instead.\""); 3260 } 3261 3262 if (powerRestorePolicy) 3263 { 3264 setPowerRestorePolicy(asyncResp, *powerRestorePolicy); 3265 } 3266 3267 if (powerMode) 3268 { 3269 setPowerMode(asyncResp, *powerMode); 3270 } 3271 3272 if (ipsEnable || ipsEnterUtil || ipsEnterTime || ipsExitUtil || ipsExitTime) 3273 { 3274 setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime, 3275 ipsExitUtil, ipsExitTime); 3276 } 3277 } 3278 3279 inline void handleSystemCollectionResetActionHead( 3280 crow::App& app, const crow::Request& req, 3281 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3282 const std::string& /*systemName*/) 3283 { 3284 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3285 { 3286 return; 3287 } 3288 asyncResp->res.addHeader( 3289 boost::beast::http::field::link, 3290 "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby"); 3291 } 3292 3293 /** 3294 * @brief Translates allowed host transitions to redfish string 3295 * 3296 * @param[in] dbusAllowedHostTran The allowed host transition on dbus 3297 * @param[out] allowableValues The translated host transition(s) 3298 * 3299 * @return Emplaces corresponding Redfish translated value(s) in 3300 * allowableValues. If translation not possible, does nothing to 3301 * allowableValues. 3302 */ 3303 inline void dbusToRfAllowedHostTransitions( 3304 const std::string& dbusAllowedHostTran, 3305 nlohmann::json::array_t& allowableValues) 3306 { 3307 if (dbusAllowedHostTran == "xyz.openbmc_project.State.Host.Transition.On") 3308 { 3309 allowableValues.emplace_back(resource::ResetType::On); 3310 allowableValues.emplace_back(resource::ResetType::ForceOn); 3311 } 3312 else if (dbusAllowedHostTran == 3313 "xyz.openbmc_project.State.Host.Transition.Off") 3314 { 3315 allowableValues.emplace_back(resource::ResetType::GracefulShutdown); 3316 } 3317 else if (dbusAllowedHostTran == 3318 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot") 3319 { 3320 allowableValues.emplace_back(resource::ResetType::GracefulRestart); 3321 } 3322 else if (dbusAllowedHostTran == 3323 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot") 3324 { 3325 allowableValues.emplace_back(resource::ResetType::ForceRestart); 3326 } 3327 else 3328 { 3329 BMCWEB_LOG_WARNING("Unsupported host tran {}", dbusAllowedHostTran); 3330 } 3331 } 3332 3333 inline void afterGetAllowedHostTransitions( 3334 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3335 const boost::system::error_code& ec, 3336 const std::vector<std::string>& allowedHostTransitions) 3337 { 3338 nlohmann::json::array_t allowableValues; 3339 3340 // Supported on all systems currently 3341 allowableValues.emplace_back(resource::ResetType::ForceOff); 3342 allowableValues.emplace_back(resource::ResetType::PowerCycle); 3343 allowableValues.emplace_back(resource::ResetType::Nmi); 3344 3345 if (ec) 3346 { 3347 if ((ec.value() == 3348 boost::system::linux_error::bad_request_descriptor) || 3349 (ec.value() == boost::asio::error::basic_errors::host_unreachable)) 3350 { 3351 // Property not implemented so just return defaults 3352 BMCWEB_LOG_DEBUG("Property not available {}", ec); 3353 allowableValues.emplace_back(resource::ResetType::On); 3354 allowableValues.emplace_back(resource::ResetType::ForceOn); 3355 allowableValues.emplace_back(resource::ResetType::ForceRestart); 3356 allowableValues.emplace_back(resource::ResetType::GracefulRestart); 3357 allowableValues.emplace_back(resource::ResetType::GracefulShutdown); 3358 } 3359 else 3360 { 3361 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 3362 messages::internalError(asyncResp->res); 3363 return; 3364 } 3365 } 3366 else 3367 { 3368 for (const std::string& transition : allowedHostTransitions) 3369 { 3370 BMCWEB_LOG_DEBUG("Found allowed host tran {}", transition); 3371 dbusToRfAllowedHostTransitions(transition, allowableValues); 3372 } 3373 } 3374 3375 nlohmann::json::object_t parameter; 3376 parameter["Name"] = "ResetType"; 3377 parameter["Required"] = true; 3378 parameter["DataType"] = action_info::ParameterTypes::String; 3379 parameter["AllowableValues"] = std::move(allowableValues); 3380 nlohmann::json::array_t parameters; 3381 parameters.emplace_back(std::move(parameter)); 3382 asyncResp->res.jsonValue["Parameters"] = std::move(parameters); 3383 } 3384 3385 inline void handleSystemCollectionResetActionGet( 3386 crow::App& app, const crow::Request& req, 3387 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3388 const std::string& systemName) 3389 { 3390 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3391 { 3392 return; 3393 } 3394 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 3395 { 3396 // Option currently returns no systems. TBD 3397 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3398 systemName); 3399 return; 3400 } 3401 3402 if constexpr (BMCWEB_HYPERVISOR_COMPUTER_SYSTEM) 3403 { 3404 if (systemName == "hypervisor") 3405 { 3406 handleHypervisorResetActionGet(asyncResp); 3407 return; 3408 } 3409 } 3410 3411 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 3412 { 3413 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3414 systemName); 3415 return; 3416 } 3417 3418 asyncResp->res.addHeader( 3419 boost::beast::http::field::link, 3420 "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby"); 3421 3422 asyncResp->res.jsonValue["@odata.id"] = 3423 boost::urls::format("/redfish/v1/Systems/{}/ResetActionInfo", 3424 BMCWEB_REDFISH_SYSTEM_URI_NAME); 3425 asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo"; 3426 asyncResp->res.jsonValue["Name"] = "Reset Action Info"; 3427 asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; 3428 3429 // Look to see if system defines AllowedHostTransitions 3430 dbus::utility::getProperty<std::vector<std::string>>( 3431 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 3432 "xyz.openbmc_project.State.Host", "AllowedHostTransitions", 3433 [asyncResp](const boost::system::error_code& ec, 3434 const std::vector<std::string>& allowedHostTransitions) { 3435 afterGetAllowedHostTransitions(asyncResp, ec, 3436 allowedHostTransitions); 3437 }); 3438 } 3439 /** 3440 * SystemResetActionInfo derived class for delivering Computer Systems 3441 * ResetType AllowableValues using ResetInfo schema. 3442 */ 3443 inline void requestRoutesSystems(App& app) 3444 { 3445 BMCWEB_ROUTE(app, "/redfish/v1/Systems/") 3446 .privileges(redfish::privileges::headComputerSystemCollection) 3447 .methods(boost::beast::http::verb::head)( 3448 std::bind_front(handleComputerSystemCollectionHead, std::ref(app))); 3449 3450 BMCWEB_ROUTE(app, "/redfish/v1/Systems/") 3451 .privileges(redfish::privileges::getComputerSystemCollection) 3452 .methods(boost::beast::http::verb::get)( 3453 std::bind_front(handleComputerSystemCollectionGet, std::ref(app))); 3454 3455 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/") 3456 .privileges(redfish::privileges::headComputerSystem) 3457 .methods(boost::beast::http::verb::head)( 3458 std::bind_front(handleComputerSystemHead, std::ref(app))); 3459 3460 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/") 3461 .privileges(redfish::privileges::getComputerSystem) 3462 .methods(boost::beast::http::verb::get)( 3463 std::bind_front(handleComputerSystemGet, std::ref(app))); 3464 3465 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/") 3466 .privileges(redfish::privileges::patchComputerSystem) 3467 .methods(boost::beast::http::verb::patch)( 3468 std::bind_front(handleComputerSystemPatch, std::ref(app))); 3469 3470 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Actions/ComputerSystem.Reset/") 3471 .privileges(redfish::privileges::postComputerSystem) 3472 .methods(boost::beast::http::verb::post)(std::bind_front( 3473 handleComputerSystemResetActionPost, std::ref(app))); 3474 3475 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/ResetActionInfo/") 3476 .privileges(redfish::privileges::headActionInfo) 3477 .methods(boost::beast::http::verb::head)(std::bind_front( 3478 handleSystemCollectionResetActionHead, std::ref(app))); 3479 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/ResetActionInfo/") 3480 .privileges(redfish::privileges::getActionInfo) 3481 .methods(boost::beast::http::verb::get)(std::bind_front( 3482 handleSystemCollectionResetActionGet, std::ref(app))); 3483 } 3484 } // namespace redfish 3485