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