1c0dd49bdSEiji Ota /*
2c0dd49bdSEiji Ota  * CDDL HEADER START
3c0dd49bdSEiji Ota  *
4c0dd49bdSEiji Ota  * The contents of this file are subject to the terms of the
5c0dd49bdSEiji Ota  * Common Development and Distribution License (the "License").
6c0dd49bdSEiji Ota  * You may not use this file except in compliance with the License.
7c0dd49bdSEiji Ota  *
8c0dd49bdSEiji Ota  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c0dd49bdSEiji Ota  * or http://www.opensolaris.org/os/licensing.
10c0dd49bdSEiji Ota  * See the License for the specific language governing permissions
11c0dd49bdSEiji Ota  * and limitations under the License.
12c0dd49bdSEiji Ota  *
13c0dd49bdSEiji Ota  * When distributing Covered Code, include this CDDL HEADER in each
14c0dd49bdSEiji Ota  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c0dd49bdSEiji Ota  * If applicable, add the following below this CDDL HEADER, with the
16c0dd49bdSEiji Ota  * fields enclosed by brackets "[]" replaced with your own identifying
17c0dd49bdSEiji Ota  * information: Portions Copyright [yyyy] [name of copyright owner]
18c0dd49bdSEiji Ota  *
19c0dd49bdSEiji Ota  * CDDL HEADER END
20c0dd49bdSEiji Ota  */
21c0dd49bdSEiji Ota /*
22c0dd49bdSEiji Ota  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23c0dd49bdSEiji Ota  */
24c0dd49bdSEiji Ota #include <sys/types.h>
25c0dd49bdSEiji Ota #include <sys/varargs.h>
26c0dd49bdSEiji Ota #include <sys/cmn_err.h>
27c0dd49bdSEiji Ota #include <sys/ddi.h>
28c0dd49bdSEiji Ota #include <sys/sunddi.h>
29*cadbfdc3SEiji Ota #include <sys/time.h>
30c0dd49bdSEiji Ota #include <sys/ib/clients/rdsv3/rdsv3_debug.h>
31c0dd49bdSEiji Ota 
32c0dd49bdSEiji Ota /*
33c0dd49bdSEiji Ota  * This file contains the debug defines and routines.
34c0dd49bdSEiji Ota  * Debugging information is collected in a circular kernel buffer. Debug
35c0dd49bdSEiji Ota  * messages with level lower than rdsv3dbglvl are ignored. The size of the
36c0dd49bdSEiji Ota  * of the debug buffer can be changed by setting 'rdsv3_debug_buf_size' in
37c0dd49bdSEiji Ota  * bytes in /etc/system.
38c0dd49bdSEiji Ota  *
39c0dd49bdSEiji Ota  * The debug buffer can be cleared by setting 'rdsv3_clear_debug_buf_flag = 1'
40c0dd49bdSEiji Ota  * on a running system.
41c0dd49bdSEiji Ota  */
42c0dd49bdSEiji Ota 
43c0dd49bdSEiji Ota #define	RDSV3_DEBUG_SIZE_EXTRA_ALLOC	8
44c0dd49bdSEiji Ota #define	RDSV3_MIN_DEBUG_BUF_SIZE		0x1000
45c0dd49bdSEiji Ota #define	RDSV3_FUNCNAME_LEN		40
46c0dd49bdSEiji Ota #define	RDSV3_PRINTBUF_LEN		4096
47c0dd49bdSEiji Ota #ifdef	DEBUG
48c0dd49bdSEiji Ota #define	RDSV3_DEBUG_BUF_SIZE		0x200000	/* 2M size */
49c0dd49bdSEiji Ota #else
50c0dd49bdSEiji Ota #define	RDSV3_DEBUG_BUF_SIZE		0x2000
51c0dd49bdSEiji Ota #endif	/* DEBUG */
52c0dd49bdSEiji Ota 
53c0dd49bdSEiji Ota /* Max length of a debug statement */
54c0dd49bdSEiji Ota #define	RDSV3_PRINT_BUF_LEN	4096
55c0dd49bdSEiji Ota 
56c0dd49bdSEiji Ota static int rdsv3_suppress_dprintf;	/* Suppress debug printing */
57c0dd49bdSEiji Ota static int rdsv3_buffer_dprintf = 1;	/* Use debug buffer (0 == console) */
58c0dd49bdSEiji Ota static int rdsv3_debug_buf_size = RDSV3_DEBUG_BUF_SIZE; /* Sz of Debug buf */
59c0dd49bdSEiji Ota static int rdsv3_allow_intr_msgs = 0;	/* log "intr" messages */
60c0dd49bdSEiji Ota char *rdsv3_debug_buf = NULL;	/* The Debug Buf */
61c0dd49bdSEiji Ota char *rdsv3_buf_sptr, *rdsv3_buf_eptr;	/* debug buffer temp pointer */
62c0dd49bdSEiji Ota int rdsv3_clear_debug_buf_flag = 0;	/* Clear debug buffer */
63c0dd49bdSEiji Ota uint_t	rdsv3dbglvl = RDSV3_LOG_L4;
64c0dd49bdSEiji Ota 
65c0dd49bdSEiji Ota /*
66c0dd49bdSEiji Ota  * Print Buffer protected by mutex for debug stuff. The mutex also
67c0dd49bdSEiji Ota  * ensures serializing debug messages.
68c0dd49bdSEiji Ota  */
69c0dd49bdSEiji Ota static kmutex_t	rdsv3_debug_mutex;
70c0dd49bdSEiji Ota static char	rdsv3_print_buf[RDSV3_PRINT_BUF_LEN];
71c0dd49bdSEiji Ota 
72c0dd49bdSEiji Ota /* Function Prototypes */
73c0dd49bdSEiji Ota static void	rdsv3_clear_print_buf();
74c0dd49bdSEiji Ota 
75c0dd49bdSEiji Ota /* RDS logging init */
76c0dd49bdSEiji Ota void
rdsv3_logging_initialization()77c0dd49bdSEiji Ota rdsv3_logging_initialization()
78c0dd49bdSEiji Ota {
79c0dd49bdSEiji Ota 	boolean_t flag = B_FALSE;
80c0dd49bdSEiji Ota 
81c0dd49bdSEiji Ota 	mutex_init(&rdsv3_debug_mutex, NULL, MUTEX_DRIVER, NULL);
82c0dd49bdSEiji Ota 	mutex_enter(&rdsv3_debug_mutex);
83c0dd49bdSEiji Ota 
84c0dd49bdSEiji Ota 	if (rdsv3_debug_buf_size <= RDSV3_DEBUG_SIZE_EXTRA_ALLOC) {
85c0dd49bdSEiji Ota 		rdsv3_debug_buf_size = RDSV3_MIN_DEBUG_BUF_SIZE;
86c0dd49bdSEiji Ota 		flag = B_TRUE;
87c0dd49bdSEiji Ota 	}
88c0dd49bdSEiji Ota 
89c0dd49bdSEiji Ota 	/* if it is less that RDSV3_MIN_DEBUG_BUF_SIZE, adjust it */
90c0dd49bdSEiji Ota 	rdsv3_debug_buf_size = max(RDSV3_MIN_DEBUG_BUF_SIZE,
91c0dd49bdSEiji Ota 	    rdsv3_debug_buf_size);
92c0dd49bdSEiji Ota 
93c0dd49bdSEiji Ota 	rdsv3_debug_buf = (char *)kmem_alloc(rdsv3_debug_buf_size, KM_SLEEP);
94c0dd49bdSEiji Ota 	rdsv3_clear_print_buf();
95c0dd49bdSEiji Ota 	mutex_exit(&rdsv3_debug_mutex);
96c0dd49bdSEiji Ota 
97c0dd49bdSEiji Ota 	if (flag == B_TRUE) {
98c0dd49bdSEiji Ota 		RDSV3_DPRINTF2("RDS", "rdsv3_debug_buf_size was too small, "
99c0dd49bdSEiji Ota 		    "adjusted to %x", rdsv3_debug_buf_size);
100c0dd49bdSEiji Ota 	}
101c0dd49bdSEiji Ota }
102c0dd49bdSEiji Ota 
103c0dd49bdSEiji Ota 
104c0dd49bdSEiji Ota /* RDS logging destroy */
105c0dd49bdSEiji Ota void
rdsv3_logging_destroy()106c0dd49bdSEiji Ota rdsv3_logging_destroy()
107c0dd49bdSEiji Ota {
108c0dd49bdSEiji Ota 	mutex_enter(&rdsv3_debug_mutex);
109c0dd49bdSEiji Ota 	if (rdsv3_debug_buf) {
110c0dd49bdSEiji Ota 		kmem_free(rdsv3_debug_buf, rdsv3_debug_buf_size);
111c0dd49bdSEiji Ota 		rdsv3_debug_buf = NULL;
112c0dd49bdSEiji Ota 	}
113c0dd49bdSEiji Ota 	mutex_exit(&rdsv3_debug_mutex);
114c0dd49bdSEiji Ota 	mutex_destroy(&rdsv3_debug_mutex);
115c0dd49bdSEiji Ota }
116c0dd49bdSEiji Ota 
117c0dd49bdSEiji Ota 
118c0dd49bdSEiji Ota /*
119c0dd49bdSEiji Ota  * debug, log, and console message handling
120c0dd49bdSEiji Ota  */
121c0dd49bdSEiji Ota 
122c0dd49bdSEiji Ota /*
123c0dd49bdSEiji Ota  * clear the RDS debug buffer
124c0dd49bdSEiji Ota  */
125c0dd49bdSEiji Ota static void
rdsv3_clear_print_buf()126c0dd49bdSEiji Ota rdsv3_clear_print_buf()
127c0dd49bdSEiji Ota {
128c0dd49bdSEiji Ota 	ASSERT(MUTEX_HELD(&rdsv3_debug_mutex));
129c0dd49bdSEiji Ota 	if (rdsv3_debug_buf) {
130c0dd49bdSEiji Ota 		rdsv3_buf_sptr = rdsv3_debug_buf;
131c0dd49bdSEiji Ota 		rdsv3_buf_eptr = rdsv3_debug_buf + rdsv3_debug_buf_size -
132c0dd49bdSEiji Ota 		    RDSV3_DEBUG_SIZE_EXTRA_ALLOC;
133c0dd49bdSEiji Ota 
134c0dd49bdSEiji Ota 		bzero(rdsv3_debug_buf, rdsv3_debug_buf_size);
135c0dd49bdSEiji Ota 	}
136c0dd49bdSEiji Ota }
137c0dd49bdSEiji Ota 
138c0dd49bdSEiji Ota 
139c0dd49bdSEiji Ota static void
rdsv3_vlog(char * name,uint_t level,char * fmt,va_list ap)140c0dd49bdSEiji Ota rdsv3_vlog(char *name, uint_t level, char *fmt, va_list ap)
141c0dd49bdSEiji Ota {
142c0dd49bdSEiji Ota 	char	*label = (name == NULL) ? "rds" : name;
143c0dd49bdSEiji Ota 	char	*msg_ptr;
144c0dd49bdSEiji Ota 	size_t	len;
145c0dd49bdSEiji Ota 
146c0dd49bdSEiji Ota 	mutex_enter(&rdsv3_debug_mutex);
147c0dd49bdSEiji Ota 
148c0dd49bdSEiji Ota 	/* if not using logging scheme; quit */
149c0dd49bdSEiji Ota 	if (rdsv3_suppress_dprintf || (rdsv3_debug_buf == NULL)) {
150c0dd49bdSEiji Ota 		mutex_exit(&rdsv3_debug_mutex);
151c0dd49bdSEiji Ota 		return;
152c0dd49bdSEiji Ota 	}
153c0dd49bdSEiji Ota 
154c0dd49bdSEiji Ota 	/* If user requests to clear debug buffer, go ahead */
155c0dd49bdSEiji Ota 	if (rdsv3_clear_debug_buf_flag != 0) {
156c0dd49bdSEiji Ota 		rdsv3_clear_print_buf();
157c0dd49bdSEiji Ota 		rdsv3_clear_debug_buf_flag = 0;
158c0dd49bdSEiji Ota 	}
159c0dd49bdSEiji Ota 
160c0dd49bdSEiji Ota 	/*
161c0dd49bdSEiji Ota 	 * put "label" into the buffer
162c0dd49bdSEiji Ota 	 */
163c0dd49bdSEiji Ota 	len = snprintf(rdsv3_print_buf, RDSV3_FUNCNAME_LEN, "%s:\t", label);
164c0dd49bdSEiji Ota 
165c0dd49bdSEiji Ota 	msg_ptr = rdsv3_print_buf + len;
166c0dd49bdSEiji Ota 	len += vsnprintf(msg_ptr, RDSV3_PRINT_BUF_LEN - len - 2, fmt, ap);
167c0dd49bdSEiji Ota 
168c0dd49bdSEiji Ota 	len = min(len, RDSV3_PRINT_BUF_LEN - 2);
169c0dd49bdSEiji Ota 	ASSERT(len == strlen(rdsv3_print_buf));
170c0dd49bdSEiji Ota 	rdsv3_print_buf[len++] = '\n';
171c0dd49bdSEiji Ota 	rdsv3_print_buf[len] = '\0';
172c0dd49bdSEiji Ota 
173c0dd49bdSEiji Ota 	/*
174c0dd49bdSEiji Ota 	 * stuff the message in the debug buf
175c0dd49bdSEiji Ota 	 */
176c0dd49bdSEiji Ota 	if (rdsv3_buffer_dprintf) {
177c0dd49bdSEiji Ota 
178c0dd49bdSEiji Ota 		/*
179c0dd49bdSEiji Ota 		 * overwrite >>>> that might be over the end of the
180c0dd49bdSEiji Ota 		 * the buffer
181c0dd49bdSEiji Ota 		 */
182c0dd49bdSEiji Ota 		*rdsv3_buf_sptr = '\0';
183c0dd49bdSEiji Ota 
184c0dd49bdSEiji Ota 		if (rdsv3_buf_sptr + len > rdsv3_buf_eptr) {
185c0dd49bdSEiji Ota 			size_t left = (uintptr_t)rdsv3_buf_eptr -
186c0dd49bdSEiji Ota 			    (uintptr_t)rdsv3_buf_sptr;
187c0dd49bdSEiji Ota 
188c0dd49bdSEiji Ota 			bcopy((caddr_t)rdsv3_print_buf,
189c0dd49bdSEiji Ota 			    (caddr_t)rdsv3_buf_sptr, left);
190c0dd49bdSEiji Ota 			bcopy((caddr_t)rdsv3_print_buf + left,
191c0dd49bdSEiji Ota 			    (caddr_t)rdsv3_debug_buf, len - left);
192c0dd49bdSEiji Ota 			rdsv3_buf_sptr = rdsv3_debug_buf + len - left;
193c0dd49bdSEiji Ota 		} else {
194c0dd49bdSEiji Ota 			bcopy((caddr_t)rdsv3_print_buf, rdsv3_buf_sptr, len);
195c0dd49bdSEiji Ota 			rdsv3_buf_sptr += len;
196c0dd49bdSEiji Ota 		}
197c0dd49bdSEiji Ota 
198c0dd49bdSEiji Ota 		/* add marker */
199c0dd49bdSEiji Ota 		(void) sprintf(rdsv3_buf_sptr, ">>>>");
200c0dd49bdSEiji Ota 	}
201c0dd49bdSEiji Ota 
202c0dd49bdSEiji Ota 	/*
203c0dd49bdSEiji Ota 	 * LINTR, L5-L2 message may go to the rdsv3_debug_buf
204c0dd49bdSEiji Ota 	 * L1 messages will go to the /var/adm/messages (debug & non-debug).
205c0dd49bdSEiji Ota 	 * L0 messages will go to console (debug & non-debug).
206c0dd49bdSEiji Ota 	 */
207c0dd49bdSEiji Ota 	switch (level) {
208c0dd49bdSEiji Ota 	case RDSV3_LOG_LINTR:
209c0dd49bdSEiji Ota 	case RDSV3_LOG_L5:
210c0dd49bdSEiji Ota 	case RDSV3_LOG_L4:
211c0dd49bdSEiji Ota 	case RDSV3_LOG_L3:
212c0dd49bdSEiji Ota 	case RDSV3_LOG_L2:
213c0dd49bdSEiji Ota 		if (!rdsv3_buffer_dprintf) {
214c0dd49bdSEiji Ota 			cmn_err(CE_CONT, "^%s", rdsv3_print_buf);
215c0dd49bdSEiji Ota 		}
216c0dd49bdSEiji Ota 		break;
217c0dd49bdSEiji Ota 	case RDSV3_LOG_L1:
218c0dd49bdSEiji Ota 		if (!rdsv3_buffer_dprintf) {
219c0dd49bdSEiji Ota 			cmn_err(CE_CONT, "^%s", rdsv3_print_buf);
220c0dd49bdSEiji Ota 		} else {
221c0dd49bdSEiji Ota 			/* go to messages file */
222c0dd49bdSEiji Ota 			cmn_err(CE_CONT, "!%s", rdsv3_print_buf);
223c0dd49bdSEiji Ota 		}
224c0dd49bdSEiji Ota 		break;
225c0dd49bdSEiji Ota 	case RDSV3_LOG_L0:
226c0dd49bdSEiji Ota 		/* Strip the "\n" added earlier */
227c0dd49bdSEiji Ota 		if (rdsv3_print_buf[len - 1] == '\n') {
228c0dd49bdSEiji Ota 			rdsv3_print_buf[len - 1] = '\0';
229c0dd49bdSEiji Ota 		}
230c0dd49bdSEiji Ota 		if (msg_ptr[len - 1] == '\n') {
231c0dd49bdSEiji Ota 			msg_ptr[len - 1] = '\0';
232c0dd49bdSEiji Ota 		}
233c0dd49bdSEiji Ota 		/* go to console */
234c0dd49bdSEiji Ota 		cmn_err(CE_CONT, "^%s", rdsv3_print_buf);
235c0dd49bdSEiji Ota 		break;
236c0dd49bdSEiji Ota 	}
237c0dd49bdSEiji Ota 
238c0dd49bdSEiji Ota 	mutex_exit(&rdsv3_debug_mutex);
239c0dd49bdSEiji Ota }
240c0dd49bdSEiji Ota 
241c0dd49bdSEiji Ota void
rdsv3_dprintf_intr(char * name,char * fmt,...)242c0dd49bdSEiji Ota rdsv3_dprintf_intr(char *name, char *fmt, ...)
243c0dd49bdSEiji Ota {
244c0dd49bdSEiji Ota 	va_list ap;
245c0dd49bdSEiji Ota 
246c0dd49bdSEiji Ota 	va_start(ap, fmt);
247c0dd49bdSEiji Ota 	rdsv3_vlog(name, RDSV3_LOG_LINTR, fmt, ap);
248c0dd49bdSEiji Ota 	va_end(ap);
249c0dd49bdSEiji Ota }
250c0dd49bdSEiji Ota 
251c0dd49bdSEiji Ota /*
252c0dd49bdSEiji Ota  * Check individual subsystem err levels
253c0dd49bdSEiji Ota  */
254c0dd49bdSEiji Ota #define	RDSV3_CHECK_ERR_LEVEL(level)		\
255c0dd49bdSEiji Ota 	if (rdsv3dbglvl < level)		\
256c0dd49bdSEiji Ota 		return;				\
257c0dd49bdSEiji Ota 
258c0dd49bdSEiji Ota void
rdsv3_dprintf5(char * name,char * fmt,...)259c0dd49bdSEiji Ota rdsv3_dprintf5(char *name, char *fmt, ...)
260c0dd49bdSEiji Ota {
261c0dd49bdSEiji Ota 	va_list ap;
262c0dd49bdSEiji Ota 
263c0dd49bdSEiji Ota 	RDSV3_CHECK_ERR_LEVEL(RDSV3_LOG_L5);
264c0dd49bdSEiji Ota 
265c0dd49bdSEiji Ota 	va_start(ap, fmt);
266c0dd49bdSEiji Ota 	rdsv3_vlog(name, RDSV3_LOG_L5, fmt, ap);
267c0dd49bdSEiji Ota 	va_end(ap);
268c0dd49bdSEiji Ota }
269c0dd49bdSEiji Ota 
270c0dd49bdSEiji Ota void
rdsv3_dprintf4(char * name,char * fmt,...)271c0dd49bdSEiji Ota rdsv3_dprintf4(char *name, char *fmt, ...)
272c0dd49bdSEiji Ota {
273c0dd49bdSEiji Ota 	va_list ap;
274c0dd49bdSEiji Ota 
275c0dd49bdSEiji Ota 	RDSV3_CHECK_ERR_LEVEL(RDSV3_LOG_L4);
276c0dd49bdSEiji Ota 
277c0dd49bdSEiji Ota 	va_start(ap, fmt);
278c0dd49bdSEiji Ota 	rdsv3_vlog(name, RDSV3_LOG_L4, fmt, ap);
279c0dd49bdSEiji Ota 	va_end(ap);
280c0dd49bdSEiji Ota }
281c0dd49bdSEiji Ota 
282c0dd49bdSEiji Ota void
rdsv3_dprintf3(char * name,char * fmt,...)283c0dd49bdSEiji Ota rdsv3_dprintf3(char *name, char *fmt, ...)
284c0dd49bdSEiji Ota {
285c0dd49bdSEiji Ota 	va_list ap;
286c0dd49bdSEiji Ota 
287c0dd49bdSEiji Ota 	RDSV3_CHECK_ERR_LEVEL(RDSV3_LOG_L3);
288c0dd49bdSEiji Ota 
289c0dd49bdSEiji Ota 	va_start(ap, fmt);
290c0dd49bdSEiji Ota 	rdsv3_vlog(name, RDSV3_LOG_L3, fmt, ap);
291c0dd49bdSEiji Ota 	va_end(ap);
292c0dd49bdSEiji Ota }
293c0dd49bdSEiji Ota 
294c0dd49bdSEiji Ota void
rdsv3_dprintf2(char * name,char * fmt,...)295c0dd49bdSEiji Ota rdsv3_dprintf2(char *name, char *fmt, ...)
296c0dd49bdSEiji Ota {
297c0dd49bdSEiji Ota 	va_list ap;
298c0dd49bdSEiji Ota 
299c0dd49bdSEiji Ota 	RDSV3_CHECK_ERR_LEVEL(RDSV3_LOG_L2);
300c0dd49bdSEiji Ota 
301c0dd49bdSEiji Ota 	va_start(ap, fmt);
302c0dd49bdSEiji Ota 	rdsv3_vlog(name, RDSV3_LOG_L2, fmt, ap);
303c0dd49bdSEiji Ota 	va_end(ap);
304c0dd49bdSEiji Ota }
305c0dd49bdSEiji Ota 
306c0dd49bdSEiji Ota void
rdsv3_dprintf1(char * name,char * fmt,...)307c0dd49bdSEiji Ota rdsv3_dprintf1(char *name, char *fmt, ...)
308c0dd49bdSEiji Ota {
309c0dd49bdSEiji Ota 	va_list ap;
310c0dd49bdSEiji Ota 
311c0dd49bdSEiji Ota 	va_start(ap, fmt);
312c0dd49bdSEiji Ota 	rdsv3_vlog(name, RDSV3_LOG_L1, fmt, ap);
313c0dd49bdSEiji Ota 	va_end(ap);
314c0dd49bdSEiji Ota }
315c0dd49bdSEiji Ota 
316c0dd49bdSEiji Ota 
317c0dd49bdSEiji Ota /*
318c0dd49bdSEiji Ota  * Function:
319c0dd49bdSEiji Ota  *      rdsv3_dprintf0
320c0dd49bdSEiji Ota  * Input:
321c0dd49bdSEiji Ota  *      name	- Name of the function generating the debug message
322c0dd49bdSEiji Ota  *  	fmt	- The message to be displayed.
323c0dd49bdSEiji Ota  * Output:
324c0dd49bdSEiji Ota  *      none
325c0dd49bdSEiji Ota  * Returns:
326c0dd49bdSEiji Ota  *      none
327c0dd49bdSEiji Ota  * Description:
328c0dd49bdSEiji Ota  *  	A generic log function to display RDS debug messages.
329c0dd49bdSEiji Ota  */
330c0dd49bdSEiji Ota void
rdsv3_dprintf0(char * name,char * fmt,...)331c0dd49bdSEiji Ota rdsv3_dprintf0(char *name, char *fmt, ...)
332c0dd49bdSEiji Ota {
333c0dd49bdSEiji Ota 	va_list ap;
334c0dd49bdSEiji Ota 
335c0dd49bdSEiji Ota 	va_start(ap, fmt);
336c0dd49bdSEiji Ota 	rdsv3_vlog(name, RDSV3_LOG_L0, fmt, ap);
337c0dd49bdSEiji Ota 	va_end(ap);
338c0dd49bdSEiji Ota }
339c0dd49bdSEiji Ota 
340c0dd49bdSEiji Ota /* For ofed rdstrace */
341c0dd49bdSEiji Ota void
rdsv3_trace(char * name,uint8_t lvl,char * fmt,...)342c0dd49bdSEiji Ota rdsv3_trace(char *name, uint8_t lvl, char *fmt, ...)
343c0dd49bdSEiji Ota {
344c0dd49bdSEiji Ota 	va_list ap;
345c0dd49bdSEiji Ota 
346c0dd49bdSEiji Ota 	va_start(ap, fmt);
347c0dd49bdSEiji Ota 	rdsv3_vlog(name, lvl, fmt, ap);
348c0dd49bdSEiji Ota 	va_end(ap);
349c0dd49bdSEiji Ota }
350*cadbfdc3SEiji Ota 
351*cadbfdc3SEiji Ota #define	DEFAULT_RATELIMIT_INTERVAL	5
352*cadbfdc3SEiji Ota #define	DEFAULT_RATELIMIT_BURST	10
353*cadbfdc3SEiji Ota 
354*cadbfdc3SEiji Ota struct ratelimit_state {
355*cadbfdc3SEiji Ota 	clock_t interval;
356*cadbfdc3SEiji Ota 	int burst;
357*cadbfdc3SEiji Ota 	int printed;
358*cadbfdc3SEiji Ota 	int missed;
359*cadbfdc3SEiji Ota 	hrtime_t begin;
360*cadbfdc3SEiji Ota 	kmutex_t lock;
361*cadbfdc3SEiji Ota };
362*cadbfdc3SEiji Ota 
363*cadbfdc3SEiji Ota #define	DEFINE_RATELIMIT_STATE(name, interval, burst)		\
364*cadbfdc3SEiji Ota 	static struct ratelimit_state name = {interval, burst, }
365*cadbfdc3SEiji Ota 
366*cadbfdc3SEiji Ota DEFINE_RATELIMIT_STATE(rdsv3_printk_ratelimit_state,
367*cadbfdc3SEiji Ota     DEFAULT_RATELIMIT_INTERVAL,
368*cadbfdc3SEiji Ota     DEFAULT_RATELIMIT_BURST);
369*cadbfdc3SEiji Ota 
370*cadbfdc3SEiji Ota int
rdsv3_printk_ratelimit(void)371*cadbfdc3SEiji Ota rdsv3_printk_ratelimit(void)
372*cadbfdc3SEiji Ota {
373*cadbfdc3SEiji Ota 	struct ratelimit_state *rs = &rdsv3_printk_ratelimit_state;
374*cadbfdc3SEiji Ota 	hrtime_t current = gethrtime();
375*cadbfdc3SEiji Ota 	int rtn = 0;
376*cadbfdc3SEiji Ota 
377*cadbfdc3SEiji Ota 	if (rs->interval) {
378*cadbfdc3SEiji Ota 		return (1);
379*cadbfdc3SEiji Ota 	}
380*cadbfdc3SEiji Ota 	mutex_enter(&rs->lock);
381*cadbfdc3SEiji Ota 	if (!rs->begin) {
382*cadbfdc3SEiji Ota 		rs->begin = current;
383*cadbfdc3SEiji Ota 	}
384*cadbfdc3SEiji Ota 	if (current < rs->begin + TICK_TO_NSEC(rs->interval)) {
385*cadbfdc3SEiji Ota 		if (rs->missed) {
386*cadbfdc3SEiji Ota 			RDSV3_DPRINTF0("rdsv3_printk_ratelimit: ",
387*cadbfdc3SEiji Ota 			    "%d callbacks suppressed\n", rs->missed);
388*cadbfdc3SEiji Ota 			rs->begin = 0;
389*cadbfdc3SEiji Ota 			rs->printed = 0;
390*cadbfdc3SEiji Ota 			rs->missed = 0;
391*cadbfdc3SEiji Ota 		}
392*cadbfdc3SEiji Ota 	}
393*cadbfdc3SEiji Ota 	if (rs->burst && rs->burst > rs->printed) {
394*cadbfdc3SEiji Ota 		rs->printed++;
395*cadbfdc3SEiji Ota 		rtn = 1;
396*cadbfdc3SEiji Ota 	} else {
397*cadbfdc3SEiji Ota 		rs->missed++;
398*cadbfdc3SEiji Ota 	}
399*cadbfdc3SEiji Ota 	mutex_exit(&rs->lock);
400*cadbfdc3SEiji Ota 	return (rtn);
401*cadbfdc3SEiji Ota }
402