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