blob: 4b765fdf0d4e02f6f5e0ad5b5bc525ca475dc468 [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
Matt Spinler468aab52020-08-13 11:04:31 -050020#include <fmt/format.h>
21
Matt Spinlera27e2e52020-04-09 11:06:11 -050022#include <phosphor-logging/log.hpp>
23
24using namespace phosphor::logging;
25
Matt Spinlera906c942019-10-08 13:42:05 -050026namespace openpower
27{
28namespace pels
29{
30namespace src
31{
32
Matt Spinler18f4b6e2020-05-21 11:36:24 -050033namespace
34{
35
36/**
37 * @brief Fills in the std::array from the string value
38 *
39 * If the string is shorter than the array, it will be padded with
40 * '\0's.
41 *
42 * @param[in] source - The string to fill in the array with
43 * @param[out] target - The input object that supports [] and size()
44 */
45template <typename T>
46void fillArray(const std::string& source, T& target)
47{
48 for (size_t i = 0; i < target.size(); i++)
49 {
50 target[i] = (source.size() > i) ? source[i] : '\0';
51 }
52}
53
Patrick Williamsd26fa3e2021-04-21 15:22:23 -050054} // namespace
Matt Spinler18f4b6e2020-05-21 11:36:24 -050055
Matt Spinlera906c942019-10-08 13:42:05 -050056FRUIdentity::FRUIdentity(Stream& pel)
57{
58 pel >> _type >> _size >> _flags;
59
Matt Spinlerba0ee002020-03-13 11:24:14 -050060 if (hasPN() || hasMP())
Matt Spinlera906c942019-10-08 13:42:05 -050061 {
62 pel.read(_pnOrProcedureID.data(), _pnOrProcedureID.size());
63 }
64
Matt Spinlerba0ee002020-03-13 11:24:14 -050065 if (hasCCIN())
Matt Spinlera906c942019-10-08 13:42:05 -050066 {
67 pel.read(_ccin.data(), _ccin.size());
68 }
69
Matt Spinlerba0ee002020-03-13 11:24:14 -050070 if (hasSN())
Matt Spinlera906c942019-10-08 13:42:05 -050071 {
72 pel.read(_sn.data(), _sn.size());
73 }
74}
75
Matt Spinlera09354b2020-03-13 10:24:52 -050076size_t FRUIdentity::flattenedSize() const
77{
78 size_t size = sizeof(_type) + sizeof(_size) + sizeof(_flags);
79
80 if (hasPN() || hasMP())
81 {
82 size += _pnOrProcedureID.size();
83 }
84
85 if (hasCCIN())
86 {
87 size += _ccin.size();
88 }
89
90 if (hasSN())
91 {
92 size += _sn.size();
93 }
94
95 return size;
96}
97
Matt Spinlerba0ee002020-03-13 11:24:14 -050098FRUIdentity::FRUIdentity(const std::string& partNumber, const std::string& ccin,
99 const std::string& serialNumber)
100{
101 _type = substructureType;
102 _flags = hardwareFRU;
103
104 setPartNumber(partNumber);
105 setCCIN(ccin);
106 setSerialNumber(serialNumber);
107
108 _size = flattenedSize();
109}
110
Matt Spinler468aab52020-08-13 11:04:31 -0500111FRUIdentity::FRUIdentity(const std::string& procedure, CalloutValueType type)
Matt Spinlerba0ee002020-03-13 11:24:14 -0500112{
113 _type = substructureType;
114 _flags = maintenanceProc;
115
Matt Spinler468aab52020-08-13 11:04:31 -0500116 setMaintenanceProcedure(procedure, type);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500117
118 _size = flattenedSize();
119}
120
Matt Spinler468aab52020-08-13 11:04:31 -0500121FRUIdentity::FRUIdentity(const std::string& fru, CalloutValueType type,
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500122 bool trustedLocationCode)
123{
124 _type = substructureType;
125 _flags = (trustedLocationCode) ? symbolicFRUTrustedLocCode : symbolicFRU;
126
Matt Spinler468aab52020-08-13 11:04:31 -0500127 setSymbolicFRU(fru, type);
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500128
129 _size = flattenedSize();
130}
131
Matt Spinlera906c942019-10-08 13:42:05 -0500132std::optional<std::string> FRUIdentity::getPN() const
133{
134 if (hasPN())
135 {
136 // NULL terminated
137 std::string pn{_pnOrProcedureID.data()};
138 return pn;
139 }
140
141 return std::nullopt;
142}
143
144std::optional<std::string> FRUIdentity::getMaintProc() const
145{
146 if (hasMP())
147 {
148 // NULL terminated
149 std::string mp{_pnOrProcedureID.data()};
150 return mp;
151 }
152
153 return std::nullopt;
154}
155
156std::optional<std::string> FRUIdentity::getCCIN() const
157{
158 if (hasCCIN())
159 {
160 std::string ccin{_ccin.begin(), _ccin.begin() + _ccin.size()};
Matt Spinlerba0ee002020-03-13 11:24:14 -0500161
162 // Don't leave any NULLs in the string (not there usually)
163 if (auto pos = ccin.find('\0'); pos != std::string::npos)
164 {
165 ccin.resize(pos);
166 }
Matt Spinlera906c942019-10-08 13:42:05 -0500167 return ccin;
168 }
169
170 return std::nullopt;
171}
172
173std::optional<std::string> FRUIdentity::getSN() const
174{
175 if (hasSN())
176 {
177 std::string sn{_sn.begin(), _sn.begin() + _sn.size()};
Matt Spinlerba0ee002020-03-13 11:24:14 -0500178
179 // Don't leave any NULLs in the string (not there usually)
180 if (auto pos = sn.find('\0'); pos != std::string::npos)
181 {
182 sn.resize(pos);
183 }
Matt Spinlera906c942019-10-08 13:42:05 -0500184 return sn;
185 }
186
187 return std::nullopt;
188}
189
Matt Spinler724d0d82019-11-06 10:05:36 -0600190void FRUIdentity::flatten(Stream& pel) const
Matt Spinlera906c942019-10-08 13:42:05 -0500191{
192 pel << _type << _size << _flags;
193
194 if (hasPN() || hasMP())
195 {
196 pel.write(_pnOrProcedureID.data(), _pnOrProcedureID.size());
197 }
198
199 if (hasCCIN())
200 {
201 pel.write(_ccin.data(), _ccin.size());
202 }
203
204 if (hasSN())
205 {
206 pel.write(_sn.data(), _sn.size());
207 }
208}
209
Matt Spinlerba0ee002020-03-13 11:24:14 -0500210void FRUIdentity::setPartNumber(const std::string& partNumber)
211{
212 _flags |= pnSupplied;
213 _flags &= ~maintProcSupplied;
214
215 auto pn = partNumber;
216
217 // Strip leading whitespace on this one.
218 while (' ' == pn.front())
219 {
220 pn = pn.substr(1);
221 }
222
Matt Spinler18f4b6e2020-05-21 11:36:24 -0500223 fillArray(pn, _pnOrProcedureID);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500224
225 // ensure null terminated
226 _pnOrProcedureID.back() = 0;
227}
228
229void FRUIdentity::setCCIN(const std::string& ccin)
230{
231 _flags |= ccinSupplied;
232
Matt Spinler18f4b6e2020-05-21 11:36:24 -0500233 fillArray(ccin, _ccin);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500234}
235
236void FRUIdentity::setSerialNumber(const std::string& serialNumber)
237{
238 _flags |= snSupplied;
239
Matt Spinler18f4b6e2020-05-21 11:36:24 -0500240 fillArray(serialNumber, _sn);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500241}
242
Matt Spinler468aab52020-08-13 11:04:31 -0500243void FRUIdentity::setMaintenanceProcedure(const std::string& procedure,
244 CalloutValueType type)
Matt Spinlerba0ee002020-03-13 11:24:14 -0500245{
246 _flags |= maintProcSupplied;
247 _flags &= ~pnSupplied;
248
Matt Spinler468aab52020-08-13 11:04:31 -0500249 if (type == CalloutValueType::registryName)
Matt Spinlera27e2e52020-04-09 11:06:11 -0500250 {
Matt Spinler468aab52020-08-13 11:04:31 -0500251 if (pel_values::maintenanceProcedures.count(procedure))
252 {
253 fillArray(pel_values::maintenanceProcedures.at(procedure),
254 _pnOrProcedureID);
255 }
256 else
257 {
258 log<level::ERR>(
259 fmt::format("Invalid maintenance procedure {}", procedure)
260 .c_str());
261 strncpy(_pnOrProcedureID.data(), "INVALID",
262 _pnOrProcedureID.size());
263 }
Matt Spinlera27e2e52020-04-09 11:06:11 -0500264 }
265 else
266 {
Matt Spinler468aab52020-08-13 11:04:31 -0500267 fillArray(procedure, _pnOrProcedureID);
Matt Spinlera27e2e52020-04-09 11:06:11 -0500268 }
Matt Spinlerba0ee002020-03-13 11:24:14 -0500269
270 // ensure null terminated
271 _pnOrProcedureID.back() = 0;
272}
273
Matt Spinler468aab52020-08-13 11:04:31 -0500274void FRUIdentity::setSymbolicFRU(const std::string& symbolicFRU,
275 CalloutValueType type)
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500276{
277
278 // Treat this has a HW callout.
279 _flags |= pnSupplied;
280 _flags &= ~maintProcSupplied;
281
Matt Spinler468aab52020-08-13 11:04:31 -0500282 if (type == CalloutValueType::registryName)
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500283 {
Matt Spinler468aab52020-08-13 11:04:31 -0500284 if (pel_values::symbolicFRUs.count(symbolicFRU))
285 {
286 fillArray(pel_values::symbolicFRUs.at(symbolicFRU),
287 _pnOrProcedureID);
288 }
289 else
290 {
291 log<level::ERR>("Invalid symbolic FRU",
292 entry("FRU=%s", symbolicFRU.c_str()));
293 strncpy(_pnOrProcedureID.data(), "INVALID",
294 _pnOrProcedureID.size());
295 }
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500296 }
297 else
298 {
Matt Spinler468aab52020-08-13 11:04:31 -0500299 fillArray(symbolicFRU, _pnOrProcedureID);
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500300 }
301
302 // ensure null terminated
303 _pnOrProcedureID.back() = 0;
304}
305
Matt Spinlera906c942019-10-08 13:42:05 -0500306} // namespace src
307} // namespace pels
308} // namespace openpower