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 "health.hpp" 19 #include "led.hpp" 20 #include "pcie.hpp" 21 #include "redfish_util.hpp" 22 23 #include <boost/container/flat_map.hpp> 24 #include <node.hpp> 25 #include <utils/fw_utils.hpp> 26 #include <utils/json_utils.hpp> 27 #include <variant> 28 29 namespace redfish 30 { 31 32 /** 33 * @brief Updates the Functional State of DIMMs 34 * 35 * @param[in] aResp Shared pointer for completing asynchronous calls 36 * @param[in] dimmState Dimm's Functional state, true/false 37 * 38 * @return None. 39 */ 40 void updateDimmProperties(std::shared_ptr<AsyncResp> aResp, 41 const std::variant<bool> &dimmState) 42 { 43 const bool *isDimmFunctional = std::get_if<bool>(&dimmState); 44 if (isDimmFunctional == nullptr) 45 { 46 messages::internalError(aResp->res); 47 return; 48 } 49 BMCWEB_LOG_DEBUG << "Dimm Functional: " << *isDimmFunctional; 50 51 // Set it as Enabled if atleast one DIMM is functional 52 // Update STATE only if previous State was DISABLED and current Dimm is 53 // ENABLED. 54 nlohmann::json &prevMemSummary = 55 aResp->res.jsonValue["MemorySummary"]["Status"]["State"]; 56 if (prevMemSummary == "Disabled") 57 { 58 if (*isDimmFunctional == true) 59 { 60 aResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 61 "Enabled"; 62 } 63 } 64 } 65 66 /* 67 * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState 68 * 69 * @param[in] aResp Shared pointer for completing asynchronous calls 70 * @param[in] cpuPresenceState CPU present or not 71 * 72 * @return None. 73 */ 74 void modifyCpuPresenceState(std::shared_ptr<AsyncResp> aResp, 75 const std::variant<bool> &cpuPresenceState) 76 { 77 const bool *isCpuPresent = std::get_if<bool>(&cpuPresenceState); 78 79 if (isCpuPresent == nullptr) 80 { 81 messages::internalError(aResp->res); 82 return; 83 } 84 BMCWEB_LOG_DEBUG << "Cpu Present: " << *isCpuPresent; 85 86 if (*isCpuPresent == true) 87 { 88 nlohmann::json &procCount = 89 aResp->res.jsonValue["ProcessorSummary"]["Count"]; 90 auto procCountPtr = 91 procCount.get_ptr<nlohmann::json::number_integer_t *>(); 92 if (procCountPtr != nullptr) 93 { 94 // shouldn't be possible to be nullptr 95 *procCountPtr += 1; 96 } 97 } 98 } 99 100 /* 101 * @brief Update "ProcessorSummary" "Status" "State" based on 102 * CPU Functional State 103 * 104 * @param[in] aResp Shared pointer for completing asynchronous calls 105 * @param[in] cpuFunctionalState is CPU functional true/false 106 * 107 * @return None. 108 */ 109 void modifyCpuFunctionalState(std::shared_ptr<AsyncResp> aResp, 110 const std::variant<bool> &cpuFunctionalState) 111 { 112 const bool *isCpuFunctional = std::get_if<bool>(&cpuFunctionalState); 113 114 if (isCpuFunctional == nullptr) 115 { 116 messages::internalError(aResp->res); 117 return; 118 } 119 BMCWEB_LOG_DEBUG << "Cpu Functional: " << *isCpuFunctional; 120 121 nlohmann::json &prevProcState = 122 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"]; 123 124 // Set it as Enabled if atleast one CPU is functional 125 // Update STATE only if previous State was Non_Functional and current CPU is 126 // Functional. 127 if (prevProcState == "Disabled") 128 { 129 if (*isCpuFunctional == true) 130 { 131 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 132 "Enabled"; 133 } 134 } 135 } 136 137 /* 138 * @brief Retrieves computer system properties over dbus 139 * 140 * @param[in] aResp Shared pointer for completing asynchronous calls 141 * @param[in] name Computer system name from request 142 * 143 * @return None. 144 */ 145 void getComputerSystem(std::shared_ptr<AsyncResp> aResp, 146 std::shared_ptr<HealthPopulate> systemHealth) 147 { 148 BMCWEB_LOG_DEBUG << "Get available system components."; 149 150 crow::connections::systemBus->async_method_call( 151 [aResp, systemHealth]( 152 const boost::system::error_code ec, 153 const std::vector<std::pair< 154 std::string, 155 std::vector<std::pair<std::string, std::vector<std::string>>>>> 156 &subtree) { 157 if (ec) 158 { 159 BMCWEB_LOG_DEBUG << "DBUS response error"; 160 messages::internalError(aResp->res); 161 return; 162 } 163 // Iterate over all retrieved ObjectPaths. 164 for (const std::pair<std::string, 165 std::vector<std::pair< 166 std::string, std::vector<std::string>>>> 167 &object : subtree) 168 { 169 const std::string &path = object.first; 170 BMCWEB_LOG_DEBUG << "Got path: " << path; 171 const std::vector< 172 std::pair<std::string, std::vector<std::string>>> 173 &connectionNames = object.second; 174 if (connectionNames.size() < 1) 175 { 176 continue; 177 } 178 179 auto memoryHealth = std::make_shared<HealthPopulate>( 180 aResp, aResp->res.jsonValue["MemorySummary"]["Status"]); 181 182 auto cpuHealth = std::make_shared<HealthPopulate>( 183 aResp, aResp->res.jsonValue["ProcessorSummary"]["Status"]); 184 185 systemHealth->children.emplace_back(memoryHealth); 186 systemHealth->children.emplace_back(cpuHealth); 187 188 // This is not system, so check if it's cpu, dimm, UUID or 189 // BiosVer 190 for (const auto &connection : connectionNames) 191 { 192 for (const auto &interfaceName : connection.second) 193 { 194 if (interfaceName == 195 "xyz.openbmc_project.Inventory.Item.Dimm") 196 { 197 BMCWEB_LOG_DEBUG 198 << "Found Dimm, now get its properties."; 199 200 crow::connections::systemBus->async_method_call( 201 [aResp, service{connection.first}, 202 path(std::move(path))]( 203 const boost::system::error_code ec, 204 const std::vector< 205 std::pair<std::string, VariantType>> 206 &properties) { 207 if (ec) 208 { 209 BMCWEB_LOG_ERROR 210 << "DBUS response error " << ec; 211 messages::internalError(aResp->res); 212 return; 213 } 214 BMCWEB_LOG_DEBUG << "Got " 215 << properties.size() 216 << " Dimm properties."; 217 218 if (properties.size() > 0) 219 { 220 for (const std::pair<std::string, 221 VariantType> 222 &property : properties) 223 { 224 if (property.first != 225 "MemorySizeInKB") 226 { 227 continue; 228 } 229 const uint32_t *value = 230 sdbusplus::message::variant_ns:: 231 get_if<uint32_t>( 232 &property.second); 233 if (value == nullptr) 234 { 235 BMCWEB_LOG_DEBUG 236 << "Find incorrect type of " 237 "MemorySize"; 238 continue; 239 } 240 nlohmann::json &totalMemory = 241 aResp->res 242 .jsonValue["MemorySummar" 243 "y"] 244 ["TotalSystemMe" 245 "moryGiB"]; 246 uint64_t *preValue = 247 totalMemory 248 .get_ptr<uint64_t *>(); 249 if (preValue == nullptr) 250 { 251 continue; 252 } 253 aResp->res 254 .jsonValue["MemorySummary"] 255 ["TotalSystemMemoryGi" 256 "B"] = 257 *value / (1024 * 1024) + 258 *preValue; 259 aResp->res 260 .jsonValue["MemorySummary"] 261 ["Status"]["State"] = 262 "Enabled"; 263 } 264 } 265 else 266 { 267 auto getDimmProperties = 268 [aResp]( 269 const boost::system::error_code 270 ec, 271 const std::variant<bool> 272 &dimmState) { 273 if (ec) 274 { 275 BMCWEB_LOG_ERROR 276 << "DBUS response " 277 "error " 278 << ec; 279 return; 280 } 281 updateDimmProperties(aResp, 282 dimmState); 283 }; 284 crow::connections::systemBus 285 ->async_method_call( 286 std::move(getDimmProperties), 287 service, path, 288 "org.freedesktop.DBus." 289 "Properties", 290 "Get", 291 "xyz.openbmc_project.State." 292 "Decorator.OperationalStatus", 293 "Functional"); 294 } 295 }, 296 connection.first, path, 297 "org.freedesktop.DBus.Properties", "GetAll", 298 "xyz.openbmc_project.Inventory.Item.Dimm"); 299 300 memoryHealth->inventory.emplace_back(path); 301 } 302 else if (interfaceName == 303 "xyz.openbmc_project.Inventory.Item.Cpu") 304 { 305 BMCWEB_LOG_DEBUG 306 << "Found Cpu, now get its properties."; 307 308 crow::connections::systemBus->async_method_call( 309 [aResp, service{connection.first}, 310 path(std::move(path))]( 311 const boost::system::error_code ec, 312 const std::vector< 313 std::pair<std::string, VariantType>> 314 &properties) { 315 if (ec) 316 { 317 BMCWEB_LOG_ERROR 318 << "DBUS response error " << ec; 319 messages::internalError(aResp->res); 320 return; 321 } 322 BMCWEB_LOG_DEBUG << "Got " 323 << properties.size() 324 << " Cpu properties."; 325 326 if (properties.size() > 0) 327 { 328 for (const auto &property : properties) 329 { 330 if (property.first == 331 "ProcessorFamily") 332 { 333 const std::string *value = 334 sdbusplus::message:: 335 variant_ns::get_if< 336 std::string>( 337 &property.second); 338 if (value != nullptr) 339 { 340 nlohmann::json 341 &procSummary = 342 aResp->res.jsonValue 343 ["ProcessorSumm" 344 "ary"]; 345 nlohmann::json &procCount = 346 procSummary["Count"]; 347 348 auto procCountPtr = 349 procCount.get_ptr< 350 nlohmann::json:: 351 number_integer_t 352 *>(); 353 if (procCountPtr != nullptr) 354 { 355 // shouldn't be possible 356 // to be nullptr 357 *procCountPtr += 1; 358 } 359 procSummary["Status"] 360 ["State"] = 361 "Enabled"; 362 procSummary["Model"] = 363 *value; 364 } 365 } 366 } 367 } 368 else 369 { 370 auto getCpuPresenceState = 371 [aResp]( 372 const boost::system::error_code 373 ec, 374 const std::variant<bool> 375 &cpuPresenceCheck) { 376 if (ec) 377 { 378 BMCWEB_LOG_ERROR 379 << "DBUS response " 380 "error " 381 << ec; 382 return; 383 } 384 modifyCpuPresenceState( 385 aResp, cpuPresenceCheck); 386 }; 387 388 auto getCpuFunctionalState = 389 [aResp]( 390 const boost::system::error_code 391 ec, 392 const std::variant<bool> 393 &cpuFunctionalCheck) { 394 if (ec) 395 { 396 BMCWEB_LOG_ERROR 397 << "DBUS response " 398 "error " 399 << ec; 400 return; 401 } 402 modifyCpuFunctionalState( 403 aResp, cpuFunctionalCheck); 404 }; 405 // Get the Presence of CPU 406 crow::connections::systemBus 407 ->async_method_call( 408 std::move(getCpuPresenceState), 409 service, path, 410 "org.freedesktop.DBus." 411 "Properties", 412 "Get", 413 "xyz.openbmc_project.Inventory." 414 "Item", 415 "Present"); 416 417 // Get the Functional State 418 crow::connections::systemBus 419 ->async_method_call( 420 std::move( 421 getCpuFunctionalState), 422 service, path, 423 "org.freedesktop.DBus." 424 "Properties", 425 "Get", 426 "xyz.openbmc_project.State." 427 "Decorator." 428 "OperationalStatus", 429 "Functional"); 430 431 // Get the MODEL from 432 // xyz.openbmc_project.Inventory.Decorator.Asset 433 // support it later as Model is Empty 434 // currently. 435 } 436 }, 437 connection.first, path, 438 "org.freedesktop.DBus.Properties", "GetAll", 439 "xyz.openbmc_project.Inventory.Item.Cpu"); 440 441 cpuHealth->inventory.emplace_back(path); 442 } 443 else if (interfaceName == 444 "xyz.openbmc_project.Common.UUID") 445 { 446 BMCWEB_LOG_DEBUG 447 << "Found UUID, now get its properties."; 448 crow::connections::systemBus->async_method_call( 449 [aResp](const boost::system::error_code ec, 450 const std::vector< 451 std::pair<std::string, VariantType>> 452 &properties) { 453 if (ec) 454 { 455 BMCWEB_LOG_DEBUG 456 << "DBUS response error " << ec; 457 messages::internalError(aResp->res); 458 return; 459 } 460 BMCWEB_LOG_DEBUG << "Got " 461 << properties.size() 462 << " UUID properties."; 463 for (const std::pair<std::string, 464 VariantType> 465 &property : properties) 466 { 467 if (property.first == "UUID") 468 { 469 const std::string *value = 470 sdbusplus::message::variant_ns:: 471 get_if<std::string>( 472 &property.second); 473 474 if (value != nullptr) 475 { 476 std::string valueStr = *value; 477 if (valueStr.size() == 32) 478 { 479 valueStr.insert(8, 1, '-'); 480 valueStr.insert(13, 1, '-'); 481 valueStr.insert(18, 1, '-'); 482 valueStr.insert(23, 1, '-'); 483 } 484 BMCWEB_LOG_DEBUG << "UUID = " 485 << valueStr; 486 aResp->res.jsonValue["UUID"] = 487 valueStr; 488 } 489 } 490 } 491 }, 492 connection.first, path, 493 "org.freedesktop.DBus.Properties", "GetAll", 494 "xyz.openbmc_project.Common.UUID"); 495 } 496 else if (interfaceName == 497 "xyz.openbmc_project.Inventory.Item.System") 498 { 499 crow::connections::systemBus->async_method_call( 500 [aResp](const boost::system::error_code ec, 501 const std::vector< 502 std::pair<std::string, VariantType>> 503 &propertiesList) { 504 if (ec) 505 { 506 // doesn't have to include this 507 // interface 508 return; 509 } 510 BMCWEB_LOG_DEBUG 511 << "Got " << propertiesList.size() 512 << " properties for system"; 513 for (const std::pair<std::string, 514 VariantType> 515 &property : propertiesList) 516 { 517 const std::string &propertyName = 518 property.first; 519 if ((propertyName == "PartNumber") || 520 (propertyName == "SerialNumber") || 521 (propertyName == "Manufacturer") || 522 (propertyName == "Model")) 523 { 524 const std::string *value = 525 std::get_if<std::string>( 526 &property.second); 527 if (value != nullptr) 528 { 529 aResp->res 530 .jsonValue[propertyName] = 531 *value; 532 } 533 } 534 } 535 aResp->res.jsonValue["Name"] = "system"; 536 aResp->res.jsonValue["Id"] = 537 aResp->res.jsonValue["SerialNumber"]; 538 // Grab the bios version 539 fw_util::getActiveFwVersion( 540 aResp, fw_util::biosPurpose, 541 "BiosVersion"); 542 }, 543 connection.first, path, 544 "org.freedesktop.DBus.Properties", "GetAll", 545 "xyz.openbmc_project.Inventory.Decorator." 546 "Asset"); 547 548 crow::connections::systemBus->async_method_call( 549 [aResp]( 550 const boost::system::error_code ec, 551 const std::variant<std::string> &property) { 552 if (ec) 553 { 554 // doesn't have to include this 555 // interface 556 return; 557 } 558 559 const std::string *value = 560 std::get_if<std::string>(&property); 561 if (value != nullptr) 562 { 563 aResp->res.jsonValue["AssetTag"] = 564 *value; 565 } 566 }, 567 connection.first, path, 568 "org.freedesktop.DBus.Properties", "Get", 569 "xyz.openbmc_project.Inventory.Decorator." 570 "AssetTag", 571 "AssetTag"); 572 } 573 } 574 } 575 } 576 }, 577 "xyz.openbmc_project.ObjectMapper", 578 "/xyz/openbmc_project/object_mapper", 579 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 580 "/xyz/openbmc_project/inventory", int32_t(0), 581 std::array<const char *, 5>{ 582 "xyz.openbmc_project.Inventory.Decorator.Asset", 583 "xyz.openbmc_project.Inventory.Item.Cpu", 584 "xyz.openbmc_project.Inventory.Item.Dimm", 585 "xyz.openbmc_project.Inventory.Item.System", 586 "xyz.openbmc_project.Common.UUID", 587 }); 588 } 589 590 /** 591 * @brief Retrieves host state properties over dbus 592 * 593 * @param[in] aResp Shared pointer for completing asynchronous calls. 594 * 595 * @return None. 596 */ 597 void getHostState(std::shared_ptr<AsyncResp> aResp) 598 { 599 BMCWEB_LOG_DEBUG << "Get host information."; 600 crow::connections::systemBus->async_method_call( 601 [aResp](const boost::system::error_code ec, 602 const std::variant<std::string> &hostState) { 603 if (ec) 604 { 605 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 606 messages::internalError(aResp->res); 607 return; 608 } 609 610 const std::string *s = std::get_if<std::string>(&hostState); 611 BMCWEB_LOG_DEBUG << "Host state: " << *s; 612 if (s != nullptr) 613 { 614 // Verify Host State 615 if (*s == "xyz.openbmc_project.State.Host.HostState.Running") 616 { 617 aResp->res.jsonValue["PowerState"] = "On"; 618 aResp->res.jsonValue["Status"]["State"] = "Enabled"; 619 } 620 else if (*s == "xyz.openbmc_project.State.Host.HostState." 621 "DiagnosticMode") 622 { 623 aResp->res.jsonValue["PowerState"] = "On"; 624 aResp->res.jsonValue["Status"]["State"] = "InTest"; 625 } 626 else 627 { 628 aResp->res.jsonValue["PowerState"] = "Off"; 629 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 630 } 631 } 632 }, 633 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 634 "org.freedesktop.DBus.Properties", "Get", 635 "xyz.openbmc_project.State.Host", "CurrentHostState"); 636 } 637 638 /** 639 * @brief Traslates boot source DBUS property value to redfish. 640 * 641 * @param[in] dbusSource The boot source in DBUS speak. 642 * 643 * @return Returns as a string, the boot source in Redfish terms. If translation 644 * cannot be done, returns an empty string. 645 */ 646 static std::string dbusToRfBootSource(const std::string &dbusSource) 647 { 648 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default") 649 { 650 return "None"; 651 } 652 else if (dbusSource == 653 "xyz.openbmc_project.Control.Boot.Source.Sources.Disk") 654 { 655 return "Hdd"; 656 } 657 else if (dbusSource == 658 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia") 659 { 660 return "Cd"; 661 } 662 else if (dbusSource == 663 "xyz.openbmc_project.Control.Boot.Source.Sources.Network") 664 { 665 return "Pxe"; 666 } 667 else if (dbusSource == 668 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia") 669 { 670 return "Usb"; 671 } 672 else 673 { 674 return ""; 675 } 676 } 677 678 /** 679 * @brief Traslates boot mode DBUS property value to redfish. 680 * 681 * @param[in] dbusMode The boot mode in DBUS speak. 682 * 683 * @return Returns as a string, the boot mode in Redfish terms. If translation 684 * cannot be done, returns an empty string. 685 */ 686 static std::string dbusToRfBootMode(const std::string &dbusMode) 687 { 688 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 689 { 690 return "None"; 691 } 692 else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe") 693 { 694 return "Diags"; 695 } 696 else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup") 697 { 698 return "BiosSetup"; 699 } 700 else 701 { 702 return ""; 703 } 704 } 705 706 /** 707 * @brief Traslates boot source from Redfish to the DBus boot paths. 708 * 709 * @param[in] rfSource The boot source in Redfish. 710 * @param[out] bootSource The DBus source 711 * @param[out] bootMode the DBus boot mode 712 * 713 * @return Integer error code. 714 */ 715 static int assignBootParameters(std::shared_ptr<AsyncResp> aResp, 716 const std::string &rfSource, 717 std::string &bootSource, std::string &bootMode) 718 { 719 // The caller has initialized the bootSource and bootMode to: 720 // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 721 // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 722 // Only modify the bootSource/bootMode variable needed to achieve the 723 // desired boot action. 724 725 if (rfSource == "None") 726 { 727 return 0; 728 } 729 else if (rfSource == "Pxe") 730 { 731 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network"; 732 } 733 else if (rfSource == "Hdd") 734 { 735 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk"; 736 } 737 else if (rfSource == "Diags") 738 { 739 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe"; 740 } 741 else if (rfSource == "Cd") 742 { 743 bootSource = 744 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia"; 745 } 746 else if (rfSource == "BiosSetup") 747 { 748 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup"; 749 } 750 else if (rfSource == "Usb") 751 { 752 bootSource = 753 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia"; 754 } 755 else 756 { 757 BMCWEB_LOG_DEBUG << "Invalid property value for " 758 "BootSourceOverrideTarget: " 759 << bootSource; 760 messages::propertyValueNotInList(aResp->res, rfSource, 761 "BootSourceTargetOverride"); 762 return -1; 763 } 764 return 0; 765 } 766 767 /** 768 * @brief Retrieves boot mode over DBUS and fills out the response 769 * 770 * @param[in] aResp Shared pointer for generating response message. 771 * @param[in] bootDbusObj The dbus object to query for boot properties. 772 * 773 * @return None. 774 */ 775 static void getBootMode(std::shared_ptr<AsyncResp> aResp, 776 std::string bootDbusObj) 777 { 778 crow::connections::systemBus->async_method_call( 779 [aResp](const boost::system::error_code ec, 780 const std::variant<std::string> &bootMode) { 781 if (ec) 782 { 783 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 784 messages::internalError(aResp->res); 785 return; 786 } 787 788 const std::string *bootModeStr = 789 std::get_if<std::string>(&bootMode); 790 791 if (!bootModeStr) 792 { 793 messages::internalError(aResp->res); 794 return; 795 } 796 797 BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr; 798 799 // TODO (Santosh): Do we need to support override mode? 800 aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy"; 801 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish." 802 "AllowableValues"] = { 803 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"}; 804 805 if (*bootModeStr != 806 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 807 { 808 auto rfMode = dbusToRfBootMode(*bootModeStr); 809 if (!rfMode.empty()) 810 { 811 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 812 rfMode; 813 } 814 } 815 816 // If the BootSourceOverrideTarget is still "None" at the end, 817 // reset the BootSourceOverrideEnabled to indicate that 818 // overrides are disabled 819 if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] == 820 "None") 821 { 822 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 823 "Disabled"; 824 } 825 }, 826 "xyz.openbmc_project.Settings", bootDbusObj, 827 "org.freedesktop.DBus.Properties", "Get", 828 "xyz.openbmc_project.Control.Boot.Mode", "BootMode"); 829 } 830 831 /** 832 * @brief Retrieves boot source over DBUS 833 * 834 * @param[in] aResp Shared pointer for generating response message. 835 * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time. 836 * 837 * @return None. 838 */ 839 static void getBootSource(std::shared_ptr<AsyncResp> aResp, bool oneTimeEnabled) 840 { 841 std::string bootDbusObj = 842 oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time" 843 : "/xyz/openbmc_project/control/host0/boot"; 844 845 BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled; 846 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 847 (oneTimeEnabled) ? "Once" : "Continuous"; 848 849 crow::connections::systemBus->async_method_call( 850 [aResp, bootDbusObj](const boost::system::error_code ec, 851 const std::variant<std::string> &bootSource) { 852 if (ec) 853 { 854 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 855 messages::internalError(aResp->res); 856 return; 857 } 858 859 const std::string *bootSourceStr = 860 std::get_if<std::string>(&bootSource); 861 862 if (!bootSourceStr) 863 { 864 messages::internalError(aResp->res); 865 return; 866 } 867 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr; 868 869 auto rfSource = dbusToRfBootSource(*bootSourceStr); 870 if (!rfSource.empty()) 871 { 872 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 873 rfSource; 874 } 875 }, 876 "xyz.openbmc_project.Settings", bootDbusObj, 877 "org.freedesktop.DBus.Properties", "Get", 878 "xyz.openbmc_project.Control.Boot.Source", "BootSource"); 879 getBootMode(std::move(aResp), std::move(bootDbusObj)); 880 } 881 882 /** 883 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 884 * get boot source and boot mode. 885 * 886 * @param[in] aResp Shared pointer for generating response message. 887 * 888 * @return None. 889 */ 890 static void getBootProperties(std::shared_ptr<AsyncResp> aResp) 891 { 892 BMCWEB_LOG_DEBUG << "Get boot information."; 893 894 crow::connections::systemBus->async_method_call( 895 [aResp](const boost::system::error_code ec, 896 const sdbusplus::message::variant<bool> &oneTime) { 897 if (ec) 898 { 899 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 900 // not an error, don't have to have the interface 901 return; 902 } 903 904 const bool *oneTimePtr = std::get_if<bool>(&oneTime); 905 906 if (!oneTimePtr) 907 { 908 messages::internalError(aResp->res); 909 return; 910 } 911 getBootSource(aResp, *oneTimePtr); 912 }, 913 "xyz.openbmc_project.Settings", 914 "/xyz/openbmc_project/control/host0/boot/one_time", 915 "org.freedesktop.DBus.Properties", "Get", 916 "xyz.openbmc_project.Object.Enable", "Enabled"); 917 } 918 919 /** 920 * @brief Sets boot properties into DBUS object(s). 921 * 922 * @param[in] aResp Shared pointer for generating response message. 923 * @param[in] oneTimeEnabled Is "one-time" setting already enabled. 924 * @param[in] bootSource The boot source to set. 925 * @param[in] bootEnable The source override "enable" to set. 926 * 927 * @return Integer error code. 928 */ 929 static void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp, 930 bool oneTimeEnabled, 931 std::optional<std::string> bootSource, 932 std::optional<std::string> bootEnable) 933 { 934 std::string bootSourceStr = 935 "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 936 std::string bootModeStr = 937 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 938 bool oneTimeSetting = oneTimeEnabled; 939 bool useBootSource = true; 940 941 // Validate incoming parameters 942 if (bootEnable) 943 { 944 if (*bootEnable == "Once") 945 { 946 oneTimeSetting = true; 947 } 948 else if (*bootEnable == "Continuous") 949 { 950 oneTimeSetting = false; 951 } 952 else if (*bootEnable == "Disabled") 953 { 954 BMCWEB_LOG_DEBUG << "Boot source override will be disabled"; 955 oneTimeSetting = false; 956 useBootSource = false; 957 } 958 else 959 { 960 BMCWEB_LOG_DEBUG << "Unsupported value for " 961 "BootSourceOverrideEnabled: " 962 << *bootEnable; 963 messages::propertyValueNotInList(aResp->res, *bootEnable, 964 "BootSourceOverrideEnabled"); 965 return; 966 } 967 } 968 969 if (bootSource && useBootSource) 970 { 971 // Source target specified 972 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource; 973 // Figure out which DBUS interface and property to use 974 if (assignBootParameters(aResp, *bootSource, bootSourceStr, 975 bootModeStr)) 976 { 977 BMCWEB_LOG_DEBUG 978 << "Invalid property value for BootSourceOverrideTarget: " 979 << *bootSource; 980 messages::propertyValueNotInList(aResp->res, *bootSource, 981 "BootSourceTargetOverride"); 982 return; 983 } 984 } 985 986 // Act on validated parameters 987 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 988 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 989 const char *bootObj = 990 oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time" 991 : "/xyz/openbmc_project/control/host0/boot"; 992 993 crow::connections::systemBus->async_method_call( 994 [aResp](const boost::system::error_code ec) { 995 if (ec) 996 { 997 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 998 messages::internalError(aResp->res); 999 return; 1000 } 1001 BMCWEB_LOG_DEBUG << "Boot source update done."; 1002 }, 1003 "xyz.openbmc_project.Settings", bootObj, 1004 "org.freedesktop.DBus.Properties", "Set", 1005 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 1006 std::variant<std::string>(bootSourceStr)); 1007 1008 crow::connections::systemBus->async_method_call( 1009 [aResp](const boost::system::error_code ec) { 1010 if (ec) 1011 { 1012 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1013 messages::internalError(aResp->res); 1014 return; 1015 } 1016 BMCWEB_LOG_DEBUG << "Boot mode update done."; 1017 }, 1018 "xyz.openbmc_project.Settings", bootObj, 1019 "org.freedesktop.DBus.Properties", "Set", 1020 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 1021 std::variant<std::string>(bootModeStr)); 1022 1023 crow::connections::systemBus->async_method_call( 1024 [aResp{std::move(aResp)}](const boost::system::error_code ec) { 1025 if (ec) 1026 { 1027 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1028 messages::internalError(aResp->res); 1029 return; 1030 } 1031 BMCWEB_LOG_DEBUG << "Boot enable update done."; 1032 }, 1033 "xyz.openbmc_project.Settings", 1034 "/xyz/openbmc_project/control/host0/boot/one_time", 1035 "org.freedesktop.DBus.Properties", "Set", 1036 "xyz.openbmc_project.Object.Enable", "Enabled", 1037 std::variant<bool>(oneTimeSetting)); 1038 } 1039 1040 /** 1041 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 1042 * set boot source/boot mode properties. 1043 * 1044 * @param[in] aResp Shared pointer for generating response message. 1045 * @param[in] bootSource The boot source from incoming RF request. 1046 * @param[in] bootEnable The boot override enable from incoming RF request. 1047 * 1048 * @return Integer error code. 1049 */ 1050 static void setBootProperties(std::shared_ptr<AsyncResp> aResp, 1051 std::optional<std::string> bootSource, 1052 std::optional<std::string> bootEnable) 1053 { 1054 BMCWEB_LOG_DEBUG << "Set boot information."; 1055 1056 crow::connections::systemBus->async_method_call( 1057 [aResp, bootSource{std::move(bootSource)}, 1058 bootEnable{std::move(bootEnable)}]( 1059 const boost::system::error_code ec, 1060 const sdbusplus::message::variant<bool> &oneTime) { 1061 if (ec) 1062 { 1063 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1064 messages::internalError(aResp->res); 1065 return; 1066 } 1067 1068 const bool *oneTimePtr = std::get_if<bool>(&oneTime); 1069 1070 if (!oneTimePtr) 1071 { 1072 messages::internalError(aResp->res); 1073 return; 1074 } 1075 1076 BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr; 1077 1078 setBootModeOrSource(aResp, *oneTimePtr, std::move(bootSource), 1079 std::move(bootEnable)); 1080 }, 1081 "xyz.openbmc_project.Settings", 1082 "/xyz/openbmc_project/control/host0/boot/one_time", 1083 "org.freedesktop.DBus.Properties", "Get", 1084 "xyz.openbmc_project.Object.Enable", "Enabled"); 1085 } 1086 1087 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1088 /** 1089 * @brief Retrieves provisioning status 1090 * 1091 * @param[in] aResp Shared pointer for completing asynchronous calls. 1092 * 1093 * @return None. 1094 */ 1095 void getProvisioningStatus(std::shared_ptr<AsyncResp> aResp) 1096 { 1097 BMCWEB_LOG_DEBUG << "Get OEM information."; 1098 crow::connections::systemBus->async_method_call( 1099 [aResp](const boost::system::error_code ec, 1100 const std::vector<std::pair<std::string, VariantType>> 1101 &propertiesList) { 1102 if (ec) 1103 { 1104 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1105 messages::internalError(aResp->res); 1106 return; 1107 } 1108 1109 const bool *provState = nullptr; 1110 const bool *lockState = nullptr; 1111 for (const std::pair<std::string, VariantType> &property : 1112 propertiesList) 1113 { 1114 if (property.first == "UfmProvisioned") 1115 { 1116 provState = std::get_if<bool>(&property.second); 1117 } 1118 else if (property.first == "UfmLocked") 1119 { 1120 lockState = std::get_if<bool>(&property.second); 1121 } 1122 } 1123 1124 if ((provState == nullptr) || (lockState == nullptr)) 1125 { 1126 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes."; 1127 messages::internalError(aResp->res); 1128 return; 1129 } 1130 1131 nlohmann::json &oemPFR = 1132 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 1133 if (*provState == true) 1134 { 1135 if (*lockState == true) 1136 { 1137 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 1138 } 1139 else 1140 { 1141 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 1142 } 1143 } 1144 else 1145 { 1146 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1147 } 1148 }, 1149 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 1150 "org.freedesktop.DBus.Properties", "GetAll", 1151 "xyz.openbmc_project.PFR.Attributes"); 1152 } 1153 #endif 1154 1155 /** 1156 * @brief Translates watchdog timeout action DBUS property value to redfish. 1157 * 1158 * @param[in] dbusAction The watchdog timeout action in D-BUS. 1159 * 1160 * @return Returns as a string, the timeout action in Redfish terms. If 1161 * translation cannot be done, returns an empty string. 1162 */ 1163 static std::string dbusToRfWatchdogAction(const std::string &dbusAction) 1164 { 1165 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 1166 { 1167 return "None"; 1168 } 1169 else if (dbusAction == 1170 "xyz.openbmc_project.State.Watchdog.Action.HardReset") 1171 { 1172 return "ResetSystem"; 1173 } 1174 else if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 1175 { 1176 return "PowerDown"; 1177 } 1178 else if (dbusAction == 1179 "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 1180 { 1181 return "PowerCycle"; 1182 } 1183 1184 return ""; 1185 } 1186 1187 /** 1188 *@brief Translates timeout action from Redfish to DBUS property value. 1189 * 1190 *@param[in] rfAction The timeout action in Redfish. 1191 * 1192 *@return Returns as a string, the time_out action as expected by DBUS. 1193 *If translation cannot be done, returns an empty string. 1194 */ 1195 1196 static std::string rfToDbusWDTTimeOutAct(const std::string &rfAction) 1197 { 1198 if (rfAction == "None") 1199 { 1200 return "xyz.openbmc_project.State.Watchdog.Action.None"; 1201 } 1202 else if (rfAction == "PowerCycle") 1203 { 1204 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 1205 } 1206 else if (rfAction == "PowerDown") 1207 { 1208 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 1209 } 1210 else if (rfAction == "ResetSystem") 1211 { 1212 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 1213 } 1214 1215 return ""; 1216 } 1217 1218 /** 1219 * @brief Retrieves host watchdog timer properties over DBUS 1220 * 1221 * @param[in] aResp Shared pointer for completing asynchronous calls. 1222 * 1223 * @return None. 1224 */ 1225 void getHostWatchdogTimer(std::shared_ptr<AsyncResp> aResp) 1226 { 1227 BMCWEB_LOG_DEBUG << "Get host watchodg"; 1228 crow::connections::systemBus->async_method_call( 1229 [aResp](const boost::system::error_code ec, 1230 PropertiesType &properties) { 1231 if (ec) 1232 { 1233 // watchdog service is stopped 1234 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1235 return; 1236 } 1237 1238 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; 1239 1240 nlohmann::json &hostWatchdogTimer = 1241 aResp->res.jsonValue["HostWatchdogTimer"]; 1242 1243 // watchdog service is running/enabled 1244 hostWatchdogTimer["Status"]["State"] = "Enabled"; 1245 1246 for (const auto &property : properties) 1247 { 1248 BMCWEB_LOG_DEBUG << "prop=" << property.first; 1249 if (property.first == "Enabled") 1250 { 1251 const bool *state = std::get_if<bool>(&property.second); 1252 1253 if (!state) 1254 { 1255 messages::internalError(aResp->res); 1256 continue; 1257 } 1258 1259 hostWatchdogTimer["FunctionEnabled"] = *state; 1260 } 1261 else if (property.first == "ExpireAction") 1262 { 1263 const std::string *s = 1264 std::get_if<std::string>(&property.second); 1265 if (!s) 1266 { 1267 messages::internalError(aResp->res); 1268 continue; 1269 } 1270 1271 std::string action = dbusToRfWatchdogAction(*s); 1272 if (action.empty()) 1273 { 1274 messages::internalError(aResp->res); 1275 continue; 1276 } 1277 hostWatchdogTimer["TimeoutAction"] = action; 1278 } 1279 } 1280 }, 1281 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 1282 "org.freedesktop.DBus.Properties", "GetAll", 1283 "xyz.openbmc_project.State.Watchdog"); 1284 } 1285 1286 /** 1287 * @brief Sets Host WatchDog Timer properties. 1288 * 1289 * @param[in] aResp Shared pointer for generating response message. 1290 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 1291 * RF request. 1292 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 1293 * 1294 * @return None. 1295 */ 1296 static void setWDTProperties(std::shared_ptr<AsyncResp> aResp, 1297 const std::optional<bool> wdtEnable, 1298 const std::optional<std::string> &wdtTimeOutAction) 1299 { 1300 BMCWEB_LOG_DEBUG << "Set host watchdog"; 1301 1302 if (wdtTimeOutAction) 1303 { 1304 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 1305 // check if TimeOut Action is Valid 1306 if (wdtTimeOutActStr.empty()) 1307 { 1308 BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " 1309 << *wdtTimeOutAction; 1310 messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, 1311 "TimeoutAction"); 1312 return; 1313 } 1314 1315 crow::connections::systemBus->async_method_call( 1316 [aResp](const boost::system::error_code ec) { 1317 if (ec) 1318 { 1319 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1320 messages::internalError(aResp->res); 1321 return; 1322 } 1323 }, 1324 "xyz.openbmc_project.Watchdog", 1325 "/xyz/openbmc_project/watchdog/host0", 1326 "org.freedesktop.DBus.Properties", "Set", 1327 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 1328 std::variant<std::string>(wdtTimeOutActStr)); 1329 } 1330 1331 if (wdtEnable) 1332 { 1333 crow::connections::systemBus->async_method_call( 1334 [aResp](const boost::system::error_code ec) { 1335 if (ec) 1336 { 1337 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1338 messages::internalError(aResp->res); 1339 return; 1340 } 1341 }, 1342 "xyz.openbmc_project.Watchdog", 1343 "/xyz/openbmc_project/watchdog/host0", 1344 "org.freedesktop.DBus.Properties", "Set", 1345 "xyz.openbmc_project.State.Watchdog", "Enabled", 1346 std::variant<bool>(*wdtEnable)); 1347 } 1348 } 1349 1350 /** 1351 * SystemsCollection derived class for delivering ComputerSystems Collection 1352 * Schema 1353 */ 1354 class SystemsCollection : public Node 1355 { 1356 public: 1357 SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/") 1358 { 1359 entityPrivileges = { 1360 {boost::beast::http::verb::get, {{"Login"}}}, 1361 {boost::beast::http::verb::head, {{"Login"}}}, 1362 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1363 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1364 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1365 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1366 } 1367 1368 private: 1369 void doGet(crow::Response &res, const crow::Request &req, 1370 const std::vector<std::string> ¶ms) override 1371 { 1372 res.jsonValue["@odata.type"] = 1373 "#ComputerSystemCollection.ComputerSystemCollection"; 1374 res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 1375 res.jsonValue["Name"] = "Computer System Collection"; 1376 res.jsonValue["Members"] = { 1377 {{"@odata.id", "/redfish/v1/Systems/system"}}}; 1378 res.jsonValue["Members@odata.count"] = 1; 1379 res.end(); 1380 } 1381 }; 1382 1383 /** 1384 * SystemActionsReset class supports handle POST method for Reset action. 1385 * The class retrieves and sends data directly to D-Bus. 1386 */ 1387 class SystemActionsReset : public Node 1388 { 1389 public: 1390 SystemActionsReset(CrowApp &app) : 1391 Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 1392 { 1393 entityPrivileges = { 1394 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1395 } 1396 1397 private: 1398 /** 1399 * Function handles POST method request. 1400 * Analyzes POST body message before sends Reset request data to D-Bus. 1401 */ 1402 void doPost(crow::Response &res, const crow::Request &req, 1403 const std::vector<std::string> ¶ms) override 1404 { 1405 auto asyncResp = std::make_shared<AsyncResp>(res); 1406 1407 std::string resetType; 1408 if (!json_util::readJson(req, res, "ResetType", resetType)) 1409 { 1410 return; 1411 } 1412 1413 // Get the command and host vs. chassis 1414 std::string command; 1415 bool hostCommand; 1416 if (resetType == "On") 1417 { 1418 command = "xyz.openbmc_project.State.Host.Transition.On"; 1419 hostCommand = true; 1420 } 1421 else if (resetType == "ForceOff") 1422 { 1423 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 1424 hostCommand = false; 1425 } 1426 else if (resetType == "ForceOn") 1427 { 1428 command = "xyz.openbmc_project.State.Host.Transition.On"; 1429 hostCommand = true; 1430 } 1431 else if (resetType == "ForceRestart") 1432 { 1433 command = 1434 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 1435 hostCommand = true; 1436 } 1437 else if (resetType == "GracefulShutdown") 1438 { 1439 command = "xyz.openbmc_project.State.Host.Transition.Off"; 1440 hostCommand = true; 1441 } 1442 else if (resetType == "GracefulRestart") 1443 { 1444 command = 1445 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot"; 1446 hostCommand = true; 1447 } 1448 else if (resetType == "PowerCycle") 1449 { 1450 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 1451 hostCommand = true; 1452 } 1453 else if (resetType == "Nmi") 1454 { 1455 doNMI(asyncResp); 1456 return; 1457 } 1458 else 1459 { 1460 messages::actionParameterUnknown(res, "Reset", resetType); 1461 return; 1462 } 1463 1464 if (hostCommand) 1465 { 1466 crow::connections::systemBus->async_method_call( 1467 [asyncResp, resetType](const boost::system::error_code ec) { 1468 if (ec) 1469 { 1470 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1471 if (ec.value() == boost::asio::error::invalid_argument) 1472 { 1473 messages::actionParameterNotSupported( 1474 asyncResp->res, resetType, "Reset"); 1475 } 1476 else 1477 { 1478 messages::internalError(asyncResp->res); 1479 } 1480 return; 1481 } 1482 messages::success(asyncResp->res); 1483 }, 1484 "xyz.openbmc_project.State.Host", 1485 "/xyz/openbmc_project/state/host0", 1486 "org.freedesktop.DBus.Properties", "Set", 1487 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 1488 std::variant<std::string>{command}); 1489 } 1490 else 1491 { 1492 crow::connections::systemBus->async_method_call( 1493 [asyncResp, resetType](const boost::system::error_code ec) { 1494 if (ec) 1495 { 1496 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1497 if (ec.value() == boost::asio::error::invalid_argument) 1498 { 1499 messages::actionParameterNotSupported( 1500 asyncResp->res, resetType, "Reset"); 1501 } 1502 else 1503 { 1504 messages::internalError(asyncResp->res); 1505 } 1506 return; 1507 } 1508 messages::success(asyncResp->res); 1509 }, 1510 "xyz.openbmc_project.State.Chassis", 1511 "/xyz/openbmc_project/state/chassis0", 1512 "org.freedesktop.DBus.Properties", "Set", 1513 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition", 1514 std::variant<std::string>{command}); 1515 } 1516 } 1517 /** 1518 * Function transceives data with dbus directly. 1519 */ 1520 void doNMI(const std::shared_ptr<AsyncResp> &asyncResp) 1521 { 1522 constexpr char const *serviceName = 1523 "xyz.openbmc_project.Control.Host.NMI"; 1524 constexpr char const *objectPath = 1525 "/xyz/openbmc_project/control/host0/nmi"; 1526 constexpr char const *interfaceName = 1527 "xyz.openbmc_project.Control.Host.NMI"; 1528 constexpr char const *method = "NMI"; 1529 1530 crow::connections::systemBus->async_method_call( 1531 [asyncResp](const boost::system::error_code ec) { 1532 if (ec) 1533 { 1534 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec; 1535 messages::internalError(asyncResp->res); 1536 return; 1537 } 1538 messages::success(asyncResp->res); 1539 }, 1540 serviceName, objectPath, interfaceName, method); 1541 } 1542 }; 1543 1544 /** 1545 * Systems derived class for delivering Computer Systems Schema. 1546 */ 1547 class Systems : public Node 1548 { 1549 public: 1550 /* 1551 * Default Constructor 1552 */ 1553 Systems(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/") 1554 { 1555 entityPrivileges = { 1556 {boost::beast::http::verb::get, {{"Login"}}}, 1557 {boost::beast::http::verb::head, {{"Login"}}}, 1558 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1559 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1560 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1561 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1562 } 1563 1564 private: 1565 /** 1566 * Functions triggers appropriate requests on DBus 1567 */ 1568 void doGet(crow::Response &res, const crow::Request &req, 1569 const std::vector<std::string> ¶ms) override 1570 { 1571 res.jsonValue["@odata.type"] = "#ComputerSystem.v1_6_0.ComputerSystem"; 1572 res.jsonValue["Name"] = "Computer System"; 1573 res.jsonValue["Id"] = "system"; 1574 res.jsonValue["SystemType"] = "Physical"; 1575 res.jsonValue["Description"] = "Computer System"; 1576 res.jsonValue["ProcessorSummary"]["Count"] = 0; 1577 res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled"; 1578 res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = uint64_t(0); 1579 res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled"; 1580 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system"; 1581 1582 res.jsonValue["Processors"] = { 1583 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 1584 res.jsonValue["Memory"] = { 1585 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 1586 res.jsonValue["Storage"] = { 1587 {"@odata.id", "/redfish/v1/Systems/system/Storage"}}; 1588 1589 // TODO Need to support ForceRestart. 1590 res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 1591 {"target", 1592 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 1593 {"ResetType@Redfish.AllowableValues", 1594 {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart", 1595 "GracefulShutdown", "PowerCycle", "Nmi"}}}; 1596 1597 res.jsonValue["LogServices"] = { 1598 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 1599 1600 res.jsonValue["Bios"] = { 1601 {"@odata.id", "/redfish/v1/Systems/system/Bios"}}; 1602 1603 res.jsonValue["Links"]["ManagedBy"] = { 1604 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 1605 1606 res.jsonValue["Status"] = { 1607 {"Health", "OK"}, 1608 {"State", "Enabled"}, 1609 }; 1610 auto asyncResp = std::make_shared<AsyncResp>(res); 1611 1612 constexpr const std::array<const char *, 4> inventoryForSystems = { 1613 "xyz.openbmc_project.Inventory.Item.Dimm", 1614 "xyz.openbmc_project.Inventory.Item.Cpu", 1615 "xyz.openbmc_project.Inventory.Item.Drive", 1616 "xyz.openbmc_project.Inventory.Item.StorageController"}; 1617 1618 auto health = std::make_shared<HealthPopulate>(asyncResp); 1619 crow::connections::systemBus->async_method_call( 1620 [health](const boost::system::error_code ec, 1621 std::vector<std::string> &resp) { 1622 if (ec) 1623 { 1624 // no inventory 1625 return; 1626 } 1627 1628 health->inventory = std::move(resp); 1629 }, 1630 "xyz.openbmc_project.ObjectMapper", 1631 "/xyz/openbmc_project/object_mapper", 1632 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 1633 int32_t(0), inventoryForSystems); 1634 1635 health->populate(); 1636 1637 getMainChassisId(asyncResp, [](const std::string &chassisId, 1638 std::shared_ptr<AsyncResp> aRsp) { 1639 aRsp->res.jsonValue["Links"]["Chassis"] = { 1640 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 1641 }); 1642 1643 getIndicatorLedState(asyncResp); 1644 getComputerSystem(asyncResp, health); 1645 getHostState(asyncResp); 1646 getBootProperties(asyncResp); 1647 getPCIeDeviceList(asyncResp, "PCIeDevices"); 1648 getHostWatchdogTimer(asyncResp); 1649 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1650 getProvisioningStatus(asyncResp); 1651 #endif 1652 } 1653 1654 void doPatch(crow::Response &res, const crow::Request &req, 1655 const std::vector<std::string> ¶ms) override 1656 { 1657 std::optional<std::string> indicatorLed; 1658 std::optional<nlohmann::json> bootProps; 1659 std::optional<nlohmann::json> wdtTimerProps; 1660 auto asyncResp = std::make_shared<AsyncResp>(res); 1661 1662 if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot", 1663 bootProps, "WatchdogTimer", wdtTimerProps)) 1664 { 1665 return; 1666 } 1667 1668 res.result(boost::beast::http::status::no_content); 1669 1670 if (wdtTimerProps) 1671 { 1672 std::optional<bool> wdtEnable; 1673 std::optional<std::string> wdtTimeOutAction; 1674 1675 if (!json_util::readJson(*wdtTimerProps, asyncResp->res, 1676 "FunctionEnabled", wdtEnable, 1677 "TimeoutAction", wdtTimeOutAction)) 1678 { 1679 return; 1680 } 1681 setWDTProperties(asyncResp, std::move(wdtEnable), 1682 std::move(wdtTimeOutAction)); 1683 } 1684 1685 if (bootProps) 1686 { 1687 std::optional<std::string> bootSource; 1688 std::optional<std::string> bootEnable; 1689 1690 if (!json_util::readJson(*bootProps, asyncResp->res, 1691 "BootSourceOverrideTarget", bootSource, 1692 "BootSourceOverrideEnabled", bootEnable)) 1693 { 1694 return; 1695 } 1696 setBootProperties(asyncResp, std::move(bootSource), 1697 std::move(bootEnable)); 1698 } 1699 1700 if (indicatorLed) 1701 { 1702 setIndicatorLedState(asyncResp, std::move(*indicatorLed)); 1703 } 1704 } 1705 }; 1706 } // namespace redfish 1707