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