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
_NOTE(MUTEX_PROTECTS_DATA (ibtf_print_mutex,ibtf_buf_sptr ibtf_buf_eptr))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
ibt_usec2ib(clock_t time_val)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
ibt_ib2usec(ib_time_t ib_time)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
ibtl_logging_initialization()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
ibtl_logging_destroy()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
ibtf_clear_print_buf()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
ibtf_vlog(char * name,uint_t level,char * fmt,va_list ap)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
ibtl_dprintf_intr(char * name,char * fmt,...)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
ibtl_dprintf5(char * name,char * fmt,...)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
ibtl_dprintf4(char * name,char * fmt,...)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
ibtl_dprintf3(char * name,char * fmt,...)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
ibtl_dprintf2(char * name,char * fmt,...)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
ibtl_dprintf1(char * name,char * fmt,...)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
ibtl_dprintf0(char * name,char * fmt,...)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