summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmily Shaffer <emilyshaffer@google.com>2017-05-08 16:36:17 -0700
committerPatrick Williams <patrick@stwcx.xyz>2017-07-17 15:06:04 -0500
commitbbef71c2a9aab57a826b4c7ec8f183e92eb6e28c (patch)
treeb67f0a7b24b5f93d488d7874bb9d4912add4579e
parenta344afc0da58007a5290c85bafd55dbea4508817 (diff)
downloadphosphor-host-ipmid-bbef71c2a9aab57a826b4c7ec8f183e92eb6e28c.tar.gz
phosphor-host-ipmid-bbef71c2a9aab57a826b4c7ec8f183e92eb6e28c.zip
sensorhandler: implement get SDR
Change-Id: I79dc59585c1f3008fc42e95a5a4792afd7268255 Signed-off-by: Emily Shaffer <emilyshaffer@google.com> Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
-rw-r--r--sensorhandler.cpp159
-rw-r--r--sensorhandler.h387
2 files changed, 544 insertions, 2 deletions
diff --git a/sensorhandler.cpp b/sensorhandler.cpp
index da6cfd9..cbf6b65 100644
--- a/sensorhandler.cpp
+++ b/sensorhandler.cpp
@@ -3,6 +3,7 @@
#include <stdio.h>
#include <string.h>
#include <bitset>
+#include <xyz/openbmc_project/Sensor/Value/server.hpp>
#include <systemd/sd-bus.h>
#include "host-ipmid/ipmid-api.h"
#include <phosphor-logging/log.hpp>
@@ -632,8 +633,8 @@ ipmi_ret_t ipmi_sen_get_sensor_reading(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
}
resp->value = raw_value * pow(10,scale);
- resp->operation = 0;
- resp->indication[0] = 0;
+ resp->operation = 1<<6; // scanning enabled
+ resp->indication[0] = 0; // not a threshold sensor. ignore
resp->indication[1] = 0;
rc = IPMI_CC_OK;
*data_len=sizeof(sensorreadingresp_t);
@@ -708,6 +709,152 @@ ipmi_ret_t ipmi_sen_reserve_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
return IPMI_CC_OK;
}
+ipmi_ret_t populate_record_from_dbus(get_sdr::SensorDataFullRecordBody *body,
+ const ipmi::sensor::Info *info,
+ ipmi_data_len_t data_len)
+{
+ /* Functional sensor case */
+ if (info->sensorInterfaces.begin()->first ==
+ "xyz.openbmc_project.Sensor.Value")
+ {
+ // Get bus
+ sd_bus *bus = ipmid_get_sd_bus_connection();
+ dbus_interface_t iface;
+
+ if (0 > find_openbmc_path(body->entity_id, &iface))
+ return IPMI_CC_SENSOR_INVALID;
+
+ body->sensor_units_1 = 0; // unsigned, no rate, no modifier, not a %
+
+ /* Unit info */
+ char *raw_cstr;
+ if (0 > sd_bus_get_property_string(bus, iface.bus, iface.path,
+ iface.interface, "Unit", NULL,
+ &raw_cstr)) {
+ fprintf(stderr, "Expected to find Unit interface in bus %s, path %s, but it was missing.\n",
+ iface.bus, iface.path);
+ return IPMI_CC_SENSOR_INVALID;
+ }
+
+ std::string raw_str(raw_cstr);
+ namespace server = sdbusplus::xyz::openbmc_project::Sensor::server;
+ server::Value::Unit unit =
+ server::Value::convertUnitFromString(raw_str);
+
+ // Unit strings defined in
+ // phosphor-dbus-interfaces/xyz/openbmc_project/Sensor/Value.interface.yaml
+ switch (unit)
+ {
+ case server::Value::Unit::DegreesC:
+ body->sensor_units_2_base = get_sdr::SENSOR_UNIT_DEGREES_C;
+ break;
+ case server::Value::Unit::RPMS:
+ body->sensor_units_2_base = get_sdr::SENSOR_UNIT_REVOLUTIONS; // revolutions
+ get_sdr::body::set_rate_unit(0b100, body); // per minute
+ break;
+ case server::Value::Unit::Volts:
+ body->sensor_units_2_base = get_sdr::SENSOR_UNIT_VOLTS;
+ break;
+ case server::Value::Unit::Meters:
+ body->sensor_units_2_base = get_sdr::SENSOR_UNIT_METERS;
+ break;
+ case server::Value::Unit::Amperes:
+ body->sensor_units_2_base = get_sdr::SENSOR_UNIT_AMPERES;
+ break;
+ case server::Value::Unit::Joules:
+ body->sensor_units_2_base = get_sdr::SENSOR_UNIT_JOULES;
+ break;
+ default:
+ fprintf(stderr, "Unknown value unit type: = %s\n", raw_cstr);
+ }
+
+ free(raw_cstr);
+
+ /* Modifiers to reading info */
+ get_sdr::body::set_b(0, body);
+ get_sdr::body::set_m(1, body);
+ body->r_b_exponents = 0;
+
+ /* ID string */
+ std::string id_string = info->sensorPath.substr(
+ info->sensorPath.find_last_of('/')+1, info->sensorPath.length());
+ get_sdr::body::set_id_type(0b00, body); // 00 = unicode
+ if (id_string.length() > FULL_RECORD_ID_STR_MAX_LENGTH)
+ {
+ get_sdr::body::set_id_strlen(FULL_RECORD_ID_STR_MAX_LENGTH, body);
+ }
+ else
+ {
+ get_sdr::body::set_id_strlen(id_string.length(), body);
+ }
+ strncpy(body->id_string, id_string.c_str(),
+ get_sdr::body::get_id_strlen(body));
+ }
+
+ 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)
+{
+ ipmi_ret_t ret = IPMI_CC_OK;
+ get_sdr::GetSdrReq *req = (get_sdr::GetSdrReq*)request;
+ get_sdr::GetSdrResp *resp = (get_sdr::GetSdrResp*)response;
+ get_sdr::SensorDataFullRecord record = {0};
+ if (req != NULL)
+ {
+ // Note: we use an iterator so we can provide the next ID at the end of
+ // the call.
+ auto sensor = sensors.begin();
+
+ // At the beginning of a scan, the host side will send us id=0.
+ if (get_sdr::request::get_record_id(req) != 0)
+ {
+ sensor = sensors.find(get_sdr::request::get_record_id(req));
+ if(sensor == sensors.end()) {
+ return IPMI_CC_SENSOR_INVALID;
+ }
+ }
+
+ uint8_t sensor_id = sensor->first;
+
+ /* Header */
+ get_sdr::header::set_record_id(sensor_id, &(record.header));
+ record.header.sdr_version = 0x51; // Based on IPMI Spec v2.0 rev 1.1
+ record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
+ record.header.record_length = sizeof(get_sdr::SensorDataFullRecord);
+
+ /* Key */
+ record.key.sensor_number = sensor_id;
+
+ /* Body */
+ record.body.entity_id = sensor_id;
+ record.body.sensor_type = sensor->second.sensorType;
+ record.body.event_reading_type = sensor->second.sensorReadingType;
+
+ // Set the type-specific details given the DBus interface
+ ret = populate_record_from_dbus(&(record.body), &(sensor->second),
+ data_len);
+
+ if (++sensor == sensors.end())
+ {
+ get_sdr::response::set_next_record_id(0xFFFF, resp); // last record
+ }
+ else
+ {
+ get_sdr::response::set_next_record_id(sensor->first, resp);
+ }
+
+ *data_len = sizeof(get_sdr::GetSdrResp) - req->offset;
+ memcpy(resp->record_data, (char*)&record + req->offset,
+ sizeof(get_sdr::SensorDataFullRecord) - req->offset);
+ }
+
+ return ret;
+}
+
+
void register_netfn_sen_functions()
{
// <Wildcard Command>
@@ -751,5 +898,13 @@ void register_netfn_sen_functions()
ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SDR_INFO,
nullptr, ipmi_sen_get_sdr_info,
PRIVILEGE_USER);
+
+ // <Get SDR>
+ printf("Registering NetFn:[0x%X], Cmd:[0x%x]\n",
+ NETFUN_SENSOR, IPMI_CMD_GET_SDR);
+ ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SDR,
+ nullptr, ipmi_sen_get_sdr,
+ PRIVILEGE_USER);
+
return;
}
diff --git a/sensorhandler.h b/sensorhandler.h
index db58c63..2b1f527 100644
--- a/sensorhandler.h
+++ b/sensorhandler.h
@@ -7,6 +7,7 @@
enum ipmi_netfn_sen_cmds
{
IPMI_CMD_GET_SDR_INFO = 0x20,
+ IPMI_CMD_GET_SDR = 0x21,
IPMI_CMD_RESERVE_SDR_REPO = 0x22,
IPMI_CMD_GET_SENSOR_READING = 0x2D,
IPMI_CMD_GET_SENSOR_TYPE = 0x2F,
@@ -99,4 +100,390 @@ struct GetSdrInfoResp
};
} // namespace get_sdr_info
+
+/**
+ * Get SDR
+ */
+namespace get_sdr
+{
+
+struct GetSdrReq
+{
+ uint8_t reservation_id_lsb;
+ uint8_t reservation_id_msb;
+ uint8_t record_id_lsb;
+ uint8_t record_id_msb;
+ uint8_t offset;
+ uint8_t bytes_to_read;
+} __attribute__((packed));
+
+namespace request
+{
+
+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)
+{
+ return (req->record_id_lsb + (req->record_id_msb << 8));
+};
+
+} // namespace request
+
+// Response
+struct GetSdrResp
+{
+ uint8_t next_record_id_lsb;
+ uint8_t next_record_id_msb;
+ uint8_t record_data[64];
+} __attribute__((packed));
+
+namespace response
+{
+
+inline void set_next_record_id(int next, GetSdrResp* resp)
+{
+ resp->next_record_id_lsb = next & 0xff;
+ resp->next_record_id_msb = (next >> 8) & 0xff;
+};
+
+} // namespace response
+
+// Record header
+struct SensorDataRecordHeader
+{
+ uint8_t record_id_lsb;
+ uint8_t record_id_msb;
+ uint8_t sdr_version;
+ uint8_t record_type;
+ uint8_t record_length; // Length not counting the header
+} __attribute__((packed));
+
+namespace header
+{
+
+inline void set_record_id(int id, SensorDataRecordHeader* hdr)
+{
+ hdr->record_id_lsb = (id & 0xFF);
+ hdr->record_id_msb = (id >> 8) & 0xFF;
+};
+
+} // namespace header
+
+enum SensorDataRecordType
+{
+ SENSOR_DATA_FULL_RECORD = 1,
+};
+
+// Record key
+struct SensorDataRecordKey
+{
+ uint8_t owner_id;
+ uint8_t owner_lun;
+ uint8_t sensor_number;
+} __attribute__((packed));
+
+namespace key
+{
+
+inline void set_owner_id_ipmb(SensorDataRecordKey* key)
+{
+ key->owner_id &= ~0x01;
+};
+
+inline void set_owner_id_system_sw(SensorDataRecordKey* key)
+{
+ key->owner_id |= 0x01;
+};
+
+inline void set_owner_id_address(uint8_t addr, SensorDataRecordKey* key)
+{
+ key->owner_id &= 0x01;
+ key->owner_id |= addr<<1;
+};
+
+inline void set_owner_lun(uint8_t lun, SensorDataRecordKey* key)
+{
+ key->owner_lun &= ~0x03;
+ key->owner_lun |= (lun&0x03);
+};
+
+inline void set_owner_lun_channel(uint8_t channel, SensorDataRecordKey* key)
+{
+ key->owner_lun &= 0x0f;
+ key->owner_lun |= ((channel & 0xf)<<4);
+};
+
+} // namespace key
+
+// Body - full record
+#define FULL_RECORD_ID_STR_MAX_LENGTH 16
+struct SensorDataFullRecordBody
+{
+ uint8_t entity_id;
+ uint8_t entity_instance;
+ uint8_t sensor_initialization;
+ uint8_t sensor_capabilities; // no macro support
+ uint8_t sensor_type;
+ uint8_t event_reading_type;
+ uint8_t supported_assertions[2]; // no macro support
+ uint8_t supported_deassertions[2]; // no macro support
+ uint8_t discrete_reading_setting_mask[2]; // no macro support
+ uint8_t sensor_units_1;
+ uint8_t sensor_units_2_base;
+ uint8_t sensor_units_3_modifier;
+ uint8_t linearization;
+ uint8_t m_lsb;
+ uint8_t m_msb_and_tolerance;
+ uint8_t b_lsb;
+ uint8_t b_msb_and_accuracy_lsb;
+ uint8_t accuracy_and_sensor_direction;
+ uint8_t r_b_exponents;
+ uint8_t analog_characteristic_flags; //no macro support
+ uint8_t nominal_reading;
+ uint8_t normal_max;
+ uint8_t normal_min;
+ uint8_t sensor_max;
+ uint8_t sensor_min;
+ uint8_t upper_nonrecoverable_threshold;
+ uint8_t upper_critical_threshold;
+ uint8_t upper_noncritical_threshold;
+ uint8_t lower_nonrecoverable_threshold;
+ uint8_t lower_critical_threshold;
+ uint8_t lower_noncritical_threshold;
+ uint8_t positive_threshold_hysteresis;
+ uint8_t negative_threshold_hysteresis;
+ uint16_t reserved;
+ uint8_t oem_reserved;
+ uint8_t id_string_info;
+ char id_string[16];
+} __attribute__((packed));
+
+namespace body
+{
+
+inline void set_entity_instance_number(uint8_t n,
+ SensorDataFullRecordBody* body)
+{
+ body->entity_instance &= 1<<7;
+ body->entity_instance |= (n & ~(1<<7));
+};
+inline void set_entity_physical_entity(SensorDataFullRecordBody* body)
+{
+ body->entity_instance &= ~(1<<7);
+};
+inline void set_entity_logical_container(SensorDataFullRecordBody* body)
+{
+ body->entity_instance |= 1<<7;
+};
+
+inline void sensor_scanning_state(bool enabled,
+ SensorDataFullRecordBody* body)
+{
+ if (enabled)
+ {
+ body->sensor_initialization |= 1<<0;
+ }
+ else
+ {
+ body->sensor_initialization &= ~(1<<0);
+ };
+};
+inline void event_generation_state(bool enabled,
+ SensorDataFullRecordBody* body)
+{
+ if (enabled)
+ {
+ body->sensor_initialization |= 1<<1;
+ }
+ else
+ {
+ body->sensor_initialization &= ~(1<<1);
+ }
+};
+inline void init_types_state(bool enabled,
+ SensorDataFullRecordBody* body)
+{
+ if (enabled)
+ {
+ body->sensor_initialization |= 1<<2;
+ }
+ else
+ {
+ body->sensor_initialization &= ~(1<<2);
+ }
+};
+inline void init_hyst_state(bool enabled,
+ SensorDataFullRecordBody* body)
+{
+ if (enabled)
+ {
+ body->sensor_initialization |= 1<<3;
+ }
+ else
+ {
+ body->sensor_initialization &= ~(1<<3);
+ }
+};
+inline void init_thresh_state(bool enabled,
+ SensorDataFullRecordBody* body)
+{
+ if (enabled)
+ {
+ body->sensor_initialization |= 1<<4;
+ }
+ else
+ {
+ body->sensor_initialization &= ~(1<<4);
+ }
+};
+inline void init_events_state(bool enabled,
+ SensorDataFullRecordBody* body)
+{
+ if (enabled)
+ {
+ body->sensor_initialization |= 1<<5;
+ }
+ else
+ {
+ body->sensor_initialization &= ~(1<<5);
+ }
+};
+inline void init_scanning_state(bool enabled,
+ SensorDataFullRecordBody* body)
+{
+ if (enabled)
+ {
+ body->sensor_initialization |= 1<<6;
+ }
+ else
+ {
+ body->sensor_initialization &= ~(1<<6);
+ }
+};
+inline void init_settable_state(bool enabled,
+ SensorDataFullRecordBody* body)
+{
+ if (enabled)
+ {
+ body->sensor_initialization |= 1<<7;
+ }
+ else
+ {
+ body->sensor_initialization &= ~(1<<7);
+ }
+};
+
+inline void set_percentage(SensorDataFullRecordBody* body)
+{
+ body->sensor_units_1 |= 1<<0;
+};
+inline void unset_percentage(SensorDataFullRecordBody* body)
+{
+ body->sensor_units_1 &= ~(1<<0);
+};
+inline void set_modifier_operation(uint8_t op, SensorDataFullRecordBody* body)
+{
+ body->sensor_units_1 &= ~(3<<1);
+ body->sensor_units_1 |= (op & 0x3)<<1;
+};
+inline void set_rate_unit(uint8_t unit, SensorDataFullRecordBody* body)
+{
+ body->sensor_units_1 &= ~(7<<3);
+ body->sensor_units_1 |= (unit & 0x7)<<3;
+};
+inline void set_analog_data_format(uint8_t format,
+ SensorDataFullRecordBody* body)
+{
+ body->sensor_units_1 &= ~(3<<6);
+ body->sensor_units_1 |= (format & 0x3)<<6;
+};
+
+inline void set_m(uint8_t m, SensorDataFullRecordBody* body)
+{
+ body->m_lsb = m & 0xff;
+ body->m_msb_and_tolerance &= ~(3<<6);
+ body->m_msb_and_tolerance |= ((m & (3<<8)) >> 2);
+};
+inline void set_tolerance(uint8_t tol, SensorDataFullRecordBody* body)
+{
+ body->m_msb_and_tolerance &= ~0x3f;
+ body->m_msb_and_tolerance |= tol & 0x3f;
+};
+
+inline void set_b(uint8_t b, SensorDataFullRecordBody* body)
+{
+ body->b_lsb = b & 0xff;
+ body->b_msb_and_accuracy_lsb &= ~(3<<6);
+ body->b_msb_and_accuracy_lsb |= ((b & (3<<8)) >> 2);
+};
+inline void set_accuracy(uint8_t acc, SensorDataFullRecordBody* body)
+{
+ body->b_msb_and_accuracy_lsb &= ~0x3f;
+ body->b_msb_and_accuracy_lsb |= acc & 0x3f;
+ body->accuracy_and_sensor_direction &= 0x0f;
+ body->accuracy_and_sensor_direction |= (acc & 0xf) << 4;
+};
+inline void set_accuracy_exp(uint8_t exp, SensorDataFullRecordBody* body)
+{
+ body->accuracy_and_sensor_direction &= ~(3<<2);
+ body->accuracy_and_sensor_direction |= (exp & 3)<<2;
+};
+inline void set_sensor_dir(uint8_t dir, SensorDataFullRecordBody* body)
+{
+ body->accuracy_and_sensor_direction &= ~(3<<0);
+ body->accuracy_and_sensor_direction |= (dir & 3);
+};
+
+inline void set_b_exp(uint8_t exp, SensorDataFullRecordBody* body)
+{
+ body->r_b_exponents &= 0xf0;
+ body->r_b_exponents |= exp & 0x0f;
+};
+inline void set_r_exp(uint8_t exp, SensorDataFullRecordBody* body)
+{
+ body->r_b_exponents &= 0x0f;
+ body->r_b_exponents |= (exp & 0x0f)<<4;
+};
+
+inline void set_id_strlen(uint8_t len, SensorDataFullRecordBody* body)
+{
+ body->id_string_info &= ~(0x1f);
+ body->id_string_info |= len & 0x1f;
+};
+inline uint8_t get_id_strlen( SensorDataFullRecordBody* body)
+{
+ return body->id_string_info & 0x1f;
+};
+inline void set_id_type(uint8_t type, SensorDataFullRecordBody* body)
+{
+ body->id_string_info &= ~(3<<6);
+ body->id_string_info |= (type & 0x3)<<6;
+};
+
+} // namespace body
+
+// More types contained in section 43.17 Sensor Unit Type Codes,
+// IPMI spec v2 rev 1.1
+enum SensorUnitTypeCodes
+{
+ SENSOR_UNIT_UNSPECIFIED = 0,
+ SENSOR_UNIT_DEGREES_C = 1,
+ SENSOR_UNIT_VOLTS = 4,
+ SENSOR_UNIT_AMPERES = 5,
+ SENSOR_UNIT_JOULES = 7,
+ SENSOR_UNIT_METERS = 34,
+ SENSOR_UNIT_REVOLUTIONS = 41,
+};
+
+struct SensorDataFullRecord
+{
+ SensorDataRecordHeader header;
+ SensorDataRecordKey key;
+ SensorDataFullRecordBody body;
+} __attribute__((packed));
+
+} // get_sdr
#endif
OpenPOWER on IntegriCloud