Enhance system VPD map

This commit enhances system VPD map to incorporate useful
information about each critical keywords like the default
keyword value, if the keyword is restorable or not, if the
keyword is resettable at manufacturing or not, if a PEL
required or not when failed to restore the keywords.

Tested the following,
1. system VPD restore on cache via parser
2. system VPD restore on hardware via vpd-manager
3. system VPD restore via vpd-tool
4. system VPD reset via vpd-tool

Signed-off-by: Priyanga Ramasamy <priyanga24@in.ibm.com>
Change-Id: I29ae6016f6d84342a8ad91ba72617a45121cf8a6
diff --git a/ibm_vpd_app.cpp b/ibm_vpd_app.cpp
index 805eee2..28ff9b1 100644
--- a/ibm_vpd_app.cpp
+++ b/ibm_vpd_app.cpp
@@ -842,8 +842,10 @@
         if (it != vpdMap.end())
         {
             const auto& kwdListForRecord = systemRecKwdPair.second;
-            for (const auto& keyword : kwdListForRecord)
+            for (const auto& keywordInfo : kwdListForRecord)
             {
+                const auto keyword = get<0>(keywordInfo);
+
                 DbusPropertyMap& kwdValMap = it->second;
                 auto iterator = kwdValMap.find(keyword);
 
@@ -856,23 +858,13 @@
                     const string& busValue = readBusProperty(
                         objectPath, ipzVpdInf + recordName, keyword);
 
-                    std::string defaultValue{' '};
+                    const auto& defaultValue = get<1>(keywordInfo);
+                    Binary busDataInBinary(busValue.begin(), busValue.end());
+                    Binary kwdDataInBinary(kwdValue.begin(), kwdValue.end());
 
-                    // Explicit check for D0 is required as this keyword will
-                    // never be blank and 0x00 should be treated as no value in
-                    // this case.
-                    if (recordName == "UTIL" && keyword == "D0")
+                    if (busDataInBinary != defaultValue)
                     {
-                        // default value of kwd D0 is 0x00. This kwd will never
-                        // be blank.
-                        defaultValue = '\0';
-                    }
-
-                    if (busValue.find_first_not_of(defaultValue) !=
-                        string::npos)
-                    {
-                        if (kwdValue.find_first_not_of(defaultValue) !=
-                            string::npos)
+                        if (kwdDataInBinary != defaultValue)
                         {
                             // both the data are present, check for mismatch
                             if (busValue != kwdValue)
@@ -917,26 +909,16 @@
                             }
                         }
 
-                        // If cache data is not blank, then irrespective of
-                        // hardware data(blank or other than cache), copy the
+                        // If cache data is not default, then irrespective of
+                        // hardware data(default or other than cache), copy the
                         // cache data to vpd map as we don't need to change the
                         // cache data in either case in the process of
                         // restoring system vpd.
-                        Binary busData(busValue.begin(), busValue.end());
                         kwdValue = busValue;
                     }
-                    else if (kwdValue.find_first_not_of(defaultValue) ==
-                             string::npos)
+                    else if (kwdDataInBinary == defaultValue &&
+                             get<2>(keywordInfo)) // Check isPELRequired is true
                     {
-                        if (recordName == "VSYS" && keyword == "FV")
-                        {
-                            // Continue to the next keyword without logging +PEL
-                            // for VSYS FV(stores min version of BMC firmware).
-                            // Reason:There is a requirement to support blank FV
-                            // so that customer can use the system without
-                            // upgrading BMC to the minimum required version.
-                            continue;
-                        }
                         string errMsg = "VPD is blank on both cache and "
                                         "hardware for record: ";
                         errMsg += (*it).first;
diff --git a/ibm_vpd_utils.hpp b/ibm_vpd_utils.hpp
index 2b75c7d..508f9d3 100644
--- a/ibm_vpd_utils.hpp
+++ b/ibm_vpd_utils.hpp
@@ -13,14 +13,29 @@
 namespace vpd
 {
 
-// Map to hold record, kwd pair which can be re-stored at standby.
-// The list of keywords for VSYS record is as per the S0 system. Should
-// be updated for another type of systems
-static const std::unordered_map<std::string, std::vector<std::string>>
-    svpdKwdMap{{"VSYS", {"BR", "TM", "SE", "SU", "RB", "WN", "RG", "FV"}},
-               {"VCEN", {"FC", "SE"}},
-               {"LXR0", {"LX"}},
-               {"UTIL", {"D0"}}};
+// Map which holds system vpd keywords which can be restored at standby and via
+// vpd-tool and also can be used to reset keywords to its defaults at
+// manufacturing. The list of keywords for VSYS record is as per the S0 system.
+// Should be updated for another type of systems For those keywords whose
+// default value is system specific, the default value field is left empty.
+// Record : {Keyword, Default value, Is PEL required on restore failure, Is MFG
+// reset required}
+static const inventory::SystemKeywordsMap svpdKwdMap{
+    {"VSYS",
+     {inventory::SystemKeywordInfo("BR", Binary(2, 0x20), true, true),
+      inventory::SystemKeywordInfo("TM", Binary(8, 0x20), true, true),
+      inventory::SystemKeywordInfo("SE", Binary(7, 0x20), true, true),
+      inventory::SystemKeywordInfo("SU", Binary(6, 0x20), true, true),
+      inventory::SystemKeywordInfo("RB", Binary(4, 0x20), true, true),
+      inventory::SystemKeywordInfo("WN", Binary(12, 0x20), true, true),
+      inventory::SystemKeywordInfo("RG", Binary(4, 0x20), true, true),
+      inventory::SystemKeywordInfo("FV", Binary(32, 0x20), false, true)}},
+    {"VCEN",
+     {inventory::SystemKeywordInfo("FC", Binary(), true, false),
+      inventory::SystemKeywordInfo("SE", Binary(7, 0x20), true, true)}},
+    {"LXR0", {inventory::SystemKeywordInfo("LX", Binary(), true, false)}},
+    {"UTIL",
+     {inventory::SystemKeywordInfo("D0", Binary(1, 0x00), true, true)}}};
 
 /** @brief Return the hex representation of the incoming byte
  *
diff --git a/types.hpp b/types.hpp
index a46e677..6579f99 100644
--- a/types.hpp
+++ b/types.hpp
@@ -61,6 +61,19 @@
 using RestoredEeproms = std::tuple<Path, std::string, Keyword, Binary>;
 using ReplaceableFrus = std::vector<VPDfilepath>;
 using EssentialFrus = std::vector<Path>;
+using RecordName = std::string;
+using KeywordDefault = Binary;
+using isPELReqOnRestoreFailure = bool;
+using isMFGResetRequired = bool;
+using SystemKeywordInfo =
+    std::tuple<Keyword, KeywordDefault, isPELReqOnRestoreFailure,
+               isMFGResetRequired>;
+
+/** Map of system backplane records to list of keywords and its related data. {
+ * Record : { Keyword, Default value, Is PEL required on restore failure, Is MFG
+ * reset required }} **/
+using SystemKeywordsMap =
+    std::unordered_map<RecordName, std::vector<SystemKeywordInfo>>;
 } // namespace inventory
 
 } // namespace vpd
diff --git a/vpd-manager/manager.cpp b/vpd-manager/manager.cpp
index c4d9838..cdf7a63 100644
--- a/vpd-manager/manager.cpp
+++ b/vpd-manager/manager.cpp
@@ -123,8 +123,10 @@
         if (it != vpdMap.end())
         {
             const auto& kwdListForRecord = systemRecKwdPair.second;
-            for (const auto& keyword : kwdListForRecord)
+            for (const auto& keywordInfo : kwdListForRecord)
             {
+                const auto& keyword = get<0>(keywordInfo);
+
                 DbusPropertyMap& kwdValMap = it->second;
                 auto iterator = kwdValMap.find(keyword);
 
diff --git a/vpd_tool_impl.cpp b/vpd_tool_impl.cpp
index c15647c..ef7ad0b 100644
--- a/vpd_tool_impl.cpp
+++ b/vpd_tool_impl.cpp
@@ -696,8 +696,10 @@
         string busStr{}, hwValStr{};
         string mismatch = "NO"; // no mismatch
 
-        for (const auto& keyword : recordKw.second)
+        for (const auto& keywordInfo : recordKw.second)
         {
+            const auto& keyword = get<0>(keywordInfo);
+
             string hardwareValue{};
             auto recItr = vpdMap.find(record);
 
@@ -953,4 +955,4 @@
         }
 
     } while (true);
-}
+}
\ No newline at end of file