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