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