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