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 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 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 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 * 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 * 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 * 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 * 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 * 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 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 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 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 * 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 * 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 * 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 */ 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 * 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 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 * 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 * 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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