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