| /** |
| * 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 <phosphor-logging/log.hpp> |
| |
| 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<FRUIdentity>(pel); |
| currentSize += _fruIdentity->flattenedSize(); |
| break; |
| } |
| case PCEIdentity::substructureType: |
| { |
| _pceIdentity = std::make_unique<PCEIdentity>(pel); |
| currentSize += _pceIdentity->flattenedSize(); |
| break; |
| } |
| case MRU::substructureType: |
| { |
| _mru = std::make_unique<MRU>(pel); |
| currentSize += _mru->flattenedSize(); |
| break; |
| } |
| default: |
| log<level::ERR>("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<MRU::MRUCallout>{}) |
| { |
| } |
| |
| Callout::Callout(CalloutPriority priority, const std::string& locationCode, |
| const std::string& partNumber, const std::string& ccin, |
| const std::string& serialNumber, |
| const std::vector<MRU::MRUCallout>& mrus) |
| { |
| _flags = calloutType | fruIdentIncluded; |
| |
| _priority = static_cast<uint8_t>(priority); |
| |
| setLocationCode(locationCode); |
| |
| _fruIdentity = |
| std::make_unique<FRUIdentity>(partNumber, ccin, serialNumber); |
| |
| if (!mrus.empty()) |
| { |
| _flags |= mruIncluded; |
| _mru = std::make_unique<MRU>(mrus); |
| } |
| |
| _size = flattenedSize(); |
| } |
| |
| Callout::Callout(CalloutPriority priority, const std::string& procedure, |
| CalloutValueType type) |
| { |
| _flags = calloutType | fruIdentIncluded; |
| |
| _priority = static_cast<uint8_t>(priority); |
| |
| _locationCodeSize = 0; |
| |
| _fruIdentity = std::make_unique<FRUIdentity>(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<uint8_t>(priority); |
| |
| setLocationCode(locationCode); |
| |
| _fruIdentity = |
| std::make_unique<FRUIdentity>(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 |