xref: /illumos-gate/usr/src/lib/libfruutils/fru_tag.c (revision defc4c8acfa01dba1ef3c13ca0cafccfcede51c0)
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 
31 char *
32 get_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 
55 size_t
56 get_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 
76 int
77 mk_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)
158 fru_tagtype_t
159 get_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
201 fru_tagtype_t
202 get_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)
225 uint32_t
226 get_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
272 uint32_t
273 get_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)
298 size_t
299 get_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
345 size_t
346 get_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 
370 int
371 tags_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