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