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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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
];
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
60 #define IBTF_DEBUG_BUF_SIZE 0x10000
62 #define IBTF_DEBUG_BUF_SIZE 0x2000
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
))
89 * Initialize ibtl_ib2usec_tbl[64] for use by ibt_usec2ib and ibt_ib2usec.
92 ibtl_ib2usec_init(void)
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
;
105 if (ibtl_ib2usec_tbl
[i
] > LONG_MAX
)
106 ibtl_ib2usec_tbl
[i
] = LONG_MAX
;
115 * time_val - Time in microsecs.
119 * Nearest IB Timeout Exponent value.
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.
127 ibt_usec2ib(clock_t time_val
)
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
)
147 * ib_time - IB Timeout Exponent value.
151 * Standard Time is microseconds.
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[].
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 */
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
;
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 */
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
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
);
237 ibtf_vlog(char *name
, uint_t level
, char *fmt
, va_list ap
)
239 char *label
= (name
== NULL
) ? "ibtl" : name
;
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
);
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
);
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
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
;
304 bcopy((caddr_t
)ibtf_print_buf
, ibtf_buf_sptr
, len
);
305 ibtf_buf_sptr
+= len
;
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
324 if (!ibtf_buffer_dprintf
) {
325 cmn_err(CE_CONT
, "^%s", ibtf_print_buf
);
330 cmn_err(CE_CONT
, "%s", ibtf_print_buf
);
332 if (!ibtf_buffer_dprintf
) {
333 cmn_err(CE_CONT
, "^%s", ibtf_print_buf
);
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
);
349 mutex_exit(&ibtf_print_mutex
);
354 ibtl_dprintf_intr(char *name
, char *fmt
, ...)
358 /* only log messages if "ibtf_allow_intr_msgs" is set */
359 if (!ibtf_allow_intr_msgs
)
363 ibtf_vlog(name
, IBTF_LOG_LINTR
, fmt
, 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) \
375 } else if (strncmp(name, "ibtl", 4) == 0) { \
376 if (ibtl_errlevel < level) \
378 } else if (strncmp(name, "ibcm", 4) == 0) { \
379 if (ibcm_errlevel < level) \
381 } else if (strncmp(name, "ibdm", 4) == 0) { \
382 if (ibdm_errlevel < level) \
384 } else if (strncmp(name, "ibnex", 5) == 0) { \
385 if (ibnex_errlevel < level) \
390 ibtl_dprintf5(char *name
, char *fmt
, ...)
394 /* check if global errlevel matches or not */
395 if (ibtf_errlevel
< IBTF_LOG_L5
)
398 IBTL_CHECK_ERR_LEVEL(IBTF_LOG_L5
);
401 ibtf_vlog(name
, IBTF_LOG_L5
, fmt
, ap
);
406 ibtl_dprintf4(char *name
, char *fmt
, ...)
410 /* check if global errlevel matches or not */
411 if (ibtf_errlevel
< IBTF_LOG_L4
)
414 IBTL_CHECK_ERR_LEVEL(IBTF_LOG_L4
);
417 ibtf_vlog(name
, IBTF_LOG_L4
, fmt
, ap
);
423 ibtl_dprintf3(char *name
, char *fmt
, ...)
427 /* check if global errlevel matches or not */
428 if (ibtf_errlevel
< IBTF_LOG_L3
)
431 IBTL_CHECK_ERR_LEVEL(IBTF_LOG_L3
);
434 ibtf_vlog(name
, IBTF_LOG_L3
, fmt
, ap
);
440 ibtl_dprintf2(char *name
, char *fmt
, ...)
444 /* check if global errlevel matches or not */
445 if (ibtf_errlevel
< IBTF_LOG_L2
)
448 IBTL_CHECK_ERR_LEVEL(IBTF_LOG_L2
);
451 ibtf_vlog(name
, IBTF_LOG_L2
, fmt
, ap
);
457 ibtl_dprintf1(char *name
, char *fmt
, ...)
461 /* check if global errlevel matches or not */
462 if (ibtf_errlevel
< IBTF_LOG_L1
)
466 ibtf_vlog(name
, IBTF_LOG_L1
, fmt
, ap
);
475 * name - Name of the subsystem generating the debug message
476 * fmt - The message to be displayed.
482 * A generic log function to display IBTF debug messages.
485 ibtl_dprintf0(char *name
, char *fmt
, ...)
489 /* check if global errlevel matches or not */
490 if (ibtf_errlevel
< IBTF_LOG_L0
)
494 ibtf_vlog(name
, IBTF_LOG_L0
, fmt
, ap
);