Read fan target sysfs value on startup

When creating the object that represents the
Control.FanSpeed interface for a fan, read the
target fan speed out of sysfs and save it in
the object so it shows up in D-Bus immediately.

Previously the Target property would have a value
of zero until another application wrote it, leaving
a window where the D-Bus property wouldn't match
the underlying sysfs file value.

Change-Id: I08b149840c2cf731bc48f89118622fa63222600e
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/fan_speed.hpp b/fan_speed.hpp
index 3203178..7fc303a 100644
--- a/fan_speed.hpp
+++ b/fan_speed.hpp
@@ -26,18 +26,20 @@
          * @param[in] bus - Dbus bus object
          * @param[in] objPath - Dbus object path
          * @param[in] defer - Dbus object registration defer
+         * @param[in] target - initial target speed value
          */
         FanSpeed(const std::string& instancePath,
                  const std::string& devPath,
                  const std::string& id,
                  sdbusplus::bus::bus& bus,
                  const char* objPath,
-                 bool defer) : FanSpeedObject(bus, objPath, defer),
+                 bool defer,
+                 uint64_t target) : FanSpeedObject(bus, objPath, defer),
                     id(id),
                     ioAccess(instancePath),
                     devPath(devPath)
         {
-            // Nothing to do here
+            FanSpeedObject::target(target);
         }
 
         /**
diff --git a/mainloop.cpp b/mainloop.cpp
index 1190d85..bf2cacc 100644
--- a/mainloop.cpp
+++ b/mainloop.cpp
@@ -346,7 +346,7 @@
         addThreshold<CriticalObject>(i.first.first, id, sensorValue, info);
 
         auto target = addTarget<hwmon::FanSpeed>(
-                i.first, ioAccess.path(), _devPath, info);
+                i.first, ioAccess, _devPath, info);
 
         if (target)
         {
diff --git a/targets.hpp b/targets.hpp
index 863eae5..5e938b0 100644
--- a/targets.hpp
+++ b/targets.hpp
@@ -1,6 +1,9 @@
 #pragma once
 
 #include <experimental/filesystem>
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/log.hpp>
+#include <xyz/openbmc_project/Sensor/Device/error.hpp>
 #include "fan_speed.hpp"
 
 /** @class Targets
@@ -31,7 +34,8 @@
  *  @tparam T - The target type
  *
  *  @param[in] sensor - A sensor type and name
- *  @param[in] instance - The target instance path
+ *  @param[in] ioAccess - hwmon sysfs access object
+ *  @param[in] devPath - The /sys/devices sysfs path
  *  @param[in] info - The sdbusplus server connection and interfaces
  *
  *  @return A shared pointer to the target interface object
@@ -39,7 +43,7 @@
  */
 template <typename T>
 std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor,
-                             const std::string& instancePath,
+                             const sysfs::hwmonio::HwmonIO& ioAccess,
                              const std::string& devPath,
                              ObjectInfo& info)
 {
@@ -52,18 +56,48 @@
     auto& objPath = std::get<std::string>(info);
 
     // Check if target sysfs file exists
-    auto sysfsFullPath = sysfs::make_sysfs_path(instancePath,
+    auto sysfsFullPath = sysfs::make_sysfs_path(ioAccess.path(),
                                                 sensor.first,
                                                 sensor.second,
                                                 hwmon::entry::target);
     if (fs::exists(sysfsFullPath))
     {
-        target = std::make_shared<T>(instancePath,
+        uint32_t targetSpeed = 0;
+
+        try
+        {
+            targetSpeed = ioAccess.read(
+                    sensor.first,
+                    sensor.second,
+                    hwmon::entry::target,
+                    sysfs::hwmonio::retries,
+                    sysfs::hwmonio::delay);
+
+        }
+        catch (const std::system_error& e)
+        {
+            using namespace phosphor::logging;
+            using namespace sdbusplus::xyz::openbmc_project::
+                Sensor::Device::Error;
+            using metadata = xyz::openbmc_project::Sensor::
+                Device::ReadFailure;
+
+            report<ReadFailure>(
+                    metadata::CALLOUT_ERRNO(e.code().value()),
+                    metadata::CALLOUT_DEVICE_PATH(devPath.c_str()));
+
+            log<level::INFO>("Logging failing sysfs file",
+                    phosphor::logging::entry(
+                            "FILE=%s", sysfsFullPath.c_str()));
+        }
+
+        target = std::make_shared<T>(ioAccess.path(),
                                      devPath,
                                      sensor.second,
                                      bus,
                                      objPath.c_str(),
-                                     deferSignals);
+                                     deferSignals,
+                                     targetSpeed);
         auto type = Targets<T>::type;
         obj[type] = target;
     }