xref: /openbmc/phosphor-logging/extensions/openpower-pels/fru_identity.cpp (revision 40fb54935ce7367636a7156039396ee91cc4d5e2)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright 2019 IBM Corporation
3 
4 #include "fru_identity.hpp"
5 
6 #include "pel_values.hpp"
7 
8 #include <phosphor-logging/lg2.hpp>
9 
10 namespace openpower
11 {
12 namespace pels
13 {
14 namespace src
15 {
16 
17 namespace
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  */
29 template <typename T>
fillArray(const std::string & source,T & target)30 void 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 
38 } // namespace
39 
FRUIdentity(Stream & pel)40 FRUIdentity::FRUIdentity(Stream& pel)
41 {
42     pel >> _type >> _size >> _flags;
43 
44     if (hasPN() || hasMP())
45     {
46         pel.read(_pnOrProcedureID.data(), _pnOrProcedureID.size());
47     }
48 
49     if (hasCCIN())
50     {
51         pel.read(_ccin.data(), _ccin.size());
52     }
53 
54     if (hasSN())
55     {
56         pel.read(_sn.data(), _sn.size());
57     }
58 }
59 
flattenedSize() const60 size_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 
FRUIdentity(const std::string & partNumber,const std::string & ccin,const std::string & serialNumber)82 FRUIdentity::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 
FRUIdentity(const std::string & procedure,CalloutValueType type)95 FRUIdentity::FRUIdentity(const std::string& procedure, CalloutValueType type)
96 {
97     _type = substructureType;
98     _flags = maintenanceProc;
99 
100     setMaintenanceProcedure(procedure, type);
101 
102     _size = flattenedSize();
103 }
104 
FRUIdentity(const std::string & fru,CalloutValueType type,bool trustedLocationCode)105 FRUIdentity::FRUIdentity(const std::string& fru, CalloutValueType type,
106                          bool trustedLocationCode)
107 {
108     _type = substructureType;
109     _flags = (trustedLocationCode) ? symbolicFRUTrustedLocCode : symbolicFRU;
110 
111     setSymbolicFRU(fru, type);
112 
113     _size = flattenedSize();
114 }
115 
getPN() const116 std::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 
getMaintProc() const128 std::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 
getCCIN() const140 std::optional<std::string> FRUIdentity::getCCIN() const
141 {
142     if (hasCCIN())
143     {
144         std::string ccin{_ccin.begin(), _ccin.begin() + _ccin.size()};
145 
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         }
151         return ccin;
152     }
153 
154     return std::nullopt;
155 }
156 
getSN() const157 std::optional<std::string> FRUIdentity::getSN() const
158 {
159     if (hasSN())
160     {
161         std::string sn{_sn.begin(), _sn.begin() + _sn.size()};
162 
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         }
168         return sn;
169     }
170 
171     return std::nullopt;
172 }
173 
flatten(Stream & pel) const174 void FRUIdentity::flatten(Stream& pel) const
175 {
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 
setPartNumber(const std::string & partNumber)194 void 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.
202     while (!pn.empty() && (' ' == pn.front()))
203     {
204         pn.erase(0, 1);
205     }
206 
207     fillArray(pn, _pnOrProcedureID);
208 
209     // ensure null terminated
210     _pnOrProcedureID.back() = 0;
211 }
212 
setCCIN(const std::string & ccin)213 void FRUIdentity::setCCIN(const std::string& ccin)
214 {
215     _flags |= ccinSupplied;
216 
217     fillArray(ccin, _ccin);
218 }
219 
setSerialNumber(const std::string & serialNumber)220 void FRUIdentity::setSerialNumber(const std::string& serialNumber)
221 {
222     _flags |= snSupplied;
223 
224     fillArray(serialNumber, _sn);
225 }
226 
setMaintenanceProcedure(const std::string & procedure,CalloutValueType type)227 void FRUIdentity::setMaintenanceProcedure(const std::string& procedure,
228                                           CalloutValueType type)
229 {
230     _flags |= maintProcSupplied;
231     _flags &= ~pnSupplied;
232 
233     if (type == CalloutValueType::registryName)
234     {
235         if (pel_values::maintenanceProcedures.count(procedure))
236         {
237             fillArray(pel_values::maintenanceProcedures.at(procedure),
238                       _pnOrProcedureID);
239         }
240         else
241         {
242             lg2::error("Invalid maintenance procedure {PROCEDURE}", "PROCEDURE",
243                        procedure);
244             strncpy(_pnOrProcedureID.data(), "INVALID",
245                     _pnOrProcedureID.size());
246         }
247     }
248     else
249     {
250         fillArray(procedure, _pnOrProcedureID);
251     }
252 
253     // ensure null terminated
254     _pnOrProcedureID.back() = 0;
255 }
256 
setSymbolicFRU(const std::string & symbolicFRU,CalloutValueType type)257 void FRUIdentity::setSymbolicFRU(const std::string& symbolicFRU,
258                                  CalloutValueType type)
259 {
260     // Treat this has a HW callout.
261     _flags |= pnSupplied;
262     _flags &= ~maintProcSupplied;
263 
264     if (type == CalloutValueType::registryName)
265     {
266         if (pel_values::symbolicFRUs.count(symbolicFRU))
267         {
268             fillArray(pel_values::symbolicFRUs.at(symbolicFRU),
269                       _pnOrProcedureID);
270         }
271         else
272         {
273             lg2::error("Invalid symbolic FRU {FRU}", "FRU", symbolicFRU);
274             strncpy(_pnOrProcedureID.data(), "INVALID",
275                     _pnOrProcedureID.size());
276         }
277     }
278     else
279     {
280         fillArray(symbolicFRU, _pnOrProcedureID);
281     }
282 
283     // ensure null terminated
284     _pnOrProcedureID.back() = 0;
285 }
286 
287 } // namespace src
288 } // namespace pels
289 } // namespace openpower
290