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