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