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
59int	rds_suppress_dprintf;		/* Suppress debug printing */
60int	rds_buffer_dprintf = 1;		/* Use debug buffer (0 == console) */
61int	rds_debug_buf_size = RDS_DEBUG_BUF_SIZE; /* Sz of Debug buf */
62int	rds_allow_intr_msgs = 0;	/* log "intr" messages */
63char	*rds_debug_buf = NULL;		/* The Debug Buf */
64char	*rds_buf_sptr, *rds_buf_eptr;	/* debug buffer temp pointer */
65int	rds_clear_debug_buf_flag = 0;	/* Clear debug buffer */
66extern uint_t	rdsdbglvl;
67
68/*
69 * Print Buffer protected by mutex for debug stuff. The mutex also
70 * ensures serializing debug messages.
71 */
72static kmutex_t	rds_debug_mutex;
73static char	rds_print_buf[RDS_PRINT_BUF_LEN];
74
75/* Function Prototypes */
76static void	rds_clear_print_buf();
77
78/* RDS logging init */
79void
80rds_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 */
108void
109rds_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 */
128static void
129rds_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
142static void
143rds_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
244void
245rds_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
261void
262rds_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
273void
274rds_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
285void
286rds_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
297void
298rds_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
309void
310rds_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 */
333void
334rds_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