1 #pragma once 2 3 #include "constants.hpp" 4 #include "types.hpp" 5 6 #include <nlohmann/json.hpp> 7 8 #include <mutex> 9 #include <optional> 10 #include <semaphore> 11 #include <tuple> 12 13 namespace vpd 14 { 15 /** 16 * @brief A class to process and publish VPD data. 17 * 18 * The class works on VPD and is mainly responsible for following tasks: 19 * 1) Select appropriate device tree and JSON. Reboot if required. 20 * 2) Get desired parser using parser factory. 21 * 3) Calling respective parser class to get parsed VPD. 22 * 4) Arranging VPD data under required interfaces. 23 * 5) Calling PIM to publish VPD. 24 * 25 * The class may also implement helper functions required for VPD handling. 26 */ 27 class Worker 28 { 29 public: 30 /** 31 * List of deleted functions. 32 */ 33 Worker(const Worker&); 34 Worker& operator=(const Worker&); 35 Worker(Worker&&) = delete; 36 37 /** 38 * @brief Constructor. 39 * 40 * In case the processing is not JSON based, no argument needs to be passed. 41 * Constructor will also, based on symlink pick the correct JSON and 42 * initialize the parsed JSON variable. 43 * 44 * @param[in] pathToConfigJSON - Path to the config JSON, if applicable. 45 * @param[in] i_maxThreadCount - Maximum thread while collecting FRUs VPD. 46 * 47 * Note: Throws std::exception in case of construction failure. Caller needs 48 * to handle to detect successful object creation. 49 */ 50 Worker(std::string pathToConfigJson = std::string(), 51 uint8_t i_maxThreadCount = constants::MAX_THREADS); 52 53 /** 54 * @brief Destructor 55 */ 56 ~Worker() = default; 57 58 #ifdef IBM_SYSTEM 59 /** 60 * @brief API to perform initial setup before manager claims Bus name. 61 * 62 * Before BUS name for VPD-Manager is claimed, fitconfig whould be set for 63 * corret device tree, inventory JSON w.r.t system should be linked and 64 * system VPD should be on DBus. 65 */ 66 void performInitialSetup(); 67 #endif 68 69 /** 70 * @brief An API to check if system VPD is already published. 71 * 72 * @return Status, true if system is already collected else false. 73 */ 74 bool isSystemVPDOnDBus() const; 75 76 /** 77 * @brief API to process all FRUs presnt in config JSON file. 78 * 79 * This API based on config JSON passed/selected for the system, will 80 * trigger parser for all the FRUs and publish it on DBus. 81 * 82 * Note: Config JSON file path should be passed to worker class constructor 83 * to make use of this API. 84 * 85 */ 86 void collectFrusFromJson(); 87 88 /** 89 * @brief API to parse VPD data 90 * 91 * @param[in] i_vpdFilePath - Path to the VPD file. 92 */ 93 types::VPDMapVariant parseVpdFile(const std::string& i_vpdFilePath); 94 95 /** 96 * @brief An API to populate DBus interfaces for a FRU. 97 * 98 * Note: Call this API to populate D-Bus. Also caller should handle empty 99 * objectInterfaceMap. 100 * 101 * @param[in] parsedVpdMap - Parsed VPD as a map. 102 * @param[out] objectInterfaceMap - Object and its interfaces map. 103 * @param[in] vpdFilePath - EEPROM path of FRU. 104 */ 105 void populateDbus(const types::VPDMapVariant& parsedVpdMap, 106 types::ObjectMap& objectInterfaceMap, 107 const std::string& vpdFilePath); 108 109 /** 110 * @brief An API to delete FRU VPD over DBus. 111 * 112 * @param[in] i_dbusObjPath - Dbus object path of the FRU. 113 * 114 * @throw std::runtime_error if given input path is empty. 115 */ 116 void deleteFruVpd(const std::string& i_dbusObjPath); 117 118 /** 119 * @brief API to get status of VPD collection process. 120 * 121 * @return - True when done, false otherwise. 122 */ isAllFruCollectionDone() const123 inline bool isAllFruCollectionDone() const 124 { 125 return m_isAllFruCollected; 126 } 127 128 /** 129 * @brief API to get system config JSON object 130 * 131 * @return System config JSON object. 132 */ getSysCfgJsonObj() const133 inline nlohmann::json getSysCfgJsonObj() const 134 { 135 return m_parsedJson; 136 } 137 138 /** 139 * @brief API to get active thread count. 140 * 141 * Each FRU is collected in a separate thread. This API gives the active 142 * thread collecting FRU's VPD at any given time. 143 * 144 * @return Count of active threads. 145 */ getActiveThreadCount() const146 size_t getActiveThreadCount() const 147 { 148 return m_activeCollectionThreadCount; 149 } 150 151 /** 152 * @brief API to get list of EEPROMs for which thread creation failed. 153 * 154 * This API returns reference to list of EEPROM paths for which VPD 155 * collection thread creation has failed. Manager needs to process this list 156 * of EEPROMs and take appropriate action. 157 * 158 * @return reference to list of EEPROM paths for which VPD collection thread 159 * creation has failed 160 */ getFailedEepromPaths()161 inline std::forward_list<std::string>& getFailedEepromPaths() noexcept 162 { 163 return m_failedEepromPaths; 164 } 165 166 private: 167 /** 168 * @brief An API to parse and publish a FRU VPD over D-Bus. 169 * 170 * Note: This API will handle all the exceptions internally and will only 171 * return status of parsing and publishing of VPD over D-Bus. 172 * 173 * @param[in] i_vpdFilePath - Path of file containing VPD. 174 * @return Tuple of status and file path. Status, true if successfull else 175 * false. 176 */ 177 std::tuple<bool, std::string> parseAndPublishVPD( 178 const std::string& i_vpdFilePath); 179 180 /** 181 * @brief An API to set appropriate device tree and JSON. 182 * 183 * This API based on system chooses corresponding device tree and JSON. 184 * If device tree change is required, it updates the "fitconfig" and reboots 185 * the system. Else it is NOOP. 186 * 187 * @throw std::runtime_error 188 */ 189 void setDeviceTreeAndJson(); 190 191 /** 192 * @brief API to select system specific JSON. 193 * 194 * The API based on the IM value of VPD, will select appropriate JSON for 195 * the system. In case no system is found corresponding to the extracted IM 196 * value, error will be logged. 197 * 198 * @param[out] systemJson - System JSON name. 199 * @param[in] parsedVpdMap - Parsed VPD map. 200 */ 201 void getSystemJson(std::string& systemJson, 202 const types::VPDMapVariant& parsedVpdMap); 203 204 /** 205 * @brief An API to read IM value from VPD. 206 * 207 * Note: Throws exception in case of error. Caller need to handle. 208 * 209 * @param[in] parsedVpd - Parsed VPD. 210 */ 211 std::string getIMValue(const types::IPZVpdMap& parsedVpd) const; 212 213 /** 214 * @brief An API to read HW version from VPD. 215 * 216 * Note: Throws exception in case of error. Caller need to handle. 217 * 218 * @param[in] parsedVpd - Parsed VPD. 219 */ 220 std::string getHWVersion(const types::IPZVpdMap& parsedVpd) const; 221 222 /** 223 * @brief An API to parse given VPD file path. 224 * 225 * @param[in] vpdFilePath - EEPROM file path. 226 * @param[out] parsedVpd - Parsed VPD as a map. 227 */ 228 void fillVPDMap(const std::string& vpdFilePath, 229 types::VPDMapVariant& parsedVpd); 230 231 /** 232 * @brief An API to parse and publish system VPD on D-Bus. 233 * 234 * Note: Throws exception in case of invalid VPD format. 235 * 236 * @param[in] parsedVpdMap - Parsed VPD as a map. 237 */ 238 void publishSystemVPD(const types::VPDMapVariant& parsedVpdMap); 239 240 /** 241 * @brief An API to process extrainterfaces w.r.t a FRU. 242 * 243 * @param[in] singleFru - JSON block for a single FRU. 244 * @param[out] interfaces - Map to hold interface along with its properties. 245 * @param[in] parsedVpdMap - Parsed VPD as a map. 246 */ 247 void processExtraInterfaces(const nlohmann::json& singleFru, 248 types::InterfaceMap& interfaces, 249 const types::VPDMapVariant& parsedVpdMap); 250 251 /** 252 * @brief An API to process embedded and synthesized FRUs. 253 * 254 * @param[in] singleFru - FRU to be processed. 255 * @param[out] interfaces - Map to hold interface along with its properties. 256 */ 257 void processEmbeddedAndSynthesizedFrus(const nlohmann::json& singleFru, 258 types::InterfaceMap& interfaces); 259 260 /** 261 * @brief An API to read process FRU based in CCIN. 262 * 263 * For some FRUs VPD can be processed only if the FRU has some specific 264 * value for CCIN. In case the value is not from that set, VPD for those 265 * FRUs can't be processed. 266 * 267 * @param[in] singleFru - Fru whose CCIN value needs to be matched. 268 * @param[in] parsedVpdMap - Parsed VPD map. 269 */ 270 bool processFruWithCCIN(const nlohmann::json& singleFru, 271 const types::VPDMapVariant& parsedVpdMap); 272 273 /** 274 * @brief API to process json's inherit flag. 275 * 276 * Inherit flag denotes that some property in the child FRU needs to be 277 * inherited from parent FRU. 278 * 279 * @param[in] parsedVpdMap - Parsed VPD as a map. 280 * @param[out] interfaces - Map to hold interface along with its properties. 281 */ 282 void processInheritFlag(const types::VPDMapVariant& parsedVpdMap, 283 types::InterfaceMap& interfaces); 284 285 /** 286 * @brief API to process json's "copyRecord" flag. 287 * 288 * copyRecord flag denotes if some record data needs to be copies in the 289 * given FRU. 290 * 291 * @param[in] singleFru - FRU being processed. 292 * @param[in] parsedVpdMap - Parsed VPD as a map. 293 * @param[out] interfaces - Map to hold interface along with its properties. 294 */ 295 void processCopyRecordFlag(const nlohmann::json& singleFru, 296 const types::VPDMapVariant& parsedVpdMap, 297 types::InterfaceMap& interfaces); 298 299 /** 300 * @brief An API to populate IPZ VPD property map. 301 * 302 * @param[out] interfacePropMap - Map of interface and properties under it. 303 * @param[in] keyordValueMap - Keyword value map of IPZ VPD. 304 * @param[in] interfaceName - Name of the interface. 305 */ 306 void populateIPZVPDpropertyMap(types::InterfaceMap& interfacePropMap, 307 const types::IPZKwdValueMap& keyordValueMap, 308 const std::string& interfaceName); 309 310 /** 311 * @brief An API to populate Kwd VPD property map. 312 * 313 * @param[in] keyordValueMap - Keyword value map of Kwd VPD. 314 * @param[out] interfaceMap - interface and property,value under it. 315 */ 316 void populateKwdVPDpropertyMap(const types::KeywordVpdMap& keyordVPDMap, 317 types::InterfaceMap& interfaceMap); 318 319 /** 320 * @brief API to populate all required interface for a FRU. 321 * 322 * @param[in] interfaceJson - JSON containing interfaces to be populated. 323 * @param[out] interfaceMap - Map to hold populated interfaces. 324 * @param[in] parsedVpdMap - Parsed VPD as a map. 325 */ 326 void populateInterfaces(const nlohmann::json& interfaceJson, 327 types::InterfaceMap& interfaceMap, 328 const types::VPDMapVariant& parsedVpdMap); 329 330 /** 331 * @brief Helper function to insert or merge in map. 332 * 333 * This method checks in the given inventory::InterfaceMap if the given 334 * interface key is existing or not. If the interface key already exists, 335 * given property map is inserted into it. If the key does'nt exist then 336 * given interface and property map pair is newly created. If the property 337 * present in propertymap already exist in the InterfaceMap, then the new 338 * property value is ignored. 339 * 340 * @param[in,out] interfaceMap - map object of type inventory::InterfaceMap 341 * only. 342 * @param[in] interface - Interface name. 343 * @param[in] property - new property map that needs to be emplaced. 344 */ 345 void insertOrMerge(types::InterfaceMap& interfaceMap, 346 const std::string& interface, 347 types::PropertyMap&& property); 348 349 /** 350 * @brief Check if the given CPU is an IO only chip. 351 * 352 * The CPU is termed as IO, whose all of the cores are bad and can never be 353 * used. Those CPU chips can be used for IO purpose like connecting PCIe 354 * devices etc., The CPU whose every cores are bad, can be identified from 355 * the CP00 record's PG keyword, only if all of the 8 EQs' value equals 356 * 0xE7F9FF. (1EQ has 4 cores grouped together by sharing its cache memory.) 357 * 358 * @param [in] pgKeyword - PG Keyword of CPU. 359 * @return true if the given cpu is an IO, false otherwise. 360 */ 361 bool isCPUIOGoodOnly(const std::string& pgKeyword); 362 363 /** 364 * @brief API to prime inventory Objects. 365 * 366 * @param[in] i_vpdFilePath - EEPROM file path. 367 * @return true if the prime inventory is success, false otherwise. 368 */ 369 bool primeInventory(const std::string& i_vpdFilePath); 370 371 /** 372 * @brief API to process preAction(base_action) defined in config JSON. 373 * 374 * @note sequence of tags under any given flag of preAction is EXTREMELY 375 * important to ensure proper processing. The API will process all the 376 * nested items under the base action sequentially. Also if any of the tag 377 * processing fails, the code will not process remaining tags under the 378 * flag. 379 * ******** sample format ************** 380 * fru EEPROM path: { 381 * base_action: { 382 * flag1: { 383 * tag1: { 384 * }, 385 * tag2: { 386 * } 387 * } 388 * flag2: { 389 * tags: { 390 * } 391 * } 392 * } 393 * } 394 * ************************************* 395 * 396 * @param[in] i_vpdFilePath - Path to the EEPROM file. 397 * @param[in] i_flagToProcess - To identify which flag(s) needs to be 398 * processed under PreAction tag of config JSON. 399 * @return Execution status. 400 */ 401 bool processPreAction(const std::string& i_vpdFilePath, 402 const std::string& i_flagToProcess); 403 404 /** 405 * @brief API to process postAction(base_action) defined in config JSON. 406 * 407 * @note Sequence of tags under any given flag of postAction is EXTREMELY 408 * important to ensure proper processing. The API will process all the 409 * nested items under the base action sequentially. Also if any of the tag 410 * processing fails, the code will not process remaining tags under the 411 * flag. 412 * ******** sample format ************** 413 * fru EEPROM path: { 414 * base_action: { 415 * flag1: { 416 * tag1: { 417 * }, 418 * tag2: { 419 * } 420 * } 421 * flag2: { 422 * tags: { 423 * } 424 * } 425 * } 426 * } 427 * ************************************* 428 * Also, if post action is required to be processed only for FRUs with 429 * certain CCIN then CCIN list can be provided under flag. 430 * 431 * @param[in] i_vpdFruPath - Path to the EEPROM file. 432 * @param[in] i_flagToProcess - To identify which flag(s) needs to be 433 * processed under postAction tag of config JSON. 434 * @param[in] i_parsedVpd - Optional Parsed VPD map. If CCIN match is 435 * required. 436 * @return Execution status. 437 */ 438 bool processPostAction( 439 const std::string& i_vpdFruPath, const std::string& i_flagToProcess, 440 const std::optional<types::VPDMapVariant> i_parsedVpd = std::nullopt); 441 442 /** 443 * @brief Function to enable and bring MUX out of idle state. 444 * 445 * This finds all the MUX defined in the system json and enables them by 446 * setting the holdidle parameter to 0. 447 * 448 * @throw std::runtime_error 449 */ 450 void enableMuxChips(); 451 452 /** 453 * @brief An API to perform backup or restore of VPD. 454 * 455 * @param[in,out] io_srcVpdMap - Source VPD map. 456 */ 457 void performBackupAndRestore(types::VPDMapVariant& io_srcVpdMap); 458 459 /** 460 * @brief API to update "Functional" property. 461 * 462 * The API sets the default value for "Functional" property once if the 463 * property is not yet populated over DBus. As the property value is not 464 * controlled by the VPD-Collection process, if it is found already 465 * populated, the functions skips re-populating the property so that already 466 * existing value can be retained. 467 * 468 * @param[in] i_inventoryObjPath - Inventory path as read from config JSON. 469 * @param[in] io_interfaces - Map to hold all the interfaces for the FRU. 470 */ 471 void processFunctionalProperty(const std::string& i_inventoryObjPath, 472 types::InterfaceMap& io_interfaces); 473 474 /** 475 * @brief API to update "enabled" property. 476 * 477 * The API sets the default value for "enabled" property once if the 478 * property is not yet populated over DBus. As the property value is not 479 * controlled by the VPD-Collection process, if it is found already 480 * populated, the functions skips re-populating the property so that already 481 * existing value can be retained. 482 * 483 * @param[in] i_inventoryObjPath - Inventory path as read from config JSON. 484 * @param[in] io_interfaces - Map to hold all the interfaces for the FRU. 485 */ 486 void processEnabledProperty(const std::string& i_inventoryObjPath, 487 types::InterfaceMap& io_interfaces); 488 489 /** 490 * @brief API to form asset tag string for the system. 491 * 492 * @param[in] i_parsedVpdMap - Parsed VPD map. 493 * 494 * @throw std::runtime_error 495 * 496 * @return - Formed asset tag string. 497 */ 498 std::string createAssetTagString( 499 const types::VPDMapVariant& i_parsedVpdMap); 500 501 /** 502 * @brief API to prime system blueprint. 503 * 504 * The API will traverse the system config JSON and will prime all the FRU 505 * paths which qualifies for priming. 506 */ 507 void primeSystemBlueprint(); 508 509 /** 510 * @brief API to set symbolic link for system config JSON. 511 * 512 * Once correct device tree is set, symbolic link to the correct sytsem 513 * config JSON is set to be used in subsequent BMC boot. 514 * 515 * @param[in] i_systemJson - system config JSON. 516 */ 517 void setJsonSymbolicLink(const std::string& i_systemJson); 518 519 /** 520 * @brief API to set present property. 521 * 522 * This API updates the present property of the given FRU with the given 523 * value. Note: It is the responsibility of the caller to determine whether 524 * the present property for the FRU should be updated or not. 525 * 526 * @param[in] i_vpdPath - EEPROM or inventory path. 527 * @param[in] i_value - value to be set. 528 */ 529 void setPresentProperty(const std::string& i_fruPath, const bool& i_value); 530 531 /** 532 * @brief API to check if the path needs to be skipped for collection. 533 * 534 * Some FRUs, under some given scenarios should not be collected and 535 * skipped. 536 * 537 * @param[in] i_vpdFilePath - EEPROM path. 538 * 539 * @return True - if path is empty or should be skipped, false otherwise. 540 */ 541 bool skipPathForCollection(const std::string& i_vpdFilePath); 542 543 /** 544 * @brief API to check if present property should be handled for given FRU. 545 * 546 * vpd-manager should update present property for a FRU if and only if it's 547 * not synthesized and vpd-manager handles present property for the FRU. 548 * This API assumes "handlePresence" tag is a subset of "synthesized" tag. 549 * 550 * @param[in] i_fru - JSON block for a single FRU. 551 * 552 * @return true if present property should be handled, false otherwise. 553 */ isPresentPropertyHandlingRequired(const nlohmann::json & i_fru) const554 inline bool isPresentPropertyHandlingRequired( 555 const nlohmann::json& i_fru) const noexcept 556 { 557 // TODO: revisit this to see if this logic can be optimized. 558 return !i_fru.value("synthesized", false) && 559 i_fru.value("handlePresence", true); 560 } 561 562 // Parsed JSON file. 563 nlohmann::json m_parsedJson{}; 564 565 // Hold if symlink is present or not. 566 bool m_isSymlinkPresent = false; 567 568 // Path to config JSON if applicable. 569 std::string& m_configJsonPath; 570 571 // Keeps track of active thread(s) doing VPD collection. 572 size_t m_activeCollectionThreadCount = 0; 573 574 // Holds status, if VPD collection has been done or not. 575 // Note: This variable does not give information about successfull or failed 576 // collection. It just states, if the VPD collection process is over or not. 577 bool m_isAllFruCollected = false; 578 579 // To distinguish the factory reset path. 580 bool m_isFactoryResetDone = false; 581 582 // Mutex to guard critical resource m_activeCollectionThreadCount. 583 std::mutex m_mutex; 584 585 // Counting semaphore to limit the number of threads. 586 std::counting_semaphore<constants::MAX_THREADS> m_semaphore; 587 588 // List of EEPROM paths for which VPD collection thread creation has failed. 589 std::forward_list<std::string> m_failedEepromPaths; 590 }; 591 } // namespace vpd 592