meta-yadro: share boot initiator mailbox support

Boot Initiator Mailbox should be available on all our hardware.
This commit moves all required files and recipes to the meta-yadro.

(From meta-yadro rev: 9ee3c28294c6a87912edbcf09b999b926634f836)

Change-Id: Idc52bfb50c8f122662279a593de0ee40703ddb51
Signed-off-by: Alexander Filippov <a.filippov@yadro.com>
Signed-off-by: Ivan Mikhaylov <i.mikhaylov@yadro.com>
Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
diff --git a/meta-yadro/recipes-phosphor/dbus/phosphor-dbus-interfaces/xyz/openbmc_project/Control/Boot/Mailbox.interface.yaml b/meta-yadro/recipes-phosphor/dbus/phosphor-dbus-interfaces/xyz/openbmc_project/Control/Boot/Mailbox.interface.yaml
new file mode 100644
index 0000000..839e8be
--- /dev/null
+++ b/meta-yadro/recipes-phosphor/dbus/phosphor-dbus-interfaces/xyz/openbmc_project/Control/Boot/Mailbox.interface.yaml
@@ -0,0 +1,63 @@
+description: >
+    Implement to provide the boot initiator (such as Petitboot or UEFI)
+    with its specific parameters. This is based on IPMI 2.0 Table 28-14
+    'Boot Option Parameters' parameter 7 'Boot initiator mailbox'.
+
+properties:
+    - name: Supported
+      type: boolean
+      flags:
+        - const
+      default: false
+      description: >
+          Specifies whether or not the mailbox is supported by the
+          boot initiator on this machine.
+
+          The property is constant and is only set by the implementation
+          on startup.
+
+    - name: IANAEnterpriseNumber
+      type: uint32
+      flags:
+        - const
+      default: 0
+      description: >
+          The 24-bit IANA Private Enterprise Number for the company or organization
+          that has specified the boot initiator. This is a machine-specific
+          constant. The implementing application is responsible for setting
+          this to the proper machine-specific value (0x000000..0xFFFFFF)
+          according to https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers.
+
+          The property is constant and is only set by the implementation
+          on startup.
+
+    - name: Data
+      type: array[byte]
+      description: >
+          The array of data bytes for the boot initiator to treat
+          in its specific way. This interface doesn't impose any
+          limitiations on the format or make any assumptions regarding
+          it. The boot initiator is responsible for parsing this array.
+
+          The size of the array is a constant depending on the requirements
+          set by the boot initiator used for a particular architecture or
+          a machine. The implementing application is responsible for setting
+          the size of this array to the proper value.
+
+          For conformance to the IPMI 2.0 specification, the size of the array
+          plus 3 (the size of IPMI 2.0 representation of IANA Enterprise Number)
+          must be a multiple of 16 with the minimum allowed size being 77
+          (5 x 16-byte blocks, minus 3) if mailbox is at all Supported.
+
+          For IPMI 2.0 this array is supposed to be split into 16-byte
+          blocks by the implementing service (block 0 being made of IANA PEN
+          plus first 13 bytes of this array). Please pay special attention
+          that this array does NOT include the IANA PEN needed for IPMI 2.0.
+          Only the actual PEN-specific data is stored here.
+
+          When partially written to, the remaining parts of this array
+          must not be automatically cleared. This is per IPMI 2.0
+          specification.
+
+          Other interfaces to the boot initiator (such as MCTP) may process
+          this array differently.
diff --git a/meta-yadro/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend b/meta-yadro/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend
new file mode 100644
index 0000000..656e151
--- /dev/null
+++ b/meta-yadro/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend
@@ -0,0 +1,15 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+# Directory with new layer of source tree with additional files
+YAML_DIR = "xyz"
+
+SRC_URI += "file://${YAML_DIR}"
+
+S = "${WORKDIR}/git"
+
+# Merge source tree by original project with our layer of additional files
+do_add_yamls(){
+    cp -r "${WORKDIR}/${YAML_DIR}" "${S}"
+}
+
+addtask do_add_yamls after do_unpack before do_configure
diff --git a/meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Add-support-for-persistent-only-settings.patch b/meta-yadro/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/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/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Add-support-for-boot-initiator-mailbox.patch b/meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Add-support-for-boot-initiator-mailbox.patch
new file mode 100644
index 0000000..922426e
--- /dev/null
+++ b/meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Add-support-for-boot-initiator-mailbox.patch
@@ -0,0 +1,477 @@
+From f19ca89265616e14ba2bb16d9a5418f23157c943 Mon Sep 17 00:00:00 2001
+From: Alexander Amelkin <a.amelkin@yadro.com>
+Date: Mon, 8 Apr 2019 17:58:42 +0300
+Subject: [PATCH] Add support for boot initiator mailbox
+
+Add handlers to process the chassis system option 7
+(boot initiator mailbox). The format of mailbox is
+specific to the machine/bootloader. This commit only
+adds generic handlers to process getting and setting
+of the mailbox data regardless of the content.
+
+Only the IANA Enterprise number is checked in the data
+block 0. Also checked are the data boundaries.
+
+It is expected that a machine-specific override for
+phosphor-settingsd sets the supported state and
+the IANA number according to the used bootloader.
+
+Resolves openbmc/openbmc#3391
+
+Change-Id: Iccbf74c0775f20c70e8deaa7b0a8bd995ebbffea
+Signed-off-by: Alexander Amelkin <a.amelkin@yadro.com>
+Signed-off-by: Ivan Mikhaylov <i.mikhaylov@yadro.com>
+---
+ chassishandler.cpp | 365 ++++++++++++++++++++++++++++++++++++++++++++-
+ chassishandler.hpp |   2 +
+ 2 files changed, 362 insertions(+), 5 deletions(-)
+
+diff --git a/chassishandler.cpp b/chassishandler.cpp
+index 0326806..538154c 100644
+--- a/chassishandler.cpp
++++ b/chassishandler.cpp
+@@ -27,6 +27,7 @@
+ #include <settings.hpp>
+ #include <sstream>
+ #include <string>
++#include <vector>
+ #include <xyz/openbmc_project/Common/error.hpp>
+ #include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
+ #include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
+@@ -125,6 +126,7 @@ namespace internal
+ {
+ 
+ constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
++constexpr auto bootMboxIntf = "xyz.openbmc_project.Control.Boot.Mailbox";
+ constexpr auto bootSourceIntf = "xyz.openbmc_project.Control.Boot.Source";
+ constexpr auto powerRestoreIntf =
+     "xyz.openbmc_project.Control.Power.RestorePolicy";
+@@ -140,8 +142,8 @@ settings::Objects& getObjects()
+     if (objectsPtr == nullptr)
+     {
+         objectsPtr = std::make_unique<settings::Objects>(
+-            dbus, std::vector<std::string>{bootModeIntf, bootSourceIntf,
+-                                           powerRestoreIntf});
++            dbus, std::vector<std::string>{bootMboxIntf, bootModeIntf,
++                                           bootSourceIntf, powerRestoreIntf});
+     }
+     return *objectsPtr;
+ }
+@@ -177,6 +179,20 @@ struct set_sys_boot_options_t
+     uint8_t data[SIZE_BOOT_OPTION];
+ } __attribute__((packed));
+ 
++struct BootMboxBlock
++{
++    uint8_t block;
++    union
++    {
++        struct
++        {
++            uint8_t ipmiIANAEnterprise[3];
++            uint8_t blockZeroData[13];
++        };
++        uint8_t data[16];
++    };
++} __attribute__((packed));
++
+ int getHostNetworkData(get_sys_boot_options_response_t* respptr)
+ {
+     ipmi::PropertyMap properties;
+@@ -1443,6 +1459,124 @@ static ipmi_ret_t setBootMode(const Mode::Modes& mode)
+     return IPMI_CC_OK;
+ }
+ 
++using MboxVec = std::vector<uint8_t>;
++
++// Check if Boot Mailbox is supported.
++static std::optional<bool> isBootMboxSupported()
++{
++    using namespace chassis::internal;
++    using namespace chassis::internal::cache;
++
++    try
++    {
++        settings::Objects& objects = getObjects();
++        auto bootMbox = settings::boot::setting(objects, bootMboxIntf);
++        const auto& bootMboxSetting = std::get<settings::Path>(bootMbox);
++        auto method = dbus.new_method_call(
++            objects.service(bootMboxSetting, bootMboxIntf).c_str(),
++            bootMboxSetting.c_str(), ipmi::PROP_INTF, "Get");
++
++        method.append(bootMboxIntf, "Supported");
++        auto reply = dbus.call(method);
++        std::variant<bool> result;
++        reply.read(result);
++        return std::get<bool>(result);
++    }
++    catch (const std::exception& e)
++    {
++        log<level::ERR>("Error getting Boot/Mailbox/Supported",
++                        entry("ERROR=%s", e.what()));
++        report<InternalFailure>();
++        return std::nullopt;
++    }
++}
++
++static std::optional<uint24_t> getBootMboxIANA()
++{
++    using namespace chassis::internal;
++    using namespace chassis::internal::cache;
++
++    try
++    {
++        settings::Objects& objects = getObjects();
++        auto bootMbox = settings::boot::setting(objects, bootMboxIntf);
++        const auto& bootMboxSetting = std::get<settings::Path>(bootMbox);
++        auto method = dbus.new_method_call(
++            objects.service(bootMboxSetting, bootMboxIntf).c_str(),
++            bootMboxSetting.c_str(), ipmi::PROP_INTF, "Get");
++
++        method.append(bootMboxIntf, "IANAEnterpriseNumber");
++        auto reply = dbus.call(method);
++        std::variant<uint32_t> result;
++        reply.read(result);
++        return std::get<uint32_t>(result);
++    }
++    catch (const std::exception& e)
++    {
++        log<level::ERR>("Error getting Boot/Mailbox/IANAEnterpriseNumber",
++                        entry("ERROR=%s", e.what()));
++        report<InternalFailure>();
++        return std::nullopt;
++    }
++}
++
++static std::optional<MboxVec> getBootMbox()
++{
++    using namespace chassis::internal;
++    using namespace chassis::internal::cache;
++
++    try
++    {
++        settings::Objects& objects = getObjects();
++        auto bootMbox = settings::boot::setting(objects, bootMboxIntf);
++        const auto& bootMboxSetting = std::get<settings::Path>(bootMbox);
++        auto method = dbus.new_method_call(
++            objects.service(bootMboxSetting, bootMboxIntf).c_str(),
++            bootMboxSetting.c_str(), ipmi::PROP_INTF, "Get");
++
++        method.append(bootMboxIntf, "Data");
++        auto reply = dbus.call(method);
++        std::variant<MboxVec> result;
++        reply.read(result);
++        return std::get<MboxVec>(result);
++    }
++    catch (const std::exception& e)
++    {
++        log<level::ERR>("Error getting Boot/Mailbox/Data",
++                        entry("ERROR=%s", e.what()));
++        report<InternalFailure>();
++        return std::nullopt;
++    }
++}
++
++static bool setBootMbox(MboxVec data)
++{
++    using namespace chassis::internal;
++    using namespace chassis::internal::cache;
++
++    try
++    {
++        settings::Objects& objects = getObjects();
++        std::variant<MboxVec> property(data);
++        auto bootMbox = settings::boot::setting(objects, bootMboxIntf);
++        const auto& bootMboxSetting = std::get<settings::Path>(bootMbox);
++        auto method = dbus.new_method_call(
++            objects.service(bootMboxSetting, bootMboxIntf).c_str(),
++            bootMboxSetting.c_str(), ipmi::PROP_INTF, "Set");
++
++        method.append(bootMboxIntf, "Data", property);
++        dbus.call(method);
++        return true;
++    }
++    catch (const std::exception& e)
++    {
++        log<level::ERR>("Error setting Boot/Mailbox/Data",
++                        entry("ERROR=%s", e.what()));
++        report<InternalFailure>();
++        return false;
++    }
++}
++
+ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+                                              ipmi_request_t request,
+                                              ipmi_response_t response,
+@@ -1543,6 +1677,106 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+             return IPMI_CC_UNSPECIFIED_ERROR;
+         }
+     }
++    else if (reqptr->parameter ==
++             static_cast<uint8_t>(BootOptionParameter::BOOT_INITIATOR_MBOX))
++    {
++        // Only allow reading the boot initiator mailbox if Mailbox is supported
++        //
++        // Algorithm:
++        // 1. Get 'Supported' property from the Control.Boot.Mailbox interface
++        // 2. If {1} is 'false', report Parameter not supported (0x80)
++        // 3. Get Block Selector from request
++        // 4. Get 'Data' vector from Control.Boot.Mailbox
++        // 5. If requested block {3} exceeds total vector size {4},
++        //    report Out of space (0xC4)
++        // 6. Return the selected block (16 bytes) from the vector
++
++        BootMboxBlock* rspMboxData =
++            reinterpret_cast<BootMboxBlock*>(resp->data);
++
++        *data_len = 0; // Assume an error and no data
++
++        resp->parm =
++            static_cast<uint8_t>(BootOptionParameter::BOOT_INITIATOR_MBOX);
++
++        try
++        {
++            // Check whether this option is supported
++            std::optional<bool> isSupported = isBootMboxSupported();
++            if (!isSupported)
++            {
++                return IPMI_CC_UNSPECIFIED_ERROR;
++            }
++
++            if (!*isSupported)
++            {
++                log<level::INFO>("Attempt to read unsupported Boot/Mailbox");
++                return IPMI_CC_PARM_NOT_SUPPORTED;
++            }
++            rc = IPMI_CC_OK;
++
++            // Requested block
++            IpmiValue reqBlock = reqptr->set; // Use "set selector"
++            rspMboxData->block = reqBlock;
++
++            // Initially assume it's block 1+
++            uint8_t* rspBlockPtr = rspMboxData->data;
++            size_t blockDataSize = sizeof(rspMboxData->data);
++            size_t dataVecStartOffset = reqBlock * blockDataSize -
++                                        sizeof(rspMboxData->ipmiIANAEnterprise);
++
++            // Adjust pointers and sizes for block 0, and fill in the IANA PEN
++            if (0 == reqBlock)
++            {
++                ipmi::message::Payload tmpPayload;
++                std::optional<uint24_t> IANAEnterprise = getBootMboxIANA();
++                if (!IANAEnterprise)
++                {
++                    return IPMI_CC_INVALID;
++                }
++                tmpPayload.pack((uint32_t)*IANAEnterprise);
++                std::copy(tmpPayload.raw.begin(), tmpPayload.raw.end(),
++                          rspMboxData->ipmiIANAEnterprise);
++
++                rspBlockPtr = rspMboxData->blockZeroData;
++                blockDataSize = sizeof(rspMboxData->blockZeroData);
++                dataVecStartOffset = 0;
++            }
++
++            // Get the total data size
++            std::optional<MboxVec> dataVec = getBootMbox();
++            if (!dataVec)
++            {
++                return IPMI_CC_INVALID;
++            }
++
++            // Does the requested block exist?
++            if ((*dataVec).size() < dataVecStartOffset + blockDataSize)
++            {
++                size_t total_size =
++                    (*dataVec).size() + sizeof(rspMboxData->ipmiIANAEnterprise);
++                size_t normalBlockSize = sizeof(rspMboxData->data);
++                log<level::ERR>(
++                    "Attempt to read unsupported block",
++                    entry("REQUESTED_BLOCK=%d", reqBlock),
++                    entry("MAX_BLOCK=%d", total_size / normalBlockSize));
++                return IPMI_CC_PARM_OUT_OF_RANGE;
++            }
++
++            // Copy the data to response from specified offset in d-bus vector
++            for (size_t i = 0; i < blockDataSize; ++i)
++            {
++                rspBlockPtr[i] = (*dataVec)[dataVecStartOffset + i];
++            }
++            *data_len = static_cast<uint8_t>(
++                BootOptionResponseSize::BOOT_INITIATOR_MBOX);
++        }
++        catch (InternalFailure& e)
++        {
++            report<InternalFailure>();
++            return IPMI_CC_UNSPECIFIED_ERROR;
++        }
++    }
+     else if (reqptr->parameter ==
+              static_cast<uint8_t>(BootOptionParameter::OPAL_NETWORK_SETTINGS))
+     {
+@@ -1599,11 +1833,9 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+     // This IPMI command does not have any resposne data
+     *data_len = 0;
+ 
+-    /*  000101
++    /*
+      * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
+-     * This is the only parameter used by petitboot.
+      */
+-
+     if (reqptr->parameter == (uint8_t)BootOptionParameter::BOOT_FLAGS)
+     {
+         IpmiValue bootOption = ((reqptr->data[1] & 0x3C) >> 2);
+@@ -1697,6 +1929,129 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+             return IPMI_CC_UNSPECIFIED_ERROR;
+         }
+     }
++    else if (reqptr->parameter ==
++             static_cast<uint8_t>(BootOptionParameter::BOOT_INITIATOR_MBOX))
++    {
++        // Only allow writing to boot initiator mailbox if:
++        // 1. Mailbox is supported
++        // 2. IANA PEN matches.
++        //
++        // Algorithm:
++        // 1. Get 'Supported' property from Control.Boot.Mailbox interface
++        // 2. If {1} is 'false', report Parameter not supported (0x80)
++        // 3. Get Block Selector from request
++        // 4. Get 'Data' array from Control.Boot.Mailbox
++        // 5. If requested block {3} exceeds total vector size {4},
++        //    report Out of range (0xC9)
++        // 6. If requsted block {3} is 0:
++        //    4.1. Get IANA PEN from request
++        //    4.2. Get 'IANAEnterpriseNumber' property from Control.Boot.Mailbox
++        //    4.3. If {4.1} doesn't match {4.2}, report 0xCC error (Invalid
++        //         data field in request)
++        // 7. Overwrite the 16 bytes at offset {3}*16 with the data from request
++        // 8. Update the 'Data' array in Control.Boot.Mailbox
++
++        BootMboxBlock* reqMboxData =
++            reinterpret_cast<BootMboxBlock*>(reqptr->data);
++
++        try
++        {
++            std::optional<bool> isSupported = isBootMboxSupported();
++            if (!isSupported)
++            {
++                return IPMI_CC_UNSPECIFIED_ERROR;
++            }
++
++            if (!*isSupported)
++            {
++                log<level::INFO>("Attempt to read unsupported Boot/Mailbox");
++                return IPMI_CC_PARM_NOT_SUPPORTED;
++            }
++
++            // Requested block
++            IpmiValue reqBlock = reqMboxData->block;
++
++            // Initially assume it's block 1+
++            uint8_t* reqBlockPtr = reqMboxData->data;
++            size_t blockDataSize = sizeof(reqMboxData->data);
++            size_t dataVecStartOffset = reqBlock * blockDataSize -
++                                        sizeof(reqMboxData->ipmiIANAEnterprise);
++
++            // Adjust pointers and sizes for block 0, and fill in the IANA PEN
++            if (0 == reqBlock)
++            {
++                uint24_t reqIANAEnterprise;
++                std::vector<uint8_t> tmp(
++                    &reqMboxData->ipmiIANAEnterprise[0],
++                    &reqMboxData->ipmiIANAEnterprise[0] +
++                        sizeof(reqMboxData->ipmiIANAEnterprise));
++                ipmi::message::Payload tmpPayload(
++                    std::forward<std::vector<uint8_t>>(tmp));
++                ipmi::Cc unpackError = tmpPayload.unpack(reqIANAEnterprise);
++                if (unpackError != ipmi::ccSuccess)
++                {
++                    return unpackError;
++                }
++
++                std::optional<uint24_t> IANAEnterprise = getBootMboxIANA();
++                if (!IANAEnterprise)
++                {
++                    return IPMI_CC_INVALID;
++                }
++
++                if (*IANAEnterprise != reqIANAEnterprise)
++                {
++                    log<level::ERR>(
++                        "Unsupported IANA Enterprise number",
++                        entry("REQUESTED_IANA=%d",
++                              static_cast<uint32_t>(reqIANAEnterprise)),
++                        entry("SUPPORTED_IANA=%d",
++                              static_cast<uint32_t>(*IANAEnterprise)));
++                    return IPMI_CC_INVALID_FIELD_REQUEST;
++                }
++
++                // For block 0 operate on data after IANA PEN
++                reqBlockPtr = reqMboxData->blockZeroData;
++                blockDataSize = sizeof(reqMboxData->blockZeroData);
++                dataVecStartOffset = 0;
++            }
++
++            // Get the data vector from d-bus
++            std::optional<MboxVec> dataVec = getBootMbox();
++            if (!dataVec)
++            {
++                return IPMI_CC_INVALID;
++            }
++
++            // Does the requested block exist?
++            if ((*dataVec).size() < dataVecStartOffset + blockDataSize)
++            {
++                size_t total_size =
++                    (*dataVec).size() + sizeof(reqMboxData->ipmiIANAEnterprise);
++                size_t normalBlockSize = sizeof(reqMboxData->data);
++                log<level::ERR>(
++                    "Attempt to read unsupported block",
++                    entry("REQUESTED_BLOCK=%d", reqBlock),
++                    entry("MAX_BLOCK=%d", total_size / normalBlockSize));
++                return IPMI_CC_PARM_OUT_OF_RANGE;
++            }
++
++            // Copy the data from request to specified offset in d-bus vector
++            for (size_t i = 0; i < blockDataSize; ++i)
++            {
++                (*dataVec)[dataVecStartOffset + i] = reqBlockPtr[i];
++            }
++            if (setBootMbox(*dataVec))
++            {
++                rc = IPMI_CC_OK;
++            }
++        }
++        catch (InternalFailure& e)
++        {
++            report<InternalFailure>();
++            return IPMI_CC_UNSPECIFIED_ERROR;
++        }
++    }
+     else if (reqptr->parameter ==
+              (uint8_t)BootOptionParameter::OPAL_NETWORK_SETTINGS)
+     {
+diff --git a/chassishandler.hpp b/chassishandler.hpp
+index dcaf06c..0e738e9 100644
+--- a/chassishandler.hpp
++++ b/chassishandler.hpp
+@@ -48,12 +48,14 @@ enum class BootOptionParameter : size_t
+ {
+     BOOT_INFO = 0x4,
+     BOOT_FLAGS = 0x5,
++    BOOT_INITIATOR_MBOX = 0x07,
+     OPAL_NETWORK_SETTINGS = 0x61
+ };
+ 
+ enum class BootOptionResponseSize : size_t
+ {
+     BOOT_FLAGS = 5,
++    BOOT_INITIATOR_MBOX = 17,
+     OPAL_NETWORK_SETTINGS = 50
+ };
+ 
+-- 
+2.21.1
+
diff --git a/meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend b/meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend
new file mode 100644
index 0000000..a326584
--- /dev/null
+++ b/meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend
@@ -0,0 +1,6 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI_append  = "\
+    file://0001-Add-support-for-persistent-only-settings.patch \
+    file://0002-Add-support-for-boot-initiator-mailbox.patch \
+"