xref: /openbmc/phosphor-logging/extensions/openpower-pels/fru_identity.cpp (revision 8a09b982ddeb0c1e13190d9cd196e06a778d6140)
1 /**
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  */
16 #include "fru_identity.hpp"
17 
18 #include "pel_values.hpp"
19 
20 #include <phosphor-logging/lg2.hpp>
21 
22 namespace openpower
23 {
24 namespace pels
25 {
26 namespace src
27 {
28 
29 namespace
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  */
41 template <typename T>
fillArray(const std::string & source,T & target)42 void 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 
50 } // namespace
51 
FRUIdentity(Stream & pel)52 FRUIdentity::FRUIdentity(Stream& pel)
53 {
54     pel >> _type >> _size >> _flags;
55 
56     if (hasPN() || hasMP())
57     {
58         pel.read(_pnOrProcedureID.data(), _pnOrProcedureID.size());
59     }
60 
61     if (hasCCIN())
62     {
63         pel.read(_ccin.data(), _ccin.size());
64     }
65 
66     if (hasSN())
67     {
68         pel.read(_sn.data(), _sn.size());
69     }
70 }
71 
flattenedSize() const72 size_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 
FRUIdentity(const std::string & partNumber,const std::string & ccin,const std::string & serialNumber)94 FRUIdentity::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 
FRUIdentity(const std::string & procedure,CalloutValueType type)107 FRUIdentity::FRUIdentity(const std::string& procedure, CalloutValueType type)
108 {
109     _type = substructureType;
110     _flags = maintenanceProc;
111 
112     setMaintenanceProcedure(procedure, type);
113 
114     _size = flattenedSize();
115 }
116 
FRUIdentity(const std::string & fru,CalloutValueType type,bool trustedLocationCode)117 FRUIdentity::FRUIdentity(const std::string& fru, CalloutValueType type,
118                          bool trustedLocationCode)
119 {
120     _type = substructureType;
121     _flags = (trustedLocationCode) ? symbolicFRUTrustedLocCode : symbolicFRU;
122 
123     setSymbolicFRU(fru, type);
124 
125     _size = flattenedSize();
126 }
127 
getPN() const128 std::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 
getMaintProc() const140 std::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 
getCCIN() const152 std::optional<std::string> FRUIdentity::getCCIN() const
153 {
154     if (hasCCIN())
155     {
156         std::string ccin{_ccin.begin(), _ccin.begin() + _ccin.size()};
157 
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         }
163         return ccin;
164     }
165 
166     return std::nullopt;
167 }
168 
getSN() const169 std::optional<std::string> FRUIdentity::getSN() const
170 {
171     if (hasSN())
172     {
173         std::string sn{_sn.begin(), _sn.begin() + _sn.size()};
174 
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         }
180         return sn;
181     }
182 
183     return std::nullopt;
184 }
185 
flatten(Stream & pel) const186 void FRUIdentity::flatten(Stream& pel) const
187 {
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 
setPartNumber(const std::string & partNumber)206 void 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.
214     while (!pn.empty() && (' ' == pn.front()))
215     {
216         pn.erase(0, 1);
217     }
218 
219     fillArray(pn, _pnOrProcedureID);
220 
221     // ensure null terminated
222     _pnOrProcedureID.back() = 0;
223 }
224 
setCCIN(const std::string & ccin)225 void FRUIdentity::setCCIN(const std::string& ccin)
226 {
227     _flags |= ccinSupplied;
228 
229     fillArray(ccin, _ccin);
230 }
231 
setSerialNumber(const std::string & serialNumber)232 void FRUIdentity::setSerialNumber(const std::string& serialNumber)
233 {
234     _flags |= snSupplied;
235 
236     fillArray(serialNumber, _sn);
237 }
238 
setMaintenanceProcedure(const std::string & procedure,CalloutValueType type)239 void FRUIdentity::setMaintenanceProcedure(const std::string& procedure,
240                                           CalloutValueType type)
241 {
242     _flags |= maintProcSupplied;
243     _flags &= ~pnSupplied;
244 
245     if (type == CalloutValueType::registryName)
246     {
247         if (pel_values::maintenanceProcedures.count(procedure))
248         {
249             fillArray(pel_values::maintenanceProcedures.at(procedure),
250                       _pnOrProcedureID);
251         }
252         else
253         {
254             lg2::error("Invalid maintenance procedure {PROCEDURE}", "PROCEDURE",
255                        procedure);
256             strncpy(_pnOrProcedureID.data(), "INVALID",
257                     _pnOrProcedureID.size());
258         }
259     }
260     else
261     {
262         fillArray(procedure, _pnOrProcedureID);
263     }
264 
265     // ensure null terminated
266     _pnOrProcedureID.back() = 0;
267 }
268 
setSymbolicFRU(const std::string & symbolicFRU,CalloutValueType type)269 void FRUIdentity::setSymbolicFRU(const std::string& symbolicFRU,
270                                  CalloutValueType type)
271 {
272     // Treat this has a HW callout.
273     _flags |= pnSupplied;
274     _flags &= ~maintProcSupplied;
275 
276     if (type == CalloutValueType::registryName)
277     {
278         if (pel_values::symbolicFRUs.count(symbolicFRU))
279         {
280             fillArray(pel_values::symbolicFRUs.at(symbolicFRU),
281                       _pnOrProcedureID);
282         }
283         else
284         {
285             lg2::error("Invalid symbolic FRU {FRU}", "FRU", symbolicFRU);
286             strncpy(_pnOrProcedureID.data(), "INVALID",
287                     _pnOrProcedureID.size());
288         }
289     }
290     else
291     {
292         fillArray(symbolicFRU, _pnOrProcedureID);
293     }
294 
295     // ensure null terminated
296     _pnOrProcedureID.back() = 0;
297 }
298 
299 } // namespace src
300 } // namespace pels
301 } // namespace openpower
302