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