xref: /openbmc/phosphor-logging/extensions/openpower-pels/fru_identity.cpp (revision 81a91e3ee4bf962111cf555ab9d3c3c51000fa3b)
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/log.hpp>
21 
22 using namespace phosphor::logging;
23 
24 namespace openpower
25 {
26 namespace pels
27 {
28 namespace src
29 {
30 
31 namespace
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  */
43 template <typename T>
44 void 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 
52 }; // namespace
53 
54 FRUIdentity::FRUIdentity(Stream& pel)
55 {
56     pel >> _type >> _size >> _flags;
57 
58     if (hasPN() || hasMP())
59     {
60         pel.read(_pnOrProcedureID.data(), _pnOrProcedureID.size());
61     }
62 
63     if (hasCCIN())
64     {
65         pel.read(_ccin.data(), _ccin.size());
66     }
67 
68     if (hasSN())
69     {
70         pel.read(_sn.data(), _sn.size());
71     }
72 }
73 
74 size_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 
96 FRUIdentity::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 
109 FRUIdentity::FRUIdentity(const std::string& procedureFromRegistry)
110 {
111     _type = substructureType;
112     _flags = maintenanceProc;
113 
114     setMaintenanceProcedure(procedureFromRegistry);
115 
116     _size = flattenedSize();
117 }
118 
119 FRUIdentity::FRUIdentity(const std::string& symbolicFRUFromRegistry,
120                          bool trustedLocationCode)
121 {
122     _type = substructureType;
123     _flags = (trustedLocationCode) ? symbolicFRUTrustedLocCode : symbolicFRU;
124 
125     setSymbolicFRU(symbolicFRUFromRegistry);
126 
127     _size = flattenedSize();
128 }
129 
130 std::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 
142 std::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 
154 std::optional<std::string> FRUIdentity::getCCIN() const
155 {
156     if (hasCCIN())
157     {
158         std::string ccin{_ccin.begin(), _ccin.begin() + _ccin.size()};
159 
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         }
165         return ccin;
166     }
167 
168     return std::nullopt;
169 }
170 
171 std::optional<std::string> FRUIdentity::getSN() const
172 {
173     if (hasSN())
174     {
175         std::string sn{_sn.begin(), _sn.begin() + _sn.size()};
176 
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         }
182         return sn;
183     }
184 
185     return std::nullopt;
186 }
187 
188 void FRUIdentity::flatten(Stream& pel) const
189 {
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 
208 void 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 
221     fillArray(pn, _pnOrProcedureID);
222 
223     // ensure null terminated
224     _pnOrProcedureID.back() = 0;
225 }
226 
227 void FRUIdentity::setCCIN(const std::string& ccin)
228 {
229     _flags |= ccinSupplied;
230 
231     fillArray(ccin, _ccin);
232 }
233 
234 void FRUIdentity::setSerialNumber(const std::string& serialNumber)
235 {
236     _flags |= snSupplied;
237 
238     fillArray(serialNumber, _sn);
239 }
240 
241 void FRUIdentity::setMaintenanceProcedure(
242     const std::string& procedureFromRegistry)
243 {
244     _flags |= maintProcSupplied;
245     _flags &= ~pnSupplied;
246 
247     if (pel_values::maintenanceProcedures.count(procedureFromRegistry))
248     {
249         fillArray(pel_values::maintenanceProcedures.at(procedureFromRegistry),
250                   _pnOrProcedureID);
251     }
252     else
253     {
254         log<level::ERR>("Invalid maintenance procedure",
255                         entry("PROCEDURE=%s", procedureFromRegistry.c_str()));
256         strncpy(_pnOrProcedureID.data(), "INVALID", _pnOrProcedureID.size());
257     }
258 
259     // ensure null terminated
260     _pnOrProcedureID.back() = 0;
261 }
262 
263 void FRUIdentity::setSymbolicFRU(const std::string& symbolicFRUFromRegistry)
264 {
265 
266     // Treat this has a HW callout.
267     _flags |= pnSupplied;
268     _flags &= ~maintProcSupplied;
269 
270     if (pel_values::symbolicFRUs.count(symbolicFRUFromRegistry))
271     {
272         fillArray(pel_values::symbolicFRUs.at(symbolicFRUFromRegistry),
273                   _pnOrProcedureID);
274     }
275     else
276     {
277         log<level::ERR>("Invalid symbolic FRU",
278                         entry("FRU=%s", symbolicFRUFromRegistry.c_str()));
279         strncpy(_pnOrProcedureID.data(), "INVALID", _pnOrProcedureID.size());
280     }
281 
282     // ensure null terminated
283     _pnOrProcedureID.back() = 0;
284 }
285 
286 } // namespace src
287 } // namespace pels
288 } // namespace openpower
289