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