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
73 longlong_t ibtl_ib2usec_tbl[64]; /* time conversion table */
74
75 /*
76 * Function:
77 * ibtl_ib2usec_init
78 * Input:
79 * none
80 * Output:
81 * none
82 * Returns:
83 * none
84 * Description:
85 * Initialize ibtl_ib2usec_tbl[64] for use by ibt_usec2ib and ibt_ib2usec.
86 */
87 void
88 ibtl_ib2usec_init(void)
89 {
90 int i;
91
92 for (i = 0; i < 64; i++) {
93 if (i < 51) { /* shift first to avoid underflow */
94 ibtl_ib2usec_tbl[i] = ((1LL << i) << 12LL) / 1000LL;
95 } else if (i < 61) { /* divide first to avoid overflow */
96 ibtl_ib2usec_tbl[i] = ((1LL << i) / 1000LL) << 12LL;
97 } else { /* max'ed out, so use MAX LONGLONG */
98 ibtl_ib2usec_tbl[i] = 0x7FFFFFFFFFFFFFFFLL;
99 }
100 #if !defined(_LP64)
101 if (ibtl_ib2usec_tbl[i] > LONG_MAX)
102 ibtl_ib2usec_tbl[i] = LONG_MAX;
103 #endif
104 }
105 }
106
107 /*
108 * Function:
109 * ibt_usec2ib
110 * Input:
111 * time_val - Time in microsecs.
112 * Output:
113 * none
114 * Returns:
115 * Nearest IB Timeout Exponent value.
116 * Description:
117 * This function converts the standard input time in microseconds to
118 * IB's 6 bits of timeout exponent, calculated based on
119 * time = 4.096us * 2 ^ exp. This is done by searching through
120 * the ibtl_ib2usec_tbl for the closest value >= time_val.
121 */
122 ib_time_t
123 ibt_usec2ib(clock_t time_val)
124 {
125 int i;
126
127 IBTF_DPRINTF_L3(ibtf_util, "ibt_usec2ib(%ld)", time_val);
128
129 /* First, leap through the table by 4 entries at a time */
130 for (i = 0; (i + 4) < 64 && ibtl_ib2usec_tbl[i + 4] < time_val; i += 4)
131 ;
132 /* Find the return value; it's now between i and i + 4, inclusive */
133 while (ibtl_ib2usec_tbl[i] < time_val)
134 i++;
135 return (i);
136 }
137
138
139 /*
140 * Function:
141 * ibt_ib2usec
142 * Input:
143 * ib_time - IB Timeout Exponent value.
144 * Output:
145 * none
146 * Returns:
147 * Standard Time is microseconds.
148 * Description:
149 * This function converts the input IB timeout exponent (6 bits) to
150 * standard time in microseconds, calculated based on
151 * time = 4.096us * 2 ^ exp.
152 * This is implemented as a simple index into ibtl_ib2usec_tbl[].
153 */
154 clock_t
155 ibt_ib2usec(ib_time_t ib_time)
156 {
157 IBTF_DPRINTF_L3(ibtf_util, "ibt_ib2usec(%d)", ib_time);
158
159 return ((clock_t)ibtl_ib2usec_tbl[ib_time & IB_TIME_EXP_MASK]);
160 }
161
162
163 /* IBTF logging init */
164 void
165 ibtl_logging_initialization()
166 {
167 boolean_t flag = B_FALSE;
168
169 IBTF_DPRINTF_L3(ibtf_util, "ibtl_logging_initialization:");
170
171 mutex_init(&ibtf_print_mutex, NULL, MUTEX_DRIVER, NULL);
172 mutex_enter(&ibtf_print_mutex);
173
174 if (ibtf_debug_buf_size <= IBTF_DEBUG_SIZE_EXTRA_ALLOC) {
175 ibtf_debug_buf_size = IBTF_MIN_DEBUG_BUF_SIZE;
176 flag = B_TRUE;
177 }
178
179 /* if it is less that IBTF_MIN_DEBUG_BUF_SIZE, adjust it */
180 ibtf_debug_buf_size = max(IBTF_MIN_DEBUG_BUF_SIZE,
181 ibtf_debug_buf_size);
182
183 ibtf_debug_buf = (char *)kmem_alloc(ibtf_debug_buf_size, KM_SLEEP);
184 ibtf_clear_print_buf();
185 mutex_exit(&ibtf_print_mutex);
186
187 if (flag == B_TRUE) {
188 IBTF_DPRINTF_L2(ibtf_util, "ibtf_debug_buf_size was too small "
189 "%x, adjusted to %x", ibtf_debug_buf_size,
190 IBTF_MIN_DEBUG_BUF_SIZE);
191 }
192 }
193
194
195 /* IBTF logging destroy */
196 void
197 ibtl_logging_destroy()
198 {
199 IBTF_DPRINTF_L3(ibtf_util, "ibtl_logging_destroy");
200
201 mutex_enter(&ibtf_print_mutex);
202 if (ibtf_debug_buf) {
203 kmem_free(ibtf_debug_buf, ibtf_debug_buf_size);
204 ibtf_debug_buf = NULL;
205 }
206 mutex_exit(&ibtf_print_mutex);
207 mutex_destroy(&ibtf_print_mutex);
208 }
209
210
211 /*
212 * debug, log, and console message handling
213 */
214
215 /*
216 * clear the IBTF trace buffer
217 */
218 static void
219 ibtf_clear_print_buf()
220 {
221 ASSERT(MUTEX_HELD(&ibtf_print_mutex));
222 if (ibtf_debug_buf) {
223 ibtf_buf_sptr = ibtf_debug_buf;
224 ibtf_buf_eptr = ibtf_debug_buf + ibtf_debug_buf_size -
225 IBTF_DEBUG_SIZE_EXTRA_ALLOC;
226
227 bzero(ibtf_debug_buf, ibtf_debug_buf_size);
228 }
229 }
230
231
232 static void
233 ibtf_vlog(char *name, uint_t level, char *fmt, va_list ap)
234 {
235 char *label = (name == NULL) ? "ibtl" : name;
236 char *msg_ptr;
237 size_t len;
238
239 mutex_enter(&ibtf_print_mutex);
240
241 /* if not using logging scheme; quit */
242 if (ibtf_suppress_dprintf || (ibtf_debug_buf == NULL)) {
243 mutex_exit(&ibtf_print_mutex);
244 return;
245 }
246
247 /* if level doesn't match, we are done */
248 if ((level < IBTF_LOG_L0) || (level > IBTF_LOG_LINTR)) {
249 mutex_exit(&ibtf_print_mutex);
250 return;
251 }
252
253 /* If user requests to clear debug buffer, go ahead */
254 if (ibtf_clear_debug_buf_flag != 0) {
255 ibtf_clear_print_buf();
256 ibtf_clear_debug_buf_flag = 0;
257 }
258
259 /*
260 * Check if we have a valid buf size?
261 * Suppress logging to ibtf_buffer if so.
262 */
263 if (ibtf_debug_buf_size <= 0) {
264 ibtf_buffer_dprintf = 0;
265 }
266
267 /*
268 * put "label" into the buffer
269 */
270 len = snprintf(ibtf_print_buf, IBTL_DRVNAME_LEN, "%s:\t", label);
271
272 msg_ptr = ibtf_print_buf + len;
273 len += vsnprintf(msg_ptr, IBTL_PRINT_BUF_LEN - len - 2, fmt, ap);
274
275 len = min(len, IBTL_PRINT_BUF_LEN - 2);
276 ASSERT(len == strlen(ibtf_print_buf));
277 ibtf_print_buf[len++] = '\n';
278 ibtf_print_buf[len] = '\0';
279
280 /*
281 * stuff the message in the debug buf
282 */
283 if (ibtf_buffer_dprintf) {
284
285 /*
286 * overwrite >>>> that might be over the end of the
287 * the buffer
288 */
289 *ibtf_buf_sptr = '\0';
290
291 if (ibtf_buf_sptr + len > ibtf_buf_eptr) {
292 size_t left = ibtf_buf_eptr - ibtf_buf_sptr;
293
294 bcopy((caddr_t)ibtf_print_buf,
295 (caddr_t)ibtf_buf_sptr, left);
296 bcopy((caddr_t)ibtf_print_buf + left,
297 (caddr_t)ibtf_debug_buf, len - left);
298 ibtf_buf_sptr = ibtf_debug_buf + len - left;
299 } else {
300 bcopy((caddr_t)ibtf_print_buf, ibtf_buf_sptr, len);
301 ibtf_buf_sptr += len;
302 }
303
304 /* add marker */
305 (void) sprintf(ibtf_buf_sptr, ">>>>");
306 }
307
308 /*
309 * LINTR, L5-L2 message may go to the ibtf_debug_buf
310 * L1 messages will go to the log buf in non-debug kernels and
311 * to console and log buf in debug kernels
312 * L0 messages are warnings and will go to console and log buf
313 */
314 switch (level) {
315 case IBTF_LOG_LINTR:
316 case IBTF_LOG_L5:
317 case IBTF_LOG_L4:
318 case IBTF_LOG_L3:
319 case IBTF_LOG_L2:
320 if (!ibtf_buffer_dprintf) {
321 cmn_err(CE_CONT, "^%s", ibtf_print_buf);
322 }
323 break;
324 case IBTF_LOG_L1:
325 #ifdef DEBUG
326 cmn_err(CE_CONT, "%s", ibtf_print_buf);
327 #else
328 if (!ibtf_buffer_dprintf) {
329 cmn_err(CE_CONT, "^%s", ibtf_print_buf);
330 }
331 #endif
332 break;
333 case IBTF_LOG_L0:
334 /* Strip the "\n" added earlier */
335 if (ibtf_print_buf[len - 1] == '\n') {
336 ibtf_print_buf[len - 1] = '\0';
337 }
338 if (msg_ptr[len - 1] == '\n') {
339 msg_ptr[len - 1] = '\0';
340 }
341 cmn_err(CE_WARN, ibtf_print_buf);
342 break;
343 }
344
345 mutex_exit(&ibtf_print_mutex);
346 }
347
348
349 void
350 ibtl_dprintf_intr(char *name, char *fmt, ...)
351 {
352 va_list ap;
353
354 /* only log messages if "ibtf_allow_intr_msgs" is set */
355 if (!ibtf_allow_intr_msgs)
356 return;
357
358 va_start(ap, fmt);
359 ibtf_vlog(name, IBTF_LOG_LINTR, fmt, ap);
360 va_end(ap);
361 }
362
363
364 /*
365 * Check individual subsystem err levels
366 */
367 #define IBTL_CHECK_ERR_LEVEL(level) \
368 if (strncmp(name, "ibgen", 5) == 0) { \
369 if (ibgen_errlevel < level) \
370 return; \
371 } else if (strncmp(name, "ibtl", 4) == 0) { \
372 if (ibtl_errlevel < level) \
373 return; \
374 } else if (strncmp(name, "ibcm", 4) == 0) { \
375 if (ibcm_errlevel < level) \
376 return; \
377 } else if (strncmp(name, "ibdm", 4) == 0) { \
378 if (ibdm_errlevel < level) \
379 return; \
380 } else if (strncmp(name, "ibnex", 5) == 0) { \
381 if (ibnex_errlevel < level) \
382 return; \
383 }
384
385 void
386 ibtl_dprintf5(char *name, char *fmt, ...)
387 {
388 va_list ap;
389
390 /* check if global errlevel matches or not */
391 if (ibtf_errlevel < IBTF_LOG_L5)
392 return;
393
394 IBTL_CHECK_ERR_LEVEL(IBTF_LOG_L5);
395
396 va_start(ap, fmt);
397 ibtf_vlog(name, IBTF_LOG_L5, fmt, ap);
398 va_end(ap);
399 }
400
401 void
402 ibtl_dprintf4(char *name, char *fmt, ...)
403 {
404 va_list ap;
405
406 /* check if global errlevel matches or not */
407 if (ibtf_errlevel < IBTF_LOG_L4)
408 return;
409
410 IBTL_CHECK_ERR_LEVEL(IBTF_LOG_L4);
411
412 va_start(ap, fmt);
413 ibtf_vlog(name, IBTF_LOG_L4, fmt, ap);
414 va_end(ap);
415 }
416
417
418 void
419 ibtl_dprintf3(char *name, char *fmt, ...)
420 {
421 va_list ap;
422
423 /* check if global errlevel matches or not */
424 if (ibtf_errlevel < IBTF_LOG_L3)
425 return;
426
427 IBTL_CHECK_ERR_LEVEL(IBTF_LOG_L3);
428
429 va_start(ap, fmt);
430 ibtf_vlog(name, IBTF_LOG_L3, fmt, ap);
431 va_end(ap);
432 }
433
434
435 void
436 ibtl_dprintf2(char *name, char *fmt, ...)
437 {
438 va_list ap;
439
440 /* check if global errlevel matches or not */
441 if (ibtf_errlevel < IBTF_LOG_L2)
442 return;
443
444 IBTL_CHECK_ERR_LEVEL(IBTF_LOG_L2);
445
446 va_start(ap, fmt);
447 ibtf_vlog(name, IBTF_LOG_L2, fmt, ap);
448 va_end(ap);
449 }
450
451
452 void
453 ibtl_dprintf1(char *name, char *fmt, ...)
454 {
455 va_list ap;
456
457 /* check if global errlevel matches or not */
458 if (ibtf_errlevel < IBTF_LOG_L1)
459 return;
460
461 va_start(ap, fmt);
462 ibtf_vlog(name, IBTF_LOG_L1, fmt, ap);
463 va_end(ap);
464 }
465
466
467 /*
468 * Function:
469 * ibtf_dprintf0
470 * Input:
471 * name - Name of the subsystem generating the debug message
472 * fmt - The message to be displayed.
473 * Output:
474 * none
475 * Returns:
476 * none
477 * Description:
478 * A generic log function to display IBTF debug messages.
479 */
480 void
481 ibtl_dprintf0(char *name, char *fmt, ...)
482 {
483 va_list ap;
484
485 /* check if global errlevel matches or not */
486 if (ibtf_errlevel < IBTF_LOG_L0)
487 return;
488
489 va_start(ap, fmt);
490 ibtf_vlog(name, IBTF_LOG_L0, fmt, ap);
491 va_end(ap);
492 }