summaryrefslogtreecommitdiffstats
path: root/extensions/openpower-pels/registry.hpp
blob: 0a75d8eba04fad9e1b2c34f935473e0c7005ecd8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
#pragma once
#include <filesystem>
#include <nlohmann/json.hpp>
#include <optional>
#include <string>
#include <vector>

namespace openpower
{
namespace pels
{
namespace message
{

constexpr auto registryFileName = "message_registry.json";
enum class LookupType
{
    name = 0,
    reasonCode = 1
};

/**
 * @brief Represents the Documentation related fields in the message registry.
 *        It is part of the 'Entry' structure that will be filled in when
 *        an error is looked up in the registry.
 *
 * If a field is wrapped by std::optional, it means the field is
 * optional in the JSON and higher level code knows how to handle it.
 */
struct DOC
{
    /**
     * @brief Description of error
     */
    std::string description;

    /**
     * @brief Error message field
     */
    std::string message;

    /**
     * @brief An optional vector of SRC word 6-9 to use as the source of the
     *        numeric arguments that will be substituted into any placeholder
     *        in the Message field.
     */
    std::optional<std::vector<std::string>> messageArgSources;
};

/**
 * @brief Represents the SRC related fields in the message registry.
 *        It is part of the 'Entry' structure that will be filled in when
 *        an error is looked up in the registry.
 *
 * If a field is wrapped by std::optional, it means the field is
 * optional in the JSON and higher level code knows how to handle it.
 */
struct SRC
{
    /**
     * @brief SRC type - The first byte of the ASCII string
     */
    uint8_t type;

    /**
     * @brief The SRC reason code (2nd half of 4B 'ASCII string' word)
     */
    uint16_t reasonCode;

    /**
     * @brief Specifies if the SRC represents a power fault.  Optional.
     */
    std::optional<bool> powerFault;

    /**
     * @brief An optional vector of SRC hexword numbers that should be used
     *        along with the SRC ASCII string to build the Symptom ID, which
     *        is a field in the Extended Header section.
     */
    using WordNum = size_t;
    std::optional<std::vector<WordNum>> symptomID;

    /**
     * @brief Which AdditionalData fields to use to fill in the user defined
     *        SRC hexwords.
     *
     * For example, if the AdditionalData event log property contained
     * "CHIPNUM=42" and this map contained {6, CHIPNUM}, then the code
     * would put 42 into SRC hexword 6.
     */
    using AdditionalDataField = std::string;
    std::optional<std::map<WordNum, AdditionalDataField>> hexwordADFields;

    SRC() : type(0), reasonCode(0)
    {
    }
};

/**
 * @brief Represents a message registry entry, which is used for creating a
 *        PEL from an OpenBMC event log.
 */
struct Entry
{
    /**
     * @brief The error name, like "xyz.openbmc_project.Error.Foo".
     */
    std::string name;

    /**
     * @brief The component ID of the PEL creator.
     */
    uint16_t componentID;

    /**
     * @brief The PEL subsystem field.
     */
    uint8_t subsystem;

    /**
     * @brief The optional PEL severity field.  If not specified, the PEL
     *        will use the severity of the OpenBMC event log.
     */
    std::optional<uint8_t> severity;

    /**
     * @brief The optional severity field to use when in manufacturing tolerance
     *        mode.
     */
    std::optional<uint8_t> mfgSeverity;

    /**
     * @brief The PEL action flags field.
     */
    std::optional<uint16_t> actionFlags;

    /**
     * @brief  The optional action flags to use instead when in manufacturing
     * tolerance mode.
     */
    std::optional<uint16_t> mfgActionFlags;

    /**
     * @brief The PEL event type field.  If not specified, higher level code
     *        will decide the value.
     */
    std::optional<uint8_t> eventType;

    /**
     * @brief The PEL event scope field.  If not specified, higher level code
     *        will decide the value.
     */
    std::optional<uint8_t> eventScope;

    /**
     * The SRC related fields.
     */
    SRC src;

    /**
     * The Documentation related fields.
     */
    DOC doc;
};

/**
 * @class Registry
 *
 * This class wraps the message registry JSON data and allows one to find
 * the message registry entry pertaining to the error name.
 *
 * So that new registry files can easily be tested, the code will look for
 * /etc/phosphor-logging/message_registry.json before looking for the real
 * path.
 */
class Registry
{
  public:
    Registry() = delete;
    ~Registry() = default;
    Registry(const Registry&) = default;
    Registry& operator=(const Registry&) = default;
    Registry(Registry&&) = default;
    Registry& operator=(Registry&&) = default;

    /**
     * @brief Constructor
     * @param[in] registryFile - The path to the file.
     */
    explicit Registry(const std::filesystem::path& registryFile) :
        _registryFile(registryFile)
    {
    }

    /**
     * @brief Find a registry entry based on its error name or reason code.
     *
     * This function does do some basic sanity checking on the JSON contents,
     * but there is also an external program that enforces a schema on the
     * registry JSON that should catch all of these problems ahead of time.
     *
     * @param[in] name - The error name, like xyz.openbmc_project.Error.Foo
     *                 - OR
     *                 - The reason code, like 0x1001
     * @param[in] type - LookupType enum value
     * @param[in] toCache - boolean to cache registry in memory
     * @return optional<Entry> A filled in message registry structure if
     *                         found, otherwise an empty optional object.
     */
    std::optional<Entry> lookup(const std::string& name, LookupType type,
                                bool toCache = false);

  private:
    /**
     * @brief Parse message registry file using nlohmann::json
     * @param[in] registryFile - The message registry JSON file
     * @return optional<nlohmann::json> The full message registry object or an
     *                                  empty optional object upon failure.
     */
    std::optional<nlohmann::json>
        readRegistry(const std::filesystem::path& registryFile);

    /**
     * @brief The path to the registry JSON file.
     */
    std::filesystem::path _registryFile;

    /**
     * @brief The full message registry object.
     */
    std::optional<nlohmann::json> _registry;
};

namespace helper
{

/**
 * @brief A helper function to get the PEL subsystem value based on
 *        the registry subsystem name.
 *
 * @param[in] subsystemName - The registry name for the subsystem
 *
 * @return uint8_t The PEL subsystem value
 */
uint8_t getSubsystem(const std::string& subsystemName);

/**
 * @brief A helper function to get the PEL severity value based on
 *        the registry severity name.
 *
 * @param[in] severityName - The registry name for the severity
 *
 * @return uint8_t The PEL severity value
 */
uint8_t getSeverity(const std::string& severityName);

/**
 * @brief A helper function to get the action flags value based on
 *        the action flag names used in the registry.
 *
 * @param[in] flags - The list of flag names from the registry.
 *
 * @return uint16_t - The bitfield of flags used in the PEL.
 */
uint16_t getActionFlags(const std::vector<std::string>& flags);

/**
 * @brief A helper function to get the PEL event type value based on
 *        the registry event type name.
 *
 * @param[in] eventTypeName - The registry name for the event type
 *
 * @return uint8_t The PEL event type value
 */
uint8_t getEventType(const std::string& eventTypeName);

/**
 * @brief A helper function to get the PEL event scope value based on
 *        the registry event scope name.
 *
 * @param[in] eventScopeName - The registry name for the event scope
 *
 * @return uint8_t The PEL event scope value
 */
uint8_t getEventScope(const std::string& eventScopeName);

/**
 * @brief Reads the "ReasonCode" field out of JSON and converts the string value
 *        such as "0x5555" to a uint16 like 0x5555.
 *
 * @param[in] src - The message registry SRC dictionary to read from
 * @param[in] name - The error name, to use in a trace if things go awry.
 *
 * @return uint16_t - The reason code
 */
uint16_t getSRCReasonCode(const nlohmann::json& src, const std::string& name);

/**
 * @brief Reads the "Type" field out of JSON and converts it to the SRC::Type
 *        value.
 *
 * @param[in] src - The message registry SRC dictionary to read from
 * @param[in] name - The error name, to use in a trace if things go awry.
 *
 * @return uint8_t - The SRC type value, like 0x11
 */
uint8_t getSRCType(const nlohmann::json& src, const std::string& name);

/**
 * @brief Reads the "Words6To9" field out of JSON and converts it to a map
 *        of the SRC word number to the AdditionalData property field used
 *        to fill it in with.
 *
 * @param[in] src - The message registry SRC dictionary to read from
 * @param[in] name - The error name, to use in a trace if things go awry.
 *
 * @return std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
 */
std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
    getSRCHexwordFields(const nlohmann::json& src, const std::string& name);

/**
 * @brief Reads the "SymptomIDFields" field out of JSON and converts it to
 *        a vector of SRC word numbers.
 *
 * @param[in] src - The message registry SRC dictionary to read from
 * @param[in] name - The error name, to use in a trace if things go awry.
 *
 * @return std::optional<std::vector<SRC::WordNum>>
 */
std::optional<std::vector<SRC::WordNum>>
    getSRCSymptomIDFields(const nlohmann::json& src, const std::string& name);

/**
 * @brief Reads the "ComponentID" field out of JSON and converts it to a
 *        uint16_t like 0xFF00.
 *
 * The ComponentID JSON field is only required if the SRC type isn't a BD
 * BMC SRC, because for those SRCs it can be inferred from the upper byte
 * of the SRC reasoncode.
 *
 * @param[in] srcType - The SRC type
 * @param[in] reasonCode - The SRC reason code
 * @param[in] pelEntry - The PEL entry JSON
 * @param[in] name - The error name, to use in a trace if things go awry.
 *
 * @return uin16_t - The component ID, like 0xFF00
 */
uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode,
                        const nlohmann::json& pelEntry,
                        const std::string& name);

} // namespace helper

} // namespace message

} // namespace pels
} // namespace openpower
OpenPOWER on IntegriCloud