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 89 Callout::Callout(CalloutPriority priority, const std::string& locationCode, 90 const std::string& partNumber, const std::string& ccin, 91 const std::string& serialNumber, 92 const std::vector<MRU::MRUCallout>& mrus) 93 { 94 _flags = calloutType | fruIdentIncluded; 95 96 _priority = static_cast<uint8_t>(priority); 97 98 setLocationCode(locationCode); 99 100 _fruIdentity = 101 std::make_unique<FRUIdentity>(partNumber, ccin, serialNumber); 102 103 if (!mrus.empty()) 104 { 105 _flags |= mruIncluded; 106 _mru = std::make_unique<MRU>(mrus); 107 } 108 109 _size = flattenedSize(); 110 } 111 112 Callout::Callout(CalloutPriority priority, const std::string& procedure, 113 CalloutValueType type) 114 { 115 _flags = calloutType | fruIdentIncluded; 116 117 _priority = static_cast<uint8_t>(priority); 118 119 _locationCodeSize = 0; 120 121 _fruIdentity = std::make_unique<FRUIdentity>(procedure, type); 122 123 _size = flattenedSize(); 124 } 125 126 Callout::Callout(CalloutPriority priority, const std::string& symbolicFRU, 127 CalloutValueType type, const std::string& locationCode, 128 bool trustedLocationCode) 129 { 130 _flags = calloutType | fruIdentIncluded; 131 132 _priority = static_cast<uint8_t>(priority); 133 134 setLocationCode(locationCode); 135 136 _fruIdentity = 137 std::make_unique<FRUIdentity>(symbolicFRU, type, trustedLocationCode); 138 139 _size = flattenedSize(); 140 } 141 142 void Callout::setLocationCode(const std::string& locationCode) 143 { 144 if (locationCode.empty()) 145 { 146 _locationCodeSize = 0; 147 return; 148 } 149 150 std::copy(locationCode.begin(), locationCode.end(), 151 std::back_inserter(_locationCode)); 152 153 if (_locationCode.size() < locationCodeMaxSize) 154 { 155 // Add a NULL, and then pad to a 4B boundary 156 _locationCode.push_back('\0'); 157 158 while (_locationCode.size() % 4) 159 { 160 _locationCode.push_back('\0'); 161 } 162 } 163 else 164 { 165 // Too big - truncate it and ensure it ends in a NULL. 166 _locationCode.resize(locationCodeMaxSize); 167 _locationCode.back() = '\0'; 168 } 169 170 _locationCodeSize = _locationCode.size(); 171 } 172 173 size_t Callout::flattenedSize() const 174 { 175 size_t size = sizeof(_size) + sizeof(_flags) + sizeof(_priority) + 176 sizeof(_locationCodeSize) + _locationCodeSize; 177 178 size += _fruIdentity ? _fruIdentity->flattenedSize() : 0; 179 size += _pceIdentity ? _pceIdentity->flattenedSize() : 0; 180 size += _mru ? _mru->flattenedSize() : 0; 181 182 return size; 183 } 184 185 void Callout::flatten(Stream& pel) const 186 { 187 pel << _size << _flags << _priority << _locationCodeSize; 188 189 if (_locationCodeSize) 190 { 191 pel << _locationCode; 192 } 193 194 if (_fruIdentity) 195 { 196 _fruIdentity->flatten(pel); 197 } 198 199 if (_pceIdentity) 200 { 201 _pceIdentity->flatten(pel); 202 } 203 if (_mru) 204 { 205 _mru->flatten(pel); 206 } 207 } 208 209 } // namespace src 210 } // namespace pels 211 } // namespace openpower 212