Allow more than 256 IPMI sensors in a system

Systems with more than 255 IPMI sensors report strange values for
sensors assigned beyond the 255 limit for a single LUN. This is due to
the sensor number assignment rolling over to 0, and then applying the
most recent SDR values to the sensor calculation.

This change assigns up to 255 sensors to a single LUN (0xFF is
reserved). When the 256th sensor is assigned the sensor gets placed in
the LUN. LUNs 0, 1, and 3 are used, as LUN 2 is special.

Another guard has been created that throws an exception when more than
765 sensors have been assigned. This makes it obvious to the system
designer the limit for IPMI sensors has been reached.

Tested:
Forced the maxmimum number of sensors in the system to be 63 per LUN.

"ipmitool sdr elist" returned correct values for every sensor even
when the sensor number displayed in the printout matched the value of
a sensor printed earlier.

"ipmitool sensor get P3V3" returns a valid reading. In my test "P3V3"
was in LUN1.

"ipmitool raw 4 0x20 0" reported 63 sensors for LUN0, and that LUN0
and LUN1 had sensors.

"ipmitool raw -l 1 4 0x20 0" reported the remaining sensor count.

"ipmitool raw 0xa 0x2d 0" returns the correct value for LUN0 Sensor 0

"ipmitool raw -l 1 0xa 0x2d 0" returns the correct value for LUN1
Sensor 0

Change-Id: Ic1708b66339e57b1b765f5a9a684e829a0ec8fba
Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com>
diff --git a/include/sdrutils.hpp b/include/sdrutils.hpp
index b3d7689..43a53fd 100644
--- a/include/sdrutils.hpp
+++ b/include/sdrutils.hpp
@@ -48,6 +48,13 @@
 
 using SensorNumMap = boost::bimap<int, std::string>;
 
+static constexpr uint16_t maxSensorsPerLUN = 255;
+static constexpr uint16_t maxIPMISensors = (maxSensorsPerLUN * 3);
+static constexpr uint16_t lun1Sensor0 = 0x100;
+static constexpr uint16_t lun3Sensor0 = 0x300;
+static constexpr uint16_t invalidSensorNumber = 0xFFFF;
+static constexpr uint8_t reservedSensorNumber = 0xFF;
+
 namespace details
 {
 inline static bool getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree)
@@ -131,11 +138,28 @@
 
     sensorNumMapPtr = std::make_shared<SensorNumMap>();
 
-    uint8_t sensorNum = 0;
+    uint16_t sensorNum = 0;
+    uint16_t sensorIndex = 0;
     for (const auto& sensor : *sensorTree)
     {
         sensorNumMapPtr->insert(
-            SensorNumMap::value_type(sensorNum++, sensor.first));
+            SensorNumMap::value_type(sensorNum, sensor.first));
+        sensorIndex++;
+        if (sensorIndex == maxSensorsPerLUN)
+        {
+            sensorIndex = lun1Sensor0;
+        }
+        else if (sensorIndex == (lun1Sensor0 | maxSensorsPerLUN))
+        {
+            // Skip assigning LUN 0x2 any sensors
+            sensorIndex = lun3Sensor0;
+        }
+        else if (sensorIndex == (lun3Sensor0 | maxSensorsPerLUN))
+        {
+            // this is an error, too many IPMI sensors
+            throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
+        }
+        sensorNum = sensorIndex;
     }
     sensorNumMap = sensorNumMapPtr;
     sensorNumMapUpated = true;
@@ -214,13 +238,13 @@
     return sensorType;
 }
 
-inline static uint8_t getSensorNumberFromPath(const std::string& path)
+inline static uint16_t getSensorNumberFromPath(const std::string& path)
 {
     std::shared_ptr<SensorNumMap> sensorNumMapPtr;
     details::getSensorNumMap(sensorNumMapPtr);
     if (!sensorNumMapPtr)
     {
-        return 0xFF;
+        return invalidSensorNumber;
     }
 
     try
@@ -230,7 +254,7 @@
     catch (std::out_of_range& e)
     {
         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
-        return 0xFF;
+        return invalidSensorNumber;
     }
 }
 
@@ -240,7 +264,7 @@
     return 0x1; // reading type = threshold
 }
 
-inline static std::string getPathFromSensorNumber(uint8_t sensorNum)
+inline static std::string getPathFromSensorNumber(uint16_t sensorNum)
 {
     std::shared_ptr<SensorNumMap> sensorNumMapPtr;
     details::getSensorNumMap(sensorNumMapPtr);
diff --git a/include/sensorcommands.hpp b/include/sensorcommands.hpp
index c0d7853..a7f9fb2 100644
--- a/include/sensorcommands.hpp
+++ b/include/sensorcommands.hpp
@@ -121,7 +121,8 @@
 namespace ipmi
 {
 extern SensorSubTree sensorTree;
-static ipmi_ret_t getSensorConnection(uint8_t sensnum, std::string& connection,
+static ipmi_ret_t getSensorConnection(ipmi::Context::ptr ctx, uint8_t sensnum,
+                                      std::string& connection,
                                       std::string& path)
 {
     if (sensorTree.empty() && !getSensorSubtree(sensorTree))
@@ -129,22 +130,22 @@
         return IPMI_CC_RESPONSE_ERROR;
     }
 
-    if (sensorTree.size() < (sensnum + 1))
+    if (ctx == nullptr)
+    {
+        return IPMI_CC_RESPONSE_ERROR;
+    }
+
+    path = getPathFromSensorNumber((ctx->lun << 8) | sensnum);
+    if (path.empty())
     {
         return IPMI_CC_INVALID_FIELD_REQUEST;
     }
 
-    uint8_t sensorIndex = sensnum;
     for (const auto& sensor : sensorTree)
     {
-        if (sensorIndex-- == 0)
+        if (path == sensor.first)
         {
-            if (!sensor.second.size())
-            {
-                return IPMI_CC_RESPONSE_ERROR;
-            }
             connection = sensor.second.begin()->first;
-            path = sensor.first;
             break;
         }
     }