xref: /openbmc/bmcweb/features/redfish/lib/systems.hpp (revision 69f353069256230827258dc35e9059cc51982cf2)
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 "health.hpp"
19 #include "led.hpp"
20 #include "pcie.hpp"
21 #include "redfish_util.hpp"
22 
23 #include <boost/container/flat_map.hpp>
24 #include <node.hpp>
25 #include <utils/fw_utils.hpp>
26 #include <utils/json_utils.hpp>
27 #include <variant>
28 
29 namespace redfish
30 {
31 
32 /**
33  * @brief Updates the Functional State of DIMMs
34  *
35  * @param[in] aResp Shared pointer for completing asynchronous calls
36  * @param[in] dimmState Dimm's Functional state, true/false
37  *
38  * @return None.
39  */
40 void updateDimmProperties(std::shared_ptr<AsyncResp> aResp,
41                           const std::variant<bool> &dimmState)
42 {
43     const bool *isDimmFunctional = std::get_if<bool>(&dimmState);
44     if (isDimmFunctional == nullptr)
45     {
46         messages::internalError(aResp->res);
47         return;
48     }
49     BMCWEB_LOG_DEBUG << "Dimm Functional: " << *isDimmFunctional;
50 
51     // Set it as Enabled if atleast one DIMM is functional
52     // Update STATE only if previous State was DISABLED and current Dimm is
53     // ENABLED.
54     nlohmann::json &prevMemSummary =
55         aResp->res.jsonValue["MemorySummary"]["Status"]["State"];
56     if (prevMemSummary == "Disabled")
57     {
58         if (*isDimmFunctional == true)
59         {
60             aResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
61                 "Enabled";
62         }
63     }
64 }
65 
66 /*
67  * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState
68  *
69  * @param[in] aResp Shared pointer for completing asynchronous calls
70  * @param[in] cpuPresenceState CPU present or not
71  *
72  * @return None.
73  */
74 void modifyCpuPresenceState(std::shared_ptr<AsyncResp> aResp,
75                             const std::variant<bool> &cpuPresenceState)
76 {
77     const bool *isCpuPresent = std::get_if<bool>(&cpuPresenceState);
78 
79     if (isCpuPresent == nullptr)
80     {
81         messages::internalError(aResp->res);
82         return;
83     }
84     BMCWEB_LOG_DEBUG << "Cpu Present: " << *isCpuPresent;
85 
86     if (*isCpuPresent == true)
87     {
88         nlohmann::json &procCount =
89             aResp->res.jsonValue["ProcessorSummary"]["Count"];
90         auto procCountPtr =
91             procCount.get_ptr<nlohmann::json::number_integer_t *>();
92         if (procCountPtr != nullptr)
93         {
94             // shouldn't be possible to be nullptr
95             *procCountPtr += 1;
96         }
97     }
98 }
99 
100 /*
101  * @brief Update "ProcessorSummary" "Status" "State" based on
102  *        CPU Functional State
103  *
104  * @param[in] aResp Shared pointer for completing asynchronous calls
105  * @param[in] cpuFunctionalState is CPU functional true/false
106  *
107  * @return None.
108  */
109 void modifyCpuFunctionalState(std::shared_ptr<AsyncResp> aResp,
110                               const std::variant<bool> &cpuFunctionalState)
111 {
112     const bool *isCpuFunctional = std::get_if<bool>(&cpuFunctionalState);
113 
114     if (isCpuFunctional == nullptr)
115     {
116         messages::internalError(aResp->res);
117         return;
118     }
119     BMCWEB_LOG_DEBUG << "Cpu Functional: " << *isCpuFunctional;
120 
121     nlohmann::json &prevProcState =
122         aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"];
123 
124     // Set it as Enabled if atleast one CPU is functional
125     // Update STATE only if previous State was Non_Functional and current CPU is
126     // Functional.
127     if (prevProcState == "Disabled")
128     {
129         if (*isCpuFunctional == true)
130         {
131             aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
132                 "Enabled";
133         }
134     }
135 }
136 
137 /*
138  * @brief Retrieves computer system properties over dbus
139  *
140  * @param[in] aResp Shared pointer for completing asynchronous calls
141  * @param[in] name  Computer system name from request
142  *
143  * @return None.
144  */
145 void getComputerSystem(std::shared_ptr<AsyncResp> aResp,
146                        std::shared_ptr<HealthPopulate> systemHealth)
147 {
148     BMCWEB_LOG_DEBUG << "Get available system components.";
149 
150     crow::connections::systemBus->async_method_call(
151         [aResp, systemHealth](
152             const boost::system::error_code ec,
153             const std::vector<std::pair<
154                 std::string,
155                 std::vector<std::pair<std::string, std::vector<std::string>>>>>
156                 &subtree) {
157             if (ec)
158             {
159                 BMCWEB_LOG_DEBUG << "DBUS response error";
160                 messages::internalError(aResp->res);
161                 return;
162             }
163             // Iterate over all retrieved ObjectPaths.
164             for (const std::pair<std::string,
165                                  std::vector<std::pair<
166                                      std::string, std::vector<std::string>>>>
167                      &object : subtree)
168             {
169                 const std::string &path = object.first;
170                 BMCWEB_LOG_DEBUG << "Got path: " << path;
171                 const std::vector<
172                     std::pair<std::string, std::vector<std::string>>>
173                     &connectionNames = object.second;
174                 if (connectionNames.size() < 1)
175                 {
176                     continue;
177                 }
178 
179                 auto memoryHealth = std::make_shared<HealthPopulate>(
180                     aResp, aResp->res.jsonValue["MemorySummary"]["Status"]);
181 
182                 auto cpuHealth = std::make_shared<HealthPopulate>(
183                     aResp, aResp->res.jsonValue["ProcessorSummary"]["Status"]);
184 
185                 systemHealth->children.emplace_back(memoryHealth);
186                 systemHealth->children.emplace_back(cpuHealth);
187 
188                 // This is not system, so check if it's cpu, dimm, UUID or
189                 // BiosVer
190                 for (const auto &connection : connectionNames)
191                 {
192                     for (const auto &interfaceName : connection.second)
193                     {
194                         if (interfaceName ==
195                             "xyz.openbmc_project.Inventory.Item.Dimm")
196                         {
197                             BMCWEB_LOG_DEBUG
198                                 << "Found Dimm, now get its properties.";
199 
200                             crow::connections::systemBus->async_method_call(
201                                 [aResp, service{connection.first},
202                                  path(std::move(path))](
203                                     const boost::system::error_code ec,
204                                     const std::vector<
205                                         std::pair<std::string, VariantType>>
206                                         &properties) {
207                                     if (ec)
208                                     {
209                                         BMCWEB_LOG_ERROR
210                                             << "DBUS response error " << ec;
211                                         messages::internalError(aResp->res);
212                                         return;
213                                     }
214                                     BMCWEB_LOG_DEBUG << "Got "
215                                                      << properties.size()
216                                                      << " Dimm properties.";
217 
218                                     if (properties.size() > 0)
219                                     {
220                                         for (const std::pair<std::string,
221                                                              VariantType>
222                                                  &property : properties)
223                                         {
224                                             if (property.first !=
225                                                 "MemorySizeInKB")
226                                             {
227                                                 continue;
228                                             }
229                                             const uint32_t *value =
230                                                 std::get_if<uint32_t>(
231                                                     &property.second);
232                                             if (value == nullptr)
233                                             {
234                                                 BMCWEB_LOG_DEBUG
235                                                     << "Find incorrect type of "
236                                                        "MemorySize";
237                                                 continue;
238                                             }
239                                             nlohmann::json &totalMemory =
240                                                 aResp->res
241                                                     .jsonValue["MemorySummar"
242                                                                "y"]
243                                                               ["TotalSystemMe"
244                                                                "moryGiB"];
245                                             uint64_t *preValue =
246                                                 totalMemory
247                                                     .get_ptr<uint64_t *>();
248                                             if (preValue == nullptr)
249                                             {
250                                                 continue;
251                                             }
252                                             aResp->res
253                                                 .jsonValue["MemorySummary"]
254                                                           ["TotalSystemMemoryGi"
255                                                            "B"] =
256                                                 *value / (1024 * 1024) +
257                                                 *preValue;
258                                             aResp->res
259                                                 .jsonValue["MemorySummary"]
260                                                           ["Status"]["State"] =
261                                                 "Enabled";
262                                         }
263                                     }
264                                     else
265                                     {
266                                         auto getDimmProperties =
267                                             [aResp](
268                                                 const boost::system::error_code
269                                                     ec,
270                                                 const std::variant<bool>
271                                                     &dimmState) {
272                                                 if (ec)
273                                                 {
274                                                     BMCWEB_LOG_ERROR
275                                                         << "DBUS response "
276                                                            "error "
277                                                         << ec;
278                                                     return;
279                                                 }
280                                                 updateDimmProperties(aResp,
281                                                                      dimmState);
282                                             };
283                                         crow::connections::systemBus
284                                             ->async_method_call(
285                                                 std::move(getDimmProperties),
286                                                 service, path,
287                                                 "org.freedesktop.DBus."
288                                                 "Properties",
289                                                 "Get",
290                                                 "xyz.openbmc_project.State."
291                                                 "Decorator.OperationalStatus",
292                                                 "Functional");
293                                     }
294                                 },
295                                 connection.first, path,
296                                 "org.freedesktop.DBus.Properties", "GetAll",
297                                 "xyz.openbmc_project.Inventory.Item.Dimm");
298 
299                             memoryHealth->inventory.emplace_back(path);
300                         }
301                         else if (interfaceName ==
302                                  "xyz.openbmc_project.Inventory.Item.Cpu")
303                         {
304                             BMCWEB_LOG_DEBUG
305                                 << "Found Cpu, now get its properties.";
306 
307                             crow::connections::systemBus->async_method_call(
308                                 [aResp, service{connection.first},
309                                  path(std::move(path))](
310                                     const boost::system::error_code ec,
311                                     const std::vector<
312                                         std::pair<std::string, VariantType>>
313                                         &properties) {
314                                     if (ec)
315                                     {
316                                         BMCWEB_LOG_ERROR
317                                             << "DBUS response error " << ec;
318                                         messages::internalError(aResp->res);
319                                         return;
320                                     }
321                                     BMCWEB_LOG_DEBUG << "Got "
322                                                      << properties.size()
323                                                      << " Cpu properties.";
324 
325                                     if (properties.size() > 0)
326                                     {
327                                         for (const auto &property : properties)
328                                         {
329                                             if (property.first ==
330                                                 "ProcessorFamily")
331                                             {
332                                                 const std::string *value =
333                                                     std::get_if<std::string>(
334                                                         &property.second);
335                                                 if (value != nullptr)
336                                                 {
337                                                     nlohmann::json
338                                                         &procSummary =
339                                                             aResp->res.jsonValue
340                                                                 ["ProcessorSumm"
341                                                                  "ary"];
342                                                     nlohmann::json &procCount =
343                                                         procSummary["Count"];
344 
345                                                     auto procCountPtr =
346                                                         procCount.get_ptr<
347                                                             nlohmann::json::
348                                                                 number_integer_t
349                                                                     *>();
350                                                     if (procCountPtr != nullptr)
351                                                     {
352                                                         // shouldn't be possible
353                                                         // to be nullptr
354                                                         *procCountPtr += 1;
355                                                     }
356                                                     procSummary["Status"]
357                                                                ["State"] =
358                                                                    "Enabled";
359                                                     procSummary["Model"] =
360                                                         *value;
361                                                 }
362                                             }
363                                         }
364                                     }
365                                     else
366                                     {
367                                         auto getCpuPresenceState =
368                                             [aResp](
369                                                 const boost::system::error_code
370                                                     ec,
371                                                 const std::variant<bool>
372                                                     &cpuPresenceCheck) {
373                                                 if (ec)
374                                                 {
375                                                     BMCWEB_LOG_ERROR
376                                                         << "DBUS response "
377                                                            "error "
378                                                         << ec;
379                                                     return;
380                                                 }
381                                                 modifyCpuPresenceState(
382                                                     aResp, cpuPresenceCheck);
383                                             };
384 
385                                         auto getCpuFunctionalState =
386                                             [aResp](
387                                                 const boost::system::error_code
388                                                     ec,
389                                                 const std::variant<bool>
390                                                     &cpuFunctionalCheck) {
391                                                 if (ec)
392                                                 {
393                                                     BMCWEB_LOG_ERROR
394                                                         << "DBUS response "
395                                                            "error "
396                                                         << ec;
397                                                     return;
398                                                 }
399                                                 modifyCpuFunctionalState(
400                                                     aResp, cpuFunctionalCheck);
401                                             };
402                                         // Get the Presence of CPU
403                                         crow::connections::systemBus
404                                             ->async_method_call(
405                                                 std::move(getCpuPresenceState),
406                                                 service, path,
407                                                 "org.freedesktop.DBus."
408                                                 "Properties",
409                                                 "Get",
410                                                 "xyz.openbmc_project.Inventory."
411                                                 "Item",
412                                                 "Present");
413 
414                                         // Get the Functional State
415                                         crow::connections::systemBus
416                                             ->async_method_call(
417                                                 std::move(
418                                                     getCpuFunctionalState),
419                                                 service, path,
420                                                 "org.freedesktop.DBus."
421                                                 "Properties",
422                                                 "Get",
423                                                 "xyz.openbmc_project.State."
424                                                 "Decorator."
425                                                 "OperationalStatus",
426                                                 "Functional");
427 
428                                         // Get the MODEL from
429                                         // xyz.openbmc_project.Inventory.Decorator.Asset
430                                         // support it later as Model  is Empty
431                                         // currently.
432                                     }
433                                 },
434                                 connection.first, path,
435                                 "org.freedesktop.DBus.Properties", "GetAll",
436                                 "xyz.openbmc_project.Inventory.Item.Cpu");
437 
438                             cpuHealth->inventory.emplace_back(path);
439                         }
440                         else if (interfaceName ==
441                                  "xyz.openbmc_project.Common.UUID")
442                         {
443                             BMCWEB_LOG_DEBUG
444                                 << "Found UUID, now get its properties.";
445                             crow::connections::systemBus->async_method_call(
446                                 [aResp](const boost::system::error_code ec,
447                                         const std::vector<
448                                             std::pair<std::string, VariantType>>
449                                             &properties) {
450                                     if (ec)
451                                     {
452                                         BMCWEB_LOG_DEBUG
453                                             << "DBUS response error " << ec;
454                                         messages::internalError(aResp->res);
455                                         return;
456                                     }
457                                     BMCWEB_LOG_DEBUG << "Got "
458                                                      << properties.size()
459                                                      << " UUID properties.";
460                                     for (const std::pair<std::string,
461                                                          VariantType>
462                                              &property : properties)
463                                     {
464                                         if (property.first == "UUID")
465                                         {
466                                             const std::string *value =
467                                                 std::get_if<std::string>(
468                                                     &property.second);
469 
470                                             if (value != nullptr)
471                                             {
472                                                 std::string valueStr = *value;
473                                                 if (valueStr.size() == 32)
474                                                 {
475                                                     valueStr.insert(8, 1, '-');
476                                                     valueStr.insert(13, 1, '-');
477                                                     valueStr.insert(18, 1, '-');
478                                                     valueStr.insert(23, 1, '-');
479                                                 }
480                                                 BMCWEB_LOG_DEBUG << "UUID = "
481                                                                  << valueStr;
482                                                 aResp->res.jsonValue["UUID"] =
483                                                     valueStr;
484                                             }
485                                         }
486                                     }
487                                 },
488                                 connection.first, path,
489                                 "org.freedesktop.DBus.Properties", "GetAll",
490                                 "xyz.openbmc_project.Common.UUID");
491                         }
492                         else if (interfaceName ==
493                                  "xyz.openbmc_project.Inventory.Item.System")
494                         {
495                             crow::connections::systemBus->async_method_call(
496                                 [aResp](const boost::system::error_code ec,
497                                         const std::vector<
498                                             std::pair<std::string, VariantType>>
499                                             &propertiesList) {
500                                     if (ec)
501                                     {
502                                         // doesn't have to include this
503                                         // interface
504                                         return;
505                                     }
506                                     BMCWEB_LOG_DEBUG
507                                         << "Got " << propertiesList.size()
508                                         << " properties for system";
509                                     for (const std::pair<std::string,
510                                                          VariantType>
511                                              &property : propertiesList)
512                                     {
513                                         const std::string &propertyName =
514                                             property.first;
515                                         if ((propertyName == "PartNumber") ||
516                                             (propertyName == "SerialNumber") ||
517                                             (propertyName == "Manufacturer") ||
518                                             (propertyName == "Model"))
519                                         {
520                                             const std::string *value =
521                                                 std::get_if<std::string>(
522                                                     &property.second);
523                                             if (value != nullptr)
524                                             {
525                                                 aResp->res
526                                                     .jsonValue[propertyName] =
527                                                     *value;
528                                             }
529                                         }
530                                     }
531 
532                                     // Grab the bios version
533                                     fw_util::getActiveFwVersion(
534                                         aResp, fw_util::biosPurpose,
535                                         "BiosVersion");
536                                 },
537                                 connection.first, path,
538                                 "org.freedesktop.DBus.Properties", "GetAll",
539                                 "xyz.openbmc_project.Inventory.Decorator."
540                                 "Asset");
541 
542                             crow::connections::systemBus->async_method_call(
543                                 [aResp](
544                                     const boost::system::error_code ec,
545                                     const std::variant<std::string> &property) {
546                                     if (ec)
547                                     {
548                                         // doesn't have to include this
549                                         // interface
550                                         return;
551                                     }
552 
553                                     const std::string *value =
554                                         std::get_if<std::string>(&property);
555                                     if (value != nullptr)
556                                     {
557                                         aResp->res.jsonValue["AssetTag"] =
558                                             *value;
559                                     }
560                                 },
561                                 connection.first, path,
562                                 "org.freedesktop.DBus.Properties", "Get",
563                                 "xyz.openbmc_project.Inventory.Decorator."
564                                 "AssetTag",
565                                 "AssetTag");
566                         }
567                     }
568                 }
569             }
570         },
571         "xyz.openbmc_project.ObjectMapper",
572         "/xyz/openbmc_project/object_mapper",
573         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
574         "/xyz/openbmc_project/inventory", int32_t(0),
575         std::array<const char *, 5>{
576             "xyz.openbmc_project.Inventory.Decorator.Asset",
577             "xyz.openbmc_project.Inventory.Item.Cpu",
578             "xyz.openbmc_project.Inventory.Item.Dimm",
579             "xyz.openbmc_project.Inventory.Item.System",
580             "xyz.openbmc_project.Common.UUID",
581         });
582 }
583 
584 /**
585  * @brief Retrieves host state properties over dbus
586  *
587  * @param[in] aResp     Shared pointer for completing asynchronous calls.
588  *
589  * @return None.
590  */
591 void getHostState(std::shared_ptr<AsyncResp> aResp)
592 {
593     BMCWEB_LOG_DEBUG << "Get host information.";
594     crow::connections::systemBus->async_method_call(
595         [aResp](const boost::system::error_code ec,
596                 const std::variant<std::string> &hostState) {
597             if (ec)
598             {
599                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
600                 messages::internalError(aResp->res);
601                 return;
602             }
603 
604             const std::string *s = std::get_if<std::string>(&hostState);
605             BMCWEB_LOG_DEBUG << "Host state: " << *s;
606             if (s != nullptr)
607             {
608                 // Verify Host State
609                 if (*s == "xyz.openbmc_project.State.Host.HostState.Running")
610                 {
611                     aResp->res.jsonValue["PowerState"] = "On";
612                     aResp->res.jsonValue["Status"]["State"] = "Enabled";
613                 }
614                 else if (*s == "xyz.openbmc_project.State.Host.HostState."
615                                "Quiesced")
616                 {
617                     aResp->res.jsonValue["PowerState"] = "On";
618                     aResp->res.jsonValue["Status"]["State"] = "Quiesced";
619                 }
620                 else if (*s == "xyz.openbmc_project.State.Host.HostState."
621                                "DiagnosticMode")
622                 {
623                     aResp->res.jsonValue["PowerState"] = "On";
624                     aResp->res.jsonValue["Status"]["State"] = "InTest";
625                 }
626                 else
627                 {
628                     aResp->res.jsonValue["PowerState"] = "Off";
629                     aResp->res.jsonValue["Status"]["State"] = "Disabled";
630                 }
631             }
632         },
633         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
634         "org.freedesktop.DBus.Properties", "Get",
635         "xyz.openbmc_project.State.Host", "CurrentHostState");
636 }
637 
638 /**
639  * @brief Traslates boot source DBUS property value to redfish.
640  *
641  * @param[in] dbusSource    The boot source in DBUS speak.
642  *
643  * @return Returns as a string, the boot source in Redfish terms. If translation
644  * cannot be done, returns an empty string.
645  */
646 static std::string dbusToRfBootSource(const std::string &dbusSource)
647 {
648     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default")
649     {
650         return "None";
651     }
652     else if (dbusSource ==
653              "xyz.openbmc_project.Control.Boot.Source.Sources.Disk")
654     {
655         return "Hdd";
656     }
657     else if (dbusSource ==
658              "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia")
659     {
660         return "Cd";
661     }
662     else if (dbusSource ==
663              "xyz.openbmc_project.Control.Boot.Source.Sources.Network")
664     {
665         return "Pxe";
666     }
667     else if (dbusSource ==
668              "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia")
669     {
670         return "Usb";
671     }
672     else
673     {
674         return "";
675     }
676 }
677 
678 /**
679  * @brief Traslates boot mode DBUS property value to redfish.
680  *
681  * @param[in] dbusMode    The boot mode in DBUS speak.
682  *
683  * @return Returns as a string, the boot mode in Redfish terms. If translation
684  * cannot be done, returns an empty string.
685  */
686 static std::string dbusToRfBootMode(const std::string &dbusMode)
687 {
688     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
689     {
690         return "None";
691     }
692     else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe")
693     {
694         return "Diags";
695     }
696     else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup")
697     {
698         return "BiosSetup";
699     }
700     else
701     {
702         return "";
703     }
704 }
705 
706 /**
707  * @brief Traslates boot source from Redfish to the DBus boot paths.
708  *
709  * @param[in] rfSource    The boot source in Redfish.
710  * @param[out] bootSource The DBus source
711  * @param[out] bootMode   the DBus boot mode
712  *
713  * @return Integer error code.
714  */
715 static int assignBootParameters(std::shared_ptr<AsyncResp> aResp,
716                                 const std::string &rfSource,
717                                 std::string &bootSource, std::string &bootMode)
718 {
719     // The caller has initialized the bootSource and bootMode to:
720     // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
721     // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
722     // Only modify the bootSource/bootMode variable needed to achieve the
723     // desired boot action.
724 
725     if (rfSource == "None")
726     {
727         return 0;
728     }
729     else if (rfSource == "Pxe")
730     {
731         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network";
732     }
733     else if (rfSource == "Hdd")
734     {
735         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk";
736     }
737     else if (rfSource == "Diags")
738     {
739         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe";
740     }
741     else if (rfSource == "Cd")
742     {
743         bootSource =
744             "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia";
745     }
746     else if (rfSource == "BiosSetup")
747     {
748         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup";
749     }
750     else if (rfSource == "Usb")
751     {
752         bootSource =
753             "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia";
754     }
755     else
756     {
757         BMCWEB_LOG_DEBUG << "Invalid property value for "
758                             "BootSourceOverrideTarget: "
759                          << bootSource;
760         messages::propertyValueNotInList(aResp->res, rfSource,
761                                          "BootSourceTargetOverride");
762         return -1;
763     }
764     return 0;
765 }
766 
767 /**
768  * @brief Retrieves boot mode over DBUS and fills out the response
769  *
770  * @param[in] aResp         Shared pointer for generating response message.
771  * @param[in] bootDbusObj   The dbus object to query for boot properties.
772  *
773  * @return None.
774  */
775 static void getBootMode(std::shared_ptr<AsyncResp> aResp,
776                         std::string bootDbusObj)
777 {
778     crow::connections::systemBus->async_method_call(
779         [aResp](const boost::system::error_code ec,
780                 const std::variant<std::string> &bootMode) {
781             if (ec)
782             {
783                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
784                 messages::internalError(aResp->res);
785                 return;
786             }
787 
788             const std::string *bootModeStr =
789                 std::get_if<std::string>(&bootMode);
790 
791             if (!bootModeStr)
792             {
793                 messages::internalError(aResp->res);
794                 return;
795             }
796 
797             BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr;
798 
799             // TODO (Santosh): Do we need to support override mode?
800             aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy";
801             aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish."
802                                          "AllowableValues"] = {
803                 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"};
804 
805             if (*bootModeStr !=
806                 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
807             {
808                 auto rfMode = dbusToRfBootMode(*bootModeStr);
809                 if (!rfMode.empty())
810                 {
811                     aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
812                         rfMode;
813                 }
814             }
815 
816             // If the BootSourceOverrideTarget is still "None" at the end,
817             // reset the BootSourceOverrideEnabled to indicate that
818             // overrides are disabled
819             if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] ==
820                 "None")
821             {
822                 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
823                     "Disabled";
824             }
825         },
826         "xyz.openbmc_project.Settings", bootDbusObj,
827         "org.freedesktop.DBus.Properties", "Get",
828         "xyz.openbmc_project.Control.Boot.Mode", "BootMode");
829 }
830 
831 /**
832  * @brief Retrieves boot source over DBUS
833  *
834  * @param[in] aResp         Shared pointer for generating response message.
835  * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time.
836  *
837  * @return None.
838  */
839 static void getBootSource(std::shared_ptr<AsyncResp> aResp, bool oneTimeEnabled)
840 {
841     std::string bootDbusObj =
842         oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time"
843                        : "/xyz/openbmc_project/control/host0/boot";
844 
845     BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled;
846     aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
847         (oneTimeEnabled) ? "Once" : "Continuous";
848 
849     crow::connections::systemBus->async_method_call(
850         [aResp, bootDbusObj](const boost::system::error_code ec,
851                              const std::variant<std::string> &bootSource) {
852             if (ec)
853             {
854                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
855                 messages::internalError(aResp->res);
856                 return;
857             }
858 
859             const std::string *bootSourceStr =
860                 std::get_if<std::string>(&bootSource);
861 
862             if (!bootSourceStr)
863             {
864                 messages::internalError(aResp->res);
865                 return;
866             }
867             BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr;
868 
869             auto rfSource = dbusToRfBootSource(*bootSourceStr);
870             if (!rfSource.empty())
871             {
872                 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
873                     rfSource;
874             }
875         },
876         "xyz.openbmc_project.Settings", bootDbusObj,
877         "org.freedesktop.DBus.Properties", "Get",
878         "xyz.openbmc_project.Control.Boot.Source", "BootSource");
879     getBootMode(std::move(aResp), std::move(bootDbusObj));
880 }
881 
882 /**
883  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
884  * get boot source and boot mode.
885  *
886  * @param[in] aResp     Shared pointer for generating response message.
887  *
888  * @return None.
889  */
890 static void getBootProperties(std::shared_ptr<AsyncResp> aResp)
891 {
892     BMCWEB_LOG_DEBUG << "Get boot information.";
893 
894     crow::connections::systemBus->async_method_call(
895         [aResp](const boost::system::error_code ec,
896                 const std::variant<bool> &oneTime) {
897             if (ec)
898             {
899                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
900                 // not an error, don't have to have the interface
901                 return;
902             }
903 
904             const bool *oneTimePtr = std::get_if<bool>(&oneTime);
905 
906             if (!oneTimePtr)
907             {
908                 messages::internalError(aResp->res);
909                 return;
910             }
911             getBootSource(aResp, *oneTimePtr);
912         },
913         "xyz.openbmc_project.Settings",
914         "/xyz/openbmc_project/control/host0/boot/one_time",
915         "org.freedesktop.DBus.Properties", "Get",
916         "xyz.openbmc_project.Object.Enable", "Enabled");
917 }
918 
919 /**
920  * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot.
921  *
922  * @param[in] aResp     Shared pointer for generating response message.
923  *
924  * @return None.
925  */
926 void getAutomaticRetry(std::shared_ptr<AsyncResp> aResp)
927 {
928     BMCWEB_LOG_DEBUG << "Get Automatic Retry policy";
929 
930     crow::connections::systemBus->async_method_call(
931         [aResp](const boost::system::error_code ec,
932                 std::variant<bool> &autoRebootEnabled) {
933             if (ec)
934             {
935                 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
936                 return;
937             }
938 
939             const bool *autoRebootEnabledPtr =
940                 std::get_if<bool>(&autoRebootEnabled);
941 
942             if (!autoRebootEnabledPtr)
943             {
944                 messages::internalError(aResp->res);
945                 return;
946             }
947 
948             BMCWEB_LOG_DEBUG << "Auto Reboot: " << *autoRebootEnabledPtr;
949             if (*autoRebootEnabledPtr == true)
950             {
951                 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
952                     "RetryAttempts";
953                 // If AutomaticRetry (AutoReboot) is enabled see how many
954                 // attempts are left
955                 crow::connections::systemBus->async_method_call(
956                     [aResp](const boost::system::error_code ec,
957                             std::variant<uint32_t> &autoRebootAttemptsLeft) {
958                         if (ec)
959                         {
960                             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
961                             return;
962                         }
963 
964                         const uint32_t *autoRebootAttemptsLeftPtr =
965                             std::get_if<uint32_t>(&autoRebootAttemptsLeft);
966 
967                         if (!autoRebootAttemptsLeftPtr)
968                         {
969                             messages::internalError(aResp->res);
970                             return;
971                         }
972 
973                         BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: "
974                                          << *autoRebootAttemptsLeftPtr;
975 
976                         aResp->res
977                             .jsonValue["Boot"]
978                                       ["RemainingAutomaticRetryAttempts"] =
979                             *autoRebootAttemptsLeftPtr;
980                     },
981                     "xyz.openbmc_project.State.Host",
982                     "/xyz/openbmc_project/state/host0",
983                     "org.freedesktop.DBus.Properties", "Get",
984                     "xyz.openbmc_project.Control.Boot.RebootAttempts",
985                     "AttemptsLeft");
986             }
987             else
988             {
989                 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
990                     "Disabled";
991             }
992 
993             // Not on D-Bus. Hardcoded here:
994             // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71
995             aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3;
996 
997             // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways,
998             // and RetryAttempts. OpenBMC only supports Disabled and
999             // RetryAttempts.
1000             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig@Redfish."
1001                                          "AllowableValues"] = {"Disabled",
1002                                                                "RetryAttempts"};
1003         },
1004         "xyz.openbmc_project.Settings",
1005         "/xyz/openbmc_project/control/host0/auto_reboot",
1006         "org.freedesktop.DBus.Properties", "Get",
1007         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot");
1008 }
1009 
1010 /**
1011  * @brief Retrieves power restore policy over DBUS.
1012  *
1013  * @param[in] aResp     Shared pointer for generating response message.
1014  *
1015  * @return None.
1016  */
1017 void getPowerRestorePolicy(std::shared_ptr<AsyncResp> aResp)
1018 {
1019     BMCWEB_LOG_DEBUG << "Get power restore policy";
1020 
1021     crow::connections::systemBus->async_method_call(
1022         [aResp](const boost::system::error_code ec,
1023                 std::variant<std::string> &policy) {
1024             if (ec)
1025             {
1026                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1027                 return;
1028             }
1029 
1030             const boost::container::flat_map<std::string, std::string>
1031                 policyMaps = {
1032                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1033                      "AlwaysOn",
1034                      "AlwaysOn"},
1035                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1036                      "AlwaysOff",
1037                      "AlwaysOff"},
1038                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1039                      "LastState",
1040                      "LastState"}};
1041 
1042             const std::string *policyPtr = std::get_if<std::string>(&policy);
1043 
1044             if (!policyPtr)
1045             {
1046                 messages::internalError(aResp->res);
1047                 return;
1048             }
1049 
1050             auto policyMapsIt = policyMaps.find(*policyPtr);
1051             if (policyMapsIt == policyMaps.end())
1052             {
1053                 messages::internalError(aResp->res);
1054                 return;
1055             }
1056 
1057             aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second;
1058         },
1059         "xyz.openbmc_project.Settings",
1060         "/xyz/openbmc_project/control/host0/power_restore_policy",
1061         "org.freedesktop.DBus.Properties", "Get",
1062         "xyz.openbmc_project.Control.Power.RestorePolicy",
1063         "PowerRestorePolicy");
1064 }
1065 
1066 /**
1067  * @brief Sets boot properties into DBUS object(s).
1068  *
1069  * @param[in] aResp           Shared pointer for generating response message.
1070  * @param[in] oneTimeEnabled  Is "one-time" setting already enabled.
1071  * @param[in] bootSource      The boot source to set.
1072  * @param[in] bootEnable      The source override "enable" to set.
1073  *
1074  * @return Integer error code.
1075  */
1076 static void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp,
1077                                 bool oneTimeEnabled,
1078                                 std::optional<std::string> bootSource,
1079                                 std::optional<std::string> bootEnable)
1080 {
1081     std::string bootSourceStr =
1082         "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
1083     std::string bootModeStr =
1084         "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
1085     bool oneTimeSetting = oneTimeEnabled;
1086     bool useBootSource = true;
1087 
1088     // Validate incoming parameters
1089     if (bootEnable)
1090     {
1091         if (*bootEnable == "Once")
1092         {
1093             oneTimeSetting = true;
1094         }
1095         else if (*bootEnable == "Continuous")
1096         {
1097             oneTimeSetting = false;
1098         }
1099         else if (*bootEnable == "Disabled")
1100         {
1101             BMCWEB_LOG_DEBUG << "Boot source override will be disabled";
1102             oneTimeSetting = false;
1103             useBootSource = false;
1104         }
1105         else
1106         {
1107             BMCWEB_LOG_DEBUG << "Unsupported value for "
1108                                 "BootSourceOverrideEnabled: "
1109                              << *bootEnable;
1110             messages::propertyValueNotInList(aResp->res, *bootEnable,
1111                                              "BootSourceOverrideEnabled");
1112             return;
1113         }
1114     }
1115 
1116     if (bootSource && useBootSource)
1117     {
1118         // Source target specified
1119         BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
1120         // Figure out which DBUS interface and property to use
1121         if (assignBootParameters(aResp, *bootSource, bootSourceStr,
1122                                  bootModeStr))
1123         {
1124             BMCWEB_LOG_DEBUG
1125                 << "Invalid property value for BootSourceOverrideTarget: "
1126                 << *bootSource;
1127             messages::propertyValueNotInList(aResp->res, *bootSource,
1128                                              "BootSourceTargetOverride");
1129             return;
1130         }
1131     }
1132 
1133     // Act on validated parameters
1134     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
1135     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
1136     const char *bootObj =
1137         oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time"
1138                        : "/xyz/openbmc_project/control/host0/boot";
1139 
1140     crow::connections::systemBus->async_method_call(
1141         [aResp](const boost::system::error_code ec) {
1142             if (ec)
1143             {
1144                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1145                 messages::internalError(aResp->res);
1146                 return;
1147             }
1148             BMCWEB_LOG_DEBUG << "Boot source update done.";
1149         },
1150         "xyz.openbmc_project.Settings", bootObj,
1151         "org.freedesktop.DBus.Properties", "Set",
1152         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1153         std::variant<std::string>(bootSourceStr));
1154 
1155     crow::connections::systemBus->async_method_call(
1156         [aResp](const boost::system::error_code ec) {
1157             if (ec)
1158             {
1159                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1160                 messages::internalError(aResp->res);
1161                 return;
1162             }
1163             BMCWEB_LOG_DEBUG << "Boot mode update done.";
1164         },
1165         "xyz.openbmc_project.Settings", bootObj,
1166         "org.freedesktop.DBus.Properties", "Set",
1167         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1168         std::variant<std::string>(bootModeStr));
1169 
1170     crow::connections::systemBus->async_method_call(
1171         [aResp{std::move(aResp)}](const boost::system::error_code ec) {
1172             if (ec)
1173             {
1174                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1175                 messages::internalError(aResp->res);
1176                 return;
1177             }
1178             BMCWEB_LOG_DEBUG << "Boot enable update done.";
1179         },
1180         "xyz.openbmc_project.Settings",
1181         "/xyz/openbmc_project/control/host0/boot/one_time",
1182         "org.freedesktop.DBus.Properties", "Set",
1183         "xyz.openbmc_project.Object.Enable", "Enabled",
1184         std::variant<bool>(oneTimeSetting));
1185 }
1186 
1187 /**
1188  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
1189  * set boot source/boot mode properties.
1190  *
1191  * @param[in] aResp      Shared pointer for generating response message.
1192  * @param[in] bootSource The boot source from incoming RF request.
1193  * @param[in] bootEnable The boot override enable from incoming RF request.
1194  *
1195  * @return Integer error code.
1196  */
1197 static void setBootSourceProperties(std::shared_ptr<AsyncResp> aResp,
1198                                     std::optional<std::string> bootSource,
1199                                     std::optional<std::string> bootEnable)
1200 {
1201     BMCWEB_LOG_DEBUG << "Set boot information.";
1202 
1203     crow::connections::systemBus->async_method_call(
1204         [aResp, bootSource{std::move(bootSource)},
1205          bootEnable{std::move(bootEnable)}](const boost::system::error_code ec,
1206                                             const std::variant<bool> &oneTime) {
1207             if (ec)
1208             {
1209                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1210                 messages::internalError(aResp->res);
1211                 return;
1212             }
1213 
1214             const bool *oneTimePtr = std::get_if<bool>(&oneTime);
1215 
1216             if (!oneTimePtr)
1217             {
1218                 messages::internalError(aResp->res);
1219                 return;
1220             }
1221 
1222             BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr;
1223 
1224             setBootModeOrSource(aResp, *oneTimePtr, std::move(bootSource),
1225                                 std::move(bootEnable));
1226         },
1227         "xyz.openbmc_project.Settings",
1228         "/xyz/openbmc_project/control/host0/boot/one_time",
1229         "org.freedesktop.DBus.Properties", "Get",
1230         "xyz.openbmc_project.Object.Enable", "Enabled");
1231 }
1232 
1233 /**
1234  * @brief Sets automaticRetry (Auto Reboot)
1235  *
1236  * @param[in] aResp   Shared pointer for generating response message.
1237  * @param[in] automaticRetryConfig  "AutomaticRetryConfig" from request.
1238  *
1239  * @return None.
1240  */
1241 static void setAutomaticRetry(std::shared_ptr<AsyncResp> aResp,
1242                               const std::string &&automaticRetryConfig)
1243 {
1244     BMCWEB_LOG_DEBUG << "Set Automatic Retry.";
1245 
1246     // OpenBMC only supports "Disabled" and "RetryAttempts".
1247     bool autoRebootEnabled;
1248 
1249     if (automaticRetryConfig == "Disabled")
1250     {
1251         autoRebootEnabled = false;
1252     }
1253     else if (automaticRetryConfig == "RetryAttempts")
1254     {
1255         autoRebootEnabled = true;
1256     }
1257     else
1258     {
1259         BMCWEB_LOG_DEBUG << "Invalid property value for "
1260                             "AutomaticRetryConfig: "
1261                          << automaticRetryConfig;
1262         messages::propertyValueNotInList(aResp->res, automaticRetryConfig,
1263                                          "AutomaticRetryConfig");
1264         return;
1265     }
1266 
1267     crow::connections::systemBus->async_method_call(
1268         [aResp](const boost::system::error_code ec) {
1269             if (ec)
1270             {
1271                 messages::internalError(aResp->res);
1272                 return;
1273             }
1274         },
1275         "xyz.openbmc_project.Settings",
1276         "/xyz/openbmc_project/control/host0/auto_reboot",
1277         "org.freedesktop.DBus.Properties", "Set",
1278         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1279         std::variant<bool>(autoRebootEnabled));
1280 }
1281 
1282 /**
1283  * @brief Sets power restore policy properties.
1284  *
1285  * @param[in] aResp   Shared pointer for generating response message.
1286  * @param[in] policy  power restore policy properties from request.
1287  *
1288  * @return None.
1289  */
1290 static void setPowerRestorePolicy(std::shared_ptr<AsyncResp> aResp,
1291                                   std::optional<std::string> policy)
1292 {
1293     BMCWEB_LOG_DEBUG << "Set power restore policy.";
1294 
1295     const boost::container::flat_map<std::string, std::string> policyMaps = {
1296         {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1297                      "AlwaysOn"},
1298         {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1299                       "AlwaysOff"},
1300         {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1301                       "LastState"}};
1302 
1303     std::string powerRestorPolicy;
1304 
1305     auto policyMapsIt = policyMaps.find(*policy);
1306     if (policyMapsIt == policyMaps.end())
1307     {
1308         messages::internalError(aResp->res);
1309         return;
1310     }
1311 
1312     powerRestorPolicy = policyMapsIt->second;
1313 
1314     crow::connections::systemBus->async_method_call(
1315         [aResp](const boost::system::error_code ec) {
1316             if (ec)
1317             {
1318                 messages::internalError(aResp->res);
1319                 return;
1320             }
1321         },
1322         "xyz.openbmc_project.Settings",
1323         "/xyz/openbmc_project/control/host0/power_restore_policy",
1324         "org.freedesktop.DBus.Properties", "Set",
1325         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1326         std::variant<std::string>(powerRestorPolicy));
1327 }
1328 
1329 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1330 /**
1331  * @brief Retrieves provisioning status
1332  *
1333  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1334  *
1335  * @return None.
1336  */
1337 void getProvisioningStatus(std::shared_ptr<AsyncResp> aResp)
1338 {
1339     BMCWEB_LOG_DEBUG << "Get OEM information.";
1340     crow::connections::systemBus->async_method_call(
1341         [aResp](const boost::system::error_code ec,
1342                 const std::vector<std::pair<std::string, VariantType>>
1343                     &propertiesList) {
1344             if (ec)
1345             {
1346                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1347                 messages::internalError(aResp->res);
1348                 return;
1349             }
1350 
1351             const bool *provState = nullptr;
1352             const bool *lockState = nullptr;
1353             for (const std::pair<std::string, VariantType> &property :
1354                  propertiesList)
1355             {
1356                 if (property.first == "UfmProvisioned")
1357                 {
1358                     provState = std::get_if<bool>(&property.second);
1359                 }
1360                 else if (property.first == "UfmLocked")
1361                 {
1362                     lockState = std::get_if<bool>(&property.second);
1363                 }
1364             }
1365 
1366             if ((provState == nullptr) || (lockState == nullptr))
1367             {
1368                 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes.";
1369                 messages::internalError(aResp->res);
1370                 return;
1371             }
1372 
1373             nlohmann::json &oemPFR =
1374                 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1375             if (*provState == true)
1376             {
1377                 if (*lockState == true)
1378                 {
1379                     oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked";
1380                 }
1381                 else
1382                 {
1383                     oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked";
1384                 }
1385             }
1386             else
1387             {
1388                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
1389             }
1390         },
1391         "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr",
1392         "org.freedesktop.DBus.Properties", "GetAll",
1393         "xyz.openbmc_project.PFR.Attributes");
1394 }
1395 #endif
1396 
1397 /**
1398  * @brief Translates watchdog timeout action DBUS property value to redfish.
1399  *
1400  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
1401  *
1402  * @return Returns as a string, the timeout action in Redfish terms. If
1403  * translation cannot be done, returns an empty string.
1404  */
1405 static std::string dbusToRfWatchdogAction(const std::string &dbusAction)
1406 {
1407     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
1408     {
1409         return "None";
1410     }
1411     else if (dbusAction ==
1412              "xyz.openbmc_project.State.Watchdog.Action.HardReset")
1413     {
1414         return "ResetSystem";
1415     }
1416     else if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
1417     {
1418         return "PowerDown";
1419     }
1420     else if (dbusAction ==
1421              "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
1422     {
1423         return "PowerCycle";
1424     }
1425 
1426     return "";
1427 }
1428 
1429 /**
1430  *@brief Translates timeout action from Redfish to DBUS property value.
1431  *
1432  *@param[in] rfAction The timeout action in Redfish.
1433  *
1434  *@return Returns as a string, the time_out action as expected by DBUS.
1435  *If translation cannot be done, returns an empty string.
1436  */
1437 
1438 static std::string rfToDbusWDTTimeOutAct(const std::string &rfAction)
1439 {
1440     if (rfAction == "None")
1441     {
1442         return "xyz.openbmc_project.State.Watchdog.Action.None";
1443     }
1444     else if (rfAction == "PowerCycle")
1445     {
1446         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
1447     }
1448     else if (rfAction == "PowerDown")
1449     {
1450         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
1451     }
1452     else if (rfAction == "ResetSystem")
1453     {
1454         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
1455     }
1456 
1457     return "";
1458 }
1459 
1460 /**
1461  * @brief Retrieves host watchdog timer properties over DBUS
1462  *
1463  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1464  *
1465  * @return None.
1466  */
1467 void getHostWatchdogTimer(std::shared_ptr<AsyncResp> aResp)
1468 {
1469     BMCWEB_LOG_DEBUG << "Get host watchodg";
1470     crow::connections::systemBus->async_method_call(
1471         [aResp](const boost::system::error_code ec,
1472                 PropertiesType &properties) {
1473             if (ec)
1474             {
1475                 // watchdog service is stopped
1476                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1477                 return;
1478             }
1479 
1480             BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
1481 
1482             nlohmann::json &hostWatchdogTimer =
1483                 aResp->res.jsonValue["HostWatchdogTimer"];
1484 
1485             // watchdog service is running/enabled
1486             hostWatchdogTimer["Status"]["State"] = "Enabled";
1487 
1488             for (const auto &property : properties)
1489             {
1490                 BMCWEB_LOG_DEBUG << "prop=" << property.first;
1491                 if (property.first == "Enabled")
1492                 {
1493                     const bool *state = std::get_if<bool>(&property.second);
1494 
1495                     if (!state)
1496                     {
1497                         messages::internalError(aResp->res);
1498                         continue;
1499                     }
1500 
1501                     hostWatchdogTimer["FunctionEnabled"] = *state;
1502                 }
1503                 else if (property.first == "ExpireAction")
1504                 {
1505                     const std::string *s =
1506                         std::get_if<std::string>(&property.second);
1507                     if (!s)
1508                     {
1509                         messages::internalError(aResp->res);
1510                         continue;
1511                     }
1512 
1513                     std::string action = dbusToRfWatchdogAction(*s);
1514                     if (action.empty())
1515                     {
1516                         messages::internalError(aResp->res);
1517                         continue;
1518                     }
1519                     hostWatchdogTimer["TimeoutAction"] = action;
1520                 }
1521             }
1522         },
1523         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
1524         "org.freedesktop.DBus.Properties", "GetAll",
1525         "xyz.openbmc_project.State.Watchdog");
1526 }
1527 
1528 /**
1529  * @brief Sets Host WatchDog Timer properties.
1530  *
1531  * @param[in] aResp      Shared pointer for generating response message.
1532  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
1533  *                       RF request.
1534  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
1535  *
1536  * @return None.
1537  */
1538 static void setWDTProperties(std::shared_ptr<AsyncResp> aResp,
1539                              const std::optional<bool> wdtEnable,
1540                              const std::optional<std::string> &wdtTimeOutAction)
1541 {
1542     BMCWEB_LOG_DEBUG << "Set host watchdog";
1543 
1544     if (wdtTimeOutAction)
1545     {
1546         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
1547         // check if TimeOut Action is Valid
1548         if (wdtTimeOutActStr.empty())
1549         {
1550             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
1551                              << *wdtTimeOutAction;
1552             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
1553                                              "TimeoutAction");
1554             return;
1555         }
1556 
1557         crow::connections::systemBus->async_method_call(
1558             [aResp](const boost::system::error_code ec) {
1559                 if (ec)
1560                 {
1561                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1562                     messages::internalError(aResp->res);
1563                     return;
1564                 }
1565             },
1566             "xyz.openbmc_project.Watchdog",
1567             "/xyz/openbmc_project/watchdog/host0",
1568             "org.freedesktop.DBus.Properties", "Set",
1569             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
1570             std::variant<std::string>(wdtTimeOutActStr));
1571     }
1572 
1573     if (wdtEnable)
1574     {
1575         crow::connections::systemBus->async_method_call(
1576             [aResp](const boost::system::error_code ec) {
1577                 if (ec)
1578                 {
1579                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1580                     messages::internalError(aResp->res);
1581                     return;
1582                 }
1583             },
1584             "xyz.openbmc_project.Watchdog",
1585             "/xyz/openbmc_project/watchdog/host0",
1586             "org.freedesktop.DBus.Properties", "Set",
1587             "xyz.openbmc_project.State.Watchdog", "Enabled",
1588             std::variant<bool>(*wdtEnable));
1589     }
1590 }
1591 
1592 /**
1593  * SystemsCollection derived class for delivering ComputerSystems Collection
1594  * Schema
1595  */
1596 class SystemsCollection : public Node
1597 {
1598   public:
1599     SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/")
1600     {
1601         entityPrivileges = {
1602             {boost::beast::http::verb::get, {{"Login"}}},
1603             {boost::beast::http::verb::head, {{"Login"}}},
1604             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1605             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1606             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1607             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1608     }
1609 
1610   private:
1611     void doGet(crow::Response &res, const crow::Request &req,
1612                const std::vector<std::string> &params) override
1613     {
1614         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1615         res.jsonValue["@odata.type"] =
1616             "#ComputerSystemCollection.ComputerSystemCollection";
1617         res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
1618         res.jsonValue["Name"] = "Computer System Collection";
1619 
1620         crow::connections::systemBus->async_method_call(
1621             [asyncResp](const boost::system::error_code ec,
1622                         const std::variant<std::string> &hostName) {
1623                 nlohmann::json &iface_array =
1624                     asyncResp->res.jsonValue["Members"];
1625                 iface_array = nlohmann::json::array();
1626                 auto &count = asyncResp->res.jsonValue["Members@odata.count"];
1627                 count = 0;
1628                 if (ec)
1629                 {
1630                     iface_array.push_back(
1631                         {{"@odata.id", "/redfish/v1/Systems/system"}});
1632                     count = iface_array.size();
1633                     return;
1634                 }
1635                 BMCWEB_LOG_DEBUG << "Hypervisor is available";
1636                 iface_array.push_back(
1637                     {{"@odata.id", "/redfish/v1/Systems/system"}});
1638                 iface_array.push_back(
1639                     {{"@odata.id", "/redfish/v1/Systems/hypervisor"}});
1640                 count = iface_array.size();
1641             },
1642             "xyz.openbmc_project.Settings", "/xyz/openbmc_project/network/vmi",
1643             "org.freedesktop.DBus.Properties", "Get",
1644             "xyz.openbmc_project.Network.SystemConfiguration", "HostName");
1645     }
1646 };
1647 
1648 /**
1649  * SystemActionsReset class supports handle POST method for Reset action.
1650  * The class retrieves and sends data directly to D-Bus.
1651  */
1652 class SystemActionsReset : public Node
1653 {
1654   public:
1655     SystemActionsReset(CrowApp &app) :
1656         Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
1657     {
1658         entityPrivileges = {
1659             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1660     }
1661 
1662   private:
1663     /**
1664      * Function handles POST method request.
1665      * Analyzes POST body message before sends Reset request data to D-Bus.
1666      */
1667     void doPost(crow::Response &res, const crow::Request &req,
1668                 const std::vector<std::string> &params) override
1669     {
1670         auto asyncResp = std::make_shared<AsyncResp>(res);
1671 
1672         std::string resetType;
1673         if (!json_util::readJson(req, res, "ResetType", resetType))
1674         {
1675             return;
1676         }
1677 
1678         // Get the command and host vs. chassis
1679         std::string command;
1680         bool hostCommand;
1681         if (resetType == "On")
1682         {
1683             command = "xyz.openbmc_project.State.Host.Transition.On";
1684             hostCommand = true;
1685         }
1686         else if (resetType == "ForceOff")
1687         {
1688             command = "xyz.openbmc_project.State.Chassis.Transition.Off";
1689             hostCommand = false;
1690         }
1691         else if (resetType == "ForceOn")
1692         {
1693             command = "xyz.openbmc_project.State.Host.Transition.On";
1694             hostCommand = true;
1695         }
1696         else if (resetType == "ForceRestart")
1697         {
1698             command =
1699                 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
1700             hostCommand = true;
1701         }
1702         else if (resetType == "GracefulShutdown")
1703         {
1704             command = "xyz.openbmc_project.State.Host.Transition.Off";
1705             hostCommand = true;
1706         }
1707         else if (resetType == "GracefulRestart")
1708         {
1709             command =
1710                 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot";
1711             hostCommand = true;
1712         }
1713         else if (resetType == "PowerCycle")
1714         {
1715             command = "xyz.openbmc_project.State.Host.Transition.Reboot";
1716             hostCommand = true;
1717         }
1718         else if (resetType == "Nmi")
1719         {
1720             doNMI(asyncResp);
1721             return;
1722         }
1723         else
1724         {
1725             messages::actionParameterUnknown(res, "Reset", resetType);
1726             return;
1727         }
1728 
1729         if (hostCommand)
1730         {
1731             crow::connections::systemBus->async_method_call(
1732                 [asyncResp, resetType](const boost::system::error_code ec) {
1733                     if (ec)
1734                     {
1735                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1736                         if (ec.value() == boost::asio::error::invalid_argument)
1737                         {
1738                             messages::actionParameterNotSupported(
1739                                 asyncResp->res, resetType, "Reset");
1740                         }
1741                         else
1742                         {
1743                             messages::internalError(asyncResp->res);
1744                         }
1745                         return;
1746                     }
1747                     messages::success(asyncResp->res);
1748                 },
1749                 "xyz.openbmc_project.State.Host",
1750                 "/xyz/openbmc_project/state/host0",
1751                 "org.freedesktop.DBus.Properties", "Set",
1752                 "xyz.openbmc_project.State.Host", "RequestedHostTransition",
1753                 std::variant<std::string>{command});
1754         }
1755         else
1756         {
1757             crow::connections::systemBus->async_method_call(
1758                 [asyncResp, resetType](const boost::system::error_code ec) {
1759                     if (ec)
1760                     {
1761                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1762                         if (ec.value() == boost::asio::error::invalid_argument)
1763                         {
1764                             messages::actionParameterNotSupported(
1765                                 asyncResp->res, resetType, "Reset");
1766                         }
1767                         else
1768                         {
1769                             messages::internalError(asyncResp->res);
1770                         }
1771                         return;
1772                     }
1773                     messages::success(asyncResp->res);
1774                 },
1775                 "xyz.openbmc_project.State.Chassis",
1776                 "/xyz/openbmc_project/state/chassis0",
1777                 "org.freedesktop.DBus.Properties", "Set",
1778                 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
1779                 std::variant<std::string>{command});
1780         }
1781     }
1782     /**
1783      * Function transceives data with dbus directly.
1784      */
1785     void doNMI(const std::shared_ptr<AsyncResp> &asyncResp)
1786     {
1787         constexpr char const *serviceName =
1788             "xyz.openbmc_project.Control.Host.NMI";
1789         constexpr char const *objectPath =
1790             "/xyz/openbmc_project/control/host0/nmi";
1791         constexpr char const *interfaceName =
1792             "xyz.openbmc_project.Control.Host.NMI";
1793         constexpr char const *method = "NMI";
1794 
1795         crow::connections::systemBus->async_method_call(
1796             [asyncResp](const boost::system::error_code ec) {
1797                 if (ec)
1798                 {
1799                     BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
1800                     messages::internalError(asyncResp->res);
1801                     return;
1802                 }
1803                 messages::success(asyncResp->res);
1804             },
1805             serviceName, objectPath, interfaceName, method);
1806     }
1807 };
1808 
1809 /**
1810  * Systems derived class for delivering Computer Systems Schema.
1811  */
1812 class Systems : public Node
1813 {
1814   public:
1815     /*
1816      * Default Constructor
1817      */
1818     Systems(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/")
1819     {
1820         entityPrivileges = {
1821             {boost::beast::http::verb::get, {{"Login"}}},
1822             {boost::beast::http::verb::head, {{"Login"}}},
1823             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1824             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1825             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1826             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1827     }
1828 
1829   private:
1830     /**
1831      * Functions triggers appropriate requests on DBus
1832      */
1833     void doGet(crow::Response &res, const crow::Request &req,
1834                const std::vector<std::string> &params) override
1835     {
1836         res.jsonValue["@odata.type"] = "#ComputerSystem.v1_11_0.ComputerSystem";
1837         res.jsonValue["Name"] = "system";
1838         res.jsonValue["Id"] = "system";
1839         res.jsonValue["SystemType"] = "Physical";
1840         res.jsonValue["Description"] = "Computer System";
1841         res.jsonValue["ProcessorSummary"]["Count"] = 0;
1842         res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled";
1843         res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = uint64_t(0);
1844         res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled";
1845         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system";
1846 
1847         res.jsonValue["Processors"] = {
1848             {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
1849         res.jsonValue["Memory"] = {
1850             {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
1851         res.jsonValue["Storage"] = {
1852             {"@odata.id", "/redfish/v1/Systems/system/Storage"}};
1853 
1854         // TODO Need to support ForceRestart.
1855         res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
1856             {"target",
1857              "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
1858             {"ResetType@Redfish.AllowableValues",
1859              {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart",
1860               "GracefulShutdown", "PowerCycle", "Nmi"}}};
1861 
1862         res.jsonValue["LogServices"] = {
1863             {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
1864 
1865         res.jsonValue["Bios"] = {
1866             {"@odata.id", "/redfish/v1/Systems/system/Bios"}};
1867 
1868         res.jsonValue["Links"]["ManagedBy"] = {
1869             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
1870 
1871         res.jsonValue["Status"] = {
1872             {"Health", "OK"},
1873             {"State", "Enabled"},
1874         };
1875         auto asyncResp = std::make_shared<AsyncResp>(res);
1876 
1877         constexpr const std::array<const char *, 4> inventoryForSystems = {
1878             "xyz.openbmc_project.Inventory.Item.Dimm",
1879             "xyz.openbmc_project.Inventory.Item.Cpu",
1880             "xyz.openbmc_project.Inventory.Item.Drive",
1881             "xyz.openbmc_project.Inventory.Item.StorageController"};
1882 
1883         auto health = std::make_shared<HealthPopulate>(asyncResp);
1884         crow::connections::systemBus->async_method_call(
1885             [health](const boost::system::error_code ec,
1886                      std::vector<std::string> &resp) {
1887                 if (ec)
1888                 {
1889                     // no inventory
1890                     return;
1891                 }
1892 
1893                 health->inventory = std::move(resp);
1894             },
1895             "xyz.openbmc_project.ObjectMapper",
1896             "/xyz/openbmc_project/object_mapper",
1897             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
1898             int32_t(0), inventoryForSystems);
1899 
1900         health->populate();
1901 
1902         getMainChassisId(asyncResp, [](const std::string &chassisId,
1903                                        std::shared_ptr<AsyncResp> aRsp) {
1904             aRsp->res.jsonValue["Links"]["Chassis"] = {
1905                 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
1906         });
1907 
1908         getIndicatorLedState(asyncResp);
1909         getComputerSystem(asyncResp, health);
1910         getHostState(asyncResp);
1911         getBootProperties(asyncResp);
1912         getPCIeDeviceList(asyncResp, "PCIeDevices");
1913         getHostWatchdogTimer(asyncResp);
1914         getPowerRestorePolicy(asyncResp);
1915         getAutomaticRetry(asyncResp);
1916 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1917         getProvisioningStatus(asyncResp);
1918 #endif
1919     }
1920 
1921     void doPatch(crow::Response &res, const crow::Request &req,
1922                  const std::vector<std::string> &params) override
1923     {
1924         std::optional<std::string> indicatorLed;
1925         std::optional<nlohmann::json> bootProps;
1926         std::optional<nlohmann::json> wdtTimerProps;
1927         std::optional<std::string> powerRestorePolicy;
1928         auto asyncResp = std::make_shared<AsyncResp>(res);
1929 
1930         if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot",
1931                                  bootProps, "WatchdogTimer", wdtTimerProps,
1932                                  "PowerRestorePolicy", powerRestorePolicy))
1933         {
1934             return;
1935         }
1936 
1937         res.result(boost::beast::http::status::no_content);
1938 
1939         if (wdtTimerProps)
1940         {
1941             std::optional<bool> wdtEnable;
1942             std::optional<std::string> wdtTimeOutAction;
1943 
1944             if (!json_util::readJson(*wdtTimerProps, asyncResp->res,
1945                                      "FunctionEnabled", wdtEnable,
1946                                      "TimeoutAction", wdtTimeOutAction))
1947             {
1948                 return;
1949             }
1950             setWDTProperties(asyncResp, std::move(wdtEnable),
1951                              std::move(wdtTimeOutAction));
1952         }
1953 
1954         if (bootProps)
1955         {
1956             std::optional<std::string> bootSource;
1957             std::optional<std::string> bootEnable;
1958             std::optional<std::string> automaticRetryConfig;
1959 
1960             if (!json_util::readJson(
1961                     *bootProps, asyncResp->res, "BootSourceOverrideTarget",
1962                     bootSource, "BootSourceOverrideEnabled", bootEnable,
1963                     "AutomaticRetryConfig", automaticRetryConfig))
1964             {
1965                 return;
1966             }
1967             if (bootSource || bootEnable)
1968             {
1969                 setBootSourceProperties(asyncResp, std::move(bootSource),
1970                                         std::move(bootEnable));
1971             }
1972             if (automaticRetryConfig)
1973             {
1974                 setAutomaticRetry(asyncResp, std::move(*automaticRetryConfig));
1975             }
1976         }
1977 
1978         if (indicatorLed)
1979         {
1980             setIndicatorLedState(asyncResp, std::move(*indicatorLed));
1981         }
1982 
1983         if (powerRestorePolicy)
1984         {
1985             setPowerRestorePolicy(asyncResp, std::move(*powerRestorePolicy));
1986         }
1987     }
1988 };
1989 } // namespace redfish
1990