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