blob: d75c30a1417316f4fbe9f1898d4cf71dae462b1b [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";
16
17/**
Matt Spinler93e29322019-09-20 11:16:15 -050018 * @brief Represents the SRC related fields in the message registry.
19 * It is part of the 'Entry' structure that will be filled in when
20 * an error is looked up in the registry.
21 *
22 * If a field is wrapped by std::optional, it means the field is
23 * optional in the JSON and higher level code knows how to handle it.
24 */
25struct SRC
26{
27 /**
28 * @brief SRC type - The first byte of the ASCII string
29 */
30 uint8_t type;
31
32 /**
33 * @brief The SRC reason code (2nd half of 4B 'ASCII string' word)
34 */
35 uint16_t reasonCode;
36
37 /**
38 * @brief Specifies if the SRC represents a power fault. Optional.
39 */
40 std::optional<bool> powerFault;
41
42 /**
43 * @brief An optional vector of SRC hexword numbers that should be used
44 * along with the SRC ASCII string to build the Symptom ID, which
45 * is a field in the Extended Header section.
46 */
47 using WordNum = size_t;
48 std::optional<std::vector<WordNum>> symptomID;
49
50 /**
51 * @brief Which AdditionalData fields to use to fill in the user defined
52 * SRC hexwords.
53 *
54 * For example, if the AdditionalData event log property contained
55 * "CHIPNUM=42" and this map contained {6, CHIPNUM}, then the code
56 * would put 42 into SRC hexword 6.
57 */
58 using AdditionalDataField = std::string;
59 std::optional<std::map<WordNum, AdditionalDataField>> hexwordADFields;
60
61 SRC() : type(0), reasonCode(0)
62 {
63 }
64};
65
66/**
Matt Spinler367144c2019-09-19 15:33:52 -050067 * @brief Represents a message registry entry, which is used for creating a
68 * PEL from an OpenBMC event log.
69 */
70struct Entry
71{
72 /**
73 * @brief The error name, like "xyz.openbmc_project.Error.Foo".
74 */
75 std::string name;
76
77 /**
Matt Spinler93e29322019-09-20 11:16:15 -050078 * @brief The component ID of the PEL creator.
79 */
80 uint16_t componentID;
81
82 /**
Matt Spinler367144c2019-09-19 15:33:52 -050083 * @brief The PEL subsystem field.
84 */
85 uint8_t subsystem;
86
87 /**
88 * @brief The optional PEL severity field. If not specified, the PEL
89 * will use the severity of the OpenBMC event log.
90 */
91 std::optional<uint8_t> severity;
92
93 /**
94 * @brief The optional severity field to use when in manufacturing tolerance
95 * mode.
96 */
97 std::optional<uint8_t> mfgSeverity;
98
99 /**
100 * @brief The PEL action flags field.
101 */
Matt Spinlere07f9152019-11-01 10:48:36 -0500102 std::optional<uint16_t> actionFlags;
Matt Spinler367144c2019-09-19 15:33:52 -0500103
104 /**
105 * @brief The optional action flags to use instead when in manufacturing
106 * tolerance mode.
107 */
108 std::optional<uint16_t> mfgActionFlags;
109
110 /**
111 * @brief The PEL event type field. If not specified, higher level code
112 * will decide the value.
113 */
114 std::optional<uint8_t> eventType;
115
116 /**
117 * @brief The PEL event scope field. If not specified, higher level code
118 * will decide the value.
119 */
120 std::optional<uint8_t> eventScope;
121
Matt Spinler93e29322019-09-20 11:16:15 -0500122 /**
123 * The SRC related fields.
124 */
125 SRC src;
Matt Spinler367144c2019-09-19 15:33:52 -0500126};
127
128/**
129 * @class Registry
130 *
131 * This class wraps the message registry JSON data and allows one to find
132 * the message registry entry pertaining to the error name.
133 *
134 * So that new registry files can easily be tested, the code will look for
135 * /etc/phosphor-logging/message_registry.json before looking for the real
136 * path.
137 */
138class Registry
139{
140 public:
141 Registry() = delete;
142 ~Registry() = default;
143 Registry(const Registry&) = default;
144 Registry& operator=(const Registry&) = default;
145 Registry(Registry&&) = default;
146 Registry& operator=(Registry&&) = default;
147
148 /**
149 * @brief Constructor
150 * @param[in] registryFile - The path to the file.
151 */
152 explicit Registry(const std::filesystem::path& registryFile) :
153 _registryFile(registryFile)
154 {
155 }
156
157 /**
158 * @brief Find a registry entry based on its error name.
159 *
160 * This function does do some basic sanity checking on the JSON contents,
161 * but there is also an external program that enforces a schema on the
162 * registry JSON that should catch all of these problems ahead of time.
163 *
164 * @param[in] name - The error name, like xyz.openbmc_project.Error.Foo
165 *
166 * @return optional<Entry> A filled in message registry structure if
167 * found, otherwise an empty optional object.
168 */
169 std::optional<Entry> lookup(const std::string& name);
170
171 private:
172 /**
173 * @brief The path to the registry JSON file.
174 */
175 std::filesystem::path _registryFile;
176};
177
178namespace helper
179{
180
181/**
182 * @brief A helper function to get the PEL subsystem value based on
183 * the registry subsystem name.
184 *
185 * @param[in] subsystemName - The registry name for the subsystem
186 *
187 * @return uint8_t The PEL subsystem value
188 */
189uint8_t getSubsystem(const std::string& subsystemName);
190
191/**
192 * @brief A helper function to get the PEL severity value based on
193 * the registry severity name.
194 *
195 * @param[in] severityName - The registry name for the severity
196 *
197 * @return uint8_t The PEL severity value
198 */
199uint8_t getSeverity(const std::string& severityName);
200
201/**
202 * @brief A helper function to get the action flags value based on
203 * the action flag names used in the registry.
204 *
205 * @param[in] flags - The list of flag names from the registry.
206 *
207 * @return uint16_t - The bitfield of flags used in the PEL.
208 */
209uint16_t getActionFlags(const std::vector<std::string>& flags);
210
211/**
212 * @brief A helper function to get the PEL event type value based on
213 * the registry event type name.
214 *
215 * @param[in] eventTypeName - The registry name for the event type
216 *
217 * @return uint8_t The PEL event type value
218 */
219uint8_t getEventType(const std::string& eventTypeName);
220
221/**
222 * @brief A helper function to get the PEL event scope value based on
223 * the registry event scope name.
224 *
225 * @param[in] eventScopeName - The registry name for the event scope
226 *
227 * @return uint8_t The PEL event scope value
228 */
229uint8_t getEventScope(const std::string& eventScopeName);
230
Matt Spinler93e29322019-09-20 11:16:15 -0500231/**
232 * @brief Reads the "ReasonCode" field out of JSON and converts the string value
233 * such as "0x5555" to a uint16 like 0x5555.
234 *
235 * @param[in] src - The message registry SRC dictionary to read from
236 * @param[in] name - The error name, to use in a trace if things go awry.
237 *
238 * @return uint16_t - The reason code
239 */
240uint16_t getSRCReasonCode(const nlohmann::json& src, const std::string& name);
241
242/**
243 * @brief Reads the "Type" field out of JSON and converts it to the SRC::Type
244 * value.
245 *
246 * @param[in] src - The message registry SRC dictionary to read from
247 * @param[in] name - The error name, to use in a trace if things go awry.
248 *
249 * @return uint8_t - The SRC type value, like 0x11
250 */
251uint8_t getSRCType(const nlohmann::json& src, const std::string& name);
252
253/**
254 * @brief Reads the "Words6To9" field out of JSON and converts it to a map
255 * of the SRC word number to the AdditionalData property field used
256 * to fill it in with.
257 *
258 * @param[in] src - The message registry SRC dictionary to read from
259 * @param[in] name - The error name, to use in a trace if things go awry.
260 *
261 * @return std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
262 */
263std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
264 getSRCHexwordFields(const nlohmann::json& src, const std::string& name);
265
266/**
267 * @brief Reads the "SymptomIDFields" field out of JSON and converts it to
268 * a vector of SRC word numbers.
269 *
270 * @param[in] src - The message registry SRC dictionary to read from
271 * @param[in] name - The error name, to use in a trace if things go awry.
272 *
273 * @return std::optional<std::vector<SRC::WordNum>>
274 */
275std::optional<std::vector<SRC::WordNum>>
276 getSRCSymptomIDFields(const nlohmann::json& src, const std::string& name);
277
278/**
279 * @brief Reads the "ComponentID" field out of JSON and converts it to a
280 * uint16_t like 0xFF00.
281 *
282 * The ComponentID JSON field is only required if the SRC type isn't a BD
283 * BMC SRC, because for those SRCs it can be inferred from the upper byte
284 * of the SRC reasoncode.
285 *
286 * @param[in] srcType - The SRC type
287 * @param[in] reasonCode - The SRC reason code
288 * @param[in] pelEntry - The PEL entry JSON
289 * @param[in] name - The error name, to use in a trace if things go awry.
290 *
291 * @return uin16_t - The component ID, like 0xFF00
292 */
293uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode,
294 const nlohmann::json& pelEntry,
295 const std::string& name);
296
Matt Spinler367144c2019-09-19 15:33:52 -0500297} // namespace helper
298
299} // namespace message
300
301} // namespace pels
302} // namespace openpower