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 "fru_identity.hpp" 17 18 #include "pel_values.hpp" 19 20 #include <fmt/format.h> 21 22 #include <phosphor-logging/log.hpp> 23 24 using namespace phosphor::logging; 25 26 namespace openpower 27 { 28 namespace pels 29 { 30 namespace src 31 { 32 33 namespace 34 { 35 36 /** 37 * @brief Fills in the std::array from the string value 38 * 39 * If the string is shorter than the array, it will be padded with 40 * '\0's. 41 * 42 * @param[in] source - The string to fill in the array with 43 * @param[out] target - The input object that supports [] and size() 44 */ 45 template <typename T> 46 void fillArray(const std::string& source, T& target) 47 { 48 for (size_t i = 0; i < target.size(); i++) 49 { 50 target[i] = (source.size() > i) ? source[i] : '\0'; 51 } 52 } 53 54 } // namespace 55 56 FRUIdentity::FRUIdentity(Stream& pel) 57 { 58 pel >> _type >> _size >> _flags; 59 60 if (hasPN() || hasMP()) 61 { 62 pel.read(_pnOrProcedureID.data(), _pnOrProcedureID.size()); 63 } 64 65 if (hasCCIN()) 66 { 67 pel.read(_ccin.data(), _ccin.size()); 68 } 69 70 if (hasSN()) 71 { 72 pel.read(_sn.data(), _sn.size()); 73 } 74 } 75 76 size_t FRUIdentity::flattenedSize() const 77 { 78 size_t size = sizeof(_type) + sizeof(_size) + sizeof(_flags); 79 80 if (hasPN() || hasMP()) 81 { 82 size += _pnOrProcedureID.size(); 83 } 84 85 if (hasCCIN()) 86 { 87 size += _ccin.size(); 88 } 89 90 if (hasSN()) 91 { 92 size += _sn.size(); 93 } 94 95 return size; 96 } 97 98 FRUIdentity::FRUIdentity(const std::string& partNumber, const std::string& ccin, 99 const std::string& serialNumber) 100 { 101 _type = substructureType; 102 _flags = hardwareFRU; 103 104 setPartNumber(partNumber); 105 setCCIN(ccin); 106 setSerialNumber(serialNumber); 107 108 _size = flattenedSize(); 109 } 110 111 FRUIdentity::FRUIdentity(const std::string& procedure, CalloutValueType type) 112 { 113 _type = substructureType; 114 _flags = maintenanceProc; 115 116 setMaintenanceProcedure(procedure, type); 117 118 _size = flattenedSize(); 119 } 120 121 FRUIdentity::FRUIdentity(const std::string& fru, CalloutValueType type, 122 bool trustedLocationCode) 123 { 124 _type = substructureType; 125 _flags = (trustedLocationCode) ? symbolicFRUTrustedLocCode : symbolicFRU; 126 127 setSymbolicFRU(fru, type); 128 129 _size = flattenedSize(); 130 } 131 132 std::optional<std::string> FRUIdentity::getPN() const 133 { 134 if (hasPN()) 135 { 136 // NULL terminated 137 std::string pn{_pnOrProcedureID.data()}; 138 return pn; 139 } 140 141 return std::nullopt; 142 } 143 144 std::optional<std::string> FRUIdentity::getMaintProc() const 145 { 146 if (hasMP()) 147 { 148 // NULL terminated 149 std::string mp{_pnOrProcedureID.data()}; 150 return mp; 151 } 152 153 return std::nullopt; 154 } 155 156 std::optional<std::string> FRUIdentity::getCCIN() const 157 { 158 if (hasCCIN()) 159 { 160 std::string ccin{_ccin.begin(), _ccin.begin() + _ccin.size()}; 161 162 // Don't leave any NULLs in the string (not there usually) 163 if (auto pos = ccin.find('\0'); pos != std::string::npos) 164 { 165 ccin.resize(pos); 166 } 167 return ccin; 168 } 169 170 return std::nullopt; 171 } 172 173 std::optional<std::string> FRUIdentity::getSN() const 174 { 175 if (hasSN()) 176 { 177 std::string sn{_sn.begin(), _sn.begin() + _sn.size()}; 178 179 // Don't leave any NULLs in the string (not there usually) 180 if (auto pos = sn.find('\0'); pos != std::string::npos) 181 { 182 sn.resize(pos); 183 } 184 return sn; 185 } 186 187 return std::nullopt; 188 } 189 190 void FRUIdentity::flatten(Stream& pel) const 191 { 192 pel << _type << _size << _flags; 193 194 if (hasPN() || hasMP()) 195 { 196 pel.write(_pnOrProcedureID.data(), _pnOrProcedureID.size()); 197 } 198 199 if (hasCCIN()) 200 { 201 pel.write(_ccin.data(), _ccin.size()); 202 } 203 204 if (hasSN()) 205 { 206 pel.write(_sn.data(), _sn.size()); 207 } 208 } 209 210 void FRUIdentity::setPartNumber(const std::string& partNumber) 211 { 212 _flags |= pnSupplied; 213 _flags &= ~maintProcSupplied; 214 215 auto pn = partNumber; 216 217 // Strip leading whitespace on this one. 218 while (' ' == pn.front()) 219 { 220 pn = pn.substr(1); 221 } 222 223 fillArray(pn, _pnOrProcedureID); 224 225 // ensure null terminated 226 _pnOrProcedureID.back() = 0; 227 } 228 229 void FRUIdentity::setCCIN(const std::string& ccin) 230 { 231 _flags |= ccinSupplied; 232 233 fillArray(ccin, _ccin); 234 } 235 236 void FRUIdentity::setSerialNumber(const std::string& serialNumber) 237 { 238 _flags |= snSupplied; 239 240 fillArray(serialNumber, _sn); 241 } 242 243 void FRUIdentity::setMaintenanceProcedure(const std::string& procedure, 244 CalloutValueType type) 245 { 246 _flags |= maintProcSupplied; 247 _flags &= ~pnSupplied; 248 249 if (type == CalloutValueType::registryName) 250 { 251 if (pel_values::maintenanceProcedures.count(procedure)) 252 { 253 fillArray(pel_values::maintenanceProcedures.at(procedure), 254 _pnOrProcedureID); 255 } 256 else 257 { 258 log<level::ERR>( 259 fmt::format("Invalid maintenance procedure {}", procedure) 260 .c_str()); 261 strncpy(_pnOrProcedureID.data(), "INVALID", 262 _pnOrProcedureID.size()); 263 } 264 } 265 else 266 { 267 fillArray(procedure, _pnOrProcedureID); 268 } 269 270 // ensure null terminated 271 _pnOrProcedureID.back() = 0; 272 } 273 274 void FRUIdentity::setSymbolicFRU(const std::string& symbolicFRU, 275 CalloutValueType type) 276 { 277 278 // Treat this has a HW callout. 279 _flags |= pnSupplied; 280 _flags &= ~maintProcSupplied; 281 282 if (type == CalloutValueType::registryName) 283 { 284 if (pel_values::symbolicFRUs.count(symbolicFRU)) 285 { 286 fillArray(pel_values::symbolicFRUs.at(symbolicFRU), 287 _pnOrProcedureID); 288 } 289 else 290 { 291 log<level::ERR>("Invalid symbolic FRU", 292 entry("FRU=%s", symbolicFRU.c_str())); 293 strncpy(_pnOrProcedureID.data(), "INVALID", 294 _pnOrProcedureID.size()); 295 } 296 } 297 else 298 { 299 fillArray(symbolicFRU, _pnOrProcedureID); 300 } 301 302 // ensure null terminated 303 _pnOrProcedureID.back() = 0; 304 } 305 306 } // namespace src 307 } // namespace pels 308 } // namespace openpower 309