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 * 46 * Note: Throws std::exception in case of construction failure. Caller needs 47 * to handle to detect successful object creation. 48 */ 49 Worker(std::string pathToConfigJson = std::string()); 50 51 /** 52 * @brief Destructor 53 */ 54 ~Worker() = default; 55 56 #ifdef IBM_SYSTEM 57 /** 58 * @brief API to perform initial setup before manager claims Bus name. 59 * 60 * Before BUS name for VPD-Manager is claimed, fitconfig whould be set for 61 * corret device tree, inventory JSON w.r.t system should be linked and 62 * system VPD should be on DBus. 63 */ 64 void performInitialSetup(); 65 #endif 66 67 /** 68 * @brief An API to check if system VPD is already published. 69 * 70 * @return Status, true if system is already collected else false. 71 */ 72 bool isSystemVPDOnDBus() const; 73 74 /** 75 * @brief API to process all FRUs presnt in config JSON file. 76 * 77 * This API based on config JSON passed/selected for the system, will 78 * trigger parser for all the FRUs and publish it on DBus. 79 * 80 * Note: Config JSON file path should be passed to worker class constructor 81 * to make use of this API. 82 * 83 */ 84 void collectFrusFromJson(); 85 86 /** 87 * @brief API to parse VPD data 88 * 89 * @param[in] i_vpdFilePath - Path to the VPD file. 90 */ 91 types::VPDMapVariant parseVpdFile(const std::string& i_vpdFilePath); 92 93 /** 94 * @brief An API to populate DBus interfaces for a FRU. 95 * 96 * Note: Call this API to populate D-Bus. Also caller should handle empty 97 * objectInterfaceMap. 98 * 99 * @param[in] parsedVpdMap - Parsed VPD as a map. 100 * @param[out] objectInterfaceMap - Object and its interfaces map. 101 * @param[in] vpdFilePath - EEPROM path of FRU. 102 */ 103 void populateDbus(const types::VPDMapVariant& parsedVpdMap, 104 types::ObjectMap& objectInterfaceMap, 105 const std::string& vpdFilePath); 106 107 /** 108 * @brief An API to delete FRU VPD over DBus. 109 * 110 * @param[in] i_dbusObjPath - Dbus object path of the FRU. 111 * 112 * @throw std::runtime_error if given input path is empty. 113 */ 114 void deleteFruVpd(const std::string& i_dbusObjPath); 115 116 /** 117 * @brief API to get status of VPD collection process. 118 * 119 * @return - True when done, false otherwise. 120 */ 121 inline bool isAllFruCollectionDone() const 122 { 123 return m_isAllFruCollected; 124 } 125 126 /** 127 * @brief API to get system config JSON object 128 * 129 * @return System config JSON object. 130 */ 131 inline nlohmann::json getSysCfgJsonObj() const 132 { 133 return m_parsedJson; 134 } 135 136 /** 137 * @brief API to get active thread count. 138 * 139 * Each FRU is collected in a separate thread. This API gives the active 140 * thread collecting FRU's VPD at any given time. 141 * 142 * @return Count of active threads. 143 */ 144 size_t getActiveThreadCount() const 145 { 146 return m_activeCollectionThreadCount; 147 } 148 149 private: 150 /** 151 * @brief An API to parse and publish a FRU VPD over D-Bus. 152 * 153 * Note: This API will handle all the exceptions internally and will only 154 * return status of parsing and publishing of VPD over D-Bus. 155 * 156 * @param[in] i_vpdFilePath - Path of file containing VPD. 157 * @return Tuple of status and file path. Status, true if successfull else 158 * false. 159 */ 160 std::tuple<bool, std::string> 161 parseAndPublishVPD(const std::string& i_vpdFilePath); 162 163 /** 164 * @brief An API to set appropriate device tree and JSON. 165 * 166 * This API based on system chooses corresponding device tree and JSON. 167 * If device tree change is required, it updates the "fitconfig" and reboots 168 * the system. Else it is NOOP. 169 * 170 * @throw std::runtime_error 171 */ 172 void setDeviceTreeAndJson(); 173 174 /** 175 * @brief API to select system specific JSON. 176 * 177 * The API based on the IM value of VPD, will select appropriate JSON for 178 * the system. In case no system is found corresponding to the extracted IM 179 * value, error will be logged. 180 * 181 * @param[out] systemJson - System JSON name. 182 * @param[in] parsedVpdMap - Parsed VPD map. 183 */ 184 void getSystemJson(std::string& systemJson, 185 const types::VPDMapVariant& parsedVpdMap); 186 187 /** 188 * @brief An API to read IM value from VPD. 189 * 190 * Note: Throws exception in case of error. Caller need to handle. 191 * 192 * @param[in] parsedVpd - Parsed VPD. 193 */ 194 std::string getIMValue(const types::IPZVpdMap& parsedVpd) const; 195 196 /** 197 * @brief An API to read HW version from VPD. 198 * 199 * Note: Throws exception in case of error. Caller need to handle. 200 * 201 * @param[in] parsedVpd - Parsed VPD. 202 */ 203 std::string getHWVersion(const types::IPZVpdMap& parsedVpd) const; 204 205 /** 206 * @brief An API to parse given VPD file path. 207 * 208 * @param[in] vpdFilePath - EEPROM file path. 209 * @param[out] parsedVpd - Parsed VPD as a map. 210 */ 211 void fillVPDMap(const std::string& vpdFilePath, 212 types::VPDMapVariant& parsedVpd); 213 214 /** 215 * @brief An API to parse and publish system VPD on D-Bus. 216 * 217 * Note: Throws exception in case of invalid VPD format. 218 * 219 * @param[in] parsedVpdMap - Parsed VPD as a map. 220 */ 221 void publishSystemVPD(const types::VPDMapVariant& parsedVpdMap); 222 223 /** 224 * @brief An API to process extrainterfaces w.r.t a FRU. 225 * 226 * @param[in] singleFru - JSON block for a single FRU. 227 * @param[out] interfaces - Map to hold interface along with its properties. 228 * @param[in] parsedVpdMap - Parsed VPD as a map. 229 */ 230 void processExtraInterfaces(const nlohmann::json& singleFru, 231 types::InterfaceMap& interfaces, 232 const types::VPDMapVariant& parsedVpdMap); 233 234 /** 235 * @brief An API to process embedded and synthesized FRUs. 236 * 237 * @param[in] singleFru - FRU to be processed. 238 * @param[out] interfaces - Map to hold interface along with its properties. 239 */ 240 void processEmbeddedAndSynthesizedFrus(const nlohmann::json& singleFru, 241 types::InterfaceMap& interfaces); 242 243 /** 244 * @brief An API to read process FRU based in CCIN. 245 * 246 * For some FRUs VPD can be processed only if the FRU has some specific 247 * value for CCIN. In case the value is not from that set, VPD for those 248 * FRUs can't be processed. 249 * 250 * @param[in] singleFru - Fru whose CCIN value needs to be matched. 251 * @param[in] parsedVpdMap - Parsed VPD map. 252 */ 253 bool processFruWithCCIN(const nlohmann::json& singleFru, 254 const types::VPDMapVariant& parsedVpdMap); 255 256 /** 257 * @brief API to process json's inherit flag. 258 * 259 * Inherit flag denotes that some property in the child FRU needs to be 260 * inherited from parent FRU. 261 * 262 * @param[in] parsedVpdMap - Parsed VPD as a map. 263 * @param[out] interfaces - Map to hold interface along with its properties. 264 */ 265 void processInheritFlag(const types::VPDMapVariant& parsedVpdMap, 266 types::InterfaceMap& interfaces); 267 268 /** 269 * @brief API to process json's "copyRecord" flag. 270 * 271 * copyRecord flag denotes if some record data needs to be copies in the 272 * given FRU. 273 * 274 * @param[in] singleFru - FRU being processed. 275 * @param[in] parsedVpdMap - Parsed VPD as a map. 276 * @param[out] interfaces - Map to hold interface along with its properties. 277 */ 278 void processCopyRecordFlag(const nlohmann::json& singleFru, 279 const types::VPDMapVariant& parsedVpdMap, 280 types::InterfaceMap& interfaces); 281 282 /** 283 * @brief An API to populate IPZ VPD property map. 284 * 285 * @param[out] interfacePropMap - Map of interface and properties under it. 286 * @param[in] keyordValueMap - Keyword value map of IPZ VPD. 287 * @param[in] interfaceName - Name of the interface. 288 */ 289 void populateIPZVPDpropertyMap(types::InterfaceMap& interfacePropMap, 290 const types::IPZKwdValueMap& keyordValueMap, 291 const std::string& interfaceName); 292 293 /** 294 * @brief An API to populate Kwd VPD property map. 295 * 296 * @param[in] keyordValueMap - Keyword value map of Kwd VPD. 297 * @param[out] interfaceMap - interface and property,value under it. 298 */ 299 void populateKwdVPDpropertyMap(const types::KeywordVpdMap& keyordVPDMap, 300 types::InterfaceMap& interfaceMap); 301 302 /** 303 * @brief API to populate all required interface for a FRU. 304 * 305 * @param[in] interfaceJson - JSON containing interfaces to be populated. 306 * @param[out] interfaceMap - Map to hold populated interfaces. 307 * @param[in] parsedVpdMap - Parsed VPD as a map. 308 */ 309 void populateInterfaces(const nlohmann::json& interfaceJson, 310 types::InterfaceMap& interfaceMap, 311 const types::VPDMapVariant& parsedVpdMap); 312 313 /** 314 * @brief Helper function to insert or merge in map. 315 * 316 * This method checks in the given inventory::InterfaceMap if the given 317 * interface key is existing or not. If the interface key already exists, 318 * given property map is inserted into it. If the key does'nt exist then 319 * given interface and property map pair is newly created. If the property 320 * present in propertymap already exist in the InterfaceMap, then the new 321 * property value is ignored. 322 * 323 * @param[in,out] interfaceMap - map object of type inventory::InterfaceMap 324 * only. 325 * @param[in] interface - Interface name. 326 * @param[in] property - new property map that needs to be emplaced. 327 */ 328 void insertOrMerge(types::InterfaceMap& interfaceMap, 329 const std::string& interface, 330 types::PropertyMap&& property); 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 482 createAssetTagString(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 // Parsed JSON file. 503 nlohmann::json m_parsedJson{}; 504 505 // Hold if symlink is present or not. 506 bool m_isSymlinkPresent = false; 507 508 // Path to config JSON if applicable. 509 std::string& m_configJsonPath; 510 511 // Keeps track of active thread(s) doing VPD collection. 512 size_t m_activeCollectionThreadCount = 0; 513 514 // Holds status, if VPD collection has been done or not. 515 // Note: This variable does not give information about successfull or failed 516 // collection. It just states, if the VPD collection process is over or not. 517 bool m_isAllFruCollected = false; 518 519 // To distinguish the factory reset path. 520 bool m_isFactoryResetDone = false; 521 522 // Mutex to guard critical resource m_activeCollectionThreadCount. 523 std::mutex m_mutex; 524 525 // Counting semaphore to limit the number of threads. 526 std::counting_semaphore<constants::MAX_THREADS> m_semaphore{ 527 constants::MAX_THREADS}; 528 }; 529 } // namespace vpd 530