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 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; 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 * 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 } 1376070Srobj 1386070Srobj /* 1396070Srobj * Translation between #defines and strings. 1406070Srobj */ 1416070Srobj void 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 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 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 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 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 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