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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 }