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