blob: d7b512df52a41fda3060c25cbae06c5ef28b20d4 [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
175 types::Path l_fruPath;
176 nlohmann::json l_sysCfgJsonObj{};
177
178 if (m_worker.get() != nullptr)
179 {
180 l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
181
182 // Get the EEPROM path
183 if (!l_sysCfgJsonObj.empty())
184 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600185 l_fruPath =
186 jsonUtility::getFruPathFromJson(l_sysCfgJsonObj, i_vpdPath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500187 }
188 }
189
190 if (l_fruPath.empty())
191 {
192 l_fruPath = i_vpdPath;
193 }
194
195 try
196 {
197 std::shared_ptr<Parser> l_parserObj =
198 std::make_shared<Parser>(l_fruPath, l_sysCfgJsonObj);
Souvik Roy9b0b0fd2025-08-08 05:20:23 +0000199
200 types::DbusVariantType l_updatedValue;
201 auto l_rc =
202 l_parserObj->updateVpdKeyword(i_paramsToWriteData, l_updatedValue);
Anupama B R8dedd1e2025-03-24 07:43:47 -0500203
204 if (l_rc != constants::FAILURE && m_backupAndRestoreObj)
205 {
206 if (m_backupAndRestoreObj->updateKeywordOnPrimaryOrBackupPath(
207 l_fruPath, i_paramsToWriteData) < constants::VALUE_0)
208 {
209 logging::logMessage(
210 "Write success, but backup and restore failed for file[" +
211 l_fruPath + "]");
212 }
213 }
Souvik Roy2ee8a212025-04-24 02:37:59 -0500214
Souvik Roy9b0b0fd2025-08-08 05:20:23 +0000215 types::WriteVpdParams l_writeParams;
216 types::BinaryVector l_valueToUpdate;
217
218 if (const types::IpzData* l_ipzData =
219 std::get_if<types::IpzData>(&i_paramsToWriteData))
220 {
221 if (const types::BinaryVector* l_val =
222 std::get_if<types::BinaryVector>(&l_updatedValue))
223 {
224 l_valueToUpdate = *l_val;
225 }
226 else
227 {
228 l_valueToUpdate = std::get<2>(*l_ipzData);
229 }
230 l_writeParams =
231 std::make_tuple(std::get<0>(*l_ipzData),
232 std::get<1>(*l_ipzData), l_valueToUpdate);
233 }
234 else if (const types::KwData* l_kwData =
235 std::get_if<types::KwData>(&i_paramsToWriteData))
236 {
237 if (const types::BinaryVector* l_val =
238 std::get_if<types::BinaryVector>(&l_updatedValue))
239 {
240 l_valueToUpdate = *l_val;
241 }
242 else
243 {
244 l_valueToUpdate = std::get<1>(*l_kwData);
245 }
246
247 l_writeParams =
248 std::make_tuple(std::get<0>(*l_kwData), l_valueToUpdate);
249 }
250
Souvik Roy2ee8a212025-04-24 02:37:59 -0500251 // update keyword in inherited FRUs
252 if (l_rc != constants::FAILURE)
253 {
254 vpdSpecificUtility::updateKwdOnInheritedFrus(
Souvik Roy9b0b0fd2025-08-08 05:20:23 +0000255 l_fruPath, l_writeParams, l_sysCfgJsonObj);
Souvik Roy2ee8a212025-04-24 02:37:59 -0500256 }
257
Souvik Roy96ebe962025-04-29 04:01:07 -0500258 // update common interface(s) properties
259 if (l_rc != constants::FAILURE)
260 {
261 vpdSpecificUtility::updateCiPropertyOfInheritedFrus(
Souvik Roy9b0b0fd2025-08-08 05:20:23 +0000262 l_fruPath, l_writeParams, l_sysCfgJsonObj);
Souvik Roy96ebe962025-04-29 04:01:07 -0500263 }
264
Anupama B R8dedd1e2025-03-24 07:43:47 -0500265 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500266 }
267 catch (const std::exception& l_exception)
268 {
269 // TODO:: error log needed
270 logging::logMessage("Update keyword failed for file[" + i_vpdPath +
271 "], reason: " + std::string(l_exception.what()));
272 return -1;
273 }
274}
275
276int Manager::updateKeywordOnHardware(
277 const types::Path i_fruPath,
278 const types::WriteVpdParams i_paramsToWriteData) noexcept
279{
280 try
281 {
282 if (i_fruPath.empty())
283 {
284 throw std::runtime_error("Given FRU path is empty");
285 }
286
287 nlohmann::json l_sysCfgJsonObj{};
288
289 if (m_worker.get() != nullptr)
290 {
291 l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
292 }
293
294 std::shared_ptr<Parser> l_parserObj =
295 std::make_shared<Parser>(i_fruPath, l_sysCfgJsonObj);
296 return l_parserObj->updateVpdKeywordOnHardware(i_paramsToWriteData);
297 }
298 catch (const std::exception& l_exception)
299 {
300 EventLogger::createAsyncPel(
301 types::ErrorType::InvalidEeprom, types::SeverityType::Informational,
302 __FILE__, __FUNCTION__, 0,
303 "Update keyword on hardware failed for file[" + i_fruPath +
304 "], reason: " + std::string(l_exception.what()),
305 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
306
307 return constants::FAILURE;
308 }
309}
310
311types::DbusVariantType Manager::readKeyword(
312 const types::Path i_fruPath, const types::ReadVpdParams i_paramsToReadData)
313{
314 try
315 {
316 nlohmann::json l_jsonObj{};
317
318 if (m_worker.get() != nullptr)
319 {
320 l_jsonObj = m_worker->getSysCfgJsonObj();
321 }
322
323 std::error_code ec;
324
325 // Check if given path is filesystem path
326 if (!std::filesystem::exists(i_fruPath, ec) && (ec))
327 {
328 throw std::runtime_error(
329 "Given file path " + i_fruPath + " not found.");
330 }
331
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500332 std::shared_ptr<vpd::Parser> l_parserObj =
333 std::make_shared<vpd::Parser>(i_fruPath, l_jsonObj);
334
335 std::shared_ptr<vpd::ParserInterface> l_vpdParserInstance =
336 l_parserObj->getVpdParserInstance();
337
338 return (
339 l_vpdParserInstance->readKeywordFromHardware(i_paramsToReadData));
340 }
341 catch (const std::exception& e)
342 {
343 logging::logMessage(
344 e.what() + std::string(". VPD manager read operation failed for ") +
345 i_fruPath);
346 throw types::DeviceError::ReadFailure();
347 }
348}
349
350void Manager::collectSingleFruVpd(
351 const sdbusplus::message::object_path& i_dbusObjPath)
352{
Anupama B Rda9806b2025-08-29 02:41:10 -0500353 if (m_vpdCollectionStatus != constants::vpdCollectionCompleted)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500354 {
Sunny Srivastava380efbb2025-04-25 10:28:30 +0530355 logging::logMessage(
356 "Currently VPD CollectionStatus is not completed. Cannot perform single FRU VPD collection for " +
357 std::string(i_dbusObjPath));
358 return;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500359 }
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600360
Sunny Srivastava380efbb2025-04-25 10:28:30 +0530361 if (m_worker.get() != nullptr)
362 {
363 m_worker->collectSingleFruVpd(i_dbusObjPath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500364 }
365}
366
367void Manager::deleteSingleFruVpd(
368 const sdbusplus::message::object_path& i_dbusObjPath)
369{
370 try
371 {
372 if (std::string(i_dbusObjPath).empty())
373 {
374 throw std::runtime_error(
375 "Given DBus object path is empty. Aborting FRU VPD deletion.");
376 }
377
378 if (m_worker.get() == nullptr)
379 {
380 throw std::runtime_error(
381 "Worker object not found, can't perform FRU VPD deletion for: " +
382 std::string(i_dbusObjPath));
383 }
384
385 m_worker->deleteFruVpd(std::string(i_dbusObjPath));
386 }
387 catch (const std::exception& l_ex)
388 {
389 // TODO: Log PEL
390 logging::logMessage(l_ex.what());
391 }
392}
393
394bool Manager::isValidUnexpandedLocationCode(
395 const std::string& i_unexpandedLocationCode)
396{
397 if ((i_unexpandedLocationCode.length() <
398 constants::UNEXP_LOCATION_CODE_MIN_LENGTH) ||
399 ((i_unexpandedLocationCode.compare(0, 4, "Ufcs") !=
400 constants::STR_CMP_SUCCESS) &&
401 (i_unexpandedLocationCode.compare(0, 4, "Umts") !=
402 constants::STR_CMP_SUCCESS)) ||
403 ((i_unexpandedLocationCode.length() >
404 constants::UNEXP_LOCATION_CODE_MIN_LENGTH) &&
405 (i_unexpandedLocationCode.find("-") != 4)))
406 {
407 return false;
408 }
409
410 return true;
411}
412
413std::string Manager::getExpandedLocationCode(
414 const std::string& i_unexpandedLocationCode,
415 [[maybe_unused]] const uint16_t i_nodeNumber)
416{
417 if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode))
418 {
419 phosphor::logging::elog<types::DbusInvalidArgument>(
420 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
421 types::InvalidArgument::ARGUMENT_VALUE(
422 i_unexpandedLocationCode.c_str()));
423 }
424
425 const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
426 if (!l_sysCfgJsonObj.contains("frus"))
427 {
428 logging::logMessage("Missing frus tag in system config JSON");
429 }
430
431 const nlohmann::json& l_listOfFrus =
432 l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
433
434 for (const auto& l_frus : l_listOfFrus.items())
435 {
436 for (const auto& l_aFru : l_frus.value())
437 {
438 if (l_aFru["extraInterfaces"].contains(
439 constants::locationCodeInf) &&
440 l_aFru["extraInterfaces"][constants::locationCodeInf].value(
441 "LocationCode", "") == i_unexpandedLocationCode)
442 {
443 return std::get<std::string>(dbusUtility::readDbusProperty(
444 l_aFru["serviceName"], l_aFru["inventoryPath"],
445 constants::locationCodeInf, "LocationCode"));
446 }
447 }
448 }
449 phosphor::logging::elog<types::DbusInvalidArgument>(
450 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
451 types::InvalidArgument::ARGUMENT_VALUE(
452 i_unexpandedLocationCode.c_str()));
453}
454
455types::ListOfPaths Manager::getFrusByUnexpandedLocationCode(
456 const std::string& i_unexpandedLocationCode,
457 [[maybe_unused]] const uint16_t i_nodeNumber)
458{
459 types::ListOfPaths l_inventoryPaths;
460
461 if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode))
462 {
463 phosphor::logging::elog<types::DbusInvalidArgument>(
464 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
465 types::InvalidArgument::ARGUMENT_VALUE(
466 i_unexpandedLocationCode.c_str()));
467 }
468
469 const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
470 if (!l_sysCfgJsonObj.contains("frus"))
471 {
472 logging::logMessage("Missing frus tag in system config JSON");
473 }
474
475 const nlohmann::json& l_listOfFrus =
476 l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
477
478 for (const auto& l_frus : l_listOfFrus.items())
479 {
480 for (const auto& l_aFru : l_frus.value())
481 {
482 if (l_aFru["extraInterfaces"].contains(
483 constants::locationCodeInf) &&
484 l_aFru["extraInterfaces"][constants::locationCodeInf].value(
485 "LocationCode", "") == i_unexpandedLocationCode)
486 {
487 l_inventoryPaths.push_back(
488 l_aFru.at("inventoryPath")
489 .get_ref<const nlohmann::json::string_t&>());
490 }
491 }
492 }
493
494 if (l_inventoryPaths.empty())
495 {
496 phosphor::logging::elog<types::DbusInvalidArgument>(
497 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
498 types::InvalidArgument::ARGUMENT_VALUE(
499 i_unexpandedLocationCode.c_str()));
500 }
501
502 return l_inventoryPaths;
503}
504
Patrick Williams43fedab2025-02-03 14:28:05 -0500505std::string Manager::getHwPath(
506 const sdbusplus::message::object_path& i_dbusObjPath)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500507{
508 // Dummy code to supress unused variable warning. To be removed.
509 logging::logMessage(std::string(i_dbusObjPath));
510
511 return std::string{};
512}
513
514std::tuple<std::string, uint16_t> Manager::getUnexpandedLocationCode(
515 const std::string& i_expandedLocationCode)
516{
517 /**
518 * Location code should always start with U and fulfil minimum length
519 * criteria.
520 */
521 if (i_expandedLocationCode[0] != 'U' ||
522 i_expandedLocationCode.length() <
523 constants::EXP_LOCATION_CODE_MIN_LENGTH)
524 {
525 phosphor::logging::elog<types::DbusInvalidArgument>(
526 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
527 types::InvalidArgument::ARGUMENT_VALUE(
528 i_expandedLocationCode.c_str()));
529 }
530
531 std::string l_fcKwd;
532
533 auto l_fcKwdValue = dbusUtility::readDbusProperty(
534 "xyz.openbmc_project.Inventory.Manager",
535 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
536 "com.ibm.ipzvpd.VCEN", "FC");
537
538 if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_fcKwdValue))
539 {
540 l_fcKwd.assign(l_kwdValue->begin(), l_kwdValue->end());
541 }
542
543 // Get the first part of expanded location code to check for FC or TM.
544 std::string l_firstKwd = i_expandedLocationCode.substr(1, 4);
545
546 std::string l_unexpandedLocationCode{};
547 uint16_t l_nodeNummber = constants::INVALID_NODE_NUMBER;
548
549 // Check if this value matches the value of FC keyword.
550 if (l_fcKwd.substr(0, 4) == l_firstKwd)
551 {
552 /**
553 * Period(.) should be there in expanded location code to seggregate
554 * FC, node number and SE values.
555 */
556 size_t l_nodeStartPos = i_expandedLocationCode.find('.');
557 if (l_nodeStartPos == std::string::npos)
558 {
559 phosphor::logging::elog<types::DbusInvalidArgument>(
560 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
561 types::InvalidArgument::ARGUMENT_VALUE(
562 i_expandedLocationCode.c_str()));
563 }
564
565 size_t l_nodeEndPos =
566 i_expandedLocationCode.find('.', l_nodeStartPos + 1);
567 if (l_nodeEndPos == std::string::npos)
568 {
569 phosphor::logging::elog<types::DbusInvalidArgument>(
570 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
571 types::InvalidArgument::ARGUMENT_VALUE(
572 i_expandedLocationCode.c_str()));
573 }
574
575 // Skip 3 bytes for '.ND'
576 l_nodeNummber = std::stoi(i_expandedLocationCode.substr(
577 l_nodeStartPos + 3, (l_nodeEndPos - l_nodeStartPos - 3)));
578
579 /**
580 * Confirm if there are other details apart FC, node number and SE
581 * in location code
582 */
583 if (i_expandedLocationCode.length() >
584 constants::EXP_LOCATION_CODE_MIN_LENGTH)
585 {
586 l_unexpandedLocationCode =
587 i_expandedLocationCode[0] + std::string("fcs") +
588 i_expandedLocationCode.substr(
589 l_nodeEndPos + 1 + constants::SE_KWD_LENGTH,
590 std::string::npos);
591 }
592 else
593 {
594 l_unexpandedLocationCode = "Ufcs";
595 }
596 }
597 else
598 {
599 std::string l_tmKwd;
600 // Read TM keyword value.
601 auto l_tmKwdValue = dbusUtility::readDbusProperty(
602 "xyz.openbmc_project.Inventory.Manager",
603 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
604 "com.ibm.ipzvpd.VSYS", "TM");
605
606 if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_tmKwdValue))
607 {
608 l_tmKwd.assign(l_kwdValue->begin(), l_kwdValue->end());
609 }
610
611 // Check if the substr matches to TM keyword value.
612 if (l_tmKwd.substr(0, 4) == l_firstKwd)
613 {
614 /**
615 * System location code will not have node number and any other
616 * details.
617 */
618 l_unexpandedLocationCode = "Umts";
619 }
620 // The given location code is neither "fcs" or "mts".
621 else
622 {
623 phosphor::logging::elog<types::DbusInvalidArgument>(
624 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
625 types::InvalidArgument::ARGUMENT_VALUE(
626 i_expandedLocationCode.c_str()));
627 }
628 }
629
630 return std::make_tuple(l_unexpandedLocationCode, l_nodeNummber);
631}
632
633types::ListOfPaths Manager::getFrusByExpandedLocationCode(
634 const std::string& i_expandedLocationCode)
635{
636 std::tuple<std::string, uint16_t> l_locationAndNodePair =
637 getUnexpandedLocationCode(i_expandedLocationCode);
638
639 return getFrusByUnexpandedLocationCode(std::get<0>(l_locationAndNodePair),
640 std::get<1>(l_locationAndNodePair));
641}
642
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500643void Manager::performVpdRecollection()
644{
Sunny Srivastava380efbb2025-04-25 10:28:30 +0530645 if (m_worker.get() != nullptr)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500646 {
Sunny Srivastava380efbb2025-04-25 10:28:30 +0530647 m_worker->performVpdRecollection();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500648 }
649}
Anupama B R7127ab42025-06-26 01:39:08 -0500650
651bool Manager::collectAllFruVpd() const noexcept
652{
653 try
654 {
655 types::SeverityType l_severityType;
Anupama B Rda9806b2025-08-29 02:41:10 -0500656 if (m_vpdCollectionStatus == constants::vpdCollectionNotStarted)
Anupama B R7127ab42025-06-26 01:39:08 -0500657 {
658 l_severityType = types::SeverityType::Informational;
659 }
Anupama B Rda9806b2025-08-29 02:41:10 -0500660 else if (m_vpdCollectionStatus == constants::vpdCollectionCompleted ||
661 m_vpdCollectionStatus == constants::vpdCollectionFailed)
Anupama B R7127ab42025-06-26 01:39:08 -0500662 {
663 l_severityType = types::SeverityType::Warning;
664 }
665 else
666 {
667 throw std::runtime_error(
668 "Invalid collection status " + m_vpdCollectionStatus +
669 ". Aborting all FRUs VPD collection.");
670 }
671
672 EventLogger::createSyncPel(
673 types::ErrorType::FirmwareError, l_severityType, __FILE__,
674 __FUNCTION__, 0, "Collect all FRUs VPD is requested.", std::nullopt,
675 std::nullopt, std::nullopt, std::nullopt);
676
Anupama B Rb6787bf2025-07-16 01:36:53 -0500677// ToDo: Handle with OEM interface
678#ifdef IBM_SYSTEM
Anupama B R7127ab42025-06-26 01:39:08 -0500679 if (m_ibmHandler.get() != nullptr)
680 {
681 m_ibmHandler->collectAllFruVpd();
682 return true;
683 }
684 else
685 {
686 throw std::runtime_error(
687 "Not found any OEM handler to collect all FRUs VPD.");
688 }
Anupama B Rb6787bf2025-07-16 01:36:53 -0500689#endif
Anupama B R7127ab42025-06-26 01:39:08 -0500690 }
691 catch (const std::exception& l_ex)
692 {
693 EventLogger::createSyncPel(
694 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
695 __FILE__, __FUNCTION__, 0, std::string(l_ex.what()), std::nullopt,
696 std::nullopt, std::nullopt, std::nullopt);
697 }
698 return false;
699}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500700} // namespace vpd