blob: 8a1469d0b8bd13625317226ce7e341d7e3206110 [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 Cain613dc902022-04-08 09:56:22 -050068 if (!pmode)
69 {
70 // Create the power mode object
71 pmode = std::make_unique<powermode::PowerMode>(
72 *this, powermode::PMODE_PATH, powermode::PIPS_PATH, event);
73 }
74
Chris Cain1718fd82022-02-16 16:39:50 -060075 if (!fs::exists(HOST_ON_FILE))
Matt Spinlerd267cec2021-09-01 14:49:19 -050076 {
Chris Cainbae4d072022-02-28 09:46:50 -060077 static bool statusObjCreated = false;
78 if (!statusObjCreated)
Chris Cain1718fd82022-02-16 16:39:50 -060079 {
Chris Cainbae4d072022-02-28 09:46:50 -060080 // Create the OCCs based on on the /dev/occX devices
81 auto occs = findOCCsInDev();
Chris Cain1718fd82022-02-16 16:39:50 -060082
Chris Cainbae4d072022-02-28 09:46:50 -060083 if (occs.empty() || (prevOCCSearch.size() != occs.size()))
Chris Cain1718fd82022-02-16 16:39:50 -060084 {
Chris Cainbae4d072022-02-28 09:46:50 -060085 // Something changed or no OCCs yet, try again in 10s.
86 // Note on the first pass prevOCCSearch will be empty,
87 // so there will be at least one delay to give things
88 // a chance to settle.
89 prevOCCSearch = occs;
90
91 log<level::INFO>(
92 fmt::format(
93 "Manager::findAndCreateObjects(): Waiting for OCCs (currently {})",
94 occs.size())
95 .c_str());
96
97 discoverTimer->restartOnce(10s);
98 }
99 else
100 {
101 // All OCCs appear to be available, create status objects
102
103 // createObjects requires OCC0 first.
104 std::sort(occs.begin(), occs.end());
105
106 log<level::INFO>(
107 fmt::format(
108 "Manager::findAndCreateObjects(): Creating {} OCC Status Objects",
109 occs.size())
110 .c_str());
111 for (auto id : occs)
112 {
113 createObjects(std::string(OCC_NAME) + std::to_string(id));
114 }
115 statusObjCreated = true;
116 }
117 }
118
119 if (statusObjCreated)
120 {
121 static bool tracedHostWait = false;
122 if (utils::isHostRunning())
123 {
124 if (tracedHostWait)
125 {
126 log<level::INFO>(
127 "Manager::findAndCreateObjects(): Host is running");
128 tracedHostWait = false;
129 }
130 waitingForAllOccActiveSensors = true;
131 checkAllActiveSensors();
132 }
133 else
134 {
135 if (!tracedHostWait)
136 {
137 log<level::INFO>(
138 "Manager::findAndCreateObjects(): Waiting for host to start");
139 tracedHostWait = true;
140 }
141 discoverTimer->restartOnce(30s);
Chris Cain1718fd82022-02-16 16:39:50 -0600142 }
143 }
Matt Spinlerd267cec2021-09-01 14:49:19 -0500144 }
145 else
146 {
Chris Cain1718fd82022-02-16 16:39:50 -0600147 log<level::INFO>(
148 fmt::format(
149 "Manager::findAndCreateObjects(): Waiting for {} to complete...",
150 HOST_ON_FILE)
151 .c_str());
152 discoverTimer->restartOnce(10s);
Matt Spinlerd267cec2021-09-01 14:49:19 -0500153 }
154#endif
155}
156
Chris Cainbae4d072022-02-28 09:46:50 -0600157#ifdef POWER10
158// Check if all occActive sensors are available
159void Manager::checkAllActiveSensors()
160{
161 static bool allActiveSensorAvailable = false;
162 static bool tracedSensorWait = false;
163
164 // Start with the assumption that all are available
165 allActiveSensorAvailable = true;
166 for (auto& obj : statusObjects)
167 {
168 // If active sensor is already true, then no need to query sensor
169 if (!obj->occActive())
170 {
171 allActiveSensorAvailable = false;
172 if (!tracedSensorWait)
173 {
174 log<level::INFO>(
175 fmt::format(
176 "Manager::checkAllActiveSensors(): Waiting on OCC{} Active sensor",
177 obj->getOccInstanceID())
178 .c_str());
179 tracedSensorWait = true;
180 }
181 pldmHandle->checkActiveSensor(obj->getOccInstanceID());
182 break;
183 }
184 }
185
186 if (allActiveSensorAvailable)
187 {
188 // All sensors were found, disable the discovery timer
189 discoverTimer.reset();
190 waitingForAllOccActiveSensors = false;
191
192 log<level::INFO>(
193 "Manager::checkAllActiveSensors(): OCC Active sensors are available");
194 tracedSensorWait = false;
195 }
196 else
197 {
198 // Not all sensors were available, so keep waiting
199 if (!tracedSensorWait)
200 {
201 log<level::INFO>(
202 "Manager::checkAllActiveSensors(): Waiting for OCC Active sensors to become available");
203 tracedSensorWait = true;
204 }
205 discoverTimer->restartOnce(30s);
206 }
207}
208#endif
209
Matt Spinlerd267cec2021-09-01 14:49:19 -0500210std::vector<int> Manager::findOCCsInDev()
211{
212 std::vector<int> occs;
213 std::regex expr{R"(occ(\d+)$)"};
214
215 for (auto& file : fs::directory_iterator("/dev"))
216 {
217 std::smatch match;
218 std::string path{file.path().string()};
219 if (std::regex_search(path, match, expr))
220 {
221 auto num = std::stoi(match[1].str());
222
223 // /dev numbering starts at 1, ours starts at 0.
224 occs.push_back(num - 1);
225 }
226 }
227
228 return occs;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530229}
230
231int Manager::cpuCreated(sdbusplus::message::message& msg)
232{
George Liubcef3b42021-09-10 12:39:02 +0800233 namespace fs = std::filesystem;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530234
235 sdbusplus::message::object_path o;
236 msg.read(o);
237 fs::path cpuPath(std::string(std::move(o)));
238
239 auto name = cpuPath.filename().string();
240 auto index = name.find(CPU_NAME);
241 name.replace(index, std::strlen(CPU_NAME), OCC_NAME);
242
243 createObjects(name);
244
245 return 0;
246}
247
248void Manager::createObjects(const std::string& occ)
249{
250 auto path = fs::path(OCC_CONTROL_ROOT) / occ;
251
Gunnar Mills94df8c92018-09-14 14:50:03 -0500252 statusObjects.emplace_back(std::make_unique<Status>(
George Liuf3b75142021-06-10 11:22:50 +0800253 event, path.c_str(), *this,
Chris Cain36f9cde2021-11-22 11:18:21 -0600254#ifdef POWER10
255 pmode,
256#endif
Gunnar Mills94df8c92018-09-14 14:50:03 -0500257 std::bind(std::mem_fn(&Manager::statusCallBack), this,
Sheldon Bailey373af752022-02-21 15:14:00 -0600258 std::placeholders::_1, std::placeholders::_2)
Tom Joseph00325232020-07-29 17:51:48 +0530259#ifdef PLDM
260 ,
261 std::bind(std::mem_fn(&pldm::Interface::resetOCC), pldmHandle.get(),
262 std::placeholders::_1)
263#endif
264 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530265
Chris Cain40501a22022-03-14 17:33:27 -0500266 // Create the power cap monitor object
267 if (!pcap)
268 {
269 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
270 *statusObjects.back());
271 }
272
Chris Cain36f9cde2021-11-22 11:18:21 -0600273 if (statusObjects.back()->isMasterOcc())
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530274 {
Chris Cain36f9cde2021-11-22 11:18:21 -0600275 log<level::INFO>(
276 fmt::format("Manager::createObjects(): OCC{} is the master",
277 statusObjects.back()->getOccInstanceID())
278 .c_str());
279 _pollTimer->setEnabled(false);
280
Chris Cain78e86012021-03-04 16:15:31 -0600281#ifdef POWER10
Chris Cain6fa848a2022-01-24 14:54:38 -0600282 // Set the master OCC on the PowerMode object
283 pmode->setMasterOcc(path);
Chris Cain78e86012021-03-04 16:15:31 -0600284#endif
Chris Cain36f9cde2021-11-22 11:18:21 -0600285 }
286
287 passThroughObjects.emplace_back(std::make_unique<PassThrough>(path.c_str()
288#ifdef POWER10
289 ,
290 pmode
291#endif
292 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530293}
294
Sheldon Bailey373af752022-02-21 15:14:00 -0600295void Manager::statusCallBack(instanceID instance, bool status)
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530296{
Gunnar Mills94df8c92018-09-14 14:50:03 -0500297 using InternalFailure =
298 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530299
300 // At this time, it won't happen but keeping it
301 // here just in case something changes in the future
302 if ((activeCount == 0) && (!status))
303 {
Sheldon Bailey373af752022-02-21 15:14:00 -0600304 log<level::ERR>(
305 fmt::format("Invalid update on OCCActive with OCC{}", instance)
306 .c_str());
307
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530308 elog<InternalFailure>();
309 }
310
Chris Caina7b74dc2021-11-10 17:03:43 -0600311 if (status == true)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600312 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600313 // OCC went active
314 ++activeCount;
315
316#ifdef POWER10
317 if (activeCount == 1)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600318 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600319 // First OCC went active (allow some time for all OCCs to go active)
320 waitForAllOccsTimer->restartOnce(30s);
Matt Spinler53f68142021-08-25 15:47:31 -0500321 }
322#endif
Chris Caina7b74dc2021-11-10 17:03:43 -0600323
324 if (activeCount == statusObjects.size())
325 {
326#ifdef POWER10
327 // All OCCs are now running
328 if (waitForAllOccsTimer->isEnabled())
329 {
330 // stop occ wait timer
331 waitForAllOccsTimer->setEnabled(false);
332 }
333#endif
334
335 // Verify master OCC and start presence monitor
336 validateOccMaster();
337 }
338
339 // Start poll timer if not already started
340 if (!_pollTimer->isEnabled())
341 {
342 log<level::INFO>(
Chris Cain36f9cde2021-11-22 11:18:21 -0600343 fmt::format("Manager: OCCs will be polled every {} seconds",
344 pollInterval)
Chris Caina7b74dc2021-11-10 17:03:43 -0600345 .c_str());
346
347 // Send poll and start OCC poll timer
348 pollerTimerExpired();
349 }
350 }
351 else
352 {
353 // OCC went away
354 --activeCount;
355
356 if (activeCount == 0)
357 {
358 // No OCCs are running
359
360 // Stop OCC poll timer
361 if (_pollTimer->isEnabled())
362 {
363 log<level::INFO>(
364 "Manager::statusCallBack(): OCCs are not running, stopping poll timer");
365 _pollTimer->setEnabled(false);
366 }
367
368#ifdef POWER10
369 // stop wait timer
370 if (waitForAllOccsTimer->isEnabled())
371 {
372 waitForAllOccsTimer->setEnabled(false);
373 }
374#endif
Chris Caina7b74dc2021-11-10 17:03:43 -0600375 }
Sheldon Bailey373af752022-02-21 15:14:00 -0600376#ifdef READ_OCC_SENSORS
377 // Clear OCC sensors
378 setSensorValueToNonFunctional(instance);
379#endif
Chris Caina8857c52021-01-27 11:53:05 -0600380 }
Chris Cainbae4d072022-02-28 09:46:50 -0600381
382#ifdef POWER10
383 if (waitingForAllOccActiveSensors)
384 {
385 checkAllActiveSensors();
386 }
387#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530388}
389
390#ifdef I2C_OCC
391void Manager::initStatusObjects()
392{
393 // Make sure we have a valid path string
394 static_assert(sizeof(DEV_PATH) != 0);
395
396 auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH);
397 for (auto& name : deviceNames)
398 {
399 i2c_occ::i2cToDbus(name);
Lei YUb5259a12017-09-01 16:22:40 +0800400 name = std::string(OCC_NAME) + '_' + name;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530401 auto path = fs::path(OCC_CONTROL_ROOT) / name;
402 statusObjects.emplace_back(
George Liuf3b75142021-06-10 11:22:50 +0800403 std::make_unique<Status>(event, path.c_str(), *this));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530404 }
Chris Cain40501a22022-03-14 17:33:27 -0500405 // The first device is master occ
406 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
407 *statusObjects.front());
Chris Cain78e86012021-03-04 16:15:31 -0600408#ifdef POWER10
Chris Cain5d66a0a2022-02-09 08:52:10 -0600409 pmode = std::make_unique<powermode::PowerMode>(*this, powermode::PMODE_PATH,
410 powermode::PIPS_PATH);
Chris Cain6fa848a2022-01-24 14:54:38 -0600411 // Set the master OCC on the PowerMode object
412 pmode->setMasterOcc(path);
Chris Cain78e86012021-03-04 16:15:31 -0600413#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530414}
415#endif
416
Tom Joseph815f9f52020-07-27 12:12:13 +0530417#ifdef PLDM
Eddie Jamescbad2192021-10-07 09:39:39 -0500418void Manager::sbeTimeout(unsigned int instance)
419{
Eddie James2a751d72022-03-04 09:16:12 -0600420 auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
421 [instance](const auto& obj) {
422 return instance == obj->getOccInstanceID();
423 });
Eddie Jamescbad2192021-10-07 09:39:39 -0500424
Eddie Jamescb018da2022-03-05 11:49:37 -0600425 if (obj != statusObjects.end() && (*obj)->occActive())
Eddie James2a751d72022-03-04 09:16:12 -0600426 {
Chris Cainbae4d072022-02-28 09:46:50 -0600427 log<level::INFO>(
428 fmt::format("SBE timeout, requesting HRESET (OCC{})", instance)
429 .c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500430
Eddie James2a751d72022-03-04 09:16:12 -0600431 setSBEState(instance, SBE_STATE_NOT_USABLE);
432
433 pldmHandle->sendHRESET(instance);
434 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500435}
436
Tom Joseph815f9f52020-07-27 12:12:13 +0530437bool Manager::updateOCCActive(instanceID instance, bool status)
438{
Chris Cain7e374fb2022-04-07 09:47:23 -0500439 auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
440 [instance](const auto& obj) {
441 return instance == obj->getOccInstanceID();
442 });
443
444 if (obj != statusObjects.end())
445 {
446 return (*obj)->occActive(status);
447 }
448 else
449 {
450 log<level::WARNING>(
451 fmt::format(
452 "Manager::updateOCCActive: No status object to update for OCC{} (active={})",
453 instance, status)
454 .c_str());
455 return false;
456 }
Tom Joseph815f9f52020-07-27 12:12:13 +0530457}
Eddie Jamescbad2192021-10-07 09:39:39 -0500458
459void Manager::sbeHRESETResult(instanceID instance, bool success)
460{
461 if (success)
462 {
Chris Cainbae4d072022-02-28 09:46:50 -0600463 log<level::INFO>(
464 fmt::format("HRESET succeeded (OCC{})", instance).c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500465
466 setSBEState(instance, SBE_STATE_BOOTED);
467
468 return;
469 }
470
471 setSBEState(instance, SBE_STATE_FAILED);
472
473 if (sbeCanDump(instance))
474 {
Chris Cainbae4d072022-02-28 09:46:50 -0600475 log<level::INFO>(
476 fmt::format("HRESET failed (OCC{}), triggering SBE dump", instance)
477 .c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500478
479 auto& bus = utils::getBus();
480 uint32_t src6 = instance << 16;
481 uint32_t logId =
482 FFDC::createPEL("org.open_power.Processor.Error.SbeChipOpTimeout",
483 src6, "SBE command timeout");
484
485 try
486 {
George Liuf3a4a692021-12-28 13:59:51 +0800487 constexpr auto path = "/org/openpower/dump";
488 constexpr auto interface = "xyz.openbmc_project.Dump.Create";
489 constexpr auto function = "CreateDump";
490
Eddie Jamescbad2192021-10-07 09:39:39 -0500491 std::string service = utils::getService(path, interface);
492 auto method =
493 bus.new_method_call(service.c_str(), path, interface, function);
494
495 std::map<std::string, std::variant<std::string, uint64_t>>
496 createParams{
497 {"com.ibm.Dump.Create.CreateParameters.ErrorLogId",
498 uint64_t(logId)},
499 {"com.ibm.Dump.Create.CreateParameters.DumpType",
500 "com.ibm.Dump.Create.DumpType.SBE"},
501 {"com.ibm.Dump.Create.CreateParameters.FailingUnitId",
502 uint64_t(instance)},
503 };
504
505 method.append(createParams);
506
507 auto response = bus.call(method);
508 }
509 catch (const sdbusplus::exception::exception& e)
510 {
511 constexpr auto ERROR_DUMP_DISABLED =
512 "xyz.openbmc_project.Dump.Create.Error.Disabled";
513 if (e.name() == ERROR_DUMP_DISABLED)
514 {
515 log<level::INFO>("Dump is disabled, skipping");
516 }
517 else
518 {
519 log<level::ERR>("Dump failed");
520 }
521 }
522 }
523}
524
525bool Manager::sbeCanDump(unsigned int instance)
526{
527 struct pdbg_target* proc = getPdbgTarget(instance);
528
529 if (!proc)
530 {
531 // allow the dump in the error case
532 return true;
533 }
534
535 try
536 {
537 if (!openpower::phal::sbe::isDumpAllowed(proc))
538 {
539 return false;
540 }
541
542 if (openpower::phal::pdbg::isSbeVitalAttnActive(proc))
543 {
544 return false;
545 }
546 }
547 catch (openpower::phal::exception::SbeError& e)
548 {
549 log<level::INFO>("Failed to query SBE state");
550 }
551
552 // allow the dump in the error case
553 return true;
554}
555
556void Manager::setSBEState(unsigned int instance, enum sbe_state state)
557{
558 struct pdbg_target* proc = getPdbgTarget(instance);
559
560 if (!proc)
561 {
562 return;
563 }
564
565 try
566 {
567 openpower::phal::sbe::setState(proc, state);
568 }
569 catch (const openpower::phal::exception::SbeError& e)
570 {
571 log<level::ERR>("Failed to set SBE state");
572 }
573}
574
575struct pdbg_target* Manager::getPdbgTarget(unsigned int instance)
576{
577 if (!pdbgInitialized)
578 {
579 try
580 {
581 openpower::phal::pdbg::init();
582 pdbgInitialized = true;
583 }
584 catch (const openpower::phal::exception::PdbgError& e)
585 {
586 log<level::ERR>("pdbg initialization failed");
587 return nullptr;
588 }
589 }
590
591 struct pdbg_target* proc = nullptr;
592 pdbg_for_each_class_target("proc", proc)
593 {
594 if (pdbg_target_index(proc) == instance)
595 {
596 return proc;
597 }
598 }
599
600 log<level::ERR>("Failed to get pdbg target");
601 return nullptr;
602}
Tom Joseph815f9f52020-07-27 12:12:13 +0530603#endif
604
Chris Caina8857c52021-01-27 11:53:05 -0600605void Manager::pollerTimerExpired()
606{
Chris Caina8857c52021-01-27 11:53:05 -0600607 if (!_pollTimer)
608 {
609 log<level::ERR>(
610 "Manager::pollerTimerExpired() ERROR: Timer not defined");
611 return;
612 }
613
614 for (auto& obj : statusObjects)
615 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600616 if (!obj->occActive())
617 {
618 // OCC is not running yet
619#ifdef READ_OCC_SENSORS
Chris Cain5d66a0a2022-02-09 08:52:10 -0600620 auto id = obj->getOccInstanceID();
Sheldon Bailey373af752022-02-21 15:14:00 -0600621 setSensorValueToNonFunctional(id);
Chris Caina7b74dc2021-11-10 17:03:43 -0600622#endif
623 continue;
624 }
625
Chris Caina8857c52021-01-27 11:53:05 -0600626 // Read sysfs to force kernel to poll OCC
627 obj->readOccState();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800628
629#ifdef READ_OCC_SENSORS
630 // Read occ sensor values
Chris Cain5d66a0a2022-02-09 08:52:10 -0600631 getSensorValues(obj);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800632#endif
Chris Caina8857c52021-01-27 11:53:05 -0600633 }
634
Chris Caina7b74dc2021-11-10 17:03:43 -0600635 if (activeCount > 0)
636 {
637 // Restart OCC poll timer
638 _pollTimer->restartOnce(std::chrono::seconds(pollInterval));
639 }
640 else
641 {
642 // No OCCs running, so poll timer will not be restarted
643 log<level::INFO>(
644 fmt::format(
645 "Manager::pollerTimerExpired: poll timer will not be restarted")
646 .c_str());
647 }
Chris Caina8857c52021-01-27 11:53:05 -0600648}
649
Chicago Duanbb895cb2021-06-18 19:37:16 +0800650#ifdef READ_OCC_SENSORS
651void Manager::readTempSensors(const fs::path& path, uint32_t id)
652{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800653 std::regex expr{"temp\\d+_label$"}; // Example: temp5_label
654 for (auto& file : fs::directory_iterator(path))
655 {
656 if (!std::regex_search(file.path().string(), expr))
657 {
658 continue;
659 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800660
Matt Spinlera26f1522021-08-25 15:50:20 -0500661 uint32_t labelValue{0};
662
663 try
664 {
665 labelValue = readFile<uint32_t>(file.path());
666 }
667 catch (const std::system_error& e)
668 {
669 log<level::DEBUG>(
670 fmt::format("readTempSensors: Failed reading {}, errno = {}",
671 file.path().string(), e.code().value())
672 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800673 continue;
674 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800675
676 const std::string& tempLabel = "label";
677 const std::string filePathString = file.path().string().substr(
678 0, file.path().string().length() - tempLabel.length());
Matt Spinlera26f1522021-08-25 15:50:20 -0500679
680 uint32_t fruTypeValue{0};
681 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800682 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500683 fruTypeValue = readFile<uint32_t>(filePathString + fruTypeSuffix);
684 }
685 catch (const std::system_error& e)
686 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800687 log<level::DEBUG>(
Matt Spinlera26f1522021-08-25 15:50:20 -0500688 fmt::format("readTempSensors: Failed reading {}, errno = {}",
689 filePathString + fruTypeSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800690 .c_str());
691 continue;
692 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800693
694 std::string sensorPath =
695 OCC_SENSORS_ROOT + std::string("/temperature/");
696
Matt Spinlerace67d82021-10-18 13:41:57 -0500697 std::string dvfsTempPath;
698
Chicago Duanbb895cb2021-06-18 19:37:16 +0800699 if (fruTypeValue == VRMVdd)
700 {
701 sensorPath.append("vrm_vdd" + std::to_string(id) + "_temp");
702 }
Matt Spinlerace67d82021-10-18 13:41:57 -0500703 else if (fruTypeValue == processorIoRing)
704 {
705 sensorPath.append("proc" + std::to_string(id) + "_ioring_temp");
706 dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/proc" +
707 std::to_string(id) + "_ioring_dvfs_temp";
708 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800709 else
710 {
Matt Spinler14d14022021-08-25 15:38:29 -0500711 uint16_t type = (labelValue & 0xFF000000) >> 24;
712 uint16_t instanceID = labelValue & 0x0000FFFF;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800713
714 if (type == OCC_DIMM_TEMP_SENSOR_TYPE)
715 {
Matt Spinler8b8abee2021-08-25 15:18:21 -0500716 if (fruTypeValue == fruTypeNotAvailable)
717 {
718 // Not all DIMM related temps are available to read
719 // (no _input file in this case)
720 continue;
721 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800722 auto iter = dimmTempSensorName.find(fruTypeValue);
723 if (iter == dimmTempSensorName.end())
724 {
George Liub5ca1012021-09-10 12:53:11 +0800725 log<level::ERR>(
726 fmt::format(
727 "readTempSensors: Fru type error! fruTypeValue = {}) ",
728 fruTypeValue)
729 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800730 continue;
731 }
732
733 sensorPath.append("dimm" + std::to_string(instanceID) +
734 iter->second);
735 }
736 else if (type == OCC_CPU_TEMP_SENSOR_TYPE)
737 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500738 if (fruTypeValue == processorCore)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800739 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500740 // The OCC reports small core temps, of which there are
741 // two per big core. All current P10 systems are in big
742 // core mode, so use a big core name.
743 uint16_t coreNum = instanceID / 2;
744 uint16_t tempNum = instanceID % 2;
745 sensorPath.append("proc" + std::to_string(id) + "_core" +
746 std::to_string(coreNum) + "_" +
747 std::to_string(tempNum) + "_temp");
748
749 dvfsTempPath = std::string{OCC_SENSORS_ROOT} +
750 "/temperature/proc" + std::to_string(id) +
751 "_core_dvfs_temp";
752 }
753 else
754 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800755 continue;
756 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800757 }
758 else
759 {
760 continue;
761 }
762 }
763
Matt Spinlerace67d82021-10-18 13:41:57 -0500764 // The dvfs temp file only needs to be read once per chip per type.
765 if (!dvfsTempPath.empty() &&
766 !dbus::OccDBusSensors::getOccDBus().hasDvfsTemp(dvfsTempPath))
767 {
768 try
769 {
770 auto dvfsValue = readFile<double>(filePathString + maxSuffix);
771
772 dbus::OccDBusSensors::getOccDBus().setDvfsTemp(
773 dvfsTempPath, dvfsValue * std::pow(10, -3));
774 }
775 catch (const std::system_error& e)
776 {
777 log<level::DEBUG>(
778 fmt::format(
779 "readTempSensors: Failed reading {}, errno = {}",
780 filePathString + maxSuffix, e.code().value())
781 .c_str());
782 }
783 }
784
Matt Spinlera26f1522021-08-25 15:50:20 -0500785 uint32_t faultValue{0};
786 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800787 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500788 faultValue = readFile<uint32_t>(filePathString + faultSuffix);
789 }
790 catch (const std::system_error& e)
791 {
792 log<level::DEBUG>(
793 fmt::format("readTempSensors: Failed reading {}, errno = {}",
794 filePathString + faultSuffix, e.code().value())
795 .c_str());
796 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800797 }
798
Matt Spinlera26f1522021-08-25 15:50:20 -0500799 if (faultValue != 0)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800800 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600801 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500802 sensorPath, std::numeric_limits<double>::quiet_NaN());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800803
Chris Cain5d66a0a2022-02-09 08:52:10 -0600804 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
805 false);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800806
Matt Spinlera26f1522021-08-25 15:50:20 -0500807 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800808 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500809
810 double tempValue{0};
811
812 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800813 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500814 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800815 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500816 catch (const std::system_error& e)
817 {
818 log<level::DEBUG>(
819 fmt::format("readTempSensors: Failed reading {}, errno = {}",
820 filePathString + inputSuffix, e.code().value())
821 .c_str());
822 continue;
823 }
824
Chris Cain5d66a0a2022-02-09 08:52:10 -0600825 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500826 sensorPath, tempValue * std::pow(10, -3));
827
Chris Cain5d66a0a2022-02-09 08:52:10 -0600828 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
829 true);
Matt Spinlera26f1522021-08-25 15:50:20 -0500830
Chris Cain6fa848a2022-01-24 14:54:38 -0600831 // At this point, the sensor will be created for sure.
832 if (existingSensors.find(sensorPath) == existingSensors.end())
833 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600834 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
835 sensorPath);
Chris Cain6fa848a2022-01-24 14:54:38 -0600836 }
837
Matt Spinlera26f1522021-08-25 15:50:20 -0500838 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800839 }
840 return;
841}
842
843std::optional<std::string>
844 Manager::getPowerLabelFunctionID(const std::string& value)
845{
846 // If the value is "system", then the FunctionID is "system".
847 if (value == "system")
848 {
849 return value;
850 }
851
852 // If the value is not "system", then the label value have 3 numbers, of
853 // which we only care about the middle one:
854 // <sensor id>_<function id>_<apss channel>
855 // eg: The value is "0_10_5" , then the FunctionID is "10".
856 if (value.find("_") == std::string::npos)
857 {
858 return std::nullopt;
859 }
860
861 auto powerLabelValue = value.substr((value.find("_") + 1));
862
863 if (powerLabelValue.find("_") == std::string::npos)
864 {
865 return std::nullopt;
866 }
867
868 return powerLabelValue.substr(0, powerLabelValue.find("_"));
869}
870
871void Manager::readPowerSensors(const fs::path& path, uint32_t id)
872{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800873 std::regex expr{"power\\d+_label$"}; // Example: power5_label
874 for (auto& file : fs::directory_iterator(path))
875 {
876 if (!std::regex_search(file.path().string(), expr))
877 {
878 continue;
879 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800880
Matt Spinlera26f1522021-08-25 15:50:20 -0500881 std::string labelValue;
882 try
883 {
884 labelValue = readFile<std::string>(file.path());
885 }
886 catch (const std::system_error& e)
887 {
888 log<level::DEBUG>(
889 fmt::format("readPowerSensors: Failed reading {}, errno = {}",
890 file.path().string(), e.code().value())
891 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800892 continue;
893 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800894
895 auto functionID = getPowerLabelFunctionID(labelValue);
896 if (functionID == std::nullopt)
897 {
898 continue;
899 }
900
901 const std::string& tempLabel = "label";
902 const std::string filePathString = file.path().string().substr(
903 0, file.path().string().length() - tempLabel.length());
904
905 std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/");
906
907 auto iter = powerSensorName.find(*functionID);
908 if (iter == powerSensorName.end())
909 {
910 continue;
911 }
912 sensorPath.append(iter->second);
913
Matt Spinlera26f1522021-08-25 15:50:20 -0500914 double tempValue{0};
915
916 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800917 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500918 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800919 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500920 catch (const std::system_error& e)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800921 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800922 log<level::DEBUG>(
Chris Cain5d66a0a2022-02-09 08:52:10 -0600923 fmt::format("readPowerSensors: Failed reading {}, errno = {}",
Matt Spinlera26f1522021-08-25 15:50:20 -0500924 filePathString + inputSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800925 .c_str());
Matt Spinlera26f1522021-08-25 15:50:20 -0500926 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800927 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500928
Chris Cain5d66a0a2022-02-09 08:52:10 -0600929 dbus::OccDBusSensors::getOccDBus().setUnit(
Chris Caind84a8332022-01-13 08:58:45 -0600930 sensorPath, "xyz.openbmc_project.Sensor.Value.Unit.Watts");
931
Chris Cain5d66a0a2022-02-09 08:52:10 -0600932 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500933 sensorPath, tempValue * std::pow(10, -3) * std::pow(10, -3));
934
Chris Cain5d66a0a2022-02-09 08:52:10 -0600935 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
936 true);
Matt Spinlera26f1522021-08-25 15:50:20 -0500937
Matt Spinler5901abd2021-09-23 13:50:03 -0500938 if (existingSensors.find(sensorPath) == existingSensors.end())
939 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600940 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
941 sensorPath);
Matt Spinler5901abd2021-09-23 13:50:03 -0500942 }
943
Matt Spinlera26f1522021-08-25 15:50:20 -0500944 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800945 }
946 return;
947}
948
949void Manager::setSensorValueToNaN(uint32_t id)
950{
951 for (const auto& [sensorPath, occId] : existingSensors)
952 {
953 if (occId == id)
954 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600955 dbus::OccDBusSensors::getOccDBus().setValue(
Chicago Duanbb895cb2021-06-18 19:37:16 +0800956 sensorPath, std::numeric_limits<double>::quiet_NaN());
957 }
958 }
959 return;
960}
961
Sheldon Bailey373af752022-02-21 15:14:00 -0600962void Manager::setSensorValueToNonFunctional(uint32_t id) const
963{
964 for (const auto& [sensorPath, occId] : existingSensors)
965 {
966 if (occId == id)
967 {
968 dbus::OccDBusSensors::getOccDBus().setValue(
969 sensorPath, std::numeric_limits<double>::quiet_NaN());
970
971 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
972 false);
973 }
974 }
975 return;
976}
977
Chris Cain5d66a0a2022-02-09 08:52:10 -0600978void Manager::getSensorValues(std::unique_ptr<Status>& occ)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800979{
Chris Caine2d0a432022-03-28 11:08:49 -0500980 static bool tracedError[8] = {0};
981 const fs::path sensorPath = occ->getHwmonPath();
Chris Cain5d66a0a2022-02-09 08:52:10 -0600982 const uint32_t id = occ->getOccInstanceID();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800983
Chris Caine2d0a432022-03-28 11:08:49 -0500984 if (fs::exists(sensorPath))
Chicago Duanbb895cb2021-06-18 19:37:16 +0800985 {
Chris Caine2d0a432022-03-28 11:08:49 -0500986 // Read temperature sensors
987 readTempSensors(sensorPath, id);
988
989 if (occ->isMasterOcc())
990 {
991 // Read power sensors
992 readPowerSensors(sensorPath, id);
993 }
994 tracedError[id] = false;
995 }
996 else
997 {
998 if (!tracedError[id])
999 {
1000 log<level::ERR>(
1001 fmt::format(
1002 "Manager::getSensorValues: OCC{} sensor path missing: {}",
1003 id, sensorPath.c_str())
1004 .c_str());
1005 tracedError[id] = true;
1006 }
Chicago Duanbb895cb2021-06-18 19:37:16 +08001007 }
1008
1009 return;
1010}
1011#endif
Chris Cain17257672021-10-22 13:41:03 -05001012
1013// Read the altitude from DBus
1014void Manager::readAltitude()
1015{
1016 static bool traceAltitudeErr = true;
1017
1018 utils::PropertyValue altitudeProperty{};
1019 try
1020 {
1021 altitudeProperty = utils::getProperty(ALTITUDE_PATH, ALTITUDE_INTERFACE,
1022 ALTITUDE_PROP);
1023 auto sensorVal = std::get<double>(altitudeProperty);
1024 if (sensorVal < 0xFFFF)
1025 {
1026 if (sensorVal < 0)
1027 {
1028 altitude = 0;
1029 }
1030 else
1031 {
1032 // Round to nearest meter
1033 altitude = uint16_t(sensorVal + 0.5);
1034 }
1035 log<level::DEBUG>(fmt::format("readAltitude: sensor={} ({}m)",
1036 sensorVal, altitude)
1037 .c_str());
1038 traceAltitudeErr = true;
1039 }
1040 else
1041 {
1042 if (traceAltitudeErr)
1043 {
1044 traceAltitudeErr = false;
1045 log<level::DEBUG>(
1046 fmt::format("Invalid altitude value: {}", sensorVal)
1047 .c_str());
1048 }
1049 }
1050 }
1051 catch (const sdbusplus::exception::exception& e)
1052 {
1053 if (traceAltitudeErr)
1054 {
1055 traceAltitudeErr = false;
1056 log<level::INFO>(
1057 fmt::format("Unable to read Altitude: {}", e.what()).c_str());
1058 }
1059 altitude = 0xFFFF; // not available
1060 }
1061}
1062
1063// Callback function when ambient temperature changes
1064void Manager::ambientCallback(sdbusplus::message::message& msg)
1065{
1066 double currentTemp = 0;
1067 uint8_t truncatedTemp = 0xFF;
1068 std::string msgSensor;
1069 std::map<std::string, std::variant<double>> msgData;
1070 msg.read(msgSensor, msgData);
1071
1072 auto valPropMap = msgData.find(AMBIENT_PROP);
1073 if (valPropMap == msgData.end())
1074 {
1075 log<level::DEBUG>("ambientCallback: Unknown ambient property changed");
1076 return;
1077 }
1078 currentTemp = std::get<double>(valPropMap->second);
1079 if (std::isnan(currentTemp))
1080 {
1081 truncatedTemp = 0xFF;
1082 }
1083 else
1084 {
1085 if (currentTemp < 0)
1086 {
1087 truncatedTemp = 0;
1088 }
1089 else
1090 {
1091 // Round to nearest degree C
1092 truncatedTemp = uint8_t(currentTemp + 0.5);
1093 }
1094 }
1095
1096 // If ambient changes, notify OCCs
1097 if (truncatedTemp != ambient)
1098 {
1099 log<level::DEBUG>(
1100 fmt::format("ambientCallback: Ambient change from {} to {}C",
1101 ambient, currentTemp)
1102 .c_str());
1103
1104 ambient = truncatedTemp;
1105 if (altitude == 0xFFFF)
1106 {
1107 // No altitude yet, try reading again
1108 readAltitude();
1109 }
1110
1111 log<level::DEBUG>(
1112 fmt::format("ambientCallback: Ambient: {}C, altitude: {}m", ambient,
1113 altitude)
1114 .c_str());
1115#ifdef POWER10
1116 // Send ambient and altitude to all OCCs
1117 for (auto& obj : statusObjects)
1118 {
1119 if (obj->occActive())
1120 {
1121 obj->sendAmbient(ambient, altitude);
1122 }
1123 }
1124#endif // POWER10
1125 }
1126}
1127
1128// return the current ambient and altitude readings
1129void Manager::getAmbientData(bool& ambientValid, uint8_t& ambientTemp,
1130 uint16_t& altitudeValue) const
1131{
1132 ambientValid = true;
1133 ambientTemp = ambient;
1134 altitudeValue = altitude;
1135
1136 if (ambient == 0xFF)
1137 {
1138 ambientValid = false;
1139 }
1140}
1141
Chris Caina7b74dc2021-11-10 17:03:43 -06001142#ifdef POWER10
1143void Manager::occsNotAllRunning()
1144{
Chris Cain6fa848a2022-01-24 14:54:38 -06001145 // Function will also gets called when occ-control app gets
1146 // restarted. (occ active sensors do not change, so the Status
1147 // object does not call Manager back for all OCCs)
Chris Caina7b74dc2021-11-10 17:03:43 -06001148
1149 if (activeCount != statusObjects.size())
1150 {
1151 // Not all OCCs went active
1152 log<level::WARNING>(
1153 fmt::format(
1154 "occsNotAllRunning: Active OCC count ({}) does not match expected count ({})",
1155 activeCount, statusObjects.size())
1156 .c_str());
1157 // Procs may be garded, so may not need reset.
1158 }
1159
1160 validateOccMaster();
1161}
1162#endif // POWER10
1163
1164// Verify single master OCC and start presence monitor
1165void Manager::validateOccMaster()
1166{
1167 int masterInstance = -1;
1168 for (auto& obj : statusObjects)
1169 {
Chris Cainbae4d072022-02-28 09:46:50 -06001170#ifdef POWER10
1171 if (!obj->occActive())
1172 {
1173 if (utils::isHostRunning())
1174 {
1175 // OCC does not appear to be active yet, check active sensor
1176 pldmHandle->checkActiveSensor(obj->getOccInstanceID());
1177 if (obj->occActive())
1178 {
1179 log<level::INFO>(
1180 fmt::format(
1181 "validateOccMaster: OCC{} is ACTIVE after reading sensor",
1182 obj->getOccInstanceID())
1183 .c_str());
1184 }
1185 }
1186 else
1187 {
1188 log<level::WARNING>(
1189 fmt::format(
1190 "validateOccMaster: HOST is not running (OCC{})",
1191 obj->getOccInstanceID())
1192 .c_str());
1193 return;
1194 }
1195 }
1196#endif // POWER10
1197
Chris Caina7b74dc2021-11-10 17:03:43 -06001198 if (obj->isMasterOcc())
1199 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001200 obj->addPresenceWatchMaster();
1201
Chris Caina7b74dc2021-11-10 17:03:43 -06001202 if (masterInstance == -1)
1203 {
1204 masterInstance = obj->getOccInstanceID();
1205 }
1206 else
1207 {
1208 log<level::ERR>(
1209 fmt::format(
1210 "validateOccMaster: Multiple OCC masters! ({} and {})",
1211 masterInstance, obj->getOccInstanceID())
1212 .c_str());
1213 // request reset
1214 obj->deviceError();
1215 }
1216 }
1217 }
Chris Cainbae4d072022-02-28 09:46:50 -06001218
Chris Caina7b74dc2021-11-10 17:03:43 -06001219 if (masterInstance < 0)
1220 {
Chris Cainbae4d072022-02-28 09:46:50 -06001221 log<level::ERR>(
1222 fmt::format("validateOccMaster: Master OCC not found! (of {} OCCs)",
1223 statusObjects.size())
1224 .c_str());
Chris Caina7b74dc2021-11-10 17:03:43 -06001225 // request reset
1226 statusObjects.front()->deviceError();
1227 }
1228 else
1229 {
1230 log<level::INFO>(
Chris Cain36f9cde2021-11-22 11:18:21 -06001231 fmt::format("validateOccMaster: OCC{} is master of {} OCCs",
1232 masterInstance, activeCount)
Chris Caina7b74dc2021-11-10 17:03:43 -06001233 .c_str());
1234 }
1235}
1236
Chris Cain40501a22022-03-14 17:33:27 -05001237void Manager::updatePcapBounds() const
1238{
1239 if (pcap)
1240 {
1241 pcap->updatePcapBounds();
1242 }
1243}
1244
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +05301245} // namespace occ
1246} // namespace open_power