1 #include <mapper.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <bitset>
5 #include <systemd/sd-bus.h>
6 #include "host-ipmid/ipmid-api.h"
7 #include <phosphor-logging/log.hpp>
8 #include "ipmid.hpp"
9 #include "sensorhandler.h"
10 #include "types.hpp"
11 #include "utils.hpp"
12 
13 extern int updateSensorRecordFromSSRAESC(const void *);
14 extern sd_bus *bus;
15 extern const ipmi::sensor::IdInfoMap sensors;
16 using namespace phosphor::logging;
17 
18 void register_netfn_sen_functions()   __attribute__((constructor));
19 
20 struct sensorTypemap_t {
21     uint8_t number;
22     uint8_t typecode;
23     char dbusname[32];
24 } ;
25 
26 
27 sensorTypemap_t g_SensorTypeMap[] = {
28 
29     {0x01, 0x6F, "Temp"},
30     {0x0C, 0x6F, "DIMM"},
31     {0x0C, 0x6F, "MEMORY_BUFFER"},
32     {0x07, 0x6F, "PROC"},
33     {0x07, 0x6F, "CORE"},
34     {0x07, 0x6F, "CPU"},
35     {0x0F, 0x6F, "BootProgress"},
36     {0xe9, 0x09, "OccStatus"},  // E9 is an internal mapping to handle sensor type code os 0x09
37     {0xC3, 0x6F, "BootCount"},
38     {0x1F, 0x6F, "OperatingSystemStatus"},
39     {0x12, 0x6F, "SYSTEM_EVENT"},
40     {0xC7, 0x03, "SYSTEM"},
41     {0xC7, 0x03, "MAIN_PLANAR"},
42     {0xC2, 0x6F, "PowerCap"},
43     {0xD8, 0x03, "PowerSupplyRedundancy"},
44     {0xDA, 0x03, "TurboAllowed"},
45     {0xB4, 0x6F, "PowerSupplyDerating"},
46     {0xFF, 0x00, ""},
47 };
48 
49 
50 struct sensor_data_t {
51     uint8_t sennum;
52 }  __attribute__ ((packed)) ;
53 
54 struct sensorreadingresp_t {
55     uint8_t value;
56     uint8_t operation;
57     uint8_t indication[2];
58 }  __attribute__ ((packed)) ;
59 
60 // Use a lookup table to find the interface name of a specific sensor
61 // This will be used until an alternative is found.  this is the first
62 // step for mapping IPMI
63 int find_interface_property_fru_type(dbus_interface_t *interface, const char *property_name, char *property_value) {
64 
65     char  *str1;
66     sd_bus_error error = SD_BUS_ERROR_NULL;
67     sd_bus_message *reply = NULL, *m=NULL;
68 
69 
70     int r;
71 
72     r = sd_bus_message_new_method_call(bus,&m,interface->bus,interface->path,"org.freedesktop.DBus.Properties","Get");
73     if (r < 0) {
74         fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
75         fprintf(stderr,"Bus: %s Path: %s Interface: %s \n",
76                 interface->bus, interface->path, interface->interface);
77         goto final;
78     }
79 
80     r = sd_bus_message_append(m, "ss", "org.openbmc.InventoryItem", property_name);
81     if (r < 0) {
82         fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r));
83         fprintf(stderr,"Bus: %s Path: %s Interface: %s \n",
84                 interface->bus, interface->path, interface->interface);
85         goto final;
86     }
87 
88     r = sd_bus_call(bus, m, 0, &error, &reply);
89     if (r < 0) {
90         fprintf(stderr, "Failed to call the method: %s", strerror(-r));
91         goto final;
92     }
93 
94     r = sd_bus_message_read(reply, "v",  "s", &str1) ;
95     if (r < 0) {
96         fprintf(stderr, "Failed to get a response: %s", strerror(-r));
97         goto final;
98     }
99 
100     strcpy(property_value, str1);
101 
102 final:
103 
104     sd_bus_error_free(&error);
105     m = sd_bus_message_unref(m);
106     reply = sd_bus_message_unref(reply);
107 
108     return r;
109 }
110 
111 
112 // Use a lookup table to find the interface name of a specific sensor
113 // This will be used until an alternative is found.  this is the first
114 // step for mapping IPMI
115 int find_openbmc_path(const char *type, const uint8_t num, dbus_interface_t *interface) {
116     char  *busname = NULL;
117     const char  *iface = "org.openbmc.managers.System";
118     const char  *objname = "/org/openbmc/managers/System";
119     char  *str1 = NULL, *str2, *str3;
120     sd_bus_error error = SD_BUS_ERROR_NULL;
121     sd_bus_message *reply = NULL;
122 
123 
124     int r;
125     r = mapper_get_service(bus, objname, &busname);
126     if (r < 0) {
127         fprintf(stderr, "Failed to get %s busname: %s\n",
128                 objname, strerror(-r));
129         goto final;
130     }
131 
132     r = sd_bus_call_method(bus,busname,objname,iface, "getObjectFromByteId",
133                            &error, &reply, "sy", type, num);
134     if (r < 0) {
135         fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
136         goto final;
137     }
138 
139     r = sd_bus_message_read(reply, "(ss)", &str2, &str3);
140     if (r < 0) {
141         fprintf(stderr, "Failed to get a response: %s", strerror(-r));
142         goto final;
143     }
144 
145     r = mapper_get_service(bus, str2, &str1);
146     if (r < 0) {
147         fprintf(stderr, "Failed to get %s busname: %s\n",
148                 str2, strerror(-r));
149         goto final;
150     }
151 
152     strncpy(interface->bus, str1, MAX_DBUS_PATH);
153     strncpy(interface->path, str2, MAX_DBUS_PATH);
154     strncpy(interface->interface, str3, MAX_DBUS_PATH);
155 
156     interface->sensornumber = num;
157 
158 final:
159 
160     sd_bus_error_free(&error);
161     reply = sd_bus_message_unref(reply);
162     free(busname);
163     free(str1);
164 
165     return r;
166 }
167 
168 
169 /////////////////////////////////////////////////////////////////////
170 //
171 // Routines used by ipmi commands wanting to interact on the dbus
172 //
173 /////////////////////////////////////////////////////////////////////
174 int set_sensor_dbus_state_s(uint8_t number, const char *method, const char *value) {
175 
176 
177     dbus_interface_t a;
178     int r;
179     sd_bus_error error = SD_BUS_ERROR_NULL;
180     sd_bus_message *m=NULL;
181 
182     fprintf(ipmidbus, "Attempting to set a dbus Variant Sensor 0x%02x via %s with a value of %s\n",
183         number, method, value);
184 
185     r = find_openbmc_path("SENSOR", number, &a);
186 
187     if (r < 0) {
188         fprintf(stderr, "Failed to find Sensor 0x%02x\n", number);
189         return 0;
190     }
191 
192     r = sd_bus_message_new_method_call(bus,&m,a.bus,a.path,a.interface,method);
193     if (r < 0) {
194         fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
195         goto final;
196     }
197 
198     r = sd_bus_message_append(m, "v", "s", value);
199     if (r < 0) {
200         fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r));
201         goto final;
202     }
203 
204 
205     r = sd_bus_call(bus, m, 0, &error, NULL);
206     if (r < 0) {
207         fprintf(stderr, "Failed to call the method: %s", strerror(-r));
208     }
209 
210 final:
211     sd_bus_error_free(&error);
212     m = sd_bus_message_unref(m);
213 
214     return 0;
215 }
216 int set_sensor_dbus_state_y(uint8_t number, const char *method, const uint8_t value) {
217 
218 
219     dbus_interface_t a;
220     int r;
221     sd_bus_error error = SD_BUS_ERROR_NULL;
222     sd_bus_message *m=NULL;
223 
224     fprintf(ipmidbus, "Attempting to set a dbus Variant Sensor 0x%02x via %s with a value of 0x%02x\n",
225         number, method, value);
226 
227     r = find_openbmc_path("SENSOR", number, &a);
228 
229     if (r < 0) {
230         fprintf(stderr, "Failed to find Sensor 0x%02x\n", number);
231         return 0;
232     }
233 
234     r = sd_bus_message_new_method_call(bus,&m,a.bus,a.path,a.interface,method);
235     if (r < 0) {
236         fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
237         goto final;
238     }
239 
240     r = sd_bus_message_append(m, "v", "i", value);
241     if (r < 0) {
242         fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r));
243         goto final;
244     }
245 
246 
247     r = sd_bus_call(bus, m, 0, &error, NULL);
248     if (r < 0) {
249         fprintf(stderr, "12 Failed to call the method: %s", strerror(-r));
250     }
251 
252 final:
253     sd_bus_error_free(&error);
254     m = sd_bus_message_unref(m);
255 
256     return 0;
257 }
258 
259 uint8_t dbus_to_sensor_type(char *p) {
260 
261     sensorTypemap_t *s = g_SensorTypeMap;
262     char r=0;
263 
264     while (s->number != 0xFF) {
265         if (!strcmp(s->dbusname,p)) {
266             r = s->number;
267              break;
268         }
269         s++;
270     }
271 
272 
273     if (s->number == 0xFF)
274         printf("Failed to find Sensor Type %s\n", p);
275 
276     return r;
277 }
278 
279 
280 uint8_t dbus_to_sensor_type_from_dbus(dbus_interface_t *a) {
281     char fru_type_name[64];
282     int r= 0;
283 
284     r = find_interface_property_fru_type(a, "fru_type", fru_type_name);
285     if (r<0) {
286         fprintf(stderr, "Failed to get a fru type: %s", strerror(-r));
287         return -1;
288     } else {
289         return dbus_to_sensor_type(fru_type_name);
290     }
291 }
292 
293 
294 uint8_t find_sensor(uint8_t sensor_number) {
295 
296     dbus_interface_t a;
297     char *p;
298     int r;
299     uint8_t type;
300 
301     r = find_openbmc_path("SENSOR", sensor_number, &a);
302 
303     if (r < 0) { return 0; }
304 
305     // This is where sensors that do not exist in dbus but do
306     // exist in the host code stop.  This should indicate it
307     // is not a supported sensor
308     if (a.interface[0] == 0) { return 0;}
309 
310     if (strstr(a.interface, "InventoryItem")) {
311         // InventoryItems are real frus.  So need to get the
312         // fru_type property
313         type = dbus_to_sensor_type_from_dbus(&a);
314     } else {
315         // Non InventoryItems
316         p = strrchr (a.path, '/');
317         type = dbus_to_sensor_type(p+1);
318     }
319 
320     return type;
321  }
322 
323 
324 
325 
326 
327 ipmi_ret_t ipmi_sen_get_sensor_type(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
328                              ipmi_request_t request, ipmi_response_t response,
329                              ipmi_data_len_t data_len, ipmi_context_t context)
330 {
331     sensor_data_t *reqptr = (sensor_data_t*)request;
332     ipmi_ret_t rc = IPMI_CC_OK;
333 
334     printf("IPMI GET_SENSOR_TYPE [0x%02X]\n",reqptr->sennum);
335 
336     // TODO Not sure what the System-event-sensor is suppose to return
337     // need to ask Hostboot team
338     unsigned char buf[] = {0x00,0x6F};
339 
340     buf[0] = find_sensor(reqptr->sennum);
341 
342     // HACK UNTIL Dbus gets updated or we find a better way
343     if (buf[0] == 0) {
344         rc = IPMI_CC_SENSOR_INVALID;
345     }
346 
347 
348     *data_len = sizeof(buf);
349     memcpy(response, &buf, *data_len);
350 
351     return rc;
352 }
353 
354 ipmi_ret_t setSensorReading(void *request)
355 {
356     auto cmdData = static_cast<SetSensorReadingReq *>(request);
357 
358     auto assertionStates =
359             (static_cast<uint16_t>(cmdData->assertOffset8_14)) << 8 |
360             cmdData->assertOffset0_7;
361 
362     auto deassertionStates =
363             (static_cast<uint16_t>(cmdData->deassertOffset8_14)) << 8 |
364             cmdData->deassertOffset0_7;
365 
366     std::bitset<16> assertionSet(assertionStates);
367     std::bitset<16> deassertionSet(deassertionStates);
368 
369     // Check if the Sensor Number is present
370     auto iter = sensors.find(cmdData->number);
371     if (iter == sensors.end())
372     {
373         return IPMI_CC_SENSOR_INVALID;
374     }
375 
376     auto& interfaceList = iter->second.sensorInterfaces;
377     if (interfaceList.empty())
378     {
379         log<level::ERR>("Interface List empty for the sensor",
380                 entry("Sensor Number = %d", cmdData->number));
381         return IPMI_CC_UNSPECIFIED_ERROR;
382     }
383 
384     ipmi::sensor::ObjectMap objects;
385     ipmi::sensor::InterfaceMap interfaces;
386     for (const auto& interface : interfaceList)
387     {
388         for (const auto& property : interface.second)
389         {
390             ipmi::sensor::PropertyMap props;
391             bool valid = false;
392             for (const auto& value : property.second)
393             {
394                 if (assertionSet.test(value.first))
395                 {
396                     props.emplace(property.first, value.second.assert);
397                     valid = true;
398                 }
399                 else if (deassertionSet.test(value.first))
400                 {
401                     props.emplace(property.first, value.second.deassert);
402                     valid = true;
403                 }
404             }
405             if (valid)
406             {
407                 interfaces.emplace(interface.first, std::move(props));
408             }
409         }
410     }
411     objects.emplace(iter->second.sensorPath, std::move(interfaces));
412 
413     sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
414     using namespace std::string_literals;
415     static const auto intf = "xyz.openbmc_project.Inventory.Manager"s;
416     static const auto path = "/xyz/openbmc_project/inventory"s;
417     std::string service;
418 
419     try
420     {
421         service = ipmi::getService(bus, intf, path);
422 
423         // Update the inventory manager
424         auto pimMsg = bus.new_method_call(service.c_str(),
425                                           path.c_str(),
426                                           intf.c_str(),
427                                           "Notify");
428         pimMsg.append(std::move(objects));
429         auto inventoryMgrResponseMsg = bus.call(pimMsg);
430         if (inventoryMgrResponseMsg.is_method_error())
431         {
432             log<level::ERR>("Error in notify call");
433             return IPMI_CC_UNSPECIFIED_ERROR;
434         }
435     }
436     catch (const std::runtime_error& e)
437     {
438         log<level::ERR>(e.what());
439         return IPMI_CC_UNSPECIFIED_ERROR;
440     }
441 
442     return IPMI_CC_OK;
443 }
444 
445 ipmi_ret_t ipmi_sen_set_sensor(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
446                              ipmi_request_t request, ipmi_response_t response,
447                              ipmi_data_len_t data_len, ipmi_context_t context)
448 {
449     sensor_data_t *reqptr = (sensor_data_t*)request;
450 
451     printf("IPMI SET_SENSOR [0x%02x]\n",reqptr->sennum);
452 
453     /*
454      * This would support the Set Sensor Reading command for the presence
455      * and functional state of Processor, Core & DIMM. For the remaining
456      * sensors the existing support is invoked.
457      */
458     auto ipmiRC = setSensorReading(request);
459 
460     if(ipmiRC == IPMI_CC_SENSOR_INVALID)
461     {
462         updateSensorRecordFromSSRAESC(reqptr);
463         ipmiRC = IPMI_CC_OK;
464     }
465 
466     *data_len=0;
467     return ipmiRC;
468 }
469 
470 
471 ipmi_ret_t ipmi_sen_get_sensor_reading(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
472                              ipmi_request_t request, ipmi_response_t response,
473                              ipmi_data_len_t data_len, ipmi_context_t context)
474 {
475     sensor_data_t *reqptr = (sensor_data_t*)request;
476     ipmi_ret_t rc = IPMI_CC_SENSOR_INVALID;
477     uint8_t type;
478     sensorreadingresp_t *resp = (sensorreadingresp_t*) response;
479     int r;
480     dbus_interface_t a;
481     sd_bus *bus = ipmid_get_sd_bus_connection();
482     sd_bus_message *reply = NULL;
483     int reading = 0;
484 
485 
486     printf("IPMI GET_SENSOR_READING [0x%02x]\n",reqptr->sennum);
487 
488     r = find_openbmc_path("SENSOR", reqptr->sennum, &a);
489 
490     if (r < 0) {
491         fprintf(stderr, "Failed to find Sensor 0x%02x\n", reqptr->sennum);
492         return IPMI_CC_SENSOR_INVALID;
493     }
494 
495     type = find_sensor(reqptr->sennum);
496     if(type == 0) {
497         fprintf(stderr, "Failed to find Sensor 0x%02x\n", reqptr->sennum);
498         return IPMI_CC_SENSOR_INVALID;
499     }
500 
501     fprintf(stderr, "Bus: %s, Path: %s, Interface: %s\n", a.bus, a.path, a.interface);
502 
503     *data_len=0;
504 
505     switch(type) {
506         case 0xC3:
507         case 0xC2:
508             r = sd_bus_get_property(bus,a.bus, a.path, a.interface, "value", NULL, &reply, "i");
509             if (r < 0) {
510                 fprintf(stderr, "Failed to call sd_bus_get_property:%d,  %s\n", r, strerror(-r));
511                 fprintf(stderr, "Bus: %s, Path: %s, Interface: %s\n",
512                         a.bus, a.path, a.interface);
513                 break;
514             }
515 
516             r = sd_bus_message_read(reply, "i", &reading);
517             if (r < 0) {
518                 fprintf(stderr, "Failed to read sensor: %s\n", strerror(-r));
519                 break;
520             }
521 
522             printf("Contents of a 0x%02x is 0x%02x\n", type, reading);
523 
524             rc = IPMI_CC_OK;
525             *data_len=sizeof(sensorreadingresp_t);
526 
527             resp->value         = (uint8_t)reading;
528             resp->operation     = 0;
529             resp->indication[0] = 0;
530             resp->indication[1] = 0;
531             break;
532 
533         default:
534             *data_len=0;
535             rc = IPMI_CC_SENSOR_INVALID;
536             break;
537     }
538 
539 
540     reply = sd_bus_message_unref(reply);
541 
542     return rc;
543 }
544 
545 ipmi_ret_t ipmi_sen_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
546                              ipmi_request_t request, ipmi_response_t response,
547                              ipmi_data_len_t data_len, ipmi_context_t context)
548 {
549     ipmi_ret_t rc = IPMI_CC_INVALID;
550 
551     printf("IPMI S/E Wildcard Netfn:[0x%X], Cmd:[0x%X]\n",netfn,cmd);
552     *data_len = 0;
553 
554     return rc;
555 }
556 
557 
558 void register_netfn_sen_functions()
559 {
560     // <Wildcard Command>
561     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_SENSOR, IPMI_CMD_WILDCARD);
562     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_WILDCARD, NULL, ipmi_sen_wildcard,
563                            PRIVILEGE_USER);
564 
565     // <Get Sensor Type>
566     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_TYPE);
567     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_TYPE, NULL, ipmi_sen_get_sensor_type,
568                            PRIVILEGE_USER);
569 
570     // <Set Sensor Reading and Event Status>
571     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_SENSOR, IPMI_CMD_SET_SENSOR);
572     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_SET_SENSOR, NULL, ipmi_sen_set_sensor,
573                            PRIVILEGE_OPERATOR);
574 
575     // <Get Sensor Reading>
576     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_READING);
577     ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_READING, NULL,
578                            ipmi_sen_get_sensor_reading, PRIVILEGE_USER);
579 
580     return;
581 }
582