Fix host ssif driver unable to create /dev/ipmi0 interface

When host boots up, during the ssif enumeration, it will send
request commands to BMC to query for data then bring up the
/dev/ipmi0 interface. The timeout duration to wait for data of
host is 15 seconds, if timeouted, host will send other commands
and continue the enumeration.

During the AC or DC cycle, BMC dbus will be busy with a lot of
traffic which is easy to cause the dbus timeout happened. Ipmid
comunicates with ssifbridge via dbus. When ipmid receive requests,
it puts in a queue and response to those requests one by one.
Because of the dbus timeout, ipmid will send the response late
which cause the mismatch and duplicate responses in the request
of host. Let say, host request command 87, but because of the
timeout, ipmid response with command 66 which may be sent by host
previously. And then, ipmid sends response of command 87.
This leads to 2 or more reponses will be sent to host.

These mismatches and duplicate responses will cause host driver
confused and failed to create ssif interface on host.

Tested:
1. Run AC cycle 200 times, ensure that ipmi in-band commands
   still work
2. Run DC cycle 400 times, ensure that ipmi in-band commands
   still work

Signed-off-by: quang.ampere <quangn@amperecomputing.com>
Change-Id: Ie08a6dd376a1460b3e63c7ecb3908ac886c521b0
diff --git a/ssifbridged.cpp b/ssifbridged.cpp
index 12f8e99..da5060b 100644
--- a/ssifbridged.cpp
+++ b/ssifbridged.cpp
@@ -31,6 +31,12 @@
 
 using namespace phosphor::logging;
 
+struct ipmi_cmd {
+    uint8_t netfn;
+    uint8_t lun;
+    uint8_t cmd;
+} prev_req_cmd;
+
 static constexpr const char devBase[] = "/dev/ipmi-ssif-host";
 /* SSIF use IPMI SSIF channel */
 static constexpr const char* ssifBus =
@@ -136,6 +142,11 @@
     uint8_t netfn = rawIter[1] >> netFnShift;
     uint8_t lun = rawIter[1] & lunMask;
     uint8_t cmd = rawIter[2];
+
+    prev_req_cmd.netfn = netfn;
+    prev_req_cmd.lun = lun;
+    prev_req_cmd.cmd = cmd;
+
     if (verbose)
     {
         std::string msgToLog = "Read ssif request message with"
@@ -159,7 +170,8 @@
     static constexpr const char ipmiQueueIntf[] =
         "xyz.openbmc_project.Ipmi.Server";
     static constexpr const char ipmiQueueMethod[] = "execute";
-    bus->async_method_call(
+    static constexpr int dbusTimeout = 40000000;
+    bus->async_method_call_timed(
         [this, netfnCap{netfn}, lunCap{lun},
          cmdCap{cmd}](const boost::system::error_code& ec,
                       const IpmiDbusRspType& response) {
@@ -173,18 +185,26 @@
                         " cmd=" + std::to_string(cmd) +
                         " error=" + ec.message();
                 log<level::ERR>(msgToLog.c_str());
-                // send unspecified error for a D-Bus error
-                constexpr uint8_t ccResponseNotAvailable = 0xce;
                 rsp.resize(sizeof(uint8_t) + sizeof(netfn) + sizeof(cmd) +
                            sizeof(cc));
-                rsp[0] = 3;
-                rsp[1] =
-                    ((netfnCap + 1) << netFnShift) | (lunCap & lunMask);
-                rsp[2] = cmdCap;
-                rsp[3] = ccResponseNotAvailable;
+                /* if dbusTimeout, just return and do not send any response
+                 * to let host continue with other commands, response here
+                 * is potentionally make the response duplicated 
+                 * */
+                return;
             }
             else
             {
+                if(prev_req_cmd.netfn != (netfn-1) ||
+                        prev_req_cmd.lun != lun ||
+                        prev_req_cmd.cmd != cmd)
+                {
+                    /* Only send response to the last request command to void
+                     * duplicated response which makes host driver confused and
+                     * failed to create interface
+                     * */
+                    return;
+                }
                 rsp.resize(sizeof(uint8_t) + sizeof(netfn) + sizeof(cmd) +
                            sizeof(cc) + payload.size());
 
@@ -226,7 +246,7 @@
                 log<level::ERR>(msgToLog.c_str());
             }
         },
-        ipmiQueueService, ipmiQueuePath, ipmiQueueIntf, ipmiQueueMethod,
+        ipmiQueueService, ipmiQueuePath, ipmiQueueIntf, ipmiQueueMethod, dbusTimeout,
         netfn, lun, cmd, data, options);
 }