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