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