sel: Support regular SEL record
Support regular SEL record logged by phosphor-sel-logger.
Tested: Manually call IpmiSelAdd to add a SEL entry in logging, and
check the ipmi sel:
# Call IpmiSelAdd method
busctl call "xyz.openbmc_project.Logging.IPMI" "/xyz/openbmc_project/Logging/IPMI" xyz.openbmc_project.Logging.IPMI IpmiSelAdd ssaybq "Sensor message" "/xyz/openbmc_project/inventory/system/board/G220A" 3 0x01 0x02 0x03 true 0x2000
# Check SEL
$ ipmitool -C17 -I lanplus -H 127.0.0.1 -U root -P 0penBmc sel get 6
SEL Record ID : 0006
Record Type : 02
Timestamp : 01/01/1970 00:11:02
Generator ID : 2000
EvM Revision : 04
Sensor Type : System Event
Sensor Number : 90
Event Type : Sensor-specific Discrete
Event Direction : Assertion Event
Event Data : 010203
Description : OEM System boot event
Signed-off-by: Lei YU <yulei.sh@bytedance.com>
Change-Id: Ifcbc4fbe8825e9624d9e7bb2419eabf707f51254
diff --git a/selutility.cpp b/selutility.cpp
index d83aa16..9187484 100644
--- a/selutility.cpp
+++ b/selutility.cpp
@@ -21,8 +21,17 @@
{
constexpr auto systemEventRecord = 0x02;
+constexpr auto generatorID = 0x2000;
+constexpr auto eventMsgRevision = 0x04;
+constexpr auto assertEvent = 0x00;
+constexpr auto deassertEvent = 0x80;
+constexpr auto selDataSize = 3;
+constexpr auto oemCDDataSize = 9;
+constexpr auto oemEFDataSize = 13;
constexpr auto propAdditionalData = "AdditionalData";
+constexpr auto propResolved = "Resolved";
+
constexpr auto strEventDir = "EVENT_DIR";
constexpr auto strGenerateId = "GENERATOR_ID";
constexpr auto strRecordType = "RECORD_TYPE";
@@ -46,6 +55,7 @@
}
using additionalDataMap = std::map<std::string, std::string>;
+using entryDataMap = std::map<PropertyName, PropertyType>;
/** Parse the entry with format like key=val */
std::pair<std::string, std::string> parseEntry(const std::string& entry)
{
@@ -68,11 +78,11 @@
return ret;
}
-uint8_t convert(const std::string_view& str, int base = 10)
+int convert(const std::string_view& str, int base = 10)
{
int ret;
std::from_chars(str.data(), str.data() + str.size(), ret, base);
- return static_cast<uint8_t>(ret);
+ return ret;
}
// Convert the string to a vector of uint8_t, where the str is formatted as hex
@@ -83,13 +93,14 @@
ret.reserve(len);
for (size_t i = 0; i < len; ++i)
{
- ret.emplace_back(convert(str.substr(i * 2, 2), 16));
+ ret.emplace_back(
+ static_cast<uint8_t>(convert(str.substr(i * 2, 2), 16)));
}
return ret;
}
/** Construct OEM SEL record according to IPMI spec 32.2, 32.3. */
-void constructOEMSel(uint8_t recordType, std::chrono::milliseconds timestamp,
+void constructOEMSEL(uint8_t recordType, std::chrono::milliseconds timestamp,
const additionalDataMap& m, GetSELEntryResponse& record)
{
auto dataIter = m.find(strSensorData);
@@ -104,17 +115,66 @@
// The ManufactureID and OEM Defined are packed in the sensor data
// Fill the 9 bytes of Manufacture ID and oemDefined
memcpy(&record.event.oemCD.manufacturerID, sensorData.data(),
- std::min(sensorData.size(), static_cast<size_t>(9)));
+ std::min(sensorData.size(), static_cast<size_t>(oemCDDataSize)));
}
else if (recordType >= 0xE0)
{
record.event.oemEF.recordType = recordType;
// The remaining 13 bytes are the OEM Defined data
memcpy(&record.event.oemEF.oemDefined, sensorData.data(),
- std::min(sensorData.size(), static_cast<size_t>(13)));
+ std::min(sensorData.size(), static_cast<size_t>(oemEFDataSize)));
}
}
+void constructSEL(uint8_t recordType, std::chrono::milliseconds timestamp,
+ const additionalDataMap& m, const entryDataMap& entryData,
+ GetSELEntryResponse& record)
+{
+ if (recordType != systemEventRecord)
+ {
+ log<level::ERR>("Invalid recordType");
+ elog<InternalFailure>();
+ }
+
+ // Default values when there is no matched sensor
+ record.event.eventRecord.sensorType = 0;
+ record.event.eventRecord.sensorNum = 0xFF;
+ record.event.eventRecord.eventType = 0;
+
+ auto iter = m.find(strSensorPath);
+ assert(iter != m.end());
+ const auto& sensorPath = iter->second;
+ auto sensorIter = invSensors.find(sensorPath);
+
+ if (sensorIter != invSensors.end())
+ {
+ // There is a matched sensor
+ record.event.eventRecord.sensorType = sensorIter->second.sensorType;
+ record.event.eventRecord.sensorNum = sensorIter->second.sensorID;
+
+ iter = m.find(strEventDir);
+ assert(iter != m.end());
+ auto eventDir = static_cast<uint8_t>(convert(iter->second));
+ uint8_t assert = eventDir ? assertEvent : deassertEvent;
+ record.event.eventRecord.eventType =
+ assert | sensorIter->second.eventReadingType;
+ }
+ record.event.eventRecord.recordType = recordType;
+ record.event.eventRecord.timeStamp = static_cast<uint32_t>(
+ std::chrono::duration_cast<std::chrono::seconds>(timestamp).count());
+ iter = m.find(strGenerateId);
+ assert(iter != m.end());
+ record.event.eventRecord.generatorID =
+ static_cast<uint16_t>(convert(iter->second));
+ record.event.eventRecord.eventMsgRevision = eventMsgRevision;
+ iter = m.find(strSensorData);
+ assert(iter != m.end());
+ auto sensorData = convertVec(iter->second);
+ // The remaining 3 bytes are the sensor data
+ memcpy(&record.event.eventRecord.eventData1, sensorData.data(),
+ std::min(sensorData.size(), static_cast<size_t>(selDataSize)));
+}
+
GetSELEntryResponse
prepareSELEntry(const std::string& objPath,
ipmi::sensor::InvObjectIDMap::const_iterator iter)
@@ -136,7 +196,7 @@
elog<InternalFailure>();
}
- std::map<PropertyName, PropertyType> entryData;
+ entryDataMap entryData;
reply.read(entryData);
// Read Id from the log entry.
@@ -162,7 +222,9 @@
if (iter == invSensors.end())
{
// It is expected to be a custom SEL entry
- record.event.oemCD.recordID =
+ // The recordID are with the same offset between different types,
+ // so we are safe to set the recordID here
+ record.event.eventRecord.recordID =
static_cast<uint16_t>(std::get<uint32_t>(iterId->second));
iterId = entryData.find(propAdditionalData);
if (iterId == entryData.end())
@@ -172,15 +234,15 @@
}
const auto& addData = std::get<AdditionalData>(iterId->second);
auto m = parseAdditionalData(addData);
- auto recordType = convert(m[strRecordType]);
+ auto recordType = static_cast<uint8_t>(convert(m[strRecordType]));
auto isOEM = isRecordOEM(recordType);
if (isOEM)
{
- constructOEMSel(recordType, chronoTimeStamp, m, record);
+ constructOEMSEL(recordType, chronoTimeStamp, m, record);
}
else
{
- // TODO
+ constructSEL(recordType, chronoTimeStamp, m, entryData, record);
}
}
else
@@ -192,9 +254,6 @@
std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp)
.count());
- static constexpr auto generatorID = 0x2000;
- static constexpr auto eventMsgRevision = 0x04;
-
record.event.eventRecord.recordType = systemEventRecord;
record.event.eventRecord.generatorID = generatorID;
record.event.eventRecord.eventMsgRevision = eventMsgRevision;
@@ -204,7 +263,6 @@
record.event.eventRecord.eventData1 = iter->second.eventOffset;
// Read Resolved from the log entry.
- static constexpr auto propResolved = "Resolved";
auto iterResolved = entryData.find(propResolved);
if (iterResolved == entryData.end())
{
@@ -212,8 +270,6 @@
elog<InternalFailure>();
}
- static constexpr auto deassertEvent = 0x80;
-
// Evaluate if the event is assertion or deassertion event
if (std::get<bool>(iterResolved->second))
{