blob: 979078ce51af2fa548a39e2b5e6cd4c5d948aae2 [file] [log] [blame]
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001#include "config.h"
2
3#include "manager.hpp"
4
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05005#include "constants.hpp"
6#include "exceptions.hpp"
7#include "logger.hpp"
8#include "parser.hpp"
9#include "parser_factory.hpp"
10#include "parser_interface.hpp"
Rekha Aparnaffdff312025-03-25 01:10:56 -050011#include "single_fab.hpp"
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050012#include "types.hpp"
13#include "utility/dbus_utility.hpp"
14#include "utility/json_utility.hpp"
15#include "utility/vpd_specific_utility.hpp"
16
17#include <boost/asio/steady_timer.hpp>
18#include <sdbusplus/bus/match.hpp>
19#include <sdbusplus/message.hpp>
20
21namespace vpd
22{
23Manager::Manager(
24 const std::shared_ptr<boost::asio::io_context>& ioCon,
25 const std::shared_ptr<sdbusplus::asio::dbus_interface>& iFace,
26 const std::shared_ptr<sdbusplus::asio::connection>& asioConnection) :
27 m_ioContext(ioCon), m_interface(iFace), m_asioConnection(asioConnection)
28{
Jinu Joy Thomas3419f5d2025-04-09 04:04:18 -050029#ifdef IBM_SYSTEM
Rekha Aparnaffdff312025-03-25 01:10:56 -050030 if (!dbusUtility::isChassisPowerOn())
31 {
32 SingleFab l_singleFab;
33 const int& l_rc = l_singleFab.singleFabImOverride();
34
35 if (l_rc == constants::FAILURE)
36 {
37 throw std::runtime_error(
38 std::string(__FUNCTION__) +
39 " : Found an invalid system configuration. Needs manual intervention. BMC is being quiesced.");
40 }
41 }
42#endif
43
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050044 try
45 {
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050046 // For backward compatibility. Should be depricated.
47 iFace->register_method(
48 "WriteKeyword",
49 [this](const sdbusplus::message::object_path i_path,
50 const std::string i_recordName, const std::string i_keyword,
51 const types::BinaryVector i_value) -> int {
52 return this->updateKeyword(
53 i_path, std::make_tuple(i_recordName, i_keyword, i_value));
54 });
55
56 // Register methods under com.ibm.VPD.Manager interface
57 iFace->register_method(
58 "UpdateKeyword",
59 [this](const types::Path i_vpdPath,
60 const types::WriteVpdParams i_paramsToWriteData) -> int {
61 return this->updateKeyword(i_vpdPath, i_paramsToWriteData);
62 });
63
64 iFace->register_method(
65 "WriteKeywordOnHardware",
66 [this](const types::Path i_fruPath,
67 const types::WriteVpdParams i_paramsToWriteData) -> int {
68 return this->updateKeywordOnHardware(i_fruPath,
69 i_paramsToWriteData);
70 });
71
72 iFace->register_method(
73 "ReadKeyword",
74 [this](const types::Path i_fruPath,
75 const types::ReadVpdParams i_paramsToReadData)
76 -> types::DbusVariantType {
77 return this->readKeyword(i_fruPath, i_paramsToReadData);
78 });
79
80 iFace->register_method(
81 "CollectFRUVPD",
82 [this](const sdbusplus::message::object_path& i_dbusObjPath) {
83 this->collectSingleFruVpd(i_dbusObjPath);
84 });
85
86 iFace->register_method(
87 "deleteFRUVPD",
88 [this](const sdbusplus::message::object_path& i_dbusObjPath) {
89 this->deleteSingleFruVpd(i_dbusObjPath);
90 });
91
92 iFace->register_method(
93 "GetExpandedLocationCode",
94 [this](const std::string& i_unexpandedLocationCode,
95 uint16_t& i_nodeNumber) -> std::string {
96 return this->getExpandedLocationCode(i_unexpandedLocationCode,
97 i_nodeNumber);
98 });
99
100 iFace->register_method("GetFRUsByExpandedLocationCode",
101 [this](const std::string& i_expandedLocationCode)
102 -> types::ListOfPaths {
103 return this->getFrusByExpandedLocationCode(
104 i_expandedLocationCode);
105 });
106
107 iFace->register_method(
108 "GetFRUsByUnexpandedLocationCode",
109 [this](const std::string& i_unexpandedLocationCode,
110 uint16_t& i_nodeNumber) -> types::ListOfPaths {
111 return this->getFrusByUnexpandedLocationCode(
112 i_unexpandedLocationCode, i_nodeNumber);
113 });
114
115 iFace->register_method(
116 "GetHardwarePath",
117 [this](const sdbusplus::message::object_path& i_dbusObjPath)
118 -> std::string { return this->getHwPath(i_dbusObjPath); });
119
120 iFace->register_method("PerformVPDRecollection", [this]() {
121 this->performVpdRecollection();
122 });
123
124 // Indicates FRU VPD collection for the system has not started.
125 iFace->register_property_rw<std::string>(
126 "CollectionStatus", sdbusplus::vtable::property_::emits_change,
127 [this](const std::string l_currStatus, const auto&) {
128 m_vpdCollectionStatus = l_currStatus;
129 return 0;
130 },
131 [this](const auto&) { return m_vpdCollectionStatus; });
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530132
133 // If required, instantiate OEM specific handler here.
134#ifdef IBM_SYSTEM
135 m_ibmHandler = std::make_shared<IbmHandler>(
136 m_worker, m_backupAndRestoreObj, m_interface, m_ioContext,
137 m_asioConnection);
138
139 // TODO: Move to respective handler class as this is OEM specific. To
140 // move this, collect single FRU VPD API needs to be modified. set
141 // callback to detect host state change.
142 registerHostStateChangeCallback();
143#else
144 m_worker = std::make_shared<Worker>(INVENTORY_JSON_DEFAULT);
145 m_interface->set_property("CollectionStatus", std::string("Completed"));
146#endif
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500147 }
148 catch (const std::exception& e)
149 {
150 logging::logMessage(
Sunny Srivastava4c509c22025-03-25 12:43:40 +0530151 "Manager class instantiation failed. " + std::string(e.what()));
152
153 vpd::EventLogger::createSyncPel(
154 vpd::EventLogger::getErrorType(e), vpd::types::SeverityType::Error,
155 __FILE__, __FUNCTION__, 0, vpd::EventLogger::getErrorMsg(e),
156 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500157 }
158}
159
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500160int Manager::updateKeyword(const types::Path i_vpdPath,
161 const types::WriteVpdParams i_paramsToWriteData)
162{
163 if (i_vpdPath.empty())
164 {
165 logging::logMessage("Given VPD path is empty.");
166 return -1;
167 }
168
169 types::Path l_fruPath;
170 nlohmann::json l_sysCfgJsonObj{};
171
172 if (m_worker.get() != nullptr)
173 {
174 l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
175
176 // Get the EEPROM path
177 if (!l_sysCfgJsonObj.empty())
178 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600179 l_fruPath =
180 jsonUtility::getFruPathFromJson(l_sysCfgJsonObj, i_vpdPath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500181 }
182 }
183
184 if (l_fruPath.empty())
185 {
186 l_fruPath = i_vpdPath;
187 }
188
189 try
190 {
191 std::shared_ptr<Parser> l_parserObj =
192 std::make_shared<Parser>(l_fruPath, l_sysCfgJsonObj);
Anupama B R8dedd1e2025-03-24 07:43:47 -0500193 auto l_rc = l_parserObj->updateVpdKeyword(i_paramsToWriteData);
194
195 if (l_rc != constants::FAILURE && m_backupAndRestoreObj)
196 {
197 if (m_backupAndRestoreObj->updateKeywordOnPrimaryOrBackupPath(
198 l_fruPath, i_paramsToWriteData) < constants::VALUE_0)
199 {
200 logging::logMessage(
201 "Write success, but backup and restore failed for file[" +
202 l_fruPath + "]");
203 }
204 }
205 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500206 }
207 catch (const std::exception& l_exception)
208 {
209 // TODO:: error log needed
210 logging::logMessage("Update keyword failed for file[" + i_vpdPath +
211 "], reason: " + std::string(l_exception.what()));
212 return -1;
213 }
214}
215
216int Manager::updateKeywordOnHardware(
217 const types::Path i_fruPath,
218 const types::WriteVpdParams i_paramsToWriteData) noexcept
219{
220 try
221 {
222 if (i_fruPath.empty())
223 {
224 throw std::runtime_error("Given FRU path is empty");
225 }
226
227 nlohmann::json l_sysCfgJsonObj{};
228
229 if (m_worker.get() != nullptr)
230 {
231 l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
232 }
233
234 std::shared_ptr<Parser> l_parserObj =
235 std::make_shared<Parser>(i_fruPath, l_sysCfgJsonObj);
236 return l_parserObj->updateVpdKeywordOnHardware(i_paramsToWriteData);
237 }
238 catch (const std::exception& l_exception)
239 {
240 EventLogger::createAsyncPel(
241 types::ErrorType::InvalidEeprom, types::SeverityType::Informational,
242 __FILE__, __FUNCTION__, 0,
243 "Update keyword on hardware failed for file[" + i_fruPath +
244 "], reason: " + std::string(l_exception.what()),
245 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
246
247 return constants::FAILURE;
248 }
249}
250
251types::DbusVariantType Manager::readKeyword(
252 const types::Path i_fruPath, const types::ReadVpdParams i_paramsToReadData)
253{
254 try
255 {
256 nlohmann::json l_jsonObj{};
257
258 if (m_worker.get() != nullptr)
259 {
260 l_jsonObj = m_worker->getSysCfgJsonObj();
261 }
262
263 std::error_code ec;
264
265 // Check if given path is filesystem path
266 if (!std::filesystem::exists(i_fruPath, ec) && (ec))
267 {
268 throw std::runtime_error(
269 "Given file path " + i_fruPath + " not found.");
270 }
271
272 logging::logMessage("Performing VPD read on " + i_fruPath);
273
274 std::shared_ptr<vpd::Parser> l_parserObj =
275 std::make_shared<vpd::Parser>(i_fruPath, l_jsonObj);
276
277 std::shared_ptr<vpd::ParserInterface> l_vpdParserInstance =
278 l_parserObj->getVpdParserInstance();
279
280 return (
281 l_vpdParserInstance->readKeywordFromHardware(i_paramsToReadData));
282 }
283 catch (const std::exception& e)
284 {
285 logging::logMessage(
286 e.what() + std::string(". VPD manager read operation failed for ") +
287 i_fruPath);
288 throw types::DeviceError::ReadFailure();
289 }
290}
291
292void Manager::collectSingleFruVpd(
293 const sdbusplus::message::object_path& i_dbusObjPath)
294{
295 try
296 {
297 if (m_vpdCollectionStatus != "Completed")
298 {
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600299 logging::logMessage(
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500300 "Currently VPD CollectionStatus is not completed. Cannot perform single FRU VPD collection for " +
301 std::string(i_dbusObjPath));
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600302 return;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500303 }
304
305 // Get system config JSON object from worker class
306 nlohmann::json l_sysCfgJsonObj{};
307
308 if (m_worker.get() != nullptr)
309 {
310 l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
311 }
312
313 // Check if system config JSON is present
314 if (l_sysCfgJsonObj.empty())
315 {
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600316 logging::logMessage(
317 "System config JSON object not present. Single FRU VPD collection is not performed for " +
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500318 std::string(i_dbusObjPath));
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600319 return;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500320 }
321
322 // Get FRU path for the given D-bus object path from JSON
323 const std::string& l_fruPath =
324 jsonUtility::getFruPathFromJson(l_sysCfgJsonObj, i_dbusObjPath);
325
326 if (l_fruPath.empty())
327 {
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600328 logging::logMessage(
329 "D-bus object path not present in JSON. Single FRU VPD collection is not performed for " +
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500330 std::string(i_dbusObjPath));
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600331 return;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500332 }
333
334 // Check if host is up and running
335 if (dbusUtility::isHostRunning())
336 {
337 if (!jsonUtility::isFruReplaceableAtRuntime(l_sysCfgJsonObj,
338 l_fruPath))
339 {
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600340 logging::logMessage(
341 "Given FRU is not replaceable at host runtime. Single FRU VPD collection is not performed for " +
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500342 std::string(i_dbusObjPath));
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600343 return;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500344 }
345 }
346 else if (dbusUtility::isBMCReady())
347 {
348 if (!jsonUtility::isFruReplaceableAtStandby(l_sysCfgJsonObj,
349 l_fruPath) &&
350 (!jsonUtility::isFruReplaceableAtRuntime(l_sysCfgJsonObj,
351 l_fruPath)))
352 {
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600353 logging::logMessage(
354 "Given FRU is neither replaceable at standby nor replaceable at runtime. Single FRU VPD collection is not performed for " +
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500355 std::string(i_dbusObjPath));
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600356 return;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500357 }
358 }
359
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600360 // Set CollectionStatus as InProgress. Since it's an intermediate state
361 // D-bus set-property call is good enough to update the status.
RekhaAparna01c532b182025-02-19 19:56:49 -0600362 const std::string& l_collStatusProp = "CollectionStatus";
363
364 if (!dbusUtility::writeDbusProperty(
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600365 jsonUtility::getServiceName(l_sysCfgJsonObj,
366 std::string(i_dbusObjPath)),
367 std::string(i_dbusObjPath), constants::vpdCollectionInterface,
368 l_collStatusProp,
RekhaAparna01c532b182025-02-19 19:56:49 -0600369 types::DbusVariantType{constants::vpdCollectionInProgress}))
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600370 {
371 logging::logMessage(
372 "Unable to set CollectionStatus as InProgress for " +
373 std::string(i_dbusObjPath) +
374 ". Continue single FRU VPD collection.");
375 }
376
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500377 // Parse VPD
378 types::VPDMapVariant l_parsedVpd = m_worker->parseVpdFile(l_fruPath);
379
380 // If l_parsedVpd is pointing to std::monostate
381 if (l_parsedVpd.index() == 0)
382 {
383 throw std::runtime_error(
384 "VPD parsing failed for " + std::string(i_dbusObjPath));
385 }
386
387 // Get D-bus object map from worker class
388 types::ObjectMap l_dbusObjectMap;
389 m_worker->populateDbus(l_parsedVpd, l_dbusObjectMap, l_fruPath);
390
391 if (l_dbusObjectMap.empty())
392 {
393 throw std::runtime_error(
394 "Failed to create D-bus object map. Single FRU VPD collection failed for " +
395 std::string(i_dbusObjPath));
396 }
397
398 // Call PIM's Notify method
399 if (!dbusUtility::callPIM(move(l_dbusObjectMap)))
400 {
401 throw std::runtime_error(
402 "Notify PIM failed. Single FRU VPD collection failed for " +
403 std::string(i_dbusObjPath));
404 }
405 }
406 catch (const std::exception& l_error)
407 {
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600408 // Notify FRU's VPD CollectionStatus as Failure
409 if (!dbusUtility::notifyFRUCollectionStatus(
410 std::string(i_dbusObjPath), constants::vpdCollectionFailure))
411 {
412 logging::logMessage(
413 "Call to PIM Notify method failed to update Collection status as Failure for " +
414 std::string(i_dbusObjPath));
415 }
416
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500417 // TODO: Log PEL
418 logging::logMessage(std::string(l_error.what()));
419 }
420}
421
422void Manager::deleteSingleFruVpd(
423 const sdbusplus::message::object_path& i_dbusObjPath)
424{
425 try
426 {
427 if (std::string(i_dbusObjPath).empty())
428 {
429 throw std::runtime_error(
430 "Given DBus object path is empty. Aborting FRU VPD deletion.");
431 }
432
433 if (m_worker.get() == nullptr)
434 {
435 throw std::runtime_error(
436 "Worker object not found, can't perform FRU VPD deletion for: " +
437 std::string(i_dbusObjPath));
438 }
439
440 m_worker->deleteFruVpd(std::string(i_dbusObjPath));
441 }
442 catch (const std::exception& l_ex)
443 {
444 // TODO: Log PEL
445 logging::logMessage(l_ex.what());
446 }
447}
448
449bool Manager::isValidUnexpandedLocationCode(
450 const std::string& i_unexpandedLocationCode)
451{
452 if ((i_unexpandedLocationCode.length() <
453 constants::UNEXP_LOCATION_CODE_MIN_LENGTH) ||
454 ((i_unexpandedLocationCode.compare(0, 4, "Ufcs") !=
455 constants::STR_CMP_SUCCESS) &&
456 (i_unexpandedLocationCode.compare(0, 4, "Umts") !=
457 constants::STR_CMP_SUCCESS)) ||
458 ((i_unexpandedLocationCode.length() >
459 constants::UNEXP_LOCATION_CODE_MIN_LENGTH) &&
460 (i_unexpandedLocationCode.find("-") != 4)))
461 {
462 return false;
463 }
464
465 return true;
466}
467
468std::string Manager::getExpandedLocationCode(
469 const std::string& i_unexpandedLocationCode,
470 [[maybe_unused]] const uint16_t i_nodeNumber)
471{
472 if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode))
473 {
474 phosphor::logging::elog<types::DbusInvalidArgument>(
475 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
476 types::InvalidArgument::ARGUMENT_VALUE(
477 i_unexpandedLocationCode.c_str()));
478 }
479
480 const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
481 if (!l_sysCfgJsonObj.contains("frus"))
482 {
483 logging::logMessage("Missing frus tag in system config JSON");
484 }
485
486 const nlohmann::json& l_listOfFrus =
487 l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
488
489 for (const auto& l_frus : l_listOfFrus.items())
490 {
491 for (const auto& l_aFru : l_frus.value())
492 {
493 if (l_aFru["extraInterfaces"].contains(
494 constants::locationCodeInf) &&
495 l_aFru["extraInterfaces"][constants::locationCodeInf].value(
496 "LocationCode", "") == i_unexpandedLocationCode)
497 {
498 return std::get<std::string>(dbusUtility::readDbusProperty(
499 l_aFru["serviceName"], l_aFru["inventoryPath"],
500 constants::locationCodeInf, "LocationCode"));
501 }
502 }
503 }
504 phosphor::logging::elog<types::DbusInvalidArgument>(
505 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
506 types::InvalidArgument::ARGUMENT_VALUE(
507 i_unexpandedLocationCode.c_str()));
508}
509
510types::ListOfPaths Manager::getFrusByUnexpandedLocationCode(
511 const std::string& i_unexpandedLocationCode,
512 [[maybe_unused]] const uint16_t i_nodeNumber)
513{
514 types::ListOfPaths l_inventoryPaths;
515
516 if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode))
517 {
518 phosphor::logging::elog<types::DbusInvalidArgument>(
519 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
520 types::InvalidArgument::ARGUMENT_VALUE(
521 i_unexpandedLocationCode.c_str()));
522 }
523
524 const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
525 if (!l_sysCfgJsonObj.contains("frus"))
526 {
527 logging::logMessage("Missing frus tag in system config JSON");
528 }
529
530 const nlohmann::json& l_listOfFrus =
531 l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
532
533 for (const auto& l_frus : l_listOfFrus.items())
534 {
535 for (const auto& l_aFru : l_frus.value())
536 {
537 if (l_aFru["extraInterfaces"].contains(
538 constants::locationCodeInf) &&
539 l_aFru["extraInterfaces"][constants::locationCodeInf].value(
540 "LocationCode", "") == i_unexpandedLocationCode)
541 {
542 l_inventoryPaths.push_back(
543 l_aFru.at("inventoryPath")
544 .get_ref<const nlohmann::json::string_t&>());
545 }
546 }
547 }
548
549 if (l_inventoryPaths.empty())
550 {
551 phosphor::logging::elog<types::DbusInvalidArgument>(
552 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
553 types::InvalidArgument::ARGUMENT_VALUE(
554 i_unexpandedLocationCode.c_str()));
555 }
556
557 return l_inventoryPaths;
558}
559
Patrick Williams43fedab2025-02-03 14:28:05 -0500560std::string Manager::getHwPath(
561 const sdbusplus::message::object_path& i_dbusObjPath)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500562{
563 // Dummy code to supress unused variable warning. To be removed.
564 logging::logMessage(std::string(i_dbusObjPath));
565
566 return std::string{};
567}
568
569std::tuple<std::string, uint16_t> Manager::getUnexpandedLocationCode(
570 const std::string& i_expandedLocationCode)
571{
572 /**
573 * Location code should always start with U and fulfil minimum length
574 * criteria.
575 */
576 if (i_expandedLocationCode[0] != 'U' ||
577 i_expandedLocationCode.length() <
578 constants::EXP_LOCATION_CODE_MIN_LENGTH)
579 {
580 phosphor::logging::elog<types::DbusInvalidArgument>(
581 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
582 types::InvalidArgument::ARGUMENT_VALUE(
583 i_expandedLocationCode.c_str()));
584 }
585
586 std::string l_fcKwd;
587
588 auto l_fcKwdValue = dbusUtility::readDbusProperty(
589 "xyz.openbmc_project.Inventory.Manager",
590 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
591 "com.ibm.ipzvpd.VCEN", "FC");
592
593 if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_fcKwdValue))
594 {
595 l_fcKwd.assign(l_kwdValue->begin(), l_kwdValue->end());
596 }
597
598 // Get the first part of expanded location code to check for FC or TM.
599 std::string l_firstKwd = i_expandedLocationCode.substr(1, 4);
600
601 std::string l_unexpandedLocationCode{};
602 uint16_t l_nodeNummber = constants::INVALID_NODE_NUMBER;
603
604 // Check if this value matches the value of FC keyword.
605 if (l_fcKwd.substr(0, 4) == l_firstKwd)
606 {
607 /**
608 * Period(.) should be there in expanded location code to seggregate
609 * FC, node number and SE values.
610 */
611 size_t l_nodeStartPos = i_expandedLocationCode.find('.');
612 if (l_nodeStartPos == std::string::npos)
613 {
614 phosphor::logging::elog<types::DbusInvalidArgument>(
615 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
616 types::InvalidArgument::ARGUMENT_VALUE(
617 i_expandedLocationCode.c_str()));
618 }
619
620 size_t l_nodeEndPos =
621 i_expandedLocationCode.find('.', l_nodeStartPos + 1);
622 if (l_nodeEndPos == std::string::npos)
623 {
624 phosphor::logging::elog<types::DbusInvalidArgument>(
625 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
626 types::InvalidArgument::ARGUMENT_VALUE(
627 i_expandedLocationCode.c_str()));
628 }
629
630 // Skip 3 bytes for '.ND'
631 l_nodeNummber = std::stoi(i_expandedLocationCode.substr(
632 l_nodeStartPos + 3, (l_nodeEndPos - l_nodeStartPos - 3)));
633
634 /**
635 * Confirm if there are other details apart FC, node number and SE
636 * in location code
637 */
638 if (i_expandedLocationCode.length() >
639 constants::EXP_LOCATION_CODE_MIN_LENGTH)
640 {
641 l_unexpandedLocationCode =
642 i_expandedLocationCode[0] + std::string("fcs") +
643 i_expandedLocationCode.substr(
644 l_nodeEndPos + 1 + constants::SE_KWD_LENGTH,
645 std::string::npos);
646 }
647 else
648 {
649 l_unexpandedLocationCode = "Ufcs";
650 }
651 }
652 else
653 {
654 std::string l_tmKwd;
655 // Read TM keyword value.
656 auto l_tmKwdValue = dbusUtility::readDbusProperty(
657 "xyz.openbmc_project.Inventory.Manager",
658 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
659 "com.ibm.ipzvpd.VSYS", "TM");
660
661 if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_tmKwdValue))
662 {
663 l_tmKwd.assign(l_kwdValue->begin(), l_kwdValue->end());
664 }
665
666 // Check if the substr matches to TM keyword value.
667 if (l_tmKwd.substr(0, 4) == l_firstKwd)
668 {
669 /**
670 * System location code will not have node number and any other
671 * details.
672 */
673 l_unexpandedLocationCode = "Umts";
674 }
675 // The given location code is neither "fcs" or "mts".
676 else
677 {
678 phosphor::logging::elog<types::DbusInvalidArgument>(
679 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
680 types::InvalidArgument::ARGUMENT_VALUE(
681 i_expandedLocationCode.c_str()));
682 }
683 }
684
685 return std::make_tuple(l_unexpandedLocationCode, l_nodeNummber);
686}
687
688types::ListOfPaths Manager::getFrusByExpandedLocationCode(
689 const std::string& i_expandedLocationCode)
690{
691 std::tuple<std::string, uint16_t> l_locationAndNodePair =
692 getUnexpandedLocationCode(i_expandedLocationCode);
693
694 return getFrusByUnexpandedLocationCode(std::get<0>(l_locationAndNodePair),
695 std::get<1>(l_locationAndNodePair));
696}
697
698void Manager::registerHostStateChangeCallback()
699{
700 static std::shared_ptr<sdbusplus::bus::match_t> l_hostState =
701 std::make_shared<sdbusplus::bus::match_t>(
702 *m_asioConnection,
703 sdbusplus::bus::match::rules::propertiesChanged(
704 constants::hostObjectPath, constants::hostInterface),
705 [this](sdbusplus::message_t& i_msg) {
706 hostStateChangeCallBack(i_msg);
707 });
708}
709
710void Manager::hostStateChangeCallBack(sdbusplus::message_t& i_msg)
711{
712 try
713 {
714 if (i_msg.is_method_error())
715 {
716 throw std::runtime_error(
717 "Error reading callback message for host state");
718 }
719
720 std::string l_objectPath;
721 types::PropertyMap l_propMap;
722 i_msg.read(l_objectPath, l_propMap);
723
724 const auto l_itr = l_propMap.find("CurrentHostState");
725
726 if (l_itr == l_propMap.end())
727 {
728 throw std::runtime_error(
729 "CurrentHostState field is missing in callback message");
730 }
731
732 if (auto l_hostState = std::get_if<std::string>(&(l_itr->second)))
733 {
734 // implies system is moving from standby to power on state
735 if (*l_hostState == "xyz.openbmc_project.State.Host.HostState."
736 "TransitioningToRunning")
737 {
738 // TODO: check for all the essential FRUs in the system.
739
740 // Perform recollection.
741 performVpdRecollection();
742 return;
743 }
744 }
745 else
746 {
747 throw std::runtime_error(
748 "Invalid type recieved in variant for host state.");
749 }
750 }
751 catch (const std::exception& l_ex)
752 {
753 // TODO: Log PEL.
754 logging::logMessage(l_ex.what());
755 }
756}
757
758void Manager::performVpdRecollection()
759{
760 try
761 {
762 if (m_worker.get() != nullptr)
763 {
764 nlohmann::json l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
765
766 // Check if system config JSON is present
767 if (l_sysCfgJsonObj.empty())
768 {
769 throw std::runtime_error(
770 "System config json object is empty, can't process recollection.");
771 }
772
773 const auto& l_frusReplaceableAtStandby =
774 jsonUtility::getListOfFrusReplaceableAtStandby(l_sysCfgJsonObj);
775
776 for (const auto& l_fruInventoryPath : l_frusReplaceableAtStandby)
777 {
778 // ToDo: Add some logic/trace to know the flow to
779 // collectSingleFruVpd has been directed via
780 // performVpdRecollection.
781 collectSingleFruVpd(l_fruInventoryPath);
782 }
783 return;
784 }
785
786 throw std::runtime_error(
787 "Worker object not found can't process recollection");
788 }
789 catch (const std::exception& l_ex)
790 {
791 // TODO Log PEL
792 logging::logMessage(
793 "VPD recollection failed with error: " + std::string(l_ex.what()));
794 }
795}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500796} // namespace vpd