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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * ibtf_util.c 28 * 29 * This file contains the IBTF module's helper/utility functions. 30 * - IBTF logging support 31 */ 32 33 #include <sys/ib/ibtl/impl/ibtl.h> 34 35 static char ibtf_util[] = "ibtl_util"; 36 37 /* Function Prototypes */ 38 static void ibtf_clear_print_buf(); 39 40 /* 41 * Print Buffer protected by mutex for debug stuff. The mutex also 42 * ensures serializing debug messages. 43 */ 44 static kmutex_t ibtf_print_mutex; 45 static char ibtf_print_buf[IBTL_PRINT_BUF_LEN]; 46 47 /* 48 * Debug Stuff. 49 */ 50 uint_t ibtf_errlevel = IBTF_LOG_L5; 51 uint_t ibgen_errlevel = IBTF_LOG_L2; 52 uint_t ibtl_errlevel = IBTF_LOG_L2; 53 uint_t ibcm_errlevel = IBTF_LOG_L2; 54 uint_t ibdm_errlevel = IBTF_LOG_L2; 55 uint_t ibnex_errlevel = IBTF_LOG_L2; 56 57 #define IBTF_DEBUG_SIZE_EXTRA_ALLOC 8 58 #define IBTF_MIN_DEBUG_BUF_SIZE 0x1000 59 #ifdef DEBUG 60 #define IBTF_DEBUG_BUF_SIZE 0x10000 61 #else 62 #define IBTF_DEBUG_BUF_SIZE 0x2000 63 #endif /* DEBUG */ 64 65 int ibtf_suppress_dprintf; /* Suppress debug printing */ 66 int ibtf_buffer_dprintf = 1; /* Use a debug print buffer */ 67 int ibtf_debug_buf_size = IBTF_DEBUG_BUF_SIZE; /* Sz of Debug buf */ 68 int ibtf_allow_intr_msgs = 0; /* log "intr" messages */ 69 char *ibtf_debug_buf = NULL; /* The Debug Buf */ 70 char *ibtf_buf_sptr, *ibtf_buf_eptr; /* debug buffer temp pointer */ 71 int ibtf_clear_debug_buf_flag = 0; /* Clear debug buffer */ 72 73 longlong_t ibtl_ib2usec_tbl[64]; /* time conversion table */ 74 75 /* 76 * Function: 77 * ibtl_ib2usec_init 78 * Input: 79 * none 80 * Output: 81 * none 82 * Returns: 83 * none 84 * Description: 85 * Initialize ibtl_ib2usec_tbl[64] for use by ibt_usec2ib and ibt_ib2usec. 86 */ 87 void 88 ibtl_ib2usec_init(void) 89 { 90 int i; 91 92 for (i = 0; i < 64; i++) { 93 if (i < 51) { /* shift first to avoid underflow */ 94 ibtl_ib2usec_tbl[i] = ((1LL << i) << 12LL) / 1000LL; 95 } else if (i < 61) { /* divide first to avoid overflow */ 96 ibtl_ib2usec_tbl[i] = ((1LL << i) / 1000LL) << 12LL; 97 } else { /* max'ed out, so use MAX LONGLONG */ 98 ibtl_ib2usec_tbl[i] = 0x7FFFFFFFFFFFFFFFLL; 99 } 100 #if !defined(_LP64) 101 if (ibtl_ib2usec_tbl[i] > LONG_MAX) 102 ibtl_ib2usec_tbl[i] = LONG_MAX; 103 #endif 104 } 105 } 106 107 /* 108 * Function: 109 * ibt_usec2ib 110 * Input: 111 * time_val - Time in microsecs. 112 * Output: 113 * none 114 * Returns: 115 * Nearest IB Timeout Exponent value. 116 * Description: 117 * This function converts the standard input time in microseconds to 118 * IB's 6 bits of timeout exponent, calculated based on 119 * time = 4.096us * 2 ^ exp. This is done by searching through 120 * the ibtl_ib2usec_tbl for the closest value >= time_val. 121 */ 122 ib_time_t 123 ibt_usec2ib(clock_t time_val) 124 { 125 int i; 126 127 IBTF_DPRINTF_L3(ibtf_util, "ibt_usec2ib(%ld)", time_val); 128 129 /* First, leap through the table by 4 entries at a time */ 130 for (i = 0; (i + 4) < 64 && ibtl_ib2usec_tbl[i + 4] < time_val; i += 4) 131 ; 132 /* Find the return value; it's now between i and i + 4, inclusive */ 133 while (ibtl_ib2usec_tbl[i] < time_val) 134 i++; 135 return (i); 136 } 137 138 139 /* 140 * Function: 141 * ibt_ib2usec 142 * Input: 143 * ib_time - IB Timeout Exponent value. 144 * Output: 145 * none 146 * Returns: 147 * Standard Time is microseconds. 148 * Description: 149 * This function converts the input IB timeout exponent (6 bits) to 150 * standard time in microseconds, calculated based on 151 * time = 4.096us * 2 ^ exp. 152 * This is implemented as a simple index into ibtl_ib2usec_tbl[]. 153 */ 154 clock_t 155 ibt_ib2usec(ib_time_t ib_time) 156 { 157 IBTF_DPRINTF_L3(ibtf_util, "ibt_ib2usec(%d)", ib_time); 158 159 return ((clock_t)ibtl_ib2usec_tbl[ib_time & IB_TIME_EXP_MASK]); 160 } 161 162 163 /* IBTF logging init */ 164 void 165 ibtl_logging_initialization() 166 { 167 boolean_t flag = B_FALSE; 168 169 IBTF_DPRINTF_L3(ibtf_util, "ibtl_logging_initialization:"); 170 171 mutex_init(&ibtf_print_mutex, NULL, MUTEX_DRIVER, NULL); 172 mutex_enter(&ibtf_print_mutex); 173 174 if (ibtf_debug_buf_size <= IBTF_DEBUG_SIZE_EXTRA_ALLOC) { 175 ibtf_debug_buf_size = IBTF_MIN_DEBUG_BUF_SIZE; 176 flag = B_TRUE; 177 } 178 179 /* if it is less that IBTF_MIN_DEBUG_BUF_SIZE, adjust it */ 180 ibtf_debug_buf_size = max(IBTF_MIN_DEBUG_BUF_SIZE, 181 ibtf_debug_buf_size); 182 183 ibtf_debug_buf = (char *)kmem_alloc(ibtf_debug_buf_size, KM_SLEEP); 184 ibtf_clear_print_buf(); 185 mutex_exit(&ibtf_print_mutex); 186 187 if (flag == B_TRUE) { 188 IBTF_DPRINTF_L2(ibtf_util, "ibtf_debug_buf_size was too small " 189 "%x, adjusted to %x", ibtf_debug_buf_size, 190 IBTF_MIN_DEBUG_BUF_SIZE); 191 } 192 } 193 194 195 /* IBTF logging destroy */ 196 void 197 ibtl_logging_destroy() 198 { 199 IBTF_DPRINTF_L3(ibtf_util, "ibtl_logging_destroy"); 200 201 mutex_enter(&ibtf_print_mutex); 202 if (ibtf_debug_buf) { 203 kmem_free(ibtf_debug_buf, ibtf_debug_buf_size); 204 ibtf_debug_buf = NULL; 205 } 206 mutex_exit(&ibtf_print_mutex); 207 mutex_destroy(&ibtf_print_mutex); 208 } 209 210 211 /* 212 * debug, log, and console message handling 213 */ 214 215 /* 216 * clear the IBTF trace buffer 217 */ 218 static void 219 ibtf_clear_print_buf() 220 { 221 ASSERT(MUTEX_HELD(&ibtf_print_mutex)); 222 if (ibtf_debug_buf) { 223 ibtf_buf_sptr = ibtf_debug_buf; 224 ibtf_buf_eptr = ibtf_debug_buf + ibtf_debug_buf_size - 225 IBTF_DEBUG_SIZE_EXTRA_ALLOC; 226 227 bzero(ibtf_debug_buf, ibtf_debug_buf_size); 228 } 229 } 230 231 232 static void 233 ibtf_vlog(char *name, uint_t level, char *fmt, va_list ap) 234 { 235 char *label = (name == NULL) ? "ibtl" : name; 236 char *msg_ptr; 237 size_t len; 238 239 mutex_enter(&ibtf_print_mutex); 240 241 /* if not using logging scheme; quit */ 242 if (ibtf_suppress_dprintf || (ibtf_debug_buf == NULL)) { 243 mutex_exit(&ibtf_print_mutex); 244 return; 245 } 246 247 /* if level doesn't match, we are done */ 248 if ((level < IBTF_LOG_L0) || (level > IBTF_LOG_LINTR)) { 249 mutex_exit(&ibtf_print_mutex); 250 return; 251 } 252 253 /* If user requests to clear debug buffer, go ahead */ 254 if (ibtf_clear_debug_buf_flag != 0) { 255 ibtf_clear_print_buf(); 256 ibtf_clear_debug_buf_flag = 0; 257 } 258 259 /* 260 * Check if we have a valid buf size? 261 * Suppress logging to ibtf_buffer if so. 262 */ 263 if (ibtf_debug_buf_size <= 0) { 264 ibtf_buffer_dprintf = 0; 265 } 266 267 /* 268 * put "label" into the buffer 269 */ 270 len = snprintf(ibtf_print_buf, IBTL_DRVNAME_LEN, "%s:\t", label); 271 272 msg_ptr = ibtf_print_buf + len; 273 len += vsnprintf(msg_ptr, IBTL_PRINT_BUF_LEN - len - 2, fmt, ap); 274 275 len = min(len, IBTL_PRINT_BUF_LEN - 2); 276 ASSERT(len == strlen(ibtf_print_buf)); 277 ibtf_print_buf[len++] = '\n'; 278 ibtf_print_buf[len] = '\0'; 279 280 /* 281 * stuff the message in the debug buf 282 */ 283 if (ibtf_buffer_dprintf) { 284 285 /* 286 * overwrite >>>> that might be over the end of the 287 * the buffer 288 */ 289 *ibtf_buf_sptr = '\0'; 290 291 if (ibtf_buf_sptr + len > ibtf_buf_eptr) { 292 size_t left = ibtf_buf_eptr - ibtf_buf_sptr; 293 294 bcopy((caddr_t)ibtf_print_buf, 295 (caddr_t)ibtf_buf_sptr, left); 296 bcopy((caddr_t)ibtf_print_buf + left, 297 (caddr_t)ibtf_debug_buf, len - left); 298 ibtf_buf_sptr = ibtf_debug_buf + len - left; 299 } else { 300 bcopy((caddr_t)ibtf_print_buf, ibtf_buf_sptr, len); 301 ibtf_buf_sptr += len; 302 } 303 304 /* add marker */ 305 (void) sprintf(ibtf_buf_sptr, ">>>>"); 306 } 307 308 /* 309 * LINTR, L5-L2 message may go to the ibtf_debug_buf 310 * L1 messages will go to the log buf in non-debug kernels and 311 * to console and log buf in debug kernels 312 * L0 messages are warnings and will go to console and log buf 313 */ 314 switch (level) { 315 case IBTF_LOG_LINTR: 316 case IBTF_LOG_L5: 317 case IBTF_LOG_L4: 318 case IBTF_LOG_L3: 319 case IBTF_LOG_L2: 320 if (!ibtf_buffer_dprintf) { 321 cmn_err(CE_CONT, "^%s", ibtf_print_buf); 322 } 323 break; 324 case IBTF_LOG_L1: 325 #ifdef DEBUG 326 cmn_err(CE_CONT, "%s", ibtf_print_buf); 327 #else 328 if (!ibtf_buffer_dprintf) { 329 cmn_err(CE_CONT, "^%s", ibtf_print_buf); 330 } 331 #endif 332 break; 333 case IBTF_LOG_L0: 334 /* Strip the "\n" added earlier */ 335 if (ibtf_print_buf[len - 1] == '\n') { 336 ibtf_print_buf[len - 1] = '\0'; 337 } 338 if (msg_ptr[len - 1] == '\n') { 339 msg_ptr[len - 1] = '\0'; 340 } 341 cmn_err(CE_WARN, ibtf_print_buf); 342 break; 343 } 344 345 mutex_exit(&ibtf_print_mutex); 346 } 347 348 349 void 350 ibtl_dprintf_intr(char *name, char *fmt, ...) 351 { 352 va_list ap; 353 354 /* only log messages if "ibtf_allow_intr_msgs" is set */ 355 if (!ibtf_allow_intr_msgs) 356 return; 357 358 va_start(ap, fmt); 359 ibtf_vlog(name, IBTF_LOG_LINTR, fmt, ap); 360 va_end(ap); 361 } 362 363 364 /* 365 * Check individual subsystem err levels 366 */ 367 #define IBTL_CHECK_ERR_LEVEL(level) \ 368 if (strncmp(name, "ibgen", 5) == 0) { \ 369 if (ibgen_errlevel < level) \ 370 return; \ 371 } else if (strncmp(name, "ibtl", 4) == 0) { \ 372 if (ibtl_errlevel < level) \ 373 return; \ 374 } else if (strncmp(name, "ibcm", 4) == 0) { \ 375 if (ibcm_errlevel < level) \ 376 return; \ 377 } else if (strncmp(name, "ibdm", 4) == 0) { \ 378 if (ibdm_errlevel < level) \ 379 return; \ 380 } else if (strncmp(name, "ibnex", 5) == 0) { \ 381 if (ibnex_errlevel < level) \ 382 return; \ 383 } 384 385 void 386 ibtl_dprintf5(char *name, char *fmt, ...) 387 { 388 va_list ap; 389 390 /* check if global errlevel matches or not */ 391 if (ibtf_errlevel < IBTF_LOG_L5) 392 return; 393 394 IBTL_CHECK_ERR_LEVEL(IBTF_LOG_L5); 395 396 va_start(ap, fmt); 397 ibtf_vlog(name, IBTF_LOG_L5, fmt, ap); 398 va_end(ap); 399 } 400 401 void 402 ibtl_dprintf4(char *name, char *fmt, ...) 403 { 404 va_list ap; 405 406 /* check if global errlevel matches or not */ 407 if (ibtf_errlevel < IBTF_LOG_L4) 408 return; 409 410 IBTL_CHECK_ERR_LEVEL(IBTF_LOG_L4); 411 412 va_start(ap, fmt); 413 ibtf_vlog(name, IBTF_LOG_L4, fmt, ap); 414 va_end(ap); 415 } 416 417 418 void 419 ibtl_dprintf3(char *name, char *fmt, ...) 420 { 421 va_list ap; 422 423 /* check if global errlevel matches or not */ 424 if (ibtf_errlevel < IBTF_LOG_L3) 425 return; 426 427 IBTL_CHECK_ERR_LEVEL(IBTF_LOG_L3); 428 429 va_start(ap, fmt); 430 ibtf_vlog(name, IBTF_LOG_L3, fmt, ap); 431 va_end(ap); 432 } 433 434 435 void 436 ibtl_dprintf2(char *name, char *fmt, ...) 437 { 438 va_list ap; 439 440 /* check if global errlevel matches or not */ 441 if (ibtf_errlevel < IBTF_LOG_L2) 442 return; 443 444 IBTL_CHECK_ERR_LEVEL(IBTF_LOG_L2); 445 446 va_start(ap, fmt); 447 ibtf_vlog(name, IBTF_LOG_L2, fmt, ap); 448 va_end(ap); 449 } 450 451 452 void 453 ibtl_dprintf1(char *name, char *fmt, ...) 454 { 455 va_list ap; 456 457 /* check if global errlevel matches or not */ 458 if (ibtf_errlevel < IBTF_LOG_L1) 459 return; 460 461 va_start(ap, fmt); 462 ibtf_vlog(name, IBTF_LOG_L1, fmt, ap); 463 va_end(ap); 464 } 465 466 467 /* 468 * Function: 469 * ibtf_dprintf0 470 * Input: 471 * name - Name of the subsystem generating the debug message 472 * fmt - The message to be displayed. 473 * Output: 474 * none 475 * Returns: 476 * none 477 * Description: 478 * A generic log function to display IBTF debug messages. 479 */ 480 void 481 ibtl_dprintf0(char *name, char *fmt, ...) 482 { 483 va_list ap; 484 485 /* check if global errlevel matches or not */ 486 if (ibtf_errlevel < IBTF_LOG_L0) 487 return; 488 489 va_start(ap, fmt); 490 ibtf_vlog(name, IBTF_LOG_L0, fmt, ap); 491 va_end(ap); 492 }