blob: 40cdf8c1675da67f5198c6c5672a03106a2cd54d [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matt Spinlera906c942019-10-08 13:42:05 -050016#include "fru_identity.hpp"
17
Matt Spinlerba0ee002020-03-13 11:24:14 -050018#include "pel_values.hpp"
19
Arya K Padman5bc26532024-04-10 06:19:25 -050020#include <phosphor-logging/lg2.hpp>
Matt Spinlera27e2e52020-04-09 11:06:11 -050021
Matt Spinlera906c942019-10-08 13:42:05 -050022namespace openpower
23{
24namespace pels
25{
26namespace src
27{
28
Matt Spinler18f4b6e2020-05-21 11:36:24 -050029namespace
30{
31
32/**
33 * @brief Fills in the std::array from the string value
34 *
35 * If the string is shorter than the array, it will be padded with
36 * '\0's.
37 *
38 * @param[in] source - The string to fill in the array with
39 * @param[out] target - The input object that supports [] and size()
40 */
41template <typename T>
42void fillArray(const std::string& source, T& target)
43{
44 for (size_t i = 0; i < target.size(); i++)
45 {
46 target[i] = (source.size() > i) ? source[i] : '\0';
47 }
48}
49
Patrick Williamsd26fa3e2021-04-21 15:22:23 -050050} // namespace
Matt Spinler18f4b6e2020-05-21 11:36:24 -050051
Matt Spinlera906c942019-10-08 13:42:05 -050052FRUIdentity::FRUIdentity(Stream& pel)
53{
54 pel >> _type >> _size >> _flags;
55
Matt Spinlerba0ee002020-03-13 11:24:14 -050056 if (hasPN() || hasMP())
Matt Spinlera906c942019-10-08 13:42:05 -050057 {
58 pel.read(_pnOrProcedureID.data(), _pnOrProcedureID.size());
59 }
60
Matt Spinlerba0ee002020-03-13 11:24:14 -050061 if (hasCCIN())
Matt Spinlera906c942019-10-08 13:42:05 -050062 {
63 pel.read(_ccin.data(), _ccin.size());
64 }
65
Matt Spinlerba0ee002020-03-13 11:24:14 -050066 if (hasSN())
Matt Spinlera906c942019-10-08 13:42:05 -050067 {
68 pel.read(_sn.data(), _sn.size());
69 }
70}
71
Matt Spinlera09354b2020-03-13 10:24:52 -050072size_t FRUIdentity::flattenedSize() const
73{
74 size_t size = sizeof(_type) + sizeof(_size) + sizeof(_flags);
75
76 if (hasPN() || hasMP())
77 {
78 size += _pnOrProcedureID.size();
79 }
80
81 if (hasCCIN())
82 {
83 size += _ccin.size();
84 }
85
86 if (hasSN())
87 {
88 size += _sn.size();
89 }
90
91 return size;
92}
93
Matt Spinlerba0ee002020-03-13 11:24:14 -050094FRUIdentity::FRUIdentity(const std::string& partNumber, const std::string& ccin,
95 const std::string& serialNumber)
96{
97 _type = substructureType;
98 _flags = hardwareFRU;
99
100 setPartNumber(partNumber);
101 setCCIN(ccin);
102 setSerialNumber(serialNumber);
103
104 _size = flattenedSize();
105}
106
Matt Spinler468aab52020-08-13 11:04:31 -0500107FRUIdentity::FRUIdentity(const std::string& procedure, CalloutValueType type)
Matt Spinlerba0ee002020-03-13 11:24:14 -0500108{
109 _type = substructureType;
110 _flags = maintenanceProc;
111
Matt Spinler468aab52020-08-13 11:04:31 -0500112 setMaintenanceProcedure(procedure, type);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500113
114 _size = flattenedSize();
115}
116
Matt Spinler468aab52020-08-13 11:04:31 -0500117FRUIdentity::FRUIdentity(const std::string& fru, CalloutValueType type,
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500118 bool trustedLocationCode)
119{
120 _type = substructureType;
121 _flags = (trustedLocationCode) ? symbolicFRUTrustedLocCode : symbolicFRU;
122
Matt Spinler468aab52020-08-13 11:04:31 -0500123 setSymbolicFRU(fru, type);
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500124
125 _size = flattenedSize();
126}
127
Matt Spinlera906c942019-10-08 13:42:05 -0500128std::optional<std::string> FRUIdentity::getPN() const
129{
130 if (hasPN())
131 {
132 // NULL terminated
133 std::string pn{_pnOrProcedureID.data()};
134 return pn;
135 }
136
137 return std::nullopt;
138}
139
140std::optional<std::string> FRUIdentity::getMaintProc() const
141{
142 if (hasMP())
143 {
144 // NULL terminated
145 std::string mp{_pnOrProcedureID.data()};
146 return mp;
147 }
148
149 return std::nullopt;
150}
151
152std::optional<std::string> FRUIdentity::getCCIN() const
153{
154 if (hasCCIN())
155 {
156 std::string ccin{_ccin.begin(), _ccin.begin() + _ccin.size()};
Matt Spinlerba0ee002020-03-13 11:24:14 -0500157
158 // Don't leave any NULLs in the string (not there usually)
159 if (auto pos = ccin.find('\0'); pos != std::string::npos)
160 {
161 ccin.resize(pos);
162 }
Matt Spinlera906c942019-10-08 13:42:05 -0500163 return ccin;
164 }
165
166 return std::nullopt;
167}
168
169std::optional<std::string> FRUIdentity::getSN() const
170{
171 if (hasSN())
172 {
173 std::string sn{_sn.begin(), _sn.begin() + _sn.size()};
Matt Spinlerba0ee002020-03-13 11:24:14 -0500174
175 // Don't leave any NULLs in the string (not there usually)
176 if (auto pos = sn.find('\0'); pos != std::string::npos)
177 {
178 sn.resize(pos);
179 }
Matt Spinlera906c942019-10-08 13:42:05 -0500180 return sn;
181 }
182
183 return std::nullopt;
184}
185
Matt Spinler724d0d82019-11-06 10:05:36 -0600186void FRUIdentity::flatten(Stream& pel) const
Matt Spinlera906c942019-10-08 13:42:05 -0500187{
188 pel << _type << _size << _flags;
189
190 if (hasPN() || hasMP())
191 {
192 pel.write(_pnOrProcedureID.data(), _pnOrProcedureID.size());
193 }
194
195 if (hasCCIN())
196 {
197 pel.write(_ccin.data(), _ccin.size());
198 }
199
200 if (hasSN())
201 {
202 pel.write(_sn.data(), _sn.size());
203 }
204}
205
Matt Spinlerba0ee002020-03-13 11:24:14 -0500206void FRUIdentity::setPartNumber(const std::string& partNumber)
207{
208 _flags |= pnSupplied;
209 _flags &= ~maintProcSupplied;
210
211 auto pn = partNumber;
212
213 // Strip leading whitespace on this one.
Patrick Williams66f36752024-09-30 21:47:57 -0400214 while (!pn.empty() && (' ' == pn.front()))
Matt Spinlerba0ee002020-03-13 11:24:14 -0500215 {
Patrick Williams66f36752024-09-30 21:47:57 -0400216 pn.erase(0, 1);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500217 }
218
Matt Spinler18f4b6e2020-05-21 11:36:24 -0500219 fillArray(pn, _pnOrProcedureID);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500220
221 // ensure null terminated
222 _pnOrProcedureID.back() = 0;
223}
224
225void FRUIdentity::setCCIN(const std::string& ccin)
226{
227 _flags |= ccinSupplied;
228
Matt Spinler18f4b6e2020-05-21 11:36:24 -0500229 fillArray(ccin, _ccin);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500230}
231
232void FRUIdentity::setSerialNumber(const std::string& serialNumber)
233{
234 _flags |= snSupplied;
235
Matt Spinler18f4b6e2020-05-21 11:36:24 -0500236 fillArray(serialNumber, _sn);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500237}
238
Matt Spinler468aab52020-08-13 11:04:31 -0500239void FRUIdentity::setMaintenanceProcedure(const std::string& procedure,
240 CalloutValueType type)
Matt Spinlerba0ee002020-03-13 11:24:14 -0500241{
242 _flags |= maintProcSupplied;
243 _flags &= ~pnSupplied;
244
Matt Spinler468aab52020-08-13 11:04:31 -0500245 if (type == CalloutValueType::registryName)
Matt Spinlera27e2e52020-04-09 11:06:11 -0500246 {
Matt Spinler468aab52020-08-13 11:04:31 -0500247 if (pel_values::maintenanceProcedures.count(procedure))
248 {
249 fillArray(pel_values::maintenanceProcedures.at(procedure),
250 _pnOrProcedureID);
251 }
252 else
253 {
Arya K Padman5bc26532024-04-10 06:19:25 -0500254 lg2::error("Invalid maintenance procedure {PROCEDURE}", "PROCEDURE",
255 procedure);
Matt Spinler468aab52020-08-13 11:04:31 -0500256 strncpy(_pnOrProcedureID.data(), "INVALID",
257 _pnOrProcedureID.size());
258 }
Matt Spinlera27e2e52020-04-09 11:06:11 -0500259 }
260 else
261 {
Matt Spinler468aab52020-08-13 11:04:31 -0500262 fillArray(procedure, _pnOrProcedureID);
Matt Spinlera27e2e52020-04-09 11:06:11 -0500263 }
Matt Spinlerba0ee002020-03-13 11:24:14 -0500264
265 // ensure null terminated
266 _pnOrProcedureID.back() = 0;
267}
268
Matt Spinler468aab52020-08-13 11:04:31 -0500269void FRUIdentity::setSymbolicFRU(const std::string& symbolicFRU,
270 CalloutValueType type)
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500271{
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500272 // Treat this has a HW callout.
273 _flags |= pnSupplied;
274 _flags &= ~maintProcSupplied;
275
Matt Spinler468aab52020-08-13 11:04:31 -0500276 if (type == CalloutValueType::registryName)
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500277 {
Matt Spinler468aab52020-08-13 11:04:31 -0500278 if (pel_values::symbolicFRUs.count(symbolicFRU))
279 {
280 fillArray(pel_values::symbolicFRUs.at(symbolicFRU),
281 _pnOrProcedureID);
282 }
283 else
284 {
Arya K Padman5bc26532024-04-10 06:19:25 -0500285 lg2::error("Invalid symbolic FRU {FRU}", "FRU", symbolicFRU);
Matt Spinler468aab52020-08-13 11:04:31 -0500286 strncpy(_pnOrProcedureID.data(), "INVALID",
287 _pnOrProcedureID.size());
288 }
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500289 }
290 else
291 {
Matt Spinler468aab52020-08-13 11:04:31 -0500292 fillArray(symbolicFRU, _pnOrProcedureID);
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500293 }
294
295 // ensure null terminated
296 _pnOrProcedureID.back() = 0;
297}
298
Matt Spinlera906c942019-10-08 13:42:05 -0500299} // namespace src
300} // namespace pels
301} // namespace openpower