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
ipmi_kontronoem_main(struct ipmi_intf * intf,int argc,char ** argv)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
ipmi_kontron_help(void)126 ipmi_kontron_help(void)
127 {
128 printf("Kontron Commands: setsn setmfgdate nextboot\n");
129 }
130
131 int
ipmi_kontronoem_set_large_buffer(struct ipmi_intf * intf,unsigned char size)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
ipmi_kontronoem_send_set_large_buffer(struct ipmi_intf * intf,unsigned char channel,unsigned char size)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
ipmi_kontron_set_serial_number(struct ipmi_intf * intf)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
ipmi_kontron_set_mfg_date(struct ipmi_intf * intf)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
ipmi_kontron_nextboot_help(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
ipmi_kontron_nextboot_set(struct ipmi_intf * intf,int argc,char ** argv)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