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>
12d700e76aSTom #include "ipmid.hpp"
13be703f71STom Joseph #include "sensorhandler.h"
14be703f71STom Joseph #include "types.hpp"
15be703f71STom Joseph #include "utils.hpp"
1618e99992SDhruvaraj Subhashchandran #include "xyz/openbmc_project/Common/error.hpp"
1718e99992SDhruvaraj Subhashchandran 
1898a23840SMatthew Barth extern int updateSensorRecordFromSSRAESC(const void *);
19d700e76aSTom extern sd_bus *bus;
20be703f71STom Joseph extern const ipmi::sensor::IdInfoMap sensors;
21be703f71STom Joseph using namespace phosphor::logging;
2218e99992SDhruvaraj Subhashchandran using InternalFailure =
2318e99992SDhruvaraj Subhashchandran     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
2498a23840SMatthew Barth 
2598a23840SMatthew Barth void register_netfn_sen_functions()   __attribute__((constructor));
2698a23840SMatthew Barth 
2798a23840SMatthew Barth struct sensorTypemap_t {
2898a23840SMatthew Barth     uint8_t number;
2998a23840SMatthew Barth     uint8_t typecode;
3098a23840SMatthew Barth     char dbusname[32];
3198a23840SMatthew Barth } ;
3298a23840SMatthew Barth 
3398a23840SMatthew Barth sensorTypemap_t g_SensorTypeMap[] = {
3498a23840SMatthew Barth 
3598a23840SMatthew Barth     {0x01, 0x6F, "Temp"},
3698a23840SMatthew Barth     {0x0C, 0x6F, "DIMM"},
3798a23840SMatthew Barth     {0x0C, 0x6F, "MEMORY_BUFFER"},
3898a23840SMatthew Barth     {0x07, 0x6F, "PROC"},
3998a23840SMatthew Barth     {0x07, 0x6F, "CORE"},
4098a23840SMatthew Barth     {0x07, 0x6F, "CPU"},
4198a23840SMatthew Barth     {0x0F, 0x6F, "BootProgress"},
4298a23840SMatthew Barth     {0xe9, 0x09, "OccStatus"},  // E9 is an internal mapping to handle sensor type code os 0x09
4398a23840SMatthew Barth     {0xC3, 0x6F, "BootCount"},
4498a23840SMatthew Barth     {0x1F, 0x6F, "OperatingSystemStatus"},
4598a23840SMatthew Barth     {0x12, 0x6F, "SYSTEM_EVENT"},
4698a23840SMatthew Barth     {0xC7, 0x03, "SYSTEM"},
4798a23840SMatthew Barth     {0xC7, 0x03, "MAIN_PLANAR"},
4898a23840SMatthew Barth     {0xC2, 0x6F, "PowerCap"},
49558184eaSTom Joseph     {0x0b, 0xCA, "PowerSupplyRedundancy"},
500661beb1SJayanth Othayoth     {0xDA, 0x03, "TurboAllowed"},
51558184eaSTom Joseph     {0xD8, 0xC8, "PowerSupplyDerating"},
5298a23840SMatthew Barth     {0xFF, 0x00, ""},
5398a23840SMatthew Barth };
5498a23840SMatthew Barth 
5598a23840SMatthew Barth 
5698a23840SMatthew Barth struct sensor_data_t {
5798a23840SMatthew Barth     uint8_t sennum;
5898a23840SMatthew Barth }  __attribute__ ((packed)) ;
5998a23840SMatthew Barth 
6098a23840SMatthew Barth struct sensorreadingresp_t {
6198a23840SMatthew Barth     uint8_t value;
6298a23840SMatthew Barth     uint8_t operation;
6398a23840SMatthew Barth     uint8_t indication[2];
6498a23840SMatthew Barth }  __attribute__ ((packed)) ;
6598a23840SMatthew Barth 
66d700e76aSTom // Use a lookup table to find the interface name of a specific sensor
67d700e76aSTom // This will be used until an alternative is found.  this is the first
68d700e76aSTom // step for mapping IPMI
69d700e76aSTom int find_interface_property_fru_type(dbus_interface_t *interface, const char *property_name, char *property_value) {
70d700e76aSTom 
71d700e76aSTom     char  *str1;
72d700e76aSTom     sd_bus_error error = SD_BUS_ERROR_NULL;
73d700e76aSTom     sd_bus_message *reply = NULL, *m=NULL;
74d700e76aSTom 
75d700e76aSTom 
76d700e76aSTom     int r;
77d700e76aSTom 
78d700e76aSTom     r = sd_bus_message_new_method_call(bus,&m,interface->bus,interface->path,"org.freedesktop.DBus.Properties","Get");
79d700e76aSTom     if (r < 0) {
80d700e76aSTom         fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
81d700e76aSTom         fprintf(stderr,"Bus: %s Path: %s Interface: %s \n",
82d700e76aSTom                 interface->bus, interface->path, interface->interface);
83d700e76aSTom         goto final;
84d700e76aSTom     }
85d700e76aSTom 
86d700e76aSTom     r = sd_bus_message_append(m, "ss", "org.openbmc.InventoryItem", property_name);
87d700e76aSTom     if (r < 0) {
88d700e76aSTom         fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r));
89d700e76aSTom         fprintf(stderr,"Bus: %s Path: %s Interface: %s \n",
90d700e76aSTom                 interface->bus, interface->path, interface->interface);
91d700e76aSTom         goto final;
92d700e76aSTom     }
93d700e76aSTom 
94d700e76aSTom     r = sd_bus_call(bus, m, 0, &error, &reply);
95d700e76aSTom     if (r < 0) {
96d700e76aSTom         fprintf(stderr, "Failed to call the method: %s", strerror(-r));
97d700e76aSTom         goto final;
98d700e76aSTom     }
99d700e76aSTom 
100d700e76aSTom     r = sd_bus_message_read(reply, "v",  "s", &str1) ;
101d700e76aSTom     if (r < 0) {
102d700e76aSTom         fprintf(stderr, "Failed to get a response: %s", strerror(-r));
103d700e76aSTom         goto final;
104d700e76aSTom     }
105d700e76aSTom 
106d700e76aSTom     strcpy(property_value, str1);
107d700e76aSTom 
108d700e76aSTom final:
109d700e76aSTom 
110d700e76aSTom     sd_bus_error_free(&error);
111d700e76aSTom     m = sd_bus_message_unref(m);
112d700e76aSTom     reply = sd_bus_message_unref(reply);
113d700e76aSTom 
114d700e76aSTom     return r;
115d700e76aSTom }
116d700e76aSTom 
1172ae09b9aSEmily Shaffer int get_bus_for_path(const char *path, char **busname) {
1182ae09b9aSEmily Shaffer     return mapper_get_service(bus, path, busname);
1192ae09b9aSEmily Shaffer }
120d700e76aSTom 
1212ae09b9aSEmily Shaffer int legacy_dbus_openbmc_path(const char *type, const uint8_t num, dbus_interface_t *interface) {
122d700e76aSTom     char  *busname = NULL;
123d700e76aSTom     const char  *iface = "org.openbmc.managers.System";
124d700e76aSTom     const char  *objname = "/org/openbmc/managers/System";
125d700e76aSTom     char  *str1 = NULL, *str2, *str3;
126d700e76aSTom     sd_bus_error error = SD_BUS_ERROR_NULL;
127d700e76aSTom     sd_bus_message *reply = NULL;
128d700e76aSTom 
129d700e76aSTom 
130d700e76aSTom     int r;
1312ae09b9aSEmily Shaffer     r = get_bus_for_path(objname, &busname);
132d700e76aSTom     if (r < 0) {
133819ddd42SBrad Bishop         fprintf(stderr, "Failed to get %s busname: %s\n",
134819ddd42SBrad Bishop                 objname, strerror(-r));
135d700e76aSTom         goto final;
136d700e76aSTom     }
137d700e76aSTom 
138d700e76aSTom     r = sd_bus_call_method(bus,busname,objname,iface, "getObjectFromByteId",
139d700e76aSTom                            &error, &reply, "sy", type, num);
140d700e76aSTom     if (r < 0) {
141d700e76aSTom         fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
142d700e76aSTom         goto final;
143d700e76aSTom     }
144d700e76aSTom 
145d700e76aSTom     r = sd_bus_message_read(reply, "(ss)", &str2, &str3);
146d700e76aSTom     if (r < 0) {
147d700e76aSTom         fprintf(stderr, "Failed to get a response: %s", strerror(-r));
148d700e76aSTom         goto final;
149d700e76aSTom     }
150d700e76aSTom 
1512ae09b9aSEmily Shaffer     r = get_bus_for_path(str2, &str1);
152d700e76aSTom     if (r < 0) {
153819ddd42SBrad Bishop         fprintf(stderr, "Failed to get %s busname: %s\n",
154819ddd42SBrad Bishop                 str2, strerror(-r));
155d700e76aSTom         goto final;
156d700e76aSTom     }
157d700e76aSTom 
158d700e76aSTom     strncpy(interface->bus, str1, MAX_DBUS_PATH);
159d700e76aSTom     strncpy(interface->path, str2, MAX_DBUS_PATH);
160d700e76aSTom     strncpy(interface->interface, str3, MAX_DBUS_PATH);
161d700e76aSTom 
162d700e76aSTom     interface->sensornumber = num;
1637117441cSEmily Shaffer     // Make sure we know that the type hasn't been set, as newer codebase will
1647117441cSEmily Shaffer     // set it automatically from the YAML at this step.
1657117441cSEmily Shaffer     interface->sensortype = 0;
166d700e76aSTom 
167d700e76aSTom final:
168d700e76aSTom 
169d700e76aSTom     sd_bus_error_free(&error);
170d700e76aSTom     reply = sd_bus_message_unref(reply);
171d700e76aSTom     free(busname);
172d700e76aSTom     free(str1);
173d700e76aSTom 
174d700e76aSTom     return r;
175d700e76aSTom }
176d700e76aSTom 
1772ae09b9aSEmily Shaffer // Use a lookup table to find the interface name of a specific sensor
1782ae09b9aSEmily Shaffer // This will be used until an alternative is found.  this is the first
1792ae09b9aSEmily Shaffer // step for mapping IPMI
1802ae09b9aSEmily Shaffer int find_openbmc_path(uint8_t num, dbus_interface_t *interface) {
1812ae09b9aSEmily Shaffer     int rc;
1822ae09b9aSEmily Shaffer 
1832ae09b9aSEmily Shaffer     // When the sensor map does not contain the sensor requested,
1842ae09b9aSEmily Shaffer     // fall back to the legacy DBus lookup (deprecated)
1852ae09b9aSEmily Shaffer     const auto& sensor_it = sensors.find(num);
1862ae09b9aSEmily Shaffer     if (sensor_it == sensors.end())
1872ae09b9aSEmily Shaffer     {
1882ae09b9aSEmily Shaffer         return legacy_dbus_openbmc_path("SENSOR", num, interface);
1892ae09b9aSEmily Shaffer     }
1902ae09b9aSEmily Shaffer 
1912ae09b9aSEmily Shaffer     const auto& info = sensor_it->second;
1922ae09b9aSEmily Shaffer 
1938451edf5SPatrick Williams     char* busname = nullptr;
1942ae09b9aSEmily Shaffer     rc = get_bus_for_path(info.sensorPath.c_str(), &busname);
1952ae09b9aSEmily Shaffer     if (rc < 0) {
1962ae09b9aSEmily Shaffer         fprintf(stderr, "Failed to get %s busname: %s\n",
1972ae09b9aSEmily Shaffer                 info.sensorPath.c_str(),
1982ae09b9aSEmily Shaffer                 busname);
1992ae09b9aSEmily Shaffer         goto final;
2002ae09b9aSEmily Shaffer     }
2012ae09b9aSEmily Shaffer 
2022ae09b9aSEmily Shaffer     interface->sensortype = info.sensorType;
2032ae09b9aSEmily Shaffer     strcpy(interface->bus, busname);
2042ae09b9aSEmily Shaffer     strcpy(interface->path, info.sensorPath.c_str());
2052ae09b9aSEmily Shaffer     // Take the interface name from the beginning of the DbusInterfaceMap. This
2062ae09b9aSEmily Shaffer     // works for the Value interface but may not suffice for more complex
2072ae09b9aSEmily Shaffer     // sensors.
2082ae09b9aSEmily Shaffer     // tracked https://github.com/openbmc/phosphor-host-ipmid/issues/103
2091bb0d387SDeepak Kodihalli     strcpy(interface->interface, info.propertyInterfaces.begin()->first.c_str());
2102ae09b9aSEmily Shaffer     interface->sensornumber = num;
2112ae09b9aSEmily Shaffer 
2122ae09b9aSEmily Shaffer final:
2132ae09b9aSEmily Shaffer     free(busname);
2142ae09b9aSEmily Shaffer     return rc;
2152ae09b9aSEmily Shaffer }
2162ae09b9aSEmily Shaffer 
217d700e76aSTom 
218d700e76aSTom /////////////////////////////////////////////////////////////////////
219d700e76aSTom //
220d700e76aSTom // Routines used by ipmi commands wanting to interact on the dbus
221d700e76aSTom //
222d700e76aSTom /////////////////////////////////////////////////////////////////////
223d700e76aSTom int set_sensor_dbus_state_s(uint8_t number, const char *method, const char *value) {
224d700e76aSTom 
225d700e76aSTom 
226d700e76aSTom     dbus_interface_t a;
227d700e76aSTom     int r;
228d700e76aSTom     sd_bus_error error = SD_BUS_ERROR_NULL;
229d700e76aSTom     sd_bus_message *m=NULL;
230d700e76aSTom 
231d700e76aSTom     fprintf(ipmidbus, "Attempting to set a dbus Variant Sensor 0x%02x via %s with a value of %s\n",
232d700e76aSTom         number, method, value);
233d700e76aSTom 
2342ae09b9aSEmily Shaffer     r = find_openbmc_path(number, &a);
235d700e76aSTom 
236d700e76aSTom     if (r < 0) {
237d700e76aSTom         fprintf(stderr, "Failed to find Sensor 0x%02x\n", number);
238d700e76aSTom         return 0;
239d700e76aSTom     }
240d700e76aSTom 
241d700e76aSTom     r = sd_bus_message_new_method_call(bus,&m,a.bus,a.path,a.interface,method);
242d700e76aSTom     if (r < 0) {
243d700e76aSTom         fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
244d700e76aSTom         goto final;
245d700e76aSTom     }
246d700e76aSTom 
247d700e76aSTom     r = sd_bus_message_append(m, "v", "s", value);
248d700e76aSTom     if (r < 0) {
249d700e76aSTom         fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r));
250d700e76aSTom         goto final;
251d700e76aSTom     }
252d700e76aSTom 
253d700e76aSTom 
254d700e76aSTom     r = sd_bus_call(bus, m, 0, &error, NULL);
255d700e76aSTom     if (r < 0) {
256d700e76aSTom         fprintf(stderr, "Failed to call the method: %s", strerror(-r));
257d700e76aSTom     }
258d700e76aSTom 
259d700e76aSTom final:
260d700e76aSTom     sd_bus_error_free(&error);
261d700e76aSTom     m = sd_bus_message_unref(m);
262d700e76aSTom 
263d700e76aSTom     return 0;
264d700e76aSTom }
265d700e76aSTom int set_sensor_dbus_state_y(uint8_t number, const char *method, const uint8_t value) {
266d700e76aSTom 
267d700e76aSTom 
268d700e76aSTom     dbus_interface_t a;
269d700e76aSTom     int r;
270d700e76aSTom     sd_bus_error error = SD_BUS_ERROR_NULL;
271d700e76aSTom     sd_bus_message *m=NULL;
272d700e76aSTom 
273d700e76aSTom     fprintf(ipmidbus, "Attempting to set a dbus Variant Sensor 0x%02x via %s with a value of 0x%02x\n",
274d700e76aSTom         number, method, value);
275d700e76aSTom 
2762ae09b9aSEmily Shaffer     r = find_openbmc_path(number, &a);
277d700e76aSTom 
278d700e76aSTom     if (r < 0) {
279d700e76aSTom         fprintf(stderr, "Failed to find Sensor 0x%02x\n", number);
280d700e76aSTom         return 0;
281d700e76aSTom     }
282d700e76aSTom 
283d700e76aSTom     r = sd_bus_message_new_method_call(bus,&m,a.bus,a.path,a.interface,method);
284d700e76aSTom     if (r < 0) {
285d700e76aSTom         fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
286d700e76aSTom         goto final;
287d700e76aSTom     }
288d700e76aSTom 
289d700e76aSTom     r = sd_bus_message_append(m, "v", "i", value);
290d700e76aSTom     if (r < 0) {
291d700e76aSTom         fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r));
292d700e76aSTom         goto final;
293d700e76aSTom     }
294d700e76aSTom 
295d700e76aSTom 
296d700e76aSTom     r = sd_bus_call(bus, m, 0, &error, NULL);
297d700e76aSTom     if (r < 0) {
298d700e76aSTom         fprintf(stderr, "12 Failed to call the method: %s", strerror(-r));
299d700e76aSTom     }
300d700e76aSTom 
301d700e76aSTom final:
302d700e76aSTom     sd_bus_error_free(&error);
303d700e76aSTom     m = sd_bus_message_unref(m);
304d700e76aSTom 
305d700e76aSTom     return 0;
306d700e76aSTom }
307d700e76aSTom 
30898a23840SMatthew Barth uint8_t dbus_to_sensor_type(char *p) {
30998a23840SMatthew Barth 
31098a23840SMatthew Barth     sensorTypemap_t *s = g_SensorTypeMap;
31198a23840SMatthew Barth     char r=0;
31298a23840SMatthew Barth     while (s->number != 0xFF) {
31398a23840SMatthew Barth         if (!strcmp(s->dbusname,p)) {
314558184eaSTom Joseph             r = s->typecode;
31598a23840SMatthew Barth              break;
31698a23840SMatthew Barth         }
31798a23840SMatthew Barth         s++;
31898a23840SMatthew Barth     }
31998a23840SMatthew Barth 
32098a23840SMatthew Barth     if (s->number == 0xFF)
32198a23840SMatthew Barth         printf("Failed to find Sensor Type %s\n", p);
32298a23840SMatthew Barth 
32398a23840SMatthew Barth     return r;
32498a23840SMatthew Barth }
32598a23840SMatthew Barth 
32698a23840SMatthew Barth 
32798a23840SMatthew Barth uint8_t dbus_to_sensor_type_from_dbus(dbus_interface_t *a) {
32898a23840SMatthew Barth     char fru_type_name[64];
32998a23840SMatthew Barth     int r= 0;
33098a23840SMatthew Barth 
33198a23840SMatthew Barth     r = find_interface_property_fru_type(a, "fru_type", fru_type_name);
33298a23840SMatthew Barth     if (r<0) {
33398a23840SMatthew Barth         fprintf(stderr, "Failed to get a fru type: %s", strerror(-r));
33498a23840SMatthew Barth         return -1;
33598a23840SMatthew Barth     } else {
33698a23840SMatthew Barth         return dbus_to_sensor_type(fru_type_name);
33798a23840SMatthew Barth     }
33898a23840SMatthew Barth }
33998a23840SMatthew Barth 
340391f3303SEmily Shaffer uint8_t get_type_from_interface(dbus_interface_t dbus_if) {
34198a23840SMatthew Barth 
34298a23840SMatthew Barth     char *p;
34356003453SBrad Bishop     uint8_t type;
34498a23840SMatthew Barth 
34598a23840SMatthew Barth     // This is where sensors that do not exist in dbus but do
34698a23840SMatthew Barth     // exist in the host code stop.  This should indicate it
34798a23840SMatthew Barth     // is not a supported sensor
348391f3303SEmily Shaffer     if (dbus_if.interface[0] == 0) { return 0;}
34998a23840SMatthew Barth 
3507117441cSEmily Shaffer     // Fetch type from interface itself.
3517117441cSEmily Shaffer     if (dbus_if.sensortype != 0)
3527117441cSEmily Shaffer     {
3537117441cSEmily Shaffer         type = dbus_if.sensortype;
3547117441cSEmily Shaffer     }
3557117441cSEmily Shaffer     // Legacy codebase does not populate type during initial handling:
3567117441cSEmily Shaffer     else if (strstr(dbus_if.interface, "InventoryItem")) {
35798a23840SMatthew Barth         // InventoryItems are real frus.  So need to get the
35898a23840SMatthew Barth         // fru_type property
359391f3303SEmily Shaffer         type = dbus_to_sensor_type_from_dbus(&dbus_if);
36098a23840SMatthew Barth     } else {
36198a23840SMatthew Barth         // Non InventoryItems
362391f3303SEmily Shaffer         p = strrchr (dbus_if.path, '/');
36356003453SBrad Bishop         type = dbus_to_sensor_type(p+1);
36498a23840SMatthew Barth     }
36598a23840SMatthew Barth 
36656003453SBrad Bishop     return type;
36798a23840SMatthew Barth  }
36898a23840SMatthew Barth 
369391f3303SEmily Shaffer // Replaces find_sensor
370391f3303SEmily Shaffer uint8_t find_type_for_sensor_number(uint8_t num) {
371391f3303SEmily Shaffer     int r;
372391f3303SEmily Shaffer     dbus_interface_t dbus_if;
3732ae09b9aSEmily Shaffer     r = find_openbmc_path(num, &dbus_if);
374391f3303SEmily Shaffer     if (r < 0) {
375391f3303SEmily Shaffer         fprintf(stderr, "Could not find sensor %d\n", num);
376391f3303SEmily Shaffer         return r;
377391f3303SEmily Shaffer     }
378391f3303SEmily Shaffer     return get_type_from_interface(dbus_if);
379391f3303SEmily Shaffer }
380391f3303SEmily Shaffer 
38198a23840SMatthew Barth 
38298a23840SMatthew Barth 
38398a23840SMatthew Barth 
38498a23840SMatthew Barth 
38598a23840SMatthew Barth ipmi_ret_t ipmi_sen_get_sensor_type(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
38698a23840SMatthew Barth                              ipmi_request_t request, ipmi_response_t response,
38798a23840SMatthew Barth                              ipmi_data_len_t data_len, ipmi_context_t context)
38898a23840SMatthew Barth {
38998a23840SMatthew Barth     sensor_data_t *reqptr = (sensor_data_t*)request;
39098a23840SMatthew Barth     ipmi_ret_t rc = IPMI_CC_OK;
39198a23840SMatthew Barth 
39298a23840SMatthew Barth     printf("IPMI GET_SENSOR_TYPE [0x%02X]\n",reqptr->sennum);
39398a23840SMatthew Barth 
39498a23840SMatthew Barth     // TODO Not sure what the System-event-sensor is suppose to return
39598a23840SMatthew Barth     // need to ask Hostboot team
39698a23840SMatthew Barth     unsigned char buf[] = {0x00,0x6F};
39798a23840SMatthew Barth 
398391f3303SEmily Shaffer     buf[0] = find_type_for_sensor_number(reqptr->sennum);
39998a23840SMatthew Barth 
40098a23840SMatthew Barth     // HACK UNTIL Dbus gets updated or we find a better way
40198a23840SMatthew Barth     if (buf[0] == 0) {
40298a23840SMatthew Barth         rc = IPMI_CC_SENSOR_INVALID;
40398a23840SMatthew Barth     }
40498a23840SMatthew Barth 
40598a23840SMatthew Barth 
40698a23840SMatthew Barth     *data_len = sizeof(buf);
40798a23840SMatthew Barth     memcpy(response, &buf, *data_len);
40898a23840SMatthew Barth 
40998a23840SMatthew Barth     return rc;
41098a23840SMatthew Barth }
41198a23840SMatthew Barth 
412cc941e15SEmily Shaffer const std::set<std::string> analogSensorInterfaces =
413cc941e15SEmily Shaffer {
414cc941e15SEmily Shaffer     "xyz.openbmc_project.Sensor.Value",
415cc941e15SEmily Shaffer };
416cc941e15SEmily Shaffer 
417cc941e15SEmily Shaffer bool isAnalogSensor(const std::string& interface)
418cc941e15SEmily Shaffer {
419cc941e15SEmily Shaffer     return (analogSensorInterfaces.count(interface));
420cc941e15SEmily Shaffer }
421cc941e15SEmily Shaffer 
422be703f71STom Joseph ipmi_ret_t setSensorReading(void *request)
423be703f71STom Joseph {
424816e92b5STom Joseph     ipmi::sensor::SetSensorReadingReq cmdData =
425816e92b5STom Joseph             *(static_cast<ipmi::sensor::SetSensorReadingReq *>(request));
426be703f71STom Joseph 
427be703f71STom Joseph     // Check if the Sensor Number is present
428e0af7209SDhruvaraj Subhashchandran     const auto iter = sensors.find(cmdData.number);
429be703f71STom Joseph     if (iter == sensors.end())
430be703f71STom Joseph     {
431be703f71STom Joseph         return IPMI_CC_SENSOR_INVALID;
432be703f71STom Joseph     }
433be703f71STom Joseph 
43418e99992SDhruvaraj Subhashchandran     try
43518e99992SDhruvaraj Subhashchandran     {
436e0af7209SDhruvaraj Subhashchandran         return iter->second.updateFunc(cmdData, iter->second);
437be703f71STom Joseph     }
43818e99992SDhruvaraj Subhashchandran     catch (InternalFailure& e)
43918e99992SDhruvaraj Subhashchandran     {
44018e99992SDhruvaraj Subhashchandran          log<level::ERR>("Set sensor failed",
44118e99992SDhruvaraj Subhashchandran                          entry("SENSOR_NUM=%d", cmdData.number));
44218e99992SDhruvaraj Subhashchandran          commit<InternalFailure>();
44318e99992SDhruvaraj Subhashchandran     }
4448202432fSTom Joseph     catch (const std::runtime_error& e)
4458202432fSTom Joseph     {
4468202432fSTom Joseph         log<level::ERR>(e.what());
4478202432fSTom Joseph     }
44818e99992SDhruvaraj Subhashchandran 
44918e99992SDhruvaraj Subhashchandran     return IPMI_CC_UNSPECIFIED_ERROR;
45018e99992SDhruvaraj Subhashchandran }
45198a23840SMatthew Barth 
45298a23840SMatthew Barth ipmi_ret_t ipmi_sen_set_sensor(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
45398a23840SMatthew Barth                              ipmi_request_t request, ipmi_response_t response,
45498a23840SMatthew Barth                              ipmi_data_len_t data_len, ipmi_context_t context)
45598a23840SMatthew Barth {
45698a23840SMatthew Barth     sensor_data_t *reqptr = (sensor_data_t*)request;
45798a23840SMatthew Barth 
45898a23840SMatthew Barth     printf("IPMI SET_SENSOR [0x%02x]\n",reqptr->sennum);
45998a23840SMatthew Barth 
460be703f71STom Joseph     /*
461be703f71STom Joseph      * This would support the Set Sensor Reading command for the presence
462be703f71STom Joseph      * and functional state of Processor, Core & DIMM. For the remaining
463be703f71STom Joseph      * sensors the existing support is invoked.
464be703f71STom Joseph      */
465be703f71STom Joseph     auto ipmiRC = setSensorReading(request);
466be703f71STom Joseph 
467be703f71STom Joseph     if(ipmiRC == IPMI_CC_SENSOR_INVALID)
468be703f71STom Joseph     {
46998a23840SMatthew Barth         updateSensorRecordFromSSRAESC(reqptr);
470be703f71STom Joseph         ipmiRC = IPMI_CC_OK;
471be703f71STom Joseph     }
47298a23840SMatthew Barth 
47398a23840SMatthew Barth     *data_len=0;
474be703f71STom Joseph     return ipmiRC;
47598a23840SMatthew Barth }
47698a23840SMatthew Barth 
47798a23840SMatthew Barth 
47898a23840SMatthew Barth ipmi_ret_t ipmi_sen_get_sensor_reading(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
47998a23840SMatthew Barth                              ipmi_request_t request, ipmi_response_t response,
48098a23840SMatthew Barth                              ipmi_data_len_t data_len, ipmi_context_t context)
48198a23840SMatthew Barth {
48298a23840SMatthew Barth     sensor_data_t *reqptr = (sensor_data_t*)request;
48398a23840SMatthew Barth     ipmi_ret_t rc = IPMI_CC_SENSOR_INVALID;
48440c35b1cSTom Joseph     uint8_t type = 0;
48598a23840SMatthew Barth     sensorreadingresp_t *resp = (sensorreadingresp_t*) response;
48698a23840SMatthew Barth     int r;
48798a23840SMatthew Barth     dbus_interface_t a;
48898a23840SMatthew Barth     sd_bus *bus = ipmid_get_sd_bus_connection();
48998a23840SMatthew Barth     sd_bus_message *reply = NULL;
49098a23840SMatthew Barth     int reading = 0;
4916244f93dSDhruvaraj Subhashchandran     char* assertion = NULL;
492*c6162fb6STom Joseph     ipmi::sensor::GetSensorResponse getResponse {};
493*c6162fb6STom Joseph     static constexpr auto scanningEnabledBit = 6;
49498a23840SMatthew Barth 
49598a23840SMatthew Barth     printf("IPMI GET_SENSOR_READING [0x%02x]\n",reqptr->sennum);
49698a23840SMatthew Barth 
4972ae09b9aSEmily Shaffer     r = find_openbmc_path(reqptr->sennum, &a);
49898a23840SMatthew Barth 
49940c35b1cSTom Joseph     if (r < 0)
50040c35b1cSTom Joseph     {
50198a23840SMatthew Barth         fprintf(stderr, "Failed to find Sensor 0x%02x\n", reqptr->sennum);
50298a23840SMatthew Barth     }
50340c35b1cSTom Joseph     else
50440c35b1cSTom Joseph     {
505391f3303SEmily Shaffer         type = get_type_from_interface(a);
50656003453SBrad Bishop         if(type == 0) {
50756003453SBrad Bishop             fprintf(stderr, "Failed to find Sensor 0x%02x\n", reqptr->sennum);
50856003453SBrad Bishop             return IPMI_CC_SENSOR_INVALID;
50956003453SBrad Bishop         }
51098a23840SMatthew Barth 
51140c35b1cSTom Joseph         fprintf(stderr, "Bus: %s, Path: %s, Interface: %s\n", a.bus, a.path,
51240c35b1cSTom Joseph                         a.interface);
51340c35b1cSTom Joseph     }
51498a23840SMatthew Barth 
51598a23840SMatthew Barth     *data_len=0;
51698a23840SMatthew Barth 
51710f4959aSEmily Shaffer     int64_t raw_value;
5181fabf229SEmily Shaffer     ipmi::sensor::Info sensor;
5191fabf229SEmily Shaffer 
52098a23840SMatthew Barth     switch(type) {
52198a23840SMatthew Barth         case 0xC2:
522d12ae758SDhruvaraj Subhashchandran         case 0xC8:
52398a23840SMatthew Barth             r = sd_bus_get_property(bus,a.bus, a.path, a.interface, "value", NULL, &reply, "i");
52498a23840SMatthew Barth             if (r < 0) {
52598a23840SMatthew Barth                 fprintf(stderr, "Failed to call sd_bus_get_property:%d,  %s\n", r, strerror(-r));
52698a23840SMatthew Barth                 fprintf(stderr, "Bus: %s, Path: %s, Interface: %s\n",
52798a23840SMatthew Barth                         a.bus, a.path, a.interface);
52898a23840SMatthew Barth                 break;
52998a23840SMatthew Barth             }
53098a23840SMatthew Barth 
53198a23840SMatthew Barth             r = sd_bus_message_read(reply, "i", &reading);
53298a23840SMatthew Barth             if (r < 0) {
53398a23840SMatthew Barth                 fprintf(stderr, "Failed to read sensor: %s\n", strerror(-r));
53498a23840SMatthew Barth                 break;
53598a23840SMatthew Barth             }
53698a23840SMatthew Barth 
53798a23840SMatthew Barth             printf("Contents of a 0x%02x is 0x%02x\n", type, reading);
53898a23840SMatthew Barth 
53998a23840SMatthew Barth             rc = IPMI_CC_OK;
54098a23840SMatthew Barth             *data_len=sizeof(sensorreadingresp_t);
54198a23840SMatthew Barth 
54298a23840SMatthew Barth             resp->value         = (uint8_t)reading;
54398a23840SMatthew Barth             resp->operation     = 0;
54498a23840SMatthew Barth             resp->indication[0] = 0;
54598a23840SMatthew Barth             resp->indication[1] = 0;
54698a23840SMatthew Barth             break;
54798a23840SMatthew Barth 
5486244f93dSDhruvaraj Subhashchandran         //TODO openbmc/openbmc#2154 Move this sensor to right place.
5496244f93dSDhruvaraj Subhashchandran         case 0xCA:
5506244f93dSDhruvaraj Subhashchandran             r = sd_bus_get_property(bus,a.bus, a.path, a.interface, "value", NULL, &reply, "s");
5516244f93dSDhruvaraj Subhashchandran             if (r < 0) {
5526244f93dSDhruvaraj Subhashchandran                 fprintf(stderr, "Failed to call sd_bus_get_property:%d,  %s\n", r, strerror(-r));
5536244f93dSDhruvaraj Subhashchandran                 fprintf(stderr, "Bus: %s, Path: %s, Interface: %s\n",
5546244f93dSDhruvaraj Subhashchandran                         a.bus, a.path, a.interface);
5556244f93dSDhruvaraj Subhashchandran                 break;
5566244f93dSDhruvaraj Subhashchandran             }
5576244f93dSDhruvaraj Subhashchandran 
5586244f93dSDhruvaraj Subhashchandran             r = sd_bus_message_read(reply, "s", &assertion);
5596244f93dSDhruvaraj Subhashchandran             if (r < 0) {
5606244f93dSDhruvaraj Subhashchandran                 fprintf(stderr, "Failed to read sensor: %s\n", strerror(-r));
5616244f93dSDhruvaraj Subhashchandran                 break;
5626244f93dSDhruvaraj Subhashchandran             }
5636244f93dSDhruvaraj Subhashchandran 
5646244f93dSDhruvaraj Subhashchandran             rc = IPMI_CC_OK;
5656244f93dSDhruvaraj Subhashchandran             *data_len=sizeof(sensorreadingresp_t);
5666244f93dSDhruvaraj Subhashchandran 
5676244f93dSDhruvaraj Subhashchandran             resp->value         = 0;
5686244f93dSDhruvaraj Subhashchandran             resp->operation     = 0;
5696244f93dSDhruvaraj Subhashchandran             if (strcmp(assertion,"Enabled") == 0)
5706244f93dSDhruvaraj Subhashchandran             {
5716244f93dSDhruvaraj Subhashchandran                 resp->indication[0] = 0x02;
5726244f93dSDhruvaraj Subhashchandran             }
5736244f93dSDhruvaraj Subhashchandran             else
5746244f93dSDhruvaraj Subhashchandran             {
5756244f93dSDhruvaraj Subhashchandran                 resp->indication[0] = 0x1;
5766244f93dSDhruvaraj Subhashchandran             }
5776244f93dSDhruvaraj Subhashchandran             resp->indication[1] = 0;
5786244f93dSDhruvaraj Subhashchandran             break;
5796244f93dSDhruvaraj Subhashchandran 
5801fabf229SEmily Shaffer         case IPMI_SENSOR_TEMP:
5811fabf229SEmily Shaffer         case IPMI_SENSOR_VOLTAGE:
5821fabf229SEmily Shaffer         case IPMI_SENSOR_CURRENT:
5831fabf229SEmily Shaffer         case IPMI_SENSOR_FAN:
5841fabf229SEmily Shaffer             // Get reading for /xyz/openbmc_project/Sensor/Value.interface
58510f4959aSEmily Shaffer             if(sensors.find(reqptr->sennum) == sensors.end())
58610f4959aSEmily Shaffer             {
58710f4959aSEmily Shaffer                 fprintf(stderr, "Failed to find config entry for Sensor 0x%02x\n",
58810f4959aSEmily Shaffer                         reqptr->sennum);
58910f4959aSEmily Shaffer                 return IPMI_CC_SENSOR_INVALID;
59010f4959aSEmily Shaffer             }
59110f4959aSEmily Shaffer 
59210f4959aSEmily Shaffer             sensor = sensors.at(reqptr->sennum);
593cc941e15SEmily Shaffer             if (ipmi::sensor::Mutability::Read !=
594cc941e15SEmily Shaffer                   (sensor.mutability & ipmi::sensor::Mutability::Read))
595cc941e15SEmily Shaffer             {
596cc941e15SEmily Shaffer                 log<level::ERR>("Sensor was not readable.\n");
597cc941e15SEmily Shaffer                 return IPMI_CC_SENSOR_INVALID;
598cc941e15SEmily Shaffer             }
599cc941e15SEmily Shaffer 
6001fabf229SEmily Shaffer 
6011fabf229SEmily Shaffer             // Get value
6021fabf229SEmily Shaffer             r = sd_bus_get_property_trivial(bus,
6031fabf229SEmily Shaffer                                             a.bus,
6041fabf229SEmily Shaffer                                             a.path,
6051fabf229SEmily Shaffer                                             a.interface,
6061fabf229SEmily Shaffer                                             "Value",
6071fabf229SEmily Shaffer                                             NULL,
6081fabf229SEmily Shaffer                                             'x',
6091fabf229SEmily Shaffer                                             &raw_value);
6101fabf229SEmily Shaffer             if (r < 0) {
6111fabf229SEmily Shaffer                 fprintf(stderr,
6121fabf229SEmily Shaffer                         "Failed to call sd_bus_get_property:%d,  %s, 'value'\n",
6131fabf229SEmily Shaffer                         r,
6141fabf229SEmily Shaffer                         strerror(-r));
6151fabf229SEmily Shaffer                 fprintf(stderr, "Bus: %s, Path: %s, Interface: %s\n",
6161fabf229SEmily Shaffer                         a.bus, a.path, a.interface);
6171fabf229SEmily Shaffer                 break;
6181fabf229SEmily Shaffer             }
6191fabf229SEmily Shaffer 
62010f4959aSEmily Shaffer             // Prevent div0
62110f4959aSEmily Shaffer             if (sensor.coefficientM == 0) {
62210f4959aSEmily Shaffer                 sensor.coefficientM = 1;
62310f4959aSEmily Shaffer             };
6241fabf229SEmily Shaffer 
62510f4959aSEmily Shaffer             resp->value = static_cast<uint8_t>(
62610f4959aSEmily Shaffer                     (raw_value - sensor.scaledOffset) / sensor.coefficientM);
627*c6162fb6STom Joseph             resp->operation = 1 << scanningEnabledBit; // scanning enabled
628bbef71c2SEmily Shaffer             resp->indication[0] = 0; // not a threshold sensor. ignore
6291fabf229SEmily Shaffer             resp->indication[1] = 0;
6301fabf229SEmily Shaffer             rc = IPMI_CC_OK;
6311fabf229SEmily Shaffer             *data_len=sizeof(sensorreadingresp_t);
6321fabf229SEmily Shaffer             break;
63398a23840SMatthew Barth         default:
63414c15467STom Joseph         {
63514c15467STom Joseph             const auto iter = sensors.find(reqptr->sennum);
63614c15467STom Joseph             if (iter == sensors.end())
63714c15467STom Joseph             {
63814c15467STom Joseph                 return IPMI_CC_SENSOR_INVALID;
63914c15467STom Joseph             }
64014c15467STom Joseph 
64114c15467STom Joseph             try
64214c15467STom Joseph             {
643*c6162fb6STom Joseph                 getResponse =  iter->second.getFunc(iter->second);
64414c15467STom Joseph                 *data_len = getResponse.size();
64514c15467STom Joseph                 memcpy(resp, getResponse.data(), *data_len);
646*c6162fb6STom Joseph                 resp->operation = 1 << scanningEnabledBit;
64714c15467STom Joseph                 return IPMI_CC_OK;
64814c15467STom Joseph             }
64914c15467STom Joseph             catch (InternalFailure& e)
65014c15467STom Joseph             {
651*c6162fb6STom Joseph                 *data_len = getResponse.size();
652*c6162fb6STom Joseph                 memcpy(resp, getResponse.data(), *data_len);
653*c6162fb6STom Joseph                 return IPMI_CC_OK;
65414c15467STom Joseph             }
6558202432fSTom Joseph             catch (const std::runtime_error& e)
6568202432fSTom Joseph             {
657*c6162fb6STom Joseph                 *data_len = getResponse.size();
658*c6162fb6STom Joseph                 memcpy(resp, getResponse.data(), *data_len);
659*c6162fb6STom Joseph                 return IPMI_CC_OK;
6608202432fSTom Joseph             }
66114c15467STom Joseph         }
66298a23840SMatthew Barth     }
66398a23840SMatthew Barth 
66498a23840SMatthew Barth     reply = sd_bus_message_unref(reply);
66598a23840SMatthew Barth 
66698a23840SMatthew Barth     return rc;
66798a23840SMatthew Barth }
66898a23840SMatthew Barth 
66998a23840SMatthew Barth ipmi_ret_t ipmi_sen_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
67098a23840SMatthew Barth                              ipmi_request_t request, ipmi_response_t response,
67198a23840SMatthew Barth                              ipmi_data_len_t data_len, ipmi_context_t context)
67298a23840SMatthew Barth {
67370aa8d96SNan Li     ipmi_ret_t rc = IPMI_CC_INVALID;
67498a23840SMatthew Barth 
67598a23840SMatthew Barth     printf("IPMI S/E Wildcard Netfn:[0x%X], Cmd:[0x%X]\n",netfn,cmd);
67698a23840SMatthew Barth     *data_len = 0;
67798a23840SMatthew Barth 
67898a23840SMatthew Barth     return rc;
67998a23840SMatthew Barth }
68098a23840SMatthew Barth 
681d06e0e7eSEmily Shaffer ipmi_ret_t ipmi_sen_get_sdr_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
682d06e0e7eSEmily Shaffer                                  ipmi_request_t request,
683d06e0e7eSEmily Shaffer                                  ipmi_response_t response,
684d06e0e7eSEmily Shaffer                                  ipmi_data_len_t data_len,
685d06e0e7eSEmily Shaffer                                  ipmi_context_t context)
686d06e0e7eSEmily Shaffer {
687d06e0e7eSEmily Shaffer     auto resp = static_cast<get_sdr_info::GetSdrInfoResp*>(response);
688d06e0e7eSEmily Shaffer     if (request == nullptr ||
689d06e0e7eSEmily Shaffer         get_sdr_info::request::get_count(request) == false)
690d06e0e7eSEmily Shaffer     {
691d06e0e7eSEmily Shaffer         // Get Sensor Count
692d06e0e7eSEmily Shaffer         resp->count = sensors.size();
693d06e0e7eSEmily Shaffer     }
694d06e0e7eSEmily Shaffer     else
695d06e0e7eSEmily Shaffer     {
696d06e0e7eSEmily Shaffer         resp->count = 1;
697d06e0e7eSEmily Shaffer     }
698d06e0e7eSEmily Shaffer 
699d06e0e7eSEmily Shaffer     // Multiple LUNs not supported.
700d06e0e7eSEmily Shaffer     namespace response = get_sdr_info::response;
701d06e0e7eSEmily Shaffer     response::set_lun_present(0, &(resp->luns_and_dynamic_population));
702d06e0e7eSEmily Shaffer     response::set_lun_not_present(1, &(resp->luns_and_dynamic_population));
703d06e0e7eSEmily Shaffer     response::set_lun_not_present(2, &(resp->luns_and_dynamic_population));
704d06e0e7eSEmily Shaffer     response::set_lun_not_present(3, &(resp->luns_and_dynamic_population));
705d06e0e7eSEmily Shaffer     response::set_static_population(&(resp->luns_and_dynamic_population));
706d06e0e7eSEmily Shaffer 
707d06e0e7eSEmily Shaffer     *data_len = SDR_INFO_RESP_SIZE;
708d06e0e7eSEmily Shaffer 
709d06e0e7eSEmily Shaffer     return IPMI_CC_OK;
710d06e0e7eSEmily Shaffer }
711d06e0e7eSEmily Shaffer 
712a344afc0SEmily Shaffer ipmi_ret_t ipmi_sen_reserve_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
713a344afc0SEmily Shaffer                                 ipmi_request_t request,
714a344afc0SEmily Shaffer                                 ipmi_response_t response,
715a344afc0SEmily Shaffer                                 ipmi_data_len_t data_len,
716a344afc0SEmily Shaffer                                 ipmi_context_t context)
717a344afc0SEmily Shaffer {
718a344afc0SEmily Shaffer     // A constant reservation ID is okay until we implement add/remove SDR.
719a344afc0SEmily Shaffer     const uint16_t reservation_id = 1;
720a344afc0SEmily Shaffer     *(uint16_t*)response = reservation_id;
7215a5a6282SEmily Shaffer     *data_len = sizeof(uint16_t);
722a344afc0SEmily Shaffer 
723a344afc0SEmily Shaffer     printf("Created new IPMI SDR reservation ID %d\n", *(uint16_t*)response);
724a344afc0SEmily Shaffer     return IPMI_CC_OK;
725a344afc0SEmily Shaffer }
72698a23840SMatthew Barth 
727cc941e15SEmily Shaffer void setUnitFieldsForObject(sd_bus *bus,
728cc941e15SEmily Shaffer                             const dbus_interface_t &iface,
729bbef71c2SEmily Shaffer                             const ipmi::sensor::Info *info,
730cc941e15SEmily Shaffer                             get_sdr::SensorDataFullRecordBody *body)
731bbef71c2SEmily Shaffer {
7321bb0d387SDeepak Kodihalli     if (info->propertyInterfaces.begin()->first ==
733bbef71c2SEmily Shaffer         "xyz.openbmc_project.Sensor.Value")
734bbef71c2SEmily Shaffer     {
735cc941e15SEmily Shaffer         std::string result {};
73662235618SEmily Shaffer         if (info->unit.empty())
73762235618SEmily Shaffer         {
738cc941e15SEmily Shaffer             char *raw_cstr = NULL;
739bbef71c2SEmily Shaffer             if (0 > sd_bus_get_property_string(bus, iface.bus, iface.path,
740bbef71c2SEmily Shaffer                                                iface.interface, "Unit", NULL,
741cc941e15SEmily Shaffer                                                &raw_cstr))
742cc941e15SEmily Shaffer             {
743cc941e15SEmily Shaffer                 log<level::WARNING>("Unit interface missing.",
744e4050f29SGunnar Mills                                     entry("BUS=%s", iface.bus),
745e4050f29SGunnar Mills                                     entry("PATH=%s", iface.path));
746bbef71c2SEmily Shaffer             }
747cc941e15SEmily Shaffer             else
748cc941e15SEmily Shaffer             {
749cc941e15SEmily Shaffer                 result = raw_cstr;
750cc941e15SEmily Shaffer             }
751cc941e15SEmily Shaffer             free(raw_cstr);
75262235618SEmily Shaffer         }
75362235618SEmily Shaffer         else
75462235618SEmily Shaffer         {
75562235618SEmily Shaffer             result = info->unit;
75662235618SEmily Shaffer         }
757bbef71c2SEmily Shaffer 
758bbef71c2SEmily Shaffer         namespace server = sdbusplus::xyz::openbmc_project::Sensor::server;
759cc941e15SEmily Shaffer         try {
760cc941e15SEmily Shaffer             auto unit = server::Value::convertUnitFromString(result);
761bbef71c2SEmily Shaffer             // Unit strings defined in
762bbef71c2SEmily Shaffer             // phosphor-dbus-interfaces/xyz/openbmc_project/Sensor/Value.interface.yaml
763bbef71c2SEmily Shaffer             switch (unit)
764bbef71c2SEmily Shaffer             {
765bbef71c2SEmily Shaffer                 case server::Value::Unit::DegreesC:
766bbef71c2SEmily Shaffer                     body->sensor_units_2_base = get_sdr::SENSOR_UNIT_DEGREES_C;
767bbef71c2SEmily Shaffer                     break;
768bbef71c2SEmily Shaffer                 case server::Value::Unit::RPMS:
769bbef71c2SEmily Shaffer                     body->sensor_units_2_base = get_sdr::SENSOR_UNIT_REVOLUTIONS; // revolutions
770bbef71c2SEmily Shaffer                     get_sdr::body::set_rate_unit(0b100, body); // per minute
771bbef71c2SEmily Shaffer                     break;
772bbef71c2SEmily Shaffer                 case server::Value::Unit::Volts:
773bbef71c2SEmily Shaffer                     body->sensor_units_2_base = get_sdr::SENSOR_UNIT_VOLTS;
774bbef71c2SEmily Shaffer                     break;
775bbef71c2SEmily Shaffer                 case server::Value::Unit::Meters:
776bbef71c2SEmily Shaffer                     body->sensor_units_2_base = get_sdr::SENSOR_UNIT_METERS;
777bbef71c2SEmily Shaffer                     break;
778bbef71c2SEmily Shaffer                 case server::Value::Unit::Amperes:
779bbef71c2SEmily Shaffer                     body->sensor_units_2_base = get_sdr::SENSOR_UNIT_AMPERES;
780bbef71c2SEmily Shaffer                     break;
781bbef71c2SEmily Shaffer                 case server::Value::Unit::Joules:
782bbef71c2SEmily Shaffer                     body->sensor_units_2_base = get_sdr::SENSOR_UNIT_JOULES;
783bbef71c2SEmily Shaffer                     break;
784bbef71c2SEmily Shaffer                 default:
785cc941e15SEmily Shaffer                     // Cannot be hit.
786cc941e15SEmily Shaffer                     fprintf(stderr, "Unknown value unit type: = %s\n", result.c_str());
787cc941e15SEmily Shaffer             }
788cc941e15SEmily Shaffer         }
789cc941e15SEmily Shaffer         catch (sdbusplus::exception::InvalidEnumString e)
790cc941e15SEmily Shaffer         {
791cc941e15SEmily Shaffer             log<level::WARNING>("Warning: no unit provided for sensor!");
792cc941e15SEmily Shaffer         }
793cc941e15SEmily Shaffer     }
794bbef71c2SEmily Shaffer }
795bbef71c2SEmily Shaffer 
796cc941e15SEmily Shaffer int64_t getScaleForObject(sd_bus *bus,
797cc941e15SEmily Shaffer                           const dbus_interface_t& iface,
798cc941e15SEmily Shaffer                           const ipmi::sensor::Info *info)
799cc941e15SEmily Shaffer {
800cc941e15SEmily Shaffer     int64_t result = 0;
801cc941e15SEmily Shaffer     if (info->propertyInterfaces.begin()->first ==
802cc941e15SEmily Shaffer         "xyz.openbmc_project.Sensor.Value")
803cc941e15SEmily Shaffer     {
80462235618SEmily Shaffer         if (info->hasScale)
80562235618SEmily Shaffer         {
80662235618SEmily Shaffer             result = info->scale;
80762235618SEmily Shaffer         }
80862235618SEmily Shaffer         else
80962235618SEmily Shaffer         {
81010f4959aSEmily Shaffer             if (0 > sd_bus_get_property_trivial(bus,
81110f4959aSEmily Shaffer                                                 iface.bus,
81210f4959aSEmily Shaffer                                                 iface.path,
81310f4959aSEmily Shaffer                                                 iface.interface,
81410f4959aSEmily Shaffer                                                 "Scale",
81510f4959aSEmily Shaffer                                                 NULL,
81610f4959aSEmily Shaffer                                                 'x',
817cc941e15SEmily Shaffer                                                 &result)) {
818cc941e15SEmily Shaffer                 log<level::WARNING>("Scale interface missing.",
819e4050f29SGunnar Mills                                     entry("BUS=%s", iface.bus),
820e4050f29SGunnar Mills                                     entry("PATH=%s", iface.path));
82110f4959aSEmily Shaffer             }
822cc941e15SEmily Shaffer         }
82362235618SEmily Shaffer     }
824cc941e15SEmily Shaffer 
825cc941e15SEmily Shaffer     return result;
826cc941e15SEmily Shaffer }
827cc941e15SEmily Shaffer 
828cc941e15SEmily Shaffer ipmi_ret_t populate_record_from_dbus(get_sdr::SensorDataFullRecordBody *body,
829cc941e15SEmily Shaffer                                      const ipmi::sensor::Info *info,
830cc941e15SEmily Shaffer                                      ipmi_data_len_t data_len)
831cc941e15SEmily Shaffer {
832cc941e15SEmily Shaffer     /* Functional sensor case */
833cc941e15SEmily Shaffer     if (isAnalogSensor(info->propertyInterfaces.begin()->first))
834cc941e15SEmily Shaffer     {
835cc941e15SEmily Shaffer         // Get bus
836cc941e15SEmily Shaffer         sd_bus *bus = ipmid_get_sd_bus_connection();
837cc941e15SEmily Shaffer         dbus_interface_t iface;
838cc941e15SEmily Shaffer 
839cc941e15SEmily Shaffer         if (0 > find_openbmc_path(body->entity_id, &iface))
840cc941e15SEmily Shaffer             return IPMI_CC_SENSOR_INVALID;
841cc941e15SEmily Shaffer 
842cc941e15SEmily Shaffer         body->sensor_units_1 = 0; // unsigned, no rate, no modifier, not a %
843cc941e15SEmily Shaffer 
844cc941e15SEmily Shaffer         /* Unit info */
845cc941e15SEmily Shaffer         setUnitFieldsForObject(bus, iface, info, body);
846cc941e15SEmily Shaffer 
847cc941e15SEmily Shaffer         /* Modifiers to reading info */
848cc941e15SEmily Shaffer         // Get scale
849cc941e15SEmily Shaffer         int64_t scale = getScaleForObject(bus, iface, info);
85010f4959aSEmily Shaffer 
85110f4959aSEmily Shaffer         get_sdr::body::set_b(info->coefficientB, body);
85210f4959aSEmily Shaffer         get_sdr::body::set_m(info->coefficientM, body);
85310f4959aSEmily Shaffer         get_sdr::body::set_b_exp(info->exponentB, body);
85410f4959aSEmily Shaffer         get_sdr::body::set_r_exp(scale, body);
855bbef71c2SEmily Shaffer 
856bbef71c2SEmily Shaffer         get_sdr::body::set_id_type(0b00, body); // 00 = unicode
8579642391dSTom Joseph     }
8589642391dSTom Joseph 
8599642391dSTom Joseph     /* ID string */
8609642391dSTom Joseph     auto id_string = info->sensorNameFunc(*info);
8619642391dSTom Joseph 
862bbef71c2SEmily Shaffer     if (id_string.length() > FULL_RECORD_ID_STR_MAX_LENGTH)
863bbef71c2SEmily Shaffer     {
864bbef71c2SEmily Shaffer         get_sdr::body::set_id_strlen(FULL_RECORD_ID_STR_MAX_LENGTH, body);
865bbef71c2SEmily Shaffer     }
866bbef71c2SEmily Shaffer     else
867bbef71c2SEmily Shaffer     {
868bbef71c2SEmily Shaffer         get_sdr::body::set_id_strlen(id_string.length(), body);
869bbef71c2SEmily Shaffer     }
870bbef71c2SEmily Shaffer     strncpy(body->id_string, id_string.c_str(),
871bbef71c2SEmily Shaffer             get_sdr::body::get_id_strlen(body));
872bbef71c2SEmily Shaffer 
873bbef71c2SEmily Shaffer     return IPMI_CC_OK;
874bbef71c2SEmily Shaffer };
875bbef71c2SEmily Shaffer 
876bbef71c2SEmily Shaffer ipmi_ret_t ipmi_sen_get_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
877bbef71c2SEmily Shaffer                             ipmi_request_t request, ipmi_response_t response,
878bbef71c2SEmily Shaffer                             ipmi_data_len_t data_len, ipmi_context_t context)
879bbef71c2SEmily Shaffer {
880bbef71c2SEmily Shaffer     ipmi_ret_t ret = IPMI_CC_OK;
881bbef71c2SEmily Shaffer     get_sdr::GetSdrReq *req = (get_sdr::GetSdrReq*)request;
882bbef71c2SEmily Shaffer     get_sdr::GetSdrResp *resp = (get_sdr::GetSdrResp*)response;
883bbef71c2SEmily Shaffer     get_sdr::SensorDataFullRecord record = {0};
884bbef71c2SEmily Shaffer     if (req != NULL)
885bbef71c2SEmily Shaffer     {
886bbef71c2SEmily Shaffer         // Note: we use an iterator so we can provide the next ID at the end of
887bbef71c2SEmily Shaffer         // the call.
888bbef71c2SEmily Shaffer         auto sensor = sensors.begin();
889bbef71c2SEmily Shaffer 
890bbef71c2SEmily Shaffer         // At the beginning of a scan, the host side will send us id=0.
891bbef71c2SEmily Shaffer         if (get_sdr::request::get_record_id(req) != 0)
892bbef71c2SEmily Shaffer         {
893bbef71c2SEmily Shaffer             sensor = sensors.find(get_sdr::request::get_record_id(req));
894bbef71c2SEmily Shaffer             if(sensor == sensors.end()) {
895bbef71c2SEmily Shaffer                 return IPMI_CC_SENSOR_INVALID;
896bbef71c2SEmily Shaffer             }
897bbef71c2SEmily Shaffer         }
898bbef71c2SEmily Shaffer 
899bbef71c2SEmily Shaffer         uint8_t sensor_id = sensor->first;
900bbef71c2SEmily Shaffer 
901bbef71c2SEmily Shaffer         /* Header */
902bbef71c2SEmily Shaffer         get_sdr::header::set_record_id(sensor_id, &(record.header));
903bbef71c2SEmily Shaffer         record.header.sdr_version = 0x51; // Based on IPMI Spec v2.0 rev 1.1
904bbef71c2SEmily Shaffer         record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
905bbef71c2SEmily Shaffer         record.header.record_length = sizeof(get_sdr::SensorDataFullRecord);
906bbef71c2SEmily Shaffer 
907bbef71c2SEmily Shaffer         /* Key */
9089642391dSTom Joseph         get_sdr::key::set_owner_id_bmc(&(record.key));
909bbef71c2SEmily Shaffer         record.key.sensor_number = sensor_id;
910bbef71c2SEmily Shaffer 
911bbef71c2SEmily Shaffer         /* Body */
9129642391dSTom Joseph         record.body.entity_id = sensor->second.entityType;
913bbef71c2SEmily Shaffer         record.body.sensor_type = sensor->second.sensorType;
914bbef71c2SEmily Shaffer         record.body.event_reading_type = sensor->second.sensorReadingType;
9159642391dSTom Joseph         record.body.entity_instance = sensor->second.instance;
916bbef71c2SEmily Shaffer 
917bbef71c2SEmily Shaffer         // Set the type-specific details given the DBus interface
918bbef71c2SEmily Shaffer         ret = populate_record_from_dbus(&(record.body), &(sensor->second),
919bbef71c2SEmily Shaffer                                         data_len);
920bbef71c2SEmily Shaffer 
921bbef71c2SEmily Shaffer         if (++sensor == sensors.end())
922bbef71c2SEmily Shaffer         {
923bbef71c2SEmily Shaffer             get_sdr::response::set_next_record_id(0xFFFF, resp); // last record
924bbef71c2SEmily Shaffer         }
925bbef71c2SEmily Shaffer         else
926bbef71c2SEmily Shaffer         {
927bbef71c2SEmily Shaffer             get_sdr::response::set_next_record_id(sensor->first, resp);
928bbef71c2SEmily Shaffer         }
929bbef71c2SEmily Shaffer 
930bbef71c2SEmily Shaffer         *data_len = sizeof(get_sdr::GetSdrResp) - req->offset;
931bbef71c2SEmily Shaffer         memcpy(resp->record_data, (char*)&record + req->offset,
932bbef71c2SEmily Shaffer                sizeof(get_sdr::SensorDataFullRecord) - req->offset);
933bbef71c2SEmily Shaffer     }
934bbef71c2SEmily Shaffer 
935bbef71c2SEmily Shaffer     return ret;
936bbef71c2SEmily Shaffer }
937bbef71c2SEmily Shaffer 
938bbef71c2SEmily Shaffer 
93998a23840SMatthew Barth void register_netfn_sen_functions()
94098a23840SMatthew Barth {
9410573237fSTom     // <Wildcard Command>
942a344afc0SEmily Shaffer     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
943a344afc0SEmily Shaffer            NETFUN_SENSOR, IPMI_CMD_WILDCARD);
944a344afc0SEmily Shaffer     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_WILDCARD,
945a344afc0SEmily Shaffer                            nullptr, ipmi_sen_wildcard,
9460573237fSTom                            PRIVILEGE_USER);
94798a23840SMatthew Barth 
9480573237fSTom     // <Get Sensor Type>
949a344afc0SEmily Shaffer     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
950a344afc0SEmily Shaffer            NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_TYPE);
951a344afc0SEmily Shaffer     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_TYPE,
952a344afc0SEmily Shaffer                            nullptr, ipmi_sen_get_sensor_type,
9530573237fSTom                            PRIVILEGE_USER);
95498a23840SMatthew Barth 
9550573237fSTom     // <Set Sensor Reading and Event Status>
956a344afc0SEmily Shaffer     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
957a344afc0SEmily Shaffer            NETFUN_SENSOR, IPMI_CMD_SET_SENSOR);
958a344afc0SEmily Shaffer     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_SET_SENSOR,
959a344afc0SEmily Shaffer                            nullptr, ipmi_sen_set_sensor,
9600573237fSTom                            PRIVILEGE_OPERATOR);
96198a23840SMatthew Barth 
9620573237fSTom     // <Get Sensor Reading>
963a344afc0SEmily Shaffer     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
964a344afc0SEmily Shaffer            NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_READING);
965a344afc0SEmily Shaffer     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_READING,
966a344afc0SEmily Shaffer                            nullptr, ipmi_sen_get_sensor_reading,
967a344afc0SEmily Shaffer                            PRIVILEGE_USER);
968a344afc0SEmily Shaffer 
969a344afc0SEmily Shaffer     // <Reserve SDR>
970a344afc0SEmily Shaffer     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",
971a344afc0SEmily Shaffer            NETFUN_SENSOR, IPMI_CMD_RESERVE_SDR_REPO);
972a344afc0SEmily Shaffer     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_RESERVE_SDR_REPO,
973a344afc0SEmily Shaffer                            nullptr, ipmi_sen_reserve_sdr,
974a344afc0SEmily Shaffer                            PRIVILEGE_USER);
97598a23840SMatthew Barth 
976d06e0e7eSEmily Shaffer     // <Get SDR Info>
977a344afc0SEmily Shaffer     printf("Registering NetFn:[0x%X], Cmd:[0x%x]\n",
978a344afc0SEmily Shaffer            NETFUN_SENSOR, IPMI_CMD_GET_SDR_INFO);
979a344afc0SEmily Shaffer     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SDR_INFO,
980a344afc0SEmily Shaffer                            nullptr, ipmi_sen_get_sdr_info,
981a344afc0SEmily Shaffer                            PRIVILEGE_USER);
982bbef71c2SEmily Shaffer 
983bbef71c2SEmily Shaffer     // <Get SDR>
984bbef71c2SEmily Shaffer     printf("Registering NetFn:[0x%X], Cmd:[0x%x]\n",
985bbef71c2SEmily Shaffer            NETFUN_SENSOR, IPMI_CMD_GET_SDR);
986bbef71c2SEmily Shaffer     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SDR,
987bbef71c2SEmily Shaffer                            nullptr, ipmi_sen_get_sdr,
988bbef71c2SEmily Shaffer                            PRIVILEGE_USER);
989bbef71c2SEmily Shaffer 
99098a23840SMatthew Barth     return;
99198a23840SMatthew Barth }
992