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