1 /*
2  * ipmi_fru.h
3  *
4  * internal IPMI interface for FRUs
5  *
6  * Author: MontaVista Software, Inc.
7  *         Corey Minyard <minyard@mvista.com>
8  *         source@mvista.com
9  *
10  * Copyright 2003 MontaVista Software Inc.
11  *
12  *  This program is free software; you can redistribute it and/or
13  *  modify it under the terms of the GNU Lesser General Public License
14  *  as published by the Free Software Foundation; either version 2 of
15  *  the License, or (at your option) any later version.
16  *
17  *
18  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  *  You should have received a copy of the GNU Lesser General Public
30  *  License along with this program; if not, write to the Free
31  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32  */
33 
34 #ifndef OPENIPMI_FRU_INTERNAL_H
35 #define OPENIPMI_FRU_INTERNAL_H
36 
37 #include <OpenIPMI/ipmi_fru.h>
38 #include <OpenIPMI/ipmi_err.h>
39 #include <OpenIPMI/os_handler.h>
40 
41 os_handler_t *i_ipmi_fru_get_os_handler(ipmi_fru_t *fru);
42 
43 /* The callbacks for FRU multi-record OEM handler, to decode the multi-record
44    and get individual field.
45    ipmi_fru_multi_record_oem_decoder_cb(): record is the raw binary multi-record
46       record_len is the length of this raw binary multi-record,
47       the doceded OEM FRU information is outputted and stored in *explain_data_p.
48    ipmi_fru_get_multi_record_oem_field_handler_cb(): this callback is called
49       when user call ipmi_fru_multi_record_get_field(). Please refer to the
50       comments for ipmi_fru_multi_record_get_field().
51    ipmi_fru_multi_record_free_explain_data_cb(): this callback is used to free
52    the OEM FRU specific data structures.
53 
54 */
55 
56 /* Free the data in the node. */
57 typedef void (*ipmi_fru_oem_node_cb)(ipmi_fru_node_t *node);
58 
59 typedef int (*ipmi_fru_oem_node_get_field_cb)
60      (ipmi_fru_node_t           *node,
61       unsigned int              index,
62       const char                **name,
63       enum ipmi_fru_data_type_e *dtype,
64       int                       *intval,
65       time_t                    *time,
66       double                    *floatval,
67       char                      **data,
68       unsigned int              *data_len,
69       ipmi_fru_node_t           **sub_node);
70 
71 typedef int (*ipmi_fru_oem_node_set_field_cb)
72      (ipmi_fru_node_t           *node,
73       unsigned int              index,
74       enum ipmi_fru_data_type_e dtype,
75       int                       intval,
76       time_t                    time,
77       double                    floatval,
78       char                      *data,
79       unsigned int              data_len);
80 
81 typedef int (*ipmi_fru_oem_node_settable_cb)
82      (ipmi_fru_node_t           *node,
83       unsigned int              index);
84 
85 typedef int (*ipmi_fru_oem_node_subtype_cb)
86      (ipmi_fru_node_t           *node,
87       enum ipmi_fru_data_type_e *dtype);
88 
89 typedef int (*ipmi_fru_oem_node_enum_val_cb)(ipmi_fru_node_t *node,
90 					     unsigned int    index,
91 					     int             *pos,
92 					     int             *nextpos,
93 					     const char      **data);
94 
95 ipmi_fru_node_t *i_ipmi_fru_node_alloc(ipmi_fru_t *fru);
96 
97 void *i_ipmi_fru_node_get_data(ipmi_fru_node_t *node);
98 void i_ipmi_fru_node_set_data(ipmi_fru_node_t *node, void *data);
99 void *i_ipmi_fru_node_get_data2(ipmi_fru_node_t *node);
100 void i_ipmi_fru_node_set_data2(ipmi_fru_node_t *node, void *data2);
101 
102 void i_ipmi_fru_node_set_destructor(ipmi_fru_node_t      *node,
103 				    ipmi_fru_oem_node_cb destroy);
104 void i_ipmi_fru_node_set_get_field(ipmi_fru_node_t                *node,
105 				   ipmi_fru_oem_node_get_field_cb get_field);
106 void i_ipmi_fru_node_set_set_field(ipmi_fru_node_t                *node,
107 				   ipmi_fru_oem_node_set_field_cb set_field);
108 void i_ipmi_fru_node_set_settable(ipmi_fru_node_t               *node,
109 				  ipmi_fru_oem_node_settable_cb settable);
110 void i_ipmi_fru_node_set_get_subtype(ipmi_fru_node_t              *node,
111 				     ipmi_fru_oem_node_subtype_cb get_subtype);
112 void i_ipmi_fru_node_set_get_enum(ipmi_fru_node_t               *node,
113 				  ipmi_fru_oem_node_enum_val_cb get_enum);
114 
115 /* Get the root node of a multi-record.  Note that the root record
116    must not be an array.  Note that you cannot keep a copy of the fru
117    pointer around after this call returns; it will be unlocked and
118    could go away after this returns. */
119 typedef int (*ipmi_fru_oem_multi_record_get_root_node_cb)
120      (ipmi_fru_t          *fru,
121       unsigned int        mr_rec_num,
122       unsigned int        manufacturer_id,
123       unsigned char       record_type_id,
124       unsigned char       *mr_data,
125       unsigned int        mr_data_len,
126       void                *cb_data,
127       const char          **name,
128       ipmi_fru_node_t     **node);
129 
130 /* Register/deregister a multi-record handler.  Note that if the
131    record type id is < 0xc0 (not OEM) then the manufacturer id does
132    not matter. */
133 int i_ipmi_fru_register_multi_record_oem_handler
134 (unsigned int                               manufacturer_id,
135  unsigned char                              record_type_id,
136  ipmi_fru_oem_multi_record_get_root_node_cb get_root,
137  void                                       *cb_data);
138 
139 int i_ipmi_fru_deregister_multi_record_oem_handler
140 (unsigned int  manufacturer_id,
141  unsigned char record_type_id);
142 
143 void i_ipmi_fru_lock(ipmi_fru_t *fru);
144 void i_ipmi_fru_unlock(ipmi_fru_t *fru);
145 
146 /* You must be holding the fru lock to call this. */
147 void i_ipmi_fru_ref_nolock(ipmi_fru_t *fru);
148 
149 /*
150  * Some specialized FRU data repositories have protection against
151  * multiple readers/writers to keep them from colliding.  The model
152  * here is similar to the other parts of IPMI.  You have a timestamp
153  * that tells the last time the repository changed.  On reading, the
154  * code will check the timestamp before and after to make sure the
155  * data hasn't changed while being written.  There is a lock for
156  * writers.  The code will lock (prepare to write), check the
157  * timestamp to make sure another writer has not modified, then write,
158  * then unlock and commit (write complete).  Note that you can have
159  * the reader timestamp without the lock, or the lock without the
160  * timestamp.
161  *
162  * You can also override the function that sends the write message.
163  * this function will get the data as formatted for a normal FRU
164  * write.
165  */
166 typedef void (*i_ipmi_fru_timestamp_cb)(ipmi_fru_t    *fru,
167 					ipmi_domain_t *domain,
168 					int           err,
169 					uint32_t      timestamp);
170 typedef void (*i_ipmi_fru_op_cb)(ipmi_fru_t    *fru,
171 				 ipmi_domain_t *domain,
172 				 int           err);
173 
174 typedef int (*i_ipmi_fru_get_timestamp_cb)(ipmi_fru_t             *fru,
175 					   ipmi_domain_t          *domain,
176 					   i_ipmi_fru_timestamp_cb handler);
177 typedef int (*i_ipmi_fru_prepare_write_cb)(ipmi_fru_t      *fru,
178 					   ipmi_domain_t   *domain,
179 					   uint32_t        timestamp,
180 					   i_ipmi_fru_op_cb done);
181 typedef int (*i_ipmi_fru_write_cb)(ipmi_fru_t      *fru,
182 				   ipmi_domain_t   *domain,
183 				   unsigned char   *data,
184 				   unsigned int    data_len,
185 				   i_ipmi_fru_op_cb done);
186 typedef int (*i_ipmi_fru_complete_write_cb)(ipmi_fru_t      *fru,
187 					    ipmi_domain_t   *domain,
188 					    int             abort,
189 					    uint32_t        timestamp,
190 					    i_ipmi_fru_op_cb done);
191 
192 int i_ipmi_fru_set_get_timestamp_handler(ipmi_fru_t                 *fru,
193 					 i_ipmi_fru_get_timestamp_cb handler);
194 int i_ipmi_fru_set_prepare_write_handler(ipmi_fru_t                 *fru,
195 					 i_ipmi_fru_prepare_write_cb handler);
196 int i_ipmi_fru_set_write_handler(ipmi_fru_t         *fru,
197 				 i_ipmi_fru_write_cb handler);
198 int i_ipmi_fru_set_complete_write_handler(ipmi_fru_t                  *fru,
199 					  i_ipmi_fru_complete_write_cb handler);
200 
201 typedef void (*i_ipmi_fru_setup_data_clean_cb)(ipmi_fru_t *fru, void *data);
202 void i_ipmi_fru_set_setup_data(ipmi_fru_t                    *fru,
203 			       void                          *data,
204 			       i_ipmi_fru_setup_data_clean_cb cleanup);
205 void *i_ipmi_fru_get_setup_data(ipmi_fru_t *fru);
206 
207 void i_ipmi_fru_get_addr(ipmi_fru_t   *fru,
208 			 ipmi_addr_t  *addr,
209 			 unsigned int *addr_len);
210 
211 
212 /* Add a record telling that a specific area of the FRU data needs to
213    be written.  Called from the write handler. */
214 int i_ipmi_fru_new_update_record(ipmi_fru_t   *fru,
215 				 unsigned int offset,
216 				 unsigned int length);
217 
218 /* Get/set the fru-type secific data.  Note that the cleanup_recs
219    function will be called on any rec_data.  The right way to set this
220    data is to set the rec data then set your ops. */
221 void *i_ipmi_fru_get_rec_data(ipmi_fru_t *fru);
222 void i_ipmi_fru_set_rec_data(ipmi_fru_t *fru, void *rec_data);
223 
224 /* Get a pointer to the fru data and the length.  Only valid during
225    decoding and writing. */
226 void *i_ipmi_fru_get_data_ptr(ipmi_fru_t *fru);
227 unsigned int i_ipmi_fru_get_data_len(ipmi_fru_t *fru);
228 
229 /* Get a debug name for the FRU */
230 char *i_ipmi_fru_get_iname(ipmi_fru_t *fru);
231 
232 /* Misc data about the FRU. */
233 unsigned int i_ipmi_fru_get_fetch_mask(ipmi_fru_t *fru);
234 int i_ipmi_fru_is_normal_fru(ipmi_fru_t *fru);
235 void i_ipmi_fru_set_is_normal_fru(ipmi_fru_t *fru, int val);
236 
237 /*
238  * Interface between the generic FRU code and the specific FRU
239  * decoders.
240  */
241 
242 typedef void (*ipmi_fru_void_op)(ipmi_fru_t *fru);
243 typedef int (*ipmi_fru_err_op)(ipmi_fru_t *fru);
244 typedef int (*ipmi_fru_get_root_node_op)(ipmi_fru_t      *fru,
245 					 const char      **name,
246 					 ipmi_fru_node_t **rnode);
247 
248 /* Add a function to cleanup the FRU record data (free all the memory)
249    as the FRU is destroyed. */
250 void i_ipmi_fru_set_op_cleanup_recs(ipmi_fru_t *fru, ipmi_fru_void_op op);
251 
252 /* Called when a write operations completes successfully, to clear out
253    all the write information. */
254 void i_ipmi_fru_set_op_write_complete(ipmi_fru_t *fru, ipmi_fru_void_op op);
255 
256 /* Called to copy all the changed data into the FRU block of data and
257    add update records for the changed data. */
258 void i_ipmi_fru_set_op_write(ipmi_fru_t *fru, ipmi_fru_err_op op);
259 
260 /* Get the root node for the user to decode. */
261 void i_ipmi_fru_set_op_get_root_node(ipmi_fru_t                *fru,
262 				    ipmi_fru_get_root_node_op op);
263 
264 /* Register a decoder for FRU data.  The provided function should
265    return success if the FRU is supported and can be decoded properly,
266    ENOSYS if the FRU information doesn't match the format, or anything
267    else for invalid FRU data.  It should register the nodes  */
268 int i_ipmi_fru_register_decoder(ipmi_fru_err_op op);
269 int i_ipmi_fru_deregister_decoder(ipmi_fru_err_op op);
270 
271 /***********************************************************************
272  *
273  * Table-driven multirecord FRU handling.
274  *
275  * This makes describing the contents of multi-record data much easier
276  * that writing your own field handling routines.
277  *
278  * You describe your data by filling in layout structures.  Three
279  * different structures exist:
280  *
281  *  struct - Defines a record node.  The top-level of a multi record
282  *  is always a record node, and arrays always consist of record
283  *  nodes.
284  *
285  *  item - These are individual data items (floats, ints, strings,
286  *  etc).  You supply an array of these in a struct layout to describe
287  *  the basic items in a record.
288  *
289  *  array - A variable-sized set of record nodes, items (or other
290  *  arrays, though that is not yet implemented).  You can insert
291  *  elements in the array and delete them.
292  *
293  * NOTE: you cannot have an array of bitfields.
294  *
295  **********************************************************************/
296 typedef struct ipmi_mr_struct_layout_s ipmi_mr_struct_layout_t;
297 typedef struct ipmi_mr_item_layout_s ipmi_mr_item_layout_t;
298 typedef struct ipmi_mr_array_layout_s ipmi_mr_array_layout_t;
299 
300 typedef struct ipmi_mr_item_info_s ipmi_mr_item_info_t;
301 typedef struct ipmi_mr_struct_info_s ipmi_mr_struct_info_t;
302 typedef struct ipmi_mr_array_info_s ipmi_mr_array_info_t;
303 
304 typedef struct ipmi_mr_offset_s ipmi_mr_offset_t;
305 
306 /* The offset structure is in all info structures as the first item,
307    it is sort of the "base type" of all the info types.  If an item is
308    contained within another item (like an item or structure in an
309    array, or an array or item in a structure), then the contained item
310    will have a pointer to the parent item's offset structure.  If an
311    item is in an array, the "next" pointer of this structure will
312    point to the next item's offset structure in the list.
313 
314    All this complexity is used to keep the offsets and lengths sane.
315    If you change an item's size (adding or deleting an element in an
316    array) you must change the length of all the parent items and the
317    offset of all succeeding items for the changed item and all items
318    succeeding all parents.  The fact that the offset is relative to
319    the parent means you have to go to all the parents to calculate the
320    real offset, but you don't have to go down arrays to recalculate
321    offsets. */
322 struct ipmi_mr_offset_s {
323     /* Items that contain this item, if we adjust this items length we
324        need to adjust the parent's lengths as well. */
325     ipmi_mr_offset_t *parent;
326 
327     /* Items after this one that need their offset adjusted if we
328        alter this item's length. */
329     ipmi_mr_offset_t *next;
330 
331     /* Offset from the beginning of the *parent*, not the whole
332        structure. */
333     uint8_t          offset;
334 
335     uint8_t          length;
336 };
337 
338 /* Stores in the data2 information for the root FRU node. */
339 typedef struct ipmi_mr_fru_info_s {
340     ipmi_fru_t   *fru;
341     unsigned int mr_rec_num;
342 } ipmi_mr_fru_info_t;
343 
344 /* A convenience structure for passing to the item get and set
345    routines. */
346 typedef struct ipmi_mr_getset_s {
347     ipmi_mr_item_layout_t     *layout;
348     ipmi_mr_offset_t          *offset;
349     unsigned char             *rdata;
350     ipmi_mr_fru_info_t        *finfo;
351 } ipmi_mr_getset_t;
352 
353 /* Information about an array. */
354 struct ipmi_mr_array_info_s {
355     ipmi_mr_offset_t       offset;
356     uint8_t                count;    /* Number of array elements. */
357     uint8_t                nr_after; /* Number of arrays after me. */
358     ipmi_mr_array_layout_t *layout;  /* Array layout */
359 
360     /* An array of ipmi_mr_struct_info_t, ipmi_mr_array_info_t, or
361        ipmi_mr_item_info_t, depending on layout functions. */
362     ipmi_mr_offset_t       **items;
363 };
364 
365 /* Information about a single item.  Note that this is only used in
366    arrays; structures use a different mechanism to manage items so
367    they can store their data more efficiently. */
368 struct ipmi_mr_item_info_s
369 {
370     ipmi_mr_offset_t      offset;
371     uint8_t               len;
372     ipmi_mr_item_layout_t *layout;
373     unsigned char         *data;
374 };
375 
376 /* Information about a structure.  The "data" field holds the data for
377    all items in the structure and the layout start offsets are used to
378    calculated how to get the individual items. */
379 struct ipmi_mr_struct_info_s
380 {
381     ipmi_mr_offset_t        offset;
382     ipmi_mr_struct_layout_t *layout;
383     unsigned char           *data;
384     ipmi_mr_array_info_t    *arrays;
385 };
386 
387 /* A descriptor for a single item.  This an appear in a structure item
388    list or in as an arrays elem_layout. */
389 struct ipmi_mr_item_layout_s
390 {
391     char                      *name;
392     enum ipmi_fru_data_type_e dtype;
393 
394     uint8_t settable;
395 
396     /* Start offset and length, either in bits for a bit offset field
397        or bytes for everything else. */
398     uint16_t start;
399     uint16_t length;
400 
401     union {
402 	float multiplier;
403 	void *tab_data;
404     } u;
405 
406     int (*set_field)(ipmi_mr_getset_t          *getset,
407 		     enum ipmi_fru_data_type_e dtype,
408 		     int                       intval,
409 		     time_t                    time,
410 		     double                    floatval,
411 		     char                      *data,
412 		     unsigned int              data_len);
413     int (*get_field)(ipmi_mr_getset_t          *getset,
414 		     enum ipmi_fru_data_type_e *dtype,
415 		     int                       *intval,
416 		     time_t                    *time,
417 		     double                    *floatval,
418 		     char                      **data,
419 		     unsigned int              *data_len);
420     int (*get_enum)(ipmi_mr_getset_t *getset,
421 		    int              *pos,
422 		    int              *nextpos,
423 		    const char       **data);
424 };
425 
426 /* Describes an array. */
427 struct ipmi_mr_array_layout_s
428 {
429     char    *name;
430     uint8_t has_count;
431     uint8_t min_elem_size;
432     uint8_t settable;
433 
434     /* Either a struct, item, or array layout, depending on the
435        functions. */
436     void *elem_layout;
437 
438     /* Check to make sure the data is valid and calculate the length
439        of the data needed for the element. */
440     int (*elem_check)(void                    *layout,
441 		      unsigned char           **mr_data,
442 		      unsigned int            *mr_data_len);
443     /* Decode the element.  The new record is returned in "rec". */
444     int (*elem_decode)(void                  *layout,
445 		       unsigned int          offset,
446 		       ipmi_mr_offset_t      *offset_parent,
447 		       ipmi_mr_offset_t      **rec,
448 		       unsigned char         **mr_data,
449 		       unsigned int          *mr_data_len);
450     /* Cleanup the array. */
451     void (*cleanup)(ipmi_mr_array_info_t *arec);
452     /* Get a field from the array. */
453     int (*get_field)(ipmi_mr_array_info_t      *arec,
454 		     ipmi_fru_node_t           *rnode,
455 		     enum ipmi_fru_data_type_e *dtype,
456 		     int                       *intval,
457 		     time_t                    *time,
458 		     double                    *floatval,
459 		     char                      **data,
460 		     unsigned int              *data_len,
461 		     ipmi_fru_node_t           **sub_node);
462     /* Set a field in the array. */
463     int (*set_field)(ipmi_mr_array_info_t      *arec,
464 		     ipmi_mr_fru_info_t        *finfo,
465 		     enum ipmi_fru_data_type_e dtype,
466 		     int                       intval,
467 		     time_t                    time,
468 		     double                    floatval,
469 		     char                      *data,
470 		     unsigned int              data_len);
471 };
472 
473 struct ipmi_mr_struct_layout_s
474 {
475     char                   *name;
476     uint8_t                length; /* Excluding arrays. */
477     unsigned int           item_count;
478     ipmi_mr_item_layout_t  *items;
479     unsigned int           array_count;
480     ipmi_mr_array_layout_t *arrays;
481 
482     void (*cleanup)(ipmi_mr_struct_info_t *rec);
483 };
484 
485 /* Get the actual offset from the beginning of the multi-record. */
486 uint8_t ipmi_mr_full_offset(ipmi_mr_offset_t *o);
487 
488 /* Resized something, adjust all the lengths and offsets in the parents. */
489 void ipmi_mr_adjust_len(ipmi_mr_offset_t *o, int len);
490 
491 /* Functions for processing arrays of structures. */
492 void ipmi_mr_struct_array_cleanup(ipmi_mr_array_info_t *arec);
493 int ipmi_mr_struct_array_get_field(ipmi_mr_array_info_t      *arec,
494 				   ipmi_fru_node_t           *rnode,
495 				   enum ipmi_fru_data_type_e *dtype,
496 				   int                       *intval,
497 				   time_t                    *time,
498 				   double                    *floatval,
499 				   char                      **data,
500 				   unsigned int              *data_len,
501 				   ipmi_fru_node_t           **sub_node);
502 int ipmi_mr_struct_array_set_field(ipmi_mr_array_info_t      *arec,
503 				   ipmi_mr_fru_info_t        *finfo,
504 				   enum ipmi_fru_data_type_e dtype,
505 				   int                       intval,
506 				   time_t                    time,
507 				   double                    floatval,
508 				   char                      *data,
509 				   unsigned int              data_len);
510 
511 /* Functions for processing arrays of items. */
512 void ipmi_mr_item_array_cleanup(ipmi_mr_array_info_t *arec);
513 int ipmi_mr_item_array_get_field(ipmi_mr_array_info_t      *arec,
514 				 ipmi_fru_node_t           *rnode,
515 				 enum ipmi_fru_data_type_e *dtype,
516 				 int                       *intval,
517 				 time_t                    *time,
518 				 double                    *floatval,
519 				 char                      **data,
520 				 unsigned int              *data_len,
521 				 ipmi_fru_node_t           **sub_node);
522 int ipmi_mr_item_array_set_field(ipmi_mr_array_info_t      *arec,
523 				 ipmi_mr_fru_info_t        *finfo,
524 				 enum ipmi_fru_data_type_e dtype,
525 				 int                       intval,
526 				 time_t                    time,
527 				 double                    floatval,
528 				 char                      *data,
529 				 unsigned int              data_len);
530 
531 /* Functions for handling structures. */
532 void ipmi_mr_struct_cleanup(ipmi_mr_struct_info_t *rec);
533 int ipmi_mr_struct_elem_check(void          *vlayout,
534 			      unsigned char **rmr_data,
535 			      unsigned int  *rmr_data_len);
536 int ipmi_mr_struct_decode(void             *vlayout,
537 			  unsigned int     offset,
538 			  ipmi_mr_offset_t *offset_parent,
539 			  ipmi_mr_offset_t **rrec,
540 			  unsigned char    **rmr_data,
541 			  unsigned int     *rmr_data_len);
542 
543 /* Functions for handling items (in arrays only). */
544 int ipmi_mr_item_elem_check(void          *vlayout,
545 			    unsigned char **rmr_data,
546 			    unsigned int  *rmr_data_len);
547 int ipmi_mr_item_decode(void             *vlayout,
548 			unsigned int     offset,
549 			ipmi_mr_offset_t *offset_parent,
550 			ipmi_mr_offset_t **rrec,
551 			unsigned char    **rmr_data,
552 			unsigned int     *rmr_data_len);
553 
554 /* Create a root node based upon a structure layout. */
555 int ipmi_mr_struct_root(ipmi_fru_t              *fru,
556 			unsigned int            mr_rec_num,
557 			unsigned char           *rmr_data,
558 			unsigned int            rmr_data_len,
559 			ipmi_mr_struct_layout_t *layout,
560 			const char              **name,
561 			ipmi_fru_node_t         **rnode);
562 
563 /***********************************************************************
564  *
565  * Generic field encoders and decoders.
566  *
567  **********************************************************************/
568 
569 /* Little-endian integer, one or more bytes. */
570 int ipmi_mr_int_set_field(ipmi_mr_getset_t          *getset,
571 			  enum ipmi_fru_data_type_e dtype,
572 			  int                       intval,
573 			  time_t                    time,
574 			  double                    floatval,
575 			  char                      *data,
576 			  unsigned int              data_len);
577 int ipmi_mr_int_get_field(ipmi_mr_getset_t          *getset,
578 			  enum ipmi_fru_data_type_e *dtype,
579 			  int                       *intval,
580 			  time_t                    *time,
581 			  double                    *floatval,
582 			  char                      **data,
583 			  unsigned int              *data_len);
584 
585 /* An integer that has is converted to float.  You must set the
586    multiplier field in the layout. */
587 int ipmi_mr_intfloat_set_field(ipmi_mr_getset_t          *getset,
588 			       enum ipmi_fru_data_type_e dtype,
589 			       int                       intval,
590 			       time_t                    time,
591 			       double                    floatval,
592 			       char                      *data,
593 			       unsigned int              data_len);
594 int ipmi_mr_intfloat_get_field(ipmi_mr_getset_t          *getset,
595 			       enum ipmi_fru_data_type_e *dtype,
596 			       int                       *intval,
597 			       time_t                    *time,
598 			       double                    *floatval,
599 			       char                      **data,
600 			       unsigned int              *data_len);
601 
602 /* A bit field in the structure.  Note that this is little endian and
603    the "start" and "length" field of the layout are in bits, not
604    bytes. */
605 int ipmi_mr_bitint_set_field(ipmi_mr_getset_t          *getset,
606 			     enum ipmi_fru_data_type_e dtype,
607 			     int                       intval,
608 			     time_t                    time,
609 			     double                    floatval,
610 			     char                      *data,
611 			     unsigned int              data_len);
612 int ipmi_mr_bitint_get_field(ipmi_mr_getset_t          *getset,
613 			     enum ipmi_fru_data_type_e *dtype,
614 			     int                       *intval,
615 			     time_t                    *time,
616 			     double                    *floatval,
617 			     char                      **data,
618 			     unsigned int              *data_len);
619 
620 /* A bitint that is a set of strings indexed by the integer value.
621    The tab_data field must be set to an ipmi_mr_tab_item_t
622    structure. */
623 typedef struct ipmi_mr_tab_item_s {
624     unsigned int count;
625     const char   *table[];
626 } ipmi_mr_tab_item_t;
627 int ipmi_mr_bitvaltab_set_field(ipmi_mr_getset_t          *getset,
628 				enum ipmi_fru_data_type_e dtype,
629 				int                       intval,
630 				time_t                    time,
631 				double                    floatval,
632 				char                      *data,
633 				unsigned int              data_len);
634 int ipmi_mr_bitvaltab_get_field(ipmi_mr_getset_t          *getset,
635 				enum ipmi_fru_data_type_e *dtype,
636 				int                       *intval,
637 				time_t                    *time,
638 				double                    *floatval,
639 				char                      **data,
640 				unsigned int              *data_len);
641 int ipmi_mr_bitvaltab_get_enum(ipmi_mr_getset_t *getset,
642 			       int              *pos,
643 			       int              *nextpos,
644 			       const char       **data);
645 
646 /* A bitint that is a set of floating point values indexed by integer
647    value.  The tab_data field must be set to an
648    ipmi_mr_floattab_item_t structure. */
649 typedef struct ipmi_mr_floattab_item_s {
650     unsigned int count;
651     double       defval; /* Default when initialized */
652     /* You specify a low, nominal, and high value.  The nominal value
653        is what it is converted to.  Anything between low and high will
654        convert to this value. */
655     struct {
656 	float      low;
657 	float      nominal;
658 	float      high;
659 	const char *nominal_str;
660     } table[];
661 } ipmi_mr_floattab_item_t;
662 int ipmi_mr_bitfloatvaltab_set_field(ipmi_mr_getset_t          *getset,
663 				     enum ipmi_fru_data_type_e dtype,
664 				     int                       intval,
665 				     time_t                    time,
666 				     double                    floatval,
667 				     char                      *data,
668 				     unsigned int              data_len);
669 int ipmi_mr_bitfloatvaltab_get_field(ipmi_mr_getset_t          *getset,
670 				     enum ipmi_fru_data_type_e *dtype,
671 				     int                       *intval,
672 				     time_t                    *time,
673 				     double                    *floatval,
674 				     char                      **data,
675 				     unsigned int              *data_len);
676 int ipmi_mr_bitfloatvaltab_get_enum(ipmi_mr_getset_t *getset,
677 				    int              *pos,
678 				    int              *nextpos,
679 				    const char       **data);
680 
681 /* A fixed-size area for a standard IPMI FRU string. */
682 int ipmi_mr_str_set_field(ipmi_mr_getset_t          *getset,
683 			  enum ipmi_fru_data_type_e dtype,
684 			  int                       intval,
685 			  time_t                    time,
686 			  double                    floatval,
687 			  char                      *data,
688 			  unsigned int              data_len);
689 int ipmi_mr_str_get_field(ipmi_mr_getset_t          *getset,
690 			  enum ipmi_fru_data_type_e *dtype,
691 			  int                       *intval,
692 			  time_t                    *time,
693 			  double                    *floatval,
694 			  char                      **data,
695 			  unsigned int              *data_len);
696 
697 /* A fixed-size area for a chunk of bytes. */
698 int ipmi_mr_binary_set_field(ipmi_mr_getset_t          *getset,
699 			     enum ipmi_fru_data_type_e dtype,
700 			     int                       intval,
701 			     time_t                    time,
702 			     double                    floatval,
703 			     char                      *data,
704 			     unsigned int              data_len);
705 int ipmi_mr_binary_get_field(ipmi_mr_getset_t          *getset,
706 			     enum ipmi_fru_data_type_e *dtype,
707 			     int                       *intval,
708 			     time_t                    *time,
709 			     double                    *floatval,
710 			     char                      **data,
711 			     unsigned int              *data_len);
712 
713 /* A four-byte IP address, represented as a string. */
714 int ipmi_mr_ip_set_field(ipmi_mr_getset_t          *getset,
715 			 enum ipmi_fru_data_type_e dtype,
716 			 int                       intval,
717 			 time_t                    time,
718 			 double                    floatval,
719 			 char                      *data,
720 			 unsigned int              data_len);
721 int ipmi_mr_ip_get_field(ipmi_mr_getset_t          *getset,
722 			 enum ipmi_fru_data_type_e *dtype,
723 			 int                       *intval,
724 			 time_t                    *time,
725 			 double                    *floatval,
726 			 char                      **data,
727 			 unsigned int              *data_len);
728 
729 #endif /* OPENIPMI_FRU_INTERNAL_H */
730