SDR: Adding fru records as part of Get SDR command
Currently Get SDR only responds with physical/virtual sensor
records,it doesn't support for FRU records,This commit adds
the support for FRU records.
Resolves openbmc/openbmc#2776
Change-Id: I34edfa892b32f4e866cf0c084d97c2f3482d40f4
Signed-off-by: Ratan Gupta <ratagupt@in.ibm.com>
diff --git a/sensorhandler.cpp b/sensorhandler.cpp
index 036eb22..1bd10b7 100644
--- a/sensorhandler.cpp
+++ b/sensorhandler.cpp
@@ -9,15 +9,23 @@
#include "host-ipmid/ipmid-api.h"
#include <phosphor-logging/log.hpp>
#include <phosphor-logging/elog-errors.hpp>
+#include "fruread.hpp"
#include "ipmid.hpp"
#include "sensorhandler.h"
#include "types.hpp"
#include "utils.hpp"
#include "xyz/openbmc_project/Common/error.hpp"
+static constexpr uint8_t fruInventoryDevice = 0x10;
+static constexpr uint8_t IPMIFruInventory = 0x02;
+static constexpr uint8_t BMCSlaveAddress = 0x20;
+
extern int updateSensorRecordFromSSRAESC(const void *);
extern sd_bus *bus;
extern const ipmi::sensor::IdInfoMap sensors;
+extern const FruMap frus;
+
+
using namespace phosphor::logging;
using InternalFailure =
sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
@@ -825,7 +833,7 @@
get_sdr_info::request::get_count(request) == false)
{
// Get Sensor Count
- resp->count = sensors.size();
+ resp->count = sensors.size() + frus.size();
}
else
{
@@ -1009,6 +1017,97 @@
return IPMI_CC_OK;
};
+ipmi_ret_t ipmi_fru_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::SensorDataFruRecord record {};
+ auto dataLength = 0;
+
+ auto fru = frus.begin();
+ uint8_t fruID {};
+ auto recordID = get_sdr::request::get_record_id(req);
+
+ fruID = recordID - FRU_RECORD_ID_START;
+ fru = frus.find(fruID);
+ if (fru == frus.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_FRU_RECORD;
+ record.header.record_length = sizeof(record.key) + sizeof(record.body);
+
+ /* Key */
+ record.key.fruID = fruID;
+ record.key.accessLun |= IPMI_LOGICAL_FRU;
+ record.key.deviceAddress = BMCSlaveAddress;
+
+ /* Body */
+ record.body.entityID = fru->second[0].entityID;
+ record.body.entityInstance = fru->second[0].entityInstance;
+ record.body.deviceType = fruInventoryDevice;
+ record.body.deviceTypeModifier = IPMIFruInventory;
+
+ /* Device ID string */
+ auto deviceID = fru->second[0].path.substr(
+ fru->second[0].path.find_last_of('/') + 1,
+ fru->second[0].path.length());
+
+
+ if (deviceID.length() > get_sdr::FRU_RECORD_DEVICE_ID_MAX_LENGTH)
+ {
+ get_sdr::body::set_device_id_strlen(
+ get_sdr::FRU_RECORD_DEVICE_ID_MAX_LENGTH,
+ &(record.body));
+ }
+ else
+ {
+ get_sdr::body::set_device_id_strlen(deviceID.length(),
+ &(record.body));
+ }
+
+ strncpy(record.body.deviceID, deviceID.c_str(),
+ get_sdr::body::get_device_id_strlen(&(record.body)));
+
+ if (++fru == frus.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);
+ }
+
+ if (req->bytes_to_read > (sizeof(*resp) - req->offset))
+ {
+ dataLength = (sizeof(*resp) - req->offset);
+ }
+ else
+ {
+ dataLength = req->bytes_to_read;
+ }
+
+ if (dataLength <= 0)
+ {
+ return IPMI_CC_REQ_DATA_LEN_INVALID;
+ }
+
+ 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_sen_get_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
ipmi_request_t request, ipmi_response_t response,
ipmi_data_len_t data_len, ipmi_context_t context)
@@ -1022,13 +1121,25 @@
// Note: we use an iterator so we can provide the next ID at the end of
// the call.
auto sensor = sensors.begin();
+ auto recordID = get_sdr::request::get_record_id(req);
// At the beginning of a scan, the host side will send us id=0.
- if (get_sdr::request::get_record_id(req) != 0)
+ if (recordID != 0)
{
- sensor = sensors.find(get_sdr::request::get_record_id(req));
- if(sensor == sensors.end()) {
- return IPMI_CC_SENSOR_INVALID;
+ // 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)
+ {
+ return ipmi_fru_get_sdr(request, response, data_len);
+ }
+ else
+ {
+ sensor = sensors.find(recordID);
+ if (sensor == sensors.end())
+ {
+ return IPMI_CC_SENSOR_INVALID;
+ }
}
}
@@ -1056,7 +1167,13 @@
if (++sensor == sensors.end())
{
- get_sdr::response::set_next_record_id(0xFFFF, resp); // last record
+ // we have reached till end of sensor, so assign the next record id
+ // to 256(Max Sensor ID = 255) + FRU ID(may start with 0).
+ auto next_record_id = (frus.size()) ?
+ frus.begin()->first + FRU_RECORD_ID_START :
+ END_OF_RECORD;
+
+ get_sdr::response::set_next_record_id(next_record_id, resp);
}
else
{