1From aaf8a4a5b82baff679f557ed83b25af6ff2919cf Mon Sep 17 00:00:00 2001
2From: Alexander Amelkin <a.amelkin@yadro.com>
3Date: Thu, 23 May 2019 20:39:57 +0300
4Subject: [PATCH] Add support for persistent-only settings
5
6Some settings such as Boot Initiator Mailbox do not support
7one-time setting mode (as per IPMI 2.0 specification).
8
9This commit adds support for such persistent-only settings.
10
11Partially resolves openbmc/openbmc#3391
12
13Change-Id: Iec8e2f5bddbc50d270916567effe334f10db2987
14Signed-off-by: Alexander Amelkin <a.amelkin@yadro.com>
15Signed-off-by: Ivan Mikhaylov <i.mikhaylov@yadro.com>
16---
17 settings.cpp | 35 +++++++++++++++++++++++++++++++----
18 1 file changed, 31 insertions(+), 4 deletions(-)
19
20diff --git a/settings.cpp b/settings.cpp
21index 2fa2511..6002365 100644
22--- a/settings.cpp
23+++ b/settings.cpp
24@@ -95,19 +95,44 @@ namespace boot
25 std::tuple<Path, OneTimeEnabled> setting(const Objects& objects,
26                                          const Interface& iface)
27 {
28-    constexpr auto bootObjCount = 2;
29+    constexpr auto ambiguousOperationCount = 2;
30     constexpr auto oneTime = "one_time";
31     constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
32+    bool oneTimeEnabled = false;
33
34     const std::vector<Path>& paths = objects.map.at(iface);
35     auto count = paths.size();
36-    if (count != bootObjCount)
37+    if (!count)
38     {
39-        log<level::ERR>("Exactly two objects expected",
40+        // If there are no objects implementing the requested interface,
41+        // that must be an error.
42+        log<level::ERR>("Interface objects not found",
43+                        entry("INTERFACE=%s", iface.c_str()));
44+        elog<InternalFailure>();
45+    }
46+    else if (count < ambiguousOperationCount)
47+    {
48+        // On the contrary, if there is just one object, that may mean
49+        // that this particular interface doesn't support one-time
50+        // setting mode (e.g. Boot Initiator Mailbox).
51+        // That is not an error, just return the regular setting.
52+        // If there's just one object, that's the only kind of setting
53+        // mode this interface supports, so just return that setting path.
54+        const Path& regularSetting = paths[0];
55+        return std::make_tuple(regularSetting, oneTimeEnabled);
56+    }
57+    else if (count > ambiguousOperationCount)
58+    {
59+        // Something must be wrong if there are more objects than expected
60+        log<level::ERR>("Exactly 1 or 2 interface objects are required",
61                         entry("INTERFACE=%s", iface.c_str()),
62                         entry("COUNT=%d", count));
63         elog<InternalFailure>();
64     }
65+
66+    // We are here because there were exactly two objects implementing the
67+    // same interface. Take those two and find out which of them is the
68+    // one-time setting, consider the other the persistent setting.
69     size_t index = 0;
70     if (std::string::npos == paths[0].rfind(oneTime))
71     {
72@@ -116,6 +141,8 @@ std::tuple<Path, OneTimeEnabled> setting(const Objects& objects,
73     const Path& oneTimeSetting = paths[index];
74     const Path& regularSetting = paths[!index];
75
76+    // Now see if the one-time setting is enabled and return the path for it
77+    // if so. Otherwise return the path for the persistent setting.
78     auto method = objects.bus.new_method_call(
79         objects.service(oneTimeSetting, iface).c_str(), oneTimeSetting.c_str(),
80         ipmi::PROP_INTF, "Get");
81@@ -131,7 +158,7 @@ std::tuple<Path, OneTimeEnabled> setting(const Objects& objects,
82
83     std::variant<bool> enabled;
84     reply.read(enabled);
85-    auto oneTimeEnabled = std::get<bool>(enabled);
86+    oneTimeEnabled = std::get<bool>(enabled);
87     const Path& setting = oneTimeEnabled ? oneTimeSetting : regularSetting;
88     return std::make_tuple(setting, oneTimeEnabled);
89 }
90--
912.21.1
92
93