xref: /openbmc/openpower-vpd-parser/vpd-manager/include/utility/vpd_specific_utility.hpp (revision 022112bc235c7f91ee998bb131f06e212dee1f6a)
1 #pragma once
2 
3 #include "config.h"
4 
5 #include "constants.hpp"
6 #include "event_logger.hpp"
7 #include "exceptions.hpp"
8 #include "logger.hpp"
9 #include "types.hpp"
10 
11 #include <nlohmann/json.hpp>
12 #include <utility/common_utility.hpp>
13 #include <utility/dbus_utility.hpp>
14 
15 #include <filesystem>
16 #include <fstream>
17 #include <regex>
18 #include <typeindex>
19 
20 namespace vpd
21 {
22 namespace vpdSpecificUtility
23 {
24 /**
25  * @brief API to generate file name for bad VPD.
26  *
27  * For i2c eeproms - the pattern of the vpd-name will be
28  * i2c-<bus-number>-<eeprom-address>.
29  * For spi eeproms - the pattern of the vpd-name will be spi-<spi-number>.
30  *
31  * @param[in] i_vpdFilePath - file path of the vpd.
32  *
33  * @return On success, returns generated file name, otherwise returns empty
34  * string.
35  */
36 inline std::string generateBadVPDFileName(
37     const std::string& i_vpdFilePath) noexcept
38 {
39     std::string l_badVpdFileName{BAD_VPD_DIR};
40     try
41     {
42         if (i_vpdFilePath.find("i2c") != std::string::npos)
43         {
44             l_badVpdFileName += "i2c-";
45             std::regex l_i2cPattern("(at24/)([0-9]+-[0-9]+)\\/");
46             std::smatch l_match;
47             if (std::regex_search(i_vpdFilePath, l_match, l_i2cPattern))
48             {
49                 l_badVpdFileName += l_match.str(2);
50             }
51         }
52         else if (i_vpdFilePath.find("spi") != std::string::npos)
53         {
54             std::regex l_spiPattern("((spi)[0-9]+)(.0)");
55             std::smatch l_match;
56             if (std::regex_search(i_vpdFilePath, l_match, l_spiPattern))
57             {
58                 l_badVpdFileName += l_match.str(1);
59             }
60         }
61     }
62     catch (const std::exception& l_ex)
63     {
64         l_badVpdFileName.clear();
65         logging::logMessage("Failed to generate bad VPD file name for [" +
66                             i_vpdFilePath + "]. Error: " + l_ex.what());
67     }
68     return l_badVpdFileName;
69 }
70 
71 /**
72  * @brief API which dumps the broken/bad vpd in a directory.
73  * When the vpd is bad, this API places  the bad vpd file inside
74  * "/tmp/bad-vpd" in BMC, in order to collect bad VPD data as a part of user
75  * initiated BMC dump.
76  *
77  *
78  * @param[in] i_vpdFilePath - vpd file path
79  * @param[in] i_vpdVector - vpd vector
80  *
81  * @return On success returns 0, otherwise returns -1.
82  */
83 inline int dumpBadVpd(const std::string& i_vpdFilePath,
84                       const types::BinaryVector& i_vpdVector) noexcept
85 {
86     int l_rc{constants::FAILURE};
87     try
88     {
89         std::filesystem::create_directory(BAD_VPD_DIR);
90         auto l_badVpdPath = generateBadVPDFileName(i_vpdFilePath);
91 
92         if (l_badVpdPath.empty())
93         {
94             throw std::runtime_error("Failed to generate bad VPD file name");
95         }
96 
97         if (std::filesystem::exists(l_badVpdPath))
98         {
99             std::error_code l_ec;
100             std::filesystem::remove(l_badVpdPath, l_ec);
101             if (l_ec) // error code
102             {
103                 const std::string l_errorMsg{
104                     "Error removing the existing broken vpd in " +
105                     l_badVpdPath +
106                     ". Error code : " + std::to_string(l_ec.value()) +
107                     ". Error message : " + l_ec.message()};
108 
109                 throw std::runtime_error(l_errorMsg);
110             }
111         }
112 
113         std::ofstream l_badVpdFileStream(l_badVpdPath, std::ofstream::binary);
114         if (!l_badVpdFileStream.is_open())
115         {
116             throw std::runtime_error(
117                 "Failed to open bad vpd file path in /tmp/bad-vpd. "
118                 "Unable to dump the broken/bad vpd file.");
119         }
120 
121         l_badVpdFileStream.write(
122             reinterpret_cast<const char*>(i_vpdVector.data()),
123             i_vpdVector.size());
124 
125         l_rc = constants::SUCCESS;
126     }
127     catch (const std::exception& l_ex)
128     {
129         logging::logMessage("Failed to dump bad VPD for [" + i_vpdFilePath +
130                             "]. Error: " + l_ex.what());
131     }
132     return l_rc;
133 }
134 
135 /**
136  * @brief An API to read value of a keyword.
137  *
138  * Note: Throws exception. Caller needs to handle.
139  *
140  * @param[in] kwdValueMap - A map having Kwd value pair.
141  * @param[in] kwd - keyword name.
142  * @param[out] kwdValue - Value of the keyword read from map.
143  */
144 inline void getKwVal(const types::IPZKwdValueMap& kwdValueMap,
145                      const std::string& kwd, std::string& kwdValue)
146 {
147     if (kwd.empty())
148     {
149         logging::logMessage("Invalid parameters");
150         throw std::runtime_error("Invalid parameters");
151     }
152 
153     auto itrToKwd = kwdValueMap.find(kwd);
154     if (itrToKwd != kwdValueMap.end())
155     {
156         kwdValue = itrToKwd->second;
157         return;
158     }
159 
160     throw std::runtime_error("Keyword not found");
161 }
162 
163 /**
164  * @brief An API to process encoding of a keyword.
165  *
166  * @param[in] i_keyword - Keyword to be processed.
167  * @param[in] i_encoding - Type of encoding.
168  *
169  * @return Value after being processed for encoded type.
170  */
171 inline std::string encodeKeyword(const std::string& i_keyword,
172                                  const std::string& i_encoding) noexcept
173 {
174     // Default value is keyword value
175     std::string l_result(i_keyword.begin(), i_keyword.end());
176     try
177     {
178         if (i_encoding == "MAC")
179         {
180             l_result.clear();
181             size_t l_firstByte = i_keyword[0];
182             l_result += commonUtility::toHex(l_firstByte >> 4);
183             l_result += commonUtility::toHex(l_firstByte & 0x0f);
184             for (size_t i = 1; i < i_keyword.size(); ++i)
185             {
186                 l_result += ":";
187                 l_result += commonUtility::toHex(i_keyword[i] >> 4);
188                 l_result += commonUtility::toHex(i_keyword[i] & 0x0f);
189             }
190         }
191         else if (i_encoding == "DATE")
192         {
193             // Date, represent as
194             // <year>-<month>-<day> <hour>:<min>
195             l_result.clear();
196             static constexpr uint8_t skipPrefix = 3;
197 
198             auto strItr = i_keyword.begin();
199             advance(strItr, skipPrefix);
200             for_each(strItr, i_keyword.end(),
201                      [&l_result](size_t c) { l_result += c; });
202 
203             l_result.insert(constants::BD_YEAR_END, 1, '-');
204             l_result.insert(constants::BD_MONTH_END, 1, '-');
205             l_result.insert(constants::BD_DAY_END, 1, ' ');
206             l_result.insert(constants::BD_HOUR_END, 1, ':');
207         }
208     }
209     catch (const std::exception& l_ex)
210     {
211         l_result.clear();
212         logging::logMessage("Failed to encode keyword [" + i_keyword +
213                             "]. Error: " + l_ex.what());
214     }
215 
216     return l_result;
217 }
218 
219 /**
220  * @brief Helper function to insert or merge in map.
221  *
222  * This method checks in an interface if the given interface exists. If the
223  * interface key already exists, property map is inserted corresponding to it.
224  * If the key does'nt exist then given interface and property map pair is newly
225  * created. If the property present in propertymap already exist in the
226  * InterfaceMap, then the new property value is ignored.
227  *
228  * @param[in,out] io_map - Interface map.
229  * @param[in] i_interface - Interface to be processed.
230  * @param[in] i_propertyMap - new property map that needs to be emplaced.
231  *
232  * @return On success returns 0, otherwise returns -1.
233  */
234 inline int insertOrMerge(types::InterfaceMap& io_map,
235                          const std::string& i_interface,
236                          types::PropertyMap&& i_propertyMap) noexcept
237 {
238     int l_rc{constants::FAILURE};
239     try
240     {
241         if (io_map.find(i_interface) != io_map.end())
242         {
243             auto& l_prop = io_map.at(i_interface);
244             std::for_each(i_propertyMap.begin(), i_propertyMap.end(),
245                           [&l_prop](auto l_keyValue) {
246                               l_prop[l_keyValue.first] = l_keyValue.second;
247                           });
248         }
249         else
250         {
251             io_map.emplace(i_interface, i_propertyMap);
252         }
253 
254         l_rc = constants::SUCCESS;
255     }
256     catch (const std::exception& l_ex)
257     {
258         // ToDo:: Log PEL
259         logging::logMessage(
260             "Inserting properties into interface[" + i_interface +
261             "] map failed, reason: " + std::string(l_ex.what()));
262     }
263     return l_rc;
264 }
265 
266 /**
267  * @brief API to expand unpanded location code.
268  *
269  * Note: The API handles all the exception internally, in case of any error
270  * unexpanded location code will be returned as it is.
271  *
272  * @param[in] unexpandedLocationCode - Unexpanded location code.
273  * @param[in] parsedVpdMap - Parsed VPD map.
274  * @return Expanded location code. In case of any error, unexpanded is returned
275  * as it is.
276  */
277 inline std::string getExpandedLocationCode(
278     const std::string& unexpandedLocationCode,
279     const types::VPDMapVariant& parsedVpdMap)
280 {
281     auto expanded{unexpandedLocationCode};
282 
283     try
284     {
285         // Expanded location code is formed by combining two keywords
286         // depending on type in unexpanded one. Second one is always "SE".
287         std::string kwd1, kwd2{constants::kwdSE};
288 
289         // interface to search for required keywords;
290         std::string kwdInterface;
291 
292         // record which holds the required keywords.
293         std::string recordName;
294 
295         auto pos = unexpandedLocationCode.find("fcs");
296         if (pos != std::string::npos)
297         {
298             kwd1 = constants::kwdFC;
299             kwdInterface = constants::vcenInf;
300             recordName = constants::recVCEN;
301         }
302         else
303         {
304             pos = unexpandedLocationCode.find("mts");
305             if (pos != std::string::npos)
306             {
307                 kwd1 = constants::kwdTM;
308                 kwdInterface = constants::vsysInf;
309                 recordName = constants::recVSYS;
310             }
311             else
312             {
313                 throw std::runtime_error(
314                     "Error detecting type of unexpanded location code.");
315             }
316         }
317 
318         std::string firstKwdValue, secondKwdValue;
319 
320         if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap);
321             ipzVpdMap && (*ipzVpdMap).find(recordName) != (*ipzVpdMap).end())
322         {
323             auto itrToVCEN = (*ipzVpdMap).find(recordName);
324             // The exceptions will be cautght at end.
325             getKwVal(itrToVCEN->second, kwd1, firstKwdValue);
326             getKwVal(itrToVCEN->second, kwd2, secondKwdValue);
327         }
328         else
329         {
330             std::array<const char*, 1> interfaceList = {kwdInterface.c_str()};
331 
332             types::MapperGetObject mapperRetValue = dbusUtility::getObjectMap(
333                 std::string(constants::systemVpdInvPath), interfaceList);
334 
335             if (mapperRetValue.empty())
336             {
337                 throw std::runtime_error("Mapper failed to get service");
338             }
339 
340             const std::string& serviceName = std::get<0>(mapperRetValue.at(0));
341 
342             auto retVal = dbusUtility::readDbusProperty(
343                 serviceName, std::string(constants::systemVpdInvPath),
344                 kwdInterface, kwd1);
345 
346             if (auto kwdVal = std::get_if<types::BinaryVector>(&retVal))
347             {
348                 firstKwdValue.assign(
349                     reinterpret_cast<const char*>(kwdVal->data()),
350                     kwdVal->size());
351             }
352             else
353             {
354                 throw std::runtime_error(
355                     "Failed to read value of " + kwd1 + " from Bus");
356             }
357 
358             retVal = dbusUtility::readDbusProperty(
359                 serviceName, std::string(constants::systemVpdInvPath),
360                 kwdInterface, kwd2);
361 
362             if (auto kwdVal = std::get_if<types::BinaryVector>(&retVal))
363             {
364                 secondKwdValue.assign(
365                     reinterpret_cast<const char*>(kwdVal->data()),
366                     kwdVal->size());
367             }
368             else
369             {
370                 throw std::runtime_error(
371                     "Failed to read value of " + kwd2 + " from Bus");
372             }
373         }
374 
375         if (unexpandedLocationCode.find("fcs") != std::string::npos)
376         {
377             // TODO: See if ND0 can be placed in the JSON
378             expanded.replace(
379                 pos, 3, firstKwdValue.substr(0, 4) + ".ND0." + secondKwdValue);
380         }
381         else
382         {
383             replace(firstKwdValue.begin(), firstKwdValue.end(), '-', '.');
384             expanded.replace(pos, 3, firstKwdValue + "." + secondKwdValue);
385         }
386     }
387     catch (const std::exception& ex)
388     {
389         logging::logMessage("Failed to expand location code with exception: " +
390                             std::string(ex.what()));
391     }
392 
393     return expanded;
394 }
395 
396 /**
397  * @brief An API to get VPD in a vector.
398  *
399  * The vector is required by the respective parser to fill the VPD map.
400  * Note: API throws exception in case of failure. Caller needs to handle.
401  *
402  * @param[in] vpdFilePath - EEPROM path of the FRU.
403  * @param[out] vpdVector - VPD in vector form.
404  * @param[in] vpdStartOffset - Offset of VPD data in EEPROM.
405  */
406 inline void getVpdDataInVector(const std::string& vpdFilePath,
407                                types::BinaryVector& vpdVector,
408                                size_t& vpdStartOffset)
409 {
410     try
411     {
412         std::fstream vpdFileStream;
413         vpdFileStream.exceptions(
414             std::ifstream::badbit | std::ifstream::failbit);
415         vpdFileStream.open(vpdFilePath, std::ios::in | std::ios::binary);
416         auto vpdSizeToRead = std::min(std::filesystem::file_size(vpdFilePath),
417                                       static_cast<uintmax_t>(65504));
418         vpdVector.resize(vpdSizeToRead);
419 
420         vpdFileStream.seekg(vpdStartOffset, std::ios_base::beg);
421         vpdFileStream.read(reinterpret_cast<char*>(&vpdVector[0]),
422                            vpdSizeToRead);
423 
424         vpdVector.resize(vpdFileStream.gcount());
425         vpdFileStream.clear(std::ios_base::eofbit);
426     }
427     catch (const std::ifstream::failure& fail)
428     {
429         std::cerr << "Exception in file handling [" << vpdFilePath
430                   << "] error : " << fail.what();
431         throw;
432     }
433 }
434 
435 /**
436  * @brief An API to get D-bus representation of given VPD keyword.
437  *
438  * @param[in] i_keywordName - VPD keyword name.
439  *
440  * @return D-bus representation of given keyword.
441  */
442 inline std::string getDbusPropNameForGivenKw(const std::string& i_keywordName)
443 {
444     // Check for "#" prefixed VPD keyword.
445     if ((i_keywordName.size() == vpd::constants::TWO_BYTES) &&
446         (i_keywordName.at(0) == constants::POUND_KW))
447     {
448         // D-bus doesn't support "#". Replace "#" with "PD_" for those "#"
449         // prefixed keywords.
450         return (std::string(constants::POUND_KW_PREFIX) +
451                 i_keywordName.substr(1));
452     }
453 
454     // Return the keyword name back, if D-bus representation is same as the VPD
455     // keyword name.
456     return i_keywordName;
457 }
458 
459 /**
460  * @brief API to find CCIN in parsed VPD map.
461  *
462  * Few FRUs need some special handling. To identify those FRUs CCIN are used.
463  * The API will check from parsed VPD map if the FRU is the one with desired
464  * CCIN.
465  *
466  * @param[in] i_JsonObject - Any JSON which contains CCIN tag to match.
467  * @param[in] i_parsedVpdMap - Parsed VPD map.
468  *
469  * @return True if found, false otherwise.
470  */
471 inline bool findCcinInVpd(const nlohmann::json& i_JsonObject,
472                           const types::VPDMapVariant& i_parsedVpdMap) noexcept
473 {
474     bool l_rc{false};
475     try
476     {
477         if (i_JsonObject.empty())
478         {
479             throw std::runtime_error("Json object is empty. Can't find CCIN");
480         }
481 
482         if (auto l_ipzVPDMap = std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
483         {
484             auto l_itrToRec = (*l_ipzVPDMap).find("VINI");
485             if (l_itrToRec == (*l_ipzVPDMap).end())
486             {
487                 throw DataException(
488                     "VINI record not found in parsed VPD. Can't find CCIN");
489             }
490 
491             std::string l_ccinFromVpd;
492             vpdSpecificUtility::getKwVal(l_itrToRec->second, "CC",
493                                          l_ccinFromVpd);
494             if (l_ccinFromVpd.empty())
495             {
496                 throw DataException(
497                     "Empty CCIN value in VPD map. Can't find CCIN");
498             }
499 
500             transform(l_ccinFromVpd.begin(), l_ccinFromVpd.end(),
501                       l_ccinFromVpd.begin(), ::toupper);
502 
503             for (std::string l_ccinValue : i_JsonObject["ccin"])
504             {
505                 transform(l_ccinValue.begin(), l_ccinValue.end(),
506                           l_ccinValue.begin(), ::toupper);
507 
508                 if (l_ccinValue.compare(l_ccinFromVpd) ==
509                     constants::STR_CMP_SUCCESS)
510                 {
511                     // CCIN found
512                     l_rc = true;
513                 }
514             }
515 
516             if (!l_rc)
517             {
518                 logging::logMessage("No match found for CCIN");
519             }
520         }
521         else
522         {
523             logging::logMessage("VPD type not supported. Can't find CCIN");
524         }
525     }
526     catch (const std::exception& l_ex)
527     {
528         const std::string l_errMsg{
529             "Failed to find CCIN in VPD. Error : " + std::string(l_ex.what())};
530 
531         if (typeid(l_ex) == std::type_index(typeid(DataException)))
532         {
533             EventLogger::createSyncPel(
534                 types::ErrorType::InvalidVpdMessage,
535                 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
536                 l_errMsg, std::nullopt, std::nullopt, std::nullopt,
537                 std::nullopt);
538         }
539 
540         logging::logMessage(l_errMsg);
541     }
542     return l_rc;
543 }
544 
545 /**
546  * @brief API to reset data of a FRU populated under PIM.
547  *
548  * This API resets the data for particular interfaces of a FRU under PIM.
549  *
550  * @param[in] i_objectPath - DBus object path of the FRU.
551  * @param[in] io_interfaceMap - Interface and its properties map.
552  */
553 inline void resetDataUnderPIM(const std::string& i_objectPath,
554                               types::InterfaceMap& io_interfaceMap)
555 {
556     try
557     {
558         std::array<const char*, 0> l_interfaces;
559         const types::MapperGetObject& l_getObjectMap =
560             dbusUtility::getObjectMap(i_objectPath, l_interfaces);
561 
562         const std::vector<std::string>& l_vpdRelatedInterfaces{
563             constants::operationalStatusInf, constants::inventoryItemInf,
564             constants::assetInf};
565 
566         for (const auto& [l_service, l_interfaceList] : l_getObjectMap)
567         {
568             if (l_service.compare(constants::pimServiceName) !=
569                 constants::STR_CMP_SUCCESS)
570             {
571                 continue;
572             }
573 
574             for (const auto& l_interface : l_interfaceList)
575             {
576                 if ((l_interface.find(constants::ipzVpdInf) !=
577                      std::string::npos) ||
578                     ((std::find(l_vpdRelatedInterfaces.begin(),
579                                 l_vpdRelatedInterfaces.end(), l_interface)) !=
580                      l_vpdRelatedInterfaces.end()))
581                 {
582                     const types::PropertyMap& l_propertyValueMap =
583                         dbusUtility::getPropertyMap(l_service, i_objectPath,
584                                                     l_interface);
585 
586                     types::PropertyMap l_propertyMap;
587 
588                     for (const auto& l_aProperty : l_propertyValueMap)
589                     {
590                         const std::string& l_propertyName = l_aProperty.first;
591                         const auto& l_propertyValue = l_aProperty.second;
592 
593                         if (std::holds_alternative<types::BinaryVector>(
594                                 l_propertyValue))
595                         {
596                             l_propertyMap.emplace(l_propertyName,
597                                                   types::BinaryVector{});
598                         }
599                         else if (std::holds_alternative<std::string>(
600                                      l_propertyValue))
601                         {
602                             l_propertyMap.emplace(l_propertyName,
603                                                   std::string{});
604                         }
605                         else if (std::holds_alternative<bool>(l_propertyValue))
606                         {
607                             // ToDo -- Update the functional status property
608                             // to true.
609                             if (l_propertyName.compare("Present") ==
610                                 constants::STR_CMP_SUCCESS)
611                             {
612                                 l_propertyMap.emplace(l_propertyName, false);
613                             }
614                         }
615                     }
616                     io_interfaceMap.emplace(l_interface,
617                                             std::move(l_propertyMap));
618                 }
619             }
620         }
621     }
622     catch (const std::exception& l_ex)
623     {
624         logging::logMessage("Failed to remove VPD for FRU: " + i_objectPath +
625                             " with error: " + std::string(l_ex.what()));
626     }
627 }
628 
629 /**
630  * @brief API to detect pass1 planar type.
631  *
632  * Based on HW version and IM keyword, This API detects is it is a pass1 planar
633  * or not.
634  *
635  * @return True if pass 1 planar, false otherwise.
636  */
637 inline bool isPass1Planar() noexcept
638 {
639     bool l_rc{false};
640     try
641     {
642         auto l_retVal = dbusUtility::readDbusProperty(
643             constants::pimServiceName, constants::systemVpdInvPath,
644             constants::viniInf, constants::kwdHW);
645 
646         auto l_hwVer = std::get_if<types::BinaryVector>(&l_retVal);
647 
648         l_retVal = dbusUtility::readDbusProperty(
649             constants::pimServiceName, constants::systemInvPath,
650             constants::vsbpInf, constants::kwdIM);
651 
652         auto l_imValue = std::get_if<types::BinaryVector>(&l_retVal);
653 
654         if (l_hwVer && l_imValue)
655         {
656             if (l_hwVer->size() != constants::VALUE_2)
657             {
658                 throw std::runtime_error("Invalid HW keyword length.");
659             }
660 
661             if (l_imValue->size() != constants::VALUE_4)
662             {
663                 throw std::runtime_error("Invalid IM keyword length.");
664             }
665 
666             const types::BinaryVector l_everest{80, 00, 48, 00};
667             const types::BinaryVector l_fuji{96, 00, 32, 00};
668 
669             if (((*l_imValue) == l_everest) || ((*l_imValue) == l_fuji))
670             {
671                 if ((*l_hwVer).at(1) < constants::VALUE_21)
672                 {
673                     l_rc = true;
674                 }
675             }
676             else if ((*l_hwVer).at(1) < constants::VALUE_2)
677             {
678                 l_rc = true;
679             }
680         }
681     }
682     catch (const std::exception& l_ex)
683     {
684         logging::logMessage("Failed to check for pass 1 planar. Error: " +
685                             std::string(l_ex.what()));
686     }
687 
688     return l_rc;
689 }
690 
691 /**
692  * @brief API to detect if system configuration is that of PowerVS system.
693  *
694  * @param[in] i_imValue - IM value of the system.
695  * @return true if it is PowerVS configuration, false otherwise.
696  */
697 inline bool isPowerVsConfiguration(const types::BinaryVector& i_imValue)
698 {
699     if (i_imValue.empty() || i_imValue.size() != constants::VALUE_4)
700     {
701         return false;
702     }
703 
704     // Should be a 0x5000XX series system.
705     if (i_imValue.at(0) == constants::HEX_VALUE_50 &&
706         i_imValue.at(1) == constants::HEX_VALUE_00)
707     {
708         std::string l_imagePrefix = dbusUtility::getImagePrefix();
709 
710         // Check image for 0x500030XX series.
711         if ((i_imValue.at(2) == constants::HEX_VALUE_30) &&
712             ((l_imagePrefix == constants::powerVsImagePrefix_MY) ||
713              (l_imagePrefix == constants::powerVsImagePrefix_NY)))
714         {
715             logging::logMessage("PowerVS configuration");
716             return true;
717         }
718 
719         // Check image for 0X500010XX series.
720         if ((i_imValue.at(2) == constants::HEX_VALUE_10) &&
721             ((l_imagePrefix == constants::powerVsImagePrefix_MZ) ||
722              (l_imagePrefix == constants::powerVsImagePrefix_NZ)))
723         {
724             logging::logMessage("PowerVS configuration");
725             return true;
726         }
727     }
728     return false;
729 }
730 } // namespace vpdSpecificUtility
731 } // namespace vpd
732