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.
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.
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]
23 * Copyright (c) 2014 Gary Mills
25 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
34 #include <sys/byteorder.h>
35 #include <sys/types.h>
36 #include <sys/nvpair.h>
41 #include "libfrureg.h"
44 #define NUM_ITER_BYTES 4
49 #define TIMESTRINGLEN 128
53 static pthread_mutex_t gLock
= PTHREAD_MUTEX_INITIALIZER
;
58 convert_field(const uint8_t *field
, const fru_regdef_t
*def
, const char *path
,
61 char timestring
[TIMESTRINGLEN
];
66 switch (def
->dataType
) {
68 assert(def
->payloadLen
<= sizeof (value
));
69 switch (def
->dispType
) {
72 if (def
->payloadLen
> sizeof (timefield
)) {
73 /* too big for formatting */
76 (void) memcpy(&timefield
, field
, sizeof (timefield
));
77 timefield
= BE_32(timefield
);
78 if (strftime(timestring
, sizeof (timestring
), "%c",
79 localtime(&timefield
)) == 0) {
80 /* buffer too small */
83 (void) nvlist_add_string(nv
, path
, timestring
);
93 (void) memcpy((((uint8_t *)&value
) +
94 sizeof (value
) - def
->payloadLen
),
95 field
, def
->payloadLen
);
97 switch (def
->payloadLen
) {
99 (void) nvlist_add_uint8(nv
, path
,
103 (void) nvlist_add_uint16(nv
, path
,
107 (void) nvlist_add_uint32(nv
, path
,
111 (void) nvlist_add_uint64(nv
, path
, value
);
117 (void) nvlist_add_string(nv
, path
, (char *)field
);
120 case FDTYPE_Enumeration
:
122 (void) memcpy((((uint8_t *)&value
) + sizeof (value
) -
123 def
->payloadLen
), field
, def
->payloadLen
);
124 value
= BE_64(value
);
125 for (i
= 0; i
< def
->enumCount
; i
++) {
126 if (def
->enumTable
[i
].value
== value
) {
127 (void) nvlist_add_string(nv
, path
,
128 def
->enumTable
[i
].text
);
134 /* nothing matched above, use byte array */
135 (void) nvlist_add_byte_array(nv
, path
, (uchar_t
*)field
,
142 convert_element(const uint8_t *data
, const fru_regdef_t
*def
, char *ppath
,
143 nvlist_t
*nv
, boolean_t from_iter
)
149 if ((def
->iterationCount
== 0) &&
150 (def
->iterationType
!= FRU_NOT_ITERATED
)) {
153 path
= (char *)def
->name
;
156 /* iteration, record and field */
157 if (def
->iterationCount
) {
164 iterlen
= (def
->payloadLen
- NUM_ITER_BYTES
) /
168 * make a new element definition to describe the components of
171 (void) memcpy(&newdef
, def
, sizeof (newdef
));
172 newdef
.iterationCount
= 0;
173 newdef
.payloadLen
= iterlen
;
175 /* validate the content of the iteration control bytes */
176 if ((data
[HEAD_ITER
] >= def
->iterationCount
) ||
177 (data
[NUM_ITER
] > def
->iterationCount
) ||
178 (data
[MAX_ITER
] != def
->iterationCount
)) {
179 /* invalid. show all iterations */
181 num
= def
->iterationCount
;
183 head
= data
[HEAD_ITER
];
184 num
= data
[NUM_ITER
];
187 nv_elems
= (nvlist_t
**)malloc(num
* sizeof (nvlist_t
*));
190 for (i
= head
, n
= 0, data
+= sizeof (uint32_t); n
< num
;
191 i
= ((i
+ 1) % def
->iterationCount
), n
++) {
192 if (nvlist_alloc(&nv_elems
[n
], NV_UNIQUE_NAME
, 0) != 0)
194 (void) snprintf(num_str
, sizeof (num_str
), "%d", n
);
195 convert_element((data
+ i
*iterlen
), &newdef
, num_str
,
196 nv_elems
[n
], B_TRUE
);
198 (void) nvlist_add_nvlist_array(nv
, path
, nv_elems
, num
);
200 } else if (def
->dataType
== FDTYPE_Record
) {
201 const fru_regdef_t
*component
;
205 if (nvlist_alloc(&nv_record
, NV_UNIQUE_NAME
, 0) != 0) {
212 for (i
= 0; i
< def
->enumCount
; i
++,
213 data
+= component
->payloadLen
) {
214 component
= fru_reg_lookup_def_by_name(
215 def
->enumTable
[i
].text
);
216 convert_element(data
, component
, "", nv_record
,
220 (void) nvlist_add_nvlist(nv
, path
, nv_record
);
223 convert_field(data
, def
, path
, nv
);
228 static fru_regdef_t
*
229 alloc_unknown_fru_regdef(void)
233 p
= malloc(sizeof (fru_regdef_t
));
237 p
->version
= REGDEF_VERSION
;
243 p
->dataType
= FDTYPE_ByteArray
;
244 p
->dispType
= FDISP_Hex
;
245 p
->purgeable
= FRU_WHICH_UNDEFINED
;
246 p
->relocatable
= FRU_WHICH_UNDEFINED
;
248 p
-> enumTable
= NULL
;
249 p
->iterationCount
= 0;
250 p
->iterationType
= FRU_NOT_ITERATED
;
251 p
->exampleString
= NULL
;
257 convert_packet(fru_tag_t
*tag
, uint8_t *payload
, size_t length
, void *args
)
260 size_t payload_length
;
261 const fru_regdef_t
*def
;
262 nvlist_t
*nv
= (nvlist_t
*)args
;
263 char tagname
[sizeof ("?_0123456789_0123456789")];
264 tag_type
= get_tag_type(tag
);
267 /* check for unrecognized tag */
268 if ((tag_type
== -1) ||
269 ((payload_length
= get_payload_length(tag
)) != length
)) {
270 fru_regdef_t
*unknown
;
272 unknown
= alloc_unknown_fru_regdef();
273 unknown
->payloadLen
= length
;
274 unknown
->dataLength
= unknown
->payloadLen
;
276 if (tag_type
== -1) {
277 (void) snprintf(tagname
, sizeof (tagname
),
280 (void) snprintf(tagname
, sizeof (tagname
),
281 "%s_%u_%u_%u", get_tagtype_str(tag_type
),
282 get_tag_dense(tag
), payload_length
, length
);
284 unknown
->name
= tagname
;
285 convert_element(payload
, unknown
, "", nv
, B_FALSE
);
288 } else if ((def
= fru_reg_lookup_def_by_tag(*tag
)) == NULL
) {
289 fru_regdef_t
*unknown
;
291 unknown
= alloc_unknown_fru_regdef();
292 unknown
->payloadLen
= length
;
293 unknown
->dataLength
= unknown
->payloadLen
;
295 (void) snprintf(tagname
, sizeof (tagname
), "%s_%u_%u",
296 get_tagtype_str(tag_type
),
297 unknown
->tagDense
, payload_length
);
299 unknown
->name
= tagname
;
300 convert_element(payload
, unknown
, "", nv
, B_FALSE
);
305 convert_element(payload
, def
, "", nv
, B_FALSE
);
309 return (FRU_SUCCESS
);
314 convert_packets_in_segment(fru_seghdl_t segment
, void *args
)
318 nvlist_t
*nv
= (nvlist_t
*)args
;
319 nvlist_t
*nv_segment
;
321 ret
= fru_get_segment_name(segment
, &name
);
322 if (ret
!= FRU_SUCCESS
) {
326 /* create a new nvlist for each segment */
327 ret
= nvlist_alloc(&nv_segment
, NV_UNIQUE_NAME
, 0);
330 return (FRU_FAILURE
);
333 /* convert the segment to an nvlist */
334 ret
= fru_for_each_packet(segment
, convert_packet
, nv_segment
);
335 if (ret
!= FRU_SUCCESS
) {
336 nvlist_free(nv_segment
);
341 /* add the nvlist for this segment */
342 (void) nvlist_add_nvlist(nv
, name
, nv_segment
);
346 return (FRU_SUCCESS
);
351 convert_fru(fru_nodehdl_t hdl
, nvlist_t
**nvlist
)
357 if (fru_get_node_type(hdl
, &fru_type
) != FRU_SUCCESS
) {
361 if (fru_type
!= FRU_NODE_CONTAINER
) {
365 err
= nvlist_alloc(&nv
, NV_UNIQUE_NAME
, 0);
370 if (fru_for_each_segment(hdl
, convert_packets_in_segment
, nv
) !=
383 rawfru_to_nvlist(uint8_t *buffer
, size_t bufsize
, char *cont_type
,
390 (void) pthread_mutex_lock(&gLock
);
391 fru_err
= fru_open_data_source("raw", buffer
, bufsize
, cont_type
,
393 if (fru_err
!= FRU_SUCCESS
) {
394 (void) pthread_mutex_unlock(&gLock
);
397 fru_err
= fru_get_root(&hdl
);
398 if (fru_err
!= FRU_SUCCESS
) {
399 (void) pthread_mutex_unlock(&gLock
);
403 err
= convert_fru(hdl
, nvlist
);
405 fru_close_data_source();
407 (void) pthread_mutex_unlock(&gLock
);