1*7836SJohn.Forte@Sun.COM /*
2*7836SJohn.Forte@Sun.COM * CDDL HEADER START
3*7836SJohn.Forte@Sun.COM *
4*7836SJohn.Forte@Sun.COM * The contents of this file are subject to the terms of the
5*7836SJohn.Forte@Sun.COM * Common Development and Distribution License (the "License").
6*7836SJohn.Forte@Sun.COM * You may not use this file except in compliance with the License.
7*7836SJohn.Forte@Sun.COM *
8*7836SJohn.Forte@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7836SJohn.Forte@Sun.COM * or http://www.opensolaris.org/os/licensing.
10*7836SJohn.Forte@Sun.COM * See the License for the specific language governing permissions
11*7836SJohn.Forte@Sun.COM * and limitations under the License.
12*7836SJohn.Forte@Sun.COM *
13*7836SJohn.Forte@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
14*7836SJohn.Forte@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7836SJohn.Forte@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
16*7836SJohn.Forte@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
17*7836SJohn.Forte@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
18*7836SJohn.Forte@Sun.COM *
19*7836SJohn.Forte@Sun.COM * CDDL HEADER END
20*7836SJohn.Forte@Sun.COM */
21*7836SJohn.Forte@Sun.COM /*
22*7836SJohn.Forte@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23*7836SJohn.Forte@Sun.COM * Use is subject to license terms.
24*7836SJohn.Forte@Sun.COM */
25*7836SJohn.Forte@Sun.COM
26*7836SJohn.Forte@Sun.COM #include <sys/types.h>
27*7836SJohn.Forte@Sun.COM #include <sys/ksynch.h>
28*7836SJohn.Forte@Sun.COM #include <sys/cmn_err.h>
29*7836SJohn.Forte@Sun.COM #include <sys/errno.h>
30*7836SJohn.Forte@Sun.COM #include <sys/kmem.h>
31*7836SJohn.Forte@Sun.COM #include <sys/ddi.h>
32*7836SJohn.Forte@Sun.COM #include <sys/nsc_thread.h>
33*7836SJohn.Forte@Sun.COM
34*7836SJohn.Forte@Sun.COM #include "sd_bcache.h"
35*7836SJohn.Forte@Sun.COM #include "sd_trace.h"
36*7836SJohn.Forte@Sun.COM #include "sd_misc.h"
37*7836SJohn.Forte@Sun.COM
38*7836SJohn.Forte@Sun.COM #ifndef _SD_NOTRACE
39*7836SJohn.Forte@Sun.COM
40*7836SJohn.Forte@Sun.COM #ifndef SM_SDTRSEMA
41*7836SJohn.Forte@Sun.COM #define SM_SDTRSEMA 1
42*7836SJohn.Forte@Sun.COM #define SM_SDTRLCK 1
43*7836SJohn.Forte@Sun.COM #endif
44*7836SJohn.Forte@Sun.COM
45*7836SJohn.Forte@Sun.COM int _sd_trace_mask = 0;
46*7836SJohn.Forte@Sun.COM
47*7836SJohn.Forte@Sun.COM /*
48*7836SJohn.Forte@Sun.COM * _sdbd_trace_t _sd_trace_table[-1, 0 .. sdbc_max_devs - 1]
49*7836SJohn.Forte@Sun.COM * allocate memory, shift pointer up by one.
50*7836SJohn.Forte@Sun.COM */
51*7836SJohn.Forte@Sun.COM static _sdbc_trace_t *_sd_trace_table;
52*7836SJohn.Forte@Sun.COM
53*7836SJohn.Forte@Sun.COM static kcondvar_t _sd_adump_cv;
54*7836SJohn.Forte@Sun.COM static int _sd_trace_configed;
55*7836SJohn.Forte@Sun.COM static kmutex_t _sd_adump_lk;
56*7836SJohn.Forte@Sun.COM
57*7836SJohn.Forte@Sun.COM static int _alert_cd = SDT_ANY_CD;
58*7836SJohn.Forte@Sun.COM static int _last_cd = SDT_ANY_CD;
59*7836SJohn.Forte@Sun.COM #define XMEM(x, y) (void)(x = y, y = (SDT_ANY_CD), x)
60*7836SJohn.Forte@Sun.COM
61*7836SJohn.Forte@Sun.COM /*
62*7836SJohn.Forte@Sun.COM * Forward declare all statics that are used before defined to enforce
63*7836SJohn.Forte@Sun.COM * parameter checking.
64*7836SJohn.Forte@Sun.COM * Some (if not all) of these could be removed if the code were reordered
65*7836SJohn.Forte@Sun.COM */
66*7836SJohn.Forte@Sun.COM
67*7836SJohn.Forte@Sun.COM static int _sd_set_adump(int cd, int flag, _sdtr_table_t *table);
68*7836SJohn.Forte@Sun.COM
69*7836SJohn.Forte@Sun.COM /*
70*7836SJohn.Forte@Sun.COM * _sdbc_tr_unload - cache is being unloaded. Release any memory/lock/sv's
71*7836SJohn.Forte@Sun.COM * created by _sdbc_tr_unload and null the stale pointers.
72*7836SJohn.Forte@Sun.COM *
73*7836SJohn.Forte@Sun.COM */
74*7836SJohn.Forte@Sun.COM void
_sdbc_tr_unload(void)75*7836SJohn.Forte@Sun.COM _sdbc_tr_unload(void)
76*7836SJohn.Forte@Sun.COM {
77*7836SJohn.Forte@Sun.COM if (_sd_trace_table)
78*7836SJohn.Forte@Sun.COM nsc_kmem_free((_sd_trace_table - 1),
79*7836SJohn.Forte@Sun.COM sizeof (_sdbc_trace_t) * (sdbc_max_devs + 1));
80*7836SJohn.Forte@Sun.COM cv_destroy(&_sd_adump_cv);
81*7836SJohn.Forte@Sun.COM mutex_destroy(&_sd_adump_lk);
82*7836SJohn.Forte@Sun.COM
83*7836SJohn.Forte@Sun.COM _sd_trace_table = NULL;
84*7836SJohn.Forte@Sun.COM }
85*7836SJohn.Forte@Sun.COM
86*7836SJohn.Forte@Sun.COM /*
87*7836SJohn.Forte@Sun.COM * _sdbc_tr_load - cache is being loaded. Allocate the memory/lock/sv's
88*7836SJohn.Forte@Sun.COM * which need to be present regardless of state of cache configuration.
89*7836SJohn.Forte@Sun.COM *
90*7836SJohn.Forte@Sun.COM */
91*7836SJohn.Forte@Sun.COM int
_sdbc_tr_load(void)92*7836SJohn.Forte@Sun.COM _sdbc_tr_load(void)
93*7836SJohn.Forte@Sun.COM {
94*7836SJohn.Forte@Sun.COM _sdbc_trace_t *m;
95*7836SJohn.Forte@Sun.COM
96*7836SJohn.Forte@Sun.COM cv_init(&_sd_adump_cv, NULL, CV_DRIVER, NULL);
97*7836SJohn.Forte@Sun.COM mutex_init(&_sd_adump_lk, NULL, MUTEX_DRIVER, NULL);
98*7836SJohn.Forte@Sun.COM
99*7836SJohn.Forte@Sun.COM /*
100*7836SJohn.Forte@Sun.COM * this maybe ought to wait to see if traces are configured, but it
101*7836SJohn.Forte@Sun.COM * is only 4k
102*7836SJohn.Forte@Sun.COM */
103*7836SJohn.Forte@Sun.COM
104*7836SJohn.Forte@Sun.COM m = (_sdbc_trace_t *)nsc_kmem_zalloc(
105*7836SJohn.Forte@Sun.COM sizeof (_sdbc_trace_t) * (sdbc_max_devs + 1),
106*7836SJohn.Forte@Sun.COM KM_NOSLEEP, sdbc_stats_mem);
107*7836SJohn.Forte@Sun.COM
108*7836SJohn.Forte@Sun.COM if (m == NULL) {
109*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN,
110*7836SJohn.Forte@Sun.COM "sdbc(_sdbc_tr_load) cannot allocate trace table");
111*7836SJohn.Forte@Sun.COM return (-1);
112*7836SJohn.Forte@Sun.COM }
113*7836SJohn.Forte@Sun.COM _sd_trace_table = m + 1;
114*7836SJohn.Forte@Sun.COM
115*7836SJohn.Forte@Sun.COM return (0);
116*7836SJohn.Forte@Sun.COM
117*7836SJohn.Forte@Sun.COM }
118*7836SJohn.Forte@Sun.COM
119*7836SJohn.Forte@Sun.COM /*
120*7836SJohn.Forte@Sun.COM * _sdbc_tr_configure - configure a trace area for the descriptor "cd".
121*7836SJohn.Forte@Sun.COM * Unlike other ..._configure routines this routine is called multiple
122*7836SJohn.Forte@Sun.COM * times since there will be an unknown number of open descriptors. At
123*7836SJohn.Forte@Sun.COM * cache config time if tracing is enabled only the slot for SDT_INV_CD
124*7836SJohn.Forte@Sun.COM * is created.
125*7836SJohn.Forte@Sun.COM *
126*7836SJohn.Forte@Sun.COM * Allocate the SD cache trace area (per device)
127*7836SJohn.Forte@Sun.COM */
128*7836SJohn.Forte@Sun.COM
129*7836SJohn.Forte@Sun.COM int
_sdbc_tr_configure(int cd)130*7836SJohn.Forte@Sun.COM _sdbc_tr_configure(int cd)
131*7836SJohn.Forte@Sun.COM {
132*7836SJohn.Forte@Sun.COM int size;
133*7836SJohn.Forte@Sun.COM _sdtr_table_t *t;
134*7836SJohn.Forte@Sun.COM kmutex_t *lk;
135*7836SJohn.Forte@Sun.COM
136*7836SJohn.Forte@Sun.COM if (!_sd_cache_config.trace_size)
137*7836SJohn.Forte@Sun.COM return (0);
138*7836SJohn.Forte@Sun.COM
139*7836SJohn.Forte@Sun.COM if (cd == SDT_INV_CD)
140*7836SJohn.Forte@Sun.COM _sd_trace_configed = 1;
141*7836SJohn.Forte@Sun.COM
142*7836SJohn.Forte@Sun.COM if (_sd_trace_table[cd].tbl)
143*7836SJohn.Forte@Sun.COM return (0);
144*7836SJohn.Forte@Sun.COM
145*7836SJohn.Forte@Sun.COM size = sizeof (_sdtr_table_t) +
146*7836SJohn.Forte@Sun.COM _sd_cache_config.trace_size * sizeof (_sdtr_t);
147*7836SJohn.Forte@Sun.COM
148*7836SJohn.Forte@Sun.COM if ((t = (_sdtr_table_t *)nsc_kmem_zalloc(size,
149*7836SJohn.Forte@Sun.COM KM_NOSLEEP, sdbc_stats_mem)) == NULL) {
150*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "sdbc(_sdbc_tr_configure) failed to "
151*7836SJohn.Forte@Sun.COM "allocate %d bytes for trace, cd=%d", size, cd);
152*7836SJohn.Forte@Sun.COM return (-1);
153*7836SJohn.Forte@Sun.COM }
154*7836SJohn.Forte@Sun.COM
155*7836SJohn.Forte@Sun.COM lk = nsc_kmem_zalloc(sizeof (kmutex_t), KM_NOSLEEP, sdbc_local_mem);
156*7836SJohn.Forte@Sun.COM if (!lk) {
157*7836SJohn.Forte@Sun.COM nsc_kmem_free(t, size);
158*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "sdbc(_sdbc_tr_configure) cannot "
159*7836SJohn.Forte@Sun.COM "alloc trace lock for cd %d", cd);
160*7836SJohn.Forte@Sun.COM return (-1);
161*7836SJohn.Forte@Sun.COM }
162*7836SJohn.Forte@Sun.COM mutex_init(lk, NULL, MUTEX_DRIVER, NULL);
163*7836SJohn.Forte@Sun.COM
164*7836SJohn.Forte@Sun.COM _sd_trace_table[cd].t_lock = lk;
165*7836SJohn.Forte@Sun.COM t->tt_cd = cd;
166*7836SJohn.Forte@Sun.COM t->tt_max = _sd_cache_config.trace_size;
167*7836SJohn.Forte@Sun.COM t->tt_mask = _sd_cache_config.trace_mask;
168*7836SJohn.Forte@Sun.COM t->tt_lbolt = (char)_sd_cache_config.trace_lbolt;
169*7836SJohn.Forte@Sun.COM t->tt_good = (char)_sd_cache_config.trace_good;
170*7836SJohn.Forte@Sun.COM _sd_trace_mask |= t->tt_mask;
171*7836SJohn.Forte@Sun.COM _sd_trace_table[cd].tbl = t;
172*7836SJohn.Forte@Sun.COM return (0);
173*7836SJohn.Forte@Sun.COM }
174*7836SJohn.Forte@Sun.COM
175*7836SJohn.Forte@Sun.COM
176*7836SJohn.Forte@Sun.COM /*
177*7836SJohn.Forte@Sun.COM * _sdbc_tr_deconfigure
178*7836SJohn.Forte@Sun.COM * free all trace memory (regions) when deconfiguring cache
179*7836SJohn.Forte@Sun.COM */
180*7836SJohn.Forte@Sun.COM void
_sdbc_tr_deconfigure(void)181*7836SJohn.Forte@Sun.COM _sdbc_tr_deconfigure(void)
182*7836SJohn.Forte@Sun.COM {
183*7836SJohn.Forte@Sun.COM int i, size;
184*7836SJohn.Forte@Sun.COM _sdbc_trace_t *tt;
185*7836SJohn.Forte@Sun.COM
186*7836SJohn.Forte@Sun.COM if (!_sd_cache_config.trace_size || !_sd_trace_configed)
187*7836SJohn.Forte@Sun.COM return;
188*7836SJohn.Forte@Sun.COM
189*7836SJohn.Forte@Sun.COM mutex_enter(&_sd_adump_lk);
190*7836SJohn.Forte@Sun.COM _sd_trace_configed = 0;
191*7836SJohn.Forte@Sun.COM cv_broadcast(&_sd_adump_cv);
192*7836SJohn.Forte@Sun.COM mutex_exit(&_sd_adump_lk);
193*7836SJohn.Forte@Sun.COM
194*7836SJohn.Forte@Sun.COM for (i = -1, tt = &_sd_trace_table[-1]; i < sdbc_max_devs; i++, tt++) {
195*7836SJohn.Forte@Sun.COM if (tt->tbl == NULL) continue;
196*7836SJohn.Forte@Sun.COM size = tt->tbl->tt_max * sizeof (_sdtr_t) +
197*7836SJohn.Forte@Sun.COM sizeof (_sdtr_table_t);
198*7836SJohn.Forte@Sun.COM if (tt->t_lock) {
199*7836SJohn.Forte@Sun.COM mutex_destroy(tt->t_lock);
200*7836SJohn.Forte@Sun.COM nsc_kmem_free(tt->t_lock, sizeof (kmutex_t));
201*7836SJohn.Forte@Sun.COM }
202*7836SJohn.Forte@Sun.COM nsc_kmem_free(tt->tbl, size);
203*7836SJohn.Forte@Sun.COM tt->t_lock = NULL;
204*7836SJohn.Forte@Sun.COM tt->tbl = NULL;
205*7836SJohn.Forte@Sun.COM }
206*7836SJohn.Forte@Sun.COM _alert_cd = SDT_ANY_CD;
207*7836SJohn.Forte@Sun.COM _last_cd = SDT_ANY_CD;
208*7836SJohn.Forte@Sun.COM }
209*7836SJohn.Forte@Sun.COM
210*7836SJohn.Forte@Sun.COM static int first_alert = 0;
211*7836SJohn.Forte@Sun.COM /*
212*7836SJohn.Forte@Sun.COM * SDALERT(f,cd,len,fba,flg,ret) \
213*7836SJohn.Forte@Sun.COM * _sd_alert(f,cd,len,fba,flg,ret)
214*7836SJohn.Forte@Sun.COM * Build a ALERT trace entry and place it into the trace table.
215*7836SJohn.Forte@Sun.COM */
216*7836SJohn.Forte@Sun.COM void
_sd_alert(int f,int cd,int len,nsc_off_t fba,int flg,int ret)217*7836SJohn.Forte@Sun.COM _sd_alert(int f, int cd, int len, nsc_off_t fba, int flg, int ret)
218*7836SJohn.Forte@Sun.COM {
219*7836SJohn.Forte@Sun.COM int tin;
220*7836SJohn.Forte@Sun.COM _sdtr_t *tp;
221*7836SJohn.Forte@Sun.COM _sdtr_table_t *t;
222*7836SJohn.Forte@Sun.COM kmutex_t *lk;
223*7836SJohn.Forte@Sun.COM
224*7836SJohn.Forte@Sun.COM if (!first_alert) {
225*7836SJohn.Forte@Sun.COM first_alert++;
226*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN,
227*7836SJohn.Forte@Sun.COM "sdbc(_sd_alert) cd=%x f=%x len=%x fba=%" NSC_SZFMT
228*7836SJohn.Forte@Sun.COM " flg=%x ret=%x", cd, f, len, fba, flg, ret);
229*7836SJohn.Forte@Sun.COM
230*7836SJohn.Forte@Sun.COM }
231*7836SJohn.Forte@Sun.COM
232*7836SJohn.Forte@Sun.COM /* Watch out for negative error codes or simply bogus cd's */
233*7836SJohn.Forte@Sun.COM
234*7836SJohn.Forte@Sun.COM if (cd < -1 || cd >= sdbc_max_devs) {
235*7836SJohn.Forte@Sun.COM /*
236*7836SJohn.Forte@Sun.COM * no device trace buffer -- use SDT_INV_CD table?
237*7836SJohn.Forte@Sun.COM */
238*7836SJohn.Forte@Sun.COM if ((t = _sd_trace_table[-1].tbl) == NULL)
239*7836SJohn.Forte@Sun.COM return;
240*7836SJohn.Forte@Sun.COM lk = _sd_trace_table[-1].t_lock;
241*7836SJohn.Forte@Sun.COM } else {
242*7836SJohn.Forte@Sun.COM lk = _sd_trace_table[cd].t_lock;
243*7836SJohn.Forte@Sun.COM if ((t = _sd_trace_table[cd].tbl) == NULL) {
244*7836SJohn.Forte@Sun.COM /*
245*7836SJohn.Forte@Sun.COM * no device trace buffer -- use SDT_INV_CD table?
246*7836SJohn.Forte@Sun.COM */
247*7836SJohn.Forte@Sun.COM if ((t = _sd_trace_table[-1].tbl) == NULL)
248*7836SJohn.Forte@Sun.COM return;
249*7836SJohn.Forte@Sun.COM lk = _sd_trace_table[-1].t_lock;
250*7836SJohn.Forte@Sun.COM }
251*7836SJohn.Forte@Sun.COM }
252*7836SJohn.Forte@Sun.COM
253*7836SJohn.Forte@Sun.COM if (!(t->tt_mask & ST_ALERT))
254*7836SJohn.Forte@Sun.COM return; /* check per-device mask */
255*7836SJohn.Forte@Sun.COM
256*7836SJohn.Forte@Sun.COM if (t->tt_good) mutex_enter(lk);
257*7836SJohn.Forte@Sun.COM t->tt_alert++; /* alert on this device */
258*7836SJohn.Forte@Sun.COM t->tt_cnt++; /* overwritten entries if (tt_cnt >= tt_max) */
259*7836SJohn.Forte@Sun.COM
260*7836SJohn.Forte@Sun.COM tin = t->tt_in++;
261*7836SJohn.Forte@Sun.COM if (tin >= t->tt_max) tin = t->tt_in = 0;
262*7836SJohn.Forte@Sun.COM tp = &t->tt_buf[tin];
263*7836SJohn.Forte@Sun.COM tp->t_time = 0; /* not filled in yet */
264*7836SJohn.Forte@Sun.COM if (t->tt_good) mutex_exit(lk);
265*7836SJohn.Forte@Sun.COM
266*7836SJohn.Forte@Sun.COM tp->t_func = (ushort_t)f | ST_ALERT;
267*7836SJohn.Forte@Sun.COM tp->t_len = (ushort_t)len;
268*7836SJohn.Forte@Sun.COM tp->t_fba = fba;
269*7836SJohn.Forte@Sun.COM tp->t_flg = flg;
270*7836SJohn.Forte@Sun.COM tp->t_ret = ret;
271*7836SJohn.Forte@Sun.COM /*
272*7836SJohn.Forte@Sun.COM * On LP64 systems we will only capture the low 32 bits of the
273*7836SJohn.Forte@Sun.COM * time this really should be good enough for our purposes.
274*7836SJohn.Forte@Sun.COM *
275*7836SJohn.Forte@Sun.COM */
276*7836SJohn.Forte@Sun.COM if (t->tt_lbolt)
277*7836SJohn.Forte@Sun.COM tp->t_time = (int)nsc_lbolt();
278*7836SJohn.Forte@Sun.COM else
279*7836SJohn.Forte@Sun.COM tp->t_time = (int)nsc_usec();
280*7836SJohn.Forte@Sun.COM
281*7836SJohn.Forte@Sun.COM /* wakeup trace daemon, with hint */
282*7836SJohn.Forte@Sun.COM _alert_cd = cd;
283*7836SJohn.Forte@Sun.COM
284*7836SJohn.Forte@Sun.COM if (_sd_trace_configed)
285*7836SJohn.Forte@Sun.COM cv_signal(&_sd_adump_cv);
286*7836SJohn.Forte@Sun.COM }
287*7836SJohn.Forte@Sun.COM
288*7836SJohn.Forte@Sun.COM
289*7836SJohn.Forte@Sun.COM /*
290*7836SJohn.Forte@Sun.COM * SDTRACE(f,cd,len,fba,flg,ret) \
291*7836SJohn.Forte@Sun.COM * if (_sd_trace_mask & (f)) _sd_trace(f,cd,len,fba,flg,ret)
292*7836SJohn.Forte@Sun.COM * Build a trace entry and place it into the trace table.
293*7836SJohn.Forte@Sun.COM */
294*7836SJohn.Forte@Sun.COM void
_sd_trace(int f,int cd,int len,nsc_off_t fba,int flg,int ret)295*7836SJohn.Forte@Sun.COM _sd_trace(int f, int cd, int len, nsc_off_t fba, int flg, int ret)
296*7836SJohn.Forte@Sun.COM {
297*7836SJohn.Forte@Sun.COM int tin;
298*7836SJohn.Forte@Sun.COM _sdtr_t *tp;
299*7836SJohn.Forte@Sun.COM _sdtr_table_t *t;
300*7836SJohn.Forte@Sun.COM kmutex_t *lk;
301*7836SJohn.Forte@Sun.COM
302*7836SJohn.Forte@Sun.COM /* Watch out for negative error codes or simply bogus cd's */
303*7836SJohn.Forte@Sun.COM
304*7836SJohn.Forte@Sun.COM if (cd < -1 || cd >= sdbc_max_devs) {
305*7836SJohn.Forte@Sun.COM /*
306*7836SJohn.Forte@Sun.COM * no device trace buffer -- use SDT_INV_CD table?
307*7836SJohn.Forte@Sun.COM */
308*7836SJohn.Forte@Sun.COM if ((t = _sd_trace_table[-1].tbl) == NULL)
309*7836SJohn.Forte@Sun.COM return;
310*7836SJohn.Forte@Sun.COM lk = _sd_trace_table[-1].t_lock;
311*7836SJohn.Forte@Sun.COM } else {
312*7836SJohn.Forte@Sun.COM lk = _sd_trace_table[cd].t_lock;
313*7836SJohn.Forte@Sun.COM if ((t = _sd_trace_table[cd].tbl) == NULL)
314*7836SJohn.Forte@Sun.COM return;
315*7836SJohn.Forte@Sun.COM }
316*7836SJohn.Forte@Sun.COM
317*7836SJohn.Forte@Sun.COM if (!(t->tt_mask & f))
318*7836SJohn.Forte@Sun.COM return; /* check per-device mask */
319*7836SJohn.Forte@Sun.COM
320*7836SJohn.Forte@Sun.COM /*
321*7836SJohn.Forte@Sun.COM * Don't overwrite if alert signaled (count lost instead)
322*7836SJohn.Forte@Sun.COM * Locking only if 'trace_good' parameter set.
323*7836SJohn.Forte@Sun.COM */
324*7836SJohn.Forte@Sun.COM if (t->tt_good) mutex_enter(lk);
325*7836SJohn.Forte@Sun.COM if (t->tt_alert && (t->tt_cnt >= t->tt_max)) {
326*7836SJohn.Forte@Sun.COM t->tt_lost++; /* lost during alert */
327*7836SJohn.Forte@Sun.COM if (t->tt_good) mutex_exit(lk);
328*7836SJohn.Forte@Sun.COM return;
329*7836SJohn.Forte@Sun.COM }
330*7836SJohn.Forte@Sun.COM t->tt_cnt++; /* overwritten entries if (tt_cnt >= tt_max) */
331*7836SJohn.Forte@Sun.COM
332*7836SJohn.Forte@Sun.COM tin = t->tt_in++;
333*7836SJohn.Forte@Sun.COM if (tin >= t->tt_max) tin = t->tt_in = 0;
334*7836SJohn.Forte@Sun.COM tp = &t->tt_buf[tin];
335*7836SJohn.Forte@Sun.COM tp->t_time = 0; /* not filled in yet */
336*7836SJohn.Forte@Sun.COM if (t->tt_good) mutex_exit(lk);
337*7836SJohn.Forte@Sun.COM
338*7836SJohn.Forte@Sun.COM tp->t_func = (ushort_t)f;
339*7836SJohn.Forte@Sun.COM tp->t_len = (ushort_t)len;
340*7836SJohn.Forte@Sun.COM tp->t_fba = fba;
341*7836SJohn.Forte@Sun.COM tp->t_flg = flg;
342*7836SJohn.Forte@Sun.COM tp->t_ret = ret;
343*7836SJohn.Forte@Sun.COM /*
344*7836SJohn.Forte@Sun.COM * On LP64 systems we will only capture the low 32 bits of the
345*7836SJohn.Forte@Sun.COM * time this really should be good enough for our purposes.
346*7836SJohn.Forte@Sun.COM *
347*7836SJohn.Forte@Sun.COM */
348*7836SJohn.Forte@Sun.COM if (t->tt_lbolt)
349*7836SJohn.Forte@Sun.COM tp->t_time = (int)nsc_lbolt();
350*7836SJohn.Forte@Sun.COM else
351*7836SJohn.Forte@Sun.COM tp->t_time = (int)nsc_usec();
352*7836SJohn.Forte@Sun.COM }
353*7836SJohn.Forte@Sun.COM
354*7836SJohn.Forte@Sun.COM /*
355*7836SJohn.Forte@Sun.COM * _sd_scan_alert -- search for device with trace alert
356*7836SJohn.Forte@Sun.COM */
357*7836SJohn.Forte@Sun.COM static int
_sd_scan_alert(void)358*7836SJohn.Forte@Sun.COM _sd_scan_alert(void)
359*7836SJohn.Forte@Sun.COM {
360*7836SJohn.Forte@Sun.COM int cd;
361*7836SJohn.Forte@Sun.COM
362*7836SJohn.Forte@Sun.COM XMEM(cd, _alert_cd);
363*7836SJohn.Forte@Sun.COM if ((cd != SDT_ANY_CD) && _sd_trace_table[cd].tbl->tt_alert)
364*7836SJohn.Forte@Sun.COM return (cd);
365*7836SJohn.Forte@Sun.COM for (cd = _last_cd + 1; cd < sdbc_max_devs; cd++)
366*7836SJohn.Forte@Sun.COM if (_sd_trace_table[cd].tbl &&
367*7836SJohn.Forte@Sun.COM _sd_trace_table[cd].tbl->tt_alert)
368*7836SJohn.Forte@Sun.COM return (_last_cd = cd);
369*7836SJohn.Forte@Sun.COM for (cd = SDT_INV_CD; cd <= _last_cd; cd++)
370*7836SJohn.Forte@Sun.COM if (_sd_trace_table[cd].tbl &&
371*7836SJohn.Forte@Sun.COM _sd_trace_table[cd].tbl->tt_alert)
372*7836SJohn.Forte@Sun.COM return (_last_cd = cd);
373*7836SJohn.Forte@Sun.COM return (SDT_ANY_CD);
374*7836SJohn.Forte@Sun.COM }
375*7836SJohn.Forte@Sun.COM
376*7836SJohn.Forte@Sun.COM /*
377*7836SJohn.Forte@Sun.COM * _sd_scan_entries -- search for next device with trace entries
378*7836SJohn.Forte@Sun.COM */
379*7836SJohn.Forte@Sun.COM static int
_sd_scan_entries(void)380*7836SJohn.Forte@Sun.COM _sd_scan_entries(void)
381*7836SJohn.Forte@Sun.COM {
382*7836SJohn.Forte@Sun.COM int cd;
383*7836SJohn.Forte@Sun.COM
384*7836SJohn.Forte@Sun.COM for (cd = _last_cd + 1; cd < sdbc_max_devs; cd++)
385*7836SJohn.Forte@Sun.COM if (_sd_trace_table[cd].tbl && _sd_trace_table[cd].tbl->tt_cnt)
386*7836SJohn.Forte@Sun.COM return (_last_cd = cd);
387*7836SJohn.Forte@Sun.COM for (cd = SDT_INV_CD; cd <= _last_cd; cd++)
388*7836SJohn.Forte@Sun.COM if (_sd_trace_table[cd].tbl && _sd_trace_table[cd].tbl->tt_cnt)
389*7836SJohn.Forte@Sun.COM return (_last_cd = cd);
390*7836SJohn.Forte@Sun.COM return (SDT_ANY_CD);
391*7836SJohn.Forte@Sun.COM }
392*7836SJohn.Forte@Sun.COM
393*7836SJohn.Forte@Sun.COM
394*7836SJohn.Forte@Sun.COM /*
395*7836SJohn.Forte@Sun.COM * _sd_adump
396*7836SJohn.Forte@Sun.COM * copy information about new trace records to trace daemon,
397*7836SJohn.Forte@Sun.COM * or modify trace parameters.
398*7836SJohn.Forte@Sun.COM *
399*7836SJohn.Forte@Sun.COM * Some tracing parameters can be modified
400*7836SJohn.Forte@Sun.COM * [Either per-device if cd specified, or the defaults if cd = SDT_ANY_CD]
401*7836SJohn.Forte@Sun.COM * SD_LOGSIZE: table.tt_max (size for future opens)
402*7836SJohn.Forte@Sun.COM * SD_SET_LBOLT: table.tt_lbolt
403*7836SJohn.Forte@Sun.COM * SD_SET_MASK: table.tt_mask
404*7836SJohn.Forte@Sun.COM * SD_SET_GOOD: table.tt_good
405*7836SJohn.Forte@Sun.COM *
406*7836SJohn.Forte@Sun.COM * if (cd >= 0) dump specific device records;
407*7836SJohn.Forte@Sun.COM * if (cd == SDT_INV_CD) dump records which don't apply to any one device.
408*7836SJohn.Forte@Sun.COM * if (cd == SDT_ANY_CD), then choose a device:
409*7836SJohn.Forte@Sun.COM * 1) most recent alert, block if (flag & SD_ALERT_WAIT)
410*7836SJohn.Forte@Sun.COM * 2) "next" device with unprocessed records.
411*7836SJohn.Forte@Sun.COM */
412*7836SJohn.Forte@Sun.COM int
_sd_adump(void * args,int * rvp)413*7836SJohn.Forte@Sun.COM _sd_adump(void *args, int *rvp)
414*7836SJohn.Forte@Sun.COM {
415*7836SJohn.Forte@Sun.COM struct a {
416*7836SJohn.Forte@Sun.COM long cd;
417*7836SJohn.Forte@Sun.COM _sdtr_table_t *table;
418*7836SJohn.Forte@Sun.COM _sdtr_t *buf;
419*7836SJohn.Forte@Sun.COM long size;
420*7836SJohn.Forte@Sun.COM long flag;
421*7836SJohn.Forte@Sun.COM } *uap = (struct a *)args;
422*7836SJohn.Forte@Sun.COM _sdtr_t *ubuf;
423*7836SJohn.Forte@Sun.COM _sdtr_table_t tt, *t;
424*7836SJohn.Forte@Sun.COM kmutex_t *lk;
425*7836SJohn.Forte@Sun.COM int cd, count, lost, new_cnt;
426*7836SJohn.Forte@Sun.COM
427*7836SJohn.Forte@Sun.COM if (uap->flag & (SD_SET_SIZE|SD_SET_MASK|SD_SET_LBOLT|SD_SET_GOOD)) {
428*7836SJohn.Forte@Sun.COM return (_sd_set_adump(uap->cd, uap->flag, uap->table));
429*7836SJohn.Forte@Sun.COM }
430*7836SJohn.Forte@Sun.COM if (! _sd_trace_configed) {
431*7836SJohn.Forte@Sun.COM return (EINVAL); /* not initialized yet */
432*7836SJohn.Forte@Sun.COM }
433*7836SJohn.Forte@Sun.COM if (uap->cd >= SDT_INV_CD) {
434*7836SJohn.Forte@Sun.COM /* specific device: check if configured. dump current state. */
435*7836SJohn.Forte@Sun.COM if ((uap->cd > (long)sdbc_max_devs) ||
436*7836SJohn.Forte@Sun.COM !(t = _sd_trace_table[uap->cd].tbl)) {
437*7836SJohn.Forte@Sun.COM return (ENOSPC); /* no space configured */
438*7836SJohn.Forte@Sun.COM }
439*7836SJohn.Forte@Sun.COM lk = _sd_trace_table[uap->cd].t_lock;
440*7836SJohn.Forte@Sun.COM cd = uap->cd;
441*7836SJohn.Forte@Sun.COM } else {
442*7836SJohn.Forte@Sun.COM /*
443*7836SJohn.Forte@Sun.COM * SDT_ANY_CD:
444*7836SJohn.Forte@Sun.COM * SD_ALERT_WAIT - wait for alert
445*7836SJohn.Forte@Sun.COM */
446*7836SJohn.Forte@Sun.COM scan:
447*7836SJohn.Forte@Sun.COM if ((cd = _sd_scan_alert()) != SDT_ANY_CD)
448*7836SJohn.Forte@Sun.COM goto dump;
449*7836SJohn.Forte@Sun.COM if ((uap->flag & SD_ALERT_WAIT)) {
450*7836SJohn.Forte@Sun.COM mutex_enter(&_sd_adump_lk);
451*7836SJohn.Forte@Sun.COM if (!_sd_trace_configed) {
452*7836SJohn.Forte@Sun.COM mutex_exit(&_sd_adump_lk);
453*7836SJohn.Forte@Sun.COM return (EINVAL);
454*7836SJohn.Forte@Sun.COM }
455*7836SJohn.Forte@Sun.COM
456*7836SJohn.Forte@Sun.COM if (!cv_wait_sig(&_sd_adump_cv, &_sd_adump_lk)) {
457*7836SJohn.Forte@Sun.COM mutex_exit(&_sd_adump_lk);
458*7836SJohn.Forte@Sun.COM return (EINTR);
459*7836SJohn.Forte@Sun.COM }
460*7836SJohn.Forte@Sun.COM mutex_exit(&_sd_adump_lk);
461*7836SJohn.Forte@Sun.COM
462*7836SJohn.Forte@Sun.COM if (!_sd_trace_configed || !_sd_cache_initialized) {
463*7836SJohn.Forte@Sun.COM return (EIDRM);
464*7836SJohn.Forte@Sun.COM }
465*7836SJohn.Forte@Sun.COM goto scan;
466*7836SJohn.Forte@Sun.COM }
467*7836SJohn.Forte@Sun.COM /* any device with entries */
468*7836SJohn.Forte@Sun.COM if ((cd = _sd_scan_entries()) == SDT_INV_CD)
469*7836SJohn.Forte@Sun.COM return (0); /* no new entries */
470*7836SJohn.Forte@Sun.COM
471*7836SJohn.Forte@Sun.COM dump:
472*7836SJohn.Forte@Sun.COM lk = _sd_trace_table[cd].t_lock;
473*7836SJohn.Forte@Sun.COM if ((t = _sd_trace_table[cd].tbl) == NULL) {
474*7836SJohn.Forte@Sun.COM if (uap->flag & SD_ALERT_WAIT) {
475*7836SJohn.Forte@Sun.COM t = _sd_trace_table[-1].tbl;
476*7836SJohn.Forte@Sun.COM lk = _sd_trace_table[-1].t_lock;
477*7836SJohn.Forte@Sun.COM } else {
478*7836SJohn.Forte@Sun.COM return (ENOSPC); /* no space configured */
479*7836SJohn.Forte@Sun.COM }
480*7836SJohn.Forte@Sun.COM }
481*7836SJohn.Forte@Sun.COM }
482*7836SJohn.Forte@Sun.COM
483*7836SJohn.Forte@Sun.COM /*
484*7836SJohn.Forte@Sun.COM * take a snapshot of the table state
485*7836SJohn.Forte@Sun.COM */
486*7836SJohn.Forte@Sun.COM if (t->tt_good)
487*7836SJohn.Forte@Sun.COM mutex_enter(lk);
488*7836SJohn.Forte@Sun.COM tt = *t;
489*7836SJohn.Forte@Sun.COM if (t->tt_good)
490*7836SJohn.Forte@Sun.COM mutex_exit(lk);
491*7836SJohn.Forte@Sun.COM
492*7836SJohn.Forte@Sun.COM /*
493*7836SJohn.Forte@Sun.COM * copy trace log entries to daemon
494*7836SJohn.Forte@Sun.COM *
495*7836SJohn.Forte@Sun.COM * size: entries in user-level 'buf'
496*7836SJohn.Forte@Sun.COM * count: how many entries to copy [force count <= size]
497*7836SJohn.Forte@Sun.COM * tt_max: size of kernel buffer
498*7836SJohn.Forte@Sun.COM * tt_cnt: written entries [lossage if tt_cnt > tt_max]
499*7836SJohn.Forte@Sun.COM * cnt: for wrap-around calculations
500*7836SJohn.Forte@Sun.COM */
501*7836SJohn.Forte@Sun.COM if ((count = tt.tt_cnt) > tt.tt_max) { /* lost from beginning */
502*7836SJohn.Forte@Sun.COM tt.tt_out = tt.tt_in;
503*7836SJohn.Forte@Sun.COM count = tt.tt_max;
504*7836SJohn.Forte@Sun.COM lost = tt.tt_cnt - tt.tt_max;
505*7836SJohn.Forte@Sun.COM } else
506*7836SJohn.Forte@Sun.COM lost = 0;
507*7836SJohn.Forte@Sun.COM if (count <= 0)
508*7836SJohn.Forte@Sun.COM return (0);
509*7836SJohn.Forte@Sun.COM if ((long)count > uap->size)
510*7836SJohn.Forte@Sun.COM count = uap->size;
511*7836SJohn.Forte@Sun.COM ubuf = uap->buf;
512*7836SJohn.Forte@Sun.COM if ((tt.tt_out + count) > tt.tt_max) {
513*7836SJohn.Forte@Sun.COM int cnt = tt.tt_max - tt.tt_out;
514*7836SJohn.Forte@Sun.COM if (cnt > count)
515*7836SJohn.Forte@Sun.COM cnt = count;
516*7836SJohn.Forte@Sun.COM if (copyout(&(t->tt_buf[tt.tt_out]), ubuf,
517*7836SJohn.Forte@Sun.COM cnt * sizeof (_sdtr_t))) {
518*7836SJohn.Forte@Sun.COM return (EFAULT);
519*7836SJohn.Forte@Sun.COM }
520*7836SJohn.Forte@Sun.COM ubuf += cnt;
521*7836SJohn.Forte@Sun.COM cnt = count - cnt;
522*7836SJohn.Forte@Sun.COM if (copyout(&(t->tt_buf[0]), ubuf, cnt * sizeof (_sdtr_t))) {
523*7836SJohn.Forte@Sun.COM return (EFAULT);
524*7836SJohn.Forte@Sun.COM }
525*7836SJohn.Forte@Sun.COM tt.tt_out = cnt;
526*7836SJohn.Forte@Sun.COM } else {
527*7836SJohn.Forte@Sun.COM if (copyout(&(t->tt_buf[tt.tt_out]), ubuf,
528*7836SJohn.Forte@Sun.COM count * sizeof (_sdtr_t))) {
529*7836SJohn.Forte@Sun.COM return (EFAULT);
530*7836SJohn.Forte@Sun.COM }
531*7836SJohn.Forte@Sun.COM tt.tt_out += count;
532*7836SJohn.Forte@Sun.COM if (tt.tt_out == tt.tt_max)
533*7836SJohn.Forte@Sun.COM tt.tt_out = 0;
534*7836SJohn.Forte@Sun.COM }
535*7836SJohn.Forte@Sun.COM
536*7836SJohn.Forte@Sun.COM /*
537*7836SJohn.Forte@Sun.COM * tt_alert uses fuzzy counting.
538*7836SJohn.Forte@Sun.COM * if multiple alerts signaled, leave it at 1.
539*7836SJohn.Forte@Sun.COM */
540*7836SJohn.Forte@Sun.COM if (t->tt_alert)
541*7836SJohn.Forte@Sun.COM t->tt_alert = (t->tt_alert > 1) ? 1 : 0;
542*7836SJohn.Forte@Sun.COM
543*7836SJohn.Forte@Sun.COM /*
544*7836SJohn.Forte@Sun.COM * tt_cntout is tt_cnt after dump
545*7836SJohn.Forte@Sun.COM * update tt_cnt for copied entries
546*7836SJohn.Forte@Sun.COM */
547*7836SJohn.Forte@Sun.COM if (t->tt_good)
548*7836SJohn.Forte@Sun.COM mutex_enter(lk);
549*7836SJohn.Forte@Sun.COM tt.tt_cntout = t->tt_cnt;
550*7836SJohn.Forte@Sun.COM t->tt_out = tt.tt_out;
551*7836SJohn.Forte@Sun.COM new_cnt = t->tt_cnt;
552*7836SJohn.Forte@Sun.COM if ((new_cnt -= count+lost) < 0)
553*7836SJohn.Forte@Sun.COM new_cnt = 0;
554*7836SJohn.Forte@Sun.COM t->tt_cnt = new_cnt; /* race with new traces if not "tt_good" */
555*7836SJohn.Forte@Sun.COM if (t->tt_good)
556*7836SJohn.Forte@Sun.COM mutex_exit(lk);
557*7836SJohn.Forte@Sun.COM
558*7836SJohn.Forte@Sun.COM if (copyout(&tt, uap->table, sizeof (tt) - sizeof (_sdtr_t))) {
559*7836SJohn.Forte@Sun.COM return (EFAULT);
560*7836SJohn.Forte@Sun.COM }
561*7836SJohn.Forte@Sun.COM *rvp = count;
562*7836SJohn.Forte@Sun.COM
563*7836SJohn.Forte@Sun.COM first_alert = 0;
564*7836SJohn.Forte@Sun.COM return (0);
565*7836SJohn.Forte@Sun.COM }
566*7836SJohn.Forte@Sun.COM
567*7836SJohn.Forte@Sun.COM
568*7836SJohn.Forte@Sun.COM /* set size, mask, lbolt, or good(locks) */
569*7836SJohn.Forte@Sun.COM static int
_sd_set_adump(int cd,int flag,_sdtr_table_t * table)570*7836SJohn.Forte@Sun.COM _sd_set_adump(int cd, int flag, _sdtr_table_t *table)
571*7836SJohn.Forte@Sun.COM {
572*7836SJohn.Forte@Sun.COM _sdtr_table_t tt, *t;
573*7836SJohn.Forte@Sun.COM
574*7836SJohn.Forte@Sun.COM if (copyin(table, &tt, sizeof (tt) - sizeof (_sdtr_t))) {
575*7836SJohn.Forte@Sun.COM return (EFAULT);
576*7836SJohn.Forte@Sun.COM }
577*7836SJohn.Forte@Sun.COM if (cd == SDT_ANY_CD) { /* modify config parameter */
578*7836SJohn.Forte@Sun.COM if (flag & SD_SET_SIZE)
579*7836SJohn.Forte@Sun.COM _sd_cache_config.trace_size = tt.tt_max;
580*7836SJohn.Forte@Sun.COM if (flag & SD_SET_MASK) {
581*7836SJohn.Forte@Sun.COM _sd_cache_config.trace_mask = tt.tt_mask;
582*7836SJohn.Forte@Sun.COM /* explicitly set global mask, not bitwise or */
583*7836SJohn.Forte@Sun.COM _sd_trace_mask = tt.tt_mask;
584*7836SJohn.Forte@Sun.COM }
585*7836SJohn.Forte@Sun.COM if (flag & SD_SET_LBOLT)
586*7836SJohn.Forte@Sun.COM _sd_cache_config.trace_lbolt = tt.tt_lbolt;
587*7836SJohn.Forte@Sun.COM if (flag & SD_SET_GOOD)
588*7836SJohn.Forte@Sun.COM _sd_cache_config.trace_good = tt.tt_good;
589*7836SJohn.Forte@Sun.COM return (0);
590*7836SJohn.Forte@Sun.COM }
591*7836SJohn.Forte@Sun.COM if (flag & SD_SET_SIZE)
592*7836SJohn.Forte@Sun.COM _sd_cache_config.trace_size = tt.tt_max;
593*7836SJohn.Forte@Sun.COM /* modify particular device parameters */
594*7836SJohn.Forte@Sun.COM if (!_sd_trace_table[cd].tbl)
595*7836SJohn.Forte@Sun.COM (void) _sdbc_tr_configure(cd);
596*7836SJohn.Forte@Sun.COM if ((t = _sd_trace_table[cd].tbl) == NULL)
597*7836SJohn.Forte@Sun.COM return (0);
598*7836SJohn.Forte@Sun.COM if (flag & SD_SET_MASK) {
599*7836SJohn.Forte@Sun.COM t->tt_mask = tt.tt_mask;
600*7836SJohn.Forte@Sun.COM _sd_trace_mask |= tt.tt_mask; /* or-ed with global mask */
601*7836SJohn.Forte@Sun.COM }
602*7836SJohn.Forte@Sun.COM if (flag & SD_SET_LBOLT)
603*7836SJohn.Forte@Sun.COM t->tt_lbolt = tt.tt_lbolt;
604*7836SJohn.Forte@Sun.COM if (flag & SD_SET_GOOD)
605*7836SJohn.Forte@Sun.COM t->tt_good = tt.tt_good;
606*7836SJohn.Forte@Sun.COM if (copyout(t, table, sizeof (*t) - sizeof (_sdtr_t))) {
607*7836SJohn.Forte@Sun.COM return (EFAULT);
608*7836SJohn.Forte@Sun.COM }
609*7836SJohn.Forte@Sun.COM return (0);
610*7836SJohn.Forte@Sun.COM }
611*7836SJohn.Forte@Sun.COM
612*7836SJohn.Forte@Sun.COM #else /* ! _SD_NOTRACE */
613*7836SJohn.Forte@Sun.COM
_sd_adump()614*7836SJohn.Forte@Sun.COM int _sd_adump() { return (ENOSYS); }
_sdbc_tr_load(void)615*7836SJohn.Forte@Sun.COM int _sdbc_tr_load(void) { return (0); }
_sdbc_tr_configure(void)616*7836SJohn.Forte@Sun.COM int _sdbc_tr_configure(void) { return (0); }
_sdbc_tr_deconfigure(void)617*7836SJohn.Forte@Sun.COM void _sdbc_tr_deconfigure(void) { return; }
_sdbc_tr_unload(void)618*7836SJohn.Forte@Sun.COM void _sdbc_tr_unload(void) { return; }
619*7836SJohn.Forte@Sun.COM
620*7836SJohn.Forte@Sun.COM #endif /* ! _SD_NOTRACE */
621