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