1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <limits.h>
29 #include <alloca.h>
30 #include "fru_access_impl.h"
31
32 #pragma init(initialize_fruaccess) /* .init section */
33
34 static hash_obj_t *hash_table[TABLE_SIZE];
35
36 /*
37 * seeprom is the driver_name for the SEEPROM device drivers in excalibur
38 * Define the devfsadm command to load the seeprom drivers if open fails.
39 */
40
41 static char devfsadm_cmd[] = "/usr/sbin/devfsadm -i seeprom";
42
43 /* this routine initialize the hash table. */
44
45 static void
initialize_fruaccess(void)46 initialize_fruaccess(void)
47 {
48 int count;
49 for (count = 0; count < TABLE_SIZE; count++) {
50 hash_table[count] = NULL;
51 }
52 }
53
54 /*
55 * called to lookup hash object for specified handle in the hash table.
56 *
57 */
58
59 static hash_obj_t *
lookup_handle_object(handle_t handle,int object_type)60 lookup_handle_object(handle_t handle, int object_type)
61 {
62 handle_t index_to_hash;
63 hash_obj_t *first_hash_obj;
64 hash_obj_t *next_hash_obj;
65
66 index_to_hash = (handle % TABLE_SIZE);
67
68 first_hash_obj = hash_table[index_to_hash];
69 for (next_hash_obj = first_hash_obj; next_hash_obj != NULL;
70 next_hash_obj = next_hash_obj->next) {
71 if ((handle == next_hash_obj->obj_hdl) &&
72 (object_type == next_hash_obj->object_type)) {
73 return (next_hash_obj);
74 }
75 }
76 return (NULL);
77 }
78
79 /* called to allocate container hash object */
80
81 static hash_obj_t *
create_container_hash_object(void)82 create_container_hash_object(void)
83 {
84 hash_obj_t *hash_obj;
85 container_obj_t *cont_obj;
86
87 cont_obj = malloc(sizeof (container_obj_t));
88 if (cont_obj == NULL) {
89 return (NULL);
90 }
91
92 hash_obj = malloc(sizeof (hash_obj_t));
93 if (hash_obj == NULL) {
94 free(cont_obj);
95 return (NULL);
96 }
97
98 cont_obj->sec_obj_list = NULL;
99
100 hash_obj->object_type = CONTAINER_TYPE;
101 hash_obj->u.cont_obj = cont_obj;
102 hash_obj->next = NULL;
103 hash_obj->prev = NULL;
104
105 return (hash_obj);
106 }
107
108 /* called to allocate section hash object */
109
110 static hash_obj_t *
create_section_hash_object(void)111 create_section_hash_object(void)
112 {
113 hash_obj_t *hash_obj;
114 section_obj_t *sec_obj;
115
116 sec_obj = malloc(sizeof (section_obj_t));
117 if (sec_obj == NULL) {
118 return (NULL);
119 }
120
121 hash_obj = malloc(sizeof (hash_obj_t));
122 if (hash_obj == NULL) {
123 free(sec_obj);
124 return (NULL);
125 }
126
127 sec_obj->next = NULL;
128 sec_obj->seg_obj_list = NULL;
129
130 hash_obj->u.sec_obj = sec_obj;
131 hash_obj->object_type = SECTION_TYPE;
132 hash_obj->next = NULL;
133 hash_obj->prev = NULL;
134
135 return (hash_obj);
136 }
137
138 /* called to allocate segment hash object */
139
140 static hash_obj_t *
create_segment_hash_object(void)141 create_segment_hash_object(void)
142 {
143 hash_obj_t *hash_obj;
144 segment_obj_t *seg_obj;
145
146 seg_obj = malloc(sizeof (segment_obj_t));
147 if (seg_obj == NULL) {
148 return (NULL);
149 }
150
151 hash_obj = malloc(sizeof (hash_obj_t));
152 if (hash_obj == NULL) {
153 free(seg_obj);
154 return (NULL);
155 }
156
157 seg_obj->next = NULL;
158 seg_obj->pkt_obj_list = NULL;
159
160 hash_obj->object_type = SEGMENT_TYPE;
161 hash_obj->u.seg_obj = seg_obj;
162 hash_obj->next = NULL;
163 hash_obj->prev = NULL;
164
165 return (hash_obj);
166 }
167
168 /* called to allocate packet hash object */
169
170 static hash_obj_t *
create_packet_hash_object(void)171 create_packet_hash_object(void)
172 {
173 hash_obj_t *hash_obj;
174 packet_obj_t *pkt_obj;
175
176 pkt_obj = malloc(sizeof (packet_obj_t));
177 if (pkt_obj == NULL) {
178 return (NULL);
179 }
180
181 hash_obj = malloc(sizeof (hash_obj_t));
182 if (hash_obj == NULL) {
183 free(pkt_obj);
184 return (NULL);
185 }
186
187 pkt_obj->next = NULL;
188
189 hash_obj->object_type = PACKET_TYPE;
190 hash_obj->u.pkt_obj = pkt_obj;
191 hash_obj->next = NULL;
192 hash_obj->prev = NULL;
193
194 return (hash_obj);
195 }
196
197 /* called to add allocated hash object into the hash table */
198
199 static void
add_hashobject_to_hashtable(hash_obj_t * hash_obj)200 add_hashobject_to_hashtable(hash_obj_t *hash_obj)
201 {
202 handle_t index_to_hash;
203 static uint64_t handle_count = 0;
204
205 hash_obj->obj_hdl = ++handle_count; /* store the handle */
206
207 /* where to add ? */
208 index_to_hash = ((hash_obj->obj_hdl) % TABLE_SIZE);
209
210 hash_obj->next = hash_table[index_to_hash];
211 hash_table[index_to_hash] = hash_obj; /* hash obj. added */
212
213 if (hash_obj->next != NULL) {
214 hash_obj->next->prev = hash_obj;
215 }
216 }
217
218 /* called to add section object list into the section list */
219
220 static void
add_to_sec_object_list(hash_obj_t * parent_obj,hash_obj_t * child_obj)221 add_to_sec_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
222 {
223 hash_obj_t *next_hash;
224
225 child_obj->u.sec_obj->cont_hdl = parent_obj->obj_hdl;
226 if (parent_obj->u.cont_obj->sec_obj_list == NULL) {
227 parent_obj->u.cont_obj->sec_obj_list = child_obj;
228 return;
229 }
230
231 for (next_hash = parent_obj->u.cont_obj->sec_obj_list;
232 next_hash->u.sec_obj->next != NULL;
233 next_hash = next_hash->u.sec_obj->next) {
234 ;
235 }
236
237 next_hash->u.sec_obj->next = child_obj;
238 }
239
240 /* called to add segment object list into segment list */
241
242 static void
add_to_seg_object_list(hash_obj_t * parent_obj,hash_obj_t * child_obj)243 add_to_seg_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
244 {
245 hash_obj_t *next_hash;
246
247 child_obj->u.seg_obj->section_hdl = parent_obj->obj_hdl;
248 if (parent_obj->u.sec_obj->seg_obj_list == NULL) {
249 parent_obj->u.sec_obj->seg_obj_list = child_obj;
250 return;
251 }
252
253 for (next_hash = parent_obj->u.sec_obj->seg_obj_list;
254 next_hash->u.seg_obj->next != NULL;
255 next_hash = next_hash->u.seg_obj->next) {
256 ;
257 }
258
259 next_hash->u.seg_obj->next = child_obj;
260 }
261
262 /* called to add packet object list into packet list */
263
264 static void
add_to_pkt_object_list(hash_obj_t * parent_obj,hash_obj_t * child_obj)265 add_to_pkt_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
266 {
267 hash_obj_t *next_hash;
268
269 /* add the packet object in the end of list */
270 child_obj->u.pkt_obj->segment_hdl = parent_obj->obj_hdl;
271
272 if (parent_obj->u.seg_obj->pkt_obj_list == NULL) {
273 parent_obj->u.seg_obj->pkt_obj_list = child_obj;
274 return;
275 }
276
277 for (next_hash = parent_obj->u.seg_obj->pkt_obj_list;
278 next_hash->u.pkt_obj->next != NULL;
279 next_hash = next_hash->u.pkt_obj->next) {
280 ;
281 }
282
283 next_hash->u.pkt_obj->next = child_obj;
284 }
285
286 static void
copy_segment_layout(segment_t * seghdr,void * layout)287 copy_segment_layout(segment_t *seghdr, void *layout)
288 {
289 segment_layout_t *seg_layout;
290
291 seg_layout = (segment_layout_t *)layout;
292 (void) memcpy(seghdr->name, &seg_layout->name, SEG_NAME_LEN);
293 seghdr->descriptor = GET_SEGMENT_DESCRIPTOR;
294 seghdr->offset = seg_layout->offset;
295 seghdr->length = seg_layout->length;
296 }
297
298 static hash_obj_t *
get_container_hash_object(int object_type,handle_t handle)299 get_container_hash_object(int object_type, handle_t handle)
300 {
301 hash_obj_t *hash_obj;
302
303 switch (object_type) {
304 case CONTAINER_TYPE :
305 break;
306 case SECTION_TYPE :
307 hash_obj = lookup_handle_object(handle, CONTAINER_TYPE);
308 if (hash_obj == NULL) {
309 return (NULL);
310 }
311 break;
312 case SEGMENT_TYPE :
313 hash_obj = lookup_handle_object(handle, SECTION_TYPE);
314 if (hash_obj == NULL) {
315 return (NULL);
316 }
317 hash_obj = lookup_handle_object(hash_obj->u.sec_obj->cont_hdl,
318 CONTAINER_TYPE);
319 break;
320 case PACKET_TYPE :
321 break;
322 default :
323 return (NULL);
324 }
325 return (hash_obj);
326 }
327
328
329 static void
sort_offsettbl(int segcnt,seg_info_t * offset_tbl)330 sort_offsettbl(int segcnt, seg_info_t *offset_tbl)
331 {
332 int cntx;
333 int cnty;
334 seg_info_t tmp;
335
336 for (cntx = 0; cntx < segcnt+2; cntx++) {
337 for (cnty = cntx+1; cnty < segcnt + 2; cnty++) {
338 if (offset_tbl[cntx].offset >
339 offset_tbl[cnty].offset) {
340 (void) memcpy(&tmp, &offset_tbl[cnty],
341 sizeof (seg_info_t));
342 (void) memcpy(&offset_tbl[cnty],
343 &offset_tbl[cntx], sizeof (seg_info_t));
344
345 (void) memcpy(&offset_tbl[cntx], &tmp,
346 sizeof (seg_info_t));
347 }
348 }
349 }
350 }
351
352 /*
353 * Description : move_segment_data() reads the segment data and writes it
354 * back to the new segment offset.
355 */
356
357 static void
move_segment_data(void * seghdr,int newoffset,container_hdl_t contfd)358 move_segment_data(void *seghdr, int newoffset, container_hdl_t contfd)
359 {
360 int ret;
361 char *buffer;
362 segment_layout_t *segment;
363
364 segment = (segment_layout_t *)seghdr;
365
366 buffer = alloca(segment->length);
367 if (buffer == NULL) {
368 return;
369 }
370
371 ret = pread(contfd, buffer, segment->length, segment->offset);
372 if (ret != segment->length) {
373 return;
374 }
375
376 segment->offset = newoffset;
377
378 ret = pwrite(contfd, buffer, segment->length, segment->offset);
379 if (ret != segment->length) {
380 return;
381 }
382 }
383
384 /*
385 * Description : pack_segment_data() moves the segment data if there is
386 * a hole between two segments.
387 */
388
389 static void
pack_segment_data(char * seghdr,int segcnt,container_hdl_t contfd,seg_info_t * offset_tbl)390 pack_segment_data(char *seghdr, int segcnt, container_hdl_t contfd,
391 seg_info_t *offset_tbl)
392 {
393 int cnt;
394 int diff;
395 int newoffset;
396
397 for (cnt = segcnt + 1; cnt > 0; cnt--) {
398 if (!offset_tbl[cnt - 1].fixed) {
399 if (offset_tbl[cnt].offset -
400 (offset_tbl[cnt -1 ].offset +
401 offset_tbl[cnt - 1].length) > 0) {
402
403 diff = offset_tbl[cnt].offset -
404 (offset_tbl[cnt - 1].offset +
405 offset_tbl[cnt - 1].length);
406 newoffset = offset_tbl[cnt - 1].offset + diff;
407
408 move_segment_data(seghdr, newoffset, contfd);
409
410 offset_tbl[cnt - 1].offset = newoffset;
411
412 sort_offsettbl(segcnt, offset_tbl);
413 }
414 }
415 }
416 }
417
418 /*
419 * Description : build_offset_tbl() builds the offset table by reading all the
420 * segment header. it makes two more entry into the table one for
421 * section size and another with start of the section after the
422 * segment header.
423 */
424
425 static int
build_offset_tbl(void * seghdr,int segcnt,int secsize,seg_info_t * offset_tbl)426 build_offset_tbl(void *seghdr, int segcnt, int secsize,
427 seg_info_t *offset_tbl)
428 {
429 int cnt;
430 fru_segdesc_t segdesc;
431 segment_layout_t *segment;
432
433 for (cnt = 0; cnt < segcnt; cnt++) {
434 segment = (segment_layout_t *)(seghdr) + cnt;
435
436 (void) memcpy(&segdesc, &segment->descriptor,
437 sizeof (uint32_t));
438 offset_tbl[cnt].segnum = cnt;
439 offset_tbl[cnt].offset = segment->offset;
440 offset_tbl[cnt].length = segment->length;
441 offset_tbl[cnt].fixed = segdesc.field.fixed;
442 }
443
444 /* upper boundary of segment area (lower address bytes) */
445 offset_tbl[cnt].segnum = -1;
446 offset_tbl[cnt].offset = sizeof (section_layout_t) +
447 ((cnt + 1) * sizeof (segment_layout_t));
448
449 offset_tbl[cnt].length = 0;
450 offset_tbl[cnt].fixed = 1;
451 /* lower boundary of segment area (higher address bytes) */
452
453 offset_tbl[cnt+1].segnum = -1;
454 offset_tbl[cnt+1].offset = secsize;
455 offset_tbl[cnt+1].length = 0;
456 offset_tbl[cnt+1].fixed = 1;
457 return (0);
458 }
459
460 static int
hole_discovery(int bytes,int segcnt,int * totsize,seg_info_t * offset_tbl)461 hole_discovery(int bytes, int segcnt, int *totsize, seg_info_t *offset_tbl)
462 {
463 int cnt = 0;
464
465 *totsize = 0;
466 for (cnt = segcnt + 1; cnt > 0; cnt--) {
467 if (bytes <= offset_tbl[cnt].offset -
468 (offset_tbl[cnt - 1].offset +
469 offset_tbl[cnt - 1].length)) {
470 return (offset_tbl[cnt].offset - bytes);
471 }
472
473 *totsize += offset_tbl[cnt].offset -
474 (offset_tbl[cnt - 1].offset + offset_tbl[cnt - 1].length);
475 }
476 return (0);
477 }
478
479
480 /*
481 * Description : segment_hdr_present() verify space for new segment header to
482 * be added.
483 */
484
485 static int
segment_hdr_present(int segoffset,int size,seg_info_t * offset_tbl)486 segment_hdr_present(int segoffset, int size, seg_info_t *offset_tbl)
487 {
488 if ((segoffset + size) <= offset_tbl[0].offset)
489 return (0);
490 else
491 return (-1);
492 }
493
494 /*
495 * Description : find_offset() is called from fru_add_segment routine to find
496 * a valid offset.
497 */
498
499 static int
find_offset(char * seghdr,int segcnt,int secsize,int * sectionoffset,int segsize,int fix,container_hdl_t contfd)500 find_offset(char *seghdr, int segcnt, int secsize, int *sectionoffset,
501 int segsize, int fix, container_hdl_t contfd)
502 {
503 int ret;
504 int newoffset;
505 int totsize = 0;
506 seg_info_t *offset_tbl;
507
508 if (segcnt == 0) {
509 if (!fix) { /* if not fixed segment */
510 *sectionoffset = secsize - segsize;
511 }
512 return (0);
513 }
514
515 /*
516 * two extra segment info structure are allocated for start of segment
517 * and other end of segment. first segment offset is first available
518 * space and length is 0. second segment offset is is segment length and
519 * offset is 0. build_offset_tbl() explains how upper boundary and lower
520 * boudary segment area are initialized in seg_info_t table.
521 */
522
523 offset_tbl = malloc((segcnt + 2) * sizeof (seg_info_t));
524 if (offset_tbl == NULL) {
525 return (-1);
526 }
527
528 /* read all the segment header to make offset table */
529 ret = build_offset_tbl(seghdr, segcnt, secsize, offset_tbl);
530 if (ret != 0) {
531 free(offset_tbl);
532 return (-1);
533 }
534
535 /* sort the table */
536 sort_offsettbl(segcnt, offset_tbl);
537
538 /* new segment header offset */
539 newoffset = sizeof (section_layout_t) + segcnt *
540 sizeof (segment_layout_t);
541
542 /* do? new segment header overlap any existing data */
543 ret = segment_hdr_present(newoffset, sizeof (segment_layout_t),
544 offset_tbl);
545 if (ret != 0) { /* make room for new segment if possible */
546
547 /* look for hole in order to move segment data */
548 if (offset_tbl[0].fixed == SEGMENT_FIXED) { /* fixed segment */
549 free(offset_tbl);
550 return (-1);
551 }
552
553 newoffset = hole_discovery(offset_tbl[0].length, segcnt,
554 &totsize, offset_tbl);
555 if (newoffset != 0) { /* found new offset */
556 /* now new offset */
557 offset_tbl[0].offset = newoffset;
558
559 /* move the segment data */
560 move_segment_data(seghdr, newoffset, contfd);
561 /* again sort the offset table */
562 sort_offsettbl(segcnt, offset_tbl);
563 } else {
564 /* pack the existing hole */
565 if (totsize > offset_tbl[0].length) {
566 pack_segment_data(seghdr, segcnt, contfd,
567 offset_tbl);
568 } else {
569 free(offset_tbl);
570 return (-1);
571 }
572 }
573 }
574
575 totsize = 0;
576 newoffset = hole_discovery(segsize, segcnt, &totsize, offset_tbl);
577
578 if (newoffset == 0) { /* No hole found */
579 if (totsize >= segsize) {
580 pack_segment_data(seghdr, segcnt, contfd, offset_tbl);
581 newoffset = hole_discovery(segsize, segcnt, &totsize,
582 offset_tbl);
583 if (newoffset != 0) {
584 *sectionoffset = newoffset;
585 free(offset_tbl);
586 return (0);
587 }
588 }
589 } else {
590 *sectionoffset = newoffset;
591 free(offset_tbl);
592 return (0);
593 }
594 free(offset_tbl);
595 return (-1);
596 }
597
598 static char *
tokenizer(char * buf,char * separator,char ** nextBuf,char * matched)599 tokenizer(char *buf, char *separator, char **nextBuf, char *matched)
600 {
601 int i = 0;
602 int j = 0;
603
604 for (i = 0; buf[i] != '\0'; i++) {
605 for (j = 0; j < strlen(separator); j++) {
606 if (buf[i] == separator[j]) {
607 buf[i] = '\0';
608 *nextBuf = &(buf[i+1]);
609 *matched = separator[j];
610 return (buf);
611 }
612 }
613 }
614
615 *nextBuf = buf;
616 *matched = '\0';
617 return (NULL);
618 }
619
620 static int
get_container_info(const char * def_file,const char * cont_desc_str,container_info_t * cont_info)621 get_container_info(const char *def_file, const char *cont_desc_str,
622 container_info_t *cont_info)
623 {
624 char *item;
625 char *token;
626 char *field;
627 char matched;
628 char buf[1024];
629 int foundIt = 0;
630 int ro_tok;
631 int index;
632 FILE *file = fopen(def_file, "r");
633
634 if (file == NULL)
635 return (-1);
636
637 cont_info->num_sections = 0;
638
639 while (fgets(buf, sizeof (buf), file) != NULL) {
640 /* ignore all comments */
641 token = tokenizer(buf, "#", &field, &matched);
642 /* find the names */
643 token = tokenizer(buf, ":", &field, &matched);
644 if (token != 0x00) {
645 token = tokenizer(token, "|", &item, &matched);
646 while (token != 0x00) {
647 if (strcmp(token, cont_desc_str) == 0) {
648 foundIt = 1;
649 goto found;
650 }
651 token = tokenizer(item, "|", &item, &matched);
652 }
653 /* check the last remaining item */
654 if ((item != 0x00) &&
655 (strcmp(item, cont_desc_str) == 0)) {
656 foundIt = 1;
657 goto found;
658 }
659 }
660 }
661
662 found :
663 if (foundIt == 1) {
664 token = tokenizer(field, ":", &field, &matched);
665 if (token == 0x00) {
666 (void) fclose(file);
667 return (-1);
668 }
669 cont_info->header_ver = (headerrev_t)atoi(token);
670
671 token = tokenizer(field, ":\n", &field, &matched);
672 while (token != 0x00) {
673 token = tokenizer(token, ",", &item, &matched);
674 if (token == 0x00) {
675 (void) fclose(file);
676 return (-1);
677 }
678 ro_tok = atoi(token);
679 index = cont_info->num_sections;
680 cont_info->section_info[index].encoding = ENC_STANDARD;
681 if (ro_tok == 1) {
682 cont_info->section_info[index].description.
683 field.read_only = 1;
684 } else if (ro_tok == 0) {
685 cont_info->section_info[index].description.
686 field.read_only = 0;
687 } else if (ro_tok == 2) {
688 /*
689 * a value of 2 in the read-only token means
690 * that the data in this section needs
691 * re-interpreting
692 */
693 cont_info->section_info[index].description.
694 field.read_only = 1;
695 } else {
696 (void) fclose(file);
697 return (-1);
698 }
699
700 token = tokenizer(item, ",", &item, &matched);
701 if (token == 0x00) {
702 (void) fclose(file);
703 return (-1);
704 }
705
706 cont_info->section_info[index].address = atoi(token);
707 if (ro_tok == 2) {
708 /*
709 * expect an extra parameter to define the
710 * data interpreter
711 */
712 token = tokenizer(item, ",", &item, &matched);
713 if (token == 0x00) {
714 (void) fclose(file);
715 return (-1);
716 }
717 }
718 if (item == '\0') {
719 (void) fclose(file);
720 return (-1);
721 }
722 cont_info->section_info[index].size =
723 ro_tok == 2 ? atoi(token) : atoi(item);
724 if (ro_tok == 2) {
725 if (strcmp(item, "SPD") == 0)
726 cont_info->section_info[index].
727 encoding = ENC_SPD;
728 else {
729 (void) fclose(file);
730 return (-1);
731 }
732 }
733 (cont_info->num_sections)++;
734
735 token = tokenizer(field, ":\n ", &field, &matched);
736 }
737 }
738 (void) fclose(file);
739 return (0);
740 }
741
742 /*
743 * Description :fru_open_container() opens the container associated with a fru.
744 * it's called by data plugin module before creating container
745 * property. it calls picltree library routine to get the
746 * device path and driver binding name for the fru to get the
747 * corresponding fru name that describe the fru layout.
748 *
749 * Arguments :picl_hdl_t fru
750 * A handle for PICL tree node of class "fru" representing the
751 * FRU with the container to open.
752 *
753 * Return :
754 * On Success, a Positive integer container handle. is returned
755 * for use in subsequent fru operations;on error, 0 is returned
756 * and "errno" is set appropriately.
757 */
758
759 container_hdl_t
fru_open_container(picl_nodehdl_t fruhdl)760 fru_open_container(picl_nodehdl_t fruhdl)
761 {
762 int retval;
763 int count;
764 int device_fd;
765 uchar_t first_byte;
766 char *bname;
767 char devpath[PATH_MAX];
768 char nmbuf[SYS_NMLN];
769 hash_obj_t *cont_hash_obj;
770 hash_obj_t *sec_hash_obj;
771 picl_nodehdl_t tmphdl;
772 picl_prophdl_t prophdl;
773 ptree_propinfo_t propinfo;
774 container_info_t cont_info;
775
776 /* Get property handle of _seeprom_source under fru node */
777 retval = ptree_get_propval_by_name(fruhdl, PICL_REFPROP_SEEPROM_SRC,
778 &tmphdl, sizeof (tmphdl));
779 if (retval != PICL_SUCCESS) {
780 return (NULL);
781 }
782
783 /* Get the device path of the fru */
784 retval = ptree_get_propval_by_name(tmphdl, PICL_PROP_DEVICEPATH,
785 devpath, PATH_MAX);
786 if (retval != PICL_SUCCESS) {
787 return (NULL);
788 }
789
790 retval = ptree_get_prop_by_name(tmphdl, PICL_PROP_BINDING_NAME,
791 &prophdl);
792 if (retval != PICL_SUCCESS) {
793 return (NULL);
794 }
795
796 retval = ptree_get_propinfo(prophdl, &propinfo);
797 if (retval != PICL_SUCCESS) {
798 return (NULL);
799 }
800
801 bname = alloca(propinfo.piclinfo.size);
802 if (bname == NULL) {
803 return (NULL);
804 }
805
806 /* get the driver binding name */
807 retval = ptree_get_propval(prophdl, bname, propinfo.piclinfo.size);
808 if (retval != PICL_SUCCESS) {
809 return (NULL);
810 }
811
812 cont_hash_obj = create_container_hash_object();
813 if (cont_hash_obj == NULL) {
814 return (NULL);
815 }
816
817 add_hashobject_to_hashtable(cont_hash_obj);
818
819 (void) strlcpy(cont_hash_obj->u.cont_obj->device_pathname, devpath,
820 sizeof (devpath));
821
822 /* check for sun or non-sun type fru */
823 if (strcmp(bname, "i2c-at34c02") == 0) {
824 device_fd = open(devpath, O_RDONLY);
825 if (device_fd < 0) {
826 return (NULL);
827 }
828 first_byte = 0x00;
829
830 retval = pread(device_fd, &first_byte, sizeof (first_byte), 0);
831 (void) close(device_fd);
832 switch (first_byte) {
833 case 0x08:
834 (void) strcpy(bname, "i2c-at34cps");
835 break;
836 case 0x80:
837 (void) strcpy(bname, "i2c-at34c02");
838 break;
839 default:
840 (void) strcpy(bname, "i2c-at34cuk");
841 break;
842 }
843 }
844
845 /* if there's a platform-specific conf file, use that */
846 retval = -1;
847 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) {
848 (void) snprintf(devpath, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF,
849 nmbuf);
850 (void) strlcat(devpath, FRU_CONTAINER_CONF, PATH_MAX);
851 retval = access(devpath, R_OK);
852 }
853 if (retval != 0) {
854 /* nothing for the platform, try the base name */
855 (void) snprintf(devpath, PATH_MAX, "%s/%s",
856 CONTAINER_DIR, FRU_CONTAINER_CONF);
857 retval = access(devpath, R_OK);
858 }
859 /* matches driver binding name to get container information */
860 if (retval == 0) {
861 retval = get_container_info(devpath, bname, &cont_info);
862 }
863 if (retval < 0) {
864 return (NULL);
865 }
866
867 cont_hash_obj->u.cont_obj->num_of_section = cont_info.num_sections;
868 cont_hash_obj->u.cont_obj->sec_obj_list = NULL;
869
870 for (count = 0; count < cont_info.num_sections; count++) {
871 sec_hash_obj = create_section_hash_object();
872 if (sec_hash_obj == NULL) {
873 return (NULL);
874 }
875
876 add_hashobject_to_hashtable(sec_hash_obj);
877
878 sec_hash_obj->u.sec_obj->section.offset =
879 cont_info.section_info[count].address;
880
881 sec_hash_obj->u.sec_obj->section.protection =
882 cont_info.section_info[count].description.field.read_only;
883
884 sec_hash_obj->u.sec_obj->section.length =
885 cont_info.section_info[count].size;
886
887 sec_hash_obj->u.sec_obj->section.version = cont_info.header_ver;
888 sec_hash_obj->u.sec_obj->encoding =
889 cont_info.section_info[count].encoding;
890
891 add_to_sec_object_list(cont_hash_obj, sec_hash_obj);
892 }
893 return (cont_hash_obj->obj_hdl);
894 }
895
896 static int
verify_header_crc8(headerrev_t head_ver,unsigned char * bytes,int length)897 verify_header_crc8(headerrev_t head_ver, unsigned char *bytes, int length)
898 {
899 int crc_offset = 0;
900 unsigned char orig_crc8 = 0;
901 unsigned char calc_crc8 = 0;
902
903 switch (head_ver) {
904 case SECTION_HDR_VER:
905 crc_offset = 4;
906 break;
907 default:
908 errno = EINVAL;
909 return (0);
910 }
911
912 orig_crc8 = bytes[crc_offset];
913 bytes[crc_offset] = 0x00; /* clear for calc */
914 calc_crc8 = compute_crc8(bytes, length);
915 bytes[crc_offset] = orig_crc8; /* restore */
916 return (orig_crc8 == calc_crc8);
917 }
918
919 /*
920 * Description :
921 * fru_get_num_sections() returns number of sections in a
922 * container. it calls get_container_index() to get the container
923 * index number in the container list.
924 *
925 * Arguments :
926 * container_hdl_t : container handle.
927 *
928 * Return :
929 * int
930 * On success, returns number of sections in a container.
931 *
932 */
933
934 /* ARGSUSED */
935 int
fru_get_num_sections(container_hdl_t container,door_cred_t * cred)936 fru_get_num_sections(container_hdl_t container, door_cred_t *cred)
937 {
938 hash_obj_t *hash_object;
939
940 hash_object = lookup_handle_object(container, CONTAINER_TYPE);
941 if (hash_object == NULL) {
942 return (-1);
943 }
944
945 return (hash_object->u.cont_obj->num_of_section);
946 }
947
948 /*
949 * called from fru_get_sections()
950 */
951
952 static void
get_section(int fd,hash_obj_t * sec_hash,section_t * section)953 get_section(int fd, hash_obj_t *sec_hash, section_t *section)
954 {
955 int retval;
956 int size;
957 int count;
958 uint16_t hdrver;
959 hash_obj_t *seg_hash;
960 unsigned char *buffer;
961 section_obj_t *sec_obj;
962 section_layout_t sec_hdr;
963 segment_layout_t *seg_hdr;
964 segment_layout_t *seg_buf;
965
966 sec_obj = sec_hash->u.sec_obj;
967 if (sec_obj == NULL) {
968 return;
969 }
970
971 /* populate section_t */
972 section->handle = sec_hash->obj_hdl;
973 section->offset = sec_obj->section.offset;
974 section->length = sec_obj->section.length;
975 section->protection = sec_obj->section.protection;
976 section->version = sec_obj->section.version;
977 sec_obj->num_of_segment = 0;
978
979 switch (sec_obj->encoding) {
980 case ENC_STANDARD:
981 /* read section header layout */
982 retval = pread(fd, &sec_hdr, sizeof (sec_hdr),
983 sec_obj->section.offset);
984 break;
985
986 case ENC_SPD:
987 retval = get_sp_sec_hdr(&sec_hdr, sizeof (sec_hdr));
988 break;
989
990 default:
991 return;
992 }
993
994 if (retval != sizeof (sec_hdr)) {
995 return;
996 }
997
998 hdrver = GET_SECTION_HDR_VERSION;
999
1000 if ((sec_hdr.headertag != SECTION_HDR_TAG) &&
1001 (hdrver != section->version)) {
1002 return;
1003 }
1004
1005 /* size = section layout + total sizeof segment header */
1006 size = sizeof (sec_hdr) + ((sec_hdr.segmentcount) *
1007 sizeof (segment_layout_t));
1008
1009 buffer = alloca(size);
1010 if (buffer == NULL) {
1011 return;
1012 }
1013
1014 /* segment header buffer */
1015 seg_buf = alloca(size - sizeof (sec_hdr));
1016 if (seg_buf == NULL) {
1017 return;
1018 }
1019
1020 switch (sec_obj->encoding) {
1021 case ENC_STANDARD:
1022 /* read segment header */
1023 retval = pread(fd, seg_buf, size - sizeof (sec_hdr),
1024 sec_obj->section.offset + sizeof (sec_hdr));
1025 break;
1026
1027 case ENC_SPD:
1028 retval =
1029 get_sp_seg_hdr(seg_buf, size - sizeof (sec_hdr));
1030 break;
1031
1032 default:
1033 return;
1034 }
1035
1036 if (retval != (size - sizeof (sec_hdr))) {
1037 return;
1038 }
1039
1040 /* copy section header layout */
1041 (void) memcpy(buffer, &sec_hdr, sizeof (sec_hdr));
1042
1043 /* copy segment header layout */
1044 (void) memcpy(buffer + sizeof (sec_hdr), seg_buf, size -
1045 sizeof (sec_hdr));
1046
1047 /* verify crc8 */
1048 retval = verify_header_crc8(hdrver, buffer, size);
1049 if (retval != TRUE) {
1050 return;
1051 }
1052
1053 section->version = hdrver;
1054 sec_obj->section.version = hdrver;
1055
1056 seg_hdr = (segment_layout_t *)seg_buf;
1057
1058 for (count = 0; count < sec_hdr.segmentcount; count++, seg_hdr++) {
1059 seg_hash = create_segment_hash_object();
1060 if (seg_hash == NULL) {
1061 return;
1062 }
1063
1064 add_hashobject_to_hashtable(seg_hash);
1065
1066 copy_segment_layout(&seg_hash->u.seg_obj->segment, seg_hdr);
1067
1068 add_to_seg_object_list(sec_hash, seg_hash);
1069
1070 sec_obj->num_of_segment++;
1071 }
1072 }
1073
1074
1075 static int
call_devfsadm(void)1076 call_devfsadm(void)
1077 {
1078 char *phys_path;
1079 di_node_t root_node;
1080 di_node_t prom_node;
1081 di_node_t f_node;
1082
1083 if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
1084 return (-1);
1085 }
1086
1087 f_node = di_drv_first_node(PICL_CLASS_SEEPROM, root_node);
1088 if (f_node != DI_NODE_NIL) {
1089 phys_path = di_devfs_path(f_node);
1090 if ((prom_node = di_init(phys_path, DINFOMINOR)) !=
1091 DI_NODE_NIL) {
1092 di_fini(prom_node);
1093 di_fini(root_node);
1094 (void) pclose(popen(devfsadm_cmd, "r"));
1095 return (0);
1096 }
1097 }
1098 di_fini(root_node);
1099 return (-1);
1100 }
1101
1102 /*
1103 * Description :
1104 * fru_get_sections() fills an array of section structures passed
1105 * as an argument.
1106 *
1107 * Arguments :
1108 * container_hdl_t : container handle(device descriptor).
1109 * section_t : array of section structure.
1110 * int : maximum number of section in a container.
1111 *
1112 * Returns :
1113 * int
1114 * On success,the number of section structures written is returned;
1115 * on error, -1 is returned and "errno" is set appropriately.
1116 *
1117 */
1118
1119 /* ARGSUSED */
1120 int
fru_get_sections(container_hdl_t container,section_t * section,int maxsec,door_cred_t * cred)1121 fru_get_sections(container_hdl_t container, section_t *section, int maxsec,
1122 door_cred_t *cred)
1123 {
1124 int device_fd;
1125 int retrys = 1;
1126 int count;
1127 hash_obj_t *cont_object;
1128 hash_obj_t *sec_hash;
1129
1130 cont_object = lookup_handle_object(container, CONTAINER_TYPE);
1131
1132 if (cont_object == NULL) {
1133 return (-1);
1134 }
1135
1136 if (cont_object->u.cont_obj->num_of_section > maxsec) {
1137 return (-1);
1138 }
1139
1140 sec_hash = cont_object->u.cont_obj->sec_obj_list;
1141 if (sec_hash == NULL) {
1142 return (-1);
1143 }
1144
1145 do {
1146 device_fd =
1147 open(cont_object->u.cont_obj->device_pathname, O_RDONLY);
1148 if (device_fd >= 0) {
1149 break;
1150 }
1151 } while ((retrys-- > 0) && (call_devfsadm() == 0));
1152
1153 if (device_fd < 0) {
1154 return (-1);
1155 }
1156
1157 for (count = 0; count < cont_object->u.cont_obj->num_of_section;
1158 count++, section++) {
1159 section->version = -1;
1160 /* populate section_t */
1161 get_section(device_fd, sec_hash, section);
1162 sec_hash = sec_hash->u.sec_obj->next;
1163 }
1164
1165 (void) close(device_fd);
1166 return (count);
1167 }
1168
1169 /*
1170 * Description :
1171 * fru_get_num_segments() returns the current number of segments
1172 * in a section.
1173 *
1174 * Arguments :
1175 * section_hdl_t : section header holding section information.
1176 *
1177 * Return :
1178 * int
1179 * On success, the number of segments in the argument section is
1180 * returned; on error -1 is returned.
1181 */
1182
1183 /* ARGSUSED */
1184 int
fru_get_num_segments(section_hdl_t section,door_cred_t * cred)1185 fru_get_num_segments(section_hdl_t section, door_cred_t *cred)
1186 {
1187 hash_obj_t *sec_object;
1188 section_obj_t *sec_obj;
1189
1190 sec_object = lookup_handle_object(section, SECTION_TYPE);
1191 if (sec_object == NULL) {
1192 return (-1);
1193 }
1194
1195 sec_obj = sec_object->u.sec_obj;
1196 if (sec_obj == NULL) {
1197 return (-1);
1198 }
1199
1200 return (sec_obj->num_of_segment);
1201 }
1202
1203 /*
1204 * Description :
1205 * fru_get_segments() fills an array of structures representing the
1206 * segments in a section.
1207 *
1208 * Arguments :
1209 * section_hdl_t : holds section number.
1210 * segment_t : on success will hold segment information.
1211 * int : maximum number of segment.
1212 *
1213 * Return :
1214 * int
1215 * On success, the number of segment structures written is
1216 * returned; on errno -1 is returned.
1217 */
1218
1219 /* ARGSUSED */
1220 int
fru_get_segments(section_hdl_t section,segment_t * segment,int maxseg,door_cred_t * cred)1221 fru_get_segments(section_hdl_t section, segment_t *segment, int maxseg,
1222 door_cred_t *cred)
1223 {
1224 int count;
1225 hash_obj_t *sec_object;
1226 hash_obj_t *seg_object;
1227 section_obj_t *sec_obj;
1228
1229 sec_object = lookup_handle_object(section, SECTION_TYPE);
1230 if (sec_object == NULL) {
1231 return (-1);
1232 }
1233
1234 sec_obj = sec_object->u.sec_obj;
1235 if (sec_obj == NULL) {
1236 return (-1);
1237 }
1238
1239 if (sec_obj->num_of_segment > maxseg) {
1240 return (-1);
1241 }
1242
1243 seg_object = sec_object->u.sec_obj->seg_obj_list;
1244 if (seg_object == NULL) {
1245 return (-1);
1246 }
1247
1248 for (count = 0; count < sec_obj->num_of_segment; count++) {
1249
1250 /* populate segment_t */
1251 segment->handle = seg_object->obj_hdl;
1252 (void) memcpy(segment->name,
1253 seg_object->u.seg_obj->segment.name, SEG_NAME_LEN);
1254 segment->descriptor = seg_object->u.seg_obj->segment.descriptor;
1255
1256 segment->offset = seg_object->u.seg_obj->segment.offset;
1257 segment->length = seg_object->u.seg_obj->segment.length;
1258 seg_object = seg_object->u.seg_obj->next;
1259 segment++;
1260 }
1261 return (0);
1262 }
1263
1264 /*
1265 * Description :
1266 * fru_add_segment() adds a segment to a section.
1267 *
1268 * Arguments :
1269 * section_hdl_t section
1270 * A handle for the section in which to add the segment.
1271 *
1272 * segment_t *segment
1273 * On entry, the "handle" component of "segment" is ignored and the
1274 * remaining components specify the parameters of the segment to be
1275 * added. On return, the "handle" component is set to the handle
1276 * for the added segment. The segment offset is mandatory for FIXED
1277 * segments; otherwise, the offset is advisory.
1278 *
1279 * Return :
1280 * int
1281 * On success, 0 is returned; on error -1 is returned.
1282 *
1283 */
1284
1285 int
fru_add_segment(section_hdl_t section,segment_t * segment,section_hdl_t * newsection,door_cred_t * cred)1286 fru_add_segment(section_hdl_t section, segment_t *segment,
1287 section_hdl_t *newsection, door_cred_t *cred)
1288 {
1289 int fd;
1290 int retval;
1291 int offset;
1292 int sec_size;
1293 int seg_cnt;
1294 int bufsize;
1295 int new_seg_offset;
1296 int new_seg_length;
1297 int fixed_segment;
1298 char trailer[] = { 0x0c, 0x00, 0x00, 0x00, 0x00 };
1299 hash_obj_t *cont_hash;
1300 hash_obj_t *sec_hash;
1301 hash_obj_t *seg_hash;
1302 fru_segdesc_t *new_seg_desc;
1303 unsigned char *crcbuf;
1304 section_layout_t sec_layout;
1305 segment_layout_t *seg_layout;
1306 segment_layout_t *segment_buf;
1307
1308 /* check the effective uid of the client */
1309 if (cred->dc_euid != 0) {
1310 errno = EPERM;
1311 return (-1); /* not a root */
1312 }
1313
1314 /* section hash */
1315 sec_hash = lookup_handle_object(section, SECTION_TYPE);
1316 if (sec_hash == NULL) {
1317 return (-1);
1318 }
1319
1320 /* check for read-only section */
1321 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
1322 errno = EPERM;
1323 return (-1);
1324 }
1325
1326 /* look for duplicate segment */
1327 seg_hash = sec_hash->u.sec_obj->seg_obj_list;
1328 while (seg_hash != NULL) {
1329 if (strncmp(segment->name, seg_hash->u.seg_obj->segment.name,
1330 SEG_NAME_LEN) == 0) {
1331 errno = EEXIST;
1332 return (-1); /* can't add duplicate segment */
1333 }
1334 seg_hash = seg_hash->u.seg_obj->next;
1335 }
1336
1337 /* get the container hash */
1338 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
1339 CONTAINER_TYPE);
1340 if (cont_hash == NULL) {
1341 return (-1);
1342 }
1343
1344 /* open the container */
1345 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR);
1346 if (fd < 0) {
1347 return (-1);
1348 }
1349
1350 /* section start here */
1351 offset = sec_hash->u.sec_obj->section.offset;
1352
1353 /* read section header layout */
1354 retval = pread(fd, &sec_layout, sizeof (sec_layout), offset);
1355 if (retval != sizeof (sec_layout)) {
1356 (void) close(fd);
1357 return (-1);
1358 }
1359
1360 /* check for valid section header */
1361 if (sec_layout.headertag != SECTION_HDR_TAG) {
1362 /* write a new one */
1363 sec_layout.headertag = SECTION_HDR_TAG;
1364 sec_layout.headerversion[0] = SECTION_HDR_VER_BIT0;
1365 sec_layout.headerversion[1] = SECTION_HDR_VER_BIT1;
1366 sec_layout.headerlength = sizeof (sec_layout);
1367 sec_layout.segmentcount = 0;
1368 }
1369
1370 /* section size */
1371 sec_size = sec_hash->u.sec_obj->section.length;
1372
1373 /* number of segment in the section */
1374 seg_cnt = sec_layout.segmentcount;
1375
1376 /* total sizeof segment + new segment */
1377 bufsize = sizeof (segment_layout_t) * (seg_cnt + 1);
1378 segment_buf = alloca(bufsize);
1379 if (segment_buf == NULL) {
1380 return (-1);
1381 }
1382
1383 /* read entire segment header */
1384 retval = pread(fd, segment_buf, (bufsize - sizeof (segment_layout_t)),
1385 offset + sizeof (section_layout_t));
1386 if (retval != (bufsize - sizeof (segment_layout_t))) {
1387 (void) close(fd);
1388 return (-1);
1389 }
1390
1391 new_seg_offset = segment->offset; /* new segment offset */
1392 new_seg_length = segment->length; /* new segment length */
1393
1394 new_seg_desc = (fru_segdesc_t *)&segment->descriptor;
1395
1396 fixed_segment = new_seg_desc->field.fixed;
1397
1398 /* get new offset for new segment to be addedd */
1399 retval = find_offset((char *)segment_buf, seg_cnt, sec_size,
1400 &new_seg_offset, new_seg_length, fixed_segment, fd);
1401
1402 if (retval != 0) {
1403 (void) close(fd);
1404 errno = EAGAIN;
1405 return (-1);
1406 }
1407
1408 /* copy new segment data in segment layout */
1409 seg_layout = (segment_layout_t *)(segment_buf + seg_cnt);
1410 (void) memcpy(&seg_layout->name, segment->name, SEG_NAME_LEN);
1411 (void) memcpy(seg_layout->descriptor, &segment->descriptor,
1412 sizeof (uint32_t));
1413 seg_layout->length = segment->length;
1414 seg_layout->offset = new_seg_offset; /* new segment offset */
1415
1416 sec_layout.segmentcount += 1;
1417
1418 crcbuf = alloca(sizeof (section_layout_t) + bufsize);
1419 if (crcbuf == NULL) {
1420 (void) close(fd);
1421 return (-1);
1422 }
1423
1424 sec_layout.headercrc8 = 0;
1425 sec_layout.headerlength += sizeof (segment_layout_t);
1426
1427 (void) memcpy(crcbuf, (char *)&sec_layout, sizeof (section_layout_t));
1428 (void) memcpy(crcbuf + sizeof (section_layout_t), segment_buf, bufsize);
1429
1430 sec_layout.headercrc8 = compute_crc8(crcbuf, bufsize +
1431 sizeof (section_layout_t));
1432
1433 /* write section header */
1434 retval = pwrite(fd, &sec_layout, sizeof (section_layout_t), offset);
1435 if (retval != sizeof (section_layout_t)) {
1436 (void) close(fd);
1437 return (-1);
1438 }
1439
1440 /* write segment header */
1441 retval = pwrite(fd, segment_buf, bufsize, offset +
1442 sizeof (section_layout_t));
1443 if (retval != bufsize) {
1444 (void) close(fd);
1445 return (-1);
1446 }
1447
1448 /* write segment trailer */
1449 retval = pwrite(fd, &trailer, sizeof (trailer), new_seg_offset);
1450 if (retval != sizeof (trailer)) {
1451 (void) close(fd);
1452 return (-1);
1453 }
1454
1455 (void) close(fd);
1456
1457 /* create new segment hash object */
1458 seg_hash = create_segment_hash_object();
1459 if (seg_hash == NULL) {
1460 return (-1);
1461 }
1462
1463 add_hashobject_to_hashtable(seg_hash);
1464
1465 copy_segment_layout(&seg_hash->u.seg_obj->segment, seg_layout);
1466
1467 add_to_seg_object_list(sec_hash, seg_hash);
1468
1469 sec_hash->u.sec_obj->num_of_segment += 1;
1470 seg_hash->u.seg_obj->trailer_offset = new_seg_offset;
1471 *newsection = section; /* return the new section handle */
1472 return (0);
1473 }
1474
1475 static void
free_pkt_object_list(hash_obj_t * hash_obj)1476 free_pkt_object_list(hash_obj_t *hash_obj)
1477 {
1478 hash_obj_t *next_obj;
1479 hash_obj_t *free_obj;
1480
1481 next_obj = hash_obj->u.seg_obj->pkt_obj_list;
1482 while (next_obj != NULL) {
1483 free_obj = next_obj;
1484 next_obj = next_obj->u.pkt_obj->next;
1485 /* if prev is NULL it's the first object in the list */
1486 if (free_obj->prev == NULL) {
1487 hash_table[(free_obj->obj_hdl % TABLE_SIZE)] =
1488 free_obj->next;
1489 if (free_obj->next != NULL) {
1490 free_obj->next->prev = free_obj->prev;
1491 }
1492 } else {
1493 free_obj->prev->next = free_obj->next;
1494 if (free_obj->next != NULL) {
1495 free_obj->next->prev = free_obj->prev;
1496 }
1497 }
1498
1499 free(free_obj->u.pkt_obj->payload);
1500 free(free_obj->u.pkt_obj);
1501 free(free_obj);
1502 }
1503
1504 hash_obj->u.seg_obj->pkt_obj_list = NULL;
1505 }
1506
1507 static void
free_segment_hash(handle_t handle,hash_obj_t * sec_hash)1508 free_segment_hash(handle_t handle, hash_obj_t *sec_hash)
1509 {
1510 hash_obj_t *seg_hash;
1511 hash_obj_t *next_hash;
1512
1513 seg_hash = sec_hash->u.sec_obj->seg_obj_list;
1514 if (seg_hash == NULL) {
1515 return;
1516 }
1517
1518 if (seg_hash->obj_hdl == handle) {
1519 sec_hash->u.sec_obj->seg_obj_list = seg_hash->u.seg_obj->next;
1520 } else {
1521 while (seg_hash->obj_hdl != handle) {
1522 next_hash = seg_hash;
1523 seg_hash = seg_hash->u.seg_obj->next;
1524 if (seg_hash == NULL) {
1525 return;
1526 }
1527 }
1528 next_hash->u.seg_obj->next = seg_hash->u.seg_obj->next;
1529 }
1530
1531 if (seg_hash->prev == NULL) {
1532 hash_table[(seg_hash->obj_hdl % TABLE_SIZE)] = seg_hash->next;
1533 if (seg_hash->next != NULL) {
1534 seg_hash->next->prev = NULL;
1535 }
1536 } else {
1537 seg_hash->prev->next = seg_hash->next;
1538 if (seg_hash->next != NULL) {
1539 seg_hash->next->prev = seg_hash->prev;
1540 }
1541 }
1542
1543 free_pkt_object_list(seg_hash);
1544 free(seg_hash->u.seg_obj);
1545 free(seg_hash);
1546 }
1547
1548 /*
1549 * Description :
1550 * fru_delete_segment() deletes a segment from a section; the
1551 * associated container data is not altered.
1552 *
1553 * Arguments : segment_hdl_t segment handle.
1554 * section_hdl_t new section handle.
1555 *
1556 * Return :
1557 * int
1558 * On success, 0 returned; On error -1 is returned.
1559 */
1560
1561 int
fru_delete_segment(segment_hdl_t segment,section_hdl_t * newsection,door_cred_t * cred)1562 fru_delete_segment(segment_hdl_t segment, section_hdl_t *newsection,
1563 door_cred_t *cred)
1564 {
1565 int num_of_seg;
1566 int bufsize;
1567 int count;
1568 int retval;
1569 int fd;
1570 int segnum;
1571 hash_obj_t *seg_hash;
1572 hash_obj_t *sec_hash;
1573 hash_obj_t *cont_hash;
1574 hash_obj_t *tmp_hash;
1575 unsigned char *buffer;
1576 fru_segdesc_t *desc;
1577 segment_layout_t *seg_buf;
1578 section_layout_t *sec_layout;
1579 segment_layout_t *seg_layout;
1580 segment_layout_t *next_layout;
1581
1582 /* check the effective uid of the client */
1583 if (cred->dc_euid != 0) {
1584 errno = EPERM;
1585 return (-1); /* not a root */
1586 }
1587
1588 seg_hash = lookup_handle_object(segment, SEGMENT_TYPE);
1589 if (seg_hash == NULL) {
1590 return (-1);
1591 }
1592
1593 desc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
1594 if (!(desc->field.field_perm & SEGMENT_DELETE)) {
1595 errno = EPERM;
1596 return (-1); /* can't delete this segment */
1597 }
1598
1599 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
1600 SECTION_TYPE);
1601 if (sec_hash == NULL) {
1602 return (-1);
1603 }
1604
1605 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
1606 errno = EPERM;
1607 return (-1);
1608 }
1609
1610 num_of_seg = sec_hash->u.sec_obj->num_of_segment;
1611
1612 bufsize = (sizeof (segment_layout_t) * num_of_seg);
1613
1614 seg_buf = alloca(bufsize);
1615 if (seg_buf == NULL) {
1616 return (-1);
1617 }
1618
1619 segnum = 0;
1620 for (tmp_hash = sec_hash->u.sec_obj->seg_obj_list; tmp_hash != NULL;
1621 tmp_hash = tmp_hash->u.seg_obj->next) {
1622 if (tmp_hash->obj_hdl == segment) {
1623 break;
1624 }
1625 segnum++;
1626 }
1627
1628 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
1629 CONTAINER_TYPE);
1630 if (cont_hash == NULL) {
1631 return (-1);
1632 }
1633
1634 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR);
1635 if (fd < 0) {
1636 return (-1);
1637 }
1638
1639 sec_layout = alloca(sizeof (section_layout_t));
1640 if (sec_layout == NULL) {
1641 (void) close(fd);
1642 return (-1);
1643 }
1644
1645 /* read section layout header */
1646 retval = pread(fd, sec_layout, sizeof (section_layout_t),
1647 sec_hash->u.sec_obj->section.offset);
1648 if (retval != sizeof (section_layout_t)) {
1649 (void) close(fd);
1650 return (-1);
1651 }
1652
1653 /* read segment header layout */
1654 retval = pread(fd, seg_buf, bufsize,
1655 sec_hash->u.sec_obj->section.offset + sizeof (section_layout_t));
1656 if (retval != bufsize) {
1657 (void) close(fd);
1658 return (-1);
1659 }
1660
1661 seg_layout = (segment_layout_t *)(seg_buf + segnum);
1662 next_layout = seg_layout;
1663 for (count = segnum;
1664 count < sec_hash->u.sec_obj->num_of_segment - 1; count++) {
1665 next_layout++;
1666 (void) memcpy(seg_layout, next_layout,
1667 sizeof (segment_layout_t));
1668 seg_layout++;
1669 }
1670
1671 (void) memset(seg_layout, '\0', sizeof (segment_layout_t));
1672
1673 sec_layout->headercrc8 = 0;
1674
1675 sec_layout->headerlength -= sizeof (segment_layout_t);
1676 sec_layout->segmentcount -= 1;
1677
1678 buffer = alloca(sec_layout->headerlength);
1679 if (buffer == NULL) {
1680 (void) close(fd);
1681 return (-1);
1682 }
1683
1684 (void) memcpy(buffer, sec_layout, sizeof (section_layout_t));
1685 (void) memcpy(buffer + sizeof (section_layout_t), seg_buf, bufsize -
1686 sizeof (segment_layout_t));
1687 sec_layout->headercrc8 = compute_crc8(buffer, sec_layout->headerlength);
1688
1689 /* write section header with update crc8 and header length */
1690 retval = pwrite(fd, sec_layout, sizeof (section_layout_t),
1691 sec_hash->u.sec_obj->section.offset);
1692 if (retval != sizeof (section_layout_t)) {
1693 (void) close(fd);
1694 return (-1);
1695 }
1696
1697 /* write the update segment header */
1698 retval = pwrite(fd, seg_buf, bufsize,
1699 sec_hash->u.sec_obj->section.offset + sizeof (section_layout_t));
1700 (void) close(fd);
1701 if (retval != bufsize) {
1702 return (-1);
1703 }
1704
1705 free_segment_hash(segment, sec_hash);
1706
1707 *newsection = sec_hash->obj_hdl;
1708 sec_hash->u.sec_obj->num_of_segment = sec_layout->segmentcount;
1709
1710 return (0);
1711 }
1712
1713 /*
1714 * Description :
1715 * fru_read_segment() reads the raw contents of a segment.
1716 *
1717 * Arguments : segment_hdl_t : segment handle.
1718 * void * : buffer containing segment data when function returns.
1719 * size_t :number of bytes.
1720 *
1721 * Return :
1722 * int
1723 * On success, the number of bytes read is returned;
1724 *
1725 * Notes :
1726 * Segments containing packets can be read in structured fashion
1727 * using the fru_get_packets() and fru_get_payload() primitives;the
1728 * entire byte range of a segment can be read using
1729 * fru_read_segment().
1730 */
1731
1732 /* ARGSUSED */
1733 ssize_t
fru_read_segment(segment_hdl_t segment,void * buffer,size_t nbytes,door_cred_t * cred)1734 fru_read_segment(segment_hdl_t segment, void *buffer, size_t nbytes,
1735 door_cred_t *cred)
1736 {
1737 int fd;
1738 int retval;
1739 hash_obj_t *seg_hash;
1740 hash_obj_t *sec_hash;
1741 hash_obj_t *cont_hash;
1742
1743 /* segment hash object */
1744 seg_hash = lookup_handle_object(segment, SEGMENT_TYPE);
1745 if (seg_hash == NULL) {
1746 return (-1);
1747 }
1748
1749 /* section hash object */
1750 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
1751 SECTION_TYPE);
1752 if (sec_hash == NULL) {
1753 return (-1);
1754 }
1755
1756 /* container hash object */
1757 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
1758 CONTAINER_TYPE);
1759 if (cont_hash == NULL) {
1760 return (-1);
1761 }
1762
1763 if (seg_hash->u.seg_obj->segment.length < nbytes) {
1764 return (-1);
1765 }
1766
1767 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDONLY);
1768 if (fd < 0) {
1769 return (-1);
1770 }
1771
1772 switch (sec_hash->u.sec_obj->encoding) {
1773 case ENC_STANDARD:
1774 retval = pread(fd, buffer, nbytes,
1775 seg_hash->u.seg_obj->segment.offset);
1776 (void) close(fd);
1777 if (retval != nbytes) {
1778 return (-1);
1779 }
1780 break;
1781
1782 case ENC_SPD: {
1783 char *spd_buf;
1784 uchar_t *ptr;
1785 size_t len;
1786
1787 spd_buf = alloca(sec_hash->u.sec_obj->section.length);
1788 if (spd_buf == NULL)
1789 retval = -1;
1790 else {
1791 retval = get_spd_data(fd, spd_buf,
1792 sec_hash->u.sec_obj->section.length,
1793 seg_hash->u.seg_obj->segment.offset);
1794 }
1795 (void) close(fd);
1796 if (retval != 0) {
1797 return (-1);
1798 }
1799 retval = cvrt_dim_data(spd_buf,
1800 sec_hash->u.sec_obj->section.length, &ptr, &len);
1801 if (retval != 0) {
1802 return (-1);
1803 }
1804 if (nbytes > len)
1805 nbytes = len;
1806 (void) memcpy(buffer, ptr, nbytes);
1807 free(ptr);
1808 break;
1809 }
1810
1811 default:
1812 return (-1);
1813 }
1814
1815 return (nbytes);
1816 }
1817
1818 /*
1819 * Description :
1820 * fru_write_segment() writes a raw segment.
1821 *
1822 * Arguments : segment_hdl_t :segment handle.
1823 * const void * : data buffer.
1824 * size_t : number of bytes.
1825 * segment_hdl_t : new segment handle.
1826 *
1827 * Returns :
1828 * int
1829 * On success, the number of bytes written is returned
1830 *
1831 */
1832 /*ARGSUSED*/
1833 int
fru_write_segment(segment_hdl_t segment,const void * data,size_t nbytes,segment_hdl_t * newsegment,door_cred_t * cred)1834 fru_write_segment(segment_hdl_t segment, const void *data, size_t nbytes,
1835 segment_hdl_t *newsegment, door_cred_t *cred)
1836 {
1837 return (ENOTSUP);
1838 }
1839
1840
1841 static int
get_packet(int device_fd,void * buffer,int size,int offset)1842 get_packet(int device_fd, void *buffer, int size, int offset)
1843 {
1844 int retval;
1845
1846 retval = pread(device_fd, (char *)buffer, size, offset);
1847 if (retval != -1) {
1848 return (0);
1849 }
1850 return (-1);
1851 }
1852
1853 static uint32_t
get_checksum_crc(hash_obj_t * seg_hash,int data_size)1854 get_checksum_crc(hash_obj_t *seg_hash, int data_size)
1855 {
1856 int protection;
1857 int offset = 0;
1858 uint32_t crc;
1859 hash_obj_t *sec_hash;
1860 hash_obj_t *pkt_hash;
1861 unsigned char *buffer;
1862
1863 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
1864 SECTION_TYPE);
1865 if (sec_hash == NULL) {
1866 return ((uint32_t)-1);
1867 }
1868
1869 buffer = alloca(data_size);
1870 if (buffer == NULL) {
1871 return ((uint32_t)-1);
1872 }
1873
1874 /* traverse the packet object list for all the tags and payload */
1875 for (pkt_hash = seg_hash->u.seg_obj->pkt_obj_list;
1876 pkt_hash != NULL; pkt_hash = pkt_hash->u.pkt_obj->next) {
1877 (void) memcpy(buffer + offset, &pkt_hash->u.pkt_obj->tag,
1878 pkt_hash->u.pkt_obj->tag_size);
1879 offset += pkt_hash->u.pkt_obj->tag_size;
1880 (void) memcpy(buffer + offset, pkt_hash->u.pkt_obj->payload,
1881 pkt_hash->u.pkt_obj->paylen);
1882 offset += pkt_hash->u.pkt_obj->paylen;
1883 }
1884
1885 protection = sec_hash->u.sec_obj->section.protection;
1886
1887 if (protection == READ_ONLY_SECTION) { /* read-only section */
1888 crc = compute_crc32(buffer, data_size);
1889 } else { /* read/write section */
1890 crc = compute_checksum32(buffer, data_size);
1891 }
1892 return (crc); /* computed crc */
1893 }
1894
1895 static int
get_dev_or_buffered_packets(hash_obj_t * seg_hash,int device_fd,int offset,int length,const char * buf)1896 get_dev_or_buffered_packets(hash_obj_t *seg_hash, int device_fd, int offset,
1897 int length, const char *buf)
1898 {
1899 int tag_size;
1900 int paylen;
1901 int retval;
1902 int seg_limit = 0;
1903 int pktcnt = 0;
1904 char *data;
1905 uint32_t crc;
1906 uint32_t origcrc;
1907 fru_tag_t tag;
1908 hash_obj_t *pkt_hash_obj;
1909 fru_segdesc_t *segdesc;
1910 fru_tagtype_t tagtype;
1911
1912 if (buf == NULL) {
1913 retval = get_packet(device_fd, &tag, sizeof (fru_tag_t),
1914 offset);
1915 if (retval == -1) {
1916 return (-1);
1917 }
1918 } else if (length - offset < sizeof (fru_tag_t)) {
1919 return (-1);
1920 } else {
1921 (void) memcpy(&tag, buf + offset, sizeof (fru_tag_t));
1922 }
1923
1924 seg_hash->u.seg_obj->trailer_offset = offset;
1925
1926 data = (char *)&tag;
1927 while (data[0] != SEG_TRAILER_TAG) {
1928 tagtype = get_tag_type(&tag); /* verify tag type */
1929 if (tagtype == -1) {
1930 return (-1);
1931 }
1932
1933 tag_size = get_tag_size(tagtype);
1934 if (tag_size == -1) {
1935 return (-1);
1936 }
1937
1938 seg_limit += tag_size;
1939 if (seg_limit > length) {
1940 return (-1);
1941 }
1942
1943 paylen = get_payload_length((void *)&tag);
1944 if (paylen == -1) {
1945 return (-1);
1946 }
1947
1948 seg_limit += paylen;
1949 if (seg_limit > length) {
1950 return (-1);
1951 }
1952
1953 pkt_hash_obj = create_packet_hash_object();
1954 if (pkt_hash_obj == NULL) {
1955 return (-1);
1956 }
1957
1958 pkt_hash_obj->u.pkt_obj->payload = malloc(paylen);
1959 if (pkt_hash_obj->u.pkt_obj->payload == NULL) {
1960 free(pkt_hash_obj);
1961 return (-1);
1962 }
1963
1964 offset += tag_size;
1965 if (buf == NULL) {
1966 retval = pread(device_fd,
1967 pkt_hash_obj->u.pkt_obj->payload, paylen, offset);
1968 } else if (paylen + offset > length) {
1969 retval = 0;
1970 } else {
1971 (void) memcpy(pkt_hash_obj->u.pkt_obj->payload,
1972 buf + offset, paylen);
1973 retval = paylen;
1974 }
1975 if (retval != paylen) {
1976 free(pkt_hash_obj->u.pkt_obj->payload);
1977 free(pkt_hash_obj);
1978 return (-1);
1979 }
1980
1981 /* don't change this */
1982 pkt_hash_obj->u.pkt_obj->tag.raw_data = 0;
1983 (void) memcpy(&pkt_hash_obj->u.pkt_obj->tag, &tag, tag_size);
1984 pkt_hash_obj->u.pkt_obj->paylen = paylen;
1985 pkt_hash_obj->u.pkt_obj->tag_size = tag_size;
1986 pkt_hash_obj->u.pkt_obj->payload_offset = offset;
1987
1988 offset += paylen;
1989
1990 add_hashobject_to_hashtable(pkt_hash_obj);
1991 add_to_pkt_object_list(seg_hash, pkt_hash_obj);
1992
1993 pktcnt++;
1994
1995 if (buf == NULL) {
1996 retval = get_packet(device_fd, &tag, sizeof (fru_tag_t),
1997 offset);
1998 if (retval == -1) {
1999 return (-1);
2000 }
2001 } else if (length - offset < sizeof (fru_tag_t)) {
2002 if (length - offset > 0) {
2003 /*
2004 * not enough data for a full fru_tag_t
2005 * just return what there is
2006 */
2007 (void) memset(&tag, 0, sizeof (fru_tag_t));
2008 (void) memcpy(&tag, buf + offset,
2009 length - offset);
2010 }
2011 } else {
2012 (void) memcpy(&tag, buf + offset, sizeof (fru_tag_t));
2013 }
2014
2015 data = (char *)&tag;
2016 }
2017
2018 segdesc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
2019
2020 seg_hash->u.seg_obj->trailer_offset = offset;
2021
2022 if (!segdesc->field.ignore_checksum) {
2023 crc = get_checksum_crc(seg_hash, seg_limit);
2024 offset = seg_hash->u.seg_obj->segment.offset;
2025
2026 if (buf == NULL) {
2027 retval = pread(device_fd, &origcrc, sizeof (origcrc),
2028 offset + seg_limit + 1);
2029 if (retval != sizeof (origcrc)) {
2030 return (-1);
2031 }
2032 } else if (length - offset < sizeof (origcrc)) {
2033 return (-1);
2034 } else {
2035 (void) memcpy(&origcrc, buf + seg_limit + 1,
2036 sizeof (origcrc));
2037 }
2038
2039 if (origcrc != crc) {
2040 seg_hash->u.seg_obj->trailer_offset = offset;
2041 }
2042 }
2043
2044 return (pktcnt);
2045 }
2046
2047 static int
get_packets(hash_obj_t * seg_hash,int device_fd,int offset,int length)2048 get_packets(hash_obj_t *seg_hash, int device_fd, int offset, int length)
2049 {
2050 return (get_dev_or_buffered_packets(seg_hash, device_fd, offset,
2051 length, NULL));
2052 }
2053
2054 static int
get_buffered_packets(hash_obj_t * seg_hash,const char * seg_buf,size_t seg_len)2055 get_buffered_packets(hash_obj_t *seg_hash, const char *seg_buf, size_t seg_len)
2056 {
2057 return (get_dev_or_buffered_packets(seg_hash, -1, 0, seg_len, seg_buf));
2058 }
2059
2060 /*
2061 * Description :
2062 * fru_get_num_packets() returns the current number of packets
2063 * in a segment.
2064 *
2065 * Arguments : segment_hdl_t : segment handle.
2066 *
2067 * Return :
2068 * int
2069 * On success, the number of packets is returned;
2070 * -1 on failure.
2071 */
2072 int
fru_get_num_packets(segment_hdl_t segment,door_cred_t * cred)2073 fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred)
2074 {
2075 int device_fd;
2076 int pktcnt;
2077 int length;
2078 uint16_t offset;
2079 hash_obj_t *cont_hash_obj;
2080 hash_obj_t *sec_hash;
2081 hash_obj_t *seg_hash;
2082 fru_segdesc_t *segdesc;
2083 segment_obj_t *segment_object;
2084
2085 seg_hash = lookup_handle_object(segment, SEGMENT_TYPE);
2086 if (seg_hash == NULL) {
2087 return (-1);
2088 }
2089
2090 segment_object = seg_hash->u.seg_obj;
2091 if (segment_object == NULL) {
2092 return (-1);
2093 }
2094
2095 segdesc = (fru_segdesc_t *)&segment_object->segment.descriptor;
2096 if (segdesc->field.opaque) {
2097 return (0);
2098 }
2099
2100 if (seg_hash->u.seg_obj->pkt_obj_list != NULL) {
2101 return (segment_object->num_of_packets);
2102 }
2103
2104 offset = segment_object->segment.offset;
2105 length = segment_object->segment.length;
2106
2107 /* section hash object */
2108 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
2109 SECTION_TYPE);
2110 if (sec_hash == NULL) {
2111 return (-1);
2112 }
2113
2114 segment_object->num_of_packets = 0;
2115
2116 switch (sec_hash->u.sec_obj->encoding) {
2117 case ENC_STANDARD:
2118 cont_hash_obj = get_container_hash_object(SEGMENT_TYPE,
2119 segment_object->section_hdl);
2120 if (cont_hash_obj == NULL) {
2121 return (-1);
2122 }
2123 device_fd = open(cont_hash_obj->u.cont_obj->device_pathname,
2124 O_RDWR);
2125 if (device_fd < 0) {
2126 return (-1);
2127 }
2128
2129 pktcnt = get_packets(seg_hash, device_fd, offset, length);
2130 (void) close(device_fd);
2131 break;
2132
2133 case ENC_SPD: {
2134 ssize_t spd_seg_len;
2135 size_t nbytes;
2136 char *seg_buf;
2137
2138 nbytes = segment_object->segment.length;
2139 seg_buf = alloca(nbytes);
2140 if (seg_buf == NULL)
2141 return (-1);
2142 spd_seg_len =
2143 fru_read_segment(segment, seg_buf, nbytes, cred);
2144 if (spd_seg_len < 0)
2145 return (-1);
2146 pktcnt = get_buffered_packets(seg_hash, seg_buf,
2147 spd_seg_len);
2148 break;
2149 }
2150
2151 default:
2152 return (-1);
2153 }
2154
2155 if (pktcnt == -1) {
2156 free_pkt_object_list(seg_hash);
2157 seg_hash->u.seg_obj->pkt_obj_list = NULL;
2158 }
2159
2160 segment_object->num_of_packets = pktcnt;
2161
2162 return (segment_object->num_of_packets);
2163 }
2164
2165
2166 /*
2167 * Description :
2168 * fru_get_packets() fills an array of structures representing the
2169 * packets in a segment.
2170 *
2171 * Arguments : segment_hdl_t : segment handle.
2172 * packet_t : packet buffer.
2173 * int : maximum number of packets.
2174 *
2175 * Return :
2176 * int
2177 * On success, the number of packet structures written is returned;
2178 * On failure -1 is returned;
2179 *
2180 */
2181
2182 /* ARGSUSED */
2183 int
fru_get_packets(segment_hdl_t segment,packet_t * packet,int maxpackets,door_cred_t * cred)2184 fru_get_packets(segment_hdl_t segment, packet_t *packet, int maxpackets,
2185 door_cred_t *cred)
2186 {
2187 int count;
2188 hash_obj_t *seg_hash_obj;
2189 hash_obj_t *pkt_hash_obj;
2190
2191 /* segment hash object */
2192 seg_hash_obj = lookup_handle_object(segment, SEGMENT_TYPE);
2193 if (seg_hash_obj == NULL) {
2194 return (-1);
2195 }
2196
2197 if (seg_hash_obj->u.seg_obj->num_of_packets != maxpackets) {
2198 return (-1);
2199 }
2200
2201 pkt_hash_obj = seg_hash_obj->u.seg_obj->pkt_obj_list;
2202 if (pkt_hash_obj == NULL) {
2203 return (-1);
2204 }
2205
2206 for (count = 0; count < maxpackets; count++, packet++) {
2207 packet->handle = pkt_hash_obj->obj_hdl;
2208 packet->tag = 0;
2209 (void) memcpy(&packet->tag, &pkt_hash_obj->u.pkt_obj->tag,
2210 pkt_hash_obj->u.pkt_obj->tag_size);
2211 pkt_hash_obj = pkt_hash_obj->u.pkt_obj->next;
2212 }
2213
2214 return (0);
2215 }
2216
2217 /*
2218 * Description :
2219 * fru_get_payload() copies the contents of a packet's payload.
2220 *
2221 * Arguments : packet_hdl_t : packet handle.
2222 * void * : payload buffer.
2223 * size_t : sizeof the buffer.
2224 *
2225 * Return :
2226 * int
2227 * On success, the number of bytes copied is returned; On error
2228 * -1 returned.
2229 */
2230
2231 /* ARGSUSED */
2232 ssize_t
fru_get_payload(packet_hdl_t packet,void * buffer,size_t nbytes,door_cred_t * cred)2233 fru_get_payload(packet_hdl_t packet, void *buffer, size_t nbytes,
2234 door_cred_t *cred)
2235 {
2236 hash_obj_t *packet_hash_obj;
2237
2238 /* packet hash object */
2239 packet_hash_obj = lookup_handle_object(packet, PACKET_TYPE);
2240 if (packet_hash_obj == NULL) {
2241 return (-1);
2242 }
2243
2244 /* verify payload length */
2245 if (nbytes != packet_hash_obj->u.pkt_obj->paylen) {
2246 return (-1);
2247 }
2248
2249 (void) memcpy(buffer, packet_hash_obj->u.pkt_obj->payload, nbytes);
2250 return (nbytes);
2251 }
2252
2253 /*
2254 * Description :
2255 * fru_update_payload() writes the contents of a packet's payload.
2256 *
2257 * Arguments : packet_hdl_t : packet handle.
2258 * const void * : data buffer.
2259 * size_t : buffer size.
2260 * packet_hdl_t : new packet handle.
2261 *
2262 * Return :
2263 * int
2264 * On success, 0 is returned; on failure
2265 * -1 is returned.
2266 */
2267
2268 int
fru_update_payload(packet_hdl_t packet,const void * data,size_t nbytes,packet_hdl_t * newpacket,door_cred_t * cred)2269 fru_update_payload(packet_hdl_t packet, const void *data, size_t nbytes,
2270 packet_hdl_t *newpacket, door_cred_t *cred)
2271 {
2272 int fd;
2273 int segment_offset;
2274 int trailer_offset;
2275 int retval;
2276 uint32_t crc;
2277 hash_obj_t *pkt_hash;
2278 hash_obj_t *seg_hash;
2279 hash_obj_t *sec_hash;
2280 hash_obj_t *cont_hash;
2281 fru_segdesc_t *desc;
2282
2283 /* check the effective uid of the client */
2284 if (cred->dc_euid != 0) {
2285 errno = EPERM;
2286 return (-1); /* not a root */
2287 }
2288
2289 /* packet hash object */
2290 pkt_hash = lookup_handle_object(packet, PACKET_TYPE);
2291 if (pkt_hash == NULL) {
2292 return (-1);
2293 }
2294
2295 /* segment hash object */
2296 seg_hash = lookup_handle_object(pkt_hash->u.pkt_obj->segment_hdl,
2297 SEGMENT_TYPE);
2298 if (seg_hash == NULL) {
2299 return (-1);
2300 }
2301
2302 /* check for write perm. */
2303 desc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
2304 if (!(desc->field.field_perm & SEGMENT_WRITE)) {
2305 errno = EPERM;
2306 return (-1); /* write not allowed */
2307 }
2308
2309 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
2310 SECTION_TYPE);
2311 if (sec_hash == NULL) {
2312 return (-1);
2313 }
2314
2315 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
2316 errno = EPERM;
2317 return (-1); /* read-only section */
2318 }
2319
2320 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
2321 CONTAINER_TYPE);
2322 if (cont_hash == NULL) {
2323 return (-1);
2324 }
2325
2326 if (pkt_hash->u.pkt_obj->paylen != nbytes) {
2327 return (-1);
2328 }
2329
2330 (void) memcpy(pkt_hash->u.pkt_obj->payload, (char *)data, nbytes);
2331 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR);
2332 if (fd < 0) {
2333 return (-1);
2334 }
2335
2336 trailer_offset = seg_hash->u.seg_obj->trailer_offset;
2337 segment_offset = seg_hash->u.seg_obj->segment.offset;
2338
2339 crc = get_checksum_crc(seg_hash, (trailer_offset - segment_offset));
2340 retval = pwrite(fd, data, nbytes, pkt_hash->u.pkt_obj->payload_offset);
2341 if (retval != nbytes) {
2342 (void) close(fd);
2343 return (-1);
2344 }
2345
2346 retval = pwrite(fd, &crc, sizeof (crc), trailer_offset + 1);
2347 (void) close(fd);
2348 if (retval != sizeof (crc)) {
2349 return (-1);
2350 }
2351 *newpacket = packet;
2352 return (0);
2353 }
2354
2355 /*
2356 * Description :
2357 * fru_append_packet() appends a packet to a segment.
2358 *
2359 * Arguments :
2360 * segment_hdl_t segment
2361 * A handle for the segment to which the packet will be appended.
2362 *
2363 * packet_t *packet
2364 * On entry, the "tag" component of "packet" specifies the tag
2365 * value for the added packet; the "handle" component is ignored.
2366 * On return, the "handle" component is set to the handle of the
2367 * appended packet.
2368 *
2369 * const void *payload
2370 * A pointer to the caller's buffer containing the payload data for
2371 * the appended packet.
2372 *
2373 * size_t nbytes
2374 * The size of the caller buffer.
2375 *
2376 * Return :
2377 * int
2378 * On success, 0 is returned; on error -1 is returned;
2379 */
2380
2381 int
fru_append_packet(segment_hdl_t segment,packet_t * packet,const void * payload,size_t nbytes,segment_hdl_t * newsegment,door_cred_t * cred)2382 fru_append_packet(segment_hdl_t segment, packet_t *packet, const void *payload,
2383 size_t nbytes, segment_hdl_t *newsegment, door_cred_t *cred)
2384 {
2385 int trailer_offset;
2386 int tag_size;
2387 int fd;
2388 int retval;
2389 char trailer[] = {0x0c, 0x00, 0x00, 0x00, 0x00};
2390 uint32_t crc;
2391 hash_obj_t *seg_hash;
2392 hash_obj_t *sec_hash;
2393 hash_obj_t *pkt_hash;
2394 hash_obj_t *cont_hash;
2395 fru_tagtype_t tagtype;
2396 fru_segdesc_t *desc;
2397
2398 /* check the effective uid of the client */
2399 if (cred->dc_euid != 0) {
2400 errno = EPERM;
2401 return (-1); /* not a root */
2402 }
2403
2404 seg_hash = lookup_handle_object(segment, SEGMENT_TYPE);
2405 if (seg_hash == NULL) {
2406 return (-1);
2407 }
2408
2409 /* check for write perm. */
2410 desc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
2411 if (!(desc->field.field_perm & SEGMENT_WRITE)) {
2412 errno = EPERM;
2413 return (-1); /* write not allowed */
2414 }
2415
2416 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
2417 SECTION_TYPE);
2418 if (sec_hash == NULL) {
2419 return (-1);
2420 }
2421
2422 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
2423 errno = EPERM;
2424 return (-1); /* read-only section */
2425 }
2426
2427 trailer_offset = seg_hash->u.seg_obj->trailer_offset;
2428
2429 /*
2430 * if trailer offset is 0 than parse the segment data to get the trailer
2431 * offset to compute the remaining space left in the segment area for
2432 * new packet to be added.
2433 */
2434 if (trailer_offset == 0) {
2435 (void) fru_get_num_packets(segment, cred);
2436 trailer_offset = seg_hash->u.seg_obj->trailer_offset;
2437 }
2438
2439 tagtype = get_tag_type((void *)&packet->tag);
2440 if (tagtype == -1) {
2441 return (-1);
2442 }
2443
2444 tag_size = get_tag_size(tagtype);
2445 if (tag_size == -1) {
2446 return (-1);
2447 }
2448
2449 if (seg_hash->u.seg_obj->segment.length >
2450 ((trailer_offset - seg_hash->u.seg_obj->segment.offset) +
2451 tag_size + nbytes + sizeof (char) + sizeof (uint32_t))) {
2452 /* create new packet hash */
2453 pkt_hash = create_packet_hash_object();
2454 if (pkt_hash == NULL) {
2455 return (-1);
2456 }
2457
2458 /* tag initialization */
2459 (void) memcpy(&pkt_hash->u.pkt_obj->tag, &packet->tag,
2460 tag_size);
2461 pkt_hash->u.pkt_obj->tag_size = tag_size;
2462
2463 /* payload inititalization */
2464 pkt_hash->u.pkt_obj->payload = malloc(nbytes);
2465 if (pkt_hash->u.pkt_obj->payload == NULL) {
2466 free(pkt_hash);
2467 return (-1);
2468 }
2469
2470 (void) memcpy(pkt_hash->u.pkt_obj->payload, payload, nbytes);
2471 pkt_hash->u.pkt_obj->paylen = nbytes;
2472 pkt_hash->u.pkt_obj->payload_offset = trailer_offset + tag_size;
2473
2474 /* add to hash table */
2475 add_hashobject_to_hashtable(pkt_hash);
2476
2477 add_to_pkt_object_list(seg_hash, pkt_hash);
2478
2479 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
2480 CONTAINER_TYPE);
2481 if (cont_hash == NULL) {
2482 return (-1);
2483 }
2484
2485 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR);
2486 if (fd < 0) {
2487 return (-1);
2488 }
2489
2490 /* update the trailer offset */
2491 trailer_offset += tag_size + nbytes;
2492
2493 /* calculate new checksum */
2494 crc = get_checksum_crc(seg_hash, (trailer_offset -
2495 seg_hash->u.seg_obj->segment.offset));
2496
2497 retval = pwrite(fd, &packet->tag, tag_size,
2498 trailer_offset - (tag_size + nbytes));
2499 if (retval != tag_size) {
2500 (void) close(fd);
2501 return (-1);
2502 }
2503
2504 retval = pwrite(fd, payload, nbytes, trailer_offset - nbytes);
2505 if (retval != nbytes) {
2506 (void) close(fd);
2507 return (-1);
2508 }
2509
2510 retval = pwrite(fd, trailer, sizeof (trailer), trailer_offset);
2511 if (retval != sizeof (trailer)) {
2512 (void) close(fd);
2513 return (-1);
2514 }
2515
2516 retval = pwrite(fd, &crc, sizeof (crc), trailer_offset + 1);
2517 (void) close(fd);
2518 if (retval != sizeof (crc)) {
2519 return (-1);
2520 }
2521
2522 seg_hash->u.seg_obj->trailer_offset = trailer_offset;
2523 seg_hash->u.seg_obj->num_of_packets += 1;
2524
2525 *newsegment = segment; /* return new segment handle */
2526 return (0);
2527 } else {
2528 errno = EAGAIN;
2529 }
2530
2531 return (-1);
2532 }
2533
2534 static void
adjust_packets(int fd,hash_obj_t * free_obj,hash_obj_t * object_list)2535 adjust_packets(int fd, hash_obj_t *free_obj, hash_obj_t *object_list)
2536 {
2537 int retval;
2538 uint32_t new_offset;
2539 hash_obj_t *hash_ptr;
2540
2541 new_offset = free_obj->u.pkt_obj->payload_offset -
2542 free_obj->u.pkt_obj->tag_size;
2543 for (hash_ptr = object_list;
2544 hash_ptr != NULL; hash_ptr = hash_ptr->u.pkt_obj->next) {
2545 retval = pwrite(fd, &hash_ptr->u.pkt_obj->tag,
2546 hash_ptr->u.pkt_obj->tag_size, new_offset);
2547 if (retval != hash_ptr->u.pkt_obj->tag_size) {
2548 return;
2549 }
2550 new_offset += hash_ptr->u.pkt_obj->tag_size;
2551 hash_ptr->u.pkt_obj->payload_offset = new_offset;
2552 retval = pwrite(fd, hash_ptr->u.pkt_obj->payload,
2553 hash_ptr->u.pkt_obj->paylen, new_offset);
2554 if (retval != hash_ptr->u.pkt_obj->paylen) {
2555 return;
2556 }
2557 new_offset += hash_ptr->u.pkt_obj->paylen;
2558 }
2559 }
2560
2561 static void
free_packet_object(handle_t handle,hash_obj_t * seg_hash)2562 free_packet_object(handle_t handle, hash_obj_t *seg_hash)
2563 {
2564 hash_obj_t *pkt_hash;
2565 hash_obj_t *next_hash;
2566
2567 pkt_hash = seg_hash->u.seg_obj->pkt_obj_list;
2568 if (pkt_hash == NULL) {
2569 return;
2570 }
2571
2572 if (pkt_hash->obj_hdl == handle) {
2573 seg_hash->u.seg_obj->pkt_obj_list = pkt_hash->u.pkt_obj->next;
2574 } else {
2575 while (pkt_hash->obj_hdl != handle) {
2576 next_hash = pkt_hash;
2577 pkt_hash = pkt_hash->u.pkt_obj->next;
2578 if (pkt_hash == NULL) {
2579 return;
2580 }
2581 }
2582 next_hash->u.pkt_obj->next = pkt_hash->u.pkt_obj->next;
2583 }
2584
2585 if (pkt_hash->prev == NULL) {
2586 hash_table[(pkt_hash->obj_hdl % TABLE_SIZE)] = pkt_hash->next;
2587 if (pkt_hash->next != NULL) {
2588 pkt_hash->next->prev = NULL;
2589 }
2590 } else {
2591 pkt_hash->prev->next = pkt_hash->next;
2592 if (pkt_hash->next != NULL) {
2593 pkt_hash->next->prev = pkt_hash->prev;
2594 }
2595 }
2596
2597 free(pkt_hash->u.pkt_obj->payload);
2598 free(pkt_hash->u.pkt_obj);
2599 free(pkt_hash);
2600 }
2601
2602 /*
2603 * Description :
2604 * fru_delete_packet() deletes a packet from a segment.
2605 *
2606 * Arguments : packet_hdl_t : packet number to be deleted.
2607 * segment_hdl_t : new segment handler.
2608 *
2609 * Return :
2610 * int
2611 * On success, 0 is returned; on error, -1.
2612 *
2613 * NOTES
2614 * Packets are adjacent; thus, deleting a packet requires moving
2615 * succeeding packets to compact the resulting hole.
2616 */
2617
2618 int
fru_delete_packet(packet_hdl_t packet,segment_hdl_t * newsegment,door_cred_t * cred)2619 fru_delete_packet(packet_hdl_t packet, segment_hdl_t *newsegment,
2620 door_cred_t *cred)
2621 {
2622 int retval;
2623 int fd;
2624 char trailer[] = { 0x0c, 0x00, 0x00, 0x00, 0x00};
2625 uint32_t crc;
2626 hash_obj_t *tmp_obj;
2627 hash_obj_t *pkt_hash;
2628 hash_obj_t *sec_hash;
2629 hash_obj_t *cont_hash;
2630 hash_obj_t *prev_obj;
2631 hash_obj_t *seg_hash;
2632 fru_segdesc_t *desc;
2633
2634 /* check the effective uid of the client */
2635 if (cred->dc_euid != 0) {
2636 errno = EPERM;
2637 return (-1); /* not a root */
2638 }
2639
2640 /* packet hash object */
2641 pkt_hash = lookup_handle_object(packet, PACKET_TYPE);
2642 if (pkt_hash == NULL) {
2643 return (-1);
2644 }
2645
2646 /* segment hash object */
2647 seg_hash = lookup_handle_object(pkt_hash->u.pkt_obj->segment_hdl,
2648 SEGMENT_TYPE);
2649 if (seg_hash == NULL) {
2650 return (-1);
2651 }
2652
2653 /* check for write perm. */
2654 desc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
2655 if (!(desc->field.field_perm & SEGMENT_WRITE)) {
2656 errno = EPERM;
2657 return (-1); /* write not allowed */
2658 }
2659
2660 /* section hash object */
2661 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
2662 SECTION_TYPE);
2663 if (sec_hash == NULL) {
2664 return (-1);
2665 }
2666
2667 if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
2668 errno = EPERM;
2669 return (-1); /* read-only section */
2670 }
2671
2672 prev_obj = seg_hash->u.seg_obj->pkt_obj_list;
2673 if (prev_obj == NULL) {
2674 return (-1);
2675 }
2676
2677 /* container hash object */
2678 cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
2679 CONTAINER_TYPE);
2680 if (cont_hash == NULL) {
2681 return (-1);
2682 }
2683
2684 fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR);
2685 if (fd < 0) {
2686 return (-1);
2687 }
2688
2689 if (prev_obj->obj_hdl == packet) { /* first object to be deleted */
2690 adjust_packets(fd, prev_obj, prev_obj->u.pkt_obj->next);
2691 seg_hash->u.seg_obj->trailer_offset -=
2692 (prev_obj->u.pkt_obj->tag_size +
2693 prev_obj->u.pkt_obj->paylen);
2694 free_packet_object(packet, seg_hash);
2695 } else {
2696 for (tmp_obj = prev_obj;
2697 tmp_obj != NULL; tmp_obj = tmp_obj->u.pkt_obj->next) {
2698 /* found the object */
2699 if (tmp_obj->obj_hdl == packet) {
2700 adjust_packets(fd, tmp_obj,
2701 tmp_obj->u.pkt_obj->next);
2702 seg_hash->u.seg_obj->trailer_offset -=
2703 (tmp_obj->u.pkt_obj->tag_size +
2704 tmp_obj->u.pkt_obj->paylen);
2705 free_packet_object(packet, seg_hash);
2706 }
2707 }
2708 }
2709
2710 seg_hash->u.seg_obj->num_of_packets -= 1;
2711
2712 /* calculate checksum */
2713 crc = get_checksum_crc(seg_hash, (seg_hash->u.seg_obj->trailer_offset -
2714 seg_hash->u.seg_obj->segment.offset));
2715 /* write trailer at new offset */
2716 retval = pwrite(fd, &trailer, sizeof (trailer),
2717 seg_hash->u.seg_obj->trailer_offset);
2718 if (retval != sizeof (trailer)) {
2719 (void) close(fd);
2720 return (-1);
2721 }
2722
2723 /* write the checksum value */
2724 retval = pwrite(fd, &crc, sizeof (crc),
2725 seg_hash->u.seg_obj->trailer_offset + 1);
2726 (void) close(fd);
2727 if (retval != sizeof (crc)) {
2728 return (-1);
2729 }
2730
2731 *newsegment = seg_hash->obj_hdl; /* return new segment handle */
2732 return (0);
2733 }
2734
2735 /*
2736 * Description :
2737 * fru_close_container() removes the association between a
2738 * container and its handle. this routines free's up all the
2739 * hash object contained under container.
2740 *
2741 * Arguments :
2742 * container_hdl_t holds the file descriptor of the fru.
2743 *
2744 * Return :
2745 * int
2746 * return 0.
2747 *
2748 */
2749
2750 /* ARGSUSED */
2751 int
fru_close_container(container_hdl_t container)2752 fru_close_container(container_hdl_t container)
2753 {
2754 hash_obj_t *hash_obj;
2755 hash_obj_t *prev_hash;
2756 hash_obj_t *sec_hash_obj;
2757 handle_t obj_hdl;
2758
2759 /* lookup for container hash object */
2760 hash_obj = lookup_handle_object(container, CONTAINER_TYPE);
2761 if (hash_obj == NULL) {
2762 return (0);
2763 }
2764
2765 /* points to section object list */
2766 sec_hash_obj = hash_obj->u.cont_obj->sec_obj_list;
2767
2768 /* traverse section object list */
2769 while (sec_hash_obj != NULL) {
2770
2771 /* traverse segment hash object in the section */
2772 while (sec_hash_obj->u.sec_obj->seg_obj_list != NULL) {
2773 /* object handle of the segment hash object */
2774 obj_hdl =
2775 sec_hash_obj->u.sec_obj->seg_obj_list->obj_hdl;
2776 free_segment_hash(obj_hdl, sec_hash_obj);
2777 }
2778
2779 /* going to free section hash object, relink the hash object */
2780 if (sec_hash_obj->prev == NULL) {
2781 hash_table[(sec_hash_obj->obj_hdl % TABLE_SIZE)] =
2782 sec_hash_obj->next;
2783 if (sec_hash_obj->next != NULL) {
2784 sec_hash_obj->next->prev = NULL;
2785 }
2786 } else {
2787 sec_hash_obj->prev->next = sec_hash_obj->next;
2788 if (sec_hash_obj->next != NULL) {
2789 sec_hash_obj->next->prev = sec_hash_obj->prev;
2790 }
2791 }
2792
2793 prev_hash = sec_hash_obj;
2794
2795 sec_hash_obj = sec_hash_obj->u.sec_obj->next;
2796
2797 free(prev_hash->u.sec_obj); /* free section hash object */
2798 free(prev_hash); /* free section hash */
2799 }
2800
2801 /* free container hash object */
2802 if (hash_obj->prev == NULL) {
2803 hash_table[(hash_obj->obj_hdl % TABLE_SIZE)] = hash_obj->next;
2804 if (hash_obj->next != NULL) {
2805 hash_obj->next->prev = NULL;
2806 }
2807 } else {
2808 hash_obj->prev->next = hash_obj->next;
2809 if (hash_obj->next != NULL) {
2810 hash_obj->next->prev = hash_obj->prev;
2811 }
2812 }
2813
2814 free(hash_obj->u.cont_obj);
2815 free(hash_obj);
2816 return (0);
2817 }
2818
2819 /*
2820 * Description :
2821 * fru_is_data_available() checks to see if the frudata
2822 * is available on a fru.
2823 *
2824 * Arguments :
2825 * picl_nodehdl_t holds the picl node handle of the fru.
2826 *
2827 * Return :
2828 * int
2829 * return 1: if FRUID information is available
2830 * return 0: if FRUID information is not present
2831 *
2832 */
2833
2834 /* ARGSUSED */
2835 int
fru_is_data_available(picl_nodehdl_t fru)2836 fru_is_data_available(picl_nodehdl_t fru)
2837 {
2838 return (0);
2839 }
2840