Hello, Zdenek,
I addressed the comment about malloc() failures in the build_fru_bloc()
function. Now it aborts the operation on any failure.
I didn't address the other malloc() failures since the spoken functions
are just dump the text.
Regards,
Dmitry
15.07.2013 15:57, Zdenek Styblik пишет:
On Mon, Jul 15, 2013 at 10:50 AM, Dmitry Bazhenov
<dim...@pigeonpoint.com> wrote:
Hello, Zdenek,
Thanks for review.
I see your point and I think it make sense. I am going to address your
comments regarding the build_fru_bloc() function since this one was under my
heavy changes.
Ok, great.
I will also look at the other functions
(fru_area_print_chassis(), fru_area_print_board(),
fru_area_print_product(), fru_area_print_multirec()), but I think they are
of different case since they are just dumping functions. And in my opinion
it is not of big deal to skip through some memory allocation failures.
*shrug* I somewhat knew it's coming, but I've failed to address it.
Yes, they are just dumping/printing data, but they're not much of
different than any other function. It may not matter in this
case/context, but it could matter in different one ...:
~~~
[ some code here ]
fru_area_print_chassis()
[ some more code here ]
~~~
Actually, these 4 functions in question are called in consecutive order.
Hm, how about this. I'll log tickets for those and it'll get
fixed(meaning I'll fix it) later. Now I hate myself for writing, even
thinking of, such thing.
The basic idea I have is to return int and check it. No biggie.
Z.
However, if it leads to dereference of NULL, then it is important to add
some safety checks there.
Will such a plan work for you?
Regards,
Dmitry
15.07.2013 14:01, Zdenek Styblik пишет:
On Thu, Jul 4, 2013 at 9:39 AM, Zdenek Styblik <zdenek.styb...@gmail.com>
wrote:
On Tue, Jul 2, 2013 at 10:41 AM, Dmitry Bazhenov <dim...@pigeonpoint.com>
wrote:
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
[...]
Dmitry,
I've given it another look. I've added space here and there and
changed C++ style comments to C style comments. I know you've followed
style in 'lib/ipmi_fru.c', however I think error messages regarding
malloc() failure should be follow the suit of the rest of the code in
ipmitool. Again, easy to fix and somewhat minor. Hell, I'll file new
ticket for it and it will be done later.
I have the following concerns, though. In function build_fru_bloc(),
if malloc() failure occurs, you just break from the loop and that's
about it. I think this is wrong. If malloc() failure occurs, then you
either should return from the function immediately, or set variable
eg. ``error = 1; break;'' and check value of such variable once you
exit the loop.
Example:
~~~
for (i = 0; i < 4; i++) {
p_new = malloc(...);
if (p_new == NULL) {
lprintf(LOG_ERR, "out of memory");
break;
}
}
/* nothing to see, nothing just happened, moving on */
[ more code, more malloc() calls etc. ]
~~~
Seems just simply wrong. Application shouldn't continue, in my
opinion, and should terminate. No such thing happens, however, and
function proceeds over malloc() failures like nothing is going on.
fru_area_print_chassis(), fru_area_print_board(),
fru_area_print_product(), fru_area_print_multirec() - similar case.
This function returns void. malloc() failure happens and all we do is
just return from the function? Eh. It just doesn't feel right to me.
Now, I stress it's my opinion application should terminate after
malloc() failure occurs even once. The reason behind this worry is
malloc() failure may occur at given time, t_0, but it doesn't have to
occur later in t_1. Now, there is a bit of inconsistency and perhaps
some NULL pointer, isn't there? Also, more malloc() calls are stacked
up and we've been told once we won't get any memory, so why should we
try again and again? OS can be under heavy load, running short on
resources, yet we'll keep bugging about memory or what not?
However, I'm open to be explained why this isn't necessary or
eventually wrong approach in general. And ok, I can imagine cases why
this is done deliberately, but is it here? Why?
I even offer to put some code behind my words as talk is cheap. I
mean, I'm ok do to changes I've just pointed out and send a patch for
review. If there is no rush as I can't do it right now.
One more thing. If this e-mail feels offensive in any way, it's not
meant to be. So please, take it easy.
Have an easy Monday,
Z.
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: 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;
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,318 @@
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");
+ free_fru_bloc(p_first);
+ return NULL;
+ }
- 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");
+ free_fru_bloc(p_first);
+ return NULL;
}
- 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");
+ free_fru_bloc(p_first);
+ return NULL;
+ }
- 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 +595,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 +620,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 +647,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 +789,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 +843,6 @@
lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)",i,i);
free(fru_data);
- fru_data = NULL;
}
@@ -1009,41 +858,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 +920,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 +931,10 @@
free(fru_area);
fru_area = NULL;
}
- if (i == j)
+
+ if (i == j) {
break;
+ }
}
if (fru_area != NULL) {
@@ -1096,39 +955,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 +1045,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 +1077,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 +1180,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 +1213,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 +1306,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 +1338,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 +1368,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 +1376,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 +1386,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 +2842,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 +3173,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 +3241,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 +3362,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 +3386,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 +3565,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 +4035,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 +4620,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;
------------------------------------------------------------------------------
See everything from the browser to the database with AppDynamics
Get end-to-end visibility with application monitoring from AppDynamics
Isolate bottlenecks and diagnose root cause in seconds.
Start your free trial of AppDynamics Pro today!
http://pubads.g.doubleclick.net/gampad/clk?id=48808831&iu=/4140/ostg.clktrk
_______________________________________________
Ipmitool-devel mailing list
Ipmitool-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ipmitool-devel