1 /* -*-mode: C; indent-tabs-mode: t; -*-
2 * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * Redistribution of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * Redistribution in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * Neither the name of Sun Microsystems, Inc. or the names of
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * This software is provided "AS IS," without a warranty of any kind.
20 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
24 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
26 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31 */
32
33 #include <string.h>
34 #include <math.h>
35 #define __USE_XOPEN /* glibc2 needs this for strptime */
36 #include <time.h>
37 #include <ctype.h>
38 #include <errno.h>
39
40 #include <ipmitool/helper.h>
41 #include <ipmitool/log.h>
42 #include <ipmitool/ipmi.h>
43 #include <ipmitool/ipmi_mc.h>
44 #include <ipmitool/ipmi_intf.h>
45 #include <ipmitool/ipmi_sel.h>
46 #include <ipmitool/ipmi_sdr.h>
47 #include <ipmitool/ipmi_fru.h>
48 #include <ipmitool/ipmi_sensor.h>
49
50 extern int verbose;
51 static int sel_extended = 0;
52 static int sel_oem_nrecs = 0;
53
54 static IPMI_OEM sel_iana = IPMI_OEM_UNKNOWN;
55
56 struct ipmi_sel_oem_msg_rec {
57 int value[14];
58 char *string[14];
59 char *text;
60 } *sel_oem_msg;
61
62 #define SEL_BYTE(n) (n-3) /* So we can refer to byte positions in log entries (byte 3 is at index 0, etc) */
63
64 // Definiation for the Decoding the SEL OEM Bytes for DELL Platfoms
65 #define BIT(x) (1 << x) /* Select the Bit */
66 #define SIZE_OF_DESC 128 /* Max Size of the description String to be displyed for the Each sel entry */
67 #define MAX_CARDNO_STR 32 /* Max Size of Card number string */
68 #define MAX_DIMM_STR 32 /* Max Size of DIMM string */
69 #define MAX_CARD_STR 32 /* Max Size of Card string */
70 /*
71 * Reads values found in message translation file. XX is a wildcard, R means reserved.
72 * Returns -1 for XX, -2 for R, -3 for non-hex (string), or positive integer from a hex value.
73 */
ipmi_sel_oem_readval(char * str)74 static int ipmi_sel_oem_readval(char *str)
75 {
76 int ret;
77 if (!strcmp(str, "XX")) {
78 return -1;
79 }
80 if (!strcmp(str, "R")) {
81 return -2;
82 }
83 if (sscanf(str, "0x%x", &ret) != 1) {
84 return -3;
85 }
86 return ret;
87 }
88
89 /*
90 * This is where the magic happens. SEL_BYTE is a bit ugly, but it allows
91 * reference to byte positions instead of array indexes which (hopefully)
92 * helps make the code easier to read.
93 */
94 static int
ipmi_sel_oem_match(uint8_t * evt,const struct ipmi_sel_oem_msg_rec * rec)95 ipmi_sel_oem_match(uint8_t *evt, const struct ipmi_sel_oem_msg_rec *rec)
96 {
97 if (evt[2] == rec->value[SEL_BYTE(3)]
98 && ((rec->value[SEL_BYTE(4)] < 0)
99 || (evt[3] == rec->value[SEL_BYTE(4)]))
100 && ((rec->value[SEL_BYTE(5)] < 0)
101 || (evt[4] == rec->value[SEL_BYTE(5)]))
102 && ((rec->value[SEL_BYTE(6)] < 0)
103 || (evt[5] == rec->value[SEL_BYTE(6)]))
104 && ((rec->value[SEL_BYTE(7)] < 0)
105 || (evt[6] == rec->value[SEL_BYTE(7)]))
106 && ((rec->value[SEL_BYTE(11)] < 0)
107 || (evt[10] == rec->value[SEL_BYTE(11)]))
108 && ((rec->value[SEL_BYTE(12)] < 0)
109 || (evt[11] == rec->value[SEL_BYTE(12)]))) {
110 return 1;
111 } else {
112 return 0;
113 }
114 }
115
ipmi_sel_oem_init(const char * filename)116 int ipmi_sel_oem_init(const char * filename)
117 {
118 FILE * fp;
119 int i, j, k, n, byte;
120 char buf[15][150];
121
122 if (filename == NULL) {
123 lprintf(LOG_ERR, "No SEL OEM filename provided");
124 return -1;
125 }
126
127 fp = ipmi_open_file_read(filename);
128 if (fp == NULL) {
129 lprintf(LOG_ERR, "Could not open %s file", filename);
130 return -1;
131 }
132
133 /* count number of records (lines) in input file */
134 sel_oem_nrecs = 0;
135 while (fscanf(fp, "%*[^\n]\n") == 0) {
136 sel_oem_nrecs++;
137 }
138
139 printf("nrecs=%d\n", sel_oem_nrecs);
140
141 rewind(fp);
142 sel_oem_msg = (struct ipmi_sel_oem_msg_rec *)calloc(sel_oem_nrecs,
143 sizeof(struct ipmi_sel_oem_msg_rec));
144
145 for (i=0; i < sel_oem_nrecs; i++) {
146 n=fscanf(fp, "\"%[^\"]\",\"%[^\"]\",\"%[^\"]\",\"%[^\"]\",\""
147 "%[^\"]\",\"%[^\"]\",\"%[^\"]\",\"%[^\"]\",\""
148 "%[^\"]\",\"%[^\"]\",\"%[^\"]\",\"%[^\"]\",\""
149 "%[^\"]\",\"%[^\"]\",\"%[^\"]\"\n",
150 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
151 buf[6], buf[7], buf[8], buf[9], buf[10], buf[11],
152 buf[12], buf[13], buf[14]);
153
154 if (n != 15) {
155 lprintf (LOG_ERR, "Encountered problems reading line %d of %s",
156 i+1, filename);
157 fclose(fp);
158 fp = NULL;
159 sel_oem_nrecs = 0;
160 /* free all the memory allocated so far */
161 for (j=0; j<i ; j++) {
162 for (k=3; k<17; k++) {
163 if (sel_oem_msg[j].value[SEL_BYTE(k)] == -3) {
164 free(sel_oem_msg[j].string[SEL_BYTE(k)]);
165 sel_oem_msg[j].string[SEL_BYTE(k)] = NULL;
166 }
167 }
168 }
169 free(sel_oem_msg);
170 sel_oem_msg = NULL;
171 return -1;
172 }
173
174 for (byte = 3; byte < 17; byte++) {
175 if ((sel_oem_msg[i].value[SEL_BYTE(byte)] =
176 ipmi_sel_oem_readval(buf[SEL_BYTE(byte)])) == -3) {
177 sel_oem_msg[i].string[SEL_BYTE(byte)] =
178 (char *)malloc(strlen(buf[SEL_BYTE(byte)]) + 1);
179 strcpy(sel_oem_msg[i].string[SEL_BYTE(byte)],
180 buf[SEL_BYTE(byte)]);
181 }
182 }
183 sel_oem_msg[i].text = (char *)malloc(strlen(buf[SEL_BYTE(17)]) + 1);
184 strcpy(sel_oem_msg[i].text, buf[SEL_BYTE(17)]);
185 }
186
187 fclose(fp);
188 fp = NULL;
189 return 0;
190 }
191
ipmi_sel_oem_message(struct sel_event_record * evt,int verbose)192 static void ipmi_sel_oem_message(struct sel_event_record * evt, int verbose)
193 {
194 /*
195 * Note: although we have a verbose argument, currently the output
196 * isn't affected by it.
197 */
198 int i, j;
199
200 for (i=0; i < sel_oem_nrecs; i++) {
201 if (ipmi_sel_oem_match((uint8_t *)evt, &sel_oem_msg[i])) {
202 printf (csv_output ? ",\"%s\"" : " | %s", sel_oem_msg[i].text);
203 for (j=4; j<17; j++) {
204 if (sel_oem_msg[i].value[SEL_BYTE(j)] == -3) {
205 printf (csv_output ? ",%s=0x%x" : " %s = 0x%x",
206 sel_oem_msg[i].string[SEL_BYTE(j)],
207 ((uint8_t *)evt)[SEL_BYTE(j)]);
208 }
209 }
210 }
211 }
212 }
213
214 static const struct valstr event_dir_vals[] = {
215 { 0, "Assertion Event" },
216 { 1, "Deassertion Event" },
217 { 0, NULL },
218 };
219
220 static const char *
ipmi_get_event_type(uint8_t code)221 ipmi_get_event_type(uint8_t code)
222 {
223 if (code == 0)
224 return "Unspecified";
225 if (code == 1)
226 return "Threshold";
227 if (code >= 0x02 && code <= 0x0b)
228 return "Generic Discrete";
229 if (code == 0x6f)
230 return "Sensor-specific Discrete";
231 if (code >= 0x70 && code <= 0x7f)
232 return "OEM";
233 return "Reserved";
234 }
235
236 static char *
ipmi_sel_timestamp(uint32_t stamp)237 ipmi_sel_timestamp(uint32_t stamp)
238 {
239 static char tbuf[40];
240 time_t s = (time_t)stamp;
241 memset(tbuf, 0, 40);
242 strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", gmtime(&s));
243 return tbuf;
244 }
245
246 static char *
ipmi_sel_timestamp_date(uint32_t stamp)247 ipmi_sel_timestamp_date(uint32_t stamp)
248 {
249 static char tbuf[11];
250 time_t s = (time_t)stamp;
251 strftime(tbuf, sizeof(tbuf), "%m/%d/%Y", gmtime(&s));
252 return tbuf;
253 }
254
255 static char *
ipmi_sel_timestamp_time(uint32_t stamp)256 ipmi_sel_timestamp_time(uint32_t stamp)
257 {
258 static char tbuf[9];
259 time_t s = (time_t)stamp;
260 strftime(tbuf, sizeof(tbuf), "%H:%M:%S", gmtime(&s));
261 return tbuf;
262 }
263
264 static char *
hex2ascii(uint8_t * hexChars,uint8_t numBytes)265 hex2ascii (uint8_t * hexChars, uint8_t numBytes)
266 {
267 int count;
268 static char hexString[SEL_OEM_NOTS_DATA_LEN+1]; /*Max Size*/
269
270 if(numBytes > SEL_OEM_NOTS_DATA_LEN)
271 numBytes = SEL_OEM_NOTS_DATA_LEN;
272
273 for(count=0;count < numBytes;count++)
274 {
275 if((hexChars[count]<0x40)||(hexChars[count]>0x7e))
276 hexString[count]='.';
277 else
278 hexString[count]=hexChars[count];
279 }
280 hexString[numBytes]='\0';
281 return hexString;
282 }
283
284 IPMI_OEM
ipmi_get_oem(struct ipmi_intf * intf)285 ipmi_get_oem(struct ipmi_intf * intf)
286 {
287 /* Execute a Get Device ID command to determine the OEM */
288 struct ipmi_rs * rsp;
289 struct ipmi_rq req;
290 struct ipm_devid_rsp *devid;
291
292 if (intf->fd == 0) {
293 if( sel_iana != IPMI_OEM_UNKNOWN ){
294 return sel_iana;
295 }
296 return IPMI_OEM_UNKNOWN;
297 }
298
299 /*
300 * Return the cached manufacturer id if the device is open and
301 * we got an identified OEM owner. Otherwise just attempt to read
302 * it.
303 */
304 if (intf->opened && intf->manufacturer_id != IPMI_OEM_UNKNOWN) {
305 return intf->manufacturer_id;
306 }
307
308 memset(&req, 0, sizeof(req));
309 req.msg.netfn = IPMI_NETFN_APP;
310 req.msg.cmd = BMC_GET_DEVICE_ID;
311 req.msg.data_len = 0;
312
313 rsp = intf->sendrecv(intf, &req);
314 if (rsp == NULL) {
315 lprintf(LOG_ERR, "Get Device ID command failed");
316 return IPMI_OEM_UNKNOWN;
317 }
318 if (rsp->ccode > 0) {
319 lprintf(LOG_ERR, "Get Device ID command failed: %#x %s",
320 rsp->ccode, val2str(rsp->ccode, completion_code_vals));
321 return IPMI_OEM_UNKNOWN;
322 }
323
324 devid = (struct ipm_devid_rsp *) rsp->data;
325
326 lprintf(LOG_DEBUG,"Iana: %u",
327 IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id));
328
329 return IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id);
330 }
331
332 static int
ipmi_sel_add_entry(struct ipmi_intf * intf,struct sel_event_record * rec)333 ipmi_sel_add_entry(struct ipmi_intf * intf, struct sel_event_record * rec)
334 {
335 struct ipmi_rs * rsp;
336 struct ipmi_rq req;
337
338 memset(&req, 0, sizeof(req));
339 req.msg.netfn = IPMI_NETFN_STORAGE;
340 req.msg.cmd = IPMI_CMD_ADD_SEL_ENTRY;
341 req.msg.data = (unsigned char *)rec;
342 req.msg.data_len = 16;
343
344 ipmi_sel_print_std_entry(intf, rec);
345
346 rsp = intf->sendrecv(intf, &req);
347 if (rsp == NULL) {
348 lprintf(LOG_ERR, "Add SEL Entry failed");
349 return -1;
350 }
351 else if (rsp->ccode > 0) {
352 lprintf(LOG_ERR, "Add SEL Entry failed: %s",
353 val2str(rsp->ccode, completion_code_vals));
354 return -1;
355 }
356
357 return 0;
358 }
359
360
361 static int
ipmi_sel_add_entries_fromfile(struct ipmi_intf * intf,const char * filename)362 ipmi_sel_add_entries_fromfile(struct ipmi_intf * intf, const char * filename)
363 {
364 FILE * fp;
365 char buf[1024];
366 char * ptr, * tok;
367 int i, j;
368 int rc = 0;
369 uint8_t rqdata[8];
370 struct sel_event_record sel_event;
371
372 if (filename == NULL)
373 return -1;
374
375 fp = ipmi_open_file_read(filename);
376 if (fp == NULL)
377 return -1;
378
379 while (feof(fp) == 0) {
380 if (fgets(buf, 1024, fp) == NULL)
381 continue;
382
383 /* clip off optional comment tail indicated by # */
384 ptr = strchr(buf, '#');
385 if (ptr)
386 *ptr = '\0';
387 else
388 ptr = buf + strlen(buf);
389
390 /* clip off trailing and leading whitespace */
391 ptr--;
392 while (isspace((int)*ptr) && ptr >= buf)
393 *ptr-- = '\0';
394 ptr = buf;
395 while (isspace((int)*ptr))
396 ptr++;
397 if (strlen(ptr) == 0)
398 continue;
399
400 /* parse the event, 7 bytes with optional comment */
401 /* 0x00 0x00 0x00 0x00 0x00 0x00 0x00 # event */
402 i = 0;
403 tok = strtok(ptr, " ");
404 while (tok) {
405 if (i == 7)
406 break;
407 j = i++;
408 if (str2uchar(tok, &rqdata[j]) != 0) {
409 break;
410 }
411 tok = strtok(NULL, " ");
412 }
413 if (i < 7) {
414 lprintf(LOG_ERR, "Invalid Event: %s",
415 buf2str(rqdata, sizeof(rqdata)));
416 continue;
417 }
418
419 memset(&sel_event, 0, sizeof(struct sel_event_record));
420 sel_event.record_id = 0x0000;
421 sel_event.record_type = 0x02;
422 sel_event.sel_type.standard_type.gen_id = 0x00;
423 sel_event.sel_type.standard_type.evm_rev = rqdata[0];
424 sel_event.sel_type.standard_type.sensor_type = rqdata[1];
425 sel_event.sel_type.standard_type.sensor_num = rqdata[2];
426 sel_event.sel_type.standard_type.event_type = rqdata[3] & 0x7f;
427 sel_event.sel_type.standard_type.event_dir = (rqdata[3] & 0x80) >> 7;
428 sel_event.sel_type.standard_type.event_data[0] = rqdata[4];
429 sel_event.sel_type.standard_type.event_data[1] = rqdata[5];
430 sel_event.sel_type.standard_type.event_data[2] = rqdata[6];
431
432 rc = ipmi_sel_add_entry(intf, &sel_event);
433 if (rc < 0)
434 break;
435 }
436
437 fclose(fp);
438 return rc;
439 }
440
441 static struct ipmi_event_sensor_types oem_kontron_event_reading_types[] __attribute__((unused)) = {
442 { 0x70 , 0x00 , 0xff, IPMI_EVENT_CLASS_DISCRETE , "OEM Firmware Info 1", "Code Assert" },
443 { 0x71 , 0x00 , 0xff, IPMI_EVENT_CLASS_DISCRETE , "OEM Firmware Info 2", "Code Assert" },
444 };
445
446 char *
get_kontron_evt_desc(struct ipmi_intf * intf,struct sel_event_record * rec)447 get_kontron_evt_desc(struct ipmi_intf * intf, struct sel_event_record * rec)
448 {
449 char * description = NULL;
450 /*
451 * Kontron OEM events are described in the product's user manual, but are limited in favor of
452 * sensor specific
453 */
454
455 /* Only standard records are defined so far */
456 if( rec->record_type < 0xC0 ){
457 struct ipmi_event_sensor_types *st=NULL;
458 for ( st=oem_kontron_event_reading_types ; st->type != NULL; st++){
459 if (st->code == rec->sel_type.standard_type.event_type ){
460 size_t len =strlen(st->desc);
461 description = (char*)malloc( len + 1 );
462 memcpy(description, st->desc , len);
463 description[len] = 0;;
464 return description;
465 }
466 }
467 }
468
469 return NULL;
470 }
471
472 char *
get_newisys_evt_desc(struct ipmi_intf * intf,struct sel_event_record * rec)473 get_newisys_evt_desc(struct ipmi_intf * intf, struct sel_event_record * rec)
474 {
475 /*
476 * Newisys OEM event descriptions can be retrieved through an
477 * OEM IPMI command.
478 */
479 struct ipmi_rs * rsp;
480 struct ipmi_rq req;
481 uint8_t msg_data[6];
482 char * description = NULL;
483
484 memset(&req, 0, sizeof(req));
485 req.msg.netfn = 0x2E;
486 req.msg.cmd = 0x01;
487 req.msg.data_len = sizeof(msg_data);
488
489 msg_data[0] = 0x15; /* IANA LSB */
490 msg_data[1] = 0x24; /* IANA */
491 msg_data[2] = 0x00; /* IANA MSB */
492 msg_data[3] = 0x01; /* Subcommand */
493 msg_data[4] = rec->record_id & 0x00FF; /* SEL Record ID LSB */
494 msg_data[5] = (rec->record_id & 0xFF00) >> 8; /* SEL Record ID MSB */
495
496 req.msg.data = msg_data;
497
498 rsp = intf->sendrecv(intf, &req);
499 if (rsp == NULL) {
500 if (verbose)
501 lprintf(LOG_ERR, "Error issuing OEM command");
502 return NULL;
503 }
504 if (rsp->ccode > 0) {
505 if (verbose)
506 lprintf(LOG_ERR, "OEM command returned error code: %s",
507 val2str(rsp->ccode, completion_code_vals));
508 return NULL;
509 }
510
511 /* Verify our response before we use it */
512 if (rsp->data_len < 5)
513 {
514 lprintf(LOG_ERR, "Newisys OEM response too short");
515 return NULL;
516 }
517 else if (rsp->data_len != (4 + rsp->data[3]))
518 {
519 lprintf(LOG_ERR, "Newisys OEM response has unexpected length");
520 return NULL;
521 }
522 else if (IPM_DEV_MANUFACTURER_ID(rsp->data) != IPMI_OEM_NEWISYS)
523 {
524 lprintf(LOG_ERR, "Newisys OEM response has unexpected length");
525 return NULL;
526 }
527
528 description = (char*)malloc(rsp->data[3] + 1);
529 memcpy(description, rsp->data + 4, rsp->data[3]);
530 description[rsp->data[3]] = 0;;
531
532 return description;
533 }
534
535 char *
get_supermicro_evt_desc(struct ipmi_intf * intf,struct sel_event_record * rec)536 get_supermicro_evt_desc(struct ipmi_intf *intf, struct sel_event_record *rec)
537 {
538 struct ipmi_rs *rsp;
539 struct ipmi_rq req;
540 char *desc = NULL;
541 int chipset_type = 1;
542 int data1;
543 int data2;
544 int data3;
545 int sensor_type;
546 uint8_t i = 0;
547 uint16_t oem_id = 0;
548 /* Get the OEM event Bytes of the SEL Records byte 13, 14, 15 to
549 * data1,data2,data3
550 */
551 data1 = rec->sel_type.standard_type.event_data[0];
552 data2 = rec->sel_type.standard_type.event_data[1];
553 data3 = rec->sel_type.standard_type.event_data[2];
554 /* Check for the Standard Event type == 0x6F */
555 if (rec->sel_type.standard_type.event_type != 0x6F) {
556 return NULL;
557 }
558 /* Allocate mem for te Description string */
559 desc = malloc(sizeof(char) * SIZE_OF_DESC);
560 if (desc == NULL) {
561 lprintf(LOG_ERR, "ipmitool: malloc failure");
562 return NULL;
563 }
564 memset(desc, '\0', SIZE_OF_DESC);
565 sensor_type = rec->sel_type.standard_type.sensor_type;
566 switch (sensor_type) {
567 case SENSOR_TYPE_MEMORY:
568 memset(&req, 0, sizeof (req));
569 req.msg.netfn = IPMI_NETFN_APP;
570 req.msg.lun = 0;
571 req.msg.cmd = BMC_GET_DEVICE_ID;
572 req.msg.data = NULL;
573 req.msg.data_len = 0;
574
575 rsp = intf->sendrecv(intf, &req);
576 if (rsp == NULL) {
577 lprintf(LOG_ERR, " Error getting system info");
578 if (desc != NULL) {
579 free(desc);
580 desc = NULL;
581 }
582 return NULL;
583 } else if (rsp->ccode > 0) {
584 lprintf(LOG_ERR, " Error getting system info: %s",
585 val2str(rsp->ccode, completion_code_vals));
586 if (desc != NULL) {
587 free(desc);
588 desc = NULL;
589 }
590 return NULL;
591 }
592 /* check the chipset type */
593 oem_id = ipmi_get_oem_id(intf);
594 if (oem_id == 0) {
595 if (desc != NULL) {
596 free(desc);
597 desc = NULL;
598 }
599 return NULL;
600 }
601 for (i = 0; supermicro_X8[i] != 0xFFFF; i++) {
602 if (oem_id == supermicro_X8[i]) {
603 chipset_type = 0;
604 break;
605 }
606 }
607 for (i = 0; supermicro_x9[i] != 0xFFFF; i++) {
608 if (oem_id == supermicro_x9[i]) {
609 chipset_type = 2;
610 break;
611 }
612 }
613 if (chipset_type == 0) {
614 snprintf(desc, SIZE_OF_DESC, "@DIMM%2X(CPU%x)",
615 data2,
616 (data3 & 0x03) + 1);
617 } else if (chipset_type == 1) {
618 snprintf(desc, SIZE_OF_DESC, "@DIMM%c%c(CPU%x)",
619 (data2 >> 4) + 0x40 + (data3 & 0x3) * 4,
620 (data2 & 0xf) + 0x27, (data3 & 0x03) + 1);
621 } else if (chipset_type == 2) {
622 snprintf(desc, SIZE_OF_DESC, "@DIMM%c%c(CPU%x)",
623 (data2 >> 4) + 0x40 + (data3 & 0x3) * 3,
624 (data2 & 0xf) + 0x27, (data3 & 0x03) + 1);
625 } else {
626 /* No description. */
627 desc[0] = '\0';
628 }
629 break;
630 case SENSOR_TYPE_SUPERMICRO_OEM:
631 if (data1 == 0x80 && data3 == 0xFF) {
632 if (data2 == 0x0) {
633 snprintf(desc, SIZE_OF_DESC, "BMC unexpected reset");
634 } else if (data2 == 0x1) {
635 snprintf(desc, SIZE_OF_DESC, "BMC cold reset");
636 } else if (data2 == 0x2) {
637 snprintf(desc, SIZE_OF_DESC, "BMC warm reset");
638 }
639 }
640 break;
641 }
642 return desc;
643 }
644
645 /*
646 * Function : Decoding the SEL OEM Bytes for the DELL Platforms.
647 * Description : The below fucntion will decode the SEL Events OEM Bytes for the Dell specific Sensors only.
648 * The below function will append the additional information Strings/description to the normal sel desc.
649 * With this the SEL will display additional information sent via OEM Bytes of the SEL Record.
650 * NOTE : Specific to DELL Platforms only.
651 * Returns : Pointer to the char string.
652 */
get_dell_evt_desc(struct ipmi_intf * intf,struct sel_event_record * rec)653 char * get_dell_evt_desc(struct ipmi_intf * intf, struct sel_event_record * rec)
654 {
655 int data1, data2, data3;
656 int sensor_type;
657 char *desc = NULL;
658
659 unsigned char count;
660 unsigned char node;
661 unsigned char dimmNum;
662 unsigned char dimmsPerNode;
663 char dimmStr[MAX_DIMM_STR];
664 char tmpdesc[SIZE_OF_DESC];
665 char* str;
666 unsigned char incr = 0;
667 unsigned char i=0,j = 0;
668 struct ipmi_rs *rsp;
669 struct ipmi_rq req;
670 char tmpData;
671 int version;
672 /* Get the OEM event Bytes of the SEL Records byte 13, 14, 15 to Data1,data2,data3 */
673 data1 = rec->sel_type.standard_type.event_data[0];
674 data2 = rec->sel_type.standard_type.event_data[1];
675 data3 = rec->sel_type.standard_type.event_data[2];
676 /* Check for the Standard Event type == 0x6F */
677 if (0x6F == rec->sel_type.standard_type.event_type)
678 {
679 sensor_type = rec->sel_type.standard_type.sensor_type;
680 /* Allocate mem for te Description string */
681 desc = (char*)malloc(SIZE_OF_DESC);
682 if(NULL == desc)
683 return NULL;
684 memset(desc,0,SIZE_OF_DESC);
685 memset(tmpdesc,0,SIZE_OF_DESC);
686 switch (sensor_type) {
687 case SENSOR_TYPE_PROCESSOR: /* Processor/CPU related OEM Sel Byte Decoding for DELL Platforms only */
688 if((OEM_CODE_IN_BYTE2 == (data1 & DATA_BYTE2_SPECIFIED_MASK)))
689 {
690 if(0x00 == (data1 & MASK_LOWER_NIBBLE))
691 snprintf(desc,SIZE_OF_DESC,"CPU Internal Err | ");
692 if(0x06 == (data1 & MASK_LOWER_NIBBLE))
693 {
694 snprintf(desc,SIZE_OF_DESC,"CPU Protocol Err | ");
695
696 }
697
698 /* change bit location to a number */
699 for (count= 0; count < 8; count++)
700 {
701 if (BIT(count)& data2)
702 {
703 count++;
704 /* 0x0A - CPU sensor number */
705 if((0x06 == (data1 & MASK_LOWER_NIBBLE)) && (0x0A == rec->sel_type.standard_type.sensor_num))
706 snprintf(desc,SIZE_OF_DESC,"FSB %d ",count); // Which CPU Has generated the FSB
707 else
708 snprintf(desc,SIZE_OF_DESC,"CPU %d | APIC ID %d ",count,data3); /* Specific CPU related info */
709 break;
710 }
711 }
712 }
713 break;
714 case SENSOR_TYPE_MEMORY: /* Memory or DIMM related OEM Sel Byte Decoding for DELL Platforms only */
715 case SENSOR_TYPE_EVT_LOG: /* Events Logging for Memory or DIMM related OEM Sel Byte Decoding for DELL Platforms only */
716
717 /* Get the current version of the IPMI Spec Based on that Decoding of memory info is done.*/
718 memset(&req, 0, sizeof (req));
719 req.msg.netfn = IPMI_NETFN_APP;
720 req.msg.lun = 0;
721 req.msg.cmd = BMC_GET_DEVICE_ID;
722 req.msg.data = NULL;
723 req.msg.data_len = 0;
724
725 rsp = intf->sendrecv(intf, &req);
726 if (NULL == rsp)
727 {
728 lprintf(LOG_ERR, " Error getting system info");
729 if (desc != NULL) {
730 free(desc);
731 desc = NULL;
732 }
733 return NULL;
734 }
735 else if (rsp->ccode > 0)
736 {
737 lprintf(LOG_ERR, " Error getting system info: %s",
738 val2str(rsp->ccode, completion_code_vals));
739 if (desc != NULL) {
740 free(desc);
741 desc = NULL;
742 }
743 return NULL;
744 }
745 version = rsp->data[4];
746 /* Memory DIMMS */
747 if( (data1 & OEM_CODE_IN_BYTE2) || (data1 & OEM_CODE_IN_BYTE3 ) )
748 {
749 /* Memory Redundancy related oem bytes docoding .. */
750 if( (SENSOR_TYPE_MEMORY == sensor_type) && (0x0B == rec->sel_type.standard_type.event_type) )
751 {
752 if(0x00 == (data1 & MASK_LOWER_NIBBLE))
753 {
754 snprintf(desc,SIZE_OF_DESC," Redundancy Regained | ");
755 }
756 else if(0x01 == (data1 & MASK_LOWER_NIBBLE))
757 {
758 snprintf(desc,SIZE_OF_DESC,"Redundancy Lost | ");
759 }
760 } /* Correctable and uncorrectable ECC Error Decoding */
761 else if(SENSOR_TYPE_MEMORY == sensor_type)
762 {
763 if(0x00 == (data1 & MASK_LOWER_NIBBLE))
764 {
765 /* 0x1C - Memory Sensor Number */
766 if(0x1C == rec->sel_type.standard_type.sensor_num)
767 {
768 /*Add the complete information about the Memory Configs.*/
769 if((data1 & OEM_CODE_IN_BYTE2) && (data1 & OEM_CODE_IN_BYTE3 ))
770 {
771 count = 0;
772 snprintf(desc,SIZE_OF_DESC,"CRC Error on:");
773 for(i=0;i<4;i++)
774 {
775 if((BIT(i))&(data2))
776 {
777 if(count)
778 {
779 str = desc+strlen(desc);
780 *str++ = ',';
781 str = '\0';
782 count = 0;
783 }
784 switch(i) /* Which type of memory config is present.. */
785 {
786 case 0: snprintf(tmpdesc,SIZE_OF_DESC,"South Bound Memory");
787 strcat(desc,tmpdesc);
788 count++;
789 break;
790 case 1: snprintf(tmpdesc,SIZE_OF_DESC,"South Bound Config");
791 strcat(desc,tmpdesc);
792 count++;
793 break;
794 case 2: snprintf(tmpdesc,SIZE_OF_DESC,"North Bound memory");
795 strcat(desc,tmpdesc);
796 count++;
797 break;
798 case 3: snprintf(tmpdesc,SIZE_OF_DESC,"North Bound memory-corr");
799 strcat(desc,tmpdesc);
800 count++;
801 break;
802 default:
803 break;
804 }
805 }
806 }
807 if(data3>=0x00 && data3<0xFF)
808 {
809 snprintf(tmpdesc,SIZE_OF_DESC,"|Failing_Channel:%d",data3);
810 strcat(desc,tmpdesc);
811 }
812 }
813 break;
814 }
815 snprintf(desc,SIZE_OF_DESC,"Correctable ECC | ");
816 }
817 else if(0x01 == (data1 & MASK_LOWER_NIBBLE))
818 {
819 snprintf(desc,SIZE_OF_DESC,"UnCorrectable ECC | ");
820 }
821 } /* Corr Memory log disabled */
822 else if(SENSOR_TYPE_EVT_LOG == sensor_type)
823 {
824 if(0x00 == (data1 & MASK_LOWER_NIBBLE))
825 snprintf(desc,SIZE_OF_DESC,"Corr Memory Log Disabled | ");
826 }
827 }
828 else
829 {
830 if(SENSOR_TYPE_SYS_EVENT == sensor_type)
831 {
832 if(0x02 == (data1 & MASK_LOWER_NIBBLE))
833 snprintf(desc,SIZE_OF_DESC,"Unknown System Hardware Failure ");
834 }
835 if(SENSOR_TYPE_EVT_LOG == sensor_type)
836 {
837 if(0x03 == (data1 & MASK_LOWER_NIBBLE))
838 snprintf(desc,SIZE_OF_DESC,"All Even Logging Dissabled");
839 }
840 }
841 /*
842 * Based on the above error, we need to find whcih memory slot or
843 * Card has got the Errors/Sel Generated.
844 */
845 if(data1 & OEM_CODE_IN_BYTE2 )
846 {
847 /* Find the Card Type */
848 if((0x0F != (data2 >> 4)) && ((data2 >> 4) < 0x08))
849 {
850 tmpData = ('A'+ (data2 >> 4));
851 if( (SENSOR_TYPE_MEMORY == sensor_type) && (0x0B == rec->sel_type.standard_type.event_type) )
852 {
853 snprintf(tmpdesc, SIZE_OF_DESC, "Bad Card %c", tmpData);
854 }
855 else
856 {
857 snprintf(tmpdesc, SIZE_OF_DESC, "Card %c", tmpData);
858 }
859 strcat(desc, tmpdesc);
860 } /* Find the Bank Number of the DIMM */
861 if (0x0F != (data2 & MASK_LOWER_NIBBLE))
862 {
863 if(0x51 == version)
864 {
865 snprintf(tmpdesc, SIZE_OF_DESC, "Bank %d", ((data2 & 0x0F)+1));
866 strcat(desc, tmpdesc);
867 }
868 else
869 {
870 incr = (data2 & 0x0f) << 3;
871 }
872 }
873
874 }
875 /* Find the DIMM Number of the Memory which has Generated the Fault or Sel */
876 if(data1 & OEM_CODE_IN_BYTE3 )
877 {
878 // Based on the IPMI Spec Need Identify the DIMM Details.
879 // For the SPEC 1.5 Only the DIMM Number is Valid.
880 if(0x51 == version)
881 {
882 snprintf(tmpdesc, SIZE_OF_DESC, "DIMM %c", ('A'+ data3));
883 strcat(desc, tmpdesc);
884 }
885 /* For the SPEC 2.0 Decode the DIMM Number as it supports more.*/
886 else if( ((data2 >> 4) > 0x07) && (0x0F != (data2 >> 4) ))
887 {
888 strcpy(dimmStr, " DIMM");
889 str = desc+strlen(desc);
890 dimmsPerNode = 4;
891 if(0x09 == (data2 >> 4)) dimmsPerNode = 6;
892 else if(0x0A == (data2 >> 4)) dimmsPerNode = 8;
893 else if(0x0B == (data2 >> 4)) dimmsPerNode = 9;
894 else if(0x0C == (data2 >> 4)) dimmsPerNode = 12;
895 else if(0x0D == (data2 >> 4)) dimmsPerNode = 24;
896 else if(0x0E == (data2 >> 4)) dimmsPerNode = 3;
897 count = 0;
898 for (i = 0; i < 8; i++)
899 {
900 if (BIT(i) & data3)
901 {
902 if(count)
903 {
904 strcat(str,",");
905 count = 0x00;
906 }
907 node = (incr + i)/dimmsPerNode;
908 dimmNum = ((incr + i)%dimmsPerNode)+1;
909 dimmStr[5] = node + 'A';
910 sprintf(tmpdesc,"%d",dimmNum);
911 for(j = 0; j < strlen(tmpdesc);j++)
912 dimmStr[6+j] = tmpdesc[j];
913 dimmStr[6+j] = '\0';
914 strcat(str,dimmStr); // final DIMM Details.
915 count++;
916 }
917 }
918 }
919 else
920 {
921 strcpy(dimmStr, " DIMM");
922 str = desc+strlen(desc);
923 count = 0;
924 for (i = 0; i < 8; i++)
925 {
926 if (BIT(i) & data3)
927 {
928 // check if more than one DIMM, if so add a comma to the string.
929 sprintf(tmpdesc,"%d",(i + incr + 1));
930 if(count)
931 {
932 strcat(str,",");
933 count = 0x00;
934 }
935 for(j = 0; j < strlen(tmpdesc);j++)
936 dimmStr[5+j] = tmpdesc[j];
937 dimmStr[5+j] = '\0';
938 strcat(str, dimmStr);
939 count++;
940 }
941 }
942 }
943 }
944 break;
945 /* Sensor In system charectorization Error Decoding.
946 Sensor type 0x20*/
947 case SENSOR_TYPE_TXT_CMD_ERROR:
948 if((0x00 == (data1 & MASK_LOWER_NIBBLE))&&((data1 & OEM_CODE_IN_BYTE2) && (data1 & OEM_CODE_IN_BYTE3)))
949 {
950 switch(data3)
951 {
952 case 0x01:
953 snprintf(desc,SIZE_OF_DESC,"BIOS TXT Error");
954 break;
955 case 0x02:
956 snprintf(desc,SIZE_OF_DESC,"Processor/FIT TXT");
957 break;
958 case 0x03:
959 snprintf(desc,SIZE_OF_DESC,"BIOS ACM TXT Error");
960 break;
961 case 0x04:
962 snprintf(desc,SIZE_OF_DESC,"SINIT ACM TXT Error");
963 break;
964 case 0xff:
965 snprintf(desc,SIZE_OF_DESC,"Unrecognized TT Error12");
966 break;
967 default:
968 break;
969 }
970 }
971 break;
972 /* OS Watch Dog Timer Sel Events */
973 case SENSOR_TYPE_WTDOG:
974
975 if(SENSOR_TYPE_OEM_SEC_EVENT == data1)
976 {
977 if(0x04 == data2)
978 {
979 snprintf(desc,SIZE_OF_DESC,"Hard Reset|Interrupt type None,SMS/OS Timer used at expiration");
980 }
981 }
982
983 break;
984 /* This Event is for BMC to Othe Hardware or CPU . */
985 case SENSOR_TYPE_VER_CHANGE:
986 if((0x02 == (data1 & MASK_LOWER_NIBBLE))&&((data1 & OEM_CODE_IN_BYTE2) && (data1 & OEM_CODE_IN_BYTE3)))
987 {
988 if(0x02 == data2)
989 {
990 if(0x00 == data3)
991 {
992 snprintf(desc, SIZE_OF_DESC, "between BMC/iDRAC Firmware and other hardware");
993 }
994 else if(0x01 == data3)
995 {
996 snprintf(desc, SIZE_OF_DESC, "between BMC/iDRAC Firmware and CPU");
997 }
998 }
999 }
1000 break;
1001 /* Flex or Mac tuning OEM Decoding for the DELL. */
1002 case SENSOR_TYPE_OEM_SEC_EVENT:
1003 /* 0x25 - Virtual MAC sensory number - Dell OEM */
1004 if(0x25 == rec->sel_type.standard_type.sensor_num)
1005 {
1006 if(0x01 == (data1 & MASK_LOWER_NIBBLE))
1007 {
1008 snprintf(desc, SIZE_OF_DESC, "Failed to program Virtual Mac Address");
1009 if((data1 & OEM_CODE_IN_BYTE2)&&(data1 & OEM_CODE_IN_BYTE3))
1010 {
1011 snprintf(tmpdesc, SIZE_OF_DESC, " at bus:%.2x device:%.2x function:%x",
1012 data3 &0x7F, (data2 >> 3) & 0x1F,
1013 data2 & 0x07);
1014 strcat(desc,tmpdesc);
1015 }
1016 }
1017 else if(0x02 == (data1 & MASK_LOWER_NIBBLE))
1018 {
1019 snprintf(desc, SIZE_OF_DESC, "Device option ROM failed to support link tuning or flex address");
1020 }
1021 else if(0x03 == (data1 & MASK_LOWER_NIBBLE))
1022 {
1023 snprintf(desc, SIZE_OF_DESC, "Failed to get link tuning or flex address data from BMC/iDRAC");
1024 }
1025 }
1026 break;
1027 case SENSOR_TYPE_CRIT_INTR:
1028 case SENSOR_TYPE_OEM_NFATAL_ERROR: /* Non - Fatal PCIe Express Error Decoding */
1029 case SENSOR_TYPE_OEM_FATAL_ERROR: /* Fatal IO Error Decoding */
1030 /* 0x29 - QPI Linx Error Sensor Dell OEM */
1031 if(0x29 == rec->sel_type.standard_type.sensor_num)
1032 {
1033 if((0x02 == (data1 & MASK_LOWER_NIBBLE))&&((data1 & OEM_CODE_IN_BYTE2) && (data1 & OEM_CODE_IN_BYTE3)))
1034 {
1035 snprintf(tmpdesc, SIZE_OF_DESC, "Partner-(LinkId:%d,AgentId:%d)|",(data2 & 0xC0),(data2 & 0x30));
1036 strcat(desc,tmpdesc);
1037 snprintf(tmpdesc, SIZE_OF_DESC, "ReportingAgent(LinkId:%d,AgentId:%d)|",(data2 & 0x0C),(data2 & 0x03));
1038 strcat(desc,tmpdesc);
1039 if(0x00 == (data3 & 0xFC))
1040 {
1041 snprintf(tmpdesc, SIZE_OF_DESC, "LinkWidthDegraded|");
1042 strcat(desc,tmpdesc);
1043 }
1044 if(BIT(1)& data3)
1045 {
1046 snprintf(tmpdesc,SIZE_OF_DESC,"PA_Type:IOH|");
1047 }
1048 else
1049 {
1050 snprintf(tmpdesc,SIZE_OF_DESC,"PA-Type:CPU|");
1051 }
1052 strcat(desc,tmpdesc);
1053 if(BIT(0)& data3)
1054 {
1055 snprintf(tmpdesc,SIZE_OF_DESC,"RA-Type:IOH");
1056 }
1057 else
1058 {
1059 snprintf(tmpdesc,SIZE_OF_DESC,"RA-Type:CPU");
1060 }
1061 strcat(desc,tmpdesc);
1062 }
1063 }
1064 else
1065 {
1066
1067 if(0x02 == (data1 & MASK_LOWER_NIBBLE))
1068 {
1069 sprintf(desc,"%s","IO channel Check NMI");
1070 }
1071 else
1072 {
1073 if(0x00 == (data1 & MASK_LOWER_NIBBLE))
1074 {
1075 snprintf(desc, SIZE_OF_DESC, "%s","PCIe Error |");
1076 }
1077 else if(0x01 == (data1 & MASK_LOWER_NIBBLE))
1078 {
1079 snprintf(desc, SIZE_OF_DESC, "%s","I/O Error |");
1080 }
1081 else if(0x04 == (data1 & MASK_LOWER_NIBBLE))
1082 {
1083 snprintf(desc, SIZE_OF_DESC, "%s","PCI PERR |");
1084 }
1085 else if(0x05 == (data1 & MASK_LOWER_NIBBLE))
1086 {
1087 snprintf(desc, SIZE_OF_DESC, "%s","PCI SERR |");
1088 }
1089 else
1090 {
1091 snprintf(desc, SIZE_OF_DESC, "%s"," ");
1092 }
1093 if (data3 & 0x80)
1094 snprintf(tmpdesc, SIZE_OF_DESC, "Slot %d", data3 & 0x7F);
1095 else
1096 snprintf(tmpdesc, SIZE_OF_DESC, "PCI bus:%.2x device:%.2x function:%x",
1097 data3 &0x7F, (data2 >> 3) & 0x1F,
1098 data2 & 0x07);
1099
1100 strcat(desc,tmpdesc);
1101 }
1102 }
1103 break;
1104 /* POST Fatal Errors generated from the Server with much more info*/
1105 case SENSOR_TYPE_FRM_PROG:
1106 if((0x0F == (data1 & MASK_LOWER_NIBBLE))&&(data1 & OEM_CODE_IN_BYTE2))
1107 {
1108 switch(data2)
1109 {
1110 case 0x80:
1111 snprintf(desc, SIZE_OF_DESC, "No memory is detected.");break;
1112 case 0x81:
1113 snprintf(desc,SIZE_OF_DESC, "Memory is detected but is not configurable.");break;
1114 case 0x82:
1115 snprintf(desc, SIZE_OF_DESC, "Memory is configured but not usable.");break;
1116 case 0x83:
1117 snprintf(desc, SIZE_OF_DESC, "System BIOS shadow failed.");break;
1118 case 0x84:
1119 snprintf(desc, SIZE_OF_DESC, "CMOS failed.");break;
1120 case 0x85:
1121 snprintf(desc, SIZE_OF_DESC, "DMA controller failed.");break;
1122 case 0x86:
1123 snprintf(desc, SIZE_OF_DESC, "Interrupt controller failed.");break;
1124 case 0x87:
1125 snprintf(desc, SIZE_OF_DESC, "Timer refresh failed.");break;
1126 case 0x88:
1127 snprintf(desc, SIZE_OF_DESC, "Programmable interval timer error.");break;
1128 case 0x89:
1129 snprintf(desc, SIZE_OF_DESC, "Parity error.");break;
1130 case 0x8A:
1131 snprintf(desc, SIZE_OF_DESC, "SIO failed.");break;
1132 case 0x8B:
1133 snprintf(desc, SIZE_OF_DESC, "Keyboard controller failed.");break;
1134 case 0x8C:
1135 snprintf(desc, SIZE_OF_DESC, "System management interrupt initialization failed.");break;
1136 case 0x8D:
1137 snprintf(desc, SIZE_OF_DESC, "TXT-SX Error.");break;
1138 case 0xC0:
1139 snprintf(desc, SIZE_OF_DESC, "Shutdown test failed.");break;
1140 case 0xC1:
1141 snprintf(desc, SIZE_OF_DESC, "BIOS POST memory test failed.");break;
1142 case 0xC2:
1143 snprintf(desc, SIZE_OF_DESC, "RAC configuration failed.");break;
1144 case 0xC3:
1145 snprintf(desc, SIZE_OF_DESC, "CPU configuration failed.");break;
1146 case 0xC4:
1147 snprintf(desc, SIZE_OF_DESC, "Incorrect memory configuration.");break;
1148 case 0xFE:
1149 snprintf(desc, SIZE_OF_DESC, "General failure after video.");
1150 break;
1151 }
1152 }
1153 break;
1154
1155 default:
1156 break;
1157 }
1158 }
1159 else
1160 {
1161 sensor_type = rec->sel_type.standard_type.event_type;
1162 }
1163 return desc;
1164 }
1165
1166 char *
ipmi_get_oem_desc(struct ipmi_intf * intf,struct sel_event_record * rec)1167 ipmi_get_oem_desc(struct ipmi_intf * intf, struct sel_event_record * rec)
1168 {
1169 char * desc = NULL;
1170
1171 switch (ipmi_get_oem(intf))
1172 {
1173 case IPMI_OEM_NEWISYS:
1174 desc = get_newisys_evt_desc(intf, rec);
1175 break;
1176 case IPMI_OEM_KONTRON:
1177 desc = get_kontron_evt_desc(intf, rec);
1178 break;
1179 case IPMI_OEM_DELL: // Dell Decoding of the OEM Bytes from SEL Record.
1180 desc = get_dell_evt_desc(intf, rec);
1181 break;
1182 case IPMI_OEM_SUPERMICRO:
1183 case IPMI_OEM_SUPERMICRO_47488:
1184 desc = get_supermicro_evt_desc(intf, rec);
1185 break;
1186 case IPMI_OEM_UNKNOWN:
1187 default:
1188 break;
1189 }
1190
1191 return desc;
1192 }
1193
1194
1195 void
ipmi_get_event_desc(struct ipmi_intf * intf,struct sel_event_record * rec,char ** desc)1196 ipmi_get_event_desc(struct ipmi_intf * intf, struct sel_event_record * rec, char ** desc)
1197 {
1198 uint8_t code, offset;
1199 struct ipmi_event_sensor_types *evt = NULL;
1200 char *sfx = NULL; /* This will be assigned if the Platform is DELL,
1201 additional info is appended to the current Description */
1202
1203 if (desc == NULL)
1204 return;
1205 *desc = NULL;
1206
1207 if ((rec->sel_type.standard_type.event_type >= 0x70) && (rec->sel_type.standard_type.event_type < 0x7F)) {
1208 *desc = ipmi_get_oem_desc(intf, rec);
1209 return;
1210 } else if (rec->sel_type.standard_type.event_type == 0x6f) {
1211 if( rec->sel_type.standard_type.sensor_type >= 0xC0 && rec->sel_type.standard_type.sensor_type < 0xF0) {
1212 IPMI_OEM iana = ipmi_get_oem(intf);
1213
1214 switch(iana){
1215 case IPMI_OEM_KONTRON:
1216 lprintf(LOG_DEBUG, "oem sensor type %x %d using oem type supplied description",
1217 rec->sel_type.standard_type.sensor_type , iana);
1218
1219 evt = oem_kontron_event_types;
1220 code = rec->sel_type.standard_type.sensor_type;
1221 break;
1222 case IPMI_OEM_DELL: /* OEM Bytes Decoding for DELLi */
1223 evt = sensor_specific_types;
1224 code = rec->sel_type.standard_type.sensor_type;
1225 if ( (OEM_CODE_IN_BYTE2 == (rec->sel_type.standard_type.event_data[0] & DATA_BYTE2_SPECIFIED_MASK)) ||
1226 (OEM_CODE_IN_BYTE3 == (rec->sel_type.standard_type.event_data[0] & DATA_BYTE3_SPECIFIED_MASK)) )
1227 {
1228 if(rec->sel_type.standard_type.event_data[0] & DATA_BYTE2_SPECIFIED_MASK)
1229 evt->data = rec->sel_type.standard_type.event_data[1];
1230
1231 sfx = ipmi_get_oem_desc(intf, rec);
1232 }
1233 break;
1234 case IPMI_OEM_SUPERMICRO:
1235 case IPMI_OEM_SUPERMICRO_47488:
1236 evt = sensor_specific_types;
1237 code = rec->sel_type.standard_type.sensor_type;
1238 sfx = ipmi_get_oem_desc(intf, rec);
1239 break;
1240 /* add your oem sensor assignation here */
1241 default:
1242 break;
1243 }
1244 if( evt == NULL ){
1245 lprintf(LOG_DEBUG, "oem sensor type %x using standard type supplied description",
1246 rec->sel_type.standard_type.sensor_type );
1247 }
1248 } else {
1249 switch (ipmi_get_oem(intf)) {
1250 case IPMI_OEM_SUPERMICRO:
1251 case IPMI_OEM_SUPERMICRO_47488:
1252 evt = sensor_specific_types;
1253 code = rec->sel_type.standard_type.sensor_type;
1254 sfx = ipmi_get_oem_desc(intf, rec);
1255 break;
1256 default:
1257 break;
1258 }
1259 }
1260 if( evt == NULL ){
1261 evt = sensor_specific_types;
1262 code = rec->sel_type.standard_type.sensor_type;
1263 }
1264 /*
1265 * Check for the OEM DELL Interface based on the Dell Specific Vendor Code.
1266 * If its Dell Platform, do the OEM Byte decode from the SEL Records.
1267 * Additional information should be written by the ipmi_get_oem_desc()
1268 */
1269 if(ipmi_get_oem(intf) == IPMI_OEM_DELL) {
1270 code = rec->sel_type.standard_type.sensor_type;
1271 if ( (OEM_CODE_IN_BYTE2 == (rec->sel_type.standard_type.event_data[0] & DATA_BYTE2_SPECIFIED_MASK)) ||
1272 (OEM_CODE_IN_BYTE3 == (rec->sel_type.standard_type.event_data[0] & DATA_BYTE3_SPECIFIED_MASK)) )
1273 {
1274 if(rec->sel_type.standard_type.event_data[0] & DATA_BYTE2_SPECIFIED_MASK)
1275 evt->data = rec->sel_type.standard_type.event_data[1];
1276 sfx = ipmi_get_oem_desc(intf, rec);
1277
1278 }
1279 else if(SENSOR_TYPE_OEM_SEC_EVENT == rec->sel_type.standard_type.event_data[0])
1280 {
1281 /* 0x23 : Sensor Number.*/
1282 if(0x23 == rec->sel_type.standard_type.sensor_num)
1283 {
1284 evt->data = rec->sel_type.standard_type.event_data[1];
1285 sfx = ipmi_get_oem_desc(intf, rec);
1286 }
1287 }
1288 }
1289 } else {
1290 evt = generic_event_types;
1291 code = rec->sel_type.standard_type.event_type;
1292 }
1293
1294 offset = rec->sel_type.standard_type.event_data[0] & 0xf;
1295
1296 while (evt->type) {
1297 if ((evt->code == code && evt->offset == offset && evt->desc != NULL) &&
1298 ((evt->data == ALL_OFFSETS_SPECIFIED) ||
1299 ((rec->sel_type.standard_type.event_data[0] & DATA_BYTE2_SPECIFIED_MASK) &&
1300 (evt->data == rec->sel_type.standard_type.event_data[1]))))
1301 {
1302 /* Increase the Malloc size to current_size + Dellspecific description size */
1303 *desc = (char *)malloc(strlen(evt->desc) + 48 + SIZE_OF_DESC);
1304 if (NULL == *desc) {
1305 lprintf(LOG_ERR, "ipmitool: malloc failure");
1306 return;
1307 }
1308 memset(*desc, 0, strlen(evt->desc)+ 48 + SIZE_OF_DESC);
1309 /*
1310 * Additional info is present for the DELL Platforms.
1311 * Append the same to the evt->desc string.
1312 */
1313 if (sfx) {
1314 sprintf(*desc, "%s (%s)", evt->desc, sfx);
1315 free(sfx);
1316 sfx = NULL;
1317 } else {
1318 sprintf(*desc, "%s", evt->desc);
1319 }
1320 return;
1321 }
1322 evt++;
1323 }
1324 /* The Above while Condition was not met beacouse the below sensor type were Newly defined OEM
1325 Secondary Events. 0xC1, 0xC2, 0xC3. */
1326 if((sfx) && (0x6F == rec->sel_type.standard_type.event_type))
1327 {
1328 uint8_t flag = 0x00;
1329 switch(code)
1330 {
1331 case SENSOR_TYPE_FRM_PROG:
1332 if(0x0F == offset)
1333 flag = 0x01;
1334 break;
1335 case SENSOR_TYPE_OEM_SEC_EVENT:
1336 if((0x01 == offset) || (0x02 == offset) || (0x03 == offset))
1337 flag = 0x01;
1338 break;
1339 case SENSOR_TYPE_OEM_NFATAL_ERROR:
1340 if((0x00 == offset) || (0x02 == offset))
1341 flag = 0x01;
1342 break;
1343 case SENSOR_TYPE_OEM_FATAL_ERROR:
1344 if(0x01 == offset)
1345 flag = 0x01;
1346 break;
1347 case SENSOR_TYPE_SUPERMICRO_OEM:
1348 flag = 0x02;
1349 break;
1350 default:
1351 break;
1352 }
1353 if(flag)
1354 {
1355 *desc = (char *)malloc( 48 + SIZE_OF_DESC);
1356 if (NULL == *desc)
1357 {
1358 lprintf(LOG_ERR, "ipmitool: malloc failure");
1359 return;
1360 }
1361 memset(*desc, 0, 48 + SIZE_OF_DESC);
1362 if (flag == 0x02) {
1363 sprintf(*desc, "%s", sfx);
1364 return;
1365 }
1366 sprintf(*desc, "(%s)",sfx);
1367 }
1368 free(sfx);
1369 sfx = NULL;
1370 }
1371 }
1372
1373
1374 const char *
ipmi_sel_get_oem_sensor_type(IPMI_OEM iana,uint8_t code)1375 ipmi_sel_get_oem_sensor_type(IPMI_OEM iana, uint8_t code)
1376 {
1377 struct ipmi_event_sensor_types *st = NULL;
1378
1379 switch(iana){
1380 case IPMI_OEM_KONTRON:
1381 st = oem_kontron_event_types;
1382 break;
1383 /* add you oem sensor type lookup assignement here */
1384 default:
1385 lprintf(LOG_DEBUG, "ipmitool: missing OEM sensor type for %ul",iana);
1386 break;
1387 }
1388
1389 if( st != NULL )
1390 for (; st->type != NULL; st++)
1391 if (st->code == code)
1392 return st->type;
1393
1394 return ipmi_sel_get_sensor_type(code);
1395 }
1396
1397 const char *
ipmi_sel_get_oem_sensor_type_offset(IPMI_OEM iana,uint8_t code,uint8_t offset)1398 ipmi_sel_get_oem_sensor_type_offset(IPMI_OEM iana, uint8_t code, uint8_t offset)
1399 {
1400 struct ipmi_event_sensor_types *st = NULL;
1401
1402 switch(iana){
1403 case IPMI_OEM_KONTRON:
1404 st = oem_kontron_event_types;
1405 break;
1406 /* add you oem sensor type lookup assignement here */
1407 default:
1408 lprintf(LOG_DEBUG,
1409 "ipmitool: missing OEM sensor type offset for %ul",iana);
1410 break;
1411 }
1412
1413 if( st != NULL )
1414 for (; st->type != NULL; st++)
1415 {
1416 if (st->code == code && st->offset == (offset&0xf))
1417 return st->type;
1418 }
1419
1420 return ipmi_sel_get_oem_sensor_type(iana,code);
1421 }
1422
1423 const char *
ipmi_sel_get_sensor_type(uint8_t code)1424 ipmi_sel_get_sensor_type(uint8_t code)
1425 {
1426 struct ipmi_event_sensor_types *st;
1427 for (st = sensor_specific_types; st->type != NULL; st++)
1428 if (st->code == code)
1429 return st->type;
1430 return "Unknown";
1431 }
1432
1433 const char *
ipmi_sel_get_sensor_type_offset(uint8_t code,uint8_t offset)1434 ipmi_sel_get_sensor_type_offset(uint8_t code, uint8_t offset)
1435 {
1436 struct ipmi_event_sensor_types *st;
1437 for (st = sensor_specific_types; st->type != NULL; st++)
1438 if (st->code == code && st->offset == (offset&0xf))
1439 return st->type;
1440
1441 return ipmi_sel_get_sensor_type(code);
1442 }
1443
1444 static int
ipmi_sel_get_info(struct ipmi_intf * intf)1445 ipmi_sel_get_info(struct ipmi_intf * intf)
1446 {
1447 struct ipmi_rs * rsp;
1448 struct ipmi_rq req;
1449 uint16_t e, version;
1450 uint32_t f;
1451 int pctfull = 0;
1452 uint32_t fs = 0xffffffff;
1453 uint32_t zeros = 0;
1454
1455
1456 memset(&req, 0, sizeof(req));
1457 req.msg.netfn = IPMI_NETFN_STORAGE;
1458 req.msg.cmd = IPMI_CMD_GET_SEL_INFO;
1459
1460 rsp = intf->sendrecv(intf, &req);
1461 if (rsp == NULL) {
1462 lprintf(LOG_ERR, "Get SEL Info command failed");
1463 return -1;
1464 }
1465 if (rsp->ccode > 0) {
1466 lprintf(LOG_ERR, "Get SEL Info command failed: %s",
1467 val2str(rsp->ccode, completion_code_vals));
1468 return -1;
1469 }
1470 if (verbose > 2)
1471 printbuf(rsp->data, rsp->data_len, "sel_info");
1472
1473 printf("SEL Information\n");
1474 version = rsp->data[0];
1475 printf("Version : %d.%d (%s)\n",
1476 version & 0xf, (version>>4) & 0xf,
1477 (version == 0x51 || version == 0x02) ? "v1.5, v2 compliant" : "Unknown");
1478
1479 /* save the entry count and free space to determine percent full */
1480 e = buf2short(rsp->data + 1);
1481 f = buf2short(rsp->data + 3);
1482 printf("Entries : %d\n", e);
1483 printf("Free Space : %d bytes %s\n", f ,(f==65535 ? "or more" : "" ));
1484
1485 if (e) {
1486 e *= 16; /* each entry takes 16 bytes */
1487 f += e; /* this is supposed to give the total size ... */
1488 pctfull = (int)(100 * ( (double)e / (double)f ));
1489 }
1490
1491 if( f >= 65535 ) {
1492 printf("Percent Used : %s\n", "unknown" );
1493 }
1494 else {
1495 printf("Percent Used : %d%%\n", pctfull);
1496 }
1497
1498
1499 if ((!memcmp(rsp->data + 5, &fs, 4)) ||
1500 (!memcmp(rsp->data + 5, &zeros, 4)))
1501 printf("Last Add Time : Not Available\n");
1502 else
1503 printf("Last Add Time : %s\n",
1504 ipmi_sel_timestamp(buf2long(rsp->data + 5)));
1505
1506 if ((!memcmp(rsp->data + 9, &fs, 4)) ||
1507 (!memcmp(rsp->data + 9, &zeros, 4)))
1508 printf("Last Del Time : Not Available\n");
1509 else
1510 printf("Last Del Time : %s\n",
1511 ipmi_sel_timestamp(buf2long(rsp->data + 9)));
1512
1513
1514 printf("Overflow : %s\n",
1515 rsp->data[13] & 0x80 ? "true" : "false");
1516 printf("Supported Cmds : ");
1517 if (rsp->data[13] & 0x0f)
1518 {
1519 if (rsp->data[13] & 0x08)
1520 printf("'Delete' ");
1521 if (rsp->data[13] & 0x04)
1522 printf("'Partial Add' ");
1523 if (rsp->data[13] & 0x02)
1524 printf("'Reserve' ");
1525 if (rsp->data[13] & 0x01)
1526 printf("'Get Alloc Info' ");
1527 }
1528 else
1529 printf("None");
1530 printf("\n");
1531
1532 /* get sel allocation info if supported */
1533 if (rsp->data[13] & 1) {
1534 memset(&req, 0, sizeof(req));
1535 req.msg.netfn = IPMI_NETFN_STORAGE;
1536 req.msg.cmd = IPMI_CMD_GET_SEL_ALLOC_INFO;
1537
1538 rsp = intf->sendrecv(intf, &req);
1539 if (rsp == NULL) {
1540 lprintf(LOG_ERR,
1541 "Get SEL Allocation Info command failed");
1542 return -1;
1543 }
1544 if (rsp->ccode > 0) {
1545 lprintf(LOG_ERR,
1546 "Get SEL Allocation Info command failed: %s",
1547 val2str(rsp->ccode, completion_code_vals));
1548 return -1;
1549 }
1550
1551 printf("# of Alloc Units : %d\n", buf2short(rsp->data));
1552 printf("Alloc Unit Size : %d\n", buf2short(rsp->data + 2));
1553 printf("# Free Units : %d\n", buf2short(rsp->data + 4));
1554 printf("Largest Free Blk : %d\n", buf2short(rsp->data + 6));
1555 printf("Max Record Size : %d\n", rsp->data[8]);
1556 }
1557 return 0;
1558 }
1559
1560 uint16_t
ipmi_sel_get_std_entry(struct ipmi_intf * intf,uint16_t id,struct sel_event_record * evt)1561 ipmi_sel_get_std_entry(struct ipmi_intf * intf, uint16_t id,
1562 struct sel_event_record * evt)
1563 {
1564 struct ipmi_rq req;
1565 struct ipmi_rs * rsp;
1566 uint8_t msg_data[6];
1567 uint16_t next;
1568 int data_count;
1569
1570 memset(msg_data, 0, 6);
1571 msg_data[0] = 0x00; /* no reserve id, not partial get */
1572 msg_data[1] = 0x00;
1573 msg_data[2] = id & 0xff;
1574 msg_data[3] = (id >> 8) & 0xff;
1575 msg_data[4] = 0x00; /* offset */
1576 msg_data[5] = 0xff; /* length */
1577
1578 memset(&req, 0, sizeof(req));
1579 req.msg.netfn = IPMI_NETFN_STORAGE;
1580 req.msg.cmd = IPMI_CMD_GET_SEL_ENTRY;
1581 req.msg.data = msg_data;
1582 req.msg.data_len = 6;
1583
1584 rsp = intf->sendrecv(intf, &req);
1585 if (rsp == NULL) {
1586 lprintf(LOG_ERR, "Get SEL Entry %x command failed", id);
1587 return 0;
1588 }
1589 if (rsp->ccode > 0) {
1590 lprintf(LOG_ERR, "Get SEL Entry %x command failed: %s",
1591 id, val2str(rsp->ccode, completion_code_vals));
1592 return 0;
1593 }
1594
1595 /* save next entry id */
1596 next = (rsp->data[1] << 8) | rsp->data[0];
1597
1598 lprintf(LOG_DEBUG, "SEL Entry: %s", buf2str(rsp->data+2, rsp->data_len-2));
1599 memset(evt, 0, sizeof(*evt));
1600
1601 /*Clear SEL Structure*/
1602 evt->record_id = 0;
1603 evt->record_type = 0;
1604 if (evt->record_type < 0xc0)
1605 {
1606 evt->sel_type.standard_type.timestamp = 0;
1607 evt->sel_type.standard_type.gen_id = 0;
1608 evt->sel_type.standard_type.evm_rev = 0;
1609 evt->sel_type.standard_type.sensor_type = 0;
1610 evt->sel_type.standard_type.sensor_num = 0;
1611 evt->sel_type.standard_type.event_type = 0;
1612 evt->sel_type.standard_type.event_dir = 0;
1613 evt->sel_type.standard_type.event_data[0] = 0;
1614 evt->sel_type.standard_type.event_data[1] = 0;
1615 evt->sel_type.standard_type.event_data[2] = 0;
1616 }
1617 else if (evt->record_type < 0xe0)
1618 {
1619 evt->sel_type.oem_ts_type.timestamp = 0;
1620 evt->sel_type.oem_ts_type.manf_id[0] = 0;
1621 evt->sel_type.oem_ts_type.manf_id[1] = 0;
1622 evt->sel_type.oem_ts_type.manf_id[2] = 0;
1623 for(data_count=0; data_count < SEL_OEM_TS_DATA_LEN ; data_count++)
1624 evt->sel_type.oem_ts_type.oem_defined[data_count] = 0;
1625 }
1626 else
1627 {
1628 for(data_count=0; data_count < SEL_OEM_NOTS_DATA_LEN ; data_count++)
1629 evt->sel_type.oem_nots_type.oem_defined[data_count] = 0;
1630 }
1631
1632 /* save response into SEL event structure */
1633 evt->record_id = (rsp->data[3] << 8) | rsp->data[2];
1634 evt->record_type = rsp->data[4];
1635 if (evt->record_type < 0xc0)
1636 {
1637 evt->sel_type.standard_type.timestamp = (rsp->data[8] << 24) | (rsp->data[7] << 16) |
1638 (rsp->data[6] << 8) | rsp->data[5];
1639 evt->sel_type.standard_type.gen_id = (rsp->data[10] << 8) | rsp->data[9];
1640 evt->sel_type.standard_type.evm_rev = rsp->data[11];
1641 evt->sel_type.standard_type.sensor_type = rsp->data[12];
1642 evt->sel_type.standard_type.sensor_num = rsp->data[13];
1643 evt->sel_type.standard_type.event_type = rsp->data[14] & 0x7f;
1644 evt->sel_type.standard_type.event_dir = (rsp->data[14] & 0x80) >> 7;
1645 evt->sel_type.standard_type.event_data[0] = rsp->data[15];
1646 evt->sel_type.standard_type.event_data[1] = rsp->data[16];
1647 evt->sel_type.standard_type.event_data[2] = rsp->data[17];
1648 }
1649 else if (evt->record_type < 0xe0)
1650 {
1651 evt->sel_type.oem_ts_type.timestamp= (rsp->data[8] << 24) | (rsp->data[7] << 16) |
1652 (rsp->data[6] << 8) | rsp->data[5];
1653 evt->sel_type.oem_ts_type.manf_id[0]= rsp->data[11];
1654 evt->sel_type.oem_ts_type.manf_id[1]= rsp->data[10];
1655 evt->sel_type.oem_ts_type.manf_id[2]= rsp->data[9];
1656 for(data_count=0; data_count < SEL_OEM_TS_DATA_LEN ; data_count++)
1657 evt->sel_type.oem_ts_type.oem_defined[data_count] = rsp->data[(data_count+12)];
1658 }
1659 else
1660 {
1661 for(data_count=0; data_count < SEL_OEM_NOTS_DATA_LEN ; data_count++)
1662 evt->sel_type.oem_nots_type.oem_defined[data_count] = rsp->data[(data_count+5)];
1663 }
1664 return next;
1665 }
1666
1667 static void
ipmi_sel_print_event_file(struct ipmi_intf * intf,struct sel_event_record * evt,FILE * fp)1668 ipmi_sel_print_event_file(struct ipmi_intf * intf, struct sel_event_record * evt, FILE * fp)
1669 {
1670 char * description;
1671
1672 if (fp == NULL)
1673 return;
1674
1675 ipmi_get_event_desc(intf, evt, &description);
1676
1677 fprintf(fp, "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x # %s #0x%02x %s\n",
1678 evt->sel_type.standard_type.evm_rev,
1679 evt->sel_type.standard_type.sensor_type,
1680 evt->sel_type.standard_type.sensor_num,
1681 evt->sel_type.standard_type.event_type | (evt->sel_type.standard_type.event_dir << 7),
1682 evt->sel_type.standard_type.event_data[0],
1683 evt->sel_type.standard_type.event_data[1],
1684 evt->sel_type.standard_type.event_data[2],
1685 (
1686 (evt->sel_type.standard_type.sensor_type >=0xC0 && evt->sel_type.standard_type.sensor_type < 0xF0)
1687 ?
1688 ipmi_sel_get_oem_sensor_type_offset(ipmi_get_oem(intf),evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0])
1689 :
1690 ipmi_sel_get_sensor_type_offset(evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0])
1691 ),
1692 evt->sel_type.standard_type.sensor_num,
1693 (description != NULL) ? description : "Unknown");
1694
1695 if (description != NULL) {
1696 free(description);
1697 description = NULL;
1698 }
1699 }
1700
1701 void
ipmi_sel_print_extended_entry(struct ipmi_intf * intf,struct sel_event_record * evt)1702 ipmi_sel_print_extended_entry(struct ipmi_intf * intf, struct sel_event_record * evt)
1703 {
1704 sel_extended++;
1705 ipmi_sel_print_std_entry(intf, evt);
1706 sel_extended--;
1707 }
1708
1709 void
ipmi_sel_print_std_entry(struct ipmi_intf * intf,struct sel_event_record * evt)1710 ipmi_sel_print_std_entry(struct ipmi_intf * intf, struct sel_event_record * evt)
1711 {
1712 char * description;
1713 struct sdr_record_list * sdr = NULL;
1714 int data_count;
1715
1716 if (sel_extended && (evt->record_type < 0xc0))
1717 sdr = ipmi_sdr_find_sdr_bynumtype(intf, evt->sel_type.standard_type.gen_id, evt->sel_type.standard_type.sensor_num, evt->sel_type.standard_type.sensor_type);
1718
1719
1720 if (!evt)
1721 return;
1722
1723 if (csv_output)
1724 printf("%x,", evt->record_id);
1725 else
1726 printf("%4x | ", evt->record_id);
1727
1728 if (evt->record_type == 0xf0)
1729 {
1730 if (csv_output)
1731 printf(",,");
1732
1733 printf ("Linux kernel panic: %.11s\n", (char *) evt + 5);
1734 return;
1735 }
1736
1737 if (evt->record_type < 0xe0)
1738 {
1739 if ((evt->sel_type.standard_type.timestamp < 0x20000000)||(evt->sel_type.oem_ts_type.timestamp < 0x20000000)){
1740 printf(" Pre-Init ");
1741
1742 if (csv_output)
1743 printf(",");
1744 else
1745 printf(" |");
1746
1747 printf("%010d", evt->sel_type.standard_type.timestamp );
1748 if (csv_output)
1749 printf(",");
1750 else
1751 printf("| ");
1752 }
1753 else {
1754 if (evt->record_type < 0xc0)
1755 printf("%s", ipmi_sel_timestamp_date(evt->sel_type.standard_type.timestamp));
1756 else
1757 printf("%s", ipmi_sel_timestamp_date(evt->sel_type.oem_ts_type.timestamp));
1758 if (csv_output)
1759 printf(",");
1760 else
1761 printf(" | ");
1762
1763 if (evt->record_type < 0xc0)
1764 printf("%s", ipmi_sel_timestamp_time(evt->sel_type.standard_type.timestamp));
1765 else
1766 printf("%s", ipmi_sel_timestamp_time(evt->sel_type.oem_ts_type.timestamp));
1767
1768 if (csv_output)
1769 printf(",");
1770 else
1771 printf(" | ");
1772 }
1773
1774 }
1775 else
1776 {
1777 if (csv_output)
1778 printf(",,");
1779 }
1780
1781 if (evt->record_type >= 0xc0)
1782 {
1783 printf ("OEM record %02x", evt->record_type);
1784 if (csv_output)
1785 printf(",");
1786 else
1787 printf(" | ");
1788
1789 if(evt->record_type <= 0xdf)
1790 {
1791 printf ("%02x%02x%02x", evt->sel_type.oem_ts_type.manf_id[0], evt->sel_type.oem_ts_type.manf_id[1], evt->sel_type.oem_ts_type.manf_id[2]);
1792 if (csv_output)
1793 printf(",");
1794 else
1795 printf(" | ");
1796 for(data_count=0;data_count < SEL_OEM_TS_DATA_LEN;data_count++)
1797 printf("%02x", evt->sel_type.oem_ts_type.oem_defined[data_count]);
1798 }
1799 else
1800 {
1801 for(data_count=0;data_count < SEL_OEM_NOTS_DATA_LEN;data_count++)
1802 printf("%02x", evt->sel_type.oem_nots_type.oem_defined[data_count]);
1803 }
1804 ipmi_sel_oem_message(evt, 0);
1805 printf ("\n");
1806 return;
1807 }
1808
1809 /* lookup SDR entry based on sensor number and type */
1810 if (sdr != NULL) {
1811 printf("%s ",
1812 (
1813 (evt->sel_type.standard_type.sensor_type >=0xC0 && evt->sel_type.standard_type.sensor_type < 0xF0)
1814 ?
1815 ipmi_sel_get_oem_sensor_type_offset(ipmi_get_oem(intf),evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0])
1816 :
1817 ipmi_sel_get_sensor_type_offset(evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0])
1818 )
1819 );
1820 switch (sdr->type) {
1821 case SDR_RECORD_TYPE_FULL_SENSOR:
1822 printf("%s", sdr->record.full->id_string);
1823 break;
1824 case SDR_RECORD_TYPE_COMPACT_SENSOR:
1825 printf("%s", sdr->record.compact->id_string);
1826 break;
1827 case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
1828 printf("%s", sdr->record.eventonly->id_string);
1829 break;
1830 case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
1831 printf("%s", sdr->record.fruloc->id_string);
1832 break;
1833 case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
1834 printf("%s", sdr->record.mcloc->id_string);
1835 break;
1836 case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
1837 printf("%s", sdr->record.genloc->id_string);
1838 break;
1839 default:
1840 printf("#%02x", evt->sel_type.standard_type.sensor_num);
1841 break;
1842 }
1843 } else {
1844 printf("%s",(
1845 (evt->sel_type.standard_type.sensor_type >=0xC0 && evt->sel_type.standard_type.sensor_type < 0xF0)
1846 ?
1847 ipmi_sel_get_oem_sensor_type_offset(ipmi_get_oem(intf),evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0])
1848 :
1849 ipmi_sel_get_sensor_type_offset(evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0])
1850 ));
1851 if (evt->sel_type.standard_type.sensor_num != 0)
1852 printf(" #0x%02x", evt->sel_type.standard_type.sensor_num);
1853 }
1854
1855 if (csv_output)
1856 printf(",");
1857 else
1858 printf(" | ");
1859
1860 ipmi_get_event_desc(intf, evt, &description);
1861 if (description) {
1862 printf("%s", description);
1863 free(description);
1864 description = NULL;
1865 }
1866
1867 if (csv_output) {
1868 printf(",");
1869 } else {
1870 printf(" | ");
1871 }
1872
1873 if (evt->sel_type.standard_type.event_dir) {
1874 printf("Deasserted");
1875 } else {
1876 printf("Asserted");
1877 }
1878
1879 if (sdr != NULL && evt->sel_type.standard_type.event_type == 1) {
1880 /*
1881 * Threshold Event
1882 */
1883 float trigger_reading = 0.0;
1884 float threshold_reading = 0.0;
1885 uint8_t threshold_reading_provided = 0;
1886
1887 /* trigger reading in event data byte 2 */
1888 if (((evt->sel_type.standard_type.event_data[0] >> 6) & 3) == 1) {
1889 trigger_reading = sdr_convert_sensor_reading(
1890 sdr->record.full, evt->sel_type.standard_type.event_data[1]);
1891 }
1892
1893 /* trigger threshold in event data byte 3 */
1894 if (((evt->sel_type.standard_type.event_data[0] >> 4) & 3) == 1) {
1895 threshold_reading = sdr_convert_sensor_reading(
1896 sdr->record.full, evt->sel_type.standard_type.event_data[2]);
1897 threshold_reading_provided = 1;
1898 }
1899
1900 if (csv_output)
1901 printf(",");
1902 else
1903 printf(" | ");
1904
1905 printf("Reading %.*f",
1906 (trigger_reading==(int)trigger_reading) ? 0 : 2,
1907 trigger_reading);
1908 if (threshold_reading_provided) {
1909 printf(" %s Threshold %.*f %s",
1910 ((evt->sel_type.standard_type.event_data[0] & 0xf) % 2) ? ">" : "<",
1911 (threshold_reading==(int)threshold_reading) ? 0 : 2,
1912 threshold_reading,
1913 ipmi_sdr_get_unit_string(sdr->record.common->unit.pct,
1914 sdr->record.common->unit.modifier,
1915 sdr->record.common->unit.type.base,
1916 sdr->record.common->unit.type.modifier));
1917 }
1918 }
1919 else if (evt->sel_type.standard_type.event_type == 0x6f) {
1920 int print_sensor = 1;
1921 switch (ipmi_get_oem(intf)) {
1922 case IPMI_OEM_SUPERMICRO:
1923 case IPMI_OEM_SUPERMICRO_47488:
1924 print_sensor = 0;
1925 break;
1926 default:
1927 break;
1928 }
1929 /*
1930 * Sensor-Specific Discrete
1931 */
1932 if (print_sensor && evt->sel_type.standard_type.sensor_type == 0xC && /*TODO*/
1933 evt->sel_type.standard_type.sensor_num == 0 &&
1934 (evt->sel_type.standard_type.event_data[0] & 0x30) == 0x20) {
1935 /* break down memory ECC reporting if we can */
1936 if (csv_output)
1937 printf(",");
1938 else
1939 printf(" | ");
1940
1941 printf("CPU %d DIMM %d",
1942 evt->sel_type.standard_type.event_data[2] & 0x0f,
1943 (evt->sel_type.standard_type.event_data[2] & 0xf0) >> 4);
1944 }
1945 }
1946
1947 printf("\n");
1948 }
1949
1950 void
ipmi_sel_print_std_entry_verbose(struct ipmi_intf * intf,struct sel_event_record * evt)1951 ipmi_sel_print_std_entry_verbose(struct ipmi_intf * intf, struct sel_event_record * evt)
1952 {
1953 char * description;
1954 int data_count;
1955
1956 if (!evt)
1957 return;
1958
1959 printf("SEL Record ID : %04x\n", evt->record_id);
1960
1961 if (evt->record_type == 0xf0)
1962 {
1963 printf (" Record Type : Linux kernel panic (OEM record %02x)\n", evt->record_type);
1964 printf (" Panic string : %.11s\n\n", (char *) evt + 5);
1965 return;
1966 }
1967
1968 printf(" Record Type : %02x", evt->record_type);
1969 if (evt->record_type >= 0xc0)
1970 {
1971 if (evt->record_type < 0xe0)
1972 printf(" (OEM timestamped)");
1973 else
1974 printf(" (OEM non-timestamped)");
1975 }
1976 printf("\n");
1977
1978 if (evt->record_type < 0xe0)
1979 {
1980 printf(" Timestamp : ");
1981 if (evt->record_type < 0xc0)
1982 printf("%s %s", ipmi_sel_timestamp_date(evt->sel_type.standard_type.timestamp),
1983 ipmi_sel_timestamp_time(evt->sel_type.standard_type.timestamp));
1984 else
1985 printf("%s %s", ipmi_sel_timestamp_date(evt->sel_type.oem_ts_type.timestamp),
1986 ipmi_sel_timestamp_time(evt->sel_type.oem_ts_type.timestamp));
1987 printf("\n");
1988 }
1989
1990 if (evt->record_type >= 0xc0)
1991 {
1992 if(evt->record_type <= 0xdf)
1993 {
1994 printf (" Manufactacturer ID : %02x%02x%02x\n", evt->sel_type.oem_ts_type.manf_id[0],
1995 evt->sel_type.oem_ts_type.manf_id[1], evt->sel_type.oem_ts_type.manf_id[2]);
1996 printf (" OEM Defined : ");
1997 for(data_count=0;data_count < SEL_OEM_TS_DATA_LEN;data_count++)
1998 printf("%02x", evt->sel_type.oem_ts_type.oem_defined[data_count]);
1999 printf(" [%s]\n\n",hex2ascii (evt->sel_type.oem_ts_type.oem_defined, SEL_OEM_TS_DATA_LEN));
2000 }
2001 else
2002 {
2003 printf (" OEM Defined : ");
2004 for(data_count=0;data_count < SEL_OEM_NOTS_DATA_LEN;data_count++)
2005 printf("%02x", evt->sel_type.oem_nots_type.oem_defined[data_count]);
2006 printf(" [%s]\n\n",hex2ascii (evt->sel_type.oem_nots_type.oem_defined, SEL_OEM_NOTS_DATA_LEN));
2007 ipmi_sel_oem_message(evt, 1);
2008 }
2009 return;
2010 }
2011
2012 printf(" Generator ID : %04x\n",
2013 evt->sel_type.standard_type.gen_id);
2014 printf(" EvM Revision : %02x\n",
2015 evt->sel_type.standard_type.evm_rev);
2016 printf(" Sensor Type : %s\n",
2017 (
2018 (evt->sel_type.standard_type.sensor_type >=0xC0 && evt->sel_type.standard_type.sensor_type < 0xF0)
2019 ?
2020 ipmi_sel_get_oem_sensor_type_offset(ipmi_get_oem(intf),evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0])
2021 :
2022 ipmi_sel_get_sensor_type_offset(evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0])
2023 )
2024 );
2025 printf(" Sensor Number : %02x\n",
2026 evt->sel_type.standard_type.sensor_num);
2027 printf(" Event Type : %s\n",
2028 ipmi_get_event_type(evt->sel_type.standard_type.event_type));
2029 printf(" Event Direction : %s\n",
2030 val2str(evt->sel_type.standard_type.event_dir, event_dir_vals));
2031 printf(" Event Data : %02x%02x%02x\n",
2032 evt->sel_type.standard_type.event_data[0], evt->sel_type.standard_type.event_data[1], evt->sel_type.standard_type.event_data[2]);
2033 ipmi_get_event_desc(intf, evt, &description);
2034 printf(" Description : %s\n",
2035 description ? description : "");
2036 free(description);
2037 description = NULL;
2038
2039 printf("\n");
2040 }
2041
2042
2043 void
ipmi_sel_print_extended_entry_verbose(struct ipmi_intf * intf,struct sel_event_record * evt)2044 ipmi_sel_print_extended_entry_verbose(struct ipmi_intf * intf, struct sel_event_record * evt)
2045 {
2046 struct sdr_record_list * sdr;
2047 char * description;
2048
2049 if (!evt)
2050 return;
2051
2052 sdr = ipmi_sdr_find_sdr_bynumtype(intf,
2053 evt->sel_type.standard_type.gen_id,
2054 evt->sel_type.standard_type.sensor_num,
2055 evt->sel_type.standard_type.sensor_type);
2056 if (sdr == NULL)
2057 {
2058 ipmi_sel_print_std_entry_verbose(intf, evt);
2059 return;
2060 }
2061
2062 printf("SEL Record ID : %04x\n", evt->record_id);
2063
2064 if (evt->record_type == 0xf0)
2065 {
2066 printf (" Record Type : "
2067 "Linux kernel panic (OEM record %02x)\n",
2068 evt->record_type);
2069 printf (" Panic string : %.11s\n\n",
2070 (char *) evt + 5);
2071 return;
2072 }
2073
2074 printf(" Record Type : %02x\n", evt->record_type);
2075 if (evt->record_type < 0xe0)
2076 {
2077 printf(" Timestamp : ");
2078 printf("%s %s\n", ipmi_sel_timestamp_date(evt->sel_type.standard_type.timestamp),
2079 ipmi_sel_timestamp_time(evt->sel_type.standard_type.timestamp));
2080 }
2081
2082
2083 printf(" Generator ID : %04x\n",
2084 evt->sel_type.standard_type.gen_id);
2085 printf(" EvM Revision : %02x\n",
2086 evt->sel_type.standard_type.evm_rev);
2087 printf(" Sensor Type : %s\n",
2088 ipmi_sel_get_sensor_type_offset(evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0]));
2089 printf(" Sensor Number : %02x\n",
2090 evt->sel_type.standard_type.sensor_num);
2091 printf(" Event Type : %s\n",
2092 ipmi_get_event_type(evt->sel_type.standard_type.event_type));
2093 printf(" Event Direction : %s\n",
2094 val2str(evt->sel_type.standard_type.event_dir, event_dir_vals));
2095 printf(" Event Data (RAW) : %02x%02x%02x\n",
2096 evt->sel_type.standard_type.event_data[0], evt->sel_type.standard_type.event_data[1], evt->sel_type.standard_type.event_data[2]);
2097
2098 /* break down event data field
2099 * as per IPMI Spec 2.0 Table 29-6 */
2100 if (evt->sel_type.standard_type.event_type == 1 && sdr->type == SDR_RECORD_TYPE_FULL_SENSOR) {
2101 /* Threshold */
2102 switch ((evt->sel_type.standard_type.event_data[0] >> 6) & 3) { /* EV1[7:6] */
2103 case 0:
2104 /* unspecified byte 2 */
2105 break;
2106 case 1:
2107 /* trigger reading in byte 2 */
2108 printf(" Trigger Reading : %.3f",
2109 sdr_convert_sensor_reading(sdr->record.full,
2110 evt->sel_type.standard_type.event_data[1]));
2111 /* determine units with possible modifiers */
2112 printf ("%s\n", ipmi_sdr_get_unit_string(sdr->record.common->unit.pct,
2113 sdr->record.common->unit.modifier,
2114 sdr->record.common->unit.type.base,
2115 sdr->record.common->unit.type.modifier));
2116 break;
2117 case 2:
2118 /* oem code in byte 2 */
2119 printf(" OEM Data : %02x\n",
2120 evt->sel_type.standard_type.event_data[1]);
2121 break;
2122 case 3:
2123 /* sensor-specific extension code in byte 2 */
2124 printf(" Sensor Extension Code : %02x\n",
2125 evt->sel_type.standard_type.event_data[1]);
2126 break;
2127 }
2128 switch ((evt->sel_type.standard_type.event_data[0] >> 4) & 3) { /* EV1[5:4] */
2129 case 0:
2130 /* unspecified byte 3 */
2131 break;
2132 case 1:
2133 /* trigger threshold value in byte 3 */
2134 printf(" Trigger Threshold : %.3f",
2135 sdr_convert_sensor_reading(sdr->record.full,
2136 evt->sel_type.standard_type.event_data[2]));
2137 /* determine units with possible modifiers */
2138 printf ("%s\n", ipmi_sdr_get_unit_string(sdr->record.common->unit.pct,
2139 sdr->record.common->unit.modifier,
2140 sdr->record.common->unit.type.base,
2141 sdr->record.common->unit.type.modifier));
2142 break;
2143 case 2:
2144 /* OEM code in byte 3 */
2145 printf(" OEM Data : %02x\n",
2146 evt->sel_type.standard_type.event_data[2]);
2147 break;
2148 case 3:
2149 /* sensor-specific extension code in byte 3 */
2150 printf(" Sensor Extension Code : %02x\n",
2151 evt->sel_type.standard_type.event_data[2]);
2152 break;
2153 }
2154 } else if (evt->sel_type.standard_type.event_type >= 0x2 && evt->sel_type.standard_type.event_type <= 0xc) {
2155 /* Generic Discrete */
2156 } else if (evt->sel_type.standard_type.event_type == 0x6f) {
2157
2158 /* Sensor-Specific Discrete */
2159 if (evt->sel_type.standard_type.sensor_type == 0xC &&
2160 evt->sel_type.standard_type.sensor_num == 0 && /**** THIS LOOK TO BE OEM ****/
2161 (evt->sel_type.standard_type.event_data[0] & 0x30) == 0x20)
2162 {
2163 /* break down memory ECC reporting if we can */
2164 printf(" Event Data : CPU %d DIMM %d\n",
2165 evt->sel_type.standard_type.event_data[2] & 0x0f,
2166 (evt->sel_type.standard_type.event_data[2] & 0xf0) >> 4);
2167 }
2168 else if(
2169 evt->sel_type.standard_type.sensor_type == 0x2b && /* Version change */
2170 evt->sel_type.standard_type.event_data[0] == 0xC1 /* Data in Data 2 */
2171 )
2172
2173 {
2174 //evt->sel_type.standard_type.event_data[1]
2175 }
2176 else
2177 {
2178 /* FIXME : Add sensor specific discrete types */
2179 printf(" Event Interpretation : Missing\n");
2180 }
2181 } else if (evt->sel_type.standard_type.event_type >= 0x70 && evt->sel_type.standard_type.event_type <= 0x7f) {
2182 /* OEM */
2183 } else {
2184 printf(" Event Data : %02x%02x%02x\n",
2185 evt->sel_type.standard_type.event_data[0], evt->sel_type.standard_type.event_data[1], evt->sel_type.standard_type.event_data[2]);
2186 }
2187
2188 ipmi_get_event_desc(intf, evt, &description);
2189 printf(" Description : %s\n",
2190 description ? description : "");
2191 free(description);
2192 description = NULL;
2193
2194 printf("\n");
2195 }
2196
2197 static int
__ipmi_sel_savelist_entries(struct ipmi_intf * intf,int count,const char * savefile,int binary)2198 __ipmi_sel_savelist_entries(struct ipmi_intf * intf, int count, const char * savefile,
2199 int binary)
2200 {
2201 struct ipmi_rs * rsp;
2202 struct ipmi_rq req;
2203 uint16_t next_id = 0, curr_id = 0;
2204 struct sel_event_record evt;
2205 int n=0;
2206 FILE * fp = NULL;
2207
2208 memset(&req, 0, sizeof(req));
2209 req.msg.netfn = IPMI_NETFN_STORAGE;
2210 req.msg.cmd = IPMI_CMD_GET_SEL_INFO;
2211
2212 rsp = intf->sendrecv(intf, &req);
2213 if (rsp == NULL) {
2214 lprintf(LOG_ERR, "Get SEL Info command failed");
2215 return -1;
2216 }
2217 if (rsp->ccode > 0) {
2218 lprintf(LOG_ERR, "Get SEL Info command failed: %s",
2219 val2str(rsp->ccode, completion_code_vals));
2220 return -1;
2221 }
2222 if (verbose > 2)
2223 printbuf(rsp->data, rsp->data_len, "sel_info");
2224
2225 if (rsp->data[1] == 0 && rsp->data[2] == 0) {
2226 lprintf(LOG_ERR, "SEL has no entries");
2227 return 0;
2228 }
2229
2230 memset(&req, 0, sizeof(req));
2231 req.msg.netfn = IPMI_NETFN_STORAGE;
2232 req.msg.cmd = IPMI_CMD_RESERVE_SEL;
2233
2234 rsp = intf->sendrecv(intf, &req);
2235 if (rsp == NULL) {
2236 lprintf(LOG_ERR, "Reserve SEL command failed");
2237 return -1;
2238 }
2239 if (rsp->ccode > 0) {
2240 lprintf(LOG_ERR, "Reserve SEL command failed: %s",
2241 val2str(rsp->ccode, completion_code_vals));
2242 return -1;
2243 }
2244
2245 if (count < 0) {
2246 /** Show only the most recent 'count' records. */
2247 int delta;
2248 uint16_t entries;
2249
2250 req.msg.cmd = IPMI_CMD_GET_SEL_INFO;
2251 rsp = intf->sendrecv(intf, &req);
2252 if (rsp == NULL) {
2253 lprintf(LOG_ERR, "Get SEL Info command failed");
2254 return -1;
2255 }
2256 if (rsp->ccode > 0) {
2257 lprintf(LOG_ERR, "Get SEL Info command failed: %s",
2258 val2str(rsp->ccode, completion_code_vals));
2259 return -1;
2260 }
2261 entries = buf2short(rsp->data + 1);
2262 if (-count > entries)
2263 count = -entries;
2264
2265 /* Get first record. */
2266 next_id = ipmi_sel_get_std_entry(intf, 0, &evt);
2267
2268 delta = next_id - evt.record_id;
2269
2270 /* Get last record. */
2271 next_id = ipmi_sel_get_std_entry(intf, 0xffff, &evt);
2272
2273 next_id = evt.record_id + count * delta + delta;
2274 }
2275
2276 if (savefile != NULL) {
2277 fp = ipmi_open_file_write(savefile);
2278 }
2279
2280 while (next_id != 0xffff) {
2281 curr_id = next_id;
2282 lprintf(LOG_DEBUG, "SEL Next ID: %04x", curr_id);
2283
2284 next_id = ipmi_sel_get_std_entry(intf, curr_id, &evt);
2285 if (next_id == 0) {
2286 /*
2287 * usually next_id of zero means end but
2288 * retry because some hardware has quirks
2289 * and will return 0 randomly.
2290 */
2291 next_id = ipmi_sel_get_std_entry(intf, curr_id, &evt);
2292 if (next_id == 0)
2293 break;
2294 }
2295
2296 if (verbose)
2297 ipmi_sel_print_std_entry_verbose(intf, &evt);
2298 else
2299 ipmi_sel_print_std_entry(intf, &evt);
2300
2301 if (fp != NULL) {
2302 if (binary)
2303 fwrite(&evt, 1, 16, fp);
2304 else
2305 ipmi_sel_print_event_file(intf, &evt, fp);
2306 }
2307
2308 if (++n == count) {
2309 break;
2310 }
2311 }
2312
2313 if (fp != NULL)
2314 fclose(fp);
2315
2316 return 0;
2317 }
2318
2319 static int
ipmi_sel_list_entries(struct ipmi_intf * intf,int count)2320 ipmi_sel_list_entries(struct ipmi_intf * intf, int count)
2321 {
2322 return __ipmi_sel_savelist_entries(intf, count, NULL, 0);
2323 }
2324
2325 static int
ipmi_sel_save_entries(struct ipmi_intf * intf,int count,const char * savefile)2326 ipmi_sel_save_entries(struct ipmi_intf * intf, int count, const char * savefile)
2327 {
2328 return __ipmi_sel_savelist_entries(intf, count, savefile, 0);
2329 }
2330
2331 /*
2332 * ipmi_sel_interpret
2333 *
2334 * return 0 on success,
2335 * -1 on error
2336 */
2337 static int
ipmi_sel_interpret(struct ipmi_intf * intf,unsigned long iana,const char * readfile,const char * format)2338 ipmi_sel_interpret(struct ipmi_intf *intf, unsigned long iana,
2339 const char *readfile, const char *format)
2340 {
2341 FILE *fp = 0;
2342 struct sel_event_record evt;
2343 char *buffer = NULL;
2344 char *cursor = NULL;
2345 int status = 0;
2346 /* since the interface is not used, iana is taken from
2347 * the command line
2348 */
2349 sel_iana = iana;
2350 if (strncmp("pps", format, 3) == 0) {
2351 /* Parser for the following format */
2352 /* 0x001F: Event: at Mar 27 06:41:10 2007;from:(0x9a,0,7);
2353 * sensor:(0xc3,119); event:0x6f(asserted): 0xA3 0x00 0x88
2354 * commonly found in PPS shelf managers
2355 * Supports a tweak for hotswap events that are already interpreted.
2356 */
2357 fp = ipmi_open_file(readfile, 0);
2358 if (fp == NULL) {
2359 lprintf(LOG_ERR, "Failed to open file '%s' for reading.",
2360 readfile);
2361 return (-1);
2362 }
2363 buffer = (char *)malloc((size_t)256);
2364 if (buffer == NULL) {
2365 lprintf(LOG_ERR, "ipmitool: malloc failure");
2366 fclose(fp);
2367 return (-1);
2368 }
2369 do {
2370 /* Only allow complete lines to be parsed,
2371 * hardcoded maximum line length
2372 */
2373 if (fgets(buffer, 256, fp) == NULL) {
2374 status = (-1);
2375 break;
2376 }
2377 if (strlen(buffer) > 255) {
2378 lprintf(LOG_ERR, "ipmitool: invalid entry found in file.");
2379 continue;
2380 }
2381 cursor = buffer;
2382 /* assume normal "System" event */
2383 evt.record_type = 2;
2384 errno = 0;
2385 evt.record_id = strtol((const char *)cursor, (char **)NULL, 16);
2386 if (errno != 0) {
2387 lprintf(LOG_ERR, "Invalid record ID.");
2388 status = (-1);
2389 break;
2390 }
2391 evt.sel_type.standard_type.evm_rev = 4;
2392
2393 /* FIXME: convert*/
2394 evt.sel_type.standard_type.timestamp;
2395
2396 /* skip timestamp */
2397 cursor = index((const char *)cursor, ';');
2398 cursor++;
2399
2400 /* FIXME: parse originator */
2401 evt.sel_type.standard_type.gen_id = 0x0020;
2402
2403 /* skip originator info */
2404 cursor = index((const char *)cursor, ';');
2405 cursor++;
2406
2407 /* Get sensor type */
2408 cursor = index((const char *)cursor, '(');
2409 cursor++;
2410
2411 errno = 0;
2412 evt.sel_type.standard_type.sensor_type =
2413 strtol((const char *)cursor, (char **)NULL, 16);
2414 if (errno != 0) {
2415 lprintf(LOG_ERR, "Invalid Sensor Type.");
2416 status = (-1);
2417 break;
2418 }
2419 cursor = index((const char *)cursor, ',');
2420 cursor++;
2421
2422 errno = 0;
2423 evt.sel_type.standard_type.sensor_num =
2424 strtol((const char *)cursor, (char **)NULL, 10);
2425 if (errno != 0) {
2426 lprintf(LOG_ERR, "Invalid Sensor Number.");
2427 status = (-1);
2428 break;
2429 }
2430
2431 /* skip to event type info */
2432 cursor = index((const char *)cursor, ':');
2433 cursor++;
2434
2435 errno = 0;
2436 evt.sel_type.standard_type.event_type=
2437 strtol((const char *)cursor, (char **)NULL, 16);
2438 if (errno != 0) {
2439 lprintf(LOG_ERR, "Invalid Event Type.");
2440 status = (-1);
2441 break;
2442 }
2443
2444 /* skip to event dir info */
2445 cursor = index((const char *)cursor, '(');
2446 cursor++;
2447 if (*cursor == 'a') {
2448 evt.sel_type.standard_type.event_dir = 0;
2449 } else {
2450 evt.sel_type.standard_type.event_dir = 1;
2451 }
2452 /* skip to data info */
2453 cursor = index((const char *)cursor, ' ');
2454 cursor++;
2455
2456 if (evt.sel_type.standard_type.sensor_type == 0xF0) {
2457 /* got to FRU id */
2458 while (!isdigit(*cursor)) {
2459 cursor++;
2460 }
2461 /* store FRUid */
2462 errno = 0;
2463 evt.sel_type.standard_type.event_data[2] =
2464 strtol(cursor, (char **)NULL, 10);
2465 if (errno != 0) {
2466 lprintf(LOG_ERR, "Invalid Event Data#2.");
2467 status = (-1);
2468 break;
2469 }
2470
2471 /* Get to previous state */
2472 cursor = index((const char *)cursor, 'M');
2473 cursor++;
2474
2475 /* Set previous state */
2476 errno = 0;
2477 evt.sel_type.standard_type.event_data[1] =
2478 strtol(cursor, (char **)NULL, 10);
2479 if (errno != 0) {
2480 lprintf(LOG_ERR, "Invalid Event Data#1.");
2481 status = (-1);
2482 break;
2483 }
2484
2485 /* Get to current state */
2486 cursor = index((const char *)cursor, 'M');
2487 cursor++;
2488
2489 /* Set current state */
2490 errno = 0;
2491 evt.sel_type.standard_type.event_data[0] =
2492 0xA0 | strtol(cursor, (char **)NULL, 10);
2493 if (errno != 0) {
2494 lprintf(LOG_ERR, "Invalid Event Data#0.");
2495 status = (-1);
2496 break;
2497 }
2498
2499 /* skip to cause */
2500 cursor = index((const char *)cursor, '=');
2501 cursor++;
2502 errno = 0;
2503 evt.sel_type.standard_type.event_data[1] |=
2504 (strtol(cursor, (char **)NULL, 16)) << 4;
2505 if (errno != 0) {
2506 lprintf(LOG_ERR, "Invalid Event Data#1.");
2507 status = (-1);
2508 break;
2509 }
2510 } else if (*cursor == '0') {
2511 errno = 0;
2512 evt.sel_type.standard_type.event_data[0] =
2513 strtol((const char *)cursor, (char **)NULL, 16);
2514 if (errno != 0) {
2515 lprintf(LOG_ERR, "Invalid Event Data#0.");
2516 status = (-1);
2517 break;
2518 }
2519 cursor = index((const char *)cursor, ' ');
2520 cursor++;
2521
2522 errno = 0;
2523 evt.sel_type.standard_type.event_data[1] =
2524 strtol((const char *)cursor, (char **)NULL, 16);
2525 if (errno != 0) {
2526 lprintf(LOG_ERR, "Invalid Event Data#1.");
2527 status = (-1);
2528 break;
2529 }
2530
2531 cursor = index((const char *)cursor, ' ');
2532 cursor++;
2533
2534 errno = 0;
2535 evt.sel_type.standard_type.event_data[2] =
2536 strtol((const char *)cursor, (char **)NULL, 16);
2537 if (errno != 0) {
2538 lprintf(LOG_ERR, "Invalid Event Data#2.");
2539 status = (-1);
2540 break;
2541 }
2542 } else {
2543 lprintf(LOG_ERR, "ipmitool: can't guess format.");
2544 }
2545 /* parse the PPS line into a sel_event_record */
2546 if (verbose) {
2547 ipmi_sel_print_std_entry_verbose(intf, &evt);
2548 } else {
2549 ipmi_sel_print_std_entry(intf, &evt);
2550 }
2551 cursor = NULL;
2552 } while (status == 0); /* until file is completely read */
2553 cursor = NULL;
2554 free(buffer);
2555 buffer = NULL;
2556 fclose(fp);
2557 } else {
2558 lprintf(LOG_ERR, "Given format '%s' is unknown.", format);
2559 status = (-1);
2560 }
2561 return status;
2562 }
2563
2564
2565 static int
ipmi_sel_writeraw(struct ipmi_intf * intf,const char * savefile)2566 ipmi_sel_writeraw(struct ipmi_intf * intf, const char * savefile)
2567 {
2568 return __ipmi_sel_savelist_entries(intf, 0, savefile, 1);
2569 }
2570
2571
2572 static int
ipmi_sel_readraw(struct ipmi_intf * intf,const char * inputfile)2573 ipmi_sel_readraw(struct ipmi_intf * intf, const char * inputfile)
2574 {
2575 struct sel_event_record evt;
2576 int ret = 0;
2577 FILE* fp = 0;
2578
2579 fp = ipmi_open_file(inputfile, 0);
2580 if (fp)
2581 {
2582 size_t bytesRead;
2583
2584 do {
2585 if ((bytesRead = fread(&evt, 1, 16, fp)) == 16)
2586 {
2587 if (verbose)
2588 ipmi_sel_print_std_entry_verbose(intf, &evt);
2589 else
2590 ipmi_sel_print_std_entry(intf, &evt);
2591 }
2592 else
2593 {
2594 if (bytesRead != 0)
2595 {
2596 lprintf(LOG_ERR, "ipmitool: incomplete record found in file.");
2597 ret = -1;
2598 }
2599
2600 break;
2601 }
2602
2603 } while (1);
2604 fclose(fp);
2605 }
2606 else
2607 {
2608 lprintf(LOG_ERR, "ipmitool: could not open input file.");
2609 ret = -1;
2610 }
2611 return ret;
2612 }
2613
2614
2615
2616 static uint16_t
ipmi_sel_reserve(struct ipmi_intf * intf)2617 ipmi_sel_reserve(struct ipmi_intf * intf)
2618 {
2619 struct ipmi_rs * rsp;
2620 struct ipmi_rq req;
2621
2622 memset(&req, 0, sizeof(req));
2623 req.msg.netfn = IPMI_NETFN_STORAGE;
2624 req.msg.cmd = IPMI_CMD_RESERVE_SEL;
2625
2626 rsp = intf->sendrecv(intf, &req);
2627 if (rsp == NULL) {
2628 lprintf(LOG_WARN, "Unable to reserve SEL");
2629 return 0;
2630 }
2631 if (rsp->ccode > 0) {
2632 printf("Unable to reserve SEL: %s",
2633 val2str(rsp->ccode, completion_code_vals));
2634 return 0;
2635 }
2636
2637 return (rsp->data[0] | (rsp->data[1] << 8));
2638 }
2639
2640
2641
2642 /*
2643 * ipmi_sel_get_time
2644 *
2645 * return 0 on success,
2646 * -1 on error
2647 */
2648 static int
ipmi_sel_get_time(struct ipmi_intf * intf)2649 ipmi_sel_get_time(struct ipmi_intf * intf)
2650 {
2651 struct ipmi_rs * rsp;
2652 struct ipmi_rq req;
2653 static char tbuf[40];
2654 uint32_t timei;
2655 time_t time;
2656
2657 memset(&req, 0, sizeof(req));
2658 req.msg.netfn = IPMI_NETFN_STORAGE;
2659 req.msg.cmd = IPMI_GET_SEL_TIME;
2660
2661 rsp = intf->sendrecv(intf, &req);
2662
2663 if (rsp == NULL) {
2664 lprintf(LOG_ERR, "Get SEL Time command failed");
2665 return -1;
2666 }
2667 if (rsp->ccode > 0) {
2668 lprintf(LOG_ERR, "Get SEL Time command failed: %s",
2669 val2str(rsp->ccode, completion_code_vals));
2670 return -1;
2671 }
2672 if (rsp->data_len != 4) {
2673 lprintf(LOG_ERR, "Get SEL Time command failed: "
2674 "Invalid data length %d", rsp->data_len);
2675 return -1;
2676 }
2677
2678 memcpy(&timei, rsp->data, 4);
2679 #if WORDS_BIGENDIAN
2680 time = (time_t)(BSWAP_32(timei));
2681 #else
2682 time = (time_t)timei;
2683 #endif
2684
2685 strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", gmtime(&time));
2686 printf("%s\n", tbuf);
2687
2688 return 0;
2689 }
2690
2691
2692
2693 /*
2694 * ipmi_sel_set_time
2695 *
2696 * return 0 on success,
2697 * -1 on error
2698 */
2699 static int
ipmi_sel_set_time(struct ipmi_intf * intf,const char * time_string)2700 ipmi_sel_set_time(struct ipmi_intf * intf, const char * time_string)
2701 {
2702 struct ipmi_rs * rsp;
2703 struct ipmi_rq req;
2704 struct tm tm = {0};
2705 time_t t;
2706 uint32_t timei;
2707 const char * time_format = "%m/%d/%Y %H:%M:%S";
2708
2709 memset(&req, 0, sizeof(req));
2710 req.msg.netfn = IPMI_NETFN_STORAGE;
2711 req.msg.cmd = IPMI_SET_SEL_TIME;
2712
2713 /* See if user requested set to current client system time */
2714 if (strncasecmp(time_string, "now", 3) == 0) {
2715 t = time(NULL);
2716 }
2717 else {
2718 /* Now how do we get our time_t from our ascii version? */
2719 if (strptime(time_string, time_format, &tm) == 0) {
2720 lprintf(LOG_ERR, "Specified time could not be parsed");
2721 return -1;
2722 }
2723 tm.tm_isdst = (-1); /* look up DST information */
2724 t = mktime(&tm);
2725 if (t < 0) {
2726 lprintf(LOG_ERR, "Specified time could not be parsed");
2727 return -1;
2728 }
2729 }
2730
2731 {
2732 //modify UTC time to local time expressed in number of seconds from 1/1/70 0:0:0 1970 GMT
2733 struct tm * tm_tmp = {0};
2734 int gt_year,gt_yday,gt_hour,lt_year,lt_yday,lt_hour;
2735 int delta_hour;
2736 tm_tmp=gmtime(&t);
2737 gt_year=tm_tmp->tm_year;
2738 gt_yday=tm_tmp->tm_yday;
2739 gt_hour=tm_tmp->tm_hour;
2740 memset(&*tm_tmp, 0, sizeof(struct tm));
2741 tm_tmp=localtime(&t);
2742 lt_year=tm_tmp->tm_year;
2743 lt_yday=tm_tmp->tm_yday;
2744 lt_hour=tm_tmp->tm_hour;
2745 delta_hour=lt_hour - gt_hour;
2746 if ( (lt_year > gt_year) || ((lt_year == gt_year) && (lt_yday > gt_yday)) )
2747 delta_hour += 24;
2748 if ( (lt_year < gt_year) || ((lt_year == gt_year) && (lt_yday < gt_yday)) )
2749 delta_hour -= 24;
2750
2751 t += (delta_hour * 60 * 60);
2752 }
2753
2754 timei = (uint32_t)t;
2755 req.msg.data = (uint8_t *)&timei;
2756 req.msg.data_len = 4;
2757
2758 #if WORDS_BIGENDIAN
2759 timei = BSWAP_32(timei);
2760 #endif
2761
2762 rsp = intf->sendrecv(intf, &req);
2763 if (rsp == NULL) {
2764 lprintf(LOG_ERR, "Set SEL Time command failed");
2765 return -1;
2766 }
2767 if (rsp->ccode > 0) {
2768 lprintf(LOG_ERR, "Set SEL Time command failed: %s",
2769 val2str(rsp->ccode, completion_code_vals));
2770 return -1;
2771 }
2772
2773 ipmi_sel_get_time(intf);
2774
2775 return 0;
2776 }
2777
2778
2779
2780 static int
ipmi_sel_clear(struct ipmi_intf * intf)2781 ipmi_sel_clear(struct ipmi_intf * intf)
2782 {
2783 struct ipmi_rs * rsp;
2784 struct ipmi_rq req;
2785 uint16_t reserve_id;
2786 uint8_t msg_data[6];
2787
2788 reserve_id = ipmi_sel_reserve(intf);
2789 if (reserve_id == 0)
2790 return -1;
2791
2792 memset(msg_data, 0, 6);
2793 msg_data[0] = reserve_id & 0xff;
2794 msg_data[1] = reserve_id >> 8;
2795 msg_data[2] = 'C';
2796 msg_data[3] = 'L';
2797 msg_data[4] = 'R';
2798 msg_data[5] = 0xaa;
2799
2800 memset(&req, 0, sizeof(req));
2801 req.msg.netfn = IPMI_NETFN_STORAGE;
2802 req.msg.cmd = IPMI_CMD_CLEAR_SEL;
2803 req.msg.data = msg_data;
2804 req.msg.data_len = 6;
2805
2806 rsp = intf->sendrecv(intf, &req);
2807 if (rsp == NULL) {
2808 lprintf(LOG_ERR, "Unable to clear SEL");
2809 return -1;
2810 }
2811 if (rsp->ccode > 0) {
2812 lprintf(LOG_ERR, "Unable to clear SEL: %s",
2813 val2str(rsp->ccode, completion_code_vals));
2814 return -1;
2815 }
2816
2817 printf("Clearing SEL. Please allow a few seconds to erase.\n");
2818 return 0;
2819 }
2820
2821 static int
ipmi_sel_delete(struct ipmi_intf * intf,int argc,char ** argv)2822 ipmi_sel_delete(struct ipmi_intf * intf, int argc, char ** argv)
2823 {
2824 struct ipmi_rs * rsp;
2825 struct ipmi_rq req;
2826 uint16_t id;
2827 uint8_t msg_data[4];
2828 int rc = 0;
2829
2830 if (argc == 0 || strncmp(argv[0], "help", 4) == 0) {
2831 lprintf(LOG_ERR, "usage: delete <id>...<id>\n");
2832 return -1;
2833 }
2834
2835 id = ipmi_sel_reserve(intf);
2836 if (id == 0)
2837 return -1;
2838
2839 memset(msg_data, 0, 4);
2840 msg_data[0] = id & 0xff;
2841 msg_data[1] = id >> 8;
2842
2843 for (; argc != 0; argc--)
2844 {
2845 if (str2ushort(argv[argc-1], &id) != 0) {
2846 lprintf(LOG_ERR, "Given SEL ID '%s' is invalid.",
2847 argv[argc-1]);
2848 rc = (-1);
2849 continue;
2850 }
2851 msg_data[2] = id & 0xff;
2852 msg_data[3] = id >> 8;
2853
2854 memset(&req, 0, sizeof(req));
2855 req.msg.netfn = IPMI_NETFN_STORAGE;
2856 req.msg.cmd = IPMI_CMD_DELETE_SEL_ENTRY;
2857 req.msg.data = msg_data;
2858 req.msg.data_len = 4;
2859
2860 rsp = intf->sendrecv(intf, &req);
2861 if (rsp == NULL) {
2862 lprintf(LOG_ERR, "Unable to delete entry %d", id);
2863 rc = -1;
2864 }
2865 else if (rsp->ccode > 0) {
2866 lprintf(LOG_ERR, "Unable to delete entry %d: %s", id,
2867 val2str(rsp->ccode, completion_code_vals));
2868 rc = -1;
2869 }
2870 else {
2871 printf("Deleted entry %d\n", id);
2872 }
2873 }
2874
2875 return rc;
2876 }
2877
2878 static int
ipmi_sel_show_entry(struct ipmi_intf * intf,int argc,char ** argv)2879 ipmi_sel_show_entry(struct ipmi_intf * intf, int argc, char ** argv)
2880 {
2881 struct entity_id entity;
2882 struct sdr_record_list *entry;
2883 struct sdr_record_list *list;
2884 struct sdr_record_list *sdr;
2885 struct sel_event_record evt;
2886 int i;
2887 int oldv;
2888 int rc = 0;
2889 uint16_t id;
2890
2891 if (argc == 0 || strncmp(argv[0], "help", 4) == 0) {
2892 lprintf(LOG_ERR, "usage: sel get <id>...<id>");
2893 return (-1);
2894 }
2895
2896 if (ipmi_sel_reserve(intf) == 0) {
2897 lprintf(LOG_ERR, "Unable to reserve SEL");
2898 return (-1);
2899 }
2900
2901 for (i = 0; i < argc; i++) {
2902 if (str2ushort(argv[i], &id) != 0) {
2903 lprintf(LOG_ERR, "Given SEL ID '%s' is invalid.",
2904 argv[i]);
2905 rc = (-1);
2906 continue;
2907 }
2908
2909 lprintf(LOG_DEBUG, "Looking up SEL entry 0x%x", id);
2910
2911 /* lookup SEL entry based on ID */
2912 if (!ipmi_sel_get_std_entry(intf, id, &evt)) {
2913 lprintf(LOG_DEBUG, "SEL Entry 0x%x not found.", id);
2914 rc = (-1);
2915 continue;
2916 }
2917 if (evt.sel_type.standard_type.sensor_num == 0
2918 && evt.sel_type.standard_type.sensor_type == 0
2919 && evt.record_type == 0) {
2920 lprintf(LOG_WARN, "SEL Entry 0x%x not found", id);
2921 rc = (-1);
2922 continue;
2923 }
2924
2925 /* lookup SDR entry based on sensor number and type */
2926 ipmi_sel_print_extended_entry_verbose(intf, &evt);
2927
2928 sdr = ipmi_sdr_find_sdr_bynumtype(intf,
2929 evt.sel_type.standard_type.gen_id,
2930 evt.sel_type.standard_type.sensor_num,
2931 evt.sel_type.standard_type.sensor_type);
2932 if (sdr == NULL) {
2933 continue;
2934 }
2935
2936 /* print SDR entry */
2937 oldv = verbose;
2938 verbose = verbose ? verbose : 1;
2939 switch (sdr->type) {
2940 case SDR_RECORD_TYPE_FULL_SENSOR:
2941 case SDR_RECORD_TYPE_COMPACT_SENSOR:
2942 ipmi_sensor_print_fc(intf, sdr->record.common,
2943 sdr->type);
2944 entity.id = sdr->record.common->entity.id;
2945 entity.instance = sdr->record.common->entity.instance;
2946 break;
2947 case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
2948 ipmi_sdr_print_sensor_eventonly(intf, sdr->record.eventonly);
2949 entity.id = sdr->record.eventonly->entity.id;
2950 entity.instance = sdr->record.eventonly->entity.instance;
2951 break;
2952 default:
2953 verbose = oldv;
2954 continue;
2955 }
2956 verbose = oldv;
2957
2958 /* lookup SDR entry based on entity id */
2959 list = ipmi_sdr_find_sdr_byentity(intf, &entity);
2960 for (entry=list; entry; entry=entry->next) {
2961 /* print FRU devices we find for this entity */
2962 if (entry->type == SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR)
2963 ipmi_fru_print(intf, entry->record.fruloc);
2964 }
2965
2966 if ((argc > 1) && (i < (argc - 1))) {
2967 printf("----------------------\n\n");
2968 }
2969 }
2970
2971 return rc;
2972 }
2973
ipmi_sel_main(struct ipmi_intf * intf,int argc,char ** argv)2974 int ipmi_sel_main(struct ipmi_intf * intf, int argc, char ** argv)
2975 {
2976 int rc = 0;
2977
2978 if (argc == 0)
2979 rc = ipmi_sel_get_info(intf);
2980 else if (strncmp(argv[0], "help", 4) == 0)
2981 lprintf(LOG_ERR, "SEL Commands: "
2982 "info clear delete list elist get add time save readraw writeraw interpret");
2983 else if (strncmp(argv[0], "interpret", 9) == 0) {
2984 uint32_t iana = 0;
2985 if (argc < 4) {
2986 lprintf(LOG_NOTICE, "usage: sel interpret iana filename format(pps)");
2987 return 0;
2988 }
2989 if (str2uint(argv[1], &iana) != 0) {
2990 lprintf(LOG_ERR, "Given IANA '%s' is invalid.",
2991 argv[1]);
2992 return (-1);
2993 }
2994 rc = ipmi_sel_interpret(intf, iana, argv[2], argv[3]);
2995 }
2996 else if (strncmp(argv[0], "info", 4) == 0)
2997 rc = ipmi_sel_get_info(intf);
2998 else if (strncmp(argv[0], "save", 4) == 0) {
2999 if (argc < 2) {
3000 lprintf(LOG_NOTICE, "usage: sel save <filename>");
3001 return 0;
3002 }
3003 rc = ipmi_sel_save_entries(intf, 0, argv[1]);
3004 }
3005 else if (strncmp(argv[0], "add", 3) == 0) {
3006 if (argc < 2) {
3007 lprintf(LOG_NOTICE, "usage: sel add <filename>");
3008 return 0;
3009 }
3010 rc = ipmi_sel_add_entries_fromfile(intf, argv[1]);
3011 }
3012 else if (strncmp(argv[0], "writeraw", 8) == 0) {
3013 if (argc < 2) {
3014 lprintf(LOG_NOTICE, "usage: sel writeraw <filename>");
3015 return 0;
3016 }
3017 rc = ipmi_sel_writeraw(intf, argv[1]);
3018 }
3019 else if (strncmp(argv[0], "readraw", 7) == 0) {
3020 if (argc < 2) {
3021 lprintf(LOG_NOTICE, "usage: sel readraw <filename>");
3022 return 0;
3023 }
3024 rc = ipmi_sel_readraw(intf, argv[1]);
3025 }
3026 else if (strncmp(argv[0], "ereadraw", 8) == 0) {
3027 if (argc < 2) {
3028 lprintf(LOG_NOTICE, "usage: sel ereadraw <filename>");
3029 return 0;
3030 }
3031 sel_extended = 1;
3032 rc = ipmi_sel_readraw(intf, argv[1]);
3033 }
3034 else if (strncmp(argv[0], "list", 4) == 0 ||
3035 strncmp(argv[0], "elist", 5) == 0) {
3036 /*
3037 * Usage:
3038 * list - show all SEL entries
3039 * list first <n> - show the first (oldest) <n> SEL entries
3040 * list last <n> - show the last (newsest) <n> SEL entries
3041 */
3042 int count = 0;
3043 int sign = 1;
3044 char *countstr = NULL;
3045
3046 if (strncmp(argv[0], "elist", 5) == 0)
3047 sel_extended = 1;
3048 else
3049 sel_extended = 0;
3050
3051 if (argc == 2) {
3052 countstr = argv[1];
3053 }
3054 else if (argc == 3) {
3055 countstr = argv[2];
3056
3057 if (strncmp(argv[1], "last", 4) == 0) {
3058 sign = -1;
3059 }
3060 else if (strncmp(argv[1], "first", 5) != 0) {
3061 lprintf(LOG_ERR, "Unknown sel list option");
3062 return -1;
3063 }
3064 }
3065
3066 if (countstr) {
3067 if (str2int(countstr, &count) != 0) {
3068 lprintf(LOG_ERR, "Numeric argument required; got '%s'",
3069 countstr);
3070 return -1;
3071 }
3072 }
3073 count *= sign;
3074
3075 rc = ipmi_sel_list_entries(intf,count);
3076 }
3077 else if (strncmp(argv[0], "clear", 5) == 0)
3078 rc = ipmi_sel_clear(intf);
3079 else if (strncmp(argv[0], "delete", 6) == 0) {
3080 if (argc < 2)
3081 lprintf(LOG_ERR, "usage: sel delete <id>...<id>");
3082 else
3083 rc = ipmi_sel_delete(intf, argc-1, &argv[1]);
3084 }
3085 else if (strncmp(argv[0], "get", 3) == 0) {
3086 if (argc < 2)
3087 lprintf(LOG_ERR, "usage: sel get <entry>");
3088 else
3089 rc = ipmi_sel_show_entry(intf, argc-1, &argv[1]);
3090 }
3091 else if (strncmp(argv[0], "time", 4) == 0) {
3092 if (argc < 2)
3093 lprintf(LOG_ERR, "sel time commands: get set");
3094 else if (strncmp(argv[1], "get", 3) == 0)
3095 ipmi_sel_get_time(intf);
3096 else if (strncmp(argv[1], "set", 3) == 0) {
3097 if (argc < 3)
3098 lprintf(LOG_ERR, "usage: sel time set \"mm/dd/yyyy hh:mm:ss\"");
3099 else
3100 rc = ipmi_sel_set_time(intf, argv[2]);
3101 } else {
3102 lprintf(LOG_ERR, "sel time commands: get set");
3103 }
3104 }
3105 else {
3106 lprintf(LOG_ERR, "Invalid SEL command: %s", argv[0]);
3107 rc = -1;
3108 }
3109
3110 return rc;
3111 }
3112