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