diff --git a/ipmitool/include/ipmitool/ipmi_kontronoem.h b/ipmitool/include/ipmitool/ipmi_kontronoem.h new file mode 100644 index 0000000..ab73cd2 --- /dev/null +++ b/ipmitool/include/ipmitool/ipmi_kontronoem.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2004 Kontron Canada, Inc. All Rights Reserved. + * + * Base on code from + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + */ + +#ifndef IPMI_KONTRONOEM_H +#define IPMI_KONTRONOEM_H + +#include +#include + + +int ipmi_kontronoem_main(struct ipmi_intf *, int, char **); + +#endif /* IPMI_KONTRONOEM_H */ + diff --git a/ipmitool/lib/Makefile.am b/ipmitool/lib/Makefile.am index a25afa6..f2ef056 100644 --- a/ipmitool/lib/Makefile.am +++ b/ipmitool/lib/Makefile.am @@ -37,7 +37,7 @@ libipmitool_la_SOURCES = helper.c ipmi_sdr.c ipmi_sel.c ipmi_sol.c ipmi_pef.c \ dimm_spd.c ipmi_sensor.c ipmi_channel.c ipmi_event.c \ ipmi_session.c ipmi_strings.c ipmi_user.c ipmi_raw.c \ ipmi_oem.c ipmi_isol.c ipmi_sunoem.c ipmi_fwum.c ipmi_picmg.c \ - ipmi_main.c ipmi_tsol.c ipmi_firewall.c + ipmi_main.c ipmi_tsol.c ipmi_firewall.c ipmi_kontronoem.c libipmitool_la_LDFLAGS = -export-dynamic libipmitool_la_LIBADD = -lm diff --git a/ipmitool/lib/ipmi_kontronoem.c b/ipmitool/lib/ipmi_kontronoem.c new file mode 100644 index 0000000..65a930c --- /dev/null +++ b/ipmitool/lib/ipmi_kontronoem.c @@ -0,0 +1,591 @@ +/* + * Copyright (c) 2004 Kontron Canada, Inc. All Rights Reserved. + * + * Base on code from + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + */ + +/* + * Tue Mar 7 14:36:12 2006 + * + * + * This code implements an Kontron OEM proprietary commands. + */ + + +#include +#include +#include +#include +#include + + +extern int verbose; +extern int read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, + uint8_t id, uint32_t offset, uint32_t length, + uint8_t *frubuf); +extern int write_fru_area(struct ipmi_intf * intf, struct fru_info *fru, + unsigned char id, unsigned int soffset, + unsigned int doffset, unsigned int length, + unsigned char *pFrubuf); + +extern char * get_fru_area_str(uint8_t * data, uint32_t * offset); + + + +static void ipmi_kontron_help(void); +static int ipmi_kontron_set_serial_number(struct ipmi_intf * intf); +static int ipmi_kontron_set_mfg_date (struct ipmi_intf * intf); + + + +int +ipmi_kontronoem_main(struct ipmi_intf * intf, int argc, char ** argv) +{ + int rc = 0; + + if (argc == 0) + ipmi_kontron_help(); + else if (strncmp(argv[0], "help", 4) == 0) + ipmi_kontron_help(); + + else if(!strncmp(argv[0], "setsn", 5)) + { + if(argc >= 1) + { + if(ipmi_kontron_set_serial_number(intf) > 0) + { + printf("FRU serial number setted successfully\n"); + } + else + { + printf("FRU serial number set failed\n"); + } + } + else + { + printf("fru setsn\n"); + } + } + else if(!strncmp(argv[0], "setmfgdate", 5)) + { + if(argc >= 1) + { + if(ipmi_kontron_set_mfg_date(intf) > 0) + { + printf("FRU manufacturing date setted successfully\n"); + } + else + { + printf("FRU manufacturing date set failed\n"); + } + } + else + { + printf("fru setmfgdate\n"); + } + + } + + else + { + printf("Invalid Kontron command: %s", argv[0]); + ipmi_kontron_help(); + rc = -1; + } + + return rc; +} + + +static void ipmi_kontron_help(void) +{ + printf("Kontron Commands: setsn setmfgdate\n"); +} + +/* ipmi_fru_set_serial_number - Set the Serial Number in FRU + * + * @intf: ipmi interface + * @id: fru id + * + * returns -1 on error + * returns 1 if successful + */ +static int +ipmi_kontron_set_serial_number(struct ipmi_intf * intf) +{ + struct ipmi_rs *rsp; + struct ipmi_rq req; + struct fru_info fru; + struct fru_header header; + uint8_t msg_data[4]; + char *sn; + uint8_t sn_size, checksum,prev_lun; + int ret = 0; + uint8_t *fru_data, *fru_area; + uint32_t fru_data_offset, fru_data_offset_tmp, board_sec_len, prod_sec_len, i; + + sn = NULL; + fru_data = NULL; + + memset(msg_data, 0, 4); + msg_data[0] = 0xb4; + msg_data[1] = 0x90; + msg_data[2] = 0x91; + msg_data[3] = 0x8b; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = 0x3E; + req.msg.cmd = 0x0C; + req.msg.data = msg_data; + req.msg.data_len = 4; + + + /* Set Lun, necessary for this oem command */ + req.msg.lun = 0x03; + + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) + { + printf(" Device not present (No Response)\n"); + return -11; + } + + if (rsp->ccode > 0) + { + printf(" This option is not implemented for this board\n"); + return -1; + } + + sn_size = rsp->data_len; + + sn = malloc(sn_size + 1); + + if(sn == NULL) + { + printf("Out of memory!"); + return; + } + + memset(sn, 0, sn_size + 1); + memcpy(sn, rsp->data, sn_size); + + if(verbose >= 1) + { + printf("Original serial number is : [%s]\n", sn); + } + + + + memset(msg_data, 0, 4); + msg_data[0] = 0; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = GET_FRU_INFO; + req.msg.data = msg_data; + req.msg.data_len = 1; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + printf(" Device not present (No Response)\n"); + free(sn); + return -1; + } + if (rsp->ccode > 0) { + printf(" Device not present (%s)\n", + val2str(rsp->ccode, completion_code_vals)); + free(sn); + return(-1); + } + + fru.size = (rsp->data[1] << 8) | rsp->data[0]; + fru.access = rsp->data[2] & 0x1; + + if (fru.size < 1) { + printf(" Invalid FRU size %d", fru.size); + free(sn); + return -1; + } + + /* + * retrieve the FRU header + */ + msg_data[0] = 0; + msg_data[1] = 0; + msg_data[2] = 0; + msg_data[3] = 8; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = GET_FRU_DATA; + req.msg.data = msg_data; + req.msg.data_len = 4; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) + { + printf(" Device not present (No Response)\n"); + free(sn); + return(-1); + } + if (rsp->ccode > 0) + { + printf(" Device not present (%s)\n", + val2str(rsp->ccode, completion_code_vals)); + free(sn); + return(-1); + } + + if (verbose > 1) + printbuf(rsp->data, rsp->data_len, "FRU DATA"); + + memcpy(&header, rsp->data + 1, 8); + + if (header.version != 1) + { + printf(" Unknown FRU header version 0x%02x", + header.version); + free(sn); + return(-1); + } + + /* Set the Board Section */ + board_sec_len = (header.offset.product * 8) - (header.offset.board * 8); + + + fru_data = malloc( fru.size); + + if(fru_data == NULL) + { + printf("Out of memory!"); + free(sn); + return(-1); + } + + memset(fru_data, 0, fru.size); + if(read_fru_area(intf ,&fru ,0 ,(header.offset.board * 8) ,board_sec_len , fru_data) < 0) + { + free(sn); + free(fru_data); + return(-1); + } + + /*Position at Board Manufacturer*/ + fru_data_offset = (header.offset.board * 8) + 6; + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + /*Position at Board Product Name*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + fru_data_offset_tmp = fru_data_offset; + + /*Position at Serial Number*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp); + + fru_data_offset ++; + + if(strlen(fru_area) != sn_size) + { + printf("The length of the serial number in the FRU Board Area is wrong.\n"); + free(sn); + free(fru_data); + return(-1); + } + + /* Copy the new serial number in the board section saved in memory*/ + memcpy(fru_data + fru_data_offset, sn, sn_size); + + checksum = 0; + /* Calculate Header Checksum */ + for( i = (header.offset.board * 8); i < (((header.offset.board * 8)+board_sec_len) - 2) ; i ++ ) + { + checksum += fru_data[i]; + } + checksum = (~checksum) + 1; + + + fru_data[(header.offset.board * 8)+board_sec_len - 1] = checksum; + + /* Write the new FRU Board section */ + if(write_fru_area(intf, &fru, 0, (header.offset.board * 8), (header.offset.board * 8), board_sec_len, fru_data) < 0) + { + free(sn); + free(fru_data); + return(-1); + } + + /* Set the Product Section */ + prod_sec_len = (header.offset.multi * 8) - (header.offset.product * 8); + + if(read_fru_area(intf ,&fru ,0 ,(header.offset.product * 8) ,prod_sec_len , fru_data) < 0) + { + free(sn); + free(fru_data); + return(-1); + } + + /*Position at Product Manufacturer*/ + fru_data_offset = (header.offset.product * 8) + 3; + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + /*Position at Product Name*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + /*Position at Product Part*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + /*Position at Product Version*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + + + fru_data_offset_tmp = fru_data_offset; + + /*Position at Serial Number*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp); + + fru_data_offset ++; + + if(strlen(fru_area) != sn_size) + { + free(sn); + free(fru_data); + printf("The length of the serial number in the FRU Product Area is wrong.\n"); + return(-1); + + } + + /* Copy the new serial number in the product section saved in memory*/ + memcpy(fru_data + fru_data_offset, sn, sn_size); + + checksum = 0; + /* Calculate Header Checksum */ + for( i = (header.offset.product * 8); i < (((header.offset.product * 8)+prod_sec_len) - 2) ; i ++ ) + { + checksum += fru_data[i]; + } + checksum = (~checksum) + 1; + + + fru_data[(header.offset.product * 8)+prod_sec_len - 1] = checksum; + + /* Write the new FRU Board section */ + if(write_fru_area(intf, &fru, 0, (header.offset.product * 8), (header.offset.product * 8), prod_sec_len, fru_data) < 0) + { + free(sn); + free(fru_data); + return -1; + } + + free(sn); + free(fru_data); + + return(1); + +} + + +/* ipmi_fru_set_mfg_date - Set the Manufacturing Date in FRU + * + * @intf: ipmi interface + * @id: fru id + * + * returns -1 on error + * returns 1 if successful + */ +static int +ipmi_kontron_set_mfg_date (struct ipmi_intf * intf) +{ + struct ipmi_rs *rsp; + struct ipmi_rq req; + struct fru_info fru; + struct fru_header header; + uint8_t msg_data[4]; + uint8_t mfg_date[3]; + + uint32_t board_sec_len, i; + uint8_t *fru_data, checksum; + int ret = 0; + + + + + memset(msg_data, 0, 4); + msg_data[0] = 0xb4; + msg_data[1] = 0x90; + msg_data[2] = 0x91; + msg_data[3] = 0x8b; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = 0x3E; + req.msg.cmd = 0x0E; + req.msg.data = msg_data; + req.msg.data_len = 4; + + /* Set Lun temporary, necessary for this oem command */ + req.msg.lun = 0x03; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) + { + printf("Device not present (No Response)\n"); + return(-1); + } + + if (rsp->ccode > 0) + { + printf("This option is not implemented for this board\n"); + return(-1); + } + + if(rsp->data_len != 3) + { + printf("Invalid response for the Manufacturing date\n"); + return(-1); + } + + memset(mfg_date, 0, 3); + memcpy(mfg_date, rsp->data, 3); + + memset(msg_data, 0, 4); + msg_data[0] = 0; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = GET_FRU_INFO; + req.msg.data = msg_data; + req.msg.data_len = 1; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + printf(" Device not present (No Response)\n"); + return(-1); + } + if (rsp->ccode > 0) { + printf(" Device not present (%s)\n", + val2str(rsp->ccode, completion_code_vals)); + return(-1); + } + + fru.size = (rsp->data[1] << 8) | rsp->data[0]; + fru.access = rsp->data[2] & 0x1; + + if (fru.size < 1) { + printf(" Invalid FRU size %d", fru.size); + return(-1); + } + + /* + * retrieve the FRU header + */ + msg_data[0] = 0; + msg_data[1] = 0; + msg_data[2] = 0; + msg_data[3] = 8; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = GET_FRU_DATA; + req.msg.data = msg_data; + req.msg.data_len = 4; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) + { + printf(" Device not present (No Response)\n"); + return(-1); + } + if (rsp->ccode > 0) + { + printf(" Device not present (%s)\n", + val2str(rsp->ccode, completion_code_vals)); + return(-1); + } + + if (verbose > 1) + printbuf(rsp->data, rsp->data_len, "FRU DATA"); + + memcpy(&header, rsp->data + 1, 8); + + if (header.version != 1) + { + printf(" Unknown FRU header version 0x%02x", + header.version); + return(-1); + } + + + board_sec_len = (header.offset.product * 8) - (header.offset.board * 8); + + fru_data = malloc( fru.size); + + if(fru_data == NULL) + { + lprintf("Out of memory!"); + return(-1); + } + + memset(fru_data, 0, fru.size); + if(read_fru_area(intf ,&fru ,0 ,(header.offset.board * 8) ,board_sec_len , fru_data) < 0) + { + free(fru_data); + return(-1); + } + + /* Copy the new manufacturing date in the board section saved in memory*/ + memcpy(fru_data + (header.offset.board * 8) + 3, mfg_date, 3); + + checksum = 0; + /* Calculate Header Checksum */ + for( i = (header.offset.board * 8); i < (((header.offset.board * 8)+board_sec_len) - 2) ; i ++ ) + { + checksum += fru_data[i]; + } + checksum = (~checksum) + 1; + + fru_data[(header.offset.board * 8)+board_sec_len - 1] = checksum; + + /* Write the new FRU Board section */ + if(write_fru_area(intf, &fru, 0, (header.offset.board * 8), (header.offset.board * 8), board_sec_len, fru_data) < 0) + { + free(fru_data); + return(-1); + } + + free(fru_data); + return(1); +} diff --git a/ipmitool/src/ipmitool.c b/ipmitool/src/ipmitool.c index f824528..fb073f0 100644 --- a/ipmitool/src/ipmitool.c +++ b/ipmitool/src/ipmitool.c @@ -31,6 +31,10 @@ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. */ #include @@ -49,7 +53,6 @@ #include #include #include -#include #include #include #include @@ -58,6 +61,7 @@ #include #include #include +#include #ifdef HAVE_CONFIG_H # include @@ -94,8 +98,8 @@ struct ipmi_cmd ipmitool_cmd_list[] = { { ipmi_user_main, "user", "Configure Management Controller users" }, { ipmi_channel_main, "channel", "Configure Management Controller channels" }, { ipmi_session_main, "session", "Print session information" }, - { ipmi_firewall_main,"firewall","Configure firmware firewall (IPMIv2.0)"}, { ipmi_sunoem_main, "sunoem", "OEM Commands for Sun servers" }, + { ipmi_kontronoem_main, "kontronoem", "OEM Commands for Kontron devices"}, { ipmi_picmg_main, "picmg", "Run a PICMG/ATCA extended cmd"}, { ipmi_fwum_main, "fwum", "Update IPMC using Kontron OEM Firmware Update Manager" }, #ifdef HAVE_READLINE