summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaghathiswari Rankappagounder Natarajan <jaghu@google.com>2019-02-12 13:22:55 -0800
committerJaghathiswari Rankappagounder Natarajan <jaghu@google.com>2019-02-15 21:48:56 +0000
commit9c11894eb919034fb7841520aea3f476783a85c6 (patch)
tree7d3b244ea082418317608fad7877de59bb549bb1
parent0780df105bdd00184de29f48e9946bebfc5b5fb2 (diff)
downloadphosphor-host-ipmid-9c11894eb919034fb7841520aea3f476783a85c6.tar.gz
phosphor-host-ipmid-9c11894eb919034fb7841520aea3f476783a85c6.zip
Add support for Entity Association Record
Adding support for Entity Association Record (SDR type - 0x08h) This patch includes: 1) Entity Association Record yaml file example 2) Entity Assocation Record related script and mako file changes 3) Adding Entity Association Record in get_sdr IPMI command response From the host, tested that entity association records can be fetched Change-Id: I9cf598e5d27d2e8c6751bbaae2176e7c976974b1 Tested: Yes Signed-off-by: Jaghathiswari Rankappagounder Natarajan <jaghu@google.com>
-rw-r--r--Makefile.am6
-rw-r--r--configure.ac4
-rwxr-xr-xscripts/entity-example.yaml127
-rwxr-xr-xscripts/entity_gen.py60
-rw-r--r--scripts/writeentity.mako.cpp34
-rw-r--r--sensorhandler.cpp94
-rw-r--r--sensorhandler.hpp54
-rw-r--r--types.hpp15
8 files changed, 387 insertions, 7 deletions
diff --git a/Makefile.am b/Makefile.am
index 9bf6d4e..20af6ed 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -20,7 +20,8 @@ nodist_ipmid_SOURCES = ipmiwhitelist.cpp
libipmi20_BUILT_LIST = \
sensor-gen.cpp \
inventory-sensor-gen.cpp \
- fru-read-gen.cpp
+ fru-read-gen.cpp \
+ entity-gen.cpp
BUILT_SOURCES = \
ipmiwhitelist.cpp \
@@ -70,6 +71,9 @@ inventory-sensor-gen.cpp:
fru-read-gen.cpp:
$(AM_V_GEN)@FRUGEN@ -o $(top_builddir) generate-cpp
+entity-gen.cpp:
+ $(AM_V_GEN)@ENTITYGEN@ -o $(top_builddir) generate-cpp
+
providers_LTLIBRARIES += libipmi20.la
libipmi20_la_SOURCES = \
app/channel.cpp \
diff --git a/configure.ac b/configure.ac
index 8ad85f2..471a7be 100644
--- a/configure.ac
+++ b/configure.ac
@@ -97,6 +97,10 @@ AS_IF([test "x$FRU_YAML_GEN" == "x"], [FRU_YAML_GEN="fru-read-example.yaml"])
FRUGEN="$PYTHON $srcdir/scripts/fru_gen.py -i $FRU_YAML_GEN"
AC_SUBST(FRUGEN)
+AS_IF([test "x$ENTITY_YAML_GEN" == "x"], [ENTITY_YAML_GEN="entity-example.yaml"])
+ENTITYGEN="$PYTHON $srcdir/scripts/entity_gen.py -i $ENTITY_YAML_GEN"
+AC_SUBST(ENTITYGEN)
+
AC_DEFINE(CALLOUT_FWD_ASSOCIATION, "callout", [The name of the callout's forward association.])
AC_DEFINE(BOARD_SENSOR, "/xyz/openbmc_project/inventory/system/chassis/motherboard", [The inventory path to the motherboard fault sensor.])
AC_DEFINE(SYSTEM_SENSOR, "/xyz/openbmc_project/inventory/system", [The inventory path to the system event sensor.])
diff --git a/scripts/entity-example.yaml b/scripts/entity-example.yaml
new file mode 100755
index 0000000..2db14cc
--- /dev/null
+++ b/scripts/entity-example.yaml
@@ -0,0 +1,127 @@
+# This record has:
+# Container Entity Id and Container Entity Instance = (0x13, 0x81)
+# Contained Entity Id and Contained Entity Instance = (0x0A, 0x1),
+# (0x0A, 0x3), (0x0A, 0x5), (0x0A, 0x7)
+# Entity Record id is the key
+0x01:
+ # Container entity contains other entities
+ # Entity Id and entity Instance for the container entity
+ containerEntityId: 0x13
+ containerEntityInstance: 0x81
+ # A record can have contained entities as a four entry list or as upto
+ # two ranges of entity instances; this record has contained entities
+ # as a four entry list
+ isList: "true"
+ # Records can be linked if necessary to extend the number of contained
+ # entities within a container entity; this record is not linked
+ isLinked: "false"
+ entityId1: 0x0A
+ entityInstance1: 0x1
+ entityId2: 0x0A
+ entityInstance2: 0x3
+ entityId3: 0x0A
+ entityInstance3: 0x5
+ entityId4: 0x0A
+ entityInstance4: 0x7
+
+# The below two records have:
+# Container Entity Id and Container Entity Instance = (0x18, 0x2)
+# Contained Entity Id and Contained Entity Instance = (0x1D, 0x1),
+# (0x1D, 0x4), (0x1D, 0x6), (0x2B, 0x1), (0x2B, 0x3), (0x0F, 0x1),
+# (0x0F, 0x3), (0x10, 0x5)
+0x02:
+ containerEntityId: 0x18
+ containerEntityInstance: 0x2
+ # This record has contained entities as a four entry list
+ isList: "true"
+ # This record is linked with the below record; this record and the
+ # below record have the same container entity Id and container entity
+ # instance;
+ isLinked: "true"
+ entityId1: 0x1D
+ entityInstance1: 0x1
+ entityId2: 0x1D
+ entityInstance2: 0x4
+ entityId3: 0x1D
+ entityInstance3: 0x6
+ entityId4: 0x2B
+ entityInstance4: 0x1
+
+0x03:
+ containerEntityId: 0x18
+ containerEntityInstance: 0x2
+ # This record has contained entities as a four entry list
+ isList: "true"
+ # This record is linked with the above record; this record and the
+ # above record have the same container entity Id and container entity
+ # instance
+ isLinked: "true"
+ entityId1: 0x2B
+ entityInstance1: 0x3
+ entityId2: 0x0F
+ entityInstance2: 0x1
+ entityId3: 0x0F
+ entityInstance3: 0x3
+ entityId4: 0x10
+ entityInstance4: 0x5
+
+# This record has:
+# Container Entity Id and Container Entity Instance = (0x1E, 0x1)
+# Contained Entity Id and Contained Entity Instance = (0x20, 0x1),
+# (0x20, 0x2), (0x20, 0x3), (0x20, 0x7), (0x20, 0x8), (0x20, 0x9)
+0x04:
+ containerEntityId: 0x1E
+ containerEntityInstance: 0x1
+ # This record has contained entities as two ranges of entity instances
+ isList: "false"
+ # This record is not linked
+ isLinked: "false"
+ entityId1: 0x20
+ entityInstance1: 0x1
+ entityId2: 0x20
+ entityInstance2: 0x3
+ entityId3: 0x20
+ entityInstance3: 0x7
+ entityId4: 0x20
+ entityInstance4: 0x9
+
+# The below two records have:
+# Container Entity Id and Container Entity Instance = (0x1E, 0x3)
+# Contained Entity Id and Contained Entity Instance = (0x20, 0x1),
+# (0x20, 0x2), (0x20, 0x3), (0x20, 0x6), (0x20, 0x7), (0x20, 0x8),
+# (0x20, 0xA), (0x20, 0xB), (0x20, 0xD), (0x20, 0xE), (0x20, 0xF)
+0x05:
+ containerEntityId: 0x1E
+ containerEntityInstance: 0x03
+ # This record has contained entities as two ranges of entity instances
+ isList: "false"
+ # This record is linked with the below record; this record and the
+ # below record have the same container entity Id and container entity
+ # instance;
+ isLinked: "true"
+ entityId1: 0x20
+ entityInstance1: 0x1
+ entityId2: 0x20
+ entityInstance2: 0x3
+ entityId3: 0x20
+ entityInstance3: 0x6
+ entityId4: 0x20
+ entityInstance4: 0x8
+
+0x06:
+ containerEntityId: 0x1E
+ containerEntityInstance: 0x03
+ # This record has contained entities as two ranges of entity instances
+ isList: "false"
+ # This record is linked with the above record; this record and the
+ # above record have the same container entity Id and container entity
+ # instance;
+ isLinked: "true"
+ entityId1: 0x20
+ entityInstance1: 0xA
+ entityId2: 0x20
+ entityInstance2: 0xB
+ entityId3: 0x20
+ entityInstance3: 0xD
+ entityId4: 0x20
+ entityInstance4: 0xF
diff --git a/scripts/entity_gen.py b/scripts/entity_gen.py
new file mode 100755
index 0000000..057821b
--- /dev/null
+++ b/scripts/entity_gen.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+
+import os
+import sys
+import yaml
+import argparse
+from mako.template import Template
+
+
+def generate_cpp(entity_yaml, output_dir):
+ with open(os.path.join(script_dir, entity_yaml), 'r') as f:
+ ifile = yaml.safe_load(f)
+ if not isinstance(ifile, dict):
+ ifile = {}
+
+ # Render the mako template
+
+ t = Template(filename=os.path.join(
+ script_dir,
+ "writeentity.mako.cpp"))
+
+ output_cpp = os.path.join(output_dir, "entity-gen.cpp")
+ with open(output_cpp, 'w') as fd:
+ fd.write(t.render(entityDict=ifile))
+
+
+def main():
+
+ valid_commands = {
+ 'generate-cpp': generate_cpp
+ }
+ parser = argparse.ArgumentParser(
+ description="IPMI Entity record parser and code generator")
+
+ parser.add_argument(
+ '-i', '--entity_yaml', dest='entity_yaml',
+ default='example.yaml', help='input entity yaml file to parse')
+
+ parser.add_argument(
+ "-o", "--output-dir", dest="outputdir",
+ default=".",
+ help="output directory")
+
+ parser.add_argument(
+ 'command', metavar='COMMAND', type=str,
+ choices=valid_commands.keys(),
+ help='Command to run.')
+
+ args = parser.parse_args()
+
+ if (not (os.path.isfile(os.path.join(script_dir, args.entity_yaml)))):
+ sys.exit("Can not find input yaml file " + args.entity_yaml)
+
+ function = valid_commands[args.command]
+ function(args.entity_yaml, args.outputdir)
+
+
+if __name__ == '__main__':
+ script_dir = os.path.dirname(os.path.realpath(__file__))
+ main()
diff --git a/scripts/writeentity.mako.cpp b/scripts/writeentity.mako.cpp
new file mode 100644
index 0000000..9de11a0
--- /dev/null
+++ b/scripts/writeentity.mako.cpp
@@ -0,0 +1,34 @@
+## This file is a template. The comment below is emitted
+## into the rendered file; feel free to edit this file.
+// !!! WARNING: This is a GENERATED Code..Please do NOT Edit !!!
+
+#include "types.hpp"
+using namespace ipmi::sensor;
+
+extern const EntityInfoMap entities = {
+% for key in entityDict.iterkeys():
+{${key},{
+<%
+ entity = entityDict[key]
+ containerEntityId = entity["containerEntityId"]
+ containerEntityInstance = entity["containerEntityInstance"]
+ isList = entity["isList"]
+ isLinked = entity["isLinked"]
+ entityId1 = entity["entityId1"]
+ entityInstance1 = entity["entityInstance1"]
+ entityId2 = entity["entityId2"]
+ entityInstance2 = entity["entityInstance2"]
+ entityId3 = entity["entityId3"]
+ entityInstance3 = entity["entityInstance3"]
+ entityId4 = entity["entityId4"]
+ entityInstance4 = entity["entityInstance4"]
+%>
+ ${containerEntityId},${containerEntityInstance},${isList},${isLinked},{
+ std::make_pair(${entityId1}, ${entityInstance1}),
+ std::make_pair(${entityId2}, ${entityInstance2}),
+ std::make_pair(${entityId3}, ${entityInstance3}),
+ std::make_pair(${entityId4}, ${entityInstance4}) }
+
+}},
+% endfor
+};
diff --git a/sensorhandler.cpp b/sensorhandler.cpp
index 40c0d3e..9d0364d 100644
--- a/sensorhandler.cpp
+++ b/sensorhandler.cpp
@@ -27,6 +27,7 @@ extern int updateSensorRecordFromSSRAESC(const void*);
extern sd_bus* bus;
extern const ipmi::sensor::IdInfoMap sensors;
extern const FruMap frus;
+extern const ipmi::sensor::EntityInfoMap entities;
using namespace phosphor::logging;
using InternalFailure =
@@ -575,7 +576,7 @@ ipmi_ret_t ipmi_sen_get_sdr_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
get_sdr_info::request::get_count(request) == false)
{
// Get Sensor Count
- resp->count = sensors.size() + frus.size();
+ resp->count = sensors.size() + frus.size() + entities.size();
}
else
{
@@ -748,13 +749,87 @@ ipmi_ret_t ipmi_fru_get_sdr(ipmi_request_t request, ipmi_response_t response,
if (++fru == frus.end())
{
+ // we have reached till end of fru, so assign the next record id to
+ // 512(Max fru ID = 511) + Entity Record ID(may start with 0).
+ auto next_record_id =
+ (entities.size()) ? entities.begin()->first + ENTITY_RECORD_ID_START
+ : END_OF_RECORD;
+ get_sdr::response::set_next_record_id(next_record_id, resp);
+ }
+ else
+ {
+ get_sdr::response::set_next_record_id(
+ (FRU_RECORD_ID_START + fru->first), resp);
+ }
+
+ // Check for invalid offset size
+ if (req->offset > sizeof(record))
+ {
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+ }
+
+ dataLength = std::min(static_cast<size_t>(req->bytes_to_read),
+ sizeof(record) - req->offset);
+
+ std::memcpy(resp->record_data,
+ reinterpret_cast<uint8_t*>(&record) + req->offset, dataLength);
+
+ *data_len = dataLength;
+ *data_len += 2; // additional 2 bytes for next record ID
+
+ return IPMI_CC_OK;
+}
+
+ipmi_ret_t ipmi_entity_get_sdr(ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len)
+{
+ auto req = reinterpret_cast<get_sdr::GetSdrReq*>(request);
+ auto resp = reinterpret_cast<get_sdr::GetSdrResp*>(response);
+ get_sdr::SensorDataEntityRecord record{};
+ auto dataLength = 0;
+
+ auto entity = entities.begin();
+ uint8_t entityRecordID;
+ auto recordID = get_sdr::request::get_record_id(req);
+
+ entityRecordID = recordID - ENTITY_RECORD_ID_START;
+ entity = entities.find(entityRecordID);
+ if (entity == entities.end())
+ {
+ return IPMI_CC_SENSOR_INVALID;
+ }
+
+ /* Header */
+ get_sdr::header::set_record_id(recordID, &(record.header));
+ record.header.sdr_version = SDR_VERSION; // Based on IPMI Spec v2.0 rev 1.1
+ record.header.record_type = get_sdr::SENSOR_DATA_ENTITY_RECORD;
+ record.header.record_length = sizeof(record.key) + sizeof(record.body);
+
+ /* Key */
+ record.key.containerEntityId = entity->second.containerEntityId;
+ record.key.containerEntityInstance = entity->second.containerEntityInstance;
+ get_sdr::key::set_flags(entity->second.isList, entity->second.isLinked,
+ &(record.key));
+ record.key.entityId1 = entity->second.containedEntities[0].first;
+ record.key.entityInstance1 = entity->second.containedEntities[0].second;
+
+ /* Body */
+ record.body.entityId2 = entity->second.containedEntities[1].first;
+ record.body.entityInstance2 = entity->second.containedEntities[1].second;
+ record.body.entityId3 = entity->second.containedEntities[2].first;
+ record.body.entityInstance3 = entity->second.containedEntities[2].second;
+ record.body.entityId4 = entity->second.containedEntities[3].first;
+ record.body.entityInstance4 = entity->second.containedEntities[3].second;
+
+ if (++entity == entities.end())
+ {
get_sdr::response::set_next_record_id(END_OF_RECORD,
resp); // last record
}
else
{
get_sdr::response::set_next_record_id(
- (FRU_RECORD_ID_START + fru->first), resp);
+ (ENTITY_RECORD_ID_START + entity->first), resp);
}
// Check for invalid offset size
@@ -793,10 +868,17 @@ ipmi_ret_t ipmi_sen_get_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
// At the beginning of a scan, the host side will send us id=0.
if (recordID != 0)
{
- // recordID greater then 255,it means it is a FRU record.
- // Currently we are supporting two record types either FULL record
- // or FRU record.
- if (recordID >= FRU_RECORD_ID_START)
+ // recordID 0 to 255 means it is a FULL record.
+ // recordID 256 to 511 means it is a FRU record.
+ // recordID greater then 511 means it is a Entity Association
+ // record. Currently we are supporting three record types: FULL
+ // record, FRU record and Enttiy Association record.
+ if (recordID >= ENTITY_RECORD_ID_START)
+ {
+ return ipmi_entity_get_sdr(request, response, data_len);
+ }
+ else if (recordID >= FRU_RECORD_ID_START &&
+ recordID < ENTITY_RECORD_ID_START)
{
return ipmi_fru_get_sdr(request, response, data_len);
}
diff --git a/sensorhandler.hpp b/sensorhandler.hpp
index 0338597..8fcf2b1 100644
--- a/sensorhandler.hpp
+++ b/sensorhandler.hpp
@@ -86,6 +86,7 @@ ipmi_ret_t ipmi_sen_reserve_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
ipmi_context_t context);
static const uint16_t FRU_RECORD_ID_START = 256;
+static const uint16_t ENTITY_RECORD_ID_START = 512;
static const uint8_t SDR_VERSION = 0x51;
static const uint16_t END_OF_RECORD = 0xFFFF;
static const uint8_t LENGTH_MASK = 0x1F;
@@ -210,6 +211,7 @@ enum SensorDataRecordType
{
SENSOR_DATA_FULL_RECORD = 0x1,
SENSOR_DATA_FRU_RECORD = 0x11,
+ SENSOR_DATA_ENTITY_RECORD = 0x8,
};
// Record key
@@ -232,9 +234,25 @@ struct SensorDataFruRecordKey
uint8_t channelNumber;
} __attribute__((packed));
+/** @struct SensorDataEntityRecordKey
+ *
+ * Entity Association Record(key) - SDR Type 8
+ */
+struct SensorDataEntityRecordKey
+{
+ uint8_t containerEntityId;
+ uint8_t containerEntityInstance;
+ uint8_t flags;
+ uint8_t entityId1;
+ uint8_t entityInstance1;
+} __attribute__((packed));
+
namespace key
{
+static constexpr uint8_t listOrRangeBit = 7;
+static constexpr uint8_t linkedBit = 6;
+
inline void set_owner_id_ipmb(SensorDataRecordKey* key)
{
key->owner_id &= ~0x01;
@@ -268,6 +286,17 @@ inline void set_owner_lun_channel(uint8_t channel, SensorDataRecordKey* key)
key->owner_lun |= ((channel & 0xf) << 4);
};
+inline void set_flags(bool isList, bool isLinked,
+ SensorDataEntityRecordKey* key)
+{
+ key->flags = 0x00;
+ if (!isList)
+ key->flags |= 1 << listOrRangeBit;
+
+ if (isLinked)
+ key->flags |= 1 << linkedBit;
+};
+
} // namespace key
/** @struct GetSensorThresholdsResponse
@@ -347,6 +376,20 @@ struct SensorDataFruRecordBody
char deviceID[FRU_RECORD_DEVICE_ID_MAX_LENGTH];
} __attribute__((packed));
+/** @struct SensorDataEntityRecordBody
+ *
+ * Entity Association Record(body) - SDR Type 8
+ */
+struct SensorDataEntityRecordBody
+{
+ uint8_t entityId2;
+ uint8_t entityInstance2;
+ uint8_t entityId3;
+ uint8_t entityInstance3;
+ uint8_t entityId4;
+ uint8_t entityInstance4;
+} __attribute__((packed));
+
namespace body
{
@@ -594,6 +637,17 @@ struct SensorDataFruRecord
SensorDataFruRecordBody body;
} __attribute__((packed));
+/** @struct SensorDataEntityRecord
+ *
+ * Entity Association Record - SDR Type 8
+ */
+struct SensorDataEntityRecord
+{
+ SensorDataRecordHeader header;
+ SensorDataEntityRecordKey key;
+ SensorDataEntityRecordBody body;
+} __attribute__((packed));
+
} // namespace get_sdr
namespace ipmi
diff --git a/types.hpp b/types.hpp
index 70f397c..57c5873 100644
--- a/types.hpp
+++ b/types.hpp
@@ -196,6 +196,21 @@ enum class ThresholdMask
CRITICAL_HIGH_MASK = 0x10,
};
+static constexpr uint8_t maxContainedEntities = 4;
+using ContainedEntitiesArray =
+ std::array<std::pair<uint8_t, uint8_t>, maxContainedEntities>;
+
+struct EntityInfo
+{
+ uint8_t containerEntityId;
+ uint8_t containerEntityInstance;
+ bool isList;
+ bool isLinked;
+ ContainedEntitiesArray containedEntities;
+};
+
+using EntityInfoMap = std::map<Id, EntityInfo>;
+
} // namespace sensor
namespace network
OpenPOWER on IntegriCloud