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