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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <sys/varargs.h>
30 #include <sys/cmn_err.h>
31 #include <sys/ddi.h>
32 #include <sys/sunddi.h>
33 #include <sys/ib/clients/rds/rdsib_debug.h>
34 
35 /*
36  * This file contains the debug defines and routines.
37  * Debugging information is collected in a circular kernel buffer. Debug
38  * messages with level lower than rdsdbglvl are ignored. The size of the
39  * of the debug buffer can be changed by setting 'rds_debug_buf_size' in
40  * bytes in /etc/system.
41  *
42  * The debug buffer can be cleared by setting 'rds_clear_debug_buf_flag = 1'
43  * on a running system.
44  */
45 
46 #define	RDS_DEBUG_SIZE_EXTRA_ALLOC	8
47 #define	RDS_MIN_DEBUG_BUF_SIZE		0x1000
48 #define	RDS_FUNCNAME_LEN		40
49 #define	RDS_PRINTBUF_LEN		4096
50 #ifdef	DEBUG
51 #define	RDS_DEBUG_BUF_SIZE		0x10000
52 #else
53 #define	RDS_DEBUG_BUF_SIZE		0x2000
54 #endif	/* DEBUG */
55 
56 /* Max length of a debug statement */
57 #define	RDS_PRINT_BUF_LEN	4096
58 
59 int	rds_suppress_dprintf;		/* Suppress debug printing */
60 int	rds_buffer_dprintf = 1;		/* Use debug buffer (0 == console) */
61 int	rds_debug_buf_size = RDS_DEBUG_BUF_SIZE; /* Sz of Debug buf */
62 int	rds_allow_intr_msgs = 0;	/* log "intr" messages */
63 char	*rds_debug_buf = NULL;		/* The Debug Buf */
64 char	*rds_buf_sptr, *rds_buf_eptr;	/* debug buffer temp pointer */
65 int	rds_clear_debug_buf_flag = 0;	/* Clear debug buffer */
66 extern uint_t	rdsdbglvl;
67 
68 /*
69  * Print Buffer protected by mutex for debug stuff. The mutex also
70  * ensures serializing debug messages.
71  */
72 static kmutex_t	rds_debug_mutex;
73 static char	rds_print_buf[RDS_PRINT_BUF_LEN];
74 
75 /* Function Prototypes */
76 static void	rds_clear_print_buf();
77 
78 /* RDS logging init */
79 void
rds_logging_initialization()80 rds_logging_initialization()
81 {
82 	boolean_t flag = B_FALSE;
83 
84 	mutex_init(&rds_debug_mutex, NULL, MUTEX_DRIVER, NULL);
85 	mutex_enter(&rds_debug_mutex);
86 
87 	if (rds_debug_buf_size <= RDS_DEBUG_SIZE_EXTRA_ALLOC) {
88 		rds_debug_buf_size = RDS_MIN_DEBUG_BUF_SIZE;
89 		flag = B_TRUE;
90 	}
91 
92 	/* if it is less that RDS_MIN_DEBUG_BUF_SIZE, adjust it */
93 	rds_debug_buf_size = max(RDS_MIN_DEBUG_BUF_SIZE,
94 	    rds_debug_buf_size);
95 
96 	rds_debug_buf = (char *)kmem_alloc(rds_debug_buf_size, KM_SLEEP);
97 	rds_clear_print_buf();
98 	mutex_exit(&rds_debug_mutex);
99 
100 	if (flag == B_TRUE) {
101 		RDS_DPRINTF2("RDS", "rds_debug_buf_size was too small, "
102 		    "adjusted to %x", rds_debug_buf_size);
103 	}
104 }
105 
106 
107 /* RDS logging destroy */
108 void
rds_logging_destroy()109 rds_logging_destroy()
110 {
111 	mutex_enter(&rds_debug_mutex);
112 	if (rds_debug_buf) {
113 		kmem_free(rds_debug_buf, rds_debug_buf_size);
114 		rds_debug_buf = NULL;
115 	}
116 	mutex_exit(&rds_debug_mutex);
117 	mutex_destroy(&rds_debug_mutex);
118 }
119 
120 
121 /*
122  * debug, log, and console message handling
123  */
124 
125 /*
126  * clear the RDS debug buffer
127  */
128 static void
rds_clear_print_buf()129 rds_clear_print_buf()
130 {
131 	ASSERT(MUTEX_HELD(&rds_debug_mutex));
132 	if (rds_debug_buf) {
133 		rds_buf_sptr = rds_debug_buf;
134 		rds_buf_eptr = rds_debug_buf + rds_debug_buf_size -
135 		    RDS_DEBUG_SIZE_EXTRA_ALLOC;
136 
137 		bzero(rds_debug_buf, rds_debug_buf_size);
138 	}
139 }
140 
141 
142 static void
rds_vlog(char * name,uint_t level,char * fmt,va_list ap)143 rds_vlog(char *name, uint_t level, char *fmt, va_list ap)
144 {
145 	char	*label = (name == NULL) ? "rds" : name;
146 	char	*msg_ptr;
147 	size_t	len;
148 
149 	mutex_enter(&rds_debug_mutex);
150 
151 	/* if not using logging scheme; quit */
152 	if (rds_suppress_dprintf || (rds_debug_buf == NULL)) {
153 		mutex_exit(&rds_debug_mutex);
154 		return;
155 	}
156 
157 	/* If user requests to clear debug buffer, go ahead */
158 	if (rds_clear_debug_buf_flag != 0) {
159 		rds_clear_print_buf();
160 		rds_clear_debug_buf_flag = 0;
161 	}
162 
163 	/*
164 	 * put "label" into the buffer
165 	 */
166 	len = snprintf(rds_print_buf, RDS_FUNCNAME_LEN, "%s:\t", label);
167 
168 	msg_ptr = rds_print_buf + len;
169 	len += vsnprintf(msg_ptr, RDS_PRINT_BUF_LEN - len - 2, fmt, ap);
170 
171 	len = min(len, RDS_PRINT_BUF_LEN - 2);
172 	ASSERT(len == strlen(rds_print_buf));
173 	rds_print_buf[len++] = '\n';
174 	rds_print_buf[len] = '\0';
175 
176 	/*
177 	 * stuff the message in the debug buf
178 	 */
179 	if (rds_buffer_dprintf) {
180 
181 		/*
182 		 * overwrite >>>> that might be over the end of the
183 		 * the buffer
184 		 */
185 		*rds_buf_sptr = '\0';
186 
187 		if (rds_buf_sptr + len > rds_buf_eptr) {
188 			size_t left = (uintptr_t)rds_buf_eptr -
189 			    (uintptr_t)rds_buf_sptr;
190 
191 			bcopy((caddr_t)rds_print_buf,
192 			    (caddr_t)rds_buf_sptr, left);
193 			bcopy((caddr_t)rds_print_buf + left,
194 			    (caddr_t)rds_debug_buf, len - left);
195 			rds_buf_sptr = rds_debug_buf + len - left;
196 		} else {
197 			bcopy((caddr_t)rds_print_buf, rds_buf_sptr, len);
198 			rds_buf_sptr += len;
199 		}
200 
201 		/* add marker */
202 		(void) sprintf(rds_buf_sptr, ">>>>");
203 	}
204 
205 	/*
206 	 * LINTR, L5-L2 message may go to the rds_debug_buf
207 	 * L1 messages will go to the /var/adm/messages (debug & non-debug).
208 	 * L0 messages will go to console (debug & non-debug).
209 	 */
210 	switch (level) {
211 	case RDS_LOG_LINTR:
212 	case RDS_LOG_L5:
213 	case RDS_LOG_L4:
214 	case RDS_LOG_L3:
215 	case RDS_LOG_L2:
216 		if (!rds_buffer_dprintf) {
217 			cmn_err(CE_CONT, "^%s", rds_print_buf);
218 		}
219 		break;
220 	case RDS_LOG_L1:
221 		if (!rds_buffer_dprintf) {
222 			cmn_err(CE_CONT, "^%s", rds_print_buf);
223 		} else {
224 			/* go to messages file */
225 			cmn_err(CE_CONT, "!%s", rds_print_buf);
226 		}
227 		break;
228 	case RDS_LOG_L0:
229 		/* Strip the "\n" added earlier */
230 		if (rds_print_buf[len - 1] == '\n') {
231 			rds_print_buf[len - 1] = '\0';
232 		}
233 		if (msg_ptr[len - 1] == '\n') {
234 			msg_ptr[len - 1] = '\0';
235 		}
236 		/* go to console */
237 		cmn_err(CE_CONT, "^%s", rds_print_buf);
238 		break;
239 	}
240 
241 	mutex_exit(&rds_debug_mutex);
242 }
243 
244 void
rds_dprintf_intr(char * name,char * fmt,...)245 rds_dprintf_intr(char *name, char *fmt, ...)
246 {
247 	va_list ap;
248 
249 	va_start(ap, fmt);
250 	rds_vlog(name, RDS_LOG_LINTR, fmt, ap);
251 	va_end(ap);
252 }
253 
254 /*
255  * Check individual subsystem err levels
256  */
257 #define	RDS_CHECK_ERR_LEVEL(level)		\
258 	if (rdsdbglvl < level)			\
259 		return;				\
260 
261 void
rds_dprintf5(char * name,char * fmt,...)262 rds_dprintf5(char *name, char *fmt, ...)
263 {
264 	va_list ap;
265 
266 	RDS_CHECK_ERR_LEVEL(RDS_LOG_L5);
267 
268 	va_start(ap, fmt);
269 	rds_vlog(name, RDS_LOG_L5, fmt, ap);
270 	va_end(ap);
271 }
272 
273 void
rds_dprintf4(char * name,char * fmt,...)274 rds_dprintf4(char *name, char *fmt, ...)
275 {
276 	va_list ap;
277 
278 	RDS_CHECK_ERR_LEVEL(RDS_LOG_L4);
279 
280 	va_start(ap, fmt);
281 	rds_vlog(name, RDS_LOG_L4, fmt, ap);
282 	va_end(ap);
283 }
284 
285 void
rds_dprintf3(char * name,char * fmt,...)286 rds_dprintf3(char *name, char *fmt, ...)
287 {
288 	va_list ap;
289 
290 	RDS_CHECK_ERR_LEVEL(RDS_LOG_L3);
291 
292 	va_start(ap, fmt);
293 	rds_vlog(name, RDS_LOG_L3, fmt, ap);
294 	va_end(ap);
295 }
296 
297 void
rds_dprintf2(char * name,char * fmt,...)298 rds_dprintf2(char *name, char *fmt, ...)
299 {
300 	va_list ap;
301 
302 	RDS_CHECK_ERR_LEVEL(RDS_LOG_L2);
303 
304 	va_start(ap, fmt);
305 	rds_vlog(name, RDS_LOG_L2, fmt, ap);
306 	va_end(ap);
307 }
308 
309 void
rds_dprintf1(char * name,char * fmt,...)310 rds_dprintf1(char *name, char *fmt, ...)
311 {
312 	va_list ap;
313 
314 	va_start(ap, fmt);
315 	rds_vlog(name, RDS_LOG_L1, fmt, ap);
316 	va_end(ap);
317 }
318 
319 
320 /*
321  * Function:
322  *      rds_dprintf0
323  * Input:
324  *      name	- Name of the function generating the debug message
325  *  	fmt	- The message to be displayed.
326  * Output:
327  *      none
328  * Returns:
329  *      none
330  * Description:
331  *  	A generic log function to display RDS debug messages.
332  */
333 void
rds_dprintf0(char * name,char * fmt,...)334 rds_dprintf0(char *name, char *fmt, ...)
335 {
336 	va_list ap;
337 
338 	va_start(ap, fmt);
339 	rds_vlog(name, RDS_LOG_L0, fmt, ap);
340 	va_end(ap);
341 }
342