/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* The SPCS status support kernel utilities
* See header spcs_s_k.h for functional spec
*/
#ifdef DS_DDICT
#endif
/*
* Debug support to allow testing in userspace
*/
#else
#endif
/*
* Unistat state data
*/
/*
* This flag is made nonzero to indicate the bytestream transport mechanism
* is initalized.
*/
static int bytestream_transport_initialized = 0;
/*
* Common code for status init
*
*/
{
#ifdef UNISTAT_TRACE
#endif
p->major = SPCS_S_MAJOR_REV;
p->minor = SPCS_S_MINOR_REV;
p->icount = 0;
p->scount = 0;
p->tcount = 0;
#ifdef UNISTAT_TRACE
#endif
}
/*
* Create and initialize local ioctl status.
*
*/
{
#ifdef UNISTAT_TRACE
#endif
kstatus = (spcs_s_pinfo_t *)
if (kstatus)
#ifdef UNISTAT_TRACE
#endif
return ((spcs_s_info_t)kstatus);
}
/*
* Initialize existing ioctl status.
*/
void
{
#ifdef UNISTAT_TRACE
#endif
}
/*
* Release (free) ioctl status storage.
* BUG: this should take an spcs_s_info_t** or else the userspace
* version shoud just take a pointer. Could hopefully fix up Simon and
* Phil's code without too much trouble to fix this. Being inconsistent
* over the long term is bad.
*/
void
{
#ifdef UNISTAT_TRACE
#endif
#ifdef UNISTAT_TRACE
#endif
}
/*
* Delete one error code and its supplemental info
* The "oldest" error code is removed.
* The assumption is that there is at least one status code present.
* Neither sdata nor tdata space is reclaimed
*/
static void
{
int i;
int d;
#ifdef UNISTAT_TRACE
#endif
for (i = 0; i < (p->icount - d); i++)
p->icount -= d;
#ifdef UNISTAT_TRACE
#endif
}
/*
* Common code for adding a status code
* Return 1 if overflow detected, 0 if enough space for code and support
* info.
*/
static boolean_t
{
c.s = stcode;
#ifdef UNISTAT_TRACE
#endif
if (p->icount == SPCS_S_IDSIZE)
spcs_delete(p);
#ifdef UNISTAT_TRACE
#endif
return (B_TRUE);
} else
#ifdef UNISTAT_TRACE
#endif
return (B_FALSE);
}
/*
* Common code for adding a string as supplemental info.
* Add_code is assumed to have been called already to ensure enough space
* idata. The string is copied into the sdata array and the index to the
* first character is put in idata along with the datatype indicator.
*/
static void
{
int len;
#ifdef UNISTAT_TRACE
#endif
/*
* The following HACK is for RDC which is somewhat careless about
* it's usage of strings. It does not make sense to panic the machine
* because we botched an informational message. Print something
* usefull so we can go back and fix it.
* This can be removed when everyone has played by the correct unistat rules
*/
if (len == 0) {
}
"!SPCS: Unistat sdata array too small: needed %d bytes",
len + 1);
}
/*
* Check the rev level of the userspace status structure
* and spew some chunks if it doesn't match the kernel's unistat rev.
* Some day something more intelligent should happen to try to provide
* backward compatiblity with some mismatches (see the impl header file).
* Returns true if the revisions are compatible, false otherwise.
*/
static boolean_t
{
char *m;
int mode = 0;
#ifdef UNISTAT_TRACE
#endif
m =
"!SPCS Unistat failure (packaging error): data struct mismatch";
/* Both match */
#ifdef UNISTAT_TRACE
#endif
return (B_TRUE);
}
/*
* Deal with each case individually.
*/
#ifdef DEBUG
#endif
if (p->major > SPCS_S_MAJOR_REV) {
/*
* couldn't guess what to do if the userspace version is ahead
* of the kernel version, so issue a warning
*/
} else if (p->major < SPCS_S_MAJOR_REV) {
/*
* kernel's major version is ahead of userspace version: do
* something extremely clever here some day instead of the
* warning
*/
} else if (p->minor < SPCS_S_MINOR_REV) {
/*
* kernel's minor version is ahead of userspace version: do
* something clever here some day instead of the warning
*/
} else {
/*
* couldn't guess what to do if the userspace version is ahead
* of the kernel's minor version, so issue a warning
*/
}
#ifdef UNISTAT_TRACE
#endif
return (B_FALSE);
}
/*
* Add a code and optional support information to status
*
* The support info can only consist of char pointers.
*
* Varargs doesn't provide a means of detecting too few supplemental
* values...
*/
void
{
spcs_s_pinfo_t *p;
char *sp;
#ifdef UNISTAT_TRACE
#endif
p = (spcs_s_pinfo_t *)kstatus;
c.s = stcode;
#ifdef UNISTAT_TRACE
#endif
return;
}
while (c.f.sup_count--) {
}
#ifdef UNISTAT_TRACE
#endif
}
/*
* Common code to copy status to userspace
*
* Only "used" data is copied to minimize overhead.
*/
static void
{
int mode = 0;
#ifdef UNISTAT_TRACE
#endif
/*
* If tdata is in use, blow up: asynch data is not intended for ioctls.
* How would we ship it back? (the user hasn't given us any place to
* put it!)
*/
/*
* Gently, Bentley
* Have to copy all the header stuff even though there is no need for
* some items like the revisions. This is unavoidable without making
* the structure more complex or guessing about alignment and the true
* size of the part of the structure sitting ahead of the {i,s,t}data
* arrays.
*/
#ifdef UNISTAT_TRACE
#endif
}
/*
* Copy the ioctl status info to userspace
*/
void
{
#ifdef UNISTAT_TRACE
#endif
(spcs_s_pinfo_t *)ustatus);
#ifdef UNISTAT_TRACE
#endif
}
/*
* Copy the ioctl status info to userspace
* Free the status info storage.
*/
void
{
#ifdef UNISTAT_TRACE
#endif
(spcs_s_pinfo_t *)ustatus);
#ifdef UNISTAT_TRACE
#endif
}
/*
* Return the oldest status code from the status info or SPCS_S_OK if
* there is none.
*/
{
spcs_s_pinfo_t *p;
#ifdef UNISTAT_TRACE
#endif
p = (spcs_s_pinfo_t *)kstatus;
#ifdef UNISTAT_TRACE
#endif
}
/*
* Return the idata index of the last status code in the array (i.e.
* the "youngest" code present). The assumption is that the caller has
* checked to see that pcount is nonzero.
*/
static int
{
int last = 0;
int idx = 0;
#ifdef UNISTAT_TRACE
#endif
}
#ifdef UNISTAT_TRACE
#endif
return (last);
}
/*
* Return the youngest status code form the status info or SPCS_S_OK if
* there is none.
*/
{
spcs_s_pinfo_t *p;
#ifdef UNISTAT_TRACE
#endif
p = (spcs_s_pinfo_t *)kstatus;
if (p->icount)
else
#ifdef UNISTAT_TRACE
#endif
return (temp);
}
/*
* Insert a new status code or NULL if there is none.
* Copy the status info to userspace.
* return a value to use as an return value (e.g. ioctl return).
*/
{
spcs_s_pinfo_t *p;
char *sp;
#ifdef UNISTAT_TRACE
#endif
p = (spcs_s_pinfo_t *)*kstatus_a;
c.s = stcode;
else {
if (stcode) {
while (c.f.sup_count--) {
}
}
}
}
#ifdef UNISTAT_TRACE
#endif
return (ret.s);
}
/*
* Insert a new status code or NULL if there is none.
* Copy the status info to userspace.
* Free the kernel status info storage
* return a value to use as an operatiion return value (e.g. ioctl return)
*/
{
spcs_s_pinfo_t *p;
char *sp;
#ifdef UNISTAT_TRACE
#endif
p = *(spcs_s_pinfo_t **)kstatus_a;
c.s = stcode;
} else {
if (stcode) {
while (c.f.sup_count--) {
}
}
}
}
#ifdef UNISTAT_TRACE
#endif
return (ret.s);
}
/*
* Return true if a status code is a Solaris error code
*/
{
#ifdef UNISTAT_TRACE
#endif
c.s = error;
}
/*
* Edit a value into a numeric string
*/
char
{
#ifdef UNISTAT_TRACE
#endif
if (buflen) {
if (hex)
else
else
} else {
}
#ifdef UNISTAT_TRACE
#endif
return (buf);
}
/*
* Initialize the bytestream mechanism.
* This is a prototype. Specification TBD. Not in 10/22 commitment
*/
int
{
#ifdef UNISTAT_TRACE
#endif
return (SPCS_S_OK);
}
/*
* Stop (shut off) the bytestream mechanism.
*
* This is a prototype. Specification TBD. Not in 10/22 commitment
*/
int
{
#ifdef UNISTAT_TRACE
#endif
return (SPCS_S_OK);
}
/*
* Add a status code and the address and length of arbitrary binary
* data to be held (possibly with other status) for later transmission to
* userspace via a pipe facility (i.e. NOT via ioctl return). This is a
* means of getting arbitrary information with or without other status
* mechanisms.
* @param kstatus The status info pointer
* @param stcode The status code to annotate the data
* @param address The starting address of the data
* @param length The byte length of the data
* This is a prototype. Specification TBD. Not in the 10/22/98 unistat
* commitment
*/
void
{
spcs_s_pinfo_t *p;
#ifdef UNISTAT_TRACE
#endif
p = (spcs_s_pinfo_t *)kstatus;
if (p->tcount == SPCS_S_TDSIZE)
"SPCS: Unistat too many calls to spcs_s_add_bytestream");
"SPCS: Unistat idata array too small in "
"spcs_s_add_bytestream");
"SPCS: Unistat wrong sup_count in spcs_s_add_bytestream");
#ifdef UNISTAT_TRACE
#endif
}
/*
* Asynchronously output unistat info and possibly bytestreams to
* userspace. The bytestream mechanism must have been initialized.
* @param kstatus The status info pointer
* @return SPCS_S_OK for normal completion, SPCS_S_ERROR otherwise
* This is a prototype. Specification TBD. Not in the 10/22/98 unistat
* commitment
*/
int
{
spcs_s_pinfo_t *p;
int i, s, b, suppcount;
#ifdef UNISTAT_TRACE
#endif
p = (spcs_s_pinfo_t *)kstatus;
/*
* Any real code would have to go through and process the
* valid but the addresses would be meaningless. Instead, for a
* stream transport mechanism the bytestream(s) would follow the
* spcs_s_pinfo_t structure. So after the last call to
* spcs_s_add_bytestream things the spcs_pinfo_t would look like this:
* |-------------|
* | preamble |
* |-------------|
* | idata |
* |(sup offset) |-----------------|
* |(sup offset) |--| | bytestream reference (index)
* |-------------| | string |
* | sdata | | ref (offset) |
* | (strings) |<-| |
* |-------------| |
* | tdata | |
* | |<----------------|
* | (length) |
* | (address) |-------------------->byte data "out there somewhere"
* |-------------|
*
* After processing in this function the data headed for a pipe or
* other sequention stream would look like this:
*
* |-------------|
* | preamble |
* |-------------|
* | idata |
* | |-----------------|
* | |--| | bytestream reference (index)
* |-------------| | string |
* | sdata | | ref (offset) |
* | (strings) |<-| |
* |-------------| |
* | tdata | |
* | |<----------------|
* | (length) |
* | (null addr) |
* |-------------|
* |first |
* |bytestream |
* |group |
* |-------------|
* |second |
* |bytestream |
* |group |
* |-------------|
* | . . . |
* |-------------|
*
* For the prototype we just dump the stuff out so we can see the
* functions work.
*/
if (! bytestream_transport_initialized) {
#ifdef UNISTAT_TRACE
#endif
return (SPCS_S_ERROR);
}
/*
* I'd like nothing more than to code up a really cool pipe or mmap'd
* shared memory scheme to shovel this stuff up to a daemon that feeds
* Java events out to listener threads belonging to both management
* software, coresw product code and developer code. As it is I just
* have time to spew stuff out via cmn_err. Have to make believe this
* is an alternative to cmn_err and not just another dang client!
*/
i = 0;
while (i < p->icount) {
/*
* can't access the status text or anything else proper and
* pretty from here in the kernel, have to just dump it. Put
* the status codes out as decimal to make them look as weird
* as possible so we see that the point of this is not for
* anybody to actually pay attention to them but to use this
* as a means of testing the rest of the prototype and
* suggesting potental functionality. We also put the oldest
* stuff out first, backwards from ioctl status. That's
* because there are only minutes to implement this and the
* point is to see the potential, etc.
*/
i++;
for (s = 0; s < suppcount; s++) {
"!Supplement %d string value: %s", s,
(char *)(p->sdata +
else {
"!Supplement %d bytestream dump:", s);
/* The SunSoft mandated 8 character tabstops */
/* really BITE MY BUTT */
for (b = 0;
b++)
b, *bp++);
}
}
i += suppcount;
}
#ifdef UNISTAT_TRACE
#endif
return (SPCS_S_OK);
}