xref: /illumos-gate/usr/src/uts/common/io/ib/clients/rdsv3/rdsv3_debug.c (revision 3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5)
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 
55 static int rdsv3_suppress_dprintf;	/* Suppress debug printing */
56 static int rdsv3_buffer_dprintf = 1;	/* Use debug buffer (0 == console) */
57 static int rdsv3_debug_buf_size = RDSV3_DEBUG_BUF_SIZE; /* Sz of Debug buf */
58 static int rdsv3_allow_intr_msgs = 0;	/* log "intr" messages */
59 char *rdsv3_debug_buf = NULL;	/* The Debug Buf */
60 char *rdsv3_buf_sptr, *rdsv3_buf_eptr;	/* debug buffer temp pointer */
61 int rdsv3_clear_debug_buf_flag = 0;	/* Clear debug buffer */
62 uint_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  */
68 static kmutex_t	rdsv3_debug_mutex;
69 static char	rdsv3_print_buf[RDSV3_PRINT_BUF_LEN];
70 
71 /* Function Prototypes */
72 static void	rdsv3_clear_print_buf();
73 
74 /* RDS logging init */
75 void
76 rdsv3_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 */
104 void
105 rdsv3_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  */
124 static void
125 rdsv3_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 
138 static void
139 rdsv3_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 
240 void
241 rdsv3_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 
257 void
258 rdsv3_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 
269 void
270 rdsv3_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 
281 void
282 rdsv3_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 
293 void
294 rdsv3_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 
305 void
306 rdsv3_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  */
329 void
330 rdsv3_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 */
340 void
341 rdsv3_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