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 * @param[in] i_vpdCollectionMode - Mode in which VPD collection should take 47 * place. 48 * 49 * Note: Throws std::exception in case of construction failure. Caller needs 50 * to handle to detect successful object creation. 51 */ 52 Worker(std::string pathToConfigJson = std::string(), 53 uint8_t i_maxThreadCount = constants::MAX_THREADS, 54 types::VpdCollectionMode i_vpdCollectionMode = 55 types::VpdCollectionMode::DEFAULT_MODE); 56 57 /** 58 * @brief Destructor 59 */ 60 ~Worker() = default; 61 62 /** 63 * @brief An API to check if system VPD is already published. 64 * 65 * @return Status, true if system is already collected else false. 66 */ 67 bool isSystemVPDOnDBus() const; 68 69 /** 70 * @brief API to process all FRUs presnt in config JSON file. 71 * 72 * This API based on config JSON passed/selected for the system, will 73 * trigger parser for all the FRUs and publish it on DBus. 74 * 75 * Note: Config JSON file path should be passed to worker class constructor 76 * to make use of this API. 77 * 78 */ 79 void collectFrusFromJson(); 80 81 /** 82 * @brief API to parse VPD data 83 * 84 * @param[in] i_vpdFilePath - Path to the VPD file. 85 */ 86 types::VPDMapVariant parseVpdFile(const std::string& i_vpdFilePath); 87 88 /** 89 * @brief An API to populate DBus interfaces for a FRU. 90 * 91 * Note: Call this API to populate D-Bus. Also caller should handle empty 92 * objectInterfaceMap. 93 * 94 * @param[in] parsedVpdMap - Parsed VPD as a map. 95 * @param[out] objectInterfaceMap - Object and its interfaces map. 96 * @param[in] vpdFilePath - EEPROM path of FRU. 97 */ 98 void populateDbus(const types::VPDMapVariant& parsedVpdMap, 99 types::ObjectMap& objectInterfaceMap, 100 const std::string& vpdFilePath); 101 102 /** 103 * @brief An API to delete FRU VPD over DBus. 104 * 105 * @param[in] i_dbusObjPath - Dbus object path of the FRU. 106 * 107 * @throw std::runtime_error if given input path is empty. 108 */ 109 void deleteFruVpd(const std::string& i_dbusObjPath); 110 111 /** 112 * @brief API to get status of VPD collection process. 113 * 114 * @return - True when done, false otherwise. 115 */ isAllFruCollectionDone() const116 inline bool isAllFruCollectionDone() const 117 { 118 return m_isAllFruCollected; 119 } 120 121 /** 122 * @brief API to get system config JSON object 123 * 124 * @return System config JSON object. 125 */ getSysCfgJsonObj() const126 inline nlohmann::json getSysCfgJsonObj() const 127 { 128 return m_parsedJson; 129 } 130 131 /** 132 * @brief API to get active thread count. 133 * 134 * Each FRU is collected in a separate thread. This API gives the active 135 * thread collecting FRU's VPD at any given time. 136 * 137 * @return Count of active threads. 138 */ getActiveThreadCount() const139 size_t getActiveThreadCount() const 140 { 141 return m_activeCollectionThreadCount; 142 } 143 144 /** 145 * @brief API to get list of EEPROMs for which thread creation failed. 146 * 147 * This API returns reference to list of EEPROM paths for which VPD 148 * collection thread creation has failed. Manager needs to process this list 149 * of EEPROMs and take appropriate action. 150 * 151 * @return reference to list of EEPROM paths for which VPD collection thread 152 * creation has failed 153 */ getFailedEepromPaths()154 inline std::forward_list<std::string>& getFailedEepromPaths() noexcept 155 { 156 return m_failedEepromPaths; 157 } 158 159 /** 160 * @brief API to get VPD collection mode 161 * 162 * @return VPD collection mode enum value 163 */ getVpdCollectionMode() const164 inline types::VpdCollectionMode getVpdCollectionMode() const 165 { 166 return m_vpdCollectionMode; 167 } 168 169 /** 170 * @brief Collect single FRU VPD 171 * API can be used to perform VPD collection for the given FRU, only if the 172 * current state of the system matches with the state at which the FRU is 173 * allowed for VPD recollection. 174 * 175 * @param[in] i_dbusObjPath - D-bus object path 176 */ 177 void collectSingleFruVpd( 178 const sdbusplus::message::object_path& i_dbusObjPath); 179 180 /** 181 * @brief Perform VPD recollection 182 * This api will trigger parser to perform VPD recollection for FRUs that 183 * can be replaced at standby. 184 */ 185 void performVpdRecollection(); 186 187 /** 188 * @brief An API to set appropriate device tree and JSON. 189 * 190 * This API based on system chooses corresponding device tree and JSON. 191 * If device tree change is required, it updates the "fitconfig" and reboots 192 * the system. Else it is NOOP. 193 * 194 * @throw std::exception 195 */ 196 void setDeviceTreeAndJson(); 197 198 /** 199 * @brief API to set CollectionStatus property. 200 * 201 * This API updates the CollectionStatus property of the given FRU with the 202 * given value. 203 * 204 * @param[in] i_vpdPath - EEPROM or inventory path. 205 * @param[in] i_value - Value to be set. 206 */ 207 void setCollectionStatusProperty(const std::string& i_fruPath, 208 const std::string& i_value) const noexcept; 209 210 private: 211 /** 212 * @brief An API to parse and publish a FRU VPD over D-Bus. 213 * 214 * Note: This API will handle all the exceptions internally and will only 215 * return status of parsing and publishing of VPD over D-Bus. 216 * 217 * @param[in] i_vpdFilePath - Path of file containing VPD. 218 * @return Tuple of status and file path. Status, true if successfull else 219 * false. 220 */ 221 std::tuple<bool, std::string> parseAndPublishVPD( 222 const std::string& i_vpdFilePath); 223 224 /** 225 * @brief API to select system specific JSON. 226 * 227 * The API based on the IM value of VPD, will select appropriate JSON for 228 * the system. In case no system is found corresponding to the extracted IM 229 * value, error will be logged. 230 * 231 * @param[out] systemJson - System JSON name. 232 * @param[in] parsedVpdMap - Parsed VPD map. 233 */ 234 void getSystemJson(std::string& systemJson, 235 const types::VPDMapVariant& parsedVpdMap); 236 237 /** 238 * @brief An API to read IM value from VPD. 239 * 240 * Note: Throws exception in case of error. Caller need to handle. 241 * 242 * @param[in] parsedVpd - Parsed VPD. 243 */ 244 std::string getIMValue(const types::IPZVpdMap& parsedVpd) const; 245 246 /** 247 * @brief An API to read HW version from VPD. 248 * 249 * Note: Throws exception in case of error. Caller need to handle. 250 * 251 * @param[in] parsedVpd - Parsed VPD. 252 */ 253 std::string getHWVersion(const types::IPZVpdMap& parsedVpd) const; 254 255 /** 256 * @brief An API to parse given VPD file path. 257 * 258 * @throw std::exception 259 * 260 * @param[in] vpdFilePath - EEPROM file path. 261 * @param[out] parsedVpd - Parsed VPD as a map. 262 */ 263 void fillVPDMap(const std::string& vpdFilePath, 264 types::VPDMapVariant& parsedVpd); 265 266 /** 267 * @brief An API to parse and publish system VPD on D-Bus. 268 * 269 * Note: Throws exception in case of invalid VPD format. 270 * 271 * @param[in] parsedVpdMap - Parsed VPD as a map. 272 */ 273 void publishSystemVPD(const types::VPDMapVariant& parsedVpdMap); 274 275 /** 276 * @brief An API to process extrainterfaces w.r.t a FRU. 277 * 278 * @param[in] singleFru - JSON block for a single FRU. 279 * @param[out] interfaces - Map to hold interface along with its properties. 280 * @param[in] parsedVpdMap - Parsed VPD as a map. 281 */ 282 void processExtraInterfaces(const nlohmann::json& singleFru, 283 types::InterfaceMap& interfaces, 284 const types::VPDMapVariant& parsedVpdMap); 285 286 /** 287 * @brief An API to process embedded and synthesized FRUs. 288 * 289 * @param[in] singleFru - FRU to be processed. 290 * @param[out] interfaces - Map to hold interface along with its properties. 291 */ 292 void processEmbeddedAndSynthesizedFrus(const nlohmann::json& singleFru, 293 types::InterfaceMap& interfaces); 294 295 /** 296 * @brief An API to read process FRU based in CCIN. 297 * 298 * For some FRUs VPD can be processed only if the FRU has some specific 299 * value for CCIN. In case the value is not from that set, VPD for those 300 * FRUs can't be processed. 301 * 302 * @param[in] singleFru - Fru whose CCIN value needs to be matched. 303 * @param[in] parsedVpdMap - Parsed VPD map. 304 */ 305 bool processFruWithCCIN(const nlohmann::json& singleFru, 306 const types::VPDMapVariant& parsedVpdMap); 307 308 /** 309 * @brief API to process json's inherit flag. 310 * 311 * Inherit flag denotes that some property in the child FRU needs to be 312 * inherited from parent FRU. 313 * 314 * @param[in] parsedVpdMap - Parsed VPD as a map. 315 * @param[out] interfaces - Map to hold interface along with its properties. 316 */ 317 void processInheritFlag(const types::VPDMapVariant& parsedVpdMap, 318 types::InterfaceMap& interfaces); 319 320 /** 321 * @brief API to process json's "copyRecord" flag. 322 * 323 * copyRecord flag denotes if some record data needs to be copies in the 324 * given FRU. 325 * 326 * @param[in] singleFru - FRU being processed. 327 * @param[in] parsedVpdMap - Parsed VPD as a map. 328 * @param[out] interfaces - Map to hold interface along with its properties. 329 */ 330 void processCopyRecordFlag(const nlohmann::json& singleFru, 331 const types::VPDMapVariant& parsedVpdMap, 332 types::InterfaceMap& interfaces); 333 334 /** 335 * @brief An API to populate IPZ VPD property map. 336 * 337 * @param[out] interfacePropMap - Map of interface and properties under it. 338 * @param[in] keyordValueMap - Keyword value map of IPZ VPD. 339 * @param[in] interfaceName - Name of the interface. 340 */ 341 void populateIPZVPDpropertyMap(types::InterfaceMap& interfacePropMap, 342 const types::IPZKwdValueMap& keyordValueMap, 343 const std::string& interfaceName); 344 345 /** 346 * @brief An API to populate Kwd VPD property map. 347 * 348 * @param[in] keyordValueMap - Keyword value map of Kwd VPD. 349 * @param[out] interfaceMap - interface and property,value under it. 350 */ 351 void populateKwdVPDpropertyMap(const types::KeywordVpdMap& keyordVPDMap, 352 types::InterfaceMap& interfaceMap); 353 354 /** 355 * @brief API to populate all required interface for a FRU. 356 * 357 * @param[in] interfaceJson - JSON containing interfaces to be populated. 358 * @param[out] interfaceMap - Map to hold populated interfaces. 359 * @param[in] parsedVpdMap - Parsed VPD as a map. 360 */ 361 void populateInterfaces(const nlohmann::json& interfaceJson, 362 types::InterfaceMap& interfaceMap, 363 const types::VPDMapVariant& parsedVpdMap); 364 365 /** 366 * @brief Check if the given CPU is an IO only chip. 367 * 368 * The CPU is termed as IO, whose all of the cores are bad and can never be 369 * used. Those CPU chips can be used for IO purpose like connecting PCIe 370 * devices etc., The CPU whose every cores are bad, can be identified from 371 * the CP00 record's PG keyword, only if all of the 8 EQs' value equals 372 * 0xE7F9FF. (1EQ has 4 cores grouped together by sharing its cache memory.) 373 * 374 * @param [in] pgKeyword - PG Keyword of CPU. 375 * @return true if the given cpu is an IO, false otherwise. 376 */ 377 bool isCPUIOGoodOnly(const std::string& pgKeyword); 378 379 /** 380 * @brief API to process preAction(base_action) defined in config JSON. 381 * 382 * @note sequence of tags under any given flag of preAction is EXTREMELY 383 * important to ensure proper processing. The API will process all the 384 * nested items under the base action sequentially. Also if any of the tag 385 * processing fails, the code will not process remaining tags under the 386 * flag. 387 * ******** sample format ************** 388 * fru EEPROM path: { 389 * base_action: { 390 * flag1: { 391 * tag1: { 392 * }, 393 * tag2: { 394 * } 395 * } 396 * flag2: { 397 * tags: { 398 * } 399 * } 400 * } 401 * } 402 * ************************************* 403 * 404 * @param[in] i_vpdFilePath - Path to the EEPROM file. 405 * @param[in] i_flagToProcess - To identify which flag(s) needs to be 406 * processed under PreAction tag of config JSON. 407 * @param[out] o_errCode - To set error code in case of error. 408 * @return Execution status. 409 */ 410 bool processPreAction(const std::string& i_vpdFilePath, 411 const std::string& i_flagToProcess, 412 uint16_t& o_errCode); 413 414 /** 415 * @brief API to process postAction(base_action) defined in config JSON. 416 * 417 * @note Sequence of tags under any given flag of postAction is EXTREMELY 418 * important to ensure proper processing. The API will process all the 419 * nested items under the base action sequentially. Also if any of the tag 420 * processing fails, the code will not process remaining tags under the 421 * flag. 422 * ******** sample format ************** 423 * fru EEPROM path: { 424 * base_action: { 425 * flag1: { 426 * tag1: { 427 * }, 428 * tag2: { 429 * } 430 * } 431 * flag2: { 432 * tags: { 433 * } 434 * } 435 * } 436 * } 437 * ************************************* 438 * Also, if post action is required to be processed only for FRUs with 439 * certain CCIN then CCIN list can be provided under flag. 440 * 441 * @param[in] i_vpdFruPath - Path to the EEPROM file. 442 * @param[in] i_flagToProcess - To identify which flag(s) needs to be 443 * processed under postAction tag of config JSON. 444 * @param[in] i_parsedVpd - Optional Parsed VPD map. If CCIN match is 445 * required. 446 * @return Execution status. 447 */ 448 bool processPostAction( 449 const std::string& i_vpdFruPath, const std::string& i_flagToProcess, 450 const std::optional<types::VPDMapVariant> i_parsedVpd = std::nullopt); 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 set symbolic link for system config JSON. 503 * 504 * Once correct device tree is set, symbolic link to the correct sytsem 505 * config JSON is set to be used in subsequent BMC boot. 506 * 507 * @param[in] i_systemJson - system config JSON. 508 */ 509 void setJsonSymbolicLink(const std::string& i_systemJson); 510 511 /** 512 * @brief API to set present property. 513 * 514 * This API updates the present property of the given FRU with the given 515 * value. Note: It is the responsibility of the caller to determine whether 516 * the present property for the FRU should be updated or not. 517 * 518 * @param[in] i_vpdPath - EEPROM or inventory path. 519 * @param[in] i_value - value to be set. 520 */ 521 void setPresentProperty(const std::string& i_fruPath, const bool& i_value); 522 523 /** 524 * @brief API to check if the path needs to be skipped for collection. 525 * 526 * Some FRUs, under some given scenarios should not be collected and 527 * skipped. 528 * 529 * @param[in] i_vpdFilePath - EEPROM path. 530 * 531 * @return True - if path is empty or should be skipped, false otherwise. 532 */ 533 bool skipPathForCollection(const std::string& i_vpdFilePath); 534 535 /** 536 * @brief API to check if present property should be handled for given FRU. 537 * 538 * vpd-manager should update present property for a FRU if and only if it's 539 * not synthesized and vpd-manager handles present property for the FRU. 540 * This API assumes "handlePresence" tag is a subset of "synthesized" tag. 541 * 542 * @param[in] i_fru - JSON block for a single FRU. 543 * 544 * @return true if present property should be handled, false otherwise. 545 */ isPresentPropertyHandlingRequired(const nlohmann::json & i_fru) const546 inline bool isPresentPropertyHandlingRequired( 547 const nlohmann::json& i_fru) const noexcept 548 { 549 // TODO: revisit this to see if this logic can be optimized. 550 return !i_fru.value("synthesized", false) && 551 i_fru.value("handlePresence", true); 552 } 553 554 // Parsed JSON file. 555 nlohmann::json m_parsedJson{}; 556 557 // Hold if symlink is present or not. 558 bool m_isSymlinkPresent = false; 559 560 // Path to config JSON if applicable. 561 std::string& m_configJsonPath; 562 563 // Keeps track of active thread(s) doing VPD collection. 564 size_t m_activeCollectionThreadCount = 0; 565 566 // Holds status, if VPD collection has been done or not. 567 // Note: This variable does not give information about successfull or failed 568 // collection. It just states, if the VPD collection process is over or not. 569 bool m_isAllFruCollected = false; 570 571 // To distinguish the factory reset path. 572 bool m_isFactoryResetDone = false; 573 574 // Mutex to guard critical resource m_activeCollectionThreadCount. 575 std::mutex m_mutex; 576 577 // Counting semaphore to limit the number of threads. 578 std::counting_semaphore<constants::MAX_THREADS> m_semaphore; 579 580 // List of EEPROM paths for which VPD collection thread creation has failed. 581 std::forward_list<std::string> m_failedEepromPaths; 582 583 // VPD collection mode 584 types::VpdCollectionMode m_vpdCollectionMode{ 585 types::VpdCollectionMode::DEFAULT_MODE}; 586 }; 587 } // namespace vpd 588