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