1 /** 2 * Copyright © 2017 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include "fan.hpp" 17 18 #include "logging.hpp" 19 #include "sdbusplus.hpp" 20 #include "system.hpp" 21 #include "types.hpp" 22 #include "utility.hpp" 23 24 #include <fmt/format.h> 25 26 #include <phosphor-logging/log.hpp> 27 28 #include <algorithm> 29 30 namespace phosphor 31 { 32 namespace fan 33 { 34 namespace monitor 35 { 36 37 using namespace phosphor::logging; 38 using namespace sdbusplus::bus::match; 39 40 Fan::Fan(Mode mode, sdbusplus::bus::bus& bus, const sdeventplus::Event& event, 41 std::unique_ptr<trust::Manager>& trust, const FanDefinition& def, 42 System& system) : 43 _bus(bus), 44 _name(std::get<fanNameField>(def)), 45 _deviation(std::get<fanDeviationField>(def)), 46 _numSensorFailsForNonFunc(std::get<numSensorFailsForNonfuncField>(def)), 47 _trustManager(trust), 48 #ifdef MONITOR_USE_JSON 49 _monitorDelay(std::get<monitorStartDelayField>(def)), 50 _monitorTimer(event, std::bind(std::mem_fn(&Fan::startMonitor), this)), 51 #endif 52 _system(system), 53 _presenceMatch(bus, 54 rules::propertiesChanged(util::INVENTORY_PATH + _name, 55 util::INV_ITEM_IFACE), 56 std::bind(std::mem_fn(&Fan::presenceChanged), this, 57 std::placeholders::_1)), 58 _presenceIfaceAddedMatch( 59 bus, 60 rules::interfacesAdded() + 61 rules::argNpath(0, util::INVENTORY_PATH + _name), 62 std::bind(std::mem_fn(&Fan::presenceIfaceAdded), this, 63 std::placeholders::_1)), 64 _fanMissingErrorDelay(std::get<fanMissingErrDelayField>(def)) 65 { 66 // Start from a known state of functional (even if 67 // _numSensorFailsForNonFunc is 0) 68 updateInventory(true); 69 70 // Setup tach sensors for monitoring 71 auto& sensors = std::get<sensorListField>(def); 72 for (auto& s : sensors) 73 { 74 try 75 { 76 _sensors.emplace_back(std::make_shared<TachSensor>( 77 mode, bus, *this, std::get<sensorNameField>(s), 78 std::get<hasTargetField>(s), std::get<funcDelay>(def), 79 std::get<targetInterfaceField>(s), std::get<factorField>(s), 80 std::get<offsetField>(s), std::get<methodField>(def), 81 std::get<thresholdField>(s), std::get<timeoutField>(def), 82 std::get<nonfuncRotorErrDelayField>(def), event)); 83 84 _trustManager->registerSensor(_sensors.back()); 85 } 86 catch (InvalidSensorError& e) 87 { 88 // Count the number of failed tach sensors, though if 89 // _numSensorFailsForNonFunc is zero that means the fan should not 90 // be set to nonfunctional. 91 if (_numSensorFailsForNonFunc && 92 (++_numFailedSensor >= _numSensorFailsForNonFunc)) 93 { 94 // Mark associated fan as nonfunctional 95 updateInventory(false); 96 } 97 } 98 } 99 100 #ifndef MONITOR_USE_JSON 101 // Check current tach state when entering monitor mode 102 if (mode != Mode::init) 103 { 104 _monitorReady = true; 105 106 // The TachSensors will now have already read the input 107 // and target values, so check them. 108 tachChanged(); 109 } 110 #else 111 if (_system.isPowerOn()) 112 { 113 _monitorTimer.restartOnce(std::chrono::seconds(_monitorDelay)); 114 } 115 #endif 116 117 if (_fanMissingErrorDelay) 118 { 119 _fanMissingErrorTimer = std::make_unique< 120 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>( 121 event, std::bind(&System::fanMissingErrorTimerExpired, &system, 122 std::ref(*this))); 123 } 124 125 try 126 { 127 _present = util::SDBusPlus::getProperty<bool>( 128 util::INVENTORY_PATH + _name, util::INV_ITEM_IFACE, "Present"); 129 130 if (!_present) 131 { 132 getLogger().log( 133 fmt::format("On startup, fan {} is missing", _name)); 134 if (_system.isPowerOn() && _fanMissingErrorTimer) 135 { 136 _fanMissingErrorTimer->restartOnce( 137 std::chrono::seconds{*_fanMissingErrorDelay}); 138 } 139 } 140 } 141 catch (const util::DBusServiceError& e) 142 { 143 // This could happen on the first BMC boot if the presence 144 // detect app hasn't started yet and there isn't an inventory 145 // cache yet. 146 } 147 } 148 149 void Fan::presenceIfaceAdded(sdbusplus::message::message& msg) 150 { 151 sdbusplus::message::object_path path; 152 std::map<std::string, std::map<std::string, std::variant<bool>>> interfaces; 153 154 msg.read(path, interfaces); 155 156 auto properties = interfaces.find(util::INV_ITEM_IFACE); 157 if (properties == interfaces.end()) 158 { 159 return; 160 } 161 162 auto property = properties->second.find("Present"); 163 if (property == properties->second.end()) 164 { 165 return; 166 } 167 168 _present = std::get<bool>(property->second); 169 170 if (!_present) 171 { 172 getLogger().log(fmt::format( 173 "New fan {} interface added and fan is not present", _name)); 174 if (_system.isPowerOn() && _fanMissingErrorTimer) 175 { 176 _fanMissingErrorTimer->restartOnce( 177 std::chrono::seconds{*_fanMissingErrorDelay}); 178 } 179 } 180 181 _system.fanStatusChange(*this); 182 } 183 184 void Fan::startMonitor() 185 { 186 _monitorReady = true; 187 188 tachChanged(); 189 } 190 191 void Fan::tachChanged() 192 { 193 if (_monitorReady) 194 { 195 for (auto& s : _sensors) 196 { 197 tachChanged(*s); 198 } 199 } 200 } 201 202 void Fan::tachChanged(TachSensor& sensor) 203 { 204 if (!_system.isPowerOn() || !_monitorReady) 205 { 206 return; 207 } 208 209 if (_trustManager->active()) 210 { 211 if (!_trustManager->checkTrust(sensor)) 212 { 213 return; 214 } 215 } 216 217 process(sensor); 218 } 219 220 void Fan::process(TachSensor& sensor) 221 { 222 // If this sensor is out of range at this moment, start 223 // its timer, at the end of which the inventory 224 // for the fan may get updated to not functional. 225 226 // If this sensor is OK, put everything back into a good state. 227 228 if (outOfRange(sensor)) 229 { 230 if (sensor.functional()) 231 { 232 switch (sensor.getMethod()) 233 { 234 case MethodMode::timebased: 235 // Start nonfunctional timer if not already running 236 sensor.startTimer(TimerMode::nonfunc); 237 break; 238 case MethodMode::count: 239 sensor.setCounter(true); 240 if (sensor.getCounter() >= sensor.getThreshold()) 241 { 242 updateState(sensor); 243 } 244 break; 245 } 246 } 247 } 248 else 249 { 250 switch (sensor.getMethod()) 251 { 252 case MethodMode::timebased: 253 if (sensor.functional()) 254 { 255 if (sensor.timerRunning()) 256 { 257 sensor.stopTimer(); 258 } 259 } 260 else 261 { 262 // Start functional timer if not already running 263 sensor.startTimer(TimerMode::func); 264 } 265 break; 266 case MethodMode::count: 267 sensor.setCounter(false); 268 if (!sensor.functional() && sensor.getCounter() == 0) 269 { 270 updateState(sensor); 271 } 272 break; 273 } 274 } 275 } 276 277 uint64_t Fan::findTargetSpeed() 278 { 279 uint64_t target = 0; 280 // The sensor doesn't support a target, 281 // so get it from another sensor. 282 auto s = std::find_if(_sensors.begin(), _sensors.end(), 283 [](const auto& s) { return s->hasTarget(); }); 284 285 if (s != _sensors.end()) 286 { 287 target = (*s)->getTarget(); 288 } 289 290 return target; 291 } 292 293 size_t Fan::countNonFunctionalSensors() 294 { 295 return std::count_if(_sensors.begin(), _sensors.end(), 296 [](const auto& s) { return !s->functional(); }); 297 } 298 299 bool Fan::outOfRange(const TachSensor& sensor) 300 { 301 auto actual = static_cast<uint64_t>(sensor.getInput()); 302 auto range = sensor.getRange(_deviation); 303 304 if ((actual < range.first) || (actual > range.second)) 305 { 306 return true; 307 } 308 309 return false; 310 } 311 312 void Fan::updateState(TachSensor& sensor) 313 { 314 auto range = sensor.getRange(_deviation); 315 316 if (!_system.isPowerOn()) 317 { 318 return; 319 } 320 321 sensor.setFunctional(!sensor.functional()); 322 getLogger().log( 323 fmt::format("Setting tach sensor {} functional state to {}. " 324 "[target = {}, input = {}, allowed range = ({} - {})]", 325 sensor.name(), sensor.functional(), sensor.getTarget(), 326 sensor.getInput(), range.first, range.second)); 327 328 // A zero value for _numSensorFailsForNonFunc means we aren't dealing 329 // with fan FRU functional status, only sensor functional status. 330 if (_numSensorFailsForNonFunc) 331 { 332 auto numNonFuncSensors = countNonFunctionalSensors(); 333 // If the fan was nonfunctional and enough sensors are now OK, 334 // the fan can be set to functional 335 if (!_functional && !(numNonFuncSensors >= _numSensorFailsForNonFunc)) 336 { 337 getLogger().log(fmt::format("Setting fan {} to functional, number " 338 "of nonfunctional sensors = {}", 339 _name, numNonFuncSensors)); 340 updateInventory(true); 341 } 342 343 // If the fan is currently functional, but too many 344 // contained sensors are now nonfunctional, update 345 // the fan to nonfunctional. 346 if (_functional && (numNonFuncSensors >= _numSensorFailsForNonFunc)) 347 { 348 getLogger().log(fmt::format("Setting fan {} to nonfunctional, " 349 "number of nonfunctional sensors = {}", 350 _name, numNonFuncSensors)); 351 updateInventory(false); 352 } 353 } 354 355 _system.fanStatusChange(*this); 356 } 357 358 void Fan::updateInventory(bool functional) 359 { 360 auto objectMap = 361 util::getObjMap<bool>(_name, util::OPERATIONAL_STATUS_INTF, 362 util::FUNCTIONAL_PROPERTY, functional); 363 auto response = util::SDBusPlus::lookupAndCallMethod( 364 _bus, util::INVENTORY_PATH, util::INVENTORY_INTF, "Notify", objectMap); 365 if (response.is_method_error()) 366 { 367 log<level::ERR>("Error in Notify call to update inventory"); 368 return; 369 } 370 371 // This will always track the current state of the inventory. 372 _functional = functional; 373 } 374 375 void Fan::presenceChanged(sdbusplus::message::message& msg) 376 { 377 std::string interface; 378 std::map<std::string, std::variant<bool>> properties; 379 380 msg.read(interface, properties); 381 382 auto presentProp = properties.find("Present"); 383 if (presentProp != properties.end()) 384 { 385 _present = std::get<bool>(presentProp->second); 386 387 getLogger().log( 388 fmt::format("Fan {} presence state change to {}", _name, _present)); 389 390 _system.fanStatusChange(*this); 391 392 if (_fanMissingErrorDelay) 393 { 394 if (!_present && _system.isPowerOn()) 395 { 396 _fanMissingErrorTimer->restartOnce( 397 std::chrono::seconds{*_fanMissingErrorDelay}); 398 } 399 else if (_present && _fanMissingErrorTimer->isEnabled()) 400 { 401 _fanMissingErrorTimer->setEnabled(false); 402 } 403 } 404 } 405 } 406 407 void Fan::sensorErrorTimerExpired(const TachSensor& sensor) 408 { 409 if (_present && _system.isPowerOn()) 410 { 411 _system.sensorErrorTimerExpired(*this, sensor); 412 } 413 } 414 415 void Fan::powerStateChanged(bool powerStateOn) 416 { 417 #ifdef MONITOR_USE_JSON 418 if (powerStateOn) 419 { 420 // set all fans back to functional to start with 421 std::for_each(_sensors.begin(), _sensors.end(), 422 [](auto& sensor) { sensor->setFunctional(true); }); 423 424 _monitorTimer.restartOnce(std::chrono::seconds(_monitorDelay)); 425 426 if (!_present) 427 { 428 getLogger().log( 429 fmt::format("At power on, fan {} is missing", _name)); 430 431 if (_fanMissingErrorTimer) 432 { 433 _fanMissingErrorTimer->restartOnce( 434 std::chrono::seconds{*_fanMissingErrorDelay}); 435 } 436 } 437 } 438 else 439 { 440 _monitorReady = false; 441 442 if (_monitorTimer.isEnabled()) 443 { 444 _monitorTimer.setEnabled(false); 445 } 446 447 if (_fanMissingErrorTimer && _fanMissingErrorTimer->isEnabled()) 448 { 449 _fanMissingErrorTimer->setEnabled(false); 450 } 451 452 std::for_each(_sensors.begin(), _sensors.end(), [](auto& sensor) { 453 if (sensor->timerRunning()) 454 { 455 sensor->stopTimer(); 456 } 457 }); 458 } 459 #endif 460 } 461 462 } // namespace monitor 463 } // namespace fan 464 } // namespace phosphor 465