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