1711d51d8SMatt Spinler /**
2711d51d8SMatt Spinler  * Copyright © 2019 IBM Corporation
3711d51d8SMatt Spinler  *
4711d51d8SMatt Spinler  * Licensed under the Apache License, Version 2.0 (the "License");
5711d51d8SMatt Spinler  * you may not use this file except in compliance with the License.
6711d51d8SMatt Spinler  * You may obtain a copy of the License at
7711d51d8SMatt Spinler  *
8711d51d8SMatt Spinler  *     http://www.apache.org/licenses/LICENSE-2.0
9711d51d8SMatt Spinler  *
10711d51d8SMatt Spinler  * Unless required by applicable law or agreed to in writing, software
11711d51d8SMatt Spinler  * distributed under the License is distributed on an "AS IS" BASIS,
12711d51d8SMatt Spinler  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13711d51d8SMatt Spinler  * See the License for the specific language governing permissions and
14711d51d8SMatt Spinler  * limitations under the License.
15711d51d8SMatt Spinler  */
16a906c940SMatt Spinler #include "fru_identity.hpp"
17a906c940SMatt Spinler 
18ba0ee002SMatt Spinler #include "pel_values.hpp"
19ba0ee002SMatt Spinler 
20468aab5fSMatt Spinler #include <fmt/format.h>
21468aab5fSMatt Spinler 
22a27e2e50SMatt Spinler #include <phosphor-logging/log.hpp>
23a27e2e50SMatt Spinler 
24a27e2e50SMatt Spinler using namespace phosphor::logging;
25a27e2e50SMatt Spinler 
26a906c940SMatt Spinler namespace openpower
27a906c940SMatt Spinler {
28a906c940SMatt Spinler namespace pels
29a906c940SMatt Spinler {
30a906c940SMatt Spinler namespace src
31a906c940SMatt Spinler {
32a906c940SMatt Spinler 
3318f4b6e8SMatt Spinler namespace
3418f4b6e8SMatt Spinler {
3518f4b6e8SMatt Spinler 
3618f4b6e8SMatt Spinler /**
3718f4b6e8SMatt Spinler  * @brief Fills in the std::array from the string value
3818f4b6e8SMatt Spinler  *
3918f4b6e8SMatt Spinler  * If the string is shorter than the array, it will be padded with
4018f4b6e8SMatt Spinler  * '\0's.
4118f4b6e8SMatt Spinler  *
4218f4b6e8SMatt Spinler  * @param[in] source - The string to fill in the array with
4318f4b6e8SMatt Spinler  * @param[out] target - The input object that supports [] and size()
4418f4b6e8SMatt Spinler  */
4518f4b6e8SMatt Spinler template <typename T>
4618f4b6e8SMatt Spinler void fillArray(const std::string& source, T& target)
4718f4b6e8SMatt Spinler {
4818f4b6e8SMatt Spinler     for (size_t i = 0; i < target.size(); i++)
4918f4b6e8SMatt Spinler     {
5018f4b6e8SMatt Spinler         target[i] = (source.size() > i) ? source[i] : '\0';
5118f4b6e8SMatt Spinler     }
5218f4b6e8SMatt Spinler }
5318f4b6e8SMatt Spinler 
54*d26fa3e7SPatrick Williams } // namespace
5518f4b6e8SMatt Spinler 
56a906c940SMatt Spinler FRUIdentity::FRUIdentity(Stream& pel)
57a906c940SMatt Spinler {
58a906c940SMatt Spinler     pel >> _type >> _size >> _flags;
59a906c940SMatt Spinler 
60ba0ee002SMatt Spinler     if (hasPN() || hasMP())
61a906c940SMatt Spinler     {
62a906c940SMatt Spinler         pel.read(_pnOrProcedureID.data(), _pnOrProcedureID.size());
63a906c940SMatt Spinler     }
64a906c940SMatt Spinler 
65ba0ee002SMatt Spinler     if (hasCCIN())
66a906c940SMatt Spinler     {
67a906c940SMatt Spinler         pel.read(_ccin.data(), _ccin.size());
68a906c940SMatt Spinler     }
69a906c940SMatt Spinler 
70ba0ee002SMatt Spinler     if (hasSN())
71a906c940SMatt Spinler     {
72a906c940SMatt Spinler         pel.read(_sn.data(), _sn.size());
73a906c940SMatt Spinler     }
74a906c940SMatt Spinler }
75a906c940SMatt Spinler 
76a09354b7SMatt Spinler size_t FRUIdentity::flattenedSize() const
77a09354b7SMatt Spinler {
78a09354b7SMatt Spinler     size_t size = sizeof(_type) + sizeof(_size) + sizeof(_flags);
79a09354b7SMatt Spinler 
80a09354b7SMatt Spinler     if (hasPN() || hasMP())
81a09354b7SMatt Spinler     {
82a09354b7SMatt Spinler         size += _pnOrProcedureID.size();
83a09354b7SMatt Spinler     }
84a09354b7SMatt Spinler 
85a09354b7SMatt Spinler     if (hasCCIN())
86a09354b7SMatt Spinler     {
87a09354b7SMatt Spinler         size += _ccin.size();
88a09354b7SMatt Spinler     }
89a09354b7SMatt Spinler 
90a09354b7SMatt Spinler     if (hasSN())
91a09354b7SMatt Spinler     {
92a09354b7SMatt Spinler         size += _sn.size();
93a09354b7SMatt Spinler     }
94a09354b7SMatt Spinler 
95a09354b7SMatt Spinler     return size;
96a09354b7SMatt Spinler }
97a09354b7SMatt Spinler 
98ba0ee002SMatt Spinler FRUIdentity::FRUIdentity(const std::string& partNumber, const std::string& ccin,
99ba0ee002SMatt Spinler                          const std::string& serialNumber)
100ba0ee002SMatt Spinler {
101ba0ee002SMatt Spinler     _type = substructureType;
102ba0ee002SMatt Spinler     _flags = hardwareFRU;
103ba0ee002SMatt Spinler 
104ba0ee002SMatt Spinler     setPartNumber(partNumber);
105ba0ee002SMatt Spinler     setCCIN(ccin);
106ba0ee002SMatt Spinler     setSerialNumber(serialNumber);
107ba0ee002SMatt Spinler 
108ba0ee002SMatt Spinler     _size = flattenedSize();
109ba0ee002SMatt Spinler }
110ba0ee002SMatt Spinler 
111468aab5fSMatt Spinler FRUIdentity::FRUIdentity(const std::string& procedure, CalloutValueType type)
112ba0ee002SMatt Spinler {
113ba0ee002SMatt Spinler     _type = substructureType;
114ba0ee002SMatt Spinler     _flags = maintenanceProc;
115ba0ee002SMatt Spinler 
116468aab5fSMatt Spinler     setMaintenanceProcedure(procedure, type);
117ba0ee002SMatt Spinler 
118ba0ee002SMatt Spinler     _size = flattenedSize();
119ba0ee002SMatt Spinler }
120ba0ee002SMatt Spinler 
121468aab5fSMatt Spinler FRUIdentity::FRUIdentity(const std::string& fru, CalloutValueType type,
1222b6dfa00SMatt Spinler                          bool trustedLocationCode)
1232b6dfa00SMatt Spinler {
1242b6dfa00SMatt Spinler     _type = substructureType;
1252b6dfa00SMatt Spinler     _flags = (trustedLocationCode) ? symbolicFRUTrustedLocCode : symbolicFRU;
1262b6dfa00SMatt Spinler 
127468aab5fSMatt Spinler     setSymbolicFRU(fru, type);
1282b6dfa00SMatt Spinler 
1292b6dfa00SMatt Spinler     _size = flattenedSize();
1302b6dfa00SMatt Spinler }
1312b6dfa00SMatt Spinler 
132a906c940SMatt Spinler std::optional<std::string> FRUIdentity::getPN() const
133a906c940SMatt Spinler {
134a906c940SMatt Spinler     if (hasPN())
135a906c940SMatt Spinler     {
136a906c940SMatt Spinler         // NULL terminated
137a906c940SMatt Spinler         std::string pn{_pnOrProcedureID.data()};
138a906c940SMatt Spinler         return pn;
139a906c940SMatt Spinler     }
140a906c940SMatt Spinler 
141a906c940SMatt Spinler     return std::nullopt;
142a906c940SMatt Spinler }
143a906c940SMatt Spinler 
144a906c940SMatt Spinler std::optional<std::string> FRUIdentity::getMaintProc() const
145a906c940SMatt Spinler {
146a906c940SMatt Spinler     if (hasMP())
147a906c940SMatt Spinler     {
148a906c940SMatt Spinler         // NULL terminated
149a906c940SMatt Spinler         std::string mp{_pnOrProcedureID.data()};
150a906c940SMatt Spinler         return mp;
151a906c940SMatt Spinler     }
152a906c940SMatt Spinler 
153a906c940SMatt Spinler     return std::nullopt;
154a906c940SMatt Spinler }
155a906c940SMatt Spinler 
156a906c940SMatt Spinler std::optional<std::string> FRUIdentity::getCCIN() const
157a906c940SMatt Spinler {
158a906c940SMatt Spinler     if (hasCCIN())
159a906c940SMatt Spinler     {
160a906c940SMatt Spinler         std::string ccin{_ccin.begin(), _ccin.begin() + _ccin.size()};
161ba0ee002SMatt Spinler 
162ba0ee002SMatt Spinler         // Don't leave any NULLs in the string (not there usually)
163ba0ee002SMatt Spinler         if (auto pos = ccin.find('\0'); pos != std::string::npos)
164ba0ee002SMatt Spinler         {
165ba0ee002SMatt Spinler             ccin.resize(pos);
166ba0ee002SMatt Spinler         }
167a906c940SMatt Spinler         return ccin;
168a906c940SMatt Spinler     }
169a906c940SMatt Spinler 
170a906c940SMatt Spinler     return std::nullopt;
171a906c940SMatt Spinler }
172a906c940SMatt Spinler 
173a906c940SMatt Spinler std::optional<std::string> FRUIdentity::getSN() const
174a906c940SMatt Spinler {
175a906c940SMatt Spinler     if (hasSN())
176a906c940SMatt Spinler     {
177a906c940SMatt Spinler         std::string sn{_sn.begin(), _sn.begin() + _sn.size()};
178ba0ee002SMatt Spinler 
179ba0ee002SMatt Spinler         // Don't leave any NULLs in the string (not there usually)
180ba0ee002SMatt Spinler         if (auto pos = sn.find('\0'); pos != std::string::npos)
181ba0ee002SMatt Spinler         {
182ba0ee002SMatt Spinler             sn.resize(pos);
183ba0ee002SMatt Spinler         }
184a906c940SMatt Spinler         return sn;
185a906c940SMatt Spinler     }
186a906c940SMatt Spinler 
187a906c940SMatt Spinler     return std::nullopt;
188a906c940SMatt Spinler }
189a906c940SMatt Spinler 
190724d0d8cSMatt Spinler void FRUIdentity::flatten(Stream& pel) const
191a906c940SMatt Spinler {
192a906c940SMatt Spinler     pel << _type << _size << _flags;
193a906c940SMatt Spinler 
194a906c940SMatt Spinler     if (hasPN() || hasMP())
195a906c940SMatt Spinler     {
196a906c940SMatt Spinler         pel.write(_pnOrProcedureID.data(), _pnOrProcedureID.size());
197a906c940SMatt Spinler     }
198a906c940SMatt Spinler 
199a906c940SMatt Spinler     if (hasCCIN())
200a906c940SMatt Spinler     {
201a906c940SMatt Spinler         pel.write(_ccin.data(), _ccin.size());
202a906c940SMatt Spinler     }
203a906c940SMatt Spinler 
204a906c940SMatt Spinler     if (hasSN())
205a906c940SMatt Spinler     {
206a906c940SMatt Spinler         pel.write(_sn.data(), _sn.size());
207a906c940SMatt Spinler     }
208a906c940SMatt Spinler }
209a906c940SMatt Spinler 
210ba0ee002SMatt Spinler void FRUIdentity::setPartNumber(const std::string& partNumber)
211ba0ee002SMatt Spinler {
212ba0ee002SMatt Spinler     _flags |= pnSupplied;
213ba0ee002SMatt Spinler     _flags &= ~maintProcSupplied;
214ba0ee002SMatt Spinler 
215ba0ee002SMatt Spinler     auto pn = partNumber;
216ba0ee002SMatt Spinler 
217ba0ee002SMatt Spinler     // Strip leading whitespace on this one.
218ba0ee002SMatt Spinler     while (' ' == pn.front())
219ba0ee002SMatt Spinler     {
220ba0ee002SMatt Spinler         pn = pn.substr(1);
221ba0ee002SMatt Spinler     }
222ba0ee002SMatt Spinler 
22318f4b6e8SMatt Spinler     fillArray(pn, _pnOrProcedureID);
224ba0ee002SMatt Spinler 
225ba0ee002SMatt Spinler     // ensure null terminated
226ba0ee002SMatt Spinler     _pnOrProcedureID.back() = 0;
227ba0ee002SMatt Spinler }
228ba0ee002SMatt Spinler 
229ba0ee002SMatt Spinler void FRUIdentity::setCCIN(const std::string& ccin)
230ba0ee002SMatt Spinler {
231ba0ee002SMatt Spinler     _flags |= ccinSupplied;
232ba0ee002SMatt Spinler 
23318f4b6e8SMatt Spinler     fillArray(ccin, _ccin);
234ba0ee002SMatt Spinler }
235ba0ee002SMatt Spinler 
236ba0ee002SMatt Spinler void FRUIdentity::setSerialNumber(const std::string& serialNumber)
237ba0ee002SMatt Spinler {
238ba0ee002SMatt Spinler     _flags |= snSupplied;
239ba0ee002SMatt Spinler 
24018f4b6e8SMatt Spinler     fillArray(serialNumber, _sn);
241ba0ee002SMatt Spinler }
242ba0ee002SMatt Spinler 
243468aab5fSMatt Spinler void FRUIdentity::setMaintenanceProcedure(const std::string& procedure,
244468aab5fSMatt Spinler                                           CalloutValueType type)
245ba0ee002SMatt Spinler {
246ba0ee002SMatt Spinler     _flags |= maintProcSupplied;
247ba0ee002SMatt Spinler     _flags &= ~pnSupplied;
248ba0ee002SMatt Spinler 
249468aab5fSMatt Spinler     if (type == CalloutValueType::registryName)
250a27e2e50SMatt Spinler     {
251468aab5fSMatt Spinler         if (pel_values::maintenanceProcedures.count(procedure))
252468aab5fSMatt Spinler         {
253468aab5fSMatt Spinler             fillArray(pel_values::maintenanceProcedures.at(procedure),
25418f4b6e8SMatt Spinler                       _pnOrProcedureID);
255a27e2e50SMatt Spinler         }
256a27e2e50SMatt Spinler         else
257a27e2e50SMatt Spinler         {
258468aab5fSMatt Spinler             log<level::ERR>(
259468aab5fSMatt Spinler                 fmt::format("Invalid maintenance procedure {}", procedure)
260468aab5fSMatt Spinler                     .c_str());
261468aab5fSMatt Spinler             strncpy(_pnOrProcedureID.data(), "INVALID",
262468aab5fSMatt Spinler                     _pnOrProcedureID.size());
263468aab5fSMatt Spinler         }
264468aab5fSMatt Spinler     }
265468aab5fSMatt Spinler     else
266468aab5fSMatt Spinler     {
267468aab5fSMatt Spinler         fillArray(procedure, _pnOrProcedureID);
268a27e2e50SMatt Spinler     }
269ba0ee002SMatt Spinler 
270ba0ee002SMatt Spinler     // ensure null terminated
271ba0ee002SMatt Spinler     _pnOrProcedureID.back() = 0;
272ba0ee002SMatt Spinler }
273ba0ee002SMatt Spinler 
274468aab5fSMatt Spinler void FRUIdentity::setSymbolicFRU(const std::string& symbolicFRU,
275468aab5fSMatt Spinler                                  CalloutValueType type)
2762b6dfa00SMatt Spinler {
2772b6dfa00SMatt Spinler 
2782b6dfa00SMatt Spinler     // Treat this has a HW callout.
2792b6dfa00SMatt Spinler     _flags |= pnSupplied;
2802b6dfa00SMatt Spinler     _flags &= ~maintProcSupplied;
2812b6dfa00SMatt Spinler 
282468aab5fSMatt Spinler     if (type == CalloutValueType::registryName)
2832b6dfa00SMatt Spinler     {
284468aab5fSMatt Spinler         if (pel_values::symbolicFRUs.count(symbolicFRU))
285468aab5fSMatt Spinler         {
286468aab5fSMatt Spinler             fillArray(pel_values::symbolicFRUs.at(symbolicFRU),
28718f4b6e8SMatt Spinler                       _pnOrProcedureID);
2882b6dfa00SMatt Spinler         }
2892b6dfa00SMatt Spinler         else
2902b6dfa00SMatt Spinler         {
2912b6dfa00SMatt Spinler             log<level::ERR>("Invalid symbolic FRU",
292468aab5fSMatt Spinler                             entry("FRU=%s", symbolicFRU.c_str()));
293468aab5fSMatt Spinler             strncpy(_pnOrProcedureID.data(), "INVALID",
294468aab5fSMatt Spinler                     _pnOrProcedureID.size());
295468aab5fSMatt Spinler         }
296468aab5fSMatt Spinler     }
297468aab5fSMatt Spinler     else
298468aab5fSMatt Spinler     {
299468aab5fSMatt Spinler         fillArray(symbolicFRU, _pnOrProcedureID);
3002b6dfa00SMatt Spinler     }
3012b6dfa00SMatt Spinler 
3022b6dfa00SMatt Spinler     // ensure null terminated
3032b6dfa00SMatt Spinler     _pnOrProcedureID.back() = 0;
3042b6dfa00SMatt Spinler }
3052b6dfa00SMatt Spinler 
306a906c940SMatt Spinler } // namespace src
307a906c940SMatt Spinler } // namespace pels
308a906c940SMatt Spinler } // namespace openpower
309