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 50static kmutex_t sol_ofs_debug_mutex; 51static char sol_ofs_print_buf[SOL_OFS_PRINT_BUF_LEN]; 52static char *sol_ofs_debug_sptr = NULL; 53static char *sol_ofs_debug_eptr = NULL; 54 55char *sol_ofs_debug_buf = NULL; 56int sol_ofs_clear_debug_buf_flag = 0; 57int sol_ofs_debug_buf_size = SOL_OFS_DEBUG_BUF_SIZE; 58int sol_ofs_suppress_dprintf = 0; 59int sol_ofs_buffer_dprintf = 1; 60int sol_ofs_supress_above_l2 = 1; 61 62int sol_ucma_errlevel = 2; /* sol_ucma driver */ 63int sol_uverbs_errlevel = 2; /* sol_uverbs driver */ 64int sol_umad_errlevel = 2; /* sol_umad driver */ 65 66int sol_rdmacm_errlevel = 2; /* rdmacm part of sol_ofs */ 67int sol_kverbs_errlevel = 2; /* kverbs part of sol_ofs */ 68/* sol_ofs module (except rdmacm and kverbs) */ 69int sol_ofs_module_errlevel = 2; 70 71/* Global error levels for all OF related modules */ 72int sol_of_errlevel = 2; 73 74static void 75sol_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 */ 90void 91sol_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 113void 114sol_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 127static void 128sol_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 253void 254sol_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 267void 268sol_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 281void 282sol_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 295void 296sol_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 307void 308sol_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 319void 320sol_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