xref: /openbmc/phosphor-logging/extensions/openpower-pels/src.cpp (revision 7b92372da378fa751c6596e5ea93936f61e61022)
1711d51d8SMatt Spinler /**
2711d51d8SMatt Spinler  * Copyright © 2019 IBM Corporation
3711d51d8SMatt Spinler  *
4711d51d8SMatt Spinler  * Licensed under the Apache License, Version 2.0 (the "License");
5711d51d8SMatt Spinler  * you may not use this file except in compliance with the License.
6711d51d8SMatt Spinler  * You may obtain a copy of the License at
7711d51d8SMatt Spinler  *
8711d51d8SMatt Spinler  *     http://www.apache.org/licenses/LICENSE-2.0
9711d51d8SMatt Spinler  *
10711d51d8SMatt Spinler  * Unless required by applicable law or agreed to in writing, software
11711d51d8SMatt Spinler  * distributed under the License is distributed on an "AS IS" BASIS,
12711d51d8SMatt Spinler  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13711d51d8SMatt Spinler  * See the License for the specific language governing permissions and
14711d51d8SMatt Spinler  * limitations under the License.
15711d51d8SMatt Spinler  */
16f9bae185SMatt Spinler #include "src.hpp"
17f9bae185SMatt Spinler 
18717de428SMatt Spinler #include "device_callouts.hpp"
190f717e10SHarisuddin Mohamed Isa #include "json_utils.hpp"
200f717e10SHarisuddin Mohamed Isa #include "paths.hpp"
210f717e10SHarisuddin Mohamed Isa #include "pel_values.hpp"
22c8d6cc61SHarisuddin Mohamed Isa #ifdef PELTOOL
23c8d6cc61SHarisuddin Mohamed Isa #include <Python.h>
240f717e10SHarisuddin Mohamed Isa 
25c8d6cc61SHarisuddin Mohamed Isa #include <nlohmann/json.hpp>
262544b419SPatrick Williams 
27c8d6cc61SHarisuddin Mohamed Isa #include <sstream>
28c8d6cc61SHarisuddin Mohamed Isa #endif
290bacc8efSMatt Spinler #include <phosphor-logging/lg2.hpp>
30f9bae185SMatt Spinler 
311aa90d49SJayanth Othayoth #include <format>
321aa90d49SJayanth Othayoth 
33f9bae185SMatt Spinler namespace openpower
34f9bae185SMatt Spinler {
35f9bae185SMatt Spinler namespace pels
36f9bae185SMatt Spinler {
370f717e10SHarisuddin Mohamed Isa namespace pv = openpower::pels::pel_values;
380f717e10SHarisuddin Mohamed Isa namespace rg = openpower::pels::message;
3985f61a63SMatt Spinler using namespace std::string_literals;
40f9bae185SMatt Spinler 
41075e5bafSMatt Spinler constexpr size_t ccinSize = 4;
42075e5bafSMatt Spinler 
43c8d6cc61SHarisuddin Mohamed Isa #ifdef PELTOOL
44516935a5SSumit Kumar using orderedJSON = nlohmann::ordered_json;
45c8d6cc61SHarisuddin Mohamed Isa 
pyDecRef(PyObject * pyObj)46c8d6cc61SHarisuddin Mohamed Isa void pyDecRef(PyObject* pyObj)
47c8d6cc61SHarisuddin Mohamed Isa {
48c8d6cc61SHarisuddin Mohamed Isa     Py_XDECREF(pyObj);
49c8d6cc61SHarisuddin Mohamed Isa }
50c8d6cc61SHarisuddin Mohamed Isa 
51c8d6cc61SHarisuddin Mohamed Isa /**
52c8d6cc61SHarisuddin Mohamed Isa  * @brief Returns a JSON string to append to SRC section.
53c8d6cc61SHarisuddin Mohamed Isa  *
54c8d6cc61SHarisuddin Mohamed Isa  * The returning string will contain a JSON object, but without
55c8d6cc61SHarisuddin Mohamed Isa  * the outer {}.  If the input JSON isn't a JSON object (dict), then
56c8d6cc61SHarisuddin Mohamed Isa  * one will be created with the input added to a 'SRC Details' key.
57c8d6cc61SHarisuddin Mohamed Isa  *
58c8d6cc61SHarisuddin Mohamed Isa  * @param[in] json - The JSON to convert to a string
59c8d6cc61SHarisuddin Mohamed Isa  *
60c8d6cc61SHarisuddin Mohamed Isa  * @return std::string - The JSON string
61c8d6cc61SHarisuddin Mohamed Isa  */
prettyJSON(const orderedJSON & json)62516935a5SSumit Kumar std::string prettyJSON(const orderedJSON& json)
63c8d6cc61SHarisuddin Mohamed Isa {
64516935a5SSumit Kumar     orderedJSON output;
65c8d6cc61SHarisuddin Mohamed Isa     if (!json.is_object())
66c8d6cc61SHarisuddin Mohamed Isa     {
67c8d6cc61SHarisuddin Mohamed Isa         output["SRC Details"] = json;
68c8d6cc61SHarisuddin Mohamed Isa     }
69c8d6cc61SHarisuddin Mohamed Isa     else
70c8d6cc61SHarisuddin Mohamed Isa     {
71c8d6cc61SHarisuddin Mohamed Isa         for (const auto& [key, value] : json.items())
72c8d6cc61SHarisuddin Mohamed Isa         {
7369c1827aSHarisuddin Mohamed Isa             output["SRC Details"][key] = value;
74c8d6cc61SHarisuddin Mohamed Isa         }
75c8d6cc61SHarisuddin Mohamed Isa     }
76c8d6cc61SHarisuddin Mohamed Isa 
77c8d6cc61SHarisuddin Mohamed Isa     // Let nlohmann do the pretty printing.
78c8d6cc61SHarisuddin Mohamed Isa     std::stringstream stream;
79c8d6cc61SHarisuddin Mohamed Isa     stream << std::setw(4) << output;
80c8d6cc61SHarisuddin Mohamed Isa 
81c8d6cc61SHarisuddin Mohamed Isa     auto jsonString = stream.str();
82c8d6cc61SHarisuddin Mohamed Isa 
83c8d6cc61SHarisuddin Mohamed Isa     // Now it looks like:
84c8d6cc61SHarisuddin Mohamed Isa     // {
85c8d6cc61SHarisuddin Mohamed Isa     //     "Key": "Value",
86c8d6cc61SHarisuddin Mohamed Isa     //     ...
87c8d6cc61SHarisuddin Mohamed Isa     // }
88c8d6cc61SHarisuddin Mohamed Isa 
89c8d6cc61SHarisuddin Mohamed Isa     // Replace the { and the following newline, and the } and its
90c8d6cc61SHarisuddin Mohamed Isa     // preceeding newline.
91c8d6cc61SHarisuddin Mohamed Isa     jsonString.erase(0, 2);
92c8d6cc61SHarisuddin Mohamed Isa 
93c8d6cc61SHarisuddin Mohamed Isa     auto pos = jsonString.find_last_of('}');
94c8d6cc61SHarisuddin Mohamed Isa     jsonString.erase(pos - 1);
95c8d6cc61SHarisuddin Mohamed Isa 
96c8d6cc61SHarisuddin Mohamed Isa     return jsonString;
97c8d6cc61SHarisuddin Mohamed Isa }
98c8d6cc61SHarisuddin Mohamed Isa 
99c8d6cc61SHarisuddin Mohamed Isa /**
100c8d6cc61SHarisuddin Mohamed Isa  * @brief Call Python modules to parse the data into a JSON string
101c8d6cc61SHarisuddin Mohamed Isa  *
102c8d6cc61SHarisuddin Mohamed Isa  * The module to call is based on the Creator Subsystem ID under the namespace
103c8d6cc61SHarisuddin Mohamed Isa  * "srcparsers". For example: "srcparsers.xsrc.xsrc" where "x" is the Creator
104c8d6cc61SHarisuddin Mohamed Isa  * Subsystem ID in ASCII lowercase.
105c8d6cc61SHarisuddin Mohamed Isa  *
106c8d6cc61SHarisuddin Mohamed Isa  * All modules must provide the following:
107c8d6cc61SHarisuddin Mohamed Isa  * Function: parseSRCToJson
108c8d6cc61SHarisuddin Mohamed Isa  * Argument list:
109c8d6cc61SHarisuddin Mohamed Isa  *    1. (str) ASCII string (Hex Word 1)
110c8d6cc61SHarisuddin Mohamed Isa  *    2. (str) Hex Word 2
111c8d6cc61SHarisuddin Mohamed Isa  *    3. (str) Hex Word 3
112c8d6cc61SHarisuddin Mohamed Isa  *    4. (str) Hex Word 4
113c8d6cc61SHarisuddin Mohamed Isa  *    5. (str) Hex Word 5
114c8d6cc61SHarisuddin Mohamed Isa  *    6. (str) Hex Word 6
115c8d6cc61SHarisuddin Mohamed Isa  *    7. (str) Hex Word 7
116c8d6cc61SHarisuddin Mohamed Isa  *    8. (str) Hex Word 8
117c8d6cc61SHarisuddin Mohamed Isa  *    9. (str) Hex Word 9
118c8d6cc61SHarisuddin Mohamed Isa  *-Return data:
119c8d6cc61SHarisuddin Mohamed Isa  *    1. (str) JSON string
120c8d6cc61SHarisuddin Mohamed Isa  *
121c8d6cc61SHarisuddin Mohamed Isa  * @param[in] hexwords - Vector of strings of Hexwords 1-9
122c8d6cc61SHarisuddin Mohamed Isa  * @param[in] creatorID - The creatorID from the Private Header section
123c8d6cc61SHarisuddin Mohamed Isa  * @return std::optional<std::string> - The JSON string if it could be created,
124c8d6cc61SHarisuddin Mohamed Isa  *                                      else std::nullopt
125c8d6cc61SHarisuddin Mohamed Isa  */
getPythonJSON(std::vector<std::string> & hexwords,uint8_t creatorID)126c8d6cc61SHarisuddin Mohamed Isa std::optional<std::string> getPythonJSON(std::vector<std::string>& hexwords,
127c8d6cc61SHarisuddin Mohamed Isa                                          uint8_t creatorID)
128c8d6cc61SHarisuddin Mohamed Isa {
129be952d2eSMatt Spinler     PyObject *pName, *pModule, *eType, *eValue, *eTraceback;
130c8d6cc61SHarisuddin Mohamed Isa     std::string pErrStr;
131c8d6cc61SHarisuddin Mohamed Isa     std::string module = getNumberString("%c", tolower(creatorID)) + "src";
132c8d6cc61SHarisuddin Mohamed Isa     pName = PyUnicode_FromString(
133c8d6cc61SHarisuddin Mohamed Isa         std::string("srcparsers." + module + "." + module).c_str());
134c8d6cc61SHarisuddin Mohamed Isa     std::unique_ptr<PyObject, decltype(&pyDecRef)> modNamePtr(pName, &pyDecRef);
135c8d6cc61SHarisuddin Mohamed Isa     pModule = PyImport_Import(pName);
136c8d6cc61SHarisuddin Mohamed Isa     if (pModule == NULL)
137c8d6cc61SHarisuddin Mohamed Isa     {
138c8d6cc61SHarisuddin Mohamed Isa         pErrStr = "No error string found";
139c8d6cc61SHarisuddin Mohamed Isa         PyErr_Fetch(&eType, &eValue, &eTraceback);
14069c1827aSHarisuddin Mohamed Isa         if (eType)
14169c1827aSHarisuddin Mohamed Isa         {
14269c1827aSHarisuddin Mohamed Isa             Py_XDECREF(eType);
14369c1827aSHarisuddin Mohamed Isa         }
14469c1827aSHarisuddin Mohamed Isa         if (eTraceback)
14569c1827aSHarisuddin Mohamed Isa         {
14669c1827aSHarisuddin Mohamed Isa             Py_XDECREF(eTraceback);
14769c1827aSHarisuddin Mohamed Isa         }
148c8d6cc61SHarisuddin Mohamed Isa         if (eValue)
149c8d6cc61SHarisuddin Mohamed Isa         {
150c8d6cc61SHarisuddin Mohamed Isa             PyObject* pStr = PyObject_Str(eValue);
15169c1827aSHarisuddin Mohamed Isa             Py_XDECREF(eValue);
152c8d6cc61SHarisuddin Mohamed Isa             if (pStr)
153c8d6cc61SHarisuddin Mohamed Isa             {
154c8d6cc61SHarisuddin Mohamed Isa                 pErrStr = PyUnicode_AsUTF8(pStr);
155c8d6cc61SHarisuddin Mohamed Isa                 Py_XDECREF(pStr);
156c8d6cc61SHarisuddin Mohamed Isa             }
157c8d6cc61SHarisuddin Mohamed Isa         }
15869c1827aSHarisuddin Mohamed Isa     }
159c8d6cc61SHarisuddin Mohamed Isa     else
160c8d6cc61SHarisuddin Mohamed Isa     {
161075c7923SPatrick Williams         std::unique_ptr<PyObject, decltype(&pyDecRef)> modPtr(
162075c7923SPatrick Williams             pModule, &pyDecRef);
16369c1827aSHarisuddin Mohamed Isa         std::string funcToCall = "parseSRCToJson";
164be952d2eSMatt Spinler         PyObject* pKey = PyUnicode_FromString(funcToCall.c_str());
16569c1827aSHarisuddin Mohamed Isa         std::unique_ptr<PyObject, decltype(&pyDecRef)> keyPtr(pKey, &pyDecRef);
166be952d2eSMatt Spinler         PyObject* pDict = PyModule_GetDict(pModule);
16769c1827aSHarisuddin Mohamed Isa         Py_INCREF(pDict);
16869c1827aSHarisuddin Mohamed Isa         if (!PyDict_Contains(pDict, pKey))
16969c1827aSHarisuddin Mohamed Isa         {
17069c1827aSHarisuddin Mohamed Isa             Py_DECREF(pDict);
1710bacc8efSMatt Spinler             lg2::error(
1720bacc8efSMatt Spinler                 "Python module error.  Function missing: {FUNC}, SRC = {SRC}, module = {MODULE}",
1730bacc8efSMatt Spinler                 "FUNC", funcToCall, "SRC", hexwords.front(), "MODULE", module);
17469c1827aSHarisuddin Mohamed Isa             return std::nullopt;
17569c1827aSHarisuddin Mohamed Isa         }
176be952d2eSMatt Spinler         PyObject* pFunc = PyDict_GetItemString(pDict, funcToCall.c_str());
17769c1827aSHarisuddin Mohamed Isa         Py_DECREF(pDict);
17869c1827aSHarisuddin Mohamed Isa         Py_INCREF(pFunc);
179c8d6cc61SHarisuddin Mohamed Isa         if (PyCallable_Check(pFunc))
180c8d6cc61SHarisuddin Mohamed Isa         {
181be952d2eSMatt Spinler             PyObject* pArgs = PyTuple_New(9);
182075c7923SPatrick Williams             std::unique_ptr<PyObject, decltype(&pyDecRef)> argPtr(
183075c7923SPatrick Williams                 pArgs, &pyDecRef);
184c8d6cc61SHarisuddin Mohamed Isa             for (size_t i = 0; i < 9; i++)
185c8d6cc61SHarisuddin Mohamed Isa             {
186c1984039SMatt Spinler                 std::string arg{"00000000"};
187c8d6cc61SHarisuddin Mohamed Isa                 if (i < hexwords.size())
188c8d6cc61SHarisuddin Mohamed Isa                 {
189c1984039SMatt Spinler                     arg = hexwords[i];
190c8d6cc61SHarisuddin Mohamed Isa                 }
191c1984039SMatt Spinler                 PyTuple_SetItem(pArgs, i, Py_BuildValue("s", arg.c_str()));
192c8d6cc61SHarisuddin Mohamed Isa             }
193be952d2eSMatt Spinler             PyObject* pResult = PyObject_CallObject(pFunc, pArgs);
19469c1827aSHarisuddin Mohamed Isa             Py_DECREF(pFunc);
195c8d6cc61SHarisuddin Mohamed Isa             if (pResult)
196c8d6cc61SHarisuddin Mohamed Isa             {
19769c1827aSHarisuddin Mohamed Isa                 std::unique_ptr<PyObject, decltype(&pyDecRef)> resPtr(
19869c1827aSHarisuddin Mohamed Isa                     pResult, &pyDecRef);
199075c7923SPatrick Williams                 PyObject* pBytes =
200075c7923SPatrick Williams                     PyUnicode_AsEncodedString(pResult, "utf-8", "~E~");
201c8d6cc61SHarisuddin Mohamed Isa                 std::unique_ptr<PyObject, decltype(&pyDecRef)> pyBytePtr(
202c8d6cc61SHarisuddin Mohamed Isa                     pBytes, &pyDecRef);
203c8d6cc61SHarisuddin Mohamed Isa                 const char* output = PyBytes_AS_STRING(pBytes);
204c8d6cc61SHarisuddin Mohamed Isa                 try
205c8d6cc61SHarisuddin Mohamed Isa                 {
206bb1c1d5cSMatt Spinler                     orderedJSON json = orderedJSON::parse(output);
20769c1827aSHarisuddin Mohamed Isa                     if ((json.is_object() && !json.empty()) ||
20869c1827aSHarisuddin Mohamed Isa                         (json.is_array() && json.size() > 0) ||
20969c1827aSHarisuddin Mohamed Isa                         (json.is_string() && json != ""))
21069c1827aSHarisuddin Mohamed Isa                     {
211c8d6cc61SHarisuddin Mohamed Isa                         return prettyJSON(json);
212c8d6cc61SHarisuddin Mohamed Isa                     }
21369c1827aSHarisuddin Mohamed Isa                 }
21466491c61SPatrick Williams                 catch (const std::exception& e)
215c8d6cc61SHarisuddin Mohamed Isa                 {
2160bacc8efSMatt Spinler                     lg2::error(
2170bacc8efSMatt Spinler                         "Bad JSON from parser. Error = {ERROR}, SRC = {SRC}, module = {MODULE}",
2180bacc8efSMatt Spinler                         "ERROR", e, "SRC", hexwords.front(), "MODULE", module);
219c8d6cc61SHarisuddin Mohamed Isa                     return std::nullopt;
220c8d6cc61SHarisuddin Mohamed Isa                 }
221c8d6cc61SHarisuddin Mohamed Isa             }
222c8d6cc61SHarisuddin Mohamed Isa             else
223c8d6cc61SHarisuddin Mohamed Isa             {
224c8d6cc61SHarisuddin Mohamed Isa                 pErrStr = "No error string found";
225c8d6cc61SHarisuddin Mohamed Isa                 PyErr_Fetch(&eType, &eValue, &eTraceback);
22669c1827aSHarisuddin Mohamed Isa                 if (eType)
22769c1827aSHarisuddin Mohamed Isa                 {
22869c1827aSHarisuddin Mohamed Isa                     Py_XDECREF(eType);
22969c1827aSHarisuddin Mohamed Isa                 }
23069c1827aSHarisuddin Mohamed Isa                 if (eTraceback)
23169c1827aSHarisuddin Mohamed Isa                 {
23269c1827aSHarisuddin Mohamed Isa                     Py_XDECREF(eTraceback);
23369c1827aSHarisuddin Mohamed Isa                 }
234c8d6cc61SHarisuddin Mohamed Isa                 if (eValue)
235c8d6cc61SHarisuddin Mohamed Isa                 {
236c8d6cc61SHarisuddin Mohamed Isa                     PyObject* pStr = PyObject_Str(eValue);
23769c1827aSHarisuddin Mohamed Isa                     Py_XDECREF(eValue);
238c8d6cc61SHarisuddin Mohamed Isa                     if (pStr)
239c8d6cc61SHarisuddin Mohamed Isa                     {
240c8d6cc61SHarisuddin Mohamed Isa                         pErrStr = PyUnicode_AsUTF8(pStr);
241c8d6cc61SHarisuddin Mohamed Isa                         Py_XDECREF(pStr);
242c8d6cc61SHarisuddin Mohamed Isa                     }
243c8d6cc61SHarisuddin Mohamed Isa                 }
244c8d6cc61SHarisuddin Mohamed Isa             }
245c8d6cc61SHarisuddin Mohamed Isa         }
24669c1827aSHarisuddin Mohamed Isa     }
247c8d6cc61SHarisuddin Mohamed Isa     if (!pErrStr.empty())
248c8d6cc61SHarisuddin Mohamed Isa     {
2490bacc8efSMatt Spinler         lg2::debug("Python exception thrown by parser. Error = {ERROR}, "
2500bacc8efSMatt Spinler                    "SRC = {SRC}, module = {MODULE}",
2510bacc8efSMatt Spinler                    "ERROR", pErrStr, "SRC", hexwords.front(), "MODULE", module);
252c8d6cc61SHarisuddin Mohamed Isa     }
253c8d6cc61SHarisuddin Mohamed Isa     return std::nullopt;
254c8d6cc61SHarisuddin Mohamed Isa }
255c8d6cc61SHarisuddin Mohamed Isa #endif
256c8d6cc61SHarisuddin Mohamed Isa 
unflatten(Stream & stream)257f9bae185SMatt Spinler void SRC::unflatten(Stream& stream)
258f9bae185SMatt Spinler {
259f9bae185SMatt Spinler     stream >> _header >> _version >> _flags >> _reserved1B >> _wordCount >>
260f9bae185SMatt Spinler         _reserved2B >> _size;
261f9bae185SMatt Spinler 
262f9bae185SMatt Spinler     for (auto& word : _hexData)
263f9bae185SMatt Spinler     {
264f9bae185SMatt Spinler         stream >> word;
265f9bae185SMatt Spinler     }
266f9bae185SMatt Spinler 
267f9bae185SMatt Spinler     _asciiString = std::make_unique<src::AsciiString>(stream);
268f9bae185SMatt Spinler 
269f9bae185SMatt Spinler     if (hasAdditionalSections())
270f9bae185SMatt Spinler     {
271f9bae185SMatt Spinler         // The callouts section is currently the only extra subsection type
272f9bae185SMatt Spinler         _callouts = std::make_unique<src::Callouts>(stream);
273f9bae185SMatt Spinler     }
274f9bae185SMatt Spinler }
275f9bae185SMatt Spinler 
flatten(Stream & stream) const2760688545bSMatt Spinler void SRC::flatten(Stream& stream) const
277f9bae185SMatt Spinler {
278f9bae185SMatt Spinler     stream << _header << _version << _flags << _reserved1B << _wordCount
279f9bae185SMatt Spinler            << _reserved2B << _size;
280f9bae185SMatt Spinler 
281f9bae185SMatt Spinler     for (auto& word : _hexData)
282f9bae185SMatt Spinler     {
283f9bae185SMatt Spinler         stream << word;
284f9bae185SMatt Spinler     }
285f9bae185SMatt Spinler 
286f9bae185SMatt Spinler     _asciiString->flatten(stream);
287f9bae185SMatt Spinler 
288f9bae185SMatt Spinler     if (_callouts)
289f9bae185SMatt Spinler     {
290f9bae185SMatt Spinler         _callouts->flatten(stream);
291f9bae185SMatt Spinler     }
292f9bae185SMatt Spinler }
293f9bae185SMatt Spinler 
SRC(Stream & pel)294f9bae185SMatt Spinler SRC::SRC(Stream& pel)
295f9bae185SMatt Spinler {
296f9bae185SMatt Spinler     try
297f9bae185SMatt Spinler     {
298f9bae185SMatt Spinler         unflatten(pel);
299f9bae185SMatt Spinler         validate();
300f9bae185SMatt Spinler     }
301f9bae185SMatt Spinler     catch (const std::exception& e)
302f9bae185SMatt Spinler     {
3030bacc8efSMatt Spinler         lg2::error("Cannot unflatten SRC, error = {ERROR}", "ERROR", e);
304f9bae185SMatt Spinler         _valid = false;
305f9bae185SMatt Spinler     }
306f9bae185SMatt Spinler }
307f9bae185SMatt Spinler 
SRC(const message::Entry & regEntry,const AdditionalData & additionalData,const nlohmann::json & jsonCallouts,const DataInterfaceBase & dataIface)308075e5bafSMatt Spinler SRC::SRC(const message::Entry& regEntry, const AdditionalData& additionalData,
3095a90a95bSMatt Spinler          const nlohmann::json& jsonCallouts, const DataInterfaceBase& dataIface)
310bd716f00SMatt Spinler {
311bd716f00SMatt Spinler     _header.id = static_cast<uint16_t>(SectionID::primarySRC);
312bd716f00SMatt Spinler     _header.version = srcSectionVersion;
313bd716f00SMatt Spinler     _header.subType = srcSectionSubtype;
314bd716f00SMatt Spinler     _header.componentID = regEntry.componentID;
315bd716f00SMatt Spinler 
316bd716f00SMatt Spinler     _version = srcVersion;
317bd716f00SMatt Spinler 
318bd716f00SMatt Spinler     _flags = 0;
319f3702bb3SVijay Lobo 
320bd716f00SMatt Spinler     _reserved1B = 0;
321bd716f00SMatt Spinler 
322bd716f00SMatt Spinler     _wordCount = numSRCHexDataWords + 1;
323bd716f00SMatt Spinler 
324bd716f00SMatt Spinler     _reserved2B = 0;
325bd716f00SMatt Spinler 
326bd716f00SMatt Spinler     // There are multiple fields encoded in the hex data words.
327bd716f00SMatt Spinler     std::for_each(_hexData.begin(), _hexData.end(),
328bd716f00SMatt Spinler                   [](auto& word) { word = 0; });
3297c619181SMatt Spinler 
3307c619181SMatt Spinler     // Hex Word 2 Nibbles:
3317c619181SMatt Spinler     //   MIGVEPFF
3327c619181SMatt Spinler     //   M: Partition dump status = 0
3337c619181SMatt Spinler     //   I: System boot state = TODO
3347c619181SMatt Spinler     //   G: Partition Boot type = 0
3359d43a727SSumit Kumar     //   V: BMC dump status
3367c619181SMatt Spinler     //   E: Platform boot mode = 0 (side = temporary, speed = fast)
3379d43a727SSumit Kumar     //   P: Platform dump status
3387c619181SMatt Spinler     //  FF: SRC format, set below
3397c619181SMatt Spinler 
340875b6c7bSVijay Lobo     setProgressCode(dataIface);
341bd716f00SMatt Spinler     setBMCFormat();
342bd716f00SMatt Spinler     setBMCPosition();
343075e5bafSMatt Spinler     setMotherboardCCIN(dataIface);
344075e5bafSMatt Spinler 
345da5b76b2SMatt Spinler     if (regEntry.src.checkstopFlag)
346da5b76b2SMatt Spinler     {
347da5b76b2SMatt Spinler         setErrorStatusFlag(ErrorStatusFlags::hwCheckstop);
348da5b76b2SMatt Spinler     }
349da5b76b2SMatt Spinler 
3503fe93e96SMatt Spinler     if (regEntry.src.deconfigFlag)
3513fe93e96SMatt Spinler     {
3523fe93e96SMatt Spinler         setErrorStatusFlag(ErrorStatusFlags::deconfigured);
3533fe93e96SMatt Spinler     }
3543fe93e96SMatt Spinler 
355bd716f00SMatt Spinler     // Fill in the last 4 words from the AdditionalData property contents.
356bd716f00SMatt Spinler     setUserDefinedHexWords(regEntry, additionalData);
357bd716f00SMatt Spinler 
358bd716f00SMatt Spinler     _asciiString = std::make_unique<src::AsciiString>(regEntry);
359bd716f00SMatt Spinler 
36050bfa69aSSumit Kumar     // Check for additional data - PEL_SUBSYSTEM
36150bfa69aSSumit Kumar     auto ss = additionalData.getValue("PEL_SUBSYSTEM");
36250bfa69aSSumit Kumar     if (ss)
36350bfa69aSSumit Kumar     {
36450bfa69aSSumit Kumar         auto eventSubsystem = std::stoul(*ss, NULL, 16);
365075c7923SPatrick Williams         std::string subsystem =
366075c7923SPatrick Williams             pv::getValue(eventSubsystem, pel_values::subsystemValues);
36750bfa69aSSumit Kumar         if (subsystem == "invalid")
36850bfa69aSSumit Kumar         {
3690bacc8efSMatt Spinler             lg2::warning("SRC: Invalid SubSystem value: {VAL}", "VAL", lg2::hex,
3700bacc8efSMatt Spinler                          eventSubsystem);
37150bfa69aSSumit Kumar         }
37250bfa69aSSumit Kumar         else
37350bfa69aSSumit Kumar         {
37450bfa69aSSumit Kumar             _asciiString->setByte(2, eventSubsystem);
37550bfa69aSSumit Kumar         }
37650bfa69aSSumit Kumar     }
37750bfa69aSSumit Kumar 
3785a90a95bSMatt Spinler     addCallouts(regEntry, additionalData, jsonCallouts, dataIface);
379bd716f00SMatt Spinler 
380bd716f00SMatt Spinler     _size = baseSRCSize;
381bd716f00SMatt Spinler     _size += _callouts ? _callouts->flattenedSize() : 0;
382bd716f00SMatt Spinler     _header.size = Section::flattenedSize() + _size;
383bd716f00SMatt Spinler 
384bd716f00SMatt Spinler     _valid = true;
385bd716f00SMatt Spinler }
386bd716f00SMatt Spinler 
setUserDefinedHexWords(const message::Entry & regEntry,const AdditionalData & ad)387bd716f00SMatt Spinler void SRC::setUserDefinedHexWords(const message::Entry& regEntry,
388bd716f00SMatt Spinler                                  const AdditionalData& ad)
389bd716f00SMatt Spinler {
390bd716f00SMatt Spinler     if (!regEntry.src.hexwordADFields)
391bd716f00SMatt Spinler     {
392bd716f00SMatt Spinler         return;
393bd716f00SMatt Spinler     }
394bd716f00SMatt Spinler 
3951a1b0dfbSHarisuddin Mohamed Isa     // Save the AdditionalData value corresponding to the first element of
3961a1b0dfbSHarisuddin Mohamed Isa     // adName tuple into _hexData[wordNum].
397bd716f00SMatt Spinler     for (const auto& [wordNum, adName] : *regEntry.src.hexwordADFields)
398bd716f00SMatt Spinler     {
399bd716f00SMatt Spinler         // Can only set words 6 - 9
400bd716f00SMatt Spinler         if (!isUserDefinedWord(wordNum))
401bd716f00SMatt Spinler         {
402075c7923SPatrick Williams             std::string msg =
403075c7923SPatrick Williams                 "SRC user data word out of range: " + std::to_string(wordNum);
40485f61a63SMatt Spinler             addDebugData(msg);
405bd716f00SMatt Spinler             continue;
406bd716f00SMatt Spinler         }
407bd716f00SMatt Spinler 
4081a1b0dfbSHarisuddin Mohamed Isa         auto value = ad.getValue(std::get<0>(adName));
409bd716f00SMatt Spinler         if (value)
410bd716f00SMatt Spinler         {
411bd716f00SMatt Spinler             _hexData[getWordIndexFromWordNum(wordNum)] =
412bd716f00SMatt Spinler                 std::strtoul(value.value().c_str(), nullptr, 0);
413bd716f00SMatt Spinler         }
414bd716f00SMatt Spinler         else
415bd716f00SMatt Spinler         {
4161a1b0dfbSHarisuddin Mohamed Isa             std::string msg = "Source for user data SRC word not found: " +
4171a1b0dfbSHarisuddin Mohamed Isa                               std::get<0>(adName);
41885f61a63SMatt Spinler             addDebugData(msg);
419bd716f00SMatt Spinler         }
420bd716f00SMatt Spinler     }
421bd716f00SMatt Spinler }
422bd716f00SMatt Spinler 
setMotherboardCCIN(const DataInterfaceBase & dataIface)423075e5bafSMatt Spinler void SRC::setMotherboardCCIN(const DataInterfaceBase& dataIface)
424075e5bafSMatt Spinler {
425075e5bafSMatt Spinler     uint32_t ccin = 0;
426075e5bafSMatt Spinler     auto ccinString = dataIface.getMotherboardCCIN();
427075e5bafSMatt Spinler 
428075e5bafSMatt Spinler     try
429075e5bafSMatt Spinler     {
430075e5bafSMatt Spinler         if (ccinString.size() == ccinSize)
431075e5bafSMatt Spinler         {
432075e5bafSMatt Spinler             ccin = std::stoi(ccinString, 0, 16);
433075e5bafSMatt Spinler         }
434075e5bafSMatt Spinler     }
43566491c61SPatrick Williams     catch (const std::exception& e)
436075e5bafSMatt Spinler     {
4370bacc8efSMatt Spinler         lg2::warning("Could not convert motherboard CCIN {CCIN} to a number",
4380bacc8efSMatt Spinler                      "CCIN", ccinString);
439075e5bafSMatt Spinler         return;
440075e5bafSMatt Spinler     }
441075e5bafSMatt Spinler 
442075e5bafSMatt Spinler     // Set the first 2 bytes
443075e5bafSMatt Spinler     _hexData[1] |= ccin << 16;
444075e5bafSMatt Spinler }
445075e5bafSMatt Spinler 
validate()446f9bae185SMatt Spinler void SRC::validate()
447f9bae185SMatt Spinler {
448f9bae185SMatt Spinler     bool failed = false;
449f9bae185SMatt Spinler 
450f9bae185SMatt Spinler     if ((header().id != static_cast<uint16_t>(SectionID::primarySRC)) &&
451f9bae185SMatt Spinler         (header().id != static_cast<uint16_t>(SectionID::secondarySRC)))
452f9bae185SMatt Spinler     {
4530bacc8efSMatt Spinler         lg2::error("Invalid SRC section ID: {ID}", "ID", lg2::hex, header().id);
454f9bae185SMatt Spinler         failed = true;
455f9bae185SMatt Spinler     }
456f9bae185SMatt Spinler 
457f9bae185SMatt Spinler     // Check the version in the SRC, not in the header
458bd716f00SMatt Spinler     if (_version != srcVersion)
459f9bae185SMatt Spinler     {
4600bacc8efSMatt Spinler         lg2::error("Invalid SRC version: {VERSION}", "VERSION", lg2::hex,
4610bacc8efSMatt Spinler                    header().version);
462f9bae185SMatt Spinler         failed = true;
463f9bae185SMatt Spinler     }
464f9bae185SMatt Spinler 
465f9bae185SMatt Spinler     _valid = failed ? false : true;
466f9bae185SMatt Spinler }
467f9bae185SMatt Spinler 
isBMCSRC() const468075e5bafSMatt Spinler bool SRC::isBMCSRC() const
469075e5bafSMatt Spinler {
470075e5bafSMatt Spinler     auto as = asciiString();
471075e5bafSMatt Spinler     if (as.length() >= 2)
472075e5bafSMatt Spinler     {
473075e5bafSMatt Spinler         uint8_t errorType = strtoul(as.substr(0, 2).c_str(), nullptr, 16);
474075e5bafSMatt Spinler         return (errorType == static_cast<uint8_t>(SRCType::bmcError) ||
475075e5bafSMatt Spinler                 errorType == static_cast<uint8_t>(SRCType::powerError));
476075e5bafSMatt Spinler     }
477075e5bafSMatt Spinler     return false;
478075e5bafSMatt Spinler }
479075e5bafSMatt Spinler 
isHostbootSRC() const4804deed972SMatt Spinler bool SRC::isHostbootSRC() const
4814deed972SMatt Spinler {
4824deed972SMatt Spinler     auto as = asciiString();
4834deed972SMatt Spinler     if (as.length() >= 2)
4844deed972SMatt Spinler     {
4854deed972SMatt Spinler         uint8_t errorType = strtoul(as.substr(0, 2).c_str(), nullptr, 16);
4864deed972SMatt Spinler         return errorType == static_cast<uint8_t>(SRCType::hostbootError);
4874deed972SMatt Spinler     }
4884deed972SMatt Spinler     return false;
4894deed972SMatt Spinler }
4904deed972SMatt Spinler 
getErrorDetails(message::Registry & registry,DetailLevel type,bool toCache) const491075c7923SPatrick Williams std::optional<std::string> SRC::getErrorDetails(
492075c7923SPatrick Williams     message::Registry& registry, DetailLevel type, bool toCache) const
4930f717e10SHarisuddin Mohamed Isa {
4940f717e10SHarisuddin Mohamed Isa     const std::string jsonIndent(indentLevel, 0x20);
4950f717e10SHarisuddin Mohamed Isa     std::string errorOut;
496075e5bafSMatt Spinler     if (isBMCSRC())
4970f717e10SHarisuddin Mohamed Isa     {
4980f717e10SHarisuddin Mohamed Isa         auto entry = registry.lookup("0x" + asciiString().substr(4, 4),
4990f717e10SHarisuddin Mohamed Isa                                      rg::LookupType::reasonCode, toCache);
5000f717e10SHarisuddin Mohamed Isa         if (entry)
5010f717e10SHarisuddin Mohamed Isa         {
5020f717e10SHarisuddin Mohamed Isa             errorOut.append(jsonIndent + "\"Error Details\": {\n");
5030f717e10SHarisuddin Mohamed Isa             auto errorMsg = getErrorMessage(*entry);
5040f717e10SHarisuddin Mohamed Isa             if (errorMsg)
5050f717e10SHarisuddin Mohamed Isa             {
5060f717e10SHarisuddin Mohamed Isa                 if (type == DetailLevel::message)
5070f717e10SHarisuddin Mohamed Isa                 {
5080f717e10SHarisuddin Mohamed Isa                     return errorMsg.value();
5090f717e10SHarisuddin Mohamed Isa                 }
5100f717e10SHarisuddin Mohamed Isa                 else
5110f717e10SHarisuddin Mohamed Isa                 {
5120f717e10SHarisuddin Mohamed Isa                     jsonInsert(errorOut, "Message", errorMsg.value(), 2);
5130f717e10SHarisuddin Mohamed Isa                 }
5140f717e10SHarisuddin Mohamed Isa             }
5150f717e10SHarisuddin Mohamed Isa             if (entry->src.hexwordADFields)
5160f717e10SHarisuddin Mohamed Isa             {
5171a1b0dfbSHarisuddin Mohamed Isa                 std::map<size_t, std::tuple<std::string, std::string>>
5181a1b0dfbSHarisuddin Mohamed Isa                     adFields = entry->src.hexwordADFields.value();
5190f717e10SHarisuddin Mohamed Isa                 for (const auto& hexwordMap : adFields)
5200f717e10SHarisuddin Mohamed Isa                 {
521e8db29b3SZane Shelley                     auto srcValue = getNumberString(
5221a1b0dfbSHarisuddin Mohamed Isa                         "0x%X",
523e8db29b3SZane Shelley                         _hexData[getWordIndexFromWordNum(hexwordMap.first)]);
524e8db29b3SZane Shelley 
525e8db29b3SZane Shelley                     auto srcKey = std::get<0>(hexwordMap.second);
526e8db29b3SZane Shelley                     auto srcDesc = std::get<1>(hexwordMap.second);
527e8db29b3SZane Shelley 
528e8db29b3SZane Shelley                     // Only include this hex word in the error details if the
529e8db29b3SZane Shelley                     // description exists.
530e8db29b3SZane Shelley                     if (!srcDesc.empty())
531e8db29b3SZane Shelley                     {
532e8db29b3SZane Shelley                         std::vector<std::string> valueDescr;
533e8db29b3SZane Shelley                         valueDescr.push_back(srcValue);
534e8db29b3SZane Shelley                         valueDescr.push_back(srcDesc);
535e8db29b3SZane Shelley                         jsonInsertArray(errorOut, srcKey, valueDescr, 2);
536e8db29b3SZane Shelley                     }
5370f717e10SHarisuddin Mohamed Isa                 }
5380f717e10SHarisuddin Mohamed Isa             }
5390f717e10SHarisuddin Mohamed Isa             errorOut.erase(errorOut.size() - 2);
5400f717e10SHarisuddin Mohamed Isa             errorOut.append("\n");
5410f717e10SHarisuddin Mohamed Isa             errorOut.append(jsonIndent + "},\n");
5420f717e10SHarisuddin Mohamed Isa             return errorOut;
5430f717e10SHarisuddin Mohamed Isa         }
5440f717e10SHarisuddin Mohamed Isa     }
5450f717e10SHarisuddin Mohamed Isa     return std::nullopt;
5460f717e10SHarisuddin Mohamed Isa }
5470f717e10SHarisuddin Mohamed Isa 
getErrorMessage(const message::Entry & regEntry) const54825291157SPatrick Williams std::optional<std::string> SRC::getErrorMessage(
54925291157SPatrick Williams     const message::Entry& regEntry) const
5500f717e10SHarisuddin Mohamed Isa {
5510f717e10SHarisuddin Mohamed Isa     try
5520f717e10SHarisuddin Mohamed Isa     {
5530f717e10SHarisuddin Mohamed Isa         if (regEntry.doc.messageArgSources)
5540f717e10SHarisuddin Mohamed Isa         {
5550f717e10SHarisuddin Mohamed Isa             std::vector<uint32_t> argSourceVals;
5560f717e10SHarisuddin Mohamed Isa             std::string message;
5570f717e10SHarisuddin Mohamed Isa             const auto& argValues = regEntry.doc.messageArgSources.value();
5580f717e10SHarisuddin Mohamed Isa             for (size_t i = 0; i < argValues.size(); ++i)
5590f717e10SHarisuddin Mohamed Isa             {
5600f717e10SHarisuddin Mohamed Isa                 argSourceVals.push_back(_hexData[getWordIndexFromWordNum(
5610f717e10SHarisuddin Mohamed Isa                     argValues[i].back() - '0')]);
5620f717e10SHarisuddin Mohamed Isa             }
5630230abb4SPatrick Williams 
5640230abb4SPatrick Williams             auto it = std::begin(regEntry.doc.message);
5650230abb4SPatrick Williams             auto it_end = std::end(regEntry.doc.message);
5660230abb4SPatrick Williams 
5670230abb4SPatrick Williams             while (it != it_end)
5680f717e10SHarisuddin Mohamed Isa             {
5690230abb4SPatrick Williams                 if (*it == '%')
5700f717e10SHarisuddin Mohamed Isa                 {
5710230abb4SPatrick Williams                     ++it;
5720230abb4SPatrick Williams 
5730230abb4SPatrick Williams                     size_t wordIndex = *it - '0';
5740230abb4SPatrick Williams                     if (isdigit(*it) && wordIndex >= 1 &&
5750f717e10SHarisuddin Mohamed Isa                         static_cast<uint16_t>(wordIndex) <=
5760f717e10SHarisuddin Mohamed Isa                             argSourceVals.size())
5770f717e10SHarisuddin Mohamed Isa                     {
5780f717e10SHarisuddin Mohamed Isa                         message.append(getNumberString(
57939936e34SZane Shelley                             "0x%08X", argSourceVals[wordIndex - 1]));
5800f717e10SHarisuddin Mohamed Isa                     }
5810f717e10SHarisuddin Mohamed Isa                     else
5820f717e10SHarisuddin Mohamed Isa                     {
5830230abb4SPatrick Williams                         message.append("%" + std::string(1, *it));
5840f717e10SHarisuddin Mohamed Isa                     }
5850f717e10SHarisuddin Mohamed Isa                 }
5860f717e10SHarisuddin Mohamed Isa                 else
5870f717e10SHarisuddin Mohamed Isa                 {
5880230abb4SPatrick Williams                     message.push_back(*it);
5890f717e10SHarisuddin Mohamed Isa                 }
5900230abb4SPatrick Williams                 ++it;
5910f717e10SHarisuddin Mohamed Isa             }
5920230abb4SPatrick Williams 
5930f717e10SHarisuddin Mohamed Isa             return message;
5940f717e10SHarisuddin Mohamed Isa         }
5950f717e10SHarisuddin Mohamed Isa         else
5960f717e10SHarisuddin Mohamed Isa         {
5970f717e10SHarisuddin Mohamed Isa             return regEntry.doc.message;
5980f717e10SHarisuddin Mohamed Isa         }
5990f717e10SHarisuddin Mohamed Isa     }
6000f717e10SHarisuddin Mohamed Isa     catch (const std::exception& e)
6010f717e10SHarisuddin Mohamed Isa     {
6020bacc8efSMatt Spinler         lg2::error(
6030bacc8efSMatt Spinler             "Cannot get error message from registry entry, error = {ERROR}",
6040bacc8efSMatt Spinler             "ERROR", e);
6050f717e10SHarisuddin Mohamed Isa     }
6060f717e10SHarisuddin Mohamed Isa     return std::nullopt;
6070f717e10SHarisuddin Mohamed Isa }
6080f717e10SHarisuddin Mohamed Isa 
getCallouts() const6090f717e10SHarisuddin Mohamed Isa std::optional<std::string> SRC::getCallouts() const
6100f717e10SHarisuddin Mohamed Isa {
6110f717e10SHarisuddin Mohamed Isa     if (!_callouts)
6120f717e10SHarisuddin Mohamed Isa     {
6130f717e10SHarisuddin Mohamed Isa         return std::nullopt;
6140f717e10SHarisuddin Mohamed Isa     }
6150f717e10SHarisuddin Mohamed Isa     std::string printOut;
6160f717e10SHarisuddin Mohamed Isa     const std::string jsonIndent(indentLevel, 0x20);
6170f717e10SHarisuddin Mohamed Isa     const auto& callout = _callouts->callouts();
6180f717e10SHarisuddin Mohamed Isa     const auto& compDescrp = pv::failingComponentType;
6190f717e10SHarisuddin Mohamed Isa     printOut.append(jsonIndent + "\"Callout Section\": {\n");
6200f717e10SHarisuddin Mohamed Isa     jsonInsert(printOut, "Callout Count", std::to_string(callout.size()), 2);
6210f717e10SHarisuddin Mohamed Isa     printOut.append(jsonIndent + jsonIndent + "\"Callouts\": [");
6220f717e10SHarisuddin Mohamed Isa     for (auto& entry : callout)
6230f717e10SHarisuddin Mohamed Isa     {
6240f717e10SHarisuddin Mohamed Isa         printOut.append("{\n");
6250f717e10SHarisuddin Mohamed Isa         if (entry->fruIdentity())
6260f717e10SHarisuddin Mohamed Isa         {
6270f717e10SHarisuddin Mohamed Isa             jsonInsert(
6280f717e10SHarisuddin Mohamed Isa                 printOut, "FRU Type",
6290f717e10SHarisuddin Mohamed Isa                 compDescrp.at(entry->fruIdentity()->failingComponentType()), 3);
6300f717e10SHarisuddin Mohamed Isa             jsonInsert(printOut, "Priority",
6310f717e10SHarisuddin Mohamed Isa                        pv::getValue(entry->priority(),
6320f717e10SHarisuddin Mohamed Isa                                     pel_values::calloutPriorityValues),
6330f717e10SHarisuddin Mohamed Isa                        3);
6340f717e10SHarisuddin Mohamed Isa             if (!entry->locationCode().empty())
6350f717e10SHarisuddin Mohamed Isa             {
6360f717e10SHarisuddin Mohamed Isa                 jsonInsert(printOut, "Location Code", entry->locationCode(), 3);
6370f717e10SHarisuddin Mohamed Isa             }
6380f717e10SHarisuddin Mohamed Isa             if (entry->fruIdentity()->getPN().has_value())
6390f717e10SHarisuddin Mohamed Isa             {
6400f717e10SHarisuddin Mohamed Isa                 jsonInsert(printOut, "Part Number",
6410f717e10SHarisuddin Mohamed Isa                            entry->fruIdentity()->getPN().value(), 3);
6420f717e10SHarisuddin Mohamed Isa             }
6430f717e10SHarisuddin Mohamed Isa             if (entry->fruIdentity()->getMaintProc().has_value())
6440f717e10SHarisuddin Mohamed Isa             {
6459e8b49e6SMatt Spinler                 jsonInsert(printOut, "Procedure",
6460f717e10SHarisuddin Mohamed Isa                            entry->fruIdentity()->getMaintProc().value(), 3);
6470f717e10SHarisuddin Mohamed Isa                 if (pv::procedureDesc.find(
6480f717e10SHarisuddin Mohamed Isa                         entry->fruIdentity()->getMaintProc().value()) !=
6490f717e10SHarisuddin Mohamed Isa                     pv::procedureDesc.end())
6500f717e10SHarisuddin Mohamed Isa                 {
6510f717e10SHarisuddin Mohamed Isa                     jsonInsert(
6520f717e10SHarisuddin Mohamed Isa                         printOut, "Description",
6530f717e10SHarisuddin Mohamed Isa                         pv::procedureDesc.at(
6540f717e10SHarisuddin Mohamed Isa                             entry->fruIdentity()->getMaintProc().value()),
6550f717e10SHarisuddin Mohamed Isa                         3);
6560f717e10SHarisuddin Mohamed Isa                 }
6570f717e10SHarisuddin Mohamed Isa             }
6580f717e10SHarisuddin Mohamed Isa             if (entry->fruIdentity()->getCCIN().has_value())
6590f717e10SHarisuddin Mohamed Isa             {
6600f717e10SHarisuddin Mohamed Isa                 jsonInsert(printOut, "CCIN",
6610f717e10SHarisuddin Mohamed Isa                            entry->fruIdentity()->getCCIN().value(), 3);
6620f717e10SHarisuddin Mohamed Isa             }
6630f717e10SHarisuddin Mohamed Isa             if (entry->fruIdentity()->getSN().has_value())
6640f717e10SHarisuddin Mohamed Isa             {
6650f717e10SHarisuddin Mohamed Isa                 jsonInsert(printOut, "Serial Number",
6660f717e10SHarisuddin Mohamed Isa                            entry->fruIdentity()->getSN().value(), 3);
6670f717e10SHarisuddin Mohamed Isa             }
6680f717e10SHarisuddin Mohamed Isa         }
6690f717e10SHarisuddin Mohamed Isa         if (entry->pceIdentity())
6700f717e10SHarisuddin Mohamed Isa         {
6710f717e10SHarisuddin Mohamed Isa             const auto& pceIdentMtms = entry->pceIdentity()->mtms();
6720f717e10SHarisuddin Mohamed Isa             if (!pceIdentMtms.machineTypeAndModel().empty())
6730f717e10SHarisuddin Mohamed Isa             {
6740f717e10SHarisuddin Mohamed Isa                 jsonInsert(printOut, "PCE MTMS",
6750f717e10SHarisuddin Mohamed Isa                            pceIdentMtms.machineTypeAndModel() + "_" +
6760f717e10SHarisuddin Mohamed Isa                                pceIdentMtms.machineSerialNumber(),
6770f717e10SHarisuddin Mohamed Isa                            3);
6780f717e10SHarisuddin Mohamed Isa             }
6790f717e10SHarisuddin Mohamed Isa             if (!entry->pceIdentity()->enclosureName().empty())
6800f717e10SHarisuddin Mohamed Isa             {
6810f717e10SHarisuddin Mohamed Isa                 jsonInsert(printOut, "PCE Name",
6820f717e10SHarisuddin Mohamed Isa                            entry->pceIdentity()->enclosureName(), 3);
6830f717e10SHarisuddin Mohamed Isa             }
6840f717e10SHarisuddin Mohamed Isa         }
6850f717e10SHarisuddin Mohamed Isa         if (entry->mru())
6860f717e10SHarisuddin Mohamed Isa         {
6870f717e10SHarisuddin Mohamed Isa             const auto& mruCallouts = entry->mru()->mrus();
6880f717e10SHarisuddin Mohamed Isa             std::string mruId;
6890f717e10SHarisuddin Mohamed Isa             for (auto& element : mruCallouts)
6900f717e10SHarisuddin Mohamed Isa             {
6910f717e10SHarisuddin Mohamed Isa                 if (!mruId.empty())
6920f717e10SHarisuddin Mohamed Isa                 {
6930f717e10SHarisuddin Mohamed Isa                     mruId.append(", " + getNumberString("%08X", element.id));
6940f717e10SHarisuddin Mohamed Isa                 }
6950f717e10SHarisuddin Mohamed Isa                 else
6960f717e10SHarisuddin Mohamed Isa                 {
6970f717e10SHarisuddin Mohamed Isa                     mruId.append(getNumberString("%08X", element.id));
6980f717e10SHarisuddin Mohamed Isa                 }
6990f717e10SHarisuddin Mohamed Isa             }
7000f717e10SHarisuddin Mohamed Isa             jsonInsert(printOut, "MRU Id", mruId, 3);
7010f717e10SHarisuddin Mohamed Isa         }
7020f717e10SHarisuddin Mohamed Isa         printOut.erase(printOut.size() - 2);
7030f717e10SHarisuddin Mohamed Isa         printOut.append("\n" + jsonIndent + jsonIndent + "}, ");
7040f717e10SHarisuddin Mohamed Isa     };
7050f717e10SHarisuddin Mohamed Isa     printOut.erase(printOut.size() - 2);
7060f717e10SHarisuddin Mohamed Isa     printOut.append("]\n" + jsonIndent + "}");
7070f717e10SHarisuddin Mohamed Isa     return printOut;
7080f717e10SHarisuddin Mohamed Isa }
7090f717e10SHarisuddin Mohamed Isa 
getJSON(message::Registry & registry,const std::vector<std::string> & plugins,uint8_t creatorID) const71025291157SPatrick Williams std::optional<std::string> SRC::getJSON(message::Registry& registry,
71125291157SPatrick Williams                                         const std::vector<std::string>& plugins
71225291157SPatrick Williams                                         [[maybe_unused]],
713c8d6cc61SHarisuddin Mohamed Isa                                         uint8_t creatorID) const
7140f717e10SHarisuddin Mohamed Isa {
7150f717e10SHarisuddin Mohamed Isa     std::string ps;
716c8d6cc61SHarisuddin Mohamed Isa     std::vector<std::string> hexwords;
717bebeb948SHarisuddin Mohamed Isa     jsonInsert(ps, pv::sectionVer, getNumberString("%d", _header.version), 1);
718bebeb948SHarisuddin Mohamed Isa     jsonInsert(ps, pv::subSection, getNumberString("%d", _header.subType), 1);
719b832aa5eSMatt Spinler     jsonInsert(ps, pv::createdBy,
720b832aa5eSMatt Spinler                getComponentName(_header.componentID, creatorID), 1);
7210f717e10SHarisuddin Mohamed Isa     jsonInsert(ps, "SRC Version", getNumberString("0x%02X", _version), 1);
722c32e5516SHarisuddin Mohamed Isa     jsonInsert(ps, "SRC Format", getNumberString("0x%02X", _hexData[0] & 0xFF),
723c32e5516SHarisuddin Mohamed Isa                1);
724c32e5516SHarisuddin Mohamed Isa     jsonInsert(ps, "Virtual Progress SRC",
725c32e5516SHarisuddin Mohamed Isa                pv::boolString.at(_flags & virtualProgressSRC), 1);
726c32e5516SHarisuddin Mohamed Isa     jsonInsert(ps, "I5/OS Service Event Bit",
727c32e5516SHarisuddin Mohamed Isa                pv::boolString.at(_flags & i5OSServiceEventBit), 1);
728c32e5516SHarisuddin Mohamed Isa     jsonInsert(ps, "Hypervisor Dump Initiated",
729c32e5516SHarisuddin Mohamed Isa                pv::boolString.at(_flags & hypDumpInit), 1);
730075e5bafSMatt Spinler 
731075e5bafSMatt Spinler     if (isBMCSRC())
732075e5bafSMatt Spinler     {
733075e5bafSMatt Spinler         std::string ccinString;
734075e5bafSMatt Spinler         uint32_t ccin = _hexData[1] >> 16;
735075e5bafSMatt Spinler 
736075e5bafSMatt Spinler         if (ccin)
737075e5bafSMatt Spinler         {
738075e5bafSMatt Spinler             ccinString = getNumberString("%04X", ccin);
739075e5bafSMatt Spinler         }
740075e5bafSMatt Spinler         // The PEL spec calls it a backplane, so call it that here.
741075e5bafSMatt Spinler         jsonInsert(ps, "Backplane CCIN", ccinString, 1);
742afa2c799SMatt Spinler 
7433e274432SSumit Kumar         jsonInsert(ps, "Terminate FW Error",
7443e274432SSumit Kumar                    pv::boolString.at(
7453e274432SSumit Kumar                        _hexData[3] &
7463e274432SSumit Kumar                        static_cast<uint32_t>(ErrorStatusFlags::terminateFwErr)),
7473e274432SSumit Kumar                    1);
7484deed972SMatt Spinler     }
7494deed972SMatt Spinler 
7504deed972SMatt Spinler     if (isBMCSRC() || isHostbootSRC())
7514deed972SMatt Spinler     {
752afa2c799SMatt Spinler         jsonInsert(ps, "Deconfigured",
753afa2c799SMatt Spinler                    pv::boolString.at(
754afa2c799SMatt Spinler                        _hexData[3] &
755afa2c799SMatt Spinler                        static_cast<uint32_t>(ErrorStatusFlags::deconfigured)),
756afa2c799SMatt Spinler                    1);
757afa2c799SMatt Spinler 
758afa2c799SMatt Spinler         jsonInsert(
759afa2c799SMatt Spinler             ps, "Guarded",
760075c7923SPatrick Williams             pv::boolString.at(
761075c7923SPatrick Williams                 _hexData[3] & static_cast<uint32_t>(ErrorStatusFlags::guarded)),
762afa2c799SMatt Spinler             1);
763075e5bafSMatt Spinler     }
764075e5bafSMatt Spinler 
765a214ed30SHarisuddin Mohamed Isa     auto errorDetails = getErrorDetails(registry, DetailLevel::json, true);
7660f717e10SHarisuddin Mohamed Isa     if (errorDetails)
7670f717e10SHarisuddin Mohamed Isa     {
7680f717e10SHarisuddin Mohamed Isa         ps.append(errorDetails.value());
7690f717e10SHarisuddin Mohamed Isa     }
7700f717e10SHarisuddin Mohamed Isa     jsonInsert(ps, "Valid Word Count", getNumberString("0x%02X", _wordCount),
7710f717e10SHarisuddin Mohamed Isa                1);
7720f717e10SHarisuddin Mohamed Isa     std::string refcode = asciiString();
773c8d6cc61SHarisuddin Mohamed Isa     hexwords.push_back(refcode);
774fecaa57cSHarisuddin Mohamed Isa     std::string extRefcode;
775fecaa57cSHarisuddin Mohamed Isa     size_t pos = refcode.find(0x20);
776fecaa57cSHarisuddin Mohamed Isa     if (pos != std::string::npos)
777fecaa57cSHarisuddin Mohamed Isa     {
778fecaa57cSHarisuddin Mohamed Isa         size_t nextPos = refcode.find_first_not_of(0x20, pos);
779fecaa57cSHarisuddin Mohamed Isa         if (nextPos != std::string::npos)
780fecaa57cSHarisuddin Mohamed Isa         {
781fecaa57cSHarisuddin Mohamed Isa             extRefcode = trimEnd(refcode.substr(nextPos));
782fecaa57cSHarisuddin Mohamed Isa         }
783fecaa57cSHarisuddin Mohamed Isa         refcode.erase(pos);
784fecaa57cSHarisuddin Mohamed Isa     }
7850f717e10SHarisuddin Mohamed Isa     jsonInsert(ps, "Reference Code", refcode, 1);
786fecaa57cSHarisuddin Mohamed Isa     if (!extRefcode.empty())
787fecaa57cSHarisuddin Mohamed Isa     {
788fecaa57cSHarisuddin Mohamed Isa         jsonInsert(ps, "Extended Reference Code", extRefcode, 1);
789fecaa57cSHarisuddin Mohamed Isa     }
7900f717e10SHarisuddin Mohamed Isa     for (size_t i = 2; i <= _wordCount; i++)
7910f717e10SHarisuddin Mohamed Isa     {
792c8d6cc61SHarisuddin Mohamed Isa         std::string tmpWord =
793c8d6cc61SHarisuddin Mohamed Isa             getNumberString("%08X", _hexData[getWordIndexFromWordNum(i)]);
794c8d6cc61SHarisuddin Mohamed Isa         jsonInsert(ps, "Hex Word " + std::to_string(i), tmpWord, 1);
795c8d6cc61SHarisuddin Mohamed Isa         hexwords.push_back(tmpWord);
7960f717e10SHarisuddin Mohamed Isa     }
7970f717e10SHarisuddin Mohamed Isa     auto calloutJson = getCallouts();
7980f717e10SHarisuddin Mohamed Isa     if (calloutJson)
7990f717e10SHarisuddin Mohamed Isa     {
8000f717e10SHarisuddin Mohamed Isa         ps.append(calloutJson.value());
801c8d6cc61SHarisuddin Mohamed Isa         ps.append(",\n");
8020f717e10SHarisuddin Mohamed Isa     }
803c8d6cc61SHarisuddin Mohamed Isa     std::string subsystem = getNumberString("%c", tolower(creatorID));
804c8d6cc61SHarisuddin Mohamed Isa     bool srcDetailExists = false;
805c8d6cc61SHarisuddin Mohamed Isa #ifdef PELTOOL
806c8d6cc61SHarisuddin Mohamed Isa     if (std::find(plugins.begin(), plugins.end(), subsystem + "src") !=
807c8d6cc61SHarisuddin Mohamed Isa         plugins.end())
808c8d6cc61SHarisuddin Mohamed Isa     {
809c8d6cc61SHarisuddin Mohamed Isa         auto pyJson = getPythonJSON(hexwords, creatorID);
810c8d6cc61SHarisuddin Mohamed Isa         if (pyJson)
811c8d6cc61SHarisuddin Mohamed Isa         {
812c8d6cc61SHarisuddin Mohamed Isa             ps.append(pyJson.value());
813c8d6cc61SHarisuddin Mohamed Isa             srcDetailExists = true;
814c8d6cc61SHarisuddin Mohamed Isa         }
815c8d6cc61SHarisuddin Mohamed Isa     }
816c8d6cc61SHarisuddin Mohamed Isa #endif
817c8d6cc61SHarisuddin Mohamed Isa     if (!srcDetailExists)
8180f717e10SHarisuddin Mohamed Isa     {
8190f717e10SHarisuddin Mohamed Isa         ps.erase(ps.size() - 2);
8200f717e10SHarisuddin Mohamed Isa     }
8210f717e10SHarisuddin Mohamed Isa     return ps;
8220f717e10SHarisuddin Mohamed Isa }
8230f717e10SHarisuddin Mohamed Isa 
addCallouts(const message::Entry & regEntry,const AdditionalData & additionalData,const nlohmann::json & jsonCallouts,const DataInterfaceBase & dataIface)8240398458dSMatt Spinler void SRC::addCallouts(const message::Entry& regEntry,
8250398458dSMatt Spinler                       const AdditionalData& additionalData,
8265a90a95bSMatt Spinler                       const nlohmann::json& jsonCallouts,
827ed046856SMatt Spinler                       const DataInterfaceBase& dataIface)
828ed046856SMatt Spinler {
829075c7923SPatrick Williams     auto registryCallouts =
830075c7923SPatrick Williams         getRegistryCallouts(regEntry, additionalData, dataIface);
831f00f9d0fSMatt Spinler 
832ed046856SMatt Spinler     auto item = additionalData.getValue("CALLOUT_INVENTORY_PATH");
83353ef1552SMiguel Gomez     auto priority = additionalData.getValue("CALLOUT_PRIORITY");
834f00f9d0fSMatt Spinler 
83553ef1552SMiguel Gomez     std::optional<CalloutPriority> calloutPriority;
83653ef1552SMiguel Gomez 
83753ef1552SMiguel Gomez     // Only  H, M or L priority values.
83853ef1552SMiguel Gomez     if (priority && !(*priority).empty())
83953ef1552SMiguel Gomez     {
84053ef1552SMiguel Gomez         uint8_t p = (*priority)[0];
84153ef1552SMiguel Gomez         if (p == 'H' || p == 'M' || p == 'L')
84253ef1552SMiguel Gomez         {
84353ef1552SMiguel Gomez             calloutPriority = static_cast<CalloutPriority>(p);
84453ef1552SMiguel Gomez         }
84553ef1552SMiguel Gomez     }
846f00f9d0fSMatt Spinler     // If the first registry callout says to use the passed in inventory
847f00f9d0fSMatt Spinler     // path to get the location code for a symbolic FRU callout with a
848f00f9d0fSMatt Spinler     // trusted location code, then do not add the inventory path as a
849f00f9d0fSMatt Spinler     // normal FRU callout.
850f00f9d0fSMatt Spinler     bool useInvForSymbolicFRULocCode =
851f00f9d0fSMatt Spinler         !registryCallouts.empty() && registryCallouts[0].useInventoryLocCode &&
852f00f9d0fSMatt Spinler         !registryCallouts[0].symbolicFRUTrusted.empty();
853f00f9d0fSMatt Spinler 
854f00f9d0fSMatt Spinler     if (item && !useInvForSymbolicFRULocCode)
855ed046856SMatt Spinler     {
85653ef1552SMiguel Gomez         addInventoryCallout(*item, calloutPriority, std::nullopt, dataIface);
857ed046856SMatt Spinler     }
858ed046856SMatt Spinler 
859717de428SMatt Spinler     addDevicePathCallouts(additionalData, dataIface);
8600398458dSMatt Spinler 
861f00f9d0fSMatt Spinler     addRegistryCallouts(registryCallouts, dataIface,
862f00f9d0fSMatt Spinler                         (useInvForSymbolicFRULocCode) ? item : std::nullopt);
8635a90a95bSMatt Spinler 
8645a90a95bSMatt Spinler     if (!jsonCallouts.empty())
8655a90a95bSMatt Spinler     {
8665a90a95bSMatt Spinler         addJSONCallouts(jsonCallouts, dataIface);
8675a90a95bSMatt Spinler     }
868ed046856SMatt Spinler }
869ed046856SMatt Spinler 
addLocationCodeOnlyCallout(const std::string & locationCode,const CalloutPriority priority)870*7b92372dSMatt Spinler void SRC::addLocationCodeOnlyCallout(const std::string& locationCode,
871*7b92372dSMatt Spinler                                      const CalloutPriority priority)
872*7b92372dSMatt Spinler {
873*7b92372dSMatt Spinler     std::string empty;
874*7b92372dSMatt Spinler     std::vector<src::MRU::MRUCallout> mrus;
875*7b92372dSMatt Spinler     auto callout = std::make_unique<src::Callout>(priority, locationCode, empty,
876*7b92372dSMatt Spinler                                                   empty, empty, mrus);
877*7b92372dSMatt Spinler     createCalloutsObject();
878*7b92372dSMatt Spinler     _callouts->addCallout(std::move(callout));
879*7b92372dSMatt Spinler }
880*7b92372dSMatt Spinler 
addInventoryCallout(const std::string & inventoryPath,const std::optional<CalloutPriority> & priority,const std::optional<std::string> & locationCode,const DataInterfaceBase & dataIface,const std::vector<src::MRU::MRUCallout> & mrus)881ed046856SMatt Spinler void SRC::addInventoryCallout(const std::string& inventoryPath,
882af191c7aSMatt Spinler                               const std::optional<CalloutPriority>& priority,
883af191c7aSMatt Spinler                               const std::optional<std::string>& locationCode,
884b8cb60feSMatt Spinler                               const DataInterfaceBase& dataIface,
885b8cb60feSMatt Spinler                               const std::vector<src::MRU::MRUCallout>& mrus)
886ed046856SMatt Spinler {
887ed046856SMatt Spinler     std::string locCode;
888ed046856SMatt Spinler     std::string fn;
889ed046856SMatt Spinler     std::string ccin;
890ed046856SMatt Spinler     std::string sn;
891ed046856SMatt Spinler     std::unique_ptr<src::Callout> callout;
892ed046856SMatt Spinler 
8939b90e2a2SMatt Spinler     try
8949b90e2a2SMatt Spinler     {
895af191c7aSMatt Spinler         // Use the passed in location code if there otherwise look it up
896af191c7aSMatt Spinler         if (locationCode)
897af191c7aSMatt Spinler         {
898af191c7aSMatt Spinler             locCode = *locationCode;
899af191c7aSMatt Spinler         }
900af191c7aSMatt Spinler         else
901af191c7aSMatt Spinler         {
9029b90e2a2SMatt Spinler             locCode = dataIface.getLocationCode(inventoryPath);
903af191c7aSMatt Spinler         }
904ed046856SMatt Spinler 
905ed046856SMatt Spinler         try
906ed046856SMatt Spinler         {
9079b90e2a2SMatt Spinler             dataIface.getHWCalloutFields(inventoryPath, fn, ccin, sn);
908ed046856SMatt Spinler 
909075c7923SPatrick Williams             CalloutPriority p =
910075c7923SPatrick Williams                 priority ? priority.value() : CalloutPriority::high;
911af191c7aSMatt Spinler 
912075c7923SPatrick Williams             callout =
913075c7923SPatrick Williams                 std::make_unique<src::Callout>(p, locCode, fn, ccin, sn, mrus);
914ed046856SMatt Spinler         }
91545e83521SPatrick Williams         catch (const sdbusplus::exception_t& e)
916ed046856SMatt Spinler         {
917075c7923SPatrick Williams             std::string msg =
918075c7923SPatrick Williams                 "No VPD found for " + inventoryPath + ": " + e.what();
91985f61a63SMatt Spinler             addDebugData(msg);
920ed046856SMatt Spinler 
9219b90e2a2SMatt Spinler             // Just create the callout with empty FRU fields
922b8cb60feSMatt Spinler             callout = std::make_unique<src::Callout>(
923b8cb60feSMatt Spinler                 CalloutPriority::high, locCode, fn, ccin, sn, mrus);
9249b90e2a2SMatt Spinler         }
9259b90e2a2SMatt Spinler     }
92645e83521SPatrick Williams     catch (const sdbusplus::exception_t& e)
9279b90e2a2SMatt Spinler     {
92885f61a63SMatt Spinler         std::string msg = "Could not get location code for " + inventoryPath +
92985f61a63SMatt Spinler                           ": " + e.what();
93085f61a63SMatt Spinler         addDebugData(msg);
9319b90e2a2SMatt Spinler 
932479b6927SMatt Spinler         // Don't add a callout in this case, because:
933479b6927SMatt Spinler         // 1) With how the inventory is primed, there is no case where
934479b6927SMatt Spinler         //    a location code is expected to be missing.  This implies
935479b6927SMatt Spinler         //    the caller is passing in something invalid.
936479b6927SMatt Spinler         // 2) The addDebugData call above will put the passed in path into
937479b6927SMatt Spinler         //    a user data section that can be seen by development for debug.
938479b6927SMatt Spinler         // 3) Even if we wanted to do a 'no_vpd_for_fru' sort of maint.
939479b6927SMatt Spinler         //    procedure, we don't have a good way to indicate to the user
940479b6927SMatt Spinler         //    anything about the intended callout (they won't see user data).
941479b6927SMatt Spinler         // 4) Creating a new standalone event log for this problem isn't
942479b6927SMatt Spinler         //    possible from inside a PEL section.
943ed046856SMatt Spinler     }
944ed046856SMatt Spinler 
945479b6927SMatt Spinler     if (callout)
946479b6927SMatt Spinler     {
9479b90e2a2SMatt Spinler         createCalloutsObject();
948ed046856SMatt Spinler         _callouts->addCallout(std::move(callout));
9490398458dSMatt Spinler     }
950479b6927SMatt Spinler }
951ed046856SMatt Spinler 
getRegistryCallouts(const message::Entry & regEntry,const AdditionalData & additionalData,const DataInterfaceBase & dataIface)952075c7923SPatrick Williams std::vector<message::RegistryCallout> SRC::getRegistryCallouts(
953075c7923SPatrick Williams     const message::Entry& regEntry, const AdditionalData& additionalData,
9540398458dSMatt Spinler     const DataInterfaceBase& dataIface)
9550398458dSMatt Spinler {
956f00f9d0fSMatt Spinler     std::vector<message::RegistryCallout> registryCallouts;
957f00f9d0fSMatt Spinler 
958f00f9d0fSMatt Spinler     if (regEntry.callouts)
959f00f9d0fSMatt Spinler     {
9609a50c8daSMatt Spinler         std::vector<std::string> systemNames;
9619a50c8daSMatt Spinler 
9620398458dSMatt Spinler         try
9630398458dSMatt Spinler         {
9649a50c8daSMatt Spinler             systemNames = dataIface.getSystemNames();
9659a50c8daSMatt Spinler         }
9669a50c8daSMatt Spinler         catch (const std::exception& e)
9679a50c8daSMatt Spinler         {
9689a50c8daSMatt Spinler             // Compatible interface not available yet
9699a50c8daSMatt Spinler         }
9700398458dSMatt Spinler 
9719a50c8daSMatt Spinler         try
9729a50c8daSMatt Spinler         {
973f00f9d0fSMatt Spinler             registryCallouts = message::Registry::getCallouts(
9746ea4d5f7SMatt Spinler                 regEntry.callouts.value(), systemNames, additionalData);
975f00f9d0fSMatt Spinler         }
976f00f9d0fSMatt Spinler         catch (const std::exception& e)
9770398458dSMatt Spinler         {
9781aa90d49SJayanth Othayoth             addDebugData(std::format(
979f00f9d0fSMatt Spinler                 "Error parsing PEL message registry callout JSON: {}",
980f00f9d0fSMatt Spinler                 e.what()));
981f00f9d0fSMatt Spinler         }
982f00f9d0fSMatt Spinler     }
983f00f9d0fSMatt Spinler 
984f00f9d0fSMatt Spinler     return registryCallouts;
985f00f9d0fSMatt Spinler }
986f00f9d0fSMatt Spinler 
addRegistryCallouts(const std::vector<message::RegistryCallout> & callouts,const DataInterfaceBase & dataIface,std::optional<std::string> trustedSymbolicFRUInvPath)987f00f9d0fSMatt Spinler void SRC::addRegistryCallouts(
988f00f9d0fSMatt Spinler     const std::vector<message::RegistryCallout>& callouts,
989f00f9d0fSMatt Spinler     const DataInterfaceBase& dataIface,
990f00f9d0fSMatt Spinler     std::optional<std::string> trustedSymbolicFRUInvPath)
991f00f9d0fSMatt Spinler {
992f00f9d0fSMatt Spinler     try
993f00f9d0fSMatt Spinler     {
994f00f9d0fSMatt Spinler         for (const auto& callout : callouts)
995f00f9d0fSMatt Spinler         {
996f00f9d0fSMatt Spinler             addRegistryCallout(callout, dataIface, trustedSymbolicFRUInvPath);
997f00f9d0fSMatt Spinler 
998f00f9d0fSMatt Spinler             // Only the first callout gets the inventory path
999f00f9d0fSMatt Spinler             if (trustedSymbolicFRUInvPath)
1000f00f9d0fSMatt Spinler             {
1001f00f9d0fSMatt Spinler                 trustedSymbolicFRUInvPath = std::nullopt;
1002f00f9d0fSMatt Spinler             }
10030398458dSMatt Spinler         }
10040398458dSMatt Spinler     }
100566491c61SPatrick Williams     catch (const std::exception& e)
10060398458dSMatt Spinler     {
1007075c7923SPatrick Williams         std::string msg =
1008075c7923SPatrick Williams             "Error parsing PEL message registry callout JSON: "s + e.what();
100985f61a63SMatt Spinler         addDebugData(msg);
10100398458dSMatt Spinler     }
10110398458dSMatt Spinler }
10120398458dSMatt Spinler 
addRegistryCallout(const message::RegistryCallout & regCallout,const DataInterfaceBase & dataIface,const std::optional<std::string> & trustedSymbolicFRUInvPath)1013f00f9d0fSMatt Spinler void SRC::addRegistryCallout(
1014f00f9d0fSMatt Spinler     const message::RegistryCallout& regCallout,
1015f00f9d0fSMatt Spinler     const DataInterfaceBase& dataIface,
1016f00f9d0fSMatt Spinler     const std::optional<std::string>& trustedSymbolicFRUInvPath)
10170398458dSMatt Spinler {
10180398458dSMatt Spinler     std::unique_ptr<src::Callout> callout;
10190398458dSMatt Spinler     auto locCode = regCallout.locCode;
1020*7b92372dSMatt Spinler     bool locExpanded = true;
10210398458dSMatt Spinler 
1022af191c7aSMatt Spinler     if (!locCode.empty())
1023af191c7aSMatt Spinler     {
1024af191c7aSMatt Spinler         try
1025af191c7aSMatt Spinler         {
1026af191c7aSMatt Spinler             locCode = dataIface.expandLocationCode(locCode, 0);
1027af191c7aSMatt Spinler         }
1028af191c7aSMatt Spinler         catch (const std::exception& e)
1029af191c7aSMatt Spinler         {
10302544b419SPatrick Williams             auto msg = "Unable to expand location code " + locCode + ": " +
10312544b419SPatrick Williams                        e.what();
1032af191c7aSMatt Spinler             addDebugData(msg);
1033*7b92372dSMatt Spinler             locExpanded = false;
1034af191c7aSMatt Spinler         }
1035af191c7aSMatt Spinler     }
1036af191c7aSMatt Spinler 
10370398458dSMatt Spinler     // Via the PEL values table, get the priority enum.
10380398458dSMatt Spinler     // The schema will have validated the priority was a valid value.
1039075c7923SPatrick Williams     auto priorityIt =
1040075c7923SPatrick Williams         pv::findByName(regCallout.priority, pv::calloutPriorityValues);
10410398458dSMatt Spinler     assert(priorityIt != pv::calloutPriorityValues.end());
10420398458dSMatt Spinler     auto priority =
10430398458dSMatt Spinler         static_cast<CalloutPriority>(std::get<pv::fieldValuePos>(*priorityIt));
10440398458dSMatt Spinler 
10450398458dSMatt Spinler     if (!regCallout.procedure.empty())
10460398458dSMatt Spinler     {
10470398458dSMatt Spinler         // Procedure callout
10482edce4e2SMatt Spinler         callout = std::make_unique<src::Callout>(priority, regCallout.procedure,
10492edce4e2SMatt Spinler                                                  src::CalloutValueType::raw);
10500398458dSMatt Spinler     }
10510398458dSMatt Spinler     else if (!regCallout.symbolicFRU.empty())
10520398458dSMatt Spinler     {
10530398458dSMatt Spinler         // Symbolic FRU callout
10540398458dSMatt Spinler         callout = std::make_unique<src::Callout>(
10550398458dSMatt Spinler             priority, regCallout.symbolicFRU, locCode, false);
10560398458dSMatt Spinler     }
10570398458dSMatt Spinler     else if (!regCallout.symbolicFRUTrusted.empty())
10580398458dSMatt Spinler     {
10590398458dSMatt Spinler         // Symbolic FRU with trusted location code callout
1060*7b92372dSMatt Spinler         bool trusted = false;
10610398458dSMatt Spinler 
1062f00f9d0fSMatt Spinler         // Use the location code from the inventory path if there is one.
1063f00f9d0fSMatt Spinler         if (trustedSymbolicFRUInvPath)
1064f00f9d0fSMatt Spinler         {
1065f00f9d0fSMatt Spinler             try
1066f00f9d0fSMatt Spinler             {
1067f00f9d0fSMatt Spinler                 locCode = dataIface.getLocationCode(*trustedSymbolicFRUInvPath);
1068*7b92372dSMatt Spinler                 trusted = true;
1069f00f9d0fSMatt Spinler             }
1070f00f9d0fSMatt Spinler             catch (const std::exception& e)
1071f00f9d0fSMatt Spinler             {
1072f00f9d0fSMatt Spinler                 addDebugData(
10731aa90d49SJayanth Othayoth                     std::format("Could not get location code for {}: {}",
1074f00f9d0fSMatt Spinler                                 *trustedSymbolicFRUInvPath, e.what()));
1075f00f9d0fSMatt Spinler                 locCode.clear();
1076f00f9d0fSMatt Spinler             }
1077f00f9d0fSMatt Spinler         }
1078f00f9d0fSMatt Spinler 
1079*7b92372dSMatt Spinler         // Can only trust the location code if it isn't empty and is expanded.
1080*7b92372dSMatt Spinler         if (!locCode.empty() && locExpanded)
1081*7b92372dSMatt Spinler         {
1082*7b92372dSMatt Spinler             trusted = true;
1083*7b92372dSMatt Spinler         }
1084*7b92372dSMatt Spinler 
10850398458dSMatt Spinler         // The registry wants it to be trusted, but that requires a valid
10860398458dSMatt Spinler         // location code for it to actually be.
10870398458dSMatt Spinler         callout = std::make_unique<src::Callout>(
1088*7b92372dSMatt Spinler             priority, regCallout.symbolicFRUTrusted, locCode, trusted);
10890398458dSMatt Spinler     }
10900398458dSMatt Spinler     else
10910398458dSMatt Spinler     {
1092af191c7aSMatt Spinler         // A hardware callout
1093*7b92372dSMatt Spinler 
1094*7b92372dSMatt Spinler         // If couldn't expand the location code, don't bother
1095*7b92372dSMatt Spinler         // looking up the inventory path.
1096*7b92372dSMatt Spinler         if (!locExpanded && !locCode.empty())
1097*7b92372dSMatt Spinler         {
1098*7b92372dSMatt Spinler             addLocationCodeOnlyCallout(locCode, priority);
1099*7b92372dSMatt Spinler             return;
1100*7b92372dSMatt Spinler         }
1101*7b92372dSMatt Spinler 
1102bad056beSMatt Spinler         std::vector<std::string> inventoryPaths;
1103af191c7aSMatt Spinler 
1104af191c7aSMatt Spinler         try
1105af191c7aSMatt Spinler         {
1106af191c7aSMatt Spinler             // Get the inventory item from the unexpanded location code
1107bad056beSMatt Spinler             inventoryPaths =
11082f9225a4SMatt Spinler                 dataIface.getInventoryFromLocCode(regCallout.locCode, 0, false);
1109af191c7aSMatt Spinler         }
1110af191c7aSMatt Spinler         catch (const std::exception& e)
1111af191c7aSMatt Spinler         {
1112af191c7aSMatt Spinler             std::string msg =
1113af191c7aSMatt Spinler                 "Unable to get inventory path from location code: " + locCode +
1114af191c7aSMatt Spinler                 ": " + e.what();
1115af191c7aSMatt Spinler             addDebugData(msg);
1116*7b92372dSMatt Spinler             if (!locCode.empty())
1117*7b92372dSMatt Spinler             {
1118*7b92372dSMatt Spinler                 // Still add a callout with just the location code.
1119*7b92372dSMatt Spinler                 addLocationCodeOnlyCallout(locCode, priority);
1120*7b92372dSMatt Spinler             }
1121af191c7aSMatt Spinler             return;
1122af191c7aSMatt Spinler         }
1123af191c7aSMatt Spinler 
1124bad056beSMatt Spinler         // Just use first path returned since they all point to the same FRU.
1125bad056beSMatt Spinler         addInventoryCallout(inventoryPaths[0], priority, locCode, dataIface);
11260398458dSMatt Spinler     }
11270398458dSMatt Spinler 
11280398458dSMatt Spinler     if (callout)
11290398458dSMatt Spinler     {
11300398458dSMatt Spinler         createCalloutsObject();
11310398458dSMatt Spinler         _callouts->addCallout(std::move(callout));
11320398458dSMatt Spinler     }
11330398458dSMatt Spinler }
1134ed046856SMatt Spinler 
addDevicePathCallouts(const AdditionalData & additionalData,const DataInterfaceBase & dataIface)1135717de428SMatt Spinler void SRC::addDevicePathCallouts(const AdditionalData& additionalData,
1136717de428SMatt Spinler                                 const DataInterfaceBase& dataIface)
1137717de428SMatt Spinler {
1138717de428SMatt Spinler     std::vector<device_callouts::Callout> callouts;
1139717de428SMatt Spinler     auto i2cBus = additionalData.getValue("CALLOUT_IIC_BUS");
1140717de428SMatt Spinler     auto i2cAddr = additionalData.getValue("CALLOUT_IIC_ADDR");
1141717de428SMatt Spinler     auto devPath = additionalData.getValue("CALLOUT_DEVICE_PATH");
1142717de428SMatt Spinler 
1143717de428SMatt Spinler     // A device callout contains either:
1144717de428SMatt Spinler     // * CALLOUT_ERRNO, CALLOUT_DEVICE_PATH
1145717de428SMatt Spinler     // * CALLOUT_ERRNO, CALLOUT_IIC_BUS, CALLOUT_IIC_ADDR
1146717de428SMatt Spinler     // We don't care about the errno.
1147717de428SMatt Spinler 
1148717de428SMatt Spinler     if (devPath)
1149717de428SMatt Spinler     {
1150717de428SMatt Spinler         try
1151717de428SMatt Spinler         {
1152717de428SMatt Spinler             callouts = device_callouts::getCallouts(*devPath,
1153717de428SMatt Spinler                                                     dataIface.getSystemNames());
1154717de428SMatt Spinler         }
1155717de428SMatt Spinler         catch (const std::exception& e)
1156717de428SMatt Spinler         {
1157717de428SMatt Spinler             addDebugData(e.what());
1158717de428SMatt Spinler             callouts.clear();
1159717de428SMatt Spinler         }
1160717de428SMatt Spinler     }
1161717de428SMatt Spinler     else if (i2cBus && i2cAddr)
1162717de428SMatt Spinler     {
1163717de428SMatt Spinler         size_t bus;
1164717de428SMatt Spinler         uint8_t address;
1165717de428SMatt Spinler 
1166717de428SMatt Spinler         try
1167717de428SMatt Spinler         {
1168717de428SMatt Spinler             // If /dev/i2c- is prepended, remove it
1169717de428SMatt Spinler             if (i2cBus->find("/dev/i2c-") != std::string::npos)
1170717de428SMatt Spinler             {
1171717de428SMatt Spinler                 *i2cBus = i2cBus->substr(9);
1172717de428SMatt Spinler             }
1173717de428SMatt Spinler 
1174717de428SMatt Spinler             bus = stoul(*i2cBus, nullptr, 0);
1175717de428SMatt Spinler             address = stoul(*i2cAddr, nullptr, 0);
1176717de428SMatt Spinler         }
1177717de428SMatt Spinler         catch (const std::exception& e)
1178717de428SMatt Spinler         {
1179075c7923SPatrick Williams             std::string msg =
1180075c7923SPatrick Williams                 "Invalid CALLOUT_IIC_BUS " + *i2cBus + " or CALLOUT_IIC_ADDR " +
1181075c7923SPatrick Williams                 *i2cAddr + " in AdditionalData property";
1182717de428SMatt Spinler             addDebugData(msg);
1183717de428SMatt Spinler             return;
1184717de428SMatt Spinler         }
1185717de428SMatt Spinler 
1186717de428SMatt Spinler         try
1187717de428SMatt Spinler         {
1188717de428SMatt Spinler             callouts = device_callouts::getI2CCallouts(
1189717de428SMatt Spinler                 bus, address, dataIface.getSystemNames());
1190717de428SMatt Spinler         }
1191717de428SMatt Spinler         catch (const std::exception& e)
1192717de428SMatt Spinler         {
1193717de428SMatt Spinler             addDebugData(e.what());
1194717de428SMatt Spinler             callouts.clear();
1195717de428SMatt Spinler         }
1196717de428SMatt Spinler     }
1197717de428SMatt Spinler 
1198717de428SMatt Spinler     for (const auto& callout : callouts)
1199717de428SMatt Spinler     {
1200717de428SMatt Spinler         // The priority shouldn't be invalid, but check just in case.
1201717de428SMatt Spinler         CalloutPriority priority = CalloutPriority::high;
1202717de428SMatt Spinler 
1203717de428SMatt Spinler         if (!callout.priority.empty())
1204717de428SMatt Spinler         {
1205717de428SMatt Spinler             auto p = pel_values::findByValue(
1206717de428SMatt Spinler                 static_cast<uint32_t>(callout.priority[0]),
1207717de428SMatt Spinler                 pel_values::calloutPriorityValues);
1208717de428SMatt Spinler 
1209717de428SMatt Spinler             if (p != pel_values::calloutPriorityValues.end())
1210717de428SMatt Spinler             {
1211717de428SMatt Spinler                 priority = static_cast<CalloutPriority>(callout.priority[0]);
1212717de428SMatt Spinler             }
1213717de428SMatt Spinler             else
1214717de428SMatt Spinler             {
1215717de428SMatt Spinler                 std::string msg =
1216717de428SMatt Spinler                     "Invalid priority found in dev callout JSON: " +
1217717de428SMatt Spinler                     callout.priority[0];
1218717de428SMatt Spinler                 addDebugData(msg);
1219717de428SMatt Spinler             }
1220717de428SMatt Spinler         }
1221717de428SMatt Spinler 
12220d92b528SMatt Spinler         std::optional<std::string> locCode;
12230d92b528SMatt Spinler 
12240d92b528SMatt Spinler         try
12250d92b528SMatt Spinler         {
12260d92b528SMatt Spinler             locCode = dataIface.expandLocationCode(callout.locationCode, 0);
12270d92b528SMatt Spinler         }
12280d92b528SMatt Spinler         catch (const std::exception& e)
12290d92b528SMatt Spinler         {
12301aa90d49SJayanth Othayoth             auto msg = std::format("Unable to expand location code {}: {}",
12310d92b528SMatt Spinler                                    callout.locationCode, e.what());
12320d92b528SMatt Spinler             addDebugData(msg);
1233*7b92372dSMatt Spinler 
1234*7b92372dSMatt Spinler             // Add the callout with just the unexpanded location code.
1235*7b92372dSMatt Spinler             addLocationCodeOnlyCallout(callout.locationCode, priority);
1236*7b92372dSMatt Spinler             continue;
12370d92b528SMatt Spinler         }
12380d92b528SMatt Spinler 
1239717de428SMatt Spinler         try
1240717de428SMatt Spinler         {
1241bad056beSMatt Spinler             auto inventoryPaths = dataIface.getInventoryFromLocCode(
12422f9225a4SMatt Spinler                 callout.locationCode, 0, false);
1243717de428SMatt Spinler 
1244bad056beSMatt Spinler             // Just use first path returned since they all
1245bad056beSMatt Spinler             // point to the same FRU.
1246bad056beSMatt Spinler             addInventoryCallout(inventoryPaths[0], priority, locCode,
1247bad056beSMatt Spinler                                 dataIface);
1248717de428SMatt Spinler         }
1249717de428SMatt Spinler         catch (const std::exception& e)
1250717de428SMatt Spinler         {
1251717de428SMatt Spinler             std::string msg =
1252717de428SMatt Spinler                 "Unable to get inventory path from location code: " +
1253717de428SMatt Spinler                 callout.locationCode + ": " + e.what();
1254717de428SMatt Spinler             addDebugData(msg);
1255*7b92372dSMatt Spinler             // Add the callout with just the location code.
1256*7b92372dSMatt Spinler             addLocationCodeOnlyCallout(callout.locationCode, priority);
1257*7b92372dSMatt Spinler             continue;
1258717de428SMatt Spinler         }
1259717de428SMatt Spinler 
1260717de428SMatt Spinler         // Until the code is there to convert these MRU value strings to
1261717de428SMatt Spinler         // the official MRU values in the callout objects, just store
1262717de428SMatt Spinler         // the MRU name in the debug UserData section.
1263717de428SMatt Spinler         if (!callout.mru.empty())
1264717de428SMatt Spinler         {
1265717de428SMatt Spinler             std::string msg = "MRU: " + callout.mru;
1266717de428SMatt Spinler             addDebugData(msg);
1267717de428SMatt Spinler         }
1268717de428SMatt Spinler 
1269717de428SMatt Spinler         // getCallouts() may have generated some debug data it stored
1270717de428SMatt Spinler         // in a callout object.  Save it as well.
1271717de428SMatt Spinler         if (!callout.debug.empty())
1272717de428SMatt Spinler         {
1273717de428SMatt Spinler             addDebugData(callout.debug);
1274717de428SMatt Spinler         }
1275717de428SMatt Spinler     }
1276717de428SMatt Spinler }
1277717de428SMatt Spinler 
addJSONCallouts(const nlohmann::json & jsonCallouts,const DataInterfaceBase & dataIface)12785a90a95bSMatt Spinler void SRC::addJSONCallouts(const nlohmann::json& jsonCallouts,
12795a90a95bSMatt Spinler                           const DataInterfaceBase& dataIface)
12805a90a95bSMatt Spinler {
12815a90a95bSMatt Spinler     if (jsonCallouts.empty())
12825a90a95bSMatt Spinler     {
12835a90a95bSMatt Spinler         return;
12845a90a95bSMatt Spinler     }
12855a90a95bSMatt Spinler 
12865a90a95bSMatt Spinler     if (!jsonCallouts.is_array())
12875a90a95bSMatt Spinler     {
12885a90a95bSMatt Spinler         addDebugData("Callout JSON isn't an array");
12895a90a95bSMatt Spinler         return;
12905a90a95bSMatt Spinler     }
12915a90a95bSMatt Spinler 
12925a90a95bSMatt Spinler     for (const auto& callout : jsonCallouts)
12935a90a95bSMatt Spinler     {
12945a90a95bSMatt Spinler         try
12955a90a95bSMatt Spinler         {
12965a90a95bSMatt Spinler             addJSONCallout(callout, dataIface);
12975a90a95bSMatt Spinler         }
12985a90a95bSMatt Spinler         catch (const std::exception& e)
12995a90a95bSMatt Spinler         {
13001aa90d49SJayanth Othayoth             addDebugData(std::format(
13015a90a95bSMatt Spinler                 "Failed extracting callout data from JSON: {}", e.what()));
13025a90a95bSMatt Spinler         }
13035a90a95bSMatt Spinler     }
13045a90a95bSMatt Spinler }
13055a90a95bSMatt Spinler 
addJSONCallout(const nlohmann::json & jsonCallout,const DataInterfaceBase & dataIface)13065a90a95bSMatt Spinler void SRC::addJSONCallout(const nlohmann::json& jsonCallout,
13075a90a95bSMatt Spinler                          const DataInterfaceBase& dataIface)
13085a90a95bSMatt Spinler {
13093bdd0110SMatt Spinler     auto priority = getPriorityFromJSON(jsonCallout);
13103bdd0110SMatt Spinler     std::string locCode;
13113bdd0110SMatt Spinler     std::string unexpandedLocCode;
13123bdd0110SMatt Spinler     std::unique_ptr<src::Callout> callout;
13133bdd0110SMatt Spinler 
13143bdd0110SMatt Spinler     // Expand the location code if it's there
13153bdd0110SMatt Spinler     if (jsonCallout.contains("LocationCode"))
13163bdd0110SMatt Spinler     {
13173bdd0110SMatt Spinler         unexpandedLocCode = jsonCallout.at("LocationCode").get<std::string>();
13183bdd0110SMatt Spinler 
13193bdd0110SMatt Spinler         try
13203bdd0110SMatt Spinler         {
13213bdd0110SMatt Spinler             locCode = dataIface.expandLocationCode(unexpandedLocCode, 0);
13223bdd0110SMatt Spinler         }
13233bdd0110SMatt Spinler         catch (const std::exception& e)
13243bdd0110SMatt Spinler         {
13251aa90d49SJayanth Othayoth             addDebugData(std::format("Unable to expand location code {}: {}",
13263bdd0110SMatt Spinler                                      unexpandedLocCode, e.what()));
13273bdd0110SMatt Spinler             // Use the value from the JSON so at least there's something
13283bdd0110SMatt Spinler             locCode = unexpandedLocCode;
13293bdd0110SMatt Spinler         }
13303bdd0110SMatt Spinler     }
13313bdd0110SMatt Spinler 
13323bdd0110SMatt Spinler     // Create either a procedure, symbolic FRU, or normal FRU callout.
13333bdd0110SMatt Spinler     if (jsonCallout.contains("Procedure"))
13343bdd0110SMatt Spinler     {
13353bdd0110SMatt Spinler         auto procedure = jsonCallout.at("Procedure").get<std::string>();
13363bdd0110SMatt Spinler 
13373c7ec6d8SMatt Spinler         // If it's the registry name instead of the raw name, convert.
13383c7ec6d8SMatt Spinler         if (pv::maintenanceProcedures.find(procedure) !=
13393c7ec6d8SMatt Spinler             pv::maintenanceProcedures.end())
13403c7ec6d8SMatt Spinler         {
13413c7ec6d8SMatt Spinler             procedure = pv::maintenanceProcedures.at(procedure);
13423c7ec6d8SMatt Spinler         }
13433c7ec6d8SMatt Spinler 
13443bdd0110SMatt Spinler         callout = std::make_unique<src::Callout>(
13453bdd0110SMatt Spinler             static_cast<CalloutPriority>(priority), procedure,
13463bdd0110SMatt Spinler             src::CalloutValueType::raw);
13473bdd0110SMatt Spinler     }
13483bdd0110SMatt Spinler     else if (jsonCallout.contains("SymbolicFRU"))
13493bdd0110SMatt Spinler     {
13503bdd0110SMatt Spinler         auto fru = jsonCallout.at("SymbolicFRU").get<std::string>();
13513bdd0110SMatt Spinler 
13523c7ec6d8SMatt Spinler         // If it's the registry name instead of the raw name, convert.
13533c7ec6d8SMatt Spinler         if (pv::symbolicFRUs.find(fru) != pv::symbolicFRUs.end())
13543c7ec6d8SMatt Spinler         {
13553c7ec6d8SMatt Spinler             fru = pv::symbolicFRUs.at(fru);
13563c7ec6d8SMatt Spinler         }
13573c7ec6d8SMatt Spinler 
13583bdd0110SMatt Spinler         bool trusted = false;
13593bdd0110SMatt Spinler         if (jsonCallout.contains("TrustedLocationCode") && !locCode.empty())
13603bdd0110SMatt Spinler         {
13613bdd0110SMatt Spinler             trusted = jsonCallout.at("TrustedLocationCode").get<bool>();
13623bdd0110SMatt Spinler         }
13633bdd0110SMatt Spinler 
13643bdd0110SMatt Spinler         callout = std::make_unique<src::Callout>(
13653bdd0110SMatt Spinler             static_cast<CalloutPriority>(priority), fru,
13663bdd0110SMatt Spinler             src::CalloutValueType::raw, locCode, trusted);
13673bdd0110SMatt Spinler     }
13683bdd0110SMatt Spinler     else
13693bdd0110SMatt Spinler     {
13703bdd0110SMatt Spinler         // A hardware FRU
13713bdd0110SMatt Spinler         std::string inventoryPath;
1372b8cb60feSMatt Spinler         std::vector<src::MRU::MRUCallout> mrus;
13733bdd0110SMatt Spinler 
13743bdd0110SMatt Spinler         if (jsonCallout.contains("InventoryPath"))
13753bdd0110SMatt Spinler         {
13763bdd0110SMatt Spinler             inventoryPath = jsonCallout.at("InventoryPath").get<std::string>();
13773bdd0110SMatt Spinler         }
13783bdd0110SMatt Spinler         else
13793bdd0110SMatt Spinler         {
13803bdd0110SMatt Spinler             if (unexpandedLocCode.empty())
13813bdd0110SMatt Spinler             {
13823bdd0110SMatt Spinler                 throw std::runtime_error{"JSON callout needs either an "
13833bdd0110SMatt Spinler                                          "inventory path or location code"};
13843bdd0110SMatt Spinler             }
13853bdd0110SMatt Spinler 
13863bdd0110SMatt Spinler             try
13873bdd0110SMatt Spinler             {
1388bad056beSMatt Spinler                 auto inventoryPaths = dataIface.getInventoryFromLocCode(
13893bdd0110SMatt Spinler                     unexpandedLocCode, 0, false);
1390bad056beSMatt Spinler                 // Just use first path returned since they all
1391bad056beSMatt Spinler                 // point to the same FRU.
1392bad056beSMatt Spinler                 inventoryPath = inventoryPaths[0];
13933bdd0110SMatt Spinler             }
13943bdd0110SMatt Spinler             catch (const std::exception& e)
13953bdd0110SMatt Spinler             {
1396*7b92372dSMatt Spinler                 addDebugData(std::format("Unable to get inventory path from "
13973bdd0110SMatt Spinler                                          "location code: {}: {}",
1398*7b92372dSMatt Spinler                                          unexpandedLocCode, e.what()));
1399*7b92372dSMatt Spinler                 addLocationCodeOnlyCallout(locCode, priority);
1400*7b92372dSMatt Spinler                 return;
14013bdd0110SMatt Spinler             }
14023bdd0110SMatt Spinler         }
14033bdd0110SMatt Spinler 
1404b8cb60feSMatt Spinler         if (jsonCallout.contains("MRUs"))
1405b8cb60feSMatt Spinler         {
1406b8cb60feSMatt Spinler             mrus = getMRUsFromJSON(jsonCallout.at("MRUs"));
1407b8cb60feSMatt Spinler         }
1408b8cb60feSMatt Spinler 
14093bdd0110SMatt Spinler         // If the location code was also passed in, use that here too
14103bdd0110SMatt Spinler         // so addInventoryCallout doesn't have to look it up.
14113bdd0110SMatt Spinler         std::optional<std::string> lc;
14123bdd0110SMatt Spinler         if (!locCode.empty())
14133bdd0110SMatt Spinler         {
14143bdd0110SMatt Spinler             lc = locCode;
14153bdd0110SMatt Spinler         }
14163bdd0110SMatt Spinler 
1417b8cb60feSMatt Spinler         addInventoryCallout(inventoryPath, priority, lc, dataIface, mrus);
1418afa2c799SMatt Spinler 
1419afa2c799SMatt Spinler         if (jsonCallout.contains("Deconfigured"))
1420afa2c799SMatt Spinler         {
1421afa2c799SMatt Spinler             if (jsonCallout.at("Deconfigured").get<bool>())
1422afa2c799SMatt Spinler             {
1423afa2c799SMatt Spinler                 setErrorStatusFlag(ErrorStatusFlags::deconfigured);
1424afa2c799SMatt Spinler             }
1425afa2c799SMatt Spinler         }
1426afa2c799SMatt Spinler 
1427afa2c799SMatt Spinler         if (jsonCallout.contains("Guarded"))
1428afa2c799SMatt Spinler         {
1429afa2c799SMatt Spinler             if (jsonCallout.at("Guarded").get<bool>())
1430afa2c799SMatt Spinler             {
1431afa2c799SMatt Spinler                 setErrorStatusFlag(ErrorStatusFlags::guarded);
1432afa2c799SMatt Spinler             }
1433afa2c799SMatt Spinler         }
14343bdd0110SMatt Spinler     }
14353bdd0110SMatt Spinler 
14363bdd0110SMatt Spinler     if (callout)
14373bdd0110SMatt Spinler     {
14383bdd0110SMatt Spinler         createCalloutsObject();
14393bdd0110SMatt Spinler         _callouts->addCallout(std::move(callout));
14403bdd0110SMatt Spinler     }
14413bdd0110SMatt Spinler }
14423bdd0110SMatt Spinler 
getPriorityFromJSON(const nlohmann::json & json)14433bdd0110SMatt Spinler CalloutPriority SRC::getPriorityFromJSON(const nlohmann::json& json)
14443bdd0110SMatt Spinler {
14453bdd0110SMatt Spinler     // Looks like:
14463bdd0110SMatt Spinler     // {
14473bdd0110SMatt Spinler     //     "Priority": "H"
14483bdd0110SMatt Spinler     // }
14493bdd0110SMatt Spinler     auto p = json.at("Priority").get<std::string>();
14503bdd0110SMatt Spinler     if (p.empty())
14513bdd0110SMatt Spinler     {
14523bdd0110SMatt Spinler         throw std::runtime_error{"Priority field in callout is empty"};
14533bdd0110SMatt Spinler     }
14543bdd0110SMatt Spinler 
14553bdd0110SMatt Spinler     auto priority = static_cast<CalloutPriority>(p.front());
14563bdd0110SMatt Spinler 
14573bdd0110SMatt Spinler     // Validate it
14583bdd0110SMatt Spinler     auto priorityIt = pv::findByValue(static_cast<uint32_t>(priority),
14593bdd0110SMatt Spinler                                       pv::calloutPriorityValues);
14603bdd0110SMatt Spinler     if (priorityIt == pv::calloutPriorityValues.end())
14613bdd0110SMatt Spinler     {
14623bdd0110SMatt Spinler         throw std::runtime_error{
14631aa90d49SJayanth Othayoth             std::format("Invalid priority '{}' found in JSON callout", p)};
14643bdd0110SMatt Spinler     }
14653bdd0110SMatt Spinler 
14663bdd0110SMatt Spinler     return priority;
14675a90a95bSMatt Spinler }
14685a90a95bSMatt Spinler 
getMRUsFromJSON(const nlohmann::json & mruJSON)146925291157SPatrick Williams std::vector<src::MRU::MRUCallout> SRC::getMRUsFromJSON(
147025291157SPatrick Williams     const nlohmann::json& mruJSON)
1471b8cb60feSMatt Spinler {
1472b8cb60feSMatt Spinler     std::vector<src::MRU::MRUCallout> mrus;
1473b8cb60feSMatt Spinler 
1474b8cb60feSMatt Spinler     // Looks like:
1475b8cb60feSMatt Spinler     // [
1476b8cb60feSMatt Spinler     //     {
1477b8cb60feSMatt Spinler     //         "ID": 100,
1478b8cb60feSMatt Spinler     //         "Priority": "H"
1479b8cb60feSMatt Spinler     //     }
1480b8cb60feSMatt Spinler     // ]
1481b8cb60feSMatt Spinler     if (!mruJSON.is_array())
1482b8cb60feSMatt Spinler     {
1483b8cb60feSMatt Spinler         addDebugData("MRU callout JSON is not an array");
1484b8cb60feSMatt Spinler         return mrus;
1485b8cb60feSMatt Spinler     }
1486b8cb60feSMatt Spinler 
1487b8cb60feSMatt Spinler     for (const auto& mruCallout : mruJSON)
1488b8cb60feSMatt Spinler     {
1489b8cb60feSMatt Spinler         try
1490b8cb60feSMatt Spinler         {
1491b8cb60feSMatt Spinler             auto priority = getPriorityFromJSON(mruCallout);
1492b8cb60feSMatt Spinler             auto id = mruCallout.at("ID").get<uint32_t>();
1493b8cb60feSMatt Spinler 
1494b8cb60feSMatt Spinler             src::MRU::MRUCallout mru{static_cast<uint32_t>(priority), id};
1495b8cb60feSMatt Spinler             mrus.push_back(std::move(mru));
1496b8cb60feSMatt Spinler         }
1497b8cb60feSMatt Spinler         catch (const std::exception& e)
1498b8cb60feSMatt Spinler         {
14991aa90d49SJayanth Othayoth             addDebugData(std::format("Invalid MRU entry in JSON: {}: {}",
1500b8cb60feSMatt Spinler                                      mruCallout.dump(), e.what()));
1501b8cb60feSMatt Spinler         }
1502b8cb60feSMatt Spinler     }
1503b8cb60feSMatt Spinler 
1504b8cb60feSMatt Spinler     return mrus;
1505b8cb60feSMatt Spinler }
1506b8cb60feSMatt Spinler 
getSrcStruct()15073e274432SSumit Kumar std::vector<uint8_t> SRC::getSrcStruct()
15083e274432SSumit Kumar {
15093e274432SSumit Kumar     std::vector<uint8_t> data;
15103e274432SSumit Kumar     Stream stream{data};
15113e274432SSumit Kumar 
15123e274432SSumit Kumar     //------ Ref section 4.3 in PEL doc---
15133e274432SSumit Kumar     //------ SRC Structure 40 bytes-------
15143e274432SSumit Kumar     // Byte-0 | Byte-1 | Byte-2 | Byte-3 |
15153e274432SSumit Kumar     // -----------------------------------
15163e274432SSumit Kumar     //   02   |   08   |   00   |   09   | ==> Header
15173e274432SSumit Kumar     //   00   |   00   |   00   |   48   | ==> Header
15183e274432SSumit Kumar     //   00   |   00   |   00   |   00   | ==> Hex data word-2
15193e274432SSumit Kumar     //   00   |   00   |   00   |   00   | ==> Hex data word-3
15203e274432SSumit Kumar     //   00   |   00   |   00   |   00   | ==> Hex data word-4
15213e274432SSumit Kumar     //   20   |   00   |   00   |   00   | ==> Hex data word-5
15223e274432SSumit Kumar     //   00   |   00   |   00   |   00   | ==> Hex data word-6
15233e274432SSumit Kumar     //   00   |   00   |   00   |   00   | ==> Hex data word-7
15243e274432SSumit Kumar     //   00   |   00   |   00   |   00   | ==> Hex data word-8
15253e274432SSumit Kumar     //   00   |   00   |   00   |   00   | ==> Hex data word-9
15263e274432SSumit Kumar     // -----------------------------------
15273e274432SSumit Kumar     //   ASCII string - 8 bytes          |
15283e274432SSumit Kumar     // -----------------------------------
15293e274432SSumit Kumar     //   ASCII space NULL - 24 bytes     |
15303e274432SSumit Kumar     // -----------------------------------
15313e274432SSumit Kumar     //_size = Base SRC struct: 8 byte header + hex data section + ASCII string
15323e274432SSumit Kumar 
15333e274432SSumit Kumar     uint8_t flags = (_flags | postOPPanel);
15343e274432SSumit Kumar 
15353e274432SSumit Kumar     stream << _version << flags << _reserved1B << _wordCount << _reserved2B
15363e274432SSumit Kumar            << _size;
15373e274432SSumit Kumar 
15383e274432SSumit Kumar     for (auto& word : _hexData)
15393e274432SSumit Kumar     {
15403e274432SSumit Kumar         stream << word;
15413e274432SSumit Kumar     }
15423e274432SSumit Kumar 
15433e274432SSumit Kumar     _asciiString->flatten(stream);
15443e274432SSumit Kumar 
15453e274432SSumit Kumar     return data;
15463e274432SSumit Kumar }
15473e274432SSumit Kumar 
setProgressCode(const DataInterfaceBase & dataIface)1548875b6c7bSVijay Lobo void SRC::setProgressCode(const DataInterfaceBase& dataIface)
1549875b6c7bSVijay Lobo {
1550875b6c7bSVijay Lobo     std::vector<uint8_t> progressSRC;
1551875b6c7bSVijay Lobo 
1552875b6c7bSVijay Lobo     try
1553875b6c7bSVijay Lobo     {
1554875b6c7bSVijay Lobo         progressSRC = dataIface.getRawProgressSRC();
1555875b6c7bSVijay Lobo     }
1556875b6c7bSVijay Lobo     catch (const std::exception& e)
1557875b6c7bSVijay Lobo     {
15580bacc8efSMatt Spinler         lg2::error("Error getting progress code: {ERROR}", "ERROR", e);
1559875b6c7bSVijay Lobo         return;
1560875b6c7bSVijay Lobo     }
1561875b6c7bSVijay Lobo 
1562875b6c7bSVijay Lobo     _hexData[2] = getProgressCode(progressSRC);
1563875b6c7bSVijay Lobo }
1564875b6c7bSVijay Lobo 
getProgressCode(std::vector<uint8_t> & rawProgressSRC)1565875b6c7bSVijay Lobo uint32_t SRC::getProgressCode(std::vector<uint8_t>& rawProgressSRC)
1566875b6c7bSVijay Lobo {
1567875b6c7bSVijay Lobo     uint32_t progressCode = 0;
1568875b6c7bSVijay Lobo 
1569875b6c7bSVijay Lobo     // A valid progress SRC is at least 72 bytes
1570875b6c7bSVijay Lobo     if (rawProgressSRC.size() < 72)
1571875b6c7bSVijay Lobo     {
1572875b6c7bSVijay Lobo         return progressCode;
1573875b6c7bSVijay Lobo     }
1574875b6c7bSVijay Lobo 
1575875b6c7bSVijay Lobo     try
1576875b6c7bSVijay Lobo     {
1577875b6c7bSVijay Lobo         // The ASCII string field in progress SRCs starts at offset 40.
1578875b6c7bSVijay Lobo         // Take the first 8 characters to put in the uint32:
1579875b6c7bSVijay Lobo         //   "CC009189" -> 0xCC009189
1580875b6c7bSVijay Lobo         Stream stream{rawProgressSRC, 40};
1581875b6c7bSVijay Lobo         src::AsciiString aString{stream};
1582875b6c7bSVijay Lobo         auto progressCodeString = aString.get().substr(0, 8);
1583875b6c7bSVijay Lobo 
1584875b6c7bSVijay Lobo         if (std::all_of(progressCodeString.begin(), progressCodeString.end(),
1585875b6c7bSVijay Lobo                         [](char c) {
1586875b6c7bSVijay Lobo                             return std::isxdigit(static_cast<unsigned char>(c));
1587875b6c7bSVijay Lobo                         }))
1588875b6c7bSVijay Lobo         {
1589875b6c7bSVijay Lobo             progressCode = std::stoul(progressCodeString, nullptr, 16);
1590875b6c7bSVijay Lobo         }
1591875b6c7bSVijay Lobo     }
1592875b6c7bSVijay Lobo     catch (const std::exception& e)
1593875b6c7bSVijay Lobo     {}
1594875b6c7bSVijay Lobo 
1595875b6c7bSVijay Lobo     return progressCode;
1596875b6c7bSVijay Lobo }
1597875b6c7bSVijay Lobo 
1598f9bae185SMatt Spinler } // namespace pels
1599f9bae185SMatt Spinler } // namespace openpower
1600