| /** |
| * 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/lg2.hpp> |
| |
| #include <map> |
| |
| namespace openpower |
| { |
| namespace pels |
| { |
| namespace src |
| { |
| |
| 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: |
| lg2::error("Invalid Callout subsection type {CALLOUT_TYPE}", |
| "CALLOUT_TYPE", lg2::hex, 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); |
| } |
| } |
| |
| bool Callout::operator==(const Callout& right) const |
| { |
| if ((_locationCodeSize != 0) || (right.locationCodeSize() != 0)) |
| { |
| return locationCode() == right.locationCode(); |
| } |
| |
| if (!_fruIdentity || !right.fruIdentity()) |
| { |
| return false; |
| } |
| |
| auto myProc = _fruIdentity->getMaintProc(); |
| auto otherProc = right.fruIdentity()->getMaintProc(); |
| if (myProc) |
| { |
| if (otherProc) |
| { |
| return *myProc == *otherProc; |
| } |
| return false; |
| } |
| |
| auto myPN = _fruIdentity->getPN(); |
| auto otherPN = right.fruIdentity()->getPN(); |
| if (myPN && otherPN) |
| { |
| return *myPN == *otherPN; |
| } |
| |
| return false; |
| } |
| |
| bool Callout::operator>(const Callout& right) const |
| { |
| // Treat all of the mediums the same |
| const std::map<std::uint8_t, int> priorities = { |
| {'H', 10}, {'M', 9}, {'A', 9}, {'B', 9}, {'C', 9}, {'L', 8}}; |
| |
| if (!priorities.contains(priority()) || |
| !priorities.contains(right.priority())) |
| { |
| return false; |
| } |
| |
| return priorities.at(priority()) > priorities.at(right.priority()); |
| } |
| |
| } // namespace src |
| } // namespace pels |
| } // namespace openpower |