xref: /openbmc/openpower-vpd-parser/vpd-manager/src/manager.cpp (revision 45273f9a16f0613d79b88a20b31f609289b8f5ae)
1 #include "config.h"
2 
3 #include "manager.hpp"
4 
5 #include "constants.hpp"
6 #include "exceptions.hpp"
7 #include "parser.hpp"
8 #include "parser_factory.hpp"
9 #include "parser_interface.hpp"
10 #include "single_fab.hpp"
11 #include "types.hpp"
12 #include "utility/dbus_utility.hpp"
13 #include "utility/json_utility.hpp"
14 #include "utility/vpd_specific_utility.hpp"
15 
16 #include <boost/asio/steady_timer.hpp>
17 #include <sdbusplus/bus/match.hpp>
18 #include <sdbusplus/message.hpp>
19 
20 namespace vpd
21 {
Manager(const std::shared_ptr<boost::asio::io_context> & ioCon,const std::shared_ptr<sdbusplus::asio::dbus_interface> & iFace,const std::shared_ptr<sdbusplus::asio::dbus_interface> & progressiFace,const std::shared_ptr<sdbusplus::asio::connection> & asioConnection)22 Manager::Manager(
23     const std::shared_ptr<boost::asio::io_context>& ioCon,
24     const std::shared_ptr<sdbusplus::asio::dbus_interface>& iFace,
25     const std::shared_ptr<sdbusplus::asio::dbus_interface>& progressiFace,
26     const std::shared_ptr<sdbusplus::asio::connection>& asioConnection) :
27     m_ioContext(ioCon), m_interface(iFace), m_progressInterface(progressiFace),
28     m_asioConnection(asioConnection), m_logger(Logger::getLoggerInstance())
29 {
30 #ifdef IBM_SYSTEM_SINGLE_FAB
31     if (!dbusUtility::isChassisPowerOn())
32     {
33         SingleFab l_singleFab;
34         const int& l_rc = l_singleFab.singleFabImOverride();
35 
36         if (l_rc == constants::FAILURE)
37         {
38             throw std::runtime_error(
39                 std::string(__FUNCTION__) +
40                 " : Found an invalid system configuration. Needs manual intervention. BMC is being quiesced.");
41         }
42     }
43 #endif
44 
45     try
46     {
47         // For backward compatibility. Should be depricated.
48         iFace->register_method(
49             "WriteKeyword",
50             [this](const sdbusplus::message::object_path i_path,
51                    const std::string i_recordName, const std::string i_keyword,
52                    const types::BinaryVector i_value) -> int {
53                 return this->updateKeyword(
54                     i_path, std::make_tuple(i_recordName, i_keyword, i_value));
55             });
56 
57         // Register methods under com.ibm.VPD.Manager interface
58         iFace->register_method(
59             "UpdateKeyword",
60             [this](const types::Path i_vpdPath,
61                    const types::WriteVpdParams i_paramsToWriteData) -> int {
62                 return this->updateKeyword(i_vpdPath, i_paramsToWriteData);
63             });
64 
65         iFace->register_method(
66             "WriteKeywordOnHardware",
67             [this](const types::Path i_fruPath,
68                    const types::WriteVpdParams i_paramsToWriteData) -> int {
69                 return this->updateKeywordOnHardware(i_fruPath,
70                                                      i_paramsToWriteData);
71             });
72 
73         iFace->register_method(
74             "ReadKeyword",
75             [this](const types::Path i_fruPath,
76                    const types::ReadVpdParams i_paramsToReadData)
77                 -> types::DbusVariantType {
78                 return this->readKeyword(i_fruPath, i_paramsToReadData);
79             });
80 
81         iFace->register_method(
82             "CollectFRUVPD",
83             [this](const sdbusplus::message::object_path& i_dbusObjPath) {
84                 this->collectSingleFruVpd(i_dbusObjPath);
85             });
86 
87         iFace->register_method(
88             "deleteFRUVPD",
89             [this](const sdbusplus::message::object_path& i_dbusObjPath) {
90                 this->deleteSingleFruVpd(i_dbusObjPath);
91             });
92 
93         iFace->register_method(
94             "GetExpandedLocationCode",
95             [this](const std::string& i_unexpandedLocationCode,
96                    uint16_t& i_nodeNumber) -> std::string {
97                 return this->getExpandedLocationCode(i_unexpandedLocationCode,
98                                                      i_nodeNumber);
99             });
100 
101         iFace->register_method("GetFRUsByExpandedLocationCode",
102                                [this](const std::string& i_expandedLocationCode)
103                                    -> types::ListOfPaths {
104                                    return this->getFrusByExpandedLocationCode(
105                                        i_expandedLocationCode);
106                                });
107 
108         iFace->register_method(
109             "GetFRUsByUnexpandedLocationCode",
110             [this](const std::string& i_unexpandedLocationCode,
111                    uint16_t& i_nodeNumber) -> types::ListOfPaths {
112                 return this->getFrusByUnexpandedLocationCode(
113                     i_unexpandedLocationCode, i_nodeNumber);
114             });
115 
116         iFace->register_method(
117             "GetHardwarePath",
118             [this](const sdbusplus::message::object_path& i_dbusObjPath)
119                 -> std::string { return this->getHwPath(i_dbusObjPath); });
120 
121         iFace->register_method("PerformVPDRecollection", [this]() {
122             this->performVpdRecollection();
123         });
124 
125         iFace->register_method("CollectAllFRUVPD", [this]() -> bool {
126             return this->collectAllFruVpd();
127         });
128 
129         // Indicates FRU VPD collection for the system has not started.
130         progressiFace->register_property_rw<std::string>(
131             "Status", sdbusplus::vtable::property_::emits_change,
132             [this](const std::string& l_currStatus, const auto&) {
133                 if (m_vpdCollectionStatus != l_currStatus)
134                 {
135                     m_vpdCollectionStatus = l_currStatus;
136                     m_interface->signal_property("Status");
137                 }
138                 return true;
139             },
140             [this](const auto&) { return m_vpdCollectionStatus; });
141 
142         // If required, instantiate OEM specific handler here.
143 #ifdef IBM_SYSTEM
144         readVpdCollectionMode();
145 
146         m_ibmHandler = std::make_shared<IbmHandler>(
147             m_worker, m_backupAndRestoreObj, m_interface, m_progressInterface,
148             m_ioContext, m_asioConnection, m_vpdCollectionMode);
149 #else
150         m_worker = std::make_shared<Worker>(INVENTORY_JSON_DEFAULT);
151         m_progressInterface->set_property(
152             "Status", std::string(constants::vpdCollectionCompleted));
153 #endif
154     }
155     catch (const std::exception& l_ex)
156     {
157         logging::logMessage(
158             "Manager class instantiation failed. " + std::string(l_ex.what()));
159 
160         m_logger->logMessage(
161             std::string("Manager class instantiation failed. Reason:") +
162                 EventLogger::getErrorMsg(l_ex),
163             PlaceHolder::PEL,
164             types::PelInfoTuple{EventLogger::getErrorType(l_ex),
165                                 types::SeverityType::Error, 0, std::nullopt,
166                                 std::nullopt, std::nullopt, std::nullopt});
167     }
168 }
169 
readVpdCollectionMode()170 void Manager::readVpdCollectionMode() noexcept
171 {
172     uint16_t l_errCode{0};
173     // check VPD collection mode
174     if (!commonUtility::isFieldModeEnabled(l_errCode))
175     {
176         if (l_errCode)
177         {
178             m_logger->logMessage(
179                 "Default mode set. Error while trying to check if field mode is enabled, error : " +
180                 commonUtility::getErrCodeMsg(l_errCode));
181 
182             return;
183         }
184 
185         m_vpdCollectionMode = commonUtility::getVpdCollectionMode(l_errCode);
186 
187         if (l_errCode)
188         {
189             m_logger->logMessage(
190                 "Default mode set. Error while trying to read VPD collection mode: " +
191                 commonUtility::getErrCodeMsg(l_errCode));
192         }
193     }
194 }
195 
updateKeyword(const types::Path i_vpdPath,const types::WriteVpdParams i_paramsToWriteData)196 int Manager::updateKeyword(const types::Path i_vpdPath,
197                            const types::WriteVpdParams i_paramsToWriteData)
198 {
199     if (i_vpdPath.empty())
200     {
201         logging::logMessage("Given VPD path is empty.");
202         return -1;
203     }
204 
205     uint16_t l_errCode = 0;
206     types::Path l_fruPath;
207     nlohmann::json l_sysCfgJsonObj{};
208 
209     if (m_worker.get() != nullptr)
210     {
211         l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
212 
213         // Get the EEPROM path
214         if (!l_sysCfgJsonObj.empty())
215         {
216             l_fruPath = jsonUtility::getFruPathFromJson(l_sysCfgJsonObj,
217                                                         i_vpdPath, l_errCode);
218         }
219     }
220 
221     if (l_fruPath.empty())
222     {
223         if (l_errCode)
224         {
225             logging::logMessage(
226                 "Failed to get FRU path from JSON for [" + i_vpdPath +
227                 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
228         }
229 
230         l_fruPath = i_vpdPath;
231     }
232 
233     try
234     {
235         std::shared_ptr<Parser> l_parserObj = std::make_shared<Parser>(
236             l_fruPath, l_sysCfgJsonObj, m_vpdCollectionMode);
237 
238         types::DbusVariantType l_updatedValue;
239         auto l_rc =
240             l_parserObj->updateVpdKeyword(i_paramsToWriteData, l_updatedValue);
241 
242         if (l_rc != constants::FAILURE && m_backupAndRestoreObj)
243         {
244             if (m_backupAndRestoreObj->updateKeywordOnPrimaryOrBackupPath(
245                     l_fruPath, i_paramsToWriteData) < constants::VALUE_0)
246             {
247                 logging::logMessage(
248                     "Write success, but backup and restore failed for file[" +
249                     l_fruPath + "]");
250             }
251         }
252 
253         types::WriteVpdParams l_writeParams;
254         types::BinaryVector l_valueToUpdate;
255 
256         if (const types::IpzData* l_ipzData =
257                 std::get_if<types::IpzData>(&i_paramsToWriteData))
258         {
259             if (const types::BinaryVector* l_val =
260                     std::get_if<types::BinaryVector>(&l_updatedValue))
261             {
262                 l_valueToUpdate = *l_val;
263             }
264             else
265             {
266                 l_valueToUpdate = std::get<2>(*l_ipzData);
267             }
268             l_writeParams =
269                 std::make_tuple(std::get<0>(*l_ipzData),
270                                 std::get<1>(*l_ipzData), l_valueToUpdate);
271         }
272         else if (const types::KwData* l_kwData =
273                      std::get_if<types::KwData>(&i_paramsToWriteData))
274         {
275             if (const types::BinaryVector* l_val =
276                     std::get_if<types::BinaryVector>(&l_updatedValue))
277             {
278                 l_valueToUpdate = *l_val;
279             }
280             else
281             {
282                 l_valueToUpdate = std::get<1>(*l_kwData);
283             }
284 
285             l_writeParams =
286                 std::make_tuple(std::get<0>(*l_kwData), l_valueToUpdate);
287         }
288 
289         // update keyword in inherited FRUs
290         if (l_rc != constants::FAILURE)
291         {
292             vpdSpecificUtility::updateKwdOnInheritedFrus(
293                 l_fruPath, l_writeParams, l_sysCfgJsonObj, l_errCode);
294 
295             if (l_errCode)
296             {
297                 logging::logMessage(
298                     "Failed to update keyword on inherited FRUs for FRU [" +
299                     l_fruPath +
300                     "] , error : " + commonUtility::getErrCodeMsg(l_errCode));
301             }
302         }
303 
304         // log VPD write success or failure
305         auto l_logger = Logger::getLoggerInstance();
306 
307         // update common interface(s) properties
308         if (l_rc != constants::FAILURE)
309         {
310             vpdSpecificUtility::updateCiPropertyOfInheritedFrus(
311                 l_fruPath, l_writeParams, l_sysCfgJsonObj, l_errCode);
312 
313             if (l_errCode)
314             {
315                 l_logger->logMessage(
316                     "Failed to update Ci property of inherited FRUs, error : " +
317                     commonUtility::getErrCodeMsg(l_errCode));
318             }
319         }
320 
321         l_logger->logMessage(
322             "VPD write " +
323                 std::string(
324                     (l_rc != constants::FAILURE) ? "successful" : "failed") +
325                 " on path[" + i_vpdPath + "] : " +
326                 vpdSpecificUtility::convertWriteVpdParamsToString(l_writeParams,
327                                                                   l_errCode),
328             PlaceHolder::VPD_WRITE);
329 
330         return l_rc;
331     }
332     catch (const std::exception& l_exception)
333     {
334         logging::logMessage("Update keyword failed for file[" + i_vpdPath +
335                             "], reason: " + std::string(l_exception.what()));
336 
337         m_logger->logMessage(
338             std::string("Update keyword failed for file[") + i_vpdPath +
339                 "], reason:" + std::string(l_exception.what()),
340             PlaceHolder::PEL,
341             types::PelInfoTuple{EventLogger::getErrorType(l_exception),
342                                 types::SeverityType::Error, 0, std::nullopt,
343                                 std::nullopt, std::nullopt, std::nullopt});
344 
345         return -1;
346     }
347 }
348 
updateKeywordOnHardware(const types::Path i_fruPath,const types::WriteVpdParams i_paramsToWriteData)349 int Manager::updateKeywordOnHardware(
350     const types::Path i_fruPath,
351     const types::WriteVpdParams i_paramsToWriteData) noexcept
352 {
353     try
354     {
355         if (i_fruPath.empty())
356         {
357             throw std::runtime_error("Given FRU path is empty");
358         }
359 
360         nlohmann::json l_sysCfgJsonObj{};
361 
362         if (m_worker.get() != nullptr)
363         {
364             l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
365         }
366 
367         std::shared_ptr<Parser> l_parserObj = std::make_shared<Parser>(
368             i_fruPath, l_sysCfgJsonObj, m_vpdCollectionMode);
369         return l_parserObj->updateVpdKeywordOnHardware(i_paramsToWriteData);
370     }
371     catch (const std::exception& l_exception)
372     {
373         m_logger->logMessage(
374             std::string("Update keyword on hardware failed for file[") +
375                 i_fruPath + "], Reason:" + std::string(l_exception.what()),
376             PlaceHolder::PEL,
377             types::PelInfoTuple{types::ErrorType::InvalidEeprom,
378                                 types::SeverityType::Informational, 0,
379                                 std::nullopt, std::nullopt, std::nullopt,
380                                 std::nullopt});
381 
382         return constants::FAILURE;
383     }
384 }
385 
readKeyword(const types::Path i_fruPath,const types::ReadVpdParams i_paramsToReadData)386 types::DbusVariantType Manager::readKeyword(
387     const types::Path i_fruPath, const types::ReadVpdParams i_paramsToReadData)
388 {
389     try
390     {
391         nlohmann::json l_jsonObj{};
392 
393         if (m_worker.get() != nullptr)
394         {
395             l_jsonObj = m_worker->getSysCfgJsonObj();
396         }
397 
398         std::error_code ec;
399 
400         // Check if given path is filesystem path
401         if (!std::filesystem::exists(i_fruPath, ec) && (ec))
402         {
403             throw std::runtime_error(
404                 "Given file path " + i_fruPath + " not found.");
405         }
406 
407         std::shared_ptr<vpd::Parser> l_parserObj =
408             std::make_shared<vpd::Parser>(i_fruPath, l_jsonObj,
409                                           m_vpdCollectionMode);
410 
411         std::shared_ptr<vpd::ParserInterface> l_vpdParserInstance =
412             l_parserObj->getVpdParserInstance();
413 
414         return (
415             l_vpdParserInstance->readKeywordFromHardware(i_paramsToReadData));
416     }
417     catch (const std::exception& l_ex)
418     {
419         logging::logMessage(
420             l_ex.what() +
421             std::string(". VPD manager read operation failed for ") +
422             i_fruPath);
423 
424         m_logger->logMessage(
425             std::string("VPD manager read operation failed for file[") +
426                 i_fruPath + "], Reason:" + std::string(l_ex.what()),
427             PlaceHolder::PEL,
428             types::PelInfoTuple{EventLogger::getErrorType(l_ex),
429                                 types::SeverityType::Informational, 0,
430                                 std::nullopt, std::nullopt, std::nullopt,
431                                 std::nullopt});
432 
433         throw types::DeviceError::ReadFailure();
434     }
435 }
436 
collectSingleFruVpd(const sdbusplus::message::object_path & i_dbusObjPath)437 void Manager::collectSingleFruVpd(
438     const sdbusplus::message::object_path& i_dbusObjPath)
439 {
440     if (m_vpdCollectionStatus != constants::vpdCollectionCompleted)
441     {
442         logging::logMessage(
443             "Currently VPD CollectionStatus is not completed. Cannot perform single FRU VPD collection for " +
444             std::string(i_dbusObjPath));
445         return;
446     }
447 
448     if (m_worker.get() != nullptr)
449     {
450         m_worker->collectSingleFruVpd(i_dbusObjPath);
451     }
452 }
453 
deleteSingleFruVpd(const sdbusplus::message::object_path & i_dbusObjPath)454 void Manager::deleteSingleFruVpd(
455     const sdbusplus::message::object_path& i_dbusObjPath)
456 {
457     try
458     {
459         if (std::string(i_dbusObjPath).empty())
460         {
461             throw std::runtime_error(
462                 "Given DBus object path is empty. Aborting FRU VPD deletion.");
463         }
464 
465         if (m_worker.get() == nullptr)
466         {
467             throw std::runtime_error(
468                 "Worker object not found, can't perform FRU VPD deletion for: " +
469                 std::string(i_dbusObjPath));
470         }
471 
472         m_worker->deleteFruVpd(std::string(i_dbusObjPath));
473     }
474     catch (const std::exception& l_ex)
475     {
476         logging::logMessage(l_ex.what());
477 
478         m_logger->logMessage(
479             std::string("VPD manager delete operation failed for object[") +
480                 std::string(i_dbusObjPath) +
481                 "], Reason:" + std::string(l_ex.what()),
482             PlaceHolder::PEL,
483             types::PelInfoTuple{EventLogger::getErrorType(l_ex),
484                                 types::SeverityType::Informational, 0,
485                                 std::nullopt, std::nullopt, std::nullopt,
486                                 std::nullopt});
487     }
488 }
489 
isValidUnexpandedLocationCode(const std::string & i_unexpandedLocationCode)490 bool Manager::isValidUnexpandedLocationCode(
491     const std::string& i_unexpandedLocationCode)
492 {
493     if ((i_unexpandedLocationCode.length() <
494          constants::UNEXP_LOCATION_CODE_MIN_LENGTH) ||
495         ((i_unexpandedLocationCode.compare(0, 4, "Ufcs") !=
496           constants::STR_CMP_SUCCESS) &&
497          (i_unexpandedLocationCode.compare(0, 4, "Umts") !=
498           constants::STR_CMP_SUCCESS)) ||
499         ((i_unexpandedLocationCode.length() >
500           constants::UNEXP_LOCATION_CODE_MIN_LENGTH) &&
501          (i_unexpandedLocationCode.find("-") != 4)))
502     {
503         return false;
504     }
505 
506     return true;
507 }
508 
getExpandedLocationCode(const std::string & i_unexpandedLocationCode,const uint16_t i_nodeNumber)509 std::string Manager::getExpandedLocationCode(
510     const std::string& i_unexpandedLocationCode,
511     [[maybe_unused]] const uint16_t i_nodeNumber)
512 {
513     if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode))
514     {
515         phosphor::logging::elog<types::DbusInvalidArgument>(
516             types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
517             types::InvalidArgument::ARGUMENT_VALUE(
518                 i_unexpandedLocationCode.c_str()));
519     }
520 
521     if (m_worker == nullptr)
522     {
523         m_logger->logMessage(
524             "Cannot get expanded location code as Worker instance is not initialized.");
525         return std::string{};
526     }
527 
528     const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
529     if (!l_sysCfgJsonObj.contains("frus"))
530     {
531         logging::logMessage("Missing frus tag in system config JSON");
532         return {};
533     }
534 
535     const nlohmann::json& l_listOfFrus =
536         l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
537 
538     for (const auto& l_frus : l_listOfFrus.items())
539     {
540         for (const auto& l_aFru : l_frus.value())
541         {
542             if (l_aFru["extraInterfaces"].contains(
543                     constants::locationCodeInf) &&
544                 l_aFru["extraInterfaces"][constants::locationCodeInf].value(
545                     "LocationCode", "") == i_unexpandedLocationCode)
546             {
547                 return std::get<std::string>(dbusUtility::readDbusProperty(
548                     l_aFru["serviceName"], l_aFru["inventoryPath"],
549                     constants::locationCodeInf, "LocationCode"));
550             }
551         }
552     }
553     phosphor::logging::elog<types::DbusInvalidArgument>(
554         types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
555         types::InvalidArgument::ARGUMENT_VALUE(
556             i_unexpandedLocationCode.c_str()));
557 }
558 
getFrusByUnexpandedLocationCode(const std::string & i_unexpandedLocationCode,const uint16_t i_nodeNumber)559 types::ListOfPaths Manager::getFrusByUnexpandedLocationCode(
560     const std::string& i_unexpandedLocationCode,
561     [[maybe_unused]] const uint16_t i_nodeNumber)
562 {
563     types::ListOfPaths l_inventoryPaths;
564 
565     if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode))
566     {
567         phosphor::logging::elog<types::DbusInvalidArgument>(
568             types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
569             types::InvalidArgument::ARGUMENT_VALUE(
570                 i_unexpandedLocationCode.c_str()));
571     }
572 
573     if (m_worker == nullptr)
574     {
575         m_logger->logMessage(
576             "Cannot get FRUs by unexpanded location code as Worker instance is not initialized");
577         return l_inventoryPaths;
578     }
579 
580     const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
581     if (!l_sysCfgJsonObj.contains("frus"))
582     {
583         logging::logMessage("Missing frus tag in system config JSON");
584         return l_inventoryPaths;
585     }
586 
587     const nlohmann::json& l_listOfFrus =
588         l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
589 
590     for (const auto& l_frus : l_listOfFrus.items())
591     {
592         for (const auto& l_aFru : l_frus.value())
593         {
594             if (l_aFru["extraInterfaces"].contains(
595                     constants::locationCodeInf) &&
596                 l_aFru["extraInterfaces"][constants::locationCodeInf].value(
597                     "LocationCode", "") == i_unexpandedLocationCode)
598             {
599                 l_inventoryPaths.push_back(
600                     l_aFru.at("inventoryPath")
601                         .get_ref<const nlohmann::json::string_t&>());
602             }
603         }
604     }
605 
606     if (l_inventoryPaths.empty())
607     {
608         phosphor::logging::elog<types::DbusInvalidArgument>(
609             types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
610             types::InvalidArgument::ARGUMENT_VALUE(
611                 i_unexpandedLocationCode.c_str()));
612     }
613 
614     return l_inventoryPaths;
615 }
616 
getHwPath(const sdbusplus::message::object_path & i_dbusObjPath)617 std::string Manager::getHwPath(
618     const sdbusplus::message::object_path& i_dbusObjPath)
619 {
620     // Dummy code to supress unused variable warning. To be removed.
621     logging::logMessage(std::string(i_dbusObjPath));
622 
623     return std::string{};
624 }
625 
getUnexpandedLocationCode(const std::string & i_expandedLocationCode)626 std::tuple<std::string, uint16_t> Manager::getUnexpandedLocationCode(
627     const std::string& i_expandedLocationCode)
628 {
629     /**
630      * Location code should always start with U and fulfil minimum length
631      * criteria.
632      */
633     if (i_expandedLocationCode[0] != 'U' ||
634         i_expandedLocationCode.length() <
635             constants::EXP_LOCATION_CODE_MIN_LENGTH)
636     {
637         phosphor::logging::elog<types::DbusInvalidArgument>(
638             types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
639             types::InvalidArgument::ARGUMENT_VALUE(
640                 i_expandedLocationCode.c_str()));
641     }
642 
643     std::string l_fcKwd;
644 
645     auto l_fcKwdValue = dbusUtility::readDbusProperty(
646         "xyz.openbmc_project.Inventory.Manager",
647         "/xyz/openbmc_project/inventory/system/chassis/motherboard",
648         "com.ibm.ipzvpd.VCEN", "FC");
649 
650     if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_fcKwdValue))
651     {
652         l_fcKwd.assign(l_kwdValue->begin(), l_kwdValue->end());
653     }
654 
655     // Get the first part of expanded location code to check for FC or TM.
656     std::string l_firstKwd = i_expandedLocationCode.substr(1, 4);
657 
658     std::string l_unexpandedLocationCode{};
659     uint16_t l_nodeNummber = constants::INVALID_NODE_NUMBER;
660 
661     // Check if this value matches the value of FC keyword.
662     if (l_fcKwd.substr(0, 4) == l_firstKwd)
663     {
664         /**
665          * Period(.) should be there in expanded location code to seggregate
666          * FC, node number and SE values.
667          */
668         size_t l_nodeStartPos = i_expandedLocationCode.find('.');
669         if (l_nodeStartPos == std::string::npos)
670         {
671             phosphor::logging::elog<types::DbusInvalidArgument>(
672                 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
673                 types::InvalidArgument::ARGUMENT_VALUE(
674                     i_expandedLocationCode.c_str()));
675         }
676 
677         size_t l_nodeEndPos =
678             i_expandedLocationCode.find('.', l_nodeStartPos + 1);
679         if (l_nodeEndPos == std::string::npos)
680         {
681             phosphor::logging::elog<types::DbusInvalidArgument>(
682                 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
683                 types::InvalidArgument::ARGUMENT_VALUE(
684                     i_expandedLocationCode.c_str()));
685         }
686 
687         // Skip 3 bytes for '.ND'
688         l_nodeNummber = std::stoi(i_expandedLocationCode.substr(
689             l_nodeStartPos + 3, (l_nodeEndPos - l_nodeStartPos - 3)));
690 
691         /**
692          * Confirm if there are other details apart FC, node number and SE
693          * in location code
694          */
695         if (i_expandedLocationCode.length() >
696             constants::EXP_LOCATION_CODE_MIN_LENGTH)
697         {
698             l_unexpandedLocationCode =
699                 i_expandedLocationCode[0] + std::string("fcs") +
700                 i_expandedLocationCode.substr(
701                     l_nodeEndPos + 1 + constants::SE_KWD_LENGTH,
702                     std::string::npos);
703         }
704         else
705         {
706             l_unexpandedLocationCode = "Ufcs";
707         }
708     }
709     else
710     {
711         std::string l_tmKwd;
712         // Read TM keyword value.
713         auto l_tmKwdValue = dbusUtility::readDbusProperty(
714             "xyz.openbmc_project.Inventory.Manager",
715             "/xyz/openbmc_project/inventory/system/chassis/motherboard",
716             "com.ibm.ipzvpd.VSYS", "TM");
717 
718         if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_tmKwdValue))
719         {
720             l_tmKwd.assign(l_kwdValue->begin(), l_kwdValue->end());
721         }
722 
723         // Check if the substr matches to TM keyword value.
724         if (l_tmKwd.substr(0, 4) == l_firstKwd)
725         {
726             /**
727              * System location code will not have node number and any other
728              * details.
729              */
730             l_unexpandedLocationCode = "Umts";
731         }
732         // The given location code is neither "fcs" or "mts".
733         else
734         {
735             phosphor::logging::elog<types::DbusInvalidArgument>(
736                 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
737                 types::InvalidArgument::ARGUMENT_VALUE(
738                     i_expandedLocationCode.c_str()));
739         }
740     }
741 
742     return std::make_tuple(l_unexpandedLocationCode, l_nodeNummber);
743 }
744 
getFrusByExpandedLocationCode(const std::string & i_expandedLocationCode)745 types::ListOfPaths Manager::getFrusByExpandedLocationCode(
746     const std::string& i_expandedLocationCode)
747 {
748     std::tuple<std::string, uint16_t> l_locationAndNodePair =
749         getUnexpandedLocationCode(i_expandedLocationCode);
750 
751     return getFrusByUnexpandedLocationCode(std::get<0>(l_locationAndNodePair),
752                                            std::get<1>(l_locationAndNodePair));
753 }
754 
performVpdRecollection()755 void Manager::performVpdRecollection()
756 {
757     if (m_worker.get() != nullptr)
758     {
759         m_worker->performVpdRecollection();
760     }
761 }
762 
collectAllFruVpd() const763 bool Manager::collectAllFruVpd() const noexcept
764 {
765     try
766     {
767         types::SeverityType l_severityType;
768         if (m_vpdCollectionStatus == constants::vpdCollectionNotStarted)
769         {
770             l_severityType = types::SeverityType::Informational;
771         }
772         else if (m_vpdCollectionStatus == constants::vpdCollectionCompleted ||
773                  m_vpdCollectionStatus == constants::vpdCollectionFailed)
774         {
775             l_severityType = types::SeverityType::Warning;
776         }
777         else
778         {
779             throw std::runtime_error(
780                 "Invalid collection status " + m_vpdCollectionStatus +
781                 ". Aborting all FRUs VPD collection.");
782         }
783 
784         m_logger->logMessage(
785             std::string("Collect all FRUs VPD is requested."), PlaceHolder::PEL,
786             types::PelInfoTuple{types::ErrorType::FirmwareError, l_severityType,
787                                 0, std::nullopt, std::nullopt, std::nullopt,
788                                 std::nullopt});
789 
790 // ToDo: Handle with OEM interface
791 #ifdef IBM_SYSTEM
792         if (m_ibmHandler.get() != nullptr)
793         {
794             m_ibmHandler->collectAllFruVpd();
795             return true;
796         }
797         else
798         {
799             throw std::runtime_error(
800                 "Not found any OEM handler to collect all FRUs VPD.");
801         }
802 #endif
803     }
804     catch (const std::exception& l_ex)
805     {
806         m_logger->logMessage(
807             std::string("Collect all FRUs VPD failed, reason- ") +
808                 std::string(l_ex.what()),
809             PlaceHolder::PEL,
810             types::PelInfoTuple{EventLogger::getErrorType(l_ex),
811                                 types::SeverityType::Warning, 0, std::nullopt,
812                                 std::nullopt, std::nullopt, std::nullopt});
813     }
814     return false;
815 }
816 } // namespace vpd
817