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