blob: 15a7bda7f73f52d6db1bef6c098ce10f0d351220 [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
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -050022#include <format>
23
Matt Spinlera906c942019-10-08 13:42:05 -050024namespace openpower
25{
26namespace pels
27{
28namespace src
29{
30
Matt Spinler18f4b6e2020-05-21 11:36:24 -050031namespace
32{
33
34/**
35 * @brief Fills in the std::array from the string value
36 *
37 * If the string is shorter than the array, it will be padded with
38 * '\0's.
39 *
40 * @param[in] source - The string to fill in the array with
41 * @param[out] target - The input object that supports [] and size()
42 */
43template <typename T>
44void fillArray(const std::string& source, T& target)
45{
46 for (size_t i = 0; i < target.size(); i++)
47 {
48 target[i] = (source.size() > i) ? source[i] : '\0';
49 }
50}
51
Patrick Williamsd26fa3e2021-04-21 15:22:23 -050052} // namespace
Matt Spinler18f4b6e2020-05-21 11:36:24 -050053
Matt Spinlera906c942019-10-08 13:42:05 -050054FRUIdentity::FRUIdentity(Stream& pel)
55{
56 pel >> _type >> _size >> _flags;
57
Matt Spinlerba0ee002020-03-13 11:24:14 -050058 if (hasPN() || hasMP())
Matt Spinlera906c942019-10-08 13:42:05 -050059 {
60 pel.read(_pnOrProcedureID.data(), _pnOrProcedureID.size());
61 }
62
Matt Spinlerba0ee002020-03-13 11:24:14 -050063 if (hasCCIN())
Matt Spinlera906c942019-10-08 13:42:05 -050064 {
65 pel.read(_ccin.data(), _ccin.size());
66 }
67
Matt Spinlerba0ee002020-03-13 11:24:14 -050068 if (hasSN())
Matt Spinlera906c942019-10-08 13:42:05 -050069 {
70 pel.read(_sn.data(), _sn.size());
71 }
72}
73
Matt Spinlera09354b2020-03-13 10:24:52 -050074size_t FRUIdentity::flattenedSize() const
75{
76 size_t size = sizeof(_type) + sizeof(_size) + sizeof(_flags);
77
78 if (hasPN() || hasMP())
79 {
80 size += _pnOrProcedureID.size();
81 }
82
83 if (hasCCIN())
84 {
85 size += _ccin.size();
86 }
87
88 if (hasSN())
89 {
90 size += _sn.size();
91 }
92
93 return size;
94}
95
Matt Spinlerba0ee002020-03-13 11:24:14 -050096FRUIdentity::FRUIdentity(const std::string& partNumber, const std::string& ccin,
97 const std::string& serialNumber)
98{
99 _type = substructureType;
100 _flags = hardwareFRU;
101
102 setPartNumber(partNumber);
103 setCCIN(ccin);
104 setSerialNumber(serialNumber);
105
106 _size = flattenedSize();
107}
108
Matt Spinler468aab52020-08-13 11:04:31 -0500109FRUIdentity::FRUIdentity(const std::string& procedure, CalloutValueType type)
Matt Spinlerba0ee002020-03-13 11:24:14 -0500110{
111 _type = substructureType;
112 _flags = maintenanceProc;
113
Matt Spinler468aab52020-08-13 11:04:31 -0500114 setMaintenanceProcedure(procedure, type);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500115
116 _size = flattenedSize();
117}
118
Matt Spinler468aab52020-08-13 11:04:31 -0500119FRUIdentity::FRUIdentity(const std::string& fru, CalloutValueType type,
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500120 bool trustedLocationCode)
121{
122 _type = substructureType;
123 _flags = (trustedLocationCode) ? symbolicFRUTrustedLocCode : symbolicFRU;
124
Matt Spinler468aab52020-08-13 11:04:31 -0500125 setSymbolicFRU(fru, type);
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500126
127 _size = flattenedSize();
128}
129
Matt Spinlera906c942019-10-08 13:42:05 -0500130std::optional<std::string> FRUIdentity::getPN() const
131{
132 if (hasPN())
133 {
134 // NULL terminated
135 std::string pn{_pnOrProcedureID.data()};
136 return pn;
137 }
138
139 return std::nullopt;
140}
141
142std::optional<std::string> FRUIdentity::getMaintProc() const
143{
144 if (hasMP())
145 {
146 // NULL terminated
147 std::string mp{_pnOrProcedureID.data()};
148 return mp;
149 }
150
151 return std::nullopt;
152}
153
154std::optional<std::string> FRUIdentity::getCCIN() const
155{
156 if (hasCCIN())
157 {
158 std::string ccin{_ccin.begin(), _ccin.begin() + _ccin.size()};
Matt Spinlerba0ee002020-03-13 11:24:14 -0500159
160 // Don't leave any NULLs in the string (not there usually)
161 if (auto pos = ccin.find('\0'); pos != std::string::npos)
162 {
163 ccin.resize(pos);
164 }
Matt Spinlera906c942019-10-08 13:42:05 -0500165 return ccin;
166 }
167
168 return std::nullopt;
169}
170
171std::optional<std::string> FRUIdentity::getSN() const
172{
173 if (hasSN())
174 {
175 std::string sn{_sn.begin(), _sn.begin() + _sn.size()};
Matt Spinlerba0ee002020-03-13 11:24:14 -0500176
177 // Don't leave any NULLs in the string (not there usually)
178 if (auto pos = sn.find('\0'); pos != std::string::npos)
179 {
180 sn.resize(pos);
181 }
Matt Spinlera906c942019-10-08 13:42:05 -0500182 return sn;
183 }
184
185 return std::nullopt;
186}
187
Matt Spinler724d0d82019-11-06 10:05:36 -0600188void FRUIdentity::flatten(Stream& pel) const
Matt Spinlera906c942019-10-08 13:42:05 -0500189{
190 pel << _type << _size << _flags;
191
192 if (hasPN() || hasMP())
193 {
194 pel.write(_pnOrProcedureID.data(), _pnOrProcedureID.size());
195 }
196
197 if (hasCCIN())
198 {
199 pel.write(_ccin.data(), _ccin.size());
200 }
201
202 if (hasSN())
203 {
204 pel.write(_sn.data(), _sn.size());
205 }
206}
207
Matt Spinlerba0ee002020-03-13 11:24:14 -0500208void FRUIdentity::setPartNumber(const std::string& partNumber)
209{
210 _flags |= pnSupplied;
211 _flags &= ~maintProcSupplied;
212
213 auto pn = partNumber;
214
215 // Strip leading whitespace on this one.
216 while (' ' == pn.front())
217 {
218 pn = pn.substr(1);
219 }
220
Matt Spinler18f4b6e2020-05-21 11:36:24 -0500221 fillArray(pn, _pnOrProcedureID);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500222
223 // ensure null terminated
224 _pnOrProcedureID.back() = 0;
225}
226
227void FRUIdentity::setCCIN(const std::string& ccin)
228{
229 _flags |= ccinSupplied;
230
Matt Spinler18f4b6e2020-05-21 11:36:24 -0500231 fillArray(ccin, _ccin);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500232}
233
234void FRUIdentity::setSerialNumber(const std::string& serialNumber)
235{
236 _flags |= snSupplied;
237
Matt Spinler18f4b6e2020-05-21 11:36:24 -0500238 fillArray(serialNumber, _sn);
Matt Spinlerba0ee002020-03-13 11:24:14 -0500239}
240
Matt Spinler468aab52020-08-13 11:04:31 -0500241void FRUIdentity::setMaintenanceProcedure(const std::string& procedure,
242 CalloutValueType type)
Matt Spinlerba0ee002020-03-13 11:24:14 -0500243{
244 _flags |= maintProcSupplied;
245 _flags &= ~pnSupplied;
246
Matt Spinler468aab52020-08-13 11:04:31 -0500247 if (type == CalloutValueType::registryName)
Matt Spinlera27e2e52020-04-09 11:06:11 -0500248 {
Matt Spinler468aab52020-08-13 11:04:31 -0500249 if (pel_values::maintenanceProcedures.count(procedure))
250 {
251 fillArray(pel_values::maintenanceProcedures.at(procedure),
252 _pnOrProcedureID);
253 }
254 else
255 {
Arya K Padman5bc26532024-04-10 06:19:25 -0500256 lg2::error("Invalid maintenance procedure {PROCEDURE}", "PROCEDURE",
257 procedure);
Matt Spinler468aab52020-08-13 11:04:31 -0500258 strncpy(_pnOrProcedureID.data(), "INVALID",
259 _pnOrProcedureID.size());
260 }
Matt Spinlera27e2e52020-04-09 11:06:11 -0500261 }
262 else
263 {
Matt Spinler468aab52020-08-13 11:04:31 -0500264 fillArray(procedure, _pnOrProcedureID);
Matt Spinlera27e2e52020-04-09 11:06:11 -0500265 }
Matt Spinlerba0ee002020-03-13 11:24:14 -0500266
267 // ensure null terminated
268 _pnOrProcedureID.back() = 0;
269}
270
Matt Spinler468aab52020-08-13 11:04:31 -0500271void FRUIdentity::setSymbolicFRU(const std::string& symbolicFRU,
272 CalloutValueType type)
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500273{
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500274 // Treat this has a HW callout.
275 _flags |= pnSupplied;
276 _flags &= ~maintProcSupplied;
277
Matt Spinler468aab52020-08-13 11:04:31 -0500278 if (type == CalloutValueType::registryName)
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500279 {
Matt Spinler468aab52020-08-13 11:04:31 -0500280 if (pel_values::symbolicFRUs.count(symbolicFRU))
281 {
282 fillArray(pel_values::symbolicFRUs.at(symbolicFRU),
283 _pnOrProcedureID);
284 }
285 else
286 {
Arya K Padman5bc26532024-04-10 06:19:25 -0500287 lg2::error("Invalid symbolic FRU {FRU}", "FRU", symbolicFRU);
Matt Spinler468aab52020-08-13 11:04:31 -0500288 strncpy(_pnOrProcedureID.data(), "INVALID",
289 _pnOrProcedureID.size());
290 }
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500291 }
292 else
293 {
Matt Spinler468aab52020-08-13 11:04:31 -0500294 fillArray(symbolicFRU, _pnOrProcedureID);
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500295 }
296
297 // ensure null terminated
298 _pnOrProcedureID.back() = 0;
299}
300
Matt Spinlera906c942019-10-08 13:42:05 -0500301} // namespace src
302} // namespace pels
303} // namespace openpower