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