Bus callout resolution support

Change-Id: I516d151350ac0d2342c966266f2e90bae8572c37
Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
diff --git a/analyzer/ras-data/data/ras-data-explorer-11.json b/analyzer/ras-data/data/ras-data-explorer-11.json
index 37a216e..9f638da 100644
--- a/analyzer/ras-data/data/ras-data-explorer-11.json
+++ b/analyzer/ras-data/data/ras-data-explorer-11.json
@@ -51,9 +51,21 @@
         ],
         "omi_bus" : [
             {
-                "type"  : "callout_bus",
-                "name"  : "omi_bus",
-                "guard" : true
+                "type"      : "callout_self",
+                "priority"  : "MED_A",
+                "guard"     : true
+            },
+            {
+                "type"      : "callout_connected",
+                "name"      : "omi_bus",
+                "priority"  : "MED_A",
+                "guard"     : true
+            },
+            {
+                "type"      : "callout_bus",
+                "name"      : "omi_bus",
+                "priority"  : "LOW",
+                "guard"     : false
             }
         ],
         "level2_M_self_L" : [
diff --git a/analyzer/ras-data/data/ras-data-explorer-20.json b/analyzer/ras-data/data/ras-data-explorer-20.json
index 1d99c6a..354106f 100644
--- a/analyzer/ras-data/data/ras-data-explorer-20.json
+++ b/analyzer/ras-data/data/ras-data-explorer-20.json
@@ -51,9 +51,21 @@
         ],
         "omi_bus" : [
             {
-                "type"  : "callout_bus",
-                "name"  : "omi_bus",
-                "guard" : true
+                "type"      : "callout_self",
+                "priority"  : "MED_A",
+                "guard"     : true
+            },
+            {
+                "type"      : "callout_connected",
+                "name"      : "omi_bus",
+                "priority"  : "MED_A",
+                "guard"     : true
+            },
+            {
+                "type"      : "callout_bus",
+                "name"      : "omi_bus",
+                "priority"  : "LOW",
+                "guard"     : false
             }
         ],
         "level2_M_self_L" : [
diff --git a/analyzer/ras-data/ras-data-definition.md b/analyzer/ras-data/ras-data-definition.md
index 2df571b..d27b3ab 100644
--- a/analyzer/ras-data/ras-data-definition.md
+++ b/analyzer/ras-data/ras-data-definition.md
@@ -147,22 +147,20 @@
 #### 5.1.5) action type `callout_bus`
 
 This will request to callout all parts associated with a bus (RX/TX endpoints
-and everything else in between the endpoints). Bus callouts have very specific
-priority:
+and everything else in between the endpoints). All parts will be called out with
+the same priority. If a particular part, like the endpoints, need to be called
+out at a different priority, they will need to be called out using a different
+action type. For example:
 
-- If an SMP cable exists, callout the cable with priority `HIGH`.
-- Callout both RX and TX endpoints with priority `MED_A`.
-- Callout everything else in between with priority `LOW`.
-
-In some special cases, the callout priority of the endpoints may differ from the
-default `MED_A`. In which case, the optional priority properties can be used.
+- `callout_self` with priority `MED_A`.         (RX endpoint MED_A)
+- `callout_connected` with priority `MED_A`.    (TX endpoint MED_A)
+- `callout_bus` with priority `LOW`.            (everything else LOW)
 
 | Keyword     | Description                                                    |
 |-------------|----------------------------------------------------------------|
 | type        | value (string): `callout_bus`                                  |
 | name        | The `<bus_name>` as defined by the `buses` keyword.            |
-| rx_priority | Optional priority of the receiving side endpoint               |
-| tx_priority | Optional priority of the transfer side endpoint                |
+| priority    | See `priority` table above.                                    |
 | guard       | See `guard` table above.                                       |
 
 #### 5.1.6) action type `callout_clock`
diff --git a/analyzer/ras-data/ras-data-parser.cpp b/analyzer/ras-data/ras-data-parser.cpp
index ea59c07..6ec8b6c 100644
--- a/analyzer/ras-data/ras-data-parser.cpp
+++ b/analyzer/ras-data/ras-data-parser.cpp
@@ -203,14 +203,15 @@
         }
         else if ("callout_bus" == type)
         {
-            auto name = a.at("name").get<std::string>();
-            // auto rx_priority = a.at("rx_priority").get<std::string>();
-            // auto tx_priority = a.at("tx_priority").get<std::string>();
-            auto guard = a.at("guard").get<bool>();
+            auto name     = a.at("name").get<std::string>();
+            auto priority = a.at("priority").get<std::string>();
+            auto guard    = a.at("guard").get<bool>();
 
-            // TODO
-            trace::inf("callout_bus: name=%s guard=%c", name.c_str(),
-                       guard ? 'T' : 'F');
+            auto busData = parseBus(i_data, name);
+
+            o_list->push(std::make_shared<BusCalloutResolution>(
+                std::get<0>(busData), std::get<1>(busData),
+                getPriority(priority), guard));
         }
         else if ("callout_clock" == type)
         {
diff --git a/analyzer/ras-data/schema/ras-data-schema-v01.json b/analyzer/ras-data/schema/ras-data-schema-v01.json
index d675631..10f03ea 100644
--- a/analyzer/ras-data/schema/ras-data-schema-v01.json
+++ b/analyzer/ras-data/schema/ras-data-schema-v01.json
@@ -143,11 +143,7 @@
                                     }
                                 },
                                 "then": {
-                                    "required": [ "name", "guard" ],
-                                    "not": { "required": [ "priority" ] },
-                                    "properties": {
-                                        "rx_priority": { "$ref": "#/definitions/priority" },
-                                        "tx_priority": { "$ref": "#/definitions/priority" }
+                                    "required": [ "name", "priority", "guard" ],
                                     }
                                 }
                             },
diff --git a/analyzer/resolution.cpp b/analyzer/resolution.cpp
index d6cd174..86a10e1 100644
--- a/analyzer/resolution.cpp
+++ b/analyzer/resolution.cpp
@@ -176,6 +176,62 @@
 
 //------------------------------------------------------------------------------
 
+void BusCalloutResolution::resolve(ServiceData& io_sd) const
+{
+    // Get the chip target from the root cause signature.
+    auto chipTarget = __getRootCauseChipTarget(io_sd);
+
+    // Get the endpoint target for the receiving side of the bus.
+    auto rxTarget = __getUnitTarget(chipTarget, iv_unitPath);
+
+    // Get the endpoint target for the transfer side of the bus.
+    auto txTarget = __getConnectedTarget(rxTarget, iv_busType);
+
+    // Callout the RX endpoint.
+    nlohmann::json rxCallout;
+    rxCallout["LocationCode"] = util::pdbg::getLocationCode(rxTarget);
+    rxCallout["Priority"]     = iv_priority.getUserDataString();
+    io_sd.addCallout(rxCallout);
+
+    // Callout the TX endpoint.
+    nlohmann::json txCallout;
+    txCallout["LocationCode"] = util::pdbg::getLocationCode(txTarget);
+    txCallout["Priority"]     = iv_priority.getUserDataString();
+    io_sd.addCallout(txCallout);
+
+    // Callout everything else in between.
+    // TODO: For P10 (OMI bus and XBUS), the callout is simply the backplane.
+    //       There isn't a devtree object for this, yet. So will need to
+    //       hardcode the location code for now. In the future, we will need a
+    //       mechanism to make this data driven.
+    nlohmann::json bpCallout;
+    bpCallout["LocationCode"] = "P0";
+    bpCallout["Priority"]     = iv_priority.getUserDataString();
+    io_sd.addCallout(bpCallout);
+
+    // Guard the RX endpoint.
+    Guard guard =
+        io_sd.addGuard(util::pdbg::getPhysDevPath(rxTarget), iv_guard);
+
+    // Guard the TX endpoint.
+    // No need to check return because it is the same as RX target.
+    io_sd.addGuard(util::pdbg::getPhysDevPath(txTarget), iv_guard);
+
+    // TODO: Currently no guard for "everything else in between".
+
+    // Add the callout FFDC to the service data.
+    nlohmann::json ffdc;
+    ffdc["Callout Type"] = "Bus Callout";
+    ffdc["Bus Type"]     = iv_busType.getString();
+    ffdc["RX Target"]    = util::pdbg::getPhysDevPath(rxTarget);
+    ffdc["TX Target"]    = util::pdbg::getPhysDevPath(txTarget);
+    ffdc["Priority"]     = iv_priority.getRegistryString();
+    ffdc["Guard Type"]   = guard.getString();
+    io_sd.addCalloutFFDC(ffdc);
+}
+
+//------------------------------------------------------------------------------
+
 void ClockCalloutResolution::resolve(ServiceData& io_sd) const
 {
     // Add the callout to the service data.
diff --git a/analyzer/resolution.hpp b/analyzer/resolution.hpp
index aee3851..9530b70 100644
--- a/analyzer/resolution.hpp
+++ b/analyzer/resolution.hpp
@@ -97,6 +97,48 @@
     void resolve(ServiceData& io_sd) const override;
 };
 
+/**
+ * @brief Resolution to callout all parts on a bus (RX/TX endpoints and
+ *         everything else in between).
+ */
+class BusCalloutResolution : public Resolution
+{
+  public:
+    /**
+     * @brief Constructor from components.
+     * @param i_busType  The bus type.
+     * @param i_unitPath The path of the chip unit that is connected to the
+     *                   other chip. An empty string refers to the chip itself,
+     *                   which generally means this chip is a child of another.
+     * @param i_priority The callout priority.
+     * @param i_guard    The guard type for this callout.
+     */
+    BusCalloutResolution(const callout::BusType& i_busType,
+                         const std::string& i_unitPath,
+                         const callout::Priority& i_priority, bool i_guard) :
+        iv_busType(i_busType),
+        iv_unitPath(i_unitPath), iv_priority(i_priority), iv_guard(i_guard)
+    {}
+
+  private:
+    /** The bus type. */
+    const callout::BusType iv_busType;
+
+    /** The devtree path the chip unit that is connected to the other chip. An
+     *  empty string refers to the chip itself, which generally means this chip
+     *  is a child of the other chip. */
+    const std::string iv_unitPath;
+
+    /** The callout priority. */
+    const callout::Priority iv_priority;
+
+    /** True, if guard is required. False, otherwise. */
+    const bool iv_guard;
+
+  public:
+    void resolve(ServiceData& io_sd) const override;
+};
+
 /** @brief Resolves a clock callout service event. */
 class ClockCalloutResolution : public Resolution
 {