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