xref: /illumos-gate/usr/src/uts/common/io/ib/clients/of/sol_ofs/sol_ofs_debug_util.c (revision c39526b769298791ff5b0b6c5e761f49aabaeb4e)
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 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * This file is more or less the same as the Solaris IBTL debug
28  * implementation. The debug functions and conf variables are
29  * similar. One significant change is :
30  * 	sol_ofs_supress_above_l2
31  * This has to be set to 0, in /etc/system to enable debug prints
32  * above level 2.
33  */
34 #include <sys/types.h>
35 #include <sys/cmn_err.h>
36 #include <sys/ddi.h>
37 #include <sys/sunddi.h>
38 #include <sys/ib/clients/of/sol_ofs/sol_ofs_common.h>
39 
40 #define	SOL_OFS_PRINT_BUF_LEN		4096
41 #define	SOL_OFS_DEBUG_BUF_SIZE		0x10000
42 #define	SOL_OFS_DEBUG_EXTRA_SIZE	8
43 #define	SOL_OFS_LOG_L5			5
44 #define	SOL_OFS_LOG_L4			4
45 #define	SOL_OFS_LOG_L3			3
46 #define	SOL_OFS_LOG_L2			2
47 #define	SOL_OFS_LOG_L1			1
48 #define	SOL_OFS_LOG_L0			0
49 
50 static kmutex_t	sol_ofs_debug_mutex;
51 static char	sol_ofs_print_buf[SOL_OFS_PRINT_BUF_LEN];
52 static char	*sol_ofs_debug_sptr = NULL;
53 static char	*sol_ofs_debug_eptr = NULL;
54 
55 char	*sol_ofs_debug_buf = NULL;
56 int	sol_ofs_clear_debug_buf_flag = 0;
57 int	sol_ofs_debug_buf_size = SOL_OFS_DEBUG_BUF_SIZE;
58 int	sol_ofs_suppress_dprintf = 0;
59 int	sol_ofs_buffer_dprintf = 1;
60 int	sol_ofs_supress_above_l2 = 1;
61 
62 int	sol_ucma_errlevel = 2;		/* sol_ucma driver */
63 int	sol_uverbs_errlevel = 2;	/* sol_uverbs driver */
64 int	sol_umad_errlevel = 2;		/* sol_umad driver */
65 
66 int	sol_rdmacm_errlevel = 2;	/* rdmacm part of sol_ofs */
67 int	sol_kverbs_errlevel = 2;	/* kverbs part of sol_ofs */
68 /* sol_ofs module (except rdmacm and kverbs) */
69 int	sol_ofs_module_errlevel = 2;
70 
71 /* Global error levels for all OF related modules */
72 int	sol_of_errlevel = 2;
73 
74 static void
75 sol_ofs_clear_dbg_buf()
76 {
77 	ASSERT(MUTEX_HELD(&sol_ofs_debug_mutex));
78 	if (sol_ofs_debug_buf) {
79 		sol_ofs_debug_sptr = sol_ofs_debug_buf;
80 		sol_ofs_debug_eptr = sol_ofs_debug_buf +
81 		    sol_ofs_debug_buf_size - SOL_OFS_DEBUG_EXTRA_SIZE;
82 		bzero(sol_ofs_debug_sptr, sol_ofs_debug_buf_size);
83 	}
84 }
85 
86 /*
87  * sol_ofs_dprintf_init() and sol_ofs_dprintf_fini() must be called
88  * from the _init of the sol_ofs module.
89  */
90 void
91 sol_ofs_dprintf_init()
92 {
93 	char	*dbg_buf;
94 
95 	mutex_init(&sol_ofs_debug_mutex, NULL, MUTEX_DRIVER, NULL);
96 
97 	if (sol_ofs_debug_buf_size < SOL_OFS_DEBUG_EXTRA_SIZE) {
98 #ifdef DEBUG
99 		cmn_err(CE_NOTE, "sol_ofs:\t debug buf size 0x%x too small, "
100 		    "setting to 0x%x", sol_ofs_debug_buf_size,
101 		    SOL_OFS_DEBUG_BUF_SIZE);
102 #endif
103 		sol_ofs_debug_buf_size = SOL_OFS_DEBUG_BUF_SIZE;
104 	}
105 
106 	dbg_buf = kmem_zalloc(sol_ofs_debug_buf_size, KM_SLEEP);
107 	mutex_enter(&sol_ofs_debug_mutex);
108 	sol_ofs_debug_buf = dbg_buf;
109 	sol_ofs_clear_dbg_buf();
110 	mutex_exit(&sol_ofs_debug_mutex);
111 }
112 
113 void
114 sol_ofs_dprintf_fini()
115 {
116 	char	*dbg_buf;
117 
118 	mutex_enter(&sol_ofs_debug_mutex);
119 	dbg_buf = sol_ofs_debug_buf;
120 	sol_ofs_debug_buf = NULL;
121 	mutex_exit(&sol_ofs_debug_mutex);
122 
123 	kmem_free(dbg_buf, sol_ofs_debug_buf_size);
124 	mutex_destroy(&sol_ofs_debug_mutex);
125 }
126 
127 static void
128 sol_ofs_dprintf_vlog(char *name, uint_t level, char *fmt, va_list ap)
129 {
130 	char	*label = (name == NULL) ? "sol_ofs_ulp" : name;
131 	char	*msg_ptr;
132 	size_t	len;
133 
134 	mutex_enter(&sol_ofs_debug_mutex);
135 	/* if not using logging scheme; quit */
136 	if (sol_ofs_suppress_dprintf || (sol_ofs_debug_buf == NULL)) {
137 		mutex_exit(&sol_ofs_debug_mutex);
138 		return;
139 	}
140 	/* if level doesn't match, we are done */
141 	if (level > SOL_OFS_LOG_L5) {
142 		mutex_exit(&sol_ofs_debug_mutex);
143 		return;
144 	}
145 
146 	/* If user requests to clear debug buffer, go ahead */
147 	if (sol_ofs_clear_debug_buf_flag) {
148 		sol_ofs_clear_dbg_buf();
149 		sol_ofs_clear_debug_buf_flag = 0;
150 	}
151 
152 	/* Skip printing to buffer, if too small */
153 	if (sol_ofs_debug_buf_size <= 0) {
154 		sol_ofs_buffer_dprintf = 0;
155 	}
156 
157 	/* Put label and debug info into buffer */
158 	len = snprintf((char *)sol_ofs_print_buf, SOL_OFS_DRV_NAME_LEN,
159 	    "%s:\t", label);
160 	msg_ptr = (char *)sol_ofs_print_buf + len;
161 	len += vsnprintf(msg_ptr, SOL_OFS_PRINT_BUF_LEN - len - 2, fmt, ap);
162 	len = min(len, SOL_OFS_PRINT_BUF_LEN - 2);
163 	ASSERT(len == strlen(sol_ofs_print_buf));
164 	sol_ofs_print_buf[len++] = '\n';
165 	sol_ofs_print_buf[len] = '\0';
166 
167 	/* Stuff into debug buffer */
168 	if (sol_ofs_buffer_dprintf) {
169 		/*
170 		 * overwrite >>>> that might be over the end of the
171 		 * buffer.
172 		 */
173 		*sol_ofs_debug_sptr = '\0';
174 
175 		if (sol_ofs_debug_sptr + len > sol_ofs_debug_eptr) {
176 			size_t left;
177 
178 			left = sol_ofs_debug_eptr - sol_ofs_debug_sptr;
179 			bcopy((caddr_t)sol_ofs_print_buf,
180 			    (caddr_t)sol_ofs_debug_sptr, left);
181 			bcopy((caddr_t)sol_ofs_print_buf + left,
182 			    (caddr_t)sol_ofs_debug_buf, len - left);
183 			sol_ofs_debug_sptr = sol_ofs_debug_buf + len - left;
184 		} else {
185 			bcopy((caddr_t)sol_ofs_print_buf,
186 			    (caddr_t)sol_ofs_debug_sptr, len);
187 			sol_ofs_debug_sptr += len;
188 		}
189 	}
190 
191 	/*
192 	 * L5-L2 message may go to the sol_ofs_debug_buf
193 	 * L1 messages will go to the log buf in non-debug kernels and
194 	 * to console and log buf in debug kernels
195 	 * L0 messages are warnings and will go to console and log buf
196 	 */
197 	switch (level) {
198 	case SOL_OFS_LOG_L5:
199 	case SOL_OFS_LOG_L4:
200 	case SOL_OFS_LOG_L3:
201 	case SOL_OFS_LOG_L2:
202 		if (!sol_ofs_buffer_dprintf) {
203 			cmn_err(CE_CONT, "^%s", sol_ofs_print_buf);
204 		}
205 		break;
206 	case SOL_OFS_LOG_L1 :
207 #ifdef	DEBUG
208 		cmn_err(CE_CONT, "%s", sol_ofs_print_buf);
209 #else
210 		if (!sol_ofs_buffer_dprintf) {
211 			cmn_err(CE_CONT, "^%s", sol_ofs_print_buf);
212 		}
213 #endif
214 		break;
215 	case SOL_OFS_LOG_L0 :
216 		/* Strip the "\n" added earlier */
217 		if (sol_ofs_print_buf[len - 1] == '\n') {
218 			sol_ofs_print_buf[len - 1] = '\0';
219 		}
220 		if (msg_ptr[len - 1] == '\n') {
221 			msg_ptr[len - 1] = '\0';
222 		}
223 		cmn_err(CE_WARN, sol_ofs_print_buf);
224 		break;
225 	}
226 
227 	mutex_exit(&sol_ofs_debug_mutex);
228 }
229 
230 /* Check individual error levels */
231 #define	SOL_OFS_CHECK_ERR_LEVEL(level)			\
232 	if (!(uint_t)strncmp(name, "sol_ucma", 8)) {	\
233 		if (sol_ucma_errlevel < level)		\
234 			return;				\
235 	} else if (!(uint_t)strncmp(name, "sol_rdmacm", 10)) {	\
236 		if (sol_rdmacm_errlevel < level)	\
237 			return;				\
238 	} else if (!(uint_t)strncmp(name, "sol_uverbs", 10)) {	\
239 		if (sol_uverbs_errlevel < level)	\
240 			return;				\
241 	} else if (!(uint_t)strncmp(name, "sol_umad", 8)) {	\
242 		if (sol_umad_errlevel < level)		\
243 			return;				\
244 	} else if (!(uint_t)strncmp(name, "sol_ofs_mod", 12)) {	\
245 		if (sol_ofs_module_errlevel < level)	\
246 			return;				\
247 	} else if (strncmp(name, "sol_kverbs", 10) == 0) {	\
248 		if (sol_kverbs_errlevel < level)		\
249 			return;				\
250 	} else if (sol_of_errlevel < level)		\
251 		return;
252 
253 void
254 sol_ofs_dprintf_l5(char *name, char *fmt, ...)
255 {
256 	va_list	ap;
257 
258 	if (sol_ofs_supress_above_l2)
259 		return;
260 	SOL_OFS_CHECK_ERR_LEVEL(SOL_OFS_LOG_L5);
261 
262 	va_start(ap, fmt);
263 	sol_ofs_dprintf_vlog(name, SOL_OFS_LOG_L5, fmt, ap);
264 	va_end(ap);
265 }
266 
267 void
268 sol_ofs_dprintf_l4(char *name, char *fmt, ...)
269 {
270 	va_list	ap;
271 
272 	if (sol_ofs_supress_above_l2)
273 		return;
274 	SOL_OFS_CHECK_ERR_LEVEL(SOL_OFS_LOG_L4);
275 
276 	va_start(ap, fmt);
277 	sol_ofs_dprintf_vlog(name, SOL_OFS_LOG_L4, fmt, ap);
278 	va_end(ap);
279 }
280 
281 void
282 sol_ofs_dprintf_l3(char *name, char *fmt, ...)
283 {
284 	va_list	ap;
285 
286 	if (sol_ofs_supress_above_l2)
287 		return;
288 	SOL_OFS_CHECK_ERR_LEVEL(SOL_OFS_LOG_L3);
289 
290 	va_start(ap, fmt);
291 	sol_ofs_dprintf_vlog(name, SOL_OFS_LOG_L3, fmt, ap);
292 	va_end(ap);
293 }
294 
295 void
296 sol_ofs_dprintf_l2(char *name, char *fmt, ...)
297 {
298 	va_list	ap;
299 
300 	SOL_OFS_CHECK_ERR_LEVEL(SOL_OFS_LOG_L2);
301 
302 	va_start(ap, fmt);
303 	sol_ofs_dprintf_vlog(name, SOL_OFS_LOG_L2, fmt, ap);
304 	va_end(ap);
305 }
306 
307 void
308 sol_ofs_dprintf_l1(char *name, char *fmt, ...)
309 {
310 	va_list	ap;
311 
312 	SOL_OFS_CHECK_ERR_LEVEL(SOL_OFS_LOG_L1);
313 
314 	va_start(ap, fmt);
315 	sol_ofs_dprintf_vlog(name, SOL_OFS_LOG_L1, fmt, ap);
316 	va_end(ap);
317 }
318 
319 void
320 sol_ofs_dprintf_l0(char *name, char *fmt, ...)
321 {
322 	va_list	ap;
323 
324 	if (sol_of_errlevel < SOL_OFS_LOG_L0)
325 		return;
326 
327 	va_start(ap, fmt);
328 	sol_ofs_dprintf_vlog(name, SOL_OFS_LOG_L1, fmt, ap);
329 	va_end(ap);
330 }
331