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