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