xref: /onnv-gate/usr/src/lib/libipmi/common/ipmi_util.c (revision 7243:2f11e164daec)
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 /*
226070Srobj  * 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 /*
376070Srobj  * Extracts bits between index h (high, inclusive) and l (low, exclusive) from
386070Srobj  * u, which must be an unsigned integer.
396070Srobj  */
406070Srobj #define	BITX(u, h, l)	(((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
416070Srobj 
426070Srobj /*
433798Seschrock  * Error handling
443798Seschrock  */
453798Seschrock int
ipmi_set_error(ipmi_handle_t * ihp,int error,const char * fmt,...)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
ipmi_errno(ipmi_handle_t * ihp)643798Seschrock ipmi_errno(ipmi_handle_t *ihp)
653798Seschrock {
663798Seschrock 	return (ihp->ih_errno);
673798Seschrock }
683798Seschrock 
693798Seschrock /* ARGSUSED */
703798Seschrock const char *
ipmi_errmsg(ipmi_handle_t * ihp)713798Seschrock ipmi_errmsg(ipmi_handle_t *ihp)
723798Seschrock {
733798Seschrock 	int i;
743798Seschrock 	const char *str;
753798Seschrock 
763798Seschrock 	str = NULL;
776070Srobj 	for (i = 0; ipmi_errno_table[i].int_name != NULL; i++) {
786070Srobj 		if (ipmi_errno_table[i].int_value == ihp->ih_errno) {
796070Srobj 			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 *
ipmi_alloc(ipmi_handle_t * ihp,size_t size)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 *
ipmi_zalloc(ipmi_handle_t * ihp,size_t size)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 *
ipmi_strdup(ipmi_handle_t * ihp,const char * str)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
ipmi_free(ipmi_handle_t * ihp,void * ptr)1333798Seschrock ipmi_free(ipmi_handle_t *ihp, void *ptr)
1343798Seschrock {
1353798Seschrock 	free(ptr);
1363798Seschrock }
1376070Srobj 
1386070Srobj /*
1396070Srobj  * Translation between #defines and strings.
1406070Srobj  */
1416070Srobj void
ipmi_entity_name(uint8_t id,char * buf,size_t len)1426070Srobj ipmi_entity_name(uint8_t id, char *buf, size_t len)
1436070Srobj {
1446070Srobj 	ipmi_name_trans_t *ntp;
1456070Srobj 
1466070Srobj 	for (ntp = &ipmi_entity_table[0]; ntp->int_name != NULL; ntp++) {
1476070Srobj 		if (ntp->int_value == id) {
1486070Srobj 			(void) strlcpy(buf, ntp->int_name, len);
1496070Srobj 			return;
1506070Srobj 		}
1516070Srobj 	}
1526070Srobj 
1536070Srobj 	(void) snprintf(buf, len, "0x%02x", id);
1546070Srobj }
1556070Srobj 
1566070Srobj void
ipmi_sensor_type_name(uint8_t type,char * buf,size_t len)1576070Srobj ipmi_sensor_type_name(uint8_t type, char *buf, size_t len)
1586070Srobj {
1596070Srobj 	ipmi_name_trans_t *ntp;
1606070Srobj 
1616070Srobj 	for (ntp = &ipmi_sensor_type_table[0]; ntp->int_name != NULL; ntp++) {
1626070Srobj 		if (ntp->int_value == type) {
1636070Srobj 			(void) strlcpy(buf, ntp->int_name, len);
1646070Srobj 			return;
1656070Srobj 		}
1666070Srobj 	}
1676070Srobj 
1686070Srobj 	(void) snprintf(buf, len, "0x%02x", type);
1696070Srobj }
1706070Srobj 
1716070Srobj void
ipmi_sensor_units_name(uint8_t type,char * buf,size_t len)172*7243Srobj ipmi_sensor_units_name(uint8_t type, char *buf, size_t len)
173*7243Srobj {
174*7243Srobj 	ipmi_name_trans_t *ntp;
175*7243Srobj 
176*7243Srobj 	for (ntp = &ipmi_units_type_table[0]; ntp->int_name != NULL; ntp++) {
177*7243Srobj 		if (ntp->int_value == type) {
178*7243Srobj 			(void) strlcpy(buf, ntp->int_name, len);
179*7243Srobj 			return;
180*7243Srobj 		}
181*7243Srobj 	}
182*7243Srobj 
183*7243Srobj 	(void) snprintf(buf, len, "0x%02x", type);
184*7243Srobj }
185*7243Srobj 
186*7243Srobj void
ipmi_sensor_reading_name(uint8_t sensor_type,uint8_t reading_type,char * buf,size_t len)1876070Srobj ipmi_sensor_reading_name(uint8_t sensor_type, uint8_t reading_type,
1886070Srobj     char *buf, size_t len)
1896070Srobj {
1906070Srobj 	uint8_t val;
1916070Srobj 	ipmi_name_trans_t *ntp;
1926070Srobj 
1936070Srobj 	if (reading_type == IPMI_RT_SPECIFIC) {
1946070Srobj 		val = sensor_type;
1956070Srobj 		ntp = &ipmi_sensor_type_table[0];
1966070Srobj 	} else {
1976070Srobj 		val = reading_type;
1986070Srobj 		ntp = &ipmi_reading_type_table[0];
1996070Srobj 	}
2006070Srobj 
2016070Srobj 	for (; ntp->int_name != NULL; ntp++) {
2026070Srobj 		if (ntp->int_value == val) {
2036070Srobj 			(void) strlcpy(buf, ntp->int_name, len);
2046070Srobj 			return;
2056070Srobj 		}
2066070Srobj 	}
2076070Srobj 
2086070Srobj 	if (reading_type == IPMI_RT_SPECIFIC)
2096070Srobj 		(void) snprintf(buf, len, "%02x/%02x", reading_type,
2106070Srobj 		    sensor_type);
2116070Srobj 	else
2126070Srobj 		(void) snprintf(buf, len, "%02x", reading_type);
2136070Srobj }
2146070Srobj 
2156070Srobj /*
2166070Srobj  * Converts a BCD decimal value to an integer.
2176070Srobj  */
2186070Srobj int
ipmi_convert_bcd(int value)2196070Srobj ipmi_convert_bcd(int value)
2206070Srobj {
2216070Srobj 	int ret = 0;
2226070Srobj 	int digit;
2236070Srobj 	int i;
2246070Srobj 
2256070Srobj 	for (i = 7; i >= 0; i--) {
2266070Srobj 		digit = ((value & (0xf << (i * 4))) >> (i * 4));
2276070Srobj 		ret += digit * 10 * i;
2286070Srobj 	}
2296070Srobj 
2306070Srobj 	return (ret);
2316070Srobj }
2326070Srobj 
2336070Srobj /*
2346070Srobj  * See sections 43.15 and 43.16
2356070Srobj  *
2366070Srobj  * This is a utility function for decoding the strings that are packed into
2376070Srobj  * sensor data records.  If the type is 6-bit packed ASCII, then it converts
2386070Srobj  * the string to an 8-bit ASCII string and copies that into the suuplied buffer.
2396070Srobj  * If it is 8-bit ASCII, it copies the string into the supplied buffer as-is.
2406070Srobj  */
2416070Srobj void
ipmi_decode_string(uint8_t type,uint8_t len,char * data,char * buf)2426070Srobj ipmi_decode_string(uint8_t type, uint8_t len, char *data, char *buf)
2436070Srobj {
2446070Srobj 	int i, j = 0, chunks, leftovers;
2456070Srobj 	uint8_t tmp, lo;
2466070Srobj 
2476070Srobj 	if (len == 0) {
2486070Srobj 		*buf = '\0';
2496070Srobj 		return;
2506070Srobj 	}
2516070Srobj 	/*
2526070Srobj 	 * If the type is 8-bit ASCII, we can simply copy the string and return
2536070Srobj 	 */
2546070Srobj 	if (type == 0x3) {
2556070Srobj 		(void) strncpy(buf, data, len);
2566070Srobj 		*(buf+len) = '\0';
2576070Srobj 		return;
2586070Srobj 	} else if (type == 0x1 || type == 0x0) {
2596070Srobj 		/*
2606070Srobj 		 * Yuck - they either used BCD plus encoding, which we don't
2616070Srobj 		 * currently handle, or they used an unspecified encoding type.
2626070Srobj 		 * In these cases we'll set buf to an empty string.  We still
2636070Srobj 		 * need to return the length so that we can get to the next
2646070Srobj 		 * record.
2656070Srobj 		 */
2666070Srobj 		*buf = '\0';
2676070Srobj 		return;
2686070Srobj 	}
2696070Srobj 
2706070Srobj 	/*
2716070Srobj 	 * Otherwise, it's 6-bit packed ASCII, so we have to convert the
2726070Srobj 	 * data first
2736070Srobj 	 */
2746070Srobj 	chunks = len / 3;
2756070Srobj 	leftovers = len % 3;
2766070Srobj 
2776070Srobj 	/*
2786070Srobj 	 * First we decode the 6-bit string in chunks of 3 bytes as far as
2796070Srobj 	 * possible
2806070Srobj 	 */
2816070Srobj 	for (i = 0; i < chunks; i++) {
2826070Srobj 		tmp = BITX(*(data+j), 5, 0);
2836070Srobj 		*buf++ = (char)(tmp + 32);
2846070Srobj 
2856070Srobj 		lo = BITX(*(data+j++), 7, 6);
2866070Srobj 		tmp = BITX(*(data+j), 3, 0);
2876070Srobj 		tmp = (tmp << 2) | lo;
2886070Srobj 		*buf++ = (char)(tmp + 32);
2896070Srobj 
2906070Srobj 		lo = BITX(*(data+j++), 7, 4);
2916070Srobj 		tmp = BITX(*(data+j), 1, 0);
2926070Srobj 		tmp = (tmp << 4) | lo;
2936070Srobj 		*buf++ = (char)(tmp + 32);
2946070Srobj 
2956070Srobj 		tmp = BITX(*(data+j++), 7, 2);
2966070Srobj 		*buf++ = (char)(tmp + 32);
2976070Srobj 	}
2986070Srobj 	switch (leftovers) {
2996070Srobj 		case 1:
3006070Srobj 			tmp = BITX(*(data+j), 5, 0);
3016070Srobj 			*buf++ = (char)(tmp + 32);
3026070Srobj 			break;
3036070Srobj 		case 2:
3046070Srobj 			tmp = BITX(*(data+j), 5, 0);
3056070Srobj 			*buf++ = (char)(tmp + 32);
3066070Srobj 
3076070Srobj 			lo = BITX(*(data+j++), 7, 6);
3086070Srobj 			tmp = BITX(*(data+j), 3, 0);
3096070Srobj 			tmp = (tmp << 2) | lo;
3106070Srobj 			*buf++ = (char)(tmp + 32);
3116070Srobj 			break;
3126070Srobj 	}
3136070Srobj 	*buf = '\0';
3146070Srobj }
315