1cb6b059eSMatt Spinler #pragma once 2cb6b059eSMatt Spinler 3b832363dSMatt Spinler #include "additional_data.hpp" 4aa659477SMatt Spinler #include "data_interface.hpp" 5cb6b059eSMatt Spinler #include "private_header.hpp" 6b832363dSMatt Spinler #include "registry.hpp" 7bd716f00SMatt Spinler #include "src.hpp" 8afa857c7SMatt Spinler #include "user_data.hpp" 956ad2a0eSMatt Spinler #include "user_data_formats.hpp" 10cb6b059eSMatt Spinler #include "user_header.hpp" 11cb6b059eSMatt Spinler 12cb6b059eSMatt Spinler #include <memory> 13cb6b059eSMatt Spinler #include <vector> 14cb6b059eSMatt Spinler 15cb6b059eSMatt Spinler namespace openpower 16cb6b059eSMatt Spinler { 17cb6b059eSMatt Spinler namespace pels 18cb6b059eSMatt Spinler { 19cb6b059eSMatt Spinler 2056ad2a0eSMatt Spinler /** 2156ad2a0eSMatt Spinler * @brief Contains information about an FFDC file. 2256ad2a0eSMatt Spinler */ 2356ad2a0eSMatt Spinler struct PelFFDCfile 2456ad2a0eSMatt Spinler { 2556ad2a0eSMatt Spinler UserDataFormat format; 2656ad2a0eSMatt Spinler uint8_t subType; 2756ad2a0eSMatt Spinler uint8_t version; 2856ad2a0eSMatt Spinler int fd; 2956ad2a0eSMatt Spinler }; 3056ad2a0eSMatt Spinler 3156ad2a0eSMatt Spinler using PelFFDC = std::vector<PelFFDCfile>; 3256ad2a0eSMatt Spinler 33cb6b059eSMatt Spinler /** @class PEL 34cb6b059eSMatt Spinler * 35cb6b059eSMatt Spinler * @brief This class represents a specific event log format referred to as a 36cb6b059eSMatt Spinler * Platform Event Log. 37cb6b059eSMatt Spinler * 38cb6b059eSMatt Spinler * Every field in a PEL are in structures call sections, of which there are 39cb6b059eSMatt Spinler * several types. Some sections are required, and some are optional. In some 40cb6b059eSMatt Spinler * cases there may be more than one instance of a section type. 41cb6b059eSMatt Spinler * 42cb6b059eSMatt Spinler * The only two required sections for every type of PEL are the Private Header 43cb6b059eSMatt Spinler * section and User Header section, which must be in the first and second 44cb6b059eSMatt Spinler * positions, respectively. 45cb6b059eSMatt Spinler * 46cb6b059eSMatt Spinler * Every section starts with an 8 byte section header, which has the section 47cb6b059eSMatt Spinler * size and type, among other things. 48cb6b059eSMatt Spinler * 49cb6b059eSMatt Spinler * This class represents all sections with objects. 50cb6b059eSMatt Spinler * 51bd716f00SMatt Spinler * The class can be constructed: 52bd716f00SMatt Spinler * - From a full formed flattened PEL. 53bd716f00SMatt Spinler * - From scratch based on an OpenBMC event and its corresponding PEL message 54bd716f00SMatt Spinler * registry entry. 55b832363dSMatt Spinler * 56cb6b059eSMatt Spinler * The data() method allows one to retrieve the PEL as a vector<uint8_t>. This 57cb6b059eSMatt Spinler * is the format in which it is stored and transmitted. 58cb6b059eSMatt Spinler */ 59cb6b059eSMatt Spinler class PEL 60cb6b059eSMatt Spinler { 61cb6b059eSMatt Spinler public: 62cb6b059eSMatt Spinler PEL() = delete; 63cb6b059eSMatt Spinler ~PEL() = default; 64cb6b059eSMatt Spinler PEL(const PEL&) = delete; 65cb6b059eSMatt Spinler PEL& operator=(const PEL&) = delete; 66cb6b059eSMatt Spinler PEL(PEL&&) = delete; 67cb6b059eSMatt Spinler PEL& operator=(PEL&&) = delete; 68cb6b059eSMatt Spinler 69cb6b059eSMatt Spinler /** 70cb6b059eSMatt Spinler * @brief Constructor 71cb6b059eSMatt Spinler * 72cb6b059eSMatt Spinler * Build a PEL from raw data. 73cb6b059eSMatt Spinler * 7407eefc54SMatt Spinler * Note: Neither this nor the following constructor can take a const vector& 7507eefc54SMatt Spinler * because the Stream class that is used to read from the vector cannot take 7607eefc54SMatt Spinler * a const. The alternative is to make a copy of the data, but as PELs can 7707eefc54SMatt Spinler * be up to 16KB that is undesireable. 7807eefc54SMatt Spinler * 79cb6b059eSMatt Spinler * @param[in] data - The PEL data 80cb6b059eSMatt Spinler */ 8107eefc54SMatt Spinler PEL(std::vector<uint8_t>& data); 82cb6b059eSMatt Spinler 83cb6b059eSMatt Spinler /** 84cb6b059eSMatt Spinler * @brief Constructor 85cb6b059eSMatt Spinler * 86cb6b059eSMatt Spinler * Build a PEL from the raw data. 87cb6b059eSMatt Spinler * 88cb6b059eSMatt Spinler * @param[in] data - the PEL data 89cb6b059eSMatt Spinler * @param[in] obmcLogID - the corresponding OpenBMC event log ID 90cb6b059eSMatt Spinler */ 9107eefc54SMatt Spinler PEL(std::vector<uint8_t>& data, uint32_t obmcLogID); 92cb6b059eSMatt Spinler 93cb6b059eSMatt Spinler /** 94b832363dSMatt Spinler * @brief Constructor 95b832363dSMatt Spinler * 96b832363dSMatt Spinler * Creates a PEL from an OpenBMC event log and its message 97b832363dSMatt Spinler * registry entry. 98b832363dSMatt Spinler * 99b832363dSMatt Spinler * @param[in] entry - The message registry entry for this error 100b832363dSMatt Spinler * @param[in] obmcLogID - ID of corresponding OpenBMC event log 101b832363dSMatt Spinler * @param[in] timestamp - Timestamp from the event log 102b832363dSMatt Spinler * @param[in] severity - Severity from the event log 103bd716f00SMatt Spinler * @param[in] additionalData - The AdditionalData contents 10456ad2a0eSMatt Spinler * @param[in] ffdcFiles - FFCD files that go into UserData sections 105aa659477SMatt Spinler * @param[in] dataIface - The data interface object 106b832363dSMatt Spinler */ 107b832363dSMatt Spinler PEL(const openpower::pels::message::Entry& entry, uint32_t obmcLogID, 108bd716f00SMatt Spinler uint64_t timestamp, phosphor::logging::Entry::Level severity, 10956ad2a0eSMatt Spinler const AdditionalData& additionalData, const PelFFDC& ffdcFiles, 110aa659477SMatt Spinler const DataInterfaceBase& dataIface); 111b832363dSMatt Spinler 112b832363dSMatt Spinler /** 113cb6b059eSMatt Spinler * @brief Convenience function to return the log ID field from the 114cb6b059eSMatt Spinler * Private Header section. 115cb6b059eSMatt Spinler * 116cb6b059eSMatt Spinler * @return uint32_t - the ID 117cb6b059eSMatt Spinler */ 118cb6b059eSMatt Spinler uint32_t id() const 119cb6b059eSMatt Spinler { 120cb6b059eSMatt Spinler return _ph->id(); 121cb6b059eSMatt Spinler } 122cb6b059eSMatt Spinler 123cb6b059eSMatt Spinler /** 124cb6b059eSMatt Spinler * @brief Convenience function to return the PLID field from the 125cb6b059eSMatt Spinler * Private Header section. 126cb6b059eSMatt Spinler * 127cb6b059eSMatt Spinler * @return uint32_t - the PLID 128cb6b059eSMatt Spinler */ 129cb6b059eSMatt Spinler uint32_t plid() const 130cb6b059eSMatt Spinler { 131cb6b059eSMatt Spinler return _ph->plid(); 132cb6b059eSMatt Spinler } 133cb6b059eSMatt Spinler 134cb6b059eSMatt Spinler /** 135cb6b059eSMatt Spinler * @brief Convenience function to return the OpenBMC event log ID field 136cb6b059eSMatt Spinler * from the Private Header section. 137cb6b059eSMatt Spinler * 138cb6b059eSMatt Spinler * @return uint32_t - the OpenBMC event log ID 139cb6b059eSMatt Spinler */ 140cb6b059eSMatt Spinler uint32_t obmcLogID() const 141cb6b059eSMatt Spinler { 142cb6b059eSMatt Spinler return _ph->obmcLogID(); 143cb6b059eSMatt Spinler } 144cb6b059eSMatt Spinler 145cb6b059eSMatt Spinler /** 146cb6b059eSMatt Spinler * @brief Convenience function to return the commit time field from 147cb6b059eSMatt Spinler * the Private Header section. 148cb6b059eSMatt Spinler * 149cb6b059eSMatt Spinler * @return BCDTime - the timestamp 150cb6b059eSMatt Spinler */ 151cb6b059eSMatt Spinler BCDTime commitTime() const 152cb6b059eSMatt Spinler { 153cb6b059eSMatt Spinler return _ph->commitTimestamp(); 154cb6b059eSMatt Spinler } 155cb6b059eSMatt Spinler 156cb6b059eSMatt Spinler /** 157cb6b059eSMatt Spinler * @brief Convenience function to return the create time field from 158cb6b059eSMatt Spinler * the Private Header section. 159cb6b059eSMatt Spinler * 160cb6b059eSMatt Spinler * @return BCDTime - the timestamp 161cb6b059eSMatt Spinler */ 162cb6b059eSMatt Spinler BCDTime createTime() const 163cb6b059eSMatt Spinler { 164cb6b059eSMatt Spinler return _ph->createTimestamp(); 165cb6b059eSMatt Spinler } 166cb6b059eSMatt Spinler 167cb6b059eSMatt Spinler /** 168cb6b059eSMatt Spinler * @brief Gives access to the Private Header section class 169cb6b059eSMatt Spinler * 17097d19b48SMatt Spinler * @return const PrivateHeader& - the private header 171cb6b059eSMatt Spinler */ 17297d19b48SMatt Spinler const PrivateHeader& privateHeader() const 173cb6b059eSMatt Spinler { 17497d19b48SMatt Spinler return *_ph; 175cb6b059eSMatt Spinler } 176cb6b059eSMatt Spinler 177cb6b059eSMatt Spinler /** 178cb6b059eSMatt Spinler * @brief Gives access to the User Header section class 179cb6b059eSMatt Spinler * 18097d19b48SMatt Spinler * @return const UserHeader& - the user header 181cb6b059eSMatt Spinler */ 18297d19b48SMatt Spinler const UserHeader& userHeader() const 183cb6b059eSMatt Spinler { 18497d19b48SMatt Spinler return *_uh; 185cb6b059eSMatt Spinler } 186cb6b059eSMatt Spinler 187cb6b059eSMatt Spinler /** 188bd716f00SMatt Spinler * @brief Gives access to the primary SRC's section class 189bd716f00SMatt Spinler * 190bd716f00SMatt Spinler * This is technically an optional section, so the return 191bd716f00SMatt Spinler * value is an std::optional<SRC*>. 192bd716f00SMatt Spinler * 193bd716f00SMatt Spinler * @return std::optional<SRC*> - the SRC section object 194bd716f00SMatt Spinler */ 195bd716f00SMatt Spinler std::optional<SRC*> primarySRC() const; 196bd716f00SMatt Spinler 197bd716f00SMatt Spinler /** 198131870c7SMatt Spinler * @brief Returns the optional sections, which is everything but 199131870c7SMatt Spinler * the Private and User Headers. 200131870c7SMatt Spinler * 201131870c7SMatt Spinler * @return const std::vector<std::unique_ptr<Section>>& 202131870c7SMatt Spinler */ 203131870c7SMatt Spinler const std::vector<std::unique_ptr<Section>>& optionalSections() const 204131870c7SMatt Spinler { 205131870c7SMatt Spinler return _optionalSections; 206131870c7SMatt Spinler } 207131870c7SMatt Spinler 208131870c7SMatt Spinler /** 209cb6b059eSMatt Spinler * @brief Returns the PEL data. 210cb6b059eSMatt Spinler * 211cb6b059eSMatt Spinler * @return std::vector<uint8_t> - the raw PEL data 212cb6b059eSMatt Spinler */ 2130688545bSMatt Spinler std::vector<uint8_t> data() const; 214cb6b059eSMatt Spinler 215cb6b059eSMatt Spinler /** 216f1b46ff4SMatt Spinler * @brief Returns the size of the PEL 217f1b46ff4SMatt Spinler * 218f1b46ff4SMatt Spinler * @return size_t The PEL size in bytes 219f1b46ff4SMatt Spinler */ 220f1b46ff4SMatt Spinler size_t size() const; 221f1b46ff4SMatt Spinler 222f1b46ff4SMatt Spinler /** 223cb6b059eSMatt Spinler * @brief Says if the PEL is valid (the sections are all valid) 224cb6b059eSMatt Spinler * 225cb6b059eSMatt Spinler * @return bool - if the PEL is valid 226cb6b059eSMatt Spinler */ 227cb6b059eSMatt Spinler bool valid() const; 228cb6b059eSMatt Spinler 229cb6b059eSMatt Spinler /** 230cb6b059eSMatt Spinler * @brief Sets the commit timestamp to the current time 231cb6b059eSMatt Spinler */ 232cb6b059eSMatt Spinler void setCommitTime(); 233cb6b059eSMatt Spinler 234cb6b059eSMatt Spinler /** 235cb6b059eSMatt Spinler * @brief Sets the error log ID field to a unique ID. 236cb6b059eSMatt Spinler */ 237cb6b059eSMatt Spinler void assignID(); 238cb6b059eSMatt Spinler 239186ce8c9SAatir /** 240186ce8c9SAatir * @brief Output a PEL in JSON. 241a214ed30SHarisuddin Mohamed Isa * @param[in] registry - Registry object reference 242*f67bafd0SHarisuddin Mohamed Isa * @param[in] plugins - Vector of strings of plugins found in filesystem 243186ce8c9SAatir */ 244*f67bafd0SHarisuddin Mohamed Isa void toJSON(message::Registry& registry, 245*f67bafd0SHarisuddin Mohamed Isa const std::vector<std::string>& plugins) const; 246186ce8c9SAatir 247f38ce984SMatt Spinler /** 248f38ce984SMatt Spinler * @brief Sets the host transmission state in the User Header 249f38ce984SMatt Spinler * 250f38ce984SMatt Spinler * @param[in] state - The state value 251f38ce984SMatt Spinler */ 252f38ce984SMatt Spinler void setHostTransmissionState(TransmissionState state) 253f38ce984SMatt Spinler { 254f38ce984SMatt Spinler _uh->setHostTransmissionState(static_cast<uint8_t>(state)); 255f38ce984SMatt Spinler } 256f38ce984SMatt Spinler 257f38ce984SMatt Spinler /** 258f38ce984SMatt Spinler * @brief Returns the host transmission state 259f38ce984SMatt Spinler * 260f38ce984SMatt Spinler * @return HostTransmissionState - The state 261f38ce984SMatt Spinler */ 262f38ce984SMatt Spinler TransmissionState hostTransmissionState() const 263f38ce984SMatt Spinler { 264f38ce984SMatt Spinler return static_cast<TransmissionState>(_uh->hostTransmissionState()); 265f38ce984SMatt Spinler } 266f38ce984SMatt Spinler 267f38ce984SMatt Spinler /** 268f38ce984SMatt Spinler * @brief Sets the HMC transmission state in the User Header 269f38ce984SMatt Spinler * 270f38ce984SMatt Spinler * @param[in] state - The state value 271f38ce984SMatt Spinler */ 272f38ce984SMatt Spinler void setHMCTransmissionState(TransmissionState state) 273f38ce984SMatt Spinler { 274f38ce984SMatt Spinler _uh->setHMCTransmissionState(static_cast<uint8_t>(state)); 275f38ce984SMatt Spinler } 276f38ce984SMatt Spinler 277f38ce984SMatt Spinler /** 278f38ce984SMatt Spinler * @brief Returns the HMC transmission state 279f38ce984SMatt Spinler * 280f38ce984SMatt Spinler * @return HMCTransmissionState - The state 281f38ce984SMatt Spinler */ 282f38ce984SMatt Spinler TransmissionState hmcTransmissionState() const 283f38ce984SMatt Spinler { 284f38ce984SMatt Spinler return static_cast<TransmissionState>(_uh->hmcTransmissionState()); 285f38ce984SMatt Spinler } 286f38ce984SMatt Spinler 287cb6b059eSMatt Spinler private: 288cb6b059eSMatt Spinler /** 289cb6b059eSMatt Spinler * @brief Builds the section objects from a PEL data buffer 290cb6b059eSMatt Spinler * 29107eefc54SMatt Spinler * Note: The data parameter cannot be const for the same reasons 29207eefc54SMatt Spinler * as listed in the constructor. 29307eefc54SMatt Spinler * 29407eefc54SMatt Spinler * @param[in] data - The PEL data 295cb6b059eSMatt Spinler * @param[in] obmcLogID - The OpenBMC event log ID to use for that 296cb6b059eSMatt Spinler * field in the Private Header. 297cb6b059eSMatt Spinler */ 29807eefc54SMatt Spinler void populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID); 299cb6b059eSMatt Spinler 300cb6b059eSMatt Spinler /** 301cb6b059eSMatt Spinler * @brief Flattens the PEL objects into the buffer 302cb6b059eSMatt Spinler * 303cb6b059eSMatt Spinler * @param[out] pelBuffer - What the data will be written to 304cb6b059eSMatt Spinler */ 3050688545bSMatt Spinler void flatten(std::vector<uint8_t>& pelBuffer) const; 306cb6b059eSMatt Spinler 307cb6b059eSMatt Spinler /** 308f1e85e20SMatt Spinler * @brief Check that the PEL fields that need to be in agreement 309f1e85e20SMatt Spinler * with each other are, and fix them up if necessary. 310f1e85e20SMatt Spinler */ 311f1e85e20SMatt Spinler void checkRulesAndFix(); 312f1e85e20SMatt Spinler 313f1e85e20SMatt Spinler /** 314acb7c106SMatt Spinler * @brief Returns a map of the section IDs that appear more than once 315acb7c106SMatt Spinler * in the PEL. The data value for each entry will be set to 0. 316acb7c106SMatt Spinler * 317acb7c106SMatt Spinler * @return std::map<uint16_t, size_t> 318acb7c106SMatt Spinler */ 319acb7c106SMatt Spinler std::map<uint16_t, size_t> getPluralSections() const; 320acb7c106SMatt Spinler 321acb7c106SMatt Spinler /** 32285f61a63SMatt Spinler * @brief Adds the UserData section to this PEL object, 32385f61a63SMatt Spinler * shrinking it if necessary 32485f61a63SMatt Spinler * 32585f61a63SMatt Spinler * @param[in] userData - The section to add 32685f61a63SMatt Spinler * 32785f61a63SMatt Spinler * @return bool - If the section was added or not. 32885f61a63SMatt Spinler */ 32985f61a63SMatt Spinler bool addUserDataSection(std::unique_ptr<UserData> userData); 33085f61a63SMatt Spinler 33185f61a63SMatt Spinler /** 33285f61a63SMatt Spinler * @brief helper function for printing PELs. 33385f61a63SMatt Spinler * @param[in] Section& - section object reference 33485f61a63SMatt Spinler * @param[in] std::string - PEL string 33585f61a63SMatt Spinler * @param[in|out] pluralSections - Map used to track sections counts for 33685f61a63SMatt Spinler * when there is more than 1. 33785f61a63SMatt Spinler * @param[in] registry - Registry object reference 338*f67bafd0SHarisuddin Mohamed Isa * @param[in] plugins - Vector of strings of plugins found in filesystem 339*f67bafd0SHarisuddin Mohamed Isa * @param[in] creatorID - Creator Subsystem ID (only for UserData section) 34085f61a63SMatt Spinler */ 34185f61a63SMatt Spinler void printSectionInJSON(const Section& section, std::string& buf, 34285f61a63SMatt Spinler std::map<uint16_t, size_t>& pluralSections, 343*f67bafd0SHarisuddin Mohamed Isa message::Registry& registry, 344*f67bafd0SHarisuddin Mohamed Isa const std::vector<std::string>& plugins, 345*f67bafd0SHarisuddin Mohamed Isa uint8_t creatorID = 0) const; 34685f61a63SMatt Spinler 34785f61a63SMatt Spinler /** 348cb6b059eSMatt Spinler * @brief The PEL Private Header section 349cb6b059eSMatt Spinler */ 350cb6b059eSMatt Spinler std::unique_ptr<PrivateHeader> _ph; 351cb6b059eSMatt Spinler 352cb6b059eSMatt Spinler /** 353cb6b059eSMatt Spinler * @brief The PEL User Header section 354cb6b059eSMatt Spinler */ 355cb6b059eSMatt Spinler std::unique_ptr<UserHeader> _uh; 356cb6b059eSMatt Spinler 357cb6b059eSMatt Spinler /** 358131870c7SMatt Spinler * @brief Holds all sections by the PH and UH. 359131870c7SMatt Spinler */ 360131870c7SMatt Spinler std::vector<std::unique_ptr<Section>> _optionalSections; 361186ce8c9SAatir 362186ce8c9SAatir /** 3636d663820SMatt Spinler * @brief The maximum size a PEL can be in bytes. 3646d663820SMatt Spinler */ 3656d663820SMatt Spinler static constexpr size_t _maxPELSize = 16384; 366cb6b059eSMatt Spinler }; 367cb6b059eSMatt Spinler 368afa857c7SMatt Spinler namespace util 369afa857c7SMatt Spinler { 370afa857c7SMatt Spinler 371afa857c7SMatt Spinler /** 37285f61a63SMatt Spinler * @brief Creates a UserData section object that contains JSON. 37385f61a63SMatt Spinler * 37485f61a63SMatt Spinler * @param[in] json - The JSON contents 37585f61a63SMatt Spinler * 37685f61a63SMatt Spinler * @return std::unique_ptr<UserData> - The UserData object 37785f61a63SMatt Spinler */ 37885f61a63SMatt Spinler std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json); 37985f61a63SMatt Spinler 38085f61a63SMatt Spinler /** 381afa857c7SMatt Spinler * @brief Create a UserData section containing the AdditionalData 382afa857c7SMatt Spinler * contents as a JSON string. 383afa857c7SMatt Spinler * 384afa857c7SMatt Spinler * @param[in] ad - The AdditionalData contents 385afa857c7SMatt Spinler * 386afa857c7SMatt Spinler * @return std::unique_ptr<UserData> - The section 387afa857c7SMatt Spinler */ 388afa857c7SMatt Spinler std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad); 389afa857c7SMatt Spinler 3904dcd3f46SMatt Spinler /** 3914dcd3f46SMatt Spinler * @brief Create a UserData section containing various useful pieces 3924dcd3f46SMatt Spinler * of system information as a JSON string. 3934dcd3f46SMatt Spinler * 3944dcd3f46SMatt Spinler * @param[in] ad - The AdditionalData contents 3954dcd3f46SMatt Spinler * @param[in] dataIface - The data interface object 3964dcd3f46SMatt Spinler * 3974dcd3f46SMatt Spinler * @return std::unique_ptr<UserData> - The section 3984dcd3f46SMatt Spinler */ 3994dcd3f46SMatt Spinler std::unique_ptr<UserData> 4004dcd3f46SMatt Spinler makeSysInfoUserDataSection(const AdditionalData& ad, 4014dcd3f46SMatt Spinler const DataInterfaceBase& dataIface); 40256ad2a0eSMatt Spinler 40356ad2a0eSMatt Spinler /** 40456ad2a0eSMatt Spinler * @brief Create a UserData section that contains the data in the file 40556ad2a0eSMatt Spinler * pointed to by the file descriptor passed in. 40656ad2a0eSMatt Spinler * 40756ad2a0eSMatt Spinler * @param[in] componentID - The component ID of the PEL creator 40856ad2a0eSMatt Spinler * @param[in] file - The FFDC file information 40956ad2a0eSMatt Spinler */ 41056ad2a0eSMatt Spinler std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID, 41156ad2a0eSMatt Spinler const PelFFDCfile& file); 412afa857c7SMatt Spinler } // namespace util 413afa857c7SMatt Spinler 414cb6b059eSMatt Spinler } // namespace pels 415cb6b059eSMatt Spinler } // namespace openpower 416