summaryrefslogtreecommitdiffstats
path: root/extensions/openpower-pels
diff options
context:
space:
mode:
authorMatt Spinler <spinler@us.ibm.com>2019-10-15 10:54:11 -0500
committerMatt Spinler <spinler@us.ibm.com>2019-11-04 16:14:12 -0600
commitbd716f00dbdf910da44935785611b49c8719249c (patch)
treeeb06bfc2a646a19ec02f9f82836191984eb30a6d /extensions/openpower-pels
parent55a697842f5d474877bb92afec2cd1c0e3100dbd (diff)
downloadphosphor-logging-bd716f00dbdf910da44935785611b49c8719249c.tar.gz
phosphor-logging-bd716f00dbdf910da44935785611b49c8719249c.zip
PEL: Create SRC section from message registry
This adds the ability to create an SRC PEL section based on the message registry entry for an OpenBMC event log. The event log's AdditionalData property is used as a source for the user defined data words of the SRC, while the other fields in the SRC's data words are filled in either from the message registry fields or from current system state or configuration. The ASCII string field of the SRC is filled in based on the message registry entry. This commit doesn't fill in every system status field, as many aren't even available anywhere yet. Also, this commit doesn't support adding callouts to an SRC, that will also be handled in the future. Signed-off-by: Matt Spinler <spinler@us.ibm.com> Change-Id: I67fe44e07e4eda6bdeedb4af2eacfc197deb6eb3
Diffstat (limited to 'extensions/openpower-pels')
-rw-r--r--extensions/openpower-pels/pel.cpp26
-rw-r--r--extensions/openpower-pels/pel.hpp28
-rw-r--r--extensions/openpower-pels/src.cpp85
-rw-r--r--extensions/openpower-pels/src.hpp127
4 files changed, 243 insertions, 23 deletions
diff --git a/extensions/openpower-pels/pel.cpp b/extensions/openpower-pels/pel.cpp
index eb1a368..157af5a 100644
--- a/extensions/openpower-pels/pel.cpp
+++ b/extensions/openpower-pels/pel.cpp
@@ -3,6 +3,7 @@
#include "bcd_time.hpp"
#include "log_id.hpp"
#include "section_factory.hpp"
+#include "src.hpp"
#include "stream.hpp"
#include <phosphor-logging/log.hpp>
@@ -14,15 +15,19 @@ namespace pels
namespace message = openpower::pels::message;
PEL::PEL(const message::Entry& entry, uint32_t obmcLogID, uint64_t timestamp,
- phosphor::logging::Entry::Level severity)
+ phosphor::logging::Entry::Level severity,
+ const AdditionalData& additionalData)
{
_ph = std::make_unique<PrivateHeader>(entry.componentID, obmcLogID,
timestamp);
_uh = std::make_unique<UserHeader>(entry, severity);
- // Add future sections here and update the count
+ auto src = std::make_unique<SRC>(entry, additionalData);
+ _optionalSections.push_back(std::move(src));
- _ph->sectionCount() = 2;
+ // Add future sections here
+
+ _ph->sectionCount() = 2 + _optionalSections.size();
}
PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
@@ -111,5 +116,20 @@ std::vector<uint8_t> PEL::data()
return pelData;
}
+std::optional<SRC*> PEL::primarySRC() const
+{
+ auto src = std::find_if(
+ _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
+ return section->header().id ==
+ static_cast<uint16_t>(SectionID::primarySRC);
+ });
+ if (src != _optionalSections.end())
+ {
+ return static_cast<SRC*>(src->get());
+ }
+
+ return std::nullopt;
+}
+
} // namespace pels
} // namespace openpower
diff --git a/extensions/openpower-pels/pel.hpp b/extensions/openpower-pels/pel.hpp
index 0c35e3e..9f34b62 100644
--- a/extensions/openpower-pels/pel.hpp
+++ b/extensions/openpower-pels/pel.hpp
@@ -3,6 +3,7 @@
#include "additional_data.hpp"
#include "private_header.hpp"
#include "registry.hpp"
+#include "src.hpp"
#include "user_header.hpp"
#include <memory>
@@ -31,15 +32,10 @@ namespace pels
*
* This class represents all sections with objects.
*
- * The available constructors are:
- * - PEL(std::vector<uint8_t>& data) - build this object out of a fully
- * formed flattened PEL.
- *
- * - PEL(const openpower::pels::message::Entry& entry,
- * uint32_t obmcLogID,
- * uint64_t timestamp,
- * phosphor::logging::Entry::Level severity)
- * - build this object from an OpenBMC event log.
+ * The class can be constructed:
+ * - From a full formed flattened PEL.
+ * - From scratch based on an OpenBMC event and its corresponding PEL message
+ * registry entry.
*
* The data() method allows one to retrieve the PEL as a vector<uint8_t>. This
* is the format in which it is stored and transmitted.
@@ -88,9 +84,11 @@ class PEL
* @param[in] obmcLogID - ID of corresponding OpenBMC event log
* @param[in] timestamp - Timestamp from the event log
* @param[in] severity - Severity from the event log
+ * @param[in] additionalData - The AdditionalData contents
*/
PEL(const openpower::pels::message::Entry& entry, uint32_t obmcLogID,
- uint64_t timestamp, phosphor::logging::Entry::Level severity);
+ uint64_t timestamp, phosphor::logging::Entry::Level severity,
+ const AdditionalData& additionalData);
/**
* @brief Convenience function to return the log ID field from the
@@ -168,6 +166,16 @@ class PEL
}
/**
+ * @brief Gives access to the primary SRC's section class
+ *
+ * This is technically an optional section, so the return
+ * value is an std::optional<SRC*>.
+ *
+ * @return std::optional<SRC*> - the SRC section object
+ */
+ std::optional<SRC*> primarySRC() const;
+
+ /**
* @brief Returns the optional sections, which is everything but
* the Private and User Headers.
*
diff --git a/extensions/openpower-pels/src.cpp b/extensions/openpower-pels/src.cpp
index 7fd7b0e..a79df8d 100644
--- a/extensions/openpower-pels/src.cpp
+++ b/extensions/openpower-pels/src.cpp
@@ -60,6 +60,86 @@ SRC::SRC(Stream& pel)
}
}
+SRC::SRC(const message::Entry& regEntry, const AdditionalData& additionalData)
+{
+ _header.id = static_cast<uint16_t>(SectionID::primarySRC);
+ _header.version = srcSectionVersion;
+ _header.subType = srcSectionSubtype;
+ _header.componentID = regEntry.componentID;
+
+ _version = srcVersion;
+
+ _flags = 0;
+ if (regEntry.src.powerFault.value_or(false))
+ {
+ _flags |= powerFaultEvent;
+ }
+
+ _reserved1B = 0;
+
+ _wordCount = numSRCHexDataWords + 1;
+
+ _reserved2B = 0;
+
+ // There are multiple fields encoded in the hex data words.
+ std::for_each(_hexData.begin(), _hexData.end(),
+ [](auto& word) { word = 0; });
+ setBMCFormat();
+ setBMCPosition();
+ // Partition dump status and partition boot type always 0 for BMC errors.
+ //
+ // TODO: Fill in other fields that aren't available yet.
+
+ // Fill in the last 4 words from the AdditionalData property contents.
+ setUserDefinedHexWords(regEntry, additionalData);
+
+ _asciiString = std::make_unique<src::AsciiString>(regEntry);
+
+ // TODO: add callouts using the Callouts object
+
+ _size = baseSRCSize;
+ _size += _callouts ? _callouts->flattenedSize() : 0;
+ _header.size = Section::flattenedSize() + _size;
+
+ _valid = true;
+}
+
+void SRC::setUserDefinedHexWords(const message::Entry& regEntry,
+ const AdditionalData& ad)
+{
+ if (!regEntry.src.hexwordADFields)
+ {
+ return;
+ }
+
+ // Save the AdditionalData value corresponding to the
+ // adName key in _hexData[wordNum].
+ for (const auto& [wordNum, adName] : *regEntry.src.hexwordADFields)
+ {
+ // Can only set words 6 - 9
+ if (!isUserDefinedWord(wordNum))
+ {
+ log<level::WARNING>("SRC user data word out of range",
+ entry("WORD_NUM=%d", wordNum),
+ entry("ERROR_NAME=%s", regEntry.name.c_str()));
+ continue;
+ }
+
+ auto value = ad.getValue(adName);
+ if (value)
+ {
+ _hexData[getWordIndexFromWordNum(wordNum)] =
+ std::strtoul(value.value().c_str(), nullptr, 0);
+ }
+ else
+ {
+ log<level::WARNING>("Source for user data SRC word not found",
+ entry("ADDITIONALDATA_KEY=%s", adName.c_str()),
+ entry("ERROR_NAME=%s", regEntry.name.c_str()));
+ }
+ }
+}
+
void SRC::validate()
{
bool failed = false;
@@ -73,10 +153,9 @@ void SRC::validate()
}
// Check the version in the SRC, not in the header
- if (_version != srcSectionVersion)
+ if (_version != srcVersion)
{
- log<level::ERR>("Invalid SRC section version",
- entry("VERSION=0x%X", _version));
+ log<level::ERR>("Invalid SRC version", entry("VERSION=0x%X", _version));
failed = true;
}
diff --git a/extensions/openpower-pels/src.hpp b/extensions/openpower-pels/src.hpp
index 365f12b..ab29c0b 100644
--- a/extensions/openpower-pels/src.hpp
+++ b/extensions/openpower-pels/src.hpp
@@ -4,6 +4,7 @@
#include "ascii_string.hpp"
#include "callouts.hpp"
#include "pel_types.hpp"
+#include "registry.hpp"
#include "section.hpp"
#include "stream.hpp"
@@ -12,8 +13,13 @@ namespace openpower
namespace pels
{
+constexpr uint8_t srcSectionVersion = 0x01;
+constexpr uint8_t srcSectionSubtype = 0x01;
constexpr size_t numSRCHexDataWords = 8;
-constexpr uint8_t srcSectionVersion = 0x02;
+constexpr uint8_t srcVersion = 0x02;
+constexpr uint8_t bmcSRCFormat = 0x55;
+constexpr uint8_t primaryBMCPosition = 0x10;
+constexpr size_t baseSRCSize = 72;
/**
* @class SRC
@@ -38,7 +44,8 @@ class SRC : public Section
public:
enum HeaderFlags
{
- additionalSections = 0x01
+ additionalSections = 0x01,
+ powerFaultEvent = 0x02
};
SRC() = delete;
@@ -58,6 +65,19 @@ class SRC : public Section
explicit SRC(Stream& pel);
/**
+ * @brief Constructor
+ *
+ * Creates the section with data from the PEL message registry entry for
+ * this error, along with the AdditionalData property contents from the
+ * corresponding event log.
+ *
+ * @param[in] regEntry - The message registry entry for this event log
+ * @param[in] additionalData - The AdditionalData properties in this event
+ * log
+ */
+ SRC(const message::Entry& regEntry, const AdditionalData& additionalData);
+
+ /**
* @brief Flatten the section into the stream
*
* @param[in] stream - The stream to write to
@@ -140,13 +160,15 @@ class SRC : public Section
return _callouts;
}
- private:
/**
- * @brief Fills in the object from the stream data
+ * @brief Returns the size of this section when flattened into a PEL
*
- * @param[in] stream - The stream to read from
+ * @return size_t - the size of the section
*/
- void unflatten(Stream& stream);
+ size_t flattenedSize() const
+ {
+ return _header.size;
+ }
/**
* @brief Says if this SRC has additional subsections in it
@@ -157,7 +179,98 @@ class SRC : public Section
*/
inline bool hasAdditionalSections() const
{
- return _flags & static_cast<uint8_t>(HeaderFlags::additionalSections);
+ return _flags & additionalSections;
+ }
+
+ /**
+ * @brief Indicates if this event log is for a power fault.
+ *
+ * This comes from a field in the message registry for BMC
+ * generated PELs.
+ *
+ * @return bool
+ */
+ inline bool isPowerFaultEvent() const
+ {
+ return _flags & powerFaultEvent;
+ }
+
+ private:
+ /**
+ * @brief Fills in the user defined hex words from the
+ * AdditionalData fields.
+ *
+ * When creating this section from a message registry entry,
+ * that entry has a field that says which AdditionalData property
+ * fields to use to fill in the user defined hex data words 6-9
+ * (which correspond to hexData words 4-7).
+ *
+ * For example, given that AdditionalData is a map of string keys
+ * to string values, find the AdditionalData value for AdditionalData
+ * key X, convert it to a uint32_t, and save it in user data word Y.
+ *
+ * @param[in] regEntry - The message registry entry for the error
+ * @param[in] additionalData - The AdditionalData map
+ */
+ void setUserDefinedHexWords(const message::Entry& regEntry,
+ const AdditionalData& additionalData);
+ /**
+ * @brief Fills in the object from the stream data
+ *
+ * @param[in] stream - The stream to read from
+ */
+ void unflatten(Stream& stream);
+
+ /**
+ * @brief Get the _hexData[] index to use based on the corresponding
+ * SRC word number.
+ *
+ * Converts the specification nomenclature to this data structure.
+ * See the _hexData documentation below for more information.
+ *
+ * @param[in] wordNum - The SRC word number, as defined by the spec.
+ *
+ * @return size_t The corresponding index into _hexData.
+ */
+ inline size_t getWordIndexFromWordNum(size_t wordNum) const
+ {
+ assert(wordNum >= 2 && wordNum <= 9);
+ return wordNum - 2;
+ }
+
+ /**
+ * @brief Says if the word number is in the range of user defined words.
+ *
+ * This is only used for BMC generated SRCs, where words 6 - 9 are the
+ * user defined ones, meaning that setUserDefinedHexWords() will be
+ * used to fill them in based on the contents of the OpenBMC event log.
+ *
+ * @param[in] wordNum - The SRC word number, as defined by the spec.
+ *
+ * @return bool - If this word number can be filled in by the creator.
+ */
+ inline bool isUserDefinedWord(size_t wordNum) const
+ {
+ return (wordNum >= 6) && (wordNum <= 9);
+ }
+
+ /**
+ * @brief Sets the SRC format byte in the hex word data.
+ */
+ inline void setBMCFormat()
+ {
+ _hexData[0] |= bmcSRCFormat;
+ }
+
+ /**
+ * @brief Sets the hex word field that specifies which BMC
+ * (primary vs backup) created the error.
+ *
+ * Can be hardcoded until there are systems with redundant BMCs.
+ */
+ inline void setBMCPosition()
+ {
+ _hexData[1] |= primaryBMCPosition;
}
/**
OpenPOWER on IntegriCloud