blob: 03140815e3e25e9fc9f2896a0fc5f17e1b653de4 [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;
Harisuddin Mohamed Isa5a3d8f42022-03-24 19:20:37 +080062
63 /**
64 * @brief An optional vector of string that forms the Notes field.
65 */
66 std::optional<std::vector<std::string>> notes;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +080067};
Matt Spinler367144c2019-09-19 15:33:52 -050068
69/**
Matt Spinler93e29322019-09-20 11:16:15 -050070 * @brief Represents the SRC related fields in the message registry.
71 * It is part of the 'Entry' structure that will be filled in when
72 * an error is looked up in the registry.
73 *
74 * If a field is wrapped by std::optional, it means the field is
75 * optional in the JSON and higher level code knows how to handle it.
76 */
77struct SRC
78{
79 /**
80 * @brief SRC type - The first byte of the ASCII string
81 */
82 uint8_t type;
83
84 /**
85 * @brief The SRC reason code (2nd half of 4B 'ASCII string' word)
86 */
87 uint16_t reasonCode;
88
89 /**
Matt Spinler93e29322019-09-20 11:16:15 -050090 * @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
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +0800102 * "CHIPNUM=42" and this map contained {6, {"CHIPNUM", "DESC"}}, then the
103 * code would put 42 into SRC hexword 6.
104 *
105 * AdditionalDataField specifies two fields from the SRC entry in the
106 * message registry: "AdditionalDataPropSource" and "Description"
Matt Spinler93e29322019-09-20 11:16:15 -0500107 */
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +0800108 using AdditionalDataField = std::tuple<std::string, std::string>;
Matt Spinler93e29322019-09-20 11:16:15 -0500109 std::optional<std::map<WordNum, AdditionalDataField>> hexwordADFields;
110
111 SRC() : type(0), reasonCode(0)
112 {
113 }
114};
115
116/**
Matt Spinler367144c2019-09-19 15:33:52 -0500117 * @brief Represents a message registry entry, which is used for creating a
118 * PEL from an OpenBMC event log.
119 */
120struct Entry
121{
122 /**
123 * @brief The error name, like "xyz.openbmc_project.Error.Foo".
124 */
125 std::string name;
126
127 /**
Matt Spinler93e29322019-09-20 11:16:15 -0500128 * @brief The component ID of the PEL creator.
129 */
130 uint16_t componentID;
131
132 /**
Matt Spinler367144c2019-09-19 15:33:52 -0500133 * @brief The PEL subsystem field.
134 */
Matt Spinler23970b02022-02-25 16:34:46 -0600135 std::optional<uint8_t> subsystem;
Matt Spinler367144c2019-09-19 15:33:52 -0500136
137 /**
138 * @brief The optional PEL severity field. If not specified, the PEL
139 * will use the severity of the OpenBMC event log.
Matt Spinleraadccc82020-04-10 14:33:42 -0500140 *
141 * If the system type is specified in any of the entries in the vector,
142 * then the system type will be needed to find the actual severity.
Matt Spinler367144c2019-09-19 15:33:52 -0500143 */
Matt Spinleraadccc82020-04-10 14:33:42 -0500144 std::optional<std::vector<RegistrySeverity>> severity;
Matt Spinler367144c2019-09-19 15:33:52 -0500145
146 /**
147 * @brief The optional severity field to use when in manufacturing tolerance
Matt Spinleraadccc82020-04-10 14:33:42 -0500148 * mode. It behaves like the severity field above.
Matt Spinler367144c2019-09-19 15:33:52 -0500149 */
Matt Spinleraadccc82020-04-10 14:33:42 -0500150 std::optional<std::vector<RegistrySeverity>> mfgSeverity;
Matt Spinler367144c2019-09-19 15:33:52 -0500151
152 /**
153 * @brief The PEL action flags field.
154 */
Matt Spinlere07f9152019-11-01 10:48:36 -0500155 std::optional<uint16_t> actionFlags;
Matt Spinler367144c2019-09-19 15:33:52 -0500156
157 /**
158 * @brief The optional action flags to use instead when in manufacturing
159 * tolerance mode.
160 */
161 std::optional<uint16_t> mfgActionFlags;
162
163 /**
164 * @brief The PEL event type field. If not specified, higher level code
165 * will decide the value.
166 */
167 std::optional<uint8_t> eventType;
168
169 /**
170 * @brief The PEL event scope field. If not specified, higher level code
171 * will decide the value.
172 */
173 std::optional<uint8_t> eventScope;
174
Matt Spinler93e29322019-09-20 11:16:15 -0500175 /**
176 * The SRC related fields.
177 */
178 SRC src;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800179
180 /**
181 * The Documentation related fields.
182 */
183 DOC doc;
Matt Spinlerd8e29002020-04-09 09:11:22 -0500184
185 /**
186 * @brief The callout JSON, if the entry has callouts.
187 */
188 std::optional<nlohmann::json> callouts;
Matt Spinler367144c2019-09-19 15:33:52 -0500189};
190
191/**
Matt Spinler6b427cc2020-04-09 09:42:59 -0500192 * @brief Holds callout information pulled out of the JSON.
193 */
194struct RegistryCallout
195{
196 std::string priority;
197 std::string locCode;
198 std::string procedure;
199 std::string symbolicFRU;
200 std::string symbolicFRUTrusted;
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500201 bool useInventoryLocCode;
Matt Spinler6b427cc2020-04-09 09:42:59 -0500202};
203
204/**
Matt Spinler367144c2019-09-19 15:33:52 -0500205 * @class Registry
206 *
207 * This class wraps the message registry JSON data and allows one to find
208 * the message registry entry pertaining to the error name.
209 *
210 * So that new registry files can easily be tested, the code will look for
211 * /etc/phosphor-logging/message_registry.json before looking for the real
212 * path.
213 */
214class Registry
215{
216 public:
217 Registry() = delete;
218 ~Registry() = default;
219 Registry(const Registry&) = default;
220 Registry& operator=(const Registry&) = default;
221 Registry(Registry&&) = default;
222 Registry& operator=(Registry&&) = default;
223
224 /**
225 * @brief Constructor
Matt Spinlerd8e29002020-04-09 09:11:22 -0500226 *
227 * Will load the callout JSON.
228 *
Matt Spinler367144c2019-09-19 15:33:52 -0500229 * @param[in] registryFile - The path to the file.
230 */
231 explicit Registry(const std::filesystem::path& registryFile) :
Matt Spinlerd8e29002020-04-09 09:11:22 -0500232 Registry(registryFile, true)
233 {
234 }
235
236 /**
237 * @brief Constructor
238 *
239 * This version contains a parameter that allows the callout JSON
240 * to be saved in the Entry struct or not, as it isn't needed at
241 * all in some cases.
242 *
243 * @param[in] registryFile - The path to the file.
244 * @param[in] loadCallouts - If the callout JSON should be saved.
245 */
246 explicit Registry(const std::filesystem::path& registryFile,
247 bool loadCallouts) :
248 _registryFile(registryFile),
249 _loadCallouts(loadCallouts)
Matt Spinler367144c2019-09-19 15:33:52 -0500250 {
251 }
252
253 /**
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800254 * @brief Find a registry entry based on its error name or reason code.
Matt Spinler367144c2019-09-19 15:33:52 -0500255 *
256 * This function does do some basic sanity checking on the JSON contents,
257 * but there is also an external program that enforces a schema on the
258 * registry JSON that should catch all of these problems ahead of time.
259 *
260 * @param[in] name - The error name, like xyz.openbmc_project.Error.Foo
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800261 * - OR
262 * - The reason code, like 0x1001
263 * @param[in] type - LookupType enum value
264 * @param[in] toCache - boolean to cache registry in memory
Matt Spinler367144c2019-09-19 15:33:52 -0500265 * @return optional<Entry> A filled in message registry structure if
266 * found, otherwise an empty optional object.
267 */
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800268 std::optional<Entry> lookup(const std::string& name, LookupType type,
269 bool toCache = false);
Matt Spinler367144c2019-09-19 15:33:52 -0500270
Matt Spinler6b427cc2020-04-09 09:42:59 -0500271 /**
272 * @brief Find the callouts to put into the PEL based on the calloutJSON
273 * data.
274 *
275 * The system type and AdditionalData are used to index into the correct
276 * callout table.
277 *
278 * Throws exceptions on failures.
279 *
280 * @param[in] calloutJSON - Where to look up the callouts
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500281 * @param[in] systemNames - List of compatible system type names
Matt Spinler6b427cc2020-04-09 09:42:59 -0500282 * @param[in] additionalData - The AdditionalData property
283 *
284 * @return std::vector<RegistryCallout> - The callouts to use
285 */
286 static std::vector<RegistryCallout>
287 getCallouts(const nlohmann::json& calloutJSON,
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500288 const std::vector<std::string>& systemNames,
Matt Spinler6b427cc2020-04-09 09:42:59 -0500289 const AdditionalData& additionalData);
290
Matt Spinler367144c2019-09-19 15:33:52 -0500291 private:
292 /**
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800293 * @brief Parse message registry file using nlohmann::json
294 * @param[in] registryFile - The message registry JSON file
295 * @return optional<nlohmann::json> The full message registry object or an
296 * empty optional object upon failure.
297 */
298 std::optional<nlohmann::json>
299 readRegistry(const std::filesystem::path& registryFile);
300
301 /**
Matt Spinler367144c2019-09-19 15:33:52 -0500302 * @brief The path to the registry JSON file.
303 */
304 std::filesystem::path _registryFile;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800305
306 /**
307 * @brief The full message registry object.
308 */
309 std::optional<nlohmann::json> _registry;
Matt Spinlerd8e29002020-04-09 09:11:22 -0500310
311 /**
312 * @brief If the callout JSON should be saved in the Entry on lookup.
313 */
314 bool _loadCallouts;
Matt Spinler367144c2019-09-19 15:33:52 -0500315};
316
317namespace helper
318{
319
320/**
321 * @brief A helper function to get the PEL subsystem value based on
322 * the registry subsystem name.
323 *
324 * @param[in] subsystemName - The registry name for the subsystem
325 *
326 * @return uint8_t The PEL subsystem value
327 */
328uint8_t getSubsystem(const std::string& subsystemName);
329
330/**
331 * @brief A helper function to get the PEL severity value based on
332 * the registry severity name.
333 *
334 * @param[in] severityName - The registry name for the severity
335 *
336 * @return uint8_t The PEL severity value
337 */
338uint8_t getSeverity(const std::string& severityName);
339
340/**
Matt Spinleraadccc82020-04-10 14:33:42 -0500341 * @brief Returns all of the system type/severity values found
342 * in the severity JSON passed in.
343 *
344 * The JSON is either a simple string, like:
345 * "unrecoverable"
346 * or an array of system type/severity pairs, like:
347 * [
348 * {
349 * "System": "1",
350 * "SevValue": "predictive"
351 * },
352 * {
353 * "System": "2",
354 * "SevValue": "recovered"
355 * }
356 * ]
357 *
358 * @param[in] severity - The severity JSON
359 * @return The list of severity/system combinations. If the System key
360 * wasn't used, then that field will be empty in the structure.
361 */
362std::vector<RegistrySeverity> getSeverities(const nlohmann::json& severity);
363
364/**
Matt Spinler367144c2019-09-19 15:33:52 -0500365 * @brief A helper function to get the action flags value based on
366 * the action flag names used in the registry.
367 *
368 * @param[in] flags - The list of flag names from the registry.
369 *
370 * @return uint16_t - The bitfield of flags used in the PEL.
371 */
372uint16_t getActionFlags(const std::vector<std::string>& flags);
373
374/**
375 * @brief A helper function to get the PEL event type value based on
376 * the registry event type name.
377 *
378 * @param[in] eventTypeName - The registry name for the event type
379 *
380 * @return uint8_t The PEL event type value
381 */
382uint8_t getEventType(const std::string& eventTypeName);
383
384/**
385 * @brief A helper function to get the PEL event scope value based on
386 * the registry event scope name.
387 *
388 * @param[in] eventScopeName - The registry name for the event scope
389 *
390 * @return uint8_t The PEL event scope value
391 */
392uint8_t getEventScope(const std::string& eventScopeName);
393
Matt Spinler93e29322019-09-20 11:16:15 -0500394/**
395 * @brief Reads the "ReasonCode" field out of JSON and converts the string value
396 * such as "0x5555" to a uint16 like 0x5555.
397 *
398 * @param[in] src - The message registry SRC dictionary to read from
399 * @param[in] name - The error name, to use in a trace if things go awry.
400 *
401 * @return uint16_t - The reason code
402 */
403uint16_t getSRCReasonCode(const nlohmann::json& src, const std::string& name);
404
405/**
406 * @brief Reads the "Type" field out of JSON and converts it to the SRC::Type
407 * value.
408 *
409 * @param[in] src - The message registry SRC dictionary to read from
410 * @param[in] name - The error name, to use in a trace if things go awry.
411 *
412 * @return uint8_t - The SRC type value, like 0x11
413 */
414uint8_t getSRCType(const nlohmann::json& src, const std::string& name);
415
416/**
417 * @brief Reads the "Words6To9" field out of JSON and converts it to a map
418 * of the SRC word number to the AdditionalData property field used
419 * to fill it in with.
420 *
421 * @param[in] src - The message registry SRC dictionary to read from
422 * @param[in] name - The error name, to use in a trace if things go awry.
423 *
424 * @return std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
425 */
426std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
427 getSRCHexwordFields(const nlohmann::json& src, const std::string& name);
428
429/**
430 * @brief Reads the "SymptomIDFields" field out of JSON and converts it to
431 * a vector of SRC word numbers.
432 *
433 * @param[in] src - The message registry SRC dictionary to read from
434 * @param[in] name - The error name, to use in a trace if things go awry.
435 *
436 * @return std::optional<std::vector<SRC::WordNum>>
437 */
438std::optional<std::vector<SRC::WordNum>>
439 getSRCSymptomIDFields(const nlohmann::json& src, const std::string& name);
440
441/**
442 * @brief Reads the "ComponentID" field out of JSON and converts it to a
443 * uint16_t like 0xFF00.
444 *
445 * The ComponentID JSON field is only required if the SRC type isn't a BD
446 * BMC SRC, because for those SRCs it can be inferred from the upper byte
447 * of the SRC reasoncode.
448 *
449 * @param[in] srcType - The SRC type
450 * @param[in] reasonCode - The SRC reason code
451 * @param[in] pelEntry - The PEL entry JSON
452 * @param[in] name - The error name, to use in a trace if things go awry.
453 *
454 * @return uin16_t - The component ID, like 0xFF00
455 */
456uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode,
457 const nlohmann::json& pelEntry,
458 const std::string& name);
459
Matt Spinler367144c2019-09-19 15:33:52 -0500460} // namespace helper
461
462} // namespace message
463
464} // namespace pels
465} // namespace openpower