Add drive logging

This adds logging for drive failures and inventory
changes.

Tested:

        {
            "@odata.context": "/redfish/v1/$metadata#LogEntry.LogEntry",
            "@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/Entries/1565674864_1",
            "@odata.type": "#LogEntry.v1_4_0.LogEntry",
            "Created": "2019-08-13T05:41:04+00:00",
            "EntryType": "Event",
            "Id": "1565674864_1",
            "Message": "Drive 2 with serial number N/A was installed.",
            "MessageArgs": [
                "Drive",
                "2",
                "N/A"
            ],
            "MessageId": "OpenBMC.0.1.InventoryAdded",
            "Name": "System Event Log Entry",
            "Severity": "OK"
        },
        {
            "@odata.context": "/redfish/v1/$metadata#LogEntry.LogEntry",
            "@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/Entries/1565674987",
            "@odata.type": "#LogEntry.v1_4_0.LogEntry",
            "Created": "2019-08-13T05:43:07+00:00",
            "EntryType": "Event",
            "Id": "1565674987",
            "Message": "Drive Error Occurred: Drive 1.",
            "MessageArgs": [
                "Drive 1"
            ],
            "MessageId": "OpenBMC.0.1.DriveError",
            "Name": "System Event Log Entry",
            "Severity": "Warning"
        }

Change-Id: Ia23e6f48b753cbeb36c3176c39a28f687ad7061c
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/hsbp-manager/include/utils.hpp b/hsbp-manager/include/utils.hpp
index a3b0294..002b1ed 100644
--- a/hsbp-manager/include/utils.hpp
+++ b/hsbp-manager/include/utils.hpp
@@ -14,6 +14,8 @@
 // limitations under the License.
 */
 
+#include <systemd/sd-journal.h>
+
 #include <boost/algorithm/string/predicate.hpp>
 #include <boost/asio/io_context.hpp>
 #include <boost/asio/steady_timer.hpp>
@@ -184,3 +186,28 @@
         power::busname, power::path, properties::interface, properties::get,
         power::interface, power::property);
 }
+
+inline void logDeviceAdded(const std::string& model, const std::string& type,
+                           const std::string& sn)
+{
+    sd_journal_send("MESSAGE=%s", "Inventory Added", "PRIORITY=%i", LOG_ERR,
+                    "REDFISH_MESSAGE_ID=%s", "OpenBMC.0.1.InventoryAdded",
+                    "REDFISH_MESSAGE_ARGS=%s,%s,%s", model.c_str(),
+                    type.c_str(), sn.c_str(), NULL);
+}
+
+inline void logDeviceRemoved(const std::string& model, const std::string& type,
+                             const std::string& sn)
+{
+    sd_journal_send("MESSAGE=%s", "Inventory Removed", "PRIORITY=%i", LOG_ERR,
+                    "REDFISH_MESSAGE_ID=%s", "OpenBMC.0.1.InventoryRemoved",
+                    "REDFISH_MESSAGE_ARGS=%s,%s,%s", model.c_str(),
+                    type.c_str(), sn.c_str(), NULL);
+}
+
+inline void logDriveError(const std::string& name)
+{
+    sd_journal_send("MESSAGE=%s", "Drive Error", "PRIORITY=%i", LOG_ERR,
+                    "REDFISH_MESSAGE_ID=%s", "OpenBMC.0.1.DriveError",
+                    "REDFISH_MESSAGE_ARGS=%s", name.c_str(), NULL);
+}
diff --git a/hsbp-manager/src/hsbp_manager.cpp b/hsbp-manager/src/hsbp_manager.cpp
index d65d80c..f6a1b5f 100644
--- a/hsbp-manager/src/hsbp_manager.cpp
+++ b/hsbp-manager/src/hsbp_manager.cpp
@@ -148,13 +148,18 @@
     Drive(size_t driveIndex, bool present, bool isOperational, bool nvme,
           bool rebuilding) :
         isNvme(nvme),
-        isPresent(present)
+        isPresent(present), index(driveIndex)
     {
         constexpr const char* basePath =
             "/xyz/openbmc_project/inventory/item/drive/Drive_";
         itemIface = objServer.add_interface(
             basePath + std::to_string(driveIndex), inventory::interface);
         itemIface->register_property("Present", isPresent);
+        if (isPresent && !isNvme)
+        {
+            // nvme drives get detected by their fru
+            logDeviceAdded("Drive", std::to_string(index), "N/A");
+        }
         itemIface->register_property("PrettyName",
                                      "Drive " + std::to_string(driveIndex));
         itemIface->initialize();
@@ -245,6 +250,7 @@
         std::vector<Association> warning = {
             {"", "warning", globalInventoryPath}};
         associations->set_property("Associations", warning);
+        logDriveError("Drive " + std::to_string(index));
     }
 
     void clearFailed(void)
@@ -253,6 +259,25 @@
         associations->set_property("Associations", std::vector<Association>{});
     }
 
+    void setPresent(bool set)
+    {
+        // nvme drives get detected by their fru
+        if (isNvme || set == isPresent)
+        {
+            return;
+        }
+        itemIface->set_property("Present", set);
+        isPresent = set;
+        if (isPresent)
+        {
+            logDeviceAdded("Drive", std::to_string(index), "N/A");
+        }
+        else
+        {
+            logDeviceRemoved("Drive", std::to_string(index), "N/A");
+        }
+    }
+
     std::shared_ptr<sdbusplus::asio::dbus_interface> itemIface;
     std::shared_ptr<sdbusplus::asio::dbus_interface> operationalIface;
     std::shared_ptr<sdbusplus::asio::dbus_interface> rebuildingIface;
@@ -262,6 +287,7 @@
 
     bool isNvme;
     bool isPresent;
+    size_t index;
 };
 
 struct Backplane
@@ -405,8 +431,7 @@
             bool isRebuilding = isPresent && (rebuilding & (1 << ii));
 
             it->isNvme = isNvme;
-            it->itemIface->set_property("Present", isPresent);
-            it->isPresent = isPresent;
+            it->setPresent(isPresent);
             it->rebuildingIface->set_property("Rebuilding", isRebuilding);
             if (isFailed || isRebuilding)
             {