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