Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / ib / ibtl / ibtl_util.c
blob44835042e4601ef03c27c0c174d73cc2d237a0a6
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * ibtf_util.c
29 * This file contains the IBTF module's helper/utility functions.
30 * - IBTF logging support
33 #include <sys/ib/ibtl/impl/ibtl.h>
35 static char ibtf_util[] = "ibtl_util";
37 /* Function Prototypes */
38 static void ibtf_clear_print_buf();
41 * Print Buffer protected by mutex for debug stuff. The mutex also
42 * ensures serializing debug messages.
44 static kmutex_t ibtf_print_mutex;
45 static char ibtf_print_buf[IBTL_PRINT_BUF_LEN];
48 * Debug Stuff.
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;
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 */
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))
74 longlong_t ibtl_ib2usec_tbl[64]; /* time conversion table */
75 _NOTE(SCHEME_PROTECTS_DATA("inconsistency OK", ibtl_ib2usec_tbl))
77 _NOTE(MUTEX_PROTECTS_DATA(ibtf_print_mutex, ibtf_buf_sptr ibtf_buf_eptr))
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.
91 void
92 ibtl_ib2usec_init(void)
94 int i;
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;
104 #if !defined(_LP64)
105 if (ibtl_ib2usec_tbl[i] > LONG_MAX)
106 ibtl_ib2usec_tbl[i] = LONG_MAX;
107 #endif
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.
126 ib_time_t
127 ibt_usec2ib(clock_t time_val)
129 int i;
131 IBTF_DPRINTF_L3(ibtf_util, "ibt_usec2ib(%ld)", time_val);
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)
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);
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[].
158 clock_t
159 ibt_ib2usec(ib_time_t ib_time)
161 IBTF_DPRINTF_L3(ibtf_util, "ibt_ib2usec(%d)", ib_time);
163 return ((clock_t)ibtl_ib2usec_tbl[ib_time & IB_TIME_EXP_MASK]);
167 /* IBTF logging init */
168 void
169 ibtl_logging_initialization()
171 boolean_t flag = B_FALSE;
173 IBTF_DPRINTF_L3(ibtf_util, "ibtl_logging_initialization:");
175 mutex_init(&ibtf_print_mutex, NULL, MUTEX_DRIVER, NULL);
176 mutex_enter(&ibtf_print_mutex);
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;
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);
187 ibtf_debug_buf = kmem_alloc(ibtf_debug_buf_size, KM_SLEEP);
188 ibtf_clear_print_buf();
189 mutex_exit(&ibtf_print_mutex);
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);
199 /* IBTF logging destroy */
200 void
201 ibtl_logging_destroy()
203 IBTF_DPRINTF_L3(ibtf_util, "ibtl_logging_destroy");
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;
210 mutex_exit(&ibtf_print_mutex);
211 mutex_destroy(&ibtf_print_mutex);
216 * debug, log, and console message handling
220 * clear the IBTF trace buffer
222 static void
223 ibtf_clear_print_buf()
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;
231 bzero(ibtf_debug_buf, ibtf_debug_buf_size);
236 static void
237 ibtf_vlog(char *name, uint_t level, char *fmt, va_list ap)
239 char *label = (name == NULL) ? "ibtl" : name;
240 char *msg_ptr;
241 size_t len;
243 mutex_enter(&ibtf_print_mutex);
245 /* if not using logging scheme; quit */
246 if (ibtf_suppress_dprintf || (ibtf_debug_buf == NULL)) {
247 mutex_exit(&ibtf_print_mutex);
248 return;
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;
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;
264 * Check if we have a valid buf size?
265 * Suppress logging to ibtf_buffer if so.
267 if (ibtf_debug_buf_size <= 0) {
268 ibtf_buffer_dprintf = 0;
272 * put "label" into the buffer
274 len = snprintf(ibtf_print_buf, IBTL_DRVNAME_LEN, "%s:\t", label);
276 msg_ptr = ibtf_print_buf + len;
277 len += vsnprintf(msg_ptr, IBTL_PRINT_BUF_LEN - len - 2, fmt, ap);
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';
285 * stuff the message in the debug buf
287 if (ibtf_buffer_dprintf) {
290 * overwrite >>>> that might be over the end of the
291 * the buffer
293 *ibtf_buf_sptr = '\0';
295 if (ibtf_buf_sptr + len > ibtf_buf_eptr) {
296 size_t left = ibtf_buf_eptr - ibtf_buf_sptr;
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;
308 /* add marker */
309 (void) sprintf(ibtf_buf_sptr, ">>>>");
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
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);
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);
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';
342 if (msg_ptr[len - 1] == '\n') {
343 msg_ptr[len - 1] = '\0';
345 cmn_err(CE_WARN, ibtf_print_buf);
346 break;
349 mutex_exit(&ibtf_print_mutex);
353 void
354 ibtl_dprintf_intr(char *name, char *fmt, ...)
356 va_list ap;
358 /* only log messages if "ibtf_allow_intr_msgs" is set */
359 if (!ibtf_allow_intr_msgs)
360 return;
362 va_start(ap, fmt);
363 ibtf_vlog(name, IBTF_LOG_LINTR, fmt, ap);
364 va_end(ap);
369 * Check individual subsystem err levels
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; \
389 void
390 ibtl_dprintf5(char *name, char *fmt, ...)
392 va_list ap;
394 /* check if global errlevel matches or not */
395 if (ibtf_errlevel < IBTF_LOG_L5)
396 return;
398 IBTL_CHECK_ERR_LEVEL(IBTF_LOG_L5);
400 va_start(ap, fmt);
401 ibtf_vlog(name, IBTF_LOG_L5, fmt, ap);
402 va_end(ap);
405 void
406 ibtl_dprintf4(char *name, char *fmt, ...)
408 va_list ap;
410 /* check if global errlevel matches or not */
411 if (ibtf_errlevel < IBTF_LOG_L4)
412 return;
414 IBTL_CHECK_ERR_LEVEL(IBTF_LOG_L4);
416 va_start(ap, fmt);
417 ibtf_vlog(name, IBTF_LOG_L4, fmt, ap);
418 va_end(ap);
422 void
423 ibtl_dprintf3(char *name, char *fmt, ...)
425 va_list ap;
427 /* check if global errlevel matches or not */
428 if (ibtf_errlevel < IBTF_LOG_L3)
429 return;
431 IBTL_CHECK_ERR_LEVEL(IBTF_LOG_L3);
433 va_start(ap, fmt);
434 ibtf_vlog(name, IBTF_LOG_L3, fmt, ap);
435 va_end(ap);
439 void
440 ibtl_dprintf2(char *name, char *fmt, ...)
442 va_list ap;
444 /* check if global errlevel matches or not */
445 if (ibtf_errlevel < IBTF_LOG_L2)
446 return;
448 IBTL_CHECK_ERR_LEVEL(IBTF_LOG_L2);
450 va_start(ap, fmt);
451 ibtf_vlog(name, IBTF_LOG_L2, fmt, ap);
452 va_end(ap);
456 void
457 ibtl_dprintf1(char *name, char *fmt, ...)
459 va_list ap;
461 /* check if global errlevel matches or not */
462 if (ibtf_errlevel < IBTF_LOG_L1)
463 return;
465 va_start(ap, fmt);
466 ibtf_vlog(name, IBTF_LOG_L1, fmt, ap);
467 va_end(ap);
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.
484 void
485 ibtl_dprintf0(char *name, char *fmt, ...)
487 va_list ap;
489 /* check if global errlevel matches or not */
490 if (ibtf_errlevel < IBTF_LOG_L0)
491 return;
493 va_start(ap, fmt);
494 ibtf_vlog(name, IBTF_LOG_L0, fmt, ap);
495 va_end(ap);