xref: /titanic_41/usr/src/lib/libipmi/common/ipmi_util.c (revision 825ba0f20a74fd9c5d0d1ce2c195da2cc88a7f77)
19113a79cSeschrock /*
29113a79cSeschrock  * CDDL HEADER START
39113a79cSeschrock  *
49113a79cSeschrock  * The contents of this file are subject to the terms of the
59113a79cSeschrock  * Common Development and Distribution License (the "License").
69113a79cSeschrock  * You may not use this file except in compliance with the License.
79113a79cSeschrock  *
89113a79cSeschrock  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99113a79cSeschrock  * or http://www.opensolaris.org/os/licensing.
109113a79cSeschrock  * See the License for the specific language governing permissions
119113a79cSeschrock  * and limitations under the License.
129113a79cSeschrock  *
139113a79cSeschrock  * When distributing Covered Code, include this CDDL HEADER in each
149113a79cSeschrock  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159113a79cSeschrock  * If applicable, add the following below this CDDL HEADER, with the
169113a79cSeschrock  * fields enclosed by brackets "[]" replaced with your own identifying
179113a79cSeschrock  * information: Portions Copyright [yyyy] [name of copyright owner]
189113a79cSeschrock  *
199113a79cSeschrock  * CDDL HEADER END
209113a79cSeschrock  */
219113a79cSeschrock /*
222eeaed14Srobj  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
239113a79cSeschrock  * Use is subject to license terms.
249113a79cSeschrock  */
259113a79cSeschrock 
269113a79cSeschrock #pragma ident	"%Z%%M%	%I%	%E% SMI"
279113a79cSeschrock 
289113a79cSeschrock #include <libipmi.h>
299113a79cSeschrock #include <stdio.h>
309113a79cSeschrock #include <stdlib.h>
319113a79cSeschrock #include <string.h>
329113a79cSeschrock #include <stdarg.h>
339113a79cSeschrock 
349113a79cSeschrock #include "ipmi_impl.h"
359113a79cSeschrock 
369113a79cSeschrock /*
372eeaed14Srobj  * Extracts bits between index h (high, inclusive) and l (low, exclusive) from
382eeaed14Srobj  * u, which must be an unsigned integer.
392eeaed14Srobj  */
402eeaed14Srobj #define	BITX(u, h, l)	(((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
412eeaed14Srobj 
422eeaed14Srobj /*
439113a79cSeschrock  * Error handling
449113a79cSeschrock  */
459113a79cSeschrock int
ipmi_set_error(ipmi_handle_t * ihp,int error,const char * fmt,...)469113a79cSeschrock ipmi_set_error(ipmi_handle_t *ihp, int error, const char *fmt, ...)
479113a79cSeschrock {
489113a79cSeschrock 	va_list ap;
499113a79cSeschrock 
509113a79cSeschrock 	va_start(ap, fmt);
519113a79cSeschrock 
529113a79cSeschrock 	ihp->ih_errno = error;
539113a79cSeschrock 	if (fmt == NULL)
549113a79cSeschrock 		ihp->ih_errmsg[0] = '\0';
559113a79cSeschrock 	else
569113a79cSeschrock 		(void) vsnprintf(ihp->ih_errmsg, sizeof (ihp->ih_errmsg),
579113a79cSeschrock 		    fmt, ap);
589113a79cSeschrock 	va_end(ap);
599113a79cSeschrock 
609113a79cSeschrock 	return (-1);
619113a79cSeschrock }
629113a79cSeschrock 
639113a79cSeschrock int
ipmi_errno(ipmi_handle_t * ihp)649113a79cSeschrock ipmi_errno(ipmi_handle_t *ihp)
659113a79cSeschrock {
669113a79cSeschrock 	return (ihp->ih_errno);
679113a79cSeschrock }
689113a79cSeschrock 
699113a79cSeschrock /* ARGSUSED */
709113a79cSeschrock const char *
ipmi_errmsg(ipmi_handle_t * ihp)719113a79cSeschrock ipmi_errmsg(ipmi_handle_t *ihp)
729113a79cSeschrock {
739113a79cSeschrock 	int i;
749113a79cSeschrock 	const char *str;
759113a79cSeschrock 
769113a79cSeschrock 	str = NULL;
772eeaed14Srobj 	for (i = 0; ipmi_errno_table[i].int_name != NULL; i++) {
782eeaed14Srobj 		if (ipmi_errno_table[i].int_value == ihp->ih_errno) {
792eeaed14Srobj 			str = ipmi_errno_table[i].int_name;
809113a79cSeschrock 			break;
819113a79cSeschrock 		}
829113a79cSeschrock 	}
839113a79cSeschrock 
849113a79cSeschrock 	if (str == NULL && (str = strerror(ihp->ih_errno)) == NULL)
859113a79cSeschrock 		str = "unknown failure";
869113a79cSeschrock 
879113a79cSeschrock 	if (ihp->ih_errmsg[0] == '\0')
889113a79cSeschrock 		return (str);
899113a79cSeschrock 
909113a79cSeschrock 	(void) snprintf(ihp->ih_errbuf, sizeof (ihp->ih_errbuf),
919113a79cSeschrock 	    "%s: %s", str, ihp->ih_errmsg);
929113a79cSeschrock 	return (ihp->ih_errbuf);
939113a79cSeschrock }
949113a79cSeschrock 
959113a79cSeschrock /*
969113a79cSeschrock  * Memory allocation
979113a79cSeschrock  */
989113a79cSeschrock void *
ipmi_alloc(ipmi_handle_t * ihp,size_t size)999113a79cSeschrock ipmi_alloc(ipmi_handle_t *ihp, size_t size)
1009113a79cSeschrock {
1019113a79cSeschrock 	void *ptr;
1029113a79cSeschrock 
1039113a79cSeschrock 	if ((ptr = malloc(size)) == NULL)
1049113a79cSeschrock 		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
1059113a79cSeschrock 
1069113a79cSeschrock 	return (ptr);
1079113a79cSeschrock }
1089113a79cSeschrock 
1099113a79cSeschrock void *
ipmi_zalloc(ipmi_handle_t * ihp,size_t size)1109113a79cSeschrock ipmi_zalloc(ipmi_handle_t *ihp, size_t size)
1119113a79cSeschrock {
1129113a79cSeschrock 	void *ptr;
1139113a79cSeschrock 
1149113a79cSeschrock 	if ((ptr = calloc(size, 1)) == NULL)
1159113a79cSeschrock 		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
1169113a79cSeschrock 
1179113a79cSeschrock 	return (ptr);
1189113a79cSeschrock }
1199113a79cSeschrock 
1201af98250Seschrock char *
ipmi_strdup(ipmi_handle_t * ihp,const char * str)1211af98250Seschrock ipmi_strdup(ipmi_handle_t *ihp, const char *str)
1221af98250Seschrock {
1231af98250Seschrock 	char *ptr;
1241af98250Seschrock 
1251af98250Seschrock 	if ((ptr = strdup(str)) == NULL)
1261af98250Seschrock 		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
1271af98250Seschrock 
1281af98250Seschrock 	return (ptr);
1291af98250Seschrock }
1301af98250Seschrock 
1319113a79cSeschrock /* ARGSUSED */
1329113a79cSeschrock void
ipmi_free(ipmi_handle_t * ihp,void * ptr)1339113a79cSeschrock ipmi_free(ipmi_handle_t *ihp, void *ptr)
1349113a79cSeschrock {
1359113a79cSeschrock 	free(ptr);
1369113a79cSeschrock }
1372eeaed14Srobj 
1382eeaed14Srobj /*
1392eeaed14Srobj  * Translation between #defines and strings.
1402eeaed14Srobj  */
1412eeaed14Srobj void
ipmi_entity_name(uint8_t id,char * buf,size_t len)1422eeaed14Srobj ipmi_entity_name(uint8_t id, char *buf, size_t len)
1432eeaed14Srobj {
1442eeaed14Srobj 	ipmi_name_trans_t *ntp;
1452eeaed14Srobj 
1462eeaed14Srobj 	for (ntp = &ipmi_entity_table[0]; ntp->int_name != NULL; ntp++) {
1472eeaed14Srobj 		if (ntp->int_value == id) {
1482eeaed14Srobj 			(void) strlcpy(buf, ntp->int_name, len);
1492eeaed14Srobj 			return;
1502eeaed14Srobj 		}
1512eeaed14Srobj 	}
1522eeaed14Srobj 
1532eeaed14Srobj 	(void) snprintf(buf, len, "0x%02x", id);
1542eeaed14Srobj }
1552eeaed14Srobj 
1562eeaed14Srobj void
ipmi_sensor_type_name(uint8_t type,char * buf,size_t len)1572eeaed14Srobj ipmi_sensor_type_name(uint8_t type, char *buf, size_t len)
1582eeaed14Srobj {
1592eeaed14Srobj 	ipmi_name_trans_t *ntp;
1602eeaed14Srobj 
1612eeaed14Srobj 	for (ntp = &ipmi_sensor_type_table[0]; ntp->int_name != NULL; ntp++) {
1622eeaed14Srobj 		if (ntp->int_value == type) {
1632eeaed14Srobj 			(void) strlcpy(buf, ntp->int_name, len);
1642eeaed14Srobj 			return;
1652eeaed14Srobj 		}
1662eeaed14Srobj 	}
1672eeaed14Srobj 
1682eeaed14Srobj 	(void) snprintf(buf, len, "0x%02x", type);
1692eeaed14Srobj }
1702eeaed14Srobj 
1712eeaed14Srobj void
ipmi_sensor_units_name(uint8_t type,char * buf,size_t len)172*825ba0f2Srobj ipmi_sensor_units_name(uint8_t type, char *buf, size_t len)
173*825ba0f2Srobj {
174*825ba0f2Srobj 	ipmi_name_trans_t *ntp;
175*825ba0f2Srobj 
176*825ba0f2Srobj 	for (ntp = &ipmi_units_type_table[0]; ntp->int_name != NULL; ntp++) {
177*825ba0f2Srobj 		if (ntp->int_value == type) {
178*825ba0f2Srobj 			(void) strlcpy(buf, ntp->int_name, len);
179*825ba0f2Srobj 			return;
180*825ba0f2Srobj 		}
181*825ba0f2Srobj 	}
182*825ba0f2Srobj 
183*825ba0f2Srobj 	(void) snprintf(buf, len, "0x%02x", type);
184*825ba0f2Srobj }
185*825ba0f2Srobj 
186*825ba0f2Srobj void
ipmi_sensor_reading_name(uint8_t sensor_type,uint8_t reading_type,char * buf,size_t len)1872eeaed14Srobj ipmi_sensor_reading_name(uint8_t sensor_type, uint8_t reading_type,
1882eeaed14Srobj     char *buf, size_t len)
1892eeaed14Srobj {
1902eeaed14Srobj 	uint8_t val;
1912eeaed14Srobj 	ipmi_name_trans_t *ntp;
1922eeaed14Srobj 
1932eeaed14Srobj 	if (reading_type == IPMI_RT_SPECIFIC) {
1942eeaed14Srobj 		val = sensor_type;
1952eeaed14Srobj 		ntp = &ipmi_sensor_type_table[0];
1962eeaed14Srobj 	} else {
1972eeaed14Srobj 		val = reading_type;
1982eeaed14Srobj 		ntp = &ipmi_reading_type_table[0];
1992eeaed14Srobj 	}
2002eeaed14Srobj 
2012eeaed14Srobj 	for (; ntp->int_name != NULL; ntp++) {
2022eeaed14Srobj 		if (ntp->int_value == val) {
2032eeaed14Srobj 			(void) strlcpy(buf, ntp->int_name, len);
2042eeaed14Srobj 			return;
2052eeaed14Srobj 		}
2062eeaed14Srobj 	}
2072eeaed14Srobj 
2082eeaed14Srobj 	if (reading_type == IPMI_RT_SPECIFIC)
2092eeaed14Srobj 		(void) snprintf(buf, len, "%02x/%02x", reading_type,
2102eeaed14Srobj 		    sensor_type);
2112eeaed14Srobj 	else
2122eeaed14Srobj 		(void) snprintf(buf, len, "%02x", reading_type);
2132eeaed14Srobj }
2142eeaed14Srobj 
2152eeaed14Srobj /*
2162eeaed14Srobj  * Converts a BCD decimal value to an integer.
2172eeaed14Srobj  */
2182eeaed14Srobj int
ipmi_convert_bcd(int value)2192eeaed14Srobj ipmi_convert_bcd(int value)
2202eeaed14Srobj {
2212eeaed14Srobj 	int ret = 0;
2222eeaed14Srobj 	int digit;
2232eeaed14Srobj 	int i;
2242eeaed14Srobj 
2252eeaed14Srobj 	for (i = 7; i >= 0; i--) {
2262eeaed14Srobj 		digit = ((value & (0xf << (i * 4))) >> (i * 4));
2272eeaed14Srobj 		ret += digit * 10 * i;
2282eeaed14Srobj 	}
2292eeaed14Srobj 
2302eeaed14Srobj 	return (ret);
2312eeaed14Srobj }
2322eeaed14Srobj 
2332eeaed14Srobj /*
2342eeaed14Srobj  * See sections 43.15 and 43.16
2352eeaed14Srobj  *
2362eeaed14Srobj  * This is a utility function for decoding the strings that are packed into
2372eeaed14Srobj  * sensor data records.  If the type is 6-bit packed ASCII, then it converts
2382eeaed14Srobj  * the string to an 8-bit ASCII string and copies that into the suuplied buffer.
2392eeaed14Srobj  * If it is 8-bit ASCII, it copies the string into the supplied buffer as-is.
2402eeaed14Srobj  */
2412eeaed14Srobj void
ipmi_decode_string(uint8_t type,uint8_t len,char * data,char * buf)2422eeaed14Srobj ipmi_decode_string(uint8_t type, uint8_t len, char *data, char *buf)
2432eeaed14Srobj {
2442eeaed14Srobj 	int i, j = 0, chunks, leftovers;
2452eeaed14Srobj 	uint8_t tmp, lo;
2462eeaed14Srobj 
2472eeaed14Srobj 	if (len == 0) {
2482eeaed14Srobj 		*buf = '\0';
2492eeaed14Srobj 		return;
2502eeaed14Srobj 	}
2512eeaed14Srobj 	/*
2522eeaed14Srobj 	 * If the type is 8-bit ASCII, we can simply copy the string and return
2532eeaed14Srobj 	 */
2542eeaed14Srobj 	if (type == 0x3) {
2552eeaed14Srobj 		(void) strncpy(buf, data, len);
2562eeaed14Srobj 		*(buf+len) = '\0';
2572eeaed14Srobj 		return;
2582eeaed14Srobj 	} else if (type == 0x1 || type == 0x0) {
2592eeaed14Srobj 		/*
2602eeaed14Srobj 		 * Yuck - they either used BCD plus encoding, which we don't
2612eeaed14Srobj 		 * currently handle, or they used an unspecified encoding type.
2622eeaed14Srobj 		 * In these cases we'll set buf to an empty string.  We still
2632eeaed14Srobj 		 * need to return the length so that we can get to the next
2642eeaed14Srobj 		 * record.
2652eeaed14Srobj 		 */
2662eeaed14Srobj 		*buf = '\0';
2672eeaed14Srobj 		return;
2682eeaed14Srobj 	}
2692eeaed14Srobj 
2702eeaed14Srobj 	/*
2712eeaed14Srobj 	 * Otherwise, it's 6-bit packed ASCII, so we have to convert the
2722eeaed14Srobj 	 * data first
2732eeaed14Srobj 	 */
2742eeaed14Srobj 	chunks = len / 3;
2752eeaed14Srobj 	leftovers = len % 3;
2762eeaed14Srobj 
2772eeaed14Srobj 	/*
2782eeaed14Srobj 	 * First we decode the 6-bit string in chunks of 3 bytes as far as
2792eeaed14Srobj 	 * possible
2802eeaed14Srobj 	 */
2812eeaed14Srobj 	for (i = 0; i < chunks; i++) {
2822eeaed14Srobj 		tmp = BITX(*(data+j), 5, 0);
2832eeaed14Srobj 		*buf++ = (char)(tmp + 32);
2842eeaed14Srobj 
2852eeaed14Srobj 		lo = BITX(*(data+j++), 7, 6);
2862eeaed14Srobj 		tmp = BITX(*(data+j), 3, 0);
2872eeaed14Srobj 		tmp = (tmp << 2) | lo;
2882eeaed14Srobj 		*buf++ = (char)(tmp + 32);
2892eeaed14Srobj 
2902eeaed14Srobj 		lo = BITX(*(data+j++), 7, 4);
2912eeaed14Srobj 		tmp = BITX(*(data+j), 1, 0);
2922eeaed14Srobj 		tmp = (tmp << 4) | lo;
2932eeaed14Srobj 		*buf++ = (char)(tmp + 32);
2942eeaed14Srobj 
2952eeaed14Srobj 		tmp = BITX(*(data+j++), 7, 2);
2962eeaed14Srobj 		*buf++ = (char)(tmp + 32);
2972eeaed14Srobj 	}
2982eeaed14Srobj 	switch (leftovers) {
2992eeaed14Srobj 		case 1:
3002eeaed14Srobj 			tmp = BITX(*(data+j), 5, 0);
3012eeaed14Srobj 			*buf++ = (char)(tmp + 32);
3022eeaed14Srobj 			break;
3032eeaed14Srobj 		case 2:
3042eeaed14Srobj 			tmp = BITX(*(data+j), 5, 0);
3052eeaed14Srobj 			*buf++ = (char)(tmp + 32);
3062eeaed14Srobj 
3072eeaed14Srobj 			lo = BITX(*(data+j++), 7, 6);
3082eeaed14Srobj 			tmp = BITX(*(data+j), 3, 0);
3092eeaed14Srobj 			tmp = (tmp << 2) | lo;
3102eeaed14Srobj 			*buf++ = (char)(tmp + 32);
3112eeaed14Srobj 			break;
3122eeaed14Srobj 	}
3132eeaed14Srobj 	*buf = '\0';
3142eeaed14Srobj }
315