blob: 27b1f63750660daade73506b2206462db7d21c18 [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,
Anupama B Rda9806b2025-08-29 02:41:10 -050026 const std::shared_ptr<sdbusplus::asio::dbus_interface>& progressiFace,
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050027 const std::shared_ptr<sdbusplus::asio::connection>& asioConnection) :
Anupama B Rda9806b2025-08-29 02:41:10 -050028 m_ioContext(ioCon), m_interface(iFace), m_progressInterface(progressiFace),
29 m_asioConnection(asioConnection)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050030{
Jinu Joy Thomas3419f5d2025-04-09 04:04:18 -050031#ifdef IBM_SYSTEM
Rekha Aparnaffdff312025-03-25 01:10:56 -050032 if (!dbusUtility::isChassisPowerOn())
33 {
34 SingleFab l_singleFab;
35 const int& l_rc = l_singleFab.singleFabImOverride();
36
37 if (l_rc == constants::FAILURE)
38 {
39 throw std::runtime_error(
40 std::string(__FUNCTION__) +
41 " : Found an invalid system configuration. Needs manual intervention. BMC is being quiesced.");
42 }
43 }
44#endif
45
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050046 try
47 {
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050048 // For backward compatibility. Should be depricated.
49 iFace->register_method(
50 "WriteKeyword",
51 [this](const sdbusplus::message::object_path i_path,
52 const std::string i_recordName, const std::string i_keyword,
53 const types::BinaryVector i_value) -> int {
54 return this->updateKeyword(
55 i_path, std::make_tuple(i_recordName, i_keyword, i_value));
56 });
57
58 // Register methods under com.ibm.VPD.Manager interface
59 iFace->register_method(
60 "UpdateKeyword",
61 [this](const types::Path i_vpdPath,
62 const types::WriteVpdParams i_paramsToWriteData) -> int {
63 return this->updateKeyword(i_vpdPath, i_paramsToWriteData);
64 });
65
66 iFace->register_method(
67 "WriteKeywordOnHardware",
68 [this](const types::Path i_fruPath,
69 const types::WriteVpdParams i_paramsToWriteData) -> int {
70 return this->updateKeywordOnHardware(i_fruPath,
71 i_paramsToWriteData);
72 });
73
74 iFace->register_method(
75 "ReadKeyword",
76 [this](const types::Path i_fruPath,
77 const types::ReadVpdParams i_paramsToReadData)
78 -> types::DbusVariantType {
79 return this->readKeyword(i_fruPath, i_paramsToReadData);
80 });
81
82 iFace->register_method(
83 "CollectFRUVPD",
84 [this](const sdbusplus::message::object_path& i_dbusObjPath) {
85 this->collectSingleFruVpd(i_dbusObjPath);
86 });
87
88 iFace->register_method(
89 "deleteFRUVPD",
90 [this](const sdbusplus::message::object_path& i_dbusObjPath) {
91 this->deleteSingleFruVpd(i_dbusObjPath);
92 });
93
94 iFace->register_method(
95 "GetExpandedLocationCode",
96 [this](const std::string& i_unexpandedLocationCode,
97 uint16_t& i_nodeNumber) -> std::string {
98 return this->getExpandedLocationCode(i_unexpandedLocationCode,
99 i_nodeNumber);
100 });
101
102 iFace->register_method("GetFRUsByExpandedLocationCode",
103 [this](const std::string& i_expandedLocationCode)
104 -> types::ListOfPaths {
105 return this->getFrusByExpandedLocationCode(
106 i_expandedLocationCode);
107 });
108
109 iFace->register_method(
110 "GetFRUsByUnexpandedLocationCode",
111 [this](const std::string& i_unexpandedLocationCode,
112 uint16_t& i_nodeNumber) -> types::ListOfPaths {
113 return this->getFrusByUnexpandedLocationCode(
114 i_unexpandedLocationCode, i_nodeNumber);
115 });
116
117 iFace->register_method(
118 "GetHardwarePath",
119 [this](const sdbusplus::message::object_path& i_dbusObjPath)
120 -> std::string { return this->getHwPath(i_dbusObjPath); });
121
122 iFace->register_method("PerformVPDRecollection", [this]() {
123 this->performVpdRecollection();
124 });
125
Anupama B R7127ab42025-06-26 01:39:08 -0500126 iFace->register_method("CollectAllFRUVPD", [this]() -> bool {
127 return this->collectAllFruVpd();
128 });
129
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500130 // Indicates FRU VPD collection for the system has not started.
Anupama B Rda9806b2025-08-29 02:41:10 -0500131 progressiFace->register_property_rw<std::string>(
132 "Status", sdbusplus::vtable::property_::emits_change,
Souvik Roya6832472025-05-22 13:18:12 -0500133 [this](const std::string& l_currStatus, const auto&) {
Souvik Roy251d85e2025-05-26 04:30:30 -0500134 if (m_vpdCollectionStatus != l_currStatus)
135 {
136 m_vpdCollectionStatus = l_currStatus;
Anupama B Rda9806b2025-08-29 02:41:10 -0500137 m_interface->signal_property("Status");
Souvik Roy251d85e2025-05-26 04:30:30 -0500138 }
Souvik Roya6832472025-05-22 13:18:12 -0500139 return true;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500140 },
141 [this](const auto&) { return m_vpdCollectionStatus; });
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530142
143 // If required, instantiate OEM specific handler here.
144#ifdef IBM_SYSTEM
145 m_ibmHandler = std::make_shared<IbmHandler>(
Anupama B Rda9806b2025-08-29 02:41:10 -0500146 m_worker, m_backupAndRestoreObj, m_interface, m_progressInterface,
147 m_ioContext, m_asioConnection);
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530148#else
149 m_worker = std::make_shared<Worker>(INVENTORY_JSON_DEFAULT);
Anupama B Rda9806b2025-08-29 02:41:10 -0500150 m_progressInterface->set_property(
151 "Status", std::string(constants::vpdCollectionCompleted));
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530152#endif
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500153 }
154 catch (const std::exception& e)
155 {
156 logging::logMessage(
Sunny Srivastava4c509c22025-03-25 12:43:40 +0530157 "Manager class instantiation failed. " + std::string(e.what()));
158
159 vpd::EventLogger::createSyncPel(
160 vpd::EventLogger::getErrorType(e), vpd::types::SeverityType::Error,
161 __FILE__, __FUNCTION__, 0, vpd::EventLogger::getErrorMsg(e),
162 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500163 }
164}
165
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500166int Manager::updateKeyword(const types::Path i_vpdPath,
167 const types::WriteVpdParams i_paramsToWriteData)
168{
169 if (i_vpdPath.empty())
170 {
171 logging::logMessage("Given VPD path is empty.");
172 return -1;
173 }
174
Rekha Aparna0578dd22025-09-02 08:20:21 -0500175 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500176 types::Path l_fruPath;
177 nlohmann::json l_sysCfgJsonObj{};
178
179 if (m_worker.get() != nullptr)
180 {
181 l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
182
183 // Get the EEPROM path
184 if (!l_sysCfgJsonObj.empty())
185 {
Rekha Aparna0578dd22025-09-02 08:20:21 -0500186 l_fruPath = jsonUtility::getFruPathFromJson(l_sysCfgJsonObj,
187 i_vpdPath, l_errCode);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500188 }
189 }
190
191 if (l_fruPath.empty())
192 {
Rekha Aparna0578dd22025-09-02 08:20:21 -0500193 if (l_errCode)
194 {
195 logging::logMessage(
196 "Failed to get FRU path from JSON for [" + i_vpdPath +
197 "], error : " + vpdSpecificUtility::getErrCodeMsg(l_errCode));
198 }
199
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500200 l_fruPath = i_vpdPath;
201 }
202
203 try
204 {
205 std::shared_ptr<Parser> l_parserObj =
206 std::make_shared<Parser>(l_fruPath, l_sysCfgJsonObj);
Souvik Roy9b0b0fd2025-08-08 05:20:23 +0000207
208 types::DbusVariantType l_updatedValue;
209 auto l_rc =
210 l_parserObj->updateVpdKeyword(i_paramsToWriteData, l_updatedValue);
Anupama B R8dedd1e2025-03-24 07:43:47 -0500211
212 if (l_rc != constants::FAILURE && m_backupAndRestoreObj)
213 {
214 if (m_backupAndRestoreObj->updateKeywordOnPrimaryOrBackupPath(
215 l_fruPath, i_paramsToWriteData) < constants::VALUE_0)
216 {
217 logging::logMessage(
218 "Write success, but backup and restore failed for file[" +
219 l_fruPath + "]");
220 }
221 }
Souvik Roy2ee8a212025-04-24 02:37:59 -0500222
Souvik Roy9b0b0fd2025-08-08 05:20:23 +0000223 types::WriteVpdParams l_writeParams;
224 types::BinaryVector l_valueToUpdate;
225
226 if (const types::IpzData* l_ipzData =
227 std::get_if<types::IpzData>(&i_paramsToWriteData))
228 {
229 if (const types::BinaryVector* l_val =
230 std::get_if<types::BinaryVector>(&l_updatedValue))
231 {
232 l_valueToUpdate = *l_val;
233 }
234 else
235 {
236 l_valueToUpdate = std::get<2>(*l_ipzData);
237 }
238 l_writeParams =
239 std::make_tuple(std::get<0>(*l_ipzData),
240 std::get<1>(*l_ipzData), l_valueToUpdate);
241 }
242 else if (const types::KwData* l_kwData =
243 std::get_if<types::KwData>(&i_paramsToWriteData))
244 {
245 if (const types::BinaryVector* l_val =
246 std::get_if<types::BinaryVector>(&l_updatedValue))
247 {
248 l_valueToUpdate = *l_val;
249 }
250 else
251 {
252 l_valueToUpdate = std::get<1>(*l_kwData);
253 }
254
255 l_writeParams =
256 std::make_tuple(std::get<0>(*l_kwData), l_valueToUpdate);
257 }
258
Souvik Roy2ee8a212025-04-24 02:37:59 -0500259 // update keyword in inherited FRUs
260 if (l_rc != constants::FAILURE)
261 {
262 vpdSpecificUtility::updateKwdOnInheritedFrus(
Souvik Roy9b0b0fd2025-08-08 05:20:23 +0000263 l_fruPath, l_writeParams, l_sysCfgJsonObj);
Souvik Roy2ee8a212025-04-24 02:37:59 -0500264 }
265
Souvik Roy96ebe962025-04-29 04:01:07 -0500266 // update common interface(s) properties
267 if (l_rc != constants::FAILURE)
268 {
269 vpdSpecificUtility::updateCiPropertyOfInheritedFrus(
Souvik Roy9b0b0fd2025-08-08 05:20:23 +0000270 l_fruPath, l_writeParams, l_sysCfgJsonObj);
Souvik Roy96ebe962025-04-29 04:01:07 -0500271 }
272
Anupama B R8dedd1e2025-03-24 07:43:47 -0500273 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500274 }
275 catch (const std::exception& l_exception)
276 {
277 // TODO:: error log needed
278 logging::logMessage("Update keyword failed for file[" + i_vpdPath +
279 "], reason: " + std::string(l_exception.what()));
280 return -1;
281 }
282}
283
284int Manager::updateKeywordOnHardware(
285 const types::Path i_fruPath,
286 const types::WriteVpdParams i_paramsToWriteData) noexcept
287{
288 try
289 {
290 if (i_fruPath.empty())
291 {
292 throw std::runtime_error("Given FRU path is empty");
293 }
294
295 nlohmann::json l_sysCfgJsonObj{};
296
297 if (m_worker.get() != nullptr)
298 {
299 l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
300 }
301
302 std::shared_ptr<Parser> l_parserObj =
303 std::make_shared<Parser>(i_fruPath, l_sysCfgJsonObj);
304 return l_parserObj->updateVpdKeywordOnHardware(i_paramsToWriteData);
305 }
306 catch (const std::exception& l_exception)
307 {
308 EventLogger::createAsyncPel(
309 types::ErrorType::InvalidEeprom, types::SeverityType::Informational,
310 __FILE__, __FUNCTION__, 0,
311 "Update keyword on hardware failed for file[" + i_fruPath +
312 "], reason: " + std::string(l_exception.what()),
313 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
314
315 return constants::FAILURE;
316 }
317}
318
319types::DbusVariantType Manager::readKeyword(
320 const types::Path i_fruPath, const types::ReadVpdParams i_paramsToReadData)
321{
322 try
323 {
324 nlohmann::json l_jsonObj{};
325
326 if (m_worker.get() != nullptr)
327 {
328 l_jsonObj = m_worker->getSysCfgJsonObj();
329 }
330
331 std::error_code ec;
332
333 // Check if given path is filesystem path
334 if (!std::filesystem::exists(i_fruPath, ec) && (ec))
335 {
336 throw std::runtime_error(
337 "Given file path " + i_fruPath + " not found.");
338 }
339
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500340 std::shared_ptr<vpd::Parser> l_parserObj =
341 std::make_shared<vpd::Parser>(i_fruPath, l_jsonObj);
342
343 std::shared_ptr<vpd::ParserInterface> l_vpdParserInstance =
344 l_parserObj->getVpdParserInstance();
345
346 return (
347 l_vpdParserInstance->readKeywordFromHardware(i_paramsToReadData));
348 }
349 catch (const std::exception& e)
350 {
351 logging::logMessage(
352 e.what() + std::string(". VPD manager read operation failed for ") +
353 i_fruPath);
354 throw types::DeviceError::ReadFailure();
355 }
356}
357
358void Manager::collectSingleFruVpd(
359 const sdbusplus::message::object_path& i_dbusObjPath)
360{
Anupama B Rda9806b2025-08-29 02:41:10 -0500361 if (m_vpdCollectionStatus != constants::vpdCollectionCompleted)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500362 {
Sunny Srivastava380efbb2025-04-25 10:28:30 +0530363 logging::logMessage(
364 "Currently VPD CollectionStatus is not completed. Cannot perform single FRU VPD collection for " +
365 std::string(i_dbusObjPath));
366 return;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500367 }
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600368
Sunny Srivastava380efbb2025-04-25 10:28:30 +0530369 if (m_worker.get() != nullptr)
370 {
371 m_worker->collectSingleFruVpd(i_dbusObjPath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500372 }
373}
374
375void Manager::deleteSingleFruVpd(
376 const sdbusplus::message::object_path& i_dbusObjPath)
377{
378 try
379 {
380 if (std::string(i_dbusObjPath).empty())
381 {
382 throw std::runtime_error(
383 "Given DBus object path is empty. Aborting FRU VPD deletion.");
384 }
385
386 if (m_worker.get() == nullptr)
387 {
388 throw std::runtime_error(
389 "Worker object not found, can't perform FRU VPD deletion for: " +
390 std::string(i_dbusObjPath));
391 }
392
393 m_worker->deleteFruVpd(std::string(i_dbusObjPath));
394 }
395 catch (const std::exception& l_ex)
396 {
397 // TODO: Log PEL
398 logging::logMessage(l_ex.what());
399 }
400}
401
402bool Manager::isValidUnexpandedLocationCode(
403 const std::string& i_unexpandedLocationCode)
404{
405 if ((i_unexpandedLocationCode.length() <
406 constants::UNEXP_LOCATION_CODE_MIN_LENGTH) ||
407 ((i_unexpandedLocationCode.compare(0, 4, "Ufcs") !=
408 constants::STR_CMP_SUCCESS) &&
409 (i_unexpandedLocationCode.compare(0, 4, "Umts") !=
410 constants::STR_CMP_SUCCESS)) ||
411 ((i_unexpandedLocationCode.length() >
412 constants::UNEXP_LOCATION_CODE_MIN_LENGTH) &&
413 (i_unexpandedLocationCode.find("-") != 4)))
414 {
415 return false;
416 }
417
418 return true;
419}
420
421std::string Manager::getExpandedLocationCode(
422 const std::string& i_unexpandedLocationCode,
423 [[maybe_unused]] const uint16_t i_nodeNumber)
424{
425 if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode))
426 {
427 phosphor::logging::elog<types::DbusInvalidArgument>(
428 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
429 types::InvalidArgument::ARGUMENT_VALUE(
430 i_unexpandedLocationCode.c_str()));
431 }
432
433 const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
434 if (!l_sysCfgJsonObj.contains("frus"))
435 {
436 logging::logMessage("Missing frus tag in system config JSON");
437 }
438
439 const nlohmann::json& l_listOfFrus =
440 l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
441
442 for (const auto& l_frus : l_listOfFrus.items())
443 {
444 for (const auto& l_aFru : l_frus.value())
445 {
446 if (l_aFru["extraInterfaces"].contains(
447 constants::locationCodeInf) &&
448 l_aFru["extraInterfaces"][constants::locationCodeInf].value(
449 "LocationCode", "") == i_unexpandedLocationCode)
450 {
451 return std::get<std::string>(dbusUtility::readDbusProperty(
452 l_aFru["serviceName"], l_aFru["inventoryPath"],
453 constants::locationCodeInf, "LocationCode"));
454 }
455 }
456 }
457 phosphor::logging::elog<types::DbusInvalidArgument>(
458 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
459 types::InvalidArgument::ARGUMENT_VALUE(
460 i_unexpandedLocationCode.c_str()));
461}
462
463types::ListOfPaths Manager::getFrusByUnexpandedLocationCode(
464 const std::string& i_unexpandedLocationCode,
465 [[maybe_unused]] const uint16_t i_nodeNumber)
466{
467 types::ListOfPaths l_inventoryPaths;
468
469 if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode))
470 {
471 phosphor::logging::elog<types::DbusInvalidArgument>(
472 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
473 types::InvalidArgument::ARGUMENT_VALUE(
474 i_unexpandedLocationCode.c_str()));
475 }
476
477 const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
478 if (!l_sysCfgJsonObj.contains("frus"))
479 {
480 logging::logMessage("Missing frus tag in system config JSON");
481 }
482
483 const nlohmann::json& l_listOfFrus =
484 l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
485
486 for (const auto& l_frus : l_listOfFrus.items())
487 {
488 for (const auto& l_aFru : l_frus.value())
489 {
490 if (l_aFru["extraInterfaces"].contains(
491 constants::locationCodeInf) &&
492 l_aFru["extraInterfaces"][constants::locationCodeInf].value(
493 "LocationCode", "") == i_unexpandedLocationCode)
494 {
495 l_inventoryPaths.push_back(
496 l_aFru.at("inventoryPath")
497 .get_ref<const nlohmann::json::string_t&>());
498 }
499 }
500 }
501
502 if (l_inventoryPaths.empty())
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
510 return l_inventoryPaths;
511}
512
Patrick Williams43fedab2025-02-03 14:28:05 -0500513std::string Manager::getHwPath(
514 const sdbusplus::message::object_path& i_dbusObjPath)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500515{
516 // Dummy code to supress unused variable warning. To be removed.
517 logging::logMessage(std::string(i_dbusObjPath));
518
519 return std::string{};
520}
521
522std::tuple<std::string, uint16_t> Manager::getUnexpandedLocationCode(
523 const std::string& i_expandedLocationCode)
524{
525 /**
526 * Location code should always start with U and fulfil minimum length
527 * criteria.
528 */
529 if (i_expandedLocationCode[0] != 'U' ||
530 i_expandedLocationCode.length() <
531 constants::EXP_LOCATION_CODE_MIN_LENGTH)
532 {
533 phosphor::logging::elog<types::DbusInvalidArgument>(
534 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
535 types::InvalidArgument::ARGUMENT_VALUE(
536 i_expandedLocationCode.c_str()));
537 }
538
539 std::string l_fcKwd;
540
541 auto l_fcKwdValue = dbusUtility::readDbusProperty(
542 "xyz.openbmc_project.Inventory.Manager",
543 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
544 "com.ibm.ipzvpd.VCEN", "FC");
545
546 if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_fcKwdValue))
547 {
548 l_fcKwd.assign(l_kwdValue->begin(), l_kwdValue->end());
549 }
550
551 // Get the first part of expanded location code to check for FC or TM.
552 std::string l_firstKwd = i_expandedLocationCode.substr(1, 4);
553
554 std::string l_unexpandedLocationCode{};
555 uint16_t l_nodeNummber = constants::INVALID_NODE_NUMBER;
556
557 // Check if this value matches the value of FC keyword.
558 if (l_fcKwd.substr(0, 4) == l_firstKwd)
559 {
560 /**
561 * Period(.) should be there in expanded location code to seggregate
562 * FC, node number and SE values.
563 */
564 size_t l_nodeStartPos = i_expandedLocationCode.find('.');
565 if (l_nodeStartPos == std::string::npos)
566 {
567 phosphor::logging::elog<types::DbusInvalidArgument>(
568 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
569 types::InvalidArgument::ARGUMENT_VALUE(
570 i_expandedLocationCode.c_str()));
571 }
572
573 size_t l_nodeEndPos =
574 i_expandedLocationCode.find('.', l_nodeStartPos + 1);
575 if (l_nodeEndPos == std::string::npos)
576 {
577 phosphor::logging::elog<types::DbusInvalidArgument>(
578 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
579 types::InvalidArgument::ARGUMENT_VALUE(
580 i_expandedLocationCode.c_str()));
581 }
582
583 // Skip 3 bytes for '.ND'
584 l_nodeNummber = std::stoi(i_expandedLocationCode.substr(
585 l_nodeStartPos + 3, (l_nodeEndPos - l_nodeStartPos - 3)));
586
587 /**
588 * Confirm if there are other details apart FC, node number and SE
589 * in location code
590 */
591 if (i_expandedLocationCode.length() >
592 constants::EXP_LOCATION_CODE_MIN_LENGTH)
593 {
594 l_unexpandedLocationCode =
595 i_expandedLocationCode[0] + std::string("fcs") +
596 i_expandedLocationCode.substr(
597 l_nodeEndPos + 1 + constants::SE_KWD_LENGTH,
598 std::string::npos);
599 }
600 else
601 {
602 l_unexpandedLocationCode = "Ufcs";
603 }
604 }
605 else
606 {
607 std::string l_tmKwd;
608 // Read TM keyword value.
609 auto l_tmKwdValue = dbusUtility::readDbusProperty(
610 "xyz.openbmc_project.Inventory.Manager",
611 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
612 "com.ibm.ipzvpd.VSYS", "TM");
613
614 if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_tmKwdValue))
615 {
616 l_tmKwd.assign(l_kwdValue->begin(), l_kwdValue->end());
617 }
618
619 // Check if the substr matches to TM keyword value.
620 if (l_tmKwd.substr(0, 4) == l_firstKwd)
621 {
622 /**
623 * System location code will not have node number and any other
624 * details.
625 */
626 l_unexpandedLocationCode = "Umts";
627 }
628 // The given location code is neither "fcs" or "mts".
629 else
630 {
631 phosphor::logging::elog<types::DbusInvalidArgument>(
632 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
633 types::InvalidArgument::ARGUMENT_VALUE(
634 i_expandedLocationCode.c_str()));
635 }
636 }
637
638 return std::make_tuple(l_unexpandedLocationCode, l_nodeNummber);
639}
640
641types::ListOfPaths Manager::getFrusByExpandedLocationCode(
642 const std::string& i_expandedLocationCode)
643{
644 std::tuple<std::string, uint16_t> l_locationAndNodePair =
645 getUnexpandedLocationCode(i_expandedLocationCode);
646
647 return getFrusByUnexpandedLocationCode(std::get<0>(l_locationAndNodePair),
648 std::get<1>(l_locationAndNodePair));
649}
650
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500651void Manager::performVpdRecollection()
652{
Sunny Srivastava380efbb2025-04-25 10:28:30 +0530653 if (m_worker.get() != nullptr)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500654 {
Sunny Srivastava380efbb2025-04-25 10:28:30 +0530655 m_worker->performVpdRecollection();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500656 }
657}
Anupama B R7127ab42025-06-26 01:39:08 -0500658
659bool Manager::collectAllFruVpd() const noexcept
660{
661 try
662 {
663 types::SeverityType l_severityType;
Anupama B Rda9806b2025-08-29 02:41:10 -0500664 if (m_vpdCollectionStatus == constants::vpdCollectionNotStarted)
Anupama B R7127ab42025-06-26 01:39:08 -0500665 {
666 l_severityType = types::SeverityType::Informational;
667 }
Anupama B Rda9806b2025-08-29 02:41:10 -0500668 else if (m_vpdCollectionStatus == constants::vpdCollectionCompleted ||
669 m_vpdCollectionStatus == constants::vpdCollectionFailed)
Anupama B R7127ab42025-06-26 01:39:08 -0500670 {
671 l_severityType = types::SeverityType::Warning;
672 }
673 else
674 {
675 throw std::runtime_error(
676 "Invalid collection status " + m_vpdCollectionStatus +
677 ". Aborting all FRUs VPD collection.");
678 }
679
680 EventLogger::createSyncPel(
681 types::ErrorType::FirmwareError, l_severityType, __FILE__,
682 __FUNCTION__, 0, "Collect all FRUs VPD is requested.", std::nullopt,
683 std::nullopt, std::nullopt, std::nullopt);
684
Anupama B Rb6787bf2025-07-16 01:36:53 -0500685// ToDo: Handle with OEM interface
686#ifdef IBM_SYSTEM
Anupama B R7127ab42025-06-26 01:39:08 -0500687 if (m_ibmHandler.get() != nullptr)
688 {
689 m_ibmHandler->collectAllFruVpd();
690 return true;
691 }
692 else
693 {
694 throw std::runtime_error(
695 "Not found any OEM handler to collect all FRUs VPD.");
696 }
Anupama B Rb6787bf2025-07-16 01:36:53 -0500697#endif
Anupama B R7127ab42025-06-26 01:39:08 -0500698 }
699 catch (const std::exception& l_ex)
700 {
701 EventLogger::createSyncPel(
702 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
703 __FILE__, __FUNCTION__, 0, std::string(l_ex.what()), std::nullopt,
704 std::nullopt, std::nullopt, std::nullopt);
705 }
706 return false;
707}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500708} // namespace vpd