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