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