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