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