From 8d1bd808dae98f7165b8ea042df45d8b82476ab7 Mon Sep 17 00:00:00 2001 From: Dhruvaraj Subhashchandran Date: Sat, 19 Apr 2025 04:39:55 -0500 Subject: [PATCH] Test Signed-off-by: Dhruvaraj Subhashchandran --- libphal/phal_sbe.C | 61 +++++---- libphal/sbeInf/plat/plat_sbe_fifo.H | 67 ++++++++++ libphal/sbeInf/response_info.H | 25 ++++ libphal/sbeInf/sbe_cmd_implementation.H | 165 ++++++++++++++++++++++++ libphal/sbeInf/sbe_cmd_protocol.H | 62 +++++++++ 5 files changed, 349 insertions(+), 31 deletions(-) create mode 100644 libphal/sbeInf/plat/plat_sbe_fifo.H create mode 100644 libphal/sbeInf/response_info.H create mode 100644 libphal/sbeInf/sbe_cmd_implementation.H create mode 100644 libphal/sbeInf/sbe_cmd_protocol.H diff --git a/libphal/phal_sbe.C b/libphal/phal_sbe.C index 9a59fbb..7029520 100644 --- a/libphal/phal_sbe.C +++ b/libphal/phal_sbe.C @@ -1,13 +1,18 @@ +#include #include "libphal.H" #include "log.H" #include "phal_exception.H" #include "utils_buffer.H" #include "utils_pdbg.H" #include "utils_tempfile.H" +//#include "plat/plat_target.H" #include #include #include +#include "sbeInf/response_info.H" +#include "sbeInf/sbe_cmd_implementation.H" + #include #include #include @@ -435,48 +440,42 @@ void getTiInfo(struct pdbg_target *proc, uint8_t **data, uint32_t *dataLen) } } -void getDump(struct pdbg_target *chip, const uint8_t type, const uint8_t clock, - const uint8_t faCollect, uint8_t **data, uint32_t *dataLen) +void getDump(struct pdbg_target* chip, + const uint8_t type, const uint8_t clock, const uint8_t faCollect, + uint8_t** data, uint32_t* dataLen) { - log(level::INFO, "Enter: getDump(%d) on %s", type, - pdbg_target_path(chip)); - - bool isOcmb = is_ody_ocmb_chip(chip); - - if (!isTgtPresent(chip)) { - log(level::ERROR, "getDump(%s) Target is not present", - pdbg_target_path(chip)); - } - - if (!isOcmb) { - // Validate input target is processor target. - validateProcTgt(chip); + std::vector dataVec; + std::vector ffdcVec; - // SBE halt state need recovery before dump chip-ops - sbeHaltStateRecovery(chip, false); - } + log(level::ERROR, "In get dump"); - // validate SBE state - validateSBEState(chip); + fapi2::Target fapiTarget(chip); + auto rc = sbeIntf::getDump(fapiTarget, type, clock, faCollect, dataVec, ffdcVec); - // get PIB target for proc else use same target - struct pdbg_target *chipOpTarget = isOcmb ? chip : getPibTarget(chip); + if (rc != fapi2::FAPI2_RC_SUCCESS) + { + log(level::ERROR, "fapi rc not success"); + *data = nullptr; + *dataLen = 0; + throw sbeError_t(exception::SBE_CMD_FAILED); + } - // call pdbg back-end function - if (sbe_dump(chipOpTarget, type, clock, faCollect, data, dataLen)) { - throw captureFFDC(chip, CO_CMD_FAILURE); - } + *dataLen = dataVec.size(); + *data = static_cast(malloc(*dataLen)); + if (!*data) + { + *dataLen = 0; + throw sbeError_t(exception::SBE_CMD_FAILED); + } - sbeError_t result = captureFFDC(chip, CO_CMD_SUCCESS); + std::memcpy(*data, dataVec.data(), *dataLen); - // Throw only if FFDC present - if (result.errType() != exception::SBE_FFDC_NO_DATA) { - throw result; - } + // need to handle FFDC } void threadStopProc(struct pdbg_target *proc) { + validateProcTgt(proc); log(level::INFO, "Enter: threadStopProc(%s)", pdbg_target_path(proc)); diff --git a/libphal/sbeInf/plat/plat_sbe_fifo.H b/libphal/sbeInf/plat/plat_sbe_fifo.H new file mode 100644 index 0000000..6c01151 --- /dev/null +++ b/libphal/sbeInf/plat/plat_sbe_fifo.H @@ -0,0 +1,67 @@ +#pragma once + +extern "C" { +#include +} + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sbeIntf { +namespace platform { + +template +void setChipOpTimeout(const fapi2::Target& target, uint32_t timeoutMs) +{ + struct pdbg_target *pib = openpower::phal::utils::pdbg::getPibTarget(target); + + sbe_set_chipop_timeout(pib, timeoutMs); +} + +template +fapi2::ReturnCode transport(const fapi2::Target& target, + const std::vector& request, uint32_t out_len, + std::vector& response) +{ + + uint8_t* out = nullptr; + + struct pdbg_target *pib = openpower::phal::utils::pdbg::getPibTarget(target); + + int rc = sbe_operation(pib, + const_cast(request.data()), + request.size(), + &out, + &out_len); + + if (rc == ETIMEDOUT) + { + return fapi2::FAPI2_RC_PLAT_ERR_SEE_DATA; + } + else if (rc != 0) + { + fprintf(stderr, "transport failed in plat: rc=0x%08X\n", rc); + return fapi2::FAPI2_RC_PLAT_ERR_SEE_DATA; + } + + if (!out || out_len == 0) + { + return fapi2::FAPI2_RC_PLAT_ERR_SEE_DATA; + } + + response.assign(out, out + out_len); + free(out); + return fapi2::FAPI2_RC_SUCCESS; +} + +} // namespace platform +} // namespace sbeIntf + diff --git a/libphal/sbeInf/response_info.H b/libphal/sbeInf/response_info.H new file mode 100644 index 0000000..008949d --- /dev/null +++ b/libphal/sbeInf/response_info.H @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +namespace sbeIntf { + +struct ResponseInfo +{ + struct FFDC + { + uint8_t slid = 0; + uint8_t severity = 0; + uint32_t chipId = 0; + std::vector rawData; + }; + + std::vector payload; + std::vector ffdcList; + uint16_t primaryStatus = 0; + uint16_t secondaryStatus = 0; +}; + +} + diff --git a/libphal/sbeInf/sbe_cmd_implementation.H b/libphal/sbeInf/sbe_cmd_implementation.H new file mode 100644 index 0000000..1536d55 --- /dev/null +++ b/libphal/sbeInf/sbe_cmd_implementation.H @@ -0,0 +1,165 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "sbe_cmd_protocol.H" +#include "plat/plat_sbe_fifo.H" + +namespace sbeIntf { + +inline std::vector toByteVector(const std::vector& words) +{ + std::vector bytes(words.size() * sizeof(uint32_t)); + std::memcpy(bytes.data(), words.data(), bytes.size()); + return bytes; +} + + +inline ResponseInfo decodeResponse(const std::vector& rawBytes) +{ + ResponseInfo out; + const size_t wordSize = sizeof(uint32_t); + const size_t wordCount = rawBytes.size() / wordSize; + const uint32_t* words = reinterpret_cast(rawBytes.data()); + + if (wordCount < 3) + { + return out; + } + + uint32_t trailerOffset = ntohl(words[wordCount - 1]); + size_t headerPos = wordCount - trailerOffset; + + if (headerPos + 1 >= wordCount) + { + return out; + } + + out.primaryStatus = ntohl(words[headerPos + 1]) >> 16; + out.secondaryStatus = ntohl(words[headerPos + 1]) & 0xFFFF; + + size_t payloadSize = headerPos * wordSize; + out.payload.assign(rawBytes.begin(), rawBytes.begin() + payloadSize); + + size_t ffdcStart = (headerPos + 2) * wordSize; + if (ffdcStart + 8 <= rawBytes.size()) + { + size_t offset = ffdcStart; + while (offset + 8 <= rawBytes.size()) + { + const uint8_t* p = &rawBytes[offset]; + uint16_t magic = ntohs(*(uint16_t*)p); + + if (magic != 0xFBAD && magic != 0xFFDC) + break; + + ResponseInfo::FFDC entry; + entry.slid = ntohs(*(uint16_t*)(p + 4)); + entry.severity = *(p + 6); + entry.chipId = *(p + 7); + + uint16_t wordLen = ntohs(*(uint16_t*)(p + 2)); + size_t byteLen = wordLen * wordSize; + + if (offset + byteLen > rawBytes.size()) + break; + + entry.rawData.assign(p, p + byteLen); + out.ffdcList.push_back(std::move(entry)); + offset += byteLen; + } + } + + return out; +} + + +template +fapi2::ReturnCode executeChipOp(const fapi2::Target& target, + const std::vector& cmd_words, + std::vector& data, + std::vector& ffdc) +{ + std::vector request = toByteVector(cmd_words); + + uint32_t cmd = ntohl(cmd_words[1]); + uint32_t timeoutMs = cmd::getRecommendedTimeoutMs(cmd); + uint32_t out_len = cmd::getRecommendedSize(cmd); + + platform::setChipOpTimeout(target, timeoutMs); + + std::vector response; + auto rc = platform::transport(target, request, out_len, response); + if (rc != fapi2::FAPI2_RC_SUCCESS) + { + return rc; + } + + auto decoded = decodeResponse(response); + data = std::move(decoded.payload); + ffdc = std::move(decoded.ffdcList); + fprintf(stderr, "SBE response status: primary=0x%08X secondary=0x%08X, payload=%zu bytes, FFDC=%zu\n", + decoded.primaryStatus, decoded.secondaryStatus, + decoded.payload.size(), decoded.ffdcList.size()); + + return (decoded.primaryStatus != 0 || decoded.secondaryStatus != 0) + ? fapi2::FAPI2_RC_PLAT_ERR_SEE_DATA + : fapi2::FAPI2_RC_SUCCESS; +} + +template +fapi2::ReturnCode captureFfdc(const fapi2::Target& target, + std::vector& discard, + std::vector& outFfdc) +{ + std::vector response; + auto encoded = cmd::encodeGetFfdc(); + uint32_t cmd = ntohl(encoded[1]); + uint32_t out_len = cmd::getRecommendedSize(cmd); + auto rc = platform::transport(target, toByteVector(encoded), out_len, response); + if (rc != fapi2::FAPI2_RC_SUCCESS) { + return rc; + } + + auto decoded = decodeResponse(response); + if (!decoded.ffdcList.empty()) { + outFfdc.insert(outFfdc.end(), + std::make_move_iterator(decoded.ffdcList.begin()), + std::make_move_iterator(decoded.ffdcList.end())); + return fapi2::FAPI2_RC_SUCCESS; + } + + return fapi2::FAPI2_RC_PLAT_ERR_SEE_DATA; +} + +template +void mergeExtraFfdc(const fapi2::Target& target, + std::vector& ffdc) +{ + std::vector extraFfdc; + std::vector discard; + auto ffdcRc = captureFfdc(target, discard, extraFfdc); + if (ffdcRc != fapi2::FAPI2_RC_SUCCESS && !extraFfdc.empty()) { + ffdc.insert(ffdc.end(), + std::make_move_iterator(extraFfdc.begin()), + std::make_move_iterator(extraFfdc.end())); + } +} + +template +fapi2::ReturnCode getDump(const fapi2::Target& target, + uint8_t type, uint8_t clock, uint8_t fa, + std::vector& data, + std::vector& ffdc) +{ + auto cmd_words = cmd::encodeGetDump(type, clock, fa); + auto rc = executeChipOp(target, cmd_words, data, ffdc); + mergeExtraFfdc(target, ffdc); + return rc; +} + +} + diff --git a/libphal/sbeInf/sbe_cmd_protocol.H b/libphal/sbeInf/sbe_cmd_protocol.H new file mode 100644 index 0000000..963847a --- /dev/null +++ b/libphal/sbeInf/sbe_cmd_protocol.H @@ -0,0 +1,62 @@ +#pragma once + +#include +#include +#include + +namespace sbeIntf { +namespace cmd { + +#define SBE_CMD(class, id) ((class << 8) | id) + +// Utility to convert uint32_t to big-endian +inline uint32_t be(uint32_t val) { + return htobe32(val); +} + +// ------------------ Chip-op Encoders ------------------ + +inline std::vector encodeGetDump(uint8_t type, uint8_t clock, uint8_t faCollect) +{ + uint32_t flags = ((faCollect & 0x1) << 16) | ((clock & 0x3) << 8) | (type & 0xf); + return { be(3), be(SBE_CMD(0xAA, 0x01)), be(flags) }; +} + +inline std::vector encodeGetFfdc() +{ + return { be(2), be(SBE_CMD(0xA8, 0x01)) }; +} + +inline std::vector encodeResetFifo() +{ + return { be(2), be(SBE_CMD(0x21, 0x01)) }; +} + +inline uint32_t getRecommendedTimeoutMs(uint32_t cmdWord) +{ + switch (cmdWord) + { + case SBE_CMD(0xAA, 0x01): + return 60000; + default: + return 5000; + } +} + +inline uint32_t getRecommendedSize(uint32_t cmd) +{ + switch (cmd) + { + case SBE_CMD(0xAA, 0x01): + return 80 * 1024 * 1024; + + case SBE_CMD(0xA8, 0x01); + return 64 * 1024; + + default: + return 4096; + } +} + +} // namespace cmd +} // namespace sbeIntf