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