xref: /openbmc/phosphor-logging/extensions/openpower-pels/callout.cpp (revision 40fb54935ce7367636a7156039396ee91cc4d5e2)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright 2019 IBM Corporation
3 
4 #include "callout.hpp"
5 
6 #include <phosphor-logging/lg2.hpp>
7 
8 #include <map>
9 
10 namespace openpower
11 {
12 namespace pels
13 {
14 namespace src
15 {
16 
17 constexpr size_t locationCodeMaxSize = 80;
18 
Callout(Stream & pel)19 Callout::Callout(Stream& pel)
20 {
21     pel >> _size >> _flags >> _priority >> _locationCodeSize;
22 
23     if (_locationCodeSize)
24     {
25         _locationCode.resize(_locationCodeSize);
26         pel >> _locationCode;
27     }
28 
29     size_t currentSize = 4 + _locationCodeSize;
30 
31     // Read in the substructures until the end of this structure.
32     // Any stream overflows will throw an exception up to the SRC constructor
33     while (_size > currentSize)
34     {
35         // Peek the type
36         uint16_t type = 0;
37         pel >> type;
38         pel.offset(pel.offset() - 2);
39 
40         switch (type)
41         {
42             case FRUIdentity::substructureType:
43             {
44                 _fruIdentity = std::make_unique<FRUIdentity>(pel);
45                 currentSize += _fruIdentity->flattenedSize();
46                 break;
47             }
48             case PCEIdentity::substructureType:
49             {
50                 _pceIdentity = std::make_unique<PCEIdentity>(pel);
51                 currentSize += _pceIdentity->flattenedSize();
52                 break;
53             }
54             case MRU::substructureType:
55             {
56                 _mru = std::make_unique<MRU>(pel);
57                 currentSize += _mru->flattenedSize();
58                 break;
59             }
60             default:
61                 lg2::error("Invalid Callout subsection type {CALLOUT_TYPE}",
62                            "CALLOUT_TYPE", lg2::hex, type);
63                 throw std::runtime_error("Invalid Callout subsection type");
64                 break;
65         }
66     }
67 }
68 
Callout(CalloutPriority priority,const std::string & locationCode,const std::string & partNumber,const std::string & ccin,const std::string & serialNumber)69 Callout::Callout(CalloutPriority priority, const std::string& locationCode,
70                  const std::string& partNumber, const std::string& ccin,
71                  const std::string& serialNumber) :
72     Callout(priority, locationCode, partNumber, ccin, serialNumber,
73             std::vector<MRU::MRUCallout>{})
74 {}
75 
Callout(CalloutPriority priority,const std::string & locationCode,const std::string & partNumber,const std::string & ccin,const std::string & serialNumber,const std::vector<MRU::MRUCallout> & mrus)76 Callout::Callout(CalloutPriority priority, const std::string& locationCode,
77                  const std::string& partNumber, const std::string& ccin,
78                  const std::string& serialNumber,
79                  const std::vector<MRU::MRUCallout>& mrus)
80 {
81     _flags = calloutType | fruIdentIncluded;
82 
83     _priority = static_cast<uint8_t>(priority);
84 
85     setLocationCode(locationCode);
86 
87     _fruIdentity =
88         std::make_unique<FRUIdentity>(partNumber, ccin, serialNumber);
89 
90     if (!mrus.empty())
91     {
92         _flags |= mruIncluded;
93         _mru = std::make_unique<MRU>(mrus);
94     }
95 
96     _size = flattenedSize();
97 }
98 
Callout(CalloutPriority priority,const std::string & procedure,CalloutValueType type)99 Callout::Callout(CalloutPriority priority, const std::string& procedure,
100                  CalloutValueType type)
101 {
102     _flags = calloutType | fruIdentIncluded;
103 
104     _priority = static_cast<uint8_t>(priority);
105 
106     _locationCodeSize = 0;
107 
108     _fruIdentity = std::make_unique<FRUIdentity>(procedure, type);
109 
110     _size = flattenedSize();
111 }
112 
Callout(CalloutPriority priority,const std::string & symbolicFRU,CalloutValueType type,const std::string & locationCode,bool trustedLocationCode)113 Callout::Callout(CalloutPriority priority, const std::string& symbolicFRU,
114                  CalloutValueType type, const std::string& locationCode,
115                  bool trustedLocationCode)
116 {
117     _flags = calloutType | fruIdentIncluded;
118 
119     _priority = static_cast<uint8_t>(priority);
120 
121     setLocationCode(locationCode);
122 
123     _fruIdentity =
124         std::make_unique<FRUIdentity>(symbolicFRU, type, trustedLocationCode);
125 
126     _size = flattenedSize();
127 }
128 
setLocationCode(const std::string & locationCode)129 void Callout::setLocationCode(const std::string& locationCode)
130 {
131     if (locationCode.empty())
132     {
133         _locationCodeSize = 0;
134         return;
135     }
136 
137     std::copy(locationCode.begin(), locationCode.end(),
138               std::back_inserter(_locationCode));
139 
140     if (_locationCode.size() < locationCodeMaxSize)
141     {
142         // Add a NULL, and then pad to a 4B boundary
143         _locationCode.push_back('\0');
144 
145         while (_locationCode.size() % 4)
146         {
147             _locationCode.push_back('\0');
148         }
149     }
150     else
151     {
152         // Too big - truncate it and ensure it ends in a NULL.
153         _locationCode.resize(locationCodeMaxSize);
154         _locationCode.back() = '\0';
155     }
156 
157     _locationCodeSize = _locationCode.size();
158 }
159 
flattenedSize() const160 size_t Callout::flattenedSize() const
161 {
162     size_t size = sizeof(_size) + sizeof(_flags) + sizeof(_priority) +
163                   sizeof(_locationCodeSize) + _locationCodeSize;
164 
165     size += _fruIdentity ? _fruIdentity->flattenedSize() : 0;
166     size += _pceIdentity ? _pceIdentity->flattenedSize() : 0;
167     size += _mru ? _mru->flattenedSize() : 0;
168 
169     return size;
170 }
171 
flatten(Stream & pel) const172 void Callout::flatten(Stream& pel) const
173 {
174     pel << _size << _flags << _priority << _locationCodeSize;
175 
176     if (_locationCodeSize)
177     {
178         pel << _locationCode;
179     }
180 
181     if (_fruIdentity)
182     {
183         _fruIdentity->flatten(pel);
184     }
185 
186     if (_pceIdentity)
187     {
188         _pceIdentity->flatten(pel);
189     }
190     if (_mru)
191     {
192         _mru->flatten(pel);
193     }
194 }
195 
operator ==(const Callout & right) const196 bool Callout::operator==(const Callout& right) const
197 {
198     if ((_locationCodeSize != 0) || (right.locationCodeSize() != 0))
199     {
200         return locationCode() == right.locationCode();
201     }
202 
203     if (!_fruIdentity || !right.fruIdentity())
204     {
205         return false;
206     }
207 
208     auto myProc = _fruIdentity->getMaintProc();
209     auto otherProc = right.fruIdentity()->getMaintProc();
210     if (myProc)
211     {
212         if (otherProc)
213         {
214             return *myProc == *otherProc;
215         }
216         return false;
217     }
218 
219     auto myPN = _fruIdentity->getPN();
220     auto otherPN = right.fruIdentity()->getPN();
221     if (myPN && otherPN)
222     {
223         return *myPN == *otherPN;
224     }
225 
226     return false;
227 }
228 
operator >(const Callout & right) const229 bool Callout::operator>(const Callout& right) const
230 {
231     // Treat all of the mediums the same
232     const std::map<std::uint8_t, int> priorities = {
233         {'H', 10}, {'M', 9}, {'A', 9}, {'B', 9}, {'C', 9}, {'L', 8}};
234 
235     if (!priorities.contains(priority()) ||
236         !priorities.contains(right.priority()))
237     {
238         return false;
239     }
240 
241     return priorities.at(priority()) > priorities.at(right.priority());
242 }
243 
244 } // namespace src
245 } // namespace pels
246 } // namespace openpower
247