Hello, Zdenek,
The FRU information sections are hardly a subject for change in the near
future. So, I guess we can skip this issue.
I updated the formatting of the patch according to your comments and
removed the restricted FRU info access entirely since the implemented
algorithm reduces the read/write size while it is not accepted.
Please, review.
Regards,
Dmitry
28.06.2013 18:51, Zdenek Styblik пишет:
On Thu, Jun 27, 2013 at 6:06 PM, Dmitry Bazhenov <dim...@pigeonpoint.com> wrote:
[...]
1] ``const char *section_id[4]'' - is there no chance at all this is
going to be extended at some point in future? If it is, I'd be for
better solution. My point is ``for (i = 0; i < 4; i++)'' and if it
gets extended so must code which follows/is using/iterate over it. But
may be I'm wrong.
Is 'for ( i = 0; i < sizeof(section_id) / siceof(section_id[0]); i++)'
solves the issue?
Dmitry,
I'm not sure if there was an issue to begin with. But to be honest,
this one looks scary. Please, let me think about it a bit, try
something; I'll try to come up with some constructive(= better?). If I
can't think of anything better, I guess, I shouldn't ask you to. I
mean, I don't know. I'll think about it, try stuff, we'll see, ok? :)
Have a nice weekend,
Z.
Index: lib/ipmi_fru.c
===================================================================
--- lib/ipmi_fru.c (revision 1373)
+++ lib/ipmi_fru.c (working copy)
@@ -48,16 +48,6 @@
# include <config.h>
#endif
-/*
-* Apparently some systems have problems with FRU access greater than 16 bytes
-* at a time, even when using byte (not word) access. In order to ensure we
-* work with the widest variety of hardware request size is capped at 16 bytes.
-* Since this may result in slowdowns on some systems with lots of FRU data you
-* can undefine this to enable larger (up to 32 bytes at a time) access.
-*
-* TODO: make this a command line option
-*/
-#define LIMIT_ALL_REQUEST_SIZE 1
#define FRU_MULTIREC_CHUNK_SIZE (255 + sizeof(struct fru_multirec_header))
extern int verbose;
@@ -71,7 +61,8 @@
static int ipmi_fru_get_multirec_from_file(char * pFileName, uint8_t * pBufArea,
uint32_t size, uint32_t offset);
static int ipmi_fru_get_multirec_size_from_file(char * pFileName, uint32_t * pSize, uint32_t * pOffset);
-int ipmi_fru_get_adjust_size_from_buffer(uint8_t * pBufArea, uint32_t *pSize);
+static int 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 int ipmi_fru_set_field_string(struct ipmi_intf * intf, unsigned
@@ -235,31 +226,32 @@
* returns -1 on error
*/
#define FRU_NUM_BLOC_COMMON_HEADER 6
-typedef struct ipmi_fru_bloc
-{
+typedef struct ipmi_fru_bloc {
+ struct ipmi_fru_bloc * next;
uint16_t start;
uint16_t size;
uint8_t blocId[32];
-}t_ipmi_fru_bloc;
+} t_ipmi_fru_bloc;
+static const char *section_id[4] = {
+ "Internal Use Section",
+ "Chassis Section",
+ "Board Section",
+ "Product Section"
+};
+
t_ipmi_fru_bloc *
-build_fru_bloc(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
- /* OUT */uint16_t * ptr_number_bloc)
+build_fru_bloc(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id)
{
- t_ipmi_fru_bloc * p_bloc;
+ t_ipmi_fru_bloc * p_first, * p_bloc, * p_new;
struct ipmi_rs * rsp;
struct ipmi_rq req;
struct fru_header header;
- uint8_t * fru_data = NULL;
+ struct fru_multirec_header rec_hdr;
uint8_t msg_data[4];
- uint16_t num_bloc;
- uint16_t bloc_count;
+ uint32_t off;
+ uint16_t i;
- (* ptr_number_bloc) = 0;
-
- /*memset(&fru, 0, sizeof(struct fru_info));*/
- memset(&header, 0, sizeof(struct fru_header));
-
/*
* get COMMON Header format
*/
@@ -274,464 +266,315 @@
req.msg.data = msg_data;
req.msg.data_len = 4;
+ rsp = intf->sendrecv(intf, &req);
- rsp = intf->sendrecv(intf, &req);
if (rsp == NULL) {
- lprintf(LOG_ERR, " Device not present (No Response)\n");
+ lprintf(LOG_ERR, " Device not present (No Response)");
return NULL;
}
+
if (rsp->ccode > 0) {
- lprintf(LOG_ERR," Device not present (%s)\n",
- val2str(rsp->ccode, completion_code_vals));
+ lprintf(LOG_ERR," Device not present (%s)",
+ val2str(rsp->ccode, completion_code_vals));
return NULL;
}
- if (verbose > 1)
+ if (verbose > 1) {
printbuf(rsp->data, rsp->data_len, "FRU DATA");
+ }
memcpy(&header, rsp->data + 1, 8);
+ /* verify header checksum */
+ if (ipmi_csum((uint8_t *)&header, 8)) {
+ lprintf(LOG_ERR, " Bad header checksum");
+ return NULL;
+ }
+
if (header.version != 1) {
- lprintf(LOG_ERR, " Unknown FRU header version 0x%02x",
- header.version);
+ lprintf(LOG_ERR, " Unknown FRU header version 0x%02x", header.version);
return NULL;
}
/******************************************
- Count the number of bloc
+ Malloc and fill up the bloc contents
*******************************************/
// Common header
- num_bloc = 1;
- // Internal
- if( header.offset.internal )
- num_bloc ++;
- // Chassis
- if( header.offset.chassis )
- num_bloc ++;
- // Board
- if( header.offset.board )
- num_bloc ++;
- // Product
- if( header.offset.product )
- num_bloc ++;
+ p_first = malloc(sizeof(struct ipmi_fru_bloc));
+ if (!p_first) {
+ lprintf(LOG_ERR, " Unable to get memory to build FRU bloc");
+ return NULL;
+ }
- // Multi
- if( header.offset.multi )
- {
+ p_bloc = p_first;
+ p_bloc->next = NULL;
+ p_bloc->start= 0;
+ p_bloc->size = fru->size;
+ strcpy((char *)p_bloc->blocId, "Common Header Section");
- uint32_t i;
- struct fru_multirec_header * h;
- uint32_t last_off, len;
+ for (i = 0; i < 4; i++) {
+ if (header.offsets[i]) {
+ p_new = malloc(sizeof(struct ipmi_fru_bloc));
+ if (!p_new) {
+ lprintf(LOG_ERR, " Unable to get memory to build FRU bloc");
+ break;
+ }
- i = last_off = (header.offset.multi*8);
- //fru_len = 0;
+ p_new->next = NULL;
+ p_new->start = header.offsets[i] * 8;
+ p_new->size = fru->size - p_new->start;
+ strcpy((char *)p_new->blocId, section_id[i]);
- fru_data = malloc(fru->size + 1);
- if (fru_data == NULL) {
- lprintf(LOG_ERR, " Out of memory!");
- return NULL;
+ p_bloc->next = p_new;
+ p_bloc->size = p_new->start - p_bloc->start;
+ p_bloc = p_new;
}
+ }
- memset(fru_data, 0, fru->size + 1);
+ // Multi
+ if (header.offset.multi) {
+ off = header.offset.multi * 8;
do {
- h = (struct fru_multirec_header *) (fru_data + i);
+ /*
+ * check for odd offset for the case of fru devices
+ * accessed by words
+ */
+ if (fru->access && (off & 1)) {
+ lprintf(LOG_ERR, " Unaligned offset for a block: %d", off);
+ /* increment offset */
+ off++;
+ break;
+ }
- // read area in (at most) FRU_MULTIREC_CHUNK_SIZE bytes at a time
- if ((last_off < (i + sizeof(*h))) || (last_off < (i + h->len)))
- {
- len = fru->size - last_off;
- if (len > FRU_MULTIREC_CHUNK_SIZE)
- len = FRU_MULTIREC_CHUNK_SIZE;
+ if (read_fru_area(intf, fru, id, off, 5,
+ (uint8_t *) &rec_hdr) < 0) {
+ break;
+ }
- if (read_fru_area(intf, fru, id, last_off, len, fru_data) < 0)
- break;
-
- last_off += len;
+ p_new = malloc(sizeof(struct ipmi_fru_bloc));
+ if (!p_new) {
+ lprintf(LOG_ERR, " Unable to get memory to build FRU bloc");
+ break;
}
- num_bloc++;
- //printf("Bloc Numb : %i\n", counter);
- //printf("Bloc Start: %i\n", i);
- //printf("Bloc Size : %i\n", h->len);
- //printf("\n");
- i += h->len + sizeof (struct fru_multirec_header);
- } while (!(h->format & 0x80) && ( last_off < fru->size));
+ p_new->next = NULL;
+ p_new->start = off;
+ p_new->size = fru->size - p_new->start;
+ sprintf((char *)p_new->blocId, "Multi-Rec Area: Type %i",
+ rec_hdr.type);
- lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)",i,i);
+ p_bloc->next = p_new;
+ p_bloc->size = p_new->start - p_bloc->start;
+ p_bloc = p_new;
- if(fru->size > i)
- {
- // Bloc for remaining space
- num_bloc ++;
- }
- }
- else
- {
- /* Since there is no multi-rec area and no end delimiter, the remaining
- space will be added to the last bloc */
- }
+ off += rec_hdr.len + sizeof(struct fru_multirec_header);
+ /* verify record header */
+ if (ipmi_csum((uint8_t *)&rec_hdr,
+ sizeof(struct fru_multirec_header))) {
+ /* can't reliably judge for the rest space */
+ break;
+ }
+ } while (!(rec_hdr.format & 0x80) && (off < fru->size));
+ lprintf(LOG_DEBUG,"Multi-Record area ends at: %i (%xh)", off, off);
- /******************************************
- Malloc and fill up the bloc contents
- *******************************************/
- p_bloc = malloc( sizeof( t_ipmi_fru_bloc ) * num_bloc );
- if(!p_bloc)
- {
- lprintf(LOG_ERR, " Unable to get memory to build Fru bloc");
+ if (fru->size > off) {
+ // Bloc for remaining space
+ p_new = malloc(sizeof(struct ipmi_fru_bloc));
+ if (!p_new) {
+ lprintf(LOG_ERR, " Unable to get memory to build FRU bloc");
+ return p_first;
+ }
- if (fru_data != NULL) {
- free(fru_data);
- fru_data = NULL;
+ p_new->next = NULL;
+ p_new->start = off;
+ p_new->size = fru->size - p_new->start;
+ strcpy((char *)p_new->blocId, "Unused space");
+
+ p_bloc->next = p_new;
+ p_bloc->size = p_new->start - p_bloc->start;
}
-
- return NULL;
}
- // Common header
- bloc_count = 0;
-
- p_bloc[bloc_count].start= 0;
- p_bloc[bloc_count].size = 8;
- strcpy((char *)p_bloc[bloc_count].blocId, "Common Header Section");
- bloc_count ++;
-
- // Internal
- if( header.offset.internal )
- {
- p_bloc[bloc_count].start = (header.offset.internal * 8);
- p_bloc[bloc_count].size = 0; // Will be fillup later
- strcpy((char *)p_bloc[bloc_count].blocId, "Internal Use Section");
- bloc_count ++;
+ /* Dump blocs */
+ for(p_bloc = p_first, i = 0; p_bloc; p_bloc = p_bloc->next) {
+ lprintf(LOG_DEBUG ,"Bloc Numb : %i", i++);
+ lprintf(LOG_DEBUG ,"Bloc Id : %s", p_bloc->blocId);
+ lprintf(LOG_DEBUG ,"Bloc Start: %i", p_bloc->start);
+ lprintf(LOG_DEBUG ,"Bloc Size : %i", p_bloc->size);
+ lprintf(LOG_DEBUG ,"");
}
- // Chassis
- if( header.offset.chassis )
- {
- p_bloc[bloc_count].start = (header.offset.chassis * 8);
- p_bloc[bloc_count].size = 0; // Will be fillup later
- strcpy((char *)p_bloc[bloc_count].blocId, "Chassis Section");
- bloc_count ++;
- }
- // Board
- if( header.offset.board )
- {
- p_bloc[bloc_count].start = (header.offset.board * 8);
- p_bloc[bloc_count].size = 0; // Will be fillup later
- strcpy((char *)p_bloc[bloc_count].blocId, "Board Section");
- bloc_count ++;
- }
- // Product
- if( header.offset.product )
- {
- p_bloc[bloc_count].start = (header.offset.product * 8);
- p_bloc[bloc_count].size = 0; // Will be fillup later
- strcpy((char *)p_bloc[bloc_count].blocId, "Product Section");
- bloc_count ++;
- }
- // Multi-Record Area
- if(
- ( header.offset.multi )
- &&
- ( fru_data )
- )
- {
- uint32_t i = (header.offset.multi*8);
- struct fru_multirec_header * h;
+ return p_first;
+}
- do {
- h = (struct fru_multirec_header *) (fru_data + i);
+static void
+free_fru_bloc(t_ipmi_fru_bloc * bloc)
+{
+ t_ipmi_fru_bloc * del;
- p_bloc[bloc_count].start = i;
- p_bloc[bloc_count].size = h->len + sizeof (struct fru_multirec_header);
- sprintf((char *)p_bloc[bloc_count].blocId, "Multi-Rec Aread: Type %i", h->type);
- bloc_count ++;
- /*printf("Bloc Start: %i\n", i);
- printf("Bloc Size : %i\n", h->len);
- printf("\n");*/
-
- i += h->len + sizeof (struct fru_multirec_header);
-
- } while (!(h->format & 0x80) && ( bloc_count < num_bloc ) );
-
- lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)",i,i);
- /* If last bloc size was defined and is not until the end, create a
- last bloc with the remaining unused space */
-
- if((fru->size > i) && (bloc_count < num_bloc))
- {
- // Bloc for remaining space
- p_bloc[bloc_count].start = i;
- p_bloc[bloc_count].size = (fru->size - i);
- sprintf((char *)p_bloc[bloc_count].blocId, "Unused space");
- bloc_count ++;
- }
-
+ while (bloc) {
+ del = bloc;
+ bloc = bloc->next;
+ free(del);
}
-
- if (fru_data != NULL) {
- free(fru_data);
- fru_data = NULL;
- }
-
- /* Fill up size for first bloc */
- {
- unsigned short counter;
- lprintf(LOG_DEBUG ,"\nNumber Bloc : %i\n", num_bloc);
- for(counter = 0; counter < (num_bloc); counter ++)
- {
- /* If size where not initialized, do it. */
- if( p_bloc[counter].size == 0)
- {
- /* If not the last bloc, use the next bloc to determine the end */
- if((counter+1) < num_bloc)
- {
- p_bloc[counter].size = (p_bloc[counter+1].start - p_bloc[counter].start);
- }
- else
- {
- p_bloc[counter].size = (fru->size - p_bloc[counter].start);
- }
- }
- lprintf(LOG_DEBUG ,"Bloc Numb : %i\n", counter);
- lprintf(LOG_DEBUG ,"Bloc Id : %s\n", p_bloc[counter].blocId);
- lprintf(LOG_DEBUG ,"Bloc Start: %i\n", p_bloc[counter].start);
- lprintf(LOG_DEBUG ,"Bloc Size : %i\n", p_bloc[counter].size);
- lprintf(LOG_DEBUG ,"\n");
- }
- }
-
- (* ptr_number_bloc) = num_bloc;
-
- return p_bloc;
}
-
+/*
+ * write FRU[doffset:length] from the pFrubuf[soffset:length]
+ * rc=1 on success
+**/
int
write_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
uint16_t soffset, uint16_t doffset,
uint16_t length, uint8_t *pFrubuf)
-{ /*
- // fill in frubuf[offset:length] from the FRU[offset:length]
- // rc=1 on success
- */
- static uint16_t fru_data_rqst_size = 32;
- uint16_t off=0, tmp, finish;
+{
+ uint16_t tmp, finish;
struct ipmi_rs * rsp;
struct ipmi_rq req;
- uint8_t msg_data[256];
- uint8_t writeLength;
- uint16_t num_bloc;
+ uint8_t msg_data[255+3];
+ uint16_t writeLength;
+ uint16_t found_bloc = 0;
finish = doffset + length; /* destination offset */
if (finish > fru->size)
{
- lprintf(LOG_ERROR, "Return error\n");
+ lprintf(LOG_ERROR, "Return error");
return -1;
}
- t_ipmi_fru_bloc * fru_bloc = build_fru_bloc(intf, fru, id, &num_bloc);
-
- if (fru_bloc == NULL) {
- lprintf(LOG_ERROR, "Failed to build FRU bloc.");
- return (-1);
+ if (fru->access && ((doffset & 1) || (length & 1))) {
+ lprintf(LOG_ERROR, "Odd offset or length specified");
+ return -1;
}
+ t_ipmi_fru_bloc * fru_bloc = build_fru_bloc(intf, fru, id);
+ t_ipmi_fru_bloc * saved_fru_bloc = fru_bloc;
+
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_STORAGE;
req.msg.cmd = SET_FRU_DATA;
req.msg.data = msg_data;
-#ifdef LIMIT_ALL_REQUEST_SIZE
- if (fru_data_rqst_size > 16)
-#else
- if (fru->access && fru_data_rqst_size > 16)
-#endif
- fru_data_rqst_size = 16;
+ /* initialize request size only once */
+ if (fru->max_write_size == 0) {
+ if (intf->channel_buf_size != 0) {
+ /* subtract 1 byte for FRU ID an 2 bytes for offset */
+ fru->max_write_size = intf->channel_buf_size - 3;
+ } else {
+ /* subtract 1 byte for FRU ID an 2 bytes for offset */
+ fru->max_write_size = 32 - 3;
+ }
- /* Check if we receive size in parameters */
- if(intf->channel_buf_size != 0)
- {
- fru_data_rqst_size = intf->channel_buf_size - 5; /* Plan for overhead */
+ /* check word access */
+ if (fru->access) {
+ fru->max_write_size &= ~1;
+ }
}
do {
- /* Temp init end_bloc to the end, if not found */
- uint16_t end_bloc = finish;
+ uint16_t end_bloc;
uint8_t protected_bloc = 0;
- uint16_t found_bloc = 0xffff;
- /* real destination offset */
- tmp = fru->access ? (doffset+off) >> 1 : (doffset+off);
- msg_data[0] = id;
- msg_data[1] = (uint8_t)tmp;
- msg_data[2] = (uint8_t)(tmp >> 8);
-
/* Write per bloc, try to find the end of a bloc*/
- {
- uint16_t counter;
- for(counter = 0; counter < (num_bloc); counter ++)
- {
- if(
- (tmp >= fru_bloc[counter].start)
- &&
- (tmp < (fru_bloc[counter].start + fru_bloc[counter].size))
- )
- {
- found_bloc = counter;
- end_bloc = (fru_bloc[counter].start + fru_bloc[counter].size);
- counter = num_bloc;
- }
- }
+ while (fru_bloc && fru_bloc->start + fru_bloc->size <= doffset) {
+ fru_bloc = fru_bloc->next;
+ found_bloc++;
}
- tmp = end_bloc - (doffset+off); /* bytes remaining for the bloc */
- if (tmp > fru_data_rqst_size) {
- memcpy(&msg_data[3], pFrubuf + soffset + off, fru_data_rqst_size);
- req.msg.data_len = fru_data_rqst_size + 3;
+ if (fru_bloc && fru_bloc->start + fru_bloc->size < finish) {
+ end_bloc = fru_bloc->start + fru_bloc->size;
+ } else {
+ end_bloc = finish;
}
- else {
- memcpy(&msg_data[3], pFrubuf + soffset + off, (uint8_t)tmp);
- req.msg.data_len = tmp + 3;
- }
- if(found_bloc == 0)
- {
- lprintf(LOG_INFO,"Writing %d bytes", (req.msg.data_len-3));
- }
- else if(found_bloc != 0xFFFF)
- {
- lprintf(LOG_INFO,"Writing %d bytes (Bloc #%i: %s)",
- (req.msg.data_len-3),
- found_bloc, fru_bloc[found_bloc].blocId);
- }
- writeLength = req.msg.data_len-3;
+ /* calculate write length */
+ tmp = end_bloc - doffset;
- rsp = intf->sendrecv(intf, &req);
- if (!rsp) {
- break;
+ /* check that write length is more than maximum request size */
+ if (tmp > fru->max_write_size) {
+ writeLength = fru->max_write_size;
+ } else {
+ writeLength = tmp;
}
- if(rsp->ccode==0x80) // Write protected section
- {
- protected_bloc = 1;
- }
- else if ((rsp->ccode==0xc7 || rsp->ccode==0xc8 || rsp->ccode==0xca ) &&
- --fru_data_rqst_size > 8) {
- lprintf(LOG_NOTICE,"Bad CC -> %x\n", rsp->ccode);
- break; /*continue;*/
- }
- else if (rsp->ccode > 0)
- break;
+ /* copy fru data */
+ memcpy(&msg_data[3], pFrubuf + soffset, writeLength);
- if(protected_bloc == 0)
- {
- lprintf(LOG_INFO,"Wrote %d bytes", writeLength);
- off += writeLength; // Write OK, bloc not protected, continue
+ /* check word access */
+ if (fru->access) {
+ writeLength &= ~1;
}
- else
- {
- if(found_bloc != 0xffff)
- {
- // Bloc protected, advise user and jump over protected bloc
- lprintf(LOG_INFO,"Bloc [%s] protected at offset: %i (size %i bytes)",
- fru_bloc[found_bloc].blocId,
- fru_bloc[found_bloc].start,
- fru_bloc[found_bloc].size);
- lprintf(LOG_INFO,"Jumping over this bloc");
- }
- else
- {
- lprintf(LOG_INFO,"Remaining FRU is protected following offset: %i",
- off);
- }
- off = end_bloc;
+ tmp = doffset;
+ if (fru->access) {
+ tmp >>= 1;
}
- } while ((doffset+off) < finish);
- free(fru_bloc);
- fru_bloc = NULL;
-
- return ((doffset+off) >= finish);
-}
-
-
-#if 0
-int
-write_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
- uint16_t soffset, uint16_t doffset,
- uint16_t length, uint8_t *pFrubuf)
-{ /*
- // fill in frubuf[offset:length] from the FRU[offset:length]
- // rc=1 on success
- */
- static uint16_t fru_data_rqst_size = 32;
- uint16_t off=0, tmp, finish;
- struct ipmi_rs * rsp;
- struct ipmi_rq req;
- uint8_t msg_data[25];
- uint8_t writeLength;
-
- finish = doffset + length; /* destination offset */
- if (finish > fru->size)
- {
- printf("Return error\n");
- return -1;
- }
- memset(&req, 0, sizeof(req));
- req.msg.netfn = IPMI_NETFN_STORAGE;
- req.msg.cmd = SET_FRU_DATA;
- req.msg.data = msg_data;
-
-#ifdef LIMIT_ALL_REQUEST_SIZE
- if (fru_data_rqst_size > 16)
-#else
- if (fru->access && fru_data_rqst_size > 16)
-#endif
- fru_data_rqst_size = 16;
-
- do {
- /* real destination offset */
- tmp = fru->access ? (doffset+off) >> 1 : (doffset+off);
msg_data[0] = id;
msg_data[1] = (uint8_t)tmp;
msg_data[2] = (uint8_t)(tmp >> 8);
- tmp = finish - (doffset+off); /* bytes remaining */
- if (tmp > 16) {
- lprintf(LOG_INFO,"Writing 16 bytes");
- memcpy(&msg_data[3], pFrubuf + soffset + off, 16);
- req.msg.data_len = 16 + 3;
+ req.msg.data_len = writeLength + 3;
+
+ if(fru_bloc) {
+ lprintf(LOG_INFO,"Writing %d bytes (Bloc #%i: %s)",
+ writeLength, found_bloc, fru_bloc->blocId);
+ } else {
+ lprintf(LOG_INFO,"Writing %d bytes", writeLength);
}
- else {
- lprintf(LOG_INFO,"Writing %d bytes", tmp);
- memcpy(&msg_data[3], pFrubuf + soffset + off, (uint8_t)tmp);
- req.msg.data_len = tmp + 3;
- }
- writeLength = req.msg.data_len-3;
-
rsp = intf->sendrecv(intf, &req);
if (!rsp) {
break;
}
- if ((rsp->ccode==0xc7 || rsp->ccode==0xc8 || rsp->ccode==0xca ) &&
- --fru_data_rqst_size > 8) {
- lprintf(LOG_NOTICE,"Bad CC -> %x\n", rsp->ccode);
- break; /*continue;*/
+
+ if (rsp->ccode == 0xc7 || rsp->ccode == 0xc8 || rsp->ccode == 0xca) {
+ if (fru->max_write_size > 8) {
+ fru->max_write_size -= 8;
+ lprintf(LOG_INFO, "Retrying FRU write with request size %d",
+ fru->max_write_size);
+ continue;
+ }
+ } else if(rsp->ccode == 0x80) {
+ rsp->ccode = 0;
+ // Write protected section
+ protected_bloc = 1;
}
+
if (rsp->ccode > 0)
break;
- off += writeLength;
- } while ((doffset+off) < finish);
+ if (protected_bloc == 0) {
+ // Write OK, bloc not protected, continue
+ lprintf(LOG_INFO,"Wrote %d bytes", writeLength);
+ doffset += writeLength;
+ soffset += writeLength;
+ } else {
+ if(fru_bloc) {
+ // Bloc protected, advise user and jump over protected bloc
+ lprintf(LOG_INFO,
+ "Bloc [%s] protected at offset: %i (size %i bytes)",
+ fru_bloc->blocId, fru_bloc->start, fru_bloc->size);
+ lprintf(LOG_INFO,"Jumping over this bloc");
+ } else {
+ lprintf(LOG_INFO,
+ "Remaining FRU is protected following offset: %i",
+ doffset);
+ }
+ soffset += end_bloc - doffset;
+ doffset = end_bloc;
+ }
+ } while (doffset < finish);
- return ((doffset+off) >= finish);
+ if (saved_fru_bloc) {
+ free_fru_bloc(saved_fru_bloc);
+ }
+
+ return doffset >= finish;
}
-#endif
/* read_fru_area - fill in frubuf[offset:length] from the FRU[offset:length]
*
@@ -749,7 +592,6 @@
read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
uint32_t offset, uint32_t length, uint8_t *frubuf)
{
- static uint32_t fru_data_rqst_size = 20;
uint32_t off = offset, tmp, finish;
struct ipmi_rs * rsp;
struct ipmi_rq req;
@@ -775,29 +617,24 @@
req.msg.data = msg_data;
req.msg.data_len = 4;
-#ifdef LIMIT_ALL_REQUEST_SIZE
- if (fru_data_rqst_size > 16)
-#else
- if (fru->access && fru_data_rqst_size > 16)
-#endif
- fru_data_rqst_size = 16;
+ if (fru->max_read_size == 0) {
+ /* subtract 1 byte for completion code and 1 for byte count */
+ fru->max_read_size = 32 - 2;
-
- /* Check if we receive size in parameters */
- if(intf->channel_buf_size != 0)
- {
- fru_data_rqst_size = intf->channel_buf_size - 9; /* Plan for overhead */
+ /* check word access */
+ if (fru->access) {
+ fru->max_read_size &= ~1;
+ }
}
-
do {
tmp = fru->access ? off >> 1 : off;
msg_data[0] = id;
msg_data[1] = (uint8_t)(tmp & 0xff);
msg_data[2] = (uint8_t)(tmp >> 8);
tmp = finish - off;
- if (tmp > fru_data_rqst_size)
- msg_data[3] = (uint8_t)fru_data_rqst_size;
+ if (tmp > fru->max_read_size)
+ msg_data[3] = (uint8_t)fru->max_read_size;
else
msg_data[3] = (uint8_t)tmp;
@@ -807,33 +644,43 @@
break;
}
if (rsp->ccode > 0) {
- /* if we get C7 or C8 or CA return code then we requested too
+ /* if we get C8h or CAh completion code then we requested too
* many bytes at once so try again with smaller size */
- if ((rsp->ccode == 0xc7 || rsp->ccode == 0xc8 || rsp->ccode == 0xca) &&
- (--fru_data_rqst_size > 8)) {
+ if ((rsp->ccode == 0xc8 || rsp->ccode == 0xca)
+ && fru->max_read_size > 8) {
+ if (fru->max_read_size > 32) {
+ /* subtract read length more aggressively */
+ fru->max_read_size -= 8;
+ } else {
+ /* subtract length less aggressively */
+ fru->max_read_size--;
+ }
+
lprintf(LOG_INFO, "Retrying FRU read with request size %d",
- fru_data_rqst_size);
+ fru->max_read_size);
continue;
}
+
lprintf(LOG_NOTICE, "FRU Read failed: %s",
val2str(rsp->ccode, completion_code_vals));
break;
}
tmp = fru->access ? rsp->data[0] << 1 : rsp->data[0];
- memcpy((frubuf + off), rsp->data + 1, tmp);
+ memcpy(frubuf, rsp->data + 1, tmp);
off += tmp;
-
+ frubuf += tmp;
/* sometimes the size returned in the Info command
* is too large. return 0 so higher level function
* still attempts to parse what was returned */
- if (tmp == 0 && off < finish)
+ if (tmp == 0 && off < finish) {
return 0;
-
+ }
} while (off < finish);
- if (off < finish)
+ if (off < finish) {
return -1;
+ }
return 0;
}
@@ -939,7 +786,7 @@
fru_area_print_multirec_bloc(struct ipmi_intf * intf, struct fru_info * fru,
uint8_t id, uint32_t offset)
{
- uint8_t * fru_data = NULL;
+ uint8_t * fru_data;
uint32_t fru_len, i;
struct fru_multirec_header * h;
uint32_t last_off, len;
@@ -993,7 +840,6 @@
lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)",i,i);
free(fru_data);
- fru_data = NULL;
}
@@ -1009,41 +855,49 @@
uint8_t id, uint32_t offset)
{
char * fru_area;
- uint8_t * fru_data = NULL;
- uint32_t fru_len, area_len, i;
+ uint8_t * fru_data;
+ uint32_t fru_len, i;
+ uint8_t tmp[2];
- i = offset;
fru_len = 0;
- fru_data = malloc(fru->size + 1);
- if (fru_data == NULL) {
- lprintf(LOG_ERR, " Out of memory!");
+ /* read enough to check length field */
+ if (read_fru_area(intf, fru, id, offset, 2, tmp) == 0) {
+ fru_len = 8 * tmp[1];
+ }
+
+ if (fru_len == 0) {
return;
}
- memset(fru_data, 0, fru->size + 1);
- /* read enough to check length field */
- if (read_fru_area(intf, fru, id, i, 2, fru_data) == 0)
- fru_len = 8 * fru_data[i + 1];
- if (fru_len <= 0) {
- free(fru_data);
- fru_data = NULL;
+ fru_data = malloc(fru_len);
+ if (fru_data == NULL) {
+ lprintf(LOG_ERR, " Out of memory!");
return;
}
+ memset(fru_data, 0, fru_len);
+
/* read in the full fru */
- if (read_fru_area(intf, fru, id, i, fru_len, fru_data) < 0) {
+ if (read_fru_area(intf, fru, id, offset, fru_len, fru_data) < 0) {
free(fru_data);
fru_data = NULL;
return;
}
- i++; /* skip fru area version */
- area_len = fru_data[i++] * 8; /* fru area length */
+ /*
+ * skip first two bytes which specify
+ * fru area version and fru area length
+ */
+ i = 2;
printf(" Chassis Type : %s\n",
- chassis_type_desc[fru_data[i++]]);
+ chassis_type_desc[fru_data[i] >
+ (sizeof(chassis_type_desc)/sizeof(chassis_type_desc[0])) - 1 ?
+ 2 : fru_data[i]]);
+ i++;
+
fru_area = get_fru_area_str(fru_data, &i);
if (fru_area != NULL) {
if (strlen(fru_area) > 0) {
@@ -1063,7 +917,7 @@
}
/* read any extra fields */
- while ((fru_data[i] != 0xc1) && (i < offset + area_len))
+ while ((fru_data[i] != 0xc1) && (i < fru_len))
{
int j = i;
fru_area = get_fru_area_str(fru_data, &i);
@@ -1074,8 +928,10 @@
free(fru_area);
fru_area = NULL;
}
- if (i == j)
+
+ if (i == j) {
break;
+ }
}
if (fru_area != NULL) {
@@ -1096,39 +952,44 @@
uint8_t id, uint32_t offset)
{
char * fru_area;
- uint8_t * fru_data = NULL;
- uint32_t fru_len, area_len, i;
+ uint8_t * fru_data;
+ uint32_t fru_len, i;
time_t tval;
+ uint8_t tmp[2];
- i = offset;
fru_len = 0;
- fru_data = malloc(fru->size + 1);
- if (fru_data == NULL) {
- lprintf(LOG_ERR, " Out of memory!");
- return;
+ /* read enough to check length field */
+ if (read_fru_area(intf, fru, id, offset, 2, tmp) == 0) {
+ fru_len = 8 * tmp[1];
}
- memset(fru_data, 0, fru->size + 1);
- /* read enough to check length field */
- if (read_fru_area(intf, fru, id, i, 2, fru_data) == 0)
- fru_len = 8 * fru_data[i + 1];
if (fru_len <= 0) {
- free(fru_data);
- fru_data = NULL;
return;
}
+ fru_data = malloc(fru_len);
+ if (fru_data == NULL) {
+ lprintf(LOG_ERR, " Out of memory!");
+ return;
+ }
+
+ memset(fru_data, 0, fru_len);
+
/* read in the full fru */
- if (read_fru_area(intf, fru, id, i, fru_len, fru_data) < 0) {
+ if (read_fru_area(intf, fru, id, offset, fru_len, fru_data) < 0) {
free(fru_data);
fru_data = NULL;
return;
}
- i++; /* skip fru area version */
- area_len = fru_data[i++] * 8; /* fru area length */
- i++; /* skip fru board language */
+ /*
+ * skip first three bytes which specify
+ * fru area version, fru area length
+ * and fru board language
+ */
+ i = 3;
+
tval=((fru_data[i+2] << 16) + (fru_data[i+1] << 8) + (fru_data[i]));
tval=tval * 60;
tval=tval + secs_from_1970_1996;
@@ -1181,7 +1042,7 @@
}
/* read any extra fields */
- while ((fru_data[i] != 0xc1) && (i < offset + area_len))
+ while ((fru_data[i] != 0xc1) && (i < fru_len))
{
int j = i;
fru_area = get_fru_area_str(fru_data, &i);
@@ -1213,39 +1074,44 @@
fru_area_print_product(struct ipmi_intf * intf, struct fru_info * fru,
uint8_t id, uint32_t offset)
{
- char * fru_area = NULL;
- uint8_t * fru_data = NULL;
- uint32_t fru_len, area_len, i;
+ char * fru_area;
+ uint8_t * fru_data;
+ uint32_t fru_len, i;
+ uint8_t tmp[2];
- i = offset;
fru_len = 0;
- fru_data = malloc(fru->size + 1);
- if (fru_data == NULL) {
- lprintf(LOG_ERR, " Out of memory!");
+ /* read enough to check length field */
+ if (read_fru_area(intf, fru, id, offset, 2, tmp) == 0) {
+ fru_len = 8 * tmp[1];
+ }
+
+ if (fru_len == 0) {
return;
}
- memset(fru_data, 0, fru->size + 1);
- /* read enough to check length field */
- if (read_fru_area(intf, fru, id, i, 2, fru_data) == 0)
- fru_len = 8 * fru_data[i + 1];
- if (fru_len <= 0) {
- free(fru_data);
- fru_data = NULL;
+ fru_data = malloc(fru_len);
+ if (fru_data == NULL) {
+ lprintf(LOG_ERR, " Out of memory!");
return;
}
+ memset(fru_data, 0, fru_len);
+
+
/* read in the full fru */
- if (read_fru_area(intf, fru, id, i, fru_len, fru_data) < 0) {
+ if (read_fru_area(intf, fru, id, offset, fru_len, fru_data) < 0) {
free(fru_data);
fru_data = NULL;
return;
}
- i++; /* skip fru area version */
- area_len = fru_data[i++] * 8; /* fru area length */
- i++; /* skip fru board language */
+ /*
+ * skip first three bytes which specify
+ * fru area version, fru area length
+ * and fru board language
+ */
+ i = 3;
fru_area = get_fru_area_str(fru_data, &i);
if (fru_area != NULL) {
@@ -1311,7 +1177,7 @@
}
/* read any extra fields */
- while ((fru_data[i] != 0xc1) && (i < offset + area_len))
+ while ((fru_data[i] != 0xc1) && (i < fru_len))
{
int j = i;
fru_area = get_fru_area_str(fru_data, &i);
@@ -1344,46 +1210,42 @@
uint8_t id, uint32_t offset)
{
uint8_t * fru_data;
- uint32_t fru_len, i;
struct fru_multirec_header * h;
struct fru_multirec_powersupply * ps;
struct fru_multirec_dcoutput * dc;
struct fru_multirec_dcload * dl;
uint16_t peak_capacity;
uint8_t peak_hold_up_time;
- uint32_t last_off, len;
+ uint32_t last_off;
- i = last_off = offset;
- fru_len = 0;
+ last_off = offset;
- fru_data = malloc(fru->size + 1);
+ fru_data = malloc(FRU_MULTIREC_CHUNK_SIZE);
if (fru_data == NULL) {
lprintf(LOG_ERR, " Out of memory!");
return;
}
- memset(fru_data, 0, fru->size + 1);
- do {
- h = (struct fru_multirec_header *) (fru_data + i);
+ memset(fru_data, 0, FRU_MULTIREC_CHUNK_SIZE);
- /* read area in (at most) FRU_MULTIREC_CHUNK_SIZE bytes at a time */
- if ((last_off < (i + sizeof(*h))) || (last_off < (i + h->len)))
- {
- len = fru->size - last_off;
- if (len > FRU_MULTIREC_CHUNK_SIZE)
- len = FRU_MULTIREC_CHUNK_SIZE;
+ h = (struct fru_multirec_header *) (fru_data);
- if (read_fru_area(intf, fru, id, last_off, len, fru_data) < 0)
- break;
+ do {
+ if (read_fru_area(intf, fru, id, last_off, sizeof(*h), fru_data) < 0) {
+ break;
+ }
- last_off += len;
+ if (h->len && read_fru_area(intf, fru, id,
+ last_off + sizeof(*h), h->len, fru_data + sizeof(*h)) < 0) {
+ break;
}
- switch (h->type)
- {
+ last_off += h->len + sizeof(*h);
+
+ switch (h->type) {
case FRU_RECORD_TYPE_POWER_SUPPLY_INFORMATION:
ps = (struct fru_multirec_powersupply *)
- (fru_data + i + sizeof (struct fru_multirec_header));
+ (fru_data + sizeof(struct fru_multirec_header));
#if WORDS_BIGENDIAN
ps->capacity = BSWAP_16(ps->capacity);
@@ -1441,7 +1303,7 @@
case FRU_RECORD_TYPE_DC_OUTPUT:
dc = (struct fru_multirec_dcoutput *)
- (fru_data + i + sizeof (struct fru_multirec_header));
+ (fru_data + sizeof(struct fru_multirec_header));
#if WORDS_BIGENDIAN
dc->nominal_voltage = BSWAP_16(dc->nominal_voltage);
@@ -1473,7 +1335,7 @@
case FRU_RECORD_TYPE_DC_LOAD:
dl = (struct fru_multirec_dcload *)
- (fru_data + i + sizeof (struct fru_multirec_header));
+ (fru_data + sizeof(struct fru_multirec_header));
#if WORDS_BIGENDIAN
dl->nominal_voltage = BSWAP_16(dl->nominal_voltage);
@@ -1503,7 +1365,7 @@
case FRU_RECORD_TYPE_OEM_EXTENSION:
{
struct fru_multirec_oem_header *oh=(struct fru_multirec_oem_header *)
- &fru_data[i + sizeof(struct fru_multirec_header)];
+ &fru_data[sizeof(struct fru_multirec_header)];
uint32_t iana = oh->mfg_id[0] | oh->mfg_id[1]<<8 | oh->mfg_id[2]<<16;
/* Now makes sure this is really PICMG record */
@@ -1511,7 +1373,7 @@
if( iana == IPMI_OEM_PICMG ){
printf(" PICMG Extension Record\n");
ipmi_fru_picmg_ext_print(fru_data,
- i + sizeof(struct fru_multirec_header),
+ sizeof(struct fru_multirec_header),
h->len);
}
/* FIXME: Add OEM record support here */
@@ -1521,13 +1383,11 @@
}
break;
}
- i += h->len + sizeof (struct fru_multirec_header);
} while (!(h->format & 0x80));
- lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)",i,i);
+ lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)", last_off, last_off);
free(fru_data);
- fru_data = NULL;
}
/* ipmi_fru_query_new_value - Query new values to replace original FRU content
@@ -2979,6 +2839,7 @@
return -1;
}
+ memset(&fru, 0, sizeof(fru));
fru.size = (rsp->data[1] << 8) | rsp->data[0];
fru.access = rsp->data[2] & 0x1;
@@ -3309,6 +3170,8 @@
printf (" Timeout accessing FRU info. (Device not present?)\n");
return;
}
+
+ memset(&fru, 0, sizeof(fru));
fru.size = (rsp->data[1] << 8) | rsp->data[0];
fru.access = rsp->data[2] & 0x1;
@@ -3375,6 +3238,8 @@
printf(" Timeout accessing FRU info. (Device not present?)\n");
return;
}
+
+ memset(&fru, 0, sizeof(fru));
fru.size = (rsp->data[1] << 8) | rsp->data[0];
fru.access = rsp->data[2] & 0x1;
@@ -3494,6 +3359,7 @@
return -1;
}
+ memset(&fru, 0, sizeof(fru));
fru.size = (rsp->data[1] << 8) | rsp->data[0];
fru.access = rsp->data[2] & 0x1;
@@ -3517,6 +3383,7 @@
i = last_off = offset;
fru_len = 0;
+ memset(&fru, 0, sizeof(fru));
fru_data = malloc(fru.size + 1);
if (fru_data == NULL) {
lprintf(LOG_ERR, " Out of memory!");
@@ -3695,6 +3562,7 @@
return -1;
}
+ memset(&fru, 0, sizeof(fru));
fru.size = (rsp->data[1] << 8) | rsp->data[0];
fru.access = rsp->data[2] & 0x1;
@@ -4164,6 +4032,7 @@
return -1;
}
+ memset(&fru, 0, sizeof(fru));
fru->size = (rsp->data[1] << 8) | rsp->data[0];
fru->access = rsp->data[2] & 0x1;
@@ -4748,6 +4617,7 @@
goto ipmi_fru_set_field_string_out;
}
+ memset(&fru, 0, sizeof(fru));
fru.size = (rsp->data[1] << 8) | rsp->data[0];
fru.access = rsp->data[2] & 0x1;
Index: lib/ipmi_kontronoem.c
===================================================================
--- lib/ipmi_kontronoem.c (revision 1373)
+++ lib/ipmi_kontronoem.c (working copy)
@@ -350,6 +350,7 @@
return(-1);
}
+ memset(&fru, 0, sizeof(fru));
fru.size = (rsp->data[1] << 8) | rsp->data[0];
fru.access = rsp->data[2] & 0x1;
@@ -637,6 +638,7 @@
return(-1);
}
+ memset(&fru, 0, sizeof(fru));
fru.size = (rsp->data[1] << 8) | rsp->data[0];
fru.access = rsp->data[2] & 0x1;
Index: include/ipmitool/ipmi_fru.h
===================================================================
--- include/ipmitool/ipmi_fru.h (revision 1373)
+++ include/ipmitool/ipmi_fru.h (working copy)
@@ -63,6 +63,8 @@
struct fru_info {
uint16_t size;
uint8_t access:1;
+ uint8_t max_read_size;
+ uint8_t max_write_size;
};
#ifdef HAVE_PRAGMA_PACK
@@ -70,13 +72,16 @@
#endif
struct fru_header {
uint8_t version;
- struct {
- uint8_t internal;
- uint8_t chassis;
- uint8_t board;
- uint8_t product;
- uint8_t multi;
- } offset;
+ union {
+ struct {
+ uint8_t internal;
+ uint8_t chassis;
+ uint8_t board;
+ uint8_t product;
+ uint8_t multi;
+ } offset;
+ uint8_t offsets[5];
+ };
uint8_t pad;
uint8_t checksum;
}ATTRIBUTE_PACKING;
------------------------------------------------------------------------------
This SF.net email is sponsored by Windows:
Build for Windows Store.
http://p.sf.net/sfu/windows-dev2dev
_______________________________________________
Ipmitool-devel mailing list
Ipmitool-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ipmitool-devel