rdsv3_debug.c revision 12198:4db936bda957
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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24#include <sys/types.h>
25#include <sys/varargs.h>
26#include <sys/cmn_err.h>
27#include <sys/ddi.h>
28#include <sys/sunddi.h>
29#include <sys/ib/clients/rdsv3/rdsv3_debug.h>
30
31/*
32 * This file contains the debug defines and routines.
33 * Debugging information is collected in a circular kernel buffer. Debug
34 * messages with level lower than rdsv3dbglvl are ignored. The size of the
35 * of the debug buffer can be changed by setting 'rdsv3_debug_buf_size' in
36 * bytes in /etc/system.
37 *
38 * The debug buffer can be cleared by setting 'rdsv3_clear_debug_buf_flag = 1'
39 * on a running system.
40 */
41
42#define	RDSV3_DEBUG_SIZE_EXTRA_ALLOC	8
43#define	RDSV3_MIN_DEBUG_BUF_SIZE		0x1000
44#define	RDSV3_FUNCNAME_LEN		40
45#define	RDSV3_PRINTBUF_LEN		4096
46#ifdef	DEBUG
47#define	RDSV3_DEBUG_BUF_SIZE		0x200000	/* 2M size */
48#else
49#define	RDSV3_DEBUG_BUF_SIZE		0x2000
50#endif	/* DEBUG */
51
52/* Max length of a debug statement */
53#define	RDSV3_PRINT_BUF_LEN	4096
54
55static int rdsv3_suppress_dprintf;	/* Suppress debug printing */
56static int rdsv3_buffer_dprintf = 1;	/* Use debug buffer (0 == console) */
57static int rdsv3_debug_buf_size = RDSV3_DEBUG_BUF_SIZE; /* Sz of Debug buf */
58static int rdsv3_allow_intr_msgs = 0;	/* log "intr" messages */
59char *rdsv3_debug_buf = NULL;	/* The Debug Buf */
60char *rdsv3_buf_sptr, *rdsv3_buf_eptr;	/* debug buffer temp pointer */
61int rdsv3_clear_debug_buf_flag = 0;	/* Clear debug buffer */
62uint_t	rdsv3dbglvl = RDSV3_LOG_L4;
63
64/*
65 * Print Buffer protected by mutex for debug stuff. The mutex also
66 * ensures serializing debug messages.
67 */
68static kmutex_t	rdsv3_debug_mutex;
69static char	rdsv3_print_buf[RDSV3_PRINT_BUF_LEN];
70
71/* Function Prototypes */
72static void	rdsv3_clear_print_buf();
73
74/* RDS logging init */
75void
76rdsv3_logging_initialization()
77{
78	boolean_t flag = B_FALSE;
79
80	mutex_init(&rdsv3_debug_mutex, NULL, MUTEX_DRIVER, NULL);
81	mutex_enter(&rdsv3_debug_mutex);
82
83	if (rdsv3_debug_buf_size <= RDSV3_DEBUG_SIZE_EXTRA_ALLOC) {
84		rdsv3_debug_buf_size = RDSV3_MIN_DEBUG_BUF_SIZE;
85		flag = B_TRUE;
86	}
87
88	/* if it is less that RDSV3_MIN_DEBUG_BUF_SIZE, adjust it */
89	rdsv3_debug_buf_size = max(RDSV3_MIN_DEBUG_BUF_SIZE,
90	    rdsv3_debug_buf_size);
91
92	rdsv3_debug_buf = (char *)kmem_alloc(rdsv3_debug_buf_size, KM_SLEEP);
93	rdsv3_clear_print_buf();
94	mutex_exit(&rdsv3_debug_mutex);
95
96	if (flag == B_TRUE) {
97		RDSV3_DPRINTF2("RDS", "rdsv3_debug_buf_size was too small, "
98		    "adjusted to %x", rdsv3_debug_buf_size);
99	}
100}
101
102
103/* RDS logging destroy */
104void
105rdsv3_logging_destroy()
106{
107	mutex_enter(&rdsv3_debug_mutex);
108	if (rdsv3_debug_buf) {
109		kmem_free(rdsv3_debug_buf, rdsv3_debug_buf_size);
110		rdsv3_debug_buf = NULL;
111	}
112	mutex_exit(&rdsv3_debug_mutex);
113	mutex_destroy(&rdsv3_debug_mutex);
114}
115
116
117/*
118 * debug, log, and console message handling
119 */
120
121/*
122 * clear the RDS debug buffer
123 */
124static void
125rdsv3_clear_print_buf()
126{
127	ASSERT(MUTEX_HELD(&rdsv3_debug_mutex));
128	if (rdsv3_debug_buf) {
129		rdsv3_buf_sptr = rdsv3_debug_buf;
130		rdsv3_buf_eptr = rdsv3_debug_buf + rdsv3_debug_buf_size -
131		    RDSV3_DEBUG_SIZE_EXTRA_ALLOC;
132
133		bzero(rdsv3_debug_buf, rdsv3_debug_buf_size);
134	}
135}
136
137
138static void
139rdsv3_vlog(char *name, uint_t level, char *fmt, va_list ap)
140{
141	char	*label = (name == NULL) ? "rds" : name;
142	char	*msg_ptr;
143	size_t	len;
144
145	mutex_enter(&rdsv3_debug_mutex);
146
147	/* if not using logging scheme; quit */
148	if (rdsv3_suppress_dprintf || (rdsv3_debug_buf == NULL)) {
149		mutex_exit(&rdsv3_debug_mutex);
150		return;
151	}
152
153	/* If user requests to clear debug buffer, go ahead */
154	if (rdsv3_clear_debug_buf_flag != 0) {
155		rdsv3_clear_print_buf();
156		rdsv3_clear_debug_buf_flag = 0;
157	}
158
159	/*
160	 * put "label" into the buffer
161	 */
162	len = snprintf(rdsv3_print_buf, RDSV3_FUNCNAME_LEN, "%s:\t", label);
163
164	msg_ptr = rdsv3_print_buf + len;
165	len += vsnprintf(msg_ptr, RDSV3_PRINT_BUF_LEN - len - 2, fmt, ap);
166
167	len = min(len, RDSV3_PRINT_BUF_LEN - 2);
168	ASSERT(len == strlen(rdsv3_print_buf));
169	rdsv3_print_buf[len++] = '\n';
170	rdsv3_print_buf[len] = '\0';
171
172	/*
173	 * stuff the message in the debug buf
174	 */
175	if (rdsv3_buffer_dprintf) {
176
177		/*
178		 * overwrite >>>> that might be over the end of the
179		 * the buffer
180		 */
181		*rdsv3_buf_sptr = '\0';
182
183		if (rdsv3_buf_sptr + len > rdsv3_buf_eptr) {
184			size_t left = (uintptr_t)rdsv3_buf_eptr -
185			    (uintptr_t)rdsv3_buf_sptr;
186
187			bcopy((caddr_t)rdsv3_print_buf,
188			    (caddr_t)rdsv3_buf_sptr, left);
189			bcopy((caddr_t)rdsv3_print_buf + left,
190			    (caddr_t)rdsv3_debug_buf, len - left);
191			rdsv3_buf_sptr = rdsv3_debug_buf + len - left;
192		} else {
193			bcopy((caddr_t)rdsv3_print_buf, rdsv3_buf_sptr, len);
194			rdsv3_buf_sptr += len;
195		}
196
197		/* add marker */
198		(void) sprintf(rdsv3_buf_sptr, ">>>>");
199	}
200
201	/*
202	 * LINTR, L5-L2 message may go to the rdsv3_debug_buf
203	 * L1 messages will go to the /var/adm/messages (debug & non-debug).
204	 * L0 messages will go to console (debug & non-debug).
205	 */
206	switch (level) {
207	case RDSV3_LOG_LINTR:
208	case RDSV3_LOG_L5:
209	case RDSV3_LOG_L4:
210	case RDSV3_LOG_L3:
211	case RDSV3_LOG_L2:
212		if (!rdsv3_buffer_dprintf) {
213			cmn_err(CE_CONT, "^%s", rdsv3_print_buf);
214		}
215		break;
216	case RDSV3_LOG_L1:
217		if (!rdsv3_buffer_dprintf) {
218			cmn_err(CE_CONT, "^%s", rdsv3_print_buf);
219		} else {
220			/* go to messages file */
221			cmn_err(CE_CONT, "!%s", rdsv3_print_buf);
222		}
223		break;
224	case RDSV3_LOG_L0:
225		/* Strip the "\n" added earlier */
226		if (rdsv3_print_buf[len - 1] == '\n') {
227			rdsv3_print_buf[len - 1] = '\0';
228		}
229		if (msg_ptr[len - 1] == '\n') {
230			msg_ptr[len - 1] = '\0';
231		}
232		/* go to console */
233		cmn_err(CE_CONT, "^%s", rdsv3_print_buf);
234		break;
235	}
236
237	mutex_exit(&rdsv3_debug_mutex);
238}
239
240void
241rdsv3_dprintf_intr(char *name, char *fmt, ...)
242{
243	va_list ap;
244
245	va_start(ap, fmt);
246	rdsv3_vlog(name, RDSV3_LOG_LINTR, fmt, ap);
247	va_end(ap);
248}
249
250/*
251 * Check individual subsystem err levels
252 */
253#define	RDSV3_CHECK_ERR_LEVEL(level)		\
254	if (rdsv3dbglvl < level)		\
255		return;				\
256
257void
258rdsv3_dprintf5(char *name, char *fmt, ...)
259{
260	va_list ap;
261
262	RDSV3_CHECK_ERR_LEVEL(RDSV3_LOG_L5);
263
264	va_start(ap, fmt);
265	rdsv3_vlog(name, RDSV3_LOG_L5, fmt, ap);
266	va_end(ap);
267}
268
269void
270rdsv3_dprintf4(char *name, char *fmt, ...)
271{
272	va_list ap;
273
274	RDSV3_CHECK_ERR_LEVEL(RDSV3_LOG_L4);
275
276	va_start(ap, fmt);
277	rdsv3_vlog(name, RDSV3_LOG_L4, fmt, ap);
278	va_end(ap);
279}
280
281void
282rdsv3_dprintf3(char *name, char *fmt, ...)
283{
284	va_list ap;
285
286	RDSV3_CHECK_ERR_LEVEL(RDSV3_LOG_L3);
287
288	va_start(ap, fmt);
289	rdsv3_vlog(name, RDSV3_LOG_L3, fmt, ap);
290	va_end(ap);
291}
292
293void
294rdsv3_dprintf2(char *name, char *fmt, ...)
295{
296	va_list ap;
297
298	RDSV3_CHECK_ERR_LEVEL(RDSV3_LOG_L2);
299
300	va_start(ap, fmt);
301	rdsv3_vlog(name, RDSV3_LOG_L2, fmt, ap);
302	va_end(ap);
303}
304
305void
306rdsv3_dprintf1(char *name, char *fmt, ...)
307{
308	va_list ap;
309
310	va_start(ap, fmt);
311	rdsv3_vlog(name, RDSV3_LOG_L1, fmt, ap);
312	va_end(ap);
313}
314
315
316/*
317 * Function:
318 *      rdsv3_dprintf0
319 * Input:
320 *      name	- Name of the function generating the debug message
321 *  	fmt	- The message to be displayed.
322 * Output:
323 *      none
324 * Returns:
325 *      none
326 * Description:
327 *  	A generic log function to display RDS debug messages.
328 */
329void
330rdsv3_dprintf0(char *name, char *fmt, ...)
331{
332	va_list ap;
333
334	va_start(ap, fmt);
335	rdsv3_vlog(name, RDSV3_LOG_L0, fmt, ap);
336	va_end(ap);
337}
338
339/* For ofed rdstrace */
340void
341rdsv3_trace(char *name, uint8_t lvl, char *fmt, ...)
342{
343	va_list ap;
344
345	va_start(ap, fmt);
346	rdsv3_vlog(name, lvl, fmt, ap);
347	va_end(ap);
348}
349