meta-nicole: phosphor-ipmi-host: Add support for persistent-only settings

Some settings such as Boot Initiator Mailbox do not support
one-time setting mode (as per IPMI 2.0 specification).

This commit adds support for such persistent-only settings.

(From meta-yadro rev: 10458e3a5362815e0f4dc45a103cbdda3165b856)

Signed-off-by: Alexander Amelkin <a.amelkin@yadro.com>
Signed-off-by: Ivan Mikhaylov <i.mikhaylov@yadro.com>
Change-Id: I44a00b9c19e12e2165a311f6b2867509ee911c80
Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
diff --git a/meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Add-support-for-persistent-only-settings.patch b/meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Add-support-for-persistent-only-settings.patch
new file mode 100644
index 0000000..f1e2c4a
--- /dev/null
+++ b/meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Add-support-for-persistent-only-settings.patch
@@ -0,0 +1,92 @@
+From aaf8a4a5b82baff679f557ed83b25af6ff2919cf Mon Sep 17 00:00:00 2001
+From: Alexander Amelkin <a.amelkin@yadro.com>
+Date: Thu, 23 May 2019 20:39:57 +0300
+Subject: [PATCH] Add support for persistent-only settings
+
+Some settings such as Boot Initiator Mailbox do not support
+one-time setting mode (as per IPMI 2.0 specification).
+
+This commit adds support for such persistent-only settings.
+
+Partially resolves openbmc/openbmc#3391
+
+Change-Id: Iec8e2f5bddbc50d270916567effe334f10db2987
+Signed-off-by: Alexander Amelkin <a.amelkin@yadro.com>
+Signed-off-by: Ivan Mikhaylov <i.mikhaylov@yadro.com>
+---
+ settings.cpp | 35 +++++++++++++++++++++++++++++++----
+ 1 file changed, 31 insertions(+), 4 deletions(-)
+
+diff --git a/settings.cpp b/settings.cpp
+index 2fa2511..6002365 100644
+--- a/settings.cpp
++++ b/settings.cpp
+@@ -95,19 +95,44 @@ namespace boot
+ std::tuple<Path, OneTimeEnabled> setting(const Objects& objects,
+                                          const Interface& iface)
+ {
+-    constexpr auto bootObjCount = 2;
++    constexpr auto ambiguousOperationCount = 2;
+     constexpr auto oneTime = "one_time";
+     constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
++    bool oneTimeEnabled = false;
+ 
+     const std::vector<Path>& paths = objects.map.at(iface);
+     auto count = paths.size();
+-    if (count != bootObjCount)
++    if (!count)
+     {
+-        log<level::ERR>("Exactly two objects expected",
++        // If there are no objects implementing the requested interface,
++        // that must be an error.
++        log<level::ERR>("Interface objects not found",
++                        entry("INTERFACE=%s", iface.c_str()));
++        elog<InternalFailure>();
++    }
++    else if (count < ambiguousOperationCount)
++    {
++        // On the contrary, if there is just one object, that may mean
++        // that this particular interface doesn't support one-time
++        // setting mode (e.g. Boot Initiator Mailbox).
++        // That is not an error, just return the regular setting.
++        // If there's just one object, that's the only kind of setting
++        // mode this interface supports, so just return that setting path.
++        const Path& regularSetting = paths[0];
++        return std::make_tuple(regularSetting, oneTimeEnabled);
++    }
++    else if (count > ambiguousOperationCount)
++    {
++        // Something must be wrong if there are more objects than expected
++        log<level::ERR>("Exactly 1 or 2 interface objects are required",
+                         entry("INTERFACE=%s", iface.c_str()),
+                         entry("COUNT=%d", count));
+         elog<InternalFailure>();
+     }
++
++    // We are here because there were exactly two objects implementing the
++    // same interface. Take those two and find out which of them is the
++    // one-time setting, consider the other the persistent setting.
+     size_t index = 0;
+     if (std::string::npos == paths[0].rfind(oneTime))
+     {
+@@ -116,6 +141,8 @@ std::tuple<Path, OneTimeEnabled> setting(const Objects& objects,
+     const Path& oneTimeSetting = paths[index];
+     const Path& regularSetting = paths[!index];
+ 
++    // Now see if the one-time setting is enabled and return the path for it
++    // if so. Otherwise return the path for the persistent setting.
+     auto method = objects.bus.new_method_call(
+         objects.service(oneTimeSetting, iface).c_str(), oneTimeSetting.c_str(),
+         ipmi::PROP_INTF, "Get");
+@@ -131,7 +158,7 @@ std::tuple<Path, OneTimeEnabled> setting(const Objects& objects,
+ 
+     std::variant<bool> enabled;
+     reply.read(enabled);
+-    auto oneTimeEnabled = std::get<bool>(enabled);
++    oneTimeEnabled = std::get<bool>(enabled);
+     const Path& setting = oneTimeEnabled ? oneTimeSetting : regularSetting;
+     return std::make_tuple(setting, oneTimeEnabled);
+ }
+-- 
+2.21.1
+
diff --git a/meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend b/meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend
index 7983e94..9596fe7 100644
--- a/meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend
+++ b/meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend
@@ -1,3 +1,4 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
 DEPENDS_append = " nicole-yaml-config"
 
 EXTRA_OECONF = " \
@@ -5,3 +6,7 @@
     INVSENSOR_YAML_GEN=${STAGING_DIR_HOST}${datadir}/nicole-yaml-config/ipmi-inventory-sensors.yaml \
     FRU_YAML_GEN=${STAGING_DIR_HOST}${datadir}/nicole-yaml-config/ipmi-fru-read.yaml \
     "
+
+SRC_URI_append  = "\
+    file://0001-Add-support-for-persistent-only-settings.patch \
+"