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
sol_ofs_clear_dbg_buf()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
sol_ofs_dprintf_init()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
sol_ofs_dprintf_fini()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
sol_ofs_dprintf_vlog(char * name,uint_t level,char * fmt,va_list ap)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
sol_ofs_dprintf_l5(char * name,char * fmt,...)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
sol_ofs_dprintf_l4(char * name,char * fmt,...)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
sol_ofs_dprintf_l3(char * name,char * fmt,...)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
sol_ofs_dprintf_l2(char * name,char * fmt,...)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
sol_ofs_dprintf_l1(char * name,char * fmt,...)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
sol_ofs_dprintf_l0(char * name,char * fmt,...)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