Add slot ipmb command

Added slot ipmb command which is used to send commands to add-in cards.
BMC will act as a bridge and forwards the data to the add-in card and
returns the response from the add-in card.

Tested:

ipmitool raw 0x3e 0x51 <address_type> <slot_num> <slave_addr> <net_fun>
<cmd>
00 //success

ipmitool raw 0x3e 0x51 <address_type> <invalid_slot_num> <slave_addr>
<net_fun> <cmd>
0xce //Command response could not be provided

ipmitool raw 0x3e 0x51 <address_type> <slot_num> <invalid_slave_addr>
<net_fun> <cmd>
0xce //Command response could not be provided

Tested the command from the shell using cmdtool via KCS interface and it
works fine.

Signed-off-by: Rajashekar Gade Reddy <raja.sekhar.reddy.gade@linux.intel.com>
Change-Id: Ic772e169569ee91328315a02633089d3894e1b0f
diff --git a/src/oemcommands.cpp b/src/oemcommands.cpp
index 7adb36a..2d639fb 100644
--- a/src/oemcommands.cpp
+++ b/src/oemcommands.cpp
@@ -606,6 +606,49 @@
     return ipmi::responseSuccess();
 }
 
+ipmi::RspType<uint8_t, std::vector<uint8_t>>
+    ipmiOEMSlotIpmb(ipmi::Context::ptr ctx, uint6_t reserved1,
+                    uint2_t slotNumber, uint3_t baseBoardSlotNum,
+                    uint3_t riserSlotNum, uint2_t reserved2, uint8_t slaveAddr,
+                    uint8_t netFn, uint8_t cmd,
+                    std::optional<std::vector<uint8_t>> writeData)
+{
+    if (reserved1 || reserved2)
+    {
+        return ipmi::responseInvalidFieldRequest();
+    }
+
+    boost::system::error_code ec;
+    using ipmbResponse = std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
+                                    std::vector<uint8_t>>;
+    ipmbResponse res = ctx->bus->yield_method_call<ipmbResponse>(
+        ctx->yield, ec, "xyz.openbmc_project.Ipmi.Channel.Ipmb",
+        "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
+        "SlotIpmbRequest", static_cast<uint8_t>(slotNumber),
+        static_cast<uint8_t>(baseBoardSlotNum), slaveAddr, netFn, cmd,
+        *writeData);
+    if (ec)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "Failed to call dbus method SlotIpmbRequest");
+        return ipmi::responseUnspecifiedError();
+    }
+
+    std::vector<uint8_t> dataReceived(0);
+    int status = -1;
+    uint8_t resNetFn = 0, resLun = 0, resCmd = 0, cc = 0;
+
+    std::tie(status, resNetFn, resLun, resCmd, cc, dataReceived) = res;
+
+    if (status)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "Failed to get response from SlotIpmbRequest");
+        return ipmi::responseResponseError();
+    }
+    return ipmi::responseSuccess(cc, dataReceived);
+}
+
 ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
                                        ipmi_request_t request,
                                        ipmi_response_t response,
@@ -3545,6 +3588,9 @@
                     intel::general::cmdSendEmbeddedFWUpdStatus,
                     Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
 
+    registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb,
+                    Privilege::Admin, ipmiOEMSlotIpmb);
+
     ipmiPrintAndRegister(intel::netFnGeneral,
                          intel::general::cmdSetPowerRestoreDelay, NULL,
                          ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);