From e0cc8553ece4bf0c0db740b4b81bac2c6c46a708 Mon Sep 17 00:00:00 2001 From: Ratan Gupta Date: Mon, 22 Jan 2018 14:23:04 +0530 Subject: 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 --- ipmid.cpp | 11 ++--- sensorhandler.cpp | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++--- sensorhandler.h | 75 +++++++++++++++++++++++++++++-- 3 files changed, 201 insertions(+), 14 deletions(-) diff --git a/ipmid.cpp b/ipmid.cpp index f06adc5..a05992b 100644 --- a/ipmid.cpp +++ b/ipmid.cpp @@ -380,10 +380,11 @@ static int handle_ipmi_command(sd_bus_message *m, void *user_data, sd_bus_error if(r != 0) { fprintf(stderr,"ERROR:[0x%X] handling NetFn:[0x%X], Cmd:[0x%X]\n",r, netfn, cmd); - - if(r < 0) { - response[0] = IPMI_CC_UNSPECIFIED_ERROR; - } + resplen = 0; + } + else + { + resplen = resplen - 1; // first byte is for return code. } fprintf(ipmiio, "IPMI Response:\n"); @@ -391,7 +392,7 @@ static int handle_ipmi_command(sd_bus_message *m, void *user_data, sd_bus_error // Send the response buffer from the ipmi command r = send_ipmi_message(m, sequence, netfn, lun, cmd, response[0], - ((unsigned char *)response) + 1, resplen - 1); + ((unsigned char *)response) + 1, resplen); if (r < 0) { fprintf(stderr, "Failed to send the response message\n"); return -1; 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 #include +#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 @@ 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(); + resp->count = sensors.size() + frus.size(); } else { @@ -1009,6 +1017,97 @@ ipmi_ret_t populate_record_from_dbus(get_sdr::SensorDataFullRecordBody *body, 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(request); + auto resp = reinterpret_cast(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(&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 @@ ipmi_ret_t ipmi_sen_get_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd, // 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 @@ ipmi_ret_t ipmi_sen_get_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 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 { diff --git a/sensorhandler.h b/sensorhandler.h index 1cf43ca..e32405d 100644 --- a/sensorhandler.h +++ b/sensorhandler.h @@ -16,6 +16,16 @@ enum ipmi_netfn_sen_cmds IPMI_CMD_GET_SENSOR_THRESHOLDS = 0x27, }; +/** + * @enum device_type + * IPMI FRU device types + */ +enum device_type +{ + IPMI_PHYSICAL_FRU = 0x00, + IPMI_LOGICAL_FRU = 0x80, +}; + // Discrete sensor types. enum ipmi_sensor_types { @@ -40,6 +50,11 @@ int set_sensor_dbus_state_s(uint8_t , const char *, const char *); int set_sensor_dbus_state_y(uint8_t , const char *, const uint8_t); int find_openbmc_path(uint8_t , dbus_interface_t *); +static const uint16_t FRU_RECORD_ID_START = 256; +static const uint8_t SDR_VERSION = 0x51; +static const uint16_t END_OF_RECORD = 0xFFFF; +static const uint8_t LENGTH_MASK = 0x1F; + /** * Get SDR Info */ @@ -109,7 +124,7 @@ inline uint8_t get_reservation_id(GetSdrReq* req) return (req->reservation_id_lsb + (req->reservation_id_msb << 8)); }; -inline uint8_t get_record_id(GetSdrReq* req) +inline uint16_t get_record_id(GetSdrReq* req) { return (req->record_id_lsb + (req->record_id_msb << 8)); }; @@ -127,7 +142,7 @@ struct GetSdrResp namespace response { -inline void set_next_record_id(int next, GetSdrResp* resp) +inline void set_next_record_id(uint16_t next, GetSdrResp* resp) { resp->next_record_id_lsb = next & 0xff; resp->next_record_id_msb = (next >> 8) & 0xff; @@ -158,7 +173,8 @@ inline void set_record_id(int id, SensorDataRecordHeader* hdr) enum SensorDataRecordType { - SENSOR_DATA_FULL_RECORD = 1, + SENSOR_DATA_FULL_RECORD = 0x1, + SENSOR_DATA_FRU_RECORD = 0x11, }; // Record key @@ -169,6 +185,18 @@ struct SensorDataRecordKey uint8_t sensor_number; } __attribute__((packed)); +/** @struct SensorDataFruRecordKey + * + * FRU Device Locator Record(key) - SDR Type 11 + */ +struct SensorDataFruRecordKey +{ + uint8_t deviceAddress; + uint8_t fruID; + uint8_t accessLun; + uint8_t channelNumber; +} __attribute__((packed)); + namespace key { @@ -219,6 +247,9 @@ struct GetSensorThresholdsResponse // Body - full record #define FULL_RECORD_ID_STR_MAX_LENGTH 16 + +static const int FRU_RECORD_DEVICE_ID_MAX_LENGTH = 16; + struct SensorDataFullRecordBody { uint8_t entity_id; @@ -260,6 +291,22 @@ struct SensorDataFullRecordBody char id_string[FULL_RECORD_ID_STR_MAX_LENGTH]; } __attribute__((packed)); +/** @struct SensorDataFruRecordBody + * + * FRU Device Locator Record(body) - SDR Type 11 + */ +struct SensorDataFruRecordBody +{ + uint8_t reserved; + uint8_t deviceType; + uint8_t deviceTypeModifier; + uint8_t entityID; + uint8_t entityInstance; + uint8_t oem; + uint8_t deviceIDLen; + char deviceID[FRU_RECORD_DEVICE_ID_MAX_LENGTH]; +} __attribute__((packed)); + namespace body { @@ -464,6 +511,17 @@ inline void set_id_type(uint8_t type, SensorDataFullRecordBody* body) body->id_string_info |= (type & 0x3)<<6; }; +inline void set_device_id_strlen(uint8_t len, SensorDataFruRecordBody* body) +{ + body->deviceIDLen &= ~(LENGTH_MASK); + body->deviceIDLen |= len & LENGTH_MASK; +}; + +inline uint8_t get_device_id_strlen(SensorDataFruRecordBody* body) +{ + return body->deviceIDLen & LENGTH_MASK; +}; + } // namespace body // More types contained in section 43.17 Sensor Unit Type Codes, @@ -486,6 +544,17 @@ struct SensorDataFullRecord SensorDataFullRecordBody body; } __attribute__((packed)); +/** @struct SensorDataFruRecord + * + * FRU Device Locator Record - SDR Type 11 + */ +struct SensorDataFruRecord +{ + SensorDataRecordHeader header; + SensorDataFruRecordKey key; + SensorDataFruRecordBody body; +} __attribute__((packed)); + } // get_sdr namespace ipmi -- cgit v1.2.1