xref: /openbmc/openpower-vpd-parser/vpd-manager/src/manager.cpp (revision c6159a29119d5e08476ed85eaf1cf47ebf9bebdb)
1 #include "config.h"
2 
3 #include "manager.hpp"
4 
5 #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"
11 #include "single_fab.hpp"
12 #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 
21 namespace vpd
22 {
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)23 Manager::Manager(
24     const std::shared_ptr<boost::asio::io_context>& ioCon,
25     const std::shared_ptr<sdbusplus::asio::dbus_interface>& iFace,
26     const std::shared_ptr<sdbusplus::asio::dbus_interface>& progressiFace,
27     const std::shared_ptr<sdbusplus::asio::connection>& asioConnection) :
28     m_ioContext(ioCon), m_interface(iFace), m_progressInterface(progressiFace),
29     m_asioConnection(asioConnection)
30 {
31 #ifdef IBM_SYSTEM
32     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 
46     try
47     {
48         // 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 
126         iFace->register_method("CollectAllFRUVPD", [this]() -> bool {
127             return this->collectAllFruVpd();
128         });
129 
130         // Indicates FRU VPD collection for the system has not started.
131         progressiFace->register_property_rw<std::string>(
132             "Status", sdbusplus::vtable::property_::emits_change,
133             [this](const std::string& l_currStatus, const auto&) {
134                 if (m_vpdCollectionStatus != l_currStatus)
135                 {
136                     m_vpdCollectionStatus = l_currStatus;
137                     m_interface->signal_property("Status");
138                 }
139                 return true;
140             },
141             [this](const auto&) { return m_vpdCollectionStatus; });
142 
143         // If required, instantiate OEM specific handler here.
144 #ifdef IBM_SYSTEM
145         m_ibmHandler = std::make_shared<IbmHandler>(
146             m_worker, m_backupAndRestoreObj, m_interface, m_progressInterface,
147             m_ioContext, m_asioConnection);
148 #else
149         m_worker = std::make_shared<Worker>(INVENTORY_JSON_DEFAULT);
150         m_progressInterface->set_property(
151             "Status", std::string(constants::vpdCollectionCompleted));
152 #endif
153     }
154     catch (const std::exception& e)
155     {
156         logging::logMessage(
157             "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);
163     }
164 }
165 
updateKeyword(const types::Path i_vpdPath,const types::WriteVpdParams i_paramsToWriteData)166 int 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 
175     uint16_t l_errCode = 0;
176     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         {
186             l_fruPath = jsonUtility::getFruPathFromJson(l_sysCfgJsonObj,
187                                                         i_vpdPath, l_errCode);
188         }
189     }
190 
191     if (l_fruPath.empty())
192     {
193         if (l_errCode)
194         {
195             logging::logMessage(
196                 "Failed to get FRU path from JSON for [" + i_vpdPath +
197                 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
198         }
199 
200         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);
207 
208         types::DbusVariantType l_updatedValue;
209         auto l_rc =
210             l_parserObj->updateVpdKeyword(i_paramsToWriteData, l_updatedValue);
211 
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         }
222 
223         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 
259         // update keyword in inherited FRUs
260         if (l_rc != constants::FAILURE)
261         {
262             vpdSpecificUtility::updateKwdOnInheritedFrus(
263                 l_fruPath, l_writeParams, l_sysCfgJsonObj);
264         }
265 
266         // update common interface(s) properties
267         if (l_rc != constants::FAILURE)
268         {
269             vpdSpecificUtility::updateCiPropertyOfInheritedFrus(
270                 l_fruPath, l_writeParams, l_sysCfgJsonObj);
271         }
272 
273         // log VPD write success or failure
274         auto l_logger = Logger::getLoggerInstance();
275 
276         uint16_t l_errorCode;
277         l_logger->logMessage(
278             "VPD write " +
279                 std::string(
280                     (l_rc != constants::FAILURE) ? "successful" : "failed") +
281                 " on path[" + i_vpdPath + "] : " +
282                 vpdSpecificUtility::convertWriteVpdParamsToString(l_writeParams,
283                                                                   l_errorCode),
284             PlaceHolder::VPD_WRITE);
285 
286         return l_rc;
287     }
288     catch (const std::exception& l_exception)
289     {
290         // TODO:: error log needed
291         logging::logMessage("Update keyword failed for file[" + i_vpdPath +
292                             "], reason: " + std::string(l_exception.what()));
293         return -1;
294     }
295 }
296 
updateKeywordOnHardware(const types::Path i_fruPath,const types::WriteVpdParams i_paramsToWriteData)297 int Manager::updateKeywordOnHardware(
298     const types::Path i_fruPath,
299     const types::WriteVpdParams i_paramsToWriteData) noexcept
300 {
301     try
302     {
303         if (i_fruPath.empty())
304         {
305             throw std::runtime_error("Given FRU path is empty");
306         }
307 
308         nlohmann::json l_sysCfgJsonObj{};
309 
310         if (m_worker.get() != nullptr)
311         {
312             l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
313         }
314 
315         std::shared_ptr<Parser> l_parserObj =
316             std::make_shared<Parser>(i_fruPath, l_sysCfgJsonObj);
317         return l_parserObj->updateVpdKeywordOnHardware(i_paramsToWriteData);
318     }
319     catch (const std::exception& l_exception)
320     {
321         EventLogger::createAsyncPel(
322             types::ErrorType::InvalidEeprom, types::SeverityType::Informational,
323             __FILE__, __FUNCTION__, 0,
324             "Update keyword on hardware failed for file[" + i_fruPath +
325                 "], reason: " + std::string(l_exception.what()),
326             std::nullopt, std::nullopt, std::nullopt, std::nullopt);
327 
328         return constants::FAILURE;
329     }
330 }
331 
readKeyword(const types::Path i_fruPath,const types::ReadVpdParams i_paramsToReadData)332 types::DbusVariantType Manager::readKeyword(
333     const types::Path i_fruPath, const types::ReadVpdParams i_paramsToReadData)
334 {
335     try
336     {
337         nlohmann::json l_jsonObj{};
338 
339         if (m_worker.get() != nullptr)
340         {
341             l_jsonObj = m_worker->getSysCfgJsonObj();
342         }
343 
344         std::error_code ec;
345 
346         // Check if given path is filesystem path
347         if (!std::filesystem::exists(i_fruPath, ec) && (ec))
348         {
349             throw std::runtime_error(
350                 "Given file path " + i_fruPath + " not found.");
351         }
352 
353         std::shared_ptr<vpd::Parser> l_parserObj =
354             std::make_shared<vpd::Parser>(i_fruPath, l_jsonObj);
355 
356         std::shared_ptr<vpd::ParserInterface> l_vpdParserInstance =
357             l_parserObj->getVpdParserInstance();
358 
359         return (
360             l_vpdParserInstance->readKeywordFromHardware(i_paramsToReadData));
361     }
362     catch (const std::exception& e)
363     {
364         logging::logMessage(
365             e.what() + std::string(". VPD manager read operation failed for ") +
366             i_fruPath);
367         throw types::DeviceError::ReadFailure();
368     }
369 }
370 
collectSingleFruVpd(const sdbusplus::message::object_path & i_dbusObjPath)371 void Manager::collectSingleFruVpd(
372     const sdbusplus::message::object_path& i_dbusObjPath)
373 {
374     if (m_vpdCollectionStatus != constants::vpdCollectionCompleted)
375     {
376         logging::logMessage(
377             "Currently VPD CollectionStatus is not completed. Cannot perform single FRU VPD collection for " +
378             std::string(i_dbusObjPath));
379         return;
380     }
381 
382     if (m_worker.get() != nullptr)
383     {
384         m_worker->collectSingleFruVpd(i_dbusObjPath);
385     }
386 }
387 
deleteSingleFruVpd(const sdbusplus::message::object_path & i_dbusObjPath)388 void Manager::deleteSingleFruVpd(
389     const sdbusplus::message::object_path& i_dbusObjPath)
390 {
391     try
392     {
393         if (std::string(i_dbusObjPath).empty())
394         {
395             throw std::runtime_error(
396                 "Given DBus object path is empty. Aborting FRU VPD deletion.");
397         }
398 
399         if (m_worker.get() == nullptr)
400         {
401             throw std::runtime_error(
402                 "Worker object not found, can't perform FRU VPD deletion for: " +
403                 std::string(i_dbusObjPath));
404         }
405 
406         m_worker->deleteFruVpd(std::string(i_dbusObjPath));
407     }
408     catch (const std::exception& l_ex)
409     {
410         // TODO: Log PEL
411         logging::logMessage(l_ex.what());
412     }
413 }
414 
isValidUnexpandedLocationCode(const std::string & i_unexpandedLocationCode)415 bool Manager::isValidUnexpandedLocationCode(
416     const std::string& i_unexpandedLocationCode)
417 {
418     if ((i_unexpandedLocationCode.length() <
419          constants::UNEXP_LOCATION_CODE_MIN_LENGTH) ||
420         ((i_unexpandedLocationCode.compare(0, 4, "Ufcs") !=
421           constants::STR_CMP_SUCCESS) &&
422          (i_unexpandedLocationCode.compare(0, 4, "Umts") !=
423           constants::STR_CMP_SUCCESS)) ||
424         ((i_unexpandedLocationCode.length() >
425           constants::UNEXP_LOCATION_CODE_MIN_LENGTH) &&
426          (i_unexpandedLocationCode.find("-") != 4)))
427     {
428         return false;
429     }
430 
431     return true;
432 }
433 
getExpandedLocationCode(const std::string & i_unexpandedLocationCode,const uint16_t i_nodeNumber)434 std::string Manager::getExpandedLocationCode(
435     const std::string& i_unexpandedLocationCode,
436     [[maybe_unused]] const uint16_t i_nodeNumber)
437 {
438     if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode))
439     {
440         phosphor::logging::elog<types::DbusInvalidArgument>(
441             types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
442             types::InvalidArgument::ARGUMENT_VALUE(
443                 i_unexpandedLocationCode.c_str()));
444     }
445 
446     const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
447     if (!l_sysCfgJsonObj.contains("frus"))
448     {
449         logging::logMessage("Missing frus tag in system config JSON");
450     }
451 
452     const nlohmann::json& l_listOfFrus =
453         l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
454 
455     for (const auto& l_frus : l_listOfFrus.items())
456     {
457         for (const auto& l_aFru : l_frus.value())
458         {
459             if (l_aFru["extraInterfaces"].contains(
460                     constants::locationCodeInf) &&
461                 l_aFru["extraInterfaces"][constants::locationCodeInf].value(
462                     "LocationCode", "") == i_unexpandedLocationCode)
463             {
464                 return std::get<std::string>(dbusUtility::readDbusProperty(
465                     l_aFru["serviceName"], l_aFru["inventoryPath"],
466                     constants::locationCodeInf, "LocationCode"));
467             }
468         }
469     }
470     phosphor::logging::elog<types::DbusInvalidArgument>(
471         types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
472         types::InvalidArgument::ARGUMENT_VALUE(
473             i_unexpandedLocationCode.c_str()));
474 }
475 
getFrusByUnexpandedLocationCode(const std::string & i_unexpandedLocationCode,const uint16_t i_nodeNumber)476 types::ListOfPaths Manager::getFrusByUnexpandedLocationCode(
477     const std::string& i_unexpandedLocationCode,
478     [[maybe_unused]] const uint16_t i_nodeNumber)
479 {
480     types::ListOfPaths l_inventoryPaths;
481 
482     if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode))
483     {
484         phosphor::logging::elog<types::DbusInvalidArgument>(
485             types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
486             types::InvalidArgument::ARGUMENT_VALUE(
487                 i_unexpandedLocationCode.c_str()));
488     }
489 
490     const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
491     if (!l_sysCfgJsonObj.contains("frus"))
492     {
493         logging::logMessage("Missing frus tag in system config JSON");
494     }
495 
496     const nlohmann::json& l_listOfFrus =
497         l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
498 
499     for (const auto& l_frus : l_listOfFrus.items())
500     {
501         for (const auto& l_aFru : l_frus.value())
502         {
503             if (l_aFru["extraInterfaces"].contains(
504                     constants::locationCodeInf) &&
505                 l_aFru["extraInterfaces"][constants::locationCodeInf].value(
506                     "LocationCode", "") == i_unexpandedLocationCode)
507             {
508                 l_inventoryPaths.push_back(
509                     l_aFru.at("inventoryPath")
510                         .get_ref<const nlohmann::json::string_t&>());
511             }
512         }
513     }
514 
515     if (l_inventoryPaths.empty())
516     {
517         phosphor::logging::elog<types::DbusInvalidArgument>(
518             types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
519             types::InvalidArgument::ARGUMENT_VALUE(
520                 i_unexpandedLocationCode.c_str()));
521     }
522 
523     return l_inventoryPaths;
524 }
525 
getHwPath(const sdbusplus::message::object_path & i_dbusObjPath)526 std::string Manager::getHwPath(
527     const sdbusplus::message::object_path& i_dbusObjPath)
528 {
529     // Dummy code to supress unused variable warning. To be removed.
530     logging::logMessage(std::string(i_dbusObjPath));
531 
532     return std::string{};
533 }
534 
getUnexpandedLocationCode(const std::string & i_expandedLocationCode)535 std::tuple<std::string, uint16_t> Manager::getUnexpandedLocationCode(
536     const std::string& i_expandedLocationCode)
537 {
538     /**
539      * Location code should always start with U and fulfil minimum length
540      * criteria.
541      */
542     if (i_expandedLocationCode[0] != 'U' ||
543         i_expandedLocationCode.length() <
544             constants::EXP_LOCATION_CODE_MIN_LENGTH)
545     {
546         phosphor::logging::elog<types::DbusInvalidArgument>(
547             types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
548             types::InvalidArgument::ARGUMENT_VALUE(
549                 i_expandedLocationCode.c_str()));
550     }
551 
552     std::string l_fcKwd;
553 
554     auto l_fcKwdValue = dbusUtility::readDbusProperty(
555         "xyz.openbmc_project.Inventory.Manager",
556         "/xyz/openbmc_project/inventory/system/chassis/motherboard",
557         "com.ibm.ipzvpd.VCEN", "FC");
558 
559     if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_fcKwdValue))
560     {
561         l_fcKwd.assign(l_kwdValue->begin(), l_kwdValue->end());
562     }
563 
564     // Get the first part of expanded location code to check for FC or TM.
565     std::string l_firstKwd = i_expandedLocationCode.substr(1, 4);
566 
567     std::string l_unexpandedLocationCode{};
568     uint16_t l_nodeNummber = constants::INVALID_NODE_NUMBER;
569 
570     // Check if this value matches the value of FC keyword.
571     if (l_fcKwd.substr(0, 4) == l_firstKwd)
572     {
573         /**
574          * Period(.) should be there in expanded location code to seggregate
575          * FC, node number and SE values.
576          */
577         size_t l_nodeStartPos = i_expandedLocationCode.find('.');
578         if (l_nodeStartPos == std::string::npos)
579         {
580             phosphor::logging::elog<types::DbusInvalidArgument>(
581                 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
582                 types::InvalidArgument::ARGUMENT_VALUE(
583                     i_expandedLocationCode.c_str()));
584         }
585 
586         size_t l_nodeEndPos =
587             i_expandedLocationCode.find('.', l_nodeStartPos + 1);
588         if (l_nodeEndPos == std::string::npos)
589         {
590             phosphor::logging::elog<types::DbusInvalidArgument>(
591                 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
592                 types::InvalidArgument::ARGUMENT_VALUE(
593                     i_expandedLocationCode.c_str()));
594         }
595 
596         // Skip 3 bytes for '.ND'
597         l_nodeNummber = std::stoi(i_expandedLocationCode.substr(
598             l_nodeStartPos + 3, (l_nodeEndPos - l_nodeStartPos - 3)));
599 
600         /**
601          * Confirm if there are other details apart FC, node number and SE
602          * in location code
603          */
604         if (i_expandedLocationCode.length() >
605             constants::EXP_LOCATION_CODE_MIN_LENGTH)
606         {
607             l_unexpandedLocationCode =
608                 i_expandedLocationCode[0] + std::string("fcs") +
609                 i_expandedLocationCode.substr(
610                     l_nodeEndPos + 1 + constants::SE_KWD_LENGTH,
611                     std::string::npos);
612         }
613         else
614         {
615             l_unexpandedLocationCode = "Ufcs";
616         }
617     }
618     else
619     {
620         std::string l_tmKwd;
621         // Read TM keyword value.
622         auto l_tmKwdValue = dbusUtility::readDbusProperty(
623             "xyz.openbmc_project.Inventory.Manager",
624             "/xyz/openbmc_project/inventory/system/chassis/motherboard",
625             "com.ibm.ipzvpd.VSYS", "TM");
626 
627         if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_tmKwdValue))
628         {
629             l_tmKwd.assign(l_kwdValue->begin(), l_kwdValue->end());
630         }
631 
632         // Check if the substr matches to TM keyword value.
633         if (l_tmKwd.substr(0, 4) == l_firstKwd)
634         {
635             /**
636              * System location code will not have node number and any other
637              * details.
638              */
639             l_unexpandedLocationCode = "Umts";
640         }
641         // The given location code is neither "fcs" or "mts".
642         else
643         {
644             phosphor::logging::elog<types::DbusInvalidArgument>(
645                 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
646                 types::InvalidArgument::ARGUMENT_VALUE(
647                     i_expandedLocationCode.c_str()));
648         }
649     }
650 
651     return std::make_tuple(l_unexpandedLocationCode, l_nodeNummber);
652 }
653 
getFrusByExpandedLocationCode(const std::string & i_expandedLocationCode)654 types::ListOfPaths Manager::getFrusByExpandedLocationCode(
655     const std::string& i_expandedLocationCode)
656 {
657     std::tuple<std::string, uint16_t> l_locationAndNodePair =
658         getUnexpandedLocationCode(i_expandedLocationCode);
659 
660     return getFrusByUnexpandedLocationCode(std::get<0>(l_locationAndNodePair),
661                                            std::get<1>(l_locationAndNodePair));
662 }
663 
performVpdRecollection()664 void Manager::performVpdRecollection()
665 {
666     if (m_worker.get() != nullptr)
667     {
668         m_worker->performVpdRecollection();
669     }
670 }
671 
collectAllFruVpd() const672 bool Manager::collectAllFruVpd() const noexcept
673 {
674     try
675     {
676         types::SeverityType l_severityType;
677         if (m_vpdCollectionStatus == constants::vpdCollectionNotStarted)
678         {
679             l_severityType = types::SeverityType::Informational;
680         }
681         else if (m_vpdCollectionStatus == constants::vpdCollectionCompleted ||
682                  m_vpdCollectionStatus == constants::vpdCollectionFailed)
683         {
684             l_severityType = types::SeverityType::Warning;
685         }
686         else
687         {
688             throw std::runtime_error(
689                 "Invalid collection status " + m_vpdCollectionStatus +
690                 ". Aborting all FRUs VPD collection.");
691         }
692 
693         EventLogger::createSyncPel(
694             types::ErrorType::FirmwareError, l_severityType, __FILE__,
695             __FUNCTION__, 0, "Collect all FRUs VPD is requested.", std::nullopt,
696             std::nullopt, std::nullopt, std::nullopt);
697 
698 // ToDo: Handle with OEM interface
699 #ifdef IBM_SYSTEM
700         if (m_ibmHandler.get() != nullptr)
701         {
702             m_ibmHandler->collectAllFruVpd();
703             return true;
704         }
705         else
706         {
707             throw std::runtime_error(
708                 "Not found any OEM handler to collect all FRUs VPD.");
709         }
710 #endif
711     }
712     catch (const std::exception& l_ex)
713     {
714         EventLogger::createSyncPel(
715             EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
716             __FILE__, __FUNCTION__, 0, std::string(l_ex.what()), std::nullopt,
717             std::nullopt, std::nullopt, std::nullopt);
718     }
719     return false;
720 }
721 } // namespace vpd
722