xref: /illumos-gate/usr/src/uts/common/io/cxgbe/t4nex/t4_debug.c (revision ba52565b00cef6c84d9c58d122f646c8f30b4a38)
1*ba52565bSPatrick Mooney /*
2*ba52565bSPatrick Mooney  * This file and its contents are supplied under the terms of the
3*ba52565bSPatrick Mooney  * Common Development and Distribution License ("CDDL"), version 1.0.
4*ba52565bSPatrick Mooney  * You may only use this file in accordance with the terms of version
5*ba52565bSPatrick Mooney  * 1.0 of the CDDL.
6*ba52565bSPatrick Mooney  *
7*ba52565bSPatrick Mooney  * A full copy of the text of the CDDL should have accompanied this
8*ba52565bSPatrick Mooney  * source.  A copy of the CDDL is also available via the Internet at
9*ba52565bSPatrick Mooney  * http://www.illumos.org/license/CDDL.
10*ba52565bSPatrick Mooney  */
11*ba52565bSPatrick Mooney 
12*ba52565bSPatrick Mooney /*
13*ba52565bSPatrick Mooney  * Copyright 2025 Oxide Computer Company
14*ba52565bSPatrick Mooney  */
15*ba52565bSPatrick Mooney 
16*ba52565bSPatrick Mooney 
17*ba52565bSPatrick Mooney #include <sys/types.h>
18*ba52565bSPatrick Mooney #include <sys/mutex.h>
19*ba52565bSPatrick Mooney #include <sys/list.h>
20*ba52565bSPatrick Mooney #include <sys/time.h>
21*ba52565bSPatrick Mooney #include <sys/varargs.h>
22*ba52565bSPatrick Mooney #include <sys/debug.h>
23*ba52565bSPatrick Mooney #include <sys/systm.h>
24*ba52565bSPatrick Mooney #include <sys/sysmacros.h>
25*ba52565bSPatrick Mooney #include <sys/sunddi.h>
26*ba52565bSPatrick Mooney #include <sys/cmn_err.h>
27*ba52565bSPatrick Mooney 
28*ba52565bSPatrick Mooney static kmutex_t t4_debug_lock;
29*ba52565bSPatrick Mooney static list_t t4_debug_msgs;
30*ba52565bSPatrick Mooney static uint_t t4_debug_size;
31*ba52565bSPatrick Mooney /* Rough counter of allocation failures during cxgb_printf() */
32*ba52565bSPatrick Mooney static uint64_t t4_debug_alloc_fail;
33*ba52565bSPatrick Mooney 
34*ba52565bSPatrick Mooney /*
35*ba52565bSPatrick Mooney  * Max ring buffer size for debug logs.  Defaults to 16KiB.
36*ba52565bSPatrick Mooney  *
37*ba52565bSPatrick Mooney  * If set to 0, no debug messages will be stored, nor will the t4-dbgmsg SDT
38*ba52565bSPatrick Mooney  * probe be fired.
39*ba52565bSPatrick Mooney  *
40*ba52565bSPatrick Mooney  * If set to < 0, then messages will be logged through the legacy cmn_err()
41*ba52565bSPatrick Mooney  * behavior (and the SDT probe is also skipped).
42*ba52565bSPatrick Mooney  */
43*ba52565bSPatrick Mooney int t4_debug_max_size = 16384;
44*ba52565bSPatrick Mooney 
45*ba52565bSPatrick Mooney typedef struct t4_dbgmsg {
46*ba52565bSPatrick Mooney 	list_node_t	tdm_node;
47*ba52565bSPatrick Mooney 	hrtime_t	tdm_when;
48*ba52565bSPatrick Mooney 	dev_info_t	*tdm_dip;
49*ba52565bSPatrick Mooney 	char		tdm_msg[];
50*ba52565bSPatrick Mooney } t4_dbgmsg_t;
51*ba52565bSPatrick Mooney 
52*ba52565bSPatrick Mooney static inline uint_t
t4_dbgmsg_sz(int sz)53*ba52565bSPatrick Mooney t4_dbgmsg_sz(int sz)
54*ba52565bSPatrick Mooney {
55*ba52565bSPatrick Mooney 	ASSERT(sz >= 0);
56*ba52565bSPatrick Mooney 	return (sizeof (t4_dbgmsg_t) + sz + 1);
57*ba52565bSPatrick Mooney }
58*ba52565bSPatrick Mooney 
59*ba52565bSPatrick Mooney static uint_t
t4_debug_free(t4_dbgmsg_t * msg)60*ba52565bSPatrick Mooney t4_debug_free(t4_dbgmsg_t *msg)
61*ba52565bSPatrick Mooney {
62*ba52565bSPatrick Mooney 	const uint_t free_sz = t4_dbgmsg_sz(strlen(msg->tdm_msg));
63*ba52565bSPatrick Mooney 	kmem_free(msg, free_sz);
64*ba52565bSPatrick Mooney 
65*ba52565bSPatrick Mooney 	return (free_sz);
66*ba52565bSPatrick Mooney }
67*ba52565bSPatrick Mooney 
68*ba52565bSPatrick Mooney void
cxgb_printf(dev_info_t * dip,int level,const char * fmt,...)69*ba52565bSPatrick Mooney cxgb_printf(dev_info_t *dip, int level, const char *fmt, ...)
70*ba52565bSPatrick Mooney {
71*ba52565bSPatrick Mooney 	va_list adx;
72*ba52565bSPatrick Mooney 
73*ba52565bSPatrick Mooney 	if (t4_debug_max_size == 0) {
74*ba52565bSPatrick Mooney 		/* User has opted out of debug messages completely */
75*ba52565bSPatrick Mooney 		return;
76*ba52565bSPatrick Mooney 	} else if (t4_debug_max_size < 0) {
77*ba52565bSPatrick Mooney 		/* User has opted into old cmn_err() behavior */
78*ba52565bSPatrick Mooney 		char pfmt[128];
79*ba52565bSPatrick Mooney 
80*ba52565bSPatrick Mooney 		(void) snprintf(pfmt, sizeof (pfmt), "%s%d: %s",
81*ba52565bSPatrick Mooney 		    ddi_driver_name(dip), ddi_get_instance(dip), fmt);
82*ba52565bSPatrick Mooney 
83*ba52565bSPatrick Mooney 		va_start(adx, fmt);
84*ba52565bSPatrick Mooney 		vcmn_err(level, pfmt, adx);
85*ba52565bSPatrick Mooney 		va_end(adx);
86*ba52565bSPatrick Mooney 
87*ba52565bSPatrick Mooney 		return;
88*ba52565bSPatrick Mooney 	}
89*ba52565bSPatrick Mooney 
90*ba52565bSPatrick Mooney 	va_start(adx, fmt);
91*ba52565bSPatrick Mooney 	const int size = vsnprintf(NULL, 0, fmt, adx);
92*ba52565bSPatrick Mooney 	va_end(adx);
93*ba52565bSPatrick Mooney 
94*ba52565bSPatrick Mooney 	const uint_t alloc_sz = t4_dbgmsg_sz(size);
95*ba52565bSPatrick Mooney 	t4_dbgmsg_t *msg = kmem_alloc(alloc_sz, KM_NOSLEEP);
96*ba52565bSPatrick Mooney 	if (msg == NULL) {
97*ba52565bSPatrick Mooney 		/*
98*ba52565bSPatrick Mooney 		 * Just note the failure and bail if the system is so pressed
99*ba52565bSPatrick Mooney 		 * for memory.
100*ba52565bSPatrick Mooney 		 */
101*ba52565bSPatrick Mooney 		DTRACE_PROBE1(t4__dbgmsg__alloc_fail, dev_info_t *, dip);
102*ba52565bSPatrick Mooney 		t4_debug_alloc_fail++;
103*ba52565bSPatrick Mooney 		return;
104*ba52565bSPatrick Mooney 	}
105*ba52565bSPatrick Mooney 	msg->tdm_when = gethrtime();
106*ba52565bSPatrick Mooney 	msg->tdm_dip = dip;
107*ba52565bSPatrick Mooney 
108*ba52565bSPatrick Mooney 	va_start(adx, fmt);
109*ba52565bSPatrick Mooney 	(void) vsnprintf(msg->tdm_msg, size + 1, fmt, adx);
110*ba52565bSPatrick Mooney 	va_end(adx);
111*ba52565bSPatrick Mooney 
112*ba52565bSPatrick Mooney 	DTRACE_PROBE2(t4__dbgmsg, dev_info_t *, dip, char *, msg->tdm_msg);
113*ba52565bSPatrick Mooney 
114*ba52565bSPatrick Mooney 	mutex_enter(&t4_debug_lock);
115*ba52565bSPatrick Mooney 	list_insert_tail(&t4_debug_msgs, msg);
116*ba52565bSPatrick Mooney 	t4_debug_size += alloc_sz;
117*ba52565bSPatrick Mooney 	while (t4_debug_size > t4_debug_max_size && t4_debug_size != 0) {
118*ba52565bSPatrick Mooney 		msg = list_remove_head(&t4_debug_msgs);
119*ba52565bSPatrick Mooney 		t4_debug_size -= t4_debug_free(msg);
120*ba52565bSPatrick Mooney 	}
121*ba52565bSPatrick Mooney 	mutex_exit(&t4_debug_lock);
122*ba52565bSPatrick Mooney }
123*ba52565bSPatrick Mooney 
124*ba52565bSPatrick Mooney void
t4_debug_init(void)125*ba52565bSPatrick Mooney t4_debug_init(void)
126*ba52565bSPatrick Mooney {
127*ba52565bSPatrick Mooney 	mutex_init(&t4_debug_lock, NULL, MUTEX_DEFAULT, NULL);
128*ba52565bSPatrick Mooney 	list_create(&t4_debug_msgs, sizeof (t4_dbgmsg_t),
129*ba52565bSPatrick Mooney 	    offsetof(t4_dbgmsg_t, tdm_node));
130*ba52565bSPatrick Mooney }
131*ba52565bSPatrick Mooney 
132*ba52565bSPatrick Mooney void
t4_debug_fini(void)133*ba52565bSPatrick Mooney t4_debug_fini(void)
134*ba52565bSPatrick Mooney {
135*ba52565bSPatrick Mooney 	t4_dbgmsg_t *msg;
136*ba52565bSPatrick Mooney 
137*ba52565bSPatrick Mooney 	while ((msg = list_remove_head(&t4_debug_msgs)) != NULL) {
138*ba52565bSPatrick Mooney 		t4_debug_size -= t4_debug_free(msg);
139*ba52565bSPatrick Mooney 	}
140*ba52565bSPatrick Mooney 	mutex_destroy(&t4_debug_lock);
141*ba52565bSPatrick Mooney }
142