1d700e76aSTom #include <mapper.h>
21fabf229SEmily Shaffer #include <math.h>
398a23840SMatthew Barth #include <stdio.h>
498a23840SMatthew Barth #include <string.h>
5cc941e15SEmily Shaffer #include <set>
6be703f71STom Joseph #include <bitset>
7bbef71c2SEmily Shaffer #include <xyz/openbmc_project/Sensor/Value/server.hpp>
898a23840SMatthew Barth #include <systemd/sd-bus.h>
9be703f71STom Joseph #include "host-ipmid/ipmid-api.h"
10be703f71STom Joseph #include <phosphor-logging/log.hpp>
1118e99992SDhruvaraj Subhashchandran #include <phosphor-logging/elog-errors.hpp>
12e0cc8553SRatan Gupta #include "fruread.hpp"
13d700e76aSTom #include "ipmid.hpp"
14be703f71STom Joseph #include "sensorhandler.h"
15be703f71STom Joseph #include "types.hpp"
16be703f71STom Joseph #include "utils.hpp"
1718e99992SDhruvaraj Subhashchandran #include "xyz/openbmc_project/Common/error.hpp"
1818e99992SDhruvaraj Subhashchandran 
19e0cc8553SRatan Gupta static constexpr uint8_t fruInventoryDevice = 0x10;
20e0cc8553SRatan Gupta static constexpr uint8_t IPMIFruInventory = 0x02;
21e0cc8553SRatan Gupta static constexpr uint8_t BMCSlaveAddress = 0x20;
22e0cc8553SRatan Gupta 
2398a23840SMatthew Barth extern int updateSensorRecordFromSSRAESC(const void *);
24d700e76aSTom extern sd_bus *bus;
25be703f71STom Joseph extern const ipmi::sensor::IdInfoMap sensors;
26e0cc8553SRatan Gupta extern const FruMap frus;
27e0cc8553SRatan Gupta 
28e0cc8553SRatan Gupta 
29be703f71STom Joseph using namespace phosphor::logging;
3018e99992SDhruvaraj Subhashchandran using InternalFailure =
3118e99992SDhruvaraj Subhashchandran     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
3298a23840SMatthew Barth 
3398a23840SMatthew Barth void register_netfn_sen_functions()   __attribute__((constructor));
3498a23840SMatthew Barth 
3598a23840SMatthew Barth struct sensorTypemap_t {
3698a23840SMatthew Barth     uint8_t number;
3798a23840SMatthew Barth     uint8_t typecode;
3898a23840SMatthew Barth     char dbusname[32];
3998a23840SMatthew Barth } ;
4098a23840SMatthew Barth 
4198a23840SMatthew Barth sensorTypemap_t g_SensorTypeMap[] = {
4298a23840SMatthew Barth 
4398a23840SMatthew Barth     {0x01, 0x6F, "Temp"},
4498a23840SMatthew Barth     {0x0C, 0x6F, "DIMM"},
4598a23840SMatthew Barth     {0x0C, 0x6F, "MEMORY_BUFFER"},
4698a23840SMatthew Barth     {0x07, 0x6F, "PROC"},
4798a23840SMatthew Barth     {0x07, 0x6F, "CORE"},
4898a23840SMatthew Barth     {0x07, 0x6F, "CPU"},
4998a23840SMatthew Barth     {0x0F, 0x6F, "BootProgress"},
5098a23840SMatthew Barth     {0xe9, 0x09, "OccStatus"},  // E9 is an internal mapping to handle sensor type code os 0x09
5198a23840SMatthew Barth     {0xC3, 0x6F, "BootCount"},
5298a23840SMatthew Barth     {0x1F, 0x6F, "OperatingSystemStatus"},
5398a23840SMatthew Barth     {0x12, 0x6F, "SYSTEM_EVENT"},
5498a23840SMatthew Barth     {0xC7, 0x03, "SYSTEM"},
5598a23840SMatthew Barth     {0xC7, 0x03, "MAIN_PLANAR"},
5698a23840SMatthew Barth     {0xC2, 0x6F, "PowerCap"},
57558184eaSTom Joseph     {0x0b, 0xCA, "PowerSupplyRedundancy"},
580661beb1SJayanth Othayoth     {0xDA, 0x03, "TurboAllowed"},
59558184eaSTom Joseph     {0xD8, 0xC8, "PowerSupplyDerating"},
6098a23840SMatthew Barth     {0xFF, 0x00, ""},
6198a23840SMatthew Barth };
6298a23840SMatthew Barth 
6398a23840SMatthew Barth 
6498a23840SMatthew Barth struct sensor_data_t {
6598a23840SMatthew Barth     uint8_t sennum;
6698a23840SMatthew Barth }  __attribute__ ((packed)) ;
6798a23840SMatthew Barth 
6898a23840SMatthew Barth struct sensorreadingresp_t {
6998a23840SMatthew Barth     uint8_t value;
7098a23840SMatthew Barth     uint8_t operation;
7198a23840SMatthew Barth     uint8_t indication[2];
7298a23840SMatthew Barth }  __attribute__ ((packed)) ;
7398a23840SMatthew Barth 
742ae09b9aSEmily Shaffer int get_bus_for_path(const char *path, char **busname) {
752ae09b9aSEmily Shaffer     return mapper_get_service(bus, path, busname);
762ae09b9aSEmily Shaffer }
77d700e76aSTom 
782ae09b9aSEmily Shaffer int legacy_dbus_openbmc_path(const char *type, const uint8_t num, dbus_interface_t *interface) {
79d700e76aSTom     char  *busname = NULL;
80d700e76aSTom     const char  *iface = "org.openbmc.managers.System";
81d700e76aSTom     const char  *objname = "/org/openbmc/managers/System";
82d700e76aSTom     char  *str1 = NULL, *str2, *str3;
83d700e76aSTom     sd_bus_error error = SD_BUS_ERROR_NULL;
84d700e76aSTom     sd_bus_message *reply = NULL;
85d700e76aSTom 
86d700e76aSTom 
87d700e76aSTom     int r;
882ae09b9aSEmily Shaffer     r = get_bus_for_path(objname, &busname);
89d700e76aSTom     if (r < 0) {
90819ddd42SBrad Bishop         fprintf(stderr, "Failed to get %s busname: %s\n",
91819ddd42SBrad Bishop                 objname, strerror(-r));
92d700e76aSTom         goto final;
93d700e76aSTom     }
94d700e76aSTom 
95d700e76aSTom     r = sd_bus_call_method(bus,busname,objname,iface, "getObjectFromByteId",
96d700e76aSTom                            &error, &reply, "sy", type, num);
97d700e76aSTom     if (r < 0) {
98d700e76aSTom         fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
99d700e76aSTom         goto final;
100d700e76aSTom     }
101d700e76aSTom 
102d700e76aSTom     r = sd_bus_message_read(reply, "(ss)", &str2, &str3);
103d700e76aSTom     if (r < 0) {
104d700e76aSTom         fprintf(stderr, "Failed to get a response: %s", strerror(-r));
105d700e76aSTom         goto final;
106d700e76aSTom     }
107d700e76aSTom 
10891875f77SLei YU     if (strlen(str2) == 0)
10991875f77SLei YU     {
11091875f77SLei YU         // Path being empty occurs when the sensor id is not in SystemManager
11191875f77SLei YU         r = -EINVAL;
11291875f77SLei YU         goto final;
11391875f77SLei YU     }
11491875f77SLei YU 
1152ae09b9aSEmily Shaffer     r = get_bus_for_path(str2, &str1);
116d700e76aSTom     if (r < 0) {
117819ddd42SBrad Bishop         fprintf(stderr, "Failed to get %s busname: %s\n",
118819ddd42SBrad Bishop                 str2, strerror(-r));
119d700e76aSTom         goto final;
120d700e76aSTom     }
121d700e76aSTom 
122d700e76aSTom     strncpy(interface->bus, str1, MAX_DBUS_PATH);
123d700e76aSTom     strncpy(interface->path, str2, MAX_DBUS_PATH);
124d700e76aSTom     strncpy(interface->interface, str3, MAX_DBUS_PATH);
125d700e76aSTom 
126d700e76aSTom     interface->sensornumber = num;
1277117441cSEmily Shaffer     // Make sure we know that the type hasn't been set, as newer codebase will
1287117441cSEmily Shaffer     // set it automatically from the YAML at this step.
1297117441cSEmily Shaffer     interface->sensortype = 0;
130d700e76aSTom 
131d700e76aSTom final:
132d700e76aSTom 
133d700e76aSTom     sd_bus_error_free(&error);
134d700e76aSTom     reply = sd_bus_message_unref(reply);
135d700e76aSTom     free(busname);
136d700e76aSTom     free(str1);
137d700e76aSTom 
138d700e76aSTom     return r;
139d700e76aSTom }
140d700e76aSTom 
1412ae09b9aSEmily Shaffer // Use a lookup table to find the interface name of a specific sensor
1422ae09b9aSEmily Shaffer // This will be used until an alternative is found.  this is the first
1432ae09b9aSEmily Shaffer // step for mapping IPMI
1442ae09b9aSEmily Shaffer int find_openbmc_path(uint8_t num, dbus_interface_t *interface) {
1452ae09b9aSEmily Shaffer     int rc;
1462ae09b9aSEmily Shaffer 
1472ae09b9aSEmily Shaffer     // When the sensor map does not contain the sensor requested,
1482ae09b9aSEmily Shaffer     // fall back to the legacy DBus lookup (deprecated)
1492ae09b9aSEmily Shaffer     const auto& sensor_it = sensors.find(num);
1502ae09b9aSEmily Shaffer     if (sensor_it == sensors.end())
1512ae09b9aSEmily Shaffer     {
1522ae09b9aSEmily Shaffer         return legacy_dbus_openbmc_path("SENSOR", num, interface);
1532ae09b9aSEmily Shaffer     }
1542ae09b9aSEmily Shaffer 
1552ae09b9aSEmily Shaffer     const auto& info = sensor_it->second;
1562ae09b9aSEmily Shaffer 
1578451edf5SPatrick Williams     char* busname = nullptr;
1582ae09b9aSEmily Shaffer     rc = get_bus_for_path(info.sensorPath.c_str(), &busname);
1592ae09b9aSEmily Shaffer     if (rc < 0) {
1602ae09b9aSEmily Shaffer         fprintf(stderr, "Failed to get %s busname: %s\n",
1612ae09b9aSEmily Shaffer                 info.sensorPath.c_str(),
1622ae09b9aSEmily Shaffer                 busname);
1632ae09b9aSEmily Shaffer         goto final;
1642ae09b9aSEmily Shaffer     }
1652ae09b9aSEmily Shaffer 
1662ae09b9aSEmily Shaffer     interface->sensortype = info.sensorType;
1672ae09b9aSEmily Shaffer     strcpy(interface->bus, busname);
1682ae09b9aSEmily Shaffer     strcpy(interface->path, info.sensorPath.c_str());
1692ae09b9aSEmily Shaffer     // Take the interface name from the beginning of the DbusInterfaceMap. This
1702ae09b9aSEmily Shaffer     // works for the Value interface but may not suffice for more complex
1712ae09b9aSEmily Shaffer     // sensors.
1722ae09b9aSEmily Shaffer     // tracked https://github.com/openbmc/phosphor-host-ipmid/issues/103
1731bb0d387SDeepak Kodihalli     strcpy(interface->interface, info.propertyInterfaces.begin()->first.c_str());
1742ae09b9aSEmily Shaffer     interface->sensornumber = num;
1752ae09b9aSEmily Shaffer 
1762ae09b9aSEmily Shaffer final:
1772ae09b9aSEmily Shaffer     free(busname);
1782ae09b9aSEmily Shaffer     return rc;
1792ae09b9aSEmily Shaffer }
1802ae09b9aSEmily Shaffer 
181d700e76aSTom 
182d700e76aSTom /////////////////////////////////////////////////////////////////////
183d700e76aSTom //
184d700e76aSTom // Routines used by ipmi commands wanting to interact on the dbus
185d700e76aSTom //
186d700e76aSTom /////////////////////////////////////////////////////////////////////
187d700e76aSTom int set_sensor_dbus_state_s(uint8_t number, const char *method, const char *value) {
188d700e76aSTom 
189d700e76aSTom 
190d700e76aSTom     dbus_interface_t a;
191d700e76aSTom     int r;
192d700e76aSTom     sd_bus_error error = SD_BUS_ERROR_NULL;
193d700e76aSTom     sd_bus_message *m=NULL;
194d700e76aSTom 
195d700e76aSTom     fprintf(ipmidbus, "Attempting to set a dbus Variant Sensor 0x%02x via %s with a value of %s\n",
196d700e76aSTom         number, method, value);
197d700e76aSTom 
1982ae09b9aSEmily Shaffer     r = find_openbmc_path(number, &a);
199d700e76aSTom 
200d700e76aSTom     if (r < 0) {
201d700e76aSTom         fprintf(stderr, "Failed to find Sensor 0x%02x\n", number);
202d700e76aSTom         return 0;
203d700e76aSTom     }
204d700e76aSTom 
205d700e76aSTom     r = sd_bus_message_new_method_call(bus,&m,a.bus,a.path,a.interface,method);
206d700e76aSTom     if (r < 0) {
207d700e76aSTom         fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
208d700e76aSTom         goto final;
209d700e76aSTom     }
210d700e76aSTom 
211d700e76aSTom     r = sd_bus_message_append(m, "v", "s", value);
212d700e76aSTom     if (r < 0) {
213d700e76aSTom         fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r));
214d700e76aSTom         goto final;
215d700e76aSTom     }
216d700e76aSTom 
217d700e76aSTom 
218d700e76aSTom     r = sd_bus_call(bus, m, 0, &error, NULL);
219d700e76aSTom     if (r < 0) {
220d700e76aSTom         fprintf(stderr, "Failed to call the method: %s", strerror(-r));
221d700e76aSTom     }
222d700e76aSTom 
223d700e76aSTom final:
224d700e76aSTom     sd_bus_error_free(&error);
225d700e76aSTom     m = sd_bus_message_unref(m);
226d700e76aSTom 
227d700e76aSTom     return 0;
228d700e76aSTom }
229d700e76aSTom int set_sensor_dbus_state_y(uint8_t number, const char *method, const uint8_t value) {
230d700e76aSTom 
231d700e76aSTom 
232d700e76aSTom     dbus_interface_t a;
233d700e76aSTom     int r;
234d700e76aSTom     sd_bus_error error = SD_BUS_ERROR_NULL;
235d700e76aSTom     sd_bus_message *m=NULL;
236d700e76aSTom 
237d700e76aSTom     fprintf(ipmidbus, "Attempting to set a dbus Variant Sensor 0x%02x via %s with a value of 0x%02x\n",
238d700e76aSTom         number, method, value);
239d700e76aSTom 
2402ae09b9aSEmily Shaffer     r = find_openbmc_path(number, &a);
241d700e76aSTom 
242d700e76aSTom     if (r < 0) {
243d700e76aSTom         fprintf(stderr, "Failed to find Sensor 0x%02x\n", number);
244d700e76aSTom         return 0;
245d700e76aSTom     }
246d700e76aSTom 
247d700e76aSTom     r = sd_bus_message_new_method_call(bus,&m,a.bus,a.path,a.interface,method);
248d700e76aSTom     if (r < 0) {
249d700e76aSTom         fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
250d700e76aSTom         goto final;
251d700e76aSTom     }
252d700e76aSTom 
253d700e76aSTom     r = sd_bus_message_append(m, "v", "i", value);
254d700e76aSTom     if (r < 0) {
255d700e76aSTom         fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r));
256d700e76aSTom         goto final;
257d700e76aSTom     }
258d700e76aSTom 
259d700e76aSTom 
260d700e76aSTom     r = sd_bus_call(bus, m, 0, &error, NULL);
261d700e76aSTom     if (r < 0) {
262d700e76aSTom         fprintf(stderr, "12 Failed to call the method: %s", strerror(-r));
263d700e76aSTom     }
264d700e76aSTom 
265d700e76aSTom final:
266d700e76aSTom     sd_bus_error_free(&error);
267d700e76aSTom     m = sd_bus_message_unref(m);
268d700e76aSTom 
269d700e76aSTom     return 0;
270d700e76aSTom }
271d700e76aSTom 
27298a23840SMatthew Barth uint8_t dbus_to_sensor_type(char *p) {
27398a23840SMatthew Barth 
27498a23840SMatthew Barth     sensorTypemap_t *s = g_SensorTypeMap;
27598a23840SMatthew Barth     char r=0;
27698a23840SMatthew Barth     while (s->number != 0xFF) {
27798a23840SMatthew Barth         if (!strcmp(s->dbusname,p)) {
278558184eaSTom Joseph             r = s->typecode;
27998a23840SMatthew Barth              break;
28098a23840SMatthew Barth         }
28198a23840SMatthew Barth         s++;
28298a23840SMatthew Barth     }
28398a23840SMatthew Barth 
28498a23840SMatthew Barth     if (s->number == 0xFF)
28598a23840SMatthew Barth         printf("Failed to find Sensor Type %s\n", p);
28698a23840SMatthew Barth 
28798a23840SMatthew Barth     return r;
28898a23840SMatthew Barth }
28998a23840SMatthew Barth 
29098a23840SMatthew Barth 
291391f3303SEmily Shaffer uint8_t get_type_from_interface(dbus_interface_t dbus_if) {
29298a23840SMatthew Barth 
29398a23840SMatthew Barth     char *p;
29456003453SBrad Bishop     uint8_t type;
29598a23840SMatthew Barth 
29698a23840SMatthew Barth     // This is where sensors that do not exist in dbus but do
29798a23840SMatthew Barth     // exist in the host code stop.  This should indicate it
29898a23840SMatthew Barth     // is not a supported sensor
299391f3303SEmily Shaffer     if (dbus_if.interface[0] == 0) { return 0;}
30098a23840SMatthew Barth 
3017117441cSEmily Shaffer     // Fetch type from interface itself.
3027117441cSEmily Shaffer     if (dbus_if.sensortype != 0)
3037117441cSEmily Shaffer     {
3047117441cSEmily Shaffer         type = dbus_if.sensortype;
30598a23840SMatthew Barth     } else {
30698a23840SMatthew Barth         // Non InventoryItems
307391f3303SEmily Shaffer         p = strrchr (dbus_if.path, '/');
30856003453SBrad Bishop         type = dbus_to_sensor_type(p+1);
30998a23840SMatthew Barth     }
31098a23840SMatthew Barth 
31156003453SBrad Bishop     return type;
31298a23840SMatthew Barth  }
31398a23840SMatthew Barth 
314391f3303SEmily Shaffer // Replaces find_sensor
315391f3303SEmily Shaffer uint8_t find_type_for_sensor_number(uint8_t num) {
316391f3303SEmily Shaffer     int r;
317391f3303SEmily Shaffer     dbus_interface_t dbus_if;
3182ae09b9aSEmily Shaffer     r = find_openbmc_path(num, &dbus_if);
319391f3303SEmily Shaffer     if (r < 0) {
320391f3303SEmily Shaffer         fprintf(stderr, "Could not find sensor %d\n", num);
32191875f77SLei YU         return 0;
322391f3303SEmily Shaffer     }
323391f3303SEmily Shaffer     return get_type_from_interface(dbus_if);
324391f3303SEmily Shaffer }
325391f3303SEmily Shaffer 
32698a23840SMatthew Barth 
32798a23840SMatthew Barth 
32898a23840SMatthew Barth 
32998a23840SMatthew Barth 
33098a23840SMatthew Barth ipmi_ret_t ipmi_sen_get_sensor_type(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
33198a23840SMatthew Barth                              ipmi_request_t request, ipmi_response_t response,
33298a23840SMatthew Barth                              ipmi_data_len_t data_len, ipmi_context_t context)
33398a23840SMatthew Barth {
33498a23840SMatthew Barth     sensor_data_t *reqptr = (sensor_data_t*)request;
33598a23840SMatthew Barth     ipmi_ret_t rc = IPMI_CC_OK;
33698a23840SMatthew Barth 
33798a23840SMatthew Barth     printf("IPMI GET_SENSOR_TYPE [0x%02X]\n",reqptr->sennum);
33898a23840SMatthew Barth 
33998a23840SMatthew Barth     // TODO Not sure what the System-event-sensor is suppose to return
34098a23840SMatthew Barth     // need to ask Hostboot team
34198a23840SMatthew Barth     unsigned char buf[] = {0x00,0x6F};
34298a23840SMatthew Barth 
343391f3303SEmily Shaffer     buf[0] = find_type_for_sensor_number(reqptr->sennum);
34498a23840SMatthew Barth 
34598a23840SMatthew Barth     // HACK UNTIL Dbus gets updated or we find a better way
34698a23840SMatthew Barth     if (buf[0] == 0) {
34798a23840SMatthew Barth         rc = IPMI_CC_SENSOR_INVALID;
34898a23840SMatthew Barth     }
34998a23840SMatthew Barth 
35098a23840SMatthew Barth 
35198a23840SMatthew Barth     *data_len = sizeof(buf);
35298a23840SMatthew Barth     memcpy(response, &buf, *data_len);
35398a23840SMatthew Barth 
35498a23840SMatthew Barth     return rc;
35598a23840SMatthew Barth }
35698a23840SMatthew Barth 
357cc941e15SEmily Shaffer const std::set<std::string> analogSensorInterfaces =
358cc941e15SEmily Shaffer {
359cc941e15SEmily Shaffer     "xyz.openbmc_project.Sensor.Value",
360e9a64056SPatrick Venture     "xyz.openbmc_project.Control.FanPwm",
361cc941e15SEmily Shaffer };
362cc941e15SEmily Shaffer 
363cc941e15SEmily Shaffer bool isAnalogSensor(const std::string& interface)
364cc941e15SEmily Shaffer {
365cc941e15SEmily Shaffer     return (analogSensorInterfaces.count(interface));
366cc941e15SEmily Shaffer }
367cc941e15SEmily Shaffer 
368be703f71STom Joseph ipmi_ret_t setSensorReading(void *request)
369be703f71STom Joseph {
370816e92b5STom Joseph     ipmi::sensor::SetSensorReadingReq cmdData =
371816e92b5STom Joseph             *(static_cast<ipmi::sensor::SetSensorReadingReq *>(request));
372be703f71STom Joseph 
373be703f71STom Joseph     // Check if the Sensor Number is present
374e0af7209SDhruvaraj Subhashchandran     const auto iter = sensors.find(cmdData.number);
375be703f71STom Joseph     if (iter == sensors.end())
376be703f71STom Joseph     {
377be703f71STom Joseph         return IPMI_CC_SENSOR_INVALID;
378be703f71STom Joseph     }
379be703f71STom Joseph 
38018e99992SDhruvaraj Subhashchandran     try
38118e99992SDhruvaraj Subhashchandran     {
3820922bde4SJayanth Othayoth         if (ipmi::sensor::Mutability::Write !=
3830922bde4SJayanth Othayoth               (iter->second.mutability & ipmi::sensor::Mutability::Write))
3840922bde4SJayanth Othayoth         {
3850922bde4SJayanth Othayoth             log<level::ERR>("Sensor Set operation is not allowed",
3860922bde4SJayanth Othayoth                             entry("SENSOR_NUM=%d", cmdData.number));
3870922bde4SJayanth Othayoth             return IPMI_CC_ILLEGAL_COMMAND;
3880922bde4SJayanth Othayoth         }
389e0af7209SDhruvaraj Subhashchandran         return iter->second.updateFunc(cmdData, iter->second);
390be703f71STom Joseph     }
39118e99992SDhruvaraj Subhashchandran     catch (InternalFailure& e)
39218e99992SDhruvaraj Subhashchandran     {
39318e99992SDhruvaraj Subhashchandran          log<level::ERR>("Set sensor failed",
39418e99992SDhruvaraj Subhashchandran                          entry("SENSOR_NUM=%d", cmdData.number));
39518e99992SDhruvaraj Subhashchandran          commit<InternalFailure>();
39618e99992SDhruvaraj Subhashchandran     }
3978202432fSTom Joseph     catch (const std::runtime_error& e)
3988202432fSTom Joseph     {
3998202432fSTom Joseph         log<level::ERR>(e.what());
4008202432fSTom Joseph     }
40118e99992SDhruvaraj Subhashchandran 
40218e99992SDhruvaraj Subhashchandran     return IPMI_CC_UNSPECIFIED_ERROR;
40318e99992SDhruvaraj Subhashchandran }
40498a23840SMatthew Barth 
40598a23840SMatthew Barth ipmi_ret_t ipmi_sen_set_sensor(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
40698a23840SMatthew Barth                              ipmi_request_t request, ipmi_response_t response,
40798a23840SMatthew Barth                              ipmi_data_len_t data_len, ipmi_context_t context)
40898a23840SMatthew Barth {
40998a23840SMatthew Barth     sensor_data_t *reqptr = (sensor_data_t*)request;
41098a23840SMatthew Barth 
41198a23840SMatthew Barth     printf("IPMI SET_SENSOR [0x%02x]\n",reqptr->sennum);
41298a23840SMatthew Barth 
413be703f71STom Joseph     /*
414be703f71STom Joseph      * This would support the Set Sensor Reading command for the presence
415be703f71STom Joseph      * and functional state of Processor, Core & DIMM. For the remaining
416be703f71STom Joseph      * sensors the existing support is invoked.
417be703f71STom Joseph      */
418be703f71STom Joseph     auto ipmiRC = setSensorReading(request);
419be703f71STom Joseph 
420be703f71STom Joseph     if(ipmiRC == IPMI_CC_SENSOR_INVALID)
421be703f71STom Joseph     {
42298a23840SMatthew Barth         updateSensorRecordFromSSRAESC(reqptr);
423be703f71STom Joseph         ipmiRC = IPMI_CC_OK;
424be703f71STom Joseph     }
42598a23840SMatthew Barth 
42698a23840SMatthew Barth     *data_len=0;
427be703f71STom Joseph     return ipmiRC;
42898a23840SMatthew Barth }
42998a23840SMatthew Barth 
4303ee668f9STom Joseph ipmi_ret_t legacyGetSensorReading(uint8_t sensorNum,
4313ee668f9STom Joseph                                   ipmi_response_t response,
4323ee668f9STom Joseph                                   ipmi_data_len_t data_len)
43398a23840SMatthew Barth {
43498a23840SMatthew Barth     int r;
43598a23840SMatthew Barth     dbus_interface_t a;
43698a23840SMatthew Barth     sd_bus *bus = ipmid_get_sd_bus_connection();
4373ee668f9STom Joseph     ipmi_ret_t rc = IPMI_CC_SENSOR_INVALID;
4383ee668f9STom Joseph     uint8_t type = 0;
43998a23840SMatthew Barth     sd_bus_message *reply = NULL;
44098a23840SMatthew Barth     int reading = 0;
4416244f93dSDhruvaraj Subhashchandran     char* assertion = NULL;
4423ee668f9STom Joseph     sensorreadingresp_t *resp = (sensorreadingresp_t*) response;
4433ee668f9STom Joseph     *data_len=0;
44498a23840SMatthew Barth 
4453ee668f9STom Joseph     r = find_openbmc_path(sensorNum, &a);
44640c35b1cSTom Joseph     if (r < 0)
44740c35b1cSTom Joseph     {
4483ee668f9STom Joseph         sd_journal_print(LOG_ERR, "Failed to find Sensor 0x%02x\n", sensorNum);
44956003453SBrad Bishop         return IPMI_CC_SENSOR_INVALID;
45056003453SBrad Bishop     }
45198a23840SMatthew Barth 
4523ee668f9STom Joseph     type = get_type_from_interface(a);
4533ee668f9STom Joseph     if (type == 0)
4543ee668f9STom Joseph     {
4553ee668f9STom Joseph         sd_journal_print(LOG_ERR, "Failed to find Sensor 0x%02x\n",
4563ee668f9STom Joseph                          sensorNum);
4573ee668f9STom Joseph         return IPMI_CC_SENSOR_INVALID;
45840c35b1cSTom Joseph     }
45998a23840SMatthew Barth 
46098a23840SMatthew Barth     switch(type) {
46198a23840SMatthew Barth         case 0xC2:
462d12ae758SDhruvaraj Subhashchandran         case 0xC8:
4633ee668f9STom Joseph             r = sd_bus_get_property(bus,a.bus, a.path, a.interface,
4643ee668f9STom Joseph                                     "value", NULL, &reply, "i");
4653ee668f9STom Joseph             if (r < 0)
4663ee668f9STom Joseph             {
4673ee668f9STom Joseph                 sd_journal_print(LOG_ERR, "Failed to call sd_bus_get_property:"
4683ee668f9STom Joseph                                  " %d, %s\n", r, strerror(-r));
4693ee668f9STom Joseph                 sd_journal_print(LOG_ERR, "Bus: %s, Path: %s, Interface: %s\n",
47098a23840SMatthew Barth                                  a.bus, a.path, a.interface);
47198a23840SMatthew Barth                 break;
47298a23840SMatthew Barth             }
47398a23840SMatthew Barth 
47498a23840SMatthew Barth             r = sd_bus_message_read(reply, "i", &reading);
47598a23840SMatthew Barth             if (r < 0) {
4763ee668f9STom Joseph                 sd_journal_print(LOG_ERR, "Failed to read sensor: %s\n",
4773ee668f9STom Joseph                                  strerror(-r));
47898a23840SMatthew Barth                 break;
47998a23840SMatthew Barth             }
48098a23840SMatthew Barth 
48198a23840SMatthew Barth             rc = IPMI_CC_OK;
48298a23840SMatthew Barth             *data_len=sizeof(sensorreadingresp_t);
48398a23840SMatthew Barth 
48498a23840SMatthew Barth             resp->value         = (uint8_t)reading;
48598a23840SMatthew Barth             resp->operation     = 0;
48698a23840SMatthew Barth             resp->indication[0] = 0;
48798a23840SMatthew Barth             resp->indication[1] = 0;
48898a23840SMatthew Barth             break;
48998a23840SMatthew Barth 
4906244f93dSDhruvaraj Subhashchandran         //TODO openbmc/openbmc#2154 Move this sensor to right place.
4916244f93dSDhruvaraj Subhashchandran         case 0xCA:
4923ee668f9STom Joseph             r = sd_bus_get_property(bus,a.bus, a.path, a.interface, "value",
4933ee668f9STom Joseph                                     NULL, &reply, "s");
4943ee668f9STom Joseph             if (r < 0)
4953ee668f9STom Joseph             {
4963ee668f9STom Joseph                 sd_journal_print(LOG_ERR, "Failed to call sd_bus_get_property:"
4973ee668f9STom Joseph                                  " %d, %s\n", r, strerror(-r));
4983ee668f9STom Joseph                 sd_journal_print(LOG_ERR, "Bus: %s, Path: %s, Interface: %s\n",
4996244f93dSDhruvaraj Subhashchandran                                  a.bus, a.path, a.interface);
5006244f93dSDhruvaraj Subhashchandran                 break;
5016244f93dSDhruvaraj Subhashchandran             }
5026244f93dSDhruvaraj Subhashchandran 
5036244f93dSDhruvaraj Subhashchandran             r = sd_bus_message_read(reply, "s", &assertion);
5043ee668f9STom Joseph             if (r < 0)
5053ee668f9STom Joseph             {
5063ee668f9STom Joseph                 sd_journal_print(LOG_ERR, "Failed to read sensor: %s\n",
5073ee668f9STom Joseph                                  strerror(-r));
5086244f93dSDhruvaraj Subhashchandran                 break;
5096244f93dSDhruvaraj Subhashchandran             }
5106244f93dSDhruvaraj Subhashchandran 
5116244f93dSDhruvaraj Subhashchandran             rc = IPMI_CC_OK;
5126244f93dSDhruvaraj Subhashchandran             *data_len=sizeof(sensorreadingresp_t);
5136244f93dSDhruvaraj Subhashchandran 
5146244f93dSDhruvaraj Subhashchandran             resp->value         = 0;
5156244f93dSDhruvaraj Subhashchandran             resp->operation     = 0;
5166244f93dSDhruvaraj Subhashchandran             if (strcmp(assertion,"Enabled") == 0)
5176244f93dSDhruvaraj Subhashchandran             {
5186244f93dSDhruvaraj Subhashchandran                 resp->indication[0] = 0x02;
5196244f93dSDhruvaraj Subhashchandran             }
5206244f93dSDhruvaraj Subhashchandran             else
5216244f93dSDhruvaraj Subhashchandran             {
5226244f93dSDhruvaraj Subhashchandran                 resp->indication[0] = 0x1;
5236244f93dSDhruvaraj Subhashchandran             }
5246244f93dSDhruvaraj Subhashchandran             resp->indication[1] = 0;
5256244f93dSDhruvaraj Subhashchandran             break;
5266244f93dSDhruvaraj Subhashchandran 
52798a23840SMatthew Barth         default:
52814c15467STom Joseph         {
5293ee668f9STom Joseph             return IPMI_CC_SENSOR_INVALID;
5303ee668f9STom Joseph         }
5313ee668f9STom Joseph     }
5323ee668f9STom Joseph 
5333ee668f9STom Joseph     reply = sd_bus_message_unref(reply);
5343ee668f9STom Joseph 
5353ee668f9STom Joseph     return rc;
5363ee668f9STom Joseph }
5373ee668f9STom Joseph 
5383ee668f9STom Joseph ipmi_ret_t ipmi_sen_get_sensor_reading(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
5393ee668f9STom Joseph                              ipmi_request_t request, ipmi_response_t response,
5403ee668f9STom Joseph                              ipmi_data_len_t data_len, ipmi_context_t context)
5413ee668f9STom Joseph {
5423ee668f9STom Joseph     sensor_data_t *reqptr = (sensor_data_t*)request;
5433ee668f9STom Joseph     sensorreadingresp_t *resp = (sensorreadingresp_t*) response;
5443ee668f9STom Joseph     ipmi::sensor::GetSensorResponse getResponse {};
5453ee668f9STom Joseph     static constexpr auto scanningEnabledBit = 6;
5463ee668f9STom Joseph 
54714c15467STom Joseph     const auto iter = sensors.find(reqptr->sennum);
54814c15467STom Joseph     if (iter == sensors.end())
54914c15467STom Joseph     {
5503ee668f9STom Joseph         return legacyGetSensorReading(reqptr->sennum, response, data_len);
55114c15467STom Joseph     }
55213b87a3eSTom Joseph     if (ipmi::sensor::Mutability::Read !=
55313b87a3eSTom Joseph           (iter->second.mutability & ipmi::sensor::Mutability::Read))
55413b87a3eSTom Joseph     {
555*6ccf8818SJayanth Othayoth         return IPMI_CC_ILLEGAL_COMMAND;
55613b87a3eSTom Joseph     }
55714c15467STom Joseph 
55814c15467STom Joseph     try
55914c15467STom Joseph     {
560c6162fb6STom Joseph         getResponse =  iter->second.getFunc(iter->second);
56114c15467STom Joseph         *data_len = getResponse.size();
56214c15467STom Joseph         memcpy(resp, getResponse.data(), *data_len);
563c6162fb6STom Joseph         resp->operation = 1 << scanningEnabledBit;
56414c15467STom Joseph         return IPMI_CC_OK;
56514c15467STom Joseph     }
5663ee668f9STom Joseph     catch (const std::exception& e)
56714c15467STom Joseph     {
568c6162fb6STom Joseph         *data_len = getResponse.size();
569c6162fb6STom Joseph         memcpy(resp, getResponse.data(), *data_len);
570c6162fb6STom Joseph         return IPMI_CC_OK;
57114c15467STom Joseph     }
57298a23840SMatthew Barth }
57398a23840SMatthew Barth 
5740ac0dd23STom Joseph void getSensorThresholds(uint8_t sensorNum,
5750ac0dd23STom Joseph                          get_sdr::GetSensorThresholdsResponse* response)
5760ac0dd23STom Joseph {
5770ac0dd23STom Joseph     constexpr auto warningThreshIntf =
5780ac0dd23STom Joseph         "xyz.openbmc_project.Sensor.Threshold.Warning";
5790ac0dd23STom Joseph     constexpr auto criticalThreshIntf =
5800ac0dd23STom Joseph         "xyz.openbmc_project.Sensor.Threshold.Critical";
5810ac0dd23STom Joseph 
5820ac0dd23STom Joseph     sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
5830ac0dd23STom Joseph 
5840ac0dd23STom Joseph     const auto iter = sensors.find(sensorNum);
5850ac0dd23STom Joseph     const auto info = iter->second;
5860ac0dd23STom Joseph 
5870ac0dd23STom Joseph     auto service = ipmi::getService(bus, info.sensorInterface, info.sensorPath);
5880ac0dd23STom Joseph 
5890ac0dd23STom Joseph     auto warnThresholds = ipmi::getAllDbusProperties(bus,
5900ac0dd23STom Joseph                                                      service,
5910ac0dd23STom Joseph                                                      info.sensorPath,
5920ac0dd23STom Joseph                                                      warningThreshIntf);
5930ac0dd23STom Joseph 
5940ac0dd23STom Joseph     double warnLow = warnThresholds["WarningLow"].get<int64_t>();
5950ac0dd23STom Joseph     double warnHigh = warnThresholds["WarningHigh"].get<int64_t>();
5960ac0dd23STom Joseph 
5970ac0dd23STom Joseph     if (warnLow != 0)
5980ac0dd23STom Joseph     {
5990ac0dd23STom Joseph         warnLow *= pow(10, info.scale - info.exponentR);
6000ac0dd23STom Joseph         response->lowerNonCritical = static_cast<uint8_t>((
6010ac0dd23STom Joseph             warnLow - info.scaledOffset) / info.coefficientM);
6020ac0dd23STom Joseph         response->validMask |= static_cast<uint8_t>(
6030ac0dd23STom Joseph                 ipmi::sensor::ThresholdMask::NON_CRITICAL_LOW_MASK);
6040ac0dd23STom Joseph     }
6050ac0dd23STom Joseph 
6060ac0dd23STom Joseph     if (warnHigh != 0)
6070ac0dd23STom Joseph     {
6080ac0dd23STom Joseph         warnHigh *= pow(10, info.scale - info.exponentR);
6090ac0dd23STom Joseph         response->upperNonCritical = static_cast<uint8_t>((
6100ac0dd23STom Joseph             warnHigh - info.scaledOffset) / info.coefficientM);
6110ac0dd23STom Joseph         response->validMask |= static_cast<uint8_t>(
6120ac0dd23STom Joseph                 ipmi::sensor::ThresholdMask::NON_CRITICAL_HIGH_MASK);
6130ac0dd23STom Joseph     }
6140ac0dd23STom Joseph 
6150ac0dd23STom Joseph     auto critThresholds = ipmi::getAllDbusProperties(bus,
6160ac0dd23STom Joseph                                                      service,
6170ac0dd23STom Joseph                                                      info.sensorPath,
6180ac0dd23STom Joseph                                                      criticalThreshIntf);
6190ac0dd23STom Joseph     double critLow = critThresholds["CriticalLow"].get<int64_t>();
6200ac0dd23STom Joseph     double critHigh = critThresholds["CriticalHigh"].get<int64_t>();
6210ac0dd23STom Joseph 
6220ac0dd23STom Joseph     if (critLow != 0)
6230ac0dd23STom Joseph     {
6240ac0dd23STom Joseph         critLow *= pow(10, info.scale - info.exponentR);
6250ac0dd23STom Joseph         response->lowerCritical = static_cast<uint8_t>((
6260ac0dd23STom Joseph             critLow - info.scaledOffset) / info.coefficientM);
6270ac0dd23STom Joseph         response->validMask |= static_cast<uint8_t>(
6280ac0dd23STom Joseph                 ipmi::sensor::ThresholdMask::CRITICAL_LOW_MASK);
6290ac0dd23STom Joseph     }
6300ac0dd23STom Joseph 
6310ac0dd23STom Joseph     if (critHigh != 0)
6320ac0dd23STom Joseph     {
6330ac0dd23STom Joseph         critHigh *= pow(10, info.scale - info.exponentR);
6340ac0dd23STom Joseph         response->upperCritical = static_cast<uint8_t>((
6350ac0dd23STom Joseph             critHigh - info.scaledOffset)/ info.coefficientM);
6360ac0dd23STom Joseph         response->validMask |= static_cast<uint8_t>(
6370ac0dd23STom Joseph                 ipmi::sensor::ThresholdMask::CRITICAL_HIGH_MASK);
6380ac0dd23STom Joseph     }
6390ac0dd23STom Joseph }
6400ac0dd23STom Joseph 
6415c0beec1SDhruvaraj Subhashchandran ipmi_ret_t ipmi_sen_get_sensor_thresholds(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
6425c0beec1SDhruvaraj Subhashchandran                              ipmi_request_t request, ipmi_response_t response,
6435c0beec1SDhruvaraj Subhashchandran                              ipmi_data_len_t data_len, ipmi_context_t context)
6445c0beec1SDhruvaraj Subhashchandran {
6450ac0dd23STom Joseph     constexpr auto valueInterface = "xyz.openbmc_project.Sensor.Value";
6465c0beec1SDhruvaraj Subhashchandran 
6475c0beec1SDhruvaraj Subhashchandran     if (*data_len != sizeof(uint8_t))
6485c0beec1SDhruvaraj Subhashchandran     {
6490ac0dd23STom Joseph         *data_len = 0;
6505c0beec1SDhruvaraj Subhashchandran         return IPMI_CC_REQ_DATA_LEN_INVALID;
6515c0beec1SDhruvaraj Subhashchandran     }
6525c0beec1SDhruvaraj Subhashchandran 
6530ac0dd23STom Joseph     auto sensorNum = *(reinterpret_cast<const uint8_t *>(request));
6540ac0dd23STom Joseph     *data_len = 0;
6555c0beec1SDhruvaraj Subhashchandran 
6565c0beec1SDhruvaraj Subhashchandran     const auto iter = sensors.find(sensorNum);
6575c0beec1SDhruvaraj Subhashchandran     if (iter == sensors.end())
6585c0beec1SDhruvaraj Subhashchandran     {
6595c0beec1SDhruvaraj Subhashchandran         return IPMI_CC_SENSOR_INVALID;
6605c0beec1SDhruvaraj Subhashchandran     }
6615c0beec1SDhruvaraj Subhashchandran 
6620ac0dd23STom Joseph     const auto info = iter->second;
6635c0beec1SDhruvaraj Subhashchandran 
6645c0beec1SDhruvaraj Subhashchandran     //Proceed only if the sensor value interface is implemented.
6650ac0dd23STom Joseph     if (info.propertyInterfaces.find(valueInterface) ==
6660ac0dd23STom Joseph         info.propertyInterfaces.end())
6675c0beec1SDhruvaraj Subhashchandran     {
6685c0beec1SDhruvaraj Subhashchandran         //return with valid mask as 0
6695c0beec1SDhruvaraj Subhashchandran         return IPMI_CC_OK;
6705c0beec1SDhruvaraj Subhashchandran     }
6715c0beec1SDhruvaraj Subhashchandran 
6720ac0dd23STom Joseph     auto responseData =
6730ac0dd23STom Joseph         reinterpret_cast<get_sdr::GetSensorThresholdsResponse*>(response);
6745c0beec1SDhruvaraj Subhashchandran 
6755c0beec1SDhruvaraj Subhashchandran     try
6765c0beec1SDhruvaraj Subhashchandran     {
6770ac0dd23STom Joseph         getSensorThresholds(sensorNum, responseData);
6785c0beec1SDhruvaraj Subhashchandran     }
6790ac0dd23STom Joseph     catch (std::exception& e)
6805c0beec1SDhruvaraj Subhashchandran     {
6810ac0dd23STom Joseph         //Mask if the property is not present
6825c0beec1SDhruvaraj Subhashchandran         responseData->validMask = 0;
6835c0beec1SDhruvaraj Subhashchandran     }
6845c0beec1SDhruvaraj Subhashchandran 
6855c0beec1SDhruvaraj Subhashchandran     *data_len = sizeof(get_sdr::GetSensorThresholdsResponse);
6865c0beec1SDhruvaraj Subhashchandran     return IPMI_CC_OK;
6875c0beec1SDhruvaraj Subhashchandran }
6885c0beec1SDhruvaraj Subhashchandran 
68998a23840SMatthew Barth ipmi_ret_t ipmi_sen_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
69098a23840SMatthew Barth                              ipmi_request_t request, ipmi_response_t response,
69198a23840SMatthew Barth                              ipmi_data_len_t data_len, ipmi_context_t context)
69298a23840SMatthew Barth {
69370aa8d96SNan Li     ipmi_ret_t rc = IPMI_CC_INVALID;
69498a23840SMatthew Barth 
69598a23840SMatthew Barth     printf("IPMI S/E Wildcard Netfn:[0x%X], Cmd:[0x%X]\n",netfn,cmd);
69698a23840SMatthew Barth     *data_len = 0;
69798a23840SMatthew Barth 
69898a23840SMatthew Barth     return rc;
69998a23840SMatthew Barth }
70098a23840SMatthew Barth 
701d06e0e7eSEmily Shaffer ipmi_ret_t ipmi_sen_get_sdr_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
702d06e0e7eSEmily Shaffer                                  ipmi_request_t request,
703d06e0e7eSEmily Shaffer                                  ipmi_response_t response,
704d06e0e7eSEmily Shaffer                                  ipmi_data_len_t data_len,
705d06e0e7eSEmily Shaffer                                  ipmi_context_t context)
706d06e0e7eSEmily Shaffer {
707d06e0e7eSEmily Shaffer     auto resp = static_cast<get_sdr_info::GetSdrInfoResp*>(response);
708d06e0e7eSEmily Shaffer     if (request == nullptr ||
709d06e0e7eSEmily Shaffer         get_sdr_info::request::get_count(request) == false)
710d06e0e7eSEmily Shaffer     {
711d06e0e7eSEmily Shaffer         // Get Sensor Count
712e0cc8553SRatan Gupta         resp->count = sensors.size() + frus.size();
713d06e0e7eSEmily Shaffer     }
714d06e0e7eSEmily Shaffer     else
715d06e0e7eSEmily Shaffer     {
716d06e0e7eSEmily Shaffer         resp->count = 1;
717d06e0e7eSEmily Shaffer     }
718d06e0e7eSEmily Shaffer 
719d06e0e7eSEmily Shaffer     // Multiple LUNs not supported.
720d06e0e7eSEmily Shaffer     namespace response = get_sdr_info::response;
721d06e0e7eSEmily Shaffer     response::set_lun_present(0, &(resp->luns_and_dynamic_population));
722d06e0e7eSEmily Shaffer     response::set_lun_not_present(1, &(resp->luns_and_dynamic_population));
723d06e0e7eSEmily Shaffer     response::set_lun_not_present(2, &(resp->luns_and_dynamic_population));
724d06e0e7eSEmily Shaffer     response::set_lun_not_present(3, &(resp->luns_and_dynamic_population));
725d06e0e7eSEmily Shaffer     response::set_static_population(&(resp->luns_and_dynamic_population));
726d06e0e7eSEmily Shaffer 
727d06e0e7eSEmily Shaffer     *data_len = SDR_INFO_RESP_SIZE;
728d06e0e7eSEmily Shaffer 
729d06e0e7eSEmily Shaffer     return IPMI_CC_OK;
730d06e0e7eSEmily Shaffer }
731d06e0e7eSEmily Shaffer 
732a344afc0SEmily Shaffer ipmi_ret_t ipmi_sen_reserve_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
733a344afc0SEmily Shaffer                                 ipmi_request_t request,
734a344afc0SEmily Shaffer                                 ipmi_response_t response,
735a344afc0SEmily Shaffer                                 ipmi_data_len_t data_len,
736a344afc0SEmily Shaffer                                 ipmi_context_t context)
737a344afc0SEmily Shaffer {
738a344afc0SEmily Shaffer     // A constant reservation ID is okay until we implement add/remove SDR.
739a344afc0SEmily Shaffer     const uint16_t reservation_id = 1;
740a344afc0SEmily Shaffer     *(uint16_t*)response = reservation_id;
7415a5a6282SEmily Shaffer     *data_len = sizeof(uint16_t);
742a344afc0SEmily Shaffer 
743a344afc0SEmily Shaffer     printf("Created new IPMI SDR reservation ID %d\n", *(uint16_t*)response);
744a344afc0SEmily Shaffer     return IPMI_CC_OK;
745a344afc0SEmily Shaffer }
74698a23840SMatthew Barth 
747dc212b23STom Joseph void setUnitFieldsForObject(const ipmi::sensor::Info *info,
748cc941e15SEmily Shaffer                             get_sdr::SensorDataFullRecordBody *body)
749bbef71c2SEmily Shaffer {
750bbef71c2SEmily Shaffer     namespace server = sdbusplus::xyz::openbmc_project::Sensor::server;
751dc212b23STom Joseph     try
752dc212b23STom Joseph     {
753dc212b23STom Joseph         auto unit = server::Value::convertUnitFromString(info->unit);
754bbef71c2SEmily Shaffer         // Unit strings defined in
755bbef71c2SEmily Shaffer         // phosphor-dbus-interfaces/xyz/openbmc_project/Sensor/Value.interface.yaml
756bbef71c2SEmily Shaffer         switch (unit)
757bbef71c2SEmily Shaffer         {
758bbef71c2SEmily Shaffer             case server::Value::Unit::DegreesC:
759bbef71c2SEmily Shaffer                 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_DEGREES_C;
760bbef71c2SEmily Shaffer                 break;
761bbef71c2SEmily Shaffer             case server::Value::Unit::RPMS:
762bbef71c2SEmily Shaffer                 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_REVOLUTIONS; // revolutions
763bbef71c2SEmily Shaffer                 get_sdr::body::set_rate_unit(0b100, body); // per minute
764bbef71c2SEmily Shaffer                 break;
765bbef71c2SEmily Shaffer             case server::Value::Unit::Volts:
766bbef71c2SEmily Shaffer                 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_VOLTS;
767bbef71c2SEmily Shaffer                 break;
768bbef71c2SEmily Shaffer             case server::Value::Unit::Meters:
769bbef71c2SEmily Shaffer                 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_METERS;
770bbef71c2SEmily Shaffer                 break;
771bbef71c2SEmily Shaffer             case server::Value::Unit::Amperes:
772bbef71c2SEmily Shaffer                 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_AMPERES;
773bbef71c2SEmily Shaffer                 break;
774bbef71c2SEmily Shaffer             case server::Value::Unit::Joules:
775bbef71c2SEmily Shaffer                 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_JOULES;
776bbef71c2SEmily Shaffer                 break;
777dc212b23STom Joseph             case server::Value::Unit::Watts:
778dc212b23STom Joseph                 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_WATTS;
779dc212b23STom Joseph                 break;
780bbef71c2SEmily Shaffer             default:
781cc941e15SEmily Shaffer                 // Cannot be hit.
782dc212b23STom Joseph                 fprintf(stderr, "Unknown value unit type: = %s\n",
783dc212b23STom Joseph                         info->unit.c_str());
784cc941e15SEmily Shaffer         }
785cc941e15SEmily Shaffer     }
786cc941e15SEmily Shaffer     catch (sdbusplus::exception::InvalidEnumString e)
787cc941e15SEmily Shaffer     {
788cc941e15SEmily Shaffer         log<level::WARNING>("Warning: no unit provided for sensor!");
789cc941e15SEmily Shaffer     }
790cc941e15SEmily Shaffer }
791cc941e15SEmily Shaffer 
792cc941e15SEmily Shaffer ipmi_ret_t populate_record_from_dbus(get_sdr::SensorDataFullRecordBody *body,
793cc941e15SEmily Shaffer                                      const ipmi::sensor::Info *info,
794cc941e15SEmily Shaffer                                      ipmi_data_len_t data_len)
795cc941e15SEmily Shaffer {
796cc941e15SEmily Shaffer     /* Functional sensor case */
797cc941e15SEmily Shaffer     if (isAnalogSensor(info->propertyInterfaces.begin()->first))
798cc941e15SEmily Shaffer     {
799cc941e15SEmily Shaffer 
800cc941e15SEmily Shaffer         body->sensor_units_1 = 0; // unsigned, no rate, no modifier, not a %
801cc941e15SEmily Shaffer 
802cc941e15SEmily Shaffer         /* Unit info */
803dc212b23STom Joseph         setUnitFieldsForObject(info, body);
80410f4959aSEmily Shaffer 
80510f4959aSEmily Shaffer         get_sdr::body::set_b(info->coefficientB, body);
80610f4959aSEmily Shaffer         get_sdr::body::set_m(info->coefficientM, body);
80710f4959aSEmily Shaffer         get_sdr::body::set_b_exp(info->exponentB, body);
808dc212b23STom Joseph         get_sdr::body::set_r_exp(info->exponentR, body);
809bbef71c2SEmily Shaffer 
810bbef71c2SEmily Shaffer         get_sdr::body::set_id_type(0b00, body); // 00 = unicode
8119642391dSTom Joseph     }
8129642391dSTom Joseph 
8139642391dSTom Joseph     /* ID string */
8149642391dSTom Joseph     auto id_string = info->sensorNameFunc(*info);
8159642391dSTom Joseph 
816bbef71c2SEmily Shaffer     if (id_string.length() > FULL_RECORD_ID_STR_MAX_LENGTH)
817bbef71c2SEmily Shaffer     {
818bbef71c2SEmily Shaffer         get_sdr::body::set_id_strlen(FULL_RECORD_ID_STR_MAX_LENGTH, body);
819bbef71c2SEmily Shaffer     }
820bbef71c2SEmily Shaffer     else
821bbef71c2SEmily Shaffer     {
822bbef71c2SEmily Shaffer         get_sdr::body::set_id_strlen(id_string.length(), body);
823bbef71c2SEmily Shaffer     }
824bbef71c2SEmily Shaffer     strncpy(body->id_string, id_string.c_str(),
825bbef71c2SEmily Shaffer             get_sdr::body::get_id_strlen(body));
826bbef71c2SEmily Shaffer 
827bbef71c2SEmily Shaffer     return IPMI_CC_OK;
828bbef71c2SEmily Shaffer };
829bbef71c2SEmily Shaffer 
830e0cc8553SRatan Gupta ipmi_ret_t ipmi_fru_get_sdr(ipmi_request_t request, ipmi_response_t response,
831e0cc8553SRatan Gupta                             ipmi_data_len_t data_len)
832e0cc8553SRatan Gupta {
833e0cc8553SRatan Gupta     auto req = reinterpret_cast<get_sdr::GetSdrReq*>(request);
834e0cc8553SRatan Gupta     auto resp = reinterpret_cast<get_sdr::GetSdrResp*>(response);
835e0cc8553SRatan Gupta     get_sdr::SensorDataFruRecord record {};
836e0cc8553SRatan Gupta     auto dataLength = 0;
837e0cc8553SRatan Gupta 
838e0cc8553SRatan Gupta     auto fru = frus.begin();
839e0cc8553SRatan Gupta     uint8_t fruID {};
840e0cc8553SRatan Gupta     auto recordID = get_sdr::request::get_record_id(req);
841e0cc8553SRatan Gupta 
842e0cc8553SRatan Gupta     fruID = recordID - FRU_RECORD_ID_START;
843e0cc8553SRatan Gupta     fru = frus.find(fruID);
844e0cc8553SRatan Gupta     if (fru == frus.end())
845e0cc8553SRatan Gupta     {
846e0cc8553SRatan Gupta         return IPMI_CC_SENSOR_INVALID;
847e0cc8553SRatan Gupta     }
848e0cc8553SRatan Gupta 
849e0cc8553SRatan Gupta     /* Header */
850e0cc8553SRatan Gupta     get_sdr::header::set_record_id(recordID, &(record.header));
851e0cc8553SRatan Gupta     record.header.sdr_version = SDR_VERSION; // Based on IPMI Spec v2.0 rev 1.1
852e0cc8553SRatan Gupta     record.header.record_type = get_sdr::SENSOR_DATA_FRU_RECORD;
853e0cc8553SRatan Gupta     record.header.record_length = sizeof(record.key) + sizeof(record.body);
854e0cc8553SRatan Gupta 
855e0cc8553SRatan Gupta     /* Key */
856e0cc8553SRatan Gupta     record.key.fruID = fruID;
857e0cc8553SRatan Gupta     record.key.accessLun |= IPMI_LOGICAL_FRU;
858e0cc8553SRatan Gupta     record.key.deviceAddress = BMCSlaveAddress;
859e0cc8553SRatan Gupta 
860e0cc8553SRatan Gupta     /* Body */
861e0cc8553SRatan Gupta     record.body.entityID = fru->second[0].entityID;
862e0cc8553SRatan Gupta     record.body.entityInstance = fru->second[0].entityInstance;
863e0cc8553SRatan Gupta     record.body.deviceType = fruInventoryDevice;
864e0cc8553SRatan Gupta     record.body.deviceTypeModifier = IPMIFruInventory;
865e0cc8553SRatan Gupta 
866e0cc8553SRatan Gupta     /* Device ID string */
867e0cc8553SRatan Gupta     auto deviceID = fru->second[0].path.substr(
868e0cc8553SRatan Gupta             fru->second[0].path.find_last_of('/') + 1,
869e0cc8553SRatan Gupta             fru->second[0].path.length());
870e0cc8553SRatan Gupta 
871e0cc8553SRatan Gupta 
872e0cc8553SRatan Gupta     if (deviceID.length() > get_sdr::FRU_RECORD_DEVICE_ID_MAX_LENGTH)
873e0cc8553SRatan Gupta     {
874e0cc8553SRatan Gupta         get_sdr::body::set_device_id_strlen(
875e0cc8553SRatan Gupta                 get_sdr::FRU_RECORD_DEVICE_ID_MAX_LENGTH,
876e0cc8553SRatan Gupta                 &(record.body));
877e0cc8553SRatan Gupta     }
878e0cc8553SRatan Gupta     else
879e0cc8553SRatan Gupta     {
880e0cc8553SRatan Gupta         get_sdr::body::set_device_id_strlen(deviceID.length(),
881e0cc8553SRatan Gupta                 &(record.body));
882e0cc8553SRatan Gupta     }
883e0cc8553SRatan Gupta 
884e0cc8553SRatan Gupta     strncpy(record.body.deviceID, deviceID.c_str(),
885e0cc8553SRatan Gupta             get_sdr::body::get_device_id_strlen(&(record.body)));
886e0cc8553SRatan Gupta 
887e0cc8553SRatan Gupta     if (++fru == frus.end())
888e0cc8553SRatan Gupta     {
889e0cc8553SRatan Gupta         get_sdr::response::set_next_record_id(END_OF_RECORD, resp); // last record
890e0cc8553SRatan Gupta     }
891e0cc8553SRatan Gupta     else
892e0cc8553SRatan Gupta     {
893e0cc8553SRatan Gupta         get_sdr::response::set_next_record_id(
894e0cc8553SRatan Gupta                 (FRU_RECORD_ID_START + fru->first), resp);
895e0cc8553SRatan Gupta     }
896e0cc8553SRatan Gupta 
897e0cc8553SRatan Gupta     if (req->bytes_to_read > (sizeof(*resp) - req->offset))
898e0cc8553SRatan Gupta     {
899e0cc8553SRatan Gupta         dataLength = (sizeof(*resp) - req->offset);
900e0cc8553SRatan Gupta     }
901e0cc8553SRatan Gupta     else
902e0cc8553SRatan Gupta     {
903e0cc8553SRatan Gupta         dataLength =  req->bytes_to_read;
904e0cc8553SRatan Gupta     }
905e0cc8553SRatan Gupta 
906e0cc8553SRatan Gupta     if (dataLength <= 0)
907e0cc8553SRatan Gupta     {
908e0cc8553SRatan Gupta         return IPMI_CC_REQ_DATA_LEN_INVALID;
909e0cc8553SRatan Gupta     }
910e0cc8553SRatan Gupta 
911e0cc8553SRatan Gupta     memcpy(resp->record_data,
912e0cc8553SRatan Gupta             reinterpret_cast<uint8_t*>(&record) + req->offset,
913e0cc8553SRatan Gupta             (dataLength));
914e0cc8553SRatan Gupta 
915e0cc8553SRatan Gupta     *data_len = dataLength;
916e0cc8553SRatan Gupta     *data_len += 2; // additional 2 bytes for next record ID
917e0cc8553SRatan Gupta 
918e0cc8553SRatan Gupta     return IPMI_CC_OK;
919e0cc8553SRatan Gupta }
920e0cc8553SRatan Gupta 
921bbef71c2SEmily Shaffer ipmi_ret_t ipmi_sen_get_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
922bbef71c2SEmily Shaffer                             ipmi_request_t request, ipmi_response_t response,
923bbef71c2SEmily Shaffer                             ipmi_data_len_t data_len, ipmi_context_t context)
924bbef71c2SEmily Shaffer {
925bbef71c2SEmily Shaffer     ipmi_ret_t ret = IPMI_CC_OK;
926bbef71c2SEmily Shaffer     get_sdr::GetSdrReq *req = (get_sdr::GetSdrReq*)request;
927bbef71c2SEmily Shaffer     get_sdr::GetSdrResp *resp = (get_sdr::GetSdrResp*)response;
928bbef71c2SEmily Shaffer     get_sdr::SensorDataFullRecord record = {0};
929bbef71c2SEmily Shaffer     if (req != NULL)
930bbef71c2SEmily Shaffer     {
931bbef71c2SEmily Shaffer         // Note: we use an iterator so we can provide the next ID at the end of
932bbef71c2SEmily Shaffer         // the call.
933bbef71c2SEmily Shaffer         auto sensor = sensors.begin();
934e0cc8553SRatan Gupta         auto recordID = get_sdr::request::get_record_id(req);
935bbef71c2SEmily Shaffer 
936bbef71c2SEmily Shaffer         // At the beginning of a scan, the host side will send us id=0.
937e0cc8553SRatan Gupta         if (recordID != 0)
938bbef71c2SEmily Shaffer         {
939e0cc8553SRatan Gupta             // recordID greater then 255,it means it is a FRU record.
940e0cc8553SRatan Gupta             // Currently we are supporting two record types either FULL record
941e0cc8553SRatan Gupta             // or FRU record.
942e0cc8553SRatan Gupta             if (recordID >= FRU_RECORD_ID_START)
943e0cc8553SRatan Gupta             {
944e0cc8553SRatan Gupta                 return ipmi_fru_get_sdr(request, response, data_len);
945e0cc8553SRatan Gupta             }
946e0cc8553SRatan Gupta             else
947e0cc8553SRatan Gupta             {
948e0cc8553SRatan Gupta                 sensor = sensors.find(recordID);
949e0cc8553SRatan Gupta                 if (sensor == sensors.end())
950e0cc8553SRatan Gupta                 {
951bbef71c2SEmily Shaffer                     return IPMI_CC_SENSOR_INVALID;
952bbef71c2SEmily Shaffer                 }
953bbef71c2SEmily Shaffer             }
954e0cc8553SRatan Gupta         }
955bbef71c2SEmily Shaffer 
956bbef71c2SEmily Shaffer         uint8_t sensor_id = sensor->first;
957bbef71c2SEmily Shaffer 
958bbef71c2SEmily Shaffer         /* Header */
959bbef71c2SEmily Shaffer         get_sdr::header::set_record_id(sensor_id, &(record.header));
960bbef71c2SEmily Shaffer         record.header.sdr_version = 0x51; // Based on IPMI Spec v2.0 rev 1.1
961bbef71c2SEmily Shaffer         record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
962bbef71c2SEmily Shaffer         record.header.record_length = sizeof(get_sdr::SensorDataFullRecord);
963bbef71c2SEmily Shaffer 
964bbef71c2SEmily Shaffer         /* Key */
9659642391dSTom Joseph         get_sdr::key::set_owner_id_bmc(&(record.key));
966bbef71c2SEmily Shaffer         record.key.sensor_number = sensor_id;
967bbef71c2SEmily Shaffer 
968bbef71c2SEmily Shaffer         /* Body */
9699642391dSTom Joseph         record.body.entity_id = sensor->second.entityType;
970bbef71c2SEmily Shaffer         record.body.sensor_type = sensor->second.sensorType;
971bbef71c2SEmily Shaffer         record.body.event_reading_type = sensor->second.sensorReadingType;
9729642391dSTom Joseph         record.body.entity_instance = sensor->second.instance;
973bbef71c2SEmily Shaffer 
974bbef71c2SEmily Shaffer         // Set the type-specific details given the DBus interface
975bbef71c2SEmily Shaffer         ret = populate_record_from_dbus(&(record.body), &(sensor->second),
976bbef71c2SEmily Shaffer                                         data_len);
977bbef71c2SEmily Shaffer 
978bbef71c2SEmily Shaffer         if (++sensor == sensors.end())
979bbef71c2SEmily Shaffer         {
980e0cc8553SRatan Gupta             // we have reached till end of sensor, so assign the next record id
981e0cc8553SRatan Gupta             // to 256(Max Sensor ID = 255) + FRU ID(may start with 0).
982e0cc8553SRatan Gupta             auto next_record_id = (frus.size()) ?
983e0cc8553SRatan Gupta                 frus.begin()->first + FRU_RECORD_ID_START :
984e0cc8553SRatan Gupta                 END_OF_RECORD;
985e0cc8553SRatan Gupta 
986e0cc8553SRatan Gupta             get_sdr::response::set_next_record_id(next_record_id, resp);
987bbef71c2SEmily Shaffer         }
988bbef71c2SEmily Shaffer         else
989bbef71c2SEmily Shaffer         {
990bbef71c2SEmily Shaffer             get_sdr::response::set_next_record_id(sensor->first, resp);
991bbef71c2SEmily Shaffer         }
992bbef71c2SEmily Shaffer 
993bbef71c2SEmily Shaffer         *data_len = sizeof(get_sdr::GetSdrResp) - req->offset;
994bbef71c2SEmily Shaffer         memcpy(resp->record_data, (char*)&record + req->offset,
995bbef71c2SEmily Shaffer                sizeof(get_sdr::SensorDataFullRecord) - req->offset);
996bbef71c2SEmily Shaffer     }
997bbef71c2SEmily Shaffer 
998bbef71c2SEmily Shaffer     return ret;
999bbef71c2SEmily Shaffer }
1000bbef71c2SEmily Shaffer 
1001bbef71c2SEmily Shaffer 
100298a23840SMatthew Barth void register_netfn_sen_functions()
100398a23840SMatthew Barth {
10040573237fSTom     // <Wildcard Command>
1005a344afc0SEmily Shaffer     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
1006a344afc0SEmily Shaffer            NETFUN_SENSOR, IPMI_CMD_WILDCARD);
1007a344afc0SEmily Shaffer     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_WILDCARD,
1008a344afc0SEmily Shaffer                            nullptr, ipmi_sen_wildcard,
10090573237fSTom                            PRIVILEGE_USER);
101098a23840SMatthew Barth 
10110573237fSTom     // <Get Sensor Type>
1012a344afc0SEmily Shaffer     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
1013a344afc0SEmily Shaffer            NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_TYPE);
1014a344afc0SEmily Shaffer     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_TYPE,
1015a344afc0SEmily Shaffer                            nullptr, ipmi_sen_get_sensor_type,
10160573237fSTom                            PRIVILEGE_USER);
101798a23840SMatthew Barth 
10180573237fSTom     // <Set Sensor Reading and Event Status>
1019a344afc0SEmily Shaffer     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
1020a344afc0SEmily Shaffer            NETFUN_SENSOR, IPMI_CMD_SET_SENSOR);
1021a344afc0SEmily Shaffer     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_SET_SENSOR,
1022a344afc0SEmily Shaffer                            nullptr, ipmi_sen_set_sensor,
10230573237fSTom                            PRIVILEGE_OPERATOR);
102498a23840SMatthew Barth 
10250573237fSTom     // <Get Sensor Reading>
1026a344afc0SEmily Shaffer     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
1027a344afc0SEmily Shaffer            NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_READING);
1028a344afc0SEmily Shaffer     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_READING,
1029a344afc0SEmily Shaffer                            nullptr, ipmi_sen_get_sensor_reading,
1030a344afc0SEmily Shaffer                            PRIVILEGE_USER);
1031a344afc0SEmily Shaffer 
10325ca50959STom Joseph     // <Reserve Device SDR Repository>
10335ca50959STom Joseph     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_RESERVE_DEVICE_SDR_REPO,
1034a344afc0SEmily Shaffer                            nullptr, ipmi_sen_reserve_sdr,
1035a344afc0SEmily Shaffer                            PRIVILEGE_USER);
103698a23840SMatthew Barth 
10375ca50959STom Joseph     // <Get Device SDR Info>
10385ca50959STom Joseph     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_DEVICE_SDR_INFO,
1039a344afc0SEmily Shaffer                            nullptr, ipmi_sen_get_sdr_info,
1040a344afc0SEmily Shaffer                            PRIVILEGE_USER);
1041bbef71c2SEmily Shaffer 
10425ca50959STom Joseph     // <Get Device SDR>
10435ca50959STom Joseph     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_DEVICE_SDR,
1044bbef71c2SEmily Shaffer                            nullptr, ipmi_sen_get_sdr,
1045bbef71c2SEmily Shaffer                            PRIVILEGE_USER);
1046bbef71c2SEmily Shaffer 
10475c0beec1SDhruvaraj Subhashchandran     // <Get Sensor Thresholds>
10485c0beec1SDhruvaraj Subhashchandran     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_THRESHOLDS,
10495c0beec1SDhruvaraj Subhashchandran                            nullptr, ipmi_sen_get_sensor_thresholds,
10505c0beec1SDhruvaraj Subhashchandran                            PRIVILEGE_USER);
10515c0beec1SDhruvaraj Subhashchandran 
105298a23840SMatthew Barth     return;
105398a23840SMatthew Barth }
1054