PEL: Add symbolic FRU support to FRUIdentity

A symbolic FRU is a FRU where the part is known, but the part number is
not available for it.  A trusted symbolic FRU adds the requirement that
the location code is known to be correct so it can be used for lighting
LEDs and FRU replacement.

The symbolic FRU name shares the same field as the part number.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I2fa936d9d7235c5cff245effcdb9d445aefffe23
diff --git a/extensions/openpower-pels/fru_identity.cpp b/extensions/openpower-pels/fru_identity.cpp
index 8cf6382..b8dc94f 100644
--- a/extensions/openpower-pels/fru_identity.cpp
+++ b/extensions/openpower-pels/fru_identity.cpp
@@ -93,6 +93,17 @@
     _size = flattenedSize();
 }
 
+FRUIdentity::FRUIdentity(const std::string& symbolicFRUFromRegistry,
+                         bool trustedLocationCode)
+{
+    _type = substructureType;
+    _flags = (trustedLocationCode) ? symbolicFRUTrustedLocCode : symbolicFRU;
+
+    setSymbolicFRU(symbolicFRUFromRegistry);
+
+    _size = flattenedSize();
+}
+
 std::optional<std::string> FRUIdentity::getPN() const
 {
     if (hasPN())
@@ -231,6 +242,30 @@
     _pnOrProcedureID.back() = 0;
 }
 
+void FRUIdentity::setSymbolicFRU(const std::string& symbolicFRUFromRegistry)
+{
+
+    // Treat this has a HW callout.
+    _flags |= pnSupplied;
+    _flags &= ~maintProcSupplied;
+
+    if (pel_values::symbolicFRUs.count(symbolicFRUFromRegistry))
+    {
+        strncpy(_pnOrProcedureID.data(),
+                pel_values::symbolicFRUs.at(symbolicFRUFromRegistry).c_str(),
+                _pnOrProcedureID.size());
+    }
+    else
+    {
+        log<level::ERR>("Invalid symbolic FRU",
+                        entry("FRU=%s", symbolicFRUFromRegistry.c_str()));
+        strncpy(_pnOrProcedureID.data(), "INVALID", _pnOrProcedureID.size());
+    }
+
+    // ensure null terminated
+    _pnOrProcedureID.back() = 0;
+}
+
 } // namespace src
 } // namespace pels
 } // namespace openpower
diff --git a/extensions/openpower-pels/fru_identity.hpp b/extensions/openpower-pels/fru_identity.hpp
index 669dc01..e5eb864 100644
--- a/extensions/openpower-pels/fru_identity.hpp
+++ b/extensions/openpower-pels/fru_identity.hpp
@@ -95,6 +95,19 @@
     FRUIdentity(const std::string& procedureFromRegistry);
 
     /**
+     * @brief Constructor
+     *
+     * Creates the object with a symbolic FRU callout.
+     *
+     * @param[in] symbolicFRUFromRegistry - The symbolic FRU name as
+     *                                      defined in the message registry.
+     * @param[in] trustedLocationCode - If this FRU callout's location code
+     *                                  can be trusted to be correct.
+     */
+    FRUIdentity(const std::string& symbolicFRUFromRegistry,
+                bool trustedLocationCode);
+
+    /**
      * @brief Flatten the object into the stream
      *
      * @param[in] stream - The stream to write to
@@ -238,6 +251,16 @@
     void setMaintenanceProcedure(const std::string& procedureFromRegistry);
 
     /**
+     * @brief Sets the 8 character null terminated symbolic FRU
+     *        field.  This is in the same field as the part
+     *        number since they are mutually exclusive.
+     *
+     * @param[in] symbolicFRUFromRegistry - The symbolic FRU name as
+     *                                      defined in the message registry.
+     */
+    void setSymbolicFRU(const std::string& symbolicFRUFromRegistry);
+
+    /**
      * @brief The callout substructure type field. Will be "ID".
      */
     uint16_t _type;
diff --git a/extensions/openpower-pels/pel_values.cpp b/extensions/openpower-pels/pel_values.cpp
index 07a0671..baf302a 100644
--- a/extensions/openpower-pels/pel_values.cpp
+++ b/extensions/openpower-pels/pel_values.cpp
@@ -218,6 +218,13 @@
 const std::map<std::string, std::string> maintenanceProcedures = {
     {"no_vpd_for_fru", "BMCSP01"}};
 
+/**
+ * @brief Map of the registry names for the symbolic FRUs to their
+ *        actual names.
+ */
+const std::map<std::string, std::string> symbolicFRUs = {
+    {"service_docs", "SVCDOCS"}};
+
 PELValues::const_iterator findByValue(uint32_t value, const PELValues& fields)
 {
     return std::find_if(fields.begin(), fields.end(),
diff --git a/extensions/openpower-pels/pel_values.hpp b/extensions/openpower-pels/pel_values.hpp
index 04c287d..5f8b852 100644
--- a/extensions/openpower-pels/pel_values.hpp
+++ b/extensions/openpower-pels/pel_values.hpp
@@ -136,6 +136,11 @@
  */
 extern const std::map<std::string, std::string> maintenanceProcedures;
 
+/**
+ * @brief Map for symbolic FRUs.
+ */
+extern const std::map<std::string, std::string> symbolicFRUs;
+
 } // namespace pel_values
 } // namespace pels
 } // namespace openpower