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