blob: b145311212ee3d38fe0d1b15cb783b5dc95e6cc0 [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 <filesystem>
5#include <nlohmann/json.hpp>
6#include <optional>
7#include <string>
8#include <vector>
9
10namespace openpower
11{
12namespace pels
13{
14namespace message
15{
16
17constexpr auto registryFileName = "message_registry.json";
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +080018enum class LookupType
19{
20 name = 0,
21 reasonCode = 1
22};
23
24/**
Matt Spinleraadccc82020-04-10 14:33:42 -050025 * @brief A possible severity/system type combination
26 *
27 * If there is no system type defined for this entry,
28 * then the system field will be empty.
29 */
30struct RegistrySeverity
31{
32 std::string system;
33 uint8_t severity;
34};
35
36/**
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +080037 * @brief Represents the Documentation related fields in the message registry.
38 * It is part of the 'Entry' structure that will be filled in when
39 * an error is looked up in the registry.
40 *
41 * If a field is wrapped by std::optional, it means the field is
42 * optional in the JSON and higher level code knows how to handle it.
43 */
44struct DOC
45{
46 /**
47 * @brief Description of error
48 */
49 std::string description;
50
51 /**
52 * @brief Error message field
53 */
54 std::string message;
55
56 /**
57 * @brief An optional vector of SRC word 6-9 to use as the source of the
58 * numeric arguments that will be substituted into any placeholder
59 * in the Message field.
60 */
61 std::optional<std::vector<std::string>> messageArgSources;
62};
Matt Spinler367144c2019-09-19 15:33:52 -050063
64/**
Matt Spinler93e29322019-09-20 11:16:15 -050065 * @brief Represents the SRC related fields in the message registry.
66 * It is part of the 'Entry' structure that will be filled in when
67 * an error is looked up in the registry.
68 *
69 * If a field is wrapped by std::optional, it means the field is
70 * optional in the JSON and higher level code knows how to handle it.
71 */
72struct SRC
73{
74 /**
75 * @brief SRC type - The first byte of the ASCII string
76 */
77 uint8_t type;
78
79 /**
80 * @brief The SRC reason code (2nd half of 4B 'ASCII string' word)
81 */
82 uint16_t reasonCode;
83
84 /**
85 * @brief Specifies if the SRC represents a power fault. Optional.
86 */
87 std::optional<bool> powerFault;
88
89 /**
90 * @brief An optional vector of SRC hexword numbers that should be used
91 * along with the SRC ASCII string to build the Symptom ID, which
92 * is a field in the Extended Header section.
93 */
94 using WordNum = size_t;
95 std::optional<std::vector<WordNum>> symptomID;
96
97 /**
98 * @brief Which AdditionalData fields to use to fill in the user defined
99 * SRC hexwords.
100 *
101 * For example, if the AdditionalData event log property contained
102 * "CHIPNUM=42" and this map contained {6, CHIPNUM}, then the code
103 * would put 42 into SRC hexword 6.
104 */
105 using AdditionalDataField = std::string;
106 std::optional<std::map<WordNum, AdditionalDataField>> hexwordADFields;
107
108 SRC() : type(0), reasonCode(0)
109 {
110 }
111};
112
113/**
Matt Spinler367144c2019-09-19 15:33:52 -0500114 * @brief Represents a message registry entry, which is used for creating a
115 * PEL from an OpenBMC event log.
116 */
117struct Entry
118{
119 /**
120 * @brief The error name, like "xyz.openbmc_project.Error.Foo".
121 */
122 std::string name;
123
124 /**
Matt Spinler93e29322019-09-20 11:16:15 -0500125 * @brief The component ID of the PEL creator.
126 */
127 uint16_t componentID;
128
129 /**
Matt Spinler367144c2019-09-19 15:33:52 -0500130 * @brief The PEL subsystem field.
131 */
132 uint8_t subsystem;
133
134 /**
135 * @brief The optional PEL severity field. If not specified, the PEL
136 * will use the severity of the OpenBMC event log.
Matt Spinleraadccc82020-04-10 14:33:42 -0500137 *
138 * If the system type is specified in any of the entries in the vector,
139 * then the system type will be needed to find the actual severity.
Matt Spinler367144c2019-09-19 15:33:52 -0500140 */
Matt Spinleraadccc82020-04-10 14:33:42 -0500141 std::optional<std::vector<RegistrySeverity>> severity;
Matt Spinler367144c2019-09-19 15:33:52 -0500142
143 /**
144 * @brief The optional severity field to use when in manufacturing tolerance
Matt Spinleraadccc82020-04-10 14:33:42 -0500145 * mode. It behaves like the severity field above.
Matt Spinler367144c2019-09-19 15:33:52 -0500146 */
Matt Spinleraadccc82020-04-10 14:33:42 -0500147 std::optional<std::vector<RegistrySeverity>> mfgSeverity;
Matt Spinler367144c2019-09-19 15:33:52 -0500148
149 /**
150 * @brief The PEL action flags field.
151 */
Matt Spinlere07f9152019-11-01 10:48:36 -0500152 std::optional<uint16_t> actionFlags;
Matt Spinler367144c2019-09-19 15:33:52 -0500153
154 /**
155 * @brief The optional action flags to use instead when in manufacturing
156 * tolerance mode.
157 */
158 std::optional<uint16_t> mfgActionFlags;
159
160 /**
161 * @brief The PEL event type field. If not specified, higher level code
162 * will decide the value.
163 */
164 std::optional<uint8_t> eventType;
165
166 /**
167 * @brief The PEL event scope field. If not specified, higher level code
168 * will decide the value.
169 */
170 std::optional<uint8_t> eventScope;
171
Matt Spinler93e29322019-09-20 11:16:15 -0500172 /**
173 * The SRC related fields.
174 */
175 SRC src;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800176
177 /**
178 * The Documentation related fields.
179 */
180 DOC doc;
Matt Spinlerd8e29002020-04-09 09:11:22 -0500181
182 /**
183 * @brief The callout JSON, if the entry has callouts.
184 */
185 std::optional<nlohmann::json> callouts;
Matt Spinler367144c2019-09-19 15:33:52 -0500186};
187
188/**
Matt Spinler6b427cc2020-04-09 09:42:59 -0500189 * @brief Holds callout information pulled out of the JSON.
190 */
191struct RegistryCallout
192{
193 std::string priority;
194 std::string locCode;
195 std::string procedure;
196 std::string symbolicFRU;
197 std::string symbolicFRUTrusted;
198};
199
200/**
Matt Spinler367144c2019-09-19 15:33:52 -0500201 * @class Registry
202 *
203 * This class wraps the message registry JSON data and allows one to find
204 * the message registry entry pertaining to the error name.
205 *
206 * So that new registry files can easily be tested, the code will look for
207 * /etc/phosphor-logging/message_registry.json before looking for the real
208 * path.
209 */
210class Registry
211{
212 public:
213 Registry() = delete;
214 ~Registry() = default;
215 Registry(const Registry&) = default;
216 Registry& operator=(const Registry&) = default;
217 Registry(Registry&&) = default;
218 Registry& operator=(Registry&&) = default;
219
220 /**
221 * @brief Constructor
Matt Spinlerd8e29002020-04-09 09:11:22 -0500222 *
223 * Will load the callout JSON.
224 *
Matt Spinler367144c2019-09-19 15:33:52 -0500225 * @param[in] registryFile - The path to the file.
226 */
227 explicit Registry(const std::filesystem::path& registryFile) :
Matt Spinlerd8e29002020-04-09 09:11:22 -0500228 Registry(registryFile, true)
229 {
230 }
231
232 /**
233 * @brief Constructor
234 *
235 * This version contains a parameter that allows the callout JSON
236 * to be saved in the Entry struct or not, as it isn't needed at
237 * all in some cases.
238 *
239 * @param[in] registryFile - The path to the file.
240 * @param[in] loadCallouts - If the callout JSON should be saved.
241 */
242 explicit Registry(const std::filesystem::path& registryFile,
243 bool loadCallouts) :
244 _registryFile(registryFile),
245 _loadCallouts(loadCallouts)
Matt Spinler367144c2019-09-19 15:33:52 -0500246 {
247 }
248
249 /**
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800250 * @brief Find a registry entry based on its error name or reason code.
Matt Spinler367144c2019-09-19 15:33:52 -0500251 *
252 * This function does do some basic sanity checking on the JSON contents,
253 * but there is also an external program that enforces a schema on the
254 * registry JSON that should catch all of these problems ahead of time.
255 *
256 * @param[in] name - The error name, like xyz.openbmc_project.Error.Foo
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800257 * - OR
258 * - The reason code, like 0x1001
259 * @param[in] type - LookupType enum value
260 * @param[in] toCache - boolean to cache registry in memory
Matt Spinler367144c2019-09-19 15:33:52 -0500261 * @return optional<Entry> A filled in message registry structure if
262 * found, otherwise an empty optional object.
263 */
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800264 std::optional<Entry> lookup(const std::string& name, LookupType type,
265 bool toCache = false);
Matt Spinler367144c2019-09-19 15:33:52 -0500266
Matt Spinler6b427cc2020-04-09 09:42:59 -0500267 /**
268 * @brief Find the callouts to put into the PEL based on the calloutJSON
269 * data.
270 *
271 * The system type and AdditionalData are used to index into the correct
272 * callout table.
273 *
274 * Throws exceptions on failures.
275 *
276 * @param[in] calloutJSON - Where to look up the callouts
277 * @param[in] systemType - The system type from EntityManager
278 * @param[in] additionalData - The AdditionalData property
279 *
280 * @return std::vector<RegistryCallout> - The callouts to use
281 */
282 static std::vector<RegistryCallout>
283 getCallouts(const nlohmann::json& calloutJSON,
284 const std::string& systemType,
285 const AdditionalData& additionalData);
286
Matt Spinler367144c2019-09-19 15:33:52 -0500287 private:
288 /**
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800289 * @brief Parse message registry file using nlohmann::json
290 * @param[in] registryFile - The message registry JSON file
291 * @return optional<nlohmann::json> The full message registry object or an
292 * empty optional object upon failure.
293 */
294 std::optional<nlohmann::json>
295 readRegistry(const std::filesystem::path& registryFile);
296
297 /**
Matt Spinler367144c2019-09-19 15:33:52 -0500298 * @brief The path to the registry JSON file.
299 */
300 std::filesystem::path _registryFile;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800301
302 /**
303 * @brief The full message registry object.
304 */
305 std::optional<nlohmann::json> _registry;
Matt Spinlerd8e29002020-04-09 09:11:22 -0500306
307 /**
308 * @brief If the callout JSON should be saved in the Entry on lookup.
309 */
310 bool _loadCallouts;
Matt Spinler367144c2019-09-19 15:33:52 -0500311};
312
313namespace helper
314{
315
316/**
317 * @brief A helper function to get the PEL subsystem value based on
318 * the registry subsystem name.
319 *
320 * @param[in] subsystemName - The registry name for the subsystem
321 *
322 * @return uint8_t The PEL subsystem value
323 */
324uint8_t getSubsystem(const std::string& subsystemName);
325
326/**
327 * @brief A helper function to get the PEL severity value based on
328 * the registry severity name.
329 *
330 * @param[in] severityName - The registry name for the severity
331 *
332 * @return uint8_t The PEL severity value
333 */
334uint8_t getSeverity(const std::string& severityName);
335
336/**
Matt Spinleraadccc82020-04-10 14:33:42 -0500337 * @brief Returns all of the system type/severity values found
338 * in the severity JSON passed in.
339 *
340 * The JSON is either a simple string, like:
341 * "unrecoverable"
342 * or an array of system type/severity pairs, like:
343 * [
344 * {
345 * "System": "1",
346 * "SevValue": "predictive"
347 * },
348 * {
349 * "System": "2",
350 * "SevValue": "recovered"
351 * }
352 * ]
353 *
354 * @param[in] severity - The severity JSON
355 * @return The list of severity/system combinations. If the System key
356 * wasn't used, then that field will be empty in the structure.
357 */
358std::vector<RegistrySeverity> getSeverities(const nlohmann::json& severity);
359
360/**
Matt Spinler367144c2019-09-19 15:33:52 -0500361 * @brief A helper function to get the action flags value based on
362 * the action flag names used in the registry.
363 *
364 * @param[in] flags - The list of flag names from the registry.
365 *
366 * @return uint16_t - The bitfield of flags used in the PEL.
367 */
368uint16_t getActionFlags(const std::vector<std::string>& flags);
369
370/**
371 * @brief A helper function to get the PEL event type value based on
372 * the registry event type name.
373 *
374 * @param[in] eventTypeName - The registry name for the event type
375 *
376 * @return uint8_t The PEL event type value
377 */
378uint8_t getEventType(const std::string& eventTypeName);
379
380/**
381 * @brief A helper function to get the PEL event scope value based on
382 * the registry event scope name.
383 *
384 * @param[in] eventScopeName - The registry name for the event scope
385 *
386 * @return uint8_t The PEL event scope value
387 */
388uint8_t getEventScope(const std::string& eventScopeName);
389
Matt Spinler93e29322019-09-20 11:16:15 -0500390/**
391 * @brief Reads the "ReasonCode" field out of JSON and converts the string value
392 * such as "0x5555" to a uint16 like 0x5555.
393 *
394 * @param[in] src - The message registry SRC dictionary to read from
395 * @param[in] name - The error name, to use in a trace if things go awry.
396 *
397 * @return uint16_t - The reason code
398 */
399uint16_t getSRCReasonCode(const nlohmann::json& src, const std::string& name);
400
401/**
402 * @brief Reads the "Type" field out of JSON and converts it to the SRC::Type
403 * value.
404 *
405 * @param[in] src - The message registry SRC dictionary to read from
406 * @param[in] name - The error name, to use in a trace if things go awry.
407 *
408 * @return uint8_t - The SRC type value, like 0x11
409 */
410uint8_t getSRCType(const nlohmann::json& src, const std::string& name);
411
412/**
413 * @brief Reads the "Words6To9" field out of JSON and converts it to a map
414 * of the SRC word number to the AdditionalData property field used
415 * to fill it in with.
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 std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
421 */
422std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
423 getSRCHexwordFields(const nlohmann::json& src, const std::string& name);
424
425/**
426 * @brief Reads the "SymptomIDFields" field out of JSON and converts it to
427 * a vector of SRC word numbers.
428 *
429 * @param[in] src - The message registry SRC dictionary to read from
430 * @param[in] name - The error name, to use in a trace if things go awry.
431 *
432 * @return std::optional<std::vector<SRC::WordNum>>
433 */
434std::optional<std::vector<SRC::WordNum>>
435 getSRCSymptomIDFields(const nlohmann::json& src, const std::string& name);
436
437/**
438 * @brief Reads the "ComponentID" field out of JSON and converts it to a
439 * uint16_t like 0xFF00.
440 *
441 * The ComponentID JSON field is only required if the SRC type isn't a BD
442 * BMC SRC, because for those SRCs it can be inferred from the upper byte
443 * of the SRC reasoncode.
444 *
445 * @param[in] srcType - The SRC type
446 * @param[in] reasonCode - The SRC reason code
447 * @param[in] pelEntry - The PEL entry JSON
448 * @param[in] name - The error name, to use in a trace if things go awry.
449 *
450 * @return uin16_t - The component ID, like 0xFF00
451 */
452uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode,
453 const nlohmann::json& pelEntry,
454 const std::string& name);
455
Matt Spinler367144c2019-09-19 15:33:52 -0500456} // namespace helper
457
458} // namespace message
459
460} // namespace pels
461} // namespace openpower