/** * Copyright © 2019 IBM Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "fru_identity.hpp" #include "pel_values.hpp" #include #include using namespace phosphor::logging; namespace openpower { namespace pels { namespace src { namespace { /** * @brief Fills in the std::array from the string value * * If the string is shorter than the array, it will be padded with * '\0's. * * @param[in] source - The string to fill in the array with * @param[out] target - The input object that supports [] and size() */ template void fillArray(const std::string& source, T& target) { for (size_t i = 0; i < target.size(); i++) { target[i] = (source.size() > i) ? source[i] : '\0'; } } } // namespace FRUIdentity::FRUIdentity(Stream& pel) { pel >> _type >> _size >> _flags; if (hasPN() || hasMP()) { pel.read(_pnOrProcedureID.data(), _pnOrProcedureID.size()); } if (hasCCIN()) { pel.read(_ccin.data(), _ccin.size()); } if (hasSN()) { pel.read(_sn.data(), _sn.size()); } } size_t FRUIdentity::flattenedSize() const { size_t size = sizeof(_type) + sizeof(_size) + sizeof(_flags); if (hasPN() || hasMP()) { size += _pnOrProcedureID.size(); } if (hasCCIN()) { size += _ccin.size(); } if (hasSN()) { size += _sn.size(); } return size; } FRUIdentity::FRUIdentity(const std::string& partNumber, const std::string& ccin, const std::string& serialNumber) { _type = substructureType; _flags = hardwareFRU; setPartNumber(partNumber); setCCIN(ccin); setSerialNumber(serialNumber); _size = flattenedSize(); } FRUIdentity::FRUIdentity(const std::string& procedure, CalloutValueType type) { _type = substructureType; _flags = maintenanceProc; setMaintenanceProcedure(procedure, type); _size = flattenedSize(); } FRUIdentity::FRUIdentity(const std::string& fru, CalloutValueType type, bool trustedLocationCode) { _type = substructureType; _flags = (trustedLocationCode) ? symbolicFRUTrustedLocCode : symbolicFRU; setSymbolicFRU(fru, type); _size = flattenedSize(); } std::optional FRUIdentity::getPN() const { if (hasPN()) { // NULL terminated std::string pn{_pnOrProcedureID.data()}; return pn; } return std::nullopt; } std::optional FRUIdentity::getMaintProc() const { if (hasMP()) { // NULL terminated std::string mp{_pnOrProcedureID.data()}; return mp; } return std::nullopt; } std::optional FRUIdentity::getCCIN() const { if (hasCCIN()) { std::string ccin{_ccin.begin(), _ccin.begin() + _ccin.size()}; // Don't leave any NULLs in the string (not there usually) if (auto pos = ccin.find('\0'); pos != std::string::npos) { ccin.resize(pos); } return ccin; } return std::nullopt; } std::optional FRUIdentity::getSN() const { if (hasSN()) { std::string sn{_sn.begin(), _sn.begin() + _sn.size()}; // Don't leave any NULLs in the string (not there usually) if (auto pos = sn.find('\0'); pos != std::string::npos) { sn.resize(pos); } return sn; } return std::nullopt; } void FRUIdentity::flatten(Stream& pel) const { pel << _type << _size << _flags; if (hasPN() || hasMP()) { pel.write(_pnOrProcedureID.data(), _pnOrProcedureID.size()); } if (hasCCIN()) { pel.write(_ccin.data(), _ccin.size()); } if (hasSN()) { pel.write(_sn.data(), _sn.size()); } } void FRUIdentity::setPartNumber(const std::string& partNumber) { _flags |= pnSupplied; _flags &= ~maintProcSupplied; auto pn = partNumber; // Strip leading whitespace on this one. while (' ' == pn.front()) { pn = pn.substr(1); } fillArray(pn, _pnOrProcedureID); // ensure null terminated _pnOrProcedureID.back() = 0; } void FRUIdentity::setCCIN(const std::string& ccin) { _flags |= ccinSupplied; fillArray(ccin, _ccin); } void FRUIdentity::setSerialNumber(const std::string& serialNumber) { _flags |= snSupplied; fillArray(serialNumber, _sn); } void FRUIdentity::setMaintenanceProcedure(const std::string& procedure, CalloutValueType type) { _flags |= maintProcSupplied; _flags &= ~pnSupplied; if (type == CalloutValueType::registryName) { if (pel_values::maintenanceProcedures.count(procedure)) { fillArray(pel_values::maintenanceProcedures.at(procedure), _pnOrProcedureID); } else { log( fmt::format("Invalid maintenance procedure {}", procedure) .c_str()); strncpy(_pnOrProcedureID.data(), "INVALID", _pnOrProcedureID.size()); } } else { fillArray(procedure, _pnOrProcedureID); } // ensure null terminated _pnOrProcedureID.back() = 0; } void FRUIdentity::setSymbolicFRU(const std::string& symbolicFRU, CalloutValueType type) { // Treat this has a HW callout. _flags |= pnSupplied; _flags &= ~maintProcSupplied; if (type == CalloutValueType::registryName) { if (pel_values::symbolicFRUs.count(symbolicFRU)) { fillArray(pel_values::symbolicFRUs.at(symbolicFRU), _pnOrProcedureID); } else { log("Invalid symbolic FRU", entry("FRU=%s", symbolicFRU.c_str())); strncpy(_pnOrProcedureID.data(), "INVALID", _pnOrProcedureID.size()); } } else { fillArray(symbolicFRU, _pnOrProcedureID); } // ensure null terminated _pnOrProcedureID.back() = 0; } } // namespace src } // namespace pels } // namespace openpower