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_FRU_RECORD = 0x11, 193 SENSOR_DATA_ENTITY_RECORD = 0x8, 194 }; 195 196 // Record key 197 struct SensorDataRecordKey 198 { 199 uint8_t owner_id; 200 uint8_t owner_lun; 201 uint8_t sensor_number; 202 } __attribute__((packed)); 203 204 /** @struct SensorDataFruRecordKey 205 * 206 * FRU Device Locator Record(key) - SDR Type 11 207 */ 208 struct SensorDataFruRecordKey 209 { 210 uint8_t deviceAddress; 211 uint8_t fruID; 212 uint8_t accessLun; 213 uint8_t channelNumber; 214 } __attribute__((packed)); 215 216 /** @struct SensorDataEntityRecordKey 217 * 218 * Entity Association Record(key) - SDR Type 8 219 */ 220 struct SensorDataEntityRecordKey 221 { 222 uint8_t containerEntityId; 223 uint8_t containerEntityInstance; 224 uint8_t flags; 225 uint8_t entityId1; 226 uint8_t entityInstance1; 227 } __attribute__((packed)); 228 229 namespace key 230 { 231 232 static constexpr uint8_t listOrRangeBit = 7; 233 static constexpr uint8_t linkedBit = 6; 234 235 inline void set_owner_id_ipmb(SensorDataRecordKey* key) 236 { 237 key->owner_id &= ~0x01; 238 }; 239 240 inline void set_owner_id_system_sw(SensorDataRecordKey* key) 241 { 242 key->owner_id |= 0x01; 243 }; 244 245 inline void set_owner_id_bmc(SensorDataRecordKey* key) 246 { 247 key->owner_id |= 0x20; 248 }; 249 250 inline void set_owner_id_address(uint8_t addr, SensorDataRecordKey* key) 251 { 252 key->owner_id &= 0x01; 253 key->owner_id |= addr << 1; 254 }; 255 256 inline void set_owner_lun(uint8_t lun, SensorDataRecordKey* key) 257 { 258 key->owner_lun &= ~0x03; 259 key->owner_lun |= (lun & 0x03); 260 }; 261 262 inline void set_owner_lun_channel(uint8_t channel, SensorDataRecordKey* key) 263 { 264 key->owner_lun &= 0x0f; 265 key->owner_lun |= ((channel & 0xf) << 4); 266 }; 267 268 inline void set_flags(bool isList, bool isLinked, 269 SensorDataEntityRecordKey* key) 270 { 271 key->flags = 0x00; 272 if (!isList) 273 key->flags |= 1 << listOrRangeBit; 274 275 if (isLinked) 276 key->flags |= 1 << linkedBit; 277 }; 278 279 } // namespace key 280 281 /** @struct GetSensorThresholdsResponse 282 * 283 * Response structure for Get Sensor Thresholds command 284 */ 285 struct GetSensorThresholdsResponse 286 { 287 uint8_t validMask; //!< valid mask 288 uint8_t lowerNonCritical; //!< lower non-critical threshold 289 uint8_t lowerCritical; //!< lower critical threshold 290 uint8_t lowerNonRecoverable; //!< lower non-recoverable threshold 291 uint8_t upperNonCritical; //!< upper non-critical threshold 292 uint8_t upperCritical; //!< upper critical threshold 293 uint8_t upperNonRecoverable; //!< upper non-recoverable threshold 294 } __attribute__((packed)); 295 296 // Body - full record 297 #define FULL_RECORD_ID_STR_MAX_LENGTH 16 298 299 static const int FRU_RECORD_DEVICE_ID_MAX_LENGTH = 16; 300 301 struct SensorDataFullRecordBody 302 { 303 uint8_t entity_id; 304 uint8_t entity_instance; 305 uint8_t sensor_initialization; 306 uint8_t sensor_capabilities; // no macro support 307 uint8_t sensor_type; 308 uint8_t event_reading_type; 309 uint8_t supported_assertions[2]; // no macro support 310 uint8_t supported_deassertions[2]; // no macro support 311 uint8_t discrete_reading_setting_mask[2]; // no macro support 312 uint8_t sensor_units_1; 313 uint8_t sensor_units_2_base; 314 uint8_t sensor_units_3_modifier; 315 uint8_t linearization; 316 uint8_t m_lsb; 317 uint8_t m_msb_and_tolerance; 318 uint8_t b_lsb; 319 uint8_t b_msb_and_accuracy_lsb; 320 uint8_t accuracy_and_sensor_direction; 321 uint8_t r_b_exponents; 322 uint8_t analog_characteristic_flags; // no macro support 323 uint8_t nominal_reading; 324 uint8_t normal_max; 325 uint8_t normal_min; 326 uint8_t sensor_max; 327 uint8_t sensor_min; 328 uint8_t upper_nonrecoverable_threshold; 329 uint8_t upper_critical_threshold; 330 uint8_t upper_noncritical_threshold; 331 uint8_t lower_nonrecoverable_threshold; 332 uint8_t lower_critical_threshold; 333 uint8_t lower_noncritical_threshold; 334 uint8_t positive_threshold_hysteresis; 335 uint8_t negative_threshold_hysteresis; 336 uint16_t reserved; 337 uint8_t oem_reserved; 338 uint8_t id_string_info; 339 char id_string[FULL_RECORD_ID_STR_MAX_LENGTH]; 340 } __attribute__((packed)); 341 342 /** @struct SensorDataFruRecordBody 343 * 344 * FRU Device Locator Record(body) - SDR Type 11 345 */ 346 struct SensorDataFruRecordBody 347 { 348 uint8_t reserved; 349 uint8_t deviceType; 350 uint8_t deviceTypeModifier; 351 uint8_t entityID; 352 uint8_t entityInstance; 353 uint8_t oem; 354 uint8_t deviceIDLen; 355 char deviceID[FRU_RECORD_DEVICE_ID_MAX_LENGTH]; 356 } __attribute__((packed)); 357 358 /** @struct SensorDataEntityRecordBody 359 * 360 * Entity Association Record(body) - SDR Type 8 361 */ 362 struct SensorDataEntityRecordBody 363 { 364 uint8_t entityId2; 365 uint8_t entityInstance2; 366 uint8_t entityId3; 367 uint8_t entityInstance3; 368 uint8_t entityId4; 369 uint8_t entityInstance4; 370 } __attribute__((packed)); 371 372 namespace body 373 { 374 375 inline void set_entity_instance_number(uint8_t n, 376 SensorDataFullRecordBody* body) 377 { 378 body->entity_instance &= 1 << 7; 379 body->entity_instance |= (n & ~(1 << 7)); 380 }; 381 inline void set_entity_physical_entity(SensorDataFullRecordBody* body) 382 { 383 body->entity_instance &= ~(1 << 7); 384 }; 385 inline void set_entity_logical_container(SensorDataFullRecordBody* body) 386 { 387 body->entity_instance |= 1 << 7; 388 }; 389 390 inline void sensor_scanning_state(bool enabled, SensorDataFullRecordBody* body) 391 { 392 if (enabled) 393 { 394 body->sensor_initialization |= 1 << 0; 395 } 396 else 397 { 398 body->sensor_initialization &= ~(1 << 0); 399 }; 400 }; 401 inline void event_generation_state(bool enabled, SensorDataFullRecordBody* body) 402 { 403 if (enabled) 404 { 405 body->sensor_initialization |= 1 << 1; 406 } 407 else 408 { 409 body->sensor_initialization &= ~(1 << 1); 410 } 411 }; 412 inline void init_types_state(bool enabled, SensorDataFullRecordBody* body) 413 { 414 if (enabled) 415 { 416 body->sensor_initialization |= 1 << 2; 417 } 418 else 419 { 420 body->sensor_initialization &= ~(1 << 2); 421 } 422 }; 423 inline void init_hyst_state(bool enabled, SensorDataFullRecordBody* body) 424 { 425 if (enabled) 426 { 427 body->sensor_initialization |= 1 << 3; 428 } 429 else 430 { 431 body->sensor_initialization &= ~(1 << 3); 432 } 433 }; 434 inline void init_thresh_state(bool enabled, SensorDataFullRecordBody* body) 435 { 436 if (enabled) 437 { 438 body->sensor_initialization |= 1 << 4; 439 } 440 else 441 { 442 body->sensor_initialization &= ~(1 << 4); 443 } 444 }; 445 inline void init_events_state(bool enabled, SensorDataFullRecordBody* body) 446 { 447 if (enabled) 448 { 449 body->sensor_initialization |= 1 << 5; 450 } 451 else 452 { 453 body->sensor_initialization &= ~(1 << 5); 454 } 455 }; 456 inline void init_scanning_state(bool enabled, SensorDataFullRecordBody* body) 457 { 458 if (enabled) 459 { 460 body->sensor_initialization |= 1 << 6; 461 } 462 else 463 { 464 body->sensor_initialization &= ~(1 << 6); 465 } 466 }; 467 inline void init_settable_state(bool enabled, SensorDataFullRecordBody* body) 468 { 469 if (enabled) 470 { 471 body->sensor_initialization |= 1 << 7; 472 } 473 else 474 { 475 body->sensor_initialization &= ~(1 << 7); 476 } 477 }; 478 479 inline void set_percentage(SensorDataFullRecordBody* body) 480 { 481 body->sensor_units_1 |= 1 << 0; 482 }; 483 inline void unset_percentage(SensorDataFullRecordBody* body) 484 { 485 body->sensor_units_1 &= ~(1 << 0); 486 }; 487 inline void set_modifier_operation(uint8_t op, SensorDataFullRecordBody* body) 488 { 489 body->sensor_units_1 &= ~(3 << 1); 490 body->sensor_units_1 |= (op & 0x3) << 1; 491 }; 492 inline void set_rate_unit(uint8_t unit, SensorDataFullRecordBody* body) 493 { 494 body->sensor_units_1 &= ~(7 << 3); 495 body->sensor_units_1 |= (unit & 0x7) << 3; 496 }; 497 inline void set_analog_data_format(uint8_t format, 498 SensorDataFullRecordBody* body) 499 { 500 body->sensor_units_1 &= ~(3 << 6); 501 body->sensor_units_1 |= (format & 0x3) << 6; 502 }; 503 504 inline void set_m(uint16_t m, SensorDataFullRecordBody* body) 505 { 506 body->m_lsb = m & 0xff; 507 body->m_msb_and_tolerance &= ~(3 << 6); 508 body->m_msb_and_tolerance |= ((m & (3 << 8)) >> 2); 509 }; 510 inline void set_tolerance(uint8_t tol, SensorDataFullRecordBody* body) 511 { 512 body->m_msb_and_tolerance &= ~0x3f; 513 body->m_msb_and_tolerance |= tol & 0x3f; 514 }; 515 516 inline void set_b(uint16_t b, SensorDataFullRecordBody* body) 517 { 518 body->b_lsb = b & 0xff; 519 body->b_msb_and_accuracy_lsb &= ~(3 << 6); 520 body->b_msb_and_accuracy_lsb |= ((b & (3 << 8)) >> 2); 521 }; 522 inline void set_accuracy(uint16_t acc, SensorDataFullRecordBody* body) 523 { 524 // bottom 6 bits 525 body->b_msb_and_accuracy_lsb &= ~0x3f; 526 body->b_msb_and_accuracy_lsb |= acc & 0x3f; 527 // top 4 bits 528 body->accuracy_and_sensor_direction &= 0x0f; 529 body->accuracy_and_sensor_direction |= ((acc >> 6) & 0xf) << 4; 530 }; 531 inline void set_accuracy_exp(uint8_t exp, SensorDataFullRecordBody* body) 532 { 533 body->accuracy_and_sensor_direction &= ~(3 << 2); 534 body->accuracy_and_sensor_direction |= (exp & 3) << 2; 535 }; 536 inline void set_sensor_dir(uint8_t dir, SensorDataFullRecordBody* body) 537 { 538 body->accuracy_and_sensor_direction &= ~(3 << 0); 539 body->accuracy_and_sensor_direction |= (dir & 3); 540 }; 541 542 inline void set_b_exp(uint8_t exp, SensorDataFullRecordBody* body) 543 { 544 body->r_b_exponents &= 0xf0; 545 body->r_b_exponents |= exp & 0x0f; 546 }; 547 inline void set_r_exp(uint8_t exp, SensorDataFullRecordBody* body) 548 { 549 body->r_b_exponents &= 0x0f; 550 body->r_b_exponents |= (exp & 0x0f) << 4; 551 }; 552 553 inline void set_id_strlen(uint8_t len, SensorDataFullRecordBody* body) 554 { 555 body->id_string_info &= ~(0x1f); 556 body->id_string_info |= len & 0x1f; 557 }; 558 inline uint8_t get_id_strlen(SensorDataFullRecordBody* body) 559 { 560 return body->id_string_info & 0x1f; 561 }; 562 inline void set_id_type(uint8_t type, SensorDataFullRecordBody* body) 563 { 564 body->id_string_info &= ~(3 << 6); 565 body->id_string_info |= (type & 0x3) << 6; 566 }; 567 568 inline void set_device_id_strlen(uint8_t len, SensorDataFruRecordBody* body) 569 { 570 body->deviceIDLen &= ~(LENGTH_MASK); 571 body->deviceIDLen |= len & LENGTH_MASK; 572 }; 573 574 inline uint8_t get_device_id_strlen(SensorDataFruRecordBody* body) 575 { 576 return body->deviceIDLen & LENGTH_MASK; 577 }; 578 579 inline void set_readable_mask(uint8_t mask, SensorDataFullRecordBody* body) 580 { 581 body->discrete_reading_setting_mask[1] = mask & 0x3F; 582 } 583 584 } // namespace body 585 586 // More types contained in section 43.17 Sensor Unit Type Codes, 587 // IPMI spec v2 rev 1.1 588 enum SensorUnitTypeCodes 589 { 590 SENSOR_UNIT_UNSPECIFIED = 0, 591 SENSOR_UNIT_DEGREES_C = 1, 592 SENSOR_UNIT_VOLTS = 4, 593 SENSOR_UNIT_AMPERES = 5, 594 SENSOR_UNIT_WATTS = 6, 595 SENSOR_UNIT_JOULES = 7, 596 SENSOR_UNIT_RPM = 18, 597 SENSOR_UNIT_METERS = 34, 598 SENSOR_UNIT_REVOLUTIONS = 41, 599 }; 600 601 struct SensorDataFullRecord 602 { 603 SensorDataRecordHeader header; 604 SensorDataRecordKey key; 605 SensorDataFullRecordBody body; 606 } __attribute__((packed)); 607 608 /** @struct SensorDataFruRecord 609 * 610 * FRU Device Locator Record - SDR Type 11 611 */ 612 struct SensorDataFruRecord 613 { 614 SensorDataRecordHeader header; 615 SensorDataFruRecordKey key; 616 SensorDataFruRecordBody body; 617 } __attribute__((packed)); 618 619 /** @struct SensorDataEntityRecord 620 * 621 * Entity Association Record - SDR Type 8 622 */ 623 struct SensorDataEntityRecord 624 { 625 SensorDataRecordHeader header; 626 SensorDataEntityRecordKey key; 627 SensorDataEntityRecordBody body; 628 } __attribute__((packed)); 629 630 } // namespace get_sdr 631 632 namespace ipmi 633 { 634 635 namespace sensor 636 { 637 638 /** 639 * @brief Map offset to the corresponding bit in the assertion byte. 640 * 641 * The discrete sensors support up to 14 states. 0-7 offsets are stored in one 642 * byte and offsets 8-14 in the second byte. 643 * 644 * @param[in] offset - offset number. 645 * @param[in/out] resp - get sensor reading response. 646 */ 647 inline void setOffset(uint8_t offset, ipmi::sensor::GetReadingResponse* resp) 648 { 649 if (offset > 7) 650 { 651 resp->assertOffset8_14 |= 1 << (offset - 8); 652 } 653 else 654 { 655 resp->assertOffset0_7 |= 1 << offset; 656 } 657 } 658 659 /** 660 * @brief Set the reading field in the response. 661 * 662 * @param[in] offset - offset number. 663 * @param[in/out] resp - get sensor reading response. 664 */ 665 inline void setReading(uint8_t value, ipmi::sensor::GetReadingResponse* resp) 666 { 667 resp->reading = value; 668 } 669 670 /** 671 * @brief Map the value to the assertion bytes. The assertion states are stored 672 * in 2 bytes. 673 * 674 * @param[in] value - value to mapped to the assertion byte. 675 * @param[in/out] resp - get sensor reading response. 676 */ 677 inline void setAssertionBytes(uint16_t value, 678 ipmi::sensor::GetReadingResponse* resp) 679 { 680 resp->assertOffset0_7 = static_cast<uint8_t>(value & 0x00FF); 681 resp->assertOffset8_14 = static_cast<uint8_t>(value >> 8); 682 } 683 684 /** 685 * @brief Set the scanning enabled bit in the response. 686 * 687 * @param[in/out] resp - get sensor reading response. 688 */ 689 inline void enableScanning(ipmi::sensor::GetReadingResponse* resp) 690 { 691 resp->operation = 1 << 6; 692 } 693 694 } // namespace sensor 695 696 } // namespace ipmi 697