Home | History | Annotate | Download | only in common
      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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 #include <libipmi.h>
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <string.h>
     32 #include <stdarg.h>
     33 
     34 #include "ipmi_impl.h"
     35 
     36 /*
     37  * Extracts bits between index h (high, inclusive) and l (low, exclusive) from
     38  * u, which must be an unsigned integer.
     39  */
     40 #define	BITX(u, h, l)	(((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
     41 
     42 /*
     43  * Error handling
     44  */
     45 int
     46 ipmi_set_error(ipmi_handle_t *ihp, int error, const char *fmt, ...)
     47 {
     48 	va_list ap;
     49 
     50 	va_start(ap, fmt);
     51 
     52 	ihp->ih_errno = error;
     53 	if (fmt == NULL)
     54 		ihp->ih_errmsg[0] = '\0';
     55 	else
     56 		(void) vsnprintf(ihp->ih_errmsg, sizeof (ihp->ih_errmsg),
     57 		    fmt, ap);
     58 	va_end(ap);
     59 
     60 	return (-1);
     61 }
     62 
     63 int
     64 ipmi_errno(ipmi_handle_t *ihp)
     65 {
     66 	return (ihp->ih_errno);
     67 }
     68 
     69 /* ARGSUSED */
     70 const char *
     71 ipmi_errmsg(ipmi_handle_t *ihp)
     72 {
     73 	int i;
     74 	const char *str;
     75 
     76 	str = NULL;
     77 	for (i = 0; ipmi_errno_table[i].int_name != NULL; i++) {
     78 		if (ipmi_errno_table[i].int_value == ihp->ih_errno) {
     79 			str = ipmi_errno_table[i].int_name;
     80 			break;
     81 		}
     82 	}
     83 
     84 	if (str == NULL && (str = strerror(ihp->ih_errno)) == NULL)
     85 		str = "unknown failure";
     86 
     87 	if (ihp->ih_errmsg[0] == '\0')
     88 		return (str);
     89 
     90 	(void) snprintf(ihp->ih_errbuf, sizeof (ihp->ih_errbuf),
     91 	    "%s: %s", str, ihp->ih_errmsg);
     92 	return (ihp->ih_errbuf);
     93 }
     94 
     95 /*
     96  * Memory allocation
     97  */
     98 void *
     99 ipmi_alloc(ipmi_handle_t *ihp, size_t size)
    100 {
    101 	void *ptr;
    102 
    103 	if ((ptr = malloc(size)) == NULL)
    104 		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
    105 
    106 	return (ptr);
    107 }
    108 
    109 void *
    110 ipmi_zalloc(ipmi_handle_t *ihp, size_t size)
    111 {
    112 	void *ptr;
    113 
    114 	if ((ptr = calloc(size, 1)) == NULL)
    115 		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
    116 
    117 	return (ptr);
    118 }
    119 
    120 char *
    121 ipmi_strdup(ipmi_handle_t *ihp, const char *str)
    122 {
    123 	char *ptr;
    124 
    125 	if ((ptr = strdup(str)) == NULL)
    126 		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
    127 
    128 	return (ptr);
    129 }
    130 
    131 /* ARGSUSED */
    132 void
    133 ipmi_free(ipmi_handle_t *ihp, void *ptr)
    134 {
    135 	free(ptr);
    136 }
    137 
    138 /*
    139  * Translation between #defines and strings.
    140  */
    141 void
    142 ipmi_entity_name(uint8_t id, char *buf, size_t len)
    143 {
    144 	ipmi_name_trans_t *ntp;
    145 
    146 	for (ntp = &ipmi_entity_table[0]; ntp->int_name != NULL; ntp++) {
    147 		if (ntp->int_value == id) {
    148 			(void) strlcpy(buf, ntp->int_name, len);
    149 			return;
    150 		}
    151 	}
    152 
    153 	(void) snprintf(buf, len, "0x%02x", id);
    154 }
    155 
    156 void
    157 ipmi_sensor_type_name(uint8_t type, char *buf, size_t len)
    158 {
    159 	ipmi_name_trans_t *ntp;
    160 
    161 	for (ntp = &ipmi_sensor_type_table[0]; ntp->int_name != NULL; ntp++) {
    162 		if (ntp->int_value == type) {
    163 			(void) strlcpy(buf, ntp->int_name, len);
    164 			return;
    165 		}
    166 	}
    167 
    168 	(void) snprintf(buf, len, "0x%02x", type);
    169 }
    170 
    171 void
    172 ipmi_sensor_units_name(uint8_t type, char *buf, size_t len)
    173 {
    174 	ipmi_name_trans_t *ntp;
    175 
    176 	for (ntp = &ipmi_units_type_table[0]; ntp->int_name != NULL; ntp++) {
    177 		if (ntp->int_value == type) {
    178 			(void) strlcpy(buf, ntp->int_name, len);
    179 			return;
    180 		}
    181 	}
    182 
    183 	(void) snprintf(buf, len, "0x%02x", type);
    184 }
    185 
    186 void
    187 ipmi_sensor_reading_name(uint8_t sensor_type, uint8_t reading_type,
    188     char *buf, size_t len)
    189 {
    190 	uint8_t val;
    191 	ipmi_name_trans_t *ntp;
    192 
    193 	if (reading_type == IPMI_RT_SPECIFIC) {
    194 		val = sensor_type;
    195 		ntp = &ipmi_sensor_type_table[0];
    196 	} else {
    197 		val = reading_type;
    198 		ntp = &ipmi_reading_type_table[0];
    199 	}
    200 
    201 	for (; ntp->int_name != NULL; ntp++) {
    202 		if (ntp->int_value == val) {
    203 			(void) strlcpy(buf, ntp->int_name, len);
    204 			return;
    205 		}
    206 	}
    207 
    208 	if (reading_type == IPMI_RT_SPECIFIC)
    209 		(void) snprintf(buf, len, "%02x/%02x", reading_type,
    210 		    sensor_type);
    211 	else
    212 		(void) snprintf(buf, len, "%02x", reading_type);
    213 }
    214 
    215 /*
    216  * Converts a BCD decimal value to an integer.
    217  */
    218 int
    219 ipmi_convert_bcd(int value)
    220 {
    221 	int ret = 0;
    222 	int digit;
    223 	int i;
    224 
    225 	for (i = 7; i >= 0; i--) {
    226 		digit = ((value & (0xf << (i * 4))) >> (i * 4));
    227 		ret += digit * 10 * i;
    228 	}
    229 
    230 	return (ret);
    231 }
    232 
    233 /*
    234  * See sections 43.15 and 43.16
    235  *
    236  * This is a utility function for decoding the strings that are packed into
    237  * sensor data records.  If the type is 6-bit packed ASCII, then it converts
    238  * the string to an 8-bit ASCII string and copies that into the suuplied buffer.
    239  * If it is 8-bit ASCII, it copies the string into the supplied buffer as-is.
    240  */
    241 void
    242 ipmi_decode_string(uint8_t type, uint8_t len, char *data, char *buf)
    243 {
    244 	int i, j = 0, chunks, leftovers;
    245 	uint8_t tmp, lo;
    246 
    247 	if (len == 0) {
    248 		*buf = '\0';
    249 		return;
    250 	}
    251 	/*
    252 	 * If the type is 8-bit ASCII, we can simply copy the string and return
    253 	 */
    254 	if (type == 0x3) {
    255 		(void) strncpy(buf, data, len);
    256 		*(buf+len) = '\0';
    257 		return;
    258 	} else if (type == 0x1 || type == 0x0) {
    259 		/*
    260 		 * Yuck - they either used BCD plus encoding, which we don't
    261 		 * currently handle, or they used an unspecified encoding type.
    262 		 * In these cases we'll set buf to an empty string.  We still
    263 		 * need to return the length so that we can get to the next
    264 		 * record.
    265 		 */
    266 		*buf = '\0';
    267 		return;
    268 	}
    269 
    270 	/*
    271 	 * Otherwise, it's 6-bit packed ASCII, so we have to convert the
    272 	 * data first
    273 	 */
    274 	chunks = len / 3;
    275 	leftovers = len % 3;
    276 
    277 	/*
    278 	 * First we decode the 6-bit string in chunks of 3 bytes as far as
    279 	 * possible
    280 	 */
    281 	for (i = 0; i < chunks; i++) {
    282 		tmp = BITX(*(data+j), 5, 0);
    283 		*buf++ = (char)(tmp + 32);
    284 
    285 		lo = BITX(*(data+j++), 7, 6);
    286 		tmp = BITX(*(data+j), 3, 0);
    287 		tmp = (tmp << 2) | lo;
    288 		*buf++ = (char)(tmp + 32);
    289 
    290 		lo = BITX(*(data+j++), 7, 4);
    291 		tmp = BITX(*(data+j), 1, 0);
    292 		tmp = (tmp << 4) | lo;
    293 		*buf++ = (char)(tmp + 32);
    294 
    295 		tmp = BITX(*(data+j++), 7, 2);
    296 		*buf++ = (char)(tmp + 32);
    297 	}
    298 	switch (leftovers) {
    299 		case 1:
    300 			tmp = BITX(*(data+j), 5, 0);
    301 			*buf++ = (char)(tmp + 32);
    302 			break;
    303 		case 2:
    304 			tmp = BITX(*(data+j), 5, 0);
    305 			*buf++ = (char)(tmp + 32);
    306 
    307 			lo = BITX(*(data+j++), 7, 6);
    308 			tmp = BITX(*(data+j), 3, 0);
    309 			tmp = (tmp << 2) | lo;
    310 			*buf++ = (char)(tmp + 32);
    311 			break;
    312 	}
    313 	*buf = '\0';
    314 }
    315