xref: /titanic_41/usr/src/uts/common/avs/ns/unistat/spcs_s_k.c (revision 3270659f55e0928d6edec3d26217cc29398a8149)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  *	The SPCS status support kernel utilities
28  *	See header spcs_s_k.h for functional spec
29  */
30 #include <sys/types.h>
31 #include <sys/ksynch.h>
32 #include <sys/kmem.h>
33 #include <sys/errno.h>
34 #include <sys/cmn_err.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
37 #include <sys/varargs.h>
38 
39 #include <sys/unistat/spcs_s.h>
40 #include <sys/unistat/spcs_s_k.h>
41 #include <sys/unistat/spcs_s_impl.h>
42 #include <sys/unistat/spcs_errors.h>
43 
44 #ifdef DS_DDICT
45 #include <sys/nsctl/contract.h>
46 #endif
47 /*
48  *	Debug support to allow testing in userspace
49  */
50 
51 #if	UNISTAT_ASSERTIONS
52 #define	_CELEVEL CE_PANIC
53 #else
54 #define	_CELEVEL CE_WARN
55 #endif
56 
57 
58 /*
59  *	Unistat state data
60  */
61 
62 /*
63  * This flag is made nonzero to indicate the bytestream transport mechanism
64  * is initalized.
65  */
66 
67 static int bytestream_transport_initialized = 0;
68 
69 /*
70  *	Common code for status init
71  *
72  */
73 
init_status(spcs_s_pinfo_t * p)74 static void init_status(spcs_s_pinfo_t *p)
75 {
76 #ifdef UNISTAT_TRACE
77 	cmn_err(CE_WARN, "!init_status entry");
78 #endif
79 	p->major = SPCS_S_MAJOR_REV;
80 	p->minor = SPCS_S_MINOR_REV;
81 	p->icount = 0;
82 	p->scount = 0;
83 	p->tcount = 0;
84 #ifdef UNISTAT_TRACE
85 	cmn_err(CE_WARN, "!init_status exit");
86 #endif
87 }
88 
89 /*
90  *	Create and initialize local ioctl status.
91  *
92  */
93 
94 spcs_s_info_t
spcs_s_kcreate()95 spcs_s_kcreate()
96 {
97 	spcs_s_pinfo_t *kstatus;
98 #ifdef UNISTAT_TRACE
99 	cmn_err(CE_WARN, "!spcs_s_kcreate entry");
100 #endif
101 	kstatus = (spcs_s_pinfo_t *)
102 	    kmem_alloc(sizeof (spcs_s_pinfo_t), KM_SLEEP);
103 
104 	if (kstatus)
105 		init_status(kstatus);
106 #ifdef UNISTAT_TRACE
107 	cmn_err(CE_WARN, "!spcs_s_kcreate exit");
108 #endif
109 	return ((spcs_s_info_t)kstatus);
110 }
111 
112 /*
113  *	Initialize existing ioctl status.
114  */
115 
116 void
spcs_s_kinit(spcs_s_info_t kstatus)117 spcs_s_kinit(spcs_s_info_t kstatus)
118 {
119 #ifdef UNISTAT_TRACE
120 	cmn_err(CE_WARN, "!spcs_s_kinit called");
121 #endif
122 	init_status((spcs_s_pinfo_t *)kstatus);
123 }
124 
125 /*
126  *	Release (free) ioctl status storage.
127  *	BUG: this should take an spcs_s_info_t** or else the userspace
128  *	version shoud just take a pointer. Could hopefully fix up Simon and
129  *	Phil's code without too much trouble to fix this. Being inconsistent
130  *	over the long term is bad.
131  */
132 
133 void
spcs_s_kfree(spcs_s_info_t kstatus)134 spcs_s_kfree(spcs_s_info_t kstatus)
135 {
136 #ifdef UNISTAT_TRACE
137 	cmn_err(CE_WARN, "!spcs_s_kfree entry");
138 #endif
139 	kmem_free((void *)kstatus, sizeof (spcs_s_pinfo_t));
140 #ifdef UNISTAT_TRACE
141 	cmn_err(CE_WARN, "!spcs_s_kfree exit");
142 #endif
143 }
144 
145 /*
146  *	Delete one error code and its supplemental info
147  *	The "oldest" error code is removed.
148  *	The assumption is that there is at least one status code present.
149  *	Neither sdata nor tdata space is reclaimed
150  */
151 
152 static void
spcs_delete(spcs_s_pinfo_t * p)153 spcs_delete(spcs_s_pinfo_t *p)
154 {
155 	int i;
156 	int d;
157 #ifdef UNISTAT_TRACE
158 	cmn_err(CE_WARN, "!spcs_s_delete entry");
159 #endif
160 	d = p->idata[0].f.sup_count + 1;
161 
162 	for (i = 0; i < (p->icount - d); i++)
163 		p->idata[i] = p->idata[i+d];
164 	p->icount -= d;
165 #ifdef UNISTAT_TRACE
166 	cmn_err(CE_WARN, "!spcs_s_delete exit");
167 #endif
168 }
169 
170 /*
171  * 	Common code for adding a status code
172  *	Return 1 if overflow detected, 0 if enough space for code and support
173  *      info.
174  */
175 
176 static boolean_t
add_code(spcs_s_pinfo_t * p,spcs_s_status_t stcode)177 add_code(spcs_s_pinfo_t *p, spcs_s_status_t stcode)
178 {
179 	spcs_s_udata_t c;
180 	c.s = stcode;
181 #ifdef UNISTAT_TRACE
182 	cmn_err(CE_WARN, "!add_code entry");
183 #endif
184 
185 	if ((p->icount + c.f.sup_count + 1) > SPCS_S_IDSIZE) {
186 		if (p->icount == SPCS_S_IDSIZE)
187 			spcs_delete(p);
188 		p->idata[p->icount++].s = SPCS_EOVERFLOW;
189 
190 		cmn_err(_CELEVEL, "!SPCS Unistat: not enough room in idata!");
191 #ifdef UNISTAT_TRACE
192 		cmn_err(CE_WARN, "!add_code exit 1");
193 #endif
194 
195 		return (B_TRUE);
196 	} else
197 		p->idata[p->icount++] = c;
198 #ifdef UNISTAT_TRACE
199 	cmn_err(CE_WARN, "!add_code exit 2");
200 #endif
201 	return (B_FALSE);
202 }
203 
204 /*
205  * 	Common code for adding a string as supplemental info.
206  *	Add_code is assumed to have been called already to ensure enough space
207  *      idata. The string is copied into the sdata array and the index to the
208  *	first character is put in idata along with the datatype indicator.
209  */
210 
211 static void
add_item(spcs_s_pinfo_t * p,char * string)212 add_item(spcs_s_pinfo_t *p, char *string)
213 {
214 	int len;
215 	char *nullstr = "XXXXXXXX";
216 #ifdef UNISTAT_TRACE
217 	cmn_err(CE_WARN, "!add_item entry");
218 #endif
219 	len = strlen(string);
220 
221 /*
222  * The following HACK is for RDC which is somewhat careless about
223  * it's usage of strings. It does not make sense to panic the machine
224  * because we botched an informational message. Print something
225  * usefull so we can go back and fix it.
226  * This can be removed when everyone has played by the correct unistat rules
227  */
228 	if (len == 0) {
229 		string = nullstr;
230 		len = strlen(nullstr);
231 	}
232 	if ((len + 1) > (SPCS_S_SDSIZE - p->scount))
233 		cmn_err(_CELEVEL,
234 		    "!SPCS: Unistat sdata array too small: needed %d bytes",
235 		    len + 1);
236 
237 	p->idata[p->icount].su.type = SU_STRING;
238 	p->idata[p->icount++].su.offset = p->scount;
239 	(void) strcpy(&(p->sdata[p->scount]), string);
240 	p->scount += len + 1;
241 }
242 
243 /*
244  *	Check the rev level of the userspace status structure
245  *	and spew some chunks if it doesn't match the kernel's unistat rev.
246  *	Some day something more intelligent should happen to try to provide
247  *	backward compatiblity with some mismatches (see the impl header file).
248  *	Returns true if the revisions are compatible, false otherwise.
249  */
250 
251 static boolean_t
check_revision(spcs_s_info_t ustatus)252 check_revision(spcs_s_info_t ustatus)
253 {
254 	char *m;
255 	char buf[SPCS_S_REVSIZE];
256 	spcs_s_pinfo_t *p = (spcs_s_pinfo_t *)buf;
257 	int mode = 0;
258 
259 #ifdef UNISTAT_TRACE
260 	cmn_err(CE_WARN, "!check_revision entry");
261 #endif
262 
263 	m =
264 	    "!SPCS Unistat failure (packaging error): data struct mismatch";
265 	(void) ddi_copyin((void *) ustatus, (void *) p, SPCS_S_REVSIZE, mode);
266 
267 	if ((p->major == SPCS_S_MAJOR_REV) && (p->minor == SPCS_S_MINOR_REV)) {
268 		/* Both match */
269 #ifdef UNISTAT_TRACE
270 		cmn_err(CE_WARN, "!check_revision exit 1");
271 #endif
272 		return (B_TRUE);
273 	}
274 
275 	/*
276 	 * We have a major and/or minor version mismatch.
277 	 * Deal with each case individually.
278 	 */
279 
280 #ifdef DEBUG
281 	cmn_err(CE_WARN, "!unistat kernel v%d.%d, user v%d.%d\n",
282 	    SPCS_S_MAJOR_REV, SPCS_S_MINOR_REV, (int)p->major, (int)p->minor);
283 #endif
284 
285 	if (p->major > SPCS_S_MAJOR_REV) {
286 		/*
287 		 * couldn't guess what to do if the userspace version is ahead
288 		 * of the kernel version, so issue a warning
289 		 */
290 		cmn_err(CE_WARN, m);
291 	} else if (p->major < SPCS_S_MAJOR_REV) {
292 		/*
293 		 * kernel's major version is ahead of userspace version: do
294 		 * something extremely clever here some day instead of the
295 		 * warning
296 		 */
297 		cmn_err(CE_WARN, m);
298 	} else if (p->minor < SPCS_S_MINOR_REV) {
299 
300 		/*
301 		 * kernel's minor version is ahead of userspace version: do
302 		 * something clever here some day instead of the warning
303 		 */
304 
305 		cmn_err(CE_WARN, m);
306 	} else {
307 		/*
308 		 * couldn't guess what to do if the userspace version is ahead
309 		 * of the kernel's minor version, so issue a warning
310 		 */
311 
312 		cmn_err(CE_WARN, m);
313 	}
314 #ifdef UNISTAT_TRACE
315 	cmn_err(CE_WARN, "!check_revision exit 2");
316 #endif
317 	return (B_FALSE);
318 }
319 
320 /*
321  *	Add a code and optional support information to status
322  *
323  *	The support info can only consist of char pointers.
324  *
325  *	Varargs doesn't provide a means of detecting too few supplemental
326  *	values...
327  */
328 
329 void
spcs_s_add(spcs_s_info_t kstatus,spcs_s_status_t stcode,...)330 spcs_s_add(spcs_s_info_t kstatus, spcs_s_status_t stcode, ...)
331 {
332 	va_list ap;
333 	spcs_s_udata_t c;
334 	spcs_s_pinfo_t *p;
335 	char *sp;
336 
337 #ifdef UNISTAT_TRACE
338 	cmn_err(CE_WARN, "!cspcs_s_add entry");
339 #endif
340 	p = (spcs_s_pinfo_t *)kstatus;
341 	c.s = stcode;
342 
343 	if (add_code(p, stcode) == B_TRUE) {
344 #ifdef UNISTAT_TRACE
345 		cmn_err(CE_WARN, "!cspcs_s_add exit 1");
346 #endif
347 		return;
348 	}
349 
350 	va_start(ap, stcode);
351 
352 	while (c.f.sup_count--) {
353 		sp = va_arg(ap, caddr_t);
354 		if (sp != (char *)NULL)
355 			add_item(p, sp);
356 	}
357 
358 	va_end(ap);
359 #ifdef UNISTAT_TRACE
360 	cmn_err(CE_WARN, "!cspcs_s_add exit 2");
361 #endif
362 }
363 
364 /*
365  *	Common code to copy status to userspace
366  *
367  *	Only "used" data is copied to minimize overhead.
368  */
369 
370 static void
scopyout(spcs_s_pinfo_t * kstatus,spcs_s_pinfo_t * ustatus)371 scopyout(spcs_s_pinfo_t *kstatus, spcs_s_pinfo_t *ustatus)
372 {
373 	int mode = 0;
374 #ifdef UNISTAT_TRACE
375 	cmn_err(CE_WARN, "!scopyout entry");
376 #endif
377 
378 	/*
379 	 * If tdata is in use, blow up: asynch data is not intended for ioctls.
380 	 * How would we ship it back? (the user hasn't given us any place to
381 	 * put it!)
382 	 */
383 
384 	if (kstatus->tcount)
385 		cmn_err(_CELEVEL, "!SPCS: Unistat async data in ioctl status!");
386 
387 	/*
388 	 * Gently, Bentley
389 	 * Have to copy all the header stuff even though there is no need for
390 	 * some items like the revisions. This is unavoidable without making
391 	 * the structure more complex or guessing about alignment and the true
392 	 * size of the part of the structure sitting ahead of the {i,s,t}data
393 	 * arrays.
394 	 */
395 
396 	(void) ddi_copyout((void *) kstatus, (void *) ustatus,
397 	    sizeof (spcs_s_pinfo_t) - (sizeof (kstatus->idata) +
398 	    sizeof (kstatus->sdata) + sizeof (kstatus->tdata)), mode);
399 	(void) ddi_copyout((void *)kstatus->idata, (void *) ustatus->idata,
400 	    (kstatus->icount * sizeof (kstatus->idata[0])), mode);
401 	(void) ddi_copyout((void *)kstatus->sdata, (void *) ustatus->sdata,
402 	    (kstatus->scount * sizeof (kstatus->sdata[0])), mode);
403 	(void) ddi_copyout((void *)kstatus->tdata, (void *) ustatus->tdata,
404 	    (kstatus->tcount * sizeof (kstatus->tdata[0])), mode);
405 #ifdef UNISTAT_TRACE
406 	cmn_err(CE_WARN, "!scopyout exit");
407 #endif
408 }
409 
410 /*
411  *	Copy the ioctl status info to userspace
412  */
413 
414 void
spcs_s_copyout(spcs_s_info_t * kstatus_a,spcs_s_info_t ustatus)415 spcs_s_copyout(spcs_s_info_t *kstatus_a, spcs_s_info_t ustatus)
416 {
417 #ifdef UNISTAT_TRACE
418 	cmn_err(CE_WARN, "!spcs_s_copyout entry");
419 #endif
420 	if (check_revision(ustatus) == B_TRUE)
421 		scopyout((spcs_s_pinfo_t *)*kstatus_a,
422 		    (spcs_s_pinfo_t *)ustatus);
423 #ifdef UNISTAT_TRACE
424 	cmn_err(CE_WARN, "!spcs_s_copyout exit");
425 #endif
426 }
427 
428 
429 /*
430  *	Copy the ioctl status info to userspace
431  *      Free the status info storage.
432  */
433 
434 void
spcs_s_copyoutf(spcs_s_info_t * kstatus_a,spcs_s_info_t ustatus)435 spcs_s_copyoutf(spcs_s_info_t *kstatus_a, spcs_s_info_t ustatus)
436 {
437 #ifdef UNISTAT_TRACE
438 	cmn_err(CE_WARN, "!spcs_s_copyoutf entry");
439 #endif
440 	if (check_revision(ustatus) == B_TRUE)
441 		scopyout((spcs_s_pinfo_t *)*kstatus_a,
442 		    (spcs_s_pinfo_t *)ustatus);
443 	spcs_s_kfree(*kstatus_a);
444 	*kstatus_a = NULL;
445 #ifdef UNISTAT_TRACE
446 	cmn_err(CE_WARN, "!spcs_s_copyoutf exit");
447 #endif
448 }
449 
450 /*
451  *	Return the oldest status code from the status info or SPCS_S_OK if
452  *      there is none.
453  */
454 
455 spcs_s_status_t
spcs_s_oldest_status(spcs_s_info_t kstatus)456 spcs_s_oldest_status(spcs_s_info_t kstatus)
457 {
458 	spcs_s_pinfo_t *p;
459 #ifdef UNISTAT_TRACE
460 	cmn_err(CE_WARN, "!spcs_s_oldest_status entry");
461 #endif
462 	p = (spcs_s_pinfo_t *)kstatus;
463 
464 #ifdef UNISTAT_TRACE
465 	cmn_err(CE_WARN, "!spcs_s_oldest_status exit");
466 #endif
467 	return (p->icount ? p->idata[0].s : SPCS_S_OK);
468 }
469 
470 /*
471  *      Return the idata index of the last status code in the array (i.e.
472  *      the "youngest" code present). The assumption is that the caller has
473  *      checked to see that pcount is nonzero.
474  */
475 
476 static int
last_code_idx(spcs_s_pinfo_t * p)477 last_code_idx(spcs_s_pinfo_t *p)
478 {
479 	int last = 0;
480 	int idx = 0;
481 #ifdef UNISTAT_TRACE
482 	cmn_err(CE_WARN, "!last_code_idx entry");
483 #endif
484 
485 	while (idx < p->icount) {
486 		last = idx;
487 		idx += p->idata[idx].f.sup_count + 1;
488 	}
489 #ifdef UNISTAT_TRACE
490 	cmn_err(CE_WARN, "!last_code_idx exit");
491 #endif
492 	return (last);
493 }
494 
495 /*
496  *	Return the youngest status code form the status info or SPCS_S_OK if
497  *      there is none.
498  */
499 
500 spcs_s_status_t
spcs_s_youngest_status(spcs_s_info_t kstatus)501 spcs_s_youngest_status(spcs_s_info_t kstatus)
502 {
503 	spcs_s_pinfo_t *p;
504 	spcs_s_status_t temp;
505 #ifdef UNISTAT_TRACE
506 	cmn_err(CE_WARN, "!spcs_s_youngest_status entry");
507 #endif
508 	p = (spcs_s_pinfo_t *)kstatus;
509 
510 	if (p->icount)
511 		temp = p->idata[last_code_idx(p)].s;
512 	else
513 		temp = SPCS_S_OK;
514 
515 #ifdef UNISTAT_TRACE
516 	cmn_err(CE_WARN, "!spcs_s_youngest_status exit");
517 #endif
518 	return (temp);
519 }
520 
521 /*
522  *      Insert a new status code or NULL if there is none.
523  *      Copy the status info to userspace.
524  *      return a value to use as an return value (e.g. ioctl return).
525  */
526 
527 spcs_s_status_t
spcs_s_ocopyout(spcs_s_info_t * kstatus_a,spcs_s_info_t ustatus,spcs_s_status_t stcode,...)528 spcs_s_ocopyout(spcs_s_info_t *kstatus_a,
529 			spcs_s_info_t ustatus, spcs_s_status_t stcode, ...)
530 {
531 	spcs_s_udata_t ret;
532 	va_list ap;
533 	spcs_s_udata_t c;
534 	spcs_s_pinfo_t *p;
535 	char *sp;
536 
537 #ifdef UNISTAT_TRACE
538 	cmn_err(CE_WARN, "!spcs_s_ocopyout entry");
539 #endif
540 	p  = (spcs_s_pinfo_t *)*kstatus_a;
541 	c.s = stcode;
542 
543 	if (check_revision(ustatus) == B_FALSE)
544 		ret.s = EINVAL;
545 	else {
546 		if (stcode) {
547 			if (add_code(p, stcode) == B_FALSE) {
548 				va_start(ap, stcode);
549 
550 				while (c.f.sup_count--) {
551 					sp = va_arg(ap, caddr_t);
552 					if (sp != (char *)NULL)
553 						add_item(p, sp);
554 				}
555 
556 				va_end(ap);
557 			}
558 		}
559 		ret.s = p->icount ? p->idata[last_code_idx(p)].s: SPCS_S_OK;
560 		scopyout(p, (spcs_s_pinfo_t *)ustatus);
561 	}
562 #ifdef UNISTAT_TRACE
563 	cmn_err(CE_WARN, "!spcs_s_ocopyout exit");
564 #endif
565 	return (ret.s);
566 }
567 
568 
569 /*
570  *      Insert a new status code or NULL if there is none.
571  *      Copy the status info to userspace.
572  *      Free the kernel status info storage
573  *      return a value to use as an operatiion return value (e.g. ioctl return)
574  */
575 
576 spcs_s_status_t
spcs_s_ocopyoutf(spcs_s_info_t * kstatus_a,spcs_s_info_t ustatus,spcs_s_status_t stcode,...)577 spcs_s_ocopyoutf(spcs_s_info_t *kstatus_a,
578 		spcs_s_info_t ustatus, spcs_s_status_t stcode, ...)
579 {
580 	spcs_s_udata_t ret;
581 	va_list ap;
582 	spcs_s_udata_t c;
583 	spcs_s_pinfo_t *p;
584 	char *sp;
585 
586 #ifdef UNISTAT_TRACE
587 	cmn_err(CE_WARN, "!spcs_s_ocopyoutf entry");
588 #endif
589 	p = *(spcs_s_pinfo_t **)kstatus_a;
590 	c.s = stcode;
591 
592 	if (check_revision(ustatus) == B_FALSE) {
593 		ret.s = EINVAL;
594 	} else {
595 		if (stcode) {
596 			if (add_code(p, stcode) == B_FALSE) {
597 				va_start(ap, stcode);
598 
599 				while (c.f.sup_count--) {
600 					sp = va_arg(ap, caddr_t);
601 					if (sp != (char *)NULL)
602 						add_item(p, sp);
603 				}
604 
605 				va_end(ap);
606 			}
607 		}
608 
609 		ret.s = p->icount ? p->idata[last_code_idx(p)].s: SPCS_S_OK;
610 		scopyout(p, (spcs_s_pinfo_t *)ustatus);
611 	}
612 	spcs_s_kfree((spcs_s_info_t)p);
613 	*kstatus_a = NULL;
614 #ifdef UNISTAT_TRACE
615 	cmn_err(CE_WARN, "!spcs_s_ocopyoutf exit");
616 #endif
617 	return (ret.s);
618 }
619 
620 /*
621  * Return true if a status code is a Solaris error code
622  */
623 
624 boolean_t
spcs_s_is_solaris(spcs_s_status_t error)625 spcs_s_is_solaris(spcs_s_status_t error)
626 {
627 	spcs_s_udata_t c;
628 #ifdef UNISTAT_TRACE
629 	cmn_err(CE_WARN, "!spcs_s_is_solaris called");
630 #endif
631 	c.s = error;
632 	return (c.f.module == 0 ? B_TRUE : B_FALSE);
633 }
634 
635 /*
636  * Edit a value into a numeric string
637  */
638 
639 char
spcs_s_inttostring(int val,char * buf,int buflen,int hex)640 *spcs_s_inttostring(int val, char *buf, int buflen, int hex)
641 {
642 	char tempbuf[20];
643 
644 #ifdef UNISTAT_TRACE
645 	cmn_err(CE_WARN, "!spcs_s_inttostring entry 0x%x", val);
646 #endif
647 	if (buflen) {
648 		if (hex)
649 			(void) sprintf(tempbuf, "0x%0X", val);
650 		else
651 			(void) sprintf(tempbuf, "%d", val);
652 		if (strlen(tempbuf) < (size_t)buflen)
653 			(void) strcpy(buf, tempbuf);
654 		else
655 			(void) strcpy(buf, "***");
656 	} else  {
657 		(void) strcpy(buf, "***");
658 	}
659 #ifdef UNISTAT_TRACE
660 		cmn_err(CE_WARN, "!spcs_s_inttostring exit: %s", buf);
661 #endif
662 	return (buf);
663 }
664 
665 /*
666  *	Initialize the bytestream mechanism.
667  *	This is a prototype. Specification TBD. Not in 10/22 commitment
668  */
669 
670 int
spcs_s_start_bytestream()671 spcs_s_start_bytestream()
672 {
673 #ifdef UNISTAT_TRACE
674 		cmn_err(CE_WARN, "!spcs_s_start_bytestream called");
675 #endif
676 	bytestream_transport_initialized = 1;
677 	return (SPCS_S_OK);
678 }
679 
680 /*
681  *	Stop (shut off) the bytestream mechanism.
682  *
683  *	This is a prototype. Specification TBD. Not in 10/22 commitment
684  */
685 
686 int
spcs_s_stop_bytestream()687 spcs_s_stop_bytestream()
688 {
689 #ifdef UNISTAT_TRACE
690 		cmn_err(CE_WARN, "!spcs_s_stop_bytestream called");
691 #endif
692 	bytestream_transport_initialized = 0;
693 	return (SPCS_S_OK);
694 }
695 
696 /*
697  *	Add a status code and the address and length of arbitrary binary
698  *	data to be held (possibly with other status) for later transmission to
699  *	userspace via a pipe facility (i.e. NOT via ioctl return). This is a
700  *	means of getting arbitrary information with or without other status
701  *	info shipped out as an alternative to cmn_err and/or trace file
702  *	mechanisms.
703  *	@param kstatus  The status info pointer
704  *	@param stcode   The status code to annotate the data
705  *	@param address  The starting address of the data
706  *	@param length   The byte length of the data
707  *	This is a prototype. Specification TBD. Not in the 10/22/98 unistat
708  *	commitment
709  */
710 
711 void
spcs_s_add_bytestream(spcs_s_info_t kstatus,spcs_s_status_t stcode,spcs_s_bytestream_ptr_t data,int size)712 spcs_s_add_bytestream(spcs_s_info_t kstatus, spcs_s_status_t stcode,
713 	spcs_s_bytestream_ptr_t data, int size)
714 {
715 	spcs_s_pinfo_t *p;
716 #ifdef UNISTAT_TRACE
717 		cmn_err(CE_WARN, "!spcs_s_add_bytestream entry");
718 #endif
719 	p = (spcs_s_pinfo_t *)kstatus;
720 
721 	if (p->tcount == SPCS_S_TDSIZE)
722 		cmn_err(CE_PANIC,
723 		    "SPCS: Unistat too many calls to spcs_s_add_bytestream");
724 	if ((p->icount + 2) >= SPCS_S_TDSIZE)
725 		cmn_err(CE_PANIC,
726 		    "SPCS: Unistat idata array too small in "
727 		    "spcs_s_add_bytestream");
728 	p->idata[p->icount].s = stcode;
729 	if (p->idata[p->icount++].f.sup_count != 1)
730 		cmn_err(CE_PANIC,
731 		    "SPCS: Unistat wrong sup_count in spcs_s_add_bytestream");
732 	p->idata[p->icount].su.type = SU_BYTESTREAM;
733 	p->idata[p->icount].su.offset = p->tcount++;
734 	p->tdata[p->idata[p->icount].su.offset].size = size;
735 	p->tdata[p->idata[p->icount++].su.offset].u_p.data = data;
736 #ifdef UNISTAT_TRACE
737 		cmn_err(CE_WARN, "!spcs_s_add_bytestream exit");
738 #endif
739 }
740 
741 /*
742  *	Asynchronously output unistat info and possibly bytestreams to
743  *	userspace. The bytestream mechanism must have been initialized.
744  *	@param kstatus  The status info pointer
745  *	@return SPCS_S_OK for normal completion, SPCS_S_ERROR otherwise
746  *	This is a prototype. Specification TBD. Not in the 10/22/98 unistat
747  *	commitment
748  */
749 
750 int
spcs_s_asynch_status(spcs_s_info_t kstatus)751 spcs_s_asynch_status(spcs_s_info_t kstatus)
752 {
753 	spcs_s_pinfo_t *p;
754 	int i, s, b, suppcount;
755 	uchar_t *bp;
756 #ifdef UNISTAT_TRACE
757 		cmn_err(CE_WARN, "!spcs_s_asynch_status entry");
758 #endif
759 	p = (spcs_s_pinfo_t *)kstatus;
760 
761 	/*
762 	 * Any real code would have to go through and process the
763 	 * address/length pairs in the tdata array. The lengths would be
764 	 * valid but the addresses would be meaningless. Instead, for a
765 	 * stream transport mechanism the bytestream(s) would follow the
766 	 * spcs_s_pinfo_t structure. So after the last call to
767 	 * spcs_s_add_bytestream things the spcs_pinfo_t would look like this:
768 	 * |-------------|
769 	 * | preamble	 |
770 	 * |-------------|
771 	 * | idata	 |
772 	 * |(sup offset) |-----------------|
773 	 * |(sup offset) |--|		   | bytestream reference (index)
774 	 * |-------------|  | string	   |
775 	 * | sdata	 |  | ref (offset) |
776 	 * | (strings)   |<-|		   |
777 	 * |-------------|		   |
778 	 * | tdata	 |		   |
779 	 * |		 |<----------------|
780 	 * | (length)    |
781 	 * | (address)   |-------------------->byte data "out there somewhere"
782 	 * |-------------|
783 	 *
784 	 * After processing in this function the data headed for a pipe or
785 	 * other sequention stream would look like this:
786 	 *
787 	 * |-------------|
788 	 * | preamble    |
789 	 * |-------------|
790 	 * | idata	 |
791 	 * |		 |-----------------|
792 	 * |		 |--|		   | bytestream reference (index)
793 	 * |-------------|  | string	   |
794 	 * | sdata	 |  | ref (offset) |
795 	 * | (strings)	 |<-|		   |
796 	 * |-------------|		   |
797 	 * | tdata	 |		   |
798 	 * |		 |<----------------|
799 	 * | (length)    |
800 	 * | (null addr) |
801 	 * |-------------|
802 	 * |first	 |
803 	 * |bytestream	 |
804 	 * |group	 |
805 	 * |-------------|
806 	 * |second	 |
807 	 * |bytestream   |
808 	 * |group	 |
809 	 * |-------------|
810 	 * | . . .	 |
811 	 * |-------------|
812 	 *
813 	 * For the prototype we just dump the stuff out so we can see the
814 	 * functions work.
815 	 */
816 
817 	if (! bytestream_transport_initialized) {
818 #ifdef UNISTAT_TRACE
819 		cmn_err(CE_WARN, "!spcs_s_asynch_status exit 1");
820 #endif
821 		return (SPCS_S_ERROR);
822 	}
823 
824 	cmn_err(CE_NOTE, "!SPCS Unistat Asynchronous Status Dump");
825 	cmn_err(CE_NOTE, "!This is a test fixture waiting for a pipe or");
826 	cmn_err(CE_NOTE, "!shared memory");
827 
828 	/*
829 	 * I'd like nothing more than to code up a really cool pipe or mmap'd
830 	 * shared memory scheme to shovel this stuff up to a daemon that feeds
831 	 * Java events out to listener threads belonging to both management
832 	 * software, coresw product code and developer code. As it is I just
833 	 * have time to spew stuff out via cmn_err. Have to make believe this
834 	 * is an alternative to cmn_err and not just another dang client!
835 	 */
836 
837 	i = 0;
838 
839 	while (i < p->icount) {
840 
841 		/*
842 		 * can't access the status text or anything else proper and
843 		 * pretty from here in the kernel, have to just dump it. Put
844 		 * the status codes out as decimal to make them look as weird
845 		 * as possible so we see that the point of this is not for
846 		 * anybody to actually pay attention to them but to use this
847 		 * as a means of testing the rest of the prototype and
848 		 * suggesting potental functionality. We also put the oldest
849 		 * stuff out first, backwards from ioctl status. That's
850 		 * because there are only minutes to implement this and the
851 		 * point is to see the potential, etc.
852 		 */
853 
854 		suppcount = p->idata[i].f.sup_count;
855 
856 		cmn_err(CE_NOTE, "!Status item %d value %x supplements %d",
857 		    i, p->idata[i].s, suppcount);
858 		i++;
859 
860 		for (s = 0; s < suppcount; s++) {
861 			if (p->idata[i+s].su.type == SU_STRING)
862 				cmn_err(CE_NOTE,
863 				    "!Supplement %d string value: %s", s,
864 				    (char *)(p->sdata +
865 				    p->idata[i+s].su.offset));
866 			else {
867 				cmn_err(CE_NOTE,
868 				    "!Supplement %d bytestream dump:", s);
869 				cmn_err(CE_NOTE, "!offset data");
870 				bp = p->tdata[p->idata[i+s].su.offset].u_p.data;
871 				/* The SunSoft mandated 8 character tabstops */
872 				/* really BITE MY BUTT */
873 				for (b = 0;
874 				    b < p->tdata[p->idata[i+s].su.offset].size;
875 				    b++)
876 					cmn_err(CE_NOTE, "!%6d   %2x",
877 					    b, *bp++);
878 			}
879 		}
880 
881 		i += suppcount;
882 	}
883 
884 #ifdef UNISTAT_TRACE
885 		cmn_err(CE_WARN, "!spcs_s_asynch_status exit 2");
886 #endif
887 	return (SPCS_S_OK);
888 }
889