blob: 0a75d8eba04fad9e1b2c34f935473e0c7005ecd8 [file] [log] [blame]
Matt Spinler367144c2019-09-19 15:33:52 -05001#pragma once
2#include <filesystem>
3#include <nlohmann/json.hpp>
4#include <optional>
5#include <string>
6#include <vector>
7
8namespace openpower
9{
10namespace pels
11{
12namespace message
13{
14
15constexpr auto registryFileName = "message_registry.json";
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +080016enum class LookupType
17{
18 name = 0,
19 reasonCode = 1
20};
21
22/**
23 * @brief Represents the Documentation related fields in the message registry.
24 * It is part of the 'Entry' structure that will be filled in when
25 * an error is looked up in the registry.
26 *
27 * If a field is wrapped by std::optional, it means the field is
28 * optional in the JSON and higher level code knows how to handle it.
29 */
30struct DOC
31{
32 /**
33 * @brief Description of error
34 */
35 std::string description;
36
37 /**
38 * @brief Error message field
39 */
40 std::string message;
41
42 /**
43 * @brief An optional vector of SRC word 6-9 to use as the source of the
44 * numeric arguments that will be substituted into any placeholder
45 * in the Message field.
46 */
47 std::optional<std::vector<std::string>> messageArgSources;
48};
Matt Spinler367144c2019-09-19 15:33:52 -050049
50/**
Matt Spinler93e29322019-09-20 11:16:15 -050051 * @brief Represents the SRC related fields in the message registry.
52 * It is part of the 'Entry' structure that will be filled in when
53 * an error is looked up in the registry.
54 *
55 * If a field is wrapped by std::optional, it means the field is
56 * optional in the JSON and higher level code knows how to handle it.
57 */
58struct SRC
59{
60 /**
61 * @brief SRC type - The first byte of the ASCII string
62 */
63 uint8_t type;
64
65 /**
66 * @brief The SRC reason code (2nd half of 4B 'ASCII string' word)
67 */
68 uint16_t reasonCode;
69
70 /**
71 * @brief Specifies if the SRC represents a power fault. Optional.
72 */
73 std::optional<bool> powerFault;
74
75 /**
76 * @brief An optional vector of SRC hexword numbers that should be used
77 * along with the SRC ASCII string to build the Symptom ID, which
78 * is a field in the Extended Header section.
79 */
80 using WordNum = size_t;
81 std::optional<std::vector<WordNum>> symptomID;
82
83 /**
84 * @brief Which AdditionalData fields to use to fill in the user defined
85 * SRC hexwords.
86 *
87 * For example, if the AdditionalData event log property contained
88 * "CHIPNUM=42" and this map contained {6, CHIPNUM}, then the code
89 * would put 42 into SRC hexword 6.
90 */
91 using AdditionalDataField = std::string;
92 std::optional<std::map<WordNum, AdditionalDataField>> hexwordADFields;
93
94 SRC() : type(0), reasonCode(0)
95 {
96 }
97};
98
99/**
Matt Spinler367144c2019-09-19 15:33:52 -0500100 * @brief Represents a message registry entry, which is used for creating a
101 * PEL from an OpenBMC event log.
102 */
103struct Entry
104{
105 /**
106 * @brief The error name, like "xyz.openbmc_project.Error.Foo".
107 */
108 std::string name;
109
110 /**
Matt Spinler93e29322019-09-20 11:16:15 -0500111 * @brief The component ID of the PEL creator.
112 */
113 uint16_t componentID;
114
115 /**
Matt Spinler367144c2019-09-19 15:33:52 -0500116 * @brief The PEL subsystem field.
117 */
118 uint8_t subsystem;
119
120 /**
121 * @brief The optional PEL severity field. If not specified, the PEL
122 * will use the severity of the OpenBMC event log.
123 */
124 std::optional<uint8_t> severity;
125
126 /**
127 * @brief The optional severity field to use when in manufacturing tolerance
128 * mode.
129 */
130 std::optional<uint8_t> mfgSeverity;
131
132 /**
133 * @brief The PEL action flags field.
134 */
Matt Spinlere07f9152019-11-01 10:48:36 -0500135 std::optional<uint16_t> actionFlags;
Matt Spinler367144c2019-09-19 15:33:52 -0500136
137 /**
138 * @brief The optional action flags to use instead when in manufacturing
139 * tolerance mode.
140 */
141 std::optional<uint16_t> mfgActionFlags;
142
143 /**
144 * @brief The PEL event type field. If not specified, higher level code
145 * will decide the value.
146 */
147 std::optional<uint8_t> eventType;
148
149 /**
150 * @brief The PEL event scope field. If not specified, higher level code
151 * will decide the value.
152 */
153 std::optional<uint8_t> eventScope;
154
Matt Spinler93e29322019-09-20 11:16:15 -0500155 /**
156 * The SRC related fields.
157 */
158 SRC src;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800159
160 /**
161 * The Documentation related fields.
162 */
163 DOC doc;
Matt Spinler367144c2019-09-19 15:33:52 -0500164};
165
166/**
167 * @class Registry
168 *
169 * This class wraps the message registry JSON data and allows one to find
170 * the message registry entry pertaining to the error name.
171 *
172 * So that new registry files can easily be tested, the code will look for
173 * /etc/phosphor-logging/message_registry.json before looking for the real
174 * path.
175 */
176class Registry
177{
178 public:
179 Registry() = delete;
180 ~Registry() = default;
181 Registry(const Registry&) = default;
182 Registry& operator=(const Registry&) = default;
183 Registry(Registry&&) = default;
184 Registry& operator=(Registry&&) = default;
185
186 /**
187 * @brief Constructor
188 * @param[in] registryFile - The path to the file.
189 */
190 explicit Registry(const std::filesystem::path& registryFile) :
191 _registryFile(registryFile)
192 {
193 }
194
195 /**
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800196 * @brief Find a registry entry based on its error name or reason code.
Matt Spinler367144c2019-09-19 15:33:52 -0500197 *
198 * This function does do some basic sanity checking on the JSON contents,
199 * but there is also an external program that enforces a schema on the
200 * registry JSON that should catch all of these problems ahead of time.
201 *
202 * @param[in] name - The error name, like xyz.openbmc_project.Error.Foo
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800203 * - OR
204 * - The reason code, like 0x1001
205 * @param[in] type - LookupType enum value
206 * @param[in] toCache - boolean to cache registry in memory
Matt Spinler367144c2019-09-19 15:33:52 -0500207 * @return optional<Entry> A filled in message registry structure if
208 * found, otherwise an empty optional object.
209 */
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800210 std::optional<Entry> lookup(const std::string& name, LookupType type,
211 bool toCache = false);
Matt Spinler367144c2019-09-19 15:33:52 -0500212
213 private:
214 /**
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800215 * @brief Parse message registry file using nlohmann::json
216 * @param[in] registryFile - The message registry JSON file
217 * @return optional<nlohmann::json> The full message registry object or an
218 * empty optional object upon failure.
219 */
220 std::optional<nlohmann::json>
221 readRegistry(const std::filesystem::path& registryFile);
222
223 /**
Matt Spinler367144c2019-09-19 15:33:52 -0500224 * @brief The path to the registry JSON file.
225 */
226 std::filesystem::path _registryFile;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800227
228 /**
229 * @brief The full message registry object.
230 */
231 std::optional<nlohmann::json> _registry;
Matt Spinler367144c2019-09-19 15:33:52 -0500232};
233
234namespace helper
235{
236
237/**
238 * @brief A helper function to get the PEL subsystem value based on
239 * the registry subsystem name.
240 *
241 * @param[in] subsystemName - The registry name for the subsystem
242 *
243 * @return uint8_t The PEL subsystem value
244 */
245uint8_t getSubsystem(const std::string& subsystemName);
246
247/**
248 * @brief A helper function to get the PEL severity value based on
249 * the registry severity name.
250 *
251 * @param[in] severityName - The registry name for the severity
252 *
253 * @return uint8_t The PEL severity value
254 */
255uint8_t getSeverity(const std::string& severityName);
256
257/**
258 * @brief A helper function to get the action flags value based on
259 * the action flag names used in the registry.
260 *
261 * @param[in] flags - The list of flag names from the registry.
262 *
263 * @return uint16_t - The bitfield of flags used in the PEL.
264 */
265uint16_t getActionFlags(const std::vector<std::string>& flags);
266
267/**
268 * @brief A helper function to get the PEL event type value based on
269 * the registry event type name.
270 *
271 * @param[in] eventTypeName - The registry name for the event type
272 *
273 * @return uint8_t The PEL event type value
274 */
275uint8_t getEventType(const std::string& eventTypeName);
276
277/**
278 * @brief A helper function to get the PEL event scope value based on
279 * the registry event scope name.
280 *
281 * @param[in] eventScopeName - The registry name for the event scope
282 *
283 * @return uint8_t The PEL event scope value
284 */
285uint8_t getEventScope(const std::string& eventScopeName);
286
Matt Spinler93e29322019-09-20 11:16:15 -0500287/**
288 * @brief Reads the "ReasonCode" field out of JSON and converts the string value
289 * such as "0x5555" to a uint16 like 0x5555.
290 *
291 * @param[in] src - The message registry SRC dictionary to read from
292 * @param[in] name - The error name, to use in a trace if things go awry.
293 *
294 * @return uint16_t - The reason code
295 */
296uint16_t getSRCReasonCode(const nlohmann::json& src, const std::string& name);
297
298/**
299 * @brief Reads the "Type" field out of JSON and converts it to the SRC::Type
300 * value.
301 *
302 * @param[in] src - The message registry SRC dictionary to read from
303 * @param[in] name - The error name, to use in a trace if things go awry.
304 *
305 * @return uint8_t - The SRC type value, like 0x11
306 */
307uint8_t getSRCType(const nlohmann::json& src, const std::string& name);
308
309/**
310 * @brief Reads the "Words6To9" field out of JSON and converts it to a map
311 * of the SRC word number to the AdditionalData property field used
312 * to fill it in with.
313 *
314 * @param[in] src - The message registry SRC dictionary to read from
315 * @param[in] name - The error name, to use in a trace if things go awry.
316 *
317 * @return std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
318 */
319std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
320 getSRCHexwordFields(const nlohmann::json& src, const std::string& name);
321
322/**
323 * @brief Reads the "SymptomIDFields" field out of JSON and converts it to
324 * a vector of SRC word numbers.
325 *
326 * @param[in] src - The message registry SRC dictionary to read from
327 * @param[in] name - The error name, to use in a trace if things go awry.
328 *
329 * @return std::optional<std::vector<SRC::WordNum>>
330 */
331std::optional<std::vector<SRC::WordNum>>
332 getSRCSymptomIDFields(const nlohmann::json& src, const std::string& name);
333
334/**
335 * @brief Reads the "ComponentID" field out of JSON and converts it to a
336 * uint16_t like 0xFF00.
337 *
338 * The ComponentID JSON field is only required if the SRC type isn't a BD
339 * BMC SRC, because for those SRCs it can be inferred from the upper byte
340 * of the SRC reasoncode.
341 *
342 * @param[in] srcType - The SRC type
343 * @param[in] reasonCode - The SRC reason code
344 * @param[in] pelEntry - The PEL entry JSON
345 * @param[in] name - The error name, to use in a trace if things go awry.
346 *
347 * @return uin16_t - The component ID, like 0xFF00
348 */
349uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode,
350 const nlohmann::json& pelEntry,
351 const std::string& name);
352
Matt Spinler367144c2019-09-19 15:33:52 -0500353} // namespace helper
354
355} // namespace message
356
357} // namespace pels
358} // namespace openpower