blob: ca774915f9f3451e4ec2b5fd1fcff58f4ad8a060 [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 +
Rekha Aparnac6159a22025-10-09 12:20:20 +0530197 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna0578dd22025-09-02 08:20:21 -0500198 }
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
Souvik Royd7c7cb52025-07-30 06:31:02 +0000273 // log VPD write success or failure
274 auto l_logger = Logger::getLoggerInstance();
275
276 uint16_t l_errorCode;
277 l_logger->logMessage(
278 "VPD write " +
279 std::string(
280 (l_rc != constants::FAILURE) ? "successful" : "failed") +
281 " on path[" + i_vpdPath + "] : " +
282 vpdSpecificUtility::convertWriteVpdParamsToString(l_writeParams,
283 l_errorCode),
284 PlaceHolder::VPD_WRITE);
285
Anupama B R8dedd1e2025-03-24 07:43:47 -0500286 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500287 }
288 catch (const std::exception& l_exception)
289 {
290 // TODO:: error log needed
291 logging::logMessage("Update keyword failed for file[" + i_vpdPath +
292 "], reason: " + std::string(l_exception.what()));
293 return -1;
294 }
295}
296
297int Manager::updateKeywordOnHardware(
298 const types::Path i_fruPath,
299 const types::WriteVpdParams i_paramsToWriteData) noexcept
300{
301 try
302 {
303 if (i_fruPath.empty())
304 {
305 throw std::runtime_error("Given FRU path is empty");
306 }
307
308 nlohmann::json l_sysCfgJsonObj{};
309
310 if (m_worker.get() != nullptr)
311 {
312 l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
313 }
314
315 std::shared_ptr<Parser> l_parserObj =
316 std::make_shared<Parser>(i_fruPath, l_sysCfgJsonObj);
317 return l_parserObj->updateVpdKeywordOnHardware(i_paramsToWriteData);
318 }
319 catch (const std::exception& l_exception)
320 {
321 EventLogger::createAsyncPel(
322 types::ErrorType::InvalidEeprom, types::SeverityType::Informational,
323 __FILE__, __FUNCTION__, 0,
324 "Update keyword on hardware failed for file[" + i_fruPath +
325 "], reason: " + std::string(l_exception.what()),
326 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
327
328 return constants::FAILURE;
329 }
330}
331
332types::DbusVariantType Manager::readKeyword(
333 const types::Path i_fruPath, const types::ReadVpdParams i_paramsToReadData)
334{
335 try
336 {
337 nlohmann::json l_jsonObj{};
338
339 if (m_worker.get() != nullptr)
340 {
341 l_jsonObj = m_worker->getSysCfgJsonObj();
342 }
343
344 std::error_code ec;
345
346 // Check if given path is filesystem path
347 if (!std::filesystem::exists(i_fruPath, ec) && (ec))
348 {
349 throw std::runtime_error(
350 "Given file path " + i_fruPath + " not found.");
351 }
352
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500353 std::shared_ptr<vpd::Parser> l_parserObj =
354 std::make_shared<vpd::Parser>(i_fruPath, l_jsonObj);
355
356 std::shared_ptr<vpd::ParserInterface> l_vpdParserInstance =
357 l_parserObj->getVpdParserInstance();
358
359 return (
360 l_vpdParserInstance->readKeywordFromHardware(i_paramsToReadData));
361 }
362 catch (const std::exception& e)
363 {
364 logging::logMessage(
365 e.what() + std::string(". VPD manager read operation failed for ") +
366 i_fruPath);
367 throw types::DeviceError::ReadFailure();
368 }
369}
370
371void Manager::collectSingleFruVpd(
372 const sdbusplus::message::object_path& i_dbusObjPath)
373{
Anupama B Rda9806b2025-08-29 02:41:10 -0500374 if (m_vpdCollectionStatus != constants::vpdCollectionCompleted)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500375 {
Sunny Srivastava380efbb2025-04-25 10:28:30 +0530376 logging::logMessage(
377 "Currently VPD CollectionStatus is not completed. Cannot perform single FRU VPD collection for " +
378 std::string(i_dbusObjPath));
379 return;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500380 }
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600381
Sunny Srivastava380efbb2025-04-25 10:28:30 +0530382 if (m_worker.get() != nullptr)
383 {
384 m_worker->collectSingleFruVpd(i_dbusObjPath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500385 }
386}
387
388void Manager::deleteSingleFruVpd(
389 const sdbusplus::message::object_path& i_dbusObjPath)
390{
391 try
392 {
393 if (std::string(i_dbusObjPath).empty())
394 {
395 throw std::runtime_error(
396 "Given DBus object path is empty. Aborting FRU VPD deletion.");
397 }
398
399 if (m_worker.get() == nullptr)
400 {
401 throw std::runtime_error(
402 "Worker object not found, can't perform FRU VPD deletion for: " +
403 std::string(i_dbusObjPath));
404 }
405
406 m_worker->deleteFruVpd(std::string(i_dbusObjPath));
407 }
408 catch (const std::exception& l_ex)
409 {
410 // TODO: Log PEL
411 logging::logMessage(l_ex.what());
412 }
413}
414
415bool Manager::isValidUnexpandedLocationCode(
416 const std::string& i_unexpandedLocationCode)
417{
418 if ((i_unexpandedLocationCode.length() <
419 constants::UNEXP_LOCATION_CODE_MIN_LENGTH) ||
420 ((i_unexpandedLocationCode.compare(0, 4, "Ufcs") !=
421 constants::STR_CMP_SUCCESS) &&
422 (i_unexpandedLocationCode.compare(0, 4, "Umts") !=
423 constants::STR_CMP_SUCCESS)) ||
424 ((i_unexpandedLocationCode.length() >
425 constants::UNEXP_LOCATION_CODE_MIN_LENGTH) &&
426 (i_unexpandedLocationCode.find("-") != 4)))
427 {
428 return false;
429 }
430
431 return true;
432}
433
434std::string Manager::getExpandedLocationCode(
435 const std::string& i_unexpandedLocationCode,
436 [[maybe_unused]] const uint16_t i_nodeNumber)
437{
438 if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode))
439 {
440 phosphor::logging::elog<types::DbusInvalidArgument>(
441 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
442 types::InvalidArgument::ARGUMENT_VALUE(
443 i_unexpandedLocationCode.c_str()));
444 }
445
446 const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
447 if (!l_sysCfgJsonObj.contains("frus"))
448 {
449 logging::logMessage("Missing frus tag in system config JSON");
450 }
451
452 const nlohmann::json& l_listOfFrus =
453 l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
454
455 for (const auto& l_frus : l_listOfFrus.items())
456 {
457 for (const auto& l_aFru : l_frus.value())
458 {
459 if (l_aFru["extraInterfaces"].contains(
460 constants::locationCodeInf) &&
461 l_aFru["extraInterfaces"][constants::locationCodeInf].value(
462 "LocationCode", "") == i_unexpandedLocationCode)
463 {
464 return std::get<std::string>(dbusUtility::readDbusProperty(
465 l_aFru["serviceName"], l_aFru["inventoryPath"],
466 constants::locationCodeInf, "LocationCode"));
467 }
468 }
469 }
470 phosphor::logging::elog<types::DbusInvalidArgument>(
471 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
472 types::InvalidArgument::ARGUMENT_VALUE(
473 i_unexpandedLocationCode.c_str()));
474}
475
476types::ListOfPaths Manager::getFrusByUnexpandedLocationCode(
477 const std::string& i_unexpandedLocationCode,
478 [[maybe_unused]] const uint16_t i_nodeNumber)
479{
480 types::ListOfPaths l_inventoryPaths;
481
482 if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode))
483 {
484 phosphor::logging::elog<types::DbusInvalidArgument>(
485 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
486 types::InvalidArgument::ARGUMENT_VALUE(
487 i_unexpandedLocationCode.c_str()));
488 }
489
490 const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
491 if (!l_sysCfgJsonObj.contains("frus"))
492 {
493 logging::logMessage("Missing frus tag in system config JSON");
494 }
495
496 const nlohmann::json& l_listOfFrus =
497 l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
498
499 for (const auto& l_frus : l_listOfFrus.items())
500 {
501 for (const auto& l_aFru : l_frus.value())
502 {
503 if (l_aFru["extraInterfaces"].contains(
504 constants::locationCodeInf) &&
505 l_aFru["extraInterfaces"][constants::locationCodeInf].value(
506 "LocationCode", "") == i_unexpandedLocationCode)
507 {
508 l_inventoryPaths.push_back(
509 l_aFru.at("inventoryPath")
510 .get_ref<const nlohmann::json::string_t&>());
511 }
512 }
513 }
514
515 if (l_inventoryPaths.empty())
516 {
517 phosphor::logging::elog<types::DbusInvalidArgument>(
518 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
519 types::InvalidArgument::ARGUMENT_VALUE(
520 i_unexpandedLocationCode.c_str()));
521 }
522
523 return l_inventoryPaths;
524}
525
Patrick Williams43fedab2025-02-03 14:28:05 -0500526std::string Manager::getHwPath(
527 const sdbusplus::message::object_path& i_dbusObjPath)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500528{
529 // Dummy code to supress unused variable warning. To be removed.
530 logging::logMessage(std::string(i_dbusObjPath));
531
532 return std::string{};
533}
534
535std::tuple<std::string, uint16_t> Manager::getUnexpandedLocationCode(
536 const std::string& i_expandedLocationCode)
537{
538 /**
539 * Location code should always start with U and fulfil minimum length
540 * criteria.
541 */
542 if (i_expandedLocationCode[0] != 'U' ||
543 i_expandedLocationCode.length() <
544 constants::EXP_LOCATION_CODE_MIN_LENGTH)
545 {
546 phosphor::logging::elog<types::DbusInvalidArgument>(
547 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
548 types::InvalidArgument::ARGUMENT_VALUE(
549 i_expandedLocationCode.c_str()));
550 }
551
552 std::string l_fcKwd;
553
554 auto l_fcKwdValue = dbusUtility::readDbusProperty(
555 "xyz.openbmc_project.Inventory.Manager",
556 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
557 "com.ibm.ipzvpd.VCEN", "FC");
558
559 if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_fcKwdValue))
560 {
561 l_fcKwd.assign(l_kwdValue->begin(), l_kwdValue->end());
562 }
563
564 // Get the first part of expanded location code to check for FC or TM.
565 std::string l_firstKwd = i_expandedLocationCode.substr(1, 4);
566
567 std::string l_unexpandedLocationCode{};
568 uint16_t l_nodeNummber = constants::INVALID_NODE_NUMBER;
569
570 // Check if this value matches the value of FC keyword.
571 if (l_fcKwd.substr(0, 4) == l_firstKwd)
572 {
573 /**
574 * Period(.) should be there in expanded location code to seggregate
575 * FC, node number and SE values.
576 */
577 size_t l_nodeStartPos = i_expandedLocationCode.find('.');
578 if (l_nodeStartPos == std::string::npos)
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 size_t l_nodeEndPos =
587 i_expandedLocationCode.find('.', l_nodeStartPos + 1);
588 if (l_nodeEndPos == std::string::npos)
589 {
590 phosphor::logging::elog<types::DbusInvalidArgument>(
591 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
592 types::InvalidArgument::ARGUMENT_VALUE(
593 i_expandedLocationCode.c_str()));
594 }
595
596 // Skip 3 bytes for '.ND'
597 l_nodeNummber = std::stoi(i_expandedLocationCode.substr(
598 l_nodeStartPos + 3, (l_nodeEndPos - l_nodeStartPos - 3)));
599
600 /**
601 * Confirm if there are other details apart FC, node number and SE
602 * in location code
603 */
604 if (i_expandedLocationCode.length() >
605 constants::EXP_LOCATION_CODE_MIN_LENGTH)
606 {
607 l_unexpandedLocationCode =
608 i_expandedLocationCode[0] + std::string("fcs") +
609 i_expandedLocationCode.substr(
610 l_nodeEndPos + 1 + constants::SE_KWD_LENGTH,
611 std::string::npos);
612 }
613 else
614 {
615 l_unexpandedLocationCode = "Ufcs";
616 }
617 }
618 else
619 {
620 std::string l_tmKwd;
621 // Read TM keyword value.
622 auto l_tmKwdValue = dbusUtility::readDbusProperty(
623 "xyz.openbmc_project.Inventory.Manager",
624 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
625 "com.ibm.ipzvpd.VSYS", "TM");
626
627 if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_tmKwdValue))
628 {
629 l_tmKwd.assign(l_kwdValue->begin(), l_kwdValue->end());
630 }
631
632 // Check if the substr matches to TM keyword value.
633 if (l_tmKwd.substr(0, 4) == l_firstKwd)
634 {
635 /**
636 * System location code will not have node number and any other
637 * details.
638 */
639 l_unexpandedLocationCode = "Umts";
640 }
641 // The given location code is neither "fcs" or "mts".
642 else
643 {
644 phosphor::logging::elog<types::DbusInvalidArgument>(
645 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
646 types::InvalidArgument::ARGUMENT_VALUE(
647 i_expandedLocationCode.c_str()));
648 }
649 }
650
651 return std::make_tuple(l_unexpandedLocationCode, l_nodeNummber);
652}
653
654types::ListOfPaths Manager::getFrusByExpandedLocationCode(
655 const std::string& i_expandedLocationCode)
656{
657 std::tuple<std::string, uint16_t> l_locationAndNodePair =
658 getUnexpandedLocationCode(i_expandedLocationCode);
659
660 return getFrusByUnexpandedLocationCode(std::get<0>(l_locationAndNodePair),
661 std::get<1>(l_locationAndNodePair));
662}
663
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500664void Manager::performVpdRecollection()
665{
Sunny Srivastava380efbb2025-04-25 10:28:30 +0530666 if (m_worker.get() != nullptr)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500667 {
Sunny Srivastava380efbb2025-04-25 10:28:30 +0530668 m_worker->performVpdRecollection();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500669 }
670}
Anupama B R7127ab42025-06-26 01:39:08 -0500671
672bool Manager::collectAllFruVpd() const noexcept
673{
674 try
675 {
676 types::SeverityType l_severityType;
Anupama B Rda9806b2025-08-29 02:41:10 -0500677 if (m_vpdCollectionStatus == constants::vpdCollectionNotStarted)
Anupama B R7127ab42025-06-26 01:39:08 -0500678 {
679 l_severityType = types::SeverityType::Informational;
680 }
Anupama B Rda9806b2025-08-29 02:41:10 -0500681 else if (m_vpdCollectionStatus == constants::vpdCollectionCompleted ||
682 m_vpdCollectionStatus == constants::vpdCollectionFailed)
Anupama B R7127ab42025-06-26 01:39:08 -0500683 {
684 l_severityType = types::SeverityType::Warning;
685 }
686 else
687 {
688 throw std::runtime_error(
689 "Invalid collection status " + m_vpdCollectionStatus +
690 ". Aborting all FRUs VPD collection.");
691 }
692
693 EventLogger::createSyncPel(
694 types::ErrorType::FirmwareError, l_severityType, __FILE__,
695 __FUNCTION__, 0, "Collect all FRUs VPD is requested.", std::nullopt,
696 std::nullopt, std::nullopt, std::nullopt);
697
Anupama B Rb6787bf2025-07-16 01:36:53 -0500698// ToDo: Handle with OEM interface
699#ifdef IBM_SYSTEM
Anupama B R7127ab42025-06-26 01:39:08 -0500700 if (m_ibmHandler.get() != nullptr)
701 {
702 m_ibmHandler->collectAllFruVpd();
703 return true;
704 }
705 else
706 {
707 throw std::runtime_error(
708 "Not found any OEM handler to collect all FRUs VPD.");
709 }
Anupama B Rb6787bf2025-07-16 01:36:53 -0500710#endif
Anupama B R7127ab42025-06-26 01:39:08 -0500711 }
712 catch (const std::exception& l_ex)
713 {
714 EventLogger::createSyncPel(
715 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
716 __FILE__, __FUNCTION__, 0, std::string(l_ex.what()), std::nullopt,
717 std::nullopt, std::nullopt, std::nullopt);
718 }
719 return false;
720}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500721} // namespace vpd