1 /*
2  * fru.c
3  *
4  * IPMI code for handling FRUs
5  *
6  * Author: MontaVista Software, Inc.
7  *         Corey Minyard <minyard@mvista.com>
8  *         source@mvista.com
9  *
10  * Copyright 2002,2003 MontaVista Software Inc.
11  *
12  * Note that this file was originally written by Thomas Kanngieser
13  * <thomas.kanngieser@fci.com> of FORCE Computers, but I've pretty
14  * much gutted it and rewritten it, nothing really remained the same.
15  * Thomas' code was helpful, though and many thanks go to him.
16  *
17  *  This program is free software; you can redistribute it and/or
18  *  modify it under the terms of the GNU Lesser General Public License
19  *  as published by the Free Software Foundation; either version 2 of
20  *  the License, or (at your option) any later version.
21  *
22  *
23  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
24  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
31  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
32  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  *  You should have received a copy of the GNU Lesser General Public
35  *  License along with this program; if not, write to the Free
36  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
37  */
38 
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdint.h>
42 #include <errno.h>
43 
44 #include <OpenIPMI/ipmiif.h>
45 #include <OpenIPMI/ipmi_fru.h>
46 #include <OpenIPMI/ipmi_err.h>
47 #include <OpenIPMI/ipmi_msgbits.h>
48 
49 #include <OpenIPMI/internal/locked_list.h>
50 #include <OpenIPMI/internal/ipmi_domain.h>
51 #include <OpenIPMI/internal/ipmi_int.h>
52 #include <OpenIPMI/internal/ipmi_utils.h>
53 #include <OpenIPMI/internal/ipmi_oem.h>
54 #include <OpenIPMI/internal/ipmi_fru.h>
55 
56 #define MAX_FRU_DATA_FETCH 32
57 #define FRU_DATA_FETCH_DECR 8
58 #define MIN_FRU_DATA_FETCH 16
59 
60 #define MAX_FRU_DATA_WRITE 16
61 #define MAX_FRU_WRITE_RETRIES 30
62 
63 #define MAX_FRU_FETCH_RETRIES 5
64 
65 #define IPMI_FRU_ATTR_NAME "ipmi_fru"
66 
67 /*
68  * A note of FRUs, fru attributes, and locking.
69  *
70  * Because we keep a list of FRUs, that makes locking a lot more
71  * complicated.  While we are deleting a FRU another thread can come
72  * along and iterate and find it.  The lock on the locked list is used
73  * along with the FRU lock to prevent this from happening.  Since in
74  * this situation, the locked list lock is held when the FRU is
75  * referenced, when we destroy the FRU we make sure that it wasn't
76  * resurrected after being deleted from this list.
77  */
78 
79 /* Record used for FRU writing. */
80 typedef struct fru_update_s fru_update_t;
81 struct fru_update_s
82 {
83     unsigned short offset;
84     unsigned short length;
85     fru_update_t   *next;
86 };
87 
88 /* Operations registered by the decode for a FRU. */
89 typedef struct ipmi_fru_op_s
90 {
91     /* Called to free all the data associated with fru record data. */
92     void (*cleanup_recs)(ipmi_fru_t *fru);
93 
94     /* Called when the FRU data has been written, to mark all the data
95        as unchanged from the FRU contents. */
96     void (*write_complete)(ipmi_fru_t *fru);
97 
98     /* Called to write any changed data into the fru and mark what is
99        changed. */
100     int (*write)(ipmi_fru_t *fru);
101 
102     /* Get the root node for this FRU. */
103     int (*get_root_node)(ipmi_fru_t      *fru,
104 			 const char      **name,
105 			 ipmi_fru_node_t **rnode);
106 } ipmi_fru_op_t;
107 
108 struct ipmi_fru_s
109 {
110     char name[IPMI_FRU_NAME_LEN+1];
111     int deleted;
112 
113     unsigned int refcount;
114 
115     /* Is the FRU being read or written? */
116     int in_use;
117 
118     ipmi_lock_t *lock;
119 
120     ipmi_addr_t  addr;
121     unsigned int addr_len;
122 
123     void                          *setup_data;
124     i_ipmi_fru_setup_data_clean_cb setup_data_cleanup;
125 
126     ipmi_domain_id_t     domain_id;
127     unsigned char        is_logical;
128     unsigned char        device_address;
129     unsigned char        device_id;
130     unsigned char        lun;
131     unsigned char        private_bus;
132     unsigned char        channel;
133 
134     unsigned int        fetch_mask;
135 
136     uint32_t last_timestamp;
137     int      fetch_retries;
138 
139     ipmi_fru_fetched_cb fetched_handler;
140     ipmi_fru_cb         domain_fetched_handler;
141     void                *fetched_cb_data;
142 
143     ipmi_fru_destroyed_cb destroy_handler;
144     void                  *destroy_cb_data;
145 
146     int           access_by_words;
147     unsigned char *data;
148     unsigned int  data_len;
149     unsigned int  curr_pos;
150     unsigned int  curr_write_len;
151     int           write_prepared;
152     int           saved_err;
153 
154     int           fetch_size;
155 
156     /* Is this in the list of FRUs? */
157     int in_frulist;
158 
159     /* The records for writing. */
160     fru_update_t *update_recs;
161     fru_update_t *update_recs_tail;
162 
163     /* The last send command for writing */
164     unsigned int  last_cmd_len;
165     unsigned int  retry_count;
166 
167     os_handler_t *os_hnd;
168 
169     /* If the FRU is a "normal" fru type, for backwards
170        compatability. */
171     int  normal_fru;
172 
173     char *fru_rec_type;
174     void *rec_data;
175     ipmi_fru_op_t ops;
176 
177     /* FRU locking handling */
178     i_ipmi_fru_get_timestamp_cb  timestamp_cb;
179     i_ipmi_fru_prepare_write_cb  prepare_write_cb;
180     i_ipmi_fru_write_cb          write_cb;
181     i_ipmi_fru_complete_write_cb complete_write_cb;
182 
183     char iname[IPMI_FRU_NAME_LEN+1];
184 
185     unsigned int options;
186 };
187 
188 #define FRU_DOMAIN_NAME(fru) (fru ? fru->iname : "")
189 
190 static void final_fru_destroy(ipmi_fru_t *fru);
191 static void fetch_complete(ipmi_domain_t *domain, ipmi_fru_t *fru, int err);
192 
193 /***********************************************************************
194  *
195  * general utilities
196  *
197  **********************************************************************/
198 void
i_ipmi_fru_lock(ipmi_fru_t * fru)199 i_ipmi_fru_lock(ipmi_fru_t *fru)
200 {
201     ipmi_lock(fru->lock);
202 }
203 
204 void
i_ipmi_fru_unlock(ipmi_fru_t * fru)205 i_ipmi_fru_unlock(ipmi_fru_t *fru)
206 {
207     ipmi_unlock(fru->lock);
208 }
209 
210 /*
211  * Must already be holding the FRU lock to call this.
212  */
213 static void
fru_get(ipmi_fru_t * fru)214 fru_get(ipmi_fru_t *fru)
215 {
216     fru->refcount++;
217 }
218 
219 void
i_ipmi_fru_ref_nolock(ipmi_fru_t * fru)220 i_ipmi_fru_ref_nolock(ipmi_fru_t *fru)
221 {
222     fru->refcount++;
223 }
224 
225 static void
fru_put(ipmi_fru_t * fru)226 fru_put(ipmi_fru_t *fru)
227 {
228     i_ipmi_fru_lock(fru);
229     fru->refcount--;
230     if (fru->refcount == 0) {
231 	final_fru_destroy(fru);
232 	return;
233     }
234     i_ipmi_fru_unlock(fru);
235 }
236 
237 void
ipmi_fru_ref(ipmi_fru_t * fru)238 ipmi_fru_ref(ipmi_fru_t *fru)
239 {
240     i_ipmi_fru_lock(fru);
241     fru_get(fru);
242     i_ipmi_fru_unlock(fru);
243 }
244 
245 void
ipmi_fru_deref(ipmi_fru_t * fru)246 ipmi_fru_deref(ipmi_fru_t *fru)
247 {
248     fru_put(fru);
249 }
250 
251 /************************************************************************
252  *
253  * Decode registration handling
254  *
255  ************************************************************************/
256 
257 static locked_list_t *fru_decode_handlers;
258 
259 int
i_ipmi_fru_register_decoder(ipmi_fru_err_op op)260 i_ipmi_fru_register_decoder(ipmi_fru_err_op op)
261 {
262     if (!locked_list_add(fru_decode_handlers, op, NULL))
263 	return ENOMEM;
264     return 0;
265 }
266 
267 int
i_ipmi_fru_deregister_decoder(ipmi_fru_err_op op)268 i_ipmi_fru_deregister_decoder(ipmi_fru_err_op op)
269 {
270     if (!locked_list_remove(fru_decode_handlers, op, NULL))
271 	return ENODEV;
272     return 0;
273 }
274 
275 typedef struct fru_decode_s
276 {
277     ipmi_fru_t *fru;
278     int        err;
279 } fru_decode_t;
280 
281 static int
fru_call_decoder(void * cb_data,void * item1,void * item2)282 fru_call_decoder(void *cb_data, void *item1, void *item2)
283 {
284     fru_decode_t    *info = cb_data;
285     ipmi_fru_err_op op = item1;
286     int             err;
287 
288     err = op(info->fru);
289     if (!err) {
290 	info->err = 0;
291 	return LOCKED_LIST_ITER_STOP;
292     } else
293 	return LOCKED_LIST_ITER_CONTINUE;
294 }
295 
296 static int
fru_call_decoders(ipmi_fru_t * fru)297 fru_call_decoders(ipmi_fru_t *fru)
298 {
299     fru_decode_t info;
300 
301     info.err = ENOSYS;
302     info.fru = fru;
303     locked_list_iterate(fru_decode_handlers, fru_call_decoder, &info);
304     return info.err;
305 }
306 
307 void
i_ipmi_fru_set_op_cleanup_recs(ipmi_fru_t * fru,ipmi_fru_void_op op)308 i_ipmi_fru_set_op_cleanup_recs(ipmi_fru_t *fru, ipmi_fru_void_op op)
309 {
310     fru->ops.cleanup_recs = op;
311 }
312 
313 void
i_ipmi_fru_set_op_write_complete(ipmi_fru_t * fru,ipmi_fru_void_op op)314 i_ipmi_fru_set_op_write_complete(ipmi_fru_t *fru, ipmi_fru_void_op op)
315 {
316     fru->ops.write_complete = op;
317 }
318 
319 void
i_ipmi_fru_set_op_write(ipmi_fru_t * fru,ipmi_fru_err_op op)320 i_ipmi_fru_set_op_write(ipmi_fru_t *fru, ipmi_fru_err_op op)
321 {
322     fru->ops.write = op;
323 }
324 
325 void
i_ipmi_fru_set_op_get_root_node(ipmi_fru_t * fru,ipmi_fru_get_root_node_op op)326 i_ipmi_fru_set_op_get_root_node(ipmi_fru_t                *fru,
327 			       ipmi_fru_get_root_node_op op)
328 {
329     fru->ops.get_root_node = op;
330 }
331 
332 
333 /***********************************************************************
334  *
335  * FRU configuration
336  *
337  **********************************************************************/
338 int
i_ipmi_fru_set_get_timestamp_handler(ipmi_fru_t * fru,i_ipmi_fru_get_timestamp_cb handler)339 i_ipmi_fru_set_get_timestamp_handler(ipmi_fru_t                 *fru,
340 				     i_ipmi_fru_get_timestamp_cb handler)
341 {
342     fru->timestamp_cb = handler;
343     return 0;
344 }
345 
346 int
i_ipmi_fru_set_prepare_write_handler(ipmi_fru_t * fru,i_ipmi_fru_prepare_write_cb handler)347 i_ipmi_fru_set_prepare_write_handler(ipmi_fru_t                 *fru,
348 				     i_ipmi_fru_prepare_write_cb handler)
349 {
350     fru->prepare_write_cb = handler;
351     return 0;
352 }
353 
354 int
i_ipmi_fru_set_write_handler(ipmi_fru_t * fru,i_ipmi_fru_write_cb handler)355 i_ipmi_fru_set_write_handler(ipmi_fru_t         *fru,
356 			     i_ipmi_fru_write_cb handler)
357 {
358     fru->write_cb = handler;
359     return 0;
360 }
361 
362 int
i_ipmi_fru_set_complete_write_handler(ipmi_fru_t * fru,i_ipmi_fru_complete_write_cb handler)363 i_ipmi_fru_set_complete_write_handler(ipmi_fru_t                  *fru,
364 				      i_ipmi_fru_complete_write_cb handler)
365 {
366     fru->complete_write_cb = handler;
367     return 0;
368 }
369 
370 void
i_ipmi_fru_get_addr(ipmi_fru_t * fru,ipmi_addr_t * addr,unsigned int * addr_len)371 i_ipmi_fru_get_addr(ipmi_fru_t *fru, ipmi_addr_t *addr, unsigned int *addr_len)
372 {
373     *addr = fru->addr;
374     *addr_len = fru->addr_len;
375 }
376 
377 void
i_ipmi_fru_set_setup_data(ipmi_fru_t * fru,void * data,i_ipmi_fru_setup_data_clean_cb cleanup)378 i_ipmi_fru_set_setup_data(ipmi_fru_t                    *fru,
379 			  void                          *data,
380 			  i_ipmi_fru_setup_data_clean_cb cleanup)
381 {
382     fru->setup_data = data;
383     fru->setup_data_cleanup = cleanup;
384 }
385 
386 void *
i_ipmi_fru_get_setup_data(ipmi_fru_t * fru)387 i_ipmi_fru_get_setup_data(ipmi_fru_t *fru)
388 {
389     return fru->setup_data;
390 }
391 
392 static int
fru_normal_write_done(ipmi_domain_t * domain,ipmi_msgi_t * rspi)393 fru_normal_write_done(ipmi_domain_t *domain, ipmi_msgi_t *rspi)
394 {
395     ipmi_msg_t      *msg = &rspi->msg;
396     ipmi_fru_t      *fru = rspi->data1;
397     unsigned char   *data = msg->data;
398     i_ipmi_fru_op_cb cb = rspi->data2;
399     int             err = 0;
400 
401     if (data[0]) {
402 	err = IPMI_IPMI_ERR_VAL(data[0]);
403 	goto out;
404     }
405 
406     if (msg->data_len < 2) {
407 	ipmi_log(IPMI_LOG_ERR_INFO,
408 		 "%sfru.c(fru_normal_write_done): "
409 		 "FRU write response too small",
410 		 FRU_DOMAIN_NAME(fru));
411 	err = EINVAL;
412 	goto out;
413     }
414 
415     if ((unsigned int) (data[1] << fru->access_by_words)
416 	!= (fru->last_cmd_len - 3))
417     {
418 	/* Write was incomplete for some reason.  Just go on but issue
419 	   a warning. */
420 	ipmi_log(IPMI_LOG_WARNING,
421 		 "%sfru.c(fru_normal_write_done): "
422 		 "Incomplete writing FRU data, write %d, expected %d",
423 		 FRU_DOMAIN_NAME(fru),
424 		 data[1] << fru->access_by_words, fru->last_cmd_len-3);
425     }
426 
427  out:
428     cb(fru, domain, err);
429     return IPMI_MSG_ITEM_NOT_USED;
430 }
431 
432 static int
fru_normal_write(ipmi_fru_t * fru,ipmi_domain_t * domain,unsigned char * data,unsigned int data_len,i_ipmi_fru_op_cb done)433 fru_normal_write(ipmi_fru_t      *fru,
434 		 ipmi_domain_t   *domain,
435 		 unsigned char   *data,
436 		 unsigned int    data_len,
437 		 i_ipmi_fru_op_cb done)
438 {
439     ipmi_msg_t msg;
440 
441     msg.netfn = IPMI_STORAGE_NETFN;
442     msg.cmd = IPMI_WRITE_FRU_DATA_CMD;
443     msg.data = data;
444     msg.data_len = data_len;
445 
446     return ipmi_send_command_addr(domain,
447 				  &fru->addr, fru->addr_len,
448 				  &msg,
449 				  fru_normal_write_done,
450 				  fru,
451 				  done);
452 }
453 
454 void
ipmi_fru_set_options(ipmi_fru_t * fru,unsigned int options)455 ipmi_fru_set_options(ipmi_fru_t *fru, unsigned int options)
456 {
457     fru->options = options;
458 }
459 
460 unsigned int
ipmi_fru_get_options(ipmi_fru_t * fru)461 ipmi_fru_get_options(ipmi_fru_t *fru)
462 {
463     return fru->options;
464 }
465 
466 /***********************************************************************
467  *
468  * FRU allocation and destruction
469  *
470  **********************************************************************/
471 
472 static void
final_fru_destroy(ipmi_fru_t * fru)473 final_fru_destroy(ipmi_fru_t *fru)
474 {
475     if (fru->in_frulist) {
476 	int                rv;
477 	ipmi_domain_attr_t *attr;
478 	locked_list_t      *frul;
479 
480 	fru->in_frulist = 0;
481 	rv = ipmi_domain_id_find_attribute(fru->domain_id, IPMI_FRU_ATTR_NAME,
482 					   &attr);
483 	if (!rv) {
484 	    fru->refcount++;
485 	    i_ipmi_fru_unlock(fru);
486 	    frul = ipmi_domain_attr_get_data(attr);
487 	    locked_list_remove(frul, fru, NULL);
488 	    ipmi_domain_attr_put(attr);
489 	    i_ipmi_fru_lock(fru);
490 	    /* While we were unlocked, someone may have come in and
491 	       grabbed the FRU by iterating the list of FRUs.  That's
492 	       ok, we just let them handle the destruction since this
493 	       code will not be entered again. */
494 	    if (fru->refcount != 1) {
495 		fru->refcount--;
496 		i_ipmi_fru_unlock(fru);
497 		return;
498 	    }
499 	}
500     }
501     i_ipmi_fru_unlock(fru);
502 
503     /* No one else can be referencing this here, so it is safe to
504        release the lock now. */
505 
506     if (fru->destroy_handler)
507 	fru->destroy_handler(fru, fru->destroy_cb_data);
508 
509     if (fru->ops.cleanup_recs)
510 	fru->ops.cleanup_recs(fru);
511 
512     while (fru->update_recs) {
513 	fru_update_t *to_free = fru->update_recs;
514 	fru->update_recs = to_free->next;
515 	ipmi_mem_free(to_free);
516     }
517     if (fru->setup_data_cleanup)
518 	fru->setup_data_cleanup(fru, fru->setup_data);
519     ipmi_destroy_lock(fru->lock);
520     ipmi_mem_free(fru);
521 }
522 
523 int
ipmi_fru_destroy_internal(ipmi_fru_t * fru,ipmi_fru_destroyed_cb handler,void * cb_data)524 ipmi_fru_destroy_internal(ipmi_fru_t            *fru,
525 			  ipmi_fru_destroyed_cb handler,
526 			  void                  *cb_data)
527 {
528     if (fru->in_frulist)
529 	return EPERM;
530 
531     i_ipmi_fru_lock(fru);
532     fru->destroy_handler = handler;
533     fru->destroy_cb_data = cb_data;
534     fru->deleted = 1;
535     i_ipmi_fru_unlock(fru);
536 
537     fru_put(fru);
538     return 0;
539 }
540 
541 int
ipmi_fru_destroy(ipmi_fru_t * fru,ipmi_fru_destroyed_cb handler,void * cb_data)542 ipmi_fru_destroy(ipmi_fru_t            *fru,
543 		 ipmi_fru_destroyed_cb handler,
544 		 void                  *cb_data)
545 {
546     ipmi_domain_attr_t *attr;
547     locked_list_t      *frul;
548     int                rv;
549 
550     i_ipmi_fru_lock(fru);
551     if (fru->in_frulist) {
552 	rv = ipmi_domain_id_find_attribute(fru->domain_id, IPMI_FRU_ATTR_NAME,
553 					   &attr);
554 	if (rv) {
555 	    i_ipmi_fru_unlock(fru);
556 	    return rv;
557 	}
558 	fru->in_frulist = 0;
559 	i_ipmi_fru_unlock(fru);
560 
561 	frul = ipmi_domain_attr_get_data(attr);
562 	if (! locked_list_remove(frul, fru, NULL)) {
563 	    /* Not in the list, it's already been removed. */
564 	    ipmi_domain_attr_put(attr);
565 	    i_ipmi_fru_unlock(fru);
566 	    return EINVAL;
567 	}
568 	ipmi_domain_attr_put(attr);
569 	fru_put(fru); /* It's not in the list any more. */
570     } else {
571 	/* User can't destroy FRUs he didn't allocate. */
572 	i_ipmi_fru_unlock(fru);
573 	return EPERM;
574     }
575 
576     return ipmi_fru_destroy_internal(fru, handler, cb_data);
577 }
578 
579 static int start_logical_fru_fetch(ipmi_domain_t *domain, ipmi_fru_t *fru);
580 static int start_physical_fru_fetch(ipmi_domain_t *domain, ipmi_fru_t *fru);
581 
582 static int
destroy_fru(void * cb_data,void * item1,void * item2)583 destroy_fru(void *cb_data, void *item1, void *item2)
584 {
585     ipmi_fru_t *fru = item1;
586 
587     /* Users are responsible for handling their own FRUs, we don't
588        delete here, just mark not in the list. */
589     i_ipmi_fru_lock(fru);
590     fru->in_frulist = 0;
591     i_ipmi_fru_unlock(fru);
592     return LOCKED_LIST_ITER_CONTINUE;
593 }
594 
595 static void
fru_attr_destroy(void * cb_data,void * data)596 fru_attr_destroy(void *cb_data, void *data)
597 {
598     locked_list_t *frul = data;
599 
600     locked_list_iterate(frul, destroy_fru, NULL);
601     locked_list_destroy(frul);
602 }
603 
604 static int
fru_attr_init(ipmi_domain_t * domain,void * cb_data,void ** data)605 fru_attr_init(ipmi_domain_t *domain, void *cb_data, void **data)
606 {
607     locked_list_t *frul;
608 
609     frul = locked_list_alloc(ipmi_domain_get_os_hnd(domain));
610     if (!frul)
611 	return ENOMEM;
612 
613     *data = frul;
614     return 0;
615 }
616 
617 static int
start_fru_fetch(ipmi_fru_t * fru,ipmi_domain_t * domain)618 start_fru_fetch(ipmi_fru_t *fru, ipmi_domain_t *domain)
619 {
620     int rv;
621 
622     fru->curr_pos = 0;
623 
624     if (fru->is_logical)
625 	rv = start_logical_fru_fetch(domain, fru);
626     else
627 	rv = start_physical_fru_fetch(domain, fru);
628 
629     return rv;
630 }
631 
632 static void
fetch_got_timestamp(ipmi_fru_t * fru,ipmi_domain_t * domain,int err,uint32_t timestamp)633 fetch_got_timestamp(ipmi_fru_t    *fru,
634 		    ipmi_domain_t *domain,
635 		    int           err,
636 		    uint32_t      timestamp)
637 {
638     int rv;
639     i_ipmi_fru_lock(fru);
640     if (fru->deleted) {
641 	fetch_complete(domain, fru, ECANCELED);
642 	goto out;
643     }
644 
645     if (err) {
646 	fetch_complete(domain, fru, err);
647 	goto out;
648     }
649 
650     fru->last_timestamp = timestamp;
651     rv = start_fru_fetch(fru, domain);
652     if (rv) {
653 	fetch_complete(domain, fru, rv);
654 	goto out;
655     }
656     i_ipmi_fru_unlock(fru);
657  out:
658     return;
659 }
660 
661 static int
ipmi_fru_alloc_internal(ipmi_domain_t * domain,unsigned char is_logical,unsigned char device_address,unsigned char device_id,unsigned char lun,unsigned char private_bus,unsigned char channel,unsigned char fetch_mask,ipmi_fru_fetched_cb fetched_handler,void * fetched_cb_data,ipmi_fru_t ** new_fru)662 ipmi_fru_alloc_internal(ipmi_domain_t       *domain,
663 			unsigned char       is_logical,
664 			unsigned char       device_address,
665 			unsigned char       device_id,
666 			unsigned char       lun,
667 			unsigned char       private_bus,
668 			unsigned char       channel,
669 			unsigned char       fetch_mask,
670 			ipmi_fru_fetched_cb fetched_handler,
671 			void                *fetched_cb_data,
672 			ipmi_fru_t          **new_fru)
673 {
674     ipmi_fru_t       *fru;
675     int              err;
676     int              len, p;
677     ipmi_ipmb_addr_t *ipmb;
678 
679     fru = ipmi_mem_alloc(sizeof(*fru));
680     if (!fru)
681 	return ENOMEM;
682     memset(fru, 0, sizeof(*fru));
683 
684     err = ipmi_create_lock(domain, &fru->lock);
685     if (err) {
686 	ipmi_mem_free(fru);
687 	return err;
688     }
689 
690     /* Refcount starts at 2 because we start a fetch immediately. */
691     fru->refcount = 2;
692     fru->in_use = 1;
693 
694     fru->domain_id = ipmi_domain_convert_to_id(domain);
695     fru->is_logical = is_logical;
696     fru->device_address = device_address;
697     fru->device_id = device_id;
698     fru->lun = lun;
699     fru->private_bus = private_bus;
700     fru->channel = channel;
701     fru->fetch_mask = fetch_mask;
702     fru->fetch_size = MAX_FRU_DATA_FETCH;
703     fru->os_hnd = ipmi_domain_get_os_hnd(domain);
704     fru->write_cb = fru_normal_write;
705 
706     len = sizeof(fru->name);
707     p = ipmi_domain_get_name(domain, fru->name, len);
708     len -= p;
709     snprintf(fru->name+p, len, ".%d", ipmi_domain_get_unique_num(domain));
710 
711     snprintf(fru->iname, sizeof(fru->iname), "%s.%d.%x.%d.%d.%d.%d ",
712 	     DOMAIN_NAME(domain), is_logical, device_address, device_id, lun,
713 	     private_bus, channel);
714 
715     fru->fetched_handler = fetched_handler;
716     fru->fetched_cb_data = fetched_cb_data;
717 
718     fru->deleted = 0;
719 
720     ipmb = (ipmi_ipmb_addr_t *) &fru->addr;
721     ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
722     ipmb->channel = fru->channel;
723     ipmb->slave_addr = fru->device_address;
724     ipmb->lun = fru->lun;
725     fru->addr_len = sizeof(*ipmb);
726 
727     err = i_ipmi_domain_fru_call_special_setup(domain, is_logical,
728 					       device_address, device_id,
729 					       lun, private_bus, channel,
730 					       fru);
731     if (err)
732 	goto out_err;
733 
734     i_ipmi_fru_lock(fru);
735     if (fru->timestamp_cb) {
736 	err = fru->timestamp_cb(fru, domain, fetch_got_timestamp);
737 	if (err)
738 	    goto out_err;
739     } else {
740 	err = start_fru_fetch(fru, domain);
741 	if (err)
742 	    goto out_err;
743     }
744 
745     *new_fru = fru;
746     return 0;
747 
748  out_err:
749     i_ipmi_fru_unlock(fru);
750     ipmi_destroy_lock(fru->lock);
751     ipmi_mem_free(fru);
752     return err;
753 }
754 
755 int
ipmi_domain_fru_alloc(ipmi_domain_t * domain,unsigned char is_logical,unsigned char device_address,unsigned char device_id,unsigned char lun,unsigned char private_bus,unsigned char channel,ipmi_fru_cb fetched_handler,void * fetched_cb_data,ipmi_fru_t ** new_fru)756 ipmi_domain_fru_alloc(ipmi_domain_t *domain,
757 		      unsigned char is_logical,
758 		      unsigned char device_address,
759 		      unsigned char device_id,
760 		      unsigned char lun,
761 		      unsigned char private_bus,
762 		      unsigned char channel,
763 		      ipmi_fru_cb   fetched_handler,
764 		      void          *fetched_cb_data,
765 		      ipmi_fru_t    **new_fru)
766 {
767     ipmi_fru_t         *nfru;
768     int                rv;
769     ipmi_domain_attr_t *attr;
770     locked_list_t      *frul;
771 
772     rv = ipmi_domain_register_attribute(domain, IPMI_FRU_ATTR_NAME,
773 					fru_attr_init,
774 					fru_attr_destroy,
775 					NULL,
776 					&attr);
777     if (rv)
778 	return rv;
779     frul = ipmi_domain_attr_get_data(attr);
780 
781     /* Be careful with locking, a FRU fetch is already going on when
782        the alloc_internal function returns. */
783     locked_list_lock(frul);
784     rv = ipmi_fru_alloc_internal(domain, is_logical, device_address,
785 				 device_id, lun, private_bus, channel,
786 				 IPMI_FRU_ALL_AREA_MASK, NULL, NULL, &nfru);
787     if (rv) {
788 	locked_list_unlock(frul);
789 	ipmi_domain_attr_put(attr);
790 	return rv;
791     }
792 
793     nfru->in_frulist = 1;
794 
795     if (! locked_list_add_nolock(frul, nfru, NULL)) {
796 	locked_list_unlock(frul);
797 	nfru->fetched_handler = NULL;
798 	ipmi_fru_destroy(nfru, NULL, NULL);
799 	ipmi_domain_attr_put(attr);
800 	return ENOMEM;
801     }
802     nfru->domain_fetched_handler = fetched_handler;
803     nfru->fetched_cb_data = fetched_cb_data;
804     i_ipmi_fru_unlock(nfru);
805     locked_list_unlock(frul);
806     ipmi_domain_attr_put(attr);
807 
808     if (new_fru)
809 	*new_fru = nfru;
810     return 0;
811 }
812 
813 int
ipmi_fru_alloc(ipmi_domain_t * domain,unsigned char is_logical,unsigned char device_address,unsigned char device_id,unsigned char lun,unsigned char private_bus,unsigned char channel,ipmi_fru_fetched_cb fetched_handler,void * fetched_cb_data,ipmi_fru_t ** new_fru)814 ipmi_fru_alloc(ipmi_domain_t       *domain,
815 	       unsigned char       is_logical,
816 	       unsigned char       device_address,
817 	       unsigned char       device_id,
818 	       unsigned char       lun,
819 	       unsigned char       private_bus,
820 	       unsigned char       channel,
821 	       ipmi_fru_fetched_cb fetched_handler,
822 	       void                *fetched_cb_data,
823 	       ipmi_fru_t          **new_fru)
824 {
825     ipmi_fru_t         *nfru;
826     int                rv;
827     ipmi_domain_attr_t *attr;
828     locked_list_t      *frul;
829 
830     rv = ipmi_domain_register_attribute(domain, IPMI_FRU_ATTR_NAME,
831 					fru_attr_init,
832 					fru_attr_destroy,
833 					NULL,
834 					&attr);
835     if (rv)
836 	return rv;
837     frul = ipmi_domain_attr_get_data(attr);
838 
839     /* Be careful with locking, a FRU fetch is already going on when
840        the alloc_internal function returns. */
841     locked_list_lock(frul);
842     rv = ipmi_fru_alloc_internal(domain, is_logical, device_address,
843 				 device_id, lun, private_bus, channel,
844 				 IPMI_FRU_ALL_AREA_MASK,
845 				 fetched_handler, fetched_cb_data, &nfru);
846     if (rv) {
847 	ipmi_domain_attr_put(attr);
848 	locked_list_unlock(frul);
849 	return rv;
850     }
851 
852     nfru->in_frulist = 1;
853 
854     if (! locked_list_add_nolock(frul, nfru, NULL)) {
855 	locked_list_unlock(frul);
856 	nfru->fetched_handler = NULL;
857 	ipmi_fru_destroy(nfru, NULL, NULL);
858 	ipmi_domain_attr_put(attr);
859 	return ENOMEM;
860     }
861     i_ipmi_fru_unlock(nfru);
862     locked_list_unlock(frul);
863     ipmi_domain_attr_put(attr);
864 
865     if (new_fru)
866 	*new_fru = nfru;
867     return 0;
868 }
869 
870 int
ipmi_fru_alloc_notrack(ipmi_domain_t * domain,unsigned char is_logical,unsigned char device_address,unsigned char device_id,unsigned char lun,unsigned char private_bus,unsigned char channel,unsigned char fetch_mask,ipmi_ifru_cb fetched_handler,void * fetched_cb_data,ipmi_fru_t ** new_fru)871 ipmi_fru_alloc_notrack(ipmi_domain_t *domain,
872 		       unsigned char is_logical,
873 		       unsigned char device_address,
874 		       unsigned char device_id,
875 		       unsigned char lun,
876 		       unsigned char private_bus,
877 		       unsigned char channel,
878 		       unsigned char fetch_mask,
879 		       ipmi_ifru_cb  fetched_handler,
880 		       void          *fetched_cb_data,
881 		       ipmi_fru_t    **new_fru)
882 {
883     ipmi_fru_t *nfru;
884     int        rv;
885 
886     rv = ipmi_fru_alloc_internal(domain, is_logical, device_address,
887 				 device_id, lun, private_bus, channel,
888 				 fetch_mask, NULL, NULL, &nfru);
889     if (rv)
890 	return rv;
891     nfru->domain_fetched_handler = fetched_handler;
892     nfru->fetched_cb_data = fetched_cb_data;
893     i_ipmi_fru_unlock(nfru);
894 
895     if (new_fru)
896 	*new_fru = nfru;
897     return 0;
898 }
899 
900 /***********************************************************************
901  *
902  * FRU Raw data reading
903  *
904  **********************************************************************/
905 
906 static void
fetch_complete(ipmi_domain_t * domain,ipmi_fru_t * fru,int err)907 fetch_complete(ipmi_domain_t *domain, ipmi_fru_t *fru, int err)
908 {
909     if (!err) {
910 	i_ipmi_fru_unlock(fru);
911 	err = fru_call_decoders(fru);
912 	if (err) {
913 	    ipmi_log(IPMI_LOG_ERR_INFO,
914 		     "%sfru.c(fetch_complete):"
915 		     " Unable to decode FRU information",
916 		     i_ipmi_fru_get_iname(fru));
917 	}
918 	i_ipmi_fru_lock(fru);
919     }
920 
921     if (fru->data)
922 	ipmi_mem_free(fru->data);
923     fru->data = NULL;
924     fru->in_use = 0;
925     i_ipmi_fru_unlock(fru);
926 
927     if (fru->fetched_handler)
928 	fru->fetched_handler(fru, err, fru->fetched_cb_data);
929     else if (fru->domain_fetched_handler)
930 	fru->domain_fetched_handler(domain, fru, err, fru->fetched_cb_data);
931 
932     fru_put(fru);
933 }
934 
935 static int request_next_data(ipmi_domain_t *domain,
936 			     ipmi_fru_t    *fru,
937 			     ipmi_addr_t   *addr,
938 			     unsigned int  addr_len);
939 
940 static void
end_fru_fetch(ipmi_fru_t * fru,ipmi_domain_t * domain,int err,uint32_t timestamp)941 end_fru_fetch(ipmi_fru_t    *fru,
942 	      ipmi_domain_t *domain,
943 	      int           err,
944 	      uint32_t      timestamp)
945 {
946     int rv;
947 
948     i_ipmi_fru_lock(fru);
949     if (fru->deleted) {
950 	fetch_complete(domain, fru, ECANCELED);
951 	goto out;
952     }
953 
954     if (err) {
955 	fetch_complete(domain, fru, err);
956 	goto out;
957     }
958 
959     if (fru->last_timestamp != timestamp) {
960 	fru->fetch_retries++;
961 	if (fru->fetch_retries > MAX_FRU_FETCH_RETRIES)
962 	    fetch_complete(domain, fru, EAGAIN);
963 	else {
964 	    ipmi_mem_free(fru->data);
965 	    fru->data = NULL;
966 	    i_ipmi_fru_unlock(fru);
967 	    fru->last_timestamp = timestamp;
968 	    rv = start_fru_fetch(fru, domain);
969 	    if (rv)
970 		fetch_complete(domain, fru, rv);
971 	}
972     } else
973 	fetch_complete(domain, fru, 0);
974 
975  out:
976     return;
977 }
978 
979 static int
fru_data_handler(ipmi_domain_t * domain,ipmi_msgi_t * rspi)980 fru_data_handler(ipmi_domain_t *domain, ipmi_msgi_t *rspi)
981 {
982     ipmi_addr_t   *addr = &rspi->addr;
983     unsigned int  addr_len = rspi->addr_len;
984     ipmi_msg_t    *msg = &rspi->msg;
985     ipmi_fru_t    *fru = rspi->data1;
986     unsigned char *data = msg->data;
987     int           count;
988     int           err;
989 
990     i_ipmi_fru_lock(fru);
991 
992     if (fru->deleted) {
993 	fetch_complete(domain, fru, ECANCELED);
994 	goto out;
995     }
996 
997     /* The timeout and unknown errors should not be necessary, but
998        some broken systems just don't return anything if the response
999        is too big. */
1000     if (((data[0] == IPMI_CANNOT_RETURN_REQ_LENGTH_CC)
1001 	 || (data[0] == IPMI_REQUESTED_DATA_LENGTH_EXCEEDED_CC)
1002 	 || (data[0] == IPMI_REQUEST_DATA_LENGTH_INVALID_CC)
1003 	 || (data[0] == IPMI_TIMEOUT_CC)
1004 	 || (data[0] == IPMI_UNKNOWN_ERR_CC))
1005 	&& (fru->fetch_size > MIN_FRU_DATA_FETCH))
1006     {
1007 	/* System couldn't support the given size, try decreasing and
1008 	   starting again. */
1009 	fru->fetch_size -= FRU_DATA_FETCH_DECR;
1010 	err = request_next_data(domain, fru, addr, addr_len);
1011 	if (err) {
1012 	    ipmi_log(IPMI_LOG_ERR_INFO,
1013 		     "%sfru.c(fru_data_handler): "
1014 		     "Error requesting next FRU data (2)",
1015 		     FRU_DOMAIN_NAME(fru));
1016 	    fetch_complete(domain, fru, err);
1017 	    goto out;
1018 	}
1019 	goto out_unlock;
1020     }
1021 
1022     if (data[0] != 0) {
1023 	if (fru->curr_pos >= 8) {
1024 	    /* Some screwy cards give more size in the info than they
1025 	       really have, if we have enough, try to process it. */
1026 	    ipmi_log(IPMI_LOG_WARNING,
1027 		     "%sfru.c(fru_data_handler): "
1028 		     "IPMI error getting FRU data: %x",
1029 		     FRU_DOMAIN_NAME(fru), data[0]);
1030 	    fru->data_len = fru->curr_pos;
1031 	    if (fru->timestamp_cb) {
1032 		err = fru->timestamp_cb(fru, domain, end_fru_fetch);
1033 		if (err)
1034 		    fetch_complete(domain, fru, err);
1035 		else
1036 		    goto out_unlock;
1037 	    } else {
1038 		fetch_complete(domain, fru, 0);
1039 	    }
1040 	} else {
1041 	    ipmi_log(IPMI_LOG_ERR_INFO,
1042 		     "%sfru.c(fru_data_handler): "
1043 		     "IPMI error getting FRU data: %x",
1044 		     FRU_DOMAIN_NAME(fru), data[0]);
1045 	    fetch_complete(domain, fru, IPMI_IPMI_ERR_VAL(data[0]));
1046 	}
1047 	goto out;
1048     }
1049 
1050     if (msg->data_len < 2) {
1051 	ipmi_log(IPMI_LOG_ERR_INFO,
1052 		 "%sfru.c(fru_data_handler): "
1053 		 "FRU data response too small",
1054 		 FRU_DOMAIN_NAME(fru));
1055 	fetch_complete(domain, fru, EINVAL);
1056 	goto out;
1057     }
1058 
1059     count = data[1] << fru->access_by_words;
1060 
1061     if (count == 0) {
1062 	ipmi_log(IPMI_LOG_ERR_INFO,
1063 		 "%sfru.c(fru_data_handler): "
1064 		 "FRU got zero-sized data, must make progress!",
1065 		 FRU_DOMAIN_NAME(fru));
1066 	fetch_complete(domain, fru, EINVAL);
1067 	goto out;
1068     }
1069 
1070     if (count > msg->data_len-2) {
1071 	ipmi_log(IPMI_LOG_ERR_INFO,
1072 		 "%sfru.c(fru_data_handler): "
1073 		 "FRU data count mismatch",
1074 		 FRU_DOMAIN_NAME(fru));
1075 	fetch_complete(domain, fru, EINVAL);
1076 	goto out;
1077     }
1078 
1079     memcpy(fru->data+fru->curr_pos, data+2, count);
1080     fru->curr_pos += count;
1081 
1082     if (fru->curr_pos < fru->data_len) {
1083 	/* More to fetch. */
1084 	err = request_next_data(domain, fru, addr, addr_len);
1085 	if (err) {
1086 	    ipmi_log(IPMI_LOG_ERR_INFO,
1087 		     "%sfru.c(fru_data_handler): "
1088 		     "Error requesting next FRU data",
1089 		     FRU_DOMAIN_NAME(fru));
1090 	    fetch_complete(domain, fru, err);
1091 	    goto out;
1092 	}
1093     } else {
1094 	if (fru->timestamp_cb) {
1095 	    err = fru->timestamp_cb(fru, domain, end_fru_fetch);
1096 	    if (err) {
1097 		fetch_complete(domain, fru, err);
1098 		goto out;
1099 	    }
1100 	} else {
1101 	    fetch_complete(domain, fru, 0);
1102 	    goto out;
1103 	}
1104     }
1105 
1106  out_unlock:
1107     i_ipmi_fru_unlock(fru);
1108  out:
1109     return IPMI_MSG_ITEM_NOT_USED;
1110 }
1111 
1112 static int
request_next_data(ipmi_domain_t * domain,ipmi_fru_t * fru,ipmi_addr_t * addr,unsigned int addr_len)1113 request_next_data(ipmi_domain_t *domain,
1114 		  ipmi_fru_t    *fru,
1115 		  ipmi_addr_t   *addr,
1116 		  unsigned int  addr_len)
1117 {
1118     unsigned char cmd_data[4];
1119     ipmi_msg_t    msg;
1120     int           to_read;
1121 
1122     /* We only request as much as we have to.  Don't always reqeust
1123        the maximum amount, some machines don't like this. */
1124     to_read = fru->data_len - fru->curr_pos;
1125     if (to_read > fru->fetch_size)
1126 	to_read = fru->fetch_size;
1127 
1128     cmd_data[0] = fru->device_id;
1129     ipmi_set_uint16(cmd_data+1, fru->curr_pos >> fru->access_by_words);
1130     cmd_data[3] = to_read >> fru->access_by_words;
1131     msg.netfn = IPMI_STORAGE_NETFN;
1132     msg.cmd = IPMI_READ_FRU_DATA_CMD;
1133     msg.data = cmd_data;
1134     msg.data_len = 4;
1135 
1136     return ipmi_send_command_addr(domain,
1137 				  addr, addr_len,
1138 				  &msg,
1139 				  fru_data_handler,
1140 				  fru,
1141 				  NULL);
1142 }
1143 
1144 static int
fru_inventory_area_handler(ipmi_domain_t * domain,ipmi_msgi_t * rspi)1145 fru_inventory_area_handler(ipmi_domain_t *domain, ipmi_msgi_t *rspi)
1146 {
1147     ipmi_addr_t   *addr = &rspi->addr;
1148     unsigned int  addr_len = rspi->addr_len;
1149     ipmi_msg_t    *msg = &rspi->msg;
1150     ipmi_fru_t    *fru = rspi->data1;
1151     unsigned char *data = msg->data;
1152     int           err;
1153 
1154     i_ipmi_fru_lock(fru);
1155 
1156     if (fru->deleted) {
1157 	fetch_complete(domain, fru, ECANCELED);
1158 	goto out;
1159     }
1160 
1161     if (data[0] != 0) {
1162 	ipmi_log(IPMI_LOG_ERR_INFO,
1163 		 "%sfru.c(fru_inventory_area_handler): "
1164 		 "IPMI error getting FRU inventory area: %x",
1165 		 FRU_DOMAIN_NAME(fru), data[0]);
1166 	fetch_complete(domain, fru, IPMI_IPMI_ERR_VAL(data[0]));
1167 	goto out;
1168     }
1169 
1170     if (msg->data_len < 4) {
1171 	ipmi_log(IPMI_LOG_ERR_INFO,
1172 		 "%sfru.c(fru_inventory_area_handler): "
1173 		 "FRU inventory area too small",
1174 		 FRU_DOMAIN_NAME(fru));
1175 	fetch_complete(domain, fru, EINVAL);
1176 	goto out;
1177     }
1178 
1179     fru->data_len = ipmi_get_uint16(data+1);
1180     fru->access_by_words = data[3] & 1;
1181 
1182     if (fru->data_len < 8) {
1183 	ipmi_log(IPMI_LOG_ERR_INFO,
1184 		 "%sfru.c(fru_inventory_area_handler): "
1185 		 "FRU space less than the header",
1186 		 FRU_DOMAIN_NAME(fru));
1187 	fetch_complete(domain, fru, EMSGSIZE);
1188 	goto out;
1189     }
1190 
1191     fru->data = ipmi_mem_alloc(fru->data_len);
1192     if (!fru->data) {
1193 	ipmi_log(IPMI_LOG_ERR_INFO,
1194 		 "%sfru.c(fru_inventory_area_handler): "
1195 		 "Error allocating FRU data",
1196 		 FRU_DOMAIN_NAME(fru));
1197 	fetch_complete(domain, fru, ENOMEM);
1198 	goto out;
1199     }
1200 
1201     err = request_next_data(domain, fru, addr, addr_len);
1202     if (err) {
1203 	ipmi_log(IPMI_LOG_ERR_INFO,
1204 		 "%sfru.c(fru_inventory_area_handler): "
1205 		 "Error requesting next FRU data",
1206 		 FRU_DOMAIN_NAME(fru));
1207 	fetch_complete(domain, fru, err);
1208 	goto out;
1209     }
1210 
1211     i_ipmi_fru_unlock(fru);
1212  out:
1213     return IPMI_MSG_ITEM_NOT_USED;
1214 }
1215 
1216 static int
start_logical_fru_fetch(ipmi_domain_t * domain,ipmi_fru_t * fru)1217 start_logical_fru_fetch(ipmi_domain_t *domain, ipmi_fru_t *fru)
1218 {
1219     unsigned char    cmd_data[1];
1220     ipmi_msg_t       msg;
1221 
1222     cmd_data[0] = fru->device_id;
1223     msg.netfn = IPMI_STORAGE_NETFN;
1224     msg.cmd = IPMI_GET_FRU_INVENTORY_AREA_INFO_CMD;
1225     msg.data = cmd_data;
1226     msg.data_len = 1;
1227 
1228     return ipmi_send_command_addr(domain,
1229 				  &fru->addr, fru->addr_len,
1230 				  &msg,
1231 				  fru_inventory_area_handler,
1232 				  fru,
1233 				  NULL);
1234 }
1235 
1236 static int
start_physical_fru_fetch(ipmi_domain_t * domain,ipmi_fru_t * fru)1237 start_physical_fru_fetch(ipmi_domain_t *domain, ipmi_fru_t *fru)
1238 {
1239     /* FIXME - this is going to suck, but needs to be implemented. */
1240     return ENOSYS;
1241 }
1242 
1243 /***********************************************************************
1244  *
1245  * FRU writing
1246  *
1247  **********************************************************************/
1248 
1249 int
i_ipmi_fru_new_update_record(ipmi_fru_t * fru,unsigned int offset,unsigned int length)1250 i_ipmi_fru_new_update_record(ipmi_fru_t   *fru,
1251 			     unsigned int offset,
1252 			     unsigned int length)
1253 {
1254     fru_update_t *urec;
1255 
1256     if (length == 0) {
1257 	ipmi_log(IPMI_LOG_WARNING,
1258 		 "fru.c(i_ipmi_fru_new_update_record): "
1259 		 "zero-length update record written");
1260 	return 0;
1261     }
1262     urec = ipmi_mem_alloc(sizeof(*urec));
1263     if (!urec)
1264 	return ENOMEM;
1265     if (fru->access_by_words) {
1266 	/* This handles the (really stupid) word access mode.  If the
1267 	   address is odd, back it up one.  If the length is odd,
1268 	   increment by one. */
1269 	if (offset & 1) {
1270 	    offset -= 1;
1271 	    length += 1;
1272 	}
1273 	urec->offset = offset;
1274 	if (length & 1) {
1275 	    length += 1;
1276 	}
1277 	urec->length = length;
1278     } else {
1279 	urec->offset = offset;
1280 	urec->length = length;
1281     }
1282     urec->next = NULL;
1283     if (fru->update_recs)
1284 	fru->update_recs_tail->next = urec;
1285     else
1286 	fru->update_recs = urec;
1287     fru->update_recs_tail = urec;
1288     return 0;
1289 }
1290 
1291 static int next_fru_write(ipmi_domain_t *domain, ipmi_fru_t *fru);
1292 void write_complete(ipmi_domain_t *domain, ipmi_fru_t *fru, int err);
1293 
1294 void
write_complete2(ipmi_fru_t * fru,ipmi_domain_t * domain,int err)1295 write_complete2(ipmi_fru_t *fru, ipmi_domain_t *domain, int err)
1296 {
1297     i_ipmi_fru_lock(fru);
1298     write_complete(domain, fru, err);
1299 }
1300 
1301 void
write_complete(ipmi_domain_t * domain,ipmi_fru_t * fru,int err)1302 write_complete(ipmi_domain_t *domain, ipmi_fru_t *fru, int err)
1303 {
1304     if (domain && fru->write_prepared) {
1305 	fru->saved_err = err;
1306 	fru->write_prepared = 0;
1307 	err = fru->complete_write_cb(fru, domain, err, fru->last_timestamp,
1308 				     write_complete2);
1309 	if (!err) {
1310 	    i_ipmi_fru_unlock(fru);
1311 	    return;
1312 	}
1313     }
1314 
1315     if (fru->saved_err) {
1316 	err = fru->saved_err;
1317 	fru->saved_err = 0;
1318     }
1319 
1320     if (!err) {
1321 	/* If we succeed, set everything unchanged. */
1322 	if (fru->ops.write_complete)
1323 	    fru->ops.write_complete(fru);
1324     }
1325     if (fru->data)
1326 	ipmi_mem_free(fru->data);
1327     fru->data = NULL;
1328 
1329     fru->in_use = 0;
1330     i_ipmi_fru_unlock(fru);
1331 
1332     if (fru->domain_fetched_handler)
1333 	fru->domain_fetched_handler(domain, fru, err, fru->fetched_cb_data);
1334 
1335     fru_put(fru);
1336 }
1337 
1338 static void
fru_write_handler(ipmi_fru_t * fru,ipmi_domain_t * domain,int err)1339 fru_write_handler(ipmi_fru_t    *fru,
1340 		  ipmi_domain_t *domain,
1341 		  int           err)
1342 {
1343     int rv;
1344 
1345     i_ipmi_fru_lock(fru);
1346 
1347     /* Note that for safety, we do not stop a fru write on deletion. */
1348 
1349     if (err == IPMI_IPMI_ERR_VAL(0x81)) {
1350 	/* Got a busy response.  Try again if we haven't run out of
1351 	   retries. */
1352 	if (fru->retry_count >= MAX_FRU_WRITE_RETRIES) {
1353 	    write_complete(domain, fru, err);
1354 	    goto out;
1355 	}
1356 	fru->retry_count++;
1357 	goto retry_write;
1358     } else if (err) {
1359 	ipmi_log(IPMI_LOG_ERR_INFO,
1360 		 "%sfru.c(fru_write_handler): "
1361 		 "IPMI error writing FRU data: %x",
1362 		 FRU_DOMAIN_NAME(fru), err);
1363 	write_complete(domain, fru, err);
1364 	goto out;
1365     }
1366 
1367     fru->update_recs->length -= fru->curr_write_len;
1368     if (fru->update_recs->length > 0) {
1369 	fru->update_recs->offset += fru->curr_write_len;
1370     } else {
1371 	fru_update_t *to_free = fru->update_recs;
1372 	fru->update_recs = to_free->next;
1373 	ipmi_mem_free(to_free);
1374     }
1375 
1376  retry_write:
1377     if (fru->update_recs) {
1378 	/* More to do. */
1379 	rv = next_fru_write(domain, fru);
1380 	if (rv) {
1381 	    write_complete(domain, fru, rv);
1382 	    goto out;
1383 	}
1384     } else {
1385 	write_complete(domain, fru, 0);
1386 	goto out;
1387     }
1388 
1389     i_ipmi_fru_unlock(fru);
1390  out:
1391     return;
1392 }
1393 
1394 static int
next_fru_write(ipmi_domain_t * domain,ipmi_fru_t * fru)1395 next_fru_write(ipmi_domain_t *domain, ipmi_fru_t *fru)
1396 {
1397     unsigned char data[MAX_FRU_DATA_WRITE+4];
1398     int           offset, length = 0, left, noff, tlen;
1399 
1400     noff = fru->update_recs->offset;
1401     offset = noff;
1402     left = MAX_FRU_DATA_WRITE;
1403     while (fru->update_recs
1404 	   && (left > 0)
1405 	   && (noff == fru->update_recs->offset))
1406     {
1407 	if (left < fru->update_recs->length)
1408 	    tlen = left;
1409 	else
1410 	    tlen = fru->update_recs->length;
1411 
1412 	noff += tlen;
1413 	length += tlen;
1414 	left -= tlen;
1415 	fru->curr_write_len = tlen;
1416     }
1417 
1418     fru->retry_count = 0;
1419     data[0] = fru->device_id;
1420     ipmi_set_uint16(data+1, offset >> fru->access_by_words);
1421     memcpy(data+3, fru->data+offset, length);
1422     fru->last_cmd_len = length + 3;
1423     return fru->write_cb(fru, domain, data, length+3, fru_write_handler);
1424 }
1425 
1426 static void
fru_write_timestamp_done(ipmi_fru_t * fru,ipmi_domain_t * domain,int err,uint32_t timestamp)1427 fru_write_timestamp_done(ipmi_fru_t    *fru,
1428 			 ipmi_domain_t *domain,
1429 			 int           err,
1430 			 uint32_t      timestamp)
1431 {
1432     int rv;
1433 
1434     i_ipmi_fru_lock(fru);
1435 
1436     if (fru->deleted) {
1437 	write_complete(domain, fru, ECANCELED);
1438 	goto out;
1439     }
1440 
1441     if (err) {
1442 	write_complete(domain, fru, err);
1443 	goto out;
1444     }
1445 
1446     rv = next_fru_write(domain, fru);
1447     if (rv) {
1448 	write_complete(domain, fru, rv);
1449 	goto out;
1450     }
1451     i_ipmi_fru_unlock(fru);
1452 
1453  out:
1454     return;
1455 }
1456 
1457 static void
fru_write_start_timestamp_check(ipmi_fru_t * fru,ipmi_domain_t * domain,int err)1458 fru_write_start_timestamp_check(ipmi_fru_t    *fru,
1459 				ipmi_domain_t *domain,
1460 				int           err)
1461 {
1462     int rv;
1463 
1464     i_ipmi_fru_lock(fru);
1465 
1466     if (fru->deleted) {
1467 	write_complete(domain, fru, ECANCELED);
1468 	goto out;
1469     }
1470 
1471     if (err) {
1472 	write_complete(domain, fru, err);
1473 	goto out;
1474     }
1475 
1476     fru->write_prepared = 1;
1477 
1478     if (fru->timestamp_cb)
1479 	rv = fru->timestamp_cb(fru, domain, fru_write_timestamp_done);
1480     else
1481 	rv = next_fru_write(domain, fru);
1482     if (rv) {
1483 	write_complete(domain, fru, rv);
1484 	goto out;
1485     }
1486     i_ipmi_fru_unlock(fru);
1487 
1488  out:
1489     return;
1490 }
1491 
1492 typedef struct start_domain_fru_write_s
1493 {
1494     ipmi_fru_t *fru;
1495     int        rv;
1496 } start_domain_fru_write_t;
1497 
1498 void
start_domain_fru_write(ipmi_domain_t * domain,void * cb_data)1499 start_domain_fru_write(ipmi_domain_t *domain, void *cb_data)
1500 {
1501     start_domain_fru_write_t *info = cb_data;
1502     ipmi_fru_t               *fru = info->fru;
1503 
1504 
1505     /* We allocate and format the entire FRU data.  We do this because
1506        of the stupid word access capability, which means we cannot
1507        necessarily do byte-aligned writes.  Because of that, we might
1508        have to have the byte before or after the actual one being
1509        written, and it may come from a different data field. */
1510     fru->data = ipmi_mem_alloc(fru->data_len);
1511     if (!fru->data) {
1512 	info->rv = ENOMEM;
1513 	goto out_unlock;
1514     }
1515     memset(fru->data, 0, fru->data_len);
1516 
1517     info->rv = fru->ops.write(fru);
1518     if (info->rv)
1519 	goto out_unlock;
1520 
1521     if (!fru->update_recs) {
1522 	/* No data changed, no write is needed. */
1523 	ipmi_mem_free(fru->data);
1524 	fru->data = NULL;
1525 	fru->in_use = 0;
1526 	i_ipmi_fru_unlock(fru);
1527 
1528 	if (fru->domain_fetched_handler)
1529 	    fru->domain_fetched_handler(domain, fru, 0, fru->fetched_cb_data);
1530 	return;
1531     }
1532 
1533     fru_get(fru);
1534     fru->write_prepared = 0;
1535 
1536     if (fru->prepare_write_cb)
1537 	info->rv = fru->prepare_write_cb(fru, domain, fru->last_timestamp,
1538 					 fru_write_start_timestamp_check);
1539     else if (fru->timestamp_cb)
1540 	info->rv = fru->timestamp_cb(fru, domain, fru_write_timestamp_done);
1541     else
1542 	info->rv = next_fru_write(domain, fru);
1543 
1544     if (info->rv)
1545 	fru_put(fru);
1546 
1547  out_unlock:
1548     if (info->rv) {
1549 	if (fru->data) {
1550 	    ipmi_mem_free(fru->data);
1551 	    fru->data = NULL;
1552 	}
1553 	fru->in_use = 0;
1554     }
1555     i_ipmi_fru_unlock(fru);
1556 }
1557 
1558 int
ipmi_fru_write(ipmi_fru_t * fru,ipmi_fru_cb done,void * cb_data)1559 ipmi_fru_write(ipmi_fru_t *fru, ipmi_fru_cb done, void *cb_data)
1560 {
1561     int                      rv;
1562     start_domain_fru_write_t info = {fru, 0};
1563 
1564     if (!fru->ops.write)
1565 	return ENOSYS;
1566 
1567     i_ipmi_fru_lock(fru);
1568     if (fru->in_use) {
1569 	/* Something else is happening with the FRU, error this
1570 	   operation. */
1571 	i_ipmi_fru_unlock(fru);
1572 	return EAGAIN;
1573     }
1574 
1575     fru->in_use = 1;
1576 
1577     fru->domain_fetched_handler = done;
1578     fru->fetched_cb_data = cb_data;
1579 
1580     /* Data is fully encoded and the update records are in place.
1581        Start the write process. */
1582     rv = ipmi_domain_pointer_cb(fru->domain_id, start_domain_fru_write, &info);
1583     if (!rv)
1584 	rv = info.rv;
1585     else {
1586 	fru->in_use = 0;
1587 	i_ipmi_fru_unlock(fru);
1588     }
1589 
1590     return rv;
1591 
1592 }
1593 
1594 /***********************************************************************
1595  *
1596  * Misc stuff.
1597  *
1598  **********************************************************************/
1599 ipmi_domain_id_t
ipmi_fru_get_domain_id(ipmi_fru_t * fru)1600 ipmi_fru_get_domain_id(ipmi_fru_t *fru)
1601 {
1602     return fru->domain_id;
1603 }
1604 
1605 void
ipmi_fru_data_free(char * data)1606 ipmi_fru_data_free(char *data)
1607 {
1608     ipmi_mem_free(data);
1609 }
1610 
1611 unsigned int
ipmi_fru_get_data_length(ipmi_fru_t * fru)1612 ipmi_fru_get_data_length(ipmi_fru_t *fru)
1613 {
1614     return fru->data_len;
1615 }
1616 
1617 int
ipmi_fru_get_name(ipmi_fru_t * fru,char * name,int length)1618 ipmi_fru_get_name(ipmi_fru_t *fru, char *name, int length)
1619 {
1620     int  slen;
1621 
1622     if (length <= 0)
1623 	return 0;
1624 
1625     /* Never changes, no lock needed. */
1626     slen = strlen(fru->name);
1627     if (slen == 0) {
1628 	if (name)
1629 	    *name = '\0';
1630 	goto out;
1631     }
1632 
1633     if (name) {
1634 	memcpy(name, fru->name, slen);
1635 	name[slen] = '\0';
1636     }
1637  out:
1638     return slen;
1639 }
1640 
1641 typedef struct iterate_frus_info_s
1642 {
1643     ipmi_fru_ptr_cb handler;
1644     void            *cb_data;
1645 } iterate_frus_info_t;
1646 
1647 static int
frus_handler(void * cb_data,void * item1,void * item2)1648 frus_handler(void *cb_data, void *item1, void *item2)
1649 {
1650     iterate_frus_info_t *info = cb_data;
1651     info->handler(item1, info->cb_data);
1652     fru_put(item1);
1653     return LOCKED_LIST_ITER_CONTINUE;
1654 }
1655 
1656 static int
frus_prefunc(void * cb_data,void * item1,void * item2)1657 frus_prefunc(void *cb_data, void *item1, void *item2)
1658 {
1659     ipmi_fru_t *fru = item1;
1660     ipmi_lock(fru->lock);
1661     fru_get(fru);
1662     ipmi_unlock(fru->lock);
1663     return LOCKED_LIST_ITER_CONTINUE;
1664 }
1665 
1666 void
ipmi_fru_iterate_frus(ipmi_domain_t * domain,ipmi_fru_ptr_cb handler,void * cb_data)1667 ipmi_fru_iterate_frus(ipmi_domain_t   *domain,
1668 		      ipmi_fru_ptr_cb handler,
1669 		      void            *cb_data)
1670 {
1671     iterate_frus_info_t info;
1672     ipmi_domain_attr_t  *attr;
1673     locked_list_t       *frus;
1674     int                 rv;
1675 
1676     rv = ipmi_domain_find_attribute(domain, IPMI_FRU_ATTR_NAME,
1677 				    &attr);
1678     if (rv)
1679 	return;
1680     frus = ipmi_domain_attr_get_data(attr);
1681 
1682     info.handler = handler;
1683     info.cb_data = cb_data;
1684     locked_list_iterate_prefunc(frus, frus_prefunc, frus_handler, &info);
1685     ipmi_domain_attr_put(attr);
1686 }
1687 
1688 /************************************************************************
1689  *
1690  * FRU node handling
1691  *
1692  ************************************************************************/
1693 
1694 int
ipmi_fru_get_root_node(ipmi_fru_t * fru,const char ** name,ipmi_fru_node_t ** node)1695 ipmi_fru_get_root_node(ipmi_fru_t      *fru,
1696 		       const char      **name,
1697 		       ipmi_fru_node_t **node)
1698 {
1699     if (!fru->ops.get_root_node)
1700 	return ENOSYS;
1701     return fru->ops.get_root_node(fru, name, node);
1702 }
1703 
1704 struct ipmi_fru_node_s
1705 {
1706     ipmi_lock_t                    *lock;
1707     unsigned int                   refcount;
1708 
1709     void                           *data;
1710     void                           *data2;
1711     ipmi_fru_oem_node_get_field_cb get_field;
1712     ipmi_fru_oem_node_set_field_cb set_field;
1713     ipmi_fru_oem_node_settable_cb  settable;
1714     ipmi_fru_oem_node_subtype_cb   get_subtype;
1715     ipmi_fru_oem_node_enum_val_cb  get_enum;
1716     ipmi_fru_oem_node_cb           destroy;
1717 };
1718 
1719 ipmi_fru_node_t *
i_ipmi_fru_node_alloc(ipmi_fru_t * fru)1720 i_ipmi_fru_node_alloc(ipmi_fru_t *fru)
1721 {
1722     ipmi_fru_node_t *node = ipmi_mem_alloc(sizeof(*node));
1723     int             rv;
1724 
1725     if (!node)
1726 	return NULL;
1727     memset(node, 0, sizeof(*node));
1728 
1729     rv = ipmi_create_lock_os_hnd(fru->os_hnd, &node->lock);
1730     if (rv) {
1731 	ipmi_mem_free(node);
1732 	return NULL;
1733     }
1734 
1735     node->refcount = 1;
1736     return node;
1737 }
1738 
1739 void
ipmi_fru_get_node(ipmi_fru_node_t * node)1740 ipmi_fru_get_node(ipmi_fru_node_t *node)
1741 {
1742     ipmi_lock(node->lock);
1743     node->refcount++;
1744     ipmi_unlock(node->lock);
1745 }
1746 
1747 void
ipmi_fru_put_node(ipmi_fru_node_t * node)1748 ipmi_fru_put_node(ipmi_fru_node_t *node)
1749 {
1750     ipmi_lock(node->lock);
1751     if (node->refcount > 1) {
1752 	node->refcount--;
1753 	ipmi_unlock(node->lock);
1754 	return;
1755     }
1756     ipmi_unlock(node->lock);
1757 
1758     if (node->destroy)
1759 	node->destroy(node);
1760     ipmi_destroy_lock(node->lock);
1761     ipmi_mem_free(node);
1762 }
1763 
1764 int
ipmi_fru_node_get_field(ipmi_fru_node_t * node,unsigned int index,const char ** name,enum ipmi_fru_data_type_e * dtype,int * intval,time_t * time,double * floatval,char ** data,unsigned int * data_len,ipmi_fru_node_t ** sub_node)1765 ipmi_fru_node_get_field(ipmi_fru_node_t           *node,
1766 			unsigned int              index,
1767 			const char                **name,
1768 			enum ipmi_fru_data_type_e *dtype,
1769 			int                       *intval,
1770 			time_t                    *time,
1771 			double                    *floatval,
1772 			char                      **data,
1773 			unsigned int              *data_len,
1774 			ipmi_fru_node_t           **sub_node)
1775 {
1776     return node->get_field(node, index, name, dtype, intval, time,
1777 			   floatval, data, data_len, sub_node);
1778 }
1779 
1780 int
ipmi_fru_node_set_field(ipmi_fru_node_t * node,unsigned int index,enum ipmi_fru_data_type_e dtype,int intval,time_t time,double floatval,char * data,unsigned int data_len)1781 ipmi_fru_node_set_field(ipmi_fru_node_t           *node,
1782 			unsigned int              index,
1783 			enum ipmi_fru_data_type_e dtype,
1784 			int                       intval,
1785 			time_t                    time,
1786 			double                    floatval,
1787 			char                      *data,
1788 			unsigned int              data_len)
1789 {
1790     if (!node->set_field)
1791 	return ENOSYS;
1792     return node->set_field(node, index, dtype, intval, time,
1793 			   floatval, data, data_len);
1794 }
1795 
1796 int
ipmi_fru_node_settable(ipmi_fru_node_t * node,unsigned int index)1797 ipmi_fru_node_settable(ipmi_fru_node_t           *node,
1798 		       unsigned int              index)
1799 {
1800     if (!node->set_field)
1801 	return ENOSYS;
1802     if (!node->settable)
1803 	return 0;
1804     return node->settable(node, index);
1805 }
1806 
1807 int
ipmi_fru_node_get_subtype(ipmi_fru_node_t * node,enum ipmi_fru_data_type_e * dtype)1808 ipmi_fru_node_get_subtype(ipmi_fru_node_t           *node,
1809 			  enum ipmi_fru_data_type_e *dtype)
1810 {
1811     if (!node->get_subtype)
1812 	return ENOSYS;
1813     return node->get_subtype(node, dtype);
1814 }
1815 
1816 int
ipmi_fru_node_get_enum_val(ipmi_fru_node_t * node,unsigned int index,int * pos,int * nextpos,const char ** data)1817 ipmi_fru_node_get_enum_val(ipmi_fru_node_t *node,
1818 			   unsigned int    index,
1819 			   int             *pos,
1820 			   int             *nextpos,
1821 			   const char      **data)
1822 {
1823     if (!node->get_enum)
1824 	return ENOSYS;
1825     return node->get_enum(node, index, pos, nextpos, data);
1826 }
1827 
1828 void *
i_ipmi_fru_node_get_data(ipmi_fru_node_t * node)1829 i_ipmi_fru_node_get_data(ipmi_fru_node_t *node)
1830 {
1831     return node->data;
1832 }
1833 
1834 void
i_ipmi_fru_node_set_data(ipmi_fru_node_t * node,void * data)1835 i_ipmi_fru_node_set_data(ipmi_fru_node_t *node, void *data)
1836 {
1837     node->data = data;
1838 }
1839 
1840 void *
i_ipmi_fru_node_get_data2(ipmi_fru_node_t * node)1841 i_ipmi_fru_node_get_data2(ipmi_fru_node_t *node)
1842 {
1843     return node->data2;
1844 }
1845 
1846 void
i_ipmi_fru_node_set_data2(ipmi_fru_node_t * node,void * data2)1847 i_ipmi_fru_node_set_data2(ipmi_fru_node_t *node, void *data2)
1848 {
1849     node->data2 = data2;
1850 }
1851 
1852 void
i_ipmi_fru_node_set_destructor(ipmi_fru_node_t * node,ipmi_fru_oem_node_cb destroy)1853 i_ipmi_fru_node_set_destructor(ipmi_fru_node_t      *node,
1854 			       ipmi_fru_oem_node_cb destroy)
1855 {
1856     node->destroy = destroy;
1857 }
1858 
1859 void
i_ipmi_fru_node_set_get_field(ipmi_fru_node_t * node,ipmi_fru_oem_node_get_field_cb get_field)1860 i_ipmi_fru_node_set_get_field(ipmi_fru_node_t                *node,
1861 			      ipmi_fru_oem_node_get_field_cb get_field)
1862 {
1863     node->get_field = get_field;
1864 }
1865 
1866 void
i_ipmi_fru_node_set_set_field(ipmi_fru_node_t * node,ipmi_fru_oem_node_set_field_cb set_field)1867 i_ipmi_fru_node_set_set_field(ipmi_fru_node_t                *node,
1868 			      ipmi_fru_oem_node_set_field_cb set_field)
1869 {
1870     node->set_field = set_field;
1871 }
1872 
1873 void
i_ipmi_fru_node_set_settable(ipmi_fru_node_t * node,ipmi_fru_oem_node_settable_cb settable)1874 i_ipmi_fru_node_set_settable(ipmi_fru_node_t               *node,
1875 			     ipmi_fru_oem_node_settable_cb settable)
1876 {
1877     node->settable = settable;
1878 }
1879 
1880 void
i_ipmi_fru_node_set_get_subtype(ipmi_fru_node_t * node,ipmi_fru_oem_node_subtype_cb get_subtype)1881 i_ipmi_fru_node_set_get_subtype(ipmi_fru_node_t              *node,
1882 				ipmi_fru_oem_node_subtype_cb get_subtype)
1883 {
1884     node->get_subtype = get_subtype;
1885 }
1886 
1887 void
i_ipmi_fru_node_set_get_enum(ipmi_fru_node_t * node,ipmi_fru_oem_node_enum_val_cb get_enum)1888 i_ipmi_fru_node_set_get_enum(ipmi_fru_node_t               *node,
1889 			     ipmi_fru_oem_node_enum_val_cb get_enum)
1890 {
1891     node->get_enum = get_enum;
1892 }
1893 
1894 
1895 /************************************************************************
1896  *
1897  * Misc external interfaces
1898  *
1899  ************************************************************************/
1900 
1901 void *
i_ipmi_fru_get_rec_data(ipmi_fru_t * fru)1902 i_ipmi_fru_get_rec_data(ipmi_fru_t *fru)
1903 {
1904     return fru->rec_data;
1905 }
1906 
1907 void
i_ipmi_fru_set_rec_data(ipmi_fru_t * fru,void * rec_data)1908 i_ipmi_fru_set_rec_data(ipmi_fru_t *fru, void *rec_data)
1909 {
1910     if (fru->rec_data && fru->ops.cleanup_recs)
1911 	fru->ops.cleanup_recs(fru);
1912     fru->rec_data = rec_data;
1913 }
1914 
1915 char *
i_ipmi_fru_get_iname(ipmi_fru_t * fru)1916 i_ipmi_fru_get_iname(ipmi_fru_t *fru)
1917 {
1918     return FRU_DOMAIN_NAME(fru);
1919 }
1920 
1921 unsigned int
i_ipmi_fru_get_fetch_mask(ipmi_fru_t * fru)1922 i_ipmi_fru_get_fetch_mask(ipmi_fru_t *fru)
1923 {
1924     return fru->fetch_mask;
1925 }
1926 
1927 void *
i_ipmi_fru_get_data_ptr(ipmi_fru_t * fru)1928 i_ipmi_fru_get_data_ptr(ipmi_fru_t *fru)
1929 {
1930     return fru->data;
1931 }
1932 unsigned int
i_ipmi_fru_get_data_len(ipmi_fru_t * fru)1933 i_ipmi_fru_get_data_len(ipmi_fru_t *fru)
1934 {
1935     return fru->data_len;
1936 }
1937 
1938 int
i_ipmi_fru_is_normal_fru(ipmi_fru_t * fru)1939 i_ipmi_fru_is_normal_fru(ipmi_fru_t *fru)
1940 {
1941     return fru->normal_fru;
1942 }
1943 
1944 void
i_ipmi_fru_set_is_normal_fru(ipmi_fru_t * fru,int val)1945 i_ipmi_fru_set_is_normal_fru(ipmi_fru_t *fru, int val)
1946 {
1947     fru->normal_fru = val;
1948 }
1949 
1950 /************************************************************************
1951  *
1952  * Init/shutdown
1953  *
1954  ************************************************************************/
1955 
1956 int
i_ipmi_fru_init(void)1957 i_ipmi_fru_init(void)
1958 {
1959     if (fru_decode_handlers)
1960 	return 0;
1961 
1962     fru_decode_handlers = locked_list_alloc(ipmi_get_global_os_handler());
1963     if (!fru_decode_handlers)
1964 	return ENOMEM;
1965     return 0;
1966 }
1967 
1968 void
i_ipmi_fru_shutdown(void)1969 i_ipmi_fru_shutdown(void)
1970 {
1971     if (fru_decode_handlers) {
1972 	locked_list_destroy(fru_decode_handlers);
1973 	fru_decode_handlers = NULL;
1974     }
1975 }
1976