xref: /openbmc/phosphor-logging/extensions/openpower-pels/fru_identity.cpp (revision 66f3675dde05a7ff4b1e6299d3860f2ee3bab143)
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  #include <format>
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>
fillArray(const std::string & source,T & target)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  
FRUIdentity(Stream & pel)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  
flattenedSize() const74  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  
FRUIdentity(const std::string & partNumber,const std::string & ccin,const std::string & serialNumber)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  
FRUIdentity(const std::string & procedure,CalloutValueType type)109  FRUIdentity::FRUIdentity(const std::string& procedure, CalloutValueType type)
110  {
111      _type = substructureType;
112      _flags = maintenanceProc;
113  
114      setMaintenanceProcedure(procedure, type);
115  
116      _size = flattenedSize();
117  }
118  
FRUIdentity(const std::string & fru,CalloutValueType type,bool trustedLocationCode)119  FRUIdentity::FRUIdentity(const std::string& fru, CalloutValueType type,
120                           bool trustedLocationCode)
121  {
122      _type = substructureType;
123      _flags = (trustedLocationCode) ? symbolicFRUTrustedLocCode : symbolicFRU;
124  
125      setSymbolicFRU(fru, type);
126  
127      _size = flattenedSize();
128  }
129  
getPN() const130  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  
getMaintProc() const142  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  
getCCIN() const154  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  
getSN() const171  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  
flatten(Stream & pel) const188  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  
setPartNumber(const std::string & partNumber)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.empty() && (' ' == pn.front()))
217      {
218          pn.erase(0, 1);
219      }
220  
221      fillArray(pn, _pnOrProcedureID);
222  
223      // ensure null terminated
224      _pnOrProcedureID.back() = 0;
225  }
226  
setCCIN(const std::string & ccin)227  void FRUIdentity::setCCIN(const std::string& ccin)
228  {
229      _flags |= ccinSupplied;
230  
231      fillArray(ccin, _ccin);
232  }
233  
setSerialNumber(const std::string & serialNumber)234  void FRUIdentity::setSerialNumber(const std::string& serialNumber)
235  {
236      _flags |= snSupplied;
237  
238      fillArray(serialNumber, _sn);
239  }
240  
setMaintenanceProcedure(const std::string & procedure,CalloutValueType type)241  void FRUIdentity::setMaintenanceProcedure(const std::string& procedure,
242                                            CalloutValueType type)
243  {
244      _flags |= maintProcSupplied;
245      _flags &= ~pnSupplied;
246  
247      if (type == CalloutValueType::registryName)
248      {
249          if (pel_values::maintenanceProcedures.count(procedure))
250          {
251              fillArray(pel_values::maintenanceProcedures.at(procedure),
252                        _pnOrProcedureID);
253          }
254          else
255          {
256              lg2::error("Invalid maintenance procedure {PROCEDURE}", "PROCEDURE",
257                         procedure);
258              strncpy(_pnOrProcedureID.data(), "INVALID",
259                      _pnOrProcedureID.size());
260          }
261      }
262      else
263      {
264          fillArray(procedure, _pnOrProcedureID);
265      }
266  
267      // ensure null terminated
268      _pnOrProcedureID.back() = 0;
269  }
270  
setSymbolicFRU(const std::string & symbolicFRU,CalloutValueType type)271  void FRUIdentity::setSymbolicFRU(const std::string& symbolicFRU,
272                                   CalloutValueType type)
273  {
274      // Treat this has a HW callout.
275      _flags |= pnSupplied;
276      _flags &= ~maintProcSupplied;
277  
278      if (type == CalloutValueType::registryName)
279      {
280          if (pel_values::symbolicFRUs.count(symbolicFRU))
281          {
282              fillArray(pel_values::symbolicFRUs.at(symbolicFRU),
283                        _pnOrProcedureID);
284          }
285          else
286          {
287              lg2::error("Invalid symbolic FRU {FRU}", "FRU", symbolicFRU);
288              strncpy(_pnOrProcedureID.data(), "INVALID",
289                      _pnOrProcedureID.size());
290          }
291      }
292      else
293      {
294          fillArray(symbolicFRU, _pnOrProcedureID);
295      }
296  
297      // ensure null terminated
298      _pnOrProcedureID.back() = 0;
299  }
300  
301  } // namespace src
302  } // namespace pels
303  } // namespace openpower
304