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