Home | History | Annotate | Download | only in ibtl
      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 }
    497