mirror of
https://github.com/ipmitool/ipmitool.git
synced 2025-05-12 19:47:23 +00:00
Added new 'FRU edit' mode (field mode)
fru edit [fruid] field [section] [index] [string]\ This can be used to change serial number information and such, use with care Cleanup/improved 'oem' edit mode : - defaults to PICMG for backward compatibily - validates that 'oem' is followed by a 'iana' number Attempted 'tabify' while integrating patch, hope the indentation will be ok for others.
This commit is contained in:
parent
8824e41b48
commit
b0c04f8577
@ -71,6 +71,9 @@ static int ipmi_fru_get_multirec_from_file(char * pFileName, uint8_t * pBufArea,
|
|||||||
static int ipmi_fru_get_multirec_size_from_file(char * pFileName, uint32_t * pSize, uint32_t * pOffset);
|
static int ipmi_fru_get_multirec_size_from_file(char * pFileName, uint32_t * pSize, uint32_t * pOffset);
|
||||||
static void ipmi_fru_get_adjust_size_from_buffer(uint8_t * pBufArea, uint32_t *pSize);
|
static void ipmi_fru_get_adjust_size_from_buffer(uint8_t * pBufArea, uint32_t *pSize);
|
||||||
static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length);
|
static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length);
|
||||||
|
static int ipmi_fru_set_field_string(struct ipmi_intf * intf, unsigned
|
||||||
|
char fruId, uint8_t f_type, uint8_t f_index, char *f_string);
|
||||||
|
|
||||||
|
|
||||||
/* get_fru_area_str - Parse FRU area string from raw data
|
/* get_fru_area_str - Parse FRU area string from raw data
|
||||||
*
|
*
|
||||||
@ -864,7 +867,7 @@ int ipmi_fru_query_new_value(uint8_t *data,int offset, size_t len)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ipmi_fru_kontron_ext_edit -
|
/* ipmi_fru_oemkontron_edit -
|
||||||
* Query new values to replace original FRU content
|
* Query new values to replace original FRU content
|
||||||
* This is a generic enough to support any type of 'OEM' record
|
* This is a generic enough to support any type of 'OEM' record
|
||||||
* because the user supplies 'IANA number' , 'record Id' and 'record' version'
|
* because the user supplies 'IANA number' , 'record Id' and 'record' version'
|
||||||
@ -935,6 +938,7 @@ static int ipmi_fru_oemkontron_edit( int argc, char ** argv,uint8_t * fru_data,
|
|||||||
offset += sizeof(struct fru_multirec_oem_header);
|
offset += sizeof(struct fru_multirec_oem_header);
|
||||||
|
|
||||||
if(!badParams){
|
if(!badParams){
|
||||||
|
/* the 'OEM' field is already checked in caller */
|
||||||
if( argc > OEM_KONTRON_SUBCOMMAND_ARG_POS ){
|
if( argc > OEM_KONTRON_SUBCOMMAND_ARG_POS ){
|
||||||
if(strncmp("oem", argv[OEM_KONTRON_SUBCOMMAND_ARG_POS],3)){
|
if(strncmp("oem", argv[OEM_KONTRON_SUBCOMMAND_ARG_POS],3)){
|
||||||
printf("usage: fru edit <id> <oem> <args...>\r\n");
|
printf("usage: fru edit <id> <oem> <args...>\r\n");
|
||||||
@ -965,14 +969,12 @@ static int ipmi_fru_oemkontron_edit( int argc, char ** argv,uint8_t * fru_data,
|
|||||||
if(!badParams){
|
if(!badParams){
|
||||||
|
|
||||||
if(oh->record_id == OEM_KONTRON_INFORMATION_RECORD ) {
|
if(oh->record_id == OEM_KONTRON_INFORMATION_RECORD ) {
|
||||||
printf(" Kontron OEM Information Record\n");
|
|
||||||
{
|
|
||||||
|
|
||||||
uint8_t version;
|
uint8_t version;
|
||||||
|
|
||||||
|
printf(" Kontron OEM Information Record\n");
|
||||||
version = oh->record_version;
|
version = oh->record_version;
|
||||||
|
|
||||||
if( version == 00 ){
|
if( version == 0 ){
|
||||||
int blockstart;
|
int blockstart;
|
||||||
uint8_t blockCount;
|
uint8_t blockCount;
|
||||||
uint8_t blockIndex=0;
|
uint8_t blockIndex=0;
|
||||||
@ -994,10 +996,8 @@ static int ipmi_fru_oemkontron_edit( int argc, char ** argv,uint8_t * fru_data,
|
|||||||
|
|
||||||
nameLen = ( fru_data[offset++] &= 0x3F );
|
nameLen = ( fru_data[offset++] &= 0x3F );
|
||||||
|
|
||||||
if(!strncmp(argv[OEM_KONTRON_NAME_ARG_POS],fru_data+offset,
|
if(!strncmp(argv[OEM_KONTRON_NAME_ARG_POS],
|
||||||
nameLen)
|
fru_data+offset,nameLen)&& (matchInstance == instance)){
|
||||||
&&
|
|
||||||
(matchInstance == instance)){
|
|
||||||
|
|
||||||
printf ("Found : %s\n",argv[OEM_KONTRON_NAME_ARG_POS]);
|
printf ("Found : %s\n",argv[OEM_KONTRON_NAME_ARG_POS]);
|
||||||
offset+=nameLen;
|
offset+=nameLen;
|
||||||
@ -1038,8 +1038,6 @@ static int ipmi_fru_oemkontron_edit( int argc, char ** argv,uint8_t * fru_data,
|
|||||||
printf(" Version: %d\n",version);
|
printf(" Version: %d\n",version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
if( hasChanged ){
|
if( hasChanged ){
|
||||||
|
|
||||||
uint8_t record_checksum =0;
|
uint8_t record_checksum =0;
|
||||||
@ -2342,6 +2340,7 @@ ipmi_fru_edit_multirec(struct ipmi_intf * intf, uint8_t id ,
|
|||||||
uint32_t offset= offFruMultiRec;
|
uint32_t offset= offFruMultiRec;
|
||||||
struct fru_multirec_header * h;
|
struct fru_multirec_header * h;
|
||||||
uint32_t last_off, len;
|
uint32_t last_off, len;
|
||||||
|
uint8_t error=0;
|
||||||
|
|
||||||
i = last_off = offset;
|
i = last_off = offset;
|
||||||
fru_len = 0;
|
fru_len = 0;
|
||||||
@ -2374,9 +2373,29 @@ ipmi_fru_edit_multirec(struct ipmi_intf * intf, uint8_t id ,
|
|||||||
&fru_data[i + sizeof(struct fru_multirec_header)];
|
&fru_data[i + sizeof(struct fru_multirec_header)];
|
||||||
uint32_t iana = oh->mfg_id[0] | oh->mfg_id[1]<<8 | oh->mfg_id[2]<<16;
|
uint32_t iana = oh->mfg_id[0] | oh->mfg_id[1]<<8 | oh->mfg_id[2]<<16;
|
||||||
|
|
||||||
|
uint32_t suppliedIana = 0 ;
|
||||||
/* Now makes sure this is really PICMG record */
|
/* Now makes sure this is really PICMG record */
|
||||||
|
|
||||||
if( iana == IPMI_OEM_PICMG && (argc <=2 )){
|
/* Default to PICMG for backward compatibility */
|
||||||
|
if( argc <=2 ) {
|
||||||
|
suppliedIana = IPMI_OEM_PICMG;
|
||||||
|
} else {
|
||||||
|
if( !strncmp( argv[2] , "oem" , 3 )) {
|
||||||
|
/* Expect IANA number next */
|
||||||
|
if( argc <= 3 ) {
|
||||||
|
lprintf(LOG_ERR, "oem iana <record> <format> [<args>]");
|
||||||
|
error = 1;
|
||||||
|
} else {
|
||||||
|
suppliedIana = atol ( argv[3] ) ;
|
||||||
|
lprintf(LOG_DEBUG, "using iana: %d", suppliedIana);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( suppliedIana == iana ) {
|
||||||
|
lprintf(LOG_DEBUG, "Matching record found" );
|
||||||
|
|
||||||
|
if( iana == IPMI_OEM_PICMG ){
|
||||||
if( ipmi_fru_picmg_ext_edit(fru_data,
|
if( ipmi_fru_picmg_ext_edit(fru_data,
|
||||||
i + sizeof(struct fru_multirec_header),
|
i + sizeof(struct fru_multirec_header),
|
||||||
h->len, h, oh )){
|
h->len, h, oh )){
|
||||||
@ -2396,11 +2415,14 @@ ipmi_fru_edit_multirec(struct ipmi_intf * intf, uint8_t id ,
|
|||||||
}
|
}
|
||||||
/* FIXME: Add OEM record support here */
|
/* FIXME: Add OEM record support here */
|
||||||
else{
|
else{
|
||||||
printf(" OEM (%s) Record\n", val2str( iana, ipmi_oem_info));
|
printf(" OEM IANA (%s) Record not support in this mode\n",
|
||||||
|
val2str( iana, ipmi_oem_info));
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i += h->len + sizeof (struct fru_multirec_header);
|
i += h->len + sizeof (struct fru_multirec_header);
|
||||||
} while (!(h->format & 0x80));
|
} while (!(h->format & 0x80) && (error != 1));
|
||||||
|
|
||||||
free(fru_data);
|
free(fru_data);
|
||||||
}
|
}
|
||||||
@ -2724,28 +2746,23 @@ ipmi_fru_main(struct ipmi_intf * intf, int argc, char ** argv)
|
|||||||
}
|
}
|
||||||
else if (!strncmp(argv[0], "read", 5)) {
|
else if (!strncmp(argv[0], "read", 5)) {
|
||||||
uint8_t fruId=0;
|
uint8_t fruId=0;
|
||||||
if((argc >= 3) && (strlen(argv[2]) > 0))
|
if((argc >= 3) && (strlen(argv[2]) > 0)){
|
||||||
{
|
|
||||||
/* There is a file name in the parameters */
|
/* There is a file name in the parameters */
|
||||||
if(strlen(argv[2]) < 512)
|
if(strlen(argv[2]) < 512)
|
||||||
{
|
{
|
||||||
fruId = atoi(argv[1]);
|
fruId = atoi(argv[1]);
|
||||||
strcpy(fileName, argv[2]);
|
strcpy(fileName, argv[2]);
|
||||||
if (verbose)
|
if (verbose){
|
||||||
{
|
|
||||||
printf("Fru Id : %d\n", fruId);
|
printf("Fru Id : %d\n", fruId);
|
||||||
printf("Fru File : %s\n", fileName);
|
printf("Fru File : %s\n", fileName);
|
||||||
}
|
}
|
||||||
ipmi_fru_read_to_bin(intf, fileName, fruId);
|
ipmi_fru_read_to_bin(intf, fileName, fruId);
|
||||||
}
|
}
|
||||||
else
|
else{
|
||||||
{
|
|
||||||
|
|
||||||
fprintf(stderr,"File name must be smaller than 512 bytes\n");
|
fprintf(stderr,"File name must be smaller than 512 bytes\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else{
|
||||||
{
|
|
||||||
printf("fru read <fru id> <fru file>\n");
|
printf("fru read <fru id> <fru file>\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2779,10 +2796,30 @@ ipmi_fru_main(struct ipmi_intf * intf, int argc, char ** argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!strncmp(argv[0], "edit", 4)) {
|
else if (!strncmp(argv[0], "edit", 4)) {
|
||||||
|
uint8_t fruId = 0;
|
||||||
if ((argc >= 2) && (strlen(argv[1]) > 0)) {
|
if ((argc >= 2) && (strlen(argv[1]) > 0)) {
|
||||||
ipmi_fru_edit_multirec(intf,atoi(argv[1]), argc, argv);
|
fruId = atoi(argv[1]);
|
||||||
|
if (verbose) {
|
||||||
|
printf("Fru Id : %d\n", fruId);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
printf("Using default FRU id: %d\n", fruId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((argc >= 3) && (strlen(argv[1]) > 0)) {
|
||||||
|
if (!strncmp(argv[2], "field", 4)){
|
||||||
|
if (argc == 6) {
|
||||||
|
ipmi_fru_set_field_string(intf, fruId,\
|
||||||
|
*argv[3], *argv[4], (char *) argv[5]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("fru edit [fruid] field [section] [index] [string]\n");
|
||||||
|
}
|
||||||
|
}else if (!strncmp(argv[2], "oem", 3)){
|
||||||
|
ipmi_fru_edit_multirec(intf,fruId, argc, argv);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
printf("fru edit <fru id>\n");
|
ipmi_fru_edit_multirec(intf,fruId, argc, argv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -2793,3 +2830,190 @@ ipmi_fru_main(struct ipmi_intf * intf, int argc, char ** argv)
|
|||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
/* ipmi_fru_set_field_string - Set a field string to a new value, Need to be the same size
|
||||||
|
*
|
||||||
|
* @intf: ipmi interface
|
||||||
|
* @id: fru id
|
||||||
|
* @f_type: Type of the Field : c=Chassis b=Board p=Product
|
||||||
|
* @f_index: findex of the field, zero indexed.
|
||||||
|
* @f_string: NULL terminated string
|
||||||
|
*
|
||||||
|
* returns -1 on error
|
||||||
|
* returns 1 if successful
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ipmi_fru_set_field_string(struct ipmi_intf * intf, uint8_t fruId, uint8_t
|
||||||
|
f_type, uint8_t f_index, char *f_string)
|
||||||
|
{
|
||||||
|
struct ipmi_rs *rsp;
|
||||||
|
struct ipmi_rq req;
|
||||||
|
|
||||||
|
struct fru_info fru;
|
||||||
|
struct fru_header header;
|
||||||
|
uint8_t msg_data[4];
|
||||||
|
uint8_t sn_size, checksum,prev_lun;
|
||||||
|
int ret = 0, i = 0;
|
||||||
|
uint8_t *fru_data, *fru_area;
|
||||||
|
uint32_t fru_field_offset, fru_field_offset_tmp;
|
||||||
|
uint32_t fru_section_len, header_offset;
|
||||||
|
|
||||||
|
fru_data = NULL;
|
||||||
|
|
||||||
|
memset(msg_data, 0, 4);
|
||||||
|
msg_data[0] = fruId;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
printf("OK\n");
|
||||||
|
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] = fruId;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
fru_data = malloc( fru.size );
|
||||||
|
|
||||||
|
if( fru_data == NULL )
|
||||||
|
{
|
||||||
|
printf("Out of memory!\n");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup offset from the field type */
|
||||||
|
|
||||||
|
/* Chassis type field */
|
||||||
|
if (f_type == 0x63) {
|
||||||
|
header_offset = (header.offset.chassis * 8);
|
||||||
|
read_fru_area(intf ,&fru, fruId, header_offset , 3 , fru_data);
|
||||||
|
fru_field_offset = (header.offset.chassis * 8) + 3;
|
||||||
|
fru_section_len = *(fru_data + header_offset + 1) * 8;
|
||||||
|
}
|
||||||
|
/* Board type field */
|
||||||
|
else if (f_type == 0x62) {
|
||||||
|
header_offset = (header.offset.board * 8);
|
||||||
|
read_fru_area(intf ,&fru, fruId, header_offset , 3 , fru_data);
|
||||||
|
fru_field_offset = (header.offset.board * 8) + 6;
|
||||||
|
fru_section_len = *(fru_data + header_offset + 1) * 8;
|
||||||
|
}
|
||||||
|
/* Product type field */
|
||||||
|
else if (f_type == 0x70) {
|
||||||
|
header_offset = (header.offset.product * 8);
|
||||||
|
read_fru_area(intf ,&fru, fruId, header_offset , 3 , fru_data);
|
||||||
|
fru_field_offset = (header.offset.product * 8) + 3;
|
||||||
|
fru_section_len = *(fru_data + header_offset + 1) * 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Wrong field type.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset(fru_data, 0, fru.size);
|
||||||
|
if( read_fru_area(intf ,&fru, fruId, header_offset ,
|
||||||
|
fru_section_len , fru_data) < 0 )
|
||||||
|
{
|
||||||
|
free(fru_data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Convert index from character to decimal */
|
||||||
|
f_index= f_index - 0x30;
|
||||||
|
|
||||||
|
/*Seek to field index */
|
||||||
|
for( i=0; i<f_index; i++ )
|
||||||
|
{
|
||||||
|
fru_area = get_fru_area_str(fru_data, &fru_field_offset);
|
||||||
|
}
|
||||||
|
if ( strlen(fru_area) == 0 ) {
|
||||||
|
printf("Field not found!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Get original field string */
|
||||||
|
fru_field_offset_tmp = fru_field_offset;
|
||||||
|
fru_area = get_fru_area_str(fru_data, &fru_field_offset);
|
||||||
|
|
||||||
|
if ( strlen(fru_area) == strlen(f_string) )
|
||||||
|
{
|
||||||
|
printf("Updating Field...\n");
|
||||||
|
memcpy(fru_data + fru_field_offset_tmp + 1,
|
||||||
|
f_string, strlen(f_string));
|
||||||
|
|
||||||
|
checksum = 0;
|
||||||
|
/* Calculate Header Checksum */
|
||||||
|
for( i = header_offset; i < header_offset
|
||||||
|
+ fru_section_len - 1; i ++ )
|
||||||
|
{
|
||||||
|
checksum += fru_data[i];
|
||||||
|
}
|
||||||
|
checksum = (~checksum) + 1;
|
||||||
|
fru_data[header_offset + fru_section_len - 1] = checksum;
|
||||||
|
|
||||||
|
/* Write te updated section to the FRU data */
|
||||||
|
if( write_fru_area(intf, &fru, fruId, header_offset,
|
||||||
|
header_offset, fru_section_len, fru_data) < 0 )
|
||||||
|
{
|
||||||
|
printf("Write to FRU data failed.\n");
|
||||||
|
free(fru_data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("String size are not equal.\n");
|
||||||
|
free(fru_data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(fru_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user