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