Ipmbbridge: Add support for multiple sub channel.

Added Multiple sub channels support for ipmb and me
type to communicate with more than one device of same type.

ChannelType supports only two channels ME and ipmb.
Using combination of devIndex and channelType approach,
can support multiple sub channels without affecting the
existing functionalities.

Single host or channel, "devIndex" will be set default index as 0.

For multiple channel under same type need to provide devIndex in
json configurations. This approach uses the sendRequest method's
first parameter values for MSB 6 bits as "devIndex" and
the remaining 2 bits as "channelType".

TESTED : Built Facebook YosemiteV2 & Tiogapass images and loaded on
the target hardware. We are able to see BMC to all
host communications through Ipmb.

Signed-off-by: Kumar Thangavel <thangavel.k@hcl.com>
Change-Id: I20a7231993a0dd1f9d396dde114837380302dc76
diff --git a/README b/README
new file mode 100644
index 0000000..f901e51
--- /dev/null
+++ b/README
@@ -0,0 +1,64 @@
+Sample config options available to configure :
+
+1. Single channel with one me and ipmb :
+
+{
+  "channels": [
+    {
+      "type": "me",
+      "slave-path": "/dev/ipmb-4",
+      "bmc-addr": 32,
+      "remote-addr": 44
+    },
+    {
+      "type": "ipmb",
+      "slave-path": "/dev/ipmb-9",
+      "bmc-addr": 32,
+      "remote-addr": 96
+    }
+  ]
+}
+
+2. Multiple sub channels with me and ipmb :
+
+{
+  "channels": [
+    {
+      "type": "me",
+      "slave-path": "/dev/ipmb-1",
+      "bmc-addr": 32,
+      "remote-addr": 64,
+      "devIndex": 0
+    },
+    {
+      "type": "ipmb",
+      "slave-path": "/dev/ipmb-3",
+      "bmc-addr": 32,
+      "remote-addr": 64,
+      "devIndex": 0
+    },
+    {
+      "type": "me",
+      "slave-path": "/dev/ipmb-5",
+      "bmc-addr": 32,
+      "remote-addr": 64,
+      "devIndex": 1
+    },
+    {
+      "type": "ipmb",
+      "slave-path": "/dev/ipmb-7",
+      "bmc-addr": 32,
+      "remote-addr": 64,
+      "devIndex": 1
+    }
+ ]
+}
+
+Config fields :
+
+type          : This points to the ChannelType. It can be ME or ipmb channel.
+slave-path    : The ipmb device path.
+bmc-addr      : This is BMC slave address to communicate between BMC and device.
+remote-addr   : This is Remote/requestor slave address to communicate between BMC and device.
+devIndex      : This devIndex used to identify the particular device/host.
+
diff --git a/ipmbbridged.cpp b/ipmbbridged.cpp
index 6496bb8..3dc1a76 100644
--- a/ipmbbridged.cpp
+++ b/ipmbbridged.cpp
@@ -518,11 +518,11 @@
 
 IpmbChannel::IpmbChannel(boost::asio::io_service &io,
                          uint8_t ipmbBmcSlaveAddress,
-                         uint8_t ipmbRqSlaveAddress, ipmbChannelType type,
+                         uint8_t ipmbRqSlaveAddress, uint8_t channelIdx,
                          std::shared_ptr<IpmbCommandFilter> commandFilter) :
     i2cSlaveDescriptor(io),
     ipmbBmcSlaveAddress(ipmbBmcSlaveAddress),
-    ipmbRqSlaveAddress(ipmbRqSlaveAddress), type(type),
+    ipmbRqSlaveAddress(ipmbRqSlaveAddress), channelIdx(channelIdx),
     commandFilter(commandFilter)
 {
 }
@@ -684,9 +684,19 @@
     return ipmbRqSlaveAddress;
 }
 
+uint8_t IpmbChannel::getDevIndex()
+{
+    return channelIdx >> 2;
+}
+
+uint8_t IpmbChannel::getChannelIdx()
+{
+    return channelIdx;
+}
+
 ipmbChannelType IpmbChannel::getChannelType()
 {
-    return type;
+    return static_cast<ipmbChannelType>((channelIdx & 3));
 }
 
 void IpmbChannel::addFilter(const uint8_t respNetFn, const uint8_t cmd)
@@ -761,12 +771,12 @@
     return returnStatus(ipmbResponseStatus::timeout);
 }
 
-static IpmbChannel *getChannel(ipmbChannelType channelType)
+static IpmbChannel *getChannel(uint8_t reqChannel)
 {
     auto channel =
         std::find_if(ipmbChannels.begin(), ipmbChannels.end(),
-                     [channelType](IpmbChannel &channel) {
-                         return channel.getChannelType() == channelType;
+                     [reqChannel](IpmbChannel &channel) {
+                         return channel.getChannelIdx() == reqChannel;
                      });
     if (channel != ipmbChannels.end())
     {
@@ -792,6 +802,7 @@
     }
     try
     {
+        uint8_t devIndex = 0;
         auto data = nlohmann::json::parse(configFile, nullptr);
         for (const auto &channelConfig : data["channels"])
         {
@@ -799,10 +810,17 @@
             const std::string &slavePath = channelConfig["slave-path"];
             uint8_t bmcAddr = channelConfig["bmc-addr"];
             uint8_t reqAddr = channelConfig["remote-addr"];
+
             ipmbChannelType type = ipmbChannelTypeMap.at(typeConfig);
 
-            auto channel = ipmbChannels.emplace(ipmbChannels.end(), io, bmcAddr,
-                                                reqAddr, type, commandFilter);
+            if (channelConfig.contains("devIndex"))
+            {
+                devIndex = channelConfig["devIndex"];
+            }
+
+            auto channel = ipmbChannels.emplace(
+                ipmbChannels.end(), io, bmcAddr, reqAddr,
+                ((devIndex << 2) | static_cast<uint8_t>(type)), commandFilter);
             if (channel->ipmbChannelInit(slavePath.c_str()) < 0)
             {
                 phosphor::logging::log<phosphor::logging::level::ERR>(
@@ -829,7 +847,8 @@
 auto ipmbHandleRequest = [](boost::asio::yield_context yield,
                             uint8_t reqChannel, uint8_t netfn, uint8_t lun,
                             uint8_t cmd, std::vector<uint8_t> dataReceived) {
-    IpmbChannel *channel = getChannel(static_cast<ipmbChannelType>(reqChannel));
+    IpmbChannel *channel = getChannel(reqChannel);
+
     if (channel == nullptr)
     {
         phosphor::logging::log<phosphor::logging::level::ERR>(
@@ -883,10 +902,10 @@
 
             message.read(reqChannel, busId, slaveAddr);
 
-            IpmbChannel *channel =
-                getChannel(static_cast<ipmbChannelType>(reqChannel));
+            IpmbChannel *channel = getChannel(reqChannel);
+
             if (channel == nullptr ||
-                reqChannel != static_cast<uint8_t>(ipmbChannelType::ipmb))
+                channel->getChannelType() != ipmbChannelType::ipmb)
             {
                 phosphor::logging::log<phosphor::logging::level::ERR>(
                     "addUpdateSlaveAddrHandler: invalid channel");
@@ -923,8 +942,8 @@
             std::vector<uint8_t> dataReceived;
             message.read(reqChannel, netFn, lun, cmd, dataReceived);
 
-            IpmbChannel *channel =
-                getChannel(static_cast<ipmbChannelType>(reqChannel));
+            IpmbChannel *channel = getChannel(reqChannel);
+
             if (channel == nullptr)
             {
                 phosphor::logging::log<phosphor::logging::level::ERR>(
diff --git a/ipmbbridged.hpp b/ipmbbridged.hpp
index c08005d..052c193 100644
--- a/ipmbbridged.hpp
+++ b/ipmbbridged.hpp
@@ -262,7 +262,7 @@
 {
   public:
     IpmbChannel(boost::asio::io_service &io, uint8_t ipmbBmcSlaveAddress,
-                uint8_t ipmbRqSlaveAddress, ipmbChannelType type,
+                uint8_t ipmbRqSlaveAddress, uint8_t channelIdx,
                 std::shared_ptr<IpmbCommandFilter> commandFilter);
 
     IpmbChannel(const IpmbChannel &) = delete;
@@ -278,6 +278,10 @@
 
     uint8_t getBusId();
 
+    uint8_t getDevIndex();
+
+    uint8_t getChannelIdx();
+
     uint8_t getBmcSlaveAddress();
 
     uint8_t getRqSlaveAddress();
@@ -301,8 +305,7 @@
     uint8_t ipmbBmcSlaveAddress;
     uint8_t ipmbRqSlaveAddress;
     uint8_t ipmbBusId;
-
-    ipmbChannelType type;
+    uint8_t channelIdx;
 
     std::shared_ptr<IpmbCommandFilter> commandFilter;