xref: /openbmc/ipmitool/lib/ipmi_kontronoem.c (revision 2d79e69f)
1c18ec02fSPetter Reinholdtsen /*
2c18ec02fSPetter Reinholdtsen  * Copyright (c) 2004 Kontron Canada, Inc.  All Rights Reserved.
3c18ec02fSPetter Reinholdtsen  *
4c18ec02fSPetter Reinholdtsen  * Base on code from
5c18ec02fSPetter Reinholdtsen  * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
6c18ec02fSPetter Reinholdtsen  *
7c18ec02fSPetter Reinholdtsen  * Redistribution and use in source and binary forms, with or without
8c18ec02fSPetter Reinholdtsen  * modification, are permitted provided that the following conditions
9c18ec02fSPetter Reinholdtsen  * are met:
10c18ec02fSPetter Reinholdtsen  *
11c18ec02fSPetter Reinholdtsen  * Redistribution of source code must retain the above copyright
12c18ec02fSPetter Reinholdtsen  * notice, this list of conditions and the following disclaimer.
13c18ec02fSPetter Reinholdtsen  *
14c18ec02fSPetter Reinholdtsen  * Redistribution in binary form must reproduce the above copyright
15c18ec02fSPetter Reinholdtsen  * notice, this list of conditions and the following disclaimer in the
16c18ec02fSPetter Reinholdtsen  * documentation and/or other materials provided with the distribution.
17c18ec02fSPetter Reinholdtsen  *
18c18ec02fSPetter Reinholdtsen  * Neither the name of Sun Microsystems, Inc. or the names of
19c18ec02fSPetter Reinholdtsen  * contributors may be used to endorse or promote products derived
20c18ec02fSPetter Reinholdtsen  * from this software without specific prior written permission.
21c18ec02fSPetter Reinholdtsen  *
22c18ec02fSPetter Reinholdtsen  * This software is provided "AS IS," without a warranty of any kind.
23c18ec02fSPetter Reinholdtsen  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
24c18ec02fSPetter Reinholdtsen  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
25c18ec02fSPetter Reinholdtsen  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
26c18ec02fSPetter Reinholdtsen  * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
27c18ec02fSPetter Reinholdtsen  * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
28c18ec02fSPetter Reinholdtsen  * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
29c18ec02fSPetter Reinholdtsen  * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
30c18ec02fSPetter Reinholdtsen  * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
31c18ec02fSPetter Reinholdtsen  * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
32c18ec02fSPetter Reinholdtsen  * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
33c18ec02fSPetter Reinholdtsen  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
34c18ec02fSPetter Reinholdtsen  */
35c18ec02fSPetter Reinholdtsen 
36c18ec02fSPetter Reinholdtsen /*
37c18ec02fSPetter Reinholdtsen  * Tue Mar 7 14:36:12 2006
38c18ec02fSPetter Reinholdtsen  * <stephane.filion@ca.kontron.com>
39c18ec02fSPetter Reinholdtsen  *
40c18ec02fSPetter Reinholdtsen  * This code implements an Kontron OEM proprietary commands.
41c18ec02fSPetter Reinholdtsen  */
42c18ec02fSPetter Reinholdtsen #include <string.h>
43c18ec02fSPetter Reinholdtsen #include <ipmitool/helper.h>
4458837647SZdenek Styblik #include <ipmitool/log.h>
45c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi.h>
46c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_intf.h>
47c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_fru.h>
48c18ec02fSPetter Reinholdtsen 
49c18ec02fSPetter Reinholdtsen extern int verbose;
50c18ec02fSPetter Reinholdtsen extern int read_fru_area(struct ipmi_intf *intf, struct fru_info *fru,
51c18ec02fSPetter Reinholdtsen 		uint8_t id, uint32_t offset, uint32_t length,
52c18ec02fSPetter Reinholdtsen 		uint8_t *frubuf);
53c18ec02fSPetter Reinholdtsen extern int write_fru_area(struct ipmi_intf * intf, struct fru_info *fru,
547560d4f2SZdenek Styblik 		uint8_t id, uint16_t soffset,
557560d4f2SZdenek Styblik 		uint16_t doffset,  uint16_t length,
567560d4f2SZdenek Styblik 		uint8_t *pFrubuf);
57c18ec02fSPetter Reinholdtsen extern char *get_fru_area_str(uint8_t *data, uint32_t *offset);
58c18ec02fSPetter Reinholdtsen 
59c18ec02fSPetter Reinholdtsen static void ipmi_kontron_help(void);
60c18ec02fSPetter Reinholdtsen static int ipmi_kontron_set_serial_number(struct ipmi_intf *intf);
61c18ec02fSPetter Reinholdtsen static int ipmi_kontron_set_mfg_date (struct ipmi_intf *intf);
62c18ec02fSPetter Reinholdtsen static void ipmi_kontron_nextboot_help(void);
6358837647SZdenek Styblik static int ipmi_kontron_nextboot_set(struct ipmi_intf *intf, int argc,
6458837647SZdenek Styblik 		char **argv);
65c18ec02fSPetter Reinholdtsen static int ipmi_kontronoem_send_set_large_buffer(struct ipmi_intf *intf,
6658837647SZdenek Styblik 		unsigned char channel, unsigned char size);
6758837647SZdenek Styblik 
6858837647SZdenek Styblik static char *bootdev[] = {"BIOS", "FDD", "HDD", "CDROM", "network", 0};
69c18ec02fSPetter Reinholdtsen 
70c18ec02fSPetter Reinholdtsen int
ipmi_kontronoem_main(struct ipmi_intf * intf,int argc,char ** argv)71c18ec02fSPetter Reinholdtsen ipmi_kontronoem_main(struct ipmi_intf *intf, int argc, char **argv)
72c18ec02fSPetter Reinholdtsen {
73c18ec02fSPetter Reinholdtsen 	int rc = 0;
7458837647SZdenek Styblik 	if (argc == 0) {
7558837647SZdenek Styblik 		lprintf(LOG_ERR, "Not enough parameters given.");
76c18ec02fSPetter Reinholdtsen 		ipmi_kontron_help();
7758837647SZdenek Styblik 		return (-1);
7858837647SZdenek Styblik 	}
7958837647SZdenek Styblik 	if (strncmp(argv[0], "help", 4) == 0) {
80c18ec02fSPetter Reinholdtsen 		ipmi_kontron_help();
8158837647SZdenek Styblik 		rc = 0;
8258837647SZdenek Styblik 	} else if (!strncmp(argv[0], "setsn", 5)) {
8358837647SZdenek Styblik 		if (argc < 1) {
84c18ec02fSPetter Reinholdtsen 			printf("fru setsn\n");
8558837647SZdenek Styblik 			return (-1);
86c18ec02fSPetter Reinholdtsen 		}
8758837647SZdenek Styblik 		if (ipmi_kontron_set_serial_number(intf) > 0) {
8858837647SZdenek Styblik 			printf("FRU serial number setted successfully\n");
8958837647SZdenek Styblik 		} else {
9058837647SZdenek Styblik 			printf("FRU serial number set failed\n");
9158837647SZdenek Styblik 			rc = (-1);
92c18ec02fSPetter Reinholdtsen 		}
9358837647SZdenek Styblik 	} else if (!strncmp(argv[0], "setmfgdate", 10)) {
9458837647SZdenek Styblik 		if (argc < 1) {
95c18ec02fSPetter Reinholdtsen 			printf("fru setmfgdate\n");
9658837647SZdenek Styblik 			return (-1);
97c18ec02fSPetter Reinholdtsen 		}
9858837647SZdenek Styblik 		if (ipmi_kontron_set_mfg_date(intf) > 0) {
9958837647SZdenek Styblik 			printf("FRU manufacturing date setted successfully\n");
10058837647SZdenek Styblik 		} else {
10158837647SZdenek Styblik 			printf("FRU manufacturing date set failed\n");
10258837647SZdenek Styblik 			rc = (-1);
103c18ec02fSPetter Reinholdtsen 		}
10458837647SZdenek Styblik 	} else if (!strncmp(argv[0], "nextboot", 8)) {
10558837647SZdenek Styblik 		if (argc < 2) {
10658837647SZdenek Styblik 			lprintf(LOG_ERR, "Not enough parameters given.");
107c18ec02fSPetter Reinholdtsen 			ipmi_kontron_nextboot_help();
10812eeca60SZdenek Styblik 			return (-1);
109c18ec02fSPetter Reinholdtsen 		}
11058837647SZdenek Styblik 		rc = ipmi_kontron_nextboot_set(intf, (argc - 1), (argv + 1));
11158837647SZdenek Styblik 		if (rc == 0) {
11258837647SZdenek Styblik 			printf("Nextboot set successfully\n");
11358837647SZdenek Styblik 		} else {
11458837647SZdenek Styblik 			printf("Nextboot set failed\n");
11558837647SZdenek Styblik 			rc = (-1);
116c18ec02fSPetter Reinholdtsen 		}
11758837647SZdenek Styblik 	} else  {
11858837647SZdenek Styblik 		lprintf(LOG_ERR, "Invalid Kontron command: %s", argv[0]);
119c18ec02fSPetter Reinholdtsen 		ipmi_kontron_help();
12058837647SZdenek Styblik 		rc = (-1);
121c18ec02fSPetter Reinholdtsen 	}
122c18ec02fSPetter Reinholdtsen 	return rc;
123c18ec02fSPetter Reinholdtsen }
124c18ec02fSPetter Reinholdtsen 
12558837647SZdenek Styblik static void
ipmi_kontron_help(void)12658837647SZdenek Styblik ipmi_kontron_help(void)
127c18ec02fSPetter Reinholdtsen {
128c18ec02fSPetter Reinholdtsen 	printf("Kontron Commands:  setsn setmfgdate nextboot\n");
129c18ec02fSPetter Reinholdtsen }
130c18ec02fSPetter Reinholdtsen 
13158837647SZdenek Styblik int
ipmi_kontronoem_set_large_buffer(struct ipmi_intf * intf,unsigned char size)13258837647SZdenek Styblik ipmi_kontronoem_set_large_buffer(struct ipmi_intf *intf, unsigned char size)
133c18ec02fSPetter Reinholdtsen {
134c18ec02fSPetter Reinholdtsen 	uint8_t error_occurs = 0;
135c18ec02fSPetter Reinholdtsen 	uint32_t prev_target_addr = intf->target_addr ;
13658837647SZdenek Styblik 	if (intf->target_addr > 0 && (intf->target_addr != intf->my_addr)) {
137c18ec02fSPetter Reinholdtsen 		intf->target_addr = intf->my_addr;
138c18ec02fSPetter Reinholdtsen 		printf("Set local big buffer\n");
13958837647SZdenek Styblik 		if (ipmi_kontronoem_send_set_large_buffer(intf, 0x0e, size) == 0) {
140c18ec02fSPetter Reinholdtsen 			printf("Set local big buffer:success\n");
14158837647SZdenek Styblik 		} else {
142c18ec02fSPetter Reinholdtsen 			error_occurs = 1;
143c18ec02fSPetter Reinholdtsen 		}
14458837647SZdenek Styblik 		if (error_occurs == 0) {
14558837647SZdenek Styblik 			if (ipmi_kontronoem_send_set_large_buffer(intf, 0x00, size) == 0) {
146c18ec02fSPetter Reinholdtsen 				printf("IPMB was set\n");
14758837647SZdenek Styblik 			} else {
148c18ec02fSPetter Reinholdtsen 				/* Revert back the previous set large buffer */
149c18ec02fSPetter Reinholdtsen 				error_occurs = 1;
150c18ec02fSPetter Reinholdtsen 				ipmi_kontronoem_send_set_large_buffer( intf, 0x0e, 0 );
151c18ec02fSPetter Reinholdtsen 			}
152c18ec02fSPetter Reinholdtsen 		}
153c18ec02fSPetter Reinholdtsen 		/* Restore target address */
154c18ec02fSPetter Reinholdtsen 		intf->target_addr = prev_target_addr;
155c18ec02fSPetter Reinholdtsen 	}
15658837647SZdenek Styblik 	if (error_occurs == 0) {
15758837647SZdenek Styblik 		if(ipmi_kontronoem_send_set_large_buffer(intf, 0x0e, size) == 0) {
15858837647SZdenek Styblik 			/* printf("Set remote big buffer\n"); */
15958837647SZdenek Styblik 		} else {
16058837647SZdenek Styblik 			if (intf->target_addr > 0  && (intf->target_addr != intf->my_addr)) {
161c18ec02fSPetter Reinholdtsen 				/* Error occurs revert back the previous set large buffer */
162c18ec02fSPetter Reinholdtsen 				intf->target_addr = intf->my_addr;
16358837647SZdenek Styblik 				/* ipmi_kontronoem_send_set_large_buffer(intf, 0x00, 0); */
164c18ec02fSPetter Reinholdtsen 				ipmi_kontronoem_send_set_large_buffer(intf, 0x0e, 0);
165c18ec02fSPetter Reinholdtsen 				intf->target_addr = prev_target_addr;
166c18ec02fSPetter Reinholdtsen 			}
167c18ec02fSPetter Reinholdtsen 		}
168c18ec02fSPetter Reinholdtsen 	}
169c18ec02fSPetter Reinholdtsen 	return error_occurs;
170c18ec02fSPetter Reinholdtsen }
171c18ec02fSPetter Reinholdtsen 
17258837647SZdenek Styblik int
ipmi_kontronoem_send_set_large_buffer(struct ipmi_intf * intf,unsigned char channel,unsigned char size)17358837647SZdenek Styblik ipmi_kontronoem_send_set_large_buffer(struct ipmi_intf *intf,
17458837647SZdenek Styblik 		unsigned char channel, unsigned char size)
175c18ec02fSPetter Reinholdtsen {
176c18ec02fSPetter Reinholdtsen 	struct ipmi_rs *rsp;
177c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
178c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[2];
179c18ec02fSPetter Reinholdtsen 	memset(msg_data, 0, sizeof(msg_data));
18058837647SZdenek Styblik 	/* channel =~ 0x0e => Currently running interface */
18158837647SZdenek Styblik 	msg_data[0] = channel;
182c18ec02fSPetter Reinholdtsen 	msg_data[1] = size;
183c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
18458837647SZdenek Styblik 	req.msg.netfn = 0x3E;
18558837647SZdenek Styblik 	/* Set Channel Buffer Length - OEM */
18658837647SZdenek Styblik 	req.msg.cmd = 0x82;
187c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
188c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 2;
189c18ec02fSPetter Reinholdtsen 	req.msg.lun = 0x00;
190c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
19158837647SZdenek Styblik 	if (rsp == NULL)  {
192c18ec02fSPetter Reinholdtsen 		printf("Cannot send large buffer command\n");
193c18ec02fSPetter Reinholdtsen 		return(-1);
19458837647SZdenek Styblik 	} else if (rsp->ccode > 0)  {
195c18ec02fSPetter Reinholdtsen 		printf("Invalid length for the selected interface (%s) %d\n",
196c18ec02fSPetter Reinholdtsen 				val2str(rsp->ccode, completion_code_vals), rsp->ccode);
197c18ec02fSPetter Reinholdtsen 		return(-1);
198c18ec02fSPetter Reinholdtsen 	}
199c18ec02fSPetter Reinholdtsen 	return 0;
200c18ec02fSPetter Reinholdtsen }
201c18ec02fSPetter Reinholdtsen 
202c18ec02fSPetter Reinholdtsen /* ipmi_fru_set_serial_number -  Set the Serial Number in FRU
203c18ec02fSPetter Reinholdtsen  *
204c18ec02fSPetter Reinholdtsen  * @intf: ipmi interface
205c18ec02fSPetter Reinholdtsen  * @id: fru id
206c18ec02fSPetter Reinholdtsen  *
207c18ec02fSPetter Reinholdtsen  * returns -1 on error
208c18ec02fSPetter Reinholdtsen  * returns 1 if successful
209c18ec02fSPetter Reinholdtsen  */
210c18ec02fSPetter Reinholdtsen static int
ipmi_kontron_set_serial_number(struct ipmi_intf * intf)211c18ec02fSPetter Reinholdtsen ipmi_kontron_set_serial_number(struct ipmi_intf *intf)
212c18ec02fSPetter Reinholdtsen {
21358837647SZdenek Styblik 	struct fru_header header;
21458837647SZdenek Styblik 	struct fru_info fru;
215c18ec02fSPetter Reinholdtsen 	struct ipmi_rs *rsp;
216c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
217c18ec02fSPetter Reinholdtsen 	char *sn;
218c18ec02fSPetter Reinholdtsen 	char *fru_area;
21958837647SZdenek Styblik 	uint8_t checksum;
22058837647SZdenek Styblik 	uint8_t *fru_data;
22158837647SZdenek Styblik 	uint8_t msg_data[4];
22258837647SZdenek Styblik 	uint8_t sn_size;
22358837647SZdenek Styblik 	uint32_t board_sec_len;
22458837647SZdenek Styblik 	uint32_t fru_data_offset;
22558837647SZdenek Styblik 	uint32_t fru_data_offset_tmp;
22658837647SZdenek Styblik 	uint32_t i;
22758837647SZdenek Styblik 	uint32_t prod_sec_len;
228c18ec02fSPetter Reinholdtsen 
229c18ec02fSPetter Reinholdtsen 	sn = NULL;
230c18ec02fSPetter Reinholdtsen 	fru_data = NULL;
231c18ec02fSPetter Reinholdtsen 
232c18ec02fSPetter Reinholdtsen 	memset(msg_data, 0, 4);
233c18ec02fSPetter Reinholdtsen 	msg_data[0] = 0xb4;
234c18ec02fSPetter Reinholdtsen 	msg_data[1] = 0x90;
235c18ec02fSPetter Reinholdtsen 	msg_data[2] = 0x91;
236c18ec02fSPetter Reinholdtsen 	msg_data[3] = 0x8b;
237c18ec02fSPetter Reinholdtsen 
238c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
239c18ec02fSPetter Reinholdtsen 	req.msg.netfn = 0x3E;
240c18ec02fSPetter Reinholdtsen 	req.msg.cmd = 0x0C;
241c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
242c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 4;
243c18ec02fSPetter Reinholdtsen 	/* Set Lun, necessary for this oem command */
244c18ec02fSPetter Reinholdtsen 	req.msg.lun = 0x03;
245c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
24658837647SZdenek Styblik 	if (rsp == NULL) {
247c18ec02fSPetter Reinholdtsen 		printf(" Device not present (No Response)\n");
24858837647SZdenek Styblik 		return (-1);
24958837647SZdenek Styblik 	} else if (rsp->ccode > 0) {
250c18ec02fSPetter Reinholdtsen 		printf(" This option is not implemented for this board\n");
25158837647SZdenek Styblik 		return (-1);
252c18ec02fSPetter Reinholdtsen 	}
253c18ec02fSPetter Reinholdtsen 	sn_size = rsp->data_len;
254c18ec02fSPetter Reinholdtsen 	sn = malloc(sn_size + 1);
25558837647SZdenek Styblik 	if (sn == NULL) {
25658837647SZdenek Styblik 		lprintf(LOG_ERR, "ipmitool: malloc failure");
25758837647SZdenek Styblik 		return (-1);
258c18ec02fSPetter Reinholdtsen 	}
259c18ec02fSPetter Reinholdtsen 	memset(sn, 0, sn_size + 1);
260c18ec02fSPetter Reinholdtsen 	memcpy(sn, rsp->data, sn_size);
26158837647SZdenek Styblik 	if (verbose >= 1) {
262c18ec02fSPetter Reinholdtsen 		printf("Original serial number is : [%s]\n", sn);
263c18ec02fSPetter Reinholdtsen 	}
264c18ec02fSPetter Reinholdtsen 	memset(msg_data, 0, 4);
265c18ec02fSPetter Reinholdtsen 	msg_data[0] = 0;
266c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
267c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
268c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_INFO;
269c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
270c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 1;
271c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
272c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
273c18ec02fSPetter Reinholdtsen 		printf(" Device not present (No Response)\n");
274c18ec02fSPetter Reinholdtsen 		free(sn);
275c18ec02fSPetter Reinholdtsen 		sn = NULL;
27658837647SZdenek Styblik 		return (-1);
27758837647SZdenek Styblik 	} else if (rsp->ccode > 0) {
278c18ec02fSPetter Reinholdtsen 		printf(" Device not present (%s)\n",
279c18ec02fSPetter Reinholdtsen 				val2str(rsp->ccode, completion_code_vals));
280c18ec02fSPetter Reinholdtsen 		free(sn);
281c18ec02fSPetter Reinholdtsen 		sn = NULL;
282c18ec02fSPetter Reinholdtsen 		return (-1);
283c18ec02fSPetter Reinholdtsen 	}
284c18ec02fSPetter Reinholdtsen 	memset(&fru, 0, sizeof(fru));
285c18ec02fSPetter Reinholdtsen 	fru.size = (rsp->data[1] << 8) | rsp->data[0];
286c18ec02fSPetter Reinholdtsen 	fru.access = rsp->data[2] & 0x1;
287c18ec02fSPetter Reinholdtsen 	if (fru.size < 1) {
288c18ec02fSPetter Reinholdtsen 		printf(" Invalid FRU size %d", fru.size);
289c18ec02fSPetter Reinholdtsen 		free(sn);
290c18ec02fSPetter Reinholdtsen 		sn = NULL;
29158837647SZdenek Styblik 		return (-1);
292c18ec02fSPetter Reinholdtsen 	}
29358837647SZdenek Styblik 	/* retrieve the FRU header */
294c18ec02fSPetter Reinholdtsen 	msg_data[0] = 0;
295c18ec02fSPetter Reinholdtsen 	msg_data[1] = 0;
296c18ec02fSPetter Reinholdtsen 	msg_data[2] = 0;
297c18ec02fSPetter Reinholdtsen 	msg_data[3] = 8;
298c18ec02fSPetter Reinholdtsen 
299c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
300c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
301c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_DATA;
302c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
303c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 4;
304c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
30558837647SZdenek Styblik 	if (rsp == NULL) {
306c18ec02fSPetter Reinholdtsen 		printf(" Device not present (No Response)\n");
307c18ec02fSPetter Reinholdtsen 		free(sn);
308c18ec02fSPetter Reinholdtsen 		sn = NULL;
309c18ec02fSPetter Reinholdtsen 		return (-1);
31058837647SZdenek Styblik 	} else if (rsp->ccode > 0) {
311c18ec02fSPetter Reinholdtsen 		printf(" Device not present (%s)\n",
312c18ec02fSPetter Reinholdtsen 				val2str(rsp->ccode, completion_code_vals));
313c18ec02fSPetter Reinholdtsen 		free(sn);
314c18ec02fSPetter Reinholdtsen 		sn = NULL;
315c18ec02fSPetter Reinholdtsen 		return (-1);
316c18ec02fSPetter Reinholdtsen 	}
31758837647SZdenek Styblik 	if (verbose > 1) {
318c18ec02fSPetter Reinholdtsen 		printbuf(rsp->data, rsp->data_len, "FRU DATA");
31958837647SZdenek Styblik 	}
320c18ec02fSPetter Reinholdtsen 	memcpy(&header, rsp->data + 1, 8);
32158837647SZdenek Styblik 	if (header.version != 1) {
322c18ec02fSPetter Reinholdtsen 		printf(" Unknown FRU header version 0x%02x",
323c18ec02fSPetter Reinholdtsen 				header.version);
324c18ec02fSPetter Reinholdtsen 		free(sn);
325c18ec02fSPetter Reinholdtsen 		sn = NULL;
326c18ec02fSPetter Reinholdtsen 		return(-1);
327c18ec02fSPetter Reinholdtsen 	}
328c18ec02fSPetter Reinholdtsen 	/* Set the Board Section */
329c18ec02fSPetter Reinholdtsen 	board_sec_len = (header.offset.product * 8) - (header.offset.board * 8);
330c18ec02fSPetter Reinholdtsen 	fru_data = malloc(fru.size);
33158837647SZdenek Styblik 	if (fru_data == NULL) {
33258837647SZdenek Styblik 		lprintf(LOG_ERR, "ipmitool: malloc failure");
333c18ec02fSPetter Reinholdtsen 		free(sn);
334c18ec02fSPetter Reinholdtsen 		sn = NULL;
335c18ec02fSPetter Reinholdtsen 		return (-1);
336c18ec02fSPetter Reinholdtsen 	}
337c18ec02fSPetter Reinholdtsen 	memset(fru_data, 0, fru.size);
33858837647SZdenek Styblik 	if (read_fru_area(intf, &fru, 0, (header.offset.board * 8),
33958837647SZdenek Styblik 				board_sec_len, fru_data) < 0) {
340c18ec02fSPetter Reinholdtsen 		free(sn);
341c18ec02fSPetter Reinholdtsen 		sn = NULL;
342c18ec02fSPetter Reinholdtsen 		free(fru_data);
343c18ec02fSPetter Reinholdtsen 		fru_data = NULL;
344c18ec02fSPetter Reinholdtsen 		return (-1);
345c18ec02fSPetter Reinholdtsen 	}
346c18ec02fSPetter Reinholdtsen 	/* Position at Board Manufacturer */
347c18ec02fSPetter Reinholdtsen 	fru_data_offset = (header.offset.board * 8) + 6;
348c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &fru_data_offset);
349*ce3f35d9SZdenek Styblik 	if (fru_area != NULL) {
350*ce3f35d9SZdenek Styblik 		free(fru_area);
351*ce3f35d9SZdenek Styblik 		fru_area = NULL;
352*ce3f35d9SZdenek Styblik 	}
353c18ec02fSPetter Reinholdtsen 	/* Position at Board Product Name */
354c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &fru_data_offset);
355*ce3f35d9SZdenek Styblik 	if (fru_area != NULL) {
356*ce3f35d9SZdenek Styblik 		free(fru_area);
357*ce3f35d9SZdenek Styblik 		fru_area = NULL;
358*ce3f35d9SZdenek Styblik 	}
359c18ec02fSPetter Reinholdtsen 	fru_data_offset_tmp = fru_data_offset;
360c18ec02fSPetter Reinholdtsen 	/* Position at Serial Number */
361c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp);
362*ce3f35d9SZdenek Styblik 	if (fru_area == NULL) {
363*ce3f35d9SZdenek Styblik 		lprintf(LOG_ERR, "Failed to read FRU Area string.");
364*ce3f35d9SZdenek Styblik 		free(fru_data);
365*ce3f35d9SZdenek Styblik 		fru_data = NULL;
366*ce3f35d9SZdenek Styblik 		free(sn);
367*ce3f35d9SZdenek Styblik 		sn = NULL;
368*ce3f35d9SZdenek Styblik 		return (-1);
369*ce3f35d9SZdenek Styblik 	}
370*ce3f35d9SZdenek Styblik 
371c18ec02fSPetter Reinholdtsen 	fru_data_offset++;
37258837647SZdenek Styblik 	if (strlen(fru_area) != sn_size) {
373c18ec02fSPetter Reinholdtsen 		printf("The length of the serial number in the FRU Board Area is wrong.\n");
374c18ec02fSPetter Reinholdtsen 		free(sn);
375c18ec02fSPetter Reinholdtsen 		sn = NULL;
376c18ec02fSPetter Reinholdtsen 		free(fru_data);
377c18ec02fSPetter Reinholdtsen 		fru_data = NULL;
378*ce3f35d9SZdenek Styblik 		free(fru_area);
379*ce3f35d9SZdenek Styblik 		fru_area = NULL;
380c18ec02fSPetter Reinholdtsen 		return(-1);
381*ce3f35d9SZdenek Styblik 	} else {
382*ce3f35d9SZdenek Styblik 		free(fru_area);
383*ce3f35d9SZdenek Styblik 		fru_area = NULL;
384c18ec02fSPetter Reinholdtsen 	}
385c18ec02fSPetter Reinholdtsen 	/* Copy the new serial number in the board section saved in memory*/
386c18ec02fSPetter Reinholdtsen 	memcpy(fru_data + fru_data_offset, sn, sn_size);
387c18ec02fSPetter Reinholdtsen 	checksum = 0;
388c18ec02fSPetter Reinholdtsen 	/* Calculate Header Checksum */
38958837647SZdenek Styblik 	for(i = (header.offset.board * 8);
39058837647SZdenek Styblik 			i < (((header.offset.board * 8) + board_sec_len) - 2);
39158837647SZdenek Styblik 			i++) {
392c18ec02fSPetter Reinholdtsen 		checksum += fru_data[i];
393c18ec02fSPetter Reinholdtsen 	}
394c18ec02fSPetter Reinholdtsen 	checksum = (~checksum) + 1;
395c18ec02fSPetter Reinholdtsen 	fru_data[(header.offset.board * 8) + board_sec_len - 1] = checksum;
396c18ec02fSPetter Reinholdtsen 	/* Write the new FRU Board section */
39758837647SZdenek Styblik 	if (write_fru_area(intf, &fru, 0, (header.offset.board * 8),
39858837647SZdenek Styblik 				(header.offset.board * 8),
39958837647SZdenek Styblik 				board_sec_len, fru_data) < 0) {
400c18ec02fSPetter Reinholdtsen 		free(sn);
401c18ec02fSPetter Reinholdtsen 		sn = NULL;
402c18ec02fSPetter Reinholdtsen 		free(fru_data);
403c18ec02fSPetter Reinholdtsen 		fru_data = NULL;
404*ce3f35d9SZdenek Styblik 		free(fru_area);
405*ce3f35d9SZdenek Styblik 		fru_area = NULL;
406c18ec02fSPetter Reinholdtsen 		return(-1);
407c18ec02fSPetter Reinholdtsen 	}
408c18ec02fSPetter Reinholdtsen 	/* Set the Product Section */
409c18ec02fSPetter Reinholdtsen 	prod_sec_len = (header.offset.multi * 8) - (header.offset.product * 8);
41058837647SZdenek Styblik 	if (read_fru_area(intf, &fru, 0, (header.offset.product * 8),
41158837647SZdenek Styblik 				prod_sec_len, fru_data) < 0) {
412c18ec02fSPetter Reinholdtsen 		free(sn);
413c18ec02fSPetter Reinholdtsen 		sn = NULL;
414c18ec02fSPetter Reinholdtsen 		free(fru_data);
415c18ec02fSPetter Reinholdtsen 		fru_data = NULL;
416*ce3f35d9SZdenek Styblik 		free(fru_area);
417*ce3f35d9SZdenek Styblik 		fru_area = NULL;
418c18ec02fSPetter Reinholdtsen 		return(-1);
419c18ec02fSPetter Reinholdtsen 	}
420c18ec02fSPetter Reinholdtsen 	/* Position at Product Manufacturer */
421c18ec02fSPetter Reinholdtsen 	fru_data_offset = (header.offset.product * 8) + 3;
422c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &fru_data_offset);
423*ce3f35d9SZdenek Styblik 	if (fru_area != NULL) {
424*ce3f35d9SZdenek Styblik 		free(fru_area);
425*ce3f35d9SZdenek Styblik 		fru_area = NULL;
426*ce3f35d9SZdenek Styblik 	}
427c18ec02fSPetter Reinholdtsen 	/* Position at Product Name */
428c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &fru_data_offset);
429*ce3f35d9SZdenek Styblik 	if (fru_area != NULL) {
430*ce3f35d9SZdenek Styblik 		free(fru_area);
431*ce3f35d9SZdenek Styblik 		fru_area = NULL;
432*ce3f35d9SZdenek Styblik 	}
433c18ec02fSPetter Reinholdtsen 	/* Position at Product Part */
434c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &fru_data_offset);
435*ce3f35d9SZdenek Styblik 	if (fru_area != NULL) {
436*ce3f35d9SZdenek Styblik 		free(fru_area);
437*ce3f35d9SZdenek Styblik 		fru_area = NULL;
438*ce3f35d9SZdenek Styblik 	}
439c18ec02fSPetter Reinholdtsen 	/* Position at Product Version */
440c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &fru_data_offset);
441*ce3f35d9SZdenek Styblik 	if (fru_area != NULL) {
442*ce3f35d9SZdenek Styblik 		free(fru_area);
443*ce3f35d9SZdenek Styblik 		fru_area = NULL;
444*ce3f35d9SZdenek Styblik 	}
445c18ec02fSPetter Reinholdtsen 	fru_data_offset_tmp = fru_data_offset;
446c18ec02fSPetter Reinholdtsen 	/* Position at Serial Number */
447c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp);
448*ce3f35d9SZdenek Styblik 	if (fru_area == NULL) {
449*ce3f35d9SZdenek Styblik 		lprintf(LOG_ERR, "Failed to read FRU Area string.");
450*ce3f35d9SZdenek Styblik 		free(sn);
451*ce3f35d9SZdenek Styblik 		sn = NULL;
452*ce3f35d9SZdenek Styblik 		free(fru_data);
453*ce3f35d9SZdenek Styblik 		fru_data = NULL;
454*ce3f35d9SZdenek Styblik 		return (-1);
455*ce3f35d9SZdenek Styblik 	}
456c18ec02fSPetter Reinholdtsen 	fru_data_offset ++;
45758837647SZdenek Styblik 	if (strlen(fru_area) != sn_size) {
458c18ec02fSPetter Reinholdtsen 		free(sn);
459c18ec02fSPetter Reinholdtsen 		sn = NULL;
460c18ec02fSPetter Reinholdtsen 		free(fru_data);
461c18ec02fSPetter Reinholdtsen 		fru_data = NULL;
462*ce3f35d9SZdenek Styblik 		free(fru_area);
463*ce3f35d9SZdenek Styblik 		fru_area = NULL;
464c18ec02fSPetter Reinholdtsen 		printf("The length of the serial number in the FRU Product Area is wrong.\n");
465c18ec02fSPetter Reinholdtsen 		return(-1);
466c18ec02fSPetter Reinholdtsen 	}
467c18ec02fSPetter Reinholdtsen 	/* Copy the new serial number in the product section saved in memory*/
468c18ec02fSPetter Reinholdtsen 	memcpy(fru_data + fru_data_offset, sn, sn_size);
469c18ec02fSPetter Reinholdtsen 	checksum = 0;
470c18ec02fSPetter Reinholdtsen 	/* Calculate Header Checksum */
47158837647SZdenek Styblik 	for (i = (header.offset.product * 8);
47258837647SZdenek Styblik 			i < (((header.offset.product * 8) + prod_sec_len) - 2);
47358837647SZdenek Styblik 			i ++) {
474c18ec02fSPetter Reinholdtsen 		checksum += fru_data[i];
475c18ec02fSPetter Reinholdtsen 	}
476c18ec02fSPetter Reinholdtsen 	checksum = (~checksum) + 1;
477c18ec02fSPetter Reinholdtsen 	fru_data[(header.offset.product * 8)+prod_sec_len - 1] = checksum;
478c18ec02fSPetter Reinholdtsen 	/* Write the new FRU Board section */
47958837647SZdenek Styblik 	if (write_fru_area(intf, &fru, 0, (header.offset.product * 8),
48058837647SZdenek Styblik 				(header.offset.product * 8),
48158837647SZdenek Styblik 				prod_sec_len, fru_data) < 0) {
482c18ec02fSPetter Reinholdtsen 		free(sn);
483c18ec02fSPetter Reinholdtsen 		sn = NULL;
484c18ec02fSPetter Reinholdtsen 		free(fru_data);
485c18ec02fSPetter Reinholdtsen 		fru_data = NULL;
486*ce3f35d9SZdenek Styblik 		free(fru_area);
487*ce3f35d9SZdenek Styblik 		fru_area = NULL;
488c18ec02fSPetter Reinholdtsen 		return -1;
489c18ec02fSPetter Reinholdtsen 	}
490c18ec02fSPetter Reinholdtsen 	free(sn);
491c18ec02fSPetter Reinholdtsen 	sn = NULL;
492c18ec02fSPetter Reinholdtsen 	free(fru_data);
493c18ec02fSPetter Reinholdtsen 	fru_data = NULL;
494*ce3f35d9SZdenek Styblik 	free(fru_area);
495*ce3f35d9SZdenek Styblik 	fru_area = NULL;
496c18ec02fSPetter Reinholdtsen 	return(1);
497c18ec02fSPetter Reinholdtsen }
498c18ec02fSPetter Reinholdtsen 
499c18ec02fSPetter Reinholdtsen /* ipmi_fru_set_mfg_date -  Set the Manufacturing Date in FRU
500c18ec02fSPetter Reinholdtsen  *
501c18ec02fSPetter Reinholdtsen  * @intf: ipmi interface
502c18ec02fSPetter Reinholdtsen  * @id: fru id
503c18ec02fSPetter Reinholdtsen  *
504c18ec02fSPetter Reinholdtsen  * returns -1 on error
505c18ec02fSPetter Reinholdtsen  * returns 1 if successful
506c18ec02fSPetter Reinholdtsen  */
507c18ec02fSPetter Reinholdtsen static int
ipmi_kontron_set_mfg_date(struct ipmi_intf * intf)508c18ec02fSPetter Reinholdtsen ipmi_kontron_set_mfg_date (struct ipmi_intf *intf)
509c18ec02fSPetter Reinholdtsen {
51058837647SZdenek Styblik 	struct fru_header header;
51158837647SZdenek Styblik 	struct fru_info fru;
512c18ec02fSPetter Reinholdtsen 	struct ipmi_rs *rsp;
513c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
51458837647SZdenek Styblik 	uint8_t *fru_data;
51558837647SZdenek Styblik 	uint8_t checksum;
516c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[4];
517c18ec02fSPetter Reinholdtsen 	uint8_t mfg_date[3];
51858837647SZdenek Styblik 	uint32_t board_sec_len;
51958837647SZdenek Styblik 	uint32_t i;
520c18ec02fSPetter Reinholdtsen 
521c18ec02fSPetter Reinholdtsen 	memset(msg_data, 0, 4);
522c18ec02fSPetter Reinholdtsen 	msg_data[0] = 0xb4;
523c18ec02fSPetter Reinholdtsen 	msg_data[1] = 0x90;
524c18ec02fSPetter Reinholdtsen 	msg_data[2] = 0x91;
525c18ec02fSPetter Reinholdtsen 	msg_data[3] = 0x8b;
526c18ec02fSPetter Reinholdtsen 
527c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
528c18ec02fSPetter Reinholdtsen 	req.msg.netfn = 0x3E;
529c18ec02fSPetter Reinholdtsen 	req.msg.cmd = 0x0E;
530c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
531c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 4;
532c18ec02fSPetter Reinholdtsen 	/* Set Lun temporary, necessary for this oem command */
533c18ec02fSPetter Reinholdtsen 	req.msg.lun = 0x03;
534c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
53558837647SZdenek Styblik 	if (rsp == NULL)  {
536c18ec02fSPetter Reinholdtsen 		printf("Device not present (No Response)\n");
537c18ec02fSPetter Reinholdtsen 		return(-1);
53858837647SZdenek Styblik 	} else if (rsp->ccode > 0) {
539c18ec02fSPetter Reinholdtsen 		printf("This option is not implemented for this board\n");
540c18ec02fSPetter Reinholdtsen 		return(-1);
541c18ec02fSPetter Reinholdtsen 	}
54258837647SZdenek Styblik 	if (rsp->data_len != 3) {
543c18ec02fSPetter Reinholdtsen 		printf("Invalid response for the Manufacturing date\n");
544c18ec02fSPetter Reinholdtsen 		return(-1);
545c18ec02fSPetter Reinholdtsen 	}
546c18ec02fSPetter Reinholdtsen 	memset(mfg_date, 0, 3);
547c18ec02fSPetter Reinholdtsen 	memcpy(mfg_date, rsp->data, 3);
548c18ec02fSPetter Reinholdtsen 	memset(msg_data, 0, 4);
549c18ec02fSPetter Reinholdtsen 	msg_data[0] = 0;
550c18ec02fSPetter Reinholdtsen 
551c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
552c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
553c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_INFO;
554c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
555c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 1;
556c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
557c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
558c18ec02fSPetter Reinholdtsen 		printf(" Device not present (No Response)\n");
559c18ec02fSPetter Reinholdtsen 		return(-1);
56058837647SZdenek Styblik 	} else if (rsp->ccode > 0) {
561c18ec02fSPetter Reinholdtsen 		printf(" Device not present (%s)\n",
562c18ec02fSPetter Reinholdtsen 				val2str(rsp->ccode, completion_code_vals));
563c18ec02fSPetter Reinholdtsen 		return(-1);
564c18ec02fSPetter Reinholdtsen 	}
565c18ec02fSPetter Reinholdtsen 
566c18ec02fSPetter Reinholdtsen 	memset(&fru, 0, sizeof(fru));
567c18ec02fSPetter Reinholdtsen 	fru.size = (rsp->data[1] << 8) | rsp->data[0];
568c18ec02fSPetter Reinholdtsen 	fru.access = rsp->data[2] & 0x1;
569c18ec02fSPetter Reinholdtsen 	if (fru.size < 1) {
570c18ec02fSPetter Reinholdtsen 		printf(" Invalid FRU size %d", fru.size);
571c18ec02fSPetter Reinholdtsen 		return(-1);
572c18ec02fSPetter Reinholdtsen 	}
57358837647SZdenek Styblik 	/* retrieve the FRU header */
574c18ec02fSPetter Reinholdtsen 	msg_data[0] = 0;
575c18ec02fSPetter Reinholdtsen 	msg_data[1] = 0;
576c18ec02fSPetter Reinholdtsen 	msg_data[2] = 0;
577c18ec02fSPetter Reinholdtsen 	msg_data[3] = 8;
578c18ec02fSPetter Reinholdtsen 
579c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
580c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
581c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_DATA;
582c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
583c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 4;
584c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
58558837647SZdenek Styblik 	if (rsp == NULL) {
586c18ec02fSPetter Reinholdtsen 		printf(" Device not present (No Response)\n");
587c18ec02fSPetter Reinholdtsen 		return (-1);
58858837647SZdenek Styblik 	} else if (rsp->ccode > 0) {
589c18ec02fSPetter Reinholdtsen 		printf(" Device not present (%s)\n",
590c18ec02fSPetter Reinholdtsen 				val2str(rsp->ccode, completion_code_vals));
591c18ec02fSPetter Reinholdtsen 		return (-1);
592c18ec02fSPetter Reinholdtsen 	}
59358837647SZdenek Styblik 	if (verbose > 1) {
594c18ec02fSPetter Reinholdtsen 		printbuf(rsp->data, rsp->data_len, "FRU DATA");
59558837647SZdenek Styblik 	}
596c18ec02fSPetter Reinholdtsen 	memcpy(&header, rsp->data + 1, 8);
59758837647SZdenek Styblik 	if (header.version != 1) {
598c18ec02fSPetter Reinholdtsen 		printf(" Unknown FRU header version 0x%02x",
599c18ec02fSPetter Reinholdtsen 				header.version);
600c18ec02fSPetter Reinholdtsen 		return(-1);
601c18ec02fSPetter Reinholdtsen 	}
602c18ec02fSPetter Reinholdtsen 	board_sec_len = (header.offset.product * 8) - (header.offset.board * 8);
603c18ec02fSPetter Reinholdtsen 	fru_data = malloc(fru.size);
60458837647SZdenek Styblik 	if(fru_data == NULL) {
60558837647SZdenek Styblik 		lprintf(LOG_ERR, "ipmitool: malloc failure");
606c18ec02fSPetter Reinholdtsen 		return(-1);
607c18ec02fSPetter Reinholdtsen 	}
608c18ec02fSPetter Reinholdtsen 	memset(fru_data, 0, fru.size);
60958837647SZdenek Styblik 	if (read_fru_area(intf ,&fru ,0 ,(header.offset.board * 8),
61058837647SZdenek Styblik 				board_sec_len ,fru_data) < 0) {
611c18ec02fSPetter Reinholdtsen 		free(fru_data);
612c18ec02fSPetter Reinholdtsen 		fru_data = NULL;
613c18ec02fSPetter Reinholdtsen 		return(-1);
614c18ec02fSPetter Reinholdtsen 	}
615c18ec02fSPetter Reinholdtsen 	/* Copy the new manufacturing date in the board section saved in memory*/
616c18ec02fSPetter Reinholdtsen 	memcpy(fru_data + (header.offset.board * 8) + 3, mfg_date, 3);
617c18ec02fSPetter Reinholdtsen 	checksum = 0;
618c18ec02fSPetter Reinholdtsen 	/* Calculate Header Checksum */
61958837647SZdenek Styblik 	for (i = (header.offset.board * 8);
62058837647SZdenek Styblik 			i < (((header.offset.board * 8) + board_sec_len) - 2);
62158837647SZdenek Styblik 			i ++ ) {
622c18ec02fSPetter Reinholdtsen 		checksum += fru_data[i];
623c18ec02fSPetter Reinholdtsen 	}
624c18ec02fSPetter Reinholdtsen 	checksum = (~checksum) + 1;
625c18ec02fSPetter Reinholdtsen 	fru_data[(header.offset.board * 8)+board_sec_len - 1] = checksum;
626c18ec02fSPetter Reinholdtsen 	/* Write the new FRU Board section */
62758837647SZdenek Styblik 	if (write_fru_area(intf, &fru, 0, (header.offset.board * 8),
62858837647SZdenek Styblik 				(header.offset.board * 8),
62958837647SZdenek Styblik 				board_sec_len, fru_data) < 0) {
630c18ec02fSPetter Reinholdtsen 		free(fru_data);
631c18ec02fSPetter Reinholdtsen 		fru_data = NULL;
632c18ec02fSPetter Reinholdtsen 		return (-1);
633c18ec02fSPetter Reinholdtsen 	}
634c18ec02fSPetter Reinholdtsen 	free(fru_data);
635c18ec02fSPetter Reinholdtsen 	fru_data = NULL;
636c18ec02fSPetter Reinholdtsen 	return (1);
637c18ec02fSPetter Reinholdtsen }
638c18ec02fSPetter Reinholdtsen 
639c18ec02fSPetter Reinholdtsen static void
ipmi_kontron_nextboot_help(void)640c18ec02fSPetter Reinholdtsen ipmi_kontron_nextboot_help(void)
641c18ec02fSPetter Reinholdtsen {
642c18ec02fSPetter Reinholdtsen 	int i;
643c18ec02fSPetter Reinholdtsen 	printf("nextboot <device>\n"
644c18ec02fSPetter Reinholdtsen 			"Supported devices:\n");
645c18ec02fSPetter Reinholdtsen 	for (i = 0; bootdev[i] != 0; i++) {
646c18ec02fSPetter Reinholdtsen 		printf("- %s\n", bootdev[i]);
647c18ec02fSPetter Reinholdtsen 	}
648c18ec02fSPetter Reinholdtsen }
649c18ec02fSPetter Reinholdtsen 
650c18ec02fSPetter Reinholdtsen /* ipmi_kontron_next_boot_set - Select the next boot order on CP6012
651c18ec02fSPetter Reinholdtsen  *
652c18ec02fSPetter Reinholdtsen  * @intf: ipmi interface
653c18ec02fSPetter Reinholdtsen  * @id: fru id
654c18ec02fSPetter Reinholdtsen  *
655c18ec02fSPetter Reinholdtsen  * returns -1 on error
656c18ec02fSPetter Reinholdtsen  * returns 1 if successful
657c18ec02fSPetter Reinholdtsen  */
658c18ec02fSPetter Reinholdtsen static int
ipmi_kontron_nextboot_set(struct ipmi_intf * intf,int argc,char ** argv)659c18ec02fSPetter Reinholdtsen ipmi_kontron_nextboot_set(struct ipmi_intf *intf, int argc, char **argv)
660c18ec02fSPetter Reinholdtsen {
661c18ec02fSPetter Reinholdtsen 	struct ipmi_rs *rsp;
662c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
663c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[8];
664c18ec02fSPetter Reinholdtsen 	int i;
665c18ec02fSPetter Reinholdtsen 
666c18ec02fSPetter Reinholdtsen 	memset(msg_data, 0, sizeof(msg_data));
667c18ec02fSPetter Reinholdtsen 	msg_data[0] = 0xb4;
668c18ec02fSPetter Reinholdtsen 	msg_data[1] = 0x90;
669c18ec02fSPetter Reinholdtsen 	msg_data[2] = 0x91;
670c18ec02fSPetter Reinholdtsen 	msg_data[3] = 0x8b;
671c18ec02fSPetter Reinholdtsen 	msg_data[4] = 0x9d;
672c18ec02fSPetter Reinholdtsen 	msg_data[5] = 0xFF;
673c18ec02fSPetter Reinholdtsen 	msg_data[6] = 0xFF; /* any */
674c18ec02fSPetter Reinholdtsen 	for (i = 0; bootdev[i] != 0; i++) {
675c18ec02fSPetter Reinholdtsen 		if (strcmp(argv[0], bootdev[i]) == 0) {
676c18ec02fSPetter Reinholdtsen 			msg_data[5] = i;
677c18ec02fSPetter Reinholdtsen 			break;
678c18ec02fSPetter Reinholdtsen 		}
679c18ec02fSPetter Reinholdtsen 	}
680c18ec02fSPetter Reinholdtsen 	/* Invalid device selected? */
681c18ec02fSPetter Reinholdtsen 	if (msg_data[5] == 0xFF) {
682c18ec02fSPetter Reinholdtsen 		printf("Unknown boot device: %s\n", argv[0]);
68358837647SZdenek Styblik 		return (-1);
684c18ec02fSPetter Reinholdtsen 	}
685c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
686c18ec02fSPetter Reinholdtsen 	req.msg.netfn = 0x3E;
687c18ec02fSPetter Reinholdtsen 	req.msg.cmd = 0x02;
688c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
689c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 7;
690c18ec02fSPetter Reinholdtsen 	/* Set Lun temporary, necessary for this oem command */
691c18ec02fSPetter Reinholdtsen 	req.msg.lun = 0x03;
692c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
69358837647SZdenek Styblik 	if (rsp == NULL) {
694c18ec02fSPetter Reinholdtsen 		printf("Device not present (No Response)\n");
695c18ec02fSPetter Reinholdtsen 		return(-1);
69658837647SZdenek Styblik 	} else if (rsp->ccode > 0) {
697c18ec02fSPetter Reinholdtsen 		printf("Device not present (%s)\n",
698c18ec02fSPetter Reinholdtsen 				val2str(rsp->ccode, completion_code_vals));
699c18ec02fSPetter Reinholdtsen 		return (-1);
700c18ec02fSPetter Reinholdtsen 	}
701c18ec02fSPetter Reinholdtsen 	return 0;
702c18ec02fSPetter Reinholdtsen }
703