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