diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/include/usr/sbeio/sbe_ffdc_package_parser.H | 283 | ||||
-rw-r--r-- | src/include/usr/sbeio/sbe_ffdc_parser.H | 8 | ||||
-rw-r--r-- | src/usr/sbeio/makefile | 2 | ||||
-rw-r--r-- | src/usr/sbeio/sbe_ffdc_package_parser.C | 299 | ||||
-rw-r--r-- | src/usr/sbeio/sbe_ffdc_parser.C | 19 | ||||
-rw-r--r-- | src/usr/sbeio/sbe_fifo_buffer.C | 306 | ||||
-rw-r--r-- | src/usr/sbeio/sbe_fifo_buffer.H | 318 | ||||
-rw-r--r-- | src/usr/sbeio/sbe_fifodd.C | 158 | ||||
-rw-r--r-- | src/usr/sbeio/sbe_fifodd.H | 2 | ||||
-rw-r--r-- | src/usr/sbeio/sbe_psudd.C | 43 | ||||
-rw-r--r-- | src/usr/sbeio/test/makefile | 4 | ||||
-rw-r--r-- | src/usr/sbeio/test/sbe_ffdc_package_parser_test.H | 688 | ||||
-rw-r--r-- | src/usr/sbeio/test/sbe_fifo_buffer_test.H | 1866 | ||||
-rw-r--r-- | src/usr/sbeio/test/sbe_test_support.H | 91 |
14 files changed, 3975 insertions, 112 deletions
diff --git a/src/include/usr/sbeio/sbe_ffdc_package_parser.H b/src/include/usr/sbeio/sbe_ffdc_package_parser.H new file mode 100644 index 000000000..1fa9cada9 --- /dev/null +++ b/src/include/usr/sbeio/sbe_ffdc_package_parser.H @@ -0,0 +1,283 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/include/usr/sbeio/sbe_ffdc_package_parser.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* 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. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __SBEIO_SBE_FFDC_PACKAGE_PARSER_H +#define __SBEIO_SBE_FFDC_PACKAGE_PARSER_H + +#include <stdint.h> +#include <memory> + +#include <errl/errlentry.H> +#include <sbeio/sbe_ffdc_parser.H> +#include <targeting/common/target.H> + +namespace SBEIO +{ + +/** + * @brief A class to support processing of parsed ffdc data. + * + * FFDC data schema is related to RC codes. There does not + * exist a facility code to identify common types of FFDC data. + * Instead, each RC code is given an FFDC schema based upon settings + * in the error_info xml files. Although many error codes share the same + * FFDC format, there is nothing to relate similar FFDC schemas to RC values, + * The mapping is the other way around, individual fapi RC codes map to + * FFDC formats. In addition, because of the use of template type deduction + * in populating FFDC data, type information which may prove useful for parsing + * is lost. To illustrate, the SBE uses a global variable to hold FFDC data for + * a request. The global variable contains a field for storing the fapiRC code + * and an array of up to 10 sbeFfdc_t structs used to hold the FFDC data. For a + * Scom PIB error, the schema of the FFDC places the scom address and size in + * first sbeFfdc_t struct and the pib rc in the second struct. Each sbeFfdc_t + * struct is just a uint64_t for the data and a uint32_t for the size. There + * is no type information stored. The uint64_t in some instances can hold + * a pointer to a target, in other instances data such as the PIB RC code and + * yet in other cases an address such as the scom address. The Scom PIB errors + * from the SBE uses only two of the sbeFfdc_t slots. Other errors use 3,4 or + * more sbeFfdc_t data. + * Because of the lack of parsing support available, this base class and + * derived classes are manually coded to group fapi RC values with similar FFDC + * formats in order to aid parsing of FFDC data. Currently, we only parse the + * format used for the scom pib memory errors returned from the SBE. + * + * + */ +class FfdcParsedPackage +{ +public: + + /** + * @brief Used to identify FFDC schema. + * + */ + enum class ParsedType{ + NONE, + SBE_SCOM_PIB_ERROR + }; + + virtual ~FfdcParsedPackage() = default; + + /** + * @brief Determines if the FFDC package was successfully parsed. + * + * @return True if the ffdc package was parsed, false otherwise. + */ + bool isValid() const {return iv_packageType != ParsedType::NONE;} + + /** + * @brief Obtain the FFDC package type that was parsed. + */ + ParsedType parsedType() const {return iv_packageType;} + + /** + * @brief Perform the default action on the parsed + * ffdc data. + * + * @param[in] i_target, the target of the request. + * @param[in] i_errl, error entry for processing. + * + */ + virtual void operator()(TARGETING::Target* i_target, + errlHndl_t i_errl + ) const {}; + + /** + * @brief bool operator for isValid. + * + */ + operator bool() const {return isValid();} + + /** + * @brief Convert fapiRC to a ParsedType. + * + * @param[in] fapiRc, the rc to convert. + * + * @return The ParsedType corresponding to fapiRc + * + */ + static ParsedType rcToParsedType(uint32_t fapiRc); + + /** + * @brief parse the FFDC package and perform the default + * operation if parsing was successful. + * + * @param[in] i_ffdc_package, the ffdc to parse and process. + * @param[in] i_target, the target of the default processing. + * @param[in] i_errl, the ErrlEntry to be used for default processing. + * + */ + static void doDefaultProcessing(const ffdc_package& i_ffdc_package, + TARGETING::Target* i_target, + errlHndl_t i_errl + ); + + /** + * @brief Parse the given FFDC data. + * + * @param[in] i_ffdc_package to parse. + * + * @return a shared pointer to an object derived from FfdcParsedPackage. + * If the package could not be parsed a raw FfdcParsedPackage + * is returned. + */ + static std::shared_ptr<const FfdcParsedPackage> + getParsedPackage(const ffdc_package& i_ffdc_package); + +protected: + + /** + * @brief Set the parsed ffdc type. + * + * @param[in] The new Parsed FFDC Type value. + * + */ + void parsedType(const ParsedType& i_parsedType) + { + iv_packageType = i_parsedType; + } + +private: + + ParsedType iv_packageType{ParsedType::NONE}; /**< The FFDC type */ +}; + + + +/** + * @brief Processing for SBE scom pib FFDC. + * + * The FFDC schema parsed by this class is as follows: + * + * u32 u32 u64 u32 u64 + * | FapiRC | Scom Addr Size | Scom Addr | PIB RC Size | PIB RC | + * + */ +class FfdcScomPibErrorPackage: public FfdcParsedPackage +{ +public: + /** + * @brief Contsructor + * + * @param[in] i_ffdc, the unparsed raw ffdc data. + * @param[in] i_ignoreRC, if true then validation of the ffdc + * schema has already been performed by the + * static method doesPackageMatchSchema. In this + * case the rc of the ffdc does not match the list of + * known fapiRC values that correspond to the ffdc + * schema parsed by this class. However, if it is assumed + * that a new fapiRC is responsible for this condition + * then we may use this class to process the FFDC regardless + * of the corresponding fapiRC. This could prove useful as + * SBE errors in messaging currently only send Scom Pib errors + * as the first FFDC entry. + */ + explicit FfdcScomPibErrorPackage(const ffdc_package& i_ffdc, + bool i_ignoreRC = false); + + virtual ~FfdcScomPibErrorPackage() = default; + + /** + * @brief Call operator for default processing. For this FFDC schema + * we call the addFruCallouts method. + * + * @param[in] i_target, the target of the default processing. + * @param[in] i_errl, the ErrlEntry to be used for default processing. + * + */ + void operator() (TARGETING::Target* i_target, + errlHndl_t i_errl + ) const override; + + /** + * @brief Use parsed data to add Fru Callouts. The method + * is virtual to facilitate a unit test seam. + * + * @param[in] i_target, the target for the callout. + * @param[in] i_errl, the ErrlEntry to which to add the callout. + * + */ + virtual void addFruCallouts (TARGETING::Target* i_target, + errlHndl_t i_errl + ) const; + + /** + * @brief Accessor for the PIB RC parsed data. + * + * @return The PIB RC Code from the FFDC data. + * + */ + uint64_t getPibRc() const {return iv_pibRc;} + + /** + * @brief Accessor for the PIB RC parsed data. + * + * @return The PIB RC Code from the FFDC data. + * + */ + uint64_t getScomAddress() const {return iv_scomAddress;} + + /** + * @brief Check if the FFDC schema matches that expected by this class, + * with the exception of the RC code. This is intended for use + * when we are always expecting a certain FFDC schema from a + * function call but perhaps a new RC has been added that has not + * yet been added to those we know of. + * + * @param[in] i_ffdc: the ffdc data to validate. + * + * @return True if the FFDC schema matches what we are expecting, false + * otherwise. + * + */ + static bool doesPackageMatchSchema(const ffdc_package& i_ffdc); + + static const uint64_t INVALID_DATA = uint64_t(-1); + +private: + + /** + * @brief Validate that the passed in FFDC data has a schema consistent + * with what we are expecting. + * + * @param[in] i_ffdc, the FFDC data to validate. + * @param[in] i_ignoreRC, Do not base validation on RC value. Setting + * this parameter to true indicates that the schema has already + * been checked by the doesPackageMatchSchema function and + * as such we just need to parse the data and not validate. + * + * @return True if the FFDC data was successfully validated and parsed, + * False otherwise. + * + */ + bool validateFFDCPackage(const ffdc_package& i_ffdc, bool i_ignoreRC); + + uint64_t iv_pibRc{INVALID_DATA}; /**< parsed pib rc code */ + uint64_t iv_scomAddress{INVALID_DATA}; /**< parsed scom address */ +}; + + +} + +#endif diff --git a/src/include/usr/sbeio/sbe_ffdc_parser.H b/src/include/usr/sbeio/sbe_ffdc_parser.H index a18d8a1ad..41ebe52ce 100644 --- a/src/include/usr/sbeio/sbe_ffdc_parser.H +++ b/src/include/usr/sbeio/sbe_ffdc_parser.H @@ -83,6 +83,14 @@ class SbeFFDCParser void * getFFDCPackage(uint8_t i_index); /** + * @brief Get the raw ffdc package stored + * @retval: True if an ffdc package is stored at index, else false. + * @param[in] i_index index number + * @param[out] o_package The package structure to fill. + */ + bool getFFDCPackage(uint8_t i_index, ffdc_package& o_package); + + /** * @brief Get the return code of the package * @retval: return code of the ffdc package * @param[in] i_index index number diff --git a/src/usr/sbeio/makefile b/src/usr/sbeio/makefile index d1369e485..4174a0181 100644 --- a/src/usr/sbeio/makefile +++ b/src/usr/sbeio/makefile @@ -45,6 +45,8 @@ OBJS += sbe_scomAccessdd.o OBJS += sbe_ffdc_parser.o OBJS += sbe_setFFDCAddr.o OBJS += sbe_memRegionMgr.o +OBJS += sbe_fifo_buffer.o +OBJS += sbe_ffdc_package_parser.o VPATH += ${ROOTPATH}/src/import/chips/p9/procedures/hwp/perv/ include ${ROOTPATH}/procedure.rules.mk diff --git a/src/usr/sbeio/sbe_ffdc_package_parser.C b/src/usr/sbeio/sbe_ffdc_package_parser.C new file mode 100644 index 000000000..213d6133b --- /dev/null +++ b/src/usr/sbeio/sbe_ffdc_package_parser.C @@ -0,0 +1,299 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/sbeio/sbe_ffdc_package_parser.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* 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. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#include <sbeio/sbe_ffdc_package_parser.H> + +#include <hwp_return_codes.H> +#include <trace/interface.H> +#include <xscom/piberror.H> + +extern trace_desc_t* g_trac_sbeio; + +#define SBE_TRACF(printf_string,args...) \ + TRACFCOMP(g_trac_sbeio, "sbe ffdc: " printf_string,##args) + +namespace SBEIO +{ + +//--------------------------------------------------------------------------- +FfdcParsedPackage::ParsedType +FfdcParsedPackage::rcToParsedType(uint32_t fapiRc) +{ + ParsedType retval{ParsedType::NONE}; + + switch(fapiRc) + { + case fapi2::RC_SBE_SCOM_FAILURE: + case fapi2::RC_SBE_PIB_XSCOM_ERROR: + case fapi2::RC_SBE_PIB_OFFLINE_ERROR: + case fapi2::RC_SBE_PIB_PARTIAL_ERROR: + case fapi2::RC_SBE_PIB_ADDRESS_ERROR: + case fapi2::RC_SBE_PIB_CLOCK_ERROR: + case fapi2::RC_SBE_PIB_PARITY_ERROR: + case fapi2::RC_SBE_PIB_TIMEOUT_ERROR: + { + retval = ParsedType::SBE_SCOM_PIB_ERROR; + break; + } + } + + return retval; +} + +//--------------------------------------------------------------------------- +void FfdcParsedPackage::doDefaultProcessing( + const ffdc_package& i_ffdc_package, + TARGETING::Target* i_target, + errlHndl_t i_errl + ) +{ + ParsedType l_type = rcToParsedType(i_ffdc_package.rc); + switch(l_type) + { + case ParsedType::SBE_SCOM_PIB_ERROR: + { + FfdcScomPibErrorPackage ffdcPackage{i_ffdc_package}; + ffdcPackage(i_target, i_errl); + break; + } + case ParsedType::NONE: + { + //If the schema matches then we probably have a new rc + //that has yet to be accounted for. + if(0 != i_ffdc_package.rc) + { + if(FfdcScomPibErrorPackage::doesPackageMatchSchema + (i_ffdc_package)) + { + SBE_TRACF(WARN_MRK"Unknown RC matches " + "SBE_SCOM_PIB_ERROR FFDC schema. RC: 0x%08X", + i_ffdc_package.rc + ); + FfdcScomPibErrorPackage ffdcPackage{i_ffdc_package, + true + }; + ffdcPackage(i_target, i_errl); + } + } + break; + } + default: + { + SBE_TRACF(INFO_MRK"Unknown FFDC schema type encountered. " + "Parsed Type: 0x%04X", + static_cast<uint16_t>(l_type) + ); + break; + } + } +} + +//--------------------------------------------------------------------------- +std::shared_ptr<const FfdcParsedPackage> +FfdcParsedPackage::getParsedPackage(const ffdc_package& i_ffdc_package) +{ + std::shared_ptr<const FfdcParsedPackage> retval; + ParsedType l_type = rcToParsedType(i_ffdc_package.rc); + + switch(l_type) + { + case ParsedType::SBE_SCOM_PIB_ERROR: + { + FfdcParsedPackage* ptr = + new FfdcScomPibErrorPackage(i_ffdc_package); + retval.reset(ptr); + break; + } + default: + { + SBE_TRACF(WARN_MRK"No FFDC schema found for RC 0x%08X", + i_ffdc_package.rc + ); + retval.reset(new FfdcParsedPackage()); + break; + } + } + + return retval; +} + +//---------------------------------------------------------------------------- +FfdcScomPibErrorPackage::FfdcScomPibErrorPackage(const ffdc_package& i_ffdc, + bool ignoreRC + ) +{ + validateFFDCPackage(i_ffdc, ignoreRC); +} + +//---------------------------------------------------------------------------- +bool FfdcScomPibErrorPackage::validateFFDCPackage(const ffdc_package& i_ffdc, + bool ignoreRC) +{ + //Schema + // u32 u32 u64 u32 u64 + // | FAPI RC | SCOM ADDR SIZE | SCOM ADDR | PIB RC SIZE | PIB RC | + + bool retval{false}; + + do + { + if(nullptr == i_ffdc.ffdcPtr) + { + parsedType(ParsedType::NONE); + break; + } + + //if ignoreRC is true then schema validation has already been done. + //Skip this step and parse the FFDC data. + if(not ignoreRC) + { + if(ParsedType::SBE_SCOM_PIB_ERROR != rcToParsedType(i_ffdc.rc)) + { + parsedType(ParsedType::NONE); + break; + } + + if(not doesPackageMatchSchema(i_ffdc)) + { + parsedType(ParsedType::NONE); + break; + } + } + + constexpr size_t scomAddressOffset = sizeof(uint32_t) + //FAPI RC + sizeof(uint32_t); //size of Scom + //Addr + + constexpr size_t pibRcOffset = sizeof(uint32_t) + //FAPI RC + sizeof(uint32_t) + //size of Scom Addr + sizeof(uint64_t) + //Scom Address + sizeof(uint32_t); //size of PIB RC + + const char* l_buffer = reinterpret_cast<const char*>(i_ffdc.ffdcPtr); + + iv_scomAddress = *(reinterpret_cast<const uint64_t*> + (l_buffer + scomAddressOffset)); + + iv_pibRc = *(reinterpret_cast<const uint64_t*> + (l_buffer + pibRcOffset)); + + //Make this instance valid by assigning a ParsedType other than none. + parsedType(ParsedType::SBE_SCOM_PIB_ERROR); + retval = true; + } + while(0); + + return retval; +} + +//------------------------------------------------------------------------ +bool FfdcScomPibErrorPackage::doesPackageMatchSchema(const ffdc_package& + i_ffdc) +{ + //Schema + // u32 u32 u64 u32 u64 + // | FAPI RC | SCOM ADDR SIZE | SCOM ADDR | PIB RC SIZE | PIB RC | + bool retval{false}; + + do + { + if(nullptr == i_ffdc.ffdcPtr) + { + return retval; + } + + constexpr uint32_t l_expectedPIBSize = sizeof(uint64_t); + constexpr uint32_t l_expectedScomAddrSize{sizeof(uint64_t)}; + constexpr size_t expectedSize = sizeof(uint32_t) + //FAPI RC + sizeof(uint32_t) + //size of Scom Addr + sizeof(uint64_t) + //Scom Address + sizeof(uint32_t) + //size of PIB RC + sizeof(uint64_t); //PIB RC + + constexpr size_t scomAddrSizeOffset = sizeof(uint32_t); //FAPI RC + constexpr size_t pibSizeOffset = sizeof(uint32_t) + //FAPI RC + sizeof(uint32_t) + //size of Scom Addr + sizeof(uint64_t); //Scom Address + + + if(expectedSize != i_ffdc.size) + { + break; + } + + const char* l_buffer = reinterpret_cast<const char*>(i_ffdc.ffdcPtr); + + if(l_expectedScomAddrSize != *(reinterpret_cast<const uint32_t*> + (l_buffer + scomAddrSizeOffset))) + { + break; + } + + uint32_t l_pibSize = *(reinterpret_cast<const uint32_t*> + (l_buffer + pibSizeOffset)); + if(l_expectedPIBSize != l_pibSize) + { + //This can be deduced as uint32_t, we'll check uint16_t as well + if(not (l_pibSize < l_expectedPIBSize && l_pibSize != 0 && + 0 == l_pibSize%sizeof(uint16_t))) + { + break; + } + } + + retval = true; + } + while(0); + + return retval; +} + + +//-------------------------------------------------------------------------- +void FfdcScomPibErrorPackage::addFruCallouts(TARGETING::Target* i_target, + errlHndl_t i_errl + ) const +{ + if(isValid()) + { + if(PIB::PIB_NO_ERROR != iv_pibRc && INVALID_DATA != iv_pibRc) + { + PIB::addFruCallouts + (i_target, iv_pibRc, iv_scomAddress, i_errl); + } + } +} + +//--------------------------------------------------------------------------- +void FfdcScomPibErrorPackage::operator()(TARGETING::Target* i_target, + errlHndl_t i_errl + ) const +{ + if(isValid()) + { + addFruCallouts(i_target, i_errl); + } +} + +} diff --git a/src/usr/sbeio/sbe_ffdc_parser.C b/src/usr/sbeio/sbe_ffdc_parser.C index b742c8cb8..029f9182c 100644 --- a/src/usr/sbeio/sbe_ffdc_parser.C +++ b/src/usr/sbeio/sbe_ffdc_parser.C @@ -223,6 +223,25 @@ void * SbeFFDCParser::getFFDCPackage(uint8_t i_index) } /* + * @brief returns the FFDC package + */ +bool SbeFFDCParser::getFFDCPackage(uint8_t i_index, ffdc_package& o_package) +{ + bool retval{false}; + uint8_t l_size = getTotalPackages(); + if((i_index >= 0) && (i_index < l_size)) + { + ffdc_package *l_ffdcPkg = iv_ffdcPackages.at(i_index); + if(l_ffdcPkg) + { + o_package = *l_ffdcPkg; + retval = true; + } + } + return retval; +} + +/* * @brief returns the RC word */ uint32_t SbeFFDCParser::getPackageRC(uint8_t i_index) diff --git a/src/usr/sbeio/sbe_fifo_buffer.C b/src/usr/sbeio/sbe_fifo_buffer.C new file mode 100644 index 000000000..c6a9914a1 --- /dev/null +++ b/src/usr/sbeio/sbe_fifo_buffer.C @@ -0,0 +1,306 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/sbeio/sbe_fifo_buffer.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* 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. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#include "sbe_fifo_buffer.H" +#include <trace/interface.H> + +#include <algorithm> +#include <string.h> + +extern trace_desc_t* g_trac_sbeio; + +#define SBE_TRACF(printf_string,args...) \ + TRACFCOMP(g_trac_sbeio, printf_string,##args) + +constexpr size_t STATUS_WORD_SIZE = + sizeof(SBEIO::SbeFifo::statusHeader)/sizeof(uint32_t); + +namespace SBEIO +{ + +//------------------------------------------------------------------------ +const char* SbeFifoRespBuffer::cv_stateStrings[] = { + "INVALID_CALLER_BUFFER", + "OVERRUN", + "MSG_SHORT_READ", + "MSG_INVALID_OFFSET", + "MSG_COMPLETE", + "MSG_INCOMPLETE" + }; + +//------------------------------------------------------------------------- +SbeFifoRespBuffer::SbeFifoRespBuffer(uint32_t* i_fifoBuffer, + size_t bufferWordSize): + iv_callerBufferPtr(i_fifoBuffer), + iv_callerWordSize( + std::min(bufferWordSize, + MSG_BUFFER_SIZE) + ) +{ + do + { + memset(iv_localMsgBuffer, 0, sizeof(iv_localMsgBuffer)); + + if(not i_fifoBuffer || iv_callerWordSize < STATUS_WORD_SIZE) + { + SBE_TRACF(ERR_MRK"SbeFifoRespBuffer CTOR: Caller buffer invalid."); + iv_state = INVALID_CALLER_BUFFER; + break; + } + + memset(iv_callerBufferPtr, 0, iv_callerWordSize*sizeof(uint32_t)); + } + while(0); +} + +//--------------------------------------------------------------------- +bool SbeFifoRespBuffer::append(uint32_t i_value) +{ + bool retval = false; + + if(iv_state == MSG_INCOMPLETE) + { + if(iv_index < iv_callerWordSize) + { + iv_callerBufferPtr[iv_index] = i_value; + } + + if(iv_index < MSG_BUFFER_SIZE) + { + iv_localMsgBuffer[iv_index] = i_value; + ++iv_index; + retval = true; + } + else + { + SBE_TRACF(ERR_MRK"SbeFifoRespBuffer::append: Overran buffer."); + iv_state = OVERRUN; + } + } + else + { + SBE_TRACF(INFO_MRK"SbeFifoRespBuffer::append. " + "Invalid state for append, current state %s", + getStateString() + ); + } + + return retval; +} + +//------------------------------------------------------------------- +void SbeFifoRespBuffer::completeMessage() +{ + do + { + if(MSG_INCOMPLETE == iv_state) + { + //Message Schema: + // |Return Data (optional)| Status Header | FFDC (optional) + // |Offset to Status Header (starting from EOT) | EOT | + + //Final index for a minimum complete message (No return data + //and no FFDC): + //Word Length of status header + + //Length of Offset (1) + Length of EOT (1) + if(iv_index < (STATUS_WORD_SIZE + 2)) + { + SBE_TRACF(ERR_MRK"SbeFifoRespBuffer::completeMessage: " + "Complete call caused short read." + ); + iv_state = MSG_SHORT_READ; + break; + } + + // |offset to header| EOT marker | current insert pos | <- iv_index + // The offset is how far to move back from from the EOT position to + // to get the index of the Status Header. + iv_offsetIndex = (iv_index - 2); + + //Validate that the offset to the status header is in range + if((iv_localMsgBuffer[iv_offsetIndex] - 1) > iv_offsetIndex) + { + //offset is to large - would go before the buffer. + SBE_TRACF(ERR_MRK"SbeFifoRespBuffer::completeMessage: " + "The offset to the StatusHeader is too large." + ); + iv_state = MSG_INVALID_OFFSET; + break; + } + else if(iv_localMsgBuffer[iv_offsetIndex] < + (STATUS_WORD_SIZE + 1)) + { + //Minimum offset (no ffdc) is StatusHeader size + 1 + SBE_TRACF(ERR_MRK"SbeFifoRespBuffer::completeMessage: " + "The offset to the StatusHeader is too small." + ); + iv_state = MSG_INVALID_OFFSET; + break; + } + + //Set The StatusHeader index + iv_statusIndex = iv_offsetIndex - + (iv_localMsgBuffer[iv_offsetIndex] - 1); + + //Determine if there is FFDC data in the buffer. We do this by + //checking that the index after the status header is less than the + //offset index. If the offset index immediately follows the status + //header then there is no FFDC in the header. + if((iv_statusIndex + STATUS_WORD_SIZE) < iv_offsetIndex) + { + iv_ffdcIndex = iv_statusIndex + STATUS_WORD_SIZE; + iv_ffdcSize = (iv_offsetIndex - iv_ffdcIndex); + } + + iv_state = MSG_COMPLETE; + } + } + while(0); + + return; +} + +//------------------------------------------------------------------------- +bool SbeFifoRespBuffer::msgContainsFFDC() +{ + bool retval{false}; + + if(isMsgComplete()) + { + if(INVALID_INDEX != iv_ffdcIndex) + { + retval = true; + } + } + + return retval; +} + +//------------------------------------------------------------------------ +const void * SbeFifoRespBuffer::getFFDCPtr() +{ + const void* retval{}; + + if(msgContainsFFDC()) + { + retval = + reinterpret_cast<const void*>(&iv_localMsgBuffer[iv_ffdcIndex]); + } + + return retval; +} + +//-------------------------------------------------------------------------- +size_t SbeFifoRespBuffer::getFFDCByteSize() +{ + size_t retval = 0; + + if(msgContainsFFDC()) + { + retval = iv_ffdcSize * sizeof(uint32_t); + } + + return retval; +} + +//-------------------------------------------------------------------------- +size_t SbeFifoRespBuffer::getFFDCWordSize() +{ + size_t retval = 0; + + if(msgContainsFFDC()) + { + retval = iv_ffdcSize; + } + + return retval; +} + +//--------------------------------------------------------------------------- +const SbeFifo::statusHeader * SbeFifoRespBuffer::getStatusHeader() +{ + const SbeFifo::statusHeader* retval{}; + + if(isMsgComplete()) + { + retval = reinterpret_cast<const SbeFifo::statusHeader *> + (&iv_localMsgBuffer[iv_statusIndex]); + } + + return retval; +} + +//--------------------------------------------------------------------------- +bool SbeFifoRespBuffer::msgContainsReturnData() +{ + bool retval{false}; + + if(isMsgComplete()) + { + retval = (iv_statusIndex > 0); + } + + return retval; +} + +//--------------------------------------------------------------------------- +const void * SbeFifoRespBuffer::getReturnData() +{ + const void * retval{}; + + if(msgContainsReturnData()) + { + retval = reinterpret_cast<const void*>(&iv_localMsgBuffer[0]); + } + + return retval; +} + +//---------------------------------------------------------------------------- +size_t SbeFifoRespBuffer::getReturnDataByteSize() +{ + size_t retval = 0; + + if(msgContainsReturnData()) + { + retval = iv_statusIndex * sizeof(uint32_t); + } + + return retval; +} + +//--------------------------------------------------------------------------- +size_t SbeFifoRespBuffer::getReturnDataWordSize() +{ + size_t retval = 0; + + if(msgContainsReturnData()) + { + retval = iv_statusIndex; + } + + return retval; +} + +} //End Namespace SBEIO diff --git a/src/usr/sbeio/sbe_fifo_buffer.H b/src/usr/sbeio/sbe_fifo_buffer.H new file mode 100644 index 000000000..fe5e50092 --- /dev/null +++ b/src/usr/sbeio/sbe_fifo_buffer.H @@ -0,0 +1,318 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/sbeio/sbe_fifo_buffer.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* 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. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __SBEIO_SBE_FIFO_BUFFER_H +#define __SBEIO_SBE_FIFO_BUFFER_H + +#include <stdint.h> + +#include "sbe_fifodd.H" + +namespace SBEIO +{ + +/** + * @brief A class for managing duel input buffers for sbeio fifo response + * messaging. + * + * Sbeio messaging uses a pair of buffers for parsing fifo response + * messages. The first buffer is a caller supplied buffer that must be large + * enough to hold required data for a given message response. For example, + * a read command will have a response that will contain the data read and a + * status header. A write command will have a response that will contain + * only a status header detailing the result of the command. In addition, + * response data can include FFDC data upon an error. The user supplied + * buffer does not need to be big enough to hold the extra data since this + * information is processed by the messaging code before returning to the + * caller. As a result, a second buffer which should be large enough to + * to contain any FFDC information is processed in parallel with the caller + * supplied buffer in order to capture a full response. + */ +class SbeFifoRespBuffer +{ +public: + + /** + * @brief Constructor. + * + * @param[in] i_fifoBuffer - The caller supplied buffer. + * @param[in] bufferWordSize - The size of the caller supplied buffer in + * uint32_t units. + */ + explicit SbeFifoRespBuffer(uint32_t * i_fifoBuffer, size_t bufferWordSize); + + //This is a helper class intended for local use only. + SbeFifoRespBuffer(const SbeFifoRespBuffer&) = delete; + SbeFifoRespBuffer(SbeFifoRespBuffer&&) = delete; + + SbeFifoRespBuffer& operator=(const SbeFifoRespBuffer&) = delete; + SbeFifoRespBuffer& operator=(SbeFifoRespBuffer&&) = delete; + + //======================= + // Message construction + //======================== + + /** + * @brief append a uint32 to the next buffer insert position. + * + * @param[in] i_value - The value to add to the buffers. + * + * @return True if the value was able to be stored in at least the local + * buffer, false otherwise. + */ + bool append(uint32_t i_value); + + /** + * @brief When the DN FIFO Dequeued EOT flag is detected + * externally, this method is called to validate + * the buffer data and set indexes to the status + * and ffdc areas. + */ + void completeMessage(); + + //============================ + // Messaging State + //============================ + + /** + * @brief operator that returns true if the messaging + * state is MSG_INCOMPLETE. This indicates that + * data is able to be appended to the buffer(s) + */ + operator bool() const {return MSG_INCOMPLETE == iv_state;} + + /** + * @brief Current state of the messaging buffer + * + */ + enum State{ + INVALID_CALLER_BUFFER = 0, /**< enum Caller buffer too short */ + OVERRUN = 1, /**< enum message larger than local + buffer */ + MSG_SHORT_READ = 2, /**< enum Message is shorter that + header */ + MSG_INVALID_OFFSET = 3, /**< enum The message contains an + invalid status header offset */ + MSG_COMPLETE = 4, /**< enum The message was read in + successfully */ + MSG_INCOMPLETE = 5 /**< enum The message is being + constructed */ + }; + + /** + * @brief Accessor for messaging state. + * + * @return The state of the messaging buffers. + */ + State getState() const {return iv_state;} + + /** + * @brief A simplified state accessor. + * + * @return True if the state is MSG_COMPLETE or MSG_INCOMPLETE + * False otherwise. + */ + bool getStatus() const {return (MSG_COMPLETE == iv_state || + MSG_INCOMPLETE == iv_state);} + + /** + * @brief Accessor for if the message has been successfully completed. + * + * @return True if the message has been successfully completed. + */ + bool isMsgComplete() const {return MSG_COMPLETE == iv_state;} + + //================= + //FFDC + //================= + + /** + * @brief Does the message contain FFDC data. + * + * @return True if the message is complete and contains FFDC data + * False otherwise. + */ + bool msgContainsFFDC(); + + /** + * @brief Accessor to FFDC data. + * + * @returns pointer to FFDC data if the message is complete and contains + * FFDC data. A nullptr is returned otherwise. + * + */ + const void * getFFDCPtr(); + + /** + * @brief FFDC data size. + * + * @return FFDC data size in bytes or 0 if the message is incomplete + * or does not have FFDC data. + */ + size_t getFFDCByteSize(); + + /** + * @brief FFDC data size. + * + * @return FFDC data size in words or 0 if the message is incomplete + * or does not have FFDC data. + */ + size_t getFFDCWordSize(); + + //================================= + // Status Header + //================================= + + /** + * @brief Returns a pointer to the StatusHeader struct. + * + * @return A pointer to the StatusHeader struct if the + * buffer state is MSG_COMPLETE, or a NULL pointer + * otherwise. + */ + const SbeFifo::statusHeader * getStatusHeader(); + + //================================ + // Return Data + //================================ + + /** + * @brief Determine if the message contains return data. + * + * @return True if the message is complete and has return data + * False otherwise. + * + */ + bool msgContainsReturnData(); + + /** + * @brief Obtain a pointer to return data + * + * @return A pointer to return data if the message is complete and + * contains return data. A nullptr is returned otherwise. + */ + const void * getReturnData(); + + /** + * @brief Obtain the return data size in bytes. + * + * @return The return data size in bytes if the message is complete and + * contains return data, 0 is returned otherwise. + */ + size_t getReturnDataByteSize(); + + /** + * @brief Obtain the return data size in uint32_t words. + * + * @return The return data size in bytes if the message is complete and + * contains return data, 0 is returned otherwise. + */ + size_t getReturnDataWordSize(); + + /* + * @brief Obtain the local buffer for debugging. + * + * @return A pointer to the local buffer. + */ + const uint32_t * localBuffer() const {return iv_localMsgBuffer;} + + /* + * @brief Obtain the current index for debugging + * + * @return - The current Index + */ + size_t index() const {return iv_index;} + + /* + * @brief Obtain the offset Index for debugging + * + * @return - The offset Index + * + */ + size_t offsetIndex() const {return iv_offsetIndex;} + + /* + * @brief Obtain the offset to the Status Header + * for debugging and error reporting. + * + * @return - The offset to the status header. + * + */ + size_t offset() const {return iv_localMsgBuffer[iv_offsetIndex];} + + //========================= + // Class Constants + //========================= + static const size_t MSG_BUFFER_SIZE = 2048; + static const size_t INVALID_INDEX = size_t(-1); + +protected: + + //===================== + // Unit Test Access + //===================== + const uint32_t * callerBuffer() const {return iv_callerBufferPtr;} + size_t callerWordSize() const {return iv_callerWordSize;} + + size_t statusIndex() const {return iv_statusIndex;} + size_t ffdcIndex() const {return iv_ffdcIndex;} + + const char* getStateString() const {return cv_stateStrings[iv_state];} + + void setBufferState(State newValue){iv_state = newValue;} + +private: + + //==================== + // Buffers + //==================== + + uint32_t iv_localMsgBuffer[MSG_BUFFER_SIZE]; /**< local buffer large enough + to hold FFDC data */ + + uint32_t * const iv_callerBufferPtr{}; /**< caller supplied buffer should + be large enough to hold at least + return data and status */ + + const size_t iv_callerWordSize; /**< caller buffer size in uint32_t units */ + + //==================== + // Index and State + //==================== + + size_t iv_index{}; /**< denotes the next insert position */ + size_t iv_offsetIndex{INVALID_INDEX}; /**< position of offset to the + status header */ + size_t iv_statusIndex{INVALID_INDEX}; /**< position of the status header */ + size_t iv_ffdcIndex{INVALID_INDEX}; /**< position of FFDC data if any */ + size_t iv_ffdcSize{0}; /**< size of ffdc data if any is present */ + + State iv_state{MSG_INCOMPLETE}; /**< Messaging State */ + + static const char* cv_stateStrings[]; /**< Messaging State Strings */ +}; + +} //End Namespace SBEIO + +#endif diff --git a/src/usr/sbeio/sbe_fifodd.C b/src/usr/sbeio/sbe_fifodd.C index 43342b790..7a26b5b71 100644 --- a/src/usr/sbeio/sbe_fifodd.C +++ b/src/usr/sbeio/sbe_fifodd.C @@ -37,7 +37,9 @@ #include <targeting/common/targetservice.H> #include <sbeio/sbeioreasoncodes.H> #include <errl/errlreasoncodes.H> +#include "sbe_fifo_buffer.H" #include "sbe_fifodd.H" +#include <sbeio/sbe_ffdc_package_parser.H> #include <sbeio/sbe_ffdc_parser.H> #include <initservice/initserviceif.H> #include <kernel/pagemgr.H> @@ -315,7 +317,8 @@ errlHndl_t SbeFifo::readResponse(TARGETING::Target * i_target, uint32_t i_responseSize) { errlHndl_t errl = NULL; - uint32_t l_readBuffer[READ_BUFFER_SIZE]; + SbeFifoRespBuffer l_fifoBuffer{o_pFifoResponse, + i_responseSize/sizeof(uint32_t)}; SBE_TRACD(ENTER_MRK "readResponse"); @@ -327,21 +330,10 @@ errlHndl_t SbeFifo::readResponse(TARGETING::Target * i_target, // to the status, which is placed at the end of the returned data // in order to reflect errors during transfer. - uint32_t * l_pReceived = o_pFifoResponse; //advance as words received - uint32_t l_maxWords = i_responseSize / sizeof(uint32_t); - //Number of words in response buffer. - uint32_t l_recWords = 0; //Number of words received. - //Used validate "distance" to status - //and pointer to status. bool l_EOT = false; - uint32_t l_last = 0; // last word received. The "current" word. - // Final read is "distance" in words to - // status header including the final - // distance word. - // receive words until EOT, but do not exceed response buffer size - bool l_overRun = false; - - do + + while(l_fifoBuffer) //keep reading data until an error or until the + //message is completely read. { // Wait for data to be ready to receive (download) or if the EOT // has been sent. If not EOT, then data ready to receive. @@ -356,52 +348,21 @@ errlHndl_t SbeFifo::readResponse(TARGETING::Target * i_target, if (l_status & DNFIFO_STATUS_DEQUEUED_EOT_FLAG) { l_EOT = true; - // ignore EOT dummy word - if (l_recWords >= (sizeof(statusHeader)/sizeof(uint32_t)) ) - { - if(l_overRun == false) { - l_pReceived--; - l_recWords--; - l_last = o_pFifoResponse[l_recWords-1]; - } else { - l_last = (uint32_t) l_readBuffer[l_recWords-2]; - } - } - break; + l_fifoBuffer.completeMessage(); } - - // When error occurs, SBE will write more than l_maxWords - // we have to keep reading 1 word at a time until we get EOT - // or more than READ_BUFFER_SIZE. Save what we read in the buffer - if (l_recWords >= l_maxWords) + else { - l_overRun = true; - } - - // read next word - errl = readFsi(i_target,SBE_FIFO_DNFIFO_DATA_OUT,&l_last); - if (errl) break; + uint32_t l_data{}; + // read next word + errl = readFsi(i_target,SBE_FIFO_DNFIFO_DATA_OUT,&l_data); + if (errl) break; - l_readBuffer[l_recWords] = l_last; - - if(l_overRun == false) { - *l_pReceived = l_last; //copy to returned output buffer - l_pReceived++; //advance to next position - } - l_recWords++; //count word received - SBE_TRACD("Read a byte from data reg: 0x%.8X",l_last); - if(l_recWords > READ_BUFFER_SIZE) { - SBE_TRACF(ERR_MRK "readResponse: data overflow without EOT"); - break; + l_fifoBuffer.append(l_data); } } - while (1); // exit check in middle of loop if (errl) break; - // At this point, - // l_recWords of words received. - // l_pReceived points to 1 word past last word received. - // l_last has last word received, which is "distance" to status + // EOT is expected before running out of response buffer if (!l_EOT) { @@ -439,23 +400,19 @@ errlHndl_t SbeFifo::readResponse(TARGETING::Target * i_target, if (errl) break; //Determine if successful. - //Last word received has distance to status in words including itself. - //l_recWords has number of words received. - //Need to have received at least status header and distance word. - if ( (l_last < (sizeof(statusHeader)/sizeof(uint32_t) + 1)) || - (l_recWords < (sizeof(statusHeader)/sizeof(uint32_t) + 1)) || - (l_last > (l_recWords)) ) + if (!l_fifoBuffer.getStatus()) { SBE_TRACF(ERR_MRK "readResponse: invalid status distance " "cmd=0x%08x distance=%d allocated response size=%d " "received word size=%d" , i_pFifoRequest[1], - l_last, + l_fifoBuffer.offset(), i_responseSize, - l_recWords); + l_fifoBuffer.index()); SBE_TRACFBIN("Invalid Response from SBE", - o_pFifoResponse,l_recWords*sizeof(l_last)); + l_fifoBuffer.localBuffer(), + l_fifoBuffer.index()*sizeof(uint32_t)); /*@ * @errortype @@ -473,8 +430,8 @@ errlHndl_t SbeFifo::readResponse(TARGETING::Target * i_target, SBEIO_FIFO_INVALID_STATUS_DISTANCE, i_pFifoRequest[1], TWO_UINT32_TO_UINT64( - TWO_UINT16_TO_UINT32(l_last, - l_recWords*sizeof(uint32_t)), + TWO_UINT16_TO_UINT32(l_fifoBuffer.offset(), + l_fifoBuffer.index()*sizeof(uint32_t)), i_responseSize)); errl->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE, @@ -488,13 +445,7 @@ errlHndl_t SbeFifo::readResponse(TARGETING::Target * i_target, } // Check status for success. - // l_pReceived points one word past last word received. - // l_last has number of words to status header including self. - - uint32_t * l_pStatusTmp = (l_overRun == false) ? - l_pReceived - l_last : //do word ptr math - &l_readBuffer[l_recWords - 1]; - statusHeader * l_pStatusHeader = (statusHeader *)l_pStatusTmp; + const statusHeader * l_pStatusHeader = l_fifoBuffer.getStatusHeader(); if ((FIFO_STATUS_MAGIC != l_pStatusHeader->magic) || (SBE_PRI_OPERATION_SUCCESSFUL != l_pStatusHeader->primaryStatus) || (SBE_SEC_OPERATION_SUCCESSFUL != l_pStatusHeader->secondaryStatus)) @@ -529,21 +480,15 @@ errlHndl_t SbeFifo::readResponse(TARGETING::Target * i_target, l_pStatusHeader->primaryStatus, l_pStatusHeader->secondaryStatus)); - /* - * The FFDC package should start at l_pReceived. - * Size of the FFDC package should be l_maxWords - l_recWords - */ - if(l_overRun == false) { - writeFFDCBuffer(l_pReceived, - sizeof(uint32_t) * (l_maxWords - l_recWords - 1)); - } else { - // If Overrun, FFDC should be - // l_recWords (words read) - l_last (distance to status) + 1 - // in l_readBuffer - writeFFDCBuffer(&l_readBuffer[l_recWords - l_last + 1], - sizeof(uint32_t) * (l_last + 1)); + if(!l_fifoBuffer.msgContainsFFDC()) + { + break; } + + writeFFDCBuffer(l_fifoBuffer.getFFDCPtr(), + l_fifoBuffer.getFFDCByteSize()); + SbeFFDCParser * l_ffdc_parser = new SbeFFDCParser(); l_ffdc_parser->parseFFDCData(iv_ffdcPackageBuffer); @@ -551,13 +496,19 @@ errlHndl_t SbeFifo::readResponse(TARGETING::Target * i_target, uint8_t l_pkgs = l_ffdc_parser->getTotalPackages(); for(uint8_t i = 0; i < l_pkgs; i++) { - uint32_t l_rc = l_ffdc_parser->getPackageRC(i); + ffdc_package l_package = {nullptr, 0, 0}; + if(!l_ffdc_parser->getFFDCPackage(i, l_package)) + { + continue; + } + + uint32_t l_rc = l_package.rc; // If fapiRC, add data to errorlog if(l_rc == fapi2::FAPI2_RC_PLAT_ERR_SEE_DATA) { errl->addFFDC( SBEIO_COMP_ID, - l_ffdc_parser->getFFDCPackage(i), - l_ffdc_parser->getPackageLength(i), + l_package.ffdcPtr, + l_package.size, 0, SBEIO_UDT_PARAMETERS, false ); @@ -573,9 +524,9 @@ errlHndl_t SbeFifo::readResponse(TARGETING::Target * i_target, * call FAPI_SET_SBE_ERROR */ sbeFfdc_t * l_ffdcBuf = new sbeFfdc_t(); - l_ffdcBuf->size = l_ffdc_parser->getPackageLength(i); + l_ffdcBuf->size = l_package.size; l_ffdcBuf->data = reinterpret_cast<uint64_t>( - l_ffdc_parser->getFFDCPackage(i)); + l_package.ffdcPtr); FAPI_SET_SBE_ERROR(l_fapiRC, l_rc, @@ -588,15 +539,19 @@ errlHndl_t SbeFifo::readResponse(TARGETING::Target * i_target, ERRORLOG::errlCommit( sbe_errl, SBEIO_COMP_ID ); } } - PIB::PibError l_pibRc = l_ffdc_parser->getPibRc(i); - if (l_pibRc != PIB::PIB_NO_ERROR) - { - //this is pibrc, call addFruCallouts to log the error - auto l_fifoReq = - (SbeFifo::fifoGetScomRequest*)i_pFifoRequest; - PIB::addFruCallouts - (i_target, l_pibRc, l_fifoReq->address, errl); - } + + //If FFDC schema is known and a processing routine + //is defined then perform the processing. + //For scom PIB errors, addFruCallputs is invoked. + //Only processing known FFDC schemas protects us + //from trying to process FFDC formats we do not + //anticipate. For example, the SBE can send + //user and attribute FFDC information after the + //Scom Error FFDC. We do not want to process that + //type of data here. + FfdcParsedPackage::doDefaultProcessing(l_package, + i_target, + errl); } errl->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE, @@ -650,7 +605,8 @@ errlHndl_t SbeFifo::waitDnFifoReady(TARGETING::Target * i_target, } else { - SBE_TRACD("SBE status reg returned fifo empty or dequeued eot flag 0x%.8X", + SBE_TRACD("SBE status reg returned fifo empty or " + "dequeued eot flag 0x%.8X", o_status); } @@ -756,7 +712,7 @@ void SbeFifo::initFFDCPackageBuffer() * @param[in] i_data FFDC error data * @param[in] i_len data buffer len to copy */ -void SbeFifo::writeFFDCBuffer( void * i_data, uint32_t i_len) { +void SbeFifo::writeFFDCBuffer(const void * i_data, uint32_t i_len) { if(i_len <= PAGESIZE * ffdcPackageSize) { initFFDCPackageBuffer(); diff --git a/src/usr/sbeio/sbe_fifodd.H b/src/usr/sbeio/sbe_fifodd.H index dd23e3c54..121d68c63 100644 --- a/src/usr/sbeio/sbe_fifodd.H +++ b/src/usr/sbeio/sbe_fifodd.H @@ -282,7 +282,7 @@ class SbeFifo * @param[in] i_len data buffer len to copy */ - void writeFFDCBuffer(void * i_data, uint32_t i_len); + void writeFFDCBuffer(const void * i_data, uint32_t i_len); private: diff --git a/src/usr/sbeio/sbe_psudd.C b/src/usr/sbeio/sbe_psudd.C index c27fdf15c..7c24cf327 100644 --- a/src/usr/sbeio/sbe_psudd.C +++ b/src/usr/sbeio/sbe_psudd.C @@ -38,6 +38,7 @@ #include <errl/errlreasoncodes.H> #include <sbeio/sbeioreasoncodes.H> #include <initservice/initserviceif.H> //@todo-RTC:149454-Remove +#include <sbeio/sbe_ffdc_package_parser.H> #include <sbeio/sbe_psudd.H> #include <sbeio/sbe_ffdc_parser.H> #include <arch/ppc.H> @@ -360,17 +361,21 @@ errlHndl_t SbePsu::readResponse(TARGETING::Target * i_target, o_pPsuResponse->secondaryStatus, i_pPsuRequest->seqID, o_pPsuResponse->seqID); - SBE_TRACFBIN( "Full response:", o_pPsuResponse, sizeof(psuResponse) ); + SBE_TRACFBIN( "Full response:", + o_pPsuResponse, + sizeof(psuResponse)); break; } //check status and seq ID in response messages - else if ((SBE_PRI_OPERATION_SUCCESSFUL != o_pPsuResponse->primaryStatus) || - (SBE_SEC_OPERATION_SUCCESSFUL != o_pPsuResponse->secondaryStatus) || - (i_pPsuRequest->seqID != o_pPsuResponse->seqID) ) + else if ((SBE_PRI_OPERATION_SUCCESSFUL != + o_pPsuResponse->primaryStatus) || + (SBE_SEC_OPERATION_SUCCESSFUL != o_pPsuResponse->secondaryStatus) || + (i_pPsuRequest->seqID != o_pPsuResponse->seqID)) { - SBE_TRACF(ERR_MRK "sbe_psudd.C :: readResponse: failing response status " + SBE_TRACF(ERR_MRK "sbe_psudd.C :: readResponse: " + "failing response status " " cmd=0x%02x%02x prim=0x%08x secondary=0x%08x" " expected seqID=%d actual seqID=%d", i_pPsuRequest->commandClass, @@ -379,7 +384,7 @@ errlHndl_t SbePsu::readResponse(TARGETING::Target * i_target, o_pPsuResponse->secondaryStatus, i_pPsuRequest->seqID, o_pPsuResponse->seqID); - SBE_TRACFBIN( "Full response:", o_pPsuResponse, sizeof(psuResponse) ); + SBE_TRACFBIN("Full response:", o_pPsuResponse, sizeof(psuResponse)); /*@ @@ -427,12 +432,31 @@ errlHndl_t SbePsu::readResponse(TARGETING::Target * i_target, uint8_t i; for(i = 0; i < l_pkgs; i++) { + ffdc_package l_package = {nullptr, 0, 0}; + if(!l_ffdc_parser->getFFDCPackage(i, l_package)) + { + continue; + } + errl->addFFDC( SBEIO_COMP_ID, - l_ffdc_parser->getFFDCPackage(i), - l_ffdc_parser->getPackageLength(i), + l_package.ffdcPtr, + l_package.size, 0, SBEIO_UDT_PARAMETERS, false ); + + //If FFDC schema is known and a processing routine + //is defined then perform the processing. + //For scom PIB errors, addFruCallputs is invoked. + //Only processing known FFDC schemas protects us + //from trying to process FFDC formats we do not + //anticipate. For example, the SBE can send + //user and attribute FFDC information after the + //Scom Error FFDC. We do not want to process that + //type of data here. + FfdcParsedPackage::doDefaultProcessing(l_package, + i_target, + errl); } delete l_ffdc_parser; } @@ -696,7 +720,8 @@ errlHndl_t SbePsu::allocateFFDCBuffer(TARGETING::Target * i_target) if(errl) { PageManager::freePage(l_ffdcPtr); - SBE_TRACF(ERR_MRK"Error setting FFDC address for proc huid=0x%08lx", l_huid); + SBE_TRACF(ERR_MRK"Error setting FFDC address for " + "proc huid=0x%08lx", l_huid); } else { diff --git a/src/usr/sbeio/test/makefile b/src/usr/sbeio/test/makefile index 2017d8aab..8dfb21f98 100644 --- a/src/usr/sbeio/test/makefile +++ b/src/usr/sbeio/test/makefile @@ -5,7 +5,7 @@ # # OpenPOWER HostBoot Project # -# Contributors Listed Below - COPYRIGHT 2011,2016 +# Contributors Listed Below - COPYRIGHT 2011,2017 # [+] International Business Machines Corp. # # @@ -25,6 +25,8 @@ ROOTPATH = ../../../.. EXTRAINCDIR += ${ROOTPATH}/src/usr/sbeio/ +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/fapi2/ +EXTRAINCDIR += ${ROOTPATH}/src/import/hwpf/fapi2/include/ MODULE = testsbeio diff --git a/src/usr/sbeio/test/sbe_ffdc_package_parser_test.H b/src/usr/sbeio/test/sbe_ffdc_package_parser_test.H new file mode 100644 index 000000000..f7de533e5 --- /dev/null +++ b/src/usr/sbeio/test/sbe_ffdc_package_parser_test.H @@ -0,0 +1,688 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/sbeio/test/sbe_ffdc_package_parser_test.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* 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. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __SBEIO_SBE_FFDC_PACKAGE_PARSER_TEST_H +#define __SBEIO_SBE_FFDC_PACKAGE_PARSER_TEST_H + +#include <hwp_return_codes.H> + +#include <sbeio/sbe_ffdc_package_parser.H> +#include <trace/interface.H> + +#include <cxxtest/TestSuite.H> +#include "sbe_test_support.H" + +extern trace_desc_t* g_trac_sbeio; + +#define SBE_FFDC_TRACD(printf_string,args...) \ + TRACDCOMP(g_trac_sbeio,"sbeFFDCParserTest: " printf_string,##args) + +using namespace SBEIO; + +class FfdcScomPibErrorPackageTestFixure: public SBEIO::FfdcScomPibErrorPackage +{ +public: + + FfdcScomPibErrorPackageTestFixure(const ffdc_package& i_ffdc, + bool i_ignoreRC = false): + FfdcScomPibErrorPackage(i_ffdc, + i_ignoreRC) + { + clearCounts(); + } + +//Mock the addFruCallouts method. +void addFruCallouts (TARGETING::Target* i_target, + errlHndl_t i_errHndl + ) const override +{ + ++cv_defaultActionInvoked; + + if(not i_target) + { + ++cv_nullTargetCount; + } + + if(not i_errHndl) + { + ++cv_nullErrlHndlCount; + } +} + +static size_t callCount() {return cv_defaultActionInvoked;} +static size_t nullTargetCount() {return cv_nullTargetCount;} +static size_t nullErrlHndlCount() {return cv_nullErrlHndlCount;} + +static void clearCounts() +{ + cv_defaultActionInvoked = 0; + cv_nullTargetCount = 0; + cv_nullErrlHndlCount = 0; +} + +private: + + static size_t cv_defaultActionInvoked; + static size_t cv_nullTargetCount; + static size_t cv_nullErrlHndlCount; +}; + +size_t FfdcScomPibErrorPackageTestFixure::cv_defaultActionInvoked = 0; +size_t FfdcScomPibErrorPackageTestFixure::cv_nullTargetCount = 0; +size_t FfdcScomPibErrorPackageTestFixure::cv_nullErrlHndlCount = 0; + + +std::vector<uint32_t> bufferFFDC = { + 0xFFDC0009, //FFDC 1 - Magic + Len + 0x0000A807, //FFDC 2 - Seq, Cmd class, cmd + 0x00983AB6, //FFDC 3 - RC_SBE_SCOM_FAILURE + 0x00000008, //FFDC 4 - scom addr size + 0x12345678, //FFDC 5 - scom addr msb + 0x9ABCDEF0, //FFDC 6 - scom addr lsb + 0x00000008, //FFDC 7 - PIB RC size + 0x00000000, //FFDC 8 - PIB_PARITY_ERROR msb + 0x00000006 //FFDC 9 - PIB_PARITY_ERROR lsb + }; + +std::vector<uint32_t> bufferUnknownRCFFDC = { + 0xFFDC0009, //FFDC 1 - Magic + Len + 0x0000A807, //FFDC 2 - Seq, Cmd class, cmd + 0xFF983AB6, //FFDC 3 - FAPI RC + 0x00000008, //FFDC 4 - scom addr size + 0x12345678, //FFDC 5 - scom addr msb + 0x9ABCDEF0, //FFDC 6 - scom addr lsb + 0x00000008, //FFDC 7 - PIB RC size + 0x00000000, //FFDC 8 - PIB_PARITY_ERROR msb + 0x00000006 //FFDC 9 - PIB_PARITY_ERROR lsb + }; + +std::vector<uint32_t> bufferBadSchemaFFDC = { + 0xFFDC000A, //FFDC 1 - Magic + Len + 0x0000A807, //FFDC 2 - Seq, Cmd class, cmd + 0x00983AB6, //FFDC 3 - RC_SBE_SCOM_FAILURE + 0x00000008, //FFDC 4 - scom addr size + 0x12345678, //FFDC 5 - scom addr msb + 0x9ABCDEF0, //FFDC 6 - scom addr lsb + 0x00000008, //FFDC 7 - PIB RC size + 0x00000000, //FFDC 8 - PIB_PARITY_ERROR msb + 0x00000006, //FFDC 9 - PIB_PARITY_ERROR lsb + 0xFFEEDDCC //FFDC 10 Extra Garbage Word + }; + +uint64_t addr = 0x1234567890ABCDEF; +TARGETING::Target* g_testTarget = reinterpret_cast<TARGETING::Target*>(addr); +errlHndl_t g_errl = reinterpret_cast<errlHndl_t>(addr); + +ffdc_package g_testPackage = {nullptr, 0, 0}; + +//============================================================ +class SbeFFDCPackageParserTest : public CxxTest::TestSuite +{ +public: + + void testGoodFFDC() + { + SBE_FFDC_TRACD("ENTER sbeFFDCParserTest testGoodFFDC"); + + bool result{true}; + + do + { + bufferFFDC[2] = static_cast<uint32_t>(fapi2::RC_SBE_SCOM_FAILURE); + g_testPackage.ffdcPtr = &bufferFFDC[2]; + g_testPackage.size = (bufferFFDC.size() - 2) * sizeof(uint32_t); + g_testPackage.rc = fapi2::RC_SBE_SCOM_FAILURE; + + bool matchesSchema = + FfdcScomPibErrorPackage::doesPackageMatchSchema(g_testPackage); + + if(not matchesSchema) + { + char strFfdc[64]; + xxdPrint(g_testPackage.ffdcPtr, g_testPackage.size, strFfdc); + + SBE_FFDC_TRACD("sbeFFDCParserTest testGoodFFDC: " + "doesPackageMatchSchema unexpectedly " + "returned false. Input FFDC:\n%s", + strFfdc + ); + + TS_FAIL("sbeFFDCParserTest testGoodFFDC: " + "doesPackageMatchSchema unexpectedly result = false." + ); + + result = false; + break; + } + + FfdcScomPibErrorPackageTestFixure l_ffdcPackage{g_testPackage}; + + if(not l_ffdcPackage.isValid()) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDC: " + "ffdc package was not successfully parsed." + ); + + result = false; + break; + } + + if(not l_ffdcPackage) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDC: " + "operator bool failed. ffdc package was not " + "successfully parsed." + ); + + result = false; + break; + } + + if(FfdcParsedPackage::ParsedType::SBE_SCOM_PIB_ERROR != + l_ffdcPackage.parsedType()) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDC: " + "Did not receive ParsedType SBE_SCOM_PIB_ERROR " + "from ParsedType() call." + ); + + result = false; + break; + } + + uint64_t scomAddr = l_ffdcPackage.getScomAddress(); + uint64_t expectedScomAddr = *(reinterpret_cast<const uint64_t*> + (&bufferFFDC[4])); + if(expectedScomAddr != scomAddr) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDC: " + "Did not receive scom addr 0x%08X as expected. " + "scom addr: 0x%08X", + expectedScomAddr, + scomAddr + ); + + result = false; + break; + } + + uint64_t pibRc = l_ffdcPackage.getPibRc(); + uint64_t expectedPibRc = *(reinterpret_cast<const uint64_t*> + (&bufferFFDC[7])); + if(expectedPibRc != pibRc) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDC: " + "Did not receive pib rc 0x%08X as expected. " + "pib rc: 0x%08X", + expectedPibRc, + pibRc + ); + + result = false; + break; + } + + l_ffdcPackage(g_testTarget, g_errl); + + if(FfdcScomPibErrorPackageTestFixure::callCount() == 0) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDC: " + "call operator did not invoke addFruCallouts" + ); + + result = false; + break; + } + + if(FfdcScomPibErrorPackageTestFixure::nullTargetCount() != 0) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDC: " + "call operator invoked addFruCallouts with a " + "null target argument." + ); + + result = false; + break; + } + + if(FfdcScomPibErrorPackageTestFixure::nullErrlHndlCount() != 0) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDC: " + "call operator invoked addFruCallouts with a " + "null errlHndl_t argument." + ); + + result = false; + break; + } + } + while(0); + + if(result) + { + SBE_FFDC_TRACD("sbeFFDCParserTest testGoodFFDC test passed!"); + } + else + { + SBE_FFDC_TRACD("sbeFFDCParserTest testGoodFFDC test failed!"); + } + } + + //------------------------------------------------------------------ + void testGoodFFDCBaseClass() + { + SBE_FFDC_TRACD("ENTER sbeFFDCParserTest TestGoodFFDCBaseClass"); + + bool result{true}; + + do + { + bufferFFDC[2] = static_cast<uint32_t>(fapi2::RC_SBE_SCOM_FAILURE); + bufferFFDC[6] = 4; // test with size of PIB RC = 4 + g_testPackage.ffdcPtr = &bufferFFDC[2]; + g_testPackage.size = (bufferFFDC.size() - 2) * sizeof(uint32_t); + g_testPackage.rc = fapi2::RC_SBE_SCOM_FAILURE; + + if(FfdcParsedPackage::ParsedType::SBE_SCOM_PIB_ERROR != + FfdcParsedPackage::rcToParsedType(fapi2::RC_SBE_SCOM_FAILURE)) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDCBaseClass: " + "RC_SBE_SCOM_FAILURE did not map to SBE_SCOM_PIB_ERROR" + ); + + result = false; + break; + } + + if(FfdcParsedPackage::ParsedType::SBE_SCOM_PIB_ERROR != + FfdcParsedPackage::rcToParsedType( + fapi2::RC_SBE_PIB_XSCOM_ERROR)) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDCBaseClass: " + "RC_SBE_PIB_XSCOM_ERROR did not map to " + "SBE_SCOM_PIB_ERROR" + ); + + result = false; + break; + } + + if(FfdcParsedPackage::ParsedType::SBE_SCOM_PIB_ERROR != + FfdcParsedPackage::rcToParsedType( + fapi2::RC_SBE_PIB_OFFLINE_ERROR)) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDCBaseClass: " + "RC_SBE_PIB_OFFLINE_ERROR did not map to " + "SBE_SCOM_PIB_ERROR" + ); + + result = false; + break; + } + + if(FfdcParsedPackage::ParsedType::SBE_SCOM_PIB_ERROR != + FfdcParsedPackage::rcToParsedType( + fapi2::RC_SBE_PIB_PARTIAL_ERROR)) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDCBaseClass: " + "RC_SBE_PIB_PARTIAL_ERROR did not map to " + "SBE_SCOM_PIB_ERROR" + ); + + result = false; + break; + } + + if(FfdcParsedPackage::ParsedType::SBE_SCOM_PIB_ERROR != + FfdcParsedPackage::rcToParsedType( + fapi2::RC_SBE_PIB_ADDRESS_ERROR)) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDCBaseClass: " + "RC_SBE_PIB_ADDRESS_ERROR did not map to " + "SBE_SCOM_PIB_ERROR" + ); + + result = false; + break; + } + + if(FfdcParsedPackage::ParsedType::SBE_SCOM_PIB_ERROR != + FfdcParsedPackage::rcToParsedType( + fapi2::RC_SBE_PIB_CLOCK_ERROR)) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDCBaseClass: " + "RC_SBE_PIB_CLOCK_ERROR did not map to " + "SBE_SCOM_PIB_ERROR" + ); + + result = false; + break; + } + + if(FfdcParsedPackage::ParsedType::SBE_SCOM_PIB_ERROR != + FfdcParsedPackage::rcToParsedType( + fapi2::RC_SBE_PIB_PARITY_ERROR)) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDCBaseClass: " + "RC_SBE_PIB_PARITY_ERROR did not map to " + "SBE_SCOM_PIB_ERROR" + ); + + result = false; + break; + } + + if(FfdcParsedPackage::ParsedType::SBE_SCOM_PIB_ERROR != + FfdcParsedPackage::rcToParsedType( + fapi2::RC_SBE_PIB_TIMEOUT_ERROR)) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDCBaseClass: " + "RC_SBE_PIB_TIMEOUT_ERROR did not map to " + "SBE_SCOM_PIB_ERROR" + ); + + result = false; + break; + } + + + if(FfdcParsedPackage::ParsedType::SBE_SCOM_PIB_ERROR == + FfdcParsedPackage::rcToParsedType(0xFFEEDDCC)) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDCBaseClass: " + "0xFFEEDDCC mapped to SBE_SCOM_PIB_ERROR" + ); + + result = false; + break; + } + + std::shared_ptr<const FfdcParsedPackage> l_package = + FfdcParsedPackage::getParsedPackage(g_testPackage); + + if(not l_package) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDCBaseClass: " + "getParsedPackage result = returned a null pointer." + ); + + result = false; + break; + } + + if(not l_package->isValid()) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDCBaseClass: " + "getParsedPackage did not parse the ffdc package." + ); + + result = false; + break; + } + + + if(FfdcParsedPackage::ParsedType::SBE_SCOM_PIB_ERROR + != l_package->parsedType()) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDCBaseClass: " + "getParsedPackage did not parse the ffdc package " + "to the correct type." + ); + + result = false; + break; + } + + FfdcScomPibErrorPackageTestFixure l_ffdcPackage{g_testPackage}; + + if(not l_ffdcPackage.isValid()) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDCBaseClass: " + "ffdc package was not successfully parsed." + ); + + result = false; + break; + } + + FfdcScomPibErrorPackageTestFixure::clearCounts(); + l_ffdcPackage(g_testTarget, g_errl); + + if(FfdcScomPibErrorPackageTestFixure::callCount() == 0) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDCBaseClass: " + "call operator did not invoke addFruCallouts" + ); + + result = false; + break; + } + + if(FfdcScomPibErrorPackageTestFixure::nullTargetCount() != 0) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDCBaseClass: " + "call operator invoked addFruCallouts with a " + "null target argument." + ); + + result = false; + break; + } + + if(FfdcScomPibErrorPackageTestFixure::nullErrlHndlCount() != 0) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDCBaseClass: " + "call operator invoked addFruCallouts with a " + "null errlHndl_t argument." + ); + + result = false; + break; + } + + g_testPackage.ffdcPtr = &bufferBadSchemaFFDC[2]; + g_testPackage.size = (bufferBadSchemaFFDC.size() - 2) * + sizeof(uint32_t); + g_testPackage.rc = 0xFF983AB6; //arbitrary value + + FfdcScomPibErrorPackageTestFixure + l_ffdcPackage_badschema{g_testPackage}; + + FfdcScomPibErrorPackageTestFixure::clearCounts(); + l_ffdcPackage_badschema(g_testTarget, g_errl); + + if(FfdcScomPibErrorPackageTestFixure::callCount() != 0) + { + TS_FAIL("sbeFFDCParserTest testGoodFFDCBaseClass: " + "call operator invoked addFruCallouts on bad FFDC" + ); + + result = false; + break; + } + } + while(0); + + if(result) + { + SBE_FFDC_TRACD("sbeFFDCParserTest testGoodFFDCBaseClass " + "test passed!"); + } + else + { + SBE_FFDC_TRACD("sbeFFDCParserTest testGoodFFDCBaseClass " + "test failed!"); + } + } + + + //------------------------------------------------------------------ + void testbadFFDCSchema() + { + SBE_FFDC_TRACD("ENTER sbeFFDCParserTest testbadFFDCSchema"); + + bufferBadSchemaFFDC[2] = static_cast<uint32_t> + (fapi2::RC_SBE_SCOM_FAILURE); + + g_testPackage.ffdcPtr = &bufferBadSchemaFFDC[2]; + g_testPackage.size = (bufferBadSchemaFFDC.size() - 2) * + sizeof(uint32_t); + g_testPackage.rc = fapi2::RC_SBE_SCOM_FAILURE; + + FfdcScomPibErrorPackageTestFixure l_ffdcPackage{g_testPackage}; + + bool result{true}; + + do + { + if(l_ffdcPackage.isValid()) + { + TS_FAIL("sbeFFDCParserTest testbadFFDCSchema: " + "ffdc package was unexpectedly successfully parsed." + ); + + result = false; + break; + } + + if(l_ffdcPackage) + { + TS_FAIL("sbeFFDCParserTest testbadFFDCSchema: " + "operator bool returned true. The ffdc package was " + "unexpectedly successfully parsed." + ); + + result = false; + break; + } + } + while(0); + + if(result) + { + SBE_FFDC_TRACD("sbeFFDCParserTest testbadFFDCSchema test passed!"); + } + else + { + SBE_FFDC_TRACD("sbeFFDCParserTest testbadFFDCSchema test failed!"); + } + } + + //--------------------------------------------------------------------- + void testWithFFDCParser() + { + + bool result{true}; + + SbeFFDCParser ffdcParser; + ffdcParser.parseFFDCData(&bufferFFDC[0]); + + do + { + if(1 != ffdcParser.getTotalPackages()) + { + TS_FAIL("sbeFFDCParserTest testWithFFDCParser: " + "ffdcParser.getTotalPackages() returned %d, " + "expected 1.", + ffdcParser.getTotalPackages() + ); + + result = false; + break; + } + + ffdc_package package; + package.ffdcPtr = ffdcParser.getFFDCPackage(0); + package.rc = ffdcParser.getPackageRC(0); + package.size = ffdcParser.getPackageLength(0); + + FfdcScomPibErrorPackageTestFixure l_ffdcPackage{package}; + + if(not l_ffdcPackage.isValid()) + { + char strFfdc[64]; + xxdPrint(package.ffdcPtr, package.size, strFfdc); + SBE_FFDC_TRACD("testWithFFDCParser " + "Ffdc package was not successfully parsed. " + "FFDC Data:\n%s", + strFfdc + ); + + TS_FAIL("sbeFFDCParserTest testWithFFDCParser: " + "Ffdc package was not successfully parsed." + ); + + result = true; + break; + } + + ffdc_package package2 = {nullptr, 0, 0}; + bool rc = ffdcParser.getFFDCPackage(0, package2); + + if(not rc) + { + TS_FAIL("sbeFFDCParserTest testWithFFDCParser: " + "ffdcParser.getFFDCPackage(0, package2) failed." + ); + + result = true; + break; + } + + FfdcScomPibErrorPackageTestFixure l_ffdcPackage2{package2}; + + if(not l_ffdcPackage2.isValid()) + { + char strFfdc[64]; + xxdPrint(package.ffdcPtr, package.size, strFfdc); + SBE_FFDC_TRACD("testWithFFDCParser " + "Ffdc package 2 was not successfully parsed. " + "FFDC Data:\n%s", + strFfdc + ); + + TS_FAIL("sbeFFDCParserTest testWithFFDCParser: " + "Ffdc package 2 was not successfully parsed." + ); + + result = true; + break; + } + } + while(0); + + if(result) + { + SBE_FFDC_TRACD("sbeFFDCParserTest testWithFFDCParser " + "test passed!"); + } + else + { + SBE_FFDC_TRACD("sbeFFDCParserTest testWithFFDCParser " + "test failed!"); + } + } +}; + +#endif diff --git a/src/usr/sbeio/test/sbe_fifo_buffer_test.H b/src/usr/sbeio/test/sbe_fifo_buffer_test.H new file mode 100644 index 000000000..0383ebe7b --- /dev/null +++ b/src/usr/sbeio/test/sbe_fifo_buffer_test.H @@ -0,0 +1,1866 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/sbeio/test/sbe_fifo_buffer_test.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* 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. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __SBEIO_SBE_FIFO_BUFFER_TEST_H +#define __SBEIO_SBE_FIFO_BUFFER_TEST_H + +#include <vector> + +#include <cxxtest/TestSuite.H> +#include "sbe_test_support.H" + +#include <sbe_fifo_buffer.H> +#include <trace/interface.H> + +extern trace_desc_t* g_trac_sbeio; + +#define SBE_BUFFER_TRACD(printf_string,args...) \ + TRACDCOMP(g_trac_sbeio,"sbeFifoBufferTest: " printf_string,##args) + +using namespace SBEIO; + +class SbeFifoRespBufferTestFixture:public SbeFifoRespBuffer +{ +public: + + explicit SbeFifoRespBufferTestFixture(uint32_t * i_fifoBuffer, + size_t bufferWordSize): + SbeFifoRespBuffer(i_fifoBuffer, + bufferWordSize) + { + } + + //expose data for testing + using SbeFifoRespBuffer::localBuffer; + using SbeFifoRespBuffer::callerBuffer; + using SbeFifoRespBuffer::callerWordSize; + using SbeFifoRespBuffer::index; + using SbeFifoRespBuffer::offsetIndex; + using SbeFifoRespBuffer::statusIndex; + using SbeFifoRespBuffer::ffdcIndex; + using SbeFifoRespBuffer::getStateString; + using SbeFifoRespBuffer::setBufferState; +}; + + +std::vector<uint32_t> bufferNoReturnNoFFDC = { + 0xC0DEA807, //Status Header 1 + 0x00000000, //Status Header 2 + 0x00000003, //Offset to Status Header + 0x00000001 //EOT + }; + +std::vector<uint32_t> bufferReturnNoFFDC = { + 0x00010002, //Return Data 1 + 0x00030004, //Return Data 2 + 0xC0DEA807, //Status Header 1 + 0x00000000, //Status Header 2 + 0x00000003, //Offset to Status Header + 0x00000001 //EOT + }; + +std::vector<uint32_t> bufferNoReturnFFDC = { + 0xC0DEA807, //Status Header 1 + 0x00FE0099, //Status Header 2 + 0xFFDC0024, //FFDC 1 + 0x00983AB6, //FFDC 2 - RC_SBE_SCOM_FAILURE + 0x00000008, //FFDC 3 - scom addr size + 0x12345678, //FFDC 4 - scom addr + 0x00000008, //FFDC 5 - PIB RC size + 0x00000006, //FFDC 6 - PIB_PARITY_ERROR + 0x00000009, //Offset to Status Header + 0x00000001, //EOT + }; + +std::vector<uint32_t> bufferReturnFFDC = { + 0x00000001, //Return Data 1 + 0x00000002, //Return Data 2 + 0x00000003, //Return Data 3 + 0xC0DEA807, //Status Header 1 + 0x00FE0099, //Status Header 2 + 0xFFDC0024, //FFDC 1 + 0x00983AB6, //FFDC 2 - RC_SBE_SCOM_FAILURE + 0x00000008, //FFDC 3 - scom addr size + 0x12345678, //FFDC 4 - scom addr + 0x00000008, //FFDC 5 - PIB RC size + 0x00000006, //FFDC 6 - PIB_PARITY_ERROR + 0x00000009, //Offset to Status Header + 0x00000001, //EOT + }; + +std::vector<uint32_t> bufferLongOffset = { + 0xC0DEA807, //Status Header 1 + 0x00000000, //Status Header 2 + 0x00000004, //Offset to Status Header + 0x00000001 //EOT + }; + +std::vector<uint32_t> bufferShortOffset = { + 0xC0DEA807, //Status Header 1 + 0x00000000, //Status Header 2 + 0x00000002, //Offset to Status Header + 0x00000001 //EOT + }; + +std::vector<uint32_t> bufferShortRead = { + 0xC0DEA807, //Status Header 1 + 0x00000000, //Status Header 2 + 0x00000001 //EOT + }; + +size_t overrun_element_count{2096}; +uint32_t overrun_element_value{34}; +std::vector<uint32_t> bufferOverrun(overrun_element_count, + overrun_element_value); + +//=================================================== +class SbeFifoBufferTest : public CxxTest::TestSuite +{ +public: + + struct expected_data + { + const char* test_name; + size_t index; + size_t offset_index; + size_t offset; + + size_t statusIndex; + const void* expected_status; + + bool expectFFDC; + size_t ffdcIndex; + size_t ffdcByteSize; + const void* expected_ffdc_data; + + bool expectReturnData; + size_t dataByteSize; + const void* expected_data; + + char strMessage[512]; + }; + + //------------------------------------------------ + void testState() + { + SBE_BUFFER_TRACD("Enter sbeFifoBufferTest testState"); + + bool result{true}; + + //Set buffer to various states and test responses + + /* The operator bool is implemented so that the fifobuffer object can + * be used as a control variable for a while loop. The operator bool + * only returns true if data is allowed to be added to the buffer + * (i.e. the state is MSG_INCOMPLETE). A SbeFifoRespBuffer object which + * is in an error state or contains a complete message is no longer + * able to accept new data to add to the internal buffers and as such + * will return false for the conversion operator. + */ + + /* The getStatus method on the other hand returns true if the + * SbeFifoRespBuffer object is not in an error state. The MSG_COMPLETE + * and MSG_INCOMPLETE are the non-error states, any other state will + * cause getStatus to return false. + */ + + do + { + uint32_t callerBuffer[4] = {0}; + SbeFifoRespBufferTestFixture fifoBuffer(callerBuffer, + sizeof(callerBuffer)/sizeof(uint32_t)); + + if(not fifoBuffer) + { + TS_FAIL("sbeFifoBufferTest testState: " + "The FIFO buffer is not in a good state after " + "CTOR call. Buffer state: %s", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + + fifoBuffer.setBufferState( + SbeFifoRespBuffer::INVALID_CALLER_BUFFER); + + if(fifoBuffer) + { + TS_FAIL("sbeFifoBufferTest testState: " + "The operator bool unexpectedly returned true " + "after setting the state to INVALID_CALLER_BUFFER" + ); + + result = false; + break; + } + + if(fifoBuffer.getStatus()) + { + TS_FAIL("sbeFifoBufferTest testState: " + "getStatus unexpectedly returned true " + "after setting the state to INVALID_CALLER_BUFFER" + ); + + result = false; + break; + } + + fifoBuffer.setBufferState(SbeFifoRespBuffer::OVERRUN); + + if(fifoBuffer) + { + TS_FAIL("sbeFifoBufferTest testState: " + "The operator bool unexpectedly returned true " + "after setting the state to OVERRUN" + ); + + result = false; + break; + } + + if(fifoBuffer.getStatus()) + { + TS_FAIL("sbeFifoBufferTest testState: " + "getStatus unexpectedly returned true " + "after setting the state to OVERRUN" + ); + + result = false; + break; + } + + fifoBuffer.setBufferState(SbeFifoRespBuffer::MSG_SHORT_READ); + + if(fifoBuffer) + { + TS_FAIL("sbeFifoBufferTest testState: " + "The operator bool unexpectedly returned true " + "after setting the state to MSG_SHORT_READ" + ); + + result = false; + break; + } + + if(fifoBuffer.getStatus()) + { + TS_FAIL("sbeFifoBufferTest testState: " + "getStatus unexpectedly returned true " + "after setting the state to MSG_SHORT_READ" + ); + + result = false; + break; + } + + fifoBuffer.setBufferState(SbeFifoRespBuffer::MSG_INVALID_OFFSET); + + if(fifoBuffer) + { + TS_FAIL("sbeFifoBufferTest testState: " + "The operator bool unexpectedly returned true " + "after setting the state to MSG_INVALID_OFFSET" + ); + + result = false; + break; + } + + if(fifoBuffer.getStatus()) + { + TS_FAIL("sbeFifoBufferTest testState: " + "getStatus unexpectedly returned true " + "after setting the state to MSG_INVALID_OFFSET" + ); + + result = false; + break; + } + + fifoBuffer.setBufferState(SbeFifoRespBuffer::MSG_COMPLETE); + + if(fifoBuffer) + { + TS_FAIL("sbeFifoBufferTest testState: " + "The operator bool unexpectedly returned true " + "after setting the state to MSG_COMPLETE" + ); + + result = false; + break; + } + + if(not fifoBuffer.getStatus()) + { + TS_FAIL("sbeFifoBufferTest testState: " + "getStatus unexpectedly returned false " + "after setting the state to MSG_COMPLETE" + ); + + result = false; + break; + } + + fifoBuffer.setBufferState(SbeFifoRespBuffer::MSG_INCOMPLETE); + + if(not fifoBuffer) + { + TS_FAIL("sbeFifoBufferTest testState: " + "The operator bool unexpectedly returned false " + "after setting the state to MSG_INCOMPLETE" + ); + + result = false; + break; + } + + if(not fifoBuffer.getStatus()) + { + TS_FAIL("sbeFifoBufferTest testState: " + "getStatus unexpectedly returned false " + "after setting the state to MSG_INCOMPLETE" + ); + + result = false; + break; + } + + SbeFifoRespBufferTestFixture fifoBuffer_null(nullptr, + sizeof(callerBuffer)/sizeof(uint32_t)); + + if(fifoBuffer_null) + { + TS_FAIL("sbeFifoBufferTest testState: " + "The FIFO buffer unexpectedly indicates a good state " + "after passing a null pointer to the CTOR. " + "Buffer state: %s", + fifoBuffer_null.getStateString() + ); + + result = false; + break; + } + + if(fifoBuffer_null.getStatus()) + { + TS_FAIL("sbeFifoBufferTest testState: " + "getStatus unexpectedly returned true " + "after passing a null pointer to the CTOR. " + "Buffer state: %s", + fifoBuffer_null.getStateString() + ); + + result = false; + break; + } + + if(SbeFifoRespBuffer::INVALID_CALLER_BUFFER != + fifoBuffer_null.getState()) + { + TS_FAIL("sbeFifoBufferTest testState: " + "Buffer in unexpected state after calling CTOR " + "w/nullptr. Buffer State: %s", + fifoBuffer_null.getStateString() + ); + + result = false; + break; + } + + SbeFifoRespBufferTestFixture fifoBuffer_short(callerBuffer, 1); + + if(fifoBuffer_short) + { + TS_FAIL("sbeFifoBufferTest testState: " + "The FIFO buffer unexpectedly indicates a good state " + "after passing a small buffer to the CTOR. " + "Buffer state: %s", + fifoBuffer_short.getStateString() + ); + + result = false; + break; + } + + if(fifoBuffer_short.getStatus()) + { + TS_FAIL("sbeFifoBufferTest testState: " + "getStatus unexpectedly returned true " + "after passing a small buffer to the CTOR. " + "Buffer state: %s", + fifoBuffer_short.getStateString() + ); + + result = false; + break; + } + + if(SbeFifoRespBuffer::INVALID_CALLER_BUFFER != + fifoBuffer_short.getState()) + { + TS_FAIL("sbeFifoBufferTest testState: " + "Buffer in unexpected state after calling CTOR " + "with a small buffer. Buffer State: %s", + fifoBuffer_short.getStateString() + ); + + result = false; + break; + } + } + while(0); + + if(result) + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testState test passed!"); + } + else + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testState test failed!"); + } + } + + //------------------------------------------------ + void testNoReturnNoFFDC() + { + SBE_BUFFER_TRACD("Enter sbeFifoBufferTest testNoReturnNoFFDC"); + + //Test with buffer data that has No Return data and No FFDC + //A successful write message will have this format. + + bool result{true}; + + do + { + uint32_t callerBuffer[2] = {0}; + SbeFifoRespBufferTestFixture fifoBuffer(callerBuffer, + sizeof(callerBuffer)/sizeof(uint32_t)); + + if(not fifoBuffer) + { + TS_FAIL("sbeFifoBufferTest testNoReturnNoFFDC: " + "The FIFO buffer is not in a good state after " + "CTOR call. Buffer state: %s", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + + setTestData(&bufferNoReturnNoFFDC); + + while(fifoBuffer) + { + uint32_t value{}; + bool rc = readTestData(value); + if(rc) + { + rc = fifoBuffer.append(value); + if(not rc) + { + TS_FAIL("sbeFifoBufferTest testNoReturnNoFFDC: " + "append operation unexpectedly failed. " + "Fifo Buffer state = %s", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + } + else + { + fifoBuffer.completeMessage(); + } + } + + if(not result) + { + break; + } + + if(SbeFifoRespBuffer::MSG_COMPLETE != fifoBuffer.getState()) + { + TS_FAIL("sbeFifoBufferTest testNoReturnNoFFDC: " + "Buffer unexpectedly not in the complete state after " + "populating buffer. State = %s.", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + + if(not fifoBuffer.isMsgComplete()) + { + TS_FAIL("sbeFifoBufferTest testNoReturnNoFFDC: " + "unexpectedly returned false for isMsgComplete" + ); + + result = false; + break; + } + + if(not fifoBuffer.getStatus()) + { + TS_FAIL("sbeFifoBufferTest testNoReturnNoFFDC: " + "unexpectedly returned false for getStatus" + ); + + result = false; + break; + } + + expected_data expData; + memset(&expData, 0, sizeof(expData)); + + expData.test_name = "sbeFifoBufferTest testNoReturnNoFFDC"; + expData.index = 4; + expData.offset_index = 2; + expData.offset = 3; + + expData.statusIndex = 0; + expData.expected_status = &bufferNoReturnNoFFDC[0]; + + expData.expectFFDC = false; + expData.expectReturnData = false; + + bool check_result = runChecks(expData, fifoBuffer); + + if(not check_result) + { + TS_FAIL("%s", expData.strMessage); + + result = false; + break; + } + } + while(0); + + if(result) + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testNoReturnNoFFDC " + "test passed!"); + } + else + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testNoReturnNoFFDC " + "test failed!"); + } + } + + //----------------------------------------------------- + void testReturnNoFFDC() + { + SBE_BUFFER_TRACD("Enter sbeFifoBufferTest testReturnNoFFDC"); + + //Test with buffer data that has Return data and No FFDC + //A successful read message will have this format. + + bool result{true}; + + do + { + uint32_t callerBuffer[4] = {0}; + SbeFifoRespBufferTestFixture fifoBuffer(callerBuffer, + sizeof(callerBuffer)/sizeof(uint32_t)); + + if(not fifoBuffer) + { + TS_FAIL("sbeFifoBufferTest testReturnNoFFDC: " + "The FIFO buffer is not in a good state after " + "CTOR call. Buffer state: %s", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + + setTestData(&bufferReturnNoFFDC); + + while(fifoBuffer) + { + uint32_t value{}; + bool rc = readTestData(value); + if(rc) + { + rc = fifoBuffer.append(value); + if(not rc) + { + TS_FAIL("sbeFifoBufferTest testReturnNoFFDC: " + "append operation unexpectedly failed. " + "Fifo Buffer state = %s", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + } + else + { + fifoBuffer.completeMessage(); + } + } + + if(not result) + { + break; + } + + if(SbeFifoRespBuffer::MSG_COMPLETE != fifoBuffer.getState()) + { + TS_FAIL("sbeFifoBufferTest testReturnNoFFDC: " + "Buffer unexpectedly not in the complete state after " + "populating buffer. State = %s.", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + + if(not fifoBuffer.isMsgComplete()) + { + TS_FAIL("sbeFifoBufferTest testReturnNoFFDC: " + "unexpectedly returned false for isMsgComplete" + ); + + result = false; + break; + } + + if(not fifoBuffer.getStatus()) + { + TS_FAIL("sbeFifoBufferTest testReturnNoFFDC: " + "unexpectedly returned false for getStatus" + ); + + result = false; + break; + } + + expected_data expData; + memset(&expData, 0, sizeof(expData)); + + expData.test_name = "sbeFifoBufferTest testReturnNoFFDC"; + expData.index = 6; + expData.offset_index = 4; + expData.offset = 3; + + expData.statusIndex = 2; + expData.expected_status = &bufferReturnNoFFDC[2]; + + expData.expectFFDC = false; + + expData.expectReturnData = true; + expData.dataByteSize = sizeof(uint32_t) * 2; + expData.expected_data = &bufferReturnNoFFDC[0]; + + bool check_result = runChecks(expData, fifoBuffer); + + if(not check_result) + { + TS_FAIL("%s", expData.strMessage); + + result = false; + break; + } + } + while(0); + + if(result) + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testReturnNoFFDC " + "test passed!"); + } + else + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testReturnNoFFDC " + "test failed!"); + } + } + + //-------------------------------------------------------------------- + void testNoReturnFFDC() + { + SBE_BUFFER_TRACD("Enter sbeFifoBufferTest testNoReturnFFDC"); + + //Test with buffer data that has No Return data and FFDC data + //An unsuccessful write message will have this format. + + bool result{true}; + + do + { + uint32_t callerBuffer[2] = {0}; + SbeFifoRespBufferTestFixture fifoBuffer(callerBuffer, + sizeof(callerBuffer)/sizeof(uint32_t)); + + if(not fifoBuffer) + { + TS_FAIL("sbeFifoBufferTest testNoReturnFFDC: " + "The FIFO buffer is not in a good state after " + "CTOR call. Buffer state: %s", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + + setTestData(&bufferNoReturnFFDC); + + while(fifoBuffer) + { + uint32_t value{}; + bool rc = readTestData(value); + if(rc) + { + rc = fifoBuffer.append(value); + if(not rc) + { + TS_FAIL("sbeFifoBufferTest testNoReturnFFDC: " + "append operation unexpectedly failed. " + "Fifo Buffer state = %s", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + } + else + { + fifoBuffer.completeMessage(); + } + } + + if(not result) + { + break; + } + + if(SbeFifoRespBuffer::MSG_COMPLETE != fifoBuffer.getState()) + { + TS_FAIL("sbeFifoBufferTest testNoReturnFFDC: " + "Buffer unexpectedly not in the complete state after " + "populating buffer. State = %s.", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + + if(not fifoBuffer.isMsgComplete()) + { + TS_FAIL("sbeFifoBufferTest testNoReturnFFDC: " + "unexpectedly returned false for isMsgComplete" + ); + + result = false; + break; + } + + if(not fifoBuffer.getStatus()) + { + TS_FAIL("sbeFifoBufferTest testNoReturnFFDC: " + "unexpectedly returned false for getStatus" + ); + + result = false; + break; + } + + expected_data expData; + memset(&expData, 0, sizeof(expData)); + + expData.test_name = "sbeFifoBufferTest testNoReturnFFDC"; + expData.index = 10; + expData.offset_index = 8; + expData.offset = 9; + + expData.statusIndex = 0; + expData.expected_status = &bufferNoReturnFFDC[0]; + + expData.expectFFDC = true; + expData.ffdcIndex = 2; + expData.ffdcByteSize = sizeof(uint32_t)*6; + expData.expected_ffdc_data = &bufferNoReturnFFDC[2]; + + expData.expectReturnData = false; + + bool check_result = runChecks(expData, fifoBuffer); + + if(not check_result) + { + TS_FAIL("%s", expData.strMessage); + result = false; + break; + } + } + while(0); + + if(result) + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testNoReturnFFDC " + "test passed!"); + } + else + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testNoReturnFFDC " + "test failed!"); + } + } + + //----------------------------------------------------------------------- + void testReturnFFDC() + { + SBE_BUFFER_TRACD("Enter sbeFifoBufferTest testReturnFFDC"); + + //Test with buffer data that has both Return data and FFDC data + + bool result{true}; + + do + { + uint32_t callerBuffer[5] = {0}; + SbeFifoRespBufferTestFixture fifoBuffer(callerBuffer, + sizeof(callerBuffer)/sizeof(uint32_t)); + + if(not fifoBuffer) + { + TS_FAIL("sbeFifoBufferTest testReturnFFDC: " + "The FIFO buffer is not in a good state after " + "CTOR call. Buffer state: %s", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + + setTestData(&bufferReturnFFDC); + + while(fifoBuffer) + { + uint32_t value{}; + bool rc = readTestData(value); + if(rc) + { + rc = fifoBuffer.append(value); + if(not rc) + { + TS_FAIL("sbeFifoBufferTest testReturnFFDC: " + "append operation unexpectedly failed. " + "Fifo Buffer state = %s", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + } + else + { + fifoBuffer.completeMessage(); + } + } + + if(not result) + { + break; + } + + if(SbeFifoRespBuffer::MSG_COMPLETE != fifoBuffer.getState()) + { + TS_FAIL("sbeFifoBufferTest testReturnFFDC: " + "Buffer unexpectedly not in the complete state after " + "populating buffer. State = %s.", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + + if(not fifoBuffer.isMsgComplete()) + { + TS_FAIL("sbeFifoBufferTest testReturnFFDC: " + "unexpectedly returned false for isMsgComplete" + ); + + result = false; + break; + } + + if(not fifoBuffer.getStatus()) + { + TS_FAIL("sbeFifoBufferTest testReturnFFDC: " + "unexpectedly returned false for getStatus" + ); + + result = false; + break; + } + + expected_data expData; + memset(&expData, 0, sizeof(expData)); + + expData.test_name = "ReturnFFDC"; + expData.index = 13; + expData.offset_index = 11; + expData.offset = 9; + + expData.statusIndex = 3; + expData.expected_status = &bufferReturnFFDC[3]; + + expData.expectFFDC = true; + expData.ffdcIndex = 5; + expData.ffdcByteSize = sizeof(uint32_t)*6; + expData.expected_ffdc_data = &bufferReturnFFDC[5]; + + expData.expectReturnData = true; + expData.dataByteSize = sizeof(uint32_t) * 3; + expData.expected_data = &bufferReturnFFDC[0]; + + bool check_result = runChecks(expData, fifoBuffer); + + if(not check_result) + { + TS_FAIL("%s", expData.strMessage); + + result = false; + break; + } + } + while(0); + + if(result) + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testReturnFFDC test passed!"); + } + else + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testReturnFFDC test failed!"); + } + } + + //------------------------------------------------------------------------ + void testBadOffsetLong() + { + SBE_BUFFER_TRACD("sbeFifoBufferTest Enter testBadOffsetLong"); + + //Test with an offset that points to beyond that start of the buffer + + bool result{true}; + + do + { + uint32_t callerBuffer[2] = {0}; + SbeFifoRespBufferTestFixture fifoBuffer(callerBuffer, + sizeof(callerBuffer)/sizeof(uint32_t)); + + if(not fifoBuffer) + { + TS_FAIL("sbeFifoBufferTest testBadOffsetLong: " + "The FIFO buffer is not in a good state after " + "CTOR call. Buffer state: %s", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + + setTestData(&bufferLongOffset); + + while(fifoBuffer) + { + uint32_t value{}; + bool rc = readTestData(value); + if(rc) + { + rc = fifoBuffer.append(value); + if(not rc) + { + TS_FAIL("sbeFifoBufferTest testBadOffsetLong: " + "append operation unexpectedly failed. " + "Fifo Buffer state = %s", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + } + else + { + fifoBuffer.completeMessage(); + } + } + + if(not result) + { + break; + } + + if(SbeFifoRespBuffer::MSG_INVALID_OFFSET != fifoBuffer.getState()) + { + TS_FAIL("sbeFifoBufferTest testBadOffsetLong: " + "Buffer unexpectedly not in the INVALID_OFFSET state " + "after populating buffer. State = %s.", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + + if(fifoBuffer.isMsgComplete()) + { + TS_FAIL("sbeFifoBufferTest testBadOffsetLong: " + "unexpectedly returned true for isMsgComplete" + ); + + result = false; + break; + } + } + while(0); + + if(result) + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testBadOffsetLong " + "test passed!"); + } + else + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testBadOffsetLong " + "test failed!"); + } + } + + //---------------------------------------------------------------------- + void testBadOffsetShort() + { + SBE_BUFFER_TRACD("Enter sbeFifoBufferTest testBadOffsetShort"); + + //Test with an offset that is too short to reach the Status Header + + bool result{true}; + + do + { + uint32_t callerBuffer[2] = {0}; + SbeFifoRespBufferTestFixture fifoBuffer(callerBuffer, + sizeof(callerBuffer)/sizeof(uint32_t)); + + if(not fifoBuffer) + { + TS_FAIL("sbeFifoBufferTest testBadOffsetShort: " + "The FIFO buffer is not in a good state after " + "CTOR call. Buffer state: %s", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + + setTestData(&bufferShortOffset); + + while(fifoBuffer) + { + uint32_t value{}; + bool rc = readTestData(value); + if(rc) + { + rc = fifoBuffer.append(value); + if(not rc) + { + TS_FAIL("sbeFifoBufferTest testBadOffsetShort: " + "append operation unexpectedly failed. " + "Fifo Buffer state = %s", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + } + else + { + fifoBuffer.completeMessage(); + } + } + + if(not result) + { + break; + } + + if(SbeFifoRespBuffer::MSG_INVALID_OFFSET != fifoBuffer.getState()) + { + TS_FAIL("sbeFifoBufferTest testBadOffsetShort: " + "Buffer unexpectedly not in the INVALID_OFFSET state " + "after populating buffer. State = %s.", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + + if(fifoBuffer.isMsgComplete()) + { + TS_FAIL("sbeFifoBufferTest testBadOffsetShort: " + "unexpectedly returned true for isMsgComplete." + ); + + result = false; + break; + } + } + while(0); + + if(result) + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testBadOffsetShort " + "test passed!"); + } + else + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testBadOffsetShort " + "test failed!"); + } + } + + //------------------------------------------------------------------------ + void testShortRead() + { + SBE_BUFFER_TRACD("Enter sbeFifoBufferTest testShortRead"); + //Test case where message is completed prematurely + + bool result{true}; + + do + { + uint32_t callerBuffer[2] = {0}; + SbeFifoRespBufferTestFixture fifoBuffer(callerBuffer, + sizeof(callerBuffer)/sizeof(uint32_t)); + + if(not fifoBuffer) + { + TS_FAIL("sbeFifoBufferTest testShortRead: " + "The FIFO buffer is not in a good state after " + "CTOR call. Buffer state: %s", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + + setTestData(&bufferShortRead); + + while(fifoBuffer) + { + uint32_t value{}; + bool rc = readTestData(value); + if(rc) + { + rc = fifoBuffer.append(value); + if(not rc) + { + TS_FAIL("sbeFifoBufferTest testShortRead: " + "append operation unexpectedly failed. " + "Fifo Buffer state = %s", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + } + else + { + fifoBuffer.completeMessage(); + } + } + + if(not result) + { + break; + } + + if(SbeFifoRespBuffer::MSG_SHORT_READ != fifoBuffer.getState()) + { + TS_FAIL("sbeFifoBufferTest testShortRead: " + "Buffer unexpectedly not in the MSG_SHORT_READ state " + "after populating buffer. State = %s.", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + + if(fifoBuffer.isMsgComplete()) + { + TS_FAIL("sbeFifoBufferTest testShortRead: " + "unexpectedly returned true for isMsgComplete" + ); + + result = false; + break; + } + } + while(0); + + if(result) + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testShortRead test passed!"); + } + else + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testShortRead test failed!"); + } + } + + //----------------------------------------------------------- + void testOverrun() + { + SBE_BUFFER_TRACD("Enter sbeFifoBufferTest testOverrun"); + + //Test the case where the message is not completed and + //overruns the local buffer. + + bool result{true}; + + do + { + uint32_t callerBuffer[2] = {0}; + SbeFifoRespBufferTestFixture fifoBuffer(callerBuffer, + sizeof(callerBuffer)/sizeof(uint32_t)); + + if(not fifoBuffer) + { + TS_FAIL("sbeFifoBufferTest testOverrun: " + "The FIFO buffer is not in a good state after " + " CTOR call. Buffer state: %s", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + + setTestData(&bufferOverrun); + + while(fifoBuffer) + { + uint32_t value{}; + bool rc = readTestData(value); + if(rc) + { + rc = fifoBuffer.append(value); + if(not rc && SbeFifoRespBuffer::OVERRUN != + fifoBuffer.getState()) + { + TS_FAIL("sbeFifoBufferTest testOverrun: " + "append operation unexpectedly failed. " + "Fifo Buffer state = %s", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + } + else + { + fifoBuffer.completeMessage(); + } + } + + if(not result) + { + break; + } + + if(SbeFifoRespBuffer::OVERRUN != fifoBuffer.getState()) + { + TS_FAIL("sbeFifoBufferTest testOverrun: " + "Buffer unexpectedly not in the OVERRUN state " + "after populating buffer. State = %s.", + fifoBuffer.getStateString() + ); + + result = false; + break; + } + + if(fifoBuffer.isMsgComplete()) + { + TS_FAIL("sbeFifoBufferTest testOverrun: " + "unexpectedly returned true for isMsgComplete" + ); + + result = false; + break; + } + } + while(0); + + if(result) + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testOverrun test passed!"); + } + else + { + SBE_BUFFER_TRACD("sbeFifoBufferTest testOverrun test failed!"); + } + } + +private: + + std::vector<uint32_t>* iv_testData{}; + std::vector<uint32_t>::const_iterator iv_itr; + + //-------------------------------------------------------- + void setTestData(std::vector<uint32_t>* i_testData) + { + iv_testData = i_testData; + resetTestData(); + } + + //--------------------------------------------------------- + void resetTestData() + { + if(iv_testData) + { + iv_itr = iv_testData->begin(); + } + } + + //--------------------------------------------------------- + bool readTestData(uint32_t& value) + { + bool retval{false}; + if(iv_testData) + { + if(iv_itr != iv_testData->end()) + { + value = *iv_itr; + ++iv_itr; + retval = true; + } + } + + return retval; + } + + //------------------------------------------------------------------ + bool runChecks(expected_data& expData, + SbeFifoRespBufferTestFixture& fifoBuffer) + { + + bool result{true}; + + do + { + if(expData.index != fifoBuffer.index()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s index not at %d as expected. Index = %d", + expData.test_name, + expData.index, + fifoBuffer.index() + ); + + result = false; + break; + } + + if(expData.offset_index != fifoBuffer.offsetIndex()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: offset index not at %d as expected. " + "Offset index = %d", + expData.test_name, + expData.offset_index, + fifoBuffer.offsetIndex() + ); + + result = false; + break; + } + + uint32_t offset = + fifoBuffer.localBuffer()[fifoBuffer.offsetIndex()]; + + if(expData.offset != offset) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "The offset is not %d as expected. Buffer Offset: %d", + expData.test_name, + expData.offset, + offset); + + result = false; + break; + } + + if(expData.statusIndex != fifoBuffer.statusIndex()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: status index not at %d as expected. " + "Status index = %d", + expData.test_name, + expData.statusIndex, + fifoBuffer.statusIndex() + ); + + result = false; + break; + } + + if(not fifoBuffer.getStatusHeader()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "getStatusHeader unexpectedly returned a nullptr.", + expData.test_name + ); + + result = false; + break; + } + + if(memcmp(expData.expected_status, fifoBuffer.getStatusHeader(), + sizeof(SbeFifo::statusHeader)) != 0) + { + char expected_xxd[128]; + char actual_xxd[128]; + + xxdPrint(fifoBuffer.getStatusHeader(), + sizeof(SbeFifo::statusHeader), + actual_xxd); + + xxdPrint(expData.expected_status, + sizeof(SbeFifo::statusHeader), + expected_xxd); + + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "Buffer StatusHeader not as expected.\n" + "Status data: \n%s\n" + "Expected data: \n%s", + expData.test_name, + actual_xxd, + expected_xxd + ); + + result = false; + break; + } + + if(expData.expectFFDC) + { + if(expData.ffdcIndex != fifoBuffer.ffdcIndex()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "ffdc index not at %d as expected. ffdc index %d", + expData.test_name, + expData.ffdcIndex, + fifoBuffer.ffdcIndex() + ); + + result = false; + break; + } + + if(not fifoBuffer.msgContainsFFDC()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "msgContainsFFDC incorrectly returned false", + expData.test_name + ); + + result = false; + break; + } + + if(not fifoBuffer.getFFDCPtr()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "getFFDCPtr unexpectedly returned a nullptr.", + expData.test_name + ); + + result = false; + break; + } + + if(expData.ffdcByteSize != fifoBuffer.getFFDCByteSize()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "Buffer FFDC size %d not as expected %d", + expData.test_name, + fifoBuffer.getFFDCByteSize(), + expData.ffdcByteSize + ); + + result = false; + break; + } + + if(expData.ffdcByteSize/sizeof(uint32_t) != + fifoBuffer.getFFDCWordSize()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "Buffer FFDC word size %d not as expected %d", + expData.test_name, + fifoBuffer.getFFDCWordSize(), + expData.ffdcByteSize/sizeof(uint32_t) + ); + + result = false; + break; + } + + if(memcmp(fifoBuffer.getFFDCPtr(), + expData.expected_ffdc_data, expData.ffdcByteSize) != 0) + { + char expected_xxd[128]; + char ffdc_xxd[128]; + + xxdPrint(fifoBuffer.getFFDCPtr(), + expData.ffdcByteSize, + ffdc_xxd); + + xxdPrint(expData.expected_ffdc_data, + expData.ffdcByteSize, + expected_xxd); + + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "Buffer FFDC data not as expected.\n" + "FFDC data: \n%s\n" + "Expected data: \n%s", + expData.test_name, + ffdc_xxd, + expected_xxd + ); + + result = false; + break; + } + } + else + { + if(SbeFifoRespBuffer::INVALID_INDEX != fifoBuffer.ffdcIndex()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "ffdc index not INVALID_INDEX as expected. " + "ffdc index = 0x%08X", + expData.test_name, + fifoBuffer.ffdcIndex() + ); + + result = false; + break; + } + + if(fifoBuffer.msgContainsFFDC()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "msgContainsFFDC incorrectly returned true", + expData.test_name + ); + + result = false; + break; + } + + if(fifoBuffer.getFFDCPtr()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "getFFDCPtr unexpectedly returned a non-nullptr.", + expData.test_name + ); + + result = false; + break; + } + + if(fifoBuffer.getFFDCByteSize() > 0) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "getFFDCByteSize unexpectedly returned a " + "non zero value: 0x%08X", + expData.test_name, + fifoBuffer.getFFDCByteSize() + ); + + result = false; + break; + } + + if(fifoBuffer.getFFDCWordSize() > 0) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "getFFDCWordSize unexpectedly returned a " + "non zero value: 0x%08X", + expData.test_name, + fifoBuffer.getFFDCWordSize() + ); + + result = false; + break; + } + } + + if(expData.expectReturnData) + { + if(not fifoBuffer.msgContainsReturnData()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "msgContainsReturnData incorrectly returned false", + expData.test_name + ); + + result = false; + break; + } + + if(not fifoBuffer.getReturnData()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "getReturnData unexpectedly returned a nullptr.", + expData.test_name + ); + + result = false; + break; + } + + if(expData.dataByteSize != fifoBuffer.getReturnDataByteSize()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "Buffer return data size %d not as expected %d", + expData.test_name, + fifoBuffer.getReturnDataByteSize(), + expData.dataByteSize + ); + + result = false; + break; + } + + if(expData.dataByteSize/sizeof(uint32_t) != + fifoBuffer.getReturnDataWordSize()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: Buffer Return data word size " + "%d not as expected %d", + expData.test_name, + fifoBuffer.getReturnDataWordSize(), + expData.dataByteSize/sizeof(uint32_t) + ); + + result = false; + break; + } + + if(memcmp(fifoBuffer.getReturnData(), + expData.expected_data, expData.dataByteSize) != 0) + { + char expected_xxd[128]; + char data_xxd[128]; + + xxdPrint(fifoBuffer.getReturnData(), + expData.dataByteSize, + data_xxd); + + xxdPrint(expData.expected_data, + expData.dataByteSize, + expected_xxd); + + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "Buffer Return data not as expected.\n" + "Return data: \n%s\n" + "Expected data: \n%s", + expData.test_name, + data_xxd, + expected_xxd + ); + + result = false; + break; + } + } + else + { + if(fifoBuffer.msgContainsReturnData()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "msgContainsReturnData incorrectly returned true", + expData.test_name + ); + + result = false; + break; + } + + if(fifoBuffer.getReturnData()) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: getReturnData unexpectedly " + "returned a non-nullptr.", + expData.test_name + ); + + result = false; + break; + } + + if(fifoBuffer.getReturnDataByteSize() > 0) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "getReturnDataByteSize unexpectedly returned a " + "non zero value: 0x%08X", + expData.test_name, + fifoBuffer.getReturnDataByteSize() + ); + + result = false; + break; + } + + if(fifoBuffer.getReturnDataWordSize() > 0) + { + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "getReturnDataWordSize unexpectedly returned a " + "non zero value: 0x%08X", + expData.test_name, + fifoBuffer.getReturnDataWordSize() + ); + + result = false; + break; + } + } + + //test that the caller buffer was populated + if(memcmp(fifoBuffer.callerBuffer(), + &((*iv_testData)[0]), + fifoBuffer.callerWordSize()*sizeof(uint32_t)) != 0) + { + char expected_xxd[128]; + char caller_xxd[128]; + + size_t data_size = fifoBuffer.callerWordSize()*sizeof(uint32_t); + + xxdPrint(fifoBuffer.callerBuffer(), + data_size, + caller_xxd); + + xxdPrint(&((*iv_testData)[0]), + data_size, + expected_xxd); + + snprintf(expData.strMessage, + sizeof(expData.strMessage), + "%s: " + "Caller buffer not as expected.\n" + "Caller Buffer: \n%s\n" + "Expected data: \n%s", + expData.test_name, + caller_xxd, + expected_xxd + ); + + result = false; + break; + } + } + while(0); + + return result; + } + +}; + +#endif diff --git a/src/usr/sbeio/test/sbe_test_support.H b/src/usr/sbeio/test/sbe_test_support.H new file mode 100644 index 000000000..606313a9e --- /dev/null +++ b/src/usr/sbeio/test/sbe_test_support.H @@ -0,0 +1,91 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/sbeio/test/sbe_test_support.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* 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. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __SBE_TEST_SUPPORT_H +#define __SBE_TEST_SUPPORT_H + +#include <stdint.h> +#include <stdio.h> + +//--------------------------------------------------------------------- +template <size_t N> +void xxdPrint(const void* pvbuffer, + size_t bufferSize, + char (&strBuffer)[N]) +{ + if(nullptr == pvbuffer || 0 == bufferSize) + { + return; + } + + const char* pbuffer = reinterpret_cast<const char*>(pvbuffer); + + char* pstr = strBuffer; + + int remaining = static_cast<int>(sizeof(strBuffer)); + memset(strBuffer, 0, sizeof(strBuffer)); + + for(size_t i=0; i < bufferSize; ++i) + { + int rc{}; + const uint8_t byteVal = + *(reinterpret_cast<const uint8_t*>(pbuffer++)); + if(i == 0) + { + rc = snprintf(pstr, remaining, "\t\t\t\t%02X", byteVal); + } + else if(i%16 == 0) + { + rc = snprintf(pstr, remaining, "\n\t\t\t\t%02X", byteVal); + } + else + { + if(i%2 == 1) + { + rc = snprintf(pstr, remaining, "%02X ", byteVal); + } + else + { + rc = snprintf(pstr, remaining, "%02X", byteVal); + } + } + + if(rc > 0 && rc < remaining) + { + remaining -= rc; + pstr += rc; + + if(remaining <= 0) + { + break; + } + } + else + { + break; + } + } +} + +#endif |