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 }