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