1 /* 2 * Redistribution and use in source and binary forms, with or without 3 * modification, are permitted provided that the following conditions 4 * are met: 5 * 6 * Redistribution of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * 9 * Redistribution in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * Neither the name of Sun Microsystems, Inc. or the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * This software is provided "AS IS," without a warranty of any kind. 18 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, 19 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A 20 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. 21 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE 22 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING 23 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL 24 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, 25 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR 26 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF 27 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 28 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 29 */ 30 31 /* 32 * Functions to program the SDR repository, from built-in sensors or 33 * from sensors dumped in a binary file. 34 */ 35 36 #include <stdlib.h> 37 #include <string.h> 38 #include <stdio.h> 39 #include <time.h> 40 #include <fcntl.h> 41 42 #include <ipmitool/helper.h> 43 #include <ipmitool/log.h> 44 #include <ipmitool/bswap.h> 45 #include <ipmitool/ipmi.h> 46 #include <ipmitool/ipmi_intf.h> 47 #include <ipmitool/ipmi_mc.h> 48 #include <ipmitool/ipmi_strings.h> 49 50 #include <ipmitool/ipmi_sdr.h> 51 52 53 #define ADD_PARTIAL_SDR 0x25 54 55 #ifdef HAVE_PRAGMA_PACK 56 #pragma pack(1) 57 #endif 58 struct sdr_add_rq { 59 uint16_t reserve_id; /* reservation ID */ 60 uint16_t id; /* record ID */ 61 uint8_t offset; /* offset into SDR */ 62 uint8_t in_progress; /* 0=partial, 1=last */ 63 #define PARTIAL_ADD (0) 64 #define LAST_RECORD (1) 65 uint8_t data[1]; /* SDR record data */ 66 } ATTRIBUTE_PACKING; 67 #ifdef HAVE_PRAGMA_PACK 68 #pragma pack(0) 69 #endif 70 71 /* This was formerly initialized to 24, reduced this to 19 so the overall 72 message fits into the recommended 32-byte limit */ 73 static int sdr_max_write_len = 19; 74 int ipmi_parse_range_list(const char *rangeList, unsigned char *pHexList); 75 int ipmi_hex_to_dec( char * rangeList, unsigned char * pDecValue); 76 77 static int 78 partial_send(struct ipmi_intf *intf, struct ipmi_rq *req, uint16_t *id) 79 { 80 struct ipmi_rs *rsp; 81 rsp = intf->sendrecv(intf, req); 82 if (rsp == NULL) { 83 return -1; 84 } 85 86 if (rsp->ccode || rsp->data_len < 2) { 87 return -1; 88 } 89 90 *id = rsp->data[0] + (rsp->data[1] << 8); 91 return 0; 92 } 93 94 int 95 ipmi_sdr_add_record(struct ipmi_intf *intf, struct sdr_record_list *sdrr) 96 { 97 struct ipmi_rq req; 98 struct sdr_add_rq *sdr_rq; 99 uint16_t reserve_id; 100 uint16_t id; 101 int i; 102 int len = sdrr->length; 103 int rc = 0; 104 105 /* actually no SDR to program */ 106 if (len < 1 || !sdrr->raw) { 107 lprintf(LOG_ERR, "ipmitool: bad record , skipped"); 108 return 0; 109 } 110 111 if (ipmi_sdr_get_reservation(intf, 0, &reserve_id)) { 112 lprintf(LOG_ERR, "ipmitool: reservation failed"); 113 return -1; 114 } 115 116 sdr_rq = (struct sdr_add_rq *)malloc(sizeof(*sdr_rq) + sdr_max_write_len); 117 if (sdr_rq == NULL) { 118 lprintf(LOG_ERR, "ipmitool: malloc failure"); 119 return -1; 120 } 121 sdr_rq->reserve_id = reserve_id; 122 sdr_rq->in_progress = PARTIAL_ADD; 123 124 memset(&req, 0, sizeof(req)); 125 req.msg.netfn = IPMI_NETFN_STORAGE; 126 req.msg.cmd = ADD_PARTIAL_SDR; 127 req.msg.data = (uint8_t *) sdr_rq; 128 129 /* header first */ 130 sdr_rq->id = 0; 131 sdr_rq->offset = 0; 132 sdr_rq->data[0] = sdrr->id & 0xFF; 133 sdr_rq->data[1] = (sdrr->id >> 8) & 0xFF; 134 sdr_rq->data[2] = sdrr->version; 135 sdr_rq->data[3] = sdrr->type; 136 sdr_rq->data[4] = sdrr->length; 137 req.msg.data_len = 5 + sizeof(*sdr_rq) - 1; 138 139 if (partial_send(intf, &req, &id)) { 140 lprintf(LOG_ERR, "ipmitool: partial send error"); 141 free(sdr_rq); 142 sdr_rq = NULL; 143 return -1; 144 } 145 146 i = 0; 147 148 /* sdr entry */ 149 while (i < len) { 150 int data_len = 0; 151 if ( (len - i) <= sdr_max_write_len) { 152 /* last crunch */ 153 data_len = len - i; 154 sdr_rq->in_progress = LAST_RECORD; 155 } else { 156 data_len = sdr_max_write_len; 157 } 158 159 sdr_rq->id = id; 160 sdr_rq->offset = i + 5; 161 memcpy(sdr_rq->data, sdrr->raw + i, data_len); 162 req.msg.data_len = data_len + sizeof(*sdr_rq) - 1; 163 164 if ((rc = partial_send(intf, &req, &id)) != 0) { 165 lprintf(LOG_ERR, "ipmitool: partial add failed"); 166 break; 167 } 168 169 i += data_len; 170 } 171 172 free(sdr_rq); 173 sdr_rq = NULL; 174 return rc; 175 } 176 177 static int 178 ipmi_sdr_repo_clear(struct ipmi_intf *intf) 179 { 180 struct ipmi_rs * rsp; 181 struct ipmi_rq req; 182 uint8_t msg_data[8]; 183 uint16_t reserve_id; 184 int try; 185 186 if (ipmi_sdr_get_reservation(intf, 0, &reserve_id)) 187 return -1; 188 189 memset(&req, 0, sizeof(req)); 190 req.msg.netfn = IPMI_NETFN_STORAGE; 191 req.msg.cmd = 0x27; // FIXME 192 req.msg.data = msg_data; 193 req.msg.data_len = 6; 194 195 msg_data[0] = reserve_id & 0xFF; 196 msg_data[1] = reserve_id >> 8; 197 msg_data[2] = 'C'; 198 msg_data[3] = 'L'; 199 msg_data[4] = 'R'; 200 msg_data[5] = 0xAA; 201 202 for (try = 0; try < 5; try++) { 203 rsp = intf->sendrecv(intf, &req); 204 if (rsp == NULL) { 205 lprintf(LOG_ERR, "Unable to clear SDRR"); 206 return -1; 207 } 208 if (rsp->ccode > 0) { 209 lprintf(LOG_ERR, "Unable to clear SDRR: %s", 210 val2str(rsp->ccode, completion_code_vals)); 211 return -1; 212 } 213 if ((rsp->data[0] & 1) == 1) { 214 printf("SDRR successfully erased\n"); 215 return 0; 216 } 217 printf("Wait for SDRR erasure completed...\n"); 218 msg_data[5] = 0; 219 sleep(1); 220 } 221 222 /* if we are here we fed up trying erase */ 223 return -1; 224 } 225 226 227 struct sdrr_queue { 228 struct sdr_record_list *head; 229 struct sdr_record_list *tail; 230 }; 231 232 233 /* 234 * Fill the SDR repository from built-in sensors 235 * 236 */ 237 238 /* 239 * Get all the SDR records stored in <queue> 240 */ 241 static int 242 sdrr_get_records(struct ipmi_intf *intf, struct ipmi_sdr_iterator *itr, 243 struct sdrr_queue *queue) 244 { 245 struct sdr_get_rs *header; 246 247 queue->head = NULL; 248 queue->tail = NULL; 249 250 while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) { 251 struct sdr_record_list *sdrr; 252 253 sdrr = malloc(sizeof (struct sdr_record_list)); 254 if (sdrr == NULL) { 255 lprintf(LOG_ERR, "ipmitool: malloc failure"); 256 return -1; 257 } 258 memset(sdrr, 0, sizeof (struct sdr_record_list)); 259 260 sdrr->id = header->id; 261 sdrr->version = header->version; 262 sdrr->type = header->type; 263 sdrr->length = header->length; 264 sdrr->raw = ipmi_sdr_get_record(intf, header, itr); 265 (void)ipmi_sdr_print_name_from_rawentry(intf, sdrr->id, sdrr->type,sdrr->raw); 266 267 /* put in the record queue */ 268 if (queue->head == NULL) 269 queue->head = sdrr; 270 else 271 queue->tail->next = sdrr; 272 queue->tail = sdrr; 273 } 274 return 0; 275 } 276 277 static int 278 sdr_copy_to_sdrr(struct ipmi_intf *intf, int use_builtin, 279 int from_addr, int to_addr) 280 { 281 int rc; 282 struct sdrr_queue sdrr_queue; 283 struct ipmi_sdr_iterator *itr; 284 struct sdr_record_list *sdrr; 285 struct sdr_record_list *sdrr_next; 286 287 /* generate list of records for this target */ 288 intf->target_addr = from_addr; 289 290 /* initialize iterator */ 291 itr = ipmi_sdr_start(intf, use_builtin); 292 if (itr == 0) 293 return 0; 294 295 printf("Load SDRs from 0x%x\n", from_addr); 296 rc = sdrr_get_records(intf, itr, &sdrr_queue); 297 ipmi_sdr_end(intf, itr); 298 /* ... */ 299 300 /* write the SDRs to the destination SDR Repository */ 301 intf->target_addr = to_addr; 302 for (sdrr = sdrr_queue.head; sdrr != NULL; sdrr = sdrr_next) { 303 sdrr_next = sdrr->next; 304 rc = ipmi_sdr_add_record(intf, sdrr); 305 if(rc < 0){ 306 lprintf(LOG_ERR, "Cannot add SDR ID 0x%04x to repository...", sdrr->id); 307 } 308 free(sdrr); 309 sdrr = NULL; 310 } 311 return rc; 312 } 313 314 int 315 ipmi_sdr_add_from_sensors(struct ipmi_intf *intf, int maxslot) 316 { 317 int i; 318 int rc = 0; 319 int slave_addr; 320 int myaddr = intf->target_addr; 321 322 if (ipmi_sdr_repo_clear(intf)) { 323 lprintf(LOG_ERR, "Cannot erase SDRR. Give up."); 324 return -1; 325 } 326 327 /* First fill the SDRR from local built-in sensors */ 328 rc = sdr_copy_to_sdrr(intf, 1, myaddr, myaddr); 329 330 /* Now fill the SDRR with remote sensors */ 331 if( maxslot != 0 ) { 332 for (i = 0, slave_addr = 0xB0; i < maxslot; i++, slave_addr += 2) { 333 /* Hole in the PICMG 2.9 mapping */ 334 if (slave_addr == 0xC2) slave_addr += 2; 335 if(sdr_copy_to_sdrr(intf, 0, slave_addr, myaddr) < 0) 336 { 337 rc = -1; 338 } 339 } 340 } 341 return rc; 342 } 343 344 int ipmi_hex_to_dec( char * strchar, unsigned char * pDecValue) 345 { 346 int rc = -1; 347 unsigned char retValue = 0; 348 349 if( 350 (strlen(strchar) == 4) 351 && 352 (strchar[0] == '0') 353 && 354 (strchar[1] == 'x') 355 ) 356 { 357 rc = 0; 358 359 if((strchar[2] >= '0') && (strchar[2] <= '9')) 360 { 361 retValue += ((strchar[2]-'0') * 16); 362 } 363 else if((strchar[2] >= 'a') && (strchar[2] <= 'f')) 364 { 365 retValue += (((strchar[2]-'a') + 10) * 16); 366 } 367 else if((strchar[2] >= 'A') && (strchar[2] <= 'F')) 368 { 369 retValue += (((strchar[2]-'A') + 10) * 16); 370 } 371 else 372 { 373 rc = -1; 374 } 375 376 if((strchar[3] >= '0') && (strchar[3] <= '9')) 377 { 378 retValue += ((strchar[3]-'0')); 379 } 380 else if((strchar[3] >= 'a') && (strchar[3] <= 'f')) 381 { 382 retValue += (((strchar[3]-'a') + 10)); 383 } 384 else if((strchar[3] >= 'A') && (strchar[3] <= 'F')) 385 { 386 retValue += (((strchar[3]-'A') + 10)); 387 } 388 else 389 { 390 rc = -1; 391 } 392 } 393 394 if(rc == 0) 395 { 396 * pDecValue = retValue; 397 } 398 else 399 { 400 lprintf(LOG_ERR, "Must be Hex value of 4 characters (Ex.: 0x24)"); 401 } 402 403 return rc; 404 } 405 406 407 408 #define MAX_NUM_SLOT 128 409 int ipmi_parse_range_list(const char *rangeList, unsigned char * pHexList) 410 { 411 int rc = -1; 412 413 unsigned char listOffset = 0; 414 char * nextString; 415 char * rangeString; 416 char * inProcessString = (char *) rangeList; 417 418 /* Discard empty string */ 419 if(strlen(rangeList) == 0) 420 { 421 return rc; 422 } 423 424 /* First, cut to comma separated string */ 425 nextString = strstr( rangeList, "," ); 426 427 if(nextString != rangeList) 428 { 429 unsigned char isLast; 430 /* We get a valid string so far */ 431 rc = 0; 432 433 do 434 { 435 if(nextString != NULL) 436 { 437 (*nextString)= 0; 438 nextString ++; 439 isLast = 0; 440 } 441 else 442 { 443 isLast = 1; 444 } 445 446 /* At this point, it is a single entry or a range */ 447 rangeString = strstr( inProcessString, "-" ); 448 if(rangeString == NULL) 449 { 450 unsigned char decValue = 0; 451 452 /* Single entry */ 453 rc = ipmi_hex_to_dec( inProcessString, &decValue); 454 455 if(rc == 0) 456 { 457 if((decValue % 2) == 0) 458 { 459 pHexList[listOffset++] = decValue; 460 } 461 else 462 { 463 lprintf(LOG_ERR, "I2C address provided value must be even."); 464 } 465 } 466 } 467 else 468 { 469 unsigned char startValue = 0; 470 unsigned char endValue = 0; 471 472 473 (*rangeString)= 0; /* Cut string*/ 474 rangeString ++; 475 476 /* Range */ 477 rc = ipmi_hex_to_dec( inProcessString, &startValue); 478 if(rc == 0) 479 rc = ipmi_hex_to_dec( rangeString, &endValue); 480 481 if(rc == 0) 482 { 483 if(((startValue % 2) == 0) && ((endValue % 2) == 0)) 484 { 485 do 486 { 487 pHexList[listOffset++] = startValue; 488 startValue += 2; 489 } 490 while(startValue != endValue); 491 pHexList[listOffset++] = endValue; 492 } 493 else 494 { 495 lprintf(LOG_ERR, "I2C address provided value must be even."); 496 } 497 } 498 } 499 500 if(isLast == 0) 501 { 502 /* Setup for next string */ 503 inProcessString = nextString; 504 nextString = strstr( rangeList, "," ); 505 } 506 }while ((isLast == 0) && (rc == 0)); 507 } 508 509 return rc; 510 } 511 512 int 513 ipmi_sdr_add_from_list(struct ipmi_intf *intf, const char *rangeList) 514 { 515 int rc = 0; 516 int slave_addr; 517 int myaddr = intf->target_addr; 518 unsigned char listValue[MAX_NUM_SLOT]; 519 520 memset( listValue, 0, MAX_NUM_SLOT ); 521 522 /* Build list from string */ 523 if(ipmi_parse_range_list(rangeList, listValue) != 0) 524 { 525 lprintf(LOG_ERR, "Range - List invalid, cannot be parsed."); 526 return -1; 527 } 528 529 { 530 unsigned char counter = 0; 531 printf("List to scan: (Built-in) "); 532 while(listValue[counter] != 0) 533 { 534 printf("%02x ", listValue[counter]); 535 counter++; 536 } 537 printf("\n"); 538 } 539 540 printf("Clearing SDR Repository\n"); 541 if (ipmi_sdr_repo_clear(intf)) { 542 lprintf(LOG_ERR, "Cannot erase SDRR. Give up."); 543 return -1; 544 } 545 546 /* First fill the SDRR from local built-in sensors */ 547 printf("Sanning built-in sensors..\n"); 548 rc = sdr_copy_to_sdrr(intf, 1, myaddr, myaddr); 549 550 /* Now fill the SDRR with provided sensors list */ 551 { 552 unsigned char counter = 0; 553 while((rc == 0) && (listValue[counter] != 0)) 554 { 555 slave_addr = listValue[counter]; 556 printf("Scanning %02Xh..\n", slave_addr); 557 if(sdr_copy_to_sdrr(intf, 0, slave_addr, myaddr) < 0) 558 { 559 rc = -1; 560 } 561 counter++; 562 } 563 } 564 565 return rc; 566 } 567 568 569 /* 570 * Fill the SDR repository from records stored in a binary file 571 * 572 */ 573 574 static int 575 ipmi_sdr_read_records(const char *filename, struct sdrr_queue *queue) 576 { 577 int rc = 0; 578 int fd; 579 uint8_t binHdr[5]; 580 581 queue->head = NULL; 582 queue->tail = NULL; 583 584 if ((fd = open(filename, O_RDONLY)) < 0) { 585 return -1; 586 } 587 588 while (read(fd, binHdr, 5) == 5) { 589 590 struct sdr_record_list *sdrr; 591 592 lprintf(LOG_DEBUG, "binHdr[0] (id[MSB]) = 0x%02x", binHdr[0]); 593 lprintf(LOG_DEBUG, "binHdr[1] (id[LSB]) = 0x%02x", binHdr[1]); 594 lprintf(LOG_DEBUG, "binHdr[2] (version) = 0x%02x", binHdr[2]); 595 lprintf(LOG_DEBUG, "binHdr[3] (type) = 0x%02x", binHdr[3]); 596 lprintf(LOG_DEBUG, "binHdr[4] (length) = 0x%02x", binHdr[4]); 597 598 sdrr = malloc(sizeof(*sdrr)); 599 if (sdrr == NULL) { 600 lprintf(LOG_ERR, "ipmitool: malloc failure"); 601 rc = -1; 602 break; 603 } 604 sdrr->id = (binHdr[1] << 8) | binHdr[0]; // LS Byte first 605 sdrr->version = binHdr[2]; 606 sdrr->type = binHdr[3]; 607 sdrr->length = binHdr[4]; 608 609 if ((sdrr->raw = malloc(sdrr->length)) == NULL) { 610 lprintf(LOG_ERR, "ipmitool: malloc failure"); 611 free(sdrr); 612 sdrr = NULL; 613 rc = -1; 614 break; 615 } 616 617 if (read(fd, sdrr->raw, sdrr->length) != sdrr->length) { 618 lprintf(LOG_ERR, "SDR from '%s' truncated", filename); 619 free(sdrr->raw); 620 sdrr->raw = NULL; 621 free(sdrr); 622 sdrr = NULL; 623 rc = -1; 624 break; 625 } 626 627 /* put in the record queue */ 628 if (queue->head == NULL) 629 queue->head = sdrr; 630 else 631 queue->tail->next = sdrr; 632 queue->tail = sdrr; 633 } 634 close(fd); 635 return rc; 636 } 637 638 int 639 ipmi_sdr_add_from_file(struct ipmi_intf *intf, const char *ifile) 640 { 641 int rc; 642 struct sdrr_queue sdrr_queue; 643 struct sdr_record_list *sdrr; 644 struct sdr_record_list *sdrr_next; 645 646 /* read the SDR records from file */ 647 rc = ipmi_sdr_read_records(ifile, &sdrr_queue); 648 649 if (ipmi_sdr_repo_clear(intf)) { 650 lprintf(LOG_ERR, "Cannot erase SDRR. Giving up."); 651 /* FIXME: free sdr list */ 652 return -1; 653 } 654 655 /* write the SDRs to the SDR Repository */ 656 for (sdrr = sdrr_queue.head; sdrr != NULL; sdrr = sdrr_next) { 657 sdrr_next = sdrr->next; 658 rc = ipmi_sdr_add_record(intf, sdrr); 659 if(rc < 0){ 660 lprintf(LOG_ERR, "Cannot add SDR ID 0x%04x to repository...", sdrr->id); 661 } 662 free(sdrr); 663 sdrr = NULL; 664 } 665 return rc; 666 } 667 668