blob: b8dc94f9e4cbe1861f79c807ab2081dd01cae943 [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 Spinlera27e2e52020-04-09 11:06:11 -050020#include <phosphor-logging/log.hpp>
21
22using namespace phosphor::logging;
23
Matt Spinlera906c942019-10-08 13:42:05 -050024namespace openpower
25{
26namespace pels
27{
28namespace src
29{
30
31FRUIdentity::FRUIdentity(Stream& pel)
32{
33 pel >> _type >> _size >> _flags;
34
Matt Spinlerba0ee002020-03-13 11:24:14 -050035 if (hasPN() || hasMP())
Matt Spinlera906c942019-10-08 13:42:05 -050036 {
37 pel.read(_pnOrProcedureID.data(), _pnOrProcedureID.size());
38 }
39
Matt Spinlerba0ee002020-03-13 11:24:14 -050040 if (hasCCIN())
Matt Spinlera906c942019-10-08 13:42:05 -050041 {
42 pel.read(_ccin.data(), _ccin.size());
43 }
44
Matt Spinlerba0ee002020-03-13 11:24:14 -050045 if (hasSN())
Matt Spinlera906c942019-10-08 13:42:05 -050046 {
47 pel.read(_sn.data(), _sn.size());
48 }
49}
50
Matt Spinlera09354b2020-03-13 10:24:52 -050051size_t FRUIdentity::flattenedSize() const
52{
53 size_t size = sizeof(_type) + sizeof(_size) + sizeof(_flags);
54
55 if (hasPN() || hasMP())
56 {
57 size += _pnOrProcedureID.size();
58 }
59
60 if (hasCCIN())
61 {
62 size += _ccin.size();
63 }
64
65 if (hasSN())
66 {
67 size += _sn.size();
68 }
69
70 return size;
71}
72
Matt Spinlerba0ee002020-03-13 11:24:14 -050073FRUIdentity::FRUIdentity(const std::string& partNumber, const std::string& ccin,
74 const std::string& serialNumber)
75{
76 _type = substructureType;
77 _flags = hardwareFRU;
78
79 setPartNumber(partNumber);
80 setCCIN(ccin);
81 setSerialNumber(serialNumber);
82
83 _size = flattenedSize();
84}
85
Matt Spinlera27e2e52020-04-09 11:06:11 -050086FRUIdentity::FRUIdentity(const std::string& procedureFromRegistry)
Matt Spinlerba0ee002020-03-13 11:24:14 -050087{
88 _type = substructureType;
89 _flags = maintenanceProc;
90
Matt Spinlera27e2e52020-04-09 11:06:11 -050091 setMaintenanceProcedure(procedureFromRegistry);
Matt Spinlerba0ee002020-03-13 11:24:14 -050092
93 _size = flattenedSize();
94}
95
Matt Spinler2b6dfa02020-04-09 11:39:05 -050096FRUIdentity::FRUIdentity(const std::string& symbolicFRUFromRegistry,
97 bool trustedLocationCode)
98{
99 _type = substructureType;
100 _flags = (trustedLocationCode) ? symbolicFRUTrustedLocCode : symbolicFRU;
101
102 setSymbolicFRU(symbolicFRUFromRegistry);
103
104 _size = flattenedSize();
105}
106
Matt Spinlera906c942019-10-08 13:42:05 -0500107std::optional<std::string> FRUIdentity::getPN() const
108{
109 if (hasPN())
110 {
111 // NULL terminated
112 std::string pn{_pnOrProcedureID.data()};
113 return pn;
114 }
115
116 return std::nullopt;
117}
118
119std::optional<std::string> FRUIdentity::getMaintProc() const
120{
121 if (hasMP())
122 {
123 // NULL terminated
124 std::string mp{_pnOrProcedureID.data()};
125 return mp;
126 }
127
128 return std::nullopt;
129}
130
131std::optional<std::string> FRUIdentity::getCCIN() const
132{
133 if (hasCCIN())
134 {
135 std::string ccin{_ccin.begin(), _ccin.begin() + _ccin.size()};
Matt Spinlerba0ee002020-03-13 11:24:14 -0500136
137 // Don't leave any NULLs in the string (not there usually)
138 if (auto pos = ccin.find('\0'); pos != std::string::npos)
139 {
140 ccin.resize(pos);
141 }
Matt Spinlera906c942019-10-08 13:42:05 -0500142 return ccin;
143 }
144
145 return std::nullopt;
146}
147
148std::optional<std::string> FRUIdentity::getSN() const
149{
150 if (hasSN())
151 {
152 std::string sn{_sn.begin(), _sn.begin() + _sn.size()};
Matt Spinlerba0ee002020-03-13 11:24:14 -0500153
154 // Don't leave any NULLs in the string (not there usually)
155 if (auto pos = sn.find('\0'); pos != std::string::npos)
156 {
157 sn.resize(pos);
158 }
Matt Spinlera906c942019-10-08 13:42:05 -0500159 return sn;
160 }
161
162 return std::nullopt;
163}
164
Matt Spinler724d0d82019-11-06 10:05:36 -0600165void FRUIdentity::flatten(Stream& pel) const
Matt Spinlera906c942019-10-08 13:42:05 -0500166{
167 pel << _type << _size << _flags;
168
169 if (hasPN() || hasMP())
170 {
171 pel.write(_pnOrProcedureID.data(), _pnOrProcedureID.size());
172 }
173
174 if (hasCCIN())
175 {
176 pel.write(_ccin.data(), _ccin.size());
177 }
178
179 if (hasSN())
180 {
181 pel.write(_sn.data(), _sn.size());
182 }
183}
184
Matt Spinlerba0ee002020-03-13 11:24:14 -0500185void FRUIdentity::setPartNumber(const std::string& partNumber)
186{
187 _flags |= pnSupplied;
188 _flags &= ~maintProcSupplied;
189
190 auto pn = partNumber;
191
192 // Strip leading whitespace on this one.
193 while (' ' == pn.front())
194 {
195 pn = pn.substr(1);
196 }
197
198 // Note: strncpy only writes NULLs if pn short
199 strncpy(_pnOrProcedureID.data(), pn.c_str(), _pnOrProcedureID.size());
200
201 // ensure null terminated
202 _pnOrProcedureID.back() = 0;
203}
204
205void FRUIdentity::setCCIN(const std::string& ccin)
206{
207 _flags |= ccinSupplied;
208
209 // Note: _ccin not null terminated, though strncpy writes NULLs if short
210 strncpy(_ccin.data(), ccin.c_str(), _ccin.size());
211}
212
213void FRUIdentity::setSerialNumber(const std::string& serialNumber)
214{
215 _flags |= snSupplied;
216
217 // Note: _sn not null terminated, though strncpy writes NULLs if short
218 strncpy(_sn.data(), serialNumber.c_str(), _sn.size());
219}
220
Matt Spinlera27e2e52020-04-09 11:06:11 -0500221void FRUIdentity::setMaintenanceProcedure(
222 const std::string& procedureFromRegistry)
Matt Spinlerba0ee002020-03-13 11:24:14 -0500223{
224 _flags |= maintProcSupplied;
225 _flags &= ~pnSupplied;
226
Matt Spinlera27e2e52020-04-09 11:06:11 -0500227 if (pel_values::maintenanceProcedures.count(procedureFromRegistry))
228 {
229 strncpy(
230 _pnOrProcedureID.data(),
231 pel_values::maintenanceProcedures.at(procedureFromRegistry).c_str(),
Matt Spinlerba0ee002020-03-13 11:24:14 -0500232 _pnOrProcedureID.size());
Matt Spinlera27e2e52020-04-09 11:06:11 -0500233 }
234 else
235 {
236 log<level::ERR>("Invalid maintenance procedure",
237 entry("PROCEDURE=%s", procedureFromRegistry.c_str()));
238 strncpy(_pnOrProcedureID.data(), "INVALID", _pnOrProcedureID.size());
239 }
Matt Spinlerba0ee002020-03-13 11:24:14 -0500240
241 // ensure null terminated
242 _pnOrProcedureID.back() = 0;
243}
244
Matt Spinler2b6dfa02020-04-09 11:39:05 -0500245void FRUIdentity::setSymbolicFRU(const std::string& symbolicFRUFromRegistry)
246{
247
248 // Treat this has a HW callout.
249 _flags |= pnSupplied;
250 _flags &= ~maintProcSupplied;
251
252 if (pel_values::symbolicFRUs.count(symbolicFRUFromRegistry))
253 {
254 strncpy(_pnOrProcedureID.data(),
255 pel_values::symbolicFRUs.at(symbolicFRUFromRegistry).c_str(),
256 _pnOrProcedureID.size());
257 }
258 else
259 {
260 log<level::ERR>("Invalid symbolic FRU",
261 entry("FRU=%s", symbolicFRUFromRegistry.c_str()));
262 strncpy(_pnOrProcedureID.data(), "INVALID", _pnOrProcedureID.size());
263 }
264
265 // ensure null terminated
266 _pnOrProcedureID.back() = 0;
267}
268
Matt Spinlera906c942019-10-08 13:42:05 -0500269} // namespace src
270} // namespace pels
271} // namespace openpower