1 /* 2 * Copyright (c) 2004 Kontron Canada, Inc. All Rights Reserved. 3 * 4 * Base on code from 5 * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * Redistribution of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * Redistribution in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * Neither the name of Sun Microsystems, Inc. or the names of 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * This software is provided "AS IS," without a warranty of any kind. 23 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, 24 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A 25 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. 26 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE 27 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING 28 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL 29 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, 30 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR 31 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF 32 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 33 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 34 */ 35 36 /* 37 * Tue Mar 7 14:36:12 2006 38 * <stephane.filion@ca.kontron.com> 39 * 40 * This code implements an Kontron OEM proprietary commands. 41 */ 42 #include <string.h> 43 #include <ipmitool/helper.h> 44 #include <ipmitool/log.h> 45 #include <ipmitool/ipmi.h> 46 #include <ipmitool/ipmi_intf.h> 47 #include <ipmitool/ipmi_fru.h> 48 49 extern int verbose; 50 extern int read_fru_area(struct ipmi_intf *intf, struct fru_info *fru, 51 uint8_t id, uint32_t offset, uint32_t length, 52 uint8_t *frubuf); 53 extern int write_fru_area(struct ipmi_intf * intf, struct fru_info *fru, 54 uint8_t id, uint16_t soffset, 55 uint16_t doffset, uint16_t length, 56 uint8_t *pFrubuf); 57 extern char *get_fru_area_str(uint8_t *data, uint32_t *offset); 58 59 static void ipmi_kontron_help(void); 60 static int ipmi_kontron_set_serial_number(struct ipmi_intf *intf); 61 static int ipmi_kontron_set_mfg_date (struct ipmi_intf *intf); 62 static void ipmi_kontron_nextboot_help(void); 63 static int ipmi_kontron_nextboot_set(struct ipmi_intf *intf, int argc, 64 char **argv); 65 static int ipmi_kontronoem_send_set_large_buffer(struct ipmi_intf *intf, 66 unsigned char channel, unsigned char size); 67 68 static char *bootdev[] = {"BIOS", "FDD", "HDD", "CDROM", "network", 0}; 69 70 int 71 ipmi_kontronoem_main(struct ipmi_intf *intf, int argc, char **argv) 72 { 73 int rc = 0; 74 if (argc == 0) { 75 lprintf(LOG_ERR, "Not enough parameters given."); 76 ipmi_kontron_help(); 77 return (-1); 78 } 79 if (strncmp(argv[0], "help", 4) == 0) { 80 ipmi_kontron_help(); 81 rc = 0; 82 } else if (!strncmp(argv[0], "setsn", 5)) { 83 if (argc < 1) { 84 printf("fru setsn\n"); 85 return (-1); 86 } 87 if (ipmi_kontron_set_serial_number(intf) > 0) { 88 printf("FRU serial number setted successfully\n"); 89 } else { 90 printf("FRU serial number set failed\n"); 91 rc = (-1); 92 } 93 } else if (!strncmp(argv[0], "setmfgdate", 10)) { 94 if (argc < 1) { 95 printf("fru setmfgdate\n"); 96 return (-1); 97 } 98 if (ipmi_kontron_set_mfg_date(intf) > 0) { 99 printf("FRU manufacturing date setted successfully\n"); 100 } else { 101 printf("FRU manufacturing date set failed\n"); 102 rc = (-1); 103 } 104 } else if (!strncmp(argv[0], "nextboot", 8)) { 105 if (argc < 2) { 106 lprintf(LOG_ERR, "Not enough parameters given."); 107 ipmi_kontron_nextboot_help(); 108 return (-1); 109 } 110 rc = ipmi_kontron_nextboot_set(intf, (argc - 1), (argv + 1)); 111 if (rc == 0) { 112 printf("Nextboot set successfully\n"); 113 } else { 114 printf("Nextboot set failed\n"); 115 rc = (-1); 116 } 117 } else { 118 lprintf(LOG_ERR, "Invalid Kontron command: %s", argv[0]); 119 ipmi_kontron_help(); 120 rc = (-1); 121 } 122 return rc; 123 } 124 125 static void 126 ipmi_kontron_help(void) 127 { 128 printf("Kontron Commands: setsn setmfgdate nextboot\n"); 129 } 130 131 int 132 ipmi_kontronoem_set_large_buffer(struct ipmi_intf *intf, unsigned char size) 133 { 134 uint8_t error_occurs = 0; 135 uint32_t prev_target_addr = intf->target_addr ; 136 if (intf->target_addr > 0 && (intf->target_addr != intf->my_addr)) { 137 intf->target_addr = intf->my_addr; 138 printf("Set local big buffer\n"); 139 if (ipmi_kontronoem_send_set_large_buffer(intf, 0x0e, size) == 0) { 140 printf("Set local big buffer:success\n"); 141 } else { 142 error_occurs = 1; 143 } 144 if (error_occurs == 0) { 145 if (ipmi_kontronoem_send_set_large_buffer(intf, 0x00, size) == 0) { 146 printf("IPMB was set\n"); 147 } else { 148 /* Revert back the previous set large buffer */ 149 error_occurs = 1; 150 ipmi_kontronoem_send_set_large_buffer( intf, 0x0e, 0 ); 151 } 152 } 153 /* Restore target address */ 154 intf->target_addr = prev_target_addr; 155 } 156 if (error_occurs == 0) { 157 if(ipmi_kontronoem_send_set_large_buffer(intf, 0x0e, size) == 0) { 158 /* printf("Set remote big buffer\n"); */ 159 } else { 160 if (intf->target_addr > 0 && (intf->target_addr != intf->my_addr)) { 161 /* Error occurs revert back the previous set large buffer */ 162 intf->target_addr = intf->my_addr; 163 /* ipmi_kontronoem_send_set_large_buffer(intf, 0x00, 0); */ 164 ipmi_kontronoem_send_set_large_buffer(intf, 0x0e, 0); 165 intf->target_addr = prev_target_addr; 166 } 167 } 168 } 169 return error_occurs; 170 } 171 172 int 173 ipmi_kontronoem_send_set_large_buffer(struct ipmi_intf *intf, 174 unsigned char channel, unsigned char size) 175 { 176 struct ipmi_rs *rsp; 177 struct ipmi_rq req; 178 uint8_t msg_data[2]; 179 memset(msg_data, 0, sizeof(msg_data)); 180 /* channel =~ 0x0e => Currently running interface */ 181 msg_data[0] = channel; 182 msg_data[1] = size; 183 memset(&req, 0, sizeof(req)); 184 req.msg.netfn = 0x3E; 185 /* Set Channel Buffer Length - OEM */ 186 req.msg.cmd = 0x82; 187 req.msg.data = msg_data; 188 req.msg.data_len = 2; 189 req.msg.lun = 0x00; 190 rsp = intf->sendrecv(intf, &req); 191 if (rsp == NULL) { 192 printf("Cannot send large buffer command\n"); 193 return(-1); 194 } else if (rsp->ccode > 0) { 195 printf("Invalid length for the selected interface (%s) %d\n", 196 val2str(rsp->ccode, completion_code_vals), rsp->ccode); 197 return(-1); 198 } 199 return 0; 200 } 201 202 /* ipmi_fru_set_serial_number - Set the Serial Number in FRU 203 * 204 * @intf: ipmi interface 205 * @id: fru id 206 * 207 * returns -1 on error 208 * returns 1 if successful 209 */ 210 static int 211 ipmi_kontron_set_serial_number(struct ipmi_intf *intf) 212 { 213 struct fru_header header; 214 struct fru_info fru; 215 struct ipmi_rs *rsp; 216 struct ipmi_rq req; 217 char *sn; 218 char *fru_area; 219 uint8_t checksum; 220 uint8_t *fru_data; 221 uint8_t msg_data[4]; 222 uint8_t sn_size; 223 uint32_t board_sec_len; 224 uint32_t fru_data_offset; 225 uint32_t fru_data_offset_tmp; 226 uint32_t i; 227 uint32_t prod_sec_len; 228 229 sn = NULL; 230 fru_data = NULL; 231 232 memset(msg_data, 0, 4); 233 msg_data[0] = 0xb4; 234 msg_data[1] = 0x90; 235 msg_data[2] = 0x91; 236 msg_data[3] = 0x8b; 237 238 memset(&req, 0, sizeof(req)); 239 req.msg.netfn = 0x3E; 240 req.msg.cmd = 0x0C; 241 req.msg.data = msg_data; 242 req.msg.data_len = 4; 243 /* Set Lun, necessary for this oem command */ 244 req.msg.lun = 0x03; 245 rsp = intf->sendrecv(intf, &req); 246 if (rsp == NULL) { 247 printf(" Device not present (No Response)\n"); 248 return (-1); 249 } else if (rsp->ccode > 0) { 250 printf(" This option is not implemented for this board\n"); 251 return (-1); 252 } 253 sn_size = rsp->data_len; 254 sn = malloc(sn_size + 1); 255 if (sn == NULL) { 256 lprintf(LOG_ERR, "ipmitool: malloc failure"); 257 return (-1); 258 } 259 memset(sn, 0, sn_size + 1); 260 memcpy(sn, rsp->data, sn_size); 261 if (verbose >= 1) { 262 printf("Original serial number is : [%s]\n", sn); 263 } 264 memset(msg_data, 0, 4); 265 msg_data[0] = 0; 266 memset(&req, 0, sizeof(req)); 267 req.msg.netfn = IPMI_NETFN_STORAGE; 268 req.msg.cmd = GET_FRU_INFO; 269 req.msg.data = msg_data; 270 req.msg.data_len = 1; 271 rsp = intf->sendrecv(intf, &req); 272 if (rsp == NULL) { 273 printf(" Device not present (No Response)\n"); 274 free(sn); 275 sn = NULL; 276 return (-1); 277 } else if (rsp->ccode > 0) { 278 printf(" Device not present (%s)\n", 279 val2str(rsp->ccode, completion_code_vals)); 280 free(sn); 281 sn = NULL; 282 return (-1); 283 } 284 memset(&fru, 0, sizeof(fru)); 285 fru.size = (rsp->data[1] << 8) | rsp->data[0]; 286 fru.access = rsp->data[2] & 0x1; 287 if (fru.size < 1) { 288 printf(" Invalid FRU size %d", fru.size); 289 free(sn); 290 sn = NULL; 291 return (-1); 292 } 293 /* retrieve the FRU header */ 294 msg_data[0] = 0; 295 msg_data[1] = 0; 296 msg_data[2] = 0; 297 msg_data[3] = 8; 298 299 memset(&req, 0, sizeof(req)); 300 req.msg.netfn = IPMI_NETFN_STORAGE; 301 req.msg.cmd = GET_FRU_DATA; 302 req.msg.data = msg_data; 303 req.msg.data_len = 4; 304 rsp = intf->sendrecv(intf, &req); 305 if (rsp == NULL) { 306 printf(" Device not present (No Response)\n"); 307 free(sn); 308 sn = NULL; 309 return (-1); 310 } else if (rsp->ccode > 0) { 311 printf(" Device not present (%s)\n", 312 val2str(rsp->ccode, completion_code_vals)); 313 free(sn); 314 sn = NULL; 315 return (-1); 316 } 317 if (verbose > 1) { 318 printbuf(rsp->data, rsp->data_len, "FRU DATA"); 319 } 320 memcpy(&header, rsp->data + 1, 8); 321 if (header.version != 1) { 322 printf(" Unknown FRU header version 0x%02x", 323 header.version); 324 free(sn); 325 sn = NULL; 326 return(-1); 327 } 328 /* Set the Board Section */ 329 board_sec_len = (header.offset.product * 8) - (header.offset.board * 8); 330 fru_data = malloc(fru.size); 331 if (fru_data == NULL) { 332 lprintf(LOG_ERR, "ipmitool: malloc failure"); 333 free(sn); 334 sn = NULL; 335 return (-1); 336 } 337 memset(fru_data, 0, fru.size); 338 if (read_fru_area(intf, &fru, 0, (header.offset.board * 8), 339 board_sec_len, fru_data) < 0) { 340 free(sn); 341 sn = NULL; 342 free(fru_data); 343 fru_data = NULL; 344 return (-1); 345 } 346 /* Position at Board Manufacturer */ 347 fru_data_offset = (header.offset.board * 8) + 6; 348 fru_area = get_fru_area_str(fru_data, &fru_data_offset); 349 if (fru_area != NULL) { 350 free(fru_area); 351 fru_area = NULL; 352 } 353 /* Position at Board Product Name */ 354 fru_area = get_fru_area_str(fru_data, &fru_data_offset); 355 if (fru_area != NULL) { 356 free(fru_area); 357 fru_area = NULL; 358 } 359 fru_data_offset_tmp = fru_data_offset; 360 /* Position at Serial Number */ 361 fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp); 362 if (fru_area == NULL) { 363 lprintf(LOG_ERR, "Failed to read FRU Area string."); 364 free(fru_data); 365 fru_data = NULL; 366 free(sn); 367 sn = NULL; 368 return (-1); 369 } 370 371 fru_data_offset++; 372 if (strlen(fru_area) != sn_size) { 373 printf("The length of the serial number in the FRU Board Area is wrong.\n"); 374 free(sn); 375 sn = NULL; 376 free(fru_data); 377 fru_data = NULL; 378 free(fru_area); 379 fru_area = NULL; 380 return(-1); 381 } else { 382 free(fru_area); 383 fru_area = NULL; 384 } 385 /* Copy the new serial number in the board section saved in memory*/ 386 memcpy(fru_data + fru_data_offset, sn, sn_size); 387 checksum = 0; 388 /* Calculate Header Checksum */ 389 for(i = (header.offset.board * 8); 390 i < (((header.offset.board * 8) + board_sec_len) - 2); 391 i++) { 392 checksum += fru_data[i]; 393 } 394 checksum = (~checksum) + 1; 395 fru_data[(header.offset.board * 8) + board_sec_len - 1] = checksum; 396 /* Write the new FRU Board section */ 397 if (write_fru_area(intf, &fru, 0, (header.offset.board * 8), 398 (header.offset.board * 8), 399 board_sec_len, fru_data) < 0) { 400 free(sn); 401 sn = NULL; 402 free(fru_data); 403 fru_data = NULL; 404 free(fru_area); 405 fru_area = NULL; 406 return(-1); 407 } 408 /* Set the Product Section */ 409 prod_sec_len = (header.offset.multi * 8) - (header.offset.product * 8); 410 if (read_fru_area(intf, &fru, 0, (header.offset.product * 8), 411 prod_sec_len, fru_data) < 0) { 412 free(sn); 413 sn = NULL; 414 free(fru_data); 415 fru_data = NULL; 416 free(fru_area); 417 fru_area = NULL; 418 return(-1); 419 } 420 /* Position at Product Manufacturer */ 421 fru_data_offset = (header.offset.product * 8) + 3; 422 fru_area = get_fru_area_str(fru_data, &fru_data_offset); 423 if (fru_area != NULL) { 424 free(fru_area); 425 fru_area = NULL; 426 } 427 /* Position at Product Name */ 428 fru_area = get_fru_area_str(fru_data, &fru_data_offset); 429 if (fru_area != NULL) { 430 free(fru_area); 431 fru_area = NULL; 432 } 433 /* Position at Product Part */ 434 fru_area = get_fru_area_str(fru_data, &fru_data_offset); 435 if (fru_area != NULL) { 436 free(fru_area); 437 fru_area = NULL; 438 } 439 /* Position at Product Version */ 440 fru_area = get_fru_area_str(fru_data, &fru_data_offset); 441 if (fru_area != NULL) { 442 free(fru_area); 443 fru_area = NULL; 444 } 445 fru_data_offset_tmp = fru_data_offset; 446 /* Position at Serial Number */ 447 fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp); 448 if (fru_area == NULL) { 449 lprintf(LOG_ERR, "Failed to read FRU Area string."); 450 free(sn); 451 sn = NULL; 452 free(fru_data); 453 fru_data = NULL; 454 return (-1); 455 } 456 fru_data_offset ++; 457 if (strlen(fru_area) != sn_size) { 458 free(sn); 459 sn = NULL; 460 free(fru_data); 461 fru_data = NULL; 462 free(fru_area); 463 fru_area = NULL; 464 printf("The length of the serial number in the FRU Product Area is wrong.\n"); 465 return(-1); 466 } 467 /* Copy the new serial number in the product section saved in memory*/ 468 memcpy(fru_data + fru_data_offset, sn, sn_size); 469 checksum = 0; 470 /* Calculate Header Checksum */ 471 for (i = (header.offset.product * 8); 472 i < (((header.offset.product * 8) + prod_sec_len) - 2); 473 i ++) { 474 checksum += fru_data[i]; 475 } 476 checksum = (~checksum) + 1; 477 fru_data[(header.offset.product * 8)+prod_sec_len - 1] = checksum; 478 /* Write the new FRU Board section */ 479 if (write_fru_area(intf, &fru, 0, (header.offset.product * 8), 480 (header.offset.product * 8), 481 prod_sec_len, fru_data) < 0) { 482 free(sn); 483 sn = NULL; 484 free(fru_data); 485 fru_data = NULL; 486 free(fru_area); 487 fru_area = NULL; 488 return -1; 489 } 490 free(sn); 491 sn = NULL; 492 free(fru_data); 493 fru_data = NULL; 494 free(fru_area); 495 fru_area = NULL; 496 return(1); 497 } 498 499 /* ipmi_fru_set_mfg_date - Set the Manufacturing Date in FRU 500 * 501 * @intf: ipmi interface 502 * @id: fru id 503 * 504 * returns -1 on error 505 * returns 1 if successful 506 */ 507 static int 508 ipmi_kontron_set_mfg_date (struct ipmi_intf *intf) 509 { 510 struct fru_header header; 511 struct fru_info fru; 512 struct ipmi_rs *rsp; 513 struct ipmi_rq req; 514 uint8_t *fru_data; 515 uint8_t checksum; 516 uint8_t msg_data[4]; 517 uint8_t mfg_date[3]; 518 uint32_t board_sec_len; 519 uint32_t i; 520 521 memset(msg_data, 0, 4); 522 msg_data[0] = 0xb4; 523 msg_data[1] = 0x90; 524 msg_data[2] = 0x91; 525 msg_data[3] = 0x8b; 526 527 memset(&req, 0, sizeof(req)); 528 req.msg.netfn = 0x3E; 529 req.msg.cmd = 0x0E; 530 req.msg.data = msg_data; 531 req.msg.data_len = 4; 532 /* Set Lun temporary, necessary for this oem command */ 533 req.msg.lun = 0x03; 534 rsp = intf->sendrecv(intf, &req); 535 if (rsp == NULL) { 536 printf("Device not present (No Response)\n"); 537 return(-1); 538 } else if (rsp->ccode > 0) { 539 printf("This option is not implemented for this board\n"); 540 return(-1); 541 } 542 if (rsp->data_len != 3) { 543 printf("Invalid response for the Manufacturing date\n"); 544 return(-1); 545 } 546 memset(mfg_date, 0, 3); 547 memcpy(mfg_date, rsp->data, 3); 548 memset(msg_data, 0, 4); 549 msg_data[0] = 0; 550 551 memset(&req, 0, sizeof(req)); 552 req.msg.netfn = IPMI_NETFN_STORAGE; 553 req.msg.cmd = GET_FRU_INFO; 554 req.msg.data = msg_data; 555 req.msg.data_len = 1; 556 rsp = intf->sendrecv(intf, &req); 557 if (rsp == NULL) { 558 printf(" Device not present (No Response)\n"); 559 return(-1); 560 } else if (rsp->ccode > 0) { 561 printf(" Device not present (%s)\n", 562 val2str(rsp->ccode, completion_code_vals)); 563 return(-1); 564 } 565 566 memset(&fru, 0, sizeof(fru)); 567 fru.size = (rsp->data[1] << 8) | rsp->data[0]; 568 fru.access = rsp->data[2] & 0x1; 569 if (fru.size < 1) { 570 printf(" Invalid FRU size %d", fru.size); 571 return(-1); 572 } 573 /* retrieve the FRU header */ 574 msg_data[0] = 0; 575 msg_data[1] = 0; 576 msg_data[2] = 0; 577 msg_data[3] = 8; 578 579 memset(&req, 0, sizeof(req)); 580 req.msg.netfn = IPMI_NETFN_STORAGE; 581 req.msg.cmd = GET_FRU_DATA; 582 req.msg.data = msg_data; 583 req.msg.data_len = 4; 584 rsp = intf->sendrecv(intf, &req); 585 if (rsp == NULL) { 586 printf(" Device not present (No Response)\n"); 587 return (-1); 588 } else if (rsp->ccode > 0) { 589 printf(" Device not present (%s)\n", 590 val2str(rsp->ccode, completion_code_vals)); 591 return (-1); 592 } 593 if (verbose > 1) { 594 printbuf(rsp->data, rsp->data_len, "FRU DATA"); 595 } 596 memcpy(&header, rsp->data + 1, 8); 597 if (header.version != 1) { 598 printf(" Unknown FRU header version 0x%02x", 599 header.version); 600 return(-1); 601 } 602 board_sec_len = (header.offset.product * 8) - (header.offset.board * 8); 603 fru_data = malloc(fru.size); 604 if(fru_data == NULL) { 605 lprintf(LOG_ERR, "ipmitool: malloc failure"); 606 return(-1); 607 } 608 memset(fru_data, 0, fru.size); 609 if (read_fru_area(intf ,&fru ,0 ,(header.offset.board * 8), 610 board_sec_len ,fru_data) < 0) { 611 free(fru_data); 612 fru_data = NULL; 613 return(-1); 614 } 615 /* Copy the new manufacturing date in the board section saved in memory*/ 616 memcpy(fru_data + (header.offset.board * 8) + 3, mfg_date, 3); 617 checksum = 0; 618 /* Calculate Header Checksum */ 619 for (i = (header.offset.board * 8); 620 i < (((header.offset.board * 8) + board_sec_len) - 2); 621 i ++ ) { 622 checksum += fru_data[i]; 623 } 624 checksum = (~checksum) + 1; 625 fru_data[(header.offset.board * 8)+board_sec_len - 1] = checksum; 626 /* Write the new FRU Board section */ 627 if (write_fru_area(intf, &fru, 0, (header.offset.board * 8), 628 (header.offset.board * 8), 629 board_sec_len, fru_data) < 0) { 630 free(fru_data); 631 fru_data = NULL; 632 return (-1); 633 } 634 free(fru_data); 635 fru_data = NULL; 636 return (1); 637 } 638 639 static void 640 ipmi_kontron_nextboot_help(void) 641 { 642 int i; 643 printf("nextboot <device>\n" 644 "Supported devices:\n"); 645 for (i = 0; bootdev[i] != 0; i++) { 646 printf("- %s\n", bootdev[i]); 647 } 648 } 649 650 /* ipmi_kontron_next_boot_set - Select the next boot order on CP6012 651 * 652 * @intf: ipmi interface 653 * @id: fru id 654 * 655 * returns -1 on error 656 * returns 1 if successful 657 */ 658 static int 659 ipmi_kontron_nextboot_set(struct ipmi_intf *intf, int argc, char **argv) 660 { 661 struct ipmi_rs *rsp; 662 struct ipmi_rq req; 663 uint8_t msg_data[8]; 664 int i; 665 666 memset(msg_data, 0, sizeof(msg_data)); 667 msg_data[0] = 0xb4; 668 msg_data[1] = 0x90; 669 msg_data[2] = 0x91; 670 msg_data[3] = 0x8b; 671 msg_data[4] = 0x9d; 672 msg_data[5] = 0xFF; 673 msg_data[6] = 0xFF; /* any */ 674 for (i = 0; bootdev[i] != 0; i++) { 675 if (strcmp(argv[0], bootdev[i]) == 0) { 676 msg_data[5] = i; 677 break; 678 } 679 } 680 /* Invalid device selected? */ 681 if (msg_data[5] == 0xFF) { 682 printf("Unknown boot device: %s\n", argv[0]); 683 return (-1); 684 } 685 memset(&req, 0, sizeof(req)); 686 req.msg.netfn = 0x3E; 687 req.msg.cmd = 0x02; 688 req.msg.data = msg_data; 689 req.msg.data_len = 7; 690 /* Set Lun temporary, necessary for this oem command */ 691 req.msg.lun = 0x03; 692 rsp = intf->sendrecv(intf, &req); 693 if (rsp == NULL) { 694 printf("Device not present (No Response)\n"); 695 return(-1); 696 } else if (rsp->ccode > 0) { 697 printf("Device not present (%s)\n", 698 val2str(rsp->ccode, completion_code_vals)); 699 return (-1); 700 } 701 return 0; 702 } 703