Ignore analysis of OCMBs that have been masked

Attentions from OCMBs chip will flow through their connected processor
chips. We should not do analysis of those attentions if they are masked
on the connected processor chip regardless if the OCMB chip shows any
active attentions. This will take care of scenarios like a channel
failure attention that has already been handled and masked by the host
firmware.

Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
Change-Id: I2c170ea4770ad3a229c1c65fa50b056fc8a6e4b2
diff --git a/test/test-pdbg-dts.cpp b/test/test-pdbg-dts.cpp
index 9853a07..83d3f89 100644
--- a/test/test-pdbg-dts.cpp
+++ b/test/test-pdbg-dts.cpp
@@ -246,4 +246,42 @@
 
     trace::inf("chips size: %u", chips.size());
     EXPECT_EQ(2, chips.size());
+
+    /* TODO: There is an issue with the getActiveChips() function that only
+     *       seems to exist in simulation. For some reason, the OCMBs do not
+     *       show up as PDBG_TARGET_ENABLED. If we remove that check, this test
+     *       case works as expected. However, we don't want to do that in
+     *       production code.  Instead, we'll need to determine why the OCMBs
+     *       are not enabled in CI test and then reenable this test case.
+    auto proc0 = getTrgt("/proc0");
+    auto proc1 = getTrgt("/proc1");
+
+    sim::ScomAccess& scom = sim::ScomAccess::getSingleton();
+    scom.flush();
+
+    // Mask off proc0 mcc0 channel 1. The connected OCMB should be removed from
+    // the list.
+    scom.add(proc0, 0x0C010D03, 0x0f00000000000000);
+
+    // Mask off one or two attentions, but not all, on proc0 mcc2. None of the
+    // connected OCMBs should be removed from the list.
+    scom.add(proc0, 0x0D010D03, 0xA500000000000000);
+
+    // Mask off proc1 mcc7 channel 0. The connected OCMB should be removed from
+    // the list.
+    scom.add(proc1, 0x0F010D43, 0xf000000000000000);
+
+    // Mask off proc1 mcc5 channels 0 and 1. Both the connected OCMBs should be
+    // removed from the list.
+    scom.add(proc1, 0x0E010D43, 0xff00000000000000);
+
+    std::vector<libhei::Chip> chips;
+    getActiveChips(chips);
+
+    // In total there should be 14 chips with 2 processors, 7 OCMBs on proc0,
+    // and 5 OCMBs on proc1.
+
+    trace::inf("chips size: %u", chips.size());
+    EXPECT_EQ(14, chips.size());
+    */
 }
diff --git a/util/pdbg.cpp b/util/pdbg.cpp
index 46bb37b..ab0b429 100644
--- a/util/pdbg.cpp
+++ b/util/pdbg.cpp
@@ -436,6 +436,58 @@
     }
 }
 
+// Should ignore OCMBs that have been masked on the processor side of the bus.
+bool __isMaskedOcmb(const libhei::Chip& i_chip)
+{
+    // TODO: This function only works for P10 processors will need to update for
+    // subsequent chips.
+
+    // Map of MCC target position to DSTL_FIR_MASK address.
+    static const std::map<unsigned int, uint64_t> addrs = {
+        {0, 0x0C010D03}, {1, 0x0C010D43}, {2, 0x0D010D03}, {3, 0x0D010D43},
+        {4, 0x0E010D03}, {5, 0x0E010D43}, {6, 0x0F010D03}, {7, 0x0F010D43},
+    };
+
+    auto ocmb = getTrgt(i_chip);
+
+    // Confirm this chip is an OCMB.
+    if (TYPE_OCMB != getTrgtType(ocmb))
+    {
+        return false;
+    }
+
+    // Get the connected MCC target on the processor chip.
+    auto mcc = pdbg_target_parent("mcc", ocmb);
+    if (nullptr == mcc)
+    {
+        throw std::logic_error("No parent MCC found for " +
+                               std::string{getPath(ocmb)});
+    }
+
+    // Read the associated DSTL_FIR_MASK.
+    uint64_t val = 0;
+    if (getScom(getParentChip(mcc), addrs.at(getUnitPos(mcc)), val))
+    {
+        // Just let this go. The SCOM code will log the error.
+        return false;
+    }
+
+    // The DSTL_FIR has bits for each of the two memory channels on the MCC.
+    auto chnlPos = getChipPos(ocmb) % 2;
+
+    // Channel 0 => bits 0-3, channel 1 => bits 4-7.
+    auto mask = (val >> (60 - (4 * chnlPos))) & 0xf;
+
+    // Return true if the mask is set to all 1's.
+    if (0xf == mask)
+    {
+        trace::inf("OCMB masked on processor side of bus: %s", getPath(ocmb));
+        return true;
+    }
+
+    return false; // default
+}
+
 void getActiveChips(std::vector<libhei::Chip>& o_chips)
 {
     o_chips.clear();
@@ -468,6 +520,11 @@
             __addChip(o_chips, ocmbTrgt, __getChipIdEc(ocmbTrgt));
         }
     }
+
+    // Ignore OCMBs that have been masked on the processor side of the bus.
+    o_chips.erase(
+        std::remove_if(o_chips.begin(), o_chips.end(), __isMaskedOcmb),
+        o_chips.end());
 }
 
 //------------------------------------------------------------------------------