/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/nsc_thread.h>
#include "sd_bcache.h"
#include "sd_trace.h"
#include "sd_misc.h"
#ifndef _SD_NOTRACE
#ifndef SM_SDTRSEMA
#endif
int _sd_trace_mask = 0;
/*
* _sdbd_trace_t _sd_trace_table[-1, 0 .. sdbc_max_devs - 1]
* allocate memory, shift pointer up by one.
*/
static int _sd_trace_configed;
/*
* Forward declare all statics that are used before defined to enforce
* parameter checking.
* Some (if not all) of these could be removed if the code were reordered
*/
/*
* created by _sdbc_tr_unload and null the stale pointers.
*
*/
void
_sdbc_tr_unload(void)
{
if (_sd_trace_table)
}
/*
* which need to be present regardless of state of cache configuration.
*
*/
int
_sdbc_tr_load(void)
{
_sdbc_trace_t *m;
/*
* this maybe ought to wait to see if traces are configured, but it
* is only 4k
*/
m = (_sdbc_trace_t *)nsc_kmem_zalloc(
if (m == NULL) {
"sdbc(_sdbc_tr_load) cannot allocate trace table");
return (-1);
}
_sd_trace_table = m + 1;
return (0);
}
/*
* _sdbc_tr_configure - configure a trace area for the descriptor "cd".
* Unlike other ..._configure routines this routine is called multiple
* times since there will be an unknown number of open descriptors. At
* cache config time if tracing is enabled only the slot for SDT_INV_CD
* is created.
*
* Allocate the SD cache trace area (per device)
*/
int
{
int size;
_sdtr_table_t *t;
if (!_sd_cache_config.trace_size)
return (0);
if (cd == SDT_INV_CD)
_sd_trace_configed = 1;
return (0);
size = sizeof (_sdtr_table_t) +
return (-1);
}
if (!lk) {
nsc_kmem_free(t, size);
"alloc trace lock for cd %d", cd);
return (-1);
}
_sd_trace_mask |= t->tt_mask;
return (0);
}
/*
* _sdbc_tr_deconfigure
* free all trace memory (regions) when deconfiguring cache
*/
void
_sdbc_tr_deconfigure(void)
{
int i, size;
return;
_sd_trace_configed = 0;
sizeof (_sdtr_table_t);
}
}
}
static int first_alert = 0;
/*
* SDALERT(f,cd,len,fba,flg,ret) \
* _sd_alert(f,cd,len,fba,flg,ret)
* Build a ALERT trace entry and place it into the trace table.
*/
void
{
int tin;
_sdtr_table_t *t;
if (!first_alert) {
first_alert++;
"sdbc(_sd_alert) cd=%x f=%x len=%x fba=%" NSC_SZFMT
}
/* Watch out for negative error codes or simply bogus cd's */
/*
* no device trace buffer -- use SDT_INV_CD table?
*/
return;
} else {
/*
* no device trace buffer -- use SDT_INV_CD table?
*/
return;
}
}
return; /* check per-device mask */
t->tt_alert++; /* alert on this device */
t->tt_cnt++; /* overwritten entries if (tt_cnt >= tt_max) */
/*
* On LP64 systems we will only capture the low 32 bits of the
* time this really should be good enough for our purposes.
*
*/
if (t->tt_lbolt)
else
/* wakeup trace daemon, with hint */
if (_sd_trace_configed)
}
/*
* SDTRACE(f,cd,len,fba,flg,ret) \
* if (_sd_trace_mask & (f)) _sd_trace(f,cd,len,fba,flg,ret)
* Build a trace entry and place it into the trace table.
*/
void
{
int tin;
_sdtr_table_t *t;
/* Watch out for negative error codes or simply bogus cd's */
/*
* no device trace buffer -- use SDT_INV_CD table?
*/
return;
} else {
return;
}
if (!(t->tt_mask & f))
return; /* check per-device mask */
/*
* Don't overwrite if alert signaled (count lost instead)
* Locking only if 'trace_good' parameter set.
*/
t->tt_lost++; /* lost during alert */
return;
}
t->tt_cnt++; /* overwritten entries if (tt_cnt >= tt_max) */
/*
* On LP64 systems we will only capture the low 32 bits of the
* time this really should be good enough for our purposes.
*
*/
if (t->tt_lbolt)
else
}
/*
* _sd_scan_alert -- search for device with trace alert
*/
static int
_sd_scan_alert(void)
{
int cd;
return (cd);
return (SDT_ANY_CD);
}
/*
* _sd_scan_entries -- search for next device with trace entries
*/
static int
_sd_scan_entries(void)
{
int cd;
return (SDT_ANY_CD);
}
/*
* _sd_adump
* copy information about new trace records to trace daemon,
* or modify trace parameters.
*
* Some tracing parameters can be modified
* [Either per-device if cd specified, or the defaults if cd = SDT_ANY_CD]
* SD_LOGSIZE: table.tt_max (size for future opens)
* SD_SET_LBOLT: table.tt_lbolt
* SD_SET_MASK: table.tt_mask
* SD_SET_GOOD: table.tt_good
*
* if (cd >= 0) dump specific device records;
* if (cd == SDT_INV_CD) dump records which don't apply to any one device.
* if (cd == SDT_ANY_CD), then choose a device:
* 1) most recent alert, block if (flag & SD_ALERT_WAIT)
* 2) "next" device with unprocessed records.
*/
int
{
struct a {
long cd;
long size;
long flag;
}
if (! _sd_trace_configed) {
return (EINVAL); /* not initialized yet */
}
/* specific device: check if configured. dump current state. */
return (ENOSPC); /* no space configured */
}
} else {
/*
* SDT_ANY_CD:
* SD_ALERT_WAIT - wait for alert
*/
scan:
goto dump;
if (!_sd_trace_configed) {
return (EINVAL);
}
return (EINTR);
}
if (!_sd_trace_configed || !_sd_cache_initialized) {
return (EIDRM);
}
goto scan;
}
/* any device with entries */
return (0); /* no new entries */
dump:
} else {
return (ENOSPC); /* no space configured */
}
}
}
/*
* take a snapshot of the table state
*/
if (t->tt_good)
tt = *t;
if (t->tt_good)
mutex_exit(lk);
/*
* copy trace log entries to daemon
*
* size: entries in user-level 'buf'
* count: how many entries to copy [force count <= size]
* tt_max: size of kernel buffer
* tt_cnt: written entries [lossage if tt_cnt > tt_max]
* cnt: for wrap-around calculations
*/
} else
lost = 0;
if (count <= 0)
return (0);
return (EFAULT);
}
return (EFAULT);
}
} else {
return (EFAULT);
}
}
/*
* tt_alert uses fuzzy counting.
* if multiple alerts signaled, leave it at 1.
*/
if (t->tt_alert)
/*
* tt_cntout is tt_cnt after dump
* update tt_cnt for copied entries
*/
if (t->tt_good)
new_cnt = 0;
if (t->tt_good)
mutex_exit(lk);
return (EFAULT);
}
first_alert = 0;
return (0);
}
/* set size, mask, lbolt, or good(locks) */
static int
{
return (EFAULT);
}
if (flag & SD_SET_SIZE)
if (flag & SD_SET_MASK) {
/* explicitly set global mask, not bitwise or */
}
if (flag & SD_SET_LBOLT)
if (flag & SD_SET_GOOD)
return (0);
}
if (flag & SD_SET_SIZE)
/* modify particular device parameters */
(void) _sdbc_tr_configure(cd);
return (0);
if (flag & SD_SET_MASK) {
}
if (flag & SD_SET_LBOLT)
if (flag & SD_SET_GOOD)
return (EFAULT);
}
return (0);
}
#else /* ! _SD_NOTRACE */
int _sdbc_tr_load(void) { return (0); }
int _sdbc_tr_configure(void) { return (0); }
void _sdbc_tr_deconfigure(void) { return; }
void _sdbc_tr_unload(void) { return; }
#endif /* ! _SD_NOTRACE */