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