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