/** * 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 "callout.hpp" #include namespace openpower { namespace pels { namespace src { using namespace phosphor::logging; constexpr size_t locationCodeMaxSize = 80; Callout::Callout(Stream& pel) { pel >> _size >> _flags >> _priority >> _locationCodeSize; if (_locationCodeSize) { _locationCode.resize(_locationCodeSize); pel >> _locationCode; } size_t currentSize = 4 + _locationCodeSize; // Read in the substructures until the end of this structure. // Any stream overflows will throw an exception up to the SRC constructor while (_size > currentSize) { // Peek the type uint16_t type = 0; pel >> type; pel.offset(pel.offset() - 2); switch (type) { case FRUIdentity::substructureType: { _fruIdentity = std::make_unique(pel); currentSize += _fruIdentity->flattenedSize(); break; } case PCEIdentity::substructureType: { _pceIdentity = std::make_unique(pel); currentSize += _pceIdentity->flattenedSize(); break; } case MRU::substructureType: { _mru = std::make_unique(pel); currentSize += _mru->flattenedSize(); break; } default: log("Invalid Callout subsection type", entry("CALLOUT_TYPE=0x%X", type)); throw std::runtime_error("Invalid Callout subsection type"); break; } } } Callout::Callout(CalloutPriority priority, const std::string& locationCode, const std::string& partNumber, const std::string& ccin, const std::string& serialNumber) : Callout(priority, locationCode, partNumber, ccin, serialNumber, std::vector{}) {} Callout::Callout(CalloutPriority priority, const std::string& locationCode, const std::string& partNumber, const std::string& ccin, const std::string& serialNumber, const std::vector& mrus) { _flags = calloutType | fruIdentIncluded; _priority = static_cast(priority); setLocationCode(locationCode); _fruIdentity = std::make_unique(partNumber, ccin, serialNumber); if (!mrus.empty()) { _flags |= mruIncluded; _mru = std::make_unique(mrus); } _size = flattenedSize(); } Callout::Callout(CalloutPriority priority, const std::string& procedure, CalloutValueType type) { _flags = calloutType | fruIdentIncluded; _priority = static_cast(priority); _locationCodeSize = 0; _fruIdentity = std::make_unique(procedure, type); _size = flattenedSize(); } Callout::Callout(CalloutPriority priority, const std::string& symbolicFRU, CalloutValueType type, const std::string& locationCode, bool trustedLocationCode) { _flags = calloutType | fruIdentIncluded; _priority = static_cast(priority); setLocationCode(locationCode); _fruIdentity = std::make_unique(symbolicFRU, type, trustedLocationCode); _size = flattenedSize(); } void Callout::setLocationCode(const std::string& locationCode) { if (locationCode.empty()) { _locationCodeSize = 0; return; } std::copy(locationCode.begin(), locationCode.end(), std::back_inserter(_locationCode)); if (_locationCode.size() < locationCodeMaxSize) { // Add a NULL, and then pad to a 4B boundary _locationCode.push_back('\0'); while (_locationCode.size() % 4) { _locationCode.push_back('\0'); } } else { // Too big - truncate it and ensure it ends in a NULL. _locationCode.resize(locationCodeMaxSize); _locationCode.back() = '\0'; } _locationCodeSize = _locationCode.size(); } size_t Callout::flattenedSize() const { size_t size = sizeof(_size) + sizeof(_flags) + sizeof(_priority) + sizeof(_locationCodeSize) + _locationCodeSize; size += _fruIdentity ? _fruIdentity->flattenedSize() : 0; size += _pceIdentity ? _pceIdentity->flattenedSize() : 0; size += _mru ? _mru->flattenedSize() : 0; return size; } void Callout::flatten(Stream& pel) const { pel << _size << _flags << _priority << _locationCodeSize; if (_locationCodeSize) { pel << _locationCode; } if (_fruIdentity) { _fruIdentity->flatten(pel); } if (_pceIdentity) { _pceIdentity->flatten(pel); } if (_mru) { _mru->flatten(pel); } } } // namespace src } // namespace pels } // namespace openpower