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 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 649113a79cSeschrock ipmi_errno(ipmi_handle_t *ihp) 659113a79cSeschrock { 669113a79cSeschrock return (ihp->ih_errno); 679113a79cSeschrock } 689113a79cSeschrock 699113a79cSeschrock /* ARGSUSED */ 709113a79cSeschrock const char * 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 * 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 * 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 * 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 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 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 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 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 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 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 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