summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--monitor/Makefile.am4
-rw-r--r--monitor/fan.cpp113
-rw-r--r--monitor/fan.hpp134
-rw-r--r--monitor/tach_sensor.cpp49
-rw-r--r--monitor/tach_sensor.hpp146
5 files changed, 445 insertions, 1 deletions
diff --git a/monitor/Makefile.am b/monitor/Makefile.am
index ceec3dd..26b66b5 100644
--- a/monitor/Makefile.am
+++ b/monitor/Makefile.am
@@ -5,8 +5,10 @@ sbin_PROGRAMS = \
phosphor-fan-monitor
phosphor_fan_monitor_SOURCES = \
+ fan.cpp \
generated.cpp \
- main.cpp
+ main.cpp \
+ tach_sensor.cpp
phosphor_fan_monitor_LDADD = \
$(SDBUSPLUS_LIBS) \
diff --git a/monitor/fan.cpp b/monitor/fan.cpp
new file mode 100644
index 0000000..b29eaab
--- /dev/null
+++ b/monitor/fan.cpp
@@ -0,0 +1,113 @@
+/**
+ * Copyright © 2017 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <algorithm>
+#include <phosphor-logging/log.hpp>
+#include "fan.hpp"
+#include "types.hpp"
+
+namespace phosphor
+{
+namespace fan
+{
+namespace monitor
+{
+
+using namespace phosphor::logging;
+
+Fan::Fan(sdbusplus::bus::bus& bus,
+ std::shared_ptr<sd_event>& events,
+ const FanDefinition& def) :
+ _bus(bus),
+ _name(std::get<fanNameField>(def)),
+ _deviation(std::get<fanDeviationField>(def)),
+ _numSensorFailsForNonFunc(std::get<numSensorFailsForNonfuncField>(def))
+{
+ auto& sensors = std::get<sensorListField>(def);
+
+ for (auto& s : sensors)
+ {
+ _sensors.emplace_back(
+ std::make_unique<TachSensor>(bus,
+ *this,
+ std::get<sensorNameField>(s),
+ std::get<hasTargetField>(s),
+ std::get<timeoutField>(def)));
+
+ }
+
+}
+
+
+uint64_t Fan::getTargetSpeed(const TachSensor& sensor)
+{
+ uint64_t target = 0;
+
+ if (sensor.hasTarget())
+ {
+ target = sensor.getTarget();
+ }
+ else
+ {
+ //The sensor doesn't support a target,
+ //so get it from another sensor.
+ auto s = std::find_if(_sensors.begin(), _sensors.end(),
+ [](const auto& s)
+ {
+ return s->hasTarget();
+ });
+
+ if (s != _sensors.end())
+ {
+ target = (*s)->getTarget();
+ }
+ }
+
+ return target;
+}
+
+
+bool Fan::tooManySensorsNonfunctional()
+{
+ size_t numFailed = std::count_if(_sensors.begin(), _sensors.end(),
+ [](const auto& s)
+ {
+ return !s->functional();
+ });
+
+ return (numFailed >= _numSensorFailsForNonFunc);
+}
+
+
+bool Fan::outOfRange(const TachSensor& sensor)
+{
+ auto actual = static_cast<uint64_t>(sensor.getInput());
+ auto target = getTargetSpeed(sensor);
+
+ uint64_t min = target * (100 - _deviation) / 100;
+ uint64_t max = target * (100 + _deviation) / 100;
+
+ if ((actual < min) || (actual > max))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+
+}
+}
+}
diff --git a/monitor/fan.hpp b/monitor/fan.hpp
new file mode 100644
index 0000000..6cbd370
--- /dev/null
+++ b/monitor/fan.hpp
@@ -0,0 +1,134 @@
+#pragma once
+
+#include <sdbusplus/bus.hpp>
+#include <tuple>
+#include <vector>
+#include "tach_sensor.hpp"
+#include "types.hpp"
+
+namespace phosphor
+{
+namespace fan
+{
+namespace monitor
+{
+
+
+/**
+ * @class Fan
+ *
+ * Represents a fan, which can contain 1 or more sensors which
+ * loosely correspond to rotors. See below.
+ *
+ * There is a sensor when hwmon exposes one, which means there is a
+ * speed value to be read. Sometimes there is a sensor per rotor,
+ * and other times multiple rotors just use 1 sensor total where
+ * the sensor reports the slowest speed of all of the rotors.
+ *
+ * A rotor's speed is set by writing the Target value of a sensor.
+ * Sometimes each sensor in a fan supports having a Target, and other
+ * times not all of them do. A TachSensor object knows if it supports
+ * the Target property.
+ *
+ * The strategy for monitoring fan speeds is as follows:
+ *
+ * Every time a Target (new speed written) or Input (actual speed read)
+ * sensor changes, check if the input value is within some range of the target
+ * value. If it isn't, start a timer at the end of which the sensor will be
+ * set to not functional. If enough sensors in the fan are now nonfunctional,
+ * set the whole fan to nonfunctional in the inventory.
+ *
+ * When sensor inputs come back within a specified range of the target,
+ * stop its timer if running, make the sensor functional again if it wasn't,
+ * and if enough sensors in the fan are now functional set the whole fan
+ * back to functional in the inventory.
+ */
+class Fan
+{
+
+ public:
+
+ Fan() = delete;
+ Fan(const Fan&) = delete;
+ Fan(Fan&&) = default;
+ Fan& operator=(const Fan&) = delete;
+ Fan& operator=(Fan&&) = default;
+ ~Fan() = default;
+
+ /**
+ * @brief Constructor
+ *
+ * @param bus - the dbus object
+ * @param events - pointer to sd_event object
+ * @param def - the fan definition structure
+ */
+ Fan(sdbusplus::bus::bus& bus,
+ std::shared_ptr<sd_event>& events,
+ const FanDefinition& def);
+
+
+ private:
+
+ /**
+ * @brief Returns the target speed of the sensor
+ *
+ * If the sensor itself doesn't have a target, it finds
+ * the target speed from another sensor.
+ *
+ * @param[in] sensor - the sensor to get the target speed for
+ */
+ uint64_t getTargetSpeed(const TachSensor& sensor);
+
+ /**
+ * @brief Returns true if the sensor input is not within
+ * some deviation of the target.
+ *
+ * @param[in] sensor - the sensor to check
+ */
+ bool outOfRange(const TachSensor& sensor);
+
+ /**
+ * @brief Returns true if too many sensors are nonfunctional
+ * as defined by _numSensorFailsForNonFunc
+ */
+ bool tooManySensorsNonfunctional();
+
+
+ /**
+ * @brief the dbus object
+ */
+ sdbusplus::bus::bus& _bus;
+
+ /**
+ * @brief The inventory name of the fan
+ */
+ const std::string _name;
+
+ /**
+ * @brief The percentage that the input speed must be below
+ * the target speed to be considered an error.
+ * Between 0 and 100.
+ */
+ const size_t _deviation;
+
+ /**
+ * The number of sensors that must be nonfunctional at the
+ * same time in order for the fan to be set to nonfunctional
+ * in the inventory.
+ */
+ const size_t _numSensorFailsForNonFunc;
+
+ /**
+ * @brief The current functional state of the fan
+ */
+ bool _functional = true;
+
+ /**
+ * The sensor objects for the fan
+ */
+ std::vector<std::unique_ptr<TachSensor>> _sensors;
+};
+
+}
+}
+}
diff --git a/monitor/tach_sensor.cpp b/monitor/tach_sensor.cpp
new file mode 100644
index 0000000..3264ddf
--- /dev/null
+++ b/monitor/tach_sensor.cpp
@@ -0,0 +1,49 @@
+/**
+ * Copyright © 2017 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <phosphor-logging/log.hpp>
+#include "fan.hpp"
+#include "tach_sensor.hpp"
+#include "../utility.hpp"
+
+namespace phosphor
+{
+namespace fan
+{
+namespace monitor
+{
+
+constexpr auto FAN_SENSOR_PATH = "/xyz/openbmc_project/sensors/fan_tach/";
+
+
+TachSensor::TachSensor(sdbusplus::bus::bus& bus,
+ Fan& fan,
+ const std::string& id,
+ bool hasTarget,
+ size_t timeout) :
+
+ _bus(bus),
+ _fan(fan),
+ _name(FAN_SENSOR_PATH + id),
+ _hasTarget(hasTarget),
+ _timeout(timeout)
+{
+ //TODO
+}
+
+
+}
+}
+}
diff --git a/monitor/tach_sensor.hpp b/monitor/tach_sensor.hpp
new file mode 100644
index 0000000..df340f5
--- /dev/null
+++ b/monitor/tach_sensor.hpp
@@ -0,0 +1,146 @@
+#pragma once
+
+#include <chrono>
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/server.hpp>
+
+namespace phosphor
+{
+namespace fan
+{
+namespace monitor
+{
+
+class Fan;
+
+
+/**
+ * @class TachSensor
+ *
+ * This class represents the sensor that reads a tach value.
+ * It may also support a Target, which is the property used to
+ * set a speed. Since it doesn't necessarily have a Target, it
+ * won't for sure know if it is running too slow, so it leaves
+ * that determination to other code.
+ *
+ * This class has a parent Fan object that knows about all
+ * sensors for that fan.
+ */
+class TachSensor
+{
+ public:
+
+ TachSensor() = delete;
+ TachSensor(const TachSensor&) = delete;
+ TachSensor(TachSensor&&) = default;
+ TachSensor& operator=(const TachSensor&) = delete;
+ TachSensor& operator=(TachSensor&&) = default;
+ ~TachSensor() = default;
+
+ /**
+ * @brief Constructor
+ *
+ * @param[in] bus - the dbus object
+ * @param[in] fan - the parent fan object
+ * @param[in] id - the id of the sensor
+ * @param[in] hasTarget - if the sensor supports
+ * setting the speed
+ * @param[in] timeout - Normal timeout value to use
+ */
+ TachSensor(sdbusplus::bus::bus& bus,
+ Fan& fan,
+ const std::string& id,
+ bool hasTarget,
+ size_t timeout);
+
+ /**
+ * @brief Returns the target speed value
+ */
+ inline uint64_t getTarget() const
+ {
+ return _tachTarget;
+ }
+
+ /**
+ * @brief Returns the input speed value
+ */
+ inline int64_t getInput() const
+ {
+ return _tachInput;
+ }
+
+ /**
+ * @brief Returns true if sensor has a target
+ */
+ inline bool hasTarget() const
+ {
+ return _hasTarget;
+ }
+
+ /**
+ * Returns true if the hardware behind this
+ * sensor is considered working OK/functional.
+ */
+ inline bool functional() const
+ {
+ return _functional;
+ }
+
+ /**
+ * Sets functional status
+ */
+ inline void setFunctional(bool functional)
+ {
+ _functional = functional;
+ }
+
+ private:
+
+ /**
+ * @brief the dbus object
+ */
+ sdbusplus::bus::bus& _bus;
+
+ /**
+ * @brief Reference to the parent Fan object
+ */
+ Fan& _fan;
+
+ /**
+ * @brief The name of the sensor, including the full path
+ *
+ * For example /xyz/openbmc_project/sensors/fan_tach/fan0
+ */
+ const std::string _name;
+
+ /**
+ * @brief If functional (not too slow). The parent
+ * fan object sets this.
+ */
+ bool _functional = true;
+
+ /**
+ * @brief If the sensor has a Target property (can set speed)
+ */
+ const bool _hasTarget;
+
+ /**
+ * @brief The input speed, from the Value dbus property
+ */
+ int64_t _tachInput = 0;
+
+ /**
+ * @brief The current target speed, from the Target dbus property
+ * (if applicable)
+ */
+ uint64_t _tachTarget = 0;
+
+ /**
+ * @brief The timeout value to use
+ */
+ const size_t _timeout;
+};
+
+}
+}
+}
OpenPOWER on IntegriCloud