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 r = sd_bus_get_property(bus,a.bus, a.path, a.interface, 464 "value", NULL, &reply, "i"); 465 if (r < 0) 466 { 467 sd_journal_print(LOG_ERR, "Failed to call sd_bus_get_property:" 468 " %d, %s\n", r, strerror(-r)); 469 sd_journal_print(LOG_ERR, "Bus: %s, Path: %s, Interface: %s\n", 470 a.bus, a.path, a.interface); 471 break; 472 } 473 474 r = sd_bus_message_read(reply, "i", &reading); 475 if (r < 0) { 476 sd_journal_print(LOG_ERR, "Failed to read sensor: %s\n", 477 strerror(-r)); 478 break; 479 } 480 481 rc = IPMI_CC_OK; 482 *data_len=sizeof(sensorreadingresp_t); 483 484 resp->value = (uint8_t)reading; 485 resp->operation = 0; 486 resp->indication[0] = 0; 487 resp->indication[1] = 0; 488 break; 489 490 case 0xC8: 491 r = sd_bus_get_property(bus,a.bus, a.path, a.interface, 492 "value", NULL, &reply, "i"); 493 if (r < 0) 494 { 495 sd_journal_print(LOG_ERR, "Failed to call sd_bus_get_property:" 496 " %d, %s\n", r, strerror(-r)); 497 sd_journal_print(LOG_ERR, "Bus: %s, Path: %s, Interface: %s\n", 498 a.bus, a.path, a.interface); 499 break; 500 } 501 502 r = sd_bus_message_read(reply, "i", &reading); 503 if (r < 0) { 504 sd_journal_print(LOG_ERR, "Failed to read sensor: %s\n", 505 strerror(-r)); 506 break; 507 } 508 509 rc = IPMI_CC_OK; 510 *data_len=sizeof(sensorreadingresp_t); 511 512 resp->value = 0; 513 resp->operation = 0; 514 resp->indication[0] = (uint8_t)reading; 515 resp->indication[1] = 0; 516 break; 517 518 //TODO openbmc/openbmc#2154 Move this sensor to right place. 519 case 0xCA: 520 r = sd_bus_get_property(bus,a.bus, a.path, a.interface, "value", 521 NULL, &reply, "s"); 522 if (r < 0) 523 { 524 sd_journal_print(LOG_ERR, "Failed to call sd_bus_get_property:" 525 " %d, %s\n", r, strerror(-r)); 526 sd_journal_print(LOG_ERR, "Bus: %s, Path: %s, Interface: %s\n", 527 a.bus, a.path, a.interface); 528 break; 529 } 530 531 r = sd_bus_message_read(reply, "s", &assertion); 532 if (r < 0) 533 { 534 sd_journal_print(LOG_ERR, "Failed to read sensor: %s\n", 535 strerror(-r)); 536 break; 537 } 538 539 rc = IPMI_CC_OK; 540 *data_len=sizeof(sensorreadingresp_t); 541 542 resp->value = 0; 543 resp->operation = 0; 544 if (strcmp(assertion,"Enabled") == 0) 545 { 546 resp->indication[0] = 0x02; 547 } 548 else 549 { 550 resp->indication[0] = 0x1; 551 } 552 resp->indication[1] = 0; 553 break; 554 555 default: 556 { 557 return IPMI_CC_SENSOR_INVALID; 558 } 559 } 560 561 reply = sd_bus_message_unref(reply); 562 563 return rc; 564 } 565 566 ipmi_ret_t ipmi_sen_get_sensor_reading(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 567 ipmi_request_t request, ipmi_response_t response, 568 ipmi_data_len_t data_len, ipmi_context_t context) 569 { 570 sensor_data_t *reqptr = (sensor_data_t*)request; 571 sensorreadingresp_t *resp = (sensorreadingresp_t*) response; 572 ipmi::sensor::GetSensorResponse getResponse {}; 573 static constexpr auto scanningEnabledBit = 6; 574 575 const auto iter = sensors.find(reqptr->sennum); 576 if (iter == sensors.end()) 577 { 578 return legacyGetSensorReading(reqptr->sennum, response, data_len); 579 } 580 if (ipmi::sensor::Mutability::Read != 581 (iter->second.mutability & ipmi::sensor::Mutability::Read)) 582 { 583 return IPMI_CC_ILLEGAL_COMMAND; 584 } 585 586 try 587 { 588 getResponse = iter->second.getFunc(iter->second); 589 *data_len = getResponse.size(); 590 memcpy(resp, getResponse.data(), *data_len); 591 resp->operation = 1 << scanningEnabledBit; 592 return IPMI_CC_OK; 593 } 594 catch (const std::exception& e) 595 { 596 *data_len = getResponse.size(); 597 memcpy(resp, getResponse.data(), *data_len); 598 return IPMI_CC_OK; 599 } 600 } 601 602 void getSensorThresholds(uint8_t sensorNum, 603 get_sdr::GetSensorThresholdsResponse* response) 604 { 605 constexpr auto warningThreshIntf = 606 "xyz.openbmc_project.Sensor.Threshold.Warning"; 607 constexpr auto criticalThreshIntf = 608 "xyz.openbmc_project.Sensor.Threshold.Critical"; 609 610 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 611 612 const auto iter = sensors.find(sensorNum); 613 const auto info = iter->second; 614 615 auto service = ipmi::getService(bus, info.sensorInterface, info.sensorPath); 616 617 auto warnThresholds = ipmi::getAllDbusProperties(bus, 618 service, 619 info.sensorPath, 620 warningThreshIntf); 621 622 double warnLow = warnThresholds["WarningLow"].get<int64_t>(); 623 double warnHigh = warnThresholds["WarningHigh"].get<int64_t>(); 624 625 if (warnLow != 0) 626 { 627 warnLow *= pow(10, info.scale - info.exponentR); 628 response->lowerNonCritical = static_cast<uint8_t>(( 629 warnLow - info.scaledOffset) / info.coefficientM); 630 response->validMask |= static_cast<uint8_t>( 631 ipmi::sensor::ThresholdMask::NON_CRITICAL_LOW_MASK); 632 } 633 634 if (warnHigh != 0) 635 { 636 warnHigh *= pow(10, info.scale - info.exponentR); 637 response->upperNonCritical = static_cast<uint8_t>(( 638 warnHigh - info.scaledOffset) / info.coefficientM); 639 response->validMask |= static_cast<uint8_t>( 640 ipmi::sensor::ThresholdMask::NON_CRITICAL_HIGH_MASK); 641 } 642 643 auto critThresholds = ipmi::getAllDbusProperties(bus, 644 service, 645 info.sensorPath, 646 criticalThreshIntf); 647 double critLow = critThresholds["CriticalLow"].get<int64_t>(); 648 double critHigh = critThresholds["CriticalHigh"].get<int64_t>(); 649 650 if (critLow != 0) 651 { 652 critLow *= pow(10, info.scale - info.exponentR); 653 response->lowerCritical = static_cast<uint8_t>(( 654 critLow - info.scaledOffset) / info.coefficientM); 655 response->validMask |= static_cast<uint8_t>( 656 ipmi::sensor::ThresholdMask::CRITICAL_LOW_MASK); 657 } 658 659 if (critHigh != 0) 660 { 661 critHigh *= pow(10, info.scale - info.exponentR); 662 response->upperCritical = static_cast<uint8_t>(( 663 critHigh - info.scaledOffset)/ info.coefficientM); 664 response->validMask |= static_cast<uint8_t>( 665 ipmi::sensor::ThresholdMask::CRITICAL_HIGH_MASK); 666 } 667 } 668 669 ipmi_ret_t ipmi_sen_get_sensor_thresholds(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 670 ipmi_request_t request, ipmi_response_t response, 671 ipmi_data_len_t data_len, ipmi_context_t context) 672 { 673 constexpr auto valueInterface = "xyz.openbmc_project.Sensor.Value"; 674 675 if (*data_len != sizeof(uint8_t)) 676 { 677 *data_len = 0; 678 return IPMI_CC_REQ_DATA_LEN_INVALID; 679 } 680 681 auto sensorNum = *(reinterpret_cast<const uint8_t *>(request)); 682 *data_len = 0; 683 684 const auto iter = sensors.find(sensorNum); 685 if (iter == sensors.end()) 686 { 687 return IPMI_CC_SENSOR_INVALID; 688 } 689 690 const auto info = iter->second; 691 692 //Proceed only if the sensor value interface is implemented. 693 if (info.propertyInterfaces.find(valueInterface) == 694 info.propertyInterfaces.end()) 695 { 696 //return with valid mask as 0 697 return IPMI_CC_OK; 698 } 699 700 auto responseData = 701 reinterpret_cast<get_sdr::GetSensorThresholdsResponse*>(response); 702 703 try 704 { 705 getSensorThresholds(sensorNum, responseData); 706 } 707 catch (std::exception& e) 708 { 709 //Mask if the property is not present 710 responseData->validMask = 0; 711 } 712 713 *data_len = sizeof(get_sdr::GetSensorThresholdsResponse); 714 return IPMI_CC_OK; 715 } 716 717 ipmi_ret_t ipmi_sen_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 718 ipmi_request_t request, ipmi_response_t response, 719 ipmi_data_len_t data_len, ipmi_context_t context) 720 { 721 ipmi_ret_t rc = IPMI_CC_INVALID; 722 723 printf("IPMI S/E Wildcard Netfn:[0x%X], Cmd:[0x%X]\n",netfn,cmd); 724 *data_len = 0; 725 726 return rc; 727 } 728 729 ipmi_ret_t ipmi_sen_get_sdr_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 730 ipmi_request_t request, 731 ipmi_response_t response, 732 ipmi_data_len_t data_len, 733 ipmi_context_t context) 734 { 735 auto resp = static_cast<get_sdr_info::GetSdrInfoResp*>(response); 736 if (request == nullptr || 737 get_sdr_info::request::get_count(request) == false) 738 { 739 // Get Sensor Count 740 resp->count = sensors.size() + frus.size(); 741 } 742 else 743 { 744 resp->count = 1; 745 } 746 747 // Multiple LUNs not supported. 748 namespace response = get_sdr_info::response; 749 response::set_lun_present(0, &(resp->luns_and_dynamic_population)); 750 response::set_lun_not_present(1, &(resp->luns_and_dynamic_population)); 751 response::set_lun_not_present(2, &(resp->luns_and_dynamic_population)); 752 response::set_lun_not_present(3, &(resp->luns_and_dynamic_population)); 753 response::set_static_population(&(resp->luns_and_dynamic_population)); 754 755 *data_len = SDR_INFO_RESP_SIZE; 756 757 return IPMI_CC_OK; 758 } 759 760 ipmi_ret_t ipmi_sen_reserve_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 761 ipmi_request_t request, 762 ipmi_response_t response, 763 ipmi_data_len_t data_len, 764 ipmi_context_t context) 765 { 766 // A constant reservation ID is okay until we implement add/remove SDR. 767 const uint16_t reservation_id = 1; 768 *(uint16_t*)response = reservation_id; 769 *data_len = sizeof(uint16_t); 770 771 printf("Created new IPMI SDR reservation ID %d\n", *(uint16_t*)response); 772 return IPMI_CC_OK; 773 } 774 775 void setUnitFieldsForObject(const ipmi::sensor::Info *info, 776 get_sdr::SensorDataFullRecordBody *body) 777 { 778 namespace server = sdbusplus::xyz::openbmc_project::Sensor::server; 779 try 780 { 781 auto unit = server::Value::convertUnitFromString(info->unit); 782 // Unit strings defined in 783 // phosphor-dbus-interfaces/xyz/openbmc_project/Sensor/Value.interface.yaml 784 switch (unit) 785 { 786 case server::Value::Unit::DegreesC: 787 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_DEGREES_C; 788 break; 789 case server::Value::Unit::RPMS: 790 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_REVOLUTIONS; // revolutions 791 get_sdr::body::set_rate_unit(0b100, body); // per minute 792 break; 793 case server::Value::Unit::Volts: 794 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_VOLTS; 795 break; 796 case server::Value::Unit::Meters: 797 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_METERS; 798 break; 799 case server::Value::Unit::Amperes: 800 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_AMPERES; 801 break; 802 case server::Value::Unit::Joules: 803 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_JOULES; 804 break; 805 case server::Value::Unit::Watts: 806 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_WATTS; 807 break; 808 default: 809 // Cannot be hit. 810 fprintf(stderr, "Unknown value unit type: = %s\n", 811 info->unit.c_str()); 812 } 813 } 814 catch (sdbusplus::exception::InvalidEnumString e) 815 { 816 log<level::WARNING>("Warning: no unit provided for sensor!"); 817 } 818 } 819 820 ipmi_ret_t populate_record_from_dbus(get_sdr::SensorDataFullRecordBody *body, 821 const ipmi::sensor::Info *info, 822 ipmi_data_len_t data_len) 823 { 824 /* Functional sensor case */ 825 if (isAnalogSensor(info->propertyInterfaces.begin()->first)) 826 { 827 828 body->sensor_units_1 = 0; // unsigned, no rate, no modifier, not a % 829 830 /* Unit info */ 831 setUnitFieldsForObject(info, body); 832 833 get_sdr::body::set_b(info->coefficientB, body); 834 get_sdr::body::set_m(info->coefficientM, body); 835 get_sdr::body::set_b_exp(info->exponentB, body); 836 get_sdr::body::set_r_exp(info->exponentR, body); 837 838 get_sdr::body::set_id_type(0b00, body); // 00 = unicode 839 } 840 841 /* ID string */ 842 auto id_string = info->sensorNameFunc(*info); 843 844 if (id_string.length() > FULL_RECORD_ID_STR_MAX_LENGTH) 845 { 846 get_sdr::body::set_id_strlen(FULL_RECORD_ID_STR_MAX_LENGTH, body); 847 } 848 else 849 { 850 get_sdr::body::set_id_strlen(id_string.length(), body); 851 } 852 strncpy(body->id_string, id_string.c_str(), 853 get_sdr::body::get_id_strlen(body)); 854 855 return IPMI_CC_OK; 856 }; 857 858 ipmi_ret_t ipmi_fru_get_sdr(ipmi_request_t request, ipmi_response_t response, 859 ipmi_data_len_t data_len) 860 { 861 auto req = reinterpret_cast<get_sdr::GetSdrReq*>(request); 862 auto resp = reinterpret_cast<get_sdr::GetSdrResp*>(response); 863 get_sdr::SensorDataFruRecord record {}; 864 auto dataLength = 0; 865 866 auto fru = frus.begin(); 867 uint8_t fruID {}; 868 auto recordID = get_sdr::request::get_record_id(req); 869 870 fruID = recordID - FRU_RECORD_ID_START; 871 fru = frus.find(fruID); 872 if (fru == frus.end()) 873 { 874 return IPMI_CC_SENSOR_INVALID; 875 } 876 877 /* Header */ 878 get_sdr::header::set_record_id(recordID, &(record.header)); 879 record.header.sdr_version = SDR_VERSION; // Based on IPMI Spec v2.0 rev 1.1 880 record.header.record_type = get_sdr::SENSOR_DATA_FRU_RECORD; 881 record.header.record_length = sizeof(record.key) + sizeof(record.body); 882 883 /* Key */ 884 record.key.fruID = fruID; 885 record.key.accessLun |= IPMI_LOGICAL_FRU; 886 record.key.deviceAddress = BMCSlaveAddress; 887 888 /* Body */ 889 record.body.entityID = fru->second[0].entityID; 890 record.body.entityInstance = fru->second[0].entityInstance; 891 record.body.deviceType = fruInventoryDevice; 892 record.body.deviceTypeModifier = IPMIFruInventory; 893 894 /* Device ID string */ 895 auto deviceID = fru->second[0].path.substr( 896 fru->second[0].path.find_last_of('/') + 1, 897 fru->second[0].path.length()); 898 899 900 if (deviceID.length() > get_sdr::FRU_RECORD_DEVICE_ID_MAX_LENGTH) 901 { 902 get_sdr::body::set_device_id_strlen( 903 get_sdr::FRU_RECORD_DEVICE_ID_MAX_LENGTH, 904 &(record.body)); 905 } 906 else 907 { 908 get_sdr::body::set_device_id_strlen(deviceID.length(), 909 &(record.body)); 910 } 911 912 strncpy(record.body.deviceID, deviceID.c_str(), 913 get_sdr::body::get_device_id_strlen(&(record.body))); 914 915 if (++fru == frus.end()) 916 { 917 get_sdr::response::set_next_record_id(END_OF_RECORD, resp); // last record 918 } 919 else 920 { 921 get_sdr::response::set_next_record_id( 922 (FRU_RECORD_ID_START + fru->first), resp); 923 } 924 925 if (req->bytes_to_read > (sizeof(*resp) - req->offset)) 926 { 927 dataLength = (sizeof(*resp) - req->offset); 928 } 929 else 930 { 931 dataLength = req->bytes_to_read; 932 } 933 934 if (dataLength <= 0) 935 { 936 return IPMI_CC_REQ_DATA_LEN_INVALID; 937 } 938 939 memcpy(resp->record_data, 940 reinterpret_cast<uint8_t*>(&record) + req->offset, 941 (dataLength)); 942 943 *data_len = dataLength; 944 *data_len += 2; // additional 2 bytes for next record ID 945 946 return IPMI_CC_OK; 947 } 948 949 ipmi_ret_t ipmi_sen_get_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 950 ipmi_request_t request, ipmi_response_t response, 951 ipmi_data_len_t data_len, ipmi_context_t context) 952 { 953 ipmi_ret_t ret = IPMI_CC_OK; 954 get_sdr::GetSdrReq *req = (get_sdr::GetSdrReq*)request; 955 get_sdr::GetSdrResp *resp = (get_sdr::GetSdrResp*)response; 956 get_sdr::SensorDataFullRecord record = {0}; 957 if (req != NULL) 958 { 959 // Note: we use an iterator so we can provide the next ID at the end of 960 // the call. 961 auto sensor = sensors.begin(); 962 auto recordID = get_sdr::request::get_record_id(req); 963 964 // At the beginning of a scan, the host side will send us id=0. 965 if (recordID != 0) 966 { 967 // recordID greater then 255,it means it is a FRU record. 968 // Currently we are supporting two record types either FULL record 969 // or FRU record. 970 if (recordID >= FRU_RECORD_ID_START) 971 { 972 return ipmi_fru_get_sdr(request, response, data_len); 973 } 974 else 975 { 976 sensor = sensors.find(recordID); 977 if (sensor == sensors.end()) 978 { 979 return IPMI_CC_SENSOR_INVALID; 980 } 981 } 982 } 983 984 uint8_t sensor_id = sensor->first; 985 986 /* Header */ 987 get_sdr::header::set_record_id(sensor_id, &(record.header)); 988 record.header.sdr_version = 0x51; // Based on IPMI Spec v2.0 rev 1.1 989 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD; 990 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord); 991 992 /* Key */ 993 get_sdr::key::set_owner_id_bmc(&(record.key)); 994 record.key.sensor_number = sensor_id; 995 996 /* Body */ 997 record.body.entity_id = sensor->second.entityType; 998 record.body.sensor_type = sensor->second.sensorType; 999 record.body.event_reading_type = sensor->second.sensorReadingType; 1000 record.body.entity_instance = sensor->second.instance; 1001 1002 // Set the type-specific details given the DBus interface 1003 ret = populate_record_from_dbus(&(record.body), &(sensor->second), 1004 data_len); 1005 1006 if (++sensor == sensors.end()) 1007 { 1008 // we have reached till end of sensor, so assign the next record id 1009 // to 256(Max Sensor ID = 255) + FRU ID(may start with 0). 1010 auto next_record_id = (frus.size()) ? 1011 frus.begin()->first + FRU_RECORD_ID_START : 1012 END_OF_RECORD; 1013 1014 get_sdr::response::set_next_record_id(next_record_id, resp); 1015 } 1016 else 1017 { 1018 get_sdr::response::set_next_record_id(sensor->first, resp); 1019 } 1020 1021 *data_len = sizeof(get_sdr::GetSdrResp) - req->offset; 1022 memcpy(resp->record_data, (char*)&record + req->offset, 1023 sizeof(get_sdr::SensorDataFullRecord) - req->offset); 1024 } 1025 1026 return ret; 1027 } 1028 1029 1030 void register_netfn_sen_functions() 1031 { 1032 // <Wildcard Command> 1033 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_WILDCARD, 1034 nullptr, ipmi_sen_wildcard, 1035 PRIVILEGE_USER); 1036 1037 // <Get Sensor Type> 1038 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_TYPE, 1039 nullptr, ipmi_sen_get_sensor_type, 1040 PRIVILEGE_USER); 1041 1042 // <Set Sensor Reading and Event Status> 1043 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_SET_SENSOR, 1044 nullptr, ipmi_sen_set_sensor, 1045 PRIVILEGE_OPERATOR); 1046 1047 // <Get Sensor Reading> 1048 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_READING, 1049 nullptr, ipmi_sen_get_sensor_reading, 1050 PRIVILEGE_USER); 1051 1052 // <Reserve Device SDR Repository> 1053 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_RESERVE_DEVICE_SDR_REPO, 1054 nullptr, ipmi_sen_reserve_sdr, 1055 PRIVILEGE_USER); 1056 1057 // <Get Device SDR Info> 1058 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_DEVICE_SDR_INFO, 1059 nullptr, ipmi_sen_get_sdr_info, 1060 PRIVILEGE_USER); 1061 1062 // <Get Device SDR> 1063 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_DEVICE_SDR, 1064 nullptr, ipmi_sen_get_sdr, 1065 PRIVILEGE_USER); 1066 1067 // <Get Sensor Thresholds> 1068 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_THRESHOLDS, 1069 nullptr, ipmi_sen_get_sensor_thresholds, 1070 PRIVILEGE_USER); 1071 1072 return; 1073 } 1074