1 #include <mapper.h> 2 #include <math.h> 3 #include <stdio.h> 4 #include <string.h> 5 #include <set> 6 #include <bitset> 7 #include <xyz/openbmc_project/Sensor/Value/server.hpp> 8 #include <systemd/sd-bus.h> 9 #include "host-ipmid/ipmid-api.h" 10 #include <phosphor-logging/log.hpp> 11 #include <phosphor-logging/elog-errors.hpp> 12 #include "ipmid.hpp" 13 #include "sensorhandler.h" 14 #include "types.hpp" 15 #include "utils.hpp" 16 #include "xyz/openbmc_project/Common/error.hpp" 17 18 extern int updateSensorRecordFromSSRAESC(const void *); 19 extern sd_bus *bus; 20 extern const ipmi::sensor::IdInfoMap sensors; 21 using namespace phosphor::logging; 22 using InternalFailure = 23 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 24 25 void register_netfn_sen_functions() __attribute__((constructor)); 26 27 struct sensorTypemap_t { 28 uint8_t number; 29 uint8_t typecode; 30 char dbusname[32]; 31 } ; 32 33 sensorTypemap_t g_SensorTypeMap[] = { 34 35 {0x01, 0x6F, "Temp"}, 36 {0x0C, 0x6F, "DIMM"}, 37 {0x0C, 0x6F, "MEMORY_BUFFER"}, 38 {0x07, 0x6F, "PROC"}, 39 {0x07, 0x6F, "CORE"}, 40 {0x07, 0x6F, "CPU"}, 41 {0x0F, 0x6F, "BootProgress"}, 42 {0xe9, 0x09, "OccStatus"}, // E9 is an internal mapping to handle sensor type code os 0x09 43 {0xC3, 0x6F, "BootCount"}, 44 {0x1F, 0x6F, "OperatingSystemStatus"}, 45 {0x12, 0x6F, "SYSTEM_EVENT"}, 46 {0xC7, 0x03, "SYSTEM"}, 47 {0xC7, 0x03, "MAIN_PLANAR"}, 48 {0xC2, 0x6F, "PowerCap"}, 49 {0x0b, 0xCA, "PowerSupplyRedundancy"}, 50 {0xDA, 0x03, "TurboAllowed"}, 51 {0xD8, 0xC8, "PowerSupplyDerating"}, 52 {0xFF, 0x00, ""}, 53 }; 54 55 56 struct sensor_data_t { 57 uint8_t sennum; 58 } __attribute__ ((packed)) ; 59 60 struct sensorreadingresp_t { 61 uint8_t value; 62 uint8_t operation; 63 uint8_t indication[2]; 64 } __attribute__ ((packed)) ; 65 66 // Use a lookup table to find the interface name of a specific sensor 67 // This will be used until an alternative is found. this is the first 68 // step for mapping IPMI 69 int find_interface_property_fru_type(dbus_interface_t *interface, const char *property_name, char *property_value) { 70 71 char *str1; 72 sd_bus_error error = SD_BUS_ERROR_NULL; 73 sd_bus_message *reply = NULL, *m=NULL; 74 75 76 int r; 77 78 r = sd_bus_message_new_method_call(bus,&m,interface->bus,interface->path,"org.freedesktop.DBus.Properties","Get"); 79 if (r < 0) { 80 fprintf(stderr, "Failed to create a method call: %s", strerror(-r)); 81 fprintf(stderr,"Bus: %s Path: %s Interface: %s \n", 82 interface->bus, interface->path, interface->interface); 83 goto final; 84 } 85 86 r = sd_bus_message_append(m, "ss", "org.openbmc.InventoryItem", property_name); 87 if (r < 0) { 88 fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r)); 89 fprintf(stderr,"Bus: %s Path: %s Interface: %s \n", 90 interface->bus, interface->path, interface->interface); 91 goto final; 92 } 93 94 r = sd_bus_call(bus, m, 0, &error, &reply); 95 if (r < 0) { 96 fprintf(stderr, "Failed to call the method: %s", strerror(-r)); 97 goto final; 98 } 99 100 r = sd_bus_message_read(reply, "v", "s", &str1) ; 101 if (r < 0) { 102 fprintf(stderr, "Failed to get a response: %s", strerror(-r)); 103 goto final; 104 } 105 106 strcpy(property_value, str1); 107 108 final: 109 110 sd_bus_error_free(&error); 111 m = sd_bus_message_unref(m); 112 reply = sd_bus_message_unref(reply); 113 114 return r; 115 } 116 117 int get_bus_for_path(const char *path, char **busname) { 118 return mapper_get_service(bus, path, busname); 119 } 120 121 int legacy_dbus_openbmc_path(const char *type, const uint8_t num, dbus_interface_t *interface) { 122 char *busname = NULL; 123 const char *iface = "org.openbmc.managers.System"; 124 const char *objname = "/org/openbmc/managers/System"; 125 char *str1 = NULL, *str2, *str3; 126 sd_bus_error error = SD_BUS_ERROR_NULL; 127 sd_bus_message *reply = NULL; 128 129 130 int r; 131 r = get_bus_for_path(objname, &busname); 132 if (r < 0) { 133 fprintf(stderr, "Failed to get %s busname: %s\n", 134 objname, strerror(-r)); 135 goto final; 136 } 137 138 r = sd_bus_call_method(bus,busname,objname,iface, "getObjectFromByteId", 139 &error, &reply, "sy", type, num); 140 if (r < 0) { 141 fprintf(stderr, "Failed to create a method call: %s", strerror(-r)); 142 goto final; 143 } 144 145 r = sd_bus_message_read(reply, "(ss)", &str2, &str3); 146 if (r < 0) { 147 fprintf(stderr, "Failed to get a response: %s", strerror(-r)); 148 goto final; 149 } 150 151 r = get_bus_for_path(str2, &str1); 152 if (r < 0) { 153 fprintf(stderr, "Failed to get %s busname: %s\n", 154 str2, strerror(-r)); 155 goto final; 156 } 157 158 strncpy(interface->bus, str1, MAX_DBUS_PATH); 159 strncpy(interface->path, str2, MAX_DBUS_PATH); 160 strncpy(interface->interface, str3, MAX_DBUS_PATH); 161 162 interface->sensornumber = num; 163 // Make sure we know that the type hasn't been set, as newer codebase will 164 // set it automatically from the YAML at this step. 165 interface->sensortype = 0; 166 167 final: 168 169 sd_bus_error_free(&error); 170 reply = sd_bus_message_unref(reply); 171 free(busname); 172 free(str1); 173 174 return r; 175 } 176 177 // Use a lookup table to find the interface name of a specific sensor 178 // This will be used until an alternative is found. this is the first 179 // step for mapping IPMI 180 int find_openbmc_path(uint8_t num, dbus_interface_t *interface) { 181 int rc; 182 183 // When the sensor map does not contain the sensor requested, 184 // fall back to the legacy DBus lookup (deprecated) 185 const auto& sensor_it = sensors.find(num); 186 if (sensor_it == sensors.end()) 187 { 188 return legacy_dbus_openbmc_path("SENSOR", num, interface); 189 } 190 191 const auto& info = sensor_it->second; 192 193 char* busname = nullptr; 194 rc = get_bus_for_path(info.sensorPath.c_str(), &busname); 195 if (rc < 0) { 196 fprintf(stderr, "Failed to get %s busname: %s\n", 197 info.sensorPath.c_str(), 198 busname); 199 goto final; 200 } 201 202 interface->sensortype = info.sensorType; 203 strcpy(interface->bus, busname); 204 strcpy(interface->path, info.sensorPath.c_str()); 205 // Take the interface name from the beginning of the DbusInterfaceMap. This 206 // works for the Value interface but may not suffice for more complex 207 // sensors. 208 // tracked https://github.com/openbmc/phosphor-host-ipmid/issues/103 209 strcpy(interface->interface, info.propertyInterfaces.begin()->first.c_str()); 210 interface->sensornumber = num; 211 212 final: 213 free(busname); 214 return rc; 215 } 216 217 218 ///////////////////////////////////////////////////////////////////// 219 // 220 // Routines used by ipmi commands wanting to interact on the dbus 221 // 222 ///////////////////////////////////////////////////////////////////// 223 int set_sensor_dbus_state_s(uint8_t number, const char *method, const char *value) { 224 225 226 dbus_interface_t a; 227 int r; 228 sd_bus_error error = SD_BUS_ERROR_NULL; 229 sd_bus_message *m=NULL; 230 231 fprintf(ipmidbus, "Attempting to set a dbus Variant Sensor 0x%02x via %s with a value of %s\n", 232 number, method, value); 233 234 r = find_openbmc_path(number, &a); 235 236 if (r < 0) { 237 fprintf(stderr, "Failed to find Sensor 0x%02x\n", number); 238 return 0; 239 } 240 241 r = sd_bus_message_new_method_call(bus,&m,a.bus,a.path,a.interface,method); 242 if (r < 0) { 243 fprintf(stderr, "Failed to create a method call: %s", strerror(-r)); 244 goto final; 245 } 246 247 r = sd_bus_message_append(m, "v", "s", value); 248 if (r < 0) { 249 fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r)); 250 goto final; 251 } 252 253 254 r = sd_bus_call(bus, m, 0, &error, NULL); 255 if (r < 0) { 256 fprintf(stderr, "Failed to call the method: %s", strerror(-r)); 257 } 258 259 final: 260 sd_bus_error_free(&error); 261 m = sd_bus_message_unref(m); 262 263 return 0; 264 } 265 int set_sensor_dbus_state_y(uint8_t number, const char *method, const uint8_t value) { 266 267 268 dbus_interface_t a; 269 int r; 270 sd_bus_error error = SD_BUS_ERROR_NULL; 271 sd_bus_message *m=NULL; 272 273 fprintf(ipmidbus, "Attempting to set a dbus Variant Sensor 0x%02x via %s with a value of 0x%02x\n", 274 number, method, value); 275 276 r = find_openbmc_path(number, &a); 277 278 if (r < 0) { 279 fprintf(stderr, "Failed to find Sensor 0x%02x\n", number); 280 return 0; 281 } 282 283 r = sd_bus_message_new_method_call(bus,&m,a.bus,a.path,a.interface,method); 284 if (r < 0) { 285 fprintf(stderr, "Failed to create a method call: %s", strerror(-r)); 286 goto final; 287 } 288 289 r = sd_bus_message_append(m, "v", "i", value); 290 if (r < 0) { 291 fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r)); 292 goto final; 293 } 294 295 296 r = sd_bus_call(bus, m, 0, &error, NULL); 297 if (r < 0) { 298 fprintf(stderr, "12 Failed to call the method: %s", strerror(-r)); 299 } 300 301 final: 302 sd_bus_error_free(&error); 303 m = sd_bus_message_unref(m); 304 305 return 0; 306 } 307 308 uint8_t dbus_to_sensor_type(char *p) { 309 310 sensorTypemap_t *s = g_SensorTypeMap; 311 char r=0; 312 while (s->number != 0xFF) { 313 if (!strcmp(s->dbusname,p)) { 314 r = s->typecode; 315 break; 316 } 317 s++; 318 } 319 320 if (s->number == 0xFF) 321 printf("Failed to find Sensor Type %s\n", p); 322 323 return r; 324 } 325 326 327 uint8_t dbus_to_sensor_type_from_dbus(dbus_interface_t *a) { 328 char fru_type_name[64]; 329 int r= 0; 330 331 r = find_interface_property_fru_type(a, "fru_type", fru_type_name); 332 if (r<0) { 333 fprintf(stderr, "Failed to get a fru type: %s", strerror(-r)); 334 return -1; 335 } else { 336 return dbus_to_sensor_type(fru_type_name); 337 } 338 } 339 340 uint8_t get_type_from_interface(dbus_interface_t dbus_if) { 341 342 char *p; 343 uint8_t type; 344 345 // This is where sensors that do not exist in dbus but do 346 // exist in the host code stop. This should indicate it 347 // is not a supported sensor 348 if (dbus_if.interface[0] == 0) { return 0;} 349 350 // Fetch type from interface itself. 351 if (dbus_if.sensortype != 0) 352 { 353 type = dbus_if.sensortype; 354 } 355 // Legacy codebase does not populate type during initial handling: 356 else if (strstr(dbus_if.interface, "InventoryItem")) { 357 // InventoryItems are real frus. So need to get the 358 // fru_type property 359 type = dbus_to_sensor_type_from_dbus(&dbus_if); 360 } else { 361 // Non InventoryItems 362 p = strrchr (dbus_if.path, '/'); 363 type = dbus_to_sensor_type(p+1); 364 } 365 366 return type; 367 } 368 369 // Replaces find_sensor 370 uint8_t find_type_for_sensor_number(uint8_t num) { 371 int r; 372 dbus_interface_t dbus_if; 373 r = find_openbmc_path(num, &dbus_if); 374 if (r < 0) { 375 fprintf(stderr, "Could not find sensor %d\n", num); 376 return r; 377 } 378 return get_type_from_interface(dbus_if); 379 } 380 381 382 383 384 385 ipmi_ret_t ipmi_sen_get_sensor_type(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 386 ipmi_request_t request, ipmi_response_t response, 387 ipmi_data_len_t data_len, ipmi_context_t context) 388 { 389 sensor_data_t *reqptr = (sensor_data_t*)request; 390 ipmi_ret_t rc = IPMI_CC_OK; 391 392 printf("IPMI GET_SENSOR_TYPE [0x%02X]\n",reqptr->sennum); 393 394 // TODO Not sure what the System-event-sensor is suppose to return 395 // need to ask Hostboot team 396 unsigned char buf[] = {0x00,0x6F}; 397 398 buf[0] = find_type_for_sensor_number(reqptr->sennum); 399 400 // HACK UNTIL Dbus gets updated or we find a better way 401 if (buf[0] == 0) { 402 rc = IPMI_CC_SENSOR_INVALID; 403 } 404 405 406 *data_len = sizeof(buf); 407 memcpy(response, &buf, *data_len); 408 409 return rc; 410 } 411 412 const std::set<std::string> analogSensorInterfaces = 413 { 414 "xyz.openbmc_project.Sensor.Value", 415 }; 416 417 bool isAnalogSensor(const std::string& interface) 418 { 419 return (analogSensorInterfaces.count(interface)); 420 } 421 422 ipmi_ret_t setSensorReading(void *request) 423 { 424 ipmi::sensor::SetSensorReadingReq cmdData = 425 *(static_cast<ipmi::sensor::SetSensorReadingReq *>(request)); 426 427 // Check if the Sensor Number is present 428 const auto iter = sensors.find(cmdData.number); 429 if (iter == sensors.end()) 430 { 431 return IPMI_CC_SENSOR_INVALID; 432 } 433 434 try 435 { 436 return iter->second.updateFunc(cmdData, iter->second); 437 } 438 catch (InternalFailure& e) 439 { 440 log<level::ERR>("Set sensor failed", 441 entry("SENSOR_NUM=%d", cmdData.number)); 442 commit<InternalFailure>(); 443 } 444 catch (const std::runtime_error& e) 445 { 446 log<level::ERR>(e.what()); 447 } 448 449 return IPMI_CC_UNSPECIFIED_ERROR; 450 } 451 452 ipmi_ret_t ipmi_sen_set_sensor(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 453 ipmi_request_t request, ipmi_response_t response, 454 ipmi_data_len_t data_len, ipmi_context_t context) 455 { 456 sensor_data_t *reqptr = (sensor_data_t*)request; 457 458 printf("IPMI SET_SENSOR [0x%02x]\n",reqptr->sennum); 459 460 /* 461 * This would support the Set Sensor Reading command for the presence 462 * and functional state of Processor, Core & DIMM. For the remaining 463 * sensors the existing support is invoked. 464 */ 465 auto ipmiRC = setSensorReading(request); 466 467 if(ipmiRC == IPMI_CC_SENSOR_INVALID) 468 { 469 updateSensorRecordFromSSRAESC(reqptr); 470 ipmiRC = IPMI_CC_OK; 471 } 472 473 *data_len=0; 474 return ipmiRC; 475 } 476 477 478 ipmi_ret_t ipmi_sen_get_sensor_reading(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 479 ipmi_request_t request, ipmi_response_t response, 480 ipmi_data_len_t data_len, ipmi_context_t context) 481 { 482 sensor_data_t *reqptr = (sensor_data_t*)request; 483 ipmi_ret_t rc = IPMI_CC_SENSOR_INVALID; 484 uint8_t type = 0; 485 sensorreadingresp_t *resp = (sensorreadingresp_t*) response; 486 int r; 487 dbus_interface_t a; 488 sd_bus *bus = ipmid_get_sd_bus_connection(); 489 sd_bus_message *reply = NULL; 490 int reading = 0; 491 492 printf("IPMI GET_SENSOR_READING [0x%02x]\n",reqptr->sennum); 493 494 r = find_openbmc_path(reqptr->sennum, &a); 495 496 if (r < 0) 497 { 498 fprintf(stderr, "Failed to find Sensor 0x%02x\n", reqptr->sennum); 499 } 500 else 501 { 502 type = get_type_from_interface(a); 503 if(type == 0) { 504 fprintf(stderr, "Failed to find Sensor 0x%02x\n", reqptr->sennum); 505 return IPMI_CC_SENSOR_INVALID; 506 } 507 508 fprintf(stderr, "Bus: %s, Path: %s, Interface: %s\n", a.bus, a.path, 509 a.interface); 510 } 511 512 *data_len=0; 513 514 int64_t raw_value; 515 ipmi::sensor::Info sensor; 516 517 switch(type) { 518 case 0xC2: 519 case 0xC8: 520 r = sd_bus_get_property(bus,a.bus, a.path, a.interface, "value", NULL, &reply, "i"); 521 if (r < 0) { 522 fprintf(stderr, "Failed to call sd_bus_get_property:%d, %s\n", r, strerror(-r)); 523 fprintf(stderr, "Bus: %s, Path: %s, Interface: %s\n", 524 a.bus, a.path, a.interface); 525 break; 526 } 527 528 r = sd_bus_message_read(reply, "i", &reading); 529 if (r < 0) { 530 fprintf(stderr, "Failed to read sensor: %s\n", strerror(-r)); 531 break; 532 } 533 534 printf("Contents of a 0x%02x is 0x%02x\n", type, reading); 535 536 rc = IPMI_CC_OK; 537 *data_len=sizeof(sensorreadingresp_t); 538 539 resp->value = (uint8_t)reading; 540 resp->operation = 0; 541 resp->indication[0] = 0; 542 resp->indication[1] = 0; 543 break; 544 545 case IPMI_SENSOR_TEMP: 546 case IPMI_SENSOR_VOLTAGE: 547 case IPMI_SENSOR_CURRENT: 548 case IPMI_SENSOR_FAN: 549 // Get reading for /xyz/openbmc_project/Sensor/Value.interface 550 if(sensors.find(reqptr->sennum) == sensors.end()) 551 { 552 fprintf(stderr, "Failed to find config entry for Sensor 0x%02x\n", 553 reqptr->sennum); 554 return IPMI_CC_SENSOR_INVALID; 555 } 556 557 sensor = sensors.at(reqptr->sennum); 558 if (ipmi::sensor::Mutability::Read != 559 (sensor.mutability & ipmi::sensor::Mutability::Read)) 560 { 561 log<level::ERR>("Sensor was not readable.\n"); 562 return IPMI_CC_SENSOR_INVALID; 563 } 564 565 566 // Get value 567 r = sd_bus_get_property_trivial(bus, 568 a.bus, 569 a.path, 570 a.interface, 571 "Value", 572 NULL, 573 'x', 574 &raw_value); 575 if (r < 0) { 576 fprintf(stderr, 577 "Failed to call sd_bus_get_property:%d, %s, 'value'\n", 578 r, 579 strerror(-r)); 580 fprintf(stderr, "Bus: %s, Path: %s, Interface: %s\n", 581 a.bus, a.path, a.interface); 582 break; 583 } 584 585 // Prevent div0 586 if (sensor.coefficientM == 0) { 587 sensor.coefficientM = 1; 588 }; 589 590 resp->value = static_cast<uint8_t>( 591 (raw_value - sensor.scaledOffset) / sensor.coefficientM); 592 resp->operation = 1<<6; // scanning enabled 593 resp->indication[0] = 0; // not a threshold sensor. ignore 594 resp->indication[1] = 0; 595 rc = IPMI_CC_OK; 596 *data_len=sizeof(sensorreadingresp_t); 597 break; 598 default: 599 { 600 const auto iter = sensors.find(reqptr->sennum); 601 if (iter == sensors.end()) 602 { 603 return IPMI_CC_SENSOR_INVALID; 604 } 605 606 try 607 { 608 auto getResponse = iter->second.getFunc(iter->second); 609 *data_len = getResponse.size(); 610 memcpy(resp, getResponse.data(), *data_len); 611 return IPMI_CC_OK; 612 } 613 catch (InternalFailure& e) 614 { 615 log<level::ERR>("Get sensor failed", 616 entry("SENSOR_NUM=%d", reqptr->sennum)); 617 commit<InternalFailure>(); 618 return IPMI_CC_SENSOR_INVALID; 619 } 620 catch (const std::runtime_error& e) 621 { 622 log<level::ERR>(e.what()); 623 return IPMI_CC_SENSOR_INVALID; 624 } 625 } 626 } 627 628 reply = sd_bus_message_unref(reply); 629 630 return rc; 631 } 632 633 ipmi_ret_t ipmi_sen_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 634 ipmi_request_t request, ipmi_response_t response, 635 ipmi_data_len_t data_len, ipmi_context_t context) 636 { 637 ipmi_ret_t rc = IPMI_CC_INVALID; 638 639 printf("IPMI S/E Wildcard Netfn:[0x%X], Cmd:[0x%X]\n",netfn,cmd); 640 *data_len = 0; 641 642 return rc; 643 } 644 645 ipmi_ret_t ipmi_sen_get_sdr_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 646 ipmi_request_t request, 647 ipmi_response_t response, 648 ipmi_data_len_t data_len, 649 ipmi_context_t context) 650 { 651 auto resp = static_cast<get_sdr_info::GetSdrInfoResp*>(response); 652 if (request == nullptr || 653 get_sdr_info::request::get_count(request) == false) 654 { 655 // Get Sensor Count 656 resp->count = sensors.size(); 657 } 658 else 659 { 660 resp->count = 1; 661 } 662 663 // Multiple LUNs not supported. 664 namespace response = get_sdr_info::response; 665 response::set_lun_present(0, &(resp->luns_and_dynamic_population)); 666 response::set_lun_not_present(1, &(resp->luns_and_dynamic_population)); 667 response::set_lun_not_present(2, &(resp->luns_and_dynamic_population)); 668 response::set_lun_not_present(3, &(resp->luns_and_dynamic_population)); 669 response::set_static_population(&(resp->luns_and_dynamic_population)); 670 671 *data_len = SDR_INFO_RESP_SIZE; 672 673 return IPMI_CC_OK; 674 } 675 676 ipmi_ret_t ipmi_sen_reserve_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 677 ipmi_request_t request, 678 ipmi_response_t response, 679 ipmi_data_len_t data_len, 680 ipmi_context_t context) 681 { 682 // A constant reservation ID is okay until we implement add/remove SDR. 683 const uint16_t reservation_id = 1; 684 *(uint16_t*)response = reservation_id; 685 *data_len = sizeof(uint16_t); 686 687 printf("Created new IPMI SDR reservation ID %d\n", *(uint16_t*)response); 688 return IPMI_CC_OK; 689 } 690 691 void setUnitFieldsForObject(sd_bus *bus, 692 const dbus_interface_t &iface, 693 const ipmi::sensor::Info *info, 694 get_sdr::SensorDataFullRecordBody *body) 695 { 696 if (info->propertyInterfaces.begin()->first == 697 "xyz.openbmc_project.Sensor.Value") 698 { 699 std::string result {}; 700 if (info->unit.empty()) 701 { 702 char *raw_cstr = NULL; 703 if (0 > sd_bus_get_property_string(bus, iface.bus, iface.path, 704 iface.interface, "Unit", NULL, 705 &raw_cstr)) 706 { 707 log<level::WARNING>("Unit interface missing.", 708 entry("BUS=%s", iface.bus), 709 entry("PATH=%s", iface.path)); 710 } 711 else 712 { 713 result = raw_cstr; 714 } 715 free(raw_cstr); 716 } 717 else 718 { 719 result = info->unit; 720 } 721 722 namespace server = sdbusplus::xyz::openbmc_project::Sensor::server; 723 try { 724 auto unit = server::Value::convertUnitFromString(result); 725 // Unit strings defined in 726 // phosphor-dbus-interfaces/xyz/openbmc_project/Sensor/Value.interface.yaml 727 switch (unit) 728 { 729 case server::Value::Unit::DegreesC: 730 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_DEGREES_C; 731 break; 732 case server::Value::Unit::RPMS: 733 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_REVOLUTIONS; // revolutions 734 get_sdr::body::set_rate_unit(0b100, body); // per minute 735 break; 736 case server::Value::Unit::Volts: 737 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_VOLTS; 738 break; 739 case server::Value::Unit::Meters: 740 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_METERS; 741 break; 742 case server::Value::Unit::Amperes: 743 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_AMPERES; 744 break; 745 case server::Value::Unit::Joules: 746 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_JOULES; 747 break; 748 default: 749 // Cannot be hit. 750 fprintf(stderr, "Unknown value unit type: = %s\n", result.c_str()); 751 } 752 } 753 catch (sdbusplus::exception::InvalidEnumString e) 754 { 755 log<level::WARNING>("Warning: no unit provided for sensor!"); 756 } 757 } 758 } 759 760 int64_t getScaleForObject(sd_bus *bus, 761 const dbus_interface_t& iface, 762 const ipmi::sensor::Info *info) 763 { 764 int64_t result = 0; 765 if (info->propertyInterfaces.begin()->first == 766 "xyz.openbmc_project.Sensor.Value") 767 { 768 if (info->hasScale) 769 { 770 result = info->scale; 771 } 772 else 773 { 774 if (0 > sd_bus_get_property_trivial(bus, 775 iface.bus, 776 iface.path, 777 iface.interface, 778 "Scale", 779 NULL, 780 'x', 781 &result)) { 782 log<level::WARNING>("Scale interface missing.", 783 entry("BUS=%s", iface.bus), 784 entry("PATH=%s", iface.path)); 785 } 786 } 787 } 788 789 return result; 790 } 791 792 ipmi_ret_t populate_record_from_dbus(get_sdr::SensorDataFullRecordBody *body, 793 const ipmi::sensor::Info *info, 794 ipmi_data_len_t data_len) 795 { 796 /* Functional sensor case */ 797 if (isAnalogSensor(info->propertyInterfaces.begin()->first)) 798 { 799 // Get bus 800 sd_bus *bus = ipmid_get_sd_bus_connection(); 801 dbus_interface_t iface; 802 803 if (0 > find_openbmc_path(body->entity_id, &iface)) 804 return IPMI_CC_SENSOR_INVALID; 805 806 body->sensor_units_1 = 0; // unsigned, no rate, no modifier, not a % 807 808 /* Unit info */ 809 setUnitFieldsForObject(bus, iface, info, body); 810 811 /* Modifiers to reading info */ 812 // Get scale 813 int64_t scale = getScaleForObject(bus, iface, info); 814 815 get_sdr::body::set_b(info->coefficientB, body); 816 get_sdr::body::set_m(info->coefficientM, body); 817 get_sdr::body::set_b_exp(info->exponentB, body); 818 get_sdr::body::set_r_exp(scale, body); 819 820 /* ID string */ 821 std::string id_string = info->sensorPath.substr( 822 info->sensorPath.find_last_of('/')+1, info->sensorPath.length()); 823 get_sdr::body::set_id_type(0b00, body); // 00 = unicode 824 if (id_string.length() > FULL_RECORD_ID_STR_MAX_LENGTH) 825 { 826 get_sdr::body::set_id_strlen(FULL_RECORD_ID_STR_MAX_LENGTH, body); 827 } 828 else 829 { 830 get_sdr::body::set_id_strlen(id_string.length(), body); 831 } 832 strncpy(body->id_string, id_string.c_str(), 833 get_sdr::body::get_id_strlen(body)); 834 } 835 836 return IPMI_CC_OK; 837 }; 838 839 ipmi_ret_t ipmi_sen_get_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 840 ipmi_request_t request, ipmi_response_t response, 841 ipmi_data_len_t data_len, ipmi_context_t context) 842 { 843 ipmi_ret_t ret = IPMI_CC_OK; 844 get_sdr::GetSdrReq *req = (get_sdr::GetSdrReq*)request; 845 get_sdr::GetSdrResp *resp = (get_sdr::GetSdrResp*)response; 846 get_sdr::SensorDataFullRecord record = {0}; 847 if (req != NULL) 848 { 849 // Note: we use an iterator so we can provide the next ID at the end of 850 // the call. 851 auto sensor = sensors.begin(); 852 853 // At the beginning of a scan, the host side will send us id=0. 854 if (get_sdr::request::get_record_id(req) != 0) 855 { 856 sensor = sensors.find(get_sdr::request::get_record_id(req)); 857 if(sensor == sensors.end()) { 858 return IPMI_CC_SENSOR_INVALID; 859 } 860 } 861 862 uint8_t sensor_id = sensor->first; 863 864 /* Header */ 865 get_sdr::header::set_record_id(sensor_id, &(record.header)); 866 record.header.sdr_version = 0x51; // Based on IPMI Spec v2.0 rev 1.1 867 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD; 868 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord); 869 870 /* Key */ 871 record.key.sensor_number = sensor_id; 872 873 /* Body */ 874 record.body.entity_id = sensor_id; 875 record.body.sensor_type = sensor->second.sensorType; 876 record.body.event_reading_type = sensor->second.sensorReadingType; 877 878 // Set the type-specific details given the DBus interface 879 ret = populate_record_from_dbus(&(record.body), &(sensor->second), 880 data_len); 881 882 if (++sensor == sensors.end()) 883 { 884 get_sdr::response::set_next_record_id(0xFFFF, resp); // last record 885 } 886 else 887 { 888 get_sdr::response::set_next_record_id(sensor->first, resp); 889 } 890 891 *data_len = sizeof(get_sdr::GetSdrResp) - req->offset; 892 memcpy(resp->record_data, (char*)&record + req->offset, 893 sizeof(get_sdr::SensorDataFullRecord) - req->offset); 894 } 895 896 return ret; 897 } 898 899 900 void register_netfn_sen_functions() 901 { 902 // <Wildcard Command> 903 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", 904 NETFUN_SENSOR, IPMI_CMD_WILDCARD); 905 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_WILDCARD, 906 nullptr, ipmi_sen_wildcard, 907 PRIVILEGE_USER); 908 909 // <Get Sensor Type> 910 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", 911 NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_TYPE); 912 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_TYPE, 913 nullptr, ipmi_sen_get_sensor_type, 914 PRIVILEGE_USER); 915 916 // <Set Sensor Reading and Event Status> 917 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", 918 NETFUN_SENSOR, IPMI_CMD_SET_SENSOR); 919 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_SET_SENSOR, 920 nullptr, ipmi_sen_set_sensor, 921 PRIVILEGE_OPERATOR); 922 923 // <Get Sensor Reading> 924 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", 925 NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_READING); 926 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_READING, 927 nullptr, ipmi_sen_get_sensor_reading, 928 PRIVILEGE_USER); 929 930 // <Reserve SDR> 931 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", 932 NETFUN_SENSOR, IPMI_CMD_RESERVE_SDR_REPO); 933 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_RESERVE_SDR_REPO, 934 nullptr, ipmi_sen_reserve_sdr, 935 PRIVILEGE_USER); 936 937 // <Get SDR Info> 938 printf("Registering NetFn:[0x%X], Cmd:[0x%x]\n", 939 NETFUN_SENSOR, IPMI_CMD_GET_SDR_INFO); 940 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SDR_INFO, 941 nullptr, ipmi_sen_get_sdr_info, 942 PRIVILEGE_USER); 943 944 // <Get SDR> 945 printf("Registering NetFn:[0x%X], Cmd:[0x%x]\n", 946 NETFUN_SENSOR, IPMI_CMD_GET_SDR); 947 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SDR, 948 nullptr, ipmi_sen_get_sdr, 949 PRIVILEGE_USER); 950 951 return; 952 } 953