1 /*
2  * Copyright (C) 2003-2015 FreeIPMI Core Team
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif /* HAVE_CONFIG_H */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #if STDC_HEADERS
26 #include <string.h>
27 #include <stdarg.h>
28 #endif /* STDC_HEADERS */
29 #include <assert.h>
30 #include <errno.h>
31 
32 #include "freeipmi/sel/ipmi-sel.h"
33 
34 #include "freeipmi/record-format/ipmi-sel-record-format.h"
35 #include "freeipmi/record-format/oem/ipmi-sel-oem-intel-record-format.h"
36 #include "freeipmi/spec/ipmi-event-reading-type-code-spec.h"
37 #include "freeipmi/spec/ipmi-iana-enterprise-numbers-spec.h"
38 #include "freeipmi/spec/ipmi-product-id-spec.h"
39 #include "freeipmi/spec/ipmi-sensor-and-event-code-tables-spec.h"
40 #include "freeipmi/spec/ipmi-sensor-types-spec.h"
41 #include "freeipmi/spec/oem/ipmi-event-reading-type-code-oem-intel-spec.h"
42 #include "freeipmi/spec/oem/ipmi-sensor-and-event-code-tables-oem-intel-spec.h"
43 #include "freeipmi/spec/oem/ipmi-sensor-numbers-oem-intel-spec.h"
44 #include "freeipmi/spec/oem/ipmi-sensor-types-oem-intel-spec.h"
45 
46 #include "ipmi-sel-common.h"
47 #include "ipmi-sel-defs.h"
48 #include "ipmi-sel-string.h"
49 #include "ipmi-sel-string-intel-node-manager.h"
50 #include "ipmi-sel-trace.h"
51 #include "ipmi-sel-util.h"
52 
53 #include "freeipmi-portability.h"
54 
55 #define INTEL_EVENT_BUFFER_LENGTH 4096
56 
57 /* return (0) - no OEM match
58  * return (1) - OEM match
59  * return (-1) - error, cleanup and return error
60  */
61 int
sel_string_output_intel_windmill_event_data1_class_sensor_specific_discrete(ipmi_sel_ctx_t ctx,struct ipmi_sel_entry * sel_entry,uint8_t sel_record_type,char * tmpbuf,unsigned int tmpbuflen,unsigned int flags,unsigned int * wlen,struct ipmi_sel_system_event_record_data * system_event_record_data)62 sel_string_output_intel_windmill_event_data1_class_sensor_specific_discrete (ipmi_sel_ctx_t ctx,
63                                                                              struct ipmi_sel_entry *sel_entry,
64                                                                              uint8_t sel_record_type,
65                                                                              char *tmpbuf,
66                                                                              unsigned int tmpbuflen,
67                                                                              unsigned int flags,
68                                                                              unsigned int *wlen,
69                                                                              struct ipmi_sel_system_event_record_data *system_event_record_data)
70 {
71   assert (ctx);
72   assert (ctx->magic == IPMI_SEL_CTX_MAGIC);
73   assert (ctx->manufacturer_id == IPMI_IANA_ENTERPRISE_ID_INTEL);
74   assert (sel_entry);
75   assert (tmpbuf);
76   assert (tmpbuflen);
77   assert (!(flags & ~IPMI_SEL_STRING_FLAGS_MASK));
78   assert (flags & IPMI_SEL_STRING_FLAGS_INTERPRET_OEM_DATA);
79   assert (wlen);
80   assert (system_event_record_data);
81   assert (system_event_record_data->event_type_code == IPMI_EVENT_READING_TYPE_CODE_SENSOR_SPECIFIC);
82   assert (ctx->product_id == IPMI_INTEL_PRODUCT_ID_WINDMILL);
83 
84   /*
85    * Intel Windmill
86    * (Quanta Winterfell)
87    * (Wiwynn Windmill)
88    */
89   if (system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_OEM_INTEL_WINDMILL_GENERIC
90       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_CPU_SEL_STATUS)
91     {
92       uint8_t sel_clear;
93       uint8_t sel_rollover;
94 
95       sel_clear = (system_event_record_data->event_data1 & IPMI_SENSOR_TYPE_OEM_INTEL_SEL_CLEAR_BITMASK);
96       sel_clear >>= IPMI_SENSOR_TYPE_OEM_INTEL_SEL_CLEAR_SHIFT;
97 
98       sel_rollover = (system_event_record_data->event_data1 & IPMI_SENSOR_TYPE_OEM_INTEL_SEL_ROLLOVER_BITMASK);
99       sel_rollover >>= IPMI_SENSOR_TYPE_OEM_INTEL_SEL_ROLLOVER_SHIFT;
100 
101       if (sel_clear)
102         {
103           snprintf (tmpbuf,
104                     tmpbuflen,
105                     "SEL Clear");
106 
107           return (1);
108         }
109 
110       if (sel_rollover)
111         {
112           snprintf (tmpbuf,
113                     tmpbuflen,
114                     "SEL Rollover");
115 
116           return (1);
117         }
118     }
119 
120   if (system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_OEM_INTEL_WINDMILL_GENERIC
121       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_CHASSIS_POWER_STATUS)
122     {
123       char *chassis_power_status_str;
124 
125       switch (system_event_record_data->event_data1)
126         {
127         case IPMI_SENSOR_TYPE_OEM_INTEL_WINDMILL_CHASSIS_POWER_STATUS_POWER_DOWN:
128           chassis_power_status_str = "Power Down";
129           break;
130         case IPMI_SENSOR_TYPE_OEM_INTEL_WINDMILL_CHASSIS_POWER_STATUS_POWER_CYCLE_RESET:
131           chassis_power_status_str = "Power Cycle/Reset";
132           break;
133         case IPMI_SENSOR_TYPE_OEM_INTEL_WINDMILL_CHASSIS_POWER_STATUS_POWER_ON:
134           chassis_power_status_str = "Power On";
135           break;
136         case IPMI_SENSOR_TYPE_OEM_INTEL_WINDMILL_CHASSIS_POWER_STATUS_AC_LOST:
137           chassis_power_status_str = "AC Lost";
138           break;
139         default:
140           chassis_power_status_str = "Unknown";
141           break;
142         }
143 
144       snprintf (tmpbuf,
145                 tmpbuflen,
146                 "Power Status = %s",
147                 chassis_power_status_str);
148 
149       return (1);
150     }
151 
152   if (system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_OEM_INTEL_WINDMILL_GENERIC
153       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_HOT_SWAP_CONTROLLER_0_STATUS_LOW)
154     {
155       char *hsc_str;
156 
157       switch (system_event_record_data->event_data1)
158         {
159         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_LOW_NONE_OF_THE_ABOVE:
160           hsc_str = "Active status bits are waiting to be read by one or more status commands.";
161           break;
162         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_LOW_CML_ERROR:
163           hsc_str = "An error was detected on the I2C/PMBus interface.";
164           break;
165         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_LOW_VIN_UV_FAULT:
166           hsc_str = "An undervoltage input fault was detected on the UV pin.";
167           break;
168         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_LOW_IOUT_OC_FAULT:
169           hsc_str = "The hot swap controller detected an overcurrent condition.";
170           break;
171         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_LOW_HOTSWAP_OFF:
172           hsc_str = "The hot swap gate driver output is disabled.";
173           break;
174         default:
175           hsc_str = "Unknown";
176           break;
177         }
178 
179       snprintf (tmpbuf,
180                 tmpbuflen,
181                 "Status = %s",
182                 hsc_str);
183 
184       return (1);
185     }
186 
187   if (system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_OEM_INTEL_WINDMILL_GENERIC
188       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_HOT_SWAP_CONTROLLER_0_STATUS_HIGH)
189     {
190       char *hsc_str;
191 
192       switch (system_event_record_data->event_data1)
193         {
194         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_HIGH_POWER_GOOD:
195           hsc_str = "The voltage on the FLB pin is below the required threshold.";
196           break;
197         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_HIGH_MFR_STATUS:
198           hsc_str = "There are one or more active status bits to be read by STATUS_MFR_SPECIFIC.";
199           break;
200         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_HIGH_INPUT_STATUS:
201           hsc_str = "There are one or more active status bits to be read by STATUS_INPUT.";
202           break;
203         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_HIGH_IOUT_STATUS:
204           hsc_str = "There are one or more active status bits to be read by STATUS_IOUT.";
205           break;
206         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_HIGH_VOUT_STATUS:
207           hsc_str = "There are one or more active status bits to be read by STATUS_VOUT.";
208           break;
209         default:
210           hsc_str = "Unknown";
211           break;
212         }
213 
214       snprintf (tmpbuf,
215                 tmpbuflen,
216                 "Status = %s",
217                 hsc_str);
218 
219       return (1);
220     }
221 
222   if (system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_OEM_INTEL_WINDMILL_GENERIC
223       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_HOT_SWAP_CONTROLLER_0_STATUS_MFR_SPECIFIC)
224     {
225       char *hsc_str;
226 
227       switch (system_event_record_data->event_data1)
228         {
229         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_MFR_SPECIFIC_IOUT_WARN2:
230           hsc_str = "An undercurrent or overcurrent condition on the output supply detected.";
231           break;
232           /* achu: HS_SHUTDOWN_CAUSE1 & HS_SHUTDOWN_CAUSE2 list 4 error messages
233            * with <00>, <01>, <10>, & <11> listed next to them.  I have no idea
234            * where these other bits come from.
235            *
236            * So all user gets is a generic "hotswap shutdown"
237            */
238         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_MFR_SPECIFIC_HS_SHUTDOWN_CAUSE1:
239           hsc_str = "Hotswap shutdown";
240           break;
241         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_MFR_SPECIFIC_HS_SHUTDOWN_CAUSE2:
242           hsc_str = "Hotswap shutdown";
243           break;
244         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_MFR_SPECIFIC_HS_INLIM:
245           hsc_str = "The ADM1276 has actively limited current into the load.";
246           break;
247         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_MFR_SPECIFIC_OV_CMP_OUT:
248           hsc_str = "Input Voltage to OV pin is above threshold.";
249           break;
250         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_MFR_SPECIFIC_UV_CMP_OUT:
251           hsc_str = "Input voltage to UV pin is below threshold.";
252           break;
253         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_MFR_SPECIFIC_FET_HEALTH_BAD:
254           hsc_str = "FET behavior suggests that the FET may be shorted.";
255           break;
256         default:
257           hsc_str = "Unknown";
258           break;
259         }
260 
261       snprintf (tmpbuf,
262                 tmpbuflen,
263                 "Status = %s",
264                 hsc_str);
265 
266       return (1);
267     }
268 
269   if (system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_OEM_INTEL_WINDMILL_GENERIC
270       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_HOT_SWAP_CONTROLLER_0_STATUS_INPUT)
271     {
272       char *hsc_str;
273 
274       switch (system_event_record_data->event_data1)
275         {
276         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_INPUT_PIN_OP_WARN:
277           hsc_str = "An overpower condition on the input supply was detected by power monitor.";
278           break;
279         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_INPUT_VIN_UV_FAULT:
280           hsc_str = "An undervoltage was detected on the UV pin.";
281           break;
282         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_INPUT_VIN_UV_WARN:
283           hsc_str = "An undervoltage condition on the input supply was detected by the power monitor.";
284           break;
285         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_INPUT_VIN_OV_WARN:
286           hsc_str = "An overvoltage condition on the input supply was detected by hte power monitor.";
287           break;
288         case IPMI_SENSOR_TYPE_OEM_INTEL_HOT_SWAP_CONTROLLER_0_STATUS_INPUT_VIN_OV_FAULT:
289           hsc_str = "An overvoltage was detected on the OV pin.";
290           break;
291         default:
292           hsc_str = "Unknown";
293           break;
294         }
295 
296       snprintf (tmpbuf,
297                 tmpbuflen,
298                 "Status = %s",
299                 hsc_str);
300 
301       return (1);
302     }
303 
304   return (0);
305 }
306 
307 static const char *
_sel_string_output_intel_windmill_native_vs_external_throttling(uint8_t event_data)308 _sel_string_output_intel_windmill_native_vs_external_throttling (uint8_t event_data)
309 {
310   uint8_t noe;
311   char *noe_str;
312 
313   noe = (event_data & IPMI_OEM_INTEL_WINDMILL_EVENT_DATA2_THROTTLING_BITMASK);
314   noe >>= IPMI_OEM_INTEL_WINDMILL_EVENT_DATA2_THROTTLING_SHIFT;
315 
316   switch (noe)
317     {
318     case IPMI_OEM_INTEL_WINDMILL_EVENT_DATA2_NATIVE_THROTTLING:
319       noe_str = "Native";
320       break;
321     case IPMI_OEM_INTEL_WINDMILL_EVENT_DATA2_EXTERNAL_THROTTLING:
322       noe_str = "External";
323       break;
324     default:
325       noe_str = "Unknown";
326       break;
327     }
328 
329   return (noe_str);
330 }
331 
332 /* return (0) - no OEM match
333  * return (1) - OEM match
334  * return (-1) - error, cleanup and return error
335  */
336 int
sel_string_output_intel_windmill_event_data2_discrete_oem(ipmi_sel_ctx_t ctx,struct ipmi_sel_entry * sel_entry,uint8_t sel_record_type,char * tmpbuf,unsigned int tmpbuflen,unsigned int flags,unsigned int * wlen,struct ipmi_sel_system_event_record_data * system_event_record_data)337 sel_string_output_intel_windmill_event_data2_discrete_oem (ipmi_sel_ctx_t ctx,
338                                                            struct ipmi_sel_entry *sel_entry,
339                                                            uint8_t sel_record_type,
340                                                            char *tmpbuf,
341                                                            unsigned int tmpbuflen,
342                                                            unsigned int flags,
343                                                            unsigned int *wlen,
344                                                            struct ipmi_sel_system_event_record_data *system_event_record_data)
345 {
346   assert (ctx);
347   assert (ctx->magic == IPMI_SEL_CTX_MAGIC);
348   assert (ctx->manufacturer_id == IPMI_IANA_ENTERPRISE_ID_INTEL);
349   assert (sel_entry);
350   assert (tmpbuf);
351   assert (tmpbuflen);
352   assert (!(flags & ~IPMI_SEL_STRING_FLAGS_MASK));
353   assert (flags & IPMI_SEL_STRING_FLAGS_INTERPRET_OEM_DATA);
354   assert (wlen);
355   assert (system_event_record_data);
356   assert (system_event_record_data->event_data2_flag == IPMI_SEL_EVENT_DATA_OEM_CODE);
357   assert (ctx->product_id == IPMI_INTEL_PRODUCT_ID_WINDMILL);
358 
359   /*
360    * Intel Windmill
361    * (Quanta Winterfell)
362    * (Wiwynn Windmill)
363    */
364   if (system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_PROCESSOR
365       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_PROC_HOT_EXTENDED_SENSOR
366       && system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_PROCESSOR_PROCESSOR_AUTOMATICALLY_THROTTLED)
367     {
368       const char *noe_str;
369 
370       noe_str = _sel_string_output_intel_windmill_native_vs_external_throttling (system_event_record_data->event_data2);
371 
372       snprintf (tmpbuf,
373                 tmpbuflen,
374                 "Throttling = %s",
375                 noe_str);
376 
377       return (1);
378     }
379 
380   if (system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_MEMORY
381       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_MEM_HOT_EXTENDED_SENSOR
382       && system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_MEMORY_MEMORY_AUTOMATICALLY_THROTTLED)
383     {
384       const char *noe_str;
385 
386       noe_str = _sel_string_output_intel_windmill_native_vs_external_throttling (system_event_record_data->event_data2);
387 
388       snprintf (tmpbuf,
389                 tmpbuflen,
390                 "Throttling = %s",
391                 noe_str);
392 
393       return (1);
394     }
395 
396   if (system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_PROCESSOR
397       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_MACHINE_CHECK_ERROR_SENSOR
398       && (system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_PROCESSOR_MACHINE_CHECK_EXCEPTION
399           || system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_PROCESSOR_CORRECTABLE_MACHINE_CHECK_ERROR))
400     {
401       snprintf (tmpbuf,
402                 tmpbuflen,
403                 "Error Code Number = %u",
404                 system_event_record_data->event_data2);
405 
406       return (1);
407     }
408 
409   if (system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT
410       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_PCIE_ERROR_SENSOR
411       && (system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_BUS_CORRECTABLE_ERROR
412           || system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_BUS_UNCORRECTABLE_ERROR
413           || system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_BUS_FATAL_ERROR))
414     {
415       uint8_t device;
416       uint8_t function;
417 
418       device = (system_event_record_data->event_data2 & IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_EVENT_DATA2_OEM_INTEL_DEVICE_NUMBER_BITMASK);
419       device >>= IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_EVENT_DATA2_OEM_INTEL_DEVICE_NUMBER_SHIFT;
420 
421       function = (system_event_record_data->event_data2 & IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_EVENT_DATA2_OEM_INTEL_FUNCTION_NUMBER_BITMASK);
422       function >>= IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_EVENT_DATA2_OEM_INTEL_FUNCTION_NUMBER_SHIFT;
423 
424       snprintf (tmpbuf,
425                 tmpbuflen,
426                 "Device %u, Function %u",
427                 device,
428                 function);
429 
430       return (1);
431     }
432 
433   if (system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_MEMORY
434       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_MEMORY_ECC_ERROR
435       && (system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_MEMORY_CORRECTABLE_MEMORY_ERROR
436           || system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_MEMORY_UNCORRECTABLE_MEMORY_ERROR))
437     {
438       uint8_t logical_rank;
439 
440       logical_rank = (system_event_record_data->event_data2 & IPMI_SENSOR_TYPE_MEMORY_EVENT_DATA2_OEM_INTEL_WINDMILL_LOGICAL_RANK_BITMASK);
441       logical_rank >>= IPMI_SENSOR_TYPE_MEMORY_EVENT_DATA2_OEM_INTEL_WINDMILL_LOGICAL_RANK_SHIFT;
442 
443       snprintf (tmpbuf,
444                 tmpbuflen,
445                 "Logical Rank = %u",
446                 logical_rank);
447 
448       return (1);
449     }
450 
451   return (0);
452 }
453 
454 /* return (0) - no OEM match
455  * return (1) - OEM match
456  * return (-1) - error, cleanup and return error
457  */
458 int
sel_string_output_intel_windmill_event_data2_class_oem(ipmi_sel_ctx_t ctx,struct ipmi_sel_entry * sel_entry,uint8_t sel_record_type,char * tmpbuf,unsigned int tmpbuflen,unsigned int flags,unsigned int * wlen,struct ipmi_sel_system_event_record_data * system_event_record_data)459 sel_string_output_intel_windmill_event_data2_class_oem (ipmi_sel_ctx_t ctx,
460                                                         struct ipmi_sel_entry *sel_entry,
461                                                         uint8_t sel_record_type,
462                                                         char *tmpbuf,
463                                                         unsigned int tmpbuflen,
464                                                         unsigned int flags,
465                                                         unsigned int *wlen,
466                                                         struct ipmi_sel_system_event_record_data *system_event_record_data)
467 {
468   assert (ctx);
469   assert (ctx->magic == IPMI_SEL_CTX_MAGIC);
470   assert (ctx->manufacturer_id == IPMI_IANA_ENTERPRISE_ID_INTEL);
471   assert (sel_entry);
472   assert (tmpbuf);
473   assert (tmpbuflen);
474   assert (!(flags & ~IPMI_SEL_STRING_FLAGS_MASK));
475   assert (flags & IPMI_SEL_STRING_FLAGS_INTERPRET_OEM_DATA);
476   assert (wlen);
477   assert (system_event_record_data);
478   assert (ctx->product_id == IPMI_INTEL_PRODUCT_ID_WINDMILL);
479 
480   /*
481    * Intel Windmill
482    * (Quanta Winterfell)
483    * (Wiwynn Windmill)
484    */
485   if (system_event_record_data->event_type_code == IPMI_EVENT_READING_TYPE_CODE_OEM_INTEL_WINDMILL_ME_FW_HEALTH_SENSOR
486       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_ME_FW_HEALTH_SENSOR
487       && system_event_record_data->offset_from_event_reading_type_code == IPMI_OEM_INTEL_WINDMILL_ME_FIRMWARE_HEALTH_EVENT_FIRMWARE_STATUS)
488     {
489       uint8_t health_event;
490       char *health_event_str;
491 
492       health_event = system_event_record_data->event_data2;
493 
494       switch (health_event)
495         {
496         case IPMI_OEM_INTEL_WINDMILL_ME_FIRMWARE_HEALTH_EVENT_EVENT_DATA2_RECOVERY_GPIO_FORCED:
497           health_event_str = "Recovery GPIO forced";
498           break;
499         case IPMI_OEM_INTEL_WINDMILL_ME_FIRMWARE_HEALTH_EVENT_EVENT_DATA2_IMAGE_EXECUTION_FAILED:
500           health_event_str = "Image execution failed";
501           break;
502         case IPMI_OEM_INTEL_WINDMILL_ME_FIRMWARE_HEALTH_EVENT_EVENT_DATA2_FLASH_ERASE_ERROR:
503           health_event_str = "Flash erase error";
504           break;
505         case IPMI_OEM_INTEL_WINDMILL_ME_FIRMWARE_HEALTH_EVENT_EVENT_DATA2_FLASH_STATE_INFORMATION:
506           health_event_str = "Flash state information";
507           break;
508         case IPMI_OEM_INTEL_WINDMILL_ME_FIRMWARE_HEALTH_EVENT_EVENT_DATA2_INTERNAL_ERROR:
509           health_event_str = "Internal error";
510           break;
511         case IPMI_OEM_INTEL_WINDMILL_ME_FIRMWARE_HEALTH_EVENT_EVENT_DATA2_BMC_COLD_RESET_ERROR:
512           health_event_str = "BMC did not respond to cold reset";
513           break;
514         case IPMI_OEM_INTEL_WINDMILL_ME_FIRMWARE_HEALTH_EVENT_EVENT_DATA2_DIRECT_FLASH_UPDATE:
515           health_event_str = "Direct flash update requested by the BIOS";
516           break;
517         case IPMI_OEM_INTEL_WINDMILL_ME_FIRMWARE_HEALTH_EVENT_EVENT_DATA2_MANUFACTURING_ERROR:
518           health_event_str = "Manufacturing error";
519           break;
520         case IPMI_OEM_INTEL_WINDMILL_ME_FIRMWARE_HEALTH_EVENT_EVENT_DATA2_PERSISTENT_STORAGE_INTEGRITY_ERROR:
521           health_event_str = "Persistent storage integrity error";
522           break;
523         default:
524           health_event_str = "Unknown";
525         }
526 
527       snprintf (tmpbuf,
528                 tmpbuflen,
529                 "Health Event = %s",
530                 health_event_str);
531 
532       return (1);
533     }
534 
535   if (system_event_record_data->event_type_code == IPMI_EVENT_READING_TYPE_CODE_OEM_INTEL_WINDMILL_OTHER_IIO_ERROR_SENSOR
536       && system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT
537       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_OTHER_IIO_ERROR_SENSOR
538       && system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_FRONT_PANEL_NMI_DIAGNOSTIC_INTERRUPT)
539     {
540       snprintf (tmpbuf,
541                 tmpbuflen,
542                 "Error ID = 0x%02X",
543                 system_event_record_data->event_data2);
544 
545       return (1);
546     }
547 
548   return (0);
549 }
550 
551 /* return (0) - no OEM match
552  * return (1) - OEM match
553  * return (-1) - error, cleanup and return error
554  */
555 int
sel_string_output_intel_windmill_event_data3_discrete_oem(ipmi_sel_ctx_t ctx,struct ipmi_sel_entry * sel_entry,uint8_t sel_record_type,char * tmpbuf,unsigned int tmpbuflen,unsigned int flags,unsigned int * wlen,struct ipmi_sel_system_event_record_data * system_event_record_data)556 sel_string_output_intel_windmill_event_data3_discrete_oem (ipmi_sel_ctx_t ctx,
557                                                            struct ipmi_sel_entry *sel_entry,
558                                                            uint8_t sel_record_type,
559                                                            char *tmpbuf,
560                                                            unsigned int tmpbuflen,
561                                                            unsigned int flags,
562                                                            unsigned int *wlen,
563                                                            struct ipmi_sel_system_event_record_data *system_event_record_data)
564 {
565   assert (ctx);
566   assert (ctx->magic == IPMI_SEL_CTX_MAGIC);
567   assert (ctx->manufacturer_id == IPMI_IANA_ENTERPRISE_ID_INTEL);
568   assert (sel_entry);
569   assert (tmpbuf);
570   assert (tmpbuflen);
571   assert (!(flags & ~IPMI_SEL_STRING_FLAGS_MASK));
572   assert (flags & IPMI_SEL_STRING_FLAGS_INTERPRET_OEM_DATA);
573   assert (wlen);
574   assert (system_event_record_data);
575   assert (system_event_record_data->event_data3_flag == IPMI_SEL_EVENT_DATA_OEM_CODE);
576   assert (ctx->product_id == IPMI_INTEL_PRODUCT_ID_WINDMILL);
577 
578   /*
579    * Intel Windmill
580    * (Quanta Winterfell)
581    * (Wiwynn Windmill)
582    */
583   if (system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_PROCESSOR
584       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_PROC_HOT_EXTENDED_SENSOR
585       && system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_PROCESSOR_PROCESSOR_AUTOMATICALLY_THROTTLED)
586     {
587       uint8_t cpu_vr;
588 
589       cpu_vr = (system_event_record_data->event_data3 & IPMI_OEM_INTEL_WINDMILL_EVENT_DATA3_THROTTLING_CPU_VR_BITMASK);
590       cpu_vr >>= IPMI_OEM_INTEL_WINDMILL_EVENT_DATA3_THROTTLING_CPU_VR_SHIFT;
591 
592       snprintf (tmpbuf,
593                 tmpbuflen,
594                 "CPU/VR = %u",
595                 cpu_vr);
596 
597       return (1);
598     }
599 
600   if (system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_MEMORY
601       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_MEM_HOT_EXTENDED_SENSOR
602       && system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_MEMORY_MEMORY_AUTOMATICALLY_THROTTLED)
603     {
604       uint8_t cpu_vr;
605       uint8_t channel_number;
606       uint8_t dimm;
607 
608       cpu_vr = (system_event_record_data->event_data3 & IPMI_OEM_INTEL_WINDMILL_EVENT_DATA3_THROTTLING_CPU_VR_BITMASK);
609       cpu_vr >>= IPMI_OEM_INTEL_WINDMILL_EVENT_DATA3_THROTTLING_CPU_VR_SHIFT;
610 
611       channel_number = (system_event_record_data->event_data3 & IPMI_OEM_INTEL_WINDMILL_EVENT_DATA3_THROTTLING_CHANNEL_NUMBER_BITMASK);
612       channel_number >>= IPMI_OEM_INTEL_WINDMILL_EVENT_DATA3_THROTTLING_CHANNEL_NUMBER_SHIFT;
613 
614       dimm = (system_event_record_data->event_data3 & IPMI_OEM_INTEL_WINDMILL_EVENT_DATA3_THROTTLING_DIMM_BITMASK);
615       dimm >>= IPMI_OEM_INTEL_WINDMILL_EVENT_DATA3_THROTTLING_DIMM_SHIFT;
616 
617       snprintf (tmpbuf,
618                 tmpbuflen,
619                 "CPU/VR = %u, Channel Number = %u, Dimm = %u",
620                 cpu_vr,
621                 channel_number,
622                 dimm);
623 
624       return (1);
625     }
626 
627   if (system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_PROCESSOR
628       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_MACHINE_CHECK_ERROR_SENSOR
629       && (system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_PROCESSOR_MACHINE_CHECK_EXCEPTION
630           || system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_PROCESSOR_CORRECTABLE_MACHINE_CHECK_ERROR))
631     {
632       uint8_t cpu_number;
633       uint8_t source;
634       uint8_t source_extra;
635 
636       cpu_number = (system_event_record_data->event_data3 & IPMI_SENSOR_TYPE_PROCESSOR_EVENT_DATA2_OEM_INTEL_WINDMILL_MACHINE_CHECK_ERROR_CPU_NUMBER_BITMASK);
637       cpu_number >>= IPMI_SENSOR_TYPE_PROCESSOR_EVENT_DATA2_OEM_INTEL_WINDMILL_MACHINE_CHECK_ERROR_CPU_NUMBER_SHIFT;
638 
639       source = (system_event_record_data->event_data3 & IPMI_SENSOR_TYPE_PROCESSOR_EVENT_DATA2_OEM_INTEL_WINDMILL_MACHINE_CHECK_ERROR_SOURCE_BITMASK);
640       source >>= IPMI_SENSOR_TYPE_PROCESSOR_EVENT_DATA2_OEM_INTEL_WINDMILL_MACHINE_CHECK_ERROR_SOURCE_SHIFT;
641 
642       source_extra = (system_event_record_data->event_data3 & IPMI_SENSOR_TYPE_PROCESSOR_EVENT_DATA2_OEM_INTEL_WINDMILL_MACHINE_CHECK_ERROR_SOURCE_EXTRA_BITMASK);
643       source_extra >>= IPMI_SENSOR_TYPE_PROCESSOR_EVENT_DATA2_OEM_INTEL_WINDMILL_MACHINE_CHECK_ERROR_SOURCE_EXTRA_SHIFT;
644 
645       if (source == IPMI_SENSOR_TYPE_PROCESSOR_EVENT_DATA2_OEM_INTEL_WINDMILL_MACHINE_CHECK_ERROR_SOURCE_QPI)
646         {
647           char *qpi_str;
648 
649           switch (source_extra)
650             {
651             case IPMI_SENSOR_TYPE_PROCESSOR_EVENT_DATA2_OEM_INTEL_WINDMILL_MACHINE_CHECK_ERROR_SOURCE_EXTRA_QPI0:
652               qpi_str = "QPI0";
653               break;
654             case IPMI_SENSOR_TYPE_PROCESSOR_EVENT_DATA2_OEM_INTEL_WINDMILL_MACHINE_CHECK_ERROR_SOURCE_EXTRA_QPI1:
655               qpi_str = "QPI1";
656               break;
657             default:
658               qpi_str = "Unknown QPI";
659               break;
660             }
661 
662           snprintf (tmpbuf,
663                     tmpbuflen,
664                     "CPU = %u, Source = %s",
665                     cpu_number,
666                     qpi_str);
667         }
668       else if (source == IPMI_SENSOR_TYPE_PROCESSOR_EVENT_DATA2_OEM_INTEL_WINDMILL_MACHINE_CHECK_ERROR_SOURCE_LLC)
669         {
670           snprintf (tmpbuf,
671                     tmpbuflen,
672                     "CPU = %u, Core = %u",
673                     cpu_number,
674                     source_extra);
675         }
676       else
677         {
678           snprintf (tmpbuf,
679                     tmpbuflen,
680                     "CPU = %u, Source = %s",
681                     cpu_number,
682                     "Unknown");
683         }
684 
685       return (1);
686     }
687 
688   if (system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT
689       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_PCIE_ERROR_SENSOR
690       && (system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_BUS_CORRECTABLE_ERROR
691           || system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_BUS_UNCORRECTABLE_ERROR
692           || system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_BUS_FATAL_ERROR))
693     {
694       snprintf (tmpbuf,
695                 tmpbuflen,
696                 "Bus Number = %u",
697                 system_event_record_data->event_data3);
698 
699       return (1);
700     }
701 
702   if (system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_MEMORY
703       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_MEMORY_ECC_ERROR
704       && (system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_MEMORY_CORRECTABLE_MEMORY_ERROR
705           || system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_MEMORY_UNCORRECTABLE_MEMORY_ERROR))
706     {
707       uint8_t cpu_number;
708       uint8_t channel_number;
709       uint8_t dimm;
710 
711       cpu_number = (system_event_record_data->event_data3 & IPMI_SENSOR_TYPE_MEMORY_EVENT_DATA3_OEM_INTEL_WINDMILL_CPU_NUMBER_BITMASK);
712       cpu_number >>= IPMI_SENSOR_TYPE_MEMORY_EVENT_DATA3_OEM_INTEL_WINDMILL_CPU_NUMBER_SHIFT;
713 
714       channel_number = (system_event_record_data->event_data3 & IPMI_SENSOR_TYPE_MEMORY_EVENT_DATA3_OEM_INTEL_WINDMILL_CHANNEL_NUMBER_BITMASK);
715       channel_number >>= IPMI_SENSOR_TYPE_MEMORY_EVENT_DATA3_OEM_INTEL_WINDMILL_CHANNEL_NUMBER_SHIFT;
716 
717       dimm = (system_event_record_data->event_data3 & IPMI_SENSOR_TYPE_MEMORY_EVENT_DATA3_OEM_INTEL_WINDMILL_DIMM_BITMASK);
718       dimm >>= IPMI_SENSOR_TYPE_MEMORY_EVENT_DATA3_OEM_INTEL_WINDMILL_DIMM_SHIFT;
719 
720       snprintf (tmpbuf,
721                 tmpbuflen,
722                 "CPU Number = %u, Channel Number = %u, Dimm = %u",
723                 cpu_number,
724                 channel_number,
725                 dimm);
726 
727       return (1);
728     }
729 
730   return (0);
731 }
732 
733 /* return (0) - no OEM match
734  * return (1) - OEM match
735  * return (-1) - error, cleanup and return error
736  */
737 int
sel_string_output_intel_windmill_event_data3_class_oem(ipmi_sel_ctx_t ctx,struct ipmi_sel_entry * sel_entry,uint8_t sel_record_type,char * tmpbuf,unsigned int tmpbuflen,unsigned int flags,unsigned int * wlen,struct ipmi_sel_system_event_record_data * system_event_record_data)738 sel_string_output_intel_windmill_event_data3_class_oem (ipmi_sel_ctx_t ctx,
739                                                         struct ipmi_sel_entry *sel_entry,
740                                                         uint8_t sel_record_type,
741                                                         char *tmpbuf,
742                                                         unsigned int tmpbuflen,
743                                                         unsigned int flags,
744                                                         unsigned int *wlen,
745                                                         struct ipmi_sel_system_event_record_data *system_event_record_data)
746 {
747   assert (ctx);
748   assert (ctx->magic == IPMI_SEL_CTX_MAGIC);
749   assert (ctx->manufacturer_id == IPMI_IANA_ENTERPRISE_ID_INTEL);
750   assert (sel_entry);
751   assert (tmpbuf);
752   assert (tmpbuflen);
753   assert (!(flags & ~IPMI_SEL_STRING_FLAGS_MASK));
754   assert (flags & IPMI_SEL_STRING_FLAGS_INTERPRET_OEM_DATA);
755   assert (wlen);
756   assert (system_event_record_data);
757   assert (ctx->product_id == IPMI_INTEL_PRODUCT_ID_WINDMILL);
758 
759   /*
760    * Intel Windmill
761    * (Quanta Winterfell)
762    * (Wiwynn Windmill)
763    */
764   if (system_event_record_data->event_type_code == IPMI_EVENT_READING_TYPE_CODE_OEM_INTEL_WINDMILL_ME_FW_HEALTH_SENSOR
765       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_ME_FW_HEALTH_SENSOR
766       && system_event_record_data->offset_from_event_reading_type_code == IPMI_OEM_INTEL_WINDMILL_ME_FIRMWARE_HEALTH_EVENT_FIRMWARE_STATUS)
767     {
768       snprintf (tmpbuf,
769                 tmpbuflen,
770                 "Extended Error Info = %02X",
771                 system_event_record_data->event_data3);
772 
773     }
774 
775   if (system_event_record_data->event_type_code == IPMI_EVENT_READING_TYPE_CODE_OEM_INTEL_WINDMILL_OTHER_IIO_ERROR_SENSOR
776       && system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT
777       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_OTHER_IIO_ERROR_SENSOR
778       && system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_FRONT_PANEL_NMI_DIAGNOSTIC_INTERRUPT)
779     {
780       uint8_t cpu_number;
781       uint8_t source;
782       char *source_str;
783 
784       cpu_number = (system_event_record_data->event_data3 & IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_EVENT_DATA3_OEM_INTEL_WINDMILL_CPU_NUMBER_BITMASK);
785       cpu_number >>= IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_EVENT_DATA3_OEM_INTEL_WINDMILL_CPU_NUMBER_SHIFT;
786 
787       source = (system_event_record_data->event_data3 & IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_EVENT_DATA3_OEM_INTEL_WINDMILL_SOURCE_BITMASK);
788       source >>= IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_EVENT_DATA3_OEM_INTEL_WINDMILL_SOURCE_SHIFT;
789 
790       switch (source)
791         {
792         case IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_EVENT_DATA3_OEM_INTEL_WINDMILL_SOURCE_IRP0:
793           source_str = "IRP0";
794           break;
795         case IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_EVENT_DATA3_OEM_INTEL_WINDMILL_SOURCE_IRP1:
796           source_str = "IRP1";
797           break;
798         case IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_EVENT_DATA3_OEM_INTEL_WINDMILL_SOURCE_IIO_CORE:
799           source_str = "IIO-Core";
800           break;
801         case IPMI_SENSOR_TYPE_CRITICAL_INTERRUPT_EVENT_DATA3_OEM_INTEL_WINDMILL_SOURCE_VT_D:
802           source_str = "VT-d";
803           break;
804         default:
805           source_str = "Unknown";
806           break;
807         }
808 
809       snprintf (tmpbuf,
810                 tmpbuflen,
811                 "CPU Number = %u, Source = %s",
812                 cpu_number, source_str);
813 
814       return (1);
815     }
816 
817   return (0);
818 }
819 
820 /* return (0) - no OEM match
821  * return (1) - OEM match
822  * return (-1) - error, cleanup and return error
823  *
824  * in oem_rv, return
825  * 0 - continue on
826  * 1 - buffer full, return full buffer to user
827  */
828 int
sel_string_output_intel_windmill_event_data2_event_data3(ipmi_sel_ctx_t ctx,struct ipmi_sel_entry * sel_entry,uint8_t sel_record_type,char * buf,unsigned int buflen,unsigned int flags,unsigned int * wlen,struct ipmi_sel_system_event_record_data * system_event_record_data,int * oem_rv)829 sel_string_output_intel_windmill_event_data2_event_data3 (ipmi_sel_ctx_t ctx,
830                                                           struct ipmi_sel_entry *sel_entry,
831                                                           uint8_t sel_record_type,
832                                                           char *buf,
833                                                           unsigned int buflen,
834                                                           unsigned int flags,
835                                                           unsigned int *wlen,
836                                                           struct ipmi_sel_system_event_record_data *system_event_record_data,
837                                                           int *oem_rv)
838 {
839   assert (ctx);
840   assert (ctx->magic == IPMI_SEL_CTX_MAGIC);
841   assert (ctx->manufacturer_id == IPMI_IANA_ENTERPRISE_ID_INTEL);
842   assert (sel_entry);
843   assert (buf);
844   assert (buflen);
845   assert (!(flags & ~IPMI_SEL_STRING_FLAGS_MASK));
846   assert (flags & IPMI_SEL_STRING_FLAGS_INTERPRET_OEM_DATA);
847   assert (wlen);
848   assert (system_event_record_data);
849   assert (oem_rv);
850   assert (ctx->product_id == IPMI_INTEL_PRODUCT_ID_WINDMILL);
851 
852   /*
853    * Intel Windmill
854    * (Quanta Winterfell)
855    * (Wiwynn Windmill)
856    */
857 
858   if (system_event_record_data->event_type_code == IPMI_EVENT_READING_TYPE_CODE_SENSOR_SPECIFIC
859       && system_event_record_data->sensor_type == IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS
860       && system_event_record_data->sensor_number == IPMI_SENSOR_NUMBER_OEM_INTEL_WINDMILL_POST_ERROR_SENSOR
861       && system_event_record_data->offset_from_event_reading_type_code == IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_SYSTEM_FIRMWARE_ERROR
862       && system_event_record_data->event_data2_flag == IPMI_SEL_EVENT_DATA_OEM_CODE
863       && system_event_record_data->event_data3_flag == IPMI_SEL_EVENT_DATA_OEM_CODE)
864     {
865       uint16_t error_code;
866       char *error_code_str = NULL;
867 
868       error_code = system_event_record_data->event_data2;
869       error_code |= (system_event_record_data->event_data3 << 8);
870 
871       switch (error_code)
872         {
873           /* These are from WiWynn doc */
874         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_PEI_CPU_MISMATCH:
875           error_code_str = "PEI CPU Mismatch";
876           break;
877         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_PEI_CPU_SELF_TEST_FAILED:
878           error_code_str = "PEI CPU Self Test Failed";
879           break;
880         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_PEI_CPU_CACHE_ERROR:
881           error_code_str = "PEI CPU Cache Error ";
882           break;
883         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_PEI_CPU_MICROCODE_UPDATE_FAILED:
884           error_code_str = "PEI CPU Microcode Update Failed";
885           break;
886         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_PEI_CPU_NO_MICROCODE:
887           error_code_str = "PEI CPU No Microcode";
888           break;
889         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_PEI_CPU_INTERNAL_ERROR:
890           error_code_str = "PEI CPU Internal Error";
891           break;
892         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_PEI_RESET_NOT_AVAILABLE1:
893           error_code_str = "PEI Reset Not Available";
894           break;
895         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_PEI_RESET_NOT_AVAILABLE2:
896           error_code_str = "PEI Reset Not Available";
897           break;
898         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_PEI_RECOVERY_NO_CAPSULE:
899           error_code_str = "PEI Recovery No Capsule";
900           break;
901         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_PEI_SB_PWR_FLR:
902           error_code_str = "PEI SB PWR FLR";
903           break;
904         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_PEI_SB_SYSPWR_FLR:
905           error_code_str = "PEI SB SYSPWR FLR";
906           break;
907         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_DXE_CLEAR_CMOS:
908           error_code_str = "DXE Clear CMOS ";
909           break;
910         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_DXE_NB_ERROR:
911           error_code_str = "DXE NB Error";
912           break;
913         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_DXE_ARCH_PROTOCOL_NOT_AVAILABLE:
914           error_code_str = "DXE Arch Protocol Not Available";
915           break;
916         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_DXE_PCI_BUS_OUT_OF_RESOURCES:
917           error_code_str = "DXE PCI Bus Out of Resources";
918           break;
919         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_DXE_LEGACY_OPROM_NO_SPACE:
920           error_code_str = "DXE Legacy OPROM No Space";
921           break;
922         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_DXE_NO_CON_OUT:
923           error_code_str = "DXE No Con Out";
924           break;
925         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_DXE_NO_CON_IN:
926           error_code_str = "DXE No Con In";
927           break;
928         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_DXE_FLASH_UPDATE_FAILED:
929           error_code_str = "DXE Flash Update Failed";
930           break;
931         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_DXE_RESET_NOT_AVAILABLE:
932           error_code_str = "DXE Reset Not Available";
933           break;
934         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_ME_RECOVERED_VIA_GR:
935           error_code_str = "ME Recovered via GR";
936           break;
937           /* These are from a Quanta doc */
938         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_CMOS_CLEAR:
939           error_code_str = "CMOS Clear";
940           break;
941         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_THERMAL_TRIP:
942           error_code_str = "Thermal Trip";
943           break;
944         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_SYS_PWROK_DROPS_UNEXPECTEDLY:
945           error_code_str = "SYS_PWROK Drops Unexpectedly";
946           break;
947         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_AC_LOST:
948           error_code_str = "AC Lost";
949           break;
950         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_RECOVER_ME_FROM_ABNORMAL_MODE:
951           error_code_str = "Recover ME from Abnormal Mode Successfully";
952           break;
953         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_BACKUP_IMAGE_LOADED_DIRECT_FW_UPDATE_NEEDED:
954           error_code_str = "Backup Image Loaded and a direct FW updated is needed";
955           break;
956         case IPMI_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS_OEM_INTEL_WINDMILL_POST_ERROR_CODE_ROCVER_HECI_FROM_ABNORMAL_MODE:
957           error_code_str = "Recover HECI from Abnormal Mode Successfully";
958           break;
959         default:
960           error_code_str = "Undefined Post Error";
961         }
962 
963       if (sel_string_snprintf (buf,
964                                buflen,
965                                wlen,
966                                "%s",
967                                error_code_str))
968         (*oem_rv) = 1;
969       else
970         (*oem_rv) = 0;
971 
972       return (1);
973     }
974 
975   return (0);
976 }
977 
978 /* return (0) - no OEM match
979  * return (1) - OEM match
980  * return (-1) - error, cleanup and return error
981  *
982  * in oem_rv, return
983  * 0 - continue on
984  * 1 - buffer full, return full buffer to user
985  */
986 int
sel_string_output_intel_windmill_oem_record_data(ipmi_sel_ctx_t ctx,struct ipmi_sel_entry * sel_entry,uint8_t sel_record_type,char * buf,unsigned int buflen,unsigned int flags,unsigned int * wlen,int * oem_rv)987 sel_string_output_intel_windmill_oem_record_data (ipmi_sel_ctx_t ctx,
988                                                   struct ipmi_sel_entry *sel_entry,
989                                                   uint8_t sel_record_type,
990                                                   char *buf,
991                                                   unsigned int buflen,
992                                                   unsigned int flags,
993                                                   unsigned int *wlen,
994                                                   int *oem_rv)
995 {
996   assert (ctx);
997   assert (ctx->magic == IPMI_SEL_CTX_MAGIC);
998   assert (ctx->manufacturer_id == IPMI_IANA_ENTERPRISE_ID_INTEL);
999   assert (ipmi_sel_record_type_class (sel_record_type) == IPMI_SEL_RECORD_TYPE_CLASS_TIMESTAMPED_OEM_RECORD
1000           || ipmi_sel_record_type_class (sel_record_type) == IPMI_SEL_RECORD_TYPE_CLASS_NON_TIMESTAMPED_OEM_RECORD);
1001   assert (sel_entry);
1002   assert (buf);
1003   assert (buflen);
1004   assert (!(flags & ~IPMI_SEL_STRING_FLAGS_MASK));
1005   assert (flags & IPMI_SEL_STRING_FLAGS_INTERPRET_OEM_DATA);
1006   assert (wlen);
1007   assert (oem_rv);
1008   assert (ctx->product_id == IPMI_INTEL_PRODUCT_ID_WINDMILL);
1009 
1010   /* Intel Windmill
1011    * (Quanta Winterfell)
1012    * (Wiwynn Windmill)
1013    */
1014 
1015   if (ipmi_sel_record_type_class (sel_record_type) == IPMI_SEL_RECORD_TYPE_CLASS_TIMESTAMPED_OEM_RECORD)
1016     {
1017       /* Bytes 11-12 - Device ID
1018        * Bytes 13-14 - Device Identification Number
1019        * Bytes 15-16 - Error Code
1020        *
1021        * I'm assuming little endian, hopefully I'm right.
1022        */
1023       uint16_t device_id;
1024       uint16_t device_identification_number;
1025       char *device_identification_number_str;
1026       uint16_t error_code;
1027       char *error_code_str;
1028 
1029       device_id = sel_entry->sel_event_record[IPMI_SEL_OEM_INTEL_WINDMILL_DEVICE_IDENTIFICATION_NUMBER_INDEX_LSB_INDEX];
1030       device_id |= (sel_entry->sel_event_record[IPMI_SEL_OEM_INTEL_WINDMILL_DEVICE_IDENTIFICATION_NUMBER_INDEX_MSB_INDEX] << 8);
1031 
1032       device_identification_number = sel_entry->sel_event_record[IPMI_SEL_OEM_INTEL_WINDMILL_DEVICE_IDENTIFICATION_NUMBER_INDEX_LSB_INDEX];
1033       device_identification_number |= (sel_entry->sel_event_record[IPMI_SEL_OEM_INTEL_WINDMILL_DEVICE_IDENTIFICATION_NUMBER_INDEX_MSB_INDEX] << 8);
1034 
1035       error_code = sel_entry->sel_event_record[IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_INDEX_LSB_INDEX];
1036       error_code |= (sel_entry->sel_event_record[IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_INDEX_MSB_INDEX] << 8);
1037 
1038       switch (device_identification_number)
1039         {
1040         case IPMI_SEL_OEM_INTEL_WINDMILL_DEVICE_IDENTIFICATION_NUMBER_DEVICE_0_IN_DMI_MODE:
1041           device_identification_number_str = "Device 0 in DMI Mode ";
1042           break;
1043         case IPMI_SEL_OEM_INTEL_WINDMILL_DEVICE_IDENTIFICATION_NUMBER_DMI_PORT_IN_PCIE_MODE:
1044           device_identification_number_str = "DMI Port in PCIe Mode ";
1045           break;
1046         case IPMI_SEL_OEM_INTEL_WINDMILL_DEVICE_IDENTIFICATION_NUMBER_PORT_1A:
1047           device_identification_number_str = "Port 1A";
1048           break;
1049         case IPMI_SEL_OEM_INTEL_WINDMILL_DEVICE_IDENTIFICATION_NUMBER_PORT_1B:
1050           device_identification_number_str = "Port 1B";
1051           break;
1052         case IPMI_SEL_OEM_INTEL_WINDMILL_DEVICE_IDENTIFICATION_NUMBER_PORT_2A:
1053           device_identification_number_str = "Port 2A";
1054           break;
1055         case IPMI_SEL_OEM_INTEL_WINDMILL_DEVICE_IDENTIFICATION_NUMBER_PORT_2B:
1056           device_identification_number_str = "Port 2B";
1057           break;
1058         case IPMI_SEL_OEM_INTEL_WINDMILL_DEVICE_IDENTIFICATION_NUMBER_PORT_2C:
1059           device_identification_number_str = "Port 2C";
1060           break;
1061         case IPMI_SEL_OEM_INTEL_WINDMILL_DEVICE_IDENTIFICATION_NUMBER_PORT_2D:
1062           device_identification_number_str = "Port 2D";
1063           break;
1064         case IPMI_SEL_OEM_INTEL_WINDMILL_DEVICE_IDENTIFICATION_NUMBER_PORT_3A_IN_PCIE_MODE:
1065           device_identification_number_str = "Port 3A in PCIe Mode";
1066           break;
1067         case IPMI_SEL_OEM_INTEL_WINDMILL_DEVICE_IDENTIFICATION_NUMBER_PORT_3B:
1068           device_identification_number_str = "Port 3B";
1069           break;
1070         case IPMI_SEL_OEM_INTEL_WINDMILL_DEVICE_IDENTIFICATION_NUMBER_PORT_3C:
1071           device_identification_number_str = "Port 3C";
1072           break;
1073         case IPMI_SEL_OEM_INTEL_WINDMILL_DEVICE_IDENTIFICATION_NUMBER_PORT_3D:
1074           device_identification_number_str = "Port 3D";
1075           break;
1076         case IPMI_SEL_OEM_INTEL_WINDMILL_DEVICE_IDENTIFICATION_NUMBER_IIO_NTB_SECONDARY_ENDPOINT:
1077           device_identification_number_str = "IIO NTB Secondary Endpoint";
1078           break;
1079         default:
1080           device_identification_number_str = "Unknown";
1081           break;
1082         }
1083 
1084       switch (error_code)
1085         {
1086         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_RECEIVER_ERROR:
1087           error_code_str = "Receiver Error";
1088           break;
1089         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_BAD_TLP:
1090           error_code_str = "Bad TLP";
1091           break;
1092         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_BAD_DLLP:
1093           error_code_str = "Bad DLPP";
1094           break;
1095         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_REPLAY_TIMEOUT:
1096           error_code_str = "Replay Time-out";
1097           break;
1098         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_REPLAY_NUMBER_ROLLOVER:
1099           error_code_str = "Replay Number Rollover";
1100           break;
1101         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_ADVISORY_NON_FATAL_ERROR:
1102           error_code_str = "Advisory Non-fatal Error";
1103           break;
1104         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_RECEIVED_ERR_COR_MESSAGE_FROM_DOWNSTREAM_DEVICE:
1105           error_code_str = "Received ERR_COR message from downstream device";
1106           break;
1107         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_PCI_EXPRESS_LINK_BANDWIDTH_CHANGED:
1108           error_code_str = "PCI Express Link Bandwidth changed";
1109           break;
1110         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_RECEIVED_UNSUPPORTED_REQUEST_COMPLETION_STATUS_FROM_DOWNSTREAM_DEVICE:
1111           error_code_str = "Received \"Unsupported Request\" completion status from downstream device.";
1112           break;
1113         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_SENT_A_PCI_EXPRESS_UNSUPPORTED_REQUEST_RESPOND_ON_INBOUND_REQUEST:
1114           error_code_str = "Sent a PCI Express \"Unsupported Request\" respond on inbound request for address decode, request type, or other reason.";
1115           break;
1116         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_RECEIVED_COMPLETER_ABORT_COMPLETION_STATUS_FROM_DOWNSTREAM_DEVICE:
1117           error_code_str = "Received \"Completer Abort\" completion status from downstream device.";
1118           break;
1119         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_SENT_A_PCI_EXPRESS_COMPLETER_ABORT_CONDITION_ON_INBOUND_REQUEST:
1120           error_code_str = "Sent a PCI Express \"Completer Abort\" condition on inbound request for address decode, request type, or other reason.";
1121           break;
1122         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_COMPLETION_TIMEOUT_ON_NP_TRANSACTION_OUTSTANDING_ON_PCI_EXPRESS_DMI:
1123           error_code_str = "Completion timeout on NP transaction outstanding on PCI Express/DMI.";
1124           break;
1125         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_RECEIVED_PCI_EXPRESS_POISONED_TLP:
1126           error_code_str = "Received PCI Express Poisoned TLP.";
1127           break;
1128         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_RECEIVED_PCI_EXPRESS_UNEXPECTED_COMPLETION:
1129           error_code_str = "Received PCI Express unexpected Completion.";
1130           break;
1131         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_PCI_EXPRESS_FLOW_CONTROL_PROTOCOL_ERROR:
1132           error_code_str = "PCI Express Flow Control Protocol Error.";
1133           break;
1134         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_RECEIVED_ERR_NONFATAL_MESSAGE_FROM_DOWNSTREAM_DEVICE:
1135           error_code_str = "Received ERR_NONFATAL Message from downstream device.";
1136           break;
1137         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_RECEIVED_A_REQUEST_FROM_A_DOWNSTREAM_COMPONENT_THAT_IS_UNSUPPORTED:
1138           error_code_str = "Received a Request from a downstream component that is unsupported.";
1139           break;
1140         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_RECEIVED_A_REQUEST_FROM_A_DOWNSTREAM_COMPONENT_THAT_IS_TO_BE_COMPLETER_ABORTED:
1141           error_code_str = "Received a Request from a downstream component that is to be completer aborted.";
1142           break;
1143         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_ACS_VIOLATION:
1144           error_code_str = "ACS Violation";
1145           break;
1146         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_PCI_EXPRESS_MALFORMED_TLP:
1147           error_code_str = "PCI Express Malformed TLP";
1148           break;
1149         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_PCI_EXPRESS_DATA_LINK_PROTOCOL_ERROR:
1150           error_code_str = "PCI Express Data Link Protocol Error";
1151           break;
1152         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_PCI_EXPRESS_RECEIVER_OVERFLOW:
1153           error_code_str = "PCI Express Receiver Overflow";
1154           break;
1155         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_SURPRISE_DOWN:
1156           error_code_str = "Surprise Down";
1157           break;
1158         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_RECEIVED_ERR_FATAL_MESSAGE_FROM_DOWNSTREAM_DEVICE:
1159           error_code_str = "Received ERR_FATAL message from downstream device.";
1160           break;
1161         case IPMI_SEL_OEM_INTEL_WINDMILL_ERROR_CODE_OUTBOUND_SWITCH_HEADER_QUEUE_PARITY_ERROR:
1162           error_code_str = "Outbound switch header queue partiy error";
1163           break;
1164         default:
1165           error_code_str = "Unknown";
1166           break;
1167         }
1168 
1169       if (sel_string_snprintf (buf,
1170                                buflen,
1171                                wlen,
1172                                "Devie ID = %u, Device Identification Number = %s, Error = %s",
1173                                device_id,
1174                                device_identification_number_str,
1175                                error_code_str))
1176         (*oem_rv) = 1;
1177       else
1178         (*oem_rv) = 0;
1179 
1180       return (1);
1181     }
1182 
1183   return (0);
1184 }
1185 
1186 struct sel_string_oem sel_string_oem_intel_windmill =
1187   {
1188     NULL,
1189     sel_string_output_intel_windmill_event_data1_class_sensor_specific_discrete,
1190     NULL,
1191     NULL,
1192     sel_string_output_intel_windmill_event_data2_discrete_oem,
1193     sel_string_output_intel_windmill_event_data2_class_oem,
1194     NULL,
1195     sel_string_output_intel_windmill_event_data3_discrete_oem,
1196     sel_string_output_intel_windmill_event_data3_class_oem,
1197     sel_string_output_intel_windmill_event_data2_event_data3,
1198     sel_string_output_intel_windmill_oem_record_data,
1199     NULL,
1200   };
1201