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