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