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/log.hpp> 19 20 namespace openpower 21 { 22 namespace pels 23 { 24 namespace src 25 { 26 27 using namespace phosphor::logging; 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 log<level::ERR>("Invalid Callout subsection type", 74 entry("CALLOUT_TYPE=0x%X", 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 = std::make_unique<FRUIdentity>(partNumber, ccin, 100 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 = std::make_unique<FRUIdentity>(symbolicFRU, type, 136 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 } // namespace src 209 } // namespace pels 210 } // namespace openpower 211