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/*
23 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <errno.h>
28
29#include "fru_tag.h"
30
31char *
32get_tagtype_str(fru_tagtype_t e)
33{
34	switch (e) {
35		case FRU_A:
36			return ("A");
37		case FRU_B:
38			return ("B");
39		case FRU_C:
40			return ("C");
41		case FRU_D:
42			return ("D");
43		case FRU_E:
44			return ("E");
45		case FRU_F:
46			return ("F");
47		case FRU_G:
48			return ("G");
49		case FRU_X:
50			return ("X");
51	}
52	return ("?");
53}
54
55size_t
56get_tag_size(fru_tagtype_t tag)
57{
58	switch (tag) {
59		case FRU_A:
60			return (1);
61		case FRU_B:
62		case FRU_C:
63			return (2);
64		case FRU_D:
65		case FRU_E:
66			return (3);
67		case FRU_F:
68			return (4);
69		case FRU_G:
70			return (6);
71	}
72	errno = EINVAL;
73	return (-1);
74}
75
76int
77mk_tag(fru_tagtype_t type, uint32_t dense, size_t pl_len,
78	fru_tag_t *tag)
79{
80	static fru_tag_t max = { 0xFFFFFFFFFFFFFFFFULL };
81	/* make sure the tag is clear. */
82	tag->raw_data = 0;
83
84	/* then fill it in with data. */
85	switch (type) {
86		case FRU_A:
87			if ((dense > max.a.dense) || (pl_len > max.a.pl_len)) {
88				errno = EINVAL;
89				return (-1);
90			}
91			tag->a.type = FRU_A_ID;
92			tag->a.dense = dense;
93			tag->a.pl_len = pl_len;
94			break;
95		case FRU_B:
96			if ((dense > max.b.dense) || (pl_len > max.b.pl_len)) {
97				errno = EINVAL;
98				return (-1);
99			}
100			tag->b.type = FRU_B_ID;
101			tag->b.dense = dense;
102			tag->b.pl_len = pl_len;
103			break;
104		case FRU_C:
105			if ((dense > max.c.dense) || (pl_len > max.c.pl_len)) {
106				errno = EINVAL;
107				return (-1);
108			}
109			tag->c.type = FRU_C_ID;
110			tag->c.dense = dense;
111			tag->c.pl_len = pl_len;
112			break;
113		case FRU_D:
114			if ((dense > max.d.dense) || (pl_len > max.d.pl_len)) {
115				errno = EINVAL;
116				return (-1);
117			}
118			tag->d.type = FRU_D_ID;
119			tag->d.dense = dense;
120			tag->d.pl_len = pl_len;
121			break;
122		case FRU_E:
123			if ((dense > max.e.dense) || (pl_len > max.e.pl_len)) {
124				errno = EINVAL;
125				return (-1);
126			}
127			tag->e.type = FRU_E_ID;
128			tag->e.dense = dense;
129			tag->e.pl_len = pl_len;
130			break;
131		case FRU_F:
132			if ((dense > max.f.dense) || (pl_len > max.f.pl_len)) {
133				errno = EINVAL;
134				return (-1);
135			}
136			tag->f.type = FRU_F_ID;
137			tag->f.dense = dense;
138			tag->f.pl_len = pl_len;
139			break;
140		case FRU_G:
141			if ((dense > max.g.dense) || (pl_len > max.g.pl_len)) {
142				errno = EINVAL;
143				return (-1);
144			}
145			tag->g.type = FRU_G_ID;
146			tag->g.dense = dense;
147			tag->g.pl_len = pl_len;
148			break;
149		default:
150			errno = EINVAL;
151			return (-1);
152	}
153
154	return (get_tag_size(type));
155}
156
157#if defined(_LITTLE_ENDIAN)
158fru_tagtype_t
159get_tag_type(fru_tag_t *tag)
160{
161	uint64_t tmp64;
162	uint32_t tmp32;
163	fru_tag_t tmp;
164
165	if (tag->a.type == FRU_A_ID)
166		return (FRU_A);
167
168	tmp.raw_data = (tag->byte[0] << 8) | tag->byte[1];
169	if (tmp.b.type == FRU_B_ID)
170		return (FRU_B);
171	if (tmp.c.type == FRU_C_ID)
172		return (FRU_C);
173
174	tmp32 = (tag->byte[0] << 16) | (tag->byte[1] << 8) | tag->byte[2];
175	tmp.raw_data = tmp32;
176	if (tmp.d.type == FRU_D_ID)
177		return (FRU_D);
178	if (tmp.e.type == FRU_E_ID)
179		return (FRU_E);
180
181	tmp32 = (tag->byte[0] << 24) | (tag->byte[1] << 16) |
182	    (tag->byte[2] << 8) | tag->byte[3];
183	tmp.raw_data = tmp32;
184	if (tmp.f.type == FRU_F_ID)
185		return (FRU_F);
186
187	tmp64 = ((uint64_t)tag->byte[0] << 40) |
188	    ((uint64_t)tag->byte[1] << 32) |
189	    ((uint64_t)tag->byte[2] << 24) |
190	    ((uint64_t)tag->byte[3] << 16) |
191	    ((uint64_t)tag->byte[4] << 8) |
192	    (uint64_t)tag->byte[5];
193	tmp.raw_data = tmp64;
194	if (tmp.g.type == FRU_G_ID)
195		return (FRU_G);
196
197	errno = EINVAL;
198	return (-1);
199}
200#else
201fru_tagtype_t
202get_tag_type(fru_tag_t *tag)
203{
204	if (tag->a.type == FRU_A_ID)
205		return (FRU_A);
206	else if (tag->b.type  == FRU_B_ID)
207		return (FRU_B);
208	else if (tag->c.type == FRU_C_ID)
209		return (FRU_C);
210	else if (tag->d.type == FRU_D_ID)
211		return (FRU_D);
212	else if (tag->e.type == FRU_E_ID)
213		return (FRU_E);
214	else if (tag->f.type == FRU_F_ID)
215		return (FRU_F);
216	else if (tag->g.type == FRU_G_ID)
217		return (FRU_G);
218	else
219		errno = EINVAL;
220		return (-1);
221}
222#endif  /* _LITTLE_ENDIAN */
223
224#if defined(_LITTLE_ENDIAN)
225uint32_t
226get_tag_dense(fru_tag_t *tag)
227{
228	uint64_t tmp64;
229	uint32_t tmp32;
230	fru_tag_t tmp;
231
232	tmp = *tag;
233	switch (get_tag_type(tag)) {
234		case FRU_A:
235			return (tag->a.dense);
236		case FRU_B:
237			tmp.raw_data = (tag->byte[0] << 8) | tag->byte[1];
238			return (tmp.b.dense);
239		case FRU_C:
240			tmp.raw_data = (tag->byte[0] << 8) | tag->byte[1];
241			return (tmp.c.dense);
242		case FRU_D:
243			tmp32 = (tag->byte[0] << 16) | (tag->byte[1] << 8) |
244			    tag->byte[2];
245			tmp.raw_data = tmp32;
246			return (tmp.d.dense);
247		case FRU_E:
248			tmp32 = (tag->byte[0] << 16) | (tag->byte[1] << 8) |
249			    tag->byte[2];
250			tmp.raw_data = tmp32;
251			return (tmp.e.dense);
252		case FRU_F:
253			tmp32 = (tag->byte[0] << 24) | (tag->byte[1] << 16) |
254			    (tag->byte[2] << 8) | tag->byte[3];
255			tmp.raw_data = tmp32;
256			return (tmp.f.dense);
257		case FRU_G:
258			tmp64 = ((uint64_t)tag->byte[0] << 40) |
259			    ((uint64_t)tag->byte[1] << 32) |
260			    ((uint64_t)tag->byte[2] << 24) |
261			    ((uint64_t)tag->byte[3] << 16) |
262			    ((uint64_t)tag->byte[4] << 8) |
263			    (uint64_t)tag->byte[5];
264			tmp.raw_data = tmp64;
265			return (tmp.g.dense);
266		default:
267			errno = EINVAL;
268			return ((uint32_t)-1);
269	}
270}
271#else
272uint32_t
273get_tag_dense(fru_tag_t *tag)
274{
275	switch (get_tag_type(tag)) {
276		case FRU_A:
277			return (tag->a.dense);
278		case FRU_B:
279			return (tag->b.dense);
280		case FRU_C:
281			return (tag->c.dense);
282		case FRU_D:
283			return (tag->d.dense);
284		case FRU_E:
285			return (tag->e.dense);
286		case FRU_F:
287			return (tag->f.dense);
288		case FRU_G:
289			return (tag->g.dense);
290		default:
291			errno = EINVAL;
292			return ((uint32_t)-1);
293	}
294}
295#endif  /* _LITTLE_ENDIAN */
296
297#if defined(_LITTLE_ENDIAN)
298size_t
299get_payload_length(fru_tag_t *tag)
300{
301	uint64_t tmp64;
302	uint32_t tmp32;
303	fru_tag_t tmp;
304
305	tmp = *tag;
306	switch (get_tag_type(tag)) {
307		case FRU_A:
308			return (tag->a.pl_len);
309		case FRU_B:
310			tmp.raw_data = (tag->byte[0] << 8) | tag->byte[1];
311			return (tmp.b.pl_len);
312		case FRU_C:
313			tmp.raw_data = (tag->byte[0] << 8) | tag->byte[1];
314			return (tmp.c.pl_len);
315		case FRU_D:
316			tmp32 = (tag->byte[0] << 16) | (tag->byte[1] << 8) |
317			    tag->byte[2];
318			tmp.raw_data = tmp32;
319			return (tmp.d.pl_len);
320		case FRU_E:
321			tmp32 = (tag->byte[0] << 16) | (tag->byte[1] << 8) |
322			    tag->byte[2];
323			tmp.raw_data = tmp32;
324			return (tmp.e.pl_len);
325		case FRU_F:
326			tmp32 = (tag->byte[0] << 24) | (tag->byte[1] << 16) |
327			    (tag->byte[2] << 8) | tag->byte[3];
328			tmp.raw_data = tmp32;
329			return (tmp.f.pl_len);
330		case FRU_G:
331			tmp64 = ((uint64_t)tag->byte[0] << 40) |
332			    ((uint64_t)tag->byte[1] << 32) |
333			    ((uint64_t)tag->byte[2] << 24) |
334			    ((uint64_t)tag->byte[3] << 16) |
335			    ((uint64_t)tag->byte[4] << 8) |
336			    (uint64_t)tag->byte[5];
337			tmp.raw_data = tmp64;
338			return (tmp.g.pl_len);
339		default:
340			errno = EINVAL;
341			return ((uint32_t)-1);
342	}
343}
344#else
345size_t
346get_payload_length(fru_tag_t *tag)
347{
348	switch (get_tag_type(tag)) {
349		case FRU_A:
350			return (tag->a.pl_len);
351		case FRU_B:
352			return (tag->b.pl_len);
353		case FRU_C:
354			return (tag->c.pl_len);
355		case FRU_D:
356			return (tag->d.pl_len);
357		case FRU_E:
358			return (tag->e.pl_len);
359		case FRU_F:
360			return (tag->f.pl_len);
361		case FRU_G:
362			return (tag->g.pl_len);
363		default:
364			errno = EINVAL;
365			return ((uint32_t)-1);
366	}
367}
368#endif  /* _LITTLE_ENDIAN */
369
370int
371tags_equal(fru_tag_t t1, fru_tag_t t2)
372{
373	return ((get_tag_type(&t1) == get_tag_type(&t2)) &&
374	    (get_tag_dense(&t1) == get_tag_dense(&t2)) &&
375	    (get_payload_length(&t1) == get_payload_length(&t2)));
376}
377