xref: /openbmc/openpower-vpd-parser/vpd-manager/src/manager.cpp (revision ffdff3132f2e523d7d444900c81cea706ec69f8f)
1fa5e4d32SSunny Srivastava #include "config.h"
2fa5e4d32SSunny Srivastava 
3fa5e4d32SSunny Srivastava #include "manager.hpp"
4fa5e4d32SSunny Srivastava 
5fa5e4d32SSunny Srivastava #include "backup_restore.hpp"
6fa5e4d32SSunny Srivastava #include "constants.hpp"
7fa5e4d32SSunny Srivastava #include "exceptions.hpp"
8fa5e4d32SSunny Srivastava #include "logger.hpp"
9fa5e4d32SSunny Srivastava #include "parser.hpp"
10fa5e4d32SSunny Srivastava #include "parser_factory.hpp"
11fa5e4d32SSunny Srivastava #include "parser_interface.hpp"
12*ffdff313SRekha Aparna #include "single_fab.hpp"
13fa5e4d32SSunny Srivastava #include "types.hpp"
14fa5e4d32SSunny Srivastava #include "utility/dbus_utility.hpp"
15fa5e4d32SSunny Srivastava #include "utility/json_utility.hpp"
16fa5e4d32SSunny Srivastava #include "utility/vpd_specific_utility.hpp"
17fa5e4d32SSunny Srivastava 
18fa5e4d32SSunny Srivastava #include <boost/asio/steady_timer.hpp>
19fa5e4d32SSunny Srivastava #include <sdbusplus/bus/match.hpp>
20fa5e4d32SSunny Srivastava #include <sdbusplus/message.hpp>
21fa5e4d32SSunny Srivastava 
22fa5e4d32SSunny Srivastava namespace vpd
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::connection> & asioConnection)23fa5e4d32SSunny Srivastava {
24fa5e4d32SSunny Srivastava Manager::Manager(
25fa5e4d32SSunny Srivastava     const std::shared_ptr<boost::asio::io_context>& ioCon,
26fa5e4d32SSunny Srivastava     const std::shared_ptr<sdbusplus::asio::dbus_interface>& iFace,
27fa5e4d32SSunny Srivastava     const std::shared_ptr<sdbusplus::asio::connection>& asioConnection) :
28fa5e4d32SSunny Srivastava     m_ioContext(ioCon), m_interface(iFace), m_asioConnection(asioConnection)
29fa5e4d32SSunny Srivastava {
30*ffdff313SRekha Aparna #ifdef IBM_SYSTEM
31*ffdff313SRekha Aparna     if (!dbusUtility::isChassisPowerOn())
32*ffdff313SRekha Aparna     {
33*ffdff313SRekha Aparna         SingleFab l_singleFab;
34*ffdff313SRekha Aparna         const int& l_rc = l_singleFab.singleFabImOverride();
35*ffdff313SRekha Aparna 
36*ffdff313SRekha Aparna         if (l_rc == constants::FAILURE)
37*ffdff313SRekha Aparna         {
38*ffdff313SRekha Aparna             throw std::runtime_error(
39*ffdff313SRekha Aparna                 std::string(__FUNCTION__) +
40*ffdff313SRekha Aparna                 " : Found an invalid system configuration. Needs manual intervention. BMC is being quiesced.");
41*ffdff313SRekha Aparna         }
42*ffdff313SRekha Aparna     }
43*ffdff313SRekha Aparna #endif
44*ffdff313SRekha Aparna 
45fa5e4d32SSunny Srivastava     try
46fa5e4d32SSunny Srivastava     {
47fa5e4d32SSunny Srivastava #ifdef IBM_SYSTEM
48765cf7b8SSunny Srivastava         if (dbusUtility::isChassisPowerOn())
49765cf7b8SSunny Srivastava         {
50765cf7b8SSunny Srivastava             // At power on, less number of FRU(s) needs collection. we can scale
51765cf7b8SSunny Srivastava             // down the threads to reduce CPU utilization.
52765cf7b8SSunny Srivastava             m_worker = std::make_shared<Worker>(INVENTORY_JSON_DEFAULT,
53765cf7b8SSunny Srivastava                                                 constants::VALUE_1);
54765cf7b8SSunny Srivastava         }
55765cf7b8SSunny Srivastava         else
56765cf7b8SSunny Srivastava         {
57765cf7b8SSunny Srivastava             // Initialize with default configuration
58fa5e4d32SSunny Srivastava             m_worker = std::make_shared<Worker>(INVENTORY_JSON_DEFAULT);
59765cf7b8SSunny Srivastava         }
60fa5e4d32SSunny Srivastava 
61fa5e4d32SSunny Srivastava         // Set up minimal things that is needed before bus name is claimed.
62fa5e4d32SSunny Srivastava         m_worker->performInitialSetup();
63fa5e4d32SSunny Srivastava 
64fa5e4d32SSunny Srivastava         // set callback to detect any asset tag change
65fa5e4d32SSunny Srivastava         registerAssetTagChangeCallback();
66fa5e4d32SSunny Srivastava 
67fa5e4d32SSunny Srivastava         // set async timer to detect if system VPD is published on D-Bus.
68fa5e4d32SSunny Srivastava         SetTimerToDetectSVPDOnDbus();
69fa5e4d32SSunny Srivastava 
70fa5e4d32SSunny Srivastava         // set async timer to detect if VPD collection is done.
71fa5e4d32SSunny Srivastava         SetTimerToDetectVpdCollectionStatus();
72fa5e4d32SSunny Srivastava 
73fa5e4d32SSunny Srivastava         // Instantiate GpioMonitor class
74fa5e4d32SSunny Srivastava         m_gpioMonitor = std::make_shared<GpioMonitor>(
75fa5e4d32SSunny Srivastava             m_worker->getSysCfgJsonObj(), m_worker, m_ioContext);
76fa5e4d32SSunny Srivastava 
77fa5e4d32SSunny Srivastava #endif
78fa5e4d32SSunny Srivastava         // set callback to detect host state change.
79fa5e4d32SSunny Srivastava         registerHostStateChangeCallback();
80fa5e4d32SSunny Srivastava 
81fa5e4d32SSunny Srivastava         // For backward compatibility. Should be depricated.
82fa5e4d32SSunny Srivastava         iFace->register_method(
83fa5e4d32SSunny Srivastava             "WriteKeyword",
84fa5e4d32SSunny Srivastava             [this](const sdbusplus::message::object_path i_path,
85fa5e4d32SSunny Srivastava                    const std::string i_recordName, const std::string i_keyword,
86fa5e4d32SSunny Srivastava                    const types::BinaryVector i_value) -> int {
87fa5e4d32SSunny Srivastava                 return this->updateKeyword(
88fa5e4d32SSunny Srivastava                     i_path, std::make_tuple(i_recordName, i_keyword, i_value));
89fa5e4d32SSunny Srivastava             });
90fa5e4d32SSunny Srivastava 
91fa5e4d32SSunny Srivastava         // Register methods under com.ibm.VPD.Manager interface
92fa5e4d32SSunny Srivastava         iFace->register_method(
93fa5e4d32SSunny Srivastava             "UpdateKeyword",
94fa5e4d32SSunny Srivastava             [this](const types::Path i_vpdPath,
95fa5e4d32SSunny Srivastava                    const types::WriteVpdParams i_paramsToWriteData) -> int {
96fa5e4d32SSunny Srivastava                 return this->updateKeyword(i_vpdPath, i_paramsToWriteData);
97fa5e4d32SSunny Srivastava             });
98fa5e4d32SSunny Srivastava 
99fa5e4d32SSunny Srivastava         iFace->register_method(
100fa5e4d32SSunny Srivastava             "WriteKeywordOnHardware",
101fa5e4d32SSunny Srivastava             [this](const types::Path i_fruPath,
102fa5e4d32SSunny Srivastava                    const types::WriteVpdParams i_paramsToWriteData) -> int {
103fa5e4d32SSunny Srivastava                 return this->updateKeywordOnHardware(i_fruPath,
104fa5e4d32SSunny Srivastava                                                      i_paramsToWriteData);
105fa5e4d32SSunny Srivastava             });
106fa5e4d32SSunny Srivastava 
107fa5e4d32SSunny Srivastava         iFace->register_method(
108fa5e4d32SSunny Srivastava             "ReadKeyword",
109fa5e4d32SSunny Srivastava             [this](const types::Path i_fruPath,
110fa5e4d32SSunny Srivastava                    const types::ReadVpdParams i_paramsToReadData)
111fa5e4d32SSunny Srivastava                 -> types::DbusVariantType {
112fa5e4d32SSunny Srivastava                 return this->readKeyword(i_fruPath, i_paramsToReadData);
113fa5e4d32SSunny Srivastava             });
114fa5e4d32SSunny Srivastava 
115fa5e4d32SSunny Srivastava         iFace->register_method(
116fa5e4d32SSunny Srivastava             "CollectFRUVPD",
117fa5e4d32SSunny Srivastava             [this](const sdbusplus::message::object_path& i_dbusObjPath) {
118fa5e4d32SSunny Srivastava                 this->collectSingleFruVpd(i_dbusObjPath);
119fa5e4d32SSunny Srivastava             });
120fa5e4d32SSunny Srivastava 
121fa5e4d32SSunny Srivastava         iFace->register_method(
122fa5e4d32SSunny Srivastava             "deleteFRUVPD",
123fa5e4d32SSunny Srivastava             [this](const sdbusplus::message::object_path& i_dbusObjPath) {
124fa5e4d32SSunny Srivastava                 this->deleteSingleFruVpd(i_dbusObjPath);
125fa5e4d32SSunny Srivastava             });
126fa5e4d32SSunny Srivastava 
127fa5e4d32SSunny Srivastava         iFace->register_method(
128fa5e4d32SSunny Srivastava             "GetExpandedLocationCode",
129fa5e4d32SSunny Srivastava             [this](const std::string& i_unexpandedLocationCode,
130fa5e4d32SSunny Srivastava                    uint16_t& i_nodeNumber) -> std::string {
131fa5e4d32SSunny Srivastava                 return this->getExpandedLocationCode(i_unexpandedLocationCode,
132fa5e4d32SSunny Srivastava                                                      i_nodeNumber);
133fa5e4d32SSunny Srivastava             });
134fa5e4d32SSunny Srivastava 
135fa5e4d32SSunny Srivastava         iFace->register_method("GetFRUsByExpandedLocationCode",
136fa5e4d32SSunny Srivastava                                [this](const std::string& i_expandedLocationCode)
137fa5e4d32SSunny Srivastava                                    -> types::ListOfPaths {
138fa5e4d32SSunny Srivastava                                    return this->getFrusByExpandedLocationCode(
139fa5e4d32SSunny Srivastava                                        i_expandedLocationCode);
140fa5e4d32SSunny Srivastava                                });
141fa5e4d32SSunny Srivastava 
142fa5e4d32SSunny Srivastava         iFace->register_method(
143fa5e4d32SSunny Srivastava             "GetFRUsByUnexpandedLocationCode",
144fa5e4d32SSunny Srivastava             [this](const std::string& i_unexpandedLocationCode,
145fa5e4d32SSunny Srivastava                    uint16_t& i_nodeNumber) -> types::ListOfPaths {
146fa5e4d32SSunny Srivastava                 return this->getFrusByUnexpandedLocationCode(
147fa5e4d32SSunny Srivastava                     i_unexpandedLocationCode, i_nodeNumber);
148fa5e4d32SSunny Srivastava             });
149fa5e4d32SSunny Srivastava 
150fa5e4d32SSunny Srivastava         iFace->register_method(
151fa5e4d32SSunny Srivastava             "GetHardwarePath",
152fa5e4d32SSunny Srivastava             [this](const sdbusplus::message::object_path& i_dbusObjPath)
153fa5e4d32SSunny Srivastava                 -> std::string { return this->getHwPath(i_dbusObjPath); });
154fa5e4d32SSunny Srivastava 
155fa5e4d32SSunny Srivastava         iFace->register_method("PerformVPDRecollection", [this]() {
156fa5e4d32SSunny Srivastava             this->performVpdRecollection();
157fa5e4d32SSunny Srivastava         });
158fa5e4d32SSunny Srivastava 
159fa5e4d32SSunny Srivastava         // Indicates FRU VPD collection for the system has not started.
160fa5e4d32SSunny Srivastava         iFace->register_property_rw<std::string>(
161fa5e4d32SSunny Srivastava             "CollectionStatus", sdbusplus::vtable::property_::emits_change,
162fa5e4d32SSunny Srivastava             [this](const std::string l_currStatus, const auto&) {
163fa5e4d32SSunny Srivastava                 m_vpdCollectionStatus = l_currStatus;
164fa5e4d32SSunny Srivastava                 return 0;
165fa5e4d32SSunny Srivastava             },
166fa5e4d32SSunny Srivastava             [this](const auto&) { return m_vpdCollectionStatus; });
167fa5e4d32SSunny Srivastava     }
168fa5e4d32SSunny Srivastava     catch (const std::exception& e)
169fa5e4d32SSunny Srivastava     {
170fa5e4d32SSunny Srivastava         logging::logMessage(
171fa5e4d32SSunny Srivastava             "VPD-Manager service failed. " + std::string(e.what()));
172fa5e4d32SSunny Srivastava         throw;
173fa5e4d32SSunny Srivastava     }
174fa5e4d32SSunny Srivastava }
175fa5e4d32SSunny Srivastava 
176fa5e4d32SSunny Srivastava #ifdef IBM_SYSTEM
177fa5e4d32SSunny Srivastava void Manager::registerAssetTagChangeCallback()
178fa5e4d32SSunny Srivastava {
179fa5e4d32SSunny Srivastava     static std::shared_ptr<sdbusplus::bus::match_t> l_assetMatch =
180fa5e4d32SSunny Srivastava         std::make_shared<sdbusplus::bus::match_t>(
181fa5e4d32SSunny Srivastava             *m_asioConnection,
182fa5e4d32SSunny Srivastava             sdbusplus::bus::match::rules::propertiesChanged(
183fa5e4d32SSunny Srivastava                 constants::systemInvPath, constants::assetTagInf),
184fa5e4d32SSunny Srivastava             [this](sdbusplus::message_t& l_msg) {
185fa5e4d32SSunny Srivastava                 processAssetTagChangeCallback(l_msg);
186fa5e4d32SSunny Srivastava             });
187fa5e4d32SSunny Srivastava }
188fa5e4d32SSunny Srivastava 
189fa5e4d32SSunny Srivastava void Manager::processAssetTagChangeCallback(sdbusplus::message_t& i_msg)
190fa5e4d32SSunny Srivastava {
191fa5e4d32SSunny Srivastava     try
192fa5e4d32SSunny Srivastava     {
193fa5e4d32SSunny Srivastava         if (i_msg.is_method_error())
194fa5e4d32SSunny Srivastava         {
195fa5e4d32SSunny Srivastava             throw std::runtime_error(
196fa5e4d32SSunny Srivastava                 "Error reading callback msg for asset tag.");
197fa5e4d32SSunny Srivastava         }
198fa5e4d32SSunny Srivastava 
199fa5e4d32SSunny Srivastava         std::string l_objectPath;
200fa5e4d32SSunny Srivastava         types::PropertyMap l_propMap;
201fa5e4d32SSunny Srivastava         i_msg.read(l_objectPath, l_propMap);
202fa5e4d32SSunny Srivastava 
203fa5e4d32SSunny Srivastava         const auto& l_itrToAssetTag = l_propMap.find("AssetTag");
204fa5e4d32SSunny Srivastava         if (l_itrToAssetTag != l_propMap.end())
205fa5e4d32SSunny Srivastava         {
206fa5e4d32SSunny Srivastava             if (auto l_assetTag =
207fa5e4d32SSunny Srivastava                     std::get_if<std::string>(&(l_itrToAssetTag->second)))
208fa5e4d32SSunny Srivastava             {
209fa5e4d32SSunny Srivastava                 // Call Notify to persist the AssetTag
210fa5e4d32SSunny Srivastava                 types::ObjectMap l_objectMap = {
211fa5e4d32SSunny Srivastava                     {sdbusplus::message::object_path(constants::systemInvPath),
212fa5e4d32SSunny Srivastava                      {{constants::assetTagInf, {{"AssetTag", *l_assetTag}}}}}};
213fa5e4d32SSunny Srivastava 
214fa5e4d32SSunny Srivastava                 // Notify PIM
215fa5e4d32SSunny Srivastava                 if (!dbusUtility::callPIM(move(l_objectMap)))
216fa5e4d32SSunny Srivastava                 {
217fa5e4d32SSunny Srivastava                     throw std::runtime_error(
218fa5e4d32SSunny Srivastava                         "Call to PIM failed for asset tag update.");
219fa5e4d32SSunny Srivastava                 }
220fa5e4d32SSunny Srivastava             }
221fa5e4d32SSunny Srivastava         }
222fa5e4d32SSunny Srivastava         else
223fa5e4d32SSunny Srivastava         {
224fa5e4d32SSunny Srivastava             throw std::runtime_error(
225fa5e4d32SSunny Srivastava                 "Could not find asset tag in callback message.");
226fa5e4d32SSunny Srivastava         }
227fa5e4d32SSunny Srivastava     }
228fa5e4d32SSunny Srivastava     catch (const std::exception& l_ex)
229fa5e4d32SSunny Srivastava     {
230fa5e4d32SSunny Srivastava         // TODO: Log PEL with below description.
231fa5e4d32SSunny Srivastava         logging::logMessage("Asset tag callback update failed with error: " +
232fa5e4d32SSunny Srivastava                             std::string(l_ex.what()));
233fa5e4d32SSunny Srivastava     }
234fa5e4d32SSunny Srivastava }
235fa5e4d32SSunny Srivastava 
236fa5e4d32SSunny Srivastava void Manager::SetTimerToDetectSVPDOnDbus()
237fa5e4d32SSunny Srivastava {
23858057c18SSunny Srivastava     try
23958057c18SSunny Srivastava     {
240fa5e4d32SSunny Srivastava         static boost::asio::steady_timer timer(*m_ioContext);
241fa5e4d32SSunny Srivastava 
242fa5e4d32SSunny Srivastava         // timer for 2 seconds
243fa5e4d32SSunny Srivastava         auto asyncCancelled = timer.expires_after(std::chrono::seconds(2));
244fa5e4d32SSunny Srivastava 
245fa5e4d32SSunny Srivastava         (asyncCancelled == 0) ? logging::logMessage("Timer started")
246fa5e4d32SSunny Srivastava                               : logging::logMessage("Timer re-started");
247fa5e4d32SSunny Srivastava 
248fa5e4d32SSunny Srivastava         timer.async_wait([this](const boost::system::error_code& ec) {
249fa5e4d32SSunny Srivastava             if (ec == boost::asio::error::operation_aborted)
250fa5e4d32SSunny Srivastava             {
251fa5e4d32SSunny Srivastava                 throw std::runtime_error(
25258057c18SSunny Srivastava                     std::string(__FUNCTION__) +
25358057c18SSunny Srivastava                     ": Timer to detect system VPD collection status was aborted.");
254fa5e4d32SSunny Srivastava             }
255fa5e4d32SSunny Srivastava 
256fa5e4d32SSunny Srivastava             if (ec)
257fa5e4d32SSunny Srivastava             {
258fa5e4d32SSunny Srivastava                 throw std::runtime_error(
25958057c18SSunny Srivastava                     std::string(__FUNCTION__) +
26058057c18SSunny Srivastava                     ": Timer to detect System VPD collection failed");
261fa5e4d32SSunny Srivastava             }
262fa5e4d32SSunny Srivastava 
263fa5e4d32SSunny Srivastava             if (m_worker->isSystemVPDOnDBus())
264fa5e4d32SSunny Srivastava             {
265fa5e4d32SSunny Srivastava                 // cancel the timer
266fa5e4d32SSunny Srivastava                 timer.cancel();
267fa5e4d32SSunny Srivastava 
268fa5e4d32SSunny Srivastava                 // Triggering FRU VPD collection. Setting status to "In
269fa5e4d32SSunny Srivastava                 // Progress".
270fa5e4d32SSunny Srivastava                 m_interface->set_property("CollectionStatus",
271fa5e4d32SSunny Srivastava                                           std::string("InProgress"));
272fa5e4d32SSunny Srivastava                 m_worker->collectFrusFromJson();
273fa5e4d32SSunny Srivastava             }
274fa5e4d32SSunny Srivastava         });
275fa5e4d32SSunny Srivastava     }
27658057c18SSunny Srivastava     catch (const std::exception& l_ex)
27758057c18SSunny Srivastava     {
27858057c18SSunny Srivastava         EventLogger::createAsyncPel(
27958057c18SSunny Srivastava             EventLogger::getErrorType(l_ex), types::SeverityType::Critical,
28058057c18SSunny Srivastava             __FILE__, __FUNCTION__, 0,
28158057c18SSunny Srivastava             std::string("Collection for FRUs failed with reason:") +
28258057c18SSunny Srivastava                 EventLogger::getErrorMsg(l_ex),
28358057c18SSunny Srivastava             std::nullopt, std::nullopt, std::nullopt, std::nullopt);
28458057c18SSunny Srivastava     }
28558057c18SSunny Srivastava }
286fa5e4d32SSunny Srivastava 
287fa5e4d32SSunny Srivastava void Manager::SetTimerToDetectVpdCollectionStatus()
288fa5e4d32SSunny Srivastava {
28959f91a84SSunny Srivastava     // Keeping max retry for 2 minutes. TODO: Make it configurable based on
290fa5e4d32SSunny Srivastava     // system type.
29159f91a84SSunny Srivastava     static constexpr auto MAX_RETRY = 12;
292fa5e4d32SSunny Srivastava 
293fa5e4d32SSunny Srivastava     static boost::asio::steady_timer l_timer(*m_ioContext);
294fa5e4d32SSunny Srivastava     static uint8_t l_timerRetry = 0;
295fa5e4d32SSunny Srivastava 
29659f91a84SSunny Srivastava     auto l_asyncCancelled = l_timer.expires_after(std::chrono::seconds(10));
297fa5e4d32SSunny Srivastava 
298fa5e4d32SSunny Srivastava     (l_asyncCancelled == 0)
299fa5e4d32SSunny Srivastava         ? logging::logMessage("Collection Timer started")
300fa5e4d32SSunny Srivastava         : logging::logMessage("Collection Timer re-started");
301fa5e4d32SSunny Srivastava 
302fa5e4d32SSunny Srivastava     l_timer.async_wait([this](const boost::system::error_code& ec) {
303fa5e4d32SSunny Srivastava         if (ec == boost::asio::error::operation_aborted)
304fa5e4d32SSunny Srivastava         {
305fa5e4d32SSunny Srivastava             throw std::runtime_error(
306fa5e4d32SSunny Srivastava                 "Timer to detect thread collection status was aborted");
307fa5e4d32SSunny Srivastava         }
308fa5e4d32SSunny Srivastava 
309fa5e4d32SSunny Srivastava         if (ec)
310fa5e4d32SSunny Srivastava         {
311fa5e4d32SSunny Srivastava             throw std::runtime_error(
312fa5e4d32SSunny Srivastava                 "Timer to detect thread collection failed");
313fa5e4d32SSunny Srivastava         }
314fa5e4d32SSunny Srivastava 
315fa5e4d32SSunny Srivastava         if (m_worker->isAllFruCollectionDone())
316fa5e4d32SSunny Srivastava         {
317fa5e4d32SSunny Srivastava             // cancel the timer
318fa5e4d32SSunny Srivastava             l_timer.cancel();
3191f4c8f81SSouvik Roy             processFailedEeproms();
3204c7798aaSSunny Srivastava 
3214c7798aaSSunny Srivastava             // update VPD for powerVS system.
3224c7798aaSSunny Srivastava             ConfigurePowerVsSystem();
3234c7798aaSSunny Srivastava 
324fa5e4d32SSunny Srivastava             m_interface->set_property("CollectionStatus",
325fa5e4d32SSunny Srivastava                                       std::string("Completed"));
326fa5e4d32SSunny Srivastava 
327fa5e4d32SSunny Srivastava             const nlohmann::json& l_sysCfgJsonObj =
328fa5e4d32SSunny Srivastava                 m_worker->getSysCfgJsonObj();
329fa5e4d32SSunny Srivastava             if (jsonUtility::isBackupAndRestoreRequired(l_sysCfgJsonObj))
330fa5e4d32SSunny Srivastava             {
331fa5e4d32SSunny Srivastava                 BackupAndRestore l_backupAndRestoreObj(l_sysCfgJsonObj);
332fa5e4d32SSunny Srivastava                 l_backupAndRestoreObj.backupAndRestore();
333fa5e4d32SSunny Srivastava             }
334fa5e4d32SSunny Srivastava         }
335fa5e4d32SSunny Srivastava         else
336fa5e4d32SSunny Srivastava         {
337fa5e4d32SSunny Srivastava             auto l_threadCount = m_worker->getActiveThreadCount();
338fa5e4d32SSunny Srivastava             if (l_timerRetry == MAX_RETRY)
339fa5e4d32SSunny Srivastava             {
340fa5e4d32SSunny Srivastava                 l_timer.cancel();
341fa5e4d32SSunny Srivastava                 logging::logMessage("Taking too long. Active thread = " +
342fa5e4d32SSunny Srivastava                                     std::to_string(l_threadCount));
343fa5e4d32SSunny Srivastava             }
344fa5e4d32SSunny Srivastava             else
345fa5e4d32SSunny Srivastava             {
346fa5e4d32SSunny Srivastava                 l_timerRetry++;
34759f91a84SSunny Srivastava                 logging::logMessage("Collection is in progress for [" +
34859f91a84SSunny Srivastava                                     std::to_string(l_threadCount) + "] FRUs.");
349fa5e4d32SSunny Srivastava 
350fa5e4d32SSunny Srivastava                 SetTimerToDetectVpdCollectionStatus();
351fa5e4d32SSunny Srivastava             }
352fa5e4d32SSunny Srivastava         }
353fa5e4d32SSunny Srivastava     });
354fa5e4d32SSunny Srivastava }
3554c7798aaSSunny Srivastava 
356022112bcSSunny Srivastava void Manager::checkAndUpdatePowerVsVpd(
357022112bcSSunny Srivastava     const nlohmann::json& i_powerVsJsonObj,
358022112bcSSunny Srivastava     std::vector<std::string>& o_failedPathList)
359022112bcSSunny Srivastava {
3600cd15e1eSSunny Srivastava     for (const auto& [l_fruPath, l_recJson] : i_powerVsJsonObj.items())
3610cd15e1eSSunny Srivastava     {
3620cd15e1eSSunny Srivastava         nlohmann::json l_sysCfgJsonObj{};
3630cd15e1eSSunny Srivastava         if (m_worker.get() != nullptr)
3640cd15e1eSSunny Srivastava         {
3650cd15e1eSSunny Srivastava             l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
3660cd15e1eSSunny Srivastava         }
3670cd15e1eSSunny Srivastava 
368f1dda767SSunny Srivastava         // The utility method will handle emty JSON case. No explicit
3690cd15e1eSSunny Srivastava         // handling required here.
3700cd15e1eSSunny Srivastava         auto l_inventoryPath = jsonUtility::getInventoryObjPathFromJson(
3710cd15e1eSSunny Srivastava             l_sysCfgJsonObj, l_fruPath);
3720cd15e1eSSunny Srivastava 
3730cd15e1eSSunny Srivastava         // Mark it as failed if inventory path not found in JSON.
3740cd15e1eSSunny Srivastava         if (l_inventoryPath.empty())
3750cd15e1eSSunny Srivastava         {
3760cd15e1eSSunny Srivastava             o_failedPathList.push_back(l_fruPath);
3770cd15e1eSSunny Srivastava             continue;
3780cd15e1eSSunny Srivastava         }
3790cd15e1eSSunny Srivastava 
380f1dda767SSunny Srivastava         // check if the FRU is present
381f1dda767SSunny Srivastava         if (!dbusUtility::isInventoryPresent(l_inventoryPath))
382f1dda767SSunny Srivastava         {
383f1dda767SSunny Srivastava             logging::logMessage(
384f1dda767SSunny Srivastava                 "Inventory not present, skip updating part number. Path: " +
385f1dda767SSunny Srivastava                 l_inventoryPath);
386f1dda767SSunny Srivastava             continue;
387f1dda767SSunny Srivastava         }
388f1dda767SSunny Srivastava 
389f1dda767SSunny Srivastava         // check if the FRU needs CCIN check before updating PN.
390f1dda767SSunny Srivastava         if (l_recJson.contains("CCIN"))
391f1dda767SSunny Srivastava         {
392f1dda767SSunny Srivastava             const auto& l_ccinFromDbus =
393f1dda767SSunny Srivastava                 vpdSpecificUtility::getCcinFromDbus(l_inventoryPath);
394f1dda767SSunny Srivastava 
395f1dda767SSunny Srivastava             // Not an ideal situation as CCIN can't be empty.
396f1dda767SSunny Srivastava             if (l_ccinFromDbus.empty())
397f1dda767SSunny Srivastava             {
398f1dda767SSunny Srivastava                 o_failedPathList.push_back(l_fruPath);
399f1dda767SSunny Srivastava                 continue;
400f1dda767SSunny Srivastava             }
401f1dda767SSunny Srivastava 
402f1dda767SSunny Srivastava             std::vector<std::string> l_ccinListFromJson = l_recJson["CCIN"];
403f1dda767SSunny Srivastava 
404f1dda767SSunny Srivastava             if (find(l_ccinListFromJson.begin(), l_ccinListFromJson.end(),
405f1dda767SSunny Srivastava                      l_ccinFromDbus) == l_ccinListFromJson.end())
406f1dda767SSunny Srivastava             {
407f1dda767SSunny Srivastava                 // Don't update PN in this case.
408f1dda767SSunny Srivastava                 continue;
409f1dda767SSunny Srivastava             }
410f1dda767SSunny Srivastava         }
411f1dda767SSunny Srivastava 
412f1dda767SSunny Srivastava         for (const auto& [l_recordName, l_kwdJson] : l_recJson.items())
413f1dda767SSunny Srivastava         {
414f1dda767SSunny Srivastava             // Record name can't be CCIN, skip processing as it is there for PN
415f1dda767SSunny Srivastava             // update based on CCIN check.
416f1dda767SSunny Srivastava             if (l_recordName == constants::kwdCCIN)
417f1dda767SSunny Srivastava             {
418f1dda767SSunny Srivastava                 continue;
419f1dda767SSunny Srivastava             }
420f1dda767SSunny Srivastava 
421f1dda767SSunny Srivastava             for (const auto& [l_kwdName, l_kwdValue] : l_kwdJson.items())
422f1dda767SSunny Srivastava             {
423f1dda767SSunny Srivastava                 // Is value of type array.
424f1dda767SSunny Srivastava                 if (!l_kwdValue.is_array())
425f1dda767SSunny Srivastava                 {
426f1dda767SSunny Srivastava                     o_failedPathList.push_back(l_fruPath);
427f1dda767SSunny Srivastava                     continue;
428f1dda767SSunny Srivastava                 }
429f1dda767SSunny Srivastava 
43022793834SSunny Srivastava                 // Get current FRU Part number.
4310cd15e1eSSunny Srivastava                 auto l_retVal = dbusUtility::readDbusProperty(
4320cd15e1eSSunny Srivastava                     constants::pimServiceName, l_inventoryPath,
43322793834SSunny Srivastava                     constants::viniInf, constants::kwdFN);
4340cd15e1eSSunny Srivastava 
43522793834SSunny Srivastava                 auto l_ptrToFn = std::get_if<types::BinaryVector>(&l_retVal);
4360cd15e1eSSunny Srivastava 
43722793834SSunny Srivastava                 if (!l_ptrToFn)
4380cd15e1eSSunny Srivastava                 {
4390cd15e1eSSunny Srivastava                     o_failedPathList.push_back(l_fruPath);
4400cd15e1eSSunny Srivastava                     continue;
4410cd15e1eSSunny Srivastava                 }
4420cd15e1eSSunny Srivastava 
4430cd15e1eSSunny Srivastava                 types::BinaryVector l_binaryKwdValue =
4440cd15e1eSSunny Srivastava                     l_kwdValue.get<types::BinaryVector>();
44522793834SSunny Srivastava                 if (l_binaryKwdValue == (*l_ptrToFn))
4460cd15e1eSSunny Srivastava                 {
4470cd15e1eSSunny Srivastava                     continue;
4480cd15e1eSSunny Srivastava                 }
4490cd15e1eSSunny Srivastava 
4500cd15e1eSSunny Srivastava                 // Update part number only if required.
4510cd15e1eSSunny Srivastava                 if (updateKeyword(
4520cd15e1eSSunny Srivastava                         l_fruPath,
4530cd15e1eSSunny Srivastava                         std::make_tuple(l_recordName, l_kwdName, l_kwdValue)) ==
4540cd15e1eSSunny Srivastava                     constants::FAILURE)
4550cd15e1eSSunny Srivastava                 {
4560cd15e1eSSunny Srivastava                     o_failedPathList.push_back(l_fruPath);
4570cd15e1eSSunny Srivastava                     continue;
4580cd15e1eSSunny Srivastava                 }
4590cd15e1eSSunny Srivastava 
46022793834SSunny Srivastava                 // update the Asset interface Spare part number explicitly.
461b83cb35fSSunny Srivastava                 if (!dbusUtility::callPIM(types::ObjectMap{
462b83cb35fSSunny Srivastava                         {l_inventoryPath,
46322793834SSunny Srivastava                          {{constants::assetInf,
46422793834SSunny Srivastava                            {{"SparePartNumber",
465b83cb35fSSunny Srivastava                              std::string(l_binaryKwdValue.begin(),
466b83cb35fSSunny Srivastava                                          l_binaryKwdValue.end())}}}}}}))
467b83cb35fSSunny Srivastava                 {
468b83cb35fSSunny Srivastava                     logging::logMessage(
46922793834SSunny Srivastava                         "Updating Spare Part Number under Asset interface failed for path [" +
470b83cb35fSSunny Srivastava                         l_inventoryPath + "]");
471b83cb35fSSunny Srivastava                 }
472b83cb35fSSunny Srivastava 
4730cd15e1eSSunny Srivastava                 // Just needed for logging.
47422793834SSunny Srivastava                 std::string l_initialPartNum((*l_ptrToFn).begin(),
47522793834SSunny Srivastava                                              (*l_ptrToFn).end());
4760cd15e1eSSunny Srivastava                 std::string l_finalPartNum(l_binaryKwdValue.begin(),
4770cd15e1eSSunny Srivastava                                            l_binaryKwdValue.end());
4780cd15e1eSSunny Srivastava                 logging::logMessage(
47922793834SSunny Srivastava                     "FRU Part number updated for path [" + l_inventoryPath +
48022793834SSunny Srivastava                     "]" + "From [" + l_initialPartNum + "]" + " to [" +
4810cd15e1eSSunny Srivastava                     l_finalPartNum + "]");
4820cd15e1eSSunny Srivastava             }
4830cd15e1eSSunny Srivastava         }
4840cd15e1eSSunny Srivastava     }
485022112bcSSunny Srivastava }
486022112bcSSunny Srivastava 
4874c7798aaSSunny Srivastava void Manager::ConfigurePowerVsSystem()
4884c7798aaSSunny Srivastava {
489022112bcSSunny Srivastava     std::vector<std::string> l_failedPathList;
4901a48f0ceSSunny Srivastava     try
4911a48f0ceSSunny Srivastava     {
4921a48f0ceSSunny Srivastava         types::BinaryVector l_imValue = dbusUtility::getImFromDbus();
4931a48f0ceSSunny Srivastava         if (l_imValue.empty())
4941a48f0ceSSunny Srivastava         {
4951a48f0ceSSunny Srivastava             throw DbusException("Invalid IM value read from Dbus");
4961a48f0ceSSunny Srivastava         }
497c6ef42d6SSunny Srivastava 
498c6ef42d6SSunny Srivastava         if (!vpdSpecificUtility::isPowerVsConfiguration(l_imValue))
499c6ef42d6SSunny Srivastava         {
500c6ef42d6SSunny Srivastava             // TODO: Should booting be blocked in case of some
501c6ef42d6SSunny Srivastava             // misconfigurations?
502c6ef42d6SSunny Srivastava             return;
503c6ef42d6SSunny Srivastava         }
504022112bcSSunny Srivastava 
505022112bcSSunny Srivastava         const nlohmann::json& l_powerVsJsonObj =
506022112bcSSunny Srivastava             jsonUtility::getPowerVsJson(l_imValue);
507022112bcSSunny Srivastava 
508022112bcSSunny Srivastava         if (l_powerVsJsonObj.empty())
509022112bcSSunny Srivastava         {
510022112bcSSunny Srivastava             throw std::runtime_error("PowerVS Json not found");
511022112bcSSunny Srivastava         }
512022112bcSSunny Srivastava 
513022112bcSSunny Srivastava         checkAndUpdatePowerVsVpd(l_powerVsJsonObj, l_failedPathList);
514022112bcSSunny Srivastava 
515022112bcSSunny Srivastava         if (!l_failedPathList.empty())
516022112bcSSunny Srivastava         {
517022112bcSSunny Srivastava             throw std::runtime_error(
518022112bcSSunny Srivastava                 "Part number update failed for following paths: ");
519022112bcSSunny Srivastava         }
5201a48f0ceSSunny Srivastava     }
5211a48f0ceSSunny Srivastava     catch (const std::exception& l_ex)
5221a48f0ceSSunny Srivastava     {
5231a48f0ceSSunny Srivastava         // TODO log appropriate PEL
5241a48f0ceSSunny Srivastava     }
5254c7798aaSSunny Srivastava }
52646f2981aSSunny Srivastava 
52746f2981aSSunny Srivastava void Manager::processFailedEeproms()
52846f2981aSSunny Srivastava {
52946f2981aSSunny Srivastava     if (m_worker.get() != nullptr)
53046f2981aSSunny Srivastava     {
53146f2981aSSunny Srivastava         // TODO:
53246f2981aSSunny Srivastava         // - iterate through list of EEPROMs for which thread creation has
53346f2981aSSunny Srivastava         // failed
53446f2981aSSunny Srivastava         // - For each failed EEPROM, trigger VPD collection
53546f2981aSSunny Srivastava         m_worker->getFailedEepromPaths().clear();
53646f2981aSSunny Srivastava     }
53746f2981aSSunny Srivastava }
538fa5e4d32SSunny Srivastava #endif
539fa5e4d32SSunny Srivastava 
540fa5e4d32SSunny Srivastava int Manager::updateKeyword(const types::Path i_vpdPath,
541fa5e4d32SSunny Srivastava                            const types::WriteVpdParams i_paramsToWriteData)
542fa5e4d32SSunny Srivastava {
543fa5e4d32SSunny Srivastava     if (i_vpdPath.empty())
544fa5e4d32SSunny Srivastava     {
545fa5e4d32SSunny Srivastava         logging::logMessage("Given VPD path is empty.");
546fa5e4d32SSunny Srivastava         return -1;
547fa5e4d32SSunny Srivastava     }
548fa5e4d32SSunny Srivastava 
549fa5e4d32SSunny Srivastava     types::Path l_fruPath;
550fa5e4d32SSunny Srivastava     nlohmann::json l_sysCfgJsonObj{};
551fa5e4d32SSunny Srivastava 
552fa5e4d32SSunny Srivastava     if (m_worker.get() != nullptr)
553fa5e4d32SSunny Srivastava     {
554fa5e4d32SSunny Srivastava         l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
555fa5e4d32SSunny Srivastava 
556fa5e4d32SSunny Srivastava         // Get the EEPROM path
557fa5e4d32SSunny Srivastava         if (!l_sysCfgJsonObj.empty())
558fa5e4d32SSunny Srivastava         {
559fa5e4d32SSunny Srivastava             l_fruPath =
560fa5e4d32SSunny Srivastava                 jsonUtility::getFruPathFromJson(l_sysCfgJsonObj, i_vpdPath);
561fa5e4d32SSunny Srivastava         }
562fa5e4d32SSunny Srivastava     }
563fa5e4d32SSunny Srivastava 
564fa5e4d32SSunny Srivastava     if (l_fruPath.empty())
565fa5e4d32SSunny Srivastava     {
566fa5e4d32SSunny Srivastava         l_fruPath = i_vpdPath;
567fa5e4d32SSunny Srivastava     }
568fa5e4d32SSunny Srivastava 
569fa5e4d32SSunny Srivastava     try
570fa5e4d32SSunny Srivastava     {
571fa5e4d32SSunny Srivastava         std::shared_ptr<Parser> l_parserObj =
572fa5e4d32SSunny Srivastava             std::make_shared<Parser>(l_fruPath, l_sysCfgJsonObj);
573fa5e4d32SSunny Srivastava         return l_parserObj->updateVpdKeyword(i_paramsToWriteData);
574fa5e4d32SSunny Srivastava     }
575fa5e4d32SSunny Srivastava     catch (const std::exception& l_exception)
576fa5e4d32SSunny Srivastava     {
577fa5e4d32SSunny Srivastava         // TODO:: error log needed
578fa5e4d32SSunny Srivastava         logging::logMessage("Update keyword failed for file[" + i_vpdPath +
579fa5e4d32SSunny Srivastava                             "], reason: " + std::string(l_exception.what()));
580fa5e4d32SSunny Srivastava         return -1;
581fa5e4d32SSunny Srivastava     }
582fa5e4d32SSunny Srivastava }
583fa5e4d32SSunny Srivastava 
584fa5e4d32SSunny Srivastava int Manager::updateKeywordOnHardware(
585fa5e4d32SSunny Srivastava     const types::Path i_fruPath,
586fa5e4d32SSunny Srivastava     const types::WriteVpdParams i_paramsToWriteData) noexcept
587fa5e4d32SSunny Srivastava {
588fa5e4d32SSunny Srivastava     try
589fa5e4d32SSunny Srivastava     {
590fa5e4d32SSunny Srivastava         if (i_fruPath.empty())
591fa5e4d32SSunny Srivastava         {
592fa5e4d32SSunny Srivastava             throw std::runtime_error("Given FRU path is empty");
593fa5e4d32SSunny Srivastava         }
594fa5e4d32SSunny Srivastava 
595fa5e4d32SSunny Srivastava         nlohmann::json l_sysCfgJsonObj{};
596fa5e4d32SSunny Srivastava 
597fa5e4d32SSunny Srivastava         if (m_worker.get() != nullptr)
598fa5e4d32SSunny Srivastava         {
599fa5e4d32SSunny Srivastava             l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
600fa5e4d32SSunny Srivastava         }
601fa5e4d32SSunny Srivastava 
602fa5e4d32SSunny Srivastava         std::shared_ptr<Parser> l_parserObj =
603fa5e4d32SSunny Srivastava             std::make_shared<Parser>(i_fruPath, l_sysCfgJsonObj);
604fa5e4d32SSunny Srivastava         return l_parserObj->updateVpdKeywordOnHardware(i_paramsToWriteData);
605fa5e4d32SSunny Srivastava     }
606fa5e4d32SSunny Srivastava     catch (const std::exception& l_exception)
607fa5e4d32SSunny Srivastava     {
608fa5e4d32SSunny Srivastava         EventLogger::createAsyncPel(
609fa5e4d32SSunny Srivastava             types::ErrorType::InvalidEeprom, types::SeverityType::Informational,
610fa5e4d32SSunny Srivastava             __FILE__, __FUNCTION__, 0,
611fa5e4d32SSunny Srivastava             "Update keyword on hardware failed for file[" + i_fruPath +
612fa5e4d32SSunny Srivastava                 "], reason: " + std::string(l_exception.what()),
613fa5e4d32SSunny Srivastava             std::nullopt, std::nullopt, std::nullopt, std::nullopt);
614fa5e4d32SSunny Srivastava 
615fa5e4d32SSunny Srivastava         return constants::FAILURE;
616fa5e4d32SSunny Srivastava     }
617fa5e4d32SSunny Srivastava }
618fa5e4d32SSunny Srivastava 
619fa5e4d32SSunny Srivastava types::DbusVariantType Manager::readKeyword(
620fa5e4d32SSunny Srivastava     const types::Path i_fruPath, const types::ReadVpdParams i_paramsToReadData)
621fa5e4d32SSunny Srivastava {
622fa5e4d32SSunny Srivastava     try
623fa5e4d32SSunny Srivastava     {
624fa5e4d32SSunny Srivastava         nlohmann::json l_jsonObj{};
625fa5e4d32SSunny Srivastava 
626fa5e4d32SSunny Srivastava         if (m_worker.get() != nullptr)
627fa5e4d32SSunny Srivastava         {
628fa5e4d32SSunny Srivastava             l_jsonObj = m_worker->getSysCfgJsonObj();
629fa5e4d32SSunny Srivastava         }
630fa5e4d32SSunny Srivastava 
631fa5e4d32SSunny Srivastava         std::error_code ec;
632fa5e4d32SSunny Srivastava 
633fa5e4d32SSunny Srivastava         // Check if given path is filesystem path
634fa5e4d32SSunny Srivastava         if (!std::filesystem::exists(i_fruPath, ec) && (ec))
635fa5e4d32SSunny Srivastava         {
636fa5e4d32SSunny Srivastava             throw std::runtime_error(
637fa5e4d32SSunny Srivastava                 "Given file path " + i_fruPath + " not found.");
638fa5e4d32SSunny Srivastava         }
639fa5e4d32SSunny Srivastava 
640fa5e4d32SSunny Srivastava         logging::logMessage("Performing VPD read on " + i_fruPath);
641fa5e4d32SSunny Srivastava 
642fa5e4d32SSunny Srivastava         std::shared_ptr<vpd::Parser> l_parserObj =
643fa5e4d32SSunny Srivastava             std::make_shared<vpd::Parser>(i_fruPath, l_jsonObj);
644fa5e4d32SSunny Srivastava 
645fa5e4d32SSunny Srivastava         std::shared_ptr<vpd::ParserInterface> l_vpdParserInstance =
646fa5e4d32SSunny Srivastava             l_parserObj->getVpdParserInstance();
647fa5e4d32SSunny Srivastava 
648fa5e4d32SSunny Srivastava         return (
649fa5e4d32SSunny Srivastava             l_vpdParserInstance->readKeywordFromHardware(i_paramsToReadData));
650fa5e4d32SSunny Srivastava     }
651fa5e4d32SSunny Srivastava     catch (const std::exception& e)
652fa5e4d32SSunny Srivastava     {
653fa5e4d32SSunny Srivastava         logging::logMessage(
654fa5e4d32SSunny Srivastava             e.what() + std::string(". VPD manager read operation failed for ") +
655fa5e4d32SSunny Srivastava             i_fruPath);
656fa5e4d32SSunny Srivastava         throw types::DeviceError::ReadFailure();
657fa5e4d32SSunny Srivastava     }
658fa5e4d32SSunny Srivastava }
659fa5e4d32SSunny Srivastava 
660fa5e4d32SSunny Srivastava void Manager::collectSingleFruVpd(
661fa5e4d32SSunny Srivastava     const sdbusplus::message::object_path& i_dbusObjPath)
662fa5e4d32SSunny Srivastava {
663fa5e4d32SSunny Srivastava     try
664fa5e4d32SSunny Srivastava     {
665fa5e4d32SSunny Srivastava         if (m_vpdCollectionStatus != "Completed")
666fa5e4d32SSunny Srivastava         {
66746b73d9fSPriyanga Ramasamy             logging::logMessage(
668fa5e4d32SSunny Srivastava                 "Currently VPD CollectionStatus is not completed. Cannot perform single FRU VPD collection for " +
669fa5e4d32SSunny Srivastava                 std::string(i_dbusObjPath));
67046b73d9fSPriyanga Ramasamy             return;
671fa5e4d32SSunny Srivastava         }
672fa5e4d32SSunny Srivastava 
673fa5e4d32SSunny Srivastava         // Get system config JSON object from worker class
674fa5e4d32SSunny Srivastava         nlohmann::json l_sysCfgJsonObj{};
675fa5e4d32SSunny Srivastava 
676fa5e4d32SSunny Srivastava         if (m_worker.get() != nullptr)
677fa5e4d32SSunny Srivastava         {
678fa5e4d32SSunny Srivastava             l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
679fa5e4d32SSunny Srivastava         }
680fa5e4d32SSunny Srivastava 
681fa5e4d32SSunny Srivastava         // Check if system config JSON is present
682fa5e4d32SSunny Srivastava         if (l_sysCfgJsonObj.empty())
683fa5e4d32SSunny Srivastava         {
68446b73d9fSPriyanga Ramasamy             logging::logMessage(
68546b73d9fSPriyanga Ramasamy                 "System config JSON object not present. Single FRU VPD collection is not performed for " +
686fa5e4d32SSunny Srivastava                 std::string(i_dbusObjPath));
68746b73d9fSPriyanga Ramasamy             return;
688fa5e4d32SSunny Srivastava         }
689fa5e4d32SSunny Srivastava 
690fa5e4d32SSunny Srivastava         // Get FRU path for the given D-bus object path from JSON
691fa5e4d32SSunny Srivastava         const std::string& l_fruPath =
692fa5e4d32SSunny Srivastava             jsonUtility::getFruPathFromJson(l_sysCfgJsonObj, i_dbusObjPath);
693fa5e4d32SSunny Srivastava 
694fa5e4d32SSunny Srivastava         if (l_fruPath.empty())
695fa5e4d32SSunny Srivastava         {
69646b73d9fSPriyanga Ramasamy             logging::logMessage(
69746b73d9fSPriyanga Ramasamy                 "D-bus object path not present in JSON. Single FRU VPD collection is not performed for " +
698fa5e4d32SSunny Srivastava                 std::string(i_dbusObjPath));
69946b73d9fSPriyanga Ramasamy             return;
700fa5e4d32SSunny Srivastava         }
701fa5e4d32SSunny Srivastava 
702fa5e4d32SSunny Srivastava         // Check if host is up and running
703fa5e4d32SSunny Srivastava         if (dbusUtility::isHostRunning())
704fa5e4d32SSunny Srivastava         {
705fa5e4d32SSunny Srivastava             if (!jsonUtility::isFruReplaceableAtRuntime(l_sysCfgJsonObj,
706fa5e4d32SSunny Srivastava                                                         l_fruPath))
707fa5e4d32SSunny Srivastava             {
70846b73d9fSPriyanga Ramasamy                 logging::logMessage(
70946b73d9fSPriyanga Ramasamy                     "Given FRU is not replaceable at host runtime. Single FRU VPD collection is not performed for " +
710fa5e4d32SSunny Srivastava                     std::string(i_dbusObjPath));
71146b73d9fSPriyanga Ramasamy                 return;
712fa5e4d32SSunny Srivastava             }
713fa5e4d32SSunny Srivastava         }
714fa5e4d32SSunny Srivastava         else if (dbusUtility::isBMCReady())
715fa5e4d32SSunny Srivastava         {
716fa5e4d32SSunny Srivastava             if (!jsonUtility::isFruReplaceableAtStandby(l_sysCfgJsonObj,
717fa5e4d32SSunny Srivastava                                                         l_fruPath) &&
718fa5e4d32SSunny Srivastava                 (!jsonUtility::isFruReplaceableAtRuntime(l_sysCfgJsonObj,
719fa5e4d32SSunny Srivastava                                                          l_fruPath)))
720fa5e4d32SSunny Srivastava             {
72146b73d9fSPriyanga Ramasamy                 logging::logMessage(
72246b73d9fSPriyanga Ramasamy                     "Given FRU is neither replaceable at standby nor replaceable at runtime. Single FRU VPD collection is not performed for " +
723fa5e4d32SSunny Srivastava                     std::string(i_dbusObjPath));
72446b73d9fSPriyanga Ramasamy                 return;
725fa5e4d32SSunny Srivastava             }
726fa5e4d32SSunny Srivastava         }
727fa5e4d32SSunny Srivastava 
72846b73d9fSPriyanga Ramasamy         // Set CollectionStatus as InProgress. Since it's an intermediate state
72946b73d9fSPriyanga Ramasamy         // D-bus set-property call is good enough to update the status.
73046b73d9fSPriyanga Ramasamy         const std::string& l_collStatusProp = "CollectionStatus";
731c532b188SRekhaAparna01 
732c532b188SRekhaAparna01         if (!dbusUtility::writeDbusProperty(
73346b73d9fSPriyanga Ramasamy                 jsonUtility::getServiceName(l_sysCfgJsonObj,
73446b73d9fSPriyanga Ramasamy                                             std::string(i_dbusObjPath)),
73546b73d9fSPriyanga Ramasamy                 std::string(i_dbusObjPath), constants::vpdCollectionInterface,
73646b73d9fSPriyanga Ramasamy                 l_collStatusProp,
737c532b188SRekhaAparna01                 types::DbusVariantType{constants::vpdCollectionInProgress}))
73846b73d9fSPriyanga Ramasamy         {
73946b73d9fSPriyanga Ramasamy             logging::logMessage(
74046b73d9fSPriyanga Ramasamy                 "Unable to set CollectionStatus as InProgress for " +
74146b73d9fSPriyanga Ramasamy                 std::string(i_dbusObjPath) +
74246b73d9fSPriyanga Ramasamy                 ". Continue single FRU VPD collection.");
74346b73d9fSPriyanga Ramasamy         }
74446b73d9fSPriyanga Ramasamy 
745fa5e4d32SSunny Srivastava         // Parse VPD
746fa5e4d32SSunny Srivastava         types::VPDMapVariant l_parsedVpd = m_worker->parseVpdFile(l_fruPath);
747fa5e4d32SSunny Srivastava 
748fa5e4d32SSunny Srivastava         // If l_parsedVpd is pointing to std::monostate
749fa5e4d32SSunny Srivastava         if (l_parsedVpd.index() == 0)
750fa5e4d32SSunny Srivastava         {
751fa5e4d32SSunny Srivastava             throw std::runtime_error(
752fa5e4d32SSunny Srivastava                 "VPD parsing failed for " + std::string(i_dbusObjPath));
753fa5e4d32SSunny Srivastava         }
754fa5e4d32SSunny Srivastava 
755fa5e4d32SSunny Srivastava         // Get D-bus object map from worker class
756fa5e4d32SSunny Srivastava         types::ObjectMap l_dbusObjectMap;
757fa5e4d32SSunny Srivastava         m_worker->populateDbus(l_parsedVpd, l_dbusObjectMap, l_fruPath);
758fa5e4d32SSunny Srivastava 
759fa5e4d32SSunny Srivastava         if (l_dbusObjectMap.empty())
760fa5e4d32SSunny Srivastava         {
761fa5e4d32SSunny Srivastava             throw std::runtime_error(
762fa5e4d32SSunny Srivastava                 "Failed to create D-bus object map. Single FRU VPD collection failed for " +
763fa5e4d32SSunny Srivastava                 std::string(i_dbusObjPath));
764fa5e4d32SSunny Srivastava         }
765fa5e4d32SSunny Srivastava 
766fa5e4d32SSunny Srivastava         // Call PIM's Notify method
767fa5e4d32SSunny Srivastava         if (!dbusUtility::callPIM(move(l_dbusObjectMap)))
768fa5e4d32SSunny Srivastava         {
769fa5e4d32SSunny Srivastava             throw std::runtime_error(
770fa5e4d32SSunny Srivastava                 "Notify PIM failed. Single FRU VPD collection failed for " +
771fa5e4d32SSunny Srivastava                 std::string(i_dbusObjPath));
772fa5e4d32SSunny Srivastava         }
773fa5e4d32SSunny Srivastava     }
774fa5e4d32SSunny Srivastava     catch (const std::exception& l_error)
775fa5e4d32SSunny Srivastava     {
77646b73d9fSPriyanga Ramasamy         // Notify FRU's VPD CollectionStatus as Failure
77746b73d9fSPriyanga Ramasamy         if (!dbusUtility::notifyFRUCollectionStatus(
77846b73d9fSPriyanga Ramasamy                 std::string(i_dbusObjPath), constants::vpdCollectionFailure))
77946b73d9fSPriyanga Ramasamy         {
78046b73d9fSPriyanga Ramasamy             logging::logMessage(
78146b73d9fSPriyanga Ramasamy                 "Call to PIM Notify method failed to update Collection status as Failure for " +
78246b73d9fSPriyanga Ramasamy                 std::string(i_dbusObjPath));
78346b73d9fSPriyanga Ramasamy         }
78446b73d9fSPriyanga Ramasamy 
785fa5e4d32SSunny Srivastava         // TODO: Log PEL
786fa5e4d32SSunny Srivastava         logging::logMessage(std::string(l_error.what()));
787fa5e4d32SSunny Srivastava     }
788fa5e4d32SSunny Srivastava }
789fa5e4d32SSunny Srivastava 
790fa5e4d32SSunny Srivastava void Manager::deleteSingleFruVpd(
791fa5e4d32SSunny Srivastava     const sdbusplus::message::object_path& i_dbusObjPath)
792fa5e4d32SSunny Srivastava {
793fa5e4d32SSunny Srivastava     try
794fa5e4d32SSunny Srivastava     {
795fa5e4d32SSunny Srivastava         if (std::string(i_dbusObjPath).empty())
796fa5e4d32SSunny Srivastava         {
797fa5e4d32SSunny Srivastava             throw std::runtime_error(
798fa5e4d32SSunny Srivastava                 "Given DBus object path is empty. Aborting FRU VPD deletion.");
799fa5e4d32SSunny Srivastava         }
800fa5e4d32SSunny Srivastava 
801fa5e4d32SSunny Srivastava         if (m_worker.get() == nullptr)
802fa5e4d32SSunny Srivastava         {
803fa5e4d32SSunny Srivastava             throw std::runtime_error(
804fa5e4d32SSunny Srivastava                 "Worker object not found, can't perform FRU VPD deletion for: " +
805fa5e4d32SSunny Srivastava                 std::string(i_dbusObjPath));
806fa5e4d32SSunny Srivastava         }
807fa5e4d32SSunny Srivastava 
808fa5e4d32SSunny Srivastava         m_worker->deleteFruVpd(std::string(i_dbusObjPath));
809fa5e4d32SSunny Srivastava     }
810fa5e4d32SSunny Srivastava     catch (const std::exception& l_ex)
811fa5e4d32SSunny Srivastava     {
812fa5e4d32SSunny Srivastava         // TODO: Log PEL
813fa5e4d32SSunny Srivastava         logging::logMessage(l_ex.what());
814fa5e4d32SSunny Srivastava     }
815fa5e4d32SSunny Srivastava }
816fa5e4d32SSunny Srivastava 
817fa5e4d32SSunny Srivastava bool Manager::isValidUnexpandedLocationCode(
818fa5e4d32SSunny Srivastava     const std::string& i_unexpandedLocationCode)
819fa5e4d32SSunny Srivastava {
820fa5e4d32SSunny Srivastava     if ((i_unexpandedLocationCode.length() <
821fa5e4d32SSunny Srivastava          constants::UNEXP_LOCATION_CODE_MIN_LENGTH) ||
822fa5e4d32SSunny Srivastava         ((i_unexpandedLocationCode.compare(0, 4, "Ufcs") !=
823fa5e4d32SSunny Srivastava           constants::STR_CMP_SUCCESS) &&
824fa5e4d32SSunny Srivastava          (i_unexpandedLocationCode.compare(0, 4, "Umts") !=
825fa5e4d32SSunny Srivastava           constants::STR_CMP_SUCCESS)) ||
826fa5e4d32SSunny Srivastava         ((i_unexpandedLocationCode.length() >
827fa5e4d32SSunny Srivastava           constants::UNEXP_LOCATION_CODE_MIN_LENGTH) &&
828fa5e4d32SSunny Srivastava          (i_unexpandedLocationCode.find("-") != 4)))
829fa5e4d32SSunny Srivastava     {
830fa5e4d32SSunny Srivastava         return false;
831fa5e4d32SSunny Srivastava     }
832fa5e4d32SSunny Srivastava 
833fa5e4d32SSunny Srivastava     return true;
834fa5e4d32SSunny Srivastava }
835fa5e4d32SSunny Srivastava 
836fa5e4d32SSunny Srivastava std::string Manager::getExpandedLocationCode(
837fa5e4d32SSunny Srivastava     const std::string& i_unexpandedLocationCode,
838fa5e4d32SSunny Srivastava     [[maybe_unused]] const uint16_t i_nodeNumber)
839fa5e4d32SSunny Srivastava {
840fa5e4d32SSunny Srivastava     if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode))
841fa5e4d32SSunny Srivastava     {
842fa5e4d32SSunny Srivastava         phosphor::logging::elog<types::DbusInvalidArgument>(
843fa5e4d32SSunny Srivastava             types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
844fa5e4d32SSunny Srivastava             types::InvalidArgument::ARGUMENT_VALUE(
845fa5e4d32SSunny Srivastava                 i_unexpandedLocationCode.c_str()));
846fa5e4d32SSunny Srivastava     }
847fa5e4d32SSunny Srivastava 
848fa5e4d32SSunny Srivastava     const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
849fa5e4d32SSunny Srivastava     if (!l_sysCfgJsonObj.contains("frus"))
850fa5e4d32SSunny Srivastava     {
851fa5e4d32SSunny Srivastava         logging::logMessage("Missing frus tag in system config JSON");
852fa5e4d32SSunny Srivastava     }
853fa5e4d32SSunny Srivastava 
854fa5e4d32SSunny Srivastava     const nlohmann::json& l_listOfFrus =
855fa5e4d32SSunny Srivastava         l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
856fa5e4d32SSunny Srivastava 
857fa5e4d32SSunny Srivastava     for (const auto& l_frus : l_listOfFrus.items())
858fa5e4d32SSunny Srivastava     {
859fa5e4d32SSunny Srivastava         for (const auto& l_aFru : l_frus.value())
860fa5e4d32SSunny Srivastava         {
861fa5e4d32SSunny Srivastava             if (l_aFru["extraInterfaces"].contains(
862fa5e4d32SSunny Srivastava                     constants::locationCodeInf) &&
863fa5e4d32SSunny Srivastava                 l_aFru["extraInterfaces"][constants::locationCodeInf].value(
864fa5e4d32SSunny Srivastava                     "LocationCode", "") == i_unexpandedLocationCode)
865fa5e4d32SSunny Srivastava             {
866fa5e4d32SSunny Srivastava                 return std::get<std::string>(dbusUtility::readDbusProperty(
867fa5e4d32SSunny Srivastava                     l_aFru["serviceName"], l_aFru["inventoryPath"],
868fa5e4d32SSunny Srivastava                     constants::locationCodeInf, "LocationCode"));
869fa5e4d32SSunny Srivastava             }
870fa5e4d32SSunny Srivastava         }
871fa5e4d32SSunny Srivastava     }
872fa5e4d32SSunny Srivastava     phosphor::logging::elog<types::DbusInvalidArgument>(
873fa5e4d32SSunny Srivastava         types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
874fa5e4d32SSunny Srivastava         types::InvalidArgument::ARGUMENT_VALUE(
875fa5e4d32SSunny Srivastava             i_unexpandedLocationCode.c_str()));
876fa5e4d32SSunny Srivastava }
877fa5e4d32SSunny Srivastava 
878fa5e4d32SSunny Srivastava types::ListOfPaths Manager::getFrusByUnexpandedLocationCode(
879fa5e4d32SSunny Srivastava     const std::string& i_unexpandedLocationCode,
880fa5e4d32SSunny Srivastava     [[maybe_unused]] const uint16_t i_nodeNumber)
881fa5e4d32SSunny Srivastava {
882fa5e4d32SSunny Srivastava     types::ListOfPaths l_inventoryPaths;
883fa5e4d32SSunny Srivastava 
884fa5e4d32SSunny Srivastava     if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode))
885fa5e4d32SSunny Srivastava     {
886fa5e4d32SSunny Srivastava         phosphor::logging::elog<types::DbusInvalidArgument>(
887fa5e4d32SSunny Srivastava             types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
888fa5e4d32SSunny Srivastava             types::InvalidArgument::ARGUMENT_VALUE(
889fa5e4d32SSunny Srivastava                 i_unexpandedLocationCode.c_str()));
890fa5e4d32SSunny Srivastava     }
891fa5e4d32SSunny Srivastava 
892fa5e4d32SSunny Srivastava     const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
893fa5e4d32SSunny Srivastava     if (!l_sysCfgJsonObj.contains("frus"))
894fa5e4d32SSunny Srivastava     {
895fa5e4d32SSunny Srivastava         logging::logMessage("Missing frus tag in system config JSON");
896fa5e4d32SSunny Srivastava     }
897fa5e4d32SSunny Srivastava 
898fa5e4d32SSunny Srivastava     const nlohmann::json& l_listOfFrus =
899fa5e4d32SSunny Srivastava         l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
900fa5e4d32SSunny Srivastava 
901fa5e4d32SSunny Srivastava     for (const auto& l_frus : l_listOfFrus.items())
902fa5e4d32SSunny Srivastava     {
903fa5e4d32SSunny Srivastava         for (const auto& l_aFru : l_frus.value())
904fa5e4d32SSunny Srivastava         {
905fa5e4d32SSunny Srivastava             if (l_aFru["extraInterfaces"].contains(
906fa5e4d32SSunny Srivastava                     constants::locationCodeInf) &&
907fa5e4d32SSunny Srivastava                 l_aFru["extraInterfaces"][constants::locationCodeInf].value(
908fa5e4d32SSunny Srivastava                     "LocationCode", "") == i_unexpandedLocationCode)
909fa5e4d32SSunny Srivastava             {
910fa5e4d32SSunny Srivastava                 l_inventoryPaths.push_back(
911fa5e4d32SSunny Srivastava                     l_aFru.at("inventoryPath")
912fa5e4d32SSunny Srivastava                         .get_ref<const nlohmann::json::string_t&>());
913fa5e4d32SSunny Srivastava             }
914fa5e4d32SSunny Srivastava         }
915fa5e4d32SSunny Srivastava     }
916fa5e4d32SSunny Srivastava 
917fa5e4d32SSunny Srivastava     if (l_inventoryPaths.empty())
918fa5e4d32SSunny Srivastava     {
919fa5e4d32SSunny Srivastava         phosphor::logging::elog<types::DbusInvalidArgument>(
920fa5e4d32SSunny Srivastava             types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
921fa5e4d32SSunny Srivastava             types::InvalidArgument::ARGUMENT_VALUE(
922fa5e4d32SSunny Srivastava                 i_unexpandedLocationCode.c_str()));
923fa5e4d32SSunny Srivastava     }
924fa5e4d32SSunny Srivastava 
925fa5e4d32SSunny Srivastava     return l_inventoryPaths;
926fa5e4d32SSunny Srivastava }
927fa5e4d32SSunny Srivastava 
92843fedabcSPatrick Williams std::string Manager::getHwPath(
92943fedabcSPatrick Williams     const sdbusplus::message::object_path& i_dbusObjPath)
930fa5e4d32SSunny Srivastava {
931fa5e4d32SSunny Srivastava     // Dummy code to supress unused variable warning. To be removed.
932fa5e4d32SSunny Srivastava     logging::logMessage(std::string(i_dbusObjPath));
933fa5e4d32SSunny Srivastava 
934fa5e4d32SSunny Srivastava     return std::string{};
935fa5e4d32SSunny Srivastava }
936fa5e4d32SSunny Srivastava 
937fa5e4d32SSunny Srivastava std::tuple<std::string, uint16_t> Manager::getUnexpandedLocationCode(
938fa5e4d32SSunny Srivastava     const std::string& i_expandedLocationCode)
939fa5e4d32SSunny Srivastava {
940fa5e4d32SSunny Srivastava     /**
941fa5e4d32SSunny Srivastava      * Location code should always start with U and fulfil minimum length
942fa5e4d32SSunny Srivastava      * criteria.
943fa5e4d32SSunny Srivastava      */
944fa5e4d32SSunny Srivastava     if (i_expandedLocationCode[0] != 'U' ||
945fa5e4d32SSunny Srivastava         i_expandedLocationCode.length() <
946fa5e4d32SSunny Srivastava             constants::EXP_LOCATION_CODE_MIN_LENGTH)
947fa5e4d32SSunny Srivastava     {
948fa5e4d32SSunny Srivastava         phosphor::logging::elog<types::DbusInvalidArgument>(
949fa5e4d32SSunny Srivastava             types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
950fa5e4d32SSunny Srivastava             types::InvalidArgument::ARGUMENT_VALUE(
951fa5e4d32SSunny Srivastava                 i_expandedLocationCode.c_str()));
952fa5e4d32SSunny Srivastava     }
953fa5e4d32SSunny Srivastava 
954fa5e4d32SSunny Srivastava     std::string l_fcKwd;
955fa5e4d32SSunny Srivastava 
956fa5e4d32SSunny Srivastava     auto l_fcKwdValue = dbusUtility::readDbusProperty(
957fa5e4d32SSunny Srivastava         "xyz.openbmc_project.Inventory.Manager",
958fa5e4d32SSunny Srivastava         "/xyz/openbmc_project/inventory/system/chassis/motherboard",
959fa5e4d32SSunny Srivastava         "com.ibm.ipzvpd.VCEN", "FC");
960fa5e4d32SSunny Srivastava 
961fa5e4d32SSunny Srivastava     if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_fcKwdValue))
962fa5e4d32SSunny Srivastava     {
963fa5e4d32SSunny Srivastava         l_fcKwd.assign(l_kwdValue->begin(), l_kwdValue->end());
964fa5e4d32SSunny Srivastava     }
965fa5e4d32SSunny Srivastava 
966fa5e4d32SSunny Srivastava     // Get the first part of expanded location code to check for FC or TM.
967fa5e4d32SSunny Srivastava     std::string l_firstKwd = i_expandedLocationCode.substr(1, 4);
968fa5e4d32SSunny Srivastava 
969fa5e4d32SSunny Srivastava     std::string l_unexpandedLocationCode{};
970fa5e4d32SSunny Srivastava     uint16_t l_nodeNummber = constants::INVALID_NODE_NUMBER;
971fa5e4d32SSunny Srivastava 
972fa5e4d32SSunny Srivastava     // Check if this value matches the value of FC keyword.
973fa5e4d32SSunny Srivastava     if (l_fcKwd.substr(0, 4) == l_firstKwd)
974fa5e4d32SSunny Srivastava     {
975fa5e4d32SSunny Srivastava         /**
976fa5e4d32SSunny Srivastava          * Period(.) should be there in expanded location code to seggregate
977fa5e4d32SSunny Srivastava          * FC, node number and SE values.
978fa5e4d32SSunny Srivastava          */
979fa5e4d32SSunny Srivastava         size_t l_nodeStartPos = i_expandedLocationCode.find('.');
980fa5e4d32SSunny Srivastava         if (l_nodeStartPos == std::string::npos)
981fa5e4d32SSunny Srivastava         {
982fa5e4d32SSunny Srivastava             phosphor::logging::elog<types::DbusInvalidArgument>(
983fa5e4d32SSunny Srivastava                 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
984fa5e4d32SSunny Srivastava                 types::InvalidArgument::ARGUMENT_VALUE(
985fa5e4d32SSunny Srivastava                     i_expandedLocationCode.c_str()));
986fa5e4d32SSunny Srivastava         }
987fa5e4d32SSunny Srivastava 
988fa5e4d32SSunny Srivastava         size_t l_nodeEndPos =
989fa5e4d32SSunny Srivastava             i_expandedLocationCode.find('.', l_nodeStartPos + 1);
990fa5e4d32SSunny Srivastava         if (l_nodeEndPos == std::string::npos)
991fa5e4d32SSunny Srivastava         {
992fa5e4d32SSunny Srivastava             phosphor::logging::elog<types::DbusInvalidArgument>(
993fa5e4d32SSunny Srivastava                 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
994fa5e4d32SSunny Srivastava                 types::InvalidArgument::ARGUMENT_VALUE(
995fa5e4d32SSunny Srivastava                     i_expandedLocationCode.c_str()));
996fa5e4d32SSunny Srivastava         }
997fa5e4d32SSunny Srivastava 
998fa5e4d32SSunny Srivastava         // Skip 3 bytes for '.ND'
999fa5e4d32SSunny Srivastava         l_nodeNummber = std::stoi(i_expandedLocationCode.substr(
1000fa5e4d32SSunny Srivastava             l_nodeStartPos + 3, (l_nodeEndPos - l_nodeStartPos - 3)));
1001fa5e4d32SSunny Srivastava 
1002fa5e4d32SSunny Srivastava         /**
1003fa5e4d32SSunny Srivastava          * Confirm if there are other details apart FC, node number and SE
1004fa5e4d32SSunny Srivastava          * in location code
1005fa5e4d32SSunny Srivastava          */
1006fa5e4d32SSunny Srivastava         if (i_expandedLocationCode.length() >
1007fa5e4d32SSunny Srivastava             constants::EXP_LOCATION_CODE_MIN_LENGTH)
1008fa5e4d32SSunny Srivastava         {
1009fa5e4d32SSunny Srivastava             l_unexpandedLocationCode =
1010fa5e4d32SSunny Srivastava                 i_expandedLocationCode[0] + std::string("fcs") +
1011fa5e4d32SSunny Srivastava                 i_expandedLocationCode.substr(
1012fa5e4d32SSunny Srivastava                     l_nodeEndPos + 1 + constants::SE_KWD_LENGTH,
1013fa5e4d32SSunny Srivastava                     std::string::npos);
1014fa5e4d32SSunny Srivastava         }
1015fa5e4d32SSunny Srivastava         else
1016fa5e4d32SSunny Srivastava         {
1017fa5e4d32SSunny Srivastava             l_unexpandedLocationCode = "Ufcs";
1018fa5e4d32SSunny Srivastava         }
1019fa5e4d32SSunny Srivastava     }
1020fa5e4d32SSunny Srivastava     else
1021fa5e4d32SSunny Srivastava     {
1022fa5e4d32SSunny Srivastava         std::string l_tmKwd;
1023fa5e4d32SSunny Srivastava         // Read TM keyword value.
1024fa5e4d32SSunny Srivastava         auto l_tmKwdValue = dbusUtility::readDbusProperty(
1025fa5e4d32SSunny Srivastava             "xyz.openbmc_project.Inventory.Manager",
1026fa5e4d32SSunny Srivastava             "/xyz/openbmc_project/inventory/system/chassis/motherboard",
1027fa5e4d32SSunny Srivastava             "com.ibm.ipzvpd.VSYS", "TM");
1028fa5e4d32SSunny Srivastava 
1029fa5e4d32SSunny Srivastava         if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_tmKwdValue))
1030fa5e4d32SSunny Srivastava         {
1031fa5e4d32SSunny Srivastava             l_tmKwd.assign(l_kwdValue->begin(), l_kwdValue->end());
1032fa5e4d32SSunny Srivastava         }
1033fa5e4d32SSunny Srivastava 
1034fa5e4d32SSunny Srivastava         // Check if the substr matches to TM keyword value.
1035fa5e4d32SSunny Srivastava         if (l_tmKwd.substr(0, 4) == l_firstKwd)
1036fa5e4d32SSunny Srivastava         {
1037fa5e4d32SSunny Srivastava             /**
1038fa5e4d32SSunny Srivastava              * System location code will not have node number and any other
1039fa5e4d32SSunny Srivastava              * details.
1040fa5e4d32SSunny Srivastava              */
1041fa5e4d32SSunny Srivastava             l_unexpandedLocationCode = "Umts";
1042fa5e4d32SSunny Srivastava         }
1043fa5e4d32SSunny Srivastava         // The given location code is neither "fcs" or "mts".
1044fa5e4d32SSunny Srivastava         else
1045fa5e4d32SSunny Srivastava         {
1046fa5e4d32SSunny Srivastava             phosphor::logging::elog<types::DbusInvalidArgument>(
1047fa5e4d32SSunny Srivastava                 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
1048fa5e4d32SSunny Srivastava                 types::InvalidArgument::ARGUMENT_VALUE(
1049fa5e4d32SSunny Srivastava                     i_expandedLocationCode.c_str()));
1050fa5e4d32SSunny Srivastava         }
1051fa5e4d32SSunny Srivastava     }
1052fa5e4d32SSunny Srivastava 
1053fa5e4d32SSunny Srivastava     return std::make_tuple(l_unexpandedLocationCode, l_nodeNummber);
1054fa5e4d32SSunny Srivastava }
1055fa5e4d32SSunny Srivastava 
1056fa5e4d32SSunny Srivastava types::ListOfPaths Manager::getFrusByExpandedLocationCode(
1057fa5e4d32SSunny Srivastava     const std::string& i_expandedLocationCode)
1058fa5e4d32SSunny Srivastava {
1059fa5e4d32SSunny Srivastava     std::tuple<std::string, uint16_t> l_locationAndNodePair =
1060fa5e4d32SSunny Srivastava         getUnexpandedLocationCode(i_expandedLocationCode);
1061fa5e4d32SSunny Srivastava 
1062fa5e4d32SSunny Srivastava     return getFrusByUnexpandedLocationCode(std::get<0>(l_locationAndNodePair),
1063fa5e4d32SSunny Srivastava                                            std::get<1>(l_locationAndNodePair));
1064fa5e4d32SSunny Srivastava }
1065fa5e4d32SSunny Srivastava 
1066fa5e4d32SSunny Srivastava void Manager::registerHostStateChangeCallback()
1067fa5e4d32SSunny Srivastava {
1068fa5e4d32SSunny Srivastava     static std::shared_ptr<sdbusplus::bus::match_t> l_hostState =
1069fa5e4d32SSunny Srivastava         std::make_shared<sdbusplus::bus::match_t>(
1070fa5e4d32SSunny Srivastava             *m_asioConnection,
1071fa5e4d32SSunny Srivastava             sdbusplus::bus::match::rules::propertiesChanged(
1072fa5e4d32SSunny Srivastava                 constants::hostObjectPath, constants::hostInterface),
1073fa5e4d32SSunny Srivastava             [this](sdbusplus::message_t& i_msg) {
1074fa5e4d32SSunny Srivastava                 hostStateChangeCallBack(i_msg);
1075fa5e4d32SSunny Srivastava             });
1076fa5e4d32SSunny Srivastava }
1077fa5e4d32SSunny Srivastava 
1078fa5e4d32SSunny Srivastava void Manager::hostStateChangeCallBack(sdbusplus::message_t& i_msg)
1079fa5e4d32SSunny Srivastava {
1080fa5e4d32SSunny Srivastava     try
1081fa5e4d32SSunny Srivastava     {
1082fa5e4d32SSunny Srivastava         if (i_msg.is_method_error())
1083fa5e4d32SSunny Srivastava         {
1084fa5e4d32SSunny Srivastava             throw std::runtime_error(
1085fa5e4d32SSunny Srivastava                 "Error reading callback message for host state");
1086fa5e4d32SSunny Srivastava         }
1087fa5e4d32SSunny Srivastava 
1088fa5e4d32SSunny Srivastava         std::string l_objectPath;
1089fa5e4d32SSunny Srivastava         types::PropertyMap l_propMap;
1090fa5e4d32SSunny Srivastava         i_msg.read(l_objectPath, l_propMap);
1091fa5e4d32SSunny Srivastava 
1092fa5e4d32SSunny Srivastava         const auto l_itr = l_propMap.find("CurrentHostState");
1093fa5e4d32SSunny Srivastava 
1094fa5e4d32SSunny Srivastava         if (l_itr == l_propMap.end())
1095fa5e4d32SSunny Srivastava         {
1096fa5e4d32SSunny Srivastava             throw std::runtime_error(
1097fa5e4d32SSunny Srivastava                 "CurrentHostState field is missing in callback message");
1098fa5e4d32SSunny Srivastava         }
1099fa5e4d32SSunny Srivastava 
1100fa5e4d32SSunny Srivastava         if (auto l_hostState = std::get_if<std::string>(&(l_itr->second)))
1101fa5e4d32SSunny Srivastava         {
1102fa5e4d32SSunny Srivastava             // implies system is moving from standby to power on state
1103fa5e4d32SSunny Srivastava             if (*l_hostState == "xyz.openbmc_project.State.Host.HostState."
1104fa5e4d32SSunny Srivastava                                 "TransitioningToRunning")
1105fa5e4d32SSunny Srivastava             {
1106fa5e4d32SSunny Srivastava                 // TODO: check for all the essential FRUs in the system.
1107fa5e4d32SSunny Srivastava 
1108fa5e4d32SSunny Srivastava                 // Perform recollection.
1109fa5e4d32SSunny Srivastava                 performVpdRecollection();
1110fa5e4d32SSunny Srivastava                 return;
1111fa5e4d32SSunny Srivastava             }
1112fa5e4d32SSunny Srivastava         }
1113fa5e4d32SSunny Srivastava         else
1114fa5e4d32SSunny Srivastava         {
1115fa5e4d32SSunny Srivastava             throw std::runtime_error(
1116fa5e4d32SSunny Srivastava                 "Invalid type recieved in variant for host state.");
1117fa5e4d32SSunny Srivastava         }
1118fa5e4d32SSunny Srivastava     }
1119fa5e4d32SSunny Srivastava     catch (const std::exception& l_ex)
1120fa5e4d32SSunny Srivastava     {
1121fa5e4d32SSunny Srivastava         // TODO: Log PEL.
1122fa5e4d32SSunny Srivastava         logging::logMessage(l_ex.what());
1123fa5e4d32SSunny Srivastava     }
1124fa5e4d32SSunny Srivastava }
1125fa5e4d32SSunny Srivastava 
1126fa5e4d32SSunny Srivastava void Manager::performVpdRecollection()
1127fa5e4d32SSunny Srivastava {
1128fa5e4d32SSunny Srivastava     try
1129fa5e4d32SSunny Srivastava     {
1130fa5e4d32SSunny Srivastava         if (m_worker.get() != nullptr)
1131fa5e4d32SSunny Srivastava         {
1132fa5e4d32SSunny Srivastava             nlohmann::json l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
1133fa5e4d32SSunny Srivastava 
1134fa5e4d32SSunny Srivastava             // Check if system config JSON is present
1135fa5e4d32SSunny Srivastava             if (l_sysCfgJsonObj.empty())
1136fa5e4d32SSunny Srivastava             {
1137fa5e4d32SSunny Srivastava                 throw std::runtime_error(
1138fa5e4d32SSunny Srivastava                     "System config json object is empty, can't process recollection.");
1139fa5e4d32SSunny Srivastava             }
1140fa5e4d32SSunny Srivastava 
1141fa5e4d32SSunny Srivastava             const auto& l_frusReplaceableAtStandby =
1142fa5e4d32SSunny Srivastava                 jsonUtility::getListOfFrusReplaceableAtStandby(l_sysCfgJsonObj);
1143fa5e4d32SSunny Srivastava 
1144fa5e4d32SSunny Srivastava             for (const auto& l_fruInventoryPath : l_frusReplaceableAtStandby)
1145fa5e4d32SSunny Srivastava             {
1146fa5e4d32SSunny Srivastava                 // ToDo: Add some logic/trace to know the flow to
1147fa5e4d32SSunny Srivastava                 // collectSingleFruVpd has been directed via
1148fa5e4d32SSunny Srivastava                 // performVpdRecollection.
1149fa5e4d32SSunny Srivastava                 collectSingleFruVpd(l_fruInventoryPath);
1150fa5e4d32SSunny Srivastava             }
1151fa5e4d32SSunny Srivastava             return;
1152fa5e4d32SSunny Srivastava         }
1153fa5e4d32SSunny Srivastava 
1154fa5e4d32SSunny Srivastava         throw std::runtime_error(
1155fa5e4d32SSunny Srivastava             "Worker object not found can't process recollection");
1156fa5e4d32SSunny Srivastava     }
1157fa5e4d32SSunny Srivastava     catch (const std::exception& l_ex)
1158fa5e4d32SSunny Srivastava     {
1159fa5e4d32SSunny Srivastava         // TODO Log PEL
1160fa5e4d32SSunny Srivastava         logging::logMessage(
1161fa5e4d32SSunny Srivastava             "VPD recollection failed with error: " + std::string(l_ex.what()));
1162fa5e4d32SSunny Srivastava     }
1163fa5e4d32SSunny Srivastava }
1164fa5e4d32SSunny Srivastava } // namespace vpd
1165