blob: 047853dceed782b1aa1a9b36e8bfe0bf792d5687 [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/**
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 */
32struct 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};
Matt Spinler367144c2019-09-19 15:33:52 -050051
52/**
Matt Spinler93e29322019-09-20 11:16:15 -050053 * @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 */
60struct 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/**
Matt Spinler367144c2019-09-19 15:33:52 -0500102 * @brief Represents a message registry entry, which is used for creating a
103 * PEL from an OpenBMC event log.
104 */
105struct Entry
106{
107 /**
108 * @brief The error name, like "xyz.openbmc_project.Error.Foo".
109 */
110 std::string name;
111
112 /**
Matt Spinler93e29322019-09-20 11:16:15 -0500113 * @brief The component ID of the PEL creator.
114 */
115 uint16_t componentID;
116
117 /**
Matt Spinler367144c2019-09-19 15:33:52 -0500118 * @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 */
Matt Spinlere07f9152019-11-01 10:48:36 -0500137 std::optional<uint16_t> actionFlags;
Matt Spinler367144c2019-09-19 15:33:52 -0500138
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
Matt Spinler93e29322019-09-20 11:16:15 -0500157 /**
158 * The SRC related fields.
159 */
160 SRC src;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800161
162 /**
163 * The Documentation related fields.
164 */
165 DOC doc;
Matt Spinlerd8e29002020-04-09 09:11:22 -0500166
167 /**
168 * @brief The callout JSON, if the entry has callouts.
169 */
170 std::optional<nlohmann::json> callouts;
Matt Spinler367144c2019-09-19 15:33:52 -0500171};
172
173/**
Matt Spinler6b427cc2020-04-09 09:42:59 -0500174 * @brief Holds callout information pulled out of the JSON.
175 */
176struct 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/**
Matt Spinler367144c2019-09-19 15:33:52 -0500186 * @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 */
195class 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
Matt Spinlerd8e29002020-04-09 09:11:22 -0500207 *
208 * Will load the callout JSON.
209 *
Matt Spinler367144c2019-09-19 15:33:52 -0500210 * @param[in] registryFile - The path to the file.
211 */
212 explicit Registry(const std::filesystem::path& registryFile) :
Matt Spinlerd8e29002020-04-09 09:11:22 -0500213 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)
Matt Spinler367144c2019-09-19 15:33:52 -0500231 {
232 }
233
234 /**
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800235 * @brief Find a registry entry based on its error name or reason code.
Matt Spinler367144c2019-09-19 15:33:52 -0500236 *
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
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800242 * - OR
243 * - The reason code, like 0x1001
244 * @param[in] type - LookupType enum value
245 * @param[in] toCache - boolean to cache registry in memory
Matt Spinler367144c2019-09-19 15:33:52 -0500246 * @return optional<Entry> A filled in message registry structure if
247 * found, otherwise an empty optional object.
248 */
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800249 std::optional<Entry> lookup(const std::string& name, LookupType type,
250 bool toCache = false);
Matt Spinler367144c2019-09-19 15:33:52 -0500251
Matt Spinler6b427cc2020-04-09 09:42:59 -0500252 /**
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
Matt Spinler367144c2019-09-19 15:33:52 -0500272 private:
273 /**
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800274 * @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 /**
Matt Spinler367144c2019-09-19 15:33:52 -0500283 * @brief The path to the registry JSON file.
284 */
285 std::filesystem::path _registryFile;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800286
287 /**
288 * @brief The full message registry object.
289 */
290 std::optional<nlohmann::json> _registry;
Matt Spinlerd8e29002020-04-09 09:11:22 -0500291
292 /**
293 * @brief If the callout JSON should be saved in the Entry on lookup.
294 */
295 bool _loadCallouts;
Matt Spinler367144c2019-09-19 15:33:52 -0500296};
297
298namespace 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 */
309uint8_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 */
319uint8_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 */
329uint16_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 */
339uint8_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 */
349uint8_t getEventScope(const std::string& eventScopeName);
350
Matt Spinler93e29322019-09-20 11:16:15 -0500351/**
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 */
360uint16_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 */
371uint8_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 */
383std::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 */
395std::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 */
413uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode,
414 const nlohmann::json& pelEntry,
415 const std::string& name);
416
Matt Spinler367144c2019-09-19 15:33:52 -0500417} // namespace helper
418
419} // namespace message
420
421} // namespace pels
422} // namespace openpower