xref: /openbmc/phosphor-logging/extensions/openpower-pels/registry.hpp (revision 6b427cc806db3eaffe278572ed71bdd5e5f522ea)
1 #pragma once
2 #include "additional_data.hpp"
3 
4 #include <filesystem>
5 #include <nlohmann/json.hpp>
6 #include <optional>
7 #include <string>
8 #include <vector>
9 
10 namespace openpower
11 {
12 namespace pels
13 {
14 namespace message
15 {
16 
17 constexpr auto registryFileName = "message_registry.json";
18 enum class LookupType
19 {
20     name = 0,
21     reasonCode = 1
22 };
23 
24 /**
25  * @brief Represents the Documentation related fields in the message registry.
26  *        It is part of the 'Entry' structure that will be filled in when
27  *        an error is looked up in the registry.
28  *
29  * If a field is wrapped by std::optional, it means the field is
30  * optional in the JSON and higher level code knows how to handle it.
31  */
32 struct DOC
33 {
34     /**
35      * @brief Description of error
36      */
37     std::string description;
38 
39     /**
40      * @brief Error message field
41      */
42     std::string message;
43 
44     /**
45      * @brief An optional vector of SRC word 6-9 to use as the source of the
46      *        numeric arguments that will be substituted into any placeholder
47      *        in the Message field.
48      */
49     std::optional<std::vector<std::string>> messageArgSources;
50 };
51 
52 /**
53  * @brief Represents the SRC related fields in the message registry.
54  *        It is part of the 'Entry' structure that will be filled in when
55  *        an error is looked up in the registry.
56  *
57  * If a field is wrapped by std::optional, it means the field is
58  * optional in the JSON and higher level code knows how to handle it.
59  */
60 struct SRC
61 {
62     /**
63      * @brief SRC type - The first byte of the ASCII string
64      */
65     uint8_t type;
66 
67     /**
68      * @brief The SRC reason code (2nd half of 4B 'ASCII string' word)
69      */
70     uint16_t reasonCode;
71 
72     /**
73      * @brief Specifies if the SRC represents a power fault.  Optional.
74      */
75     std::optional<bool> powerFault;
76 
77     /**
78      * @brief An optional vector of SRC hexword numbers that should be used
79      *        along with the SRC ASCII string to build the Symptom ID, which
80      *        is a field in the Extended Header section.
81      */
82     using WordNum = size_t;
83     std::optional<std::vector<WordNum>> symptomID;
84 
85     /**
86      * @brief Which AdditionalData fields to use to fill in the user defined
87      *        SRC hexwords.
88      *
89      * For example, if the AdditionalData event log property contained
90      * "CHIPNUM=42" and this map contained {6, CHIPNUM}, then the code
91      * would put 42 into SRC hexword 6.
92      */
93     using AdditionalDataField = std::string;
94     std::optional<std::map<WordNum, AdditionalDataField>> hexwordADFields;
95 
96     SRC() : type(0), reasonCode(0)
97     {
98     }
99 };
100 
101 /**
102  * @brief Represents a message registry entry, which is used for creating a
103  *        PEL from an OpenBMC event log.
104  */
105 struct Entry
106 {
107     /**
108      * @brief The error name, like "xyz.openbmc_project.Error.Foo".
109      */
110     std::string name;
111 
112     /**
113      * @brief The component ID of the PEL creator.
114      */
115     uint16_t componentID;
116 
117     /**
118      * @brief The PEL subsystem field.
119      */
120     uint8_t subsystem;
121 
122     /**
123      * @brief The optional PEL severity field.  If not specified, the PEL
124      *        will use the severity of the OpenBMC event log.
125      */
126     std::optional<uint8_t> severity;
127 
128     /**
129      * @brief The optional severity field to use when in manufacturing tolerance
130      *        mode.
131      */
132     std::optional<uint8_t> mfgSeverity;
133 
134     /**
135      * @brief The PEL action flags field.
136      */
137     std::optional<uint16_t> actionFlags;
138 
139     /**
140      * @brief  The optional action flags to use instead when in manufacturing
141      * tolerance mode.
142      */
143     std::optional<uint16_t> mfgActionFlags;
144 
145     /**
146      * @brief The PEL event type field.  If not specified, higher level code
147      *        will decide the value.
148      */
149     std::optional<uint8_t> eventType;
150 
151     /**
152      * @brief The PEL event scope field.  If not specified, higher level code
153      *        will decide the value.
154      */
155     std::optional<uint8_t> eventScope;
156 
157     /**
158      * The SRC related fields.
159      */
160     SRC src;
161 
162     /**
163      * The Documentation related fields.
164      */
165     DOC doc;
166 
167     /**
168      * @brief The callout JSON, if the entry has callouts.
169      */
170     std::optional<nlohmann::json> callouts;
171 };
172 
173 /**
174  * @brief Holds callout information pulled out of the JSON.
175  */
176 struct RegistryCallout
177 {
178     std::string priority;
179     std::string locCode;
180     std::string procedure;
181     std::string symbolicFRU;
182     std::string symbolicFRUTrusted;
183 };
184 
185 /**
186  * @class Registry
187  *
188  * This class wraps the message registry JSON data and allows one to find
189  * the message registry entry pertaining to the error name.
190  *
191  * So that new registry files can easily be tested, the code will look for
192  * /etc/phosphor-logging/message_registry.json before looking for the real
193  * path.
194  */
195 class Registry
196 {
197   public:
198     Registry() = delete;
199     ~Registry() = default;
200     Registry(const Registry&) = default;
201     Registry& operator=(const Registry&) = default;
202     Registry(Registry&&) = default;
203     Registry& operator=(Registry&&) = default;
204 
205     /**
206      * @brief Constructor
207      *
208      * Will load the callout JSON.
209      *
210      * @param[in] registryFile - The path to the file.
211      */
212     explicit Registry(const std::filesystem::path& registryFile) :
213         Registry(registryFile, true)
214     {
215     }
216 
217     /**
218      * @brief Constructor
219      *
220      * This version contains a parameter that allows the callout JSON
221      * to be saved in the Entry struct or not, as it isn't needed at
222      * all in some cases.
223      *
224      * @param[in] registryFile - The path to the file.
225      * @param[in] loadCallouts - If the callout JSON should be saved.
226      */
227     explicit Registry(const std::filesystem::path& registryFile,
228                       bool loadCallouts) :
229         _registryFile(registryFile),
230         _loadCallouts(loadCallouts)
231     {
232     }
233 
234     /**
235      * @brief Find a registry entry based on its error name or reason code.
236      *
237      * This function does do some basic sanity checking on the JSON contents,
238      * but there is also an external program that enforces a schema on the
239      * registry JSON that should catch all of these problems ahead of time.
240      *
241      * @param[in] name - The error name, like xyz.openbmc_project.Error.Foo
242      *                 - OR
243      *                 - The reason code, like 0x1001
244      * @param[in] type - LookupType enum value
245      * @param[in] toCache - boolean to cache registry in memory
246      * @return optional<Entry> A filled in message registry structure if
247      *                         found, otherwise an empty optional object.
248      */
249     std::optional<Entry> lookup(const std::string& name, LookupType type,
250                                 bool toCache = false);
251 
252     /**
253      * @brief Find the callouts to put into the PEL based on the calloutJSON
254      *        data.
255      *
256      * The system type and AdditionalData are used to index into the correct
257      * callout table.
258      *
259      * Throws exceptions on failures.
260      *
261      * @param[in] calloutJSON - Where to look up the  callouts
262      * @param[in] systemType - The system type from EntityManager
263      * @param[in] additionalData - The AdditionalData property
264      *
265      * @return std::vector<RegistryCallout> - The callouts to use
266      */
267     static std::vector<RegistryCallout>
268         getCallouts(const nlohmann::json& calloutJSON,
269                     const std::string& systemType,
270                     const AdditionalData& additionalData);
271 
272   private:
273     /**
274      * @brief Parse message registry file using nlohmann::json
275      * @param[in] registryFile - The message registry JSON file
276      * @return optional<nlohmann::json> The full message registry object or an
277      *                                  empty optional object upon failure.
278      */
279     std::optional<nlohmann::json>
280         readRegistry(const std::filesystem::path& registryFile);
281 
282     /**
283      * @brief The path to the registry JSON file.
284      */
285     std::filesystem::path _registryFile;
286 
287     /**
288      * @brief The full message registry object.
289      */
290     std::optional<nlohmann::json> _registry;
291 
292     /**
293      * @brief If the callout JSON should be saved in the Entry on lookup.
294      */
295     bool _loadCallouts;
296 };
297 
298 namespace helper
299 {
300 
301 /**
302  * @brief A helper function to get the PEL subsystem value based on
303  *        the registry subsystem name.
304  *
305  * @param[in] subsystemName - The registry name for the subsystem
306  *
307  * @return uint8_t The PEL subsystem value
308  */
309 uint8_t getSubsystem(const std::string& subsystemName);
310 
311 /**
312  * @brief A helper function to get the PEL severity value based on
313  *        the registry severity name.
314  *
315  * @param[in] severityName - The registry name for the severity
316  *
317  * @return uint8_t The PEL severity value
318  */
319 uint8_t getSeverity(const std::string& severityName);
320 
321 /**
322  * @brief A helper function to get the action flags value based on
323  *        the action flag names used in the registry.
324  *
325  * @param[in] flags - The list of flag names from the registry.
326  *
327  * @return uint16_t - The bitfield of flags used in the PEL.
328  */
329 uint16_t getActionFlags(const std::vector<std::string>& flags);
330 
331 /**
332  * @brief A helper function to get the PEL event type value based on
333  *        the registry event type name.
334  *
335  * @param[in] eventTypeName - The registry name for the event type
336  *
337  * @return uint8_t The PEL event type value
338  */
339 uint8_t getEventType(const std::string& eventTypeName);
340 
341 /**
342  * @brief A helper function to get the PEL event scope value based on
343  *        the registry event scope name.
344  *
345  * @param[in] eventScopeName - The registry name for the event scope
346  *
347  * @return uint8_t The PEL event scope value
348  */
349 uint8_t getEventScope(const std::string& eventScopeName);
350 
351 /**
352  * @brief Reads the "ReasonCode" field out of JSON and converts the string value
353  *        such as "0x5555" to a uint16 like 0x5555.
354  *
355  * @param[in] src - The message registry SRC dictionary to read from
356  * @param[in] name - The error name, to use in a trace if things go awry.
357  *
358  * @return uint16_t - The reason code
359  */
360 uint16_t getSRCReasonCode(const nlohmann::json& src, const std::string& name);
361 
362 /**
363  * @brief Reads the "Type" field out of JSON and converts it to the SRC::Type
364  *        value.
365  *
366  * @param[in] src - The message registry SRC dictionary to read from
367  * @param[in] name - The error name, to use in a trace if things go awry.
368  *
369  * @return uint8_t - The SRC type value, like 0x11
370  */
371 uint8_t getSRCType(const nlohmann::json& src, const std::string& name);
372 
373 /**
374  * @brief Reads the "Words6To9" field out of JSON and converts it to a map
375  *        of the SRC word number to the AdditionalData property field used
376  *        to fill it in with.
377  *
378  * @param[in] src - The message registry SRC dictionary to read from
379  * @param[in] name - The error name, to use in a trace if things go awry.
380  *
381  * @return std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
382  */
383 std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
384     getSRCHexwordFields(const nlohmann::json& src, const std::string& name);
385 
386 /**
387  * @brief Reads the "SymptomIDFields" field out of JSON and converts it to
388  *        a vector of SRC word numbers.
389  *
390  * @param[in] src - The message registry SRC dictionary to read from
391  * @param[in] name - The error name, to use in a trace if things go awry.
392  *
393  * @return std::optional<std::vector<SRC::WordNum>>
394  */
395 std::optional<std::vector<SRC::WordNum>>
396     getSRCSymptomIDFields(const nlohmann::json& src, const std::string& name);
397 
398 /**
399  * @brief Reads the "ComponentID" field out of JSON and converts it to a
400  *        uint16_t like 0xFF00.
401  *
402  * The ComponentID JSON field is only required if the SRC type isn't a BD
403  * BMC SRC, because for those SRCs it can be inferred from the upper byte
404  * of the SRC reasoncode.
405  *
406  * @param[in] srcType - The SRC type
407  * @param[in] reasonCode - The SRC reason code
408  * @param[in] pelEntry - The PEL entry JSON
409  * @param[in] name - The error name, to use in a trace if things go awry.
410  *
411  * @return uin16_t - The component ID, like 0xFF00
412  */
413 uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode,
414                         const nlohmann::json& pelEntry,
415                         const std::string& name);
416 
417 } // namespace helper
418 
419 } // namespace message
420 
421 } // namespace pels
422 } // namespace openpower
423