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