13798Seschrock /*
23798Seschrock  * CDDL HEADER START
33798Seschrock  *
43798Seschrock  * The contents of this file are subject to the terms of the
53798Seschrock  * Common Development and Distribution License (the "License").
63798Seschrock  * You may not use this file except in compliance with the License.
73798Seschrock  *
83798Seschrock  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93798Seschrock  * or http://www.opensolaris.org/os/licensing.
103798Seschrock  * See the License for the specific language governing permissions
113798Seschrock  * and limitations under the License.
123798Seschrock  *
133798Seschrock  * When distributing Covered Code, include this CDDL HEADER in each
143798Seschrock  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153798Seschrock  * If applicable, add the following below this CDDL HEADER, with the
163798Seschrock  * fields enclosed by brackets "[]" replaced with your own identifying
173798Seschrock  * information: Portions Copyright [yyyy] [name of copyright owner]
183798Seschrock  *
193798Seschrock  * CDDL HEADER END
203798Seschrock  */
213798Seschrock /*
22*6070Srobj  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
233798Seschrock  * Use is subject to license terms.
243798Seschrock  */
253798Seschrock 
263798Seschrock #pragma ident	"%Z%%M%	%I%	%E% SMI"
273798Seschrock 
283798Seschrock #include <libipmi.h>
293798Seschrock #include <stdio.h>
303798Seschrock #include <stdlib.h>
313798Seschrock #include <string.h>
323798Seschrock #include <stdarg.h>
333798Seschrock 
343798Seschrock #include "ipmi_impl.h"
353798Seschrock 
363798Seschrock /*
37*6070Srobj  * Extracts bits between index h (high, inclusive) and l (low, exclusive) from
38*6070Srobj  * u, which must be an unsigned integer.
39*6070Srobj  */
40*6070Srobj #define	BITX(u, h, l)	(((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
41*6070Srobj 
42*6070Srobj /*
433798Seschrock  * Error handling
443798Seschrock  */
453798Seschrock int
463798Seschrock ipmi_set_error(ipmi_handle_t *ihp, int error, const char *fmt, ...)
473798Seschrock {
483798Seschrock 	va_list ap;
493798Seschrock 
503798Seschrock 	va_start(ap, fmt);
513798Seschrock 
523798Seschrock 	ihp->ih_errno = error;
533798Seschrock 	if (fmt == NULL)
543798Seschrock 		ihp->ih_errmsg[0] = '\0';
553798Seschrock 	else
563798Seschrock 		(void) vsnprintf(ihp->ih_errmsg, sizeof (ihp->ih_errmsg),
573798Seschrock 		    fmt, ap);
583798Seschrock 	va_end(ap);
593798Seschrock 
603798Seschrock 	return (-1);
613798Seschrock }
623798Seschrock 
633798Seschrock int
643798Seschrock ipmi_errno(ipmi_handle_t *ihp)
653798Seschrock {
663798Seschrock 	return (ihp->ih_errno);
673798Seschrock }
683798Seschrock 
693798Seschrock /* ARGSUSED */
703798Seschrock const char *
713798Seschrock ipmi_errmsg(ipmi_handle_t *ihp)
723798Seschrock {
733798Seschrock 	int i;
743798Seschrock 	const char *str;
753798Seschrock 
763798Seschrock 	str = NULL;
77*6070Srobj 	for (i = 0; ipmi_errno_table[i].int_name != NULL; i++) {
78*6070Srobj 		if (ipmi_errno_table[i].int_value == ihp->ih_errno) {
79*6070Srobj 			str = ipmi_errno_table[i].int_name;
803798Seschrock 			break;
813798Seschrock 		}
823798Seschrock 	}
833798Seschrock 
843798Seschrock 	if (str == NULL && (str = strerror(ihp->ih_errno)) == NULL)
853798Seschrock 		str = "unknown failure";
863798Seschrock 
873798Seschrock 	if (ihp->ih_errmsg[0] == '\0')
883798Seschrock 		return (str);
893798Seschrock 
903798Seschrock 	(void) snprintf(ihp->ih_errbuf, sizeof (ihp->ih_errbuf),
913798Seschrock 	    "%s: %s", str, ihp->ih_errmsg);
923798Seschrock 	return (ihp->ih_errbuf);
933798Seschrock }
943798Seschrock 
953798Seschrock /*
963798Seschrock  * Memory allocation
973798Seschrock  */
983798Seschrock void *
993798Seschrock ipmi_alloc(ipmi_handle_t *ihp, size_t size)
1003798Seschrock {
1013798Seschrock 	void *ptr;
1023798Seschrock 
1033798Seschrock 	if ((ptr = malloc(size)) == NULL)
1043798Seschrock 		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
1053798Seschrock 
1063798Seschrock 	return (ptr);
1073798Seschrock }
1083798Seschrock 
1093798Seschrock void *
1103798Seschrock ipmi_zalloc(ipmi_handle_t *ihp, size_t size)
1113798Seschrock {
1123798Seschrock 	void *ptr;
1133798Seschrock 
1143798Seschrock 	if ((ptr = calloc(size, 1)) == NULL)
1153798Seschrock 		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
1163798Seschrock 
1173798Seschrock 	return (ptr);
1183798Seschrock }
1193798Seschrock 
1205345Seschrock char *
1215345Seschrock ipmi_strdup(ipmi_handle_t *ihp, const char *str)
1225345Seschrock {
1235345Seschrock 	char *ptr;
1245345Seschrock 
1255345Seschrock 	if ((ptr = strdup(str)) == NULL)
1265345Seschrock 		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
1275345Seschrock 
1285345Seschrock 	return (ptr);
1295345Seschrock }
1305345Seschrock 
1313798Seschrock /* ARGSUSED */
1323798Seschrock void
1333798Seschrock ipmi_free(ipmi_handle_t *ihp, void *ptr)
1343798Seschrock {
1353798Seschrock 	free(ptr);
1363798Seschrock }
137*6070Srobj 
138*6070Srobj /*
139*6070Srobj  * Translation between #defines and strings.
140*6070Srobj  */
141*6070Srobj void
142*6070Srobj ipmi_entity_name(uint8_t id, char *buf, size_t len)
143*6070Srobj {
144*6070Srobj 	ipmi_name_trans_t *ntp;
145*6070Srobj 
146*6070Srobj 	for (ntp = &ipmi_entity_table[0]; ntp->int_name != NULL; ntp++) {
147*6070Srobj 		if (ntp->int_value == id) {
148*6070Srobj 			(void) strlcpy(buf, ntp->int_name, len);
149*6070Srobj 			return;
150*6070Srobj 		}
151*6070Srobj 	}
152*6070Srobj 
153*6070Srobj 	(void) snprintf(buf, len, "0x%02x", id);
154*6070Srobj }
155*6070Srobj 
156*6070Srobj void
157*6070Srobj ipmi_sensor_type_name(uint8_t type, char *buf, size_t len)
158*6070Srobj {
159*6070Srobj 	ipmi_name_trans_t *ntp;
160*6070Srobj 
161*6070Srobj 	for (ntp = &ipmi_sensor_type_table[0]; ntp->int_name != NULL; ntp++) {
162*6070Srobj 		if (ntp->int_value == type) {
163*6070Srobj 			(void) strlcpy(buf, ntp->int_name, len);
164*6070Srobj 			return;
165*6070Srobj 		}
166*6070Srobj 	}
167*6070Srobj 
168*6070Srobj 	(void) snprintf(buf, len, "0x%02x", type);
169*6070Srobj }
170*6070Srobj 
171*6070Srobj void
172*6070Srobj ipmi_sensor_reading_name(uint8_t sensor_type, uint8_t reading_type,
173*6070Srobj     char *buf, size_t len)
174*6070Srobj {
175*6070Srobj 	uint8_t val;
176*6070Srobj 	ipmi_name_trans_t *ntp;
177*6070Srobj 
178*6070Srobj 	if (reading_type == IPMI_RT_SPECIFIC) {
179*6070Srobj 		val = sensor_type;
180*6070Srobj 		ntp = &ipmi_sensor_type_table[0];
181*6070Srobj 	} else {
182*6070Srobj 		val = reading_type;
183*6070Srobj 		ntp = &ipmi_reading_type_table[0];
184*6070Srobj 	}
185*6070Srobj 
186*6070Srobj 	for (; ntp->int_name != NULL; ntp++) {
187*6070Srobj 		if (ntp->int_value == val) {
188*6070Srobj 			(void) strlcpy(buf, ntp->int_name, len);
189*6070Srobj 			return;
190*6070Srobj 		}
191*6070Srobj 	}
192*6070Srobj 
193*6070Srobj 	if (reading_type == IPMI_RT_SPECIFIC)
194*6070Srobj 		(void) snprintf(buf, len, "%02x/%02x", reading_type,
195*6070Srobj 		    sensor_type);
196*6070Srobj 	else
197*6070Srobj 		(void) snprintf(buf, len, "%02x", reading_type);
198*6070Srobj }
199*6070Srobj 
200*6070Srobj /*
201*6070Srobj  * Converts a BCD decimal value to an integer.
202*6070Srobj  */
203*6070Srobj int
204*6070Srobj ipmi_convert_bcd(int value)
205*6070Srobj {
206*6070Srobj 	int ret = 0;
207*6070Srobj 	int digit;
208*6070Srobj 	int i;
209*6070Srobj 
210*6070Srobj 	for (i = 7; i >= 0; i--) {
211*6070Srobj 		digit = ((value & (0xf << (i * 4))) >> (i * 4));
212*6070Srobj 		ret += digit * 10 * i;
213*6070Srobj 	}
214*6070Srobj 
215*6070Srobj 	return (ret);
216*6070Srobj }
217*6070Srobj 
218*6070Srobj /*
219*6070Srobj  * See sections 43.15 and 43.16
220*6070Srobj  *
221*6070Srobj  * This is a utility function for decoding the strings that are packed into
222*6070Srobj  * sensor data records.  If the type is 6-bit packed ASCII, then it converts
223*6070Srobj  * the string to an 8-bit ASCII string and copies that into the suuplied buffer.
224*6070Srobj  * If it is 8-bit ASCII, it copies the string into the supplied buffer as-is.
225*6070Srobj  */
226*6070Srobj void
227*6070Srobj ipmi_decode_string(uint8_t type, uint8_t len, char *data, char *buf)
228*6070Srobj {
229*6070Srobj 	int i, j = 0, chunks, leftovers;
230*6070Srobj 	uint8_t tmp, lo;
231*6070Srobj 
232*6070Srobj 	if (len == 0) {
233*6070Srobj 		*buf = '\0';
234*6070Srobj 		return;
235*6070Srobj 	}
236*6070Srobj 	/*
237*6070Srobj 	 * If the type is 8-bit ASCII, we can simply copy the string and return
238*6070Srobj 	 */
239*6070Srobj 	if (type == 0x3) {
240*6070Srobj 		(void) strncpy(buf, data, len);
241*6070Srobj 		*(buf+len) = '\0';
242*6070Srobj 		return;
243*6070Srobj 	} else if (type == 0x1 || type == 0x0) {
244*6070Srobj 		/*
245*6070Srobj 		 * Yuck - they either used BCD plus encoding, which we don't
246*6070Srobj 		 * currently handle, or they used an unspecified encoding type.
247*6070Srobj 		 * In these cases we'll set buf to an empty string.  We still
248*6070Srobj 		 * need to return the length so that we can get to the next
249*6070Srobj 		 * record.
250*6070Srobj 		 */
251*6070Srobj 		*buf = '\0';
252*6070Srobj 		return;
253*6070Srobj 	}
254*6070Srobj 
255*6070Srobj 	/*
256*6070Srobj 	 * Otherwise, it's 6-bit packed ASCII, so we have to convert the
257*6070Srobj 	 * data first
258*6070Srobj 	 */
259*6070Srobj 	chunks = len / 3;
260*6070Srobj 	leftovers = len % 3;
261*6070Srobj 
262*6070Srobj 	/*
263*6070Srobj 	 * First we decode the 6-bit string in chunks of 3 bytes as far as
264*6070Srobj 	 * possible
265*6070Srobj 	 */
266*6070Srobj 	for (i = 0; i < chunks; i++) {
267*6070Srobj 		tmp = BITX(*(data+j), 5, 0);
268*6070Srobj 		*buf++ = (char)(tmp + 32);
269*6070Srobj 
270*6070Srobj 		lo = BITX(*(data+j++), 7, 6);
271*6070Srobj 		tmp = BITX(*(data+j), 3, 0);
272*6070Srobj 		tmp = (tmp << 2) | lo;
273*6070Srobj 		*buf++ = (char)(tmp + 32);
274*6070Srobj 
275*6070Srobj 		lo = BITX(*(data+j++), 7, 4);
276*6070Srobj 		tmp = BITX(*(data+j), 1, 0);
277*6070Srobj 		tmp = (tmp << 4) | lo;
278*6070Srobj 		*buf++ = (char)(tmp + 32);
279*6070Srobj 
280*6070Srobj 		tmp = BITX(*(data+j++), 7, 2);
281*6070Srobj 		*buf++ = (char)(tmp + 32);
282*6070Srobj 	}
283*6070Srobj 	switch (leftovers) {
284*6070Srobj 		case 1:
285*6070Srobj 			tmp = BITX(*(data+j), 5, 0);
286*6070Srobj 			*buf++ = (char)(tmp + 32);
287*6070Srobj 			break;
288*6070Srobj 		case 2:
289*6070Srobj 			tmp = BITX(*(data+j), 5, 0);
290*6070Srobj 			*buf++ = (char)(tmp + 32);
291*6070Srobj 
292*6070Srobj 			lo = BITX(*(data+j++), 7, 6);
293*6070Srobj 			tmp = BITX(*(data+j), 3, 0);
294*6070Srobj 			tmp = (tmp << 2) | lo;
295*6070Srobj 			*buf++ = (char)(tmp + 32);
296*6070Srobj 			break;
297*6070Srobj 	}
298*6070Srobj 	*buf = '\0';
299*6070Srobj }
300