Blame lib/ipmi_kontronoem.c

Packit d14fb6
/*
Packit d14fb6
 * Copyright (c) 2004 Kontron Canada, Inc.  All Rights Reserved.
Packit d14fb6
 *
Packit d14fb6
 * Base on code from
Packit d14fb6
 * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
Packit d14fb6
 *
Packit d14fb6
 * Redistribution and use in source and binary forms, with or without
Packit d14fb6
 * modification, are permitted provided that the following conditions
Packit d14fb6
 * are met:
Packit d14fb6
 *
Packit d14fb6
 * Redistribution of source code must retain the above copyright
Packit d14fb6
 * notice, this list of conditions and the following disclaimer.
Packit d14fb6
 *
Packit d14fb6
 * Redistribution in binary form must reproduce the above copyright
Packit d14fb6
 * notice, this list of conditions and the following disclaimer in the
Packit d14fb6
 * documentation and/or other materials provided with the distribution.
Packit d14fb6
 *
Packit d14fb6
 * Neither the name of Sun Microsystems, Inc. or the names of
Packit d14fb6
 * contributors may be used to endorse or promote products derived
Packit d14fb6
 * from this software without specific prior written permission.
Packit d14fb6
 *
Packit d14fb6
 * This software is provided "AS IS," without a warranty of any kind.
Packit d14fb6
 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
Packit d14fb6
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
Packit d14fb6
 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
Packit d14fb6
 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
Packit d14fb6
 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
Packit d14fb6
 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
Packit d14fb6
 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
Packit d14fb6
 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
Packit d14fb6
 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
Packit d14fb6
 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
Packit d14fb6
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
Packit d14fb6
 */
Packit d14fb6
Packit d14fb6
/*
Packit d14fb6
 * Tue Mar 7 14:36:12 2006
Packit d14fb6
 * <stephane.filion@ca.kontron.com>
Packit d14fb6
 *
Packit d14fb6
 * This code implements an Kontron OEM proprietary commands.
Packit d14fb6
 */
Packit d14fb6
#include <string.h>
Packit d14fb6
#include <ipmitool/helper.h>
Packit d14fb6
#include <ipmitool/log.h>
Packit d14fb6
#include <ipmitool/ipmi.h>
Packit d14fb6
#include <ipmitool/ipmi_intf.h>
Packit d14fb6
#include <ipmitool/ipmi_fru.h>
Packit d14fb6
Packit d14fb6
extern int verbose;
Packit d14fb6
extern int read_fru_area(struct ipmi_intf *intf, struct fru_info *fru,
Packit d14fb6
		uint8_t id, uint32_t offset, uint32_t length,
Packit d14fb6
		uint8_t *frubuf);
Packit d14fb6
extern int write_fru_area(struct ipmi_intf * intf, struct fru_info *fru,
Packit d14fb6
		uint8_t id, uint16_t soffset,
Packit d14fb6
		uint16_t doffset,  uint16_t length,
Packit d14fb6
		uint8_t *pFrubuf);
Packit d14fb6
extern char *get_fru_area_str(uint8_t *data, uint32_t *offset);
Packit d14fb6
Packit d14fb6
static void ipmi_kontron_help(void);
Packit d14fb6
static int ipmi_kontron_set_serial_number(struct ipmi_intf *intf);
Packit d14fb6
static int ipmi_kontron_set_mfg_date (struct ipmi_intf *intf);
Packit d14fb6
static void ipmi_kontron_nextboot_help(void);
Packit d14fb6
static int ipmi_kontron_nextboot_set(struct ipmi_intf *intf, int argc,
Packit d14fb6
		char **argv);
Packit d14fb6
static int ipmi_kontronoem_send_set_large_buffer(struct ipmi_intf *intf,
Packit d14fb6
		unsigned char channel, unsigned char size);
Packit d14fb6
Packit d14fb6
static char *bootdev[] = {"BIOS", "FDD", "HDD", "CDROM", "network", 0};
Packit d14fb6
Packit d14fb6
int
Packit d14fb6
ipmi_kontronoem_main(struct ipmi_intf *intf, int argc, char **argv)
Packit d14fb6
{
Packit d14fb6
	int rc = 0;
Packit d14fb6
	if (argc == 0) {
Packit d14fb6
		lprintf(LOG_ERR, "Not enough parameters given.");
Packit d14fb6
		ipmi_kontron_help();
Packit d14fb6
		return (-1);
Packit d14fb6
	}
Packit d14fb6
	if (strncmp(argv[0], "help", 4) == 0) {
Packit d14fb6
		ipmi_kontron_help();
Packit d14fb6
		rc = 0;
Packit d14fb6
	} else if (!strncmp(argv[0], "setsn", 5)) {
Packit d14fb6
		if (argc < 1) {
Packit d14fb6
			printf("fru setsn\n");
Packit d14fb6
			return (-1);
Packit d14fb6
		}
Packit d14fb6
		if (ipmi_kontron_set_serial_number(intf) > 0) {
Packit d14fb6
			printf("FRU serial number setted successfully\n");
Packit d14fb6
		} else {
Packit d14fb6
			printf("FRU serial number set failed\n");
Packit d14fb6
			rc = (-1);
Packit d14fb6
		}
Packit d14fb6
	} else if (!strncmp(argv[0], "setmfgdate", 10)) {
Packit d14fb6
		if (argc < 1) {
Packit d14fb6
			printf("fru setmfgdate\n");
Packit d14fb6
			return (-1);
Packit d14fb6
		}
Packit d14fb6
		if (ipmi_kontron_set_mfg_date(intf) > 0) {
Packit d14fb6
			printf("FRU manufacturing date setted successfully\n");
Packit d14fb6
		} else {
Packit d14fb6
			printf("FRU manufacturing date set failed\n");
Packit d14fb6
			rc = (-1);
Packit d14fb6
		}
Packit d14fb6
	} else if (!strncmp(argv[0], "nextboot", 8)) {
Packit d14fb6
		if (argc < 2) {
Packit d14fb6
			lprintf(LOG_ERR, "Not enough parameters given.");
Packit d14fb6
			ipmi_kontron_nextboot_help();
Packit d14fb6
			return (-1);
Packit d14fb6
		}
Packit d14fb6
		rc = ipmi_kontron_nextboot_set(intf, (argc - 1), (argv + 1));
Packit d14fb6
		if (rc == 0) {
Packit d14fb6
			printf("Nextboot set successfully\n");
Packit d14fb6
		} else {
Packit d14fb6
			printf("Nextboot set failed\n");
Packit d14fb6
			rc = (-1);
Packit d14fb6
		}
Packit d14fb6
	} else  {
Packit d14fb6
		lprintf(LOG_ERR, "Invalid Kontron command: %s", argv[0]);
Packit d14fb6
		ipmi_kontron_help();
Packit d14fb6
		rc = (-1);
Packit d14fb6
	}
Packit d14fb6
	return rc;
Packit d14fb6
}
Packit d14fb6
Packit d14fb6
static void
Packit d14fb6
ipmi_kontron_help(void)
Packit d14fb6
{
Packit d14fb6
	printf("Kontron Commands:  setsn setmfgdate nextboot\n");
Packit d14fb6
}
Packit d14fb6
Packit d14fb6
int
Packit d14fb6
ipmi_kontronoem_set_large_buffer(struct ipmi_intf *intf, unsigned char size)
Packit d14fb6
{
Packit d14fb6
	uint8_t error_occurs = 0;
Packit d14fb6
	uint32_t prev_target_addr = intf->target_addr ;
Packit d14fb6
	if (intf->target_addr > 0 && (intf->target_addr != intf->my_addr)) {
Packit d14fb6
		intf->target_addr = intf->my_addr;
Packit d14fb6
		printf("Set local big buffer\n");
Packit d14fb6
		if (ipmi_kontronoem_send_set_large_buffer(intf, 0x0e, size) == 0) {
Packit d14fb6
			printf("Set local big buffer:success\n");
Packit d14fb6
		} else {
Packit d14fb6
			error_occurs = 1;
Packit d14fb6
		}
Packit d14fb6
		if (error_occurs == 0) {
Packit d14fb6
			if (ipmi_kontronoem_send_set_large_buffer(intf, 0x00, size) == 0) {
Packit d14fb6
				printf("IPMB was set\n");
Packit d14fb6
			} else {
Packit d14fb6
				/* Revert back the previous set large buffer */
Packit d14fb6
				error_occurs = 1;
Packit d14fb6
				ipmi_kontronoem_send_set_large_buffer( intf, 0x0e, 0 );
Packit d14fb6
			}
Packit d14fb6
		}
Packit d14fb6
		/* Restore target address */
Packit d14fb6
		intf->target_addr = prev_target_addr;
Packit d14fb6
	}
Packit d14fb6
	if (error_occurs == 0) {
Packit d14fb6
		if(ipmi_kontronoem_send_set_large_buffer(intf, 0x0e, size) == 0) {
Packit d14fb6
			/* printf("Set remote big buffer\n"); */
Packit d14fb6
		} else {
Packit d14fb6
			if (intf->target_addr > 0  && (intf->target_addr != intf->my_addr)) {
Packit d14fb6
				/* Error occurs revert back the previous set large buffer */
Packit d14fb6
				intf->target_addr = intf->my_addr;
Packit d14fb6
				/* ipmi_kontronoem_send_set_large_buffer(intf, 0x00, 0); */
Packit d14fb6
				ipmi_kontronoem_send_set_large_buffer(intf, 0x0e, 0);
Packit d14fb6
				intf->target_addr = prev_target_addr;
Packit d14fb6
			}
Packit d14fb6
		}
Packit d14fb6
	}
Packit d14fb6
	return error_occurs;
Packit d14fb6
}
Packit d14fb6
Packit d14fb6
int
Packit d14fb6
ipmi_kontronoem_send_set_large_buffer(struct ipmi_intf *intf,
Packit d14fb6
		unsigned char channel, unsigned char size)
Packit d14fb6
{
Packit d14fb6
	struct ipmi_rs *rsp;
Packit d14fb6
	struct ipmi_rq req;
Packit d14fb6
	uint8_t msg_data[2];
Packit d14fb6
	memset(msg_data, 0, sizeof(msg_data));
Packit d14fb6
	/* channel =~ 0x0e => Currently running interface */
Packit d14fb6
	msg_data[0] = channel;
Packit d14fb6
	msg_data[1] = size;
Packit d14fb6
	memset(&req, 0, sizeof(req));
Packit d14fb6
	req.msg.netfn = 0x3E;
Packit d14fb6
	/* Set Channel Buffer Length - OEM */
Packit d14fb6
	req.msg.cmd = 0x82;
Packit d14fb6
	req.msg.data = msg_data;
Packit d14fb6
	req.msg.data_len = 2;
Packit d14fb6
	req.msg.lun = 0x00;
Packit d14fb6
	rsp = intf->sendrecv(intf, &req;;
Packit d14fb6
	if (rsp == NULL)  {
Packit d14fb6
		printf("Cannot send large buffer command\n");
Packit d14fb6
		return(-1);
Packit d14fb6
	} else if (rsp->ccode > 0)  {
Packit d14fb6
		printf("Invalid length for the selected interface (%s) %d\n",
Packit d14fb6
				val2str(rsp->ccode, completion_code_vals), rsp->ccode);
Packit d14fb6
		return(-1);
Packit d14fb6
	}
Packit d14fb6
	return 0;
Packit d14fb6
}
Packit d14fb6
Packit d14fb6
/* ipmi_fru_set_serial_number -  Set the Serial Number in FRU
Packit d14fb6
 *
Packit d14fb6
 * @intf: ipmi interface
Packit d14fb6
 * @id: fru id
Packit d14fb6
 *
Packit d14fb6
 * returns -1 on error
Packit d14fb6
 * returns 1 if successful
Packit d14fb6
 */
Packit d14fb6
static int
Packit d14fb6
ipmi_kontron_set_serial_number(struct ipmi_intf *intf)
Packit d14fb6
{
Packit d14fb6
	struct fru_header header;
Packit d14fb6
	struct fru_info fru;
Packit d14fb6
	struct ipmi_rs *rsp;
Packit d14fb6
	struct ipmi_rq req;
Packit d14fb6
	char *sn;
Packit d14fb6
	char *fru_area;
Packit d14fb6
	uint8_t checksum;
Packit d14fb6
	uint8_t *fru_data;
Packit d14fb6
	uint8_t msg_data[4];
Packit d14fb6
	uint8_t sn_size;
Packit d14fb6
	uint32_t board_sec_len;
Packit d14fb6
	uint32_t fru_data_offset;
Packit d14fb6
	uint32_t fru_data_offset_tmp;
Packit d14fb6
	uint32_t i;
Packit d14fb6
	uint32_t prod_sec_len;
Packit d14fb6
Packit d14fb6
	sn = NULL;
Packit d14fb6
	fru_data = NULL;
Packit d14fb6
Packit d14fb6
	memset(msg_data, 0, 4);
Packit d14fb6
	msg_data[0] = 0xb4;
Packit d14fb6
	msg_data[1] = 0x90;
Packit d14fb6
	msg_data[2] = 0x91;
Packit d14fb6
	msg_data[3] = 0x8b;
Packit d14fb6
Packit d14fb6
	memset(&req, 0, sizeof(req));
Packit d14fb6
	req.msg.netfn = 0x3E;
Packit d14fb6
	req.msg.cmd = 0x0C;
Packit d14fb6
	req.msg.data = msg_data;
Packit d14fb6
	req.msg.data_len = 4;
Packit d14fb6
	/* Set Lun, necessary for this oem command */
Packit d14fb6
	req.msg.lun = 0x03;
Packit d14fb6
	rsp = intf->sendrecv(intf, &req;;
Packit d14fb6
	if (rsp == NULL) {
Packit d14fb6
		printf(" Device not present (No Response)\n");
Packit d14fb6
		return (-1);
Packit d14fb6
	} else if (rsp->ccode > 0) {
Packit d14fb6
		printf(" This option is not implemented for this board\n");
Packit d14fb6
		return (-1);
Packit d14fb6
	}
Packit d14fb6
	sn_size = rsp->data_len;
Packit d14fb6
	sn = malloc(sn_size + 1);
Packit d14fb6
	if (sn == NULL) {
Packit d14fb6
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit d14fb6
		return (-1);
Packit d14fb6
	}
Packit d14fb6
	memset(sn, 0, sn_size + 1);
Packit d14fb6
	memcpy(sn, rsp->data, sn_size);
Packit d14fb6
	if (verbose >= 1) {
Packit d14fb6
		printf("Original serial number is : [%s]\n", sn);
Packit d14fb6
	}
Packit d14fb6
	memset(msg_data, 0, 4);
Packit d14fb6
	msg_data[0] = 0;
Packit d14fb6
	memset(&req, 0, sizeof(req));
Packit d14fb6
	req.msg.netfn = IPMI_NETFN_STORAGE;
Packit d14fb6
	req.msg.cmd = GET_FRU_INFO;
Packit d14fb6
	req.msg.data = msg_data;
Packit d14fb6
	req.msg.data_len = 1;
Packit d14fb6
	rsp = intf->sendrecv(intf, &req;;
Packit d14fb6
	if (rsp == NULL) {
Packit d14fb6
		printf(" Device not present (No Response)\n");
Packit d14fb6
		free(sn);
Packit d14fb6
		sn = NULL;
Packit d14fb6
		return (-1);
Packit d14fb6
	} else if (rsp->ccode > 0) {
Packit d14fb6
		printf(" Device not present (%s)\n",
Packit d14fb6
				val2str(rsp->ccode, completion_code_vals));
Packit d14fb6
		free(sn);
Packit d14fb6
		sn = NULL;
Packit d14fb6
		return (-1);
Packit d14fb6
	}
Packit d14fb6
	memset(&fru, 0, sizeof(fru));
Packit d14fb6
	fru.size = (rsp->data[1] << 8) | rsp->data[0];
Packit d14fb6
	fru.access = rsp->data[2] & 0x1;
Packit d14fb6
	if (fru.size < 1) {
Packit d14fb6
		printf(" Invalid FRU size %d", fru.size);
Packit d14fb6
		free(sn);
Packit d14fb6
		sn = NULL;
Packit d14fb6
		return (-1);
Packit d14fb6
	}
Packit d14fb6
	/* retrieve the FRU header */
Packit d14fb6
	msg_data[0] = 0;
Packit d14fb6
	msg_data[1] = 0;
Packit d14fb6
	msg_data[2] = 0;
Packit d14fb6
	msg_data[3] = 8;
Packit d14fb6
Packit d14fb6
	memset(&req, 0, sizeof(req));
Packit d14fb6
	req.msg.netfn = IPMI_NETFN_STORAGE;
Packit d14fb6
	req.msg.cmd = GET_FRU_DATA;
Packit d14fb6
	req.msg.data = msg_data;
Packit d14fb6
	req.msg.data_len = 4;
Packit d14fb6
	rsp = intf->sendrecv(intf, &req;;
Packit d14fb6
	if (rsp == NULL) {
Packit d14fb6
		printf(" Device not present (No Response)\n");
Packit d14fb6
		free(sn);
Packit d14fb6
		sn = NULL;
Packit d14fb6
		return (-1);
Packit d14fb6
	} else if (rsp->ccode > 0) {
Packit d14fb6
		printf(" Device not present (%s)\n",
Packit d14fb6
				val2str(rsp->ccode, completion_code_vals));
Packit d14fb6
		free(sn);
Packit d14fb6
		sn = NULL;
Packit d14fb6
		return (-1);
Packit d14fb6
	}
Packit d14fb6
	if (verbose > 1) {
Packit d14fb6
		printbuf(rsp->data, rsp->data_len, "FRU DATA");
Packit d14fb6
	}
Packit d14fb6
	memcpy(&header, rsp->data + 1, 8);
Packit d14fb6
	if (header.version != 1) {
Packit d14fb6
		printf(" Unknown FRU header version 0x%02x",
Packit d14fb6
				header.version);
Packit d14fb6
		free(sn);
Packit d14fb6
		sn = NULL;
Packit d14fb6
		return(-1);
Packit d14fb6
	}
Packit d14fb6
	/* Set the Board Section */
Packit d14fb6
	board_sec_len = (header.offset.product * 8) - (header.offset.board * 8);
Packit d14fb6
	fru_data = malloc(fru.size);
Packit d14fb6
	if (fru_data == NULL) {
Packit d14fb6
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit d14fb6
		free(sn);
Packit d14fb6
		sn = NULL;
Packit d14fb6
		return (-1);
Packit d14fb6
	}
Packit d14fb6
	memset(fru_data, 0, fru.size);
Packit d14fb6
	if (read_fru_area(intf, &fru, 0, (header.offset.board * 8),
Packit d14fb6
				board_sec_len, fru_data) < 0) {
Packit d14fb6
		free(sn);
Packit d14fb6
		sn = NULL;
Packit d14fb6
		free(fru_data);
Packit d14fb6
		fru_data = NULL;
Packit d14fb6
		return (-1);
Packit d14fb6
	}
Packit d14fb6
	/* Position at Board Manufacturer */
Packit d14fb6
	fru_data_offset = (header.offset.board * 8) + 6;
Packit d14fb6
	fru_area = get_fru_area_str(fru_data, &fru_data_offset);
Packit d14fb6
	if (fru_area != NULL) {
Packit d14fb6
		free(fru_area);
Packit d14fb6
		fru_area = NULL;
Packit d14fb6
	}
Packit d14fb6
	/* Position at Board Product Name */
Packit d14fb6
	fru_area = get_fru_area_str(fru_data, &fru_data_offset);
Packit d14fb6
	if (fru_area != NULL) {
Packit d14fb6
		free(fru_area);
Packit d14fb6
		fru_area = NULL;
Packit d14fb6
	}
Packit d14fb6
	fru_data_offset_tmp = fru_data_offset;
Packit d14fb6
	/* Position at Serial Number */
Packit d14fb6
	fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp);
Packit d14fb6
	if (fru_area == NULL) {
Packit d14fb6
		lprintf(LOG_ERR, "Failed to read FRU Area string.");
Packit d14fb6
		free(fru_data);
Packit d14fb6
		fru_data = NULL;
Packit d14fb6
		free(sn);
Packit d14fb6
		sn = NULL;
Packit d14fb6
		return (-1);
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	fru_data_offset++;
Packit d14fb6
	if (strlen(fru_area) != sn_size) {
Packit d14fb6
		printf("The length of the serial number in the FRU Board Area is wrong.\n");
Packit d14fb6
		free(sn);
Packit d14fb6
		sn = NULL;
Packit d14fb6
		free(fru_data);
Packit d14fb6
		fru_data = NULL;
Packit d14fb6
		free(fru_area);
Packit d14fb6
		fru_area = NULL;
Packit d14fb6
		return(-1);
Packit d14fb6
	} else {
Packit d14fb6
		free(fru_area);
Packit d14fb6
		fru_area = NULL;
Packit d14fb6
	}
Packit d14fb6
	/* Copy the new serial number in the board section saved in memory*/
Packit d14fb6
	memcpy(fru_data + fru_data_offset, sn, sn_size);
Packit d14fb6
	checksum = 0;
Packit d14fb6
	/* Calculate Header Checksum */
Packit d14fb6
	for(i = (header.offset.board * 8);
Packit d14fb6
			i < (((header.offset.board * 8) + board_sec_len) - 2);
Packit d14fb6
			i++) {
Packit d14fb6
		checksum += fru_data[i];
Packit d14fb6
	}
Packit d14fb6
	checksum = (~checksum) + 1;
Packit d14fb6
	fru_data[(header.offset.board * 8) + board_sec_len - 1] = checksum;
Packit d14fb6
	/* Write the new FRU Board section */
Packit d14fb6
	if (write_fru_area(intf, &fru, 0, (header.offset.board * 8),
Packit d14fb6
				(header.offset.board * 8),
Packit d14fb6
				board_sec_len, fru_data) < 0) {
Packit d14fb6
		free(sn);
Packit d14fb6
		sn = NULL;
Packit d14fb6
		free(fru_data);
Packit d14fb6
		fru_data = NULL;
Packit d14fb6
		free(fru_area);
Packit d14fb6
		fru_area = NULL;
Packit d14fb6
		return(-1);
Packit d14fb6
	}
Packit d14fb6
	/* Set the Product Section */
Packit d14fb6
	prod_sec_len = (header.offset.multi * 8) - (header.offset.product * 8);
Packit d14fb6
	if (read_fru_area(intf, &fru, 0, (header.offset.product * 8),
Packit d14fb6
				prod_sec_len, fru_data) < 0) {
Packit d14fb6
		free(sn);
Packit d14fb6
		sn = NULL;
Packit d14fb6
		free(fru_data);
Packit d14fb6
		fru_data = NULL;
Packit d14fb6
		free(fru_area);
Packit d14fb6
		fru_area = NULL;
Packit d14fb6
		return(-1);
Packit d14fb6
	}
Packit d14fb6
	/* Position at Product Manufacturer */
Packit d14fb6
	fru_data_offset = (header.offset.product * 8) + 3;
Packit d14fb6
	fru_area = get_fru_area_str(fru_data, &fru_data_offset);
Packit d14fb6
	if (fru_area != NULL) {
Packit d14fb6
		free(fru_area);
Packit d14fb6
		fru_area = NULL;
Packit d14fb6
	}
Packit d14fb6
	/* Position at Product Name */
Packit d14fb6
	fru_area = get_fru_area_str(fru_data, &fru_data_offset);
Packit d14fb6
	if (fru_area != NULL) {
Packit d14fb6
		free(fru_area);
Packit d14fb6
		fru_area = NULL;
Packit d14fb6
	}
Packit d14fb6
	/* Position at Product Part */
Packit d14fb6
	fru_area = get_fru_area_str(fru_data, &fru_data_offset);
Packit d14fb6
	if (fru_area != NULL) {
Packit d14fb6
		free(fru_area);
Packit d14fb6
		fru_area = NULL;
Packit d14fb6
	}
Packit d14fb6
	/* Position at Product Version */
Packit d14fb6
	fru_area = get_fru_area_str(fru_data, &fru_data_offset);
Packit d14fb6
	if (fru_area != NULL) {
Packit d14fb6
		free(fru_area);
Packit d14fb6
		fru_area = NULL;
Packit d14fb6
	}
Packit d14fb6
	fru_data_offset_tmp = fru_data_offset;
Packit d14fb6
	/* Position at Serial Number */
Packit d14fb6
	fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp);
Packit d14fb6
	if (fru_area == NULL) {
Packit d14fb6
		lprintf(LOG_ERR, "Failed to read FRU Area string.");
Packit d14fb6
		free(sn);
Packit d14fb6
		sn = NULL;
Packit d14fb6
		free(fru_data);
Packit d14fb6
		fru_data = NULL;
Packit d14fb6
		return (-1);
Packit d14fb6
	}
Packit d14fb6
	fru_data_offset ++;
Packit d14fb6
	if (strlen(fru_area) != sn_size) {
Packit d14fb6
		free(sn);
Packit d14fb6
		sn = NULL;
Packit d14fb6
		free(fru_data);
Packit d14fb6
		fru_data = NULL;
Packit d14fb6
		free(fru_area);
Packit d14fb6
		fru_area = NULL;
Packit d14fb6
		printf("The length of the serial number in the FRU Product Area is wrong.\n");
Packit d14fb6
		return(-1);
Packit d14fb6
	}
Packit d14fb6
	/* Copy the new serial number in the product section saved in memory*/
Packit d14fb6
	memcpy(fru_data + fru_data_offset, sn, sn_size);
Packit d14fb6
	checksum = 0;
Packit d14fb6
	/* Calculate Header Checksum */
Packit d14fb6
	for (i = (header.offset.product * 8);
Packit d14fb6
			i < (((header.offset.product * 8) + prod_sec_len) - 2);
Packit d14fb6
			i ++) {
Packit d14fb6
		checksum += fru_data[i];
Packit d14fb6
	}
Packit d14fb6
	checksum = (~checksum) + 1;
Packit d14fb6
	fru_data[(header.offset.product * 8)+prod_sec_len - 1] = checksum;
Packit d14fb6
	/* Write the new FRU Board section */
Packit d14fb6
	if (write_fru_area(intf, &fru, 0, (header.offset.product * 8),
Packit d14fb6
				(header.offset.product * 8),
Packit d14fb6
				prod_sec_len, fru_data) < 0) {
Packit d14fb6
		free(sn);
Packit d14fb6
		sn = NULL;
Packit d14fb6
		free(fru_data);
Packit d14fb6
		fru_data = NULL;
Packit d14fb6
		free(fru_area);
Packit d14fb6
		fru_area = NULL;
Packit d14fb6
		return -1;
Packit d14fb6
	}
Packit d14fb6
	free(sn);
Packit d14fb6
	sn = NULL;
Packit d14fb6
	free(fru_data);
Packit d14fb6
	fru_data = NULL;
Packit d14fb6
	free(fru_area);
Packit d14fb6
	fru_area = NULL;
Packit d14fb6
	return(1);
Packit d14fb6
}
Packit d14fb6
Packit d14fb6
/* ipmi_fru_set_mfg_date -  Set the Manufacturing Date in FRU
Packit d14fb6
 *
Packit d14fb6
 * @intf: ipmi interface
Packit d14fb6
 * @id: fru id
Packit d14fb6
 *
Packit d14fb6
 * returns -1 on error
Packit d14fb6
 * returns 1 if successful
Packit d14fb6
 */
Packit d14fb6
static int
Packit d14fb6
ipmi_kontron_set_mfg_date (struct ipmi_intf *intf)
Packit d14fb6
{
Packit d14fb6
	struct fru_header header;
Packit d14fb6
	struct fru_info fru;
Packit d14fb6
	struct ipmi_rs *rsp;
Packit d14fb6
	struct ipmi_rq req;
Packit d14fb6
	uint8_t *fru_data;
Packit d14fb6
	uint8_t checksum;
Packit d14fb6
	uint8_t msg_data[4];
Packit d14fb6
	uint8_t mfg_date[3];
Packit d14fb6
	uint32_t board_sec_len;
Packit d14fb6
	uint32_t i;
Packit d14fb6
Packit d14fb6
	memset(msg_data, 0, 4);
Packit d14fb6
	msg_data[0] = 0xb4;
Packit d14fb6
	msg_data[1] = 0x90;
Packit d14fb6
	msg_data[2] = 0x91;
Packit d14fb6
	msg_data[3] = 0x8b;
Packit d14fb6
Packit d14fb6
	memset(&req, 0, sizeof(req));
Packit d14fb6
	req.msg.netfn = 0x3E;
Packit d14fb6
	req.msg.cmd = 0x0E;
Packit d14fb6
	req.msg.data = msg_data;
Packit d14fb6
	req.msg.data_len = 4;
Packit d14fb6
	/* Set Lun temporary, necessary for this oem command */
Packit d14fb6
	req.msg.lun = 0x03;
Packit d14fb6
	rsp = intf->sendrecv(intf, &req;;
Packit d14fb6
	if (rsp == NULL)  {
Packit d14fb6
		printf("Device not present (No Response)\n");
Packit d14fb6
		return(-1);
Packit d14fb6
	} else if (rsp->ccode > 0) {
Packit d14fb6
		printf("This option is not implemented for this board\n");
Packit d14fb6
		return(-1);
Packit d14fb6
	}
Packit d14fb6
	if (rsp->data_len != 3) {
Packit d14fb6
		printf("Invalid response for the Manufacturing date\n");
Packit d14fb6
		return(-1);
Packit d14fb6
	}
Packit d14fb6
	memset(mfg_date, 0, 3);
Packit d14fb6
	memcpy(mfg_date, rsp->data, 3);
Packit d14fb6
	memset(msg_data, 0, 4);
Packit d14fb6
	msg_data[0] = 0;
Packit d14fb6
Packit d14fb6
	memset(&req, 0, sizeof(req));
Packit d14fb6
	req.msg.netfn = IPMI_NETFN_STORAGE;
Packit d14fb6
	req.msg.cmd = GET_FRU_INFO;
Packit d14fb6
	req.msg.data = msg_data;
Packit d14fb6
	req.msg.data_len = 1;
Packit d14fb6
	rsp = intf->sendrecv(intf, &req;;
Packit d14fb6
	if (rsp == NULL) {
Packit d14fb6
		printf(" Device not present (No Response)\n");
Packit d14fb6
		return(-1);
Packit d14fb6
	} else if (rsp->ccode > 0) {
Packit d14fb6
		printf(" Device not present (%s)\n",
Packit d14fb6
				val2str(rsp->ccode, completion_code_vals));
Packit d14fb6
		return(-1);
Packit d14fb6
	}
Packit d14fb6
Packit d14fb6
	memset(&fru, 0, sizeof(fru));
Packit d14fb6
	fru.size = (rsp->data[1] << 8) | rsp->data[0];
Packit d14fb6
	fru.access = rsp->data[2] & 0x1;
Packit d14fb6
	if (fru.size < 1) {
Packit d14fb6
		printf(" Invalid FRU size %d", fru.size);
Packit d14fb6
		return(-1);
Packit d14fb6
	}
Packit d14fb6
	/* retrieve the FRU header */
Packit d14fb6
	msg_data[0] = 0;
Packit d14fb6
	msg_data[1] = 0;
Packit d14fb6
	msg_data[2] = 0;
Packit d14fb6
	msg_data[3] = 8;
Packit d14fb6
Packit d14fb6
	memset(&req, 0, sizeof(req));
Packit d14fb6
	req.msg.netfn = IPMI_NETFN_STORAGE;
Packit d14fb6
	req.msg.cmd = GET_FRU_DATA;
Packit d14fb6
	req.msg.data = msg_data;
Packit d14fb6
	req.msg.data_len = 4;
Packit d14fb6
	rsp = intf->sendrecv(intf, &req;;
Packit d14fb6
	if (rsp == NULL) {
Packit d14fb6
		printf(" Device not present (No Response)\n");
Packit d14fb6
		return (-1);
Packit d14fb6
	} else if (rsp->ccode > 0) {
Packit d14fb6
		printf(" Device not present (%s)\n",
Packit d14fb6
				val2str(rsp->ccode, completion_code_vals));
Packit d14fb6
		return (-1);
Packit d14fb6
	}
Packit d14fb6
	if (verbose > 1) {
Packit d14fb6
		printbuf(rsp->data, rsp->data_len, "FRU DATA");
Packit d14fb6
	}
Packit d14fb6
	memcpy(&header, rsp->data + 1, 8);
Packit d14fb6
	if (header.version != 1) {
Packit d14fb6
		printf(" Unknown FRU header version 0x%02x",
Packit d14fb6
				header.version);
Packit d14fb6
		return(-1);
Packit d14fb6
	}
Packit d14fb6
	board_sec_len = (header.offset.product * 8) - (header.offset.board * 8);
Packit d14fb6
	fru_data = malloc(fru.size);
Packit d14fb6
	if(fru_data == NULL) {
Packit d14fb6
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit d14fb6
		return(-1);
Packit d14fb6
	}
Packit d14fb6
	memset(fru_data, 0, fru.size);
Packit d14fb6
	if (read_fru_area(intf ,&fru ,0 ,(header.offset.board * 8),
Packit d14fb6
				board_sec_len ,fru_data) < 0) {
Packit d14fb6
		free(fru_data);
Packit d14fb6
		fru_data = NULL;
Packit d14fb6
		return(-1);
Packit d14fb6
	}
Packit d14fb6
	/* Copy the new manufacturing date in the board section saved in memory*/
Packit d14fb6
	memcpy(fru_data + (header.offset.board * 8) + 3, mfg_date, 3);
Packit d14fb6
	checksum = 0;
Packit d14fb6
	/* Calculate Header Checksum */
Packit d14fb6
	for (i = (header.offset.board * 8);
Packit d14fb6
			i < (((header.offset.board * 8) + board_sec_len) - 2);
Packit d14fb6
			i ++ ) {
Packit d14fb6
		checksum += fru_data[i];
Packit d14fb6
	}
Packit d14fb6
	checksum = (~checksum) + 1;
Packit d14fb6
	fru_data[(header.offset.board * 8)+board_sec_len - 1] = checksum;
Packit d14fb6
	/* Write the new FRU Board section */
Packit d14fb6
	if (write_fru_area(intf, &fru, 0, (header.offset.board * 8),
Packit d14fb6
				(header.offset.board * 8),
Packit d14fb6
				board_sec_len, fru_data) < 0) {
Packit d14fb6
		free(fru_data);
Packit d14fb6
		fru_data = NULL;
Packit d14fb6
		return (-1);
Packit d14fb6
	}
Packit d14fb6
	free(fru_data);
Packit d14fb6
	fru_data = NULL;
Packit d14fb6
	return (1);
Packit d14fb6
}
Packit d14fb6
Packit d14fb6
static void
Packit d14fb6
ipmi_kontron_nextboot_help(void)
Packit d14fb6
{
Packit d14fb6
	int i;
Packit d14fb6
	printf("nextboot <device>\n"
Packit d14fb6
			"Supported devices:\n");
Packit d14fb6
	for (i = 0; bootdev[i] != 0; i++) {
Packit d14fb6
		printf("- %s\n", bootdev[i]);
Packit d14fb6
	}
Packit d14fb6
}
Packit d14fb6
Packit d14fb6
/* ipmi_kontron_next_boot_set - Select the next boot order on CP6012
Packit d14fb6
 *
Packit d14fb6
 * @intf: ipmi interface
Packit d14fb6
 * @id: fru id
Packit d14fb6
 *
Packit d14fb6
 * returns -1 on error
Packit d14fb6
 * returns 1 if successful
Packit d14fb6
 */
Packit d14fb6
static int
Packit d14fb6
ipmi_kontron_nextboot_set(struct ipmi_intf *intf, int argc, char **argv)
Packit d14fb6
{
Packit d14fb6
	struct ipmi_rs *rsp;
Packit d14fb6
	struct ipmi_rq req;
Packit d14fb6
	uint8_t msg_data[8];
Packit d14fb6
	int i;
Packit d14fb6
Packit d14fb6
	memset(msg_data, 0, sizeof(msg_data));
Packit d14fb6
	msg_data[0] = 0xb4;
Packit d14fb6
	msg_data[1] = 0x90;
Packit d14fb6
	msg_data[2] = 0x91;
Packit d14fb6
	msg_data[3] = 0x8b;
Packit d14fb6
	msg_data[4] = 0x9d;
Packit d14fb6
	msg_data[5] = 0xFF;
Packit d14fb6
	msg_data[6] = 0xFF; /* any */
Packit d14fb6
	for (i = 0; bootdev[i] != 0; i++) {
Packit d14fb6
		if (strcmp(argv[0], bootdev[i]) == 0) {
Packit d14fb6
			msg_data[5] = i;
Packit d14fb6
			break;
Packit d14fb6
		}
Packit d14fb6
	}
Packit d14fb6
	/* Invalid device selected? */
Packit d14fb6
	if (msg_data[5] == 0xFF) {
Packit d14fb6
		printf("Unknown boot device: %s\n", argv[0]);
Packit d14fb6
		return (-1);
Packit d14fb6
	}
Packit d14fb6
	memset(&req, 0, sizeof(req));
Packit d14fb6
	req.msg.netfn = 0x3E;
Packit d14fb6
	req.msg.cmd = 0x02;
Packit d14fb6
	req.msg.data = msg_data;
Packit d14fb6
	req.msg.data_len = 7;
Packit d14fb6
	/* Set Lun temporary, necessary for this oem command */
Packit d14fb6
	req.msg.lun = 0x03;
Packit d14fb6
	rsp = intf->sendrecv(intf, &req;;
Packit d14fb6
	if (rsp == NULL) {
Packit d14fb6
		printf("Device not present (No Response)\n");
Packit d14fb6
		return(-1);
Packit d14fb6
	} else if (rsp->ccode > 0) {
Packit d14fb6
		printf("Device not present (%s)\n",
Packit d14fb6
				val2str(rsp->ccode, completion_code_vals));
Packit d14fb6
		return (-1);
Packit d14fb6
	}
Packit d14fb6
	return 0;
Packit d14fb6
}