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