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