blob: f5888b3810b62903fcf2dfd2cd9e4570e31678cb [file] [log] [blame]
Matt Spinler367144c2019-09-19 15:33:52 -05001#pragma once
Matt Spinler6b427cc2020-04-09 09:42:59 -05002#include "additional_data.hpp"
3
Matt Spinler367144c2019-09-19 15:33:52 -05004#include <nlohmann/json.hpp>
Patrick Williams2544b412022-10-04 08:41:06 -05005
6#include <filesystem>
Matt Spinler367144c2019-09-19 15:33:52 -05007#include <optional>
8#include <string>
9#include <vector>
10
11namespace openpower
12{
13namespace pels
14{
15namespace message
16{
17
18constexpr auto registryFileName = "message_registry.json";
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +080019enum class LookupType
20{
21 name = 0,
22 reasonCode = 1
23};
24
25/**
Matt Spinleraadccc82020-04-10 14:33:42 -050026 * @brief A possible severity/system type combination
27 *
28 * If there is no system type defined for this entry,
29 * then the system field will be empty.
30 */
31struct RegistrySeverity
32{
33 std::string system;
34 uint8_t severity;
35};
36
37/**
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +080038 * @brief Represents the Documentation related fields in the message registry.
39 * It is part of the 'Entry' structure that will be filled in when
40 * an error is looked up in the registry.
41 *
42 * If a field is wrapped by std::optional, it means the field is
43 * optional in the JSON and higher level code knows how to handle it.
44 */
45struct DOC
46{
47 /**
48 * @brief Description of error
49 */
50 std::string description;
51
52 /**
53 * @brief Error message field
54 */
55 std::string message;
56
57 /**
58 * @brief An optional vector of SRC word 6-9 to use as the source of the
59 * numeric arguments that will be substituted into any placeholder
60 * in the Message field.
61 */
62 std::optional<std::vector<std::string>> messageArgSources;
63};
Matt Spinler367144c2019-09-19 15:33:52 -050064
65/**
Matt Spinler93e29322019-09-20 11:16:15 -050066 * @brief Represents the SRC related fields in the message registry.
67 * It is part of the 'Entry' structure that will be filled in when
68 * an error is looked up in the registry.
69 *
70 * If a field is wrapped by std::optional, it means the field is
71 * optional in the JSON and higher level code knows how to handle it.
72 */
73struct SRC
74{
75 /**
76 * @brief SRC type - The first byte of the ASCII string
77 */
78 uint8_t type;
79
80 /**
81 * @brief The SRC reason code (2nd half of 4B 'ASCII string' word)
82 */
83 uint16_t reasonCode;
84
85 /**
Matt Spinler93e29322019-09-20 11:16:15 -050086 * @brief An optional vector of SRC hexword numbers that should be used
87 * along with the SRC ASCII string to build the Symptom ID, which
88 * is a field in the Extended Header section.
89 */
90 using WordNum = size_t;
91 std::optional<std::vector<WordNum>> symptomID;
92
93 /**
94 * @brief Which AdditionalData fields to use to fill in the user defined
95 * SRC hexwords.
96 *
97 * For example, if the AdditionalData event log property contained
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +080098 * "CHIPNUM=42" and this map contained {6, {"CHIPNUM", "DESC"}}, then the
99 * code would put 42 into SRC hexword 6.
100 *
101 * AdditionalDataField specifies two fields from the SRC entry in the
102 * message registry: "AdditionalDataPropSource" and "Description"
Matt Spinler93e29322019-09-20 11:16:15 -0500103 */
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +0800104 using AdditionalDataField = std::tuple<std::string, std::string>;
Matt Spinler93e29322019-09-20 11:16:15 -0500105 std::optional<std::map<WordNum, AdditionalDataField>> hexwordADFields;
106
Patrick Williams2544b412022-10-04 08:41:06 -0500107 SRC() : type(0), reasonCode(0) {}
Matt Spinler93e29322019-09-20 11:16:15 -0500108};
109
110/**
Matt Spinler367144c2019-09-19 15:33:52 -0500111 * @brief Represents a message registry entry, which is used for creating a
112 * PEL from an OpenBMC event log.
113 */
114struct Entry
115{
116 /**
117 * @brief The error name, like "xyz.openbmc_project.Error.Foo".
118 */
119 std::string name;
120
121 /**
Matt Spinler93e29322019-09-20 11:16:15 -0500122 * @brief The component ID of the PEL creator.
123 */
124 uint16_t componentID;
125
126 /**
Matt Spinler367144c2019-09-19 15:33:52 -0500127 * @brief The PEL subsystem field.
128 */
Matt Spinler23970b02022-02-25 16:34:46 -0600129 std::optional<uint8_t> subsystem;
Matt Spinler367144c2019-09-19 15:33:52 -0500130
131 /**
132 * @brief The optional PEL severity field. If not specified, the PEL
133 * will use the severity of the OpenBMC event log.
Matt Spinleraadccc82020-04-10 14:33:42 -0500134 *
135 * If the system type is specified in any of the entries in the vector,
136 * then the system type will be needed to find the actual severity.
Matt Spinler367144c2019-09-19 15:33:52 -0500137 */
Matt Spinleraadccc82020-04-10 14:33:42 -0500138 std::optional<std::vector<RegistrySeverity>> severity;
Matt Spinler367144c2019-09-19 15:33:52 -0500139
140 /**
141 * @brief The optional severity field to use when in manufacturing tolerance
Matt Spinleraadccc82020-04-10 14:33:42 -0500142 * mode. It behaves like the severity field above.
Matt Spinler367144c2019-09-19 15:33:52 -0500143 */
Matt Spinleraadccc82020-04-10 14:33:42 -0500144 std::optional<std::vector<RegistrySeverity>> mfgSeverity;
Matt Spinler367144c2019-09-19 15:33:52 -0500145
146 /**
147 * @brief The PEL action flags field.
148 */
Matt Spinlere07f9152019-11-01 10:48:36 -0500149 std::optional<uint16_t> actionFlags;
Matt Spinler367144c2019-09-19 15:33:52 -0500150
151 /**
152 * @brief The optional action flags to use instead when in manufacturing
153 * tolerance mode.
154 */
155 std::optional<uint16_t> mfgActionFlags;
156
157 /**
158 * @brief The PEL event type field. If not specified, higher level code
159 * will decide the value.
160 */
161 std::optional<uint8_t> eventType;
162
163 /**
164 * @brief The PEL event scope field. If not specified, higher level code
165 * will decide the value.
166 */
167 std::optional<uint8_t> eventScope;
168
Matt Spinler93e29322019-09-20 11:16:15 -0500169 /**
170 * The SRC related fields.
171 */
172 SRC src;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800173
174 /**
175 * The Documentation related fields.
176 */
177 DOC doc;
Matt Spinlerd8e29002020-04-09 09:11:22 -0500178
179 /**
180 * @brief The callout JSON, if the entry has callouts.
181 */
182 std::optional<nlohmann::json> callouts;
Matt Spinler367144c2019-09-19 15:33:52 -0500183};
184
185/**
Matt Spinler6b427cc2020-04-09 09:42:59 -0500186 * @brief Holds callout information pulled out of the JSON.
187 */
188struct RegistryCallout
189{
190 std::string priority;
191 std::string locCode;
192 std::string procedure;
193 std::string symbolicFRU;
194 std::string symbolicFRUTrusted;
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500195 bool useInventoryLocCode;
Matt Spinler6b427cc2020-04-09 09:42:59 -0500196};
197
198/**
Matt Spinler367144c2019-09-19 15:33:52 -0500199 * @class Registry
200 *
201 * This class wraps the message registry JSON data and allows one to find
202 * the message registry entry pertaining to the error name.
203 *
204 * So that new registry files can easily be tested, the code will look for
205 * /etc/phosphor-logging/message_registry.json before looking for the real
206 * path.
207 */
208class Registry
209{
210 public:
211 Registry() = delete;
212 ~Registry() = default;
213 Registry(const Registry&) = default;
214 Registry& operator=(const Registry&) = default;
215 Registry(Registry&&) = default;
216 Registry& operator=(Registry&&) = default;
217
218 /**
219 * @brief Constructor
Matt Spinlerd8e29002020-04-09 09:11:22 -0500220 *
221 * Will load the callout JSON.
222 *
Matt Spinler367144c2019-09-19 15:33:52 -0500223 * @param[in] registryFile - The path to the file.
224 */
225 explicit Registry(const std::filesystem::path& registryFile) :
Matt Spinlerd8e29002020-04-09 09:11:22 -0500226 Registry(registryFile, true)
Patrick Williams2544b412022-10-04 08:41:06 -0500227 {}
Matt Spinlerd8e29002020-04-09 09:11:22 -0500228
229 /**
230 * @brief Constructor
231 *
232 * This version contains a parameter that allows the callout JSON
233 * to be saved in the Entry struct or not, as it isn't needed at
234 * all in some cases.
235 *
236 * @param[in] registryFile - The path to the file.
237 * @param[in] loadCallouts - If the callout JSON should be saved.
238 */
239 explicit Registry(const std::filesystem::path& registryFile,
240 bool loadCallouts) :
241 _registryFile(registryFile),
242 _loadCallouts(loadCallouts)
Patrick Williams2544b412022-10-04 08:41:06 -0500243 {}
Matt Spinler367144c2019-09-19 15:33:52 -0500244
245 /**
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800246 * @brief Find a registry entry based on its error name or reason code.
Matt Spinler367144c2019-09-19 15:33:52 -0500247 *
248 * This function does do some basic sanity checking on the JSON contents,
249 * but there is also an external program that enforces a schema on the
250 * registry JSON that should catch all of these problems ahead of time.
251 *
252 * @param[in] name - The error name, like xyz.openbmc_project.Error.Foo
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800253 * - OR
254 * - The reason code, like 0x1001
255 * @param[in] type - LookupType enum value
256 * @param[in] toCache - boolean to cache registry in memory
Matt Spinler367144c2019-09-19 15:33:52 -0500257 * @return optional<Entry> A filled in message registry structure if
258 * found, otherwise an empty optional object.
259 */
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800260 std::optional<Entry> lookup(const std::string& name, LookupType type,
261 bool toCache = false);
Matt Spinler367144c2019-09-19 15:33:52 -0500262
Matt Spinler6b427cc2020-04-09 09:42:59 -0500263 /**
264 * @brief Find the callouts to put into the PEL based on the calloutJSON
265 * data.
266 *
267 * The system type and AdditionalData are used to index into the correct
268 * callout table.
269 *
270 * Throws exceptions on failures.
271 *
272 * @param[in] calloutJSON - Where to look up the callouts
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500273 * @param[in] systemNames - List of compatible system type names
Matt Spinler6b427cc2020-04-09 09:42:59 -0500274 * @param[in] additionalData - The AdditionalData property
275 *
276 * @return std::vector<RegistryCallout> - The callouts to use
277 */
278 static std::vector<RegistryCallout>
279 getCallouts(const nlohmann::json& calloutJSON,
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500280 const std::vector<std::string>& systemNames,
Matt Spinler6b427cc2020-04-09 09:42:59 -0500281 const AdditionalData& additionalData);
282
Matt Spinler367144c2019-09-19 15:33:52 -0500283 private:
284 /**
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800285 * @brief Parse message registry file using nlohmann::json
286 * @param[in] registryFile - The message registry JSON file
287 * @return optional<nlohmann::json> The full message registry object or an
288 * empty optional object upon failure.
289 */
290 std::optional<nlohmann::json>
291 readRegistry(const std::filesystem::path& registryFile);
292
293 /**
Matt Spinler367144c2019-09-19 15:33:52 -0500294 * @brief The path to the registry JSON file.
295 */
296 std::filesystem::path _registryFile;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800297
298 /**
299 * @brief The full message registry object.
300 */
301 std::optional<nlohmann::json> _registry;
Matt Spinlerd8e29002020-04-09 09:11:22 -0500302
303 /**
304 * @brief If the callout JSON should be saved in the Entry on lookup.
305 */
306 bool _loadCallouts;
Matt Spinler367144c2019-09-19 15:33:52 -0500307};
308
309namespace helper
310{
311
312/**
313 * @brief A helper function to get the PEL subsystem value based on
314 * the registry subsystem name.
315 *
316 * @param[in] subsystemName - The registry name for the subsystem
317 *
318 * @return uint8_t The PEL subsystem value
319 */
320uint8_t getSubsystem(const std::string& subsystemName);
321
322/**
323 * @brief A helper function to get the PEL severity value based on
324 * the registry severity name.
325 *
326 * @param[in] severityName - The registry name for the severity
327 *
328 * @return uint8_t The PEL severity value
329 */
330uint8_t getSeverity(const std::string& severityName);
331
332/**
Matt Spinleraadccc82020-04-10 14:33:42 -0500333 * @brief Returns all of the system type/severity values found
334 * in the severity JSON passed in.
335 *
336 * The JSON is either a simple string, like:
337 * "unrecoverable"
338 * or an array of system type/severity pairs, like:
339 * [
340 * {
341 * "System": "1",
342 * "SevValue": "predictive"
343 * },
344 * {
345 * "System": "2",
346 * "SevValue": "recovered"
347 * }
348 * ]
349 *
350 * @param[in] severity - The severity JSON
351 * @return The list of severity/system combinations. If the System key
352 * wasn't used, then that field will be empty in the structure.
353 */
354std::vector<RegistrySeverity> getSeverities(const nlohmann::json& severity);
355
356/**
Matt Spinler367144c2019-09-19 15:33:52 -0500357 * @brief A helper function to get the action flags value based on
358 * the action flag names used in the registry.
359 *
360 * @param[in] flags - The list of flag names from the registry.
361 *
362 * @return uint16_t - The bitfield of flags used in the PEL.
363 */
364uint16_t getActionFlags(const std::vector<std::string>& flags);
365
366/**
367 * @brief A helper function to get the PEL event type value based on
368 * the registry event type name.
369 *
370 * @param[in] eventTypeName - The registry name for the event type
371 *
372 * @return uint8_t The PEL event type value
373 */
374uint8_t getEventType(const std::string& eventTypeName);
375
376/**
377 * @brief A helper function to get the PEL event scope value based on
378 * the registry event scope name.
379 *
380 * @param[in] eventScopeName - The registry name for the event scope
381 *
382 * @return uint8_t The PEL event scope value
383 */
384uint8_t getEventScope(const std::string& eventScopeName);
385
Matt Spinler93e29322019-09-20 11:16:15 -0500386/**
387 * @brief Reads the "ReasonCode" field out of JSON and converts the string value
388 * such as "0x5555" to a uint16 like 0x5555.
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 uint16_t - The reason code
394 */
395uint16_t getSRCReasonCode(const nlohmann::json& src, const std::string& name);
396
397/**
398 * @brief Reads the "Type" field out of JSON and converts it to the SRC::Type
399 * value.
400 *
401 * @param[in] src - The message registry SRC dictionary to read from
402 * @param[in] name - The error name, to use in a trace if things go awry.
403 *
404 * @return uint8_t - The SRC type value, like 0x11
405 */
406uint8_t getSRCType(const nlohmann::json& src, const std::string& name);
407
408/**
409 * @brief Reads the "Words6To9" field out of JSON and converts it to a map
410 * of the SRC word number to the AdditionalData property field used
411 * to fill it in with.
412 *
413 * @param[in] src - The message registry SRC dictionary to read from
414 * @param[in] name - The error name, to use in a trace if things go awry.
415 *
416 * @return std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
417 */
418std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
419 getSRCHexwordFields(const nlohmann::json& src, const std::string& name);
420
421/**
422 * @brief Reads the "SymptomIDFields" field out of JSON and converts it to
423 * a vector of SRC word numbers.
424 *
425 * @param[in] src - The message registry SRC dictionary to read from
426 * @param[in] name - The error name, to use in a trace if things go awry.
427 *
428 * @return std::optional<std::vector<SRC::WordNum>>
429 */
430std::optional<std::vector<SRC::WordNum>>
431 getSRCSymptomIDFields(const nlohmann::json& src, const std::string& name);
432
433/**
434 * @brief Reads the "ComponentID" field out of JSON and converts it to a
435 * uint16_t like 0xFF00.
436 *
437 * The ComponentID JSON field is only required if the SRC type isn't a BD
438 * BMC SRC, because for those SRCs it can be inferred from the upper byte
439 * of the SRC reasoncode.
440 *
441 * @param[in] srcType - The SRC type
442 * @param[in] reasonCode - The SRC reason code
443 * @param[in] pelEntry - The PEL entry JSON
444 * @param[in] name - The error name, to use in a trace if things go awry.
445 *
446 * @return uin16_t - The component ID, like 0xFF00
447 */
448uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode,
449 const nlohmann::json& pelEntry,
450 const std::string& name);
451
Matt Spinler367144c2019-09-19 15:33:52 -0500452} // namespace helper
453
454} // namespace message
455
456} // namespace pels
457} // namespace openpower