19ea8bee7SMatthew Barth /**
29ea8bee7SMatthew Barth * Copyright © 2020 IBM Corporation
39ea8bee7SMatthew Barth *
49ea8bee7SMatthew Barth * Licensed under the Apache License, Version 2.0 (the "License");
59ea8bee7SMatthew Barth * you may not use this file except in compliance with the License.
69ea8bee7SMatthew Barth * You may obtain a copy of the License at
79ea8bee7SMatthew Barth *
89ea8bee7SMatthew Barth * http://www.apache.org/licenses/LICENSE-2.0
99ea8bee7SMatthew Barth *
109ea8bee7SMatthew Barth * Unless required by applicable law or agreed to in writing, software
119ea8bee7SMatthew Barth * distributed under the License is distributed on an "AS IS" BASIS,
129ea8bee7SMatthew Barth * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139ea8bee7SMatthew Barth * See the License for the specific language governing permissions and
149ea8bee7SMatthew Barth * limitations under the License.
159ea8bee7SMatthew Barth */
169ea8bee7SMatthew Barth #include "json_parser.hpp"
179ea8bee7SMatthew Barth
1822ab93b4SMatthew Barth #include "conditions.hpp"
199ea8bee7SMatthew Barth #include "json_config.hpp"
209ea8bee7SMatthew Barth #include "nonzero_speed_trust.hpp"
21f06ab07cSMatt Spinler #include "power_interface.hpp"
22f06ab07cSMatt Spinler #include "power_off_rule.hpp"
2369f2f48eSJolie Ku #include "tach_sensor.hpp"
249ea8bee7SMatthew Barth #include "types.hpp"
259ea8bee7SMatthew Barth
269ea8bee7SMatthew Barth #include <nlohmann/json.hpp>
279ea8bee7SMatthew Barth #include <phosphor-logging/log.hpp>
289ea8bee7SMatthew Barth
299ea8bee7SMatthew Barth #include <algorithm>
30fbf4703fSPatrick Williams #include <format>
319ea8bee7SMatthew Barth #include <map>
329ea8bee7SMatthew Barth #include <memory>
3322ab93b4SMatthew Barth #include <optional>
349ea8bee7SMatthew Barth #include <vector>
359ea8bee7SMatthew Barth
369ea8bee7SMatthew Barth namespace phosphor::fan::monitor
379ea8bee7SMatthew Barth {
389ea8bee7SMatthew Barth
399ea8bee7SMatthew Barth using json = nlohmann::json;
409ea8bee7SMatthew Barth using namespace phosphor::logging;
419ea8bee7SMatthew Barth
429ea8bee7SMatthew Barth namespace tClass
439ea8bee7SMatthew Barth {
449ea8bee7SMatthew Barth
459ea8bee7SMatthew Barth // Get a constructed trust group class for a non-zero speed group
469ea8bee7SMatthew Barth CreateGroupFunction
getNonZeroSpeed(const std::vector<trust::GroupDefinition> & group)479ea8bee7SMatthew Barth getNonZeroSpeed(const std::vector<trust::GroupDefinition>& group)
489ea8bee7SMatthew Barth {
499ea8bee7SMatthew Barth return [group]() {
509ea8bee7SMatthew Barth return std::make_unique<trust::NonzeroSpeed>(std::move(group));
519ea8bee7SMatthew Barth };
529ea8bee7SMatthew Barth }
539ea8bee7SMatthew Barth
549ea8bee7SMatthew Barth } // namespace tClass
559ea8bee7SMatthew Barth
569ea8bee7SMatthew Barth const std::map<std::string, trustHandler> trusts = {
579ea8bee7SMatthew Barth {"nonzerospeed", tClass::getNonZeroSpeed}};
583ad14346SMatthew Barth const std::map<std::string, condHandler> conditions = {
593ad14346SMatthew Barth {"propertiesmatch", condition::getPropertiesMatch}};
6069f2f48eSJolie Ku const std::map<std::string, size_t> methods = {
6169f2f48eSJolie Ku {"timebased", MethodMode::timebased}, {"count", MethodMode::count}};
629ea8bee7SMatthew Barth
getTrustGrps(const json & obj)639ea8bee7SMatthew Barth const std::vector<CreateGroupFunction> getTrustGrps(const json& obj)
649ea8bee7SMatthew Barth {
659ea8bee7SMatthew Barth std::vector<CreateGroupFunction> grpFuncs;
669ea8bee7SMatthew Barth
679ea8bee7SMatthew Barth if (obj.contains("sensor_trust_groups"))
689ea8bee7SMatthew Barth {
699ea8bee7SMatthew Barth for (auto& stg : obj["sensor_trust_groups"])
709ea8bee7SMatthew Barth {
719ea8bee7SMatthew Barth if (!stg.contains("class") || !stg.contains("group"))
729ea8bee7SMatthew Barth {
739ea8bee7SMatthew Barth // Log error on missing required parameters
749ea8bee7SMatthew Barth log<level::ERR>(
759ea8bee7SMatthew Barth "Missing required fan monitor trust group parameters",
769ea8bee7SMatthew Barth entry("REQUIRED_PARAMETERS=%s", "{class, group}"));
779ea8bee7SMatthew Barth throw std::runtime_error(
789ea8bee7SMatthew Barth "Missing required fan trust group parameters");
799ea8bee7SMatthew Barth }
809ea8bee7SMatthew Barth auto tgClass = stg["class"].get<std::string>();
819ea8bee7SMatthew Barth std::vector<trust::GroupDefinition> group;
829ea8bee7SMatthew Barth for (auto& member : stg["group"])
839ea8bee7SMatthew Barth {
849ea8bee7SMatthew Barth // Construct list of group members
859ea8bee7SMatthew Barth if (!member.contains("name"))
869ea8bee7SMatthew Barth {
879ea8bee7SMatthew Barth // Log error on missing required parameter
889ea8bee7SMatthew Barth log<level::ERR>(
899ea8bee7SMatthew Barth "Missing required fan monitor trust group member name",
909ea8bee7SMatthew Barth entry("CLASS=%s", tgClass.c_str()));
919ea8bee7SMatthew Barth throw std::runtime_error(
929ea8bee7SMatthew Barth "Missing required fan monitor trust group member name");
939ea8bee7SMatthew Barth }
949ea8bee7SMatthew Barth auto in_trust = true;
959ea8bee7SMatthew Barth if (member.contains("in_trust"))
969ea8bee7SMatthew Barth {
979ea8bee7SMatthew Barth in_trust = member["in_trust"].get<bool>();
989ea8bee7SMatthew Barth }
999ea8bee7SMatthew Barth group.emplace_back(trust::GroupDefinition{
1009ea8bee7SMatthew Barth member["name"].get<std::string>(), in_trust});
1019ea8bee7SMatthew Barth }
1029ea8bee7SMatthew Barth // The class for fan sensor trust groups
1039ea8bee7SMatthew Barth // (Must have a supported function within the tClass namespace)
1049ea8bee7SMatthew Barth std::transform(tgClass.begin(), tgClass.end(), tgClass.begin(),
1059ea8bee7SMatthew Barth tolower);
1069ea8bee7SMatthew Barth auto handler = trusts.find(tgClass);
1079ea8bee7SMatthew Barth if (handler != trusts.end())
1089ea8bee7SMatthew Barth {
1099ea8bee7SMatthew Barth // Call function for trust group class
1109ea8bee7SMatthew Barth grpFuncs.emplace_back(handler->second(group));
1119ea8bee7SMatthew Barth }
1129ea8bee7SMatthew Barth else
1139ea8bee7SMatthew Barth {
1149ea8bee7SMatthew Barth // Log error on unsupported trust group class
1159ea8bee7SMatthew Barth log<level::ERR>("Invalid fan monitor trust group class",
1169ea8bee7SMatthew Barth entry("CLASS=%s", tgClass.c_str()));
1179ea8bee7SMatthew Barth throw std::runtime_error(
1189ea8bee7SMatthew Barth "Invalid fan monitor trust group class");
1199ea8bee7SMatthew Barth }
1209ea8bee7SMatthew Barth }
1219ea8bee7SMatthew Barth }
1229ea8bee7SMatthew Barth
1239ea8bee7SMatthew Barth return grpFuncs;
1249ea8bee7SMatthew Barth }
1259ea8bee7SMatthew Barth
getSensorDefs(const json & sensors)12622ab93b4SMatthew Barth const std::vector<SensorDefinition> getSensorDefs(const json& sensors)
12722ab93b4SMatthew Barth {
12822ab93b4SMatthew Barth std::vector<SensorDefinition> sensorDefs;
12922ab93b4SMatthew Barth
13022ab93b4SMatthew Barth for (const auto& sensor : sensors)
13122ab93b4SMatthew Barth {
13222ab93b4SMatthew Barth if (!sensor.contains("name") || !sensor.contains("has_target"))
13322ab93b4SMatthew Barth {
13422ab93b4SMatthew Barth // Log error on missing required parameters
13522ab93b4SMatthew Barth log<level::ERR>(
13622ab93b4SMatthew Barth "Missing required fan sensor definition parameters",
13722ab93b4SMatthew Barth entry("REQUIRED_PARAMETERS=%s", "{name, has_target}"));
13822ab93b4SMatthew Barth throw std::runtime_error(
13922ab93b4SMatthew Barth "Missing required fan sensor definition parameters");
14022ab93b4SMatthew Barth }
14122ab93b4SMatthew Barth // Target interface is optional and defaults to
14222ab93b4SMatthew Barth // 'xyz.openbmc_project.Control.FanSpeed'
14322ab93b4SMatthew Barth std::string targetIntf = "xyz.openbmc_project.Control.FanSpeed";
14422ab93b4SMatthew Barth if (sensor.contains("target_interface"))
14522ab93b4SMatthew Barth {
14622ab93b4SMatthew Barth targetIntf = sensor["target_interface"].get<std::string>();
14722ab93b4SMatthew Barth }
14827cc39f1SChau Ly // Target path is optional
14927cc39f1SChau Ly std::string targetPath;
15027cc39f1SChau Ly if (sensor.contains("target_path"))
15127cc39f1SChau Ly {
15227cc39f1SChau Ly targetPath = sensor["target_path"].get<std::string>();
15327cc39f1SChau Ly }
15422ab93b4SMatthew Barth // Factor is optional and defaults to 1
15518fb12b8SMatt Spinler double factor = 1.0;
15622ab93b4SMatthew Barth if (sensor.contains("factor"))
15722ab93b4SMatthew Barth {
15822ab93b4SMatthew Barth factor = sensor["factor"].get<double>();
15922ab93b4SMatthew Barth }
16022ab93b4SMatthew Barth // Offset is optional and defaults to 0
16118fb12b8SMatt Spinler int64_t offset = 0;
16222ab93b4SMatthew Barth if (sensor.contains("offset"))
16322ab93b4SMatthew Barth {
16422ab93b4SMatthew Barth offset = sensor["offset"].get<int64_t>();
16522ab93b4SMatthew Barth }
16669f2f48eSJolie Ku // Threshold is optional and defaults to 1
16718fb12b8SMatt Spinler size_t threshold = 1;
16869f2f48eSJolie Ku if (sensor.contains("threshold"))
16969f2f48eSJolie Ku {
17069f2f48eSJolie Ku threshold = sensor["threshold"].get<size_t>();
17169f2f48eSJolie Ku }
1728a8aa442SMatthew Barth // Ignore being above the allowed max is optional, defaults to not
1738a8aa442SMatthew Barth bool ignoreAboveMax = false;
1748a8aa442SMatthew Barth if (sensor.contains("ignore_above_max"))
1758a8aa442SMatthew Barth {
1768a8aa442SMatthew Barth ignoreAboveMax = sensor["ignore_above_max"].get<bool>();
1778a8aa442SMatthew Barth }
17822ab93b4SMatthew Barth
179*dfddd648SPatrick Williams SensorDefinition def{
180*dfddd648SPatrick Williams .name = sensor["name"].get<std::string>(),
18118fb12b8SMatt Spinler .hasTarget = sensor["has_target"].get<bool>(),
18218fb12b8SMatt Spinler .targetInterface = targetIntf,
18318fb12b8SMatt Spinler .targetPath = targetPath,
18418fb12b8SMatt Spinler .factor = factor,
18518fb12b8SMatt Spinler .offset = offset,
18618fb12b8SMatt Spinler .threshold = threshold,
18718fb12b8SMatt Spinler .ignoreAboveMax = ignoreAboveMax};
18818fb12b8SMatt Spinler
18918fb12b8SMatt Spinler sensorDefs.push_back(std::move(def));
19022ab93b4SMatthew Barth }
19122ab93b4SMatthew Barth
19222ab93b4SMatthew Barth return sensorDefs;
19322ab93b4SMatthew Barth }
19422ab93b4SMatthew Barth
getFanDefs(const json & obj)19522ab93b4SMatthew Barth const std::vector<FanDefinition> getFanDefs(const json& obj)
19622ab93b4SMatthew Barth {
19722ab93b4SMatthew Barth std::vector<FanDefinition> fanDefs;
19822ab93b4SMatthew Barth
19922ab93b4SMatthew Barth for (const auto& fan : obj["fans"])
20022ab93b4SMatthew Barth {
20169f2f48eSJolie Ku if (!fan.contains("inventory") || !fan.contains("deviation") ||
20269f2f48eSJolie Ku !fan.contains("sensors"))
20322ab93b4SMatthew Barth {
20422ab93b4SMatthew Barth // Log error on missing required parameters
20522ab93b4SMatthew Barth log<level::ERR>(
20622ab93b4SMatthew Barth "Missing required fan monitor definition parameters",
20722ab93b4SMatthew Barth entry("REQUIRED_PARAMETERS=%s",
20869f2f48eSJolie Ku "{inventory, deviation, sensors}"));
20922ab93b4SMatthew Barth throw std::runtime_error(
21022ab93b4SMatthew Barth "Missing required fan monitor definition parameters");
21122ab93b4SMatthew Barth }
2124c4de263SMatthew Barth // Valid deviation range is 0 - 100%
2134c4de263SMatthew Barth auto deviation = fan["deviation"].get<size_t>();
214808d7fe8SMike Capps if (100 < deviation)
2154c4de263SMatthew Barth {
216fbf4703fSPatrick Williams auto msg = std::format(
2174c4de263SMatthew Barth "Invalid deviation of {} found, must be between 0 and 100",
21878182482SMike Capps deviation);
21978182482SMike Capps
22078182482SMike Capps log<level::ERR>(msg.c_str());
22178182482SMike Capps throw std::runtime_error(msg.c_str());
2224c4de263SMatthew Barth }
2234c4de263SMatthew Barth
224f724c16bSMatt Spinler // Upper deviation defaults to the deviation value and
225f724c16bSMatt Spinler // can also be separately specified.
226f724c16bSMatt Spinler size_t upperDeviation = deviation;
227f724c16bSMatt Spinler if (fan.contains("upper_deviation"))
228f724c16bSMatt Spinler {
229f724c16bSMatt Spinler upperDeviation = fan["upper_deviation"].get<size_t>();
230f724c16bSMatt Spinler if (100 < upperDeviation)
231f724c16bSMatt Spinler {
232f724c16bSMatt Spinler auto msg =
233fbf4703fSPatrick Williams std::format("Invalid upper_deviation of {} found, must "
234f724c16bSMatt Spinler "be between 0 and 100",
235f724c16bSMatt Spinler upperDeviation);
236f724c16bSMatt Spinler
237f724c16bSMatt Spinler log<level::ERR>(msg.c_str());
238f724c16bSMatt Spinler throw std::runtime_error(msg.c_str());
239f724c16bSMatt Spinler }
240f724c16bSMatt Spinler }
241f724c16bSMatt Spinler
24222ab93b4SMatthew Barth // Construct the sensor definitions for this fan
24322ab93b4SMatthew Barth auto sensorDefs = getSensorDefs(fan["sensors"]);
24422ab93b4SMatthew Barth
24522ab93b4SMatthew Barth // Functional delay is optional and defaults to 0
24622ab93b4SMatthew Barth size_t funcDelay = 0;
24722ab93b4SMatthew Barth if (fan.contains("functional_delay"))
24822ab93b4SMatthew Barth {
24922ab93b4SMatthew Barth funcDelay = fan["functional_delay"].get<size_t>();
25022ab93b4SMatthew Barth }
25122ab93b4SMatthew Barth
25269f2f48eSJolie Ku // Method is optional and defaults to time based functional
25369f2f48eSJolie Ku // determination
25469f2f48eSJolie Ku size_t method = MethodMode::timebased;
255623635c6SMatt Spinler size_t countInterval = 1;
25669f2f48eSJolie Ku if (fan.contains("method"))
25769f2f48eSJolie Ku {
25869f2f48eSJolie Ku auto methodConf = fan["method"].get<std::string>();
25969f2f48eSJolie Ku auto methodFunc = methods.find(methodConf);
26069f2f48eSJolie Ku if (methodFunc != methods.end())
26169f2f48eSJolie Ku {
26269f2f48eSJolie Ku method = methodFunc->second;
26369f2f48eSJolie Ku }
26469f2f48eSJolie Ku else
26569f2f48eSJolie Ku {
26669f2f48eSJolie Ku // Log error on unsupported method parameter
26769f2f48eSJolie Ku log<level::ERR>("Invalid fan method");
26869f2f48eSJolie Ku throw std::runtime_error("Invalid fan method");
26969f2f48eSJolie Ku }
270623635c6SMatt Spinler
271623635c6SMatt Spinler // Read the count interval value used with the count method.
272623635c6SMatt Spinler if (method == MethodMode::count)
273623635c6SMatt Spinler {
274623635c6SMatt Spinler if (fan.contains("count_interval"))
275623635c6SMatt Spinler {
276623635c6SMatt Spinler countInterval = fan["count_interval"].get<size_t>();
277623635c6SMatt Spinler }
278623635c6SMatt Spinler }
27969f2f48eSJolie Ku }
28069f2f48eSJolie Ku
28169f2f48eSJolie Ku // Timeout defaults to 0
28269f2f48eSJolie Ku size_t timeout = 0;
28369f2f48eSJolie Ku if (method == MethodMode::timebased)
28469f2f48eSJolie Ku {
28569f2f48eSJolie Ku if (!fan.contains("allowed_out_of_range_time"))
28669f2f48eSJolie Ku {
28769f2f48eSJolie Ku // Log error on missing required parameter
28869f2f48eSJolie Ku log<level::ERR>(
28969f2f48eSJolie Ku "Missing required fan monitor definition parameters",
29069f2f48eSJolie Ku entry("REQUIRED_PARAMETER=%s",
29169f2f48eSJolie Ku "{allowed_out_of_range_time}"));
29269f2f48eSJolie Ku throw std::runtime_error(
29369f2f48eSJolie Ku "Missing required fan monitor definition parameters");
29469f2f48eSJolie Ku }
29569f2f48eSJolie Ku else
29669f2f48eSJolie Ku {
29769f2f48eSJolie Ku timeout = fan["allowed_out_of_range_time"].get<size_t>();
29869f2f48eSJolie Ku }
29969f2f48eSJolie Ku }
30069f2f48eSJolie Ku
301b0412d07SMatt Spinler // Monitor start delay is optional and defaults to 0
302b0412d07SMatt Spinler size_t monitorDelay = 0;
303b0412d07SMatt Spinler if (fan.contains("monitor_start_delay"))
304b0412d07SMatt Spinler {
305b0412d07SMatt Spinler monitorDelay = fan["monitor_start_delay"].get<size_t>();
306b0412d07SMatt Spinler }
307b0412d07SMatt Spinler
308ae1f8efeSMatt Spinler // num_sensors_nonfunc_for_fan_nonfunc is optional and defaults
309ae1f8efeSMatt Spinler // to zero if not present, meaning the code will not set the
310ae1f8efeSMatt Spinler // parent fan to nonfunctional based on sensors.
311ae1f8efeSMatt Spinler size_t nonfuncSensorsCount = 0;
312ae1f8efeSMatt Spinler if (fan.contains("num_sensors_nonfunc_for_fan_nonfunc"))
313ae1f8efeSMatt Spinler {
314ae1f8efeSMatt Spinler nonfuncSensorsCount =
315ae1f8efeSMatt Spinler fan["num_sensors_nonfunc_for_fan_nonfunc"].get<size_t>();
316ae1f8efeSMatt Spinler }
317ae1f8efeSMatt Spinler
318f13b42e2SMatt Spinler // nonfunc_rotor_error_delay is optional, though it will
319f13b42e2SMatt Spinler // default to zero if 'fault_handling' is present.
320f13b42e2SMatt Spinler std::optional<size_t> nonfuncRotorErrorDelay;
321f13b42e2SMatt Spinler if (fan.contains("nonfunc_rotor_error_delay"))
322f13b42e2SMatt Spinler {
323f13b42e2SMatt Spinler nonfuncRotorErrorDelay =
324f13b42e2SMatt Spinler fan["nonfunc_rotor_error_delay"].get<size_t>();
325f13b42e2SMatt Spinler }
326f13b42e2SMatt Spinler else if (obj.contains("fault_handling"))
327f13b42e2SMatt Spinler {
328f13b42e2SMatt Spinler nonfuncRotorErrorDelay = 0;
329f13b42e2SMatt Spinler }
330f13b42e2SMatt Spinler
33127f6b686SMatt Spinler // fan_missing_error_delay is optional.
33227f6b686SMatt Spinler std::optional<size_t> fanMissingErrorDelay;
33327f6b686SMatt Spinler if (fan.contains("fan_missing_error_delay"))
33427f6b686SMatt Spinler {
33527f6b686SMatt Spinler fanMissingErrorDelay =
33627f6b686SMatt Spinler fan.at("fan_missing_error_delay").get<size_t>();
33727f6b686SMatt Spinler }
33827f6b686SMatt Spinler
3393ad14346SMatthew Barth // Handle optional conditions
3408a0c2327SMatthew Barth auto cond = std::optional<Condition>();
3413ad14346SMatthew Barth if (fan.contains("condition"))
3423ad14346SMatthew Barth {
3433ad14346SMatthew Barth if (!fan["condition"].contains("name"))
3443ad14346SMatthew Barth {
3453ad14346SMatthew Barth // Log error on missing required parameter
3463ad14346SMatthew Barth log<level::ERR>(
3473ad14346SMatthew Barth "Missing required fan monitor condition parameter",
3483ad14346SMatthew Barth entry("REQUIRED_PARAMETER=%s", "{name}"));
3493ad14346SMatthew Barth throw std::runtime_error(
3503ad14346SMatthew Barth "Missing required fan monitor condition parameter");
3513ad14346SMatthew Barth }
3523ad14346SMatthew Barth auto name = fan["condition"]["name"].get<std::string>();
3533ad14346SMatthew Barth // The function for fan monitoring condition
3543ad14346SMatthew Barth // (Must have a supported function within the condition namespace)
3553ad14346SMatthew Barth std::transform(name.begin(), name.end(), name.begin(), tolower);
3563ad14346SMatthew Barth auto handler = conditions.find(name);
3573ad14346SMatthew Barth if (handler != conditions.end())
3583ad14346SMatthew Barth {
3593ad14346SMatthew Barth cond = handler->second(fan["condition"]);
3603ad14346SMatthew Barth }
3613ad14346SMatthew Barth else
3623ad14346SMatthew Barth {
3633ad14346SMatthew Barth log<level::INFO>(
3643ad14346SMatthew Barth "No handler found for configured condition",
3653ad14346SMatthew Barth entry("CONDITION_NAME=%s", name.c_str()),
3663ad14346SMatthew Barth entry("JSON_DUMP=%s", fan["condition"].dump().c_str()));
3673ad14346SMatthew Barth }
3683ad14346SMatthew Barth }
36969f2f48eSJolie Ku
370a3584bd2SMatt Spinler // if the fan should be set to functional when plugged in
371a3584bd2SMatt Spinler bool setFuncOnPresent = false;
372a3584bd2SMatt Spinler if (fan.contains("set_func_on_present"))
373a3584bd2SMatt Spinler {
374a3584bd2SMatt Spinler setFuncOnPresent = fan["set_func_on_present"].get<bool>();
375a3584bd2SMatt Spinler }
376a3584bd2SMatt Spinler
377*dfddd648SPatrick Williams FanDefinition def{
378*dfddd648SPatrick Williams .name = fan["inventory"].get<std::string>(),
37918fb12b8SMatt Spinler .method = method,
38018fb12b8SMatt Spinler .funcDelay = funcDelay,
38118fb12b8SMatt Spinler .timeout = timeout,
38218fb12b8SMatt Spinler .deviation = deviation,
383f724c16bSMatt Spinler .upperDeviation = upperDeviation,
38418fb12b8SMatt Spinler .numSensorFailsForNonfunc = nonfuncSensorsCount,
38518fb12b8SMatt Spinler .monitorStartDelay = monitorDelay,
38618fb12b8SMatt Spinler .countInterval = countInterval,
38718fb12b8SMatt Spinler .nonfuncRotorErrDelay = nonfuncRotorErrorDelay,
38818fb12b8SMatt Spinler .fanMissingErrDelay = fanMissingErrorDelay,
38918fb12b8SMatt Spinler .sensorList = std::move(sensorDefs),
39018fb12b8SMatt Spinler .condition = cond,
39118fb12b8SMatt Spinler .funcOnPresent = setFuncOnPresent};
39218fb12b8SMatt Spinler
39318fb12b8SMatt Spinler fanDefs.push_back(std::move(def));
39422ab93b4SMatthew Barth }
39522ab93b4SMatthew Barth
39622ab93b4SMatthew Barth return fanDefs;
39722ab93b4SMatthew Barth }
39822ab93b4SMatthew Barth
getPowerOffPowerRuleState(const json & powerOffConfig)399f06ab07cSMatt Spinler PowerRuleState getPowerOffPowerRuleState(const json& powerOffConfig)
400f06ab07cSMatt Spinler {
401f06ab07cSMatt Spinler // The state is optional and defaults to runtime
402f06ab07cSMatt Spinler PowerRuleState ruleState{PowerRuleState::runtime};
403f06ab07cSMatt Spinler
404f06ab07cSMatt Spinler if (powerOffConfig.contains("state"))
405f06ab07cSMatt Spinler {
406f06ab07cSMatt Spinler auto state = powerOffConfig.at("state").get<std::string>();
407f06ab07cSMatt Spinler if (state == "at_pgood")
408f06ab07cSMatt Spinler {
409f06ab07cSMatt Spinler ruleState = PowerRuleState::atPgood;
410f06ab07cSMatt Spinler }
411f06ab07cSMatt Spinler else if (state != "runtime")
412f06ab07cSMatt Spinler {
413fbf4703fSPatrick Williams auto msg = std::format("Invalid power off state entry {}", state);
414f06ab07cSMatt Spinler log<level::ERR>(msg.c_str());
415f06ab07cSMatt Spinler throw std::runtime_error(msg.c_str());
416f06ab07cSMatt Spinler }
417f06ab07cSMatt Spinler }
418f06ab07cSMatt Spinler
419f06ab07cSMatt Spinler return ruleState;
420f06ab07cSMatt Spinler }
421f06ab07cSMatt Spinler
getPowerOffCause(const json & powerOffConfig)422f06ab07cSMatt Spinler std::unique_ptr<PowerOffCause> getPowerOffCause(const json& powerOffConfig)
423f06ab07cSMatt Spinler {
424f06ab07cSMatt Spinler std::unique_ptr<PowerOffCause> cause;
425f06ab07cSMatt Spinler
426f06ab07cSMatt Spinler if (!powerOffConfig.contains("count") || !powerOffConfig.contains("cause"))
427f06ab07cSMatt Spinler {
428f06ab07cSMatt Spinler const auto msg =
429f06ab07cSMatt Spinler "Missing 'count' or 'cause' entries in power off config";
430f06ab07cSMatt Spinler log<level::ERR>(msg);
431f06ab07cSMatt Spinler throw std::runtime_error(msg);
432f06ab07cSMatt Spinler }
433f06ab07cSMatt Spinler
434f06ab07cSMatt Spinler auto count = powerOffConfig.at("count").get<size_t>();
435f06ab07cSMatt Spinler auto powerOffCause = powerOffConfig.at("cause").get<std::string>();
436f06ab07cSMatt Spinler
437f06ab07cSMatt Spinler const std::map<std::string, std::function<std::unique_ptr<PowerOffCause>()>>
438f06ab07cSMatt Spinler causes{
439f06ab07cSMatt Spinler {"missing_fan_frus",
440f06ab07cSMatt Spinler [count]() { return std::make_unique<MissingFanFRUCause>(count); }},
4414c62fc77SMatt Spinler {"nonfunc_fan_rotors",
4424c62fc77SMatt Spinler [count]() {
443f06ab07cSMatt Spinler return std::make_unique<NonfuncFanRotorCause>(count);
4444c62fc77SMatt Spinler }},
4454c62fc77SMatt Spinler {"fan_frus_with_nonfunc_rotors", [count]() {
4464c62fc77SMatt Spinler return std::make_unique<FanFRUsWithNonfuncRotorsCause>(count);
447f06ab07cSMatt Spinler }}};
448f06ab07cSMatt Spinler
449f06ab07cSMatt Spinler auto it = causes.find(powerOffCause);
450f06ab07cSMatt Spinler if (it != causes.end())
451f06ab07cSMatt Spinler {
452f06ab07cSMatt Spinler cause = it->second();
453f06ab07cSMatt Spinler }
454f06ab07cSMatt Spinler else
455f06ab07cSMatt Spinler {
456f06ab07cSMatt Spinler auto msg =
457fbf4703fSPatrick Williams std::format("Invalid power off cause {} in power off config JSON",
458f06ab07cSMatt Spinler powerOffCause);
459f06ab07cSMatt Spinler log<level::ERR>(msg.c_str());
460f06ab07cSMatt Spinler throw std::runtime_error(msg.c_str());
461f06ab07cSMatt Spinler }
462f06ab07cSMatt Spinler
463f06ab07cSMatt Spinler return cause;
464f06ab07cSMatt Spinler }
465f06ab07cSMatt Spinler
466f06ab07cSMatt Spinler std::unique_ptr<PowerOffAction>
getPowerOffAction(const json & powerOffConfig,std::shared_ptr<PowerInterfaceBase> & powerInterface,PowerOffAction::PrePowerOffFunc & func)467f06ab07cSMatt Spinler getPowerOffAction(const json& powerOffConfig,
468ac1efc11SMatt Spinler std::shared_ptr<PowerInterfaceBase>& powerInterface,
469ac1efc11SMatt Spinler PowerOffAction::PrePowerOffFunc& func)
470f06ab07cSMatt Spinler {
471f06ab07cSMatt Spinler std::unique_ptr<PowerOffAction> action;
472f06ab07cSMatt Spinler if (!powerOffConfig.contains("type"))
473f06ab07cSMatt Spinler {
474f06ab07cSMatt Spinler const auto msg = "Missing 'type' entry in power off config";
475f06ab07cSMatt Spinler log<level::ERR>(msg);
476f06ab07cSMatt Spinler throw std::runtime_error(msg);
477f06ab07cSMatt Spinler }
478f06ab07cSMatt Spinler
479f06ab07cSMatt Spinler auto type = powerOffConfig.at("type").get<std::string>();
480f06ab07cSMatt Spinler
481f06ab07cSMatt Spinler if (((type == "hard") || (type == "soft")) &&
482f06ab07cSMatt Spinler !powerOffConfig.contains("delay"))
483f06ab07cSMatt Spinler {
484f06ab07cSMatt Spinler const auto msg = "Missing 'delay' entry in power off config";
485f06ab07cSMatt Spinler log<level::ERR>(msg);
486f06ab07cSMatt Spinler throw std::runtime_error(msg);
487f06ab07cSMatt Spinler }
488f06ab07cSMatt Spinler else if ((type == "epow") &&
489f06ab07cSMatt Spinler (!powerOffConfig.contains("service_mode_delay") ||
490f06ab07cSMatt Spinler !powerOffConfig.contains("meltdown_delay")))
491f06ab07cSMatt Spinler {
492f06ab07cSMatt Spinler const auto msg = "Missing 'service_mode_delay' or 'meltdown_delay' "
493f06ab07cSMatt Spinler "entry in power off config";
494f06ab07cSMatt Spinler log<level::ERR>(msg);
495f06ab07cSMatt Spinler throw std::runtime_error(msg);
496f06ab07cSMatt Spinler }
497f06ab07cSMatt Spinler
498f06ab07cSMatt Spinler if (type == "hard")
499f06ab07cSMatt Spinler {
500f06ab07cSMatt Spinler action = std::make_unique<HardPowerOff>(
501ac1efc11SMatt Spinler powerOffConfig.at("delay").get<uint32_t>(), powerInterface, func);
502f06ab07cSMatt Spinler }
503f06ab07cSMatt Spinler else if (type == "soft")
504f06ab07cSMatt Spinler {
505f06ab07cSMatt Spinler action = std::make_unique<SoftPowerOff>(
506ac1efc11SMatt Spinler powerOffConfig.at("delay").get<uint32_t>(), powerInterface, func);
507f06ab07cSMatt Spinler }
508f06ab07cSMatt Spinler else if (type == "epow")
509f06ab07cSMatt Spinler {
510f06ab07cSMatt Spinler action = std::make_unique<EpowPowerOff>(
511f06ab07cSMatt Spinler powerOffConfig.at("service_mode_delay").get<uint32_t>(),
512ac1efc11SMatt Spinler powerOffConfig.at("meltdown_delay").get<uint32_t>(), powerInterface,
513ac1efc11SMatt Spinler func);
514f06ab07cSMatt Spinler }
515f06ab07cSMatt Spinler else
516f06ab07cSMatt Spinler {
517*dfddd648SPatrick Williams auto msg =
518*dfddd648SPatrick Williams std::format("Invalid 'type' entry {} in power off config", type);
519f06ab07cSMatt Spinler log<level::ERR>(msg.c_str());
520f06ab07cSMatt Spinler throw std::runtime_error(msg.c_str());
521f06ab07cSMatt Spinler }
522f06ab07cSMatt Spinler
523f06ab07cSMatt Spinler return action;
524f06ab07cSMatt Spinler }
525f06ab07cSMatt Spinler
getPowerOffRules(const json & obj,std::shared_ptr<PowerInterfaceBase> & powerInterface,PowerOffAction::PrePowerOffFunc & func)526*dfddd648SPatrick Williams std::vector<std::unique_ptr<PowerOffRule>> getPowerOffRules(
527*dfddd648SPatrick Williams const json& obj, std::shared_ptr<PowerInterfaceBase>& powerInterface,
528ac1efc11SMatt Spinler PowerOffAction::PrePowerOffFunc& func)
529f06ab07cSMatt Spinler {
530f06ab07cSMatt Spinler std::vector<std::unique_ptr<PowerOffRule>> rules;
531f06ab07cSMatt Spinler
532f06ab07cSMatt Spinler if (!(obj.contains("fault_handling") &&
533f06ab07cSMatt Spinler obj.at("fault_handling").contains("power_off_config")))
534f06ab07cSMatt Spinler {
535f06ab07cSMatt Spinler return rules;
536f06ab07cSMatt Spinler }
537f06ab07cSMatt Spinler
538f06ab07cSMatt Spinler for (const auto& config : obj.at("fault_handling").at("power_off_config"))
539f06ab07cSMatt Spinler {
540f06ab07cSMatt Spinler auto state = getPowerOffPowerRuleState(config);
541f06ab07cSMatt Spinler auto cause = getPowerOffCause(config);
542ac1efc11SMatt Spinler auto action = getPowerOffAction(config, powerInterface, func);
543f06ab07cSMatt Spinler
544f06ab07cSMatt Spinler auto rule = std::make_unique<PowerOffRule>(
545f06ab07cSMatt Spinler std::move(state), std::move(cause), std::move(action));
546f06ab07cSMatt Spinler rules.push_back(std::move(rule));
547f06ab07cSMatt Spinler }
548f06ab07cSMatt Spinler
549f06ab07cSMatt Spinler return rules;
550f06ab07cSMatt Spinler }
551f06ab07cSMatt Spinler
getNumNonfuncRotorsBeforeError(const json & obj)552f13b42e2SMatt Spinler std::optional<size_t> getNumNonfuncRotorsBeforeError(const json& obj)
553f13b42e2SMatt Spinler {
554f13b42e2SMatt Spinler std::optional<size_t> num;
555f13b42e2SMatt Spinler
556f13b42e2SMatt Spinler if (obj.contains("fault_handling"))
557f13b42e2SMatt Spinler {
558f13b42e2SMatt Spinler // Defaults to 1 if not present inside of 'fault_handling'.
559f13b42e2SMatt Spinler num = obj.at("fault_handling")
560f13b42e2SMatt Spinler .value("num_nonfunc_rotors_before_error", 1);
561f13b42e2SMatt Spinler }
562f13b42e2SMatt Spinler
563f13b42e2SMatt Spinler return num;
564f13b42e2SMatt Spinler }
565f13b42e2SMatt Spinler
5669ea8bee7SMatthew Barth } // namespace phosphor::fan::monitor
567