blob: 41dc7692d3ab3e64da66f0f1762b2074b5171ab3 [file] [log] [blame]
Alexander Hansen40fb5492025-10-28 17:56:12 +01001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright 2019 IBM Corporation
3
Matt Spinlera906c942019-10-08 13:42:05 -05004#include "fru_identity.hpp"
5
Matt Spinlerba0ee002020-03-13 11:24:14 -05006#include "pel_values.hpp"
7
Arya K Padman5bc26532024-04-10 06:19:25 -05008#include <phosphor-logging/lg2.hpp>
Matt Spinlera27e2e52020-04-09 11:06:11 -05009
Matt Spinlera906c942019-10-08 13:42:05 -050010namespace openpower
11{
12namespace pels
13{
14namespace src
15{
16
Matt Spinler18f4b6e2020-05-21 11:36:24 -050017namespace
18{
19
20/**
21 * @brief Fills in the std::array from the string value
22 *
23 * If the string is shorter than the array, it will be padded with
24 * '\0's.
25 *
26 * @param[in] source - The string to fill in the array with
27 * @param[out] target - The input object that supports [] and size()
28 */
29template <typename T>
30void fillArray(const std::string& source, T& target)
31{
32 for (size_t i = 0; i < target.size(); i++)
33 {
34 target[i] = (source.size() > i) ? source[i] : '\0';
35 }
36}
37
Patrick Williamsd26fa3e2021-04-21 15:22:23 -050038} // namespace
Matt Spinler18f4b6e2020-05-21 11:36:24 -050039
Matt Spinlera906c942019-10-08 13:42:05 -050040FRUIdentity::FRUIdentity(Stream& pel)
41{
42 pel >> _type >> _size >> _flags;
43
Matt Spinlerba0ee002020-03-13 11:24:14 -050044 if (hasPN() || hasMP())
Matt Spinlera906c942019-10-08 13:42:05 -050045 {
46 pel.read(_pnOrProcedureID.data(), _pnOrProcedureID.size());
47 }
48
Matt Spinlerba0ee002020-03-13 11:24:14 -050049 if (hasCCIN())
Matt Spinlera906c942019-10-08 13:42:05 -050050 {
51 pel.read(_ccin.data(), _ccin.size());
52 }
53
Matt Spinlerba0ee002020-03-13 11:24:14 -050054 if (hasSN())
Matt Spinlera906c942019-10-08 13:42:05 -050055 {
56 pel.read(_sn.data(), _sn.size());
57 }
58}
59
Matt Spinlera09354b2020-03-13 10:24:52 -050060size_t FRUIdentity::flattenedSize() const
61{
62 size_t size = sizeof(_type) + sizeof(_size) + sizeof(_flags);
63
64 if (hasPN() || hasMP())
65 {
66 size += _pnOrProcedureID.size();
67 }
68
69 if (hasCCIN())
70 {
71 size += _ccin.size();
72 }
73
74 if (hasSN())
75 {
76 size += _sn.size();
77 }
78
79 return size;
80}
81
Matt Spinlerba0ee002020-03-13 11:24:14 -050082FRUIdentity::FRUIdentity(const std::string& partNumber, const std::string& ccin,
83 const std::string& serialNumber)
84{
85 _type = substructureType;
86 _flags = hardwareFRU;
87
88 setPartNumber(partNumber);
89 setCCIN(ccin);
90 setSerialNumber(serialNumber);
91
92 _size = flattenedSize();
93}
94
Matt Spinler468aab52020-08-13 11:04:31 -050095FRUIdentity::FRUIdentity(const std::string& procedure, CalloutValueType type)
Matt Spinlerba0ee002020-03-13 11:24:14 -050096{
97 _type = substructureType;
98 _flags = maintenanceProc;
99
Matt Spinler468aab52020-08-13 11:04:31 -0500100 setMaintenanceProcedure(procedure, type);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500101
102 _size = flattenedSize();
103}
104
Matt Spinler468aab52020-08-13 11:04:31 -0500105FRUIdentity::FRUIdentity(const std::string& fru, CalloutValueType type,
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500106 bool trustedLocationCode)
107{
108 _type = substructureType;
109 _flags = (trustedLocationCode) ? symbolicFRUTrustedLocCode : symbolicFRU;
110
Matt Spinler468aab52020-08-13 11:04:31 -0500111 setSymbolicFRU(fru, type);
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500112
113 _size = flattenedSize();
114}
115
Matt Spinlera906c942019-10-08 13:42:05 -0500116std::optional<std::string> FRUIdentity::getPN() const
117{
118 if (hasPN())
119 {
120 // NULL terminated
121 std::string pn{_pnOrProcedureID.data()};
122 return pn;
123 }
124
125 return std::nullopt;
126}
127
128std::optional<std::string> FRUIdentity::getMaintProc() const
129{
130 if (hasMP())
131 {
132 // NULL terminated
133 std::string mp{_pnOrProcedureID.data()};
134 return mp;
135 }
136
137 return std::nullopt;
138}
139
140std::optional<std::string> FRUIdentity::getCCIN() const
141{
142 if (hasCCIN())
143 {
144 std::string ccin{_ccin.begin(), _ccin.begin() + _ccin.size()};
Matt Spinlerba0ee002020-03-13 11:24:14 -0500145
146 // Don't leave any NULLs in the string (not there usually)
147 if (auto pos = ccin.find('\0'); pos != std::string::npos)
148 {
149 ccin.resize(pos);
150 }
Matt Spinlera906c942019-10-08 13:42:05 -0500151 return ccin;
152 }
153
154 return std::nullopt;
155}
156
157std::optional<std::string> FRUIdentity::getSN() const
158{
159 if (hasSN())
160 {
161 std::string sn{_sn.begin(), _sn.begin() + _sn.size()};
Matt Spinlerba0ee002020-03-13 11:24:14 -0500162
163 // Don't leave any NULLs in the string (not there usually)
164 if (auto pos = sn.find('\0'); pos != std::string::npos)
165 {
166 sn.resize(pos);
167 }
Matt Spinlera906c942019-10-08 13:42:05 -0500168 return sn;
169 }
170
171 return std::nullopt;
172}
173
Matt Spinler724d0d82019-11-06 10:05:36 -0600174void FRUIdentity::flatten(Stream& pel) const
Matt Spinlera906c942019-10-08 13:42:05 -0500175{
176 pel << _type << _size << _flags;
177
178 if (hasPN() || hasMP())
179 {
180 pel.write(_pnOrProcedureID.data(), _pnOrProcedureID.size());
181 }
182
183 if (hasCCIN())
184 {
185 pel.write(_ccin.data(), _ccin.size());
186 }
187
188 if (hasSN())
189 {
190 pel.write(_sn.data(), _sn.size());
191 }
192}
193
Matt Spinlerba0ee002020-03-13 11:24:14 -0500194void FRUIdentity::setPartNumber(const std::string& partNumber)
195{
196 _flags |= pnSupplied;
197 _flags &= ~maintProcSupplied;
198
199 auto pn = partNumber;
200
201 // Strip leading whitespace on this one.
Patrick Williams66f36752024-09-30 21:47:57 -0400202 while (!pn.empty() && (' ' == pn.front()))
Matt Spinlerba0ee002020-03-13 11:24:14 -0500203 {
Patrick Williams66f36752024-09-30 21:47:57 -0400204 pn.erase(0, 1);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500205 }
206
Matt Spinler18f4b6e2020-05-21 11:36:24 -0500207 fillArray(pn, _pnOrProcedureID);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500208
209 // ensure null terminated
210 _pnOrProcedureID.back() = 0;
211}
212
213void FRUIdentity::setCCIN(const std::string& ccin)
214{
215 _flags |= ccinSupplied;
216
Matt Spinler18f4b6e2020-05-21 11:36:24 -0500217 fillArray(ccin, _ccin);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500218}
219
220void FRUIdentity::setSerialNumber(const std::string& serialNumber)
221{
222 _flags |= snSupplied;
223
Matt Spinler18f4b6e2020-05-21 11:36:24 -0500224 fillArray(serialNumber, _sn);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500225}
226
Matt Spinler468aab52020-08-13 11:04:31 -0500227void FRUIdentity::setMaintenanceProcedure(const std::string& procedure,
228 CalloutValueType type)
Matt Spinlerba0ee002020-03-13 11:24:14 -0500229{
230 _flags |= maintProcSupplied;
231 _flags &= ~pnSupplied;
232
Matt Spinler468aab52020-08-13 11:04:31 -0500233 if (type == CalloutValueType::registryName)
Matt Spinlera27e2e52020-04-09 11:06:11 -0500234 {
Matt Spinler468aab52020-08-13 11:04:31 -0500235 if (pel_values::maintenanceProcedures.count(procedure))
236 {
237 fillArray(pel_values::maintenanceProcedures.at(procedure),
238 _pnOrProcedureID);
239 }
240 else
241 {
Arya K Padman5bc26532024-04-10 06:19:25 -0500242 lg2::error("Invalid maintenance procedure {PROCEDURE}", "PROCEDURE",
243 procedure);
Matt Spinler468aab52020-08-13 11:04:31 -0500244 strncpy(_pnOrProcedureID.data(), "INVALID",
245 _pnOrProcedureID.size());
246 }
Matt Spinlera27e2e52020-04-09 11:06:11 -0500247 }
248 else
249 {
Matt Spinler468aab52020-08-13 11:04:31 -0500250 fillArray(procedure, _pnOrProcedureID);
Matt Spinlera27e2e52020-04-09 11:06:11 -0500251 }
Matt Spinlerba0ee002020-03-13 11:24:14 -0500252
253 // ensure null terminated
254 _pnOrProcedureID.back() = 0;
255}
256
Matt Spinler468aab52020-08-13 11:04:31 -0500257void FRUIdentity::setSymbolicFRU(const std::string& symbolicFRU,
258 CalloutValueType type)
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500259{
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500260 // Treat this has a HW callout.
261 _flags |= pnSupplied;
262 _flags &= ~maintProcSupplied;
263
Matt Spinler468aab52020-08-13 11:04:31 -0500264 if (type == CalloutValueType::registryName)
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500265 {
Matt Spinler468aab52020-08-13 11:04:31 -0500266 if (pel_values::symbolicFRUs.count(symbolicFRU))
267 {
268 fillArray(pel_values::symbolicFRUs.at(symbolicFRU),
269 _pnOrProcedureID);
270 }
271 else
272 {
Arya K Padman5bc26532024-04-10 06:19:25 -0500273 lg2::error("Invalid symbolic FRU {FRU}", "FRU", symbolicFRU);
Matt Spinler468aab52020-08-13 11:04:31 -0500274 strncpy(_pnOrProcedureID.data(), "INVALID",
275 _pnOrProcedureID.size());
276 }
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500277 }
278 else
279 {
Matt Spinler468aab52020-08-13 11:04:31 -0500280 fillArray(symbolicFRU, _pnOrProcedureID);
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500281 }
282
283 // ensure null terminated
284 _pnOrProcedureID.back() = 0;
285}
286
Matt Spinlera906c942019-10-08 13:42:05 -0500287} // namespace src
288} // namespace pels
289} // namespace openpower