PEL: Support 'PossibleSubsystems' in msg registry

Add a 'PossibleSubsystems' field to the message registry schema where
someone can list which subsystems they might pass into the PEL_SUBSYSTEM
AdditionalData property field when creating a PEL.

The PossibleSubsystems value will be used by a off-BMC script that
generates field documentation for SRCs, so it knows what all SRC ASCII
string values are possible for that entry since the subsystem is part of
them. For example, if that field was ['processor', 'memory'], then that
means the possible SRCs are BD10AAAA and BD20AAAA for reason code
'AAAA'.

The Subsystem and PossibleSubsystems fields are mutually exclusive in
the message registry, so code changes had to be made to support the
subsystem field now being optional.

There is now a chance that even though the subsystem is supposed to be
passed in using PEL_SUBSYSTEM, it isn't.  In that case, the 'Other'
subsystem will be used, since it seems fairly generic.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: Ic8087fc46b2a192459b7287186f8972610e84730
diff --git a/test/openpower-pels/ascii_string_test.cpp b/test/openpower-pels/ascii_string_test.cpp
index 96ee4ad..2d23847 100644
--- a/test/openpower-pels/ascii_string_test.cpp
+++ b/test/openpower-pels/ascii_string_test.cpp
@@ -84,3 +84,16 @@
 
     EXPECT_THROW(src::AsciiString as{stream}, std::out_of_range);
 }
+
+TEST(AsciiStringTest, MissingSubsystemTest)
+{
+    message::Entry entry;
+    entry.src.type = 0xBD;
+    entry.src.reasonCode = 0xABCD;
+
+    src::AsciiString as{entry};
+    auto data = as.get();
+
+    // Default subsystem is 0x70
+    EXPECT_EQ(data, "BD70ABCD                        ");
+}
diff --git a/test/openpower-pels/registry_test.cpp b/test/openpower-pels/registry_test.cpp
index c7d88c9..5cfd5e5 100644
--- a/test/openpower-pels/registry_test.cpp
+++ b/test/openpower-pels/registry_test.cpp
@@ -101,6 +101,21 @@
                     "dump that provides debug information."
                 ]
             }
+        },
+
+        {
+            "Name": "xyz.openbmc_project.Common.Error.Timeout",
+            "PossibleSubsystems": ["processor", "memory"],
+
+            "SRC":
+            {
+                "ReasonCode": "0x2030"
+            },
+            "Documentation":
+            {
+                "Description": "A PGOOD Fault",
+                "Message": "PS had a PGOOD Fault"
+            }
         }
     ]
 }
@@ -651,3 +666,14 @@
         }
     }
 }
+
+TEST_F(RegistryTest, TestNoSubsystem)
+{
+    auto path = RegistryTest::writeData(registryData);
+    Registry registry{path};
+
+    auto entry = registry.lookup("xyz.openbmc_project.Common.Error.Timeout",
+                                 LookupType::name);
+    ASSERT_TRUE(entry);
+    EXPECT_FALSE(entry->subsystem);
+}
diff --git a/test/openpower-pels/user_header_test.cpp b/test/openpower-pels/user_header_test.cpp
index 59199fb..233f08b 100644
--- a/test/openpower-pels/user_header_test.cpp
+++ b/test/openpower-pels/user_header_test.cpp
@@ -313,19 +313,56 @@
 TEST(UserHeaderTest, UseEventLogPELSubsystem)
 {
     using namespace openpower::pels::message;
-    Entry regEntry;
 
-    regEntry.name = "test";
-    regEntry.subsystem = 5;
-    regEntry.actionFlags = 0xC000;
-    regEntry.eventType = 1;
-    regEntry.eventScope = 2;
+    {
+        Entry regEntry;
 
-    MockDataInterface dataIface;
-    std::vector<std::string> adData{"PEL_SUBSYSTEM=0x25"};
-    AdditionalData ad{adData};
+        regEntry.name = "test";
+        regEntry.subsystem = 5;
+        regEntry.actionFlags = 0xC000;
+        regEntry.eventType = 1;
+        regEntry.eventScope = 2;
 
-    UserHeader uh(regEntry, phosphor::logging::Entry::Level::Critical, ad,
-                  dataIface);
-    ASSERT_EQ(uh.subsystem(), 0x25);
+        MockDataInterface dataIface;
+        std::vector<std::string> adData{"PEL_SUBSYSTEM=0x25"};
+        AdditionalData ad{adData};
+
+        UserHeader uh(regEntry, phosphor::logging::Entry::Level::Critical, ad,
+                      dataIface);
+        ASSERT_EQ(uh.subsystem(), 0x25);
+    }
+    {
+        // No subsystem in registry, and invalid PEL_SUBSYSTEM
+        Entry regEntry;
+
+        regEntry.name = "test";
+        regEntry.actionFlags = 0xC000;
+        regEntry.eventType = 1;
+        regEntry.eventScope = 2;
+
+        MockDataInterface dataIface;
+        std::vector<std::string> adData{"PEL_SUBSYSTEM=0x99"};
+        AdditionalData ad{adData};
+
+        UserHeader uh(regEntry, phosphor::logging::Entry::Level::Critical, ad,
+                      dataIface);
+        ASSERT_EQ(uh.subsystem(), 0x70); // others
+    }
+    {
+        // No subsystem in registry or PEL_SUBSYSTEM
+        Entry regEntry;
+
+        regEntry.name = "test";
+        regEntry.actionFlags = 0xC000;
+        regEntry.eventType = 1;
+        regEntry.eventScope = 2;
+
+        MockDataInterface dataIface;
+        std::vector<std::string> adData;
+        AdditionalData ad{adData};
+
+        UserHeader uh(regEntry, phosphor::logging::Entry::Level::Critical, ad,
+                      dataIface);
+        ASSERT_EQ(uh.subsystem(), 0x70); // others
+    }
 }