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