blob: f0c59bb9e1b785818565a0f62242c6154f22f483 [file] [log] [blame]
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +05301#include "config.h"
2
Gunnar Mills94df8c92018-09-14 14:50:03 -05003#include "occ_manager.hpp"
4
5#include "i2c_occ.hpp"
Chicago Duanbb895cb2021-06-18 19:37:16 +08006#include "occ_dbus.hpp"
Gunnar Mills94df8c92018-09-14 14:50:03 -05007#include "utils.hpp"
8
George Liub5ca1012021-09-10 12:53:11 +08009#include <phosphor-logging/elog-errors.hpp>
10#include <phosphor-logging/log.hpp>
11#include <xyz/openbmc_project/Common/error.hpp>
12
Matt Spinlerd267cec2021-09-01 14:49:19 -050013#include <chrono>
Chicago Duanbb895cb2021-06-18 19:37:16 +080014#include <cmath>
George Liubcef3b42021-09-10 12:39:02 +080015#include <filesystem>
Chris Cain36f9cde2021-11-22 11:18:21 -060016#include <fstream>
Chicago Duanbb895cb2021-06-18 19:37:16 +080017#include <regex>
Gunnar Mills94df8c92018-09-14 14:50:03 -050018
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053019namespace open_power
20{
21namespace occ
22{
23
Matt Spinler8b8abee2021-08-25 15:18:21 -050024constexpr uint32_t fruTypeNotAvailable = 0xFF;
Matt Spinlera26f1522021-08-25 15:50:20 -050025constexpr auto fruTypeSuffix = "fru_type";
26constexpr auto faultSuffix = "fault";
27constexpr auto inputSuffix = "input";
Matt Spinlerace67d82021-10-18 13:41:57 -050028constexpr auto maxSuffix = "max";
Matt Spinler8b8abee2021-08-25 15:18:21 -050029
Chris Cain1718fd82022-02-16 16:39:50 -060030const auto HOST_ON_FILE = "/run/openbmc/host@0-on";
31
Chris Caina8857c52021-01-27 11:53:05 -060032using namespace phosphor::logging;
Chris Caina7b74dc2021-11-10 17:03:43 -060033using namespace std::literals::chrono_literals;
Chris Caina8857c52021-01-27 11:53:05 -060034
Matt Spinlera26f1522021-08-25 15:50:20 -050035template <typename T>
36T readFile(const std::string& path)
37{
38 std::ifstream ifs;
39 ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit |
40 std::ifstream::eofbit);
41 T data;
42
43 try
44 {
45 ifs.open(path);
46 ifs >> data;
47 ifs.close();
48 }
49 catch (const std::exception& e)
50 {
51 auto err = errno;
52 throw std::system_error(err, std::generic_category());
53 }
54
55 return data;
56}
57
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053058void Manager::findAndCreateObjects()
59{
Matt Spinlerd267cec2021-09-01 14:49:19 -050060#ifndef POWER10
Deepak Kodihalli370f06b2017-10-25 04:26:07 -050061 for (auto id = 0; id < MAX_CPUS; ++id)
62 {
Deepak Kodihalli30417a12017-12-04 00:54:01 -060063 // Create one occ per cpu
64 auto occ = std::string(OCC_NAME) + std::to_string(id);
65 createObjects(occ);
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053066 }
Matt Spinlerd267cec2021-09-01 14:49:19 -050067#else
Chris Cain1718fd82022-02-16 16:39:50 -060068 if (!fs::exists(HOST_ON_FILE))
Matt Spinlerd267cec2021-09-01 14:49:19 -050069 {
Chris Cainbae4d072022-02-28 09:46:50 -060070 static bool statusObjCreated = false;
71 if (!statusObjCreated)
Chris Cain1718fd82022-02-16 16:39:50 -060072 {
Chris Cainbae4d072022-02-28 09:46:50 -060073 // Create the OCCs based on on the /dev/occX devices
74 auto occs = findOCCsInDev();
Chris Cain1718fd82022-02-16 16:39:50 -060075
Chris Cainbae4d072022-02-28 09:46:50 -060076 if (occs.empty() || (prevOCCSearch.size() != occs.size()))
Chris Cain1718fd82022-02-16 16:39:50 -060077 {
Chris Cainbae4d072022-02-28 09:46:50 -060078 // Something changed or no OCCs yet, try again in 10s.
79 // Note on the first pass prevOCCSearch will be empty,
80 // so there will be at least one delay to give things
81 // a chance to settle.
82 prevOCCSearch = occs;
83
84 log<level::INFO>(
85 fmt::format(
86 "Manager::findAndCreateObjects(): Waiting for OCCs (currently {})",
87 occs.size())
88 .c_str());
89
90 discoverTimer->restartOnce(10s);
91 }
92 else
93 {
94 // All OCCs appear to be available, create status objects
95
96 // createObjects requires OCC0 first.
97 std::sort(occs.begin(), occs.end());
98
99 log<level::INFO>(
100 fmt::format(
101 "Manager::findAndCreateObjects(): Creating {} OCC Status Objects",
102 occs.size())
103 .c_str());
104 for (auto id : occs)
105 {
106 createObjects(std::string(OCC_NAME) + std::to_string(id));
107 }
108 statusObjCreated = true;
109 }
110 }
111
112 if (statusObjCreated)
113 {
114 static bool tracedHostWait = false;
115 if (utils::isHostRunning())
116 {
117 if (tracedHostWait)
118 {
119 log<level::INFO>(
120 "Manager::findAndCreateObjects(): Host is running");
121 tracedHostWait = false;
122 }
123 waitingForAllOccActiveSensors = true;
124 checkAllActiveSensors();
125 }
126 else
127 {
128 if (!tracedHostWait)
129 {
130 log<level::INFO>(
131 "Manager::findAndCreateObjects(): Waiting for host to start");
132 tracedHostWait = true;
133 }
134 discoverTimer->restartOnce(30s);
Chris Cain1718fd82022-02-16 16:39:50 -0600135 }
136 }
Matt Spinlerd267cec2021-09-01 14:49:19 -0500137 }
138 else
139 {
Chris Cain1718fd82022-02-16 16:39:50 -0600140 log<level::INFO>(
141 fmt::format(
142 "Manager::findAndCreateObjects(): Waiting for {} to complete...",
143 HOST_ON_FILE)
144 .c_str());
145 discoverTimer->restartOnce(10s);
Matt Spinlerd267cec2021-09-01 14:49:19 -0500146 }
147#endif
148}
149
Chris Cainbae4d072022-02-28 09:46:50 -0600150#ifdef POWER10
151// Check if all occActive sensors are available
152void Manager::checkAllActiveSensors()
153{
154 static bool allActiveSensorAvailable = false;
155 static bool tracedSensorWait = false;
156
157 // Start with the assumption that all are available
158 allActiveSensorAvailable = true;
159 for (auto& obj : statusObjects)
160 {
161 // If active sensor is already true, then no need to query sensor
162 if (!obj->occActive())
163 {
164 allActiveSensorAvailable = false;
165 if (!tracedSensorWait)
166 {
167 log<level::INFO>(
168 fmt::format(
169 "Manager::checkAllActiveSensors(): Waiting on OCC{} Active sensor",
170 obj->getOccInstanceID())
171 .c_str());
172 tracedSensorWait = true;
173 }
174 pldmHandle->checkActiveSensor(obj->getOccInstanceID());
175 break;
176 }
177 }
178
179 if (allActiveSensorAvailable)
180 {
181 // All sensors were found, disable the discovery timer
182 discoverTimer.reset();
183 waitingForAllOccActiveSensors = false;
184
185 log<level::INFO>(
186 "Manager::checkAllActiveSensors(): OCC Active sensors are available");
187 tracedSensorWait = false;
188 }
189 else
190 {
191 // Not all sensors were available, so keep waiting
192 if (!tracedSensorWait)
193 {
194 log<level::INFO>(
195 "Manager::checkAllActiveSensors(): Waiting for OCC Active sensors to become available");
196 tracedSensorWait = true;
197 }
198 discoverTimer->restartOnce(30s);
199 }
200}
201#endif
202
Matt Spinlerd267cec2021-09-01 14:49:19 -0500203std::vector<int> Manager::findOCCsInDev()
204{
205 std::vector<int> occs;
206 std::regex expr{R"(occ(\d+)$)"};
207
208 for (auto& file : fs::directory_iterator("/dev"))
209 {
210 std::smatch match;
211 std::string path{file.path().string()};
212 if (std::regex_search(path, match, expr))
213 {
214 auto num = std::stoi(match[1].str());
215
216 // /dev numbering starts at 1, ours starts at 0.
217 occs.push_back(num - 1);
218 }
219 }
220
221 return occs;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530222}
223
224int Manager::cpuCreated(sdbusplus::message::message& msg)
225{
George Liubcef3b42021-09-10 12:39:02 +0800226 namespace fs = std::filesystem;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530227
228 sdbusplus::message::object_path o;
229 msg.read(o);
230 fs::path cpuPath(std::string(std::move(o)));
231
232 auto name = cpuPath.filename().string();
233 auto index = name.find(CPU_NAME);
234 name.replace(index, std::strlen(CPU_NAME), OCC_NAME);
235
236 createObjects(name);
237
238 return 0;
239}
240
241void Manager::createObjects(const std::string& occ)
242{
243 auto path = fs::path(OCC_CONTROL_ROOT) / occ;
244
Chris Cain6fa848a2022-01-24 14:54:38 -0600245#ifdef POWER10
246 if (!pmode)
247 {
Chris Cain1be43372021-12-09 19:29:37 -0600248 // Create the power mode object
Chris Cain5d66a0a2022-02-09 08:52:10 -0600249 pmode = std::make_unique<powermode::PowerMode>(
Chris Cain1be43372021-12-09 19:29:37 -0600250 *this, powermode::PMODE_PATH, powermode::PIPS_PATH);
Chris Cain6fa848a2022-01-24 14:54:38 -0600251 }
252#endif
253
Gunnar Mills94df8c92018-09-14 14:50:03 -0500254 statusObjects.emplace_back(std::make_unique<Status>(
George Liuf3b75142021-06-10 11:22:50 +0800255 event, path.c_str(), *this,
Chris Cain36f9cde2021-11-22 11:18:21 -0600256#ifdef POWER10
257 pmode,
258#endif
Gunnar Mills94df8c92018-09-14 14:50:03 -0500259 std::bind(std::mem_fn(&Manager::statusCallBack), this,
Sheldon Bailey373af752022-02-21 15:14:00 -0600260 std::placeholders::_1, std::placeholders::_2)
Tom Joseph00325232020-07-29 17:51:48 +0530261#ifdef PLDM
262 ,
263 std::bind(std::mem_fn(&pldm::Interface::resetOCC), pldmHandle.get(),
264 std::placeholders::_1)
265#endif
266 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530267
Chris Cain40501a22022-03-14 17:33:27 -0500268 // Create the power cap monitor object
269 if (!pcap)
270 {
271 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
272 *statusObjects.back());
273 }
274
Chris Cain36f9cde2021-11-22 11:18:21 -0600275 if (statusObjects.back()->isMasterOcc())
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530276 {
Chris Cain36f9cde2021-11-22 11:18:21 -0600277 log<level::INFO>(
278 fmt::format("Manager::createObjects(): OCC{} is the master",
279 statusObjects.back()->getOccInstanceID())
280 .c_str());
281 _pollTimer->setEnabled(false);
282
Chris Cain78e86012021-03-04 16:15:31 -0600283#ifdef POWER10
Chris Cain6fa848a2022-01-24 14:54:38 -0600284 // Set the master OCC on the PowerMode object
285 pmode->setMasterOcc(path);
Chris Cain78e86012021-03-04 16:15:31 -0600286#endif
Chris Cain36f9cde2021-11-22 11:18:21 -0600287 }
288
289 passThroughObjects.emplace_back(std::make_unique<PassThrough>(path.c_str()
290#ifdef POWER10
291 ,
292 pmode
293#endif
294 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530295}
296
Sheldon Bailey373af752022-02-21 15:14:00 -0600297void Manager::statusCallBack(instanceID instance, bool status)
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530298{
Gunnar Mills94df8c92018-09-14 14:50:03 -0500299 using InternalFailure =
300 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530301
302 // At this time, it won't happen but keeping it
303 // here just in case something changes in the future
304 if ((activeCount == 0) && (!status))
305 {
Sheldon Bailey373af752022-02-21 15:14:00 -0600306 log<level::ERR>(
307 fmt::format("Invalid update on OCCActive with OCC{}", instance)
308 .c_str());
309
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530310 elog<InternalFailure>();
311 }
312
Chris Caina7b74dc2021-11-10 17:03:43 -0600313 if (status == true)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600314 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600315 // OCC went active
316 ++activeCount;
317
318#ifdef POWER10
319 if (activeCount == 1)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600320 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600321 // First OCC went active (allow some time for all OCCs to go active)
322 waitForAllOccsTimer->restartOnce(30s);
Matt Spinler53f68142021-08-25 15:47:31 -0500323 }
324#endif
Chris Caina7b74dc2021-11-10 17:03:43 -0600325
326 if (activeCount == statusObjects.size())
327 {
328#ifdef POWER10
329 // All OCCs are now running
330 if (waitForAllOccsTimer->isEnabled())
331 {
332 // stop occ wait timer
333 waitForAllOccsTimer->setEnabled(false);
334 }
335#endif
336
337 // Verify master OCC and start presence monitor
338 validateOccMaster();
339 }
340
341 // Start poll timer if not already started
342 if (!_pollTimer->isEnabled())
343 {
344 log<level::INFO>(
Chris Cain36f9cde2021-11-22 11:18:21 -0600345 fmt::format("Manager: OCCs will be polled every {} seconds",
346 pollInterval)
Chris Caina7b74dc2021-11-10 17:03:43 -0600347 .c_str());
348
349 // Send poll and start OCC poll timer
350 pollerTimerExpired();
351 }
352 }
353 else
354 {
355 // OCC went away
356 --activeCount;
357
358 if (activeCount == 0)
359 {
360 // No OCCs are running
361
362 // Stop OCC poll timer
363 if (_pollTimer->isEnabled())
364 {
365 log<level::INFO>(
366 "Manager::statusCallBack(): OCCs are not running, stopping poll timer");
367 _pollTimer->setEnabled(false);
368 }
369
370#ifdef POWER10
371 // stop wait timer
372 if (waitForAllOccsTimer->isEnabled())
373 {
374 waitForAllOccsTimer->setEnabled(false);
375 }
376#endif
Chris Caina7b74dc2021-11-10 17:03:43 -0600377 }
Sheldon Bailey373af752022-02-21 15:14:00 -0600378#ifdef READ_OCC_SENSORS
379 // Clear OCC sensors
380 setSensorValueToNonFunctional(instance);
381#endif
Chris Caina8857c52021-01-27 11:53:05 -0600382 }
Chris Cainbae4d072022-02-28 09:46:50 -0600383
384#ifdef POWER10
385 if (waitingForAllOccActiveSensors)
386 {
387 checkAllActiveSensors();
388 }
389#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530390}
391
392#ifdef I2C_OCC
393void Manager::initStatusObjects()
394{
395 // Make sure we have a valid path string
396 static_assert(sizeof(DEV_PATH) != 0);
397
398 auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH);
399 for (auto& name : deviceNames)
400 {
401 i2c_occ::i2cToDbus(name);
Lei YUb5259a12017-09-01 16:22:40 +0800402 name = std::string(OCC_NAME) + '_' + name;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530403 auto path = fs::path(OCC_CONTROL_ROOT) / name;
404 statusObjects.emplace_back(
George Liuf3b75142021-06-10 11:22:50 +0800405 std::make_unique<Status>(event, path.c_str(), *this));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530406 }
Chris Cain40501a22022-03-14 17:33:27 -0500407 // The first device is master occ
408 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
409 *statusObjects.front());
Chris Cain78e86012021-03-04 16:15:31 -0600410#ifdef POWER10
Chris Cain5d66a0a2022-02-09 08:52:10 -0600411 pmode = std::make_unique<powermode::PowerMode>(*this, powermode::PMODE_PATH,
412 powermode::PIPS_PATH);
Chris Cain6fa848a2022-01-24 14:54:38 -0600413 // Set the master OCC on the PowerMode object
414 pmode->setMasterOcc(path);
Chris Cain78e86012021-03-04 16:15:31 -0600415#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530416}
417#endif
418
Tom Joseph815f9f52020-07-27 12:12:13 +0530419#ifdef PLDM
Eddie Jamescbad2192021-10-07 09:39:39 -0500420void Manager::sbeTimeout(unsigned int instance)
421{
Eddie James2a751d72022-03-04 09:16:12 -0600422 auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
423 [instance](const auto& obj) {
424 return instance == obj->getOccInstanceID();
425 });
Eddie Jamescbad2192021-10-07 09:39:39 -0500426
Eddie Jamescb018da2022-03-05 11:49:37 -0600427 if (obj != statusObjects.end() && (*obj)->occActive())
Eddie James2a751d72022-03-04 09:16:12 -0600428 {
Chris Cainbae4d072022-02-28 09:46:50 -0600429 log<level::INFO>(
430 fmt::format("SBE timeout, requesting HRESET (OCC{})", instance)
431 .c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500432
Eddie James2a751d72022-03-04 09:16:12 -0600433 setSBEState(instance, SBE_STATE_NOT_USABLE);
434
435 pldmHandle->sendHRESET(instance);
436 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500437}
438
Tom Joseph815f9f52020-07-27 12:12:13 +0530439bool Manager::updateOCCActive(instanceID instance, bool status)
440{
Chris Cain7e374fb2022-04-07 09:47:23 -0500441 auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
442 [instance](const auto& obj) {
443 return instance == obj->getOccInstanceID();
444 });
445
446 if (obj != statusObjects.end())
447 {
448 return (*obj)->occActive(status);
449 }
450 else
451 {
452 log<level::WARNING>(
453 fmt::format(
454 "Manager::updateOCCActive: No status object to update for OCC{} (active={})",
455 instance, status)
456 .c_str());
457 return false;
458 }
Tom Joseph815f9f52020-07-27 12:12:13 +0530459}
Eddie Jamescbad2192021-10-07 09:39:39 -0500460
461void Manager::sbeHRESETResult(instanceID instance, bool success)
462{
463 if (success)
464 {
Chris Cainbae4d072022-02-28 09:46:50 -0600465 log<level::INFO>(
466 fmt::format("HRESET succeeded (OCC{})", instance).c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500467
468 setSBEState(instance, SBE_STATE_BOOTED);
469
470 return;
471 }
472
473 setSBEState(instance, SBE_STATE_FAILED);
474
475 if (sbeCanDump(instance))
476 {
Chris Cainbae4d072022-02-28 09:46:50 -0600477 log<level::INFO>(
478 fmt::format("HRESET failed (OCC{}), triggering SBE dump", instance)
479 .c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500480
481 auto& bus = utils::getBus();
482 uint32_t src6 = instance << 16;
483 uint32_t logId =
484 FFDC::createPEL("org.open_power.Processor.Error.SbeChipOpTimeout",
485 src6, "SBE command timeout");
486
487 try
488 {
George Liuf3a4a692021-12-28 13:59:51 +0800489 constexpr auto path = "/org/openpower/dump";
490 constexpr auto interface = "xyz.openbmc_project.Dump.Create";
491 constexpr auto function = "CreateDump";
492
Eddie Jamescbad2192021-10-07 09:39:39 -0500493 std::string service = utils::getService(path, interface);
494 auto method =
495 bus.new_method_call(service.c_str(), path, interface, function);
496
497 std::map<std::string, std::variant<std::string, uint64_t>>
498 createParams{
499 {"com.ibm.Dump.Create.CreateParameters.ErrorLogId",
500 uint64_t(logId)},
501 {"com.ibm.Dump.Create.CreateParameters.DumpType",
502 "com.ibm.Dump.Create.DumpType.SBE"},
503 {"com.ibm.Dump.Create.CreateParameters.FailingUnitId",
504 uint64_t(instance)},
505 };
506
507 method.append(createParams);
508
509 auto response = bus.call(method);
510 }
511 catch (const sdbusplus::exception::exception& e)
512 {
513 constexpr auto ERROR_DUMP_DISABLED =
514 "xyz.openbmc_project.Dump.Create.Error.Disabled";
515 if (e.name() == ERROR_DUMP_DISABLED)
516 {
517 log<level::INFO>("Dump is disabled, skipping");
518 }
519 else
520 {
521 log<level::ERR>("Dump failed");
522 }
523 }
524 }
525}
526
527bool Manager::sbeCanDump(unsigned int instance)
528{
529 struct pdbg_target* proc = getPdbgTarget(instance);
530
531 if (!proc)
532 {
533 // allow the dump in the error case
534 return true;
535 }
536
537 try
538 {
539 if (!openpower::phal::sbe::isDumpAllowed(proc))
540 {
541 return false;
542 }
543
544 if (openpower::phal::pdbg::isSbeVitalAttnActive(proc))
545 {
546 return false;
547 }
548 }
549 catch (openpower::phal::exception::SbeError& e)
550 {
551 log<level::INFO>("Failed to query SBE state");
552 }
553
554 // allow the dump in the error case
555 return true;
556}
557
558void Manager::setSBEState(unsigned int instance, enum sbe_state state)
559{
560 struct pdbg_target* proc = getPdbgTarget(instance);
561
562 if (!proc)
563 {
564 return;
565 }
566
567 try
568 {
569 openpower::phal::sbe::setState(proc, state);
570 }
571 catch (const openpower::phal::exception::SbeError& e)
572 {
573 log<level::ERR>("Failed to set SBE state");
574 }
575}
576
577struct pdbg_target* Manager::getPdbgTarget(unsigned int instance)
578{
579 if (!pdbgInitialized)
580 {
581 try
582 {
583 openpower::phal::pdbg::init();
584 pdbgInitialized = true;
585 }
586 catch (const openpower::phal::exception::PdbgError& e)
587 {
588 log<level::ERR>("pdbg initialization failed");
589 return nullptr;
590 }
591 }
592
593 struct pdbg_target* proc = nullptr;
594 pdbg_for_each_class_target("proc", proc)
595 {
596 if (pdbg_target_index(proc) == instance)
597 {
598 return proc;
599 }
600 }
601
602 log<level::ERR>("Failed to get pdbg target");
603 return nullptr;
604}
Tom Joseph815f9f52020-07-27 12:12:13 +0530605#endif
606
Chris Caina8857c52021-01-27 11:53:05 -0600607void Manager::pollerTimerExpired()
608{
Chris Caina8857c52021-01-27 11:53:05 -0600609 if (!_pollTimer)
610 {
611 log<level::ERR>(
612 "Manager::pollerTimerExpired() ERROR: Timer not defined");
613 return;
614 }
615
616 for (auto& obj : statusObjects)
617 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600618 if (!obj->occActive())
619 {
620 // OCC is not running yet
621#ifdef READ_OCC_SENSORS
Chris Cain5d66a0a2022-02-09 08:52:10 -0600622 auto id = obj->getOccInstanceID();
Sheldon Bailey373af752022-02-21 15:14:00 -0600623 setSensorValueToNonFunctional(id);
Chris Caina7b74dc2021-11-10 17:03:43 -0600624#endif
625 continue;
626 }
627
Chris Caina8857c52021-01-27 11:53:05 -0600628 // Read sysfs to force kernel to poll OCC
629 obj->readOccState();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800630
631#ifdef READ_OCC_SENSORS
632 // Read occ sensor values
Chris Cain5d66a0a2022-02-09 08:52:10 -0600633 getSensorValues(obj);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800634#endif
Chris Caina8857c52021-01-27 11:53:05 -0600635 }
636
Chris Caina7b74dc2021-11-10 17:03:43 -0600637 if (activeCount > 0)
638 {
639 // Restart OCC poll timer
640 _pollTimer->restartOnce(std::chrono::seconds(pollInterval));
641 }
642 else
643 {
644 // No OCCs running, so poll timer will not be restarted
645 log<level::INFO>(
646 fmt::format(
647 "Manager::pollerTimerExpired: poll timer will not be restarted")
648 .c_str());
649 }
Chris Caina8857c52021-01-27 11:53:05 -0600650}
651
Chicago Duanbb895cb2021-06-18 19:37:16 +0800652#ifdef READ_OCC_SENSORS
653void Manager::readTempSensors(const fs::path& path, uint32_t id)
654{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800655 std::regex expr{"temp\\d+_label$"}; // Example: temp5_label
656 for (auto& file : fs::directory_iterator(path))
657 {
658 if (!std::regex_search(file.path().string(), expr))
659 {
660 continue;
661 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800662
Matt Spinlera26f1522021-08-25 15:50:20 -0500663 uint32_t labelValue{0};
664
665 try
666 {
667 labelValue = readFile<uint32_t>(file.path());
668 }
669 catch (const std::system_error& e)
670 {
671 log<level::DEBUG>(
672 fmt::format("readTempSensors: Failed reading {}, errno = {}",
673 file.path().string(), e.code().value())
674 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800675 continue;
676 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800677
678 const std::string& tempLabel = "label";
679 const std::string filePathString = file.path().string().substr(
680 0, file.path().string().length() - tempLabel.length());
Matt Spinlera26f1522021-08-25 15:50:20 -0500681
682 uint32_t fruTypeValue{0};
683 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800684 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500685 fruTypeValue = readFile<uint32_t>(filePathString + fruTypeSuffix);
686 }
687 catch (const std::system_error& e)
688 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800689 log<level::DEBUG>(
Matt Spinlera26f1522021-08-25 15:50:20 -0500690 fmt::format("readTempSensors: Failed reading {}, errno = {}",
691 filePathString + fruTypeSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800692 .c_str());
693 continue;
694 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800695
696 std::string sensorPath =
697 OCC_SENSORS_ROOT + std::string("/temperature/");
698
Matt Spinlerace67d82021-10-18 13:41:57 -0500699 std::string dvfsTempPath;
700
Chicago Duanbb895cb2021-06-18 19:37:16 +0800701 if (fruTypeValue == VRMVdd)
702 {
703 sensorPath.append("vrm_vdd" + std::to_string(id) + "_temp");
704 }
Matt Spinlerace67d82021-10-18 13:41:57 -0500705 else if (fruTypeValue == processorIoRing)
706 {
707 sensorPath.append("proc" + std::to_string(id) + "_ioring_temp");
708 dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/proc" +
709 std::to_string(id) + "_ioring_dvfs_temp";
710 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800711 else
712 {
Matt Spinler14d14022021-08-25 15:38:29 -0500713 uint16_t type = (labelValue & 0xFF000000) >> 24;
714 uint16_t instanceID = labelValue & 0x0000FFFF;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800715
716 if (type == OCC_DIMM_TEMP_SENSOR_TYPE)
717 {
Matt Spinler8b8abee2021-08-25 15:18:21 -0500718 if (fruTypeValue == fruTypeNotAvailable)
719 {
720 // Not all DIMM related temps are available to read
721 // (no _input file in this case)
722 continue;
723 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800724 auto iter = dimmTempSensorName.find(fruTypeValue);
725 if (iter == dimmTempSensorName.end())
726 {
George Liub5ca1012021-09-10 12:53:11 +0800727 log<level::ERR>(
728 fmt::format(
729 "readTempSensors: Fru type error! fruTypeValue = {}) ",
730 fruTypeValue)
731 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800732 continue;
733 }
734
735 sensorPath.append("dimm" + std::to_string(instanceID) +
736 iter->second);
737 }
738 else if (type == OCC_CPU_TEMP_SENSOR_TYPE)
739 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500740 if (fruTypeValue == processorCore)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800741 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500742 // The OCC reports small core temps, of which there are
743 // two per big core. All current P10 systems are in big
744 // core mode, so use a big core name.
745 uint16_t coreNum = instanceID / 2;
746 uint16_t tempNum = instanceID % 2;
747 sensorPath.append("proc" + std::to_string(id) + "_core" +
748 std::to_string(coreNum) + "_" +
749 std::to_string(tempNum) + "_temp");
750
751 dvfsTempPath = std::string{OCC_SENSORS_ROOT} +
752 "/temperature/proc" + std::to_string(id) +
753 "_core_dvfs_temp";
754 }
755 else
756 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800757 continue;
758 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800759 }
760 else
761 {
762 continue;
763 }
764 }
765
Matt Spinlerace67d82021-10-18 13:41:57 -0500766 // The dvfs temp file only needs to be read once per chip per type.
767 if (!dvfsTempPath.empty() &&
768 !dbus::OccDBusSensors::getOccDBus().hasDvfsTemp(dvfsTempPath))
769 {
770 try
771 {
772 auto dvfsValue = readFile<double>(filePathString + maxSuffix);
773
774 dbus::OccDBusSensors::getOccDBus().setDvfsTemp(
775 dvfsTempPath, dvfsValue * std::pow(10, -3));
776 }
777 catch (const std::system_error& e)
778 {
779 log<level::DEBUG>(
780 fmt::format(
781 "readTempSensors: Failed reading {}, errno = {}",
782 filePathString + maxSuffix, e.code().value())
783 .c_str());
784 }
785 }
786
Matt Spinlera26f1522021-08-25 15:50:20 -0500787 uint32_t faultValue{0};
788 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800789 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500790 faultValue = readFile<uint32_t>(filePathString + faultSuffix);
791 }
792 catch (const std::system_error& e)
793 {
794 log<level::DEBUG>(
795 fmt::format("readTempSensors: Failed reading {}, errno = {}",
796 filePathString + faultSuffix, e.code().value())
797 .c_str());
798 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800799 }
800
Matt Spinlera26f1522021-08-25 15:50:20 -0500801 if (faultValue != 0)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800802 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600803 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500804 sensorPath, std::numeric_limits<double>::quiet_NaN());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800805
Chris Cain5d66a0a2022-02-09 08:52:10 -0600806 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
807 false);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800808
Matt Spinlera26f1522021-08-25 15:50:20 -0500809 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800810 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500811
812 double tempValue{0};
813
814 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800815 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500816 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800817 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500818 catch (const std::system_error& e)
819 {
820 log<level::DEBUG>(
821 fmt::format("readTempSensors: Failed reading {}, errno = {}",
822 filePathString + inputSuffix, e.code().value())
823 .c_str());
824 continue;
825 }
826
Chris Cain5d66a0a2022-02-09 08:52:10 -0600827 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500828 sensorPath, tempValue * std::pow(10, -3));
829
Chris Cain5d66a0a2022-02-09 08:52:10 -0600830 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
831 true);
Matt Spinlera26f1522021-08-25 15:50:20 -0500832
Chris Cain6fa848a2022-01-24 14:54:38 -0600833 // At this point, the sensor will be created for sure.
834 if (existingSensors.find(sensorPath) == existingSensors.end())
835 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600836 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
837 sensorPath);
Chris Cain6fa848a2022-01-24 14:54:38 -0600838 }
839
Matt Spinlera26f1522021-08-25 15:50:20 -0500840 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800841 }
842 return;
843}
844
845std::optional<std::string>
846 Manager::getPowerLabelFunctionID(const std::string& value)
847{
848 // If the value is "system", then the FunctionID is "system".
849 if (value == "system")
850 {
851 return value;
852 }
853
854 // If the value is not "system", then the label value have 3 numbers, of
855 // which we only care about the middle one:
856 // <sensor id>_<function id>_<apss channel>
857 // eg: The value is "0_10_5" , then the FunctionID is "10".
858 if (value.find("_") == std::string::npos)
859 {
860 return std::nullopt;
861 }
862
863 auto powerLabelValue = value.substr((value.find("_") + 1));
864
865 if (powerLabelValue.find("_") == std::string::npos)
866 {
867 return std::nullopt;
868 }
869
870 return powerLabelValue.substr(0, powerLabelValue.find("_"));
871}
872
873void Manager::readPowerSensors(const fs::path& path, uint32_t id)
874{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800875 std::regex expr{"power\\d+_label$"}; // Example: power5_label
876 for (auto& file : fs::directory_iterator(path))
877 {
878 if (!std::regex_search(file.path().string(), expr))
879 {
880 continue;
881 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800882
Matt Spinlera26f1522021-08-25 15:50:20 -0500883 std::string labelValue;
884 try
885 {
886 labelValue = readFile<std::string>(file.path());
887 }
888 catch (const std::system_error& e)
889 {
890 log<level::DEBUG>(
891 fmt::format("readPowerSensors: Failed reading {}, errno = {}",
892 file.path().string(), e.code().value())
893 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800894 continue;
895 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800896
897 auto functionID = getPowerLabelFunctionID(labelValue);
898 if (functionID == std::nullopt)
899 {
900 continue;
901 }
902
903 const std::string& tempLabel = "label";
904 const std::string filePathString = file.path().string().substr(
905 0, file.path().string().length() - tempLabel.length());
906
907 std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/");
908
909 auto iter = powerSensorName.find(*functionID);
910 if (iter == powerSensorName.end())
911 {
912 continue;
913 }
914 sensorPath.append(iter->second);
915
Matt Spinlera26f1522021-08-25 15:50:20 -0500916 double tempValue{0};
917
918 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800919 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500920 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800921 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500922 catch (const std::system_error& e)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800923 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800924 log<level::DEBUG>(
Chris Cain5d66a0a2022-02-09 08:52:10 -0600925 fmt::format("readPowerSensors: Failed reading {}, errno = {}",
Matt Spinlera26f1522021-08-25 15:50:20 -0500926 filePathString + inputSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800927 .c_str());
Matt Spinlera26f1522021-08-25 15:50:20 -0500928 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800929 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500930
Chris Cain5d66a0a2022-02-09 08:52:10 -0600931 dbus::OccDBusSensors::getOccDBus().setUnit(
Chris Caind84a8332022-01-13 08:58:45 -0600932 sensorPath, "xyz.openbmc_project.Sensor.Value.Unit.Watts");
933
Chris Cain5d66a0a2022-02-09 08:52:10 -0600934 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500935 sensorPath, tempValue * std::pow(10, -3) * std::pow(10, -3));
936
Chris Cain5d66a0a2022-02-09 08:52:10 -0600937 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
938 true);
Matt Spinlera26f1522021-08-25 15:50:20 -0500939
Matt Spinler5901abd2021-09-23 13:50:03 -0500940 if (existingSensors.find(sensorPath) == existingSensors.end())
941 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600942 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
943 sensorPath);
Matt Spinler5901abd2021-09-23 13:50:03 -0500944 }
945
Matt Spinlera26f1522021-08-25 15:50:20 -0500946 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800947 }
948 return;
949}
950
951void Manager::setSensorValueToNaN(uint32_t id)
952{
953 for (const auto& [sensorPath, occId] : existingSensors)
954 {
955 if (occId == id)
956 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600957 dbus::OccDBusSensors::getOccDBus().setValue(
Chicago Duanbb895cb2021-06-18 19:37:16 +0800958 sensorPath, std::numeric_limits<double>::quiet_NaN());
959 }
960 }
961 return;
962}
963
Sheldon Bailey373af752022-02-21 15:14:00 -0600964void Manager::setSensorValueToNonFunctional(uint32_t id) const
965{
966 for (const auto& [sensorPath, occId] : existingSensors)
967 {
968 if (occId == id)
969 {
970 dbus::OccDBusSensors::getOccDBus().setValue(
971 sensorPath, std::numeric_limits<double>::quiet_NaN());
972
973 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
974 false);
975 }
976 }
977 return;
978}
979
Chris Cain5d66a0a2022-02-09 08:52:10 -0600980void Manager::getSensorValues(std::unique_ptr<Status>& occ)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800981{
Chris Caine2d0a432022-03-28 11:08:49 -0500982 static bool tracedError[8] = {0};
983 const fs::path sensorPath = occ->getHwmonPath();
Chris Cain5d66a0a2022-02-09 08:52:10 -0600984 const uint32_t id = occ->getOccInstanceID();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800985
Chris Caine2d0a432022-03-28 11:08:49 -0500986 if (fs::exists(sensorPath))
Chicago Duanbb895cb2021-06-18 19:37:16 +0800987 {
Chris Caine2d0a432022-03-28 11:08:49 -0500988 // Read temperature sensors
989 readTempSensors(sensorPath, id);
990
991 if (occ->isMasterOcc())
992 {
993 // Read power sensors
994 readPowerSensors(sensorPath, id);
995 }
996 tracedError[id] = false;
997 }
998 else
999 {
1000 if (!tracedError[id])
1001 {
1002 log<level::ERR>(
1003 fmt::format(
1004 "Manager::getSensorValues: OCC{} sensor path missing: {}",
1005 id, sensorPath.c_str())
1006 .c_str());
1007 tracedError[id] = true;
1008 }
Chicago Duanbb895cb2021-06-18 19:37:16 +08001009 }
1010
1011 return;
1012}
1013#endif
Chris Cain17257672021-10-22 13:41:03 -05001014
1015// Read the altitude from DBus
1016void Manager::readAltitude()
1017{
1018 static bool traceAltitudeErr = true;
1019
1020 utils::PropertyValue altitudeProperty{};
1021 try
1022 {
1023 altitudeProperty = utils::getProperty(ALTITUDE_PATH, ALTITUDE_INTERFACE,
1024 ALTITUDE_PROP);
1025 auto sensorVal = std::get<double>(altitudeProperty);
1026 if (sensorVal < 0xFFFF)
1027 {
1028 if (sensorVal < 0)
1029 {
1030 altitude = 0;
1031 }
1032 else
1033 {
1034 // Round to nearest meter
1035 altitude = uint16_t(sensorVal + 0.5);
1036 }
1037 log<level::DEBUG>(fmt::format("readAltitude: sensor={} ({}m)",
1038 sensorVal, altitude)
1039 .c_str());
1040 traceAltitudeErr = true;
1041 }
1042 else
1043 {
1044 if (traceAltitudeErr)
1045 {
1046 traceAltitudeErr = false;
1047 log<level::DEBUG>(
1048 fmt::format("Invalid altitude value: {}", sensorVal)
1049 .c_str());
1050 }
1051 }
1052 }
1053 catch (const sdbusplus::exception::exception& e)
1054 {
1055 if (traceAltitudeErr)
1056 {
1057 traceAltitudeErr = false;
1058 log<level::INFO>(
1059 fmt::format("Unable to read Altitude: {}", e.what()).c_str());
1060 }
1061 altitude = 0xFFFF; // not available
1062 }
1063}
1064
1065// Callback function when ambient temperature changes
1066void Manager::ambientCallback(sdbusplus::message::message& msg)
1067{
1068 double currentTemp = 0;
1069 uint8_t truncatedTemp = 0xFF;
1070 std::string msgSensor;
1071 std::map<std::string, std::variant<double>> msgData;
1072 msg.read(msgSensor, msgData);
1073
1074 auto valPropMap = msgData.find(AMBIENT_PROP);
1075 if (valPropMap == msgData.end())
1076 {
1077 log<level::DEBUG>("ambientCallback: Unknown ambient property changed");
1078 return;
1079 }
1080 currentTemp = std::get<double>(valPropMap->second);
1081 if (std::isnan(currentTemp))
1082 {
1083 truncatedTemp = 0xFF;
1084 }
1085 else
1086 {
1087 if (currentTemp < 0)
1088 {
1089 truncatedTemp = 0;
1090 }
1091 else
1092 {
1093 // Round to nearest degree C
1094 truncatedTemp = uint8_t(currentTemp + 0.5);
1095 }
1096 }
1097
1098 // If ambient changes, notify OCCs
1099 if (truncatedTemp != ambient)
1100 {
1101 log<level::DEBUG>(
1102 fmt::format("ambientCallback: Ambient change from {} to {}C",
1103 ambient, currentTemp)
1104 .c_str());
1105
1106 ambient = truncatedTemp;
1107 if (altitude == 0xFFFF)
1108 {
1109 // No altitude yet, try reading again
1110 readAltitude();
1111 }
1112
1113 log<level::DEBUG>(
1114 fmt::format("ambientCallback: Ambient: {}C, altitude: {}m", ambient,
1115 altitude)
1116 .c_str());
1117#ifdef POWER10
1118 // Send ambient and altitude to all OCCs
1119 for (auto& obj : statusObjects)
1120 {
1121 if (obj->occActive())
1122 {
1123 obj->sendAmbient(ambient, altitude);
1124 }
1125 }
1126#endif // POWER10
1127 }
1128}
1129
1130// return the current ambient and altitude readings
1131void Manager::getAmbientData(bool& ambientValid, uint8_t& ambientTemp,
1132 uint16_t& altitudeValue) const
1133{
1134 ambientValid = true;
1135 ambientTemp = ambient;
1136 altitudeValue = altitude;
1137
1138 if (ambient == 0xFF)
1139 {
1140 ambientValid = false;
1141 }
1142}
1143
Chris Caina7b74dc2021-11-10 17:03:43 -06001144#ifdef POWER10
1145void Manager::occsNotAllRunning()
1146{
Chris Cain6fa848a2022-01-24 14:54:38 -06001147 // Function will also gets called when occ-control app gets
1148 // restarted. (occ active sensors do not change, so the Status
1149 // object does not call Manager back for all OCCs)
Chris Caina7b74dc2021-11-10 17:03:43 -06001150
1151 if (activeCount != statusObjects.size())
1152 {
1153 // Not all OCCs went active
1154 log<level::WARNING>(
1155 fmt::format(
1156 "occsNotAllRunning: Active OCC count ({}) does not match expected count ({})",
1157 activeCount, statusObjects.size())
1158 .c_str());
1159 // Procs may be garded, so may not need reset.
1160 }
1161
1162 validateOccMaster();
1163}
1164#endif // POWER10
1165
1166// Verify single master OCC and start presence monitor
1167void Manager::validateOccMaster()
1168{
1169 int masterInstance = -1;
1170 for (auto& obj : statusObjects)
1171 {
Chris Cainbae4d072022-02-28 09:46:50 -06001172#ifdef POWER10
1173 if (!obj->occActive())
1174 {
1175 if (utils::isHostRunning())
1176 {
1177 // OCC does not appear to be active yet, check active sensor
1178 pldmHandle->checkActiveSensor(obj->getOccInstanceID());
1179 if (obj->occActive())
1180 {
1181 log<level::INFO>(
1182 fmt::format(
1183 "validateOccMaster: OCC{} is ACTIVE after reading sensor",
1184 obj->getOccInstanceID())
1185 .c_str());
1186 }
1187 }
1188 else
1189 {
1190 log<level::WARNING>(
1191 fmt::format(
1192 "validateOccMaster: HOST is not running (OCC{})",
1193 obj->getOccInstanceID())
1194 .c_str());
1195 return;
1196 }
1197 }
1198#endif // POWER10
1199
Chris Caina7b74dc2021-11-10 17:03:43 -06001200 if (obj->isMasterOcc())
1201 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001202 obj->addPresenceWatchMaster();
1203
Chris Caina7b74dc2021-11-10 17:03:43 -06001204 if (masterInstance == -1)
1205 {
1206 masterInstance = obj->getOccInstanceID();
1207 }
1208 else
1209 {
1210 log<level::ERR>(
1211 fmt::format(
1212 "validateOccMaster: Multiple OCC masters! ({} and {})",
1213 masterInstance, obj->getOccInstanceID())
1214 .c_str());
1215 // request reset
1216 obj->deviceError();
1217 }
1218 }
1219 }
Chris Cainbae4d072022-02-28 09:46:50 -06001220
Chris Caina7b74dc2021-11-10 17:03:43 -06001221 if (masterInstance < 0)
1222 {
Chris Cainbae4d072022-02-28 09:46:50 -06001223 log<level::ERR>(
1224 fmt::format("validateOccMaster: Master OCC not found! (of {} OCCs)",
1225 statusObjects.size())
1226 .c_str());
Chris Caina7b74dc2021-11-10 17:03:43 -06001227 // request reset
1228 statusObjects.front()->deviceError();
1229 }
1230 else
1231 {
1232 log<level::INFO>(
Chris Cain36f9cde2021-11-22 11:18:21 -06001233 fmt::format("validateOccMaster: OCC{} is master of {} OCCs",
1234 masterInstance, activeCount)
Chris Caina7b74dc2021-11-10 17:03:43 -06001235 .c_str());
1236 }
1237}
1238
Chris Cain40501a22022-03-14 17:33:27 -05001239void Manager::updatePcapBounds() const
1240{
1241 if (pcap)
1242 {
1243 pcap->updatePcapBounds();
1244 }
1245}
1246
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +05301247} // namespace occ
1248} // namespace open_power