summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Spinler <spinler@us.ibm.com>2019-09-30 15:35:53 -0500
committerMatt Spinler <spinler@us.ibm.com>2019-10-22 14:09:56 +0000
commit6852d7222d9268d2b205672d6296424c0581c830 (patch)
tree7a1a2ee0e0e9623be9f9cf2169cd0eaf5cf04c80
parent828c4835df7cb7a31ac08b55bc98d8354fca7ad1 (diff)
downloadphosphor-logging-6852d7222d9268d2b205672d6296424c0581c830.tar.gz
phosphor-logging-6852d7222d9268d2b205672d6296424c0581c830.zip
PEL: Represent the SRC ASCII string field
In the SRC section of a PEL, there is a field called the 'ASCII string'. This is the string of 32 characters that shows up on the panel when the SRC function is chosen, and usually when people refer to an SRC, the first 8 characters of this field is what they are referring to. This new class handles that string. It will belong to the SRC section object. For BMC error SRCs, it looks like: BDSSRRRR Where: BD = "BD", indicating a BMC error SRC SS = subsystem value from PEL spec RRRR = reason code of the error The remaining 24 characters are spaces (' '). For example: "BD8D1234 " For BMC power* related errors, the value is: "11001234 " Where the difference is the "11" instead of "BD", and the following 2 bytes are always "00". * 'power' means comes from the repository that monitors for power faults. This is different purely to help keep field service documentation the same as in previous IBM server generations. Signed-off-by: Matt Spinler <spinler@us.ibm.com> Change-Id: I6e7292e7f5b501428999781b1a5ee5c243a63ac6
-rw-r--r--extensions/openpower-pels/ascii_string.cpp83
-rw-r--r--extensions/openpower-pels/ascii_string.hpp103
-rw-r--r--extensions/openpower-pels/openpower-pels.mk1
-rw-r--r--test/openpower-pels/Makefile.include9
-rw-r--r--test/openpower-pels/ascii_string_test.cpp71
5 files changed, 267 insertions, 0 deletions
diff --git a/extensions/openpower-pels/ascii_string.cpp b/extensions/openpower-pels/ascii_string.cpp
new file mode 100644
index 0000000..6d4711e
--- /dev/null
+++ b/extensions/openpower-pels/ascii_string.cpp
@@ -0,0 +1,83 @@
+#include "ascii_string.hpp"
+
+#include "pel_types.hpp"
+
+#include <phosphor-logging/log.hpp>
+
+namespace openpower
+{
+namespace pels
+{
+namespace src
+{
+
+using namespace phosphor::logging;
+
+AsciiString::AsciiString(Stream& stream)
+{
+ unflatten(stream);
+}
+
+AsciiString::AsciiString(const message::Entry& entry)
+{
+ // Power Error: 1100RRRR
+ // BMC Error: BDSSRRRR
+ // where:
+ // RRRR = reason code
+ // SS = subsystem ID
+
+ // First is type, like 'BD'
+ setByte(0, entry.src.type);
+
+ // Next is '00', or subsystem ID
+ if (entry.src.type == static_cast<uint8_t>(SRCType::powerError))
+ {
+ setByte(2, 0x00);
+ }
+ else // BMC Error
+ {
+ setByte(2, entry.subsystem);
+ }
+
+ // Then the reason code
+ setByte(4, entry.src.reasonCode >> 8);
+ setByte(6, entry.src.reasonCode & 0xFF);
+
+ // Padded with spaces
+ for (size_t offset = 8; offset < asciiStringSize; offset++)
+ {
+ _string[offset] = ' ';
+ }
+}
+
+void AsciiString::flatten(Stream& stream)
+{
+ stream.write(_string.data(), _string.size());
+}
+
+void AsciiString::unflatten(Stream& stream)
+{
+ stream.read(_string.data(), _string.size());
+}
+
+std::string AsciiString::get() const
+{
+ std::string string{_string.begin(), _string.begin() + _string.size()};
+ return string;
+}
+
+void AsciiString::setByte(size_t byteOffset, uint8_t value)
+{
+ assert(byteOffset < asciiStringSize);
+
+ char characters[3];
+ sprintf(characters, "%02X", value);
+
+ auto writeOffset = byteOffset;
+ _string[writeOffset++] = characters[0];
+ _string[writeOffset] = characters[1];
+}
+
+} // namespace src
+} // namespace pels
+} // namespace openpower
diff --git a/extensions/openpower-pels/ascii_string.hpp b/extensions/openpower-pels/ascii_string.hpp
new file mode 100644
index 0000000..d3ede0f
--- /dev/null
+++ b/extensions/openpower-pels/ascii_string.hpp
@@ -0,0 +1,103 @@
+#pragma once
+
+#include "registry.hpp"
+#include "stream.hpp"
+
+#include <string>
+
+namespace openpower
+{
+namespace pels
+{
+namespace src
+{
+
+const size_t asciiStringSize = 32;
+
+/**
+ * @class AsciiString
+ *
+ * This represents the ASCII string field in the SRC PEL section.
+ * This 32 character string shows up on the panel on a function 11.
+ *
+ * The first 2 characters are the SRC type, like 'BD' or '11'.
+ * Next is the subsystem, like '8D', if a BD SRC, otherwise '00'.
+ * Next is the reason code, like 'AAAA'.
+ * The rest is filled in with spaces.
+ */
+class AsciiString
+{
+ public:
+ AsciiString() = delete;
+ ~AsciiString() = default;
+ AsciiString(const AsciiString&) = default;
+ AsciiString& operator=(const AsciiString&) = default;
+ AsciiString(AsciiString&&) = default;
+ AsciiString& operator=(AsciiString&&) = default;
+
+ /**
+ * @brief Constructor
+ *
+ * Fills in this class's data fields from the stream.
+ *
+ * @param[in] pel - the PEL data stream
+ */
+ explicit AsciiString(Stream& stream);
+
+ /**
+ * @brief Constructor
+ *
+ * Fills in the class from the registry entry
+ */
+ explicit AsciiString(const message::Entry& entry);
+
+ /**
+ * @brief Flatten the object into the stream
+ *
+ * @param[in] stream - The stream to write to
+ */
+ void flatten(Stream& stream);
+
+ /**
+ * @brief Fills in the object from the stream data
+ *
+ * @param[in] stream - The stream to read from
+ */
+ void unflatten(Stream& stream);
+
+ /**
+ * @brief Return the 32 character ASCII string data
+ *
+ * @return std::string - The data
+ */
+ std::string get() const;
+
+ private:
+ /**
+ * @brief Converts a byte of raw data to 2 characters
+ * and writes it to the offset.
+ *
+ * For example, if string is: "AABBCCDD"
+ *
+ * setByte(0, 0x11);
+ * setByte(1, 0x22);
+ * setByte(2, 0x33);
+ * setByte(3, 0x44);
+ *
+ * results in "11223344"
+ *
+ * @param[in] offset - The offset into the ascii string
+ * @param[in] value - The value to write (0x55 -> "55")
+ */
+ void setByte(size_t offset, uint8_t value);
+
+ /**
+ * @brief The ASCII string itself
+ */
+ std::array<char, asciiStringSize> _string;
+};
+
+} // namespace src
+
+} // namespace pels
+} // namespace openpower
diff --git a/extensions/openpower-pels/openpower-pels.mk b/extensions/openpower-pels/openpower-pels.mk
index c74f205..07d7522 100644
--- a/extensions/openpower-pels/openpower-pels.mk
+++ b/extensions/openpower-pels/openpower-pels.mk
@@ -1,4 +1,5 @@
phosphor_log_manager_SOURCES += \
+ extensions/openpower-pels/ascii_string.cpp \
extensions/openpower-pels/bcd_time.cpp \
extensions/openpower-pels/data_interface.cpp \
extensions/openpower-pels/entry_points.cpp \
diff --git a/test/openpower-pels/Makefile.include b/test/openpower-pels/Makefile.include
index b6b49aa..d9a6375 100644
--- a/test/openpower-pels/Makefile.include
+++ b/test/openpower-pels/Makefile.include
@@ -2,6 +2,7 @@ TESTS += $(check_PROGRAMS)
check_PROGRAMS += \
additional_data_test \
+ ascii_string_test \
bcd_time_test \
failing_mtms_test \
generic_section_test \
@@ -190,3 +191,11 @@ user_data_test_LDADD = \
$(test_ldadd) \
$(top_builddir)/extensions/openpower-pels/user_data.o
user_data_test_LDFLAGS = $(test_ldflags)
+
+ascii_string_test_SOURCES = %reldir%/ascii_string_test.cpp
+ascii_string_test_CPPFLAGS = $(test_cppflags)
+ascii_string_test_CXXFLAGS = $(test_cxxflags)
+ascii_string_test_LDADD = \
+ $(test_ldadd) \
+ $(top_builddir)/extensions/openpower-pels/ascii_string.o
+ascii_string_test_LDFLAGS = $(test_ldflags)
diff --git a/test/openpower-pels/ascii_string_test.cpp b/test/openpower-pels/ascii_string_test.cpp
new file mode 100644
index 0000000..022620d
--- /dev/null
+++ b/test/openpower-pels/ascii_string_test.cpp
@@ -0,0 +1,71 @@
+#include "extensions/openpower-pels/ascii_string.hpp"
+#include "extensions/openpower-pels/registry.hpp"
+
+#include <gtest/gtest.h>
+
+using namespace openpower::pels;
+
+TEST(AsciiStringTest, AsciiStringTest)
+{
+ // Build the ASCII string from a message registry entry
+ message::Entry entry;
+ entry.src.type = 0xBD;
+ entry.src.reasonCode = 0xABCD;
+ entry.subsystem = 0x37;
+
+ src::AsciiString as{entry};
+
+ auto data = as.get();
+
+ EXPECT_EQ(data, "BD37ABCD ");
+
+ // Now flatten it
+ std::vector<uint8_t> flattenedData;
+ Stream stream{flattenedData};
+
+ as.flatten(stream);
+
+ for (size_t i = 0; i < 32; i++)
+ {
+ EXPECT_EQ(data[i], flattenedData[i]);
+ }
+}
+
+// A 0x11 power SRC doesn't have the subsystem in it
+TEST(AsciiStringTest, PowerErrorTest)
+{
+ message::Entry entry;
+ entry.src.type = 0x11;
+ entry.src.reasonCode = 0xABCD;
+ entry.subsystem = 0x37;
+
+ src::AsciiString as{entry};
+ auto data = as.get();
+
+ EXPECT_EQ(data, "1100ABCD ");
+}
+
+TEST(AsciiStringTest, UnflattenTest)
+{
+ std::vector<uint8_t> rawData{'B', 'D', '5', '6', '1', '2', 'A', 'B'};
+
+ for (int i = 8; i < 32; i++)
+ {
+ rawData.push_back(' ');
+ }
+
+ Stream stream{rawData};
+ src::AsciiString as{stream};
+
+ auto data = as.get();
+
+ EXPECT_EQ(data, "BD5612AB ");
+}
+
+TEST(AsciiStringTest, UnderflowTest)
+{
+ std::vector<uint8_t> rawData{'B', 'D', '5', '6'};
+ Stream stream{rawData};
+
+ EXPECT_THROW(src::AsciiString as{stream}, std::out_of_range);
+}
OpenPOWER on IntegriCloud