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