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