Enable/disable logic for each attention type

Allow the handler for each attention type to be enabled or
disabled. The default is all attention handlers are enabled.

Signed-off-by: Ben Tyner <ben.tyner@ibm.com>
Change-Id: Ibe2e7848a7064ae164f70aa5ea5bfca486c4036b
diff --git a/attn/attention.cpp b/attn/attention.cpp
index c13bf64..0806ef2 100644
--- a/attn/attention.cpp
+++ b/attn/attention.cpp
@@ -1,21 +1,16 @@
 #include <attention.hpp>
+#include <attn_config.hpp>
 
 namespace attn
 {
 
 /** @brief Main constructor. */
 Attention::Attention(AttentionType i_type, int (*i_handler)(Attention*),
-                     pdbg_target* i_target, bool i_breakpoints) :
+                     pdbg_target* i_target, Config* i_config) :
     iv_type(i_type),
-    iv_handler(i_handler), iv_target(i_target)
+    iv_handler(i_handler), iv_target(i_target), iv_config(i_config)
 
-{
-    // set attention handler configuration flags
-    if (true == i_breakpoints)
-    {
-        iv_flags |= enableBreakpoints;
-    }
-}
+{}
 
 /** @brief Get attention priority */
 int Attention::getPriority() const
@@ -23,16 +18,10 @@
     return iv_type;
 }
 
-/** @brief Get configuration flags */
-uint32_t Attention::getFlags() const
+/* @brief Get config object */
+Config* Attention::getConfig() const
 {
-    return iv_flags;
-}
-
-/** @brief Set configuration flags */
-void Attention::setFlags(uint32_t i_flags)
-{
-    iv_flags = i_flags;
+    return iv_config;
 }
 
 /* @brief Call attention handler function */
@@ -41,7 +30,7 @@
     return iv_handler(this);
 }
 
-/** @brief less than operator */
+/** @brief less than operator, for heap creation */
 bool Attention::operator<(const Attention& right) const
 {
     return (getPriority() < right.getPriority());
diff --git a/attn/attention.hpp b/attn/attention.hpp
index 28e7c76..a4d3461 100644
--- a/attn/attention.hpp
+++ b/attn/attention.hpp
@@ -2,6 +2,10 @@
 
 #include <libpdbg.h>
 
+#include <attn/attn_config.hpp>
+
+#include <bitset>
+
 namespace attn
 {
 
@@ -34,7 +38,7 @@
 
     /** @brief Main constructors */
     Attention(AttentionType i_type, int (*i_handler)(Attention*),
-              pdbg_target* i_target, bool i_breakpoints);
+              pdbg_target* i_target, Config* i_config);
 
     /** @brief Destructor */
     ~Attention() = default;
@@ -42,11 +46,8 @@
     /** @brief Get attention priority */
     int getPriority() const;
 
-    /** @brief Get configuration flags */
-    uint32_t getFlags() const;
-
-    /** @brief Set configuration flags */
-    void setFlags(uint32_t i_flags);
+    /* @brief Get config object */
+    Config* getConfig() const;
 
     /* @brief Call attention handler function */
     int handle();
@@ -64,7 +65,7 @@
     AttentionType iv_type;         // attention type
     int (*iv_handler)(Attention*); // handler function
     pdbg_target* iv_target;        // handler function target
-    uint32_t iv_flags = 0;         // configuration flags
+    Config* iv_config;             // configuration flags
 };
 
 } // namespace attn
diff --git a/attn/attn_config.cpp b/attn/attn_config.cpp
new file mode 100644
index 0000000..caee221
--- /dev/null
+++ b/attn/attn_config.cpp
@@ -0,0 +1,47 @@
+#include <attn/attn_config.hpp>
+
+namespace attn
+{
+
+/** @brief Main constructor */
+Config::Config(bool i_vital, bool i_checkstop, bool i_terminate,
+               bool i_breakpoints)
+{
+    setConfig(i_vital, i_checkstop, i_terminate, i_breakpoints);
+}
+
+/** @brief Get state of flag */
+bool Config::getFlag(AttentionFlag i_flag) const
+{
+    return (iv_flags.test(i_flag));
+}
+
+/** @brief Set configuration flag */
+void Config::setFlag(AttentionFlag i_flag)
+{
+    iv_flags.set(i_flag);
+}
+
+/** @brief Clear configuration flag */
+void Config::clearFlag(AttentionFlag i_flag)
+{
+    iv_flags.reset(i_flag);
+}
+
+/** @brief Set state of all configuration data */
+void Config::setConfig(bool i_vital, bool i_checkstop, bool i_terminate,
+                       bool i_breakpoints)
+{
+    (true == i_vital) ? iv_flags.set(enVital) : iv_flags.reset(enVital);
+
+    (true == i_checkstop) ? iv_flags.set(enCheckstop)
+                          : iv_flags.reset(enCheckstop);
+
+    (true == i_terminate) ? iv_flags.set(enTerminate)
+                          : iv_flags.reset(enTerminate);
+
+    (true == i_breakpoints) ? iv_flags.set(enBreakpoints)
+                            : iv_flags.reset(enBreakpoints);
+}
+
+} // namespace attn
diff --git a/attn/attn_config.hpp b/attn/attn_config.hpp
new file mode 100644
index 0000000..ec8013b
--- /dev/null
+++ b/attn/attn_config.hpp
@@ -0,0 +1,57 @@
+#pragma once
+#include <bitset>
+
+namespace attn
+{
+
+/** @brief configuration flags */
+enum AttentionFlag
+{
+    enVital       = 0,
+    enCheckstop   = 1,
+    enTerminate   = 2,
+    enBreakpoints = 3,
+    lastFlag
+};
+
+/** @brief Objhects to hold configuration data */
+class Config
+{
+  public: // methods
+    /** @brief Default constructor */
+    Config() = delete;
+
+    /** @brief Crate configuration object
+     *
+     * Create a configuration object to hold the attention handler
+     * configuration data
+     *
+     * @param i_vital       Enable vital attention handling
+     * @param i_checkstop   Enable checkstop attention handling
+     * @param i_terminate   Enable TI attention handling
+     * @param i_+breakpoint Enable breakpoint attention handling
+     */
+    Config(bool i_vital, bool i_checkstop, bool i_terminate,
+           bool i_breakpoints);
+
+    /** @brief Default destructor */
+    ~Config() = default;
+
+    /** @brief Get state of flag */
+    bool getFlag(AttentionFlag i_flag) const;
+
+    /** @brief Set configuration flag */
+    void setFlag(AttentionFlag i_flag);
+
+    /** @brief Clear configuration flag */
+    void clearFlag(AttentionFlag i_flag);
+
+    /** @brief Set state of all configuration data */
+    void setConfig(bool i_vital, bool i_checkstop, bool i_terminate,
+                   bool i_breakpoints);
+
+  private:
+    std::bitset<lastFlag> iv_flags; // configuration flags
+};
+
+} // namespace attn
diff --git a/attn/attn_handler.cpp b/attn/attn_handler.cpp
index 65d980a..a6bd469 100644
--- a/attn/attn_handler.cpp
+++ b/attn/attn_handler.cpp
@@ -1,5 +1,6 @@
 #include <analyzer/analyzer_main.hpp>
 #include <attention.hpp>
+#include <attn_config.hpp>
 #include <bp_handler.hpp>
 #include <logging.hpp>
 #include <ti_handler.hpp>
@@ -20,7 +21,8 @@
  * @brief Handle SBE vital attention
  *
  * @param i_attention Attention object
- * @return 0 = success
+ * @return 0 indicates that the vital attention was successfully handled
+ *         1 indicates that the vital attention was NOT successfully handled
  */
 int handleVital(Attention* i_attention);
 
@@ -28,7 +30,9 @@
  * @brief Handle checkstop attention
  *
  * @param i_attention Attention object
- * @return 0 = success
+ * @return 0 indicates that the checkstop attention was successfully handled
+ *         1 indicates that the checkstop attention was NOT successfully
+ *           handled.
  */
 int handleCheckstop(Attention* i_attention);
 
@@ -36,7 +40,8 @@
  * @brief Handle special attention
  *
  * @param i_attention Attention object
- * @return 0 = success
+ * @return 0 indicates that the special attention was successfully handled
+ *         1 indicates that the special attention was NOT successfully handled
  */
 int handleSpecial(Attention* i_attention);
 
@@ -45,7 +50,7 @@
  *
  * @param i_breakpoints true = breakpoint special attn handling enabled
  */
-void attnHandler(const bool i_breakpoints)
+void attnHandler(Config* i_config)
 {
     // Vector of active attentions to be handled
     std::vector<Attention> active_attentions;
@@ -94,9 +99,8 @@
                     // bit 0 on "left": bit 30 = SBE vital attention
                     if (isr_val & isr_mask & 0x00000002)
                     {
-                        active_attentions.emplace_back(Attention::Vital,
-                                                       handleVital, target,
-                                                       i_breakpoints);
+                        active_attentions.emplace_back(
+                            Attention::Vital, handleVital, target, i_config);
                     }
 
                     // bit 0 on "left": bit 1 = checkstop
@@ -104,7 +108,7 @@
                     {
                         active_attentions.emplace_back(Attention::Checkstop,
                                                        handleCheckstop, target,
-                                                       i_breakpoints);
+                                                       i_config);
                     }
 
                     // bit 0 on "left": bit 2 = special attention
@@ -112,7 +116,7 @@
                     {
                         active_attentions.emplace_back(Attention::Special,
                                                        handleSpecial, target,
-                                                       i_breakpoints);
+                                                       i_config);
                     }
                 } // cfam 0x100d valid
             }     // cfam 0x1007 valid
@@ -144,16 +148,25 @@
 
 /**
  * @brief Handle SBE vital attention
+ *
+ * @param i_attention Attention object
+ * @return 0 indicates that the vital attention was successfully handled
+ *         1 indicates that the vital attention was NOT successfully handled
  */
 int handleVital(Attention* i_attention)
 {
-    int rc = RC_NOT_SUCCESS; // vital attention handling not yet supported
+    int rc = RC_SUCCESS; // assume vital handled
 
-    log<level::INFO>("vital");
-
-    if (RC_SUCCESS != rc)
+    // if vital handling enabled, handle vital attention
+    if (false == (i_attention->getConfig()->getFlag(enVital)))
+    {
+        log<level::INFO>("vital handling disabled");
+        rc = RC_NOT_SUCCESS;
+    }
+    else
     {
         log<level::INFO>("vital NOT handled");
+        rc = RC_NOT_SUCCESS;
     }
 
     return rc;
@@ -161,50 +174,71 @@
 
 /**
  * @brief Handle checkstop attention
+ *
+ * @param i_attention Attention object
+ * @return 0 indicates that the checkstop attention was successfully handled
+ *         1 indicates that the checkstop attention was NOT successfully
+ *           handled.
  */
 int handleCheckstop(Attention* i_attention)
 {
-    int rc = RC_SUCCESS; // checkstop handling supported
+    int rc = RC_SUCCESS; // assume checkstop handled
 
-    log<level::INFO>("checkstop");
-
-    analyzer::analyzeHardware();
+    // if checkstop handling enabled, handle checkstop attention
+    if (false == (i_attention->getConfig()->getFlag(enCheckstop)))
+    {
+        log<level::INFO>("Checkstop handling disabled");
+        rc = RC_NOT_SUCCESS;
+    }
+    else
+    {
+        analyzer::analyzeHardware();
+        rc = RC_SUCCESS;
+    }
 
     return rc;
 }
 
 /**
  * @brief Handle special attention
+ *
+ * @param i_attention Attention object
+ * @return 0 indicates that the special attention was successfully handled
+ *         1 indicates that the special attention was NOT successfully handled
  */
 int handleSpecial(Attention* i_attention)
 {
-    int rc = RC_SUCCESS; // special attention handling supported
+    int rc = RC_NOT_SUCCESS; // assume special attention handling disabled
 
-    log<level::INFO>("special");
+    // Until the special attention chipop is availabe we will treat the special
+    // attention as a TI. If TI handling is disabled we will treat the special
+    // attention as a breakpopint.
 
-    // Right now we always handle breakpoint special attentions if breakpoint
-    // attn handling is enabled. This will eventually check if breakpoint attn
-    // handing is enabled AND there is a breakpoint pending.
-    if (0 != (i_attention->getFlags() & enableBreakpoints))
-    {
-        log<level::INFO>("breakpoint");
-
-        // Call the breakpoint special attention handler
-        bpHandler();
-    }
-    // Right now if breakpoint attn handling is not enabled we will treat the
-    // special attention as a TI. This will eventually be changed to check
-    // whether a TI is active and handle it regardless of whether breakpoint
-    // handling is enbaled or not.
-    else
+    // TI attention gets priority over breakpoints, if enabled then handle
+    if (true == (i_attention->getConfig()->getFlag(enTerminate)))
     {
         log<level::INFO>("TI (terminate immediately)");
 
         // Call TI special attention handler
         tiHandler();
+        rc = RC_SUCCESS;
+    }
+    else
+    {
+        if (true == (i_attention->getConfig()->getFlag(enBreakpoints)))
+        {
+            log<level::INFO>("breakpoint");
+
+            // Call the breakpoint special attention handler
+            bpHandler();
+            rc = RC_SUCCESS;
+        }
     }
 
-    // TODO recoverable errors?
+    if (RC_SUCCESS != rc)
+    {
+        log<level::INFO>("Special attn handling disabled");
+    }
 
     return rc;
 }
diff --git a/attn/attn_handler.hpp b/attn/attn_handler.hpp
index 5bfe995..f81a9e7 100644
--- a/attn/attn_handler.hpp
+++ b/attn/attn_handler.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include <attn/attn_config.hpp>
+
 namespace attn
 {
 
@@ -10,19 +12,18 @@
  * System Checkstop (checkstop) and Special Attention (special) and handle
  * each as follows:
  *
- * checkstop: TBD
+ * checkstop: Call hardware error analyzer
  * vital:     TBD
  * special:   Determine if the special attention is a Breakpoint (BP),
  *            Terminate Immediately (TI) or CoreCodeToSp (corecode). For each
  *            special attention type, do the following:
  *
  *            BP:          Notify Cronus
- *            TI:          TBD
+ *            TI:          Start host diagnostics mode systemd unit
  *            Corecode:    TBD
- *            Recoverable: TBD
  *
- * @param i_breakpoints true = breakpoint special attn handling enabled
+ * @param i_config pointer to attention handler configuration object
  */
-void attnHandler(const bool i_breakpoints);
+void attnHandler(Config* i_config);
 
 } // namespace attn
diff --git a/attn/attn_main.cpp b/attn/attn_main.cpp
index 492531b..46455b3 100644
--- a/attn/attn_main.cpp
+++ b/attn/attn_main.cpp
@@ -6,7 +6,7 @@
 /**
  * @brief Attention handler application main()
  */
-int attnDaemon(bool i_breakpoints)
+int attnDaemon(Config* i_config)
 {
     int rc = 0; // assume success
 
@@ -31,8 +31,8 @@
     {
         // Creating a vector of one gpio to monitor
         std::vector<std::unique_ptr<attn::AttnMonitor>> gpios;
-        gpios.push_back(std::make_unique<attn::AttnMonitor>(line, config, io,
-                                                            i_breakpoints));
+        gpios.push_back(
+            std::make_unique<attn::AttnMonitor>(line, config, io, i_config));
 
         io.run(); // start GPIO monitor
     }
diff --git a/attn/attn_main.hpp b/attn/attn_main.hpp
index 4403b45..b0b954b 100644
--- a/attn/attn_main.hpp
+++ b/attn/attn_main.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include <attn/attn_config.hpp>
+
 namespace attn
 {
 
@@ -9,10 +11,10 @@
  * Request the attention gpio for monitoring and attach the attention handler
  * as the gpio event handler.
  *
- * @param i_breakpoints     enables breakpoint special attn handling
+ * @param i_config     pointer to attention handler configuration object
  *
  * @return 0 == success
  */
-int attnDaemon(bool i_breakpoints);
+int attnDaemon(Config* i_config);
 
 } // namespace attn
diff --git a/attn/attn_monitor.cpp b/attn/attn_monitor.cpp
index eb46978..13b7f15 100644
--- a/attn/attn_monitor.cpp
+++ b/attn/attn_monitor.cpp
@@ -50,7 +50,7 @@
         {
             // active attention when gpio == 0
             case 0:
-                attnHandler(iv_breakpoints);
+                attnHandler(iv_config);
                 break;
 
             // gpio == 1, GPIO handler should not be executing
diff --git a/attn/attn_monitor.hpp b/attn/attn_monitor.hpp
index 251857b..7b70316 100644
--- a/attn/attn_monitor.hpp
+++ b/attn/attn_monitor.hpp
@@ -2,6 +2,7 @@
 
 #include <gpiod.h>
 
+#include <attn/attn_config.hpp>
 #include <boost/asio/io_service.hpp>
 #include <boost/asio/posix/stream_descriptor.hpp>
 
@@ -22,16 +23,16 @@
      * The AttnMonitor constructor will create a new object and start
      * the objects associated GPIO listener.
      *
-     * @param line     GPIO line handle
-     * @param config   configuration of line
-     * @param io       io service
-     * @param i_breakpoints true = breakpoint special attn handling enabled
+     * @param line         GPIO line handle
+     * @param config       configuration of line
+     * @param io           io service
+     * @param i_attnConfig poiner to attention handler configuration object
      */
     AttnMonitor(gpiod_line* line, gpiod_line_request_config& config,
-                boost::asio::io_service& io, bool i_breakpoints) :
+                boost::asio::io_service& io, Config* i_attnConfig) :
         iv_gpioLine(line),
         iv_gpioConfig(config), iv_gpioEventDescriptor(io),
-        iv_breakpoints(i_breakpoints)
+        iv_config(i_attnConfig)
     {
 
         requestGPIOEvent(); // registers the event handler
@@ -59,6 +60,9 @@
     /** @brief GPIO event descriptor */
     boost::asio::posix::stream_descriptor iv_gpioEventDescriptor;
 
+    /** @brief attention handler configuration object pointer */
+    Config* iv_config;
+
   private: // class methods
     /** @brief schedule a gpio event handler */
     void scheduleGPIOEvent();
@@ -68,9 +72,6 @@
 
     /** @brief register for a gpio event */
     void requestGPIOEvent();
-
-    /** @brief enable breakpoint special attn handling */
-    bool iv_breakpoints;
 };
 
 } // namespace attn
diff --git a/attn/meson.build b/attn/meson.build
index 40a3875..6a0bcc2 100644
--- a/attn/meson.build
+++ b/attn/meson.build
@@ -40,7 +40,7 @@
 # gather attention sources to be used here and elsewhere if needed
 attn_src = files('attn_main.cpp', 'attn_handler.cpp', 'attn_monitor.cpp',
                  'bp_handler.cpp', 'ti_handler.cpp', logging_src,
-                 'attention.cpp')
+                 'attention.cpp', 'attn_config.cpp')
 
 # Create attention handler library
 attn = static_library('attn_handler',
diff --git a/main.cpp b/main.cpp
index bb43990..4e73e03 100644
--- a/main.cpp
+++ b/main.cpp
@@ -14,9 +14,21 @@
  *
  * Command line arguments:
  *
- *  analyze         analyze hardware
- *  --daemon        load application as a daemon
- *  --breakpoints   enable breakpoint special attn handling (in daemon mode)
+ * commands:
+ *
+ *   analyze            analyze hardware
+ *
+ * options:
+ *
+ *  --daemon            load application as a daemon
+ *  --vital off         disable vital attention handling (daemon mode)
+ *  --checkstop off     disable checkstop attention handling (daemon mode)
+ *  --terminate off     disable TI attention handling (daemon mode)
+ *  --breakpoints off   disable breakpoint attention handling (daemon mode)
+ *
+ *  example:
+ *
+ *    openpower-hw-diags --daemon --terminate off
  *
  * @return 0 = success
  */
@@ -24,22 +36,29 @@
 {
     int rc = 0; // return code
 
+    // attention handler configuration flags
+    bool vital_enable     = true;
+    bool checkstop_enable = true;
+    bool ti_enable        = true;
+    bool bp_enable        = true;
+
     // initialize pdbg targets
     pdbg_targets_init(nullptr);
 
-    // TODO Handle target init fail
+    // get configuration options
+    parseConfig(argv, argv + argc, vital_enable, checkstop_enable, ti_enable,
+                bp_enable);
 
     // check if we are being loaded as a daemon
     if (true == getCliOption(argv, argv + argc, "--daemon"))
     {
-        // Check command line args for breakpoint handling enable option
-        bool bp_enable = getCliOption(argv, argv + argc, "--breakpoints");
+        attn::Config config(vital_enable, checkstop_enable, ti_enable,
+                            bp_enable);
 
         // Configure and start attention monitor
-        attn::attnDaemon(bp_enable);
+        attn::attnDaemon(&config);
     }
-    // We are being loaded as an application, so parse the command line
-    // arguments to determine what operation is being requested.
+    // we are being loaded as an application
     else
     {
         // Request to analyze the hardware for error conditions
diff --git a/test/end2end/main.cpp b/test/end2end/main.cpp
index 3232903..fe637f6 100644
--- a/test/end2end/main.cpp
+++ b/test/end2end/main.cpp
@@ -1,18 +1,32 @@
 #include <libpdbg.h>
 
+#include <attn/attn_config.hpp>
 #include <attn/attn_handler.hpp>
+#include <cli.hpp>
 
-// The attnHandler() function is called when the an attention GPIO event is
-// triggered. We call it here directly to simulatea a GPIO event.
-int main()
+/** @brief Attention handler test application */
+int main(int argc, char* argv[])
 {
     int rc = 0; // return code
 
+    // attention handler configuration flags
+    bool vital_enable     = true;
+    bool checkstop_enable = true;
+    bool ti_enable        = true;
+    bool bp_enable        = true;
+
     // initialize pdbg targets
     pdbg_targets_init(nullptr);
 
+    // convert cmd line args to config values
+    parseConfig(argv, argv + argc, vital_enable, checkstop_enable, ti_enable,
+                bp_enable);
+
+    // create attention handler config object
+    attn::Config config(vital_enable, checkstop_enable, ti_enable, bp_enable);
+
     // exercise attention gpio event path
-    attn::attnHandler(false); // false = breakpoint handling disabled
+    attn::attnHandler(&config);
 
     return rc;
 }
diff --git a/test/end2end/meson.build b/test/end2end/meson.build
index f2031d6..e672d98 100644
--- a/test/end2end/meson.build
+++ b/test/end2end/meson.build
@@ -1,7 +1,7 @@
 # create openpower-hw-diags executable for local testing
 executable('openpower-hw-diags-test',
             'main.cpp', 'logging.cpp', 'bp_handler.cpp', 'ti_handler.cpp',
-            'analyzer_main.cpp',
+            'analyzer_main.cpp', '../../cli.cpp',
             link_with : [analyzer, attn],
             include_directories : incdir,
             dependencies : libhei_dep,