Capture data support for an isolation bit

User applications can not specify registers to capture if there is an
active attention on a specific bit in an isolation node. This helps
reduce the number of registers captured by default when analyzing an
isolation node.

Change-Id: I50c88cb8a2fa3d89d2c7446dbc04d0f33bbb0cd2
Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
diff --git a/src/isolator/hei_isolation_node.cpp b/src/isolator/hei_isolation_node.cpp
index 5bcfff8..119c5ae 100644
--- a/src/isolator/hei_isolation_node.cpp
+++ b/src/isolator/hei_isolation_node.cpp
@@ -14,30 +14,8 @@
     // Keep track of nodes that have been analyzed to avoid cyclic isolation.
     pushIsolationStack();
 
-    // Capture all registers for this node.
-    for (const auto& hwReg : iv_capRegs)
-    {
-        // Read the register (adds BitString to register cache).
-        if (hwReg->read(i_chip))
-        {
-            // The register read failed.
-            // TODO: Would be nice to add SCOM errors to the log just in case
-            //       traces are not available.
-            // TODO: This trace could be redundant with the user application,
-            //       which will have more information on the actual chip that
-            //       failed anyway. Leaving it commented out for now until the
-            //       SCOM errors are added to the log.
-            // HEI_ERR("register read failed on chip type=0x%0" PRIx32
-            //         "address=0x%0" PRIx64,
-            //         i_chip.getType(), hwReg->getAddress());
-        }
-        else
-        {
-            // Add to the FFDC.
-            io_isoData.addRegister(i_chip, hwReg->getId(), hwReg->getInstance(),
-                                   hwReg->getBitString(i_chip));
-        }
-    }
+    // Capture default set of registers for this node.
+    captureRegisters(i_chip, io_isoData);
 
     // Get the rule for this attention type.
     auto rule_itr = iv_rules.find(i_attnType);
@@ -63,6 +41,9 @@
             // At least one active bit was found.
             o_activeAttn = true;
 
+            // Capture registers specific to this isolation bit.
+            captureRegisters(i_chip, io_isoData, bit);
+
             // Determine if this attention originated from another register or
             // if it is a leaf in the isolation tree.
             auto child_itr = iv_children.find(bit);
@@ -109,15 +90,31 @@
 
 //------------------------------------------------------------------------------
 
-void IsolationNode::addCaptureRegister(HardwareRegister::ConstPtr i_hwReg)
+void IsolationNode::addCaptureRegister(HardwareRegister::ConstPtr i_hwReg,
+                                       BitPosition_t i_bit)
 {
     HEI_ASSERT(i_hwReg); // should not be null
 
-    // If the register already exists, ignore it. Otherwise, add it to the list.
-    auto itr = std::find(iv_capRegs.begin(), iv_capRegs.end(), i_hwReg);
-    if (iv_capRegs.end() == itr)
+    // Check the bit range.
+    if (MAX_BIT_POSITION != i_bit)
     {
-        iv_capRegs.push_back(i_hwReg);
+        if (REG_TYPE_SCOM == iv_regType || REG_TYPE_ID_SCOM == iv_regType)
+        {
+            HEI_ASSERT(i_bit < 64);
+        }
+        else
+        {
+            HEI_ASSERT(false); // register type unsupported
+        }
+    }
+
+    // Add this capture register only if it does not already exist in the list.
+    auto itr = iv_capRegs.find(i_bit);
+    if (iv_capRegs.end() == itr ||
+        itr->second.end() ==
+            std::find(itr->second.begin(), itr->second.end(), i_hwReg))
+    {
+        iv_capRegs[i_bit].push_back(i_hwReg);
     }
 }
 
@@ -165,4 +162,43 @@
 
 //------------------------------------------------------------------------------
 
+void IsolationNode::captureRegisters(const Chip& i_chip,
+                                     IsolationData& io_isoData,
+                                     BitPosition_t i_bit) const
+{
+    auto itr = iv_capRegs.find(i_bit);
+    if (iv_capRegs.end() != itr)
+    {
+        // Capture all registers for this node.
+        for (const auto& hwReg : itr->second)
+        {
+            // Read the register (adds BitString to register cache).
+            if (hwReg->read(i_chip))
+            {
+                // The register read failed.
+                // TODO: Would be nice to add SCOM errors to the log just in
+                // case
+                //       traces are not available.
+                // TODO: This trace could be redundant with the user
+                // application,
+                //       which will have more information on the actual chip
+                //       that failed anyway. Leaving it commented out for now
+                //       until the SCOM errors are added to the log.
+                // HEI_ERR("register read failed on chip type=0x%0" PRIx32
+                //         "address=0x%0" PRIx64,
+                //         i_chip.getType(), hwReg->getAddress());
+            }
+            else
+            {
+                // Add to the FFDC.
+                io_isoData.addRegister(i_chip, hwReg->getId(),
+                                       hwReg->getInstance(),
+                                       hwReg->getBitString(i_chip));
+            }
+        }
+    }
+}
+
+//------------------------------------------------------------------------------
+
 } // end namespace libhei
diff --git a/src/isolator/hei_isolation_node.hpp b/src/isolator/hei_isolation_node.hpp
index ebb1850..858a8c1 100644
--- a/src/isolator/hei_isolation_node.hpp
+++ b/src/isolator/hei_isolation_node.hpp
@@ -85,10 +85,14 @@
     const RegisterType_t iv_regType;
 
     /**
-     * The list of register to capture and add to the log for additional
-     * debugging.
+     * The lists of register to capture and add to the log for additional
+     * debugging. The lists are indexed in a map where the key is a bit
+     * position. All registers that should be captured by default when
+     * isolating to this node will have a bit position of `MAX_BIT_POSITION`.
+     * Otherwise, any other list targeted for a specific bit will only be
+     * captured if there is an active attention on that bit.
      */
-    std::vector<HardwareRegister::ConstPtr> iv_capRegs;
+    std::map<BitPosition_t, std::vector<HardwareRegister::ConstPtr>> iv_capRegs;
 
     /**
      * This register could report multiple types of attentions. We can use a
@@ -131,9 +135,14 @@
      * This is only intended to be used during initialization of the isolator.
      * Duplicate registers will be ignored.
      *
-     * @param The target hardware register.
+     * @param i_hwReg The target hardware register.
+     * @param i_bit   If specified, the given register should only be captured
+     *                when there is an active attention on the given bit. If
+     *                omitted, the given register will be captured any time
+     *                this isolation node is analyzed.
      */
-    void addCaptureRegister(HardwareRegister::ConstPtr i_hwReg);
+    void addCaptureRegister(HardwareRegister::ConstPtr i_hwReg,
+                            BitPosition_t i_bit = MAX_BIT_POSITION);
 
     /**
      * @brief Adds a register rule for the given attention type. See iv_rules
@@ -183,6 +192,19 @@
         return iv_regType;
     }
 
+  private: // Member functions
+    /**
+     * @param  i_chip     The target chip for isolation.
+     * @param  io_isoData The isolation data returned back to the user
+     *                    application.
+     * @param  i_bit      If specified, only the registers specifically
+     *                    targeted for the given bit are captured. If omitted,
+     *                    the default list of registers for this isolation node
+     *                    will be captured.
+     */
+    void captureRegisters(const Chip& i_chip, IsolationData& io_isoData,
+                          BitPosition_t i_bit = MAX_BIT_POSITION) const;
+
   private: // Isolation stack and supporting functions.
     /** When analyze() is called at the tree root, all recursive calls to
      *  analyze() will target the same chip and attention type. So we only need