1 #pragma once 2 3 #include <stdint.h> 4 5 #include <ipmid/api.hpp> 6 #include <ipmid/types.hpp> 7 8 // IPMI commands for net functions. 9 enum ipmi_netfn_sen_cmds 10 { 11 IPMI_CMD_PLATFORM_EVENT = 0x2, 12 IPMI_CMD_GET_DEVICE_SDR_INFO = 0x20, 13 IPMI_CMD_GET_DEVICE_SDR = 0x21, 14 IPMI_CMD_RESERVE_DEVICE_SDR_REPO = 0x22, 15 IPMI_CMD_GET_SENSOR_READING = 0x2D, 16 IPMI_CMD_GET_SENSOR_TYPE = 0x2F, 17 IPMI_CMD_SET_SENSOR = 0x30, 18 IPMI_CMD_GET_SENSOR_THRESHOLDS = 0x27, 19 }; 20 21 /** 22 * @enum device_type 23 * IPMI FRU device types 24 */ 25 enum device_type 26 { 27 IPMI_PHYSICAL_FRU = 0x00, 28 IPMI_LOGICAL_FRU = 0x80, 29 }; 30 31 // Discrete sensor types. 32 enum ipmi_sensor_types 33 { 34 IPMI_SENSOR_TEMP = 0x01, 35 IPMI_SENSOR_VOLTAGE = 0x02, 36 IPMI_SENSOR_CURRENT = 0x03, 37 IPMI_SENSOR_FAN = 0x04, 38 IPMI_SENSOR_TPM = 0xCC, 39 }; 40 41 #define MAX_DBUS_PATH 128 42 struct dbus_interface_t 43 { 44 uint8_t sensornumber; 45 uint8_t sensortype; 46 47 char bus[MAX_DBUS_PATH]; 48 char path[MAX_DBUS_PATH]; 49 char interface[MAX_DBUS_PATH]; 50 }; 51 52 struct PlatformEventRequest 53 { 54 uint8_t eventMessageRevision; 55 uint8_t sensorType; 56 uint8_t sensorNumber; 57 uint8_t eventDirectionType; 58 uint8_t data[3]; 59 }; 60 61 static constexpr char const* ipmiSELPath = "/xyz/openbmc_project/Logging/IPMI"; 62 static constexpr char const* ipmiSELAddInterface = 63 "xyz.openbmc_project.Logging.IPMI"; 64 static const std::string ipmiSELAddMessage = "SEL Entry"; 65 66 static constexpr int selSystemEventSizeWith3Bytes = 8; 67 static constexpr int selSystemEventSizeWith2Bytes = 7; 68 static constexpr int selSystemEventSizeWith1Bytes = 6; 69 static constexpr int selIPMBEventSize = 7; 70 static constexpr uint8_t directionMask = 0x80; 71 static constexpr uint8_t byte3EnableMask = 0x30; 72 static constexpr uint8_t byte2EnableMask = 0xC0; 73 74 int set_sensor_dbus_state_s(uint8_t, const char*, const char*); 75 int set_sensor_dbus_state_y(uint8_t, const char*, const uint8_t); 76 int find_openbmc_path(uint8_t, dbus_interface_t*); 77 78 ipmi_ret_t ipmi_sen_get_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 79 ipmi_request_t request, ipmi_response_t response, 80 ipmi_data_len_t data_len, ipmi_context_t context); 81 82 ipmi_ret_t ipmi_sen_reserve_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 83 ipmi_request_t request, 84 ipmi_response_t response, 85 ipmi_data_len_t data_len, 86 ipmi_context_t context); 87 88 static const uint16_t FRU_RECORD_ID_START = 256; 89 static const uint16_t ENTITY_RECORD_ID_START = 512; 90 static const uint8_t SDR_VERSION = 0x51; 91 static const uint16_t END_OF_RECORD = 0xFFFF; 92 static const uint8_t LENGTH_MASK = 0x1F; 93 94 /** 95 * Get SDR Info 96 */ 97 98 namespace get_sdr_info 99 { 100 namespace request 101 { 102 // Note: for some reason the ipmi_request_t appears to be the 103 // raw value for this call. 104 inline bool get_count(void* req) 105 { 106 return (bool)((uint64_t)(req)&1); 107 } 108 } // namespace request 109 110 namespace response 111 { 112 #define SDR_INFO_RESP_SIZE 2 113 inline void set_lun_present(int lun, uint8_t* resp) 114 { 115 *resp |= 1 << lun; 116 } 117 inline void set_lun_not_present(int lun, uint8_t* resp) 118 { 119 *resp &= ~(1 << lun); 120 } 121 inline void set_dynamic_population(uint8_t* resp) 122 { 123 *resp |= 1 << 7; 124 } 125 inline void set_static_population(uint8_t* resp) 126 { 127 *resp &= ~(1 << 7); 128 } 129 } // namespace response 130 131 struct GetSdrInfoResp 132 { 133 uint8_t count; 134 uint8_t luns_and_dynamic_population; 135 }; 136 137 } // namespace get_sdr_info 138 139 /** 140 * Get SDR 141 */ 142 namespace get_sdr 143 { 144 145 struct GetSdrReq 146 { 147 uint8_t reservation_id_lsb; 148 uint8_t reservation_id_msb; 149 uint8_t record_id_lsb; 150 uint8_t record_id_msb; 151 uint8_t offset; 152 uint8_t bytes_to_read; 153 } __attribute__((packed)); 154 155 namespace request 156 { 157 158 inline uint8_t get_reservation_id(GetSdrReq* req) 159 { 160 return (req->reservation_id_lsb + (req->reservation_id_msb << 8)); 161 }; 162 163 inline uint16_t get_record_id(GetSdrReq* req) 164 { 165 return (req->record_id_lsb + (req->record_id_msb << 8)); 166 }; 167 168 } // namespace request 169 170 // Response 171 struct GetSdrResp 172 { 173 uint8_t next_record_id_lsb; 174 uint8_t next_record_id_msb; 175 uint8_t record_data[64]; 176 } __attribute__((packed)); 177 178 namespace response 179 { 180 181 inline void set_next_record_id(uint16_t next, GetSdrResp* resp) 182 { 183 resp->next_record_id_lsb = next & 0xff; 184 resp->next_record_id_msb = (next >> 8) & 0xff; 185 }; 186 187 } // namespace response 188 189 // Record header 190 struct SensorDataRecordHeader 191 { 192 uint8_t record_id_lsb; 193 uint8_t record_id_msb; 194 uint8_t sdr_version; 195 uint8_t record_type; 196 uint8_t record_length; // Length not counting the header 197 } __attribute__((packed)); 198 199 namespace header 200 { 201 202 inline void set_record_id(int id, SensorDataRecordHeader* hdr) 203 { 204 hdr->record_id_lsb = (id & 0xFF); 205 hdr->record_id_msb = (id >> 8) & 0xFF; 206 }; 207 208 } // namespace header 209 210 enum SensorDataRecordType 211 { 212 SENSOR_DATA_FULL_RECORD = 0x1, 213 SENSOR_DATA_FRU_RECORD = 0x11, 214 SENSOR_DATA_ENTITY_RECORD = 0x8, 215 }; 216 217 // Record key 218 struct SensorDataRecordKey 219 { 220 uint8_t owner_id; 221 uint8_t owner_lun; 222 uint8_t sensor_number; 223 } __attribute__((packed)); 224 225 /** @struct SensorDataFruRecordKey 226 * 227 * FRU Device Locator Record(key) - SDR Type 11 228 */ 229 struct SensorDataFruRecordKey 230 { 231 uint8_t deviceAddress; 232 uint8_t fruID; 233 uint8_t accessLun; 234 uint8_t channelNumber; 235 } __attribute__((packed)); 236 237 /** @struct SensorDataEntityRecordKey 238 * 239 * Entity Association Record(key) - SDR Type 8 240 */ 241 struct SensorDataEntityRecordKey 242 { 243 uint8_t containerEntityId; 244 uint8_t containerEntityInstance; 245 uint8_t flags; 246 uint8_t entityId1; 247 uint8_t entityInstance1; 248 } __attribute__((packed)); 249 250 namespace key 251 { 252 253 static constexpr uint8_t listOrRangeBit = 7; 254 static constexpr uint8_t linkedBit = 6; 255 256 inline void set_owner_id_ipmb(SensorDataRecordKey* key) 257 { 258 key->owner_id &= ~0x01; 259 }; 260 261 inline void set_owner_id_system_sw(SensorDataRecordKey* key) 262 { 263 key->owner_id |= 0x01; 264 }; 265 266 inline void set_owner_id_bmc(SensorDataRecordKey* key) 267 { 268 key->owner_id |= 0x20; 269 }; 270 271 inline void set_owner_id_address(uint8_t addr, SensorDataRecordKey* key) 272 { 273 key->owner_id &= 0x01; 274 key->owner_id |= addr << 1; 275 }; 276 277 inline void set_owner_lun(uint8_t lun, SensorDataRecordKey* key) 278 { 279 key->owner_lun &= ~0x03; 280 key->owner_lun |= (lun & 0x03); 281 }; 282 283 inline void set_owner_lun_channel(uint8_t channel, SensorDataRecordKey* key) 284 { 285 key->owner_lun &= 0x0f; 286 key->owner_lun |= ((channel & 0xf) << 4); 287 }; 288 289 inline void set_flags(bool isList, bool isLinked, 290 SensorDataEntityRecordKey* key) 291 { 292 key->flags = 0x00; 293 if (!isList) 294 key->flags |= 1 << listOrRangeBit; 295 296 if (isLinked) 297 key->flags |= 1 << linkedBit; 298 }; 299 300 } // namespace key 301 302 /** @struct GetSensorThresholdsResponse 303 * 304 * Response structure for Get Sensor Thresholds command 305 */ 306 struct GetSensorThresholdsResponse 307 { 308 uint8_t validMask; //!< valid mask 309 uint8_t lowerNonCritical; //!< lower non-critical threshold 310 uint8_t lowerCritical; //!< lower critical threshold 311 uint8_t lowerNonRecoverable; //!< lower non-recoverable threshold 312 uint8_t upperNonCritical; //!< upper non-critical threshold 313 uint8_t upperCritical; //!< upper critical threshold 314 uint8_t upperNonRecoverable; //!< upper non-recoverable threshold 315 } __attribute__((packed)); 316 317 // Body - full record 318 #define FULL_RECORD_ID_STR_MAX_LENGTH 16 319 320 static const int FRU_RECORD_DEVICE_ID_MAX_LENGTH = 16; 321 322 struct SensorDataFullRecordBody 323 { 324 uint8_t entity_id; 325 uint8_t entity_instance; 326 uint8_t sensor_initialization; 327 uint8_t sensor_capabilities; // no macro support 328 uint8_t sensor_type; 329 uint8_t event_reading_type; 330 uint8_t supported_assertions[2]; // no macro support 331 uint8_t supported_deassertions[2]; // no macro support 332 uint8_t discrete_reading_setting_mask[2]; // no macro support 333 uint8_t sensor_units_1; 334 uint8_t sensor_units_2_base; 335 uint8_t sensor_units_3_modifier; 336 uint8_t linearization; 337 uint8_t m_lsb; 338 uint8_t m_msb_and_tolerance; 339 uint8_t b_lsb; 340 uint8_t b_msb_and_accuracy_lsb; 341 uint8_t accuracy_and_sensor_direction; 342 uint8_t r_b_exponents; 343 uint8_t analog_characteristic_flags; // no macro support 344 uint8_t nominal_reading; 345 uint8_t normal_max; 346 uint8_t normal_min; 347 uint8_t sensor_max; 348 uint8_t sensor_min; 349 uint8_t upper_nonrecoverable_threshold; 350 uint8_t upper_critical_threshold; 351 uint8_t upper_noncritical_threshold; 352 uint8_t lower_nonrecoverable_threshold; 353 uint8_t lower_critical_threshold; 354 uint8_t lower_noncritical_threshold; 355 uint8_t positive_threshold_hysteresis; 356 uint8_t negative_threshold_hysteresis; 357 uint16_t reserved; 358 uint8_t oem_reserved; 359 uint8_t id_string_info; 360 char id_string[FULL_RECORD_ID_STR_MAX_LENGTH]; 361 } __attribute__((packed)); 362 363 /** @struct SensorDataFruRecordBody 364 * 365 * FRU Device Locator Record(body) - SDR Type 11 366 */ 367 struct SensorDataFruRecordBody 368 { 369 uint8_t reserved; 370 uint8_t deviceType; 371 uint8_t deviceTypeModifier; 372 uint8_t entityID; 373 uint8_t entityInstance; 374 uint8_t oem; 375 uint8_t deviceIDLen; 376 char deviceID[FRU_RECORD_DEVICE_ID_MAX_LENGTH]; 377 } __attribute__((packed)); 378 379 /** @struct SensorDataEntityRecordBody 380 * 381 * Entity Association Record(body) - SDR Type 8 382 */ 383 struct SensorDataEntityRecordBody 384 { 385 uint8_t entityId2; 386 uint8_t entityInstance2; 387 uint8_t entityId3; 388 uint8_t entityInstance3; 389 uint8_t entityId4; 390 uint8_t entityInstance4; 391 } __attribute__((packed)); 392 393 namespace body 394 { 395 396 inline void set_entity_instance_number(uint8_t n, 397 SensorDataFullRecordBody* body) 398 { 399 body->entity_instance &= 1 << 7; 400 body->entity_instance |= (n & ~(1 << 7)); 401 }; 402 inline void set_entity_physical_entity(SensorDataFullRecordBody* body) 403 { 404 body->entity_instance &= ~(1 << 7); 405 }; 406 inline void set_entity_logical_container(SensorDataFullRecordBody* body) 407 { 408 body->entity_instance |= 1 << 7; 409 }; 410 411 inline void sensor_scanning_state(bool enabled, SensorDataFullRecordBody* body) 412 { 413 if (enabled) 414 { 415 body->sensor_initialization |= 1 << 0; 416 } 417 else 418 { 419 body->sensor_initialization &= ~(1 << 0); 420 }; 421 }; 422 inline void event_generation_state(bool enabled, SensorDataFullRecordBody* body) 423 { 424 if (enabled) 425 { 426 body->sensor_initialization |= 1 << 1; 427 } 428 else 429 { 430 body->sensor_initialization &= ~(1 << 1); 431 } 432 }; 433 inline void init_types_state(bool enabled, SensorDataFullRecordBody* body) 434 { 435 if (enabled) 436 { 437 body->sensor_initialization |= 1 << 2; 438 } 439 else 440 { 441 body->sensor_initialization &= ~(1 << 2); 442 } 443 }; 444 inline void init_hyst_state(bool enabled, SensorDataFullRecordBody* body) 445 { 446 if (enabled) 447 { 448 body->sensor_initialization |= 1 << 3; 449 } 450 else 451 { 452 body->sensor_initialization &= ~(1 << 3); 453 } 454 }; 455 inline void init_thresh_state(bool enabled, SensorDataFullRecordBody* body) 456 { 457 if (enabled) 458 { 459 body->sensor_initialization |= 1 << 4; 460 } 461 else 462 { 463 body->sensor_initialization &= ~(1 << 4); 464 } 465 }; 466 inline void init_events_state(bool enabled, SensorDataFullRecordBody* body) 467 { 468 if (enabled) 469 { 470 body->sensor_initialization |= 1 << 5; 471 } 472 else 473 { 474 body->sensor_initialization &= ~(1 << 5); 475 } 476 }; 477 inline void init_scanning_state(bool enabled, SensorDataFullRecordBody* body) 478 { 479 if (enabled) 480 { 481 body->sensor_initialization |= 1 << 6; 482 } 483 else 484 { 485 body->sensor_initialization &= ~(1 << 6); 486 } 487 }; 488 inline void init_settable_state(bool enabled, SensorDataFullRecordBody* body) 489 { 490 if (enabled) 491 { 492 body->sensor_initialization |= 1 << 7; 493 } 494 else 495 { 496 body->sensor_initialization &= ~(1 << 7); 497 } 498 }; 499 500 inline void set_percentage(SensorDataFullRecordBody* body) 501 { 502 body->sensor_units_1 |= 1 << 0; 503 }; 504 inline void unset_percentage(SensorDataFullRecordBody* body) 505 { 506 body->sensor_units_1 &= ~(1 << 0); 507 }; 508 inline void set_modifier_operation(uint8_t op, SensorDataFullRecordBody* body) 509 { 510 body->sensor_units_1 &= ~(3 << 1); 511 body->sensor_units_1 |= (op & 0x3) << 1; 512 }; 513 inline void set_rate_unit(uint8_t unit, SensorDataFullRecordBody* body) 514 { 515 body->sensor_units_1 &= ~(7 << 3); 516 body->sensor_units_1 |= (unit & 0x7) << 3; 517 }; 518 inline void set_analog_data_format(uint8_t format, 519 SensorDataFullRecordBody* body) 520 { 521 body->sensor_units_1 &= ~(3 << 6); 522 body->sensor_units_1 |= (format & 0x3) << 6; 523 }; 524 525 inline void set_m(uint16_t m, SensorDataFullRecordBody* body) 526 { 527 body->m_lsb = m & 0xff; 528 body->m_msb_and_tolerance &= ~(3 << 6); 529 body->m_msb_and_tolerance |= ((m & (3 << 8)) >> 2); 530 }; 531 inline void set_tolerance(uint8_t tol, SensorDataFullRecordBody* body) 532 { 533 body->m_msb_and_tolerance &= ~0x3f; 534 body->m_msb_and_tolerance |= tol & 0x3f; 535 }; 536 537 inline void set_b(uint16_t b, SensorDataFullRecordBody* body) 538 { 539 body->b_lsb = b & 0xff; 540 body->b_msb_and_accuracy_lsb &= ~(3 << 6); 541 body->b_msb_and_accuracy_lsb |= ((b & (3 << 8)) >> 2); 542 }; 543 inline void set_accuracy(uint16_t acc, SensorDataFullRecordBody* body) 544 { 545 // bottom 6 bits 546 body->b_msb_and_accuracy_lsb &= ~0x3f; 547 body->b_msb_and_accuracy_lsb |= acc & 0x3f; 548 // top 4 bits 549 body->accuracy_and_sensor_direction &= 0x0f; 550 body->accuracy_and_sensor_direction |= ((acc >> 6) & 0xf) << 4; 551 }; 552 inline void set_accuracy_exp(uint8_t exp, SensorDataFullRecordBody* body) 553 { 554 body->accuracy_and_sensor_direction &= ~(3 << 2); 555 body->accuracy_and_sensor_direction |= (exp & 3) << 2; 556 }; 557 inline void set_sensor_dir(uint8_t dir, SensorDataFullRecordBody* body) 558 { 559 body->accuracy_and_sensor_direction &= ~(3 << 0); 560 body->accuracy_and_sensor_direction |= (dir & 3); 561 }; 562 563 inline void set_b_exp(uint8_t exp, SensorDataFullRecordBody* body) 564 { 565 body->r_b_exponents &= 0xf0; 566 body->r_b_exponents |= exp & 0x0f; 567 }; 568 inline void set_r_exp(uint8_t exp, SensorDataFullRecordBody* body) 569 { 570 body->r_b_exponents &= 0x0f; 571 body->r_b_exponents |= (exp & 0x0f) << 4; 572 }; 573 574 inline void set_id_strlen(uint8_t len, SensorDataFullRecordBody* body) 575 { 576 body->id_string_info &= ~(0x1f); 577 body->id_string_info |= len & 0x1f; 578 }; 579 inline uint8_t get_id_strlen(SensorDataFullRecordBody* body) 580 { 581 return body->id_string_info & 0x1f; 582 }; 583 inline void set_id_type(uint8_t type, SensorDataFullRecordBody* body) 584 { 585 body->id_string_info &= ~(3 << 6); 586 body->id_string_info |= (type & 0x3) << 6; 587 }; 588 589 inline void set_device_id_strlen(uint8_t len, SensorDataFruRecordBody* body) 590 { 591 body->deviceIDLen &= ~(LENGTH_MASK); 592 body->deviceIDLen |= len & LENGTH_MASK; 593 }; 594 595 inline uint8_t get_device_id_strlen(SensorDataFruRecordBody* body) 596 { 597 return body->deviceIDLen & LENGTH_MASK; 598 }; 599 600 inline void set_readable_mask(uint8_t mask, SensorDataFullRecordBody* body) 601 { 602 body->discrete_reading_setting_mask[1] = mask & 0x3F; 603 } 604 605 } // namespace body 606 607 // More types contained in section 43.17 Sensor Unit Type Codes, 608 // IPMI spec v2 rev 1.1 609 enum SensorUnitTypeCodes 610 { 611 SENSOR_UNIT_UNSPECIFIED = 0, 612 SENSOR_UNIT_DEGREES_C = 1, 613 SENSOR_UNIT_VOLTS = 4, 614 SENSOR_UNIT_AMPERES = 5, 615 SENSOR_UNIT_WATTS = 6, 616 SENSOR_UNIT_JOULES = 7, 617 SENSOR_UNIT_RPM = 18, 618 SENSOR_UNIT_METERS = 34, 619 SENSOR_UNIT_REVOLUTIONS = 41, 620 }; 621 622 struct SensorDataFullRecord 623 { 624 SensorDataRecordHeader header; 625 SensorDataRecordKey key; 626 SensorDataFullRecordBody body; 627 } __attribute__((packed)); 628 629 /** @struct SensorDataFruRecord 630 * 631 * FRU Device Locator Record - SDR Type 11 632 */ 633 struct SensorDataFruRecord 634 { 635 SensorDataRecordHeader header; 636 SensorDataFruRecordKey key; 637 SensorDataFruRecordBody body; 638 } __attribute__((packed)); 639 640 /** @struct SensorDataEntityRecord 641 * 642 * Entity Association Record - SDR Type 8 643 */ 644 struct SensorDataEntityRecord 645 { 646 SensorDataRecordHeader header; 647 SensorDataEntityRecordKey key; 648 SensorDataEntityRecordBody body; 649 } __attribute__((packed)); 650 651 } // namespace get_sdr 652 653 namespace ipmi 654 { 655 656 namespace sensor 657 { 658 659 /** 660 * @brief Map offset to the corresponding bit in the assertion byte. 661 * 662 * The discrete sensors support up to 14 states. 0-7 offsets are stored in one 663 * byte and offsets 8-14 in the second byte. 664 * 665 * @param[in] offset - offset number. 666 * @param[in/out] resp - get sensor reading response. 667 */ 668 inline void setOffset(uint8_t offset, ipmi::sensor::GetReadingResponse* resp) 669 { 670 if (offset > 7) 671 { 672 resp->assertOffset8_14 |= 1 << (offset - 8); 673 } 674 else 675 { 676 resp->assertOffset0_7 |= 1 << offset; 677 } 678 } 679 680 /** 681 * @brief Set the reading field in the response. 682 * 683 * @param[in] offset - offset number. 684 * @param[in/out] resp - get sensor reading response. 685 */ 686 inline void setReading(uint8_t value, ipmi::sensor::GetReadingResponse* resp) 687 { 688 resp->reading = value; 689 } 690 691 /** 692 * @brief Map the value to the assertion bytes. The assertion states are stored 693 * in 2 bytes. 694 * 695 * @param[in] value - value to mapped to the assertion byte. 696 * @param[in/out] resp - get sensor reading response. 697 */ 698 inline void setAssertionBytes(uint16_t value, 699 ipmi::sensor::GetReadingResponse* resp) 700 { 701 resp->assertOffset0_7 = static_cast<uint8_t>(value & 0x00FF); 702 resp->assertOffset8_14 = static_cast<uint8_t>(value >> 8); 703 } 704 705 /** 706 * @brief Set the scanning enabled bit in the response. 707 * 708 * @param[in/out] resp - get sensor reading response. 709 */ 710 inline void enableScanning(ipmi::sensor::GetReadingResponse* resp) 711 { 712 resp->operation = 1 << 6; 713 } 714 715 } // namespace sensor 716 717 } // namespace ipmi 718