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 /* 22*6070Srobj * 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 /* 37*6070Srobj * Extracts bits between index h (high, inclusive) and l (low, exclusive) from 38*6070Srobj * u, which must be an unsigned integer. 39*6070Srobj */ 40*6070Srobj #define BITX(u, h, l) (((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU)) 41*6070Srobj 42*6070Srobj /* 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; 77*6070Srobj for (i = 0; ipmi_errno_table[i].int_name != NULL; i++) { 78*6070Srobj if (ipmi_errno_table[i].int_value == ihp->ih_errno) { 79*6070Srobj 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 } 137*6070Srobj 138*6070Srobj /* 139*6070Srobj * Translation between #defines and strings. 140*6070Srobj */ 141*6070Srobj void 142*6070Srobj ipmi_entity_name(uint8_t id, char *buf, size_t len) 143*6070Srobj { 144*6070Srobj ipmi_name_trans_t *ntp; 145*6070Srobj 146*6070Srobj for (ntp = &ipmi_entity_table[0]; ntp->int_name != NULL; ntp++) { 147*6070Srobj if (ntp->int_value == id) { 148*6070Srobj (void) strlcpy(buf, ntp->int_name, len); 149*6070Srobj return; 150*6070Srobj } 151*6070Srobj } 152*6070Srobj 153*6070Srobj (void) snprintf(buf, len, "0x%02x", id); 154*6070Srobj } 155*6070Srobj 156*6070Srobj void 157*6070Srobj ipmi_sensor_type_name(uint8_t type, char *buf, size_t len) 158*6070Srobj { 159*6070Srobj ipmi_name_trans_t *ntp; 160*6070Srobj 161*6070Srobj for (ntp = &ipmi_sensor_type_table[0]; ntp->int_name != NULL; ntp++) { 162*6070Srobj if (ntp->int_value == type) { 163*6070Srobj (void) strlcpy(buf, ntp->int_name, len); 164*6070Srobj return; 165*6070Srobj } 166*6070Srobj } 167*6070Srobj 168*6070Srobj (void) snprintf(buf, len, "0x%02x", type); 169*6070Srobj } 170*6070Srobj 171*6070Srobj void 172*6070Srobj ipmi_sensor_reading_name(uint8_t sensor_type, uint8_t reading_type, 173*6070Srobj char *buf, size_t len) 174*6070Srobj { 175*6070Srobj uint8_t val; 176*6070Srobj ipmi_name_trans_t *ntp; 177*6070Srobj 178*6070Srobj if (reading_type == IPMI_RT_SPECIFIC) { 179*6070Srobj val = sensor_type; 180*6070Srobj ntp = &ipmi_sensor_type_table[0]; 181*6070Srobj } else { 182*6070Srobj val = reading_type; 183*6070Srobj ntp = &ipmi_reading_type_table[0]; 184*6070Srobj } 185*6070Srobj 186*6070Srobj for (; ntp->int_name != NULL; ntp++) { 187*6070Srobj if (ntp->int_value == val) { 188*6070Srobj (void) strlcpy(buf, ntp->int_name, len); 189*6070Srobj return; 190*6070Srobj } 191*6070Srobj } 192*6070Srobj 193*6070Srobj if (reading_type == IPMI_RT_SPECIFIC) 194*6070Srobj (void) snprintf(buf, len, "%02x/%02x", reading_type, 195*6070Srobj sensor_type); 196*6070Srobj else 197*6070Srobj (void) snprintf(buf, len, "%02x", reading_type); 198*6070Srobj } 199*6070Srobj 200*6070Srobj /* 201*6070Srobj * Converts a BCD decimal value to an integer. 202*6070Srobj */ 203*6070Srobj int 204*6070Srobj ipmi_convert_bcd(int value) 205*6070Srobj { 206*6070Srobj int ret = 0; 207*6070Srobj int digit; 208*6070Srobj int i; 209*6070Srobj 210*6070Srobj for (i = 7; i >= 0; i--) { 211*6070Srobj digit = ((value & (0xf << (i * 4))) >> (i * 4)); 212*6070Srobj ret += digit * 10 * i; 213*6070Srobj } 214*6070Srobj 215*6070Srobj return (ret); 216*6070Srobj } 217*6070Srobj 218*6070Srobj /* 219*6070Srobj * See sections 43.15 and 43.16 220*6070Srobj * 221*6070Srobj * This is a utility function for decoding the strings that are packed into 222*6070Srobj * sensor data records. If the type is 6-bit packed ASCII, then it converts 223*6070Srobj * the string to an 8-bit ASCII string and copies that into the suuplied buffer. 224*6070Srobj * If it is 8-bit ASCII, it copies the string into the supplied buffer as-is. 225*6070Srobj */ 226*6070Srobj void 227*6070Srobj ipmi_decode_string(uint8_t type, uint8_t len, char *data, char *buf) 228*6070Srobj { 229*6070Srobj int i, j = 0, chunks, leftovers; 230*6070Srobj uint8_t tmp, lo; 231*6070Srobj 232*6070Srobj if (len == 0) { 233*6070Srobj *buf = '\0'; 234*6070Srobj return; 235*6070Srobj } 236*6070Srobj /* 237*6070Srobj * If the type is 8-bit ASCII, we can simply copy the string and return 238*6070Srobj */ 239*6070Srobj if (type == 0x3) { 240*6070Srobj (void) strncpy(buf, data, len); 241*6070Srobj *(buf+len) = '\0'; 242*6070Srobj return; 243*6070Srobj } else if (type == 0x1 || type == 0x0) { 244*6070Srobj /* 245*6070Srobj * Yuck - they either used BCD plus encoding, which we don't 246*6070Srobj * currently handle, or they used an unspecified encoding type. 247*6070Srobj * In these cases we'll set buf to an empty string. We still 248*6070Srobj * need to return the length so that we can get to the next 249*6070Srobj * record. 250*6070Srobj */ 251*6070Srobj *buf = '\0'; 252*6070Srobj return; 253*6070Srobj } 254*6070Srobj 255*6070Srobj /* 256*6070Srobj * Otherwise, it's 6-bit packed ASCII, so we have to convert the 257*6070Srobj * data first 258*6070Srobj */ 259*6070Srobj chunks = len / 3; 260*6070Srobj leftovers = len % 3; 261*6070Srobj 262*6070Srobj /* 263*6070Srobj * First we decode the 6-bit string in chunks of 3 bytes as far as 264*6070Srobj * possible 265*6070Srobj */ 266*6070Srobj for (i = 0; i < chunks; i++) { 267*6070Srobj tmp = BITX(*(data+j), 5, 0); 268*6070Srobj *buf++ = (char)(tmp + 32); 269*6070Srobj 270*6070Srobj lo = BITX(*(data+j++), 7, 6); 271*6070Srobj tmp = BITX(*(data+j), 3, 0); 272*6070Srobj tmp = (tmp << 2) | lo; 273*6070Srobj *buf++ = (char)(tmp + 32); 274*6070Srobj 275*6070Srobj lo = BITX(*(data+j++), 7, 4); 276*6070Srobj tmp = BITX(*(data+j), 1, 0); 277*6070Srobj tmp = (tmp << 4) | lo; 278*6070Srobj *buf++ = (char)(tmp + 32); 279*6070Srobj 280*6070Srobj tmp = BITX(*(data+j++), 7, 2); 281*6070Srobj *buf++ = (char)(tmp + 32); 282*6070Srobj } 283*6070Srobj switch (leftovers) { 284*6070Srobj case 1: 285*6070Srobj tmp = BITX(*(data+j), 5, 0); 286*6070Srobj *buf++ = (char)(tmp + 32); 287*6070Srobj break; 288*6070Srobj case 2: 289*6070Srobj tmp = BITX(*(data+j), 5, 0); 290*6070Srobj *buf++ = (char)(tmp + 32); 291*6070Srobj 292*6070Srobj lo = BITX(*(data+j++), 7, 6); 293*6070Srobj tmp = BITX(*(data+j), 3, 0); 294*6070Srobj tmp = (tmp << 2) | lo; 295*6070Srobj *buf++ = (char)(tmp + 32); 296*6070Srobj break; 297*6070Srobj } 298*6070Srobj *buf = '\0'; 299*6070Srobj } 300