diff options
author | Donald Washburn <dwashbur@us.ibm.com> | 2017-07-17 10:42:31 -0500 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2017-08-04 09:53:29 -0400 |
commit | 69b38d2b257691fb31347ef0ab1ffab9f74d8ab7 (patch) | |
tree | 8eccdf31f23fbde982483a95ded019fdc4971e4a /src | |
parent | 45b70ed84ad53ad79f2e7929523665d20d94509b (diff) | |
download | blackbird-hostboot-69b38d2b257691fb31347ef0ab1ffab9f74d8ab7.tar.gz blackbird-hostboot-69b38d2b257691fb31347ef0ab1ffab9f74d8ab7.zip |
Added parser for scom FFDC data and a SBE messaging buffer class.
The FFDC data from an SBE Scom read/write needed to be parsed and used to
invoke PIB::addFruCallouts during both FIFO and PSU operations. During task
research it was discovered that the error code path for reading FIFO request
responses had several errors. These errors related to manipulating a duel
buffer system.
Fixed these errors and encapsulated the duel buffer handling in order to
facilitate unit testing.
* Created FFDC parsing classes FfdcParsedPackage and FfdcScomPibErrorPackage
in order to validate and process FFDC data based upon the return code
contained within the FFDC.
* Created the SbeFifoRespBuffer class for encapsulating the handling for
the duel buffers used in the fifo readResponse method.
* Modified the SbeFifo::readResponse method to use the SbeFifoRespBuffer
class for messaging and the new FFDC parsing classes for handling PIB
addFruCallouts.
* Modified the SbePsu::readResponse method to use the FFDC parser classes to
invoke PIB::addFruCallouts.
* Added Unit Tests for SbeFifoRespBuffer, FfdcParsedPackage and
FfdcScomPibErrorPackage.
Change-Id: I195fa036dfa6a0d66d9a3dc15aeb8b0f01cf798c
RTC: 175891
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/43212
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Reviewed-by: Martin Gloff <mgloff@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Dzuy Nguyen <dzuy@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
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 |