monitor: Track fan health in the System object
To prepare for being able to power off the system based on missing fans
or nonfunctional fan sensors, put a global view of this health for all
fans in the System object. This requires now keeping track of fan
presence.
This information is stored in a map based on the fan name. It is done
this way, as opposed to just always calling present/functional APIs on
the Fan objects, so that the code that will be using this information
can be tested in isolation without the System or Fan objects.
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: Ieb1d4003bd13cebc806fd06f0064c63ea8ac6180
diff --git a/monitor/fan.cpp b/monitor/fan.cpp
index 525a22b..6abd2da 100644
--- a/monitor/fan.cpp
+++ b/monitor/fan.cpp
@@ -48,7 +48,12 @@
_monitorDelay(std::get<monitorStartDelayField>(def)),
_monitorTimer(event, std::bind(std::mem_fn(&Fan::startMonitor), this)),
#endif
- _system(system)
+ _system(system),
+ _presenceMatch(bus,
+ rules::propertiesChanged(util::INVENTORY_PATH + _name,
+ util::INV_ITEM_IFACE),
+ std::bind(std::mem_fn(&Fan::presenceChanged), this,
+ std::placeholders::_1))
{
// Start from a known state of functional
updateInventory(true);
@@ -92,8 +97,11 @@
// If it used the JSON config, then it also will do all the work
// out of fan-monitor-init, after _monitorDelay.
_monitorTimer.restartOnce(std::chrono::seconds(_monitorDelay));
-
#endif
+
+ // Get the initial presence state
+ _present = util::SDBusPlus::getProperty<bool>(
+ util::INVENTORY_PATH + _name, util::INV_ITEM_IFACE, "Present");
}
void Fan::startMonitor()
@@ -229,6 +237,8 @@
updateInventory(false);
}
+
+ _system.fanStatusChange(*this);
}
void Fan::updateInventory(bool functional)
@@ -248,6 +258,21 @@
_functional = functional;
}
+void Fan::presenceChanged(sdbusplus::message::message& msg)
+{
+ std::string interface;
+ std::map<std::string, std::variant<bool>> properties;
+
+ msg.read(interface, properties);
+
+ auto presentProp = properties.find("Present");
+ if (presentProp != properties.end())
+ {
+ _present = std::get<bool>(presentProp->second);
+
+ _system.fanStatusChange(*this);
+ }
+}
} // namespace monitor
} // namespace fan
} // namespace phosphor
diff --git a/monitor/fan.hpp b/monitor/fan.hpp
index 537d8fd..a7db524 100644
--- a/monitor/fan.hpp
+++ b/monitor/fan.hpp
@@ -138,6 +138,26 @@
*/
uint64_t findTargetSpeed();
+ /**
+ * @brief Returns the contained TachSensor objects
+ *
+ * @return std::vector<std::shared_ptr<TachSensor>> - The sensors
+ */
+ const std::vector<std::shared_ptr<TachSensor>>& sensors() const
+ {
+ return _sensors;
+ }
+
+ /**
+ * @brief Returns the presence status of the fan
+ *
+ * @return bool - If the fan is present or not
+ */
+ bool present() const
+ {
+ return _present;
+ }
+
private:
/**
* @brief Returns true if the sensor input is not within
@@ -169,6 +189,13 @@
void startMonitor();
/**
+ * @brief Called when the fan presence property changes on D-Bus
+ *
+ * @param[in] msg - The message from the propertiesChanged signal
+ */
+ void presenceChanged(sdbusplus::message::message& msg);
+
+ /**
* @brief the dbus object
*/
sdbusplus::bus::bus& _bus;
@@ -234,6 +261,18 @@
* @brief Reference to the System object
*/
System& _system;
+
+ /**
+ * @brief The match object for propertiesChanged signals
+ * for the inventory item interface to track the
+ * Present property.
+ */
+ sdbusplus::bus::match::match _presenceMatch;
+
+ /**
+ * @brief The current presence state
+ */
+ bool _present = false;
};
} // namespace monitor
diff --git a/monitor/system.cpp b/monitor/system.cpp
index 9b93999..41a5750 100644
--- a/monitor/system.cpp
+++ b/monitor/system.cpp
@@ -67,6 +67,7 @@
setTrustMgr(trustGrps);
// Clear/set configured fan definitions
_fans.clear();
+ _fanHealth.clear();
setFans(fanDefs);
log<level::INFO>("Configuration reloaded successfully");
}
@@ -117,7 +118,26 @@
}
_fans.emplace_back(
std::make_unique<Fan>(_mode, _bus, _event, _trust, fanDef, *this));
+
+ updateFanHealth(*(_fans.back()));
}
}
+void System::updateFanHealth(const Fan& fan)
+{
+ std::vector<bool> sensorStatus;
+ for (const auto& sensor : fan.sensors())
+ {
+ sensorStatus.push_back(sensor->functional());
+ }
+
+ _fanHealth[fan.getName()] =
+ std::make_tuple(fan.present(), std::move(sensorStatus));
+}
+
+void System::fanStatusChange(const Fan& fan)
+{
+ updateFanHealth(fan);
+}
+
} // namespace phosphor::fan::monitor
diff --git a/monitor/system.hpp b/monitor/system.hpp
index 9757082..7c424a2 100644
--- a/monitor/system.hpp
+++ b/monitor/system.hpp
@@ -62,6 +62,15 @@
void sighupHandler(sdeventplus::source::Signal&,
const struct signalfd_siginfo*);
+ /**
+ * @brief Called from the fan when it changes either
+ * present or functional status to update the
+ * fan health map.
+ *
+ * @param[in] fan - The fan that changed
+ */
+ void fanStatusChange(const Fan& fan);
+
private:
/* The mode of fan monitor */
Mode _mode;
@@ -79,6 +88,11 @@
std::vector<std::unique_ptr<Fan>> _fans;
/**
+ * @brief The latest health of all the fans
+ */
+ FanHealth _fanHealth;
+
+ /**
* @brief Retrieve the configured trust groups
*
* @param[in] jsonObj - JSON object to parse from
@@ -109,6 +123,13 @@
* @param[in] fanDefs - list of fan definitions to create fans monitored
*/
void setFans(const std::vector<FanDefinition>& fanDefs);
+
+ /**
+ * @brief Updates the fan health map entry for the fan passed in
+ *
+ * @param[in] fan - The fan to update the health map with
+ */
+ void updateFanHealth(const Fan& fan);
};
} // namespace phosphor::fan::monitor
diff --git a/monitor/types.hpp b/monitor/types.hpp
index 9f69adf..ff46fcd 100644
--- a/monitor/types.hpp
+++ b/monitor/types.hpp
@@ -114,6 +114,11 @@
std::tuple<std::string, size_t, size_t, size_t, size_t, size_t,
std::vector<SensorDefinition>, std::optional<Condition>>;
+constexpr auto presentHealthPos = 0;
+constexpr auto sensorFuncHealthPos = 1;
+
+using FanHealthEntry = std::tuple<bool, std::vector<bool>>;
+using FanHealth = std::map<std::string, FanHealthEntry>;
} // namespace monitor
} // namespace fan
} // namespace phosphor
diff --git a/utility.hpp b/utility.hpp
index 4e8c226..271bb9c 100644
--- a/utility.hpp
+++ b/utility.hpp
@@ -31,6 +31,8 @@
"xyz.openbmc_project.State.Decorator.OperationalStatus";
constexpr auto FUNCTIONAL_PROPERTY = "Functional";
+constexpr auto INV_ITEM_IFACE = "xyz.openbmc_project.Inventory.Item";
+
class FileDescriptor
{
public: