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