bmc-reset: check if host is running

This is the backup plan to ensuring the host is not running before the
BMC issues a power off to the system. Prior to this procedure being
called, the BMC has tried all other communication mechanisms to talk
with the host and they have failed. The design is that the host
firmware will write the value 0xA5000001 to Mailbox scratch register
12 when they are up and running to a point where communication to the
BMC is no longer required to function. On a power off or shutdown
this register is cleared by the host and BMC firmware. If the BMC sees
the 0xA5000001 pattern in the scratch register then it assumes the host
is running and will leave power on to the system.

Why not put this in phosphor-state-manager where the other checks are
for the host running?
- This is a very POWER10 specific piece of logic
- A lot of tight coupling would have been required between state-manager
  and proc-control
- In the end, it was less work to just put this in proc-control

Tested:
- Verified when CFAM is not A5000001, call returns without error and
  /run file is not created
- Verified when CFAM is A5000001, call returns without error and /run
  file is created

Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
Change-Id: I3f6be9160d8d89e556a722d9f6cb00f94be2b994
diff --git a/procedures/phal/common_utils.cpp b/procedures/phal/common_utils.cpp
index ca37ace..708df40 100644
--- a/procedures/phal/common_utils.cpp
+++ b/procedures/phal/common_utils.cpp
@@ -59,11 +59,6 @@
     }
 }
 
-/**
- *  @brief  Check if primary processor or not
- *
- *  @return True/False
- */
 bool isPrimaryProc(struct pdbg_target* procTarget)
 {
     ATTR_PROC_MASTER_TYPE_Type type;
@@ -87,5 +82,46 @@
     }
 }
 
+uint32_t getCFAM(struct pdbg_target* procTarget, const uint32_t reg,
+                 uint32_t& val)
+{
+    auto procIdx = pdbg_target_index(procTarget);
+    char path[16];
+    sprintf(path, "/proc%d/pib", procIdx);
+
+    pdbg_target* pibTarget = pdbg_target_from_path(nullptr, path);
+    if (nullptr == pibTarget)
+    {
+        log<level::ERR>("pib path of target not found",
+                        entry("TARGET_PATH=%s", path));
+        return -1;
+    }
+
+    // probe PIB and ensure it's enabled
+    if (PDBG_TARGET_ENABLED != pdbg_target_probe(pibTarget))
+    {
+        log<level::ERR>("probe on pib target failed");
+        return -1;
+    }
+
+    // now build FSI path and read the input reg
+    sprintf(path, "/proc%d/fsi", procIdx);
+    pdbg_target* fsiTarget = pdbg_target_from_path(nullptr, path);
+    if (nullptr == fsiTarget)
+    {
+        log<level::ERR>("fsi path or target not found");
+        return -1;
+    }
+
+    auto rc = fsi_read(fsiTarget, reg, &val);
+    if (rc)
+    {
+        log<level::ERR>("failed to read input cfam", entry("RC=%u", rc),
+                        entry("CFAM=0x%X", reg), entry("TARGET_PATH=%s", path));
+        return rc;
+    }
+    return 0;
+}
+
 } // namespace phal
 } // namespace openpower