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 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <string.h>
  29 #include <unistd.h>
  30 #include <errno.h>
  31 #include <signal.h>
  32 #include <setjmp.h>
  33 
  34 #include <kstat.h>
  35 
  36 #include <sys/nsctl/rdc.h>
  37 #include <sys/nsctl/rdc_io.h>
  38 #include <sys/nsctl/rdc_bitmap.h>
  39 
  40 #include "sdbc_stats.h"
  41 #include "sndr_stats.h"
  42 
  43 #include "dsstat.h"
  44 #include "common.h"
  45 #include "report.h"
  46 
  47 static sndrstat_t *sndr_top;
  48 
  49 void sndr_add_stat(sndrstat_t *);
  50 sndrstat_t *sndr_del_stat(sndrstat_t *);
  51 
  52 int sndr_value_check(sndrstat_t *);
  53 int sndr_validate(kstat_t *);
  54 int sndr_strcmp(char *, char *);
  55 int sndr_vol_selected(kstat_t *);
  56 
  57 void getType(kstat_t *, char *);
  58 void getStat(kstat_t *, char *);
  59 void getQueue(kstat_t *, char *);
  60 void printQueueStats(int, kstat_t *);
  61 float getSyncNeeded(kstat_t *);
  62 
  63 static void update_sighandler(int);
  64 static void discover_sighandler(int);
  65 
  66 static sigjmp_buf update_env, discover_env;
  67 static sig_atomic_t sig_raised = 0;
  68 /*
  69  * sndr_discover() - looks for new statistics to be monitored.
  70  * Verifies that any statistics found are now already being
  71  * monitored.
  72  *
  73  */
  74 int
  75 sndr_discover(kstat_ctl_t *kc)
  76 {
  77         static int validated = 0;
  78         struct sigaction segv_act;
  79         int rc = 0;
  80         kstat_t *ksp;
  81 
  82 
  83         (void) signal(SIGSEGV, discover_sighandler);
  84         (void) sigaction(SIGSEGV, NULL, &segv_act);
  85 
  86         /* Loop on all kstats */
  87         for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
  88                 int kinst;
  89                 char kname[KSTAT_STRLEN + 1];
  90                 sndrstat_t *cur;
  91                 sndrstat_t *sndrstat = NULL;
  92                 kstat_t *bmp_ksp;
  93                 kstat_t *sec_ksp;
  94 
  95                 /* Serach for SNDR set */
  96                 if (strcmp(ksp->ks_module, RDC_KSTAT_MODULE) != 0 ||
  97                     strcmp(ksp->ks_name, RDC_KSTAT_INFO) != 0) {
  98                         continue;
  99                 }
 100 
 101                 if (kstat_read(kc, ksp, NULL) == -1)
 102                         continue;
 103 
 104                 /*
 105                  * Validate kstat structure
 106                  */
 107                 if (! validated) {
 108                         if (sndr_validate(ksp))
 109                                 return (EINVAL);
 110 
 111                         validated++;
 112                 }
 113 
 114                 /*
 115                  * Duplicate check
 116                  */
 117                 for (cur = sndr_top; cur != NULL; cur = cur->next) {
 118                         char *cur_vname, *tst_vname;
 119                         uint32_t cur_inst, tst_inst;
 120 
 121                         cur_vname = kstat_value(cur->pre_set, RDC_IKSTAT_FILE);
 122                         cur_inst = cur->pre_set->ks_instance;
 123 
 124                         tst_vname = kstat_value(ksp, RDC_IKSTAT_FILE);
 125                         tst_inst = ksp->ks_instance;
 126 
 127                         if (strcmp(cur_vname, tst_vname) == 0 &&
 128                             cur_inst == tst_inst)
 129                                 goto next;
 130                 }
 131 
 132                 /*
 133                  * Initialize new record
 134                  */
 135                 sndrstat = (sndrstat_t *)calloc(1, sizeof (sndrstat_t));
 136                 kinst = ksp->ks_instance;
 137 
 138                 /*
 139                  * Set kstat
 140                  */
 141                 sndrstat->pre_set = kstat_retrieve(kc, ksp);
 142 
 143                 if (sndrstat->pre_set == NULL)
 144                         goto next;
 145 
 146                 sndrstat->collected |= GOT_SET_KSTAT;
 147 
 148                 /*
 149                  * Bitmap kstat
 150                  */
 151                 (void) sprintf(kname, "%s%d", RDC_KSTAT_BMPNAME, kinst);
 152 
 153                 bmp_ksp = kstat_lookup(kc, RDC_KSTAT_BMPNAME, kinst, kname);
 154                 sndrstat->pre_bmp = kstat_retrieve(kc, bmp_ksp);
 155 
 156                 if (sndrstat->pre_bmp == NULL)
 157                         goto next;
 158 
 159                 sndrstat->collected |= GOT_BMP_KSTAT;
 160 
 161                 /*
 162                  * Secondary kstat
 163                  */
 164                 (void) sprintf(kname, "%s%d", RDC_KSTAT_RDCNAME, kinst);
 165 
 166                 sec_ksp = kstat_lookup(kc, RDC_KSTAT_MODULE, kinst, kname);
 167                 sndrstat->pre_sec = kstat_retrieve(kc, sec_ksp);
 168 
 169                 if (sndrstat->pre_sec == NULL)
 170                         goto next;
 171 
 172                 sndrstat->collected |= GOT_SEC_KSTAT;
 173 
 174 next:
 175                 /*
 176                  * Check if we got a complete set of stats
 177                  */
 178                 if (sndrstat == NULL)
 179                         continue;
 180 
 181                 if (SNDR_COMPLETE(sndrstat->collected)) {
 182                         (void) sndr_del_stat(sndrstat);
 183                         continue;
 184                 }
 185 
 186                 /*
 187                  * Add to linked list
 188                  */
 189                 sndr_add_stat(sndrstat);
 190         }
 191 
 192         (void) sigsetjmp(discover_env, 0);
 193         if (sig_raised) {
 194                 sig_raised = 0;
 195                 rc = -1;
 196         }
 197         (void) sigaction(SIGSEGV, &segv_act, NULL);
 198 
 199         return (rc);
 200 }
 201 
 202 void
 203 discover_sighandler(int sig)
 204 {
 205         switch (sig) {
 206         case SIGSEGV:
 207                 sig_raised = 1;
 208                 siglongjmp(discover_env, sig);
 209         default:
 210                 exit(sig);
 211         }
 212 }
 213 
 214 void
 215 update_sighandler(int sig)
 216 {
 217         switch (sig) {
 218         case SIGSEGV:
 219                 sig_raised = 1;
 220                 siglongjmp(update_env, sig);
 221         default:
 222                 exit(sig);
 223         }
 224 }
 225 
 226 /*
 227  * sndr_update() - updates all of the statistics currently being monitored.
 228  *
 229  */
 230 int
 231 sndr_update(kstat_ctl_t *kc)
 232 {
 233         sndrstat_t *cur;
 234         struct sigaction segv_act;
 235         int rc = 0;
 236 
 237         (void) signal(SIGSEGV, update_sighandler);
 238         (void) sigaction(SIGSEGV, NULL, &segv_act);
 239 
 240         for (cur = sndr_top; cur != NULL; cur = cur->next) {
 241                 int kinst;
 242                 char kname[KSTAT_STRLEN + 1];
 243                 kstat_t *ksp = NULL;
 244                 char *cur_vname, *tst_vname;
 245 
 246                 cur->collected = 0;
 247 
 248                 /*
 249                  * Age off old stats
 250                  */
 251                 if (cur->cur_set != NULL) {
 252                         kstat_free(cur->pre_set);
 253                         kstat_free(cur->pre_bmp);
 254                         kstat_free(cur->pre_sec);
 255 
 256                         cur->pre_set = cur->cur_set;
 257                         cur->pre_bmp = cur->cur_bmp;
 258                         cur->pre_sec = cur->cur_sec;
 259                 }
 260 
 261                 /*
 262                  * Set kstat
 263                  */
 264                 (void) strncpy(kname, cur->pre_set->ks_name, KSTAT_STRLEN);
 265                 kname[KSTAT_STRLEN] = '\0';
 266 
 267                 kinst = cur->pre_set->ks_instance;
 268 
 269                 ksp = kstat_lookup(kc, RDC_KSTAT_MODULE, kinst, kname);
 270 
 271                 if ((cur->cur_set = kstat_retrieve(kc, ksp)) == NULL)
 272                         continue;
 273 
 274                 cur->collected |= GOT_SET_KSTAT;
 275 
 276                 /*
 277                  * Validate set
 278                  */
 279                 cur_vname = kstat_value(cur->pre_set, RDC_IKSTAT_FILE);
 280                 tst_vname = kstat_value(cur->cur_set, RDC_IKSTAT_FILE);
 281 
 282                 if (strcmp(cur_vname, tst_vname) != 0)
 283                         continue;
 284 
 285                 /*
 286                  * Bitmap kstat
 287                  */
 288                 (void) sprintf(kname, "%s%d", RDC_KSTAT_BMPNAME, kinst);
 289 
 290                 ksp = kstat_lookup(kc, RDC_KSTAT_BMPNAME, kinst, kname);
 291 
 292                 if ((cur->cur_bmp = kstat_retrieve(kc, ksp)) == NULL)
 293                         continue;
 294 
 295                 cur->collected |= GOT_BMP_KSTAT;
 296 
 297                 /*
 298                  * Secondary kstat
 299                  */
 300                 (void) sprintf(kname, "%s%d", RDC_KSTAT_RDCNAME, kinst);
 301 
 302                 ksp = kstat_lookup(kc, RDC_KSTAT_MODULE, kinst, kname);
 303 
 304                 if ((cur->cur_sec = kstat_retrieve(kc, ksp)) == NULL)
 305                         continue;
 306 
 307                 cur->collected |= GOT_SEC_KSTAT;
 308 
 309         }
 310 
 311         (void) sigsetjmp(update_env, 0);
 312         if (sig_raised) {
 313                 sig_raised = 0;
 314                 rc = -1;
 315         }
 316         (void) sigaction(SIGSEGV, &segv_act, NULL);
 317 
 318         return (rc);
 319 }
 320 
 321 /*
 322  * sndr_report() - outputs statistics for the statistics currently being
 323  * monitored.  Deletes statistics for volumes that have been disabled.
 324  *
 325  */
 326 int
 327 sndr_report()
 328 {
 329         int padsz;
 330         char pad[20] = "";
 331         sndrstat_t *cur, *pre = NULL;
 332 
 333         if (sndr_top == NULL)
 334                 return (0);
 335 
 336         /* Create padding string for secondary report lines */
 337         padsz = 0;
 338         if (dflags & FLAGS) {
 339                 padsz += STAT_HDR_SIZE;
 340                 padsz += STAT_HDR_SIZE;
 341         }
 342 
 343         if (dflags & ASYNC_QUEUE)
 344                 padsz += STAT_HDR_SIZE;
 345 
 346         if (dflags & PCTS)
 347                 padsz += PCT_HDR_SIZE;
 348 
 349         if (padsz) {
 350                 char fmt[20];
 351                 (void) sprintf(fmt, "%%%ds", padsz);
 352                 (void) sprintf(pad, fmt, " ");
 353         }
 354 
 355         for (cur = sndr_top; cur != NULL; ) { /*CSTYLED */
 356                 int first = 1;
 357                 char data[20] = "";
 358 
 359                 /* Check to see if this is this a complete */
 360                 if (SNDR_COMPLETE(cur->collected)) {
 361                         char *c;
 362                         char vn[NSC_MAXPATH + 1];
 363                         sndrstat_t *next;
 364 
 365                         /* notify user of set being disabled */
 366                         c = kstat_value(cur->pre_set, RDC_IKSTAT_SECFILE);
 367                         (void) strncpy(vn, c, NSC_MAXPATH);
 368                         vn[NSC_MAXPATH] = '\0';
 369 
 370                         (void) printf(DATA_C16, vn);
 371                         (void) printf(" %s\n", RDC_DISABLED);
 372 
 373                         next = sndr_del_stat(cur);
 374 
 375                         /* free memory and remove stat from list */
 376                         if (! pre)
 377                                 cur = sndr_top = next;
 378                         else
 379                                 cur = pre->next = next;
 380 
 381                         continue;
 382                 }
 383 
 384                 /* Check to see if the user specified this volume */
 385                 if (! sndr_vol_selected(cur->pre_set))
 386                         goto next;
 387 
 388                 /* Check to see if zflag applies */
 389                 if (zflag && sndr_value_check(cur) == 0)
 390                         goto next;
 391 
 392                 /* Calculate flags */
 393                 if (dflags & FLAGS) {
 394                         char c[STAT_HDR_SIZE];
 395                         char vtype[STAT_HDR_SIZE];
 396                         char vstat[STAT_HDR_SIZE];
 397 
 398                         getType(cur->cur_set, &c[0]);
 399                         (void) sprintf(vtype, DATA_C2, c);
 400                         (void) strcat(data, vtype);
 401 
 402                         getStat(cur->cur_set, &c[0]);
 403                         (void) sprintf(vstat, DATA_C2, c);
 404                         (void) strcat(data, vstat);
 405                 }
 406 
 407                 /* Async. queue statistics */
 408                 if (dflags & ASYNC_QUEUE) {
 409                         char c[STAT_HDR_SIZE];
 410                         char qtype[STAT_HDR_SIZE];
 411 
 412                         getQueue(cur->cur_set, &c[0]);
 413                         (void) sprintf(qtype, DATA_C2, c);
 414                         (void) strcat(data, qtype);
 415                 }
 416 
 417                 /* Calculate sync needed percentages */
 418                 if (dflags & PCTS) {
 419                         char snpct[10];
 420 
 421                         (void) sprintf(snpct, DATA_F62,
 422                             getSyncNeeded(cur->cur_set));
 423                         (void) strcat(data, snpct);
 424                 }
 425 
 426                 /* Output */
 427                 if (rflags & SNDR_NET) {
 428                         char *c;
 429                         char type[STAT_HDR_SIZE];
 430                         char vn[NAMED_LEN + 1];
 431 
 432                         getType(cur->cur_set, &type[0]);
 433 
 434                         if (type[0] == 'S') {
 435                                 c = kstat_value(cur->pre_set,
 436                                     RDC_IKSTAT_FILE);
 437                         } else {
 438                                 c = kstat_value(cur->pre_set,
 439                                     RDC_IKSTAT_SECFILE);
 440                         }
 441 
 442                         /* Only print last 15 characters */
 443                         if (strlen(c) >= NAMED_LEN) {
 444                                 c += strlen(c) - NAMED_LEN;
 445                         }
 446                         (void) strncpy(vn, c, NAMED_LEN);
 447                         vn[NAMED_LEN] = '\0';
 448 
 449                         header();
 450                         (void) printf(DATA_C16, vn);
 451                         (void) printf("%s", data);
 452                         (void) printf(ROLE_INF_FMT, RDC_SECONDARY);
 453 
 454                         /* Async. queue statistics */
 455                         if (dflags & ASYNC_QUEUE)
 456                                 printQueueStats(first, cur->cur_set);
 457 
 458                         io_report(cur->cur_sec, cur->pre_sec,
 459                             sdbc_getstat(vn));
 460                         (void) printf("\n");
 461 
 462                         if (first) {
 463                                 (void) strcpy(data, strlen(pad) > 0 ? pad : "");
 464                                 first = 0;
 465                         }
 466                 }
 467 
 468                 if (rflags & SNDR_BMP) {
 469                         char *c;
 470                         char vn[16];
 471 
 472                         c = kstat_value(cur->pre_set, RDC_IKSTAT_BITMAP);
 473 
 474                         /* Only print last 15 characters */
 475                         if (strlen(c) >= NAMED_LEN) {
 476                                 c += strlen(c) - NAMED_LEN;
 477                         }
 478                         (void) strncpy(vn, c, NAMED_LEN);
 479                         vn[NAMED_LEN] = '\0';
 480 
 481                         header();
 482                         (void) printf(DATA_C16, vn);
 483                         (void) printf("%s", data);
 484                         (void) printf(ROLE_INF_FMT, RDC_BITMAP);
 485 
 486                         /* Async. queue statistics */
 487                         if (dflags & ASYNC_QUEUE)
 488                                 printQueueStats(first, cur->cur_set);
 489 
 490                         io_report(cur->cur_bmp, cur->pre_bmp,
 491                             sdbc_getstat(vn));
 492                         (void) printf("\n");
 493 
 494                         if (first) {
 495                                 (void) strcpy(data, strlen(pad) > 0 ? pad : "");
 496                                 first = 0;
 497                         }
 498                 }
 499 next:
 500                 pre = cur;
 501                 cur = cur->next;
 502         }
 503 
 504         return (0);
 505 }
 506 
 507 /*
 508  * sndr_add_stat() - adds a fully populated sndrstat_t structure
 509  * to the linked list of currently monitored kstats.  The structure
 510  * will be added in alphabetical order, using the volume name as the
 511  * key.
 512  *
 513  * parameters
 514  *      sndrstat_t *sndrstat - to be added to the list.
 515  *
 516  */
 517 void
 518 sndr_add_stat(sndrstat_t *sndrstat)
 519 {
 520 
 521         sndrstat_t *cur;
 522 
 523         if (sndr_top == NULL) {
 524                 sndr_top = sndrstat;
 525                 return;
 526         }
 527 
 528         for (cur = sndr_top; cur != NULL; cur = cur->next) {
 529                 char *cur_vname, *nxt_vname, *tst_vname;
 530 
 531                 cur_vname = kstat_value(cur->pre_set, RDC_IKSTAT_FILE);
 532                 tst_vname = kstat_value(sndrstat->pre_set, RDC_IKSTAT_FILE);
 533 
 534                 if (strcmp(cur_vname, tst_vname) <= 0) {
 535                         /*
 536                          * If we get to the last item in the list, then just
 537                          * add this one to the end
 538                          */
 539                         if (cur->next == NULL) {
 540                                 cur->next = sndrstat;
 541                                 return;
 542                         }
 543 
 544                         nxt_vname = kstat_value(cur->next->pre_set,
 545                             RDC_IKSTAT_FILE);
 546 
 547                         if (strcmp(nxt_vname, tst_vname) > 0) {
 548                                 sndrstat->next = cur->next;
 549                                 cur->next = sndrstat;
 550                                 return;
 551                         }
 552                 } else {
 553                         if (cur == sndr_top)
 554                                 sndr_top = sndrstat;
 555 
 556                         sndrstat->next = cur;
 557 
 558                         return;
 559                 }
 560         }
 561 }
 562 
 563 /*
 564  * sndr_del_stat() - deallocate memory for the structure being
 565  * passed in.
 566  *
 567  * parameters
 568  *      sndrstat_t *sndrstat - structure to be deallocated
 569  *
 570  * returns
 571  *      sndrstat_t * - pointer to the "next" structures in the
 572  *      linked list. May be NULL if we are removing the last
 573  *      structure in the linked list.
 574  *
 575  */
 576 sndrstat_t *
 577 sndr_del_stat(sndrstat_t *sndrstat)
 578 {
 579 
 580         sndrstat_t *next = sndrstat->next;
 581 
 582         kstat_free(sndrstat->pre_set);
 583         kstat_free(sndrstat->pre_bmp);
 584         kstat_free(sndrstat->pre_sec);
 585         kstat_free(sndrstat->cur_set);
 586         kstat_free(sndrstat->cur_bmp);
 587         kstat_free(sndrstat->cur_sec);
 588 
 589         free(sndrstat);
 590 
 591         return (next);
 592 }
 593 
 594 /*
 595  * sndr_value_check() - check to determine if any activity was registered
 596  * on this volume by checking the previous stats vs. the current stats.
 597  *
 598  * parameters
 599  *      sndrstat_t *sndrstat - structure to be checked
 600  *
 601  * returns
 602  *      0 - no activity
 603  *      1 - activity
 604  */
 605 int
 606 sndr_value_check(sndrstat_t *sndrstat)
 607 {
 608         if (SNDR_COMPLETE(sndrstat->collected))
 609                 return (1);
 610 
 611         if (io_value_check(sndrstat->pre_bmp->ks_data,
 612             sndrstat->cur_bmp->ks_data)) {
 613                 return (1);
 614         }
 615 
 616         if (io_value_check(sndrstat->pre_sec->ks_data,
 617             sndrstat->cur_sec->ks_data)) {
 618                 return (1);
 619         }
 620 
 621         return (0);
 622 }
 623 
 624 /*
 625  * sndr_validate() - validates the fields required by dsstat exist in
 626  * the kstat_t structure passed in.  This check keeps dsstat from
 627  * core dumping if the kstat_named_t structures change in any of the
 628  * services that dsstat monitors.
 629  *
 630  * paramaters
 631  *      kstat_t *ksp - kstat_t structure to check.  The ks_data field
 632  *      should have been populated with a call to kstat_read()
 633  *
 634  * returns
 635  *      0 - all fields are contained in the kstat
 636  *      1 - a field required by dsstat is not in the kstat
 637  */
 638 int
 639 sndr_validate(kstat_t *ksp)
 640 {
 641         if (! kstat_value(ksp, RDC_IKSTAT_FILE) ||
 642             ! kstat_value(ksp, RDC_IKSTAT_FLAGS) ||
 643             ! kstat_value(ksp, RDC_IKSTAT_SYNCFLAGS) ||
 644             ! kstat_value(ksp, RDC_IKSTAT_BMPFLAGS) ||
 645             ! kstat_value(ksp, RDC_IKSTAT_VOLSIZE) ||
 646             ! kstat_value(ksp, RDC_IKSTAT_BITSSET) ||
 647             ! kstat_value(ksp, RDC_IKSTAT_QUEUE_TYPE) ||
 648             ! kstat_value(ksp, RDC_IKSTAT_ASYNC_ITEMS) ||
 649             ! kstat_value(ksp, RDC_IKSTAT_ASYNC_BLOCKS) ||
 650             ! kstat_value(ksp, RDC_IKSTAT_ASYNC_ITEM_HWM) ||
 651             ! kstat_value(ksp, RDC_IKSTAT_ASYNC_BLOCK_HWM))
 652                 return (1);
 653 
 654         return (0);
 655 }
 656 
 657 void
 658 getType(kstat_t *ksp, char *vtype)
 659 {
 660         uint32_t *set_flags;
 661 
 662         set_flags = kstat_value(ksp, RDC_IKSTAT_FLAGS);
 663 
 664         if (*set_flags & RDC_PRIMARY)
 665                 (void) strcpy(vtype, "P");
 666         else
 667                 (void) strcpy(vtype, "S");
 668 }
 669 
 670 void
 671 getStat(kstat_t *ksp, char *vstat)
 672 {
 673         uint32_t *set_flags;
 674         uint32_t *syn_flags;
 675         uint32_t *bmp_flags;
 676 
 677         set_flags = kstat_value(ksp, RDC_IKSTAT_FLAGS);
 678         syn_flags = kstat_value(ksp, RDC_IKSTAT_SYNCFLAGS);
 679         bmp_flags = kstat_value(ksp, RDC_IKSTAT_BMPFLAGS);
 680 
 681         (void) strcpy(vstat, "R");
 682 
 683         if (*set_flags & RDC_SYNCING) {
 684                 if (*set_flags & RDC_SLAVE)
 685                         if (*set_flags & RDC_PRIMARY)
 686                                 (void) strcpy(vstat, "RS");
 687                         else
 688                                 (void) strcpy(vstat, "SY");
 689                 else
 690                         if (*set_flags & RDC_PRIMARY)
 691                                 (void) strcpy(vstat, "SY");
 692                         else
 693                                 (void) strcpy(vstat, "RS");
 694         }
 695 
 696         if (*set_flags & RDC_LOGGING) {
 697                 (void) strcpy(vstat, "L");
 698 
 699                 if (*set_flags & RDC_QUEUING)
 700                         (void) strcpy(vstat, "Q");
 701 
 702                 if (*set_flags & RDC_DISKQ_FAILED)
 703                         (void) strcpy(vstat, "QF");
 704 
 705                 if (*syn_flags & RDC_SYNC_NEEDED)
 706                         (void) strcpy(vstat, "SN");
 707 
 708                 if (*syn_flags & RDC_RSYNC_NEEDED)
 709                         (void) strcpy(vstat, "RN");
 710         }
 711 
 712         if (*syn_flags & RDC_FCAL_FAILED)
 713                 (void) strcpy(vstat, "FF");
 714 
 715         if (*bmp_flags & RDC_BMP_FAILED)
 716                 (void) strcpy(vstat, "BF");
 717 
 718         if (*syn_flags & RDC_VOL_FAILED)
 719                 (void) strcpy(vstat, "VF");
 720 }
 721 
 722 void
 723 getQueue(kstat_t *ksp, char *vqueue)
 724 {
 725         char *qtype;
 726 
 727         (void) strcpy(vqueue, "-");
 728 
 729         qtype = kstat_value(ksp, RDC_IKSTAT_QUEUE_TYPE);
 730 
 731         if (strcmp(qtype, "memory") == 0)
 732                 (void) strcpy(vqueue, "M");
 733 
 734         if (strcmp(qtype, "disk") == 0)
 735                 (void) strcpy(vqueue, "D");
 736 }
 737 
 738 float
 739 getSyncNeeded(kstat_t *ksp)
 740 {
 741         uint32_t *volsize, *bitsset;
 742         uint32_t bits, segs;
 743         float pct;
 744 
 745         volsize = kstat_value(ksp, RDC_IKSTAT_VOLSIZE);
 746         bitsset = kstat_value(ksp, RDC_IKSTAT_BITSSET);
 747 
 748         segs = FBA_TO_LOG_LEN(*volsize);
 749         bits = *bitsset > 0 ? *bitsset : 0;
 750 
 751         pct  = segs ? ((float)bits/(float)segs) : 0.0;
 752         pct *= 100;
 753 
 754         return (pct);
 755 }
 756 
 757 /*
 758  * Special handling for compatibility.
 759  * "dsstat -s <set>" allows set name to be the last 15 chars,
 760  * due to 15 characters limit of old kstat information.
 761  *
 762  * return 0 if:
 763  * 1) full and partial are same
 764  * 2) partial is the last 15 chars of full
 765  */
 766 int
 767 sndr_strcmp(char *full, char *partial)
 768 {
 769         char *f = full;
 770         int rc;
 771 
 772         rc = strcmp(full, partial);
 773 
 774         if (rc != 0 &&
 775             (strlen(partial) == NAMED_LEN) &&
 776             (strlen(full) > NAMED_LEN)) {
 777                 f += strlen(full) - NAMED_LEN;
 778                 rc = strncmp(f, partial, NAMED_LEN);
 779         }
 780 
 781         return (rc);
 782 }
 783 
 784 int
 785 sndr_vol_selected(kstat_t *ksp)
 786 {
 787         vslist_t *vslist = vs_top;
 788 
 789         for (vslist = vs_top; vslist != NULL; vslist = vslist->next) {
 790                 char *vn;
 791                 char *vh;
 792 
 793                 /* If no host specified, check local only */
 794                 if (vslist->volhost == NULL) {
 795                         vn = kstat_value(ksp, RDC_IKSTAT_FILE);
 796 
 797                         if (sndr_strcmp(vn, vslist->volname))
 798                                 continue;
 799                         else
 800                                 break;
 801                 }
 802 
 803                 /* Check primary */
 804                 vn = kstat_value(ksp, RDC_IKSTAT_FILE);
 805                 vh = kstat_value(ksp, RDC_IKSTAT_PRIMARY_HOST);
 806 
 807                 if (sndr_strcmp(vn, vslist->volname) == 0 &&
 808                     sndr_strcmp(vh, vslist->volhost) == 0)
 809                         break;
 810 
 811                 /* Check secondary */
 812                 vn = kstat_value(ksp, RDC_IKSTAT_SECFILE);
 813                 vh = kstat_value(ksp, RDC_IKSTAT_SECONDARY_HOST);
 814 
 815                 if (sndr_strcmp(vn, vslist->volname) == 0 &&
 816                     sndr_strcmp(vh, vslist->volhost) == 0)
 817                         break;
 818         }
 819 
 820         if (vs_top != NULL && vslist == NULL)
 821                 return (0);
 822 
 823         return (1);
 824 }
 825 
 826 void
 827 printQueueStats(int first, kstat_t *cur_set)
 828 {
 829         uint32_t *val;
 830 
 831         if (! first) {
 832                 /* Filler for async. queue fields */
 833                 (void) printf(TPS_HDR_FMT, NO_INFO);
 834                 (void) printf(KPS_HDR_FMT, NO_INFO);
 835                 (void) printf(TPS_HDR_FMT, NO_INFO);
 836                 (void) printf(KPS_HDR_FMT, NO_INFO);
 837 
 838                 return;
 839         }
 840 
 841         val = (uint32_t *)kstat_value(cur_set, RDC_IKSTAT_ASYNC_ITEMS);
 842         (void) printf(TPS_INF_FMT, *val);
 843 
 844         val = (uint32_t *)kstat_value(cur_set, RDC_IKSTAT_ASYNC_BLOCKS);
 845         (void) printf(KPS_INF_FMT, (float)(*val / 2));
 846 
 847         val = (uint32_t *)kstat_value(cur_set, RDC_IKSTAT_ASYNC_ITEM_HWM);
 848         (void) printf(TPS_INF_FMT, *val);
 849 
 850         val = (uint32_t *)kstat_value(cur_set, RDC_IKSTAT_ASYNC_BLOCK_HWM);
 851         (void) printf(KPS_INF_FMT, (float)(*val / 2));
 852 }