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