1c63e2e82SMatt Spinler /**
2c63e2e82SMatt Spinler * Copyright © 2019 IBM Corporation
3c63e2e82SMatt Spinler *
4c63e2e82SMatt Spinler * Licensed under the Apache License, Version 2.0 (the "License");
5c63e2e82SMatt Spinler * you may not use this file except in compliance with the License.
6c63e2e82SMatt Spinler * You may obtain a copy of the License at
7c63e2e82SMatt Spinler *
8c63e2e82SMatt Spinler * http://www.apache.org/licenses/LICENSE-2.0
9c63e2e82SMatt Spinler *
10c63e2e82SMatt Spinler * Unless required by applicable law or agreed to in writing, software
11c63e2e82SMatt Spinler * distributed under the License is distributed on an "AS IS" BASIS,
12c63e2e82SMatt Spinler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c63e2e82SMatt Spinler * See the License for the specific language governing permissions and
14c63e2e82SMatt Spinler * limitations under the License.
15c63e2e82SMatt Spinler */
16c63e2e82SMatt Spinler #include "extended_user_header.hpp"
17c63e2e82SMatt Spinler
18160c51cbSHarisuddin Mohamed Isa #include "json_utils.hpp"
19c63e2e82SMatt Spinler #include "pel_types.hpp"
20bebeb948SHarisuddin Mohamed Isa #include "pel_values.hpp"
21c63e2e82SMatt Spinler
22*5bc26533SArya K Padman #include <phosphor-logging/lg2.hpp>
23c63e2e82SMatt Spinler
24c63e2e82SMatt Spinler namespace openpower
25c63e2e82SMatt Spinler {
26c63e2e82SMatt Spinler namespace pels
27c63e2e82SMatt Spinler {
28c63e2e82SMatt Spinler
29bebeb948SHarisuddin Mohamed Isa namespace pv = openpower::pels::pel_values;
30*5bc26533SArya K Padman
31c63e2e82SMatt Spinler const size_t defaultSymptomIDWord = 3;
32c63e2e82SMatt Spinler const size_t symptomIDMaxSize = 80;
33c63e2e82SMatt Spinler
ExtendedUserHeader(Stream & pel)34c63e2e82SMatt Spinler ExtendedUserHeader::ExtendedUserHeader(Stream& pel)
35c63e2e82SMatt Spinler {
36c63e2e82SMatt Spinler try
37c63e2e82SMatt Spinler {
38c63e2e82SMatt Spinler unflatten(pel);
39c63e2e82SMatt Spinler validate();
40c63e2e82SMatt Spinler }
41c63e2e82SMatt Spinler catch (const std::exception& e)
42c63e2e82SMatt Spinler {
43*5bc26533SArya K Padman lg2::error("Cannot unflatten extended user header: {EXCEPTION}",
44*5bc26533SArya K Padman "EXCEPTION", e);
45c63e2e82SMatt Spinler _valid = false;
46c63e2e82SMatt Spinler }
47c63e2e82SMatt Spinler }
48c63e2e82SMatt Spinler
ExtendedUserHeader(const DataInterfaceBase & dataIface,const message::Entry & regEntry,const SRC & src)49c63e2e82SMatt Spinler ExtendedUserHeader::ExtendedUserHeader(const DataInterfaceBase& dataIface,
50c63e2e82SMatt Spinler const message::Entry& regEntry,
51c63e2e82SMatt Spinler const SRC& src) :
52c63e2e82SMatt Spinler _mtms(dataIface.getMachineTypeModel(), dataIface.getMachineSerialNumber())
53c63e2e82SMatt Spinler {
54c63e2e82SMatt Spinler _header.id = static_cast<uint16_t>(SectionID::extendedUserHeader);
55c63e2e82SMatt Spinler _header.version = extendedUserHeaderVersion;
56c63e2e82SMatt Spinler _header.subType = 0;
57c63e2e82SMatt Spinler _header.componentID = static_cast<uint16_t>(ComponentID::phosphorLogging);
58c63e2e82SMatt Spinler
59c63e2e82SMatt Spinler memset(_serverFWVersion.data(), 0, _serverFWVersion.size());
60c63e2e82SMatt Spinler auto version = dataIface.getServerFWVersion();
61c63e2e82SMatt Spinler
62c63e2e82SMatt Spinler // The last byte must always be the NULL terminator
63c63e2e82SMatt Spinler for (size_t i = 0; i < version.size() && i < firmwareVersionSize - 1; i++)
64c63e2e82SMatt Spinler {
65c63e2e82SMatt Spinler _serverFWVersion[i] = version[i];
66c63e2e82SMatt Spinler }
67c63e2e82SMatt Spinler
68c63e2e82SMatt Spinler memset(_subsystemFWVersion.data(), 0, _subsystemFWVersion.size());
69c63e2e82SMatt Spinler version = dataIface.getBMCFWVersion();
70c63e2e82SMatt Spinler
71c63e2e82SMatt Spinler // The last byte must always be the NULL terminator
72c63e2e82SMatt Spinler for (size_t i = 0; i < version.size() && i < firmwareVersionSize - 1; i++)
73c63e2e82SMatt Spinler {
74c63e2e82SMatt Spinler _subsystemFWVersion[i] = version[i];
75c63e2e82SMatt Spinler }
76c63e2e82SMatt Spinler
77c63e2e82SMatt Spinler createSymptomID(regEntry, src);
78c63e2e82SMatt Spinler
79c63e2e82SMatt Spinler _header.size = flattenedSize();
80c63e2e82SMatt Spinler _valid = true;
81c63e2e82SMatt Spinler }
82c63e2e82SMatt Spinler
flatten(Stream & pel) const83c63e2e82SMatt Spinler void ExtendedUserHeader::flatten(Stream& pel) const
84c63e2e82SMatt Spinler {
85c63e2e82SMatt Spinler pel << _header << _mtms;
86c63e2e82SMatt Spinler pel.write(_serverFWVersion.data(), _serverFWVersion.size());
87c63e2e82SMatt Spinler pel.write(_subsystemFWVersion.data(), _subsystemFWVersion.size());
88c63e2e82SMatt Spinler pel << _reserved4B << _refTime << _reserved1B1 << _reserved1B2
89c63e2e82SMatt Spinler << _reserved1B3 << _symptomIDSize << _symptomID;
90c63e2e82SMatt Spinler }
91c63e2e82SMatt Spinler
unflatten(Stream & pel)92c63e2e82SMatt Spinler void ExtendedUserHeader::unflatten(Stream& pel)
93c63e2e82SMatt Spinler {
94c63e2e82SMatt Spinler pel >> _header >> _mtms;
95c63e2e82SMatt Spinler pel.read(_serverFWVersion.data(), _serverFWVersion.size());
96c63e2e82SMatt Spinler pel.read(_subsystemFWVersion.data(), _subsystemFWVersion.size());
97c63e2e82SMatt Spinler pel >> _reserved4B >> _refTime >> _reserved1B1 >> _reserved1B2 >>
98c63e2e82SMatt Spinler _reserved1B3 >> _symptomIDSize;
99c63e2e82SMatt Spinler
100c63e2e82SMatt Spinler _symptomID.resize(_symptomIDSize);
101c63e2e82SMatt Spinler pel >> _symptomID;
102c63e2e82SMatt Spinler }
103c63e2e82SMatt Spinler
validate()104c63e2e82SMatt Spinler void ExtendedUserHeader::validate()
105c63e2e82SMatt Spinler {
106c63e2e82SMatt Spinler bool failed = false;
107c63e2e82SMatt Spinler
108c63e2e82SMatt Spinler if (header().id != static_cast<uint16_t>(SectionID::extendedUserHeader))
109c63e2e82SMatt Spinler {
110*5bc26533SArya K Padman lg2::error("Invalid ExtendedUserHeader section ID: {HEADER_ID}",
111*5bc26533SArya K Padman "HEADER_ID", lg2::hex, header().id);
112c63e2e82SMatt Spinler failed = true;
113c63e2e82SMatt Spinler }
114c63e2e82SMatt Spinler
115c63e2e82SMatt Spinler if (header().version != extendedUserHeaderVersion)
116c63e2e82SMatt Spinler {
117*5bc26533SArya K Padman lg2::error("Invalid ExtendedUserHeader version: {HEADER_VERSION}",
118*5bc26533SArya K Padman "HEADER_VERSION", lg2::hex, header().version);
119c63e2e82SMatt Spinler failed = true;
120c63e2e82SMatt Spinler }
121c63e2e82SMatt Spinler
122c63e2e82SMatt Spinler _valid = (failed) ? false : true;
123c63e2e82SMatt Spinler }
124c63e2e82SMatt Spinler
createSymptomID(const message::Entry & regEntry,const SRC & src)125c63e2e82SMatt Spinler void ExtendedUserHeader::createSymptomID(const message::Entry& regEntry,
126c63e2e82SMatt Spinler const SRC& src)
127c63e2e82SMatt Spinler {
128c63e2e82SMatt Spinler // Contains the first 8 characters of the ASCII string plus additional
129c63e2e82SMatt Spinler // words from the SRC, separated by underscores. The message registry
130c63e2e82SMatt Spinler // says which words to use, though that's optional and if not present
131c63e2e82SMatt Spinler // then use a default word.
132c63e2e82SMatt Spinler std::vector<size_t> idWords;
133c63e2e82SMatt Spinler
134c63e2e82SMatt Spinler if (regEntry.src.symptomID)
135c63e2e82SMatt Spinler {
136c63e2e82SMatt Spinler idWords = regEntry.src.symptomID.value();
137c63e2e82SMatt Spinler }
138c63e2e82SMatt Spinler else
139c63e2e82SMatt Spinler {
140c63e2e82SMatt Spinler idWords.push_back(defaultSymptomIDWord);
141c63e2e82SMatt Spinler }
142c63e2e82SMatt Spinler
143c63e2e82SMatt Spinler auto symptomID = src.asciiString().substr(0, 8);
144c63e2e82SMatt Spinler
145c63e2e82SMatt Spinler const auto& hexWords = src.hexwordData();
146c63e2e82SMatt Spinler
147c63e2e82SMatt Spinler for (auto wordNum : idWords)
148c63e2e82SMatt Spinler {
149c63e2e82SMatt Spinler symptomID.push_back('_');
150c63e2e82SMatt Spinler
151c63e2e82SMatt Spinler // Get the hexword array index for this SRC word
152c63e2e82SMatt Spinler auto index = src.getWordIndexFromWordNum(wordNum);
153c63e2e82SMatt Spinler
154c63e2e82SMatt Spinler // Convert to ASCII
155c63e2e82SMatt Spinler char word[20];
156c63e2e82SMatt Spinler sprintf(word, "%08X", hexWords[index]);
157c63e2e82SMatt Spinler symptomID += word;
158c63e2e82SMatt Spinler }
159c63e2e82SMatt Spinler
160c63e2e82SMatt Spinler std::copy(symptomID.begin(), symptomID.end(),
161c63e2e82SMatt Spinler std::back_inserter(_symptomID));
162c63e2e82SMatt Spinler
163c63e2e82SMatt Spinler // Max total size is 80, including the upcoming NULL
164c63e2e82SMatt Spinler if (_symptomID.size() > (symptomIDMaxSize - 1))
165c63e2e82SMatt Spinler {
166c63e2e82SMatt Spinler _symptomID.resize(symptomIDMaxSize - 1);
167c63e2e82SMatt Spinler }
168c63e2e82SMatt Spinler
169c63e2e82SMatt Spinler // NULL terminated
170c63e2e82SMatt Spinler _symptomID.push_back(0);
171c63e2e82SMatt Spinler
172c63e2e82SMatt Spinler // PAD with NULLs to a 4 byte boundary
173c63e2e82SMatt Spinler while ((_symptomID.size() % 4) != 0)
174c63e2e82SMatt Spinler {
175c63e2e82SMatt Spinler _symptomID.push_back(0);
176c63e2e82SMatt Spinler }
177c63e2e82SMatt Spinler
178c63e2e82SMatt Spinler _symptomIDSize = _symptomID.size();
179c63e2e82SMatt Spinler }
180c63e2e82SMatt Spinler
getJSON(uint8_t creatorID) const181b832aa5eSMatt Spinler std::optional<std::string> ExtendedUserHeader::getJSON(uint8_t creatorID) const
182160c51cbSHarisuddin Mohamed Isa {
183160c51cbSHarisuddin Mohamed Isa std::string json;
184bebeb948SHarisuddin Mohamed Isa jsonInsert(json, pv::sectionVer, getNumberString("%d", _header.version), 1);
185bebeb948SHarisuddin Mohamed Isa jsonInsert(json, pv::subSection, getNumberString("%d", _header.subType), 1);
186bebeb948SHarisuddin Mohamed Isa jsonInsert(json, pv::createdBy,
187b832aa5eSMatt Spinler getComponentName(_header.componentID, creatorID), 1);
188160c51cbSHarisuddin Mohamed Isa jsonInsert(json, "Reporting Machine Type", machineTypeModel(), 1);
189160c51cbSHarisuddin Mohamed Isa jsonInsert(json, "Reporting Serial Number", trimEnd(machineSerialNumber()),
190160c51cbSHarisuddin Mohamed Isa 1);
191160c51cbSHarisuddin Mohamed Isa jsonInsert(json, "FW Released Ver", serverFWVersion(), 1);
192160c51cbSHarisuddin Mohamed Isa jsonInsert(json, "FW SubSys Version", subsystemFWVersion(), 1);
193160c51cbSHarisuddin Mohamed Isa jsonInsert(json, "Common Ref Time",
194160c51cbSHarisuddin Mohamed Isa getNumberString("%02X", _refTime.month) + '/' +
195160c51cbSHarisuddin Mohamed Isa getNumberString("%02X", _refTime.day) + '/' +
196160c51cbSHarisuddin Mohamed Isa getNumberString("%02X", _refTime.yearMSB) +
197160c51cbSHarisuddin Mohamed Isa getNumberString("%02X", _refTime.yearLSB) + ' ' +
198160c51cbSHarisuddin Mohamed Isa getNumberString("%02X", _refTime.hour) + ':' +
199160c51cbSHarisuddin Mohamed Isa getNumberString("%02X", _refTime.minutes) + ':' +
200160c51cbSHarisuddin Mohamed Isa getNumberString("%02X", _refTime.seconds),
201160c51cbSHarisuddin Mohamed Isa 1);
202160c51cbSHarisuddin Mohamed Isa jsonInsert(json, "Symptom Id Len", getNumberString("%d", _symptomIDSize),
203160c51cbSHarisuddin Mohamed Isa 1);
204160c51cbSHarisuddin Mohamed Isa jsonInsert(json, "Symptom Id", symptomID(), 1);
205160c51cbSHarisuddin Mohamed Isa json.erase(json.size() - 2);
206160c51cbSHarisuddin Mohamed Isa return json;
207160c51cbSHarisuddin Mohamed Isa }
208160c51cbSHarisuddin Mohamed Isa
209c63e2e82SMatt Spinler } // namespace pels
210c63e2e82SMatt Spinler } // namespace openpower
211