blob: cd39b3fb33855f7184d337cbc6d6919123d52d08 [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>
Matt Spinler711f1122022-12-15 11:41:20 -06009#include <variant>
Matt Spinler367144c2019-09-19 15:33:52 -050010#include <vector>
11
12namespace openpower
13{
14namespace pels
15{
16namespace message
17{
18
19constexpr auto registryFileName = "message_registry.json";
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +080020enum class LookupType
21{
22 name = 0,
23 reasonCode = 1
24};
25
26/**
Matt Spinleraadccc82020-04-10 14:33:42 -050027 * @brief A possible severity/system type combination
28 *
29 * If there is no system type defined for this entry,
30 * then the system field will be empty.
31 */
32struct RegistrySeverity
33{
34 std::string system;
35 uint8_t severity;
36};
37
38/**
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +080039 * @brief Represents the Documentation related fields in the message registry.
40 * It is part of the 'Entry' structure that will be filled in when
41 * an error is looked up in the registry.
42 *
43 * If a field is wrapped by std::optional, it means the field is
44 * optional in the JSON and higher level code knows how to handle it.
45 */
46struct DOC
47{
48 /**
49 * @brief Description of error
50 */
51 std::string description;
52
53 /**
54 * @brief Error message field
55 */
56 std::string message;
57
58 /**
59 * @brief An optional vector of SRC word 6-9 to use as the source of the
60 * numeric arguments that will be substituted into any placeholder
61 * in the Message field.
62 */
63 std::optional<std::vector<std::string>> messageArgSources;
64};
Matt Spinler367144c2019-09-19 15:33:52 -050065
66/**
Matt Spinler93e29322019-09-20 11:16:15 -050067 * @brief Represents the SRC related fields in the message registry.
68 * It is part of the 'Entry' structure that will be filled in when
69 * an error is looked up in the registry.
70 *
71 * If a field is wrapped by std::optional, it means the field is
72 * optional in the JSON and higher level code knows how to handle it.
73 */
74struct SRC
75{
76 /**
77 * @brief SRC type - The first byte of the ASCII string
78 */
79 uint8_t type;
80
81 /**
82 * @brief The SRC reason code (2nd half of 4B 'ASCII string' word)
83 */
84 uint16_t reasonCode;
85
86 /**
Matt Spinler93e29322019-09-20 11:16:15 -050087 * @brief An optional vector of SRC hexword numbers that should be used
88 * along with the SRC ASCII string to build the Symptom ID, which
89 * is a field in the Extended Header section.
90 */
91 using WordNum = size_t;
92 std::optional<std::vector<WordNum>> symptomID;
93
94 /**
95 * @brief Which AdditionalData fields to use to fill in the user defined
96 * SRC hexwords.
97 *
98 * For example, if the AdditionalData event log property contained
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +080099 * "CHIPNUM=42" and this map contained {6, {"CHIPNUM", "DESC"}}, then the
100 * code would put 42 into SRC hexword 6.
101 *
102 * AdditionalDataField specifies two fields from the SRC entry in the
103 * message registry: "AdditionalDataPropSource" and "Description"
Matt Spinler93e29322019-09-20 11:16:15 -0500104 */
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +0800105 using AdditionalDataField = std::tuple<std::string, std::string>;
Matt Spinler93e29322019-09-20 11:16:15 -0500106 std::optional<std::map<WordNum, AdditionalDataField>> hexwordADFields;
107
Matt Spinler3fe93e92023-04-14 14:06:59 -0500108 /**
109 * @brief If the Deconfigured flag should be set in hex word 5
110 */
111 bool deconfigFlag;
112
Matt Spinlerda5b76b2023-06-01 15:56:57 -0500113 /**
114 * @brief If the checkstop flag should be set in hex word 5
115 */
116 bool checkstopFlag;
117
118 SRC() : type(0), reasonCode(0), deconfigFlag(false), checkstopFlag(false) {}
Matt Spinler93e29322019-09-20 11:16:15 -0500119};
120
Matt Spinler711f1122022-12-15 11:41:20 -0600121struct AppCapture
122{
123 std::string syslogID;
124 size_t numLines;
125};
126
127// Can specify either the syslog IDs to capture along with how many
128// entries of each, or just how many entries to get the full journal.
129using AppCaptureList = std::vector<AppCapture>;
130using JournalCapture = std::variant<size_t, AppCaptureList>;
131
Matt Spinler93e29322019-09-20 11:16:15 -0500132/**
Matt Spinler367144c2019-09-19 15:33:52 -0500133 * @brief Represents a message registry entry, which is used for creating a
134 * PEL from an OpenBMC event log.
135 */
136struct Entry
137{
138 /**
139 * @brief The error name, like "xyz.openbmc_project.Error.Foo".
140 */
141 std::string name;
142
143 /**
Matt Spinler93e29322019-09-20 11:16:15 -0500144 * @brief The component ID of the PEL creator.
145 */
146 uint16_t componentID;
147
148 /**
Matt Spinler367144c2019-09-19 15:33:52 -0500149 * @brief The PEL subsystem field.
150 */
Matt Spinler23970b02022-02-25 16:34:46 -0600151 std::optional<uint8_t> subsystem;
Matt Spinler367144c2019-09-19 15:33:52 -0500152
153 /**
154 * @brief The optional PEL severity field. If not specified, the PEL
155 * will use the severity of the OpenBMC event log.
Matt Spinleraadccc82020-04-10 14:33:42 -0500156 *
157 * If the system type is specified in any of the entries in the vector,
158 * then the system type will be needed to find the actual severity.
Matt Spinler367144c2019-09-19 15:33:52 -0500159 */
Matt Spinleraadccc82020-04-10 14:33:42 -0500160 std::optional<std::vector<RegistrySeverity>> severity;
Matt Spinler367144c2019-09-19 15:33:52 -0500161
162 /**
163 * @brief The optional severity field to use when in manufacturing tolerance
Matt Spinleraadccc82020-04-10 14:33:42 -0500164 * mode. It behaves like the severity field above.
Matt Spinler367144c2019-09-19 15:33:52 -0500165 */
Matt Spinleraadccc82020-04-10 14:33:42 -0500166 std::optional<std::vector<RegistrySeverity>> mfgSeverity;
Matt Spinler367144c2019-09-19 15:33:52 -0500167
168 /**
169 * @brief The PEL action flags field.
170 */
Matt Spinlere07f9152019-11-01 10:48:36 -0500171 std::optional<uint16_t> actionFlags;
Matt Spinler367144c2019-09-19 15:33:52 -0500172
173 /**
174 * @brief The optional action flags to use instead when in manufacturing
175 * tolerance mode.
176 */
177 std::optional<uint16_t> mfgActionFlags;
178
179 /**
180 * @brief The PEL event type field. If not specified, higher level code
181 * will decide the value.
182 */
183 std::optional<uint8_t> eventType;
184
185 /**
186 * @brief The PEL event scope field. If not specified, higher level code
187 * will decide the value.
188 */
189 std::optional<uint8_t> eventScope;
190
Matt Spinler93e29322019-09-20 11:16:15 -0500191 /**
192 * The SRC related fields.
193 */
194 SRC src;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800195
196 /**
197 * The Documentation related fields.
198 */
199 DOC doc;
Matt Spinlerd8e29002020-04-09 09:11:22 -0500200
201 /**
202 * @brief The callout JSON, if the entry has callouts.
203 */
204 std::optional<nlohmann::json> callouts;
Matt Spinler711f1122022-12-15 11:41:20 -0600205
206 /**
207 * @brief The journal capture instructions, if present.
208 */
209 std::optional<JournalCapture> journalCapture;
Matt Spinler367144c2019-09-19 15:33:52 -0500210};
211
212/**
Matt Spinler6b427cc2020-04-09 09:42:59 -0500213 * @brief Holds callout information pulled out of the JSON.
214 */
215struct RegistryCallout
216{
217 std::string priority;
218 std::string locCode;
219 std::string procedure;
220 std::string symbolicFRU;
221 std::string symbolicFRUTrusted;
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500222 bool useInventoryLocCode;
Matt Spinler6b427cc2020-04-09 09:42:59 -0500223};
224
225/**
Matt Spinler367144c2019-09-19 15:33:52 -0500226 * @class Registry
227 *
228 * This class wraps the message registry JSON data and allows one to find
229 * the message registry entry pertaining to the error name.
230 *
231 * So that new registry files can easily be tested, the code will look for
232 * /etc/phosphor-logging/message_registry.json before looking for the real
233 * path.
234 */
235class Registry
236{
237 public:
238 Registry() = delete;
239 ~Registry() = default;
240 Registry(const Registry&) = default;
241 Registry& operator=(const Registry&) = default;
242 Registry(Registry&&) = default;
243 Registry& operator=(Registry&&) = default;
244
245 /**
246 * @brief Constructor
Matt Spinlerd8e29002020-04-09 09:11:22 -0500247 *
248 * Will load the callout JSON.
249 *
Matt Spinler367144c2019-09-19 15:33:52 -0500250 * @param[in] registryFile - The path to the file.
251 */
252 explicit Registry(const std::filesystem::path& registryFile) :
Matt Spinlerd8e29002020-04-09 09:11:22 -0500253 Registry(registryFile, true)
Patrick Williams2544b412022-10-04 08:41:06 -0500254 {}
Matt Spinlerd8e29002020-04-09 09:11:22 -0500255
256 /**
257 * @brief Constructor
258 *
259 * This version contains a parameter that allows the callout JSON
260 * to be saved in the Entry struct or not, as it isn't needed at
261 * all in some cases.
262 *
263 * @param[in] registryFile - The path to the file.
264 * @param[in] loadCallouts - If the callout JSON should be saved.
265 */
266 explicit Registry(const std::filesystem::path& registryFile,
267 bool loadCallouts) :
268 _registryFile(registryFile),
269 _loadCallouts(loadCallouts)
Patrick Williams2544b412022-10-04 08:41:06 -0500270 {}
Matt Spinler367144c2019-09-19 15:33:52 -0500271
272 /**
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800273 * @brief Find a registry entry based on its error name or reason code.
Matt Spinler367144c2019-09-19 15:33:52 -0500274 *
275 * This function does do some basic sanity checking on the JSON contents,
276 * but there is also an external program that enforces a schema on the
277 * registry JSON that should catch all of these problems ahead of time.
278 *
279 * @param[in] name - The error name, like xyz.openbmc_project.Error.Foo
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800280 * - OR
281 * - The reason code, like 0x1001
282 * @param[in] type - LookupType enum value
283 * @param[in] toCache - boolean to cache registry in memory
Matt Spinler367144c2019-09-19 15:33:52 -0500284 * @return optional<Entry> A filled in message registry structure if
285 * found, otherwise an empty optional object.
286 */
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800287 std::optional<Entry> lookup(const std::string& name, LookupType type,
288 bool toCache = false);
Matt Spinler367144c2019-09-19 15:33:52 -0500289
Matt Spinler6b427cc2020-04-09 09:42:59 -0500290 /**
291 * @brief Find the callouts to put into the PEL based on the calloutJSON
292 * data.
293 *
294 * The system type and AdditionalData are used to index into the correct
295 * callout table.
296 *
297 * Throws exceptions on failures.
298 *
299 * @param[in] calloutJSON - Where to look up the callouts
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500300 * @param[in] systemNames - List of compatible system type names
Matt Spinler6b427cc2020-04-09 09:42:59 -0500301 * @param[in] additionalData - The AdditionalData property
302 *
303 * @return std::vector<RegistryCallout> - The callouts to use
304 */
305 static std::vector<RegistryCallout>
306 getCallouts(const nlohmann::json& calloutJSON,
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500307 const std::vector<std::string>& systemNames,
Matt Spinler6b427cc2020-04-09 09:42:59 -0500308 const AdditionalData& additionalData);
309
Matt Spinler367144c2019-09-19 15:33:52 -0500310 private:
311 /**
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800312 * @brief Parse message registry file using nlohmann::json
313 * @param[in] registryFile - The message registry JSON file
314 * @return optional<nlohmann::json> The full message registry object or an
315 * empty optional object upon failure.
316 */
317 std::optional<nlohmann::json>
318 readRegistry(const std::filesystem::path& registryFile);
319
320 /**
Matt Spinler367144c2019-09-19 15:33:52 -0500321 * @brief The path to the registry JSON file.
322 */
323 std::filesystem::path _registryFile;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800324
325 /**
326 * @brief The full message registry object.
327 */
328 std::optional<nlohmann::json> _registry;
Matt Spinlerd8e29002020-04-09 09:11:22 -0500329
330 /**
331 * @brief If the callout JSON should be saved in the Entry on lookup.
332 */
333 bool _loadCallouts;
Matt Spinler367144c2019-09-19 15:33:52 -0500334};
335
336namespace helper
337{
338
339/**
340 * @brief A helper function to get the PEL subsystem value based on
341 * the registry subsystem name.
342 *
343 * @param[in] subsystemName - The registry name for the subsystem
344 *
345 * @return uint8_t The PEL subsystem value
346 */
347uint8_t getSubsystem(const std::string& subsystemName);
348
349/**
350 * @brief A helper function to get the PEL severity value based on
351 * the registry severity name.
352 *
353 * @param[in] severityName - The registry name for the severity
354 *
355 * @return uint8_t The PEL severity value
356 */
357uint8_t getSeverity(const std::string& severityName);
358
359/**
Matt Spinleraadccc82020-04-10 14:33:42 -0500360 * @brief Returns all of the system type/severity values found
361 * in the severity JSON passed in.
362 *
363 * The JSON is either a simple string, like:
364 * "unrecoverable"
365 * or an array of system type/severity pairs, like:
366 * [
367 * {
368 * "System": "1",
369 * "SevValue": "predictive"
370 * },
371 * {
372 * "System": "2",
373 * "SevValue": "recovered"
374 * }
375 * ]
376 *
377 * @param[in] severity - The severity JSON
378 * @return The list of severity/system combinations. If the System key
379 * wasn't used, then that field will be empty in the structure.
380 */
381std::vector<RegistrySeverity> getSeverities(const nlohmann::json& severity);
382
383/**
Matt Spinler367144c2019-09-19 15:33:52 -0500384 * @brief A helper function to get the action flags value based on
385 * the action flag names used in the registry.
386 *
387 * @param[in] flags - The list of flag names from the registry.
388 *
389 * @return uint16_t - The bitfield of flags used in the PEL.
390 */
391uint16_t getActionFlags(const std::vector<std::string>& flags);
392
393/**
394 * @brief A helper function to get the PEL event type value based on
395 * the registry event type name.
396 *
397 * @param[in] eventTypeName - The registry name for the event type
398 *
399 * @return uint8_t The PEL event type value
400 */
401uint8_t getEventType(const std::string& eventTypeName);
402
403/**
404 * @brief A helper function to get the PEL event scope value based on
405 * the registry event scope name.
406 *
407 * @param[in] eventScopeName - The registry name for the event scope
408 *
409 * @return uint8_t The PEL event scope value
410 */
411uint8_t getEventScope(const std::string& eventScopeName);
412
Matt Spinler93e29322019-09-20 11:16:15 -0500413/**
414 * @brief Reads the "ReasonCode" field out of JSON and converts the string value
415 * such as "0x5555" to a uint16 like 0x5555.
416 *
417 * @param[in] src - The message registry SRC dictionary to read from
418 * @param[in] name - The error name, to use in a trace if things go awry.
419 *
420 * @return uint16_t - The reason code
421 */
422uint16_t getSRCReasonCode(const nlohmann::json& src, const std::string& name);
423
424/**
425 * @brief Reads the "Type" field out of JSON and converts it to the SRC::Type
426 * value.
427 *
428 * @param[in] src - The message registry SRC dictionary to read from
429 * @param[in] name - The error name, to use in a trace if things go awry.
430 *
431 * @return uint8_t - The SRC type value, like 0x11
432 */
433uint8_t getSRCType(const nlohmann::json& src, const std::string& name);
434
435/**
436 * @brief Reads the "Words6To9" field out of JSON and converts it to a map
437 * of the SRC word number to the AdditionalData property field used
438 * to fill it in with.
439 *
440 * @param[in] src - The message registry SRC dictionary to read from
441 * @param[in] name - The error name, to use in a trace if things go awry.
442 *
443 * @return std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
444 */
445std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
446 getSRCHexwordFields(const nlohmann::json& src, const std::string& name);
447
448/**
449 * @brief Reads the "SymptomIDFields" field out of JSON and converts it to
450 * a vector of SRC word numbers.
451 *
452 * @param[in] src - The message registry SRC dictionary to read from
453 * @param[in] name - The error name, to use in a trace if things go awry.
454 *
455 * @return std::optional<std::vector<SRC::WordNum>>
456 */
457std::optional<std::vector<SRC::WordNum>>
458 getSRCSymptomIDFields(const nlohmann::json& src, const std::string& name);
459
460/**
Matt Spinler3fe93e92023-04-14 14:06:59 -0500461 * @brief Returns the value of the 'DeconfigFlag' field.
462 *
463 * @param[in] src - The message registry SRC dictionary to read from
464 *
465 * @return bool - The field value
466 */
467bool getSRCDeconfigFlag(const nlohmann::json& src);
468
469/**
Matt Spinler93e29322019-09-20 11:16:15 -0500470 * @brief Reads the "ComponentID" field out of JSON and converts it to a
471 * uint16_t like 0xFF00.
472 *
473 * The ComponentID JSON field is only required if the SRC type isn't a BD
474 * BMC SRC, because for those SRCs it can be inferred from the upper byte
475 * of the SRC reasoncode.
476 *
477 * @param[in] srcType - The SRC type
478 * @param[in] reasonCode - The SRC reason code
479 * @param[in] pelEntry - The PEL entry JSON
480 * @param[in] name - The error name, to use in a trace if things go awry.
481 *
482 * @return uin16_t - The component ID, like 0xFF00
483 */
484uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode,
485 const nlohmann::json& pelEntry,
486 const std::string& name);
487
Matt Spinler367144c2019-09-19 15:33:52 -0500488} // namespace helper
489
490} // namespace message
491
492} // namespace pels
493} // namespace openpower