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::exception 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 * @throw std::exception 226 * 227 * @param[in] vpdFilePath - EEPROM file path. 228 * @param[out] parsedVpd - Parsed VPD as a map. 229 */ 230 void fillVPDMap(const std::string& vpdFilePath, 231 types::VPDMapVariant& parsedVpd); 232 233 /** 234 * @brief An API to parse and publish system VPD on D-Bus. 235 * 236 * Note: Throws exception in case of invalid VPD format. 237 * 238 * @param[in] parsedVpdMap - Parsed VPD as a map. 239 */ 240 void publishSystemVPD(const types::VPDMapVariant& parsedVpdMap); 241 242 /** 243 * @brief An API to process extrainterfaces w.r.t a FRU. 244 * 245 * @param[in] singleFru - JSON block for a single FRU. 246 * @param[out] interfaces - Map to hold interface along with its properties. 247 * @param[in] parsedVpdMap - Parsed VPD as a map. 248 */ 249 void processExtraInterfaces(const nlohmann::json& singleFru, 250 types::InterfaceMap& interfaces, 251 const types::VPDMapVariant& parsedVpdMap); 252 253 /** 254 * @brief An API to process embedded and synthesized FRUs. 255 * 256 * @param[in] singleFru - FRU to be processed. 257 * @param[out] interfaces - Map to hold interface along with its properties. 258 */ 259 void processEmbeddedAndSynthesizedFrus(const nlohmann::json& singleFru, 260 types::InterfaceMap& interfaces); 261 262 /** 263 * @brief An API to read process FRU based in CCIN. 264 * 265 * For some FRUs VPD can be processed only if the FRU has some specific 266 * value for CCIN. In case the value is not from that set, VPD for those 267 * FRUs can't be processed. 268 * 269 * @param[in] singleFru - Fru whose CCIN value needs to be matched. 270 * @param[in] parsedVpdMap - Parsed VPD map. 271 */ 272 bool processFruWithCCIN(const nlohmann::json& singleFru, 273 const types::VPDMapVariant& parsedVpdMap); 274 275 /** 276 * @brief API to process json's inherit flag. 277 * 278 * Inherit flag denotes that some property in the child FRU needs to be 279 * inherited from parent FRU. 280 * 281 * @param[in] parsedVpdMap - Parsed VPD as a map. 282 * @param[out] interfaces - Map to hold interface along with its properties. 283 */ 284 void processInheritFlag(const types::VPDMapVariant& parsedVpdMap, 285 types::InterfaceMap& interfaces); 286 287 /** 288 * @brief API to process json's "copyRecord" flag. 289 * 290 * copyRecord flag denotes if some record data needs to be copies in the 291 * given FRU. 292 * 293 * @param[in] singleFru - FRU being processed. 294 * @param[in] parsedVpdMap - Parsed VPD as a map. 295 * @param[out] interfaces - Map to hold interface along with its properties. 296 */ 297 void processCopyRecordFlag(const nlohmann::json& singleFru, 298 const types::VPDMapVariant& parsedVpdMap, 299 types::InterfaceMap& interfaces); 300 301 /** 302 * @brief An API to populate IPZ VPD property map. 303 * 304 * @param[out] interfacePropMap - Map of interface and properties under it. 305 * @param[in] keyordValueMap - Keyword value map of IPZ VPD. 306 * @param[in] interfaceName - Name of the interface. 307 */ 308 void populateIPZVPDpropertyMap(types::InterfaceMap& interfacePropMap, 309 const types::IPZKwdValueMap& keyordValueMap, 310 const std::string& interfaceName); 311 312 /** 313 * @brief An API to populate Kwd VPD property map. 314 * 315 * @param[in] keyordValueMap - Keyword value map of Kwd VPD. 316 * @param[out] interfaceMap - interface and property,value under it. 317 */ 318 void populateKwdVPDpropertyMap(const types::KeywordVpdMap& keyordVPDMap, 319 types::InterfaceMap& interfaceMap); 320 321 /** 322 * @brief API to populate all required interface for a FRU. 323 * 324 * @param[in] interfaceJson - JSON containing interfaces to be populated. 325 * @param[out] interfaceMap - Map to hold populated interfaces. 326 * @param[in] parsedVpdMap - Parsed VPD as a map. 327 */ 328 void populateInterfaces(const nlohmann::json& interfaceJson, 329 types::InterfaceMap& interfaceMap, 330 const types::VPDMapVariant& parsedVpdMap); 331 332 /** 333 * @brief Check if the given CPU is an IO only chip. 334 * 335 * The CPU is termed as IO, whose all of the cores are bad and can never be 336 * used. Those CPU chips can be used for IO purpose like connecting PCIe 337 * devices etc., The CPU whose every cores are bad, can be identified from 338 * the CP00 record's PG keyword, only if all of the 8 EQs' value equals 339 * 0xE7F9FF. (1EQ has 4 cores grouped together by sharing its cache memory.) 340 * 341 * @param [in] pgKeyword - PG Keyword of CPU. 342 * @return true if the given cpu is an IO, false otherwise. 343 */ 344 bool isCPUIOGoodOnly(const std::string& pgKeyword); 345 346 /** 347 * @brief API to prime inventory Objects. 348 * 349 * @param[in] i_vpdFilePath - EEPROM file path. 350 * @return true if the prime inventory is success, false otherwise. 351 */ 352 bool primeInventory(const std::string& i_vpdFilePath); 353 354 /** 355 * @brief API to process preAction(base_action) defined in config JSON. 356 * 357 * @note sequence of tags under any given flag of preAction is EXTREMELY 358 * important to ensure proper processing. The API will process all the 359 * nested items under the base action sequentially. Also if any of the tag 360 * processing fails, the code will not process remaining tags under the 361 * flag. 362 * ******** sample format ************** 363 * fru EEPROM path: { 364 * base_action: { 365 * flag1: { 366 * tag1: { 367 * }, 368 * tag2: { 369 * } 370 * } 371 * flag2: { 372 * tags: { 373 * } 374 * } 375 * } 376 * } 377 * ************************************* 378 * 379 * @param[in] i_vpdFilePath - Path to the EEPROM file. 380 * @param[in] i_flagToProcess - To identify which flag(s) needs to be 381 * processed under PreAction tag of config JSON. 382 * @return Execution status. 383 */ 384 bool processPreAction(const std::string& i_vpdFilePath, 385 const std::string& i_flagToProcess); 386 387 /** 388 * @brief API to process postAction(base_action) defined in config JSON. 389 * 390 * @note Sequence of tags under any given flag of postAction is EXTREMELY 391 * important to ensure proper processing. The API will process all the 392 * nested items under the base action sequentially. Also if any of the tag 393 * processing fails, the code will not process remaining tags under the 394 * flag. 395 * ******** sample format ************** 396 * fru EEPROM path: { 397 * base_action: { 398 * flag1: { 399 * tag1: { 400 * }, 401 * tag2: { 402 * } 403 * } 404 * flag2: { 405 * tags: { 406 * } 407 * } 408 * } 409 * } 410 * ************************************* 411 * Also, if post action is required to be processed only for FRUs with 412 * certain CCIN then CCIN list can be provided under flag. 413 * 414 * @param[in] i_vpdFruPath - Path to the EEPROM file. 415 * @param[in] i_flagToProcess - To identify which flag(s) needs to be 416 * processed under postAction tag of config JSON. 417 * @param[in] i_parsedVpd - Optional Parsed VPD map. If CCIN match is 418 * required. 419 * @return Execution status. 420 */ 421 bool processPostAction( 422 const std::string& i_vpdFruPath, const std::string& i_flagToProcess, 423 const std::optional<types::VPDMapVariant> i_parsedVpd = std::nullopt); 424 425 /** 426 * @brief Function to enable and bring MUX out of idle state. 427 * 428 * This finds all the MUX defined in the system json and enables them by 429 * setting the holdidle parameter to 0. 430 * 431 * @throw std::runtime_error 432 */ 433 void enableMuxChips(); 434 435 /** 436 * @brief An API to perform backup or restore of VPD. 437 * 438 * @param[in,out] io_srcVpdMap - Source VPD map. 439 */ 440 void performBackupAndRestore(types::VPDMapVariant& io_srcVpdMap); 441 442 /** 443 * @brief API to update "Functional" property. 444 * 445 * The API sets the default value for "Functional" property once if the 446 * property is not yet populated over DBus. As the property value is not 447 * controlled by the VPD-Collection process, if it is found already 448 * populated, the functions skips re-populating the property so that already 449 * existing value can be retained. 450 * 451 * @param[in] i_inventoryObjPath - Inventory path as read from config JSON. 452 * @param[in] io_interfaces - Map to hold all the interfaces for the FRU. 453 */ 454 void processFunctionalProperty(const std::string& i_inventoryObjPath, 455 types::InterfaceMap& io_interfaces); 456 457 /** 458 * @brief API to update "enabled" property. 459 * 460 * The API sets the default value for "enabled" property once if the 461 * property is not yet populated over DBus. As the property value is not 462 * controlled by the VPD-Collection process, if it is found already 463 * populated, the functions skips re-populating the property so that already 464 * existing value can be retained. 465 * 466 * @param[in] i_inventoryObjPath - Inventory path as read from config JSON. 467 * @param[in] io_interfaces - Map to hold all the interfaces for the FRU. 468 */ 469 void processEnabledProperty(const std::string& i_inventoryObjPath, 470 types::InterfaceMap& io_interfaces); 471 472 /** 473 * @brief API to form asset tag string for the system. 474 * 475 * @param[in] i_parsedVpdMap - Parsed VPD map. 476 * 477 * @throw std::runtime_error 478 * 479 * @return - Formed asset tag string. 480 */ 481 std::string createAssetTagString( 482 const types::VPDMapVariant& i_parsedVpdMap); 483 484 /** 485 * @brief API to prime system blueprint. 486 * 487 * The API will traverse the system config JSON and will prime all the FRU 488 * paths which qualifies for priming. 489 */ 490 void primeSystemBlueprint(); 491 492 /** 493 * @brief API to set symbolic link for system config JSON. 494 * 495 * Once correct device tree is set, symbolic link to the correct sytsem 496 * config JSON is set to be used in subsequent BMC boot. 497 * 498 * @param[in] i_systemJson - system config JSON. 499 */ 500 void setJsonSymbolicLink(const std::string& i_systemJson); 501 502 /** 503 * @brief API to set present property. 504 * 505 * This API updates the present property of the given FRU with the given 506 * value. Note: It is the responsibility of the caller to determine whether 507 * the present property for the FRU should be updated or not. 508 * 509 * @param[in] i_vpdPath - EEPROM or inventory path. 510 * @param[in] i_value - value to be set. 511 */ 512 void setPresentProperty(const std::string& i_fruPath, const bool& i_value); 513 514 /** 515 * @brief API to check if the path needs to be skipped for collection. 516 * 517 * Some FRUs, under some given scenarios should not be collected and 518 * skipped. 519 * 520 * @param[in] i_vpdFilePath - EEPROM path. 521 * 522 * @return True - if path is empty or should be skipped, false otherwise. 523 */ 524 bool skipPathForCollection(const std::string& i_vpdFilePath); 525 526 /** 527 * @brief API to check if present property should be handled for given FRU. 528 * 529 * vpd-manager should update present property for a FRU if and only if it's 530 * not synthesized and vpd-manager handles present property for the FRU. 531 * This API assumes "handlePresence" tag is a subset of "synthesized" tag. 532 * 533 * @param[in] i_fru - JSON block for a single FRU. 534 * 535 * @return true if present property should be handled, false otherwise. 536 */ isPresentPropertyHandlingRequired(const nlohmann::json & i_fru) const537 inline bool isPresentPropertyHandlingRequired( 538 const nlohmann::json& i_fru) const noexcept 539 { 540 // TODO: revisit this to see if this logic can be optimized. 541 return !i_fru.value("synthesized", false) && 542 i_fru.value("handlePresence", true); 543 } 544 545 // Parsed JSON file. 546 nlohmann::json m_parsedJson{}; 547 548 // Hold if symlink is present or not. 549 bool m_isSymlinkPresent = false; 550 551 // Path to config JSON if applicable. 552 std::string& m_configJsonPath; 553 554 // Keeps track of active thread(s) doing VPD collection. 555 size_t m_activeCollectionThreadCount = 0; 556 557 // Holds status, if VPD collection has been done or not. 558 // Note: This variable does not give information about successfull or failed 559 // collection. It just states, if the VPD collection process is over or not. 560 bool m_isAllFruCollected = false; 561 562 // To distinguish the factory reset path. 563 bool m_isFactoryResetDone = false; 564 565 // Mutex to guard critical resource m_activeCollectionThreadCount. 566 std::mutex m_mutex; 567 568 // Counting semaphore to limit the number of threads. 569 std::counting_semaphore<constants::MAX_THREADS> m_semaphore; 570 571 // List of EEPROM paths for which VPD collection thread creation has failed. 572 std::forward_list<std::string> m_failedEepromPaths; 573 }; 574 } // namespace vpd 575