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 Check if the given CPU is an IO only chip. 332 * 333 * The CPU is termed as IO, whose all of the cores are bad and can never be 334 * used. Those CPU chips can be used for IO purpose like connecting PCIe 335 * devices etc., The CPU whose every cores are bad, can be identified from 336 * the CP00 record's PG keyword, only if all of the 8 EQs' value equals 337 * 0xE7F9FF. (1EQ has 4 cores grouped together by sharing its cache memory.) 338 * 339 * @param [in] pgKeyword - PG Keyword of CPU. 340 * @return true if the given cpu is an IO, false otherwise. 341 */ 342 bool isCPUIOGoodOnly(const std::string& pgKeyword); 343 344 /** 345 * @brief API to prime inventory Objects. 346 * 347 * @param[in] i_vpdFilePath - EEPROM file path. 348 * @return true if the prime inventory is success, false otherwise. 349 */ 350 bool primeInventory(const std::string& i_vpdFilePath); 351 352 /** 353 * @brief API to process preAction(base_action) defined in config JSON. 354 * 355 * @note sequence of tags under any given flag of preAction is EXTREMELY 356 * important to ensure proper processing. The API will process all the 357 * nested items under the base action sequentially. Also if any of the tag 358 * processing fails, the code will not process remaining tags under the 359 * flag. 360 * ******** sample format ************** 361 * fru EEPROM path: { 362 * base_action: { 363 * flag1: { 364 * tag1: { 365 * }, 366 * tag2: { 367 * } 368 * } 369 * flag2: { 370 * tags: { 371 * } 372 * } 373 * } 374 * } 375 * ************************************* 376 * 377 * @param[in] i_vpdFilePath - Path to the EEPROM file. 378 * @param[in] i_flagToProcess - To identify which flag(s) needs to be 379 * processed under PreAction tag of config JSON. 380 * @return Execution status. 381 */ 382 bool processPreAction(const std::string& i_vpdFilePath, 383 const std::string& i_flagToProcess); 384 385 /** 386 * @brief API to process postAction(base_action) defined in config JSON. 387 * 388 * @note Sequence of tags under any given flag of postAction is EXTREMELY 389 * important to ensure proper processing. The API will process all the 390 * nested items under the base action sequentially. Also if any of the tag 391 * processing fails, the code will not process remaining tags under the 392 * flag. 393 * ******** sample format ************** 394 * fru EEPROM path: { 395 * base_action: { 396 * flag1: { 397 * tag1: { 398 * }, 399 * tag2: { 400 * } 401 * } 402 * flag2: { 403 * tags: { 404 * } 405 * } 406 * } 407 * } 408 * ************************************* 409 * Also, if post action is required to be processed only for FRUs with 410 * certain CCIN then CCIN list can be provided under flag. 411 * 412 * @param[in] i_vpdFruPath - Path to the EEPROM file. 413 * @param[in] i_flagToProcess - To identify which flag(s) needs to be 414 * processed under postAction tag of config JSON. 415 * @param[in] i_parsedVpd - Optional Parsed VPD map. If CCIN match is 416 * required. 417 * @return Execution status. 418 */ 419 bool processPostAction( 420 const std::string& i_vpdFruPath, const std::string& i_flagToProcess, 421 const std::optional<types::VPDMapVariant> i_parsedVpd = std::nullopt); 422 423 /** 424 * @brief Function to enable and bring MUX out of idle state. 425 * 426 * This finds all the MUX defined in the system json and enables them by 427 * setting the holdidle parameter to 0. 428 * 429 * @throw std::runtime_error 430 */ 431 void enableMuxChips(); 432 433 /** 434 * @brief An API to perform backup or restore of VPD. 435 * 436 * @param[in,out] io_srcVpdMap - Source VPD map. 437 */ 438 void performBackupAndRestore(types::VPDMapVariant& io_srcVpdMap); 439 440 /** 441 * @brief API to update "Functional" property. 442 * 443 * The API sets the default value for "Functional" property once if the 444 * property is not yet populated over DBus. As the property value is not 445 * controlled by the VPD-Collection process, if it is found already 446 * populated, the functions skips re-populating the property so that already 447 * existing value can be retained. 448 * 449 * @param[in] i_inventoryObjPath - Inventory path as read from config JSON. 450 * @param[in] io_interfaces - Map to hold all the interfaces for the FRU. 451 */ 452 void processFunctionalProperty(const std::string& i_inventoryObjPath, 453 types::InterfaceMap& io_interfaces); 454 455 /** 456 * @brief API to update "enabled" property. 457 * 458 * The API sets the default value for "enabled" property once if the 459 * property is not yet populated over DBus. As the property value is not 460 * controlled by the VPD-Collection process, if it is found already 461 * populated, the functions skips re-populating the property so that already 462 * existing value can be retained. 463 * 464 * @param[in] i_inventoryObjPath - Inventory path as read from config JSON. 465 * @param[in] io_interfaces - Map to hold all the interfaces for the FRU. 466 */ 467 void processEnabledProperty(const std::string& i_inventoryObjPath, 468 types::InterfaceMap& io_interfaces); 469 470 /** 471 * @brief API to form asset tag string for the system. 472 * 473 * @param[in] i_parsedVpdMap - Parsed VPD map. 474 * 475 * @throw std::runtime_error 476 * 477 * @return - Formed asset tag string. 478 */ 479 std::string createAssetTagString( 480 const types::VPDMapVariant& i_parsedVpdMap); 481 482 /** 483 * @brief API to prime system blueprint. 484 * 485 * The API will traverse the system config JSON and will prime all the FRU 486 * paths which qualifies for priming. 487 */ 488 void primeSystemBlueprint(); 489 490 /** 491 * @brief API to set symbolic link for system config JSON. 492 * 493 * Once correct device tree is set, symbolic link to the correct sytsem 494 * config JSON is set to be used in subsequent BMC boot. 495 * 496 * @param[in] i_systemJson - system config JSON. 497 */ 498 void setJsonSymbolicLink(const std::string& i_systemJson); 499 500 /** 501 * @brief API to set present property. 502 * 503 * This API updates the present property of the given FRU with the given 504 * value. Note: It is the responsibility of the caller to determine whether 505 * the present property for the FRU should be updated or not. 506 * 507 * @param[in] i_vpdPath - EEPROM or inventory path. 508 * @param[in] i_value - value to be set. 509 */ 510 void setPresentProperty(const std::string& i_fruPath, const bool& i_value); 511 512 /** 513 * @brief API to check if the path needs to be skipped for collection. 514 * 515 * Some FRUs, under some given scenarios should not be collected and 516 * skipped. 517 * 518 * @param[in] i_vpdFilePath - EEPROM path. 519 * 520 * @return True - if path is empty or should be skipped, false otherwise. 521 */ 522 bool skipPathForCollection(const std::string& i_vpdFilePath); 523 524 /** 525 * @brief API to check if present property should be handled for given FRU. 526 * 527 * vpd-manager should update present property for a FRU if and only if it's 528 * not synthesized and vpd-manager handles present property for the FRU. 529 * This API assumes "handlePresence" tag is a subset of "synthesized" tag. 530 * 531 * @param[in] i_fru - JSON block for a single FRU. 532 * 533 * @return true if present property should be handled, false otherwise. 534 */ isPresentPropertyHandlingRequired(const nlohmann::json & i_fru) const535 inline bool isPresentPropertyHandlingRequired( 536 const nlohmann::json& i_fru) const noexcept 537 { 538 // TODO: revisit this to see if this logic can be optimized. 539 return !i_fru.value("synthesized", false) && 540 i_fru.value("handlePresence", true); 541 } 542 543 // Parsed JSON file. 544 nlohmann::json m_parsedJson{}; 545 546 // Hold if symlink is present or not. 547 bool m_isSymlinkPresent = false; 548 549 // Path to config JSON if applicable. 550 std::string& m_configJsonPath; 551 552 // Keeps track of active thread(s) doing VPD collection. 553 size_t m_activeCollectionThreadCount = 0; 554 555 // Holds status, if VPD collection has been done or not. 556 // Note: This variable does not give information about successfull or failed 557 // collection. It just states, if the VPD collection process is over or not. 558 bool m_isAllFruCollected = false; 559 560 // To distinguish the factory reset path. 561 bool m_isFactoryResetDone = false; 562 563 // Mutex to guard critical resource m_activeCollectionThreadCount. 564 std::mutex m_mutex; 565 566 // Counting semaphore to limit the number of threads. 567 std::counting_semaphore<constants::MAX_THREADS> m_semaphore; 568 569 // List of EEPROM paths for which VPD collection thread creation has failed. 570 std::forward_list<std::string> m_failedEepromPaths; 571 }; 572 } // namespace vpd 573