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