PEL: Still create callout without full loc code

When PELs are created early during a power on reset, the service that
expands location codes may not be online yet.  Previously, callouts just
wouldn't be created if a location code couldn't be expanded.

Fix that so that a callout is still created with the unexpanded location
code, as that is still better than nothing.  In those cases, the
CC/PN/FN fields would also be empty since those are obtained by finding
the FRU inventory path from the location code.

Also create a similar callout in the case where the call to get the
inventory path from a location code fails.

This applies for callouts created via:
- The PEL message registry
- The device path lookup tables
- JSON FFDC files

Tested:
New unit tests that cover these paths pass.

On a system, after stopping vpd-manager.service, will get callouts like:
```
    "Callout Section": {
        "Callout Count":        "4",
        "Callouts": [{
            "FRU Type":         "Normal Hardware FRU",
            "Priority":         "Mandatory, replace all with this type as a unit",
            "Location Code":    "P0-C5",
            "Part Number":      "",
            "CCIN":             "",
            "Serial Number":    ""
        }, {
            "FRU Type":         "Normal Hardware FRU",
            "Priority":         "Mandatory, replace all with this type as a unit",
            "Location Code":    "E0",
            "Part Number":      "",
            "CCIN":             "",
            "Serial Number":    ""
        }, {
            "FRU Type":         "Normal Hardware FRU",
            "Priority":         "Lowest priority replacement",
            "Location Code":    "P0",
            "Part Number":      "",
            "CCIN":             "",
            "Serial Number":    ""
        }, {
            "FRU Type":         "Normal Hardware FRU",
            "Priority":         "Lowest priority replacement",
            "Location Code":    "P0-T4",
            "Part Number":      "",
            "CCIN":             "",
            "Serial Number":    ""
        }]
    }
```

Change-Id: Ia7e94f9d4848f78ba0b00023438c4db4135fed75
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/extensions/openpower-pels/src.cpp b/extensions/openpower-pels/src.cpp
index 7b7e59f..cfa7155 100644
--- a/extensions/openpower-pels/src.cpp
+++ b/extensions/openpower-pels/src.cpp
@@ -867,6 +867,17 @@
     }
 }
 
+void SRC::addLocationCodeOnlyCallout(const std::string& locationCode,
+                                     const CalloutPriority priority)
+{
+    std::string empty;
+    std::vector<src::MRU::MRUCallout> mrus;
+    auto callout = std::make_unique<src::Callout>(priority, locationCode, empty,
+                                                  empty, empty, mrus);
+    createCalloutsObject();
+    _callouts->addCallout(std::move(callout));
+}
+
 void SRC::addInventoryCallout(const std::string& inventoryPath,
                               const std::optional<CalloutPriority>& priority,
                               const std::optional<std::string>& locationCode,
@@ -1006,6 +1017,7 @@
 {
     std::unique_ptr<src::Callout> callout;
     auto locCode = regCallout.locCode;
+    bool locExpanded = true;
 
     if (!locCode.empty())
     {
@@ -1018,7 +1030,7 @@
             auto msg = "Unable to expand location code " + locCode + ": " +
                        e.what();
             addDebugData(msg);
-            return;
+            locExpanded = false;
         }
     }
 
@@ -1045,6 +1057,7 @@
     else if (!regCallout.symbolicFRUTrusted.empty())
     {
         // Symbolic FRU with trusted location code callout
+        bool trusted = false;
 
         // Use the location code from the inventory path if there is one.
         if (trustedSymbolicFRUInvPath)
@@ -1052,6 +1065,7 @@
             try
             {
                 locCode = dataIface.getLocationCode(*trustedSymbolicFRUInvPath);
+                trusted = true;
             }
             catch (const std::exception& e)
             {
@@ -1062,14 +1076,29 @@
             }
         }
 
+        // Can only trust the location code if it isn't empty and is expanded.
+        if (!locCode.empty() && locExpanded)
+        {
+            trusted = true;
+        }
+
         // The registry wants it to be trusted, but that requires a valid
         // location code for it to actually be.
         callout = std::make_unique<src::Callout>(
-            priority, regCallout.symbolicFRUTrusted, locCode, !locCode.empty());
+            priority, regCallout.symbolicFRUTrusted, locCode, trusted);
     }
     else
     {
         // A hardware callout
+
+        // If couldn't expand the location code, don't bother
+        // looking up the inventory path.
+        if (!locExpanded && !locCode.empty())
+        {
+            addLocationCodeOnlyCallout(locCode, priority);
+            return;
+        }
+
         std::vector<std::string> inventoryPaths;
 
         try
@@ -1084,6 +1113,11 @@
                 "Unable to get inventory path from location code: " + locCode +
                 ": " + e.what();
             addDebugData(msg);
+            if (!locCode.empty())
+            {
+                // Still add a callout with just the location code.
+                addLocationCodeOnlyCallout(locCode, priority);
+            }
             return;
         }
 
@@ -1196,6 +1230,10 @@
             auto msg = std::format("Unable to expand location code {}: {}",
                                    callout.locationCode, e.what());
             addDebugData(msg);
+
+            // Add the callout with just the unexpanded location code.
+            addLocationCodeOnlyCallout(callout.locationCode, priority);
+            continue;
         }
 
         try
@@ -1214,6 +1252,9 @@
                 "Unable to get inventory path from location code: " +
                 callout.locationCode + ": " + e.what();
             addDebugData(msg);
+            // Add the callout with just the location code.
+            addLocationCodeOnlyCallout(callout.locationCode, priority);
+            continue;
         }
 
         // Until the code is there to convert these MRU value strings to
@@ -1352,10 +1393,11 @@
             }
             catch (const std::exception& e)
             {
-                throw std::runtime_error{
-                    std::format("Unable to get inventory path from "
-                                "location code: {}: {}",
-                                unexpandedLocCode, e.what())};
+                addDebugData(std::format("Unable to get inventory path from "
+                                         "location code: {}: {}",
+                                         unexpandedLocCode, e.what()));
+                addLocationCodeOnlyCallout(locCode, priority);
+                return;
             }
         }