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 /*
  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include <errno.h>
  28 #include <stdio.h>
  29 #include <unistd.h>
  30 #include <strings.h>
  31 #include <stdlib.h>
  32 
  33 #include <sys/types.h>
  34 #include <sys/time.h>
  35 #include <sys/nsctl/sdbc_ioctl.h>
  36 #include <sys/nsctl/rdc_ioctl.h>
  37 #include <sys/nsctl/sd_bcache.h>
  38 #include <sys/nsctl/sd_conf.h>
  39 #include <sys/nsctl/rdc_io.h>
  40 #include <sys/nsctl/rdc_bitmap.h>
  41 #include <sys/unistat/spcs_s_u.h>
  42 #include <curses.h>
  43 
  44 static rdc_status_t *rdc_status;
  45 static rdc_u_info_t *rdc_info;
  46 static int rdc_maxsets;
  47 static int rdc_enabled_sets;
  48 
  49 static unsigned prev_time, delta_time;
  50 #ifdef m88k
  51 extern unsigned *usec_ptr;
  52 #endif
  53 static int bright = 0;
  54 
  55 extern int sdbc_max_devices;
  56 
  57 extern _sd_stats_t *cs_cur;
  58 extern _sd_stats_t *cs_prev;
  59 extern _sd_stats_t *cs_persec;
  60 
  61 extern int *on_off;
  62 extern int *dual_on_off;
  63 extern int *updates_prev;
  64 extern double *rate_prev;
  65 extern int *samples;
  66 
  67 int             range_num = 0;
  68 int             screen = 0;
  69 int             dual_screen = 0;
  70 static          int rnum = 0;
  71 
  72 typedef struct {
  73         int lb, ub;
  74 } range_t;
  75 range_t ranges[100];
  76 
  77 extern int range_first();
  78 extern int range_next(int);
  79 extern int range_last();
  80 
  81 static int dual_initted = 0;
  82 static char status[11][30];
  83 
  84 unsigned dc_delta_time, dc_prev_time;
  85 
  86 #ifdef m88k
  87 #define USEC_INIT()     usec_ptr = (unsigned int *)timer_init()
  88 #define USEC_READ()     (*usec_ptr)
  89 #else /* !m88k */
  90 #define USEC_INIT()     USEC_START()
  91 #include <sys/time.h>
  92 static struct timeval Usec_time;
  93 static int Usec_started = 0;
  94 
  95 void total_display(void);
  96 void disp_stats(void);
  97 void do_calc(void);
  98 void init_dual(void);
  99 void calc_time(void);
 100 void calc_completion(int, int, int);
 101 void disp_total_stats(void);
 102 void display_cache(void);
 103 
 104 #define DISPLEN 16
 105 
 106 static void
 107 USEC_START(void)
 108 {
 109         if (!Usec_started) {
 110                 (void) gettimeofday(&Usec_time, NULL);
 111                 Usec_started = 1;
 112         }
 113 }
 114 
 115 static unsigned int
 116 USEC_READ()
 117 {
 118         struct timeval tv;
 119         if (!Usec_started)
 120                 USEC_START();
 121 
 122         (void) gettimeofday(&tv, NULL);
 123         return (unsigned)((tv.tv_sec - Usec_time.tv_sec) * 1000000 +
 124             (tv.tv_usec - Usec_time.tv_usec));
 125 }
 126 #endif /* m88k */
 127 
 128 #define SAMPLE_RATE 5
 129 
 130 /*
 131  * refresh curses window to file
 132  */
 133 void
 134 wrefresh_file(WINDOW *win, int fd)
 135 {
 136         char buf[8192], c, *cp = buf, *line, *blank, *empty;
 137         int x, y;
 138 
 139         empty = NULL;           /* cull trailing empty lines */
 140         for (y = 0; y < win->_maxy; y++) {
 141                 line = cp;
 142                 blank = NULL;   /* cull trailing blanks */
 143                 for (x = 0; x < win->_maxx; x++) {
 144                         c = (win->_y[y][x]) & A_CHARTEXT;
 145                         if (c != ' ')
 146                                 blank = NULL;
 147                         else if (blank == NULL)
 148                                 blank = cp;
 149                         *cp++ = c;
 150                 }
 151                 if (blank)
 152                         cp = blank;
 153                 if (line != cp)
 154                         empty = NULL;
 155                 else if (empty == NULL)
 156                         empty = cp + 1;
 157                 *cp++ = '\n';
 158         }
 159         if (empty)
 160                 cp = empty;
 161         *cp++ = '\f'; *cp++ = '\n'; *cp = '\0';
 162         /* cp is eliminated by short _maxy and _maxx, it won't overflow */
 163         /* LINTED, cp - buf won't be > INT32_MAX */
 164         (void) write(fd, buf, cp - buf);
 165 }
 166 
 167 
 168 int
 169 higher(int high)
 170 {
 171         int i;
 172 
 173         for (i = high + 1; i <= sdbc_max_devices; i++) {
 174                 if (cs_cur->st_shared[i].sh_alloc)
 175                         return (i);
 176         }
 177         return (0);
 178 }
 179 
 180 int
 181 is_dirty()
 182 {
 183         int i, dirty = 0;
 184         spcs_s_info_t ustats;
 185 
 186         if (SDBC_IOCTL(SDBC_STATS, cs_cur, 0, 0, 0, 0,
 187             &ustats) == SPCS_S_ERROR) {
 188                 perror("Could not get stats from kernel");
 189                 if (ustats) {
 190                         spcs_s_report(ustats, stderr);
 191                         spcs_s_ufree(&ustats);
 192                 }
 193                 return (-errno);
 194         }
 195         if (cs_cur->st_cachesize == 0)
 196                 return (0);
 197 
 198         for (i = 0; i < cs_cur->st_count; i++)  {
 199                 if (cs_cur->st_shared[i].sh_alloc)
 200                         dirty += cs_cur->st_shared[i].sh_numdirty;
 201         }
 202 
 203         return (dirty != 0);
 204 }
 205 
 206 void
 207 display_cache(void)
 208 {
 209         static int first = 1;
 210         spcs_s_info_t ustats;
 211 
 212         if (SDBC_IOCTL(SDBC_STATS, cs_cur, 0, 0, 0, 0, &ustats) ==
 213             SPCS_S_ERROR) {
 214                 perror("sd_stats");
 215                 if (ustats) {
 216                         spcs_s_report(ustats, stderr);
 217                         spcs_s_ufree(&ustats);
 218                 }
 219         }
 220 
 221         do_calc();
 222         if (first) {
 223                 prev_time = USEC_READ();
 224                 first = 0;
 225         } else
 226                 disp_stats();
 227 }
 228 
 229 void
 230 total_display(void)
 231 {
 232         spcs_s_info_t ustats;
 233 
 234         if (SDBC_IOCTL(SDBC_STATS, cs_cur, 0, 0, 0, 0, &ustats) ==
 235             SPCS_S_ERROR) {
 236                 if (ustats) {
 237                         spcs_s_report(ustats, stderr);
 238                         spcs_s_ufree(&ustats);
 239                 }
 240                 perror("sd_stats");
 241         }
 242         disp_total_stats();
 243 }
 244 
 245 
 246 int
 247 range_first()
 248 {
 249         rnum = 0;
 250         return (ranges[rnum].lb);
 251 }
 252 
 253 int
 254 range_next(int cd)
 255 {
 256         if (ranges[rnum].ub > cd)
 257                 return (cd + 1);
 258         if (range_num > rnum)
 259                 rnum++;
 260         else
 261                 return (cd + 1);
 262         return (ranges[rnum].lb);
 263 }
 264 
 265 int
 266 range_last() {
 267         return (ranges[range_num].ub);
 268 }
 269 
 270 
 271 void
 272 set_dual_on_off()
 273 {
 274         int i, j, ct = 0, newct = 0;
 275 
 276         for (i = range_first(); i < rdc_enabled_sets && i <= range_last();
 277             i = range_next(i)) {
 278                 if (rdc_info[i].flags & RDC_ENABLED) {
 279                         ct++;
 280                         if (ct > dual_screen * ((LINES - 9) / 2))
 281                                 break;
 282                 }
 283         }
 284         if (((i >= rdc_enabled_sets) ||
 285             (i > range_last())) && (dual_screen > 0)) {
 286                 dual_screen--;
 287                 set_dual_on_off();
 288         } else {
 289                 bzero(dual_on_off, sdbc_max_devices * sizeof (int));
 290                 for (j = i; j < rdc_enabled_sets && j <= range_last();
 291                     j = range_next(j)) {
 292                         if (rdc_info[j].flags & RDC_ENABLED) {
 293                                 newct++;
 294                                 if (newct <= (LINES - 9) / 2) {
 295                                         dual_on_off[j] = 1;
 296                                 } else
 297                                         break;
 298                         }
 299                 }
 300         }
 301 }
 302 
 303 
 304 void
 305 set_on_off()
 306 {
 307         int i, j, ct = 0, newct = 0;
 308 
 309         for (i = range_first(); i <= range_last(); i = range_next(i)) {
 310                 if (cs_cur->st_shared[i].sh_alloc) {
 311                         ct++;
 312                         if (ct > screen*((LINES - 9) / 2))
 313                                 break;
 314                 }
 315         }
 316         if ((i > range_last()) && (screen > 0)) {
 317                 screen--;
 318                 set_on_off();
 319         } else {
 320                 bzero(on_off, sdbc_max_devices * sizeof (int));
 321                 for (j = i; j <= range_last(); j = range_next(j)) {
 322                         if (cs_cur->st_shared[j].sh_alloc) {
 323                                 newct++;
 324                                 if (newct <= (LINES - 9) / 2)
 325                                         on_off[j] = 1;
 326                                 else
 327                                         break;
 328                         }
 329                 }
 330         }
 331 }
 332 
 333 void
 334 disp_stats(void)
 335 {
 336         double  read_s, write_s, access_s, readp, writep;
 337         double  rmiss_s, wmiss_s;
 338         double  elapsed = delta_time / 1000000.0;
 339         double  kbps = elapsed * 1024.0; /* for Kbytes per second */
 340         int     rtotal, wtotal, i, j;
 341         double  throughput = 0.0, rthroughput = 0.0;
 342         double  creads = 0.0, cwrites = 0.0;
 343         char    status_bit, down = 0;
 344         int     len;
 345         char    fn[19];
 346 
 347         if (delta_time != 0) {
 348                 read_s  = cs_persec->st_rdhits / elapsed;
 349                 write_s = cs_persec->st_wrhits / elapsed;
 350                 rmiss_s = cs_persec->st_rdmiss / elapsed;
 351                 wmiss_s = cs_persec->st_wrmiss / elapsed;
 352                 access_s = (cs_persec->st_wrhits + cs_persec->st_rdhits +
 353                     cs_persec->st_rdmiss + cs_persec->st_wrmiss) / elapsed;
 354         } else
 355                 read_s = write_s = access_s = 0.0;
 356 
 357         rtotal = cs_persec->st_rdhits + cs_persec->st_rdmiss;
 358         wtotal = cs_persec->st_wrhits + cs_persec->st_wrmiss;
 359         if (rtotal != 0)
 360                 readp = cs_persec->st_rdhits / (double)rtotal;
 361         else
 362                 readp = 0.0;
 363 
 364         if (wtotal != 0) {
 365                 writep = cs_persec->st_wrhits / (double)wtotal;
 366         } else
 367                 writep = 0.0;
 368 
 369         set_on_off();
 370         if (cs_cur->st_cachesize == 0)
 371                 (void) mvprintw(0, 20, "****** Storage Cache Disabled ******");
 372         else
 373                 (void) mvprintw(0, 20, "******      Storage Cache     ******");
 374         (void) mvprintw(2, 26, "disk_io       cache          write_blocks");
 375         (void) attron(A_UNDERLINE);
 376         (void) mvprintw(3, 1, " cd cached_partition  reads writes  reads writes"
 377             "  dirty todisk failed");
 378         (void) attroff(A_UNDERLINE);
 379         for (i = 0, j = 0; j < cs_cur->st_count; i++) {
 380                 if (i >= sdbc_max_devices)
 381                         break;
 382                 if (cs_cur->st_shared[i].sh_alloc)  {
 383                         cs_persec->st_shared[i].sh_disk_write /= kbps;
 384                         cs_persec->st_shared[i].sh_disk_read  /= kbps;
 385                         cs_persec->st_shared[i].sh_cache_write /= kbps;
 386                         cs_persec->st_shared[i].sh_cache_read /= kbps;
 387                         rthroughput += cs_persec->st_shared[i].sh_disk_read;
 388                         throughput += cs_persec->st_shared[i].sh_disk_write;
 389                         creads += cs_persec->st_shared[i].sh_cache_read;
 390                         cwrites += cs_persec->st_shared[i].sh_cache_write;
 391                         if (!down)
 392                                 down = cs_cur->st_shared[i].sh_failed;
 393                         if (cs_cur->st_shared[i].sh_failed && bright) {
 394                                 status_bit = '*';
 395                         } else
 396                                 status_bit = ' ';
 397                         if ((len = strlen(cs_cur->st_shared[i].sh_filename))
 398                             > 15) {
 399                                 (void) strcpy(fn, "...");
 400                                 (void) strcat(fn,
 401                                     cs_cur->st_shared[i].sh_filename +
 402                                     len - 12);
 403                         } else
 404                                 (void) strcpy(fn,
 405                                     cs_cur->st_shared[i].sh_filename);
 406                         if (on_off[i]) {
 407                                 (void) mvprintw(4 + j, 1,
 408                                     "%3d %-15s%c %6d %6d %6d %6d %6d %6d %6d",
 409                                     cs_cur->st_shared[i].sh_cd,
 410                                     fn,
 411                                     status_bit,
 412                                     cs_persec->st_shared[i].sh_disk_read,
 413                                     cs_persec->st_shared[i].sh_disk_write,
 414                                     cs_persec->st_shared[i].sh_cache_read,
 415                                     cs_persec->st_shared[i].sh_cache_write,
 416                                     cs_cur->st_shared[i].sh_numdirty,
 417                                     cs_cur->st_shared[i].sh_numio,
 418                                     cs_cur->st_shared[i].sh_numfail);
 419                                 j++;
 420                         }
 421                 }
 422         }
 423         bright = !bright;
 424 
 425         (void) mvprintw(4 + j, 22, "------ ------ ------ ------");
 426         (void) mvprintw(5 + j, 6, " Kbytes/s total:%6d %6d %6d %6d",
 427             (int)rthroughput, (int)throughput,
 428             (int)creads, (int)cwrites);
 429         (void) mvprintw(7 + j, 1, "accesses/s");
 430         (void) mvprintw(7 + j, 15, "read/s    write/s   %%readh   %%writeh");
 431 
 432         (void) attron(A_UNDERLINE);
 433         (void) mvprintw(8 + j, 1, "            ");
 434         (void) mvprintw(8 + j, 13,
 435             "                                                ");
 436         (void) mvprintw(8 + j, 13, "(misses/s) (misses/s)");
 437         (void) attroff(A_UNDERLINE);
 438 
 439         (void) mvprintw(9 + j, 0, "%10.2lf    %7.2f    %7.2f   %6.1f    %6.1f",
 440             access_s, read_s, write_s, readp * 100.0, writep * 100.0);
 441         (void) mvprintw(10 + j, 0, "             (%7.2f ) (%7.2f )\n\n",
 442             rmiss_s, wmiss_s);
 443 
 444         if (down)
 445                 (void) mvprintw(20 + j, 1, "* -- disk off-line");
 446 }
 447 
 448 void
 449 do_calc(void)
 450 {
 451         int i, j;
 452 
 453         delta_time = USEC_READ() - prev_time;
 454 
 455         cs_persec->st_rdhits = cs_cur->st_rdhits - cs_prev->st_rdhits;
 456         cs_persec->st_rdmiss = cs_cur->st_rdmiss - cs_prev->st_rdmiss;
 457         cs_persec->st_wrhits = cs_cur->st_wrhits - cs_prev->st_wrhits;
 458         cs_persec->st_wrmiss = cs_cur->st_wrmiss - cs_prev->st_wrmiss;
 459 
 460         for (i = 0, j = 0; j < cs_cur->st_count; i++) {
 461                 if (i >= sdbc_max_devices)
 462                         break;
 463                 if (cs_cur->st_shared[i].sh_alloc) {
 464                         cs_persec->st_shared[i].sh_disk_write =
 465                             FBA_SIZE(cs_cur->st_shared[i].sh_disk_write -
 466                             cs_prev->st_shared[i].sh_disk_write);
 467                         cs_persec->st_shared[i].sh_disk_read =
 468                             FBA_SIZE(cs_cur->st_shared[i].sh_disk_read -
 469                             cs_prev->st_shared[i].sh_disk_read);
 470                         cs_persec->st_shared[i].sh_cache_read =
 471                             FBA_SIZE(cs_cur->st_shared[i].sh_cache_read -
 472                             cs_prev->st_shared[i].sh_cache_read);
 473                         cs_persec->st_shared[i].sh_cache_write =
 474                             FBA_SIZE(cs_cur->st_shared[i].sh_cache_write -
 475                             cs_prev->st_shared[i].sh_cache_write);
 476                         j++;
 477                 }
 478         }
 479         (void) memcpy((char *) cs_prev, (char *) cs_cur, sizeof (_sd_stats_t) +
 480             (sdbc_max_devices - 1) * sizeof (_sd_shared_t));
 481         prev_time = USEC_READ();
 482 }
 483 
 484 
 485 void
 486 init_dual(void)
 487 {
 488 #define IND_ENABLED             0
 489 #define IND_RESYNC              1
 490 #define IND_RESYNC_REVERSE      2
 491 #define IND_VOLUME_DOWN         3
 492 #define IND_MIRROR_DOWN         4
 493 #define IND_LOGGING             5
 494 #define IND_RESYNC_NEEDED       6
 495 #define IND_REV_RESYNC_NEEDED   7
 496 #define IND_BITMAP_FAILED       8
 497 #define IND_FULL_SYNC_NEEDED    9
 498 #define IND_FCAL_FAILED         10
 499         (void) strcpy(status[IND_ENABLED], "replicating");
 500         (void) strcpy(status[IND_RESYNC], "sync");
 501         (void) strcpy(status[IND_RESYNC_REVERSE], "rev sync");
 502         (void) strcpy(status[IND_VOLUME_DOWN], "volume down");
 503         (void) strcpy(status[IND_MIRROR_DOWN], "mirror down");
 504         (void) strcpy(status[IND_LOGGING], "logging");
 505         (void) strcpy(status[IND_RESYNC_NEEDED], "need sync");
 506         (void) strcpy(status[IND_REV_RESYNC_NEEDED], "need rev sync");
 507         (void) strcpy(status[IND_BITMAP_FAILED], "bitmap failed");
 508         (void) strcpy(status[IND_FULL_SYNC_NEEDED], "full sync needed");
 509         (void) strcpy(status[IND_FCAL_FAILED], "fcal failed");
 510         dual_initted = 1;
 511 }
 512 
 513 
 514 int
 515 rdc_get_maxsets(void)
 516 {
 517         rdc_status_t rdc_status;
 518         spcs_s_info_t ustatus;
 519         int rc;
 520 
 521         rdc_status.nset = 0;
 522         ustatus = spcs_s_ucreate();
 523 
 524         rc = RDC_IOCTL(RDC_STATUS, &rdc_status, 0, 0, 0, 0, ustatus);
 525         spcs_s_ufree(&ustatus);
 526 
 527         if (rc == SPCS_S_ERROR)
 528                 return (-1);
 529 
 530         return (rdc_status.maxsets);
 531 }
 532 
 533 int
 534 dual_stats()
 535 {
 536         int ind, i, k, len;
 537         int stars, size, segs;
 538         int rdcindex;
 539         float pct;
 540         char    fn[19];
 541         char *phost;
 542         char *shost;
 543         char *pfile;
 544         char *sfile;
 545         char lhost[16];
 546         spcs_s_info_t ustats = NULL;
 547 
 548         (void) gethostname(lhost, 16);
 549 
 550         if (rdc_maxsets <= 0)
 551                 rdc_maxsets = rdc_get_maxsets();
 552 
 553         if (rdc_maxsets < 0)
 554                 goto no_stats;
 555 
 556         if (!rdc_status) {
 557                 rdc_status = malloc(sizeof (rdc_status_t) +
 558                         (sizeof (rdc_set_t) * (rdc_maxsets - 1)));
 559                 if (!rdc_status) {
 560 no_stats:
 561                         (void) mvprintw(0, 20,
 562                                 "****** Dual Copy Not Available ******");
 563                         return (-1);
 564                 }
 565 
 566                 rdc_info = rdc_status->rdc_set;
 567         }
 568 
 569         rdc_status->nset = rdc_maxsets;
 570         ustats = spcs_s_ucreate();
 571 
 572         size = RDC_IOCTL(RDC_STATUS, rdc_status, 0, 0, 0, 0, ustats);
 573         if (size == SPCS_S_ERROR) {
 574                 if (ustats) {
 575                         spcs_s_report(ustats, stderr);
 576                         spcs_s_ufree(&ustats);
 577                 }
 578                 (void) mvprintw(0, 20, "****** Dual Copy Not Available ******");
 579                 return (-1);
 580         }
 581         spcs_s_ufree(&ustats);
 582         rdc_enabled_sets = rdc_status->nset;
 583 
 584         if (!dual_initted)
 585                 init_dual();
 586 
 587         set_dual_on_off();
 588 
 589         calc_time();
 590 
 591         (void) mvprintw(0, 20, "****** Dual Copy Statistics ******");
 592         (void) attron(A_UNDERLINE);
 593         (void) mvprintw(2,  0, "primary");
 594         (void) mvprintw(2, 22, "link status");
 595         (void) mvprintw(2, 36, "secondary");
 596         (void) mvprintw(2, 54, "dual copy status");
 597         (void) attroff(A_UNDERLINE);
 598 
 599         for (rdcindex = 0, k = 0; rdcindex < rdc_enabled_sets; rdcindex++)  {
 600                 if (!(rdc_info[rdcindex].flags & RDC_ENABLED) ||
 601                     !dual_on_off[rdcindex])
 602                         continue;
 603 
 604                 if (rdc_info[rdcindex].sync_flags & RDC_VOL_FAILED)
 605                         ind = IND_VOLUME_DOWN;
 606                 else if (rdc_info[rdcindex].flags & RDC_FCAL_FAILED)
 607                         ind = IND_FCAL_FAILED;
 608                 else if (rdc_info[rdcindex].bmap_flags & RDC_BMP_FAILED)
 609                         ind = IND_BITMAP_FAILED;
 610                 else if (rdc_info[rdcindex].flags & RDC_LOGGING) {
 611                         if (rdc_info[rdcindex].sync_flags &
 612                             RDC_SYNC_NEEDED)
 613                                 ind = IND_RESYNC_NEEDED;
 614                         else if (rdc_info[rdcindex].sync_flags &
 615                             RDC_RSYNC_NEEDED)
 616                                 ind = IND_REV_RESYNC_NEEDED;
 617                         else
 618                                 ind = IND_LOGGING;
 619                 } else if ((rdc_info[rdcindex].flags & RDC_SLAVE) &&
 620                     (rdc_info[rdcindex].flags & RDC_SYNCING)) {
 621                         if (rdc_info[rdcindex].flags & RDC_PRIMARY)
 622                                 ind = IND_RESYNC_REVERSE;
 623                         else
 624                                 ind = IND_RESYNC;
 625                 } else if (rdc_info[rdcindex].flags & RDC_SYNCING) {
 626                         if (rdc_info[rdcindex].flags & RDC_PRIMARY)
 627                                 ind = IND_RESYNC;
 628                         else
 629                                 ind = IND_RESYNC_REVERSE;
 630                 } else
 631                         ind = IND_ENABLED;
 632 
 633                 phost = rdc_info[rdcindex].primary.intf;
 634                 pfile = rdc_info[rdcindex].primary.file;
 635                 shost = rdc_info[rdcindex].secondary.intf;
 636                 sfile = rdc_info[rdcindex].secondary.file;
 637 
 638                 if ((len = strlen(phost)) > 8) {
 639                         (void) mvprintw(4 + k, 0, ".%+7s:",
 640                                 phost + len - 7);
 641                 } else
 642                         (void) mvprintw(4 + k, 0, "%+8s:", phost);
 643 
 644                 if ((len = strlen(pfile)) > DISPLEN) {
 645                         (void) mvprintw(4 + k, 9, "...%-13s",
 646                             pfile + len - DISPLEN + 3);
 647                 } else
 648                         (void) mvprintw(4 + k, 9, "%-16s", pfile);
 649 
 650                 (void) attron(A_BOLD);
 651                 (void) mvprintw(4 + k, 26, "*");
 652                 (void) mvprintw(4 + k, 28, "*");
 653 
 654                 (void) mvprintw(4 + k, 56, "%-8s", status[ind]);
 655                 (void) attroff(A_BOLD);
 656 
 657                 if (ind == IND_RESYNC_REVERSE) {
 658                         if (bright && !(rdc_info[rdcindex].flags & RDC_LOGGING))
 659                                 (void) mvprintw(4 + k, 27, "<");
 660                         if (rdc_info[rdcindex].flags & RDC_PRIMARY &&
 661                             !(rdc_info[rdcindex].flags & RDC_LOGGING))
 662                                 calc_completion(rdcindex,
 663                                 rdc_info[rdcindex].bits_set, 4 + k);
 664                 } else if (ind == IND_RESYNC) {
 665                         if (bright && !(rdc_info[rdcindex].flags & RDC_LOGGING))
 666                                 (void) mvprintw(4 + k, 27, ">");
 667                         if (rdc_info[rdcindex].flags & RDC_PRIMARY &&
 668                             !(rdc_info[rdcindex].flags & RDC_LOGGING))
 669                                 calc_completion(rdcindex,
 670                                 rdc_info[rdcindex].bits_set, 4 + k);
 671                 } else if (ind == IND_LOGGING)
 672                         (void) mvprintw(4 + k, 27, ".");
 673                 else if (ind == IND_ENABLED)
 674                         (void) mvprintw(4 + k, 27, "=");
 675 
 676                 if ((len = strlen(shost)) > 8) {
 677                         (void) mvprintw(4 + k, 30, ".%+7s:",
 678                                 shost + len - 7);
 679                 } else
 680                         (void) mvprintw(4 + k, 30, "%+8s:", shost);
 681 
 682                 if ((len = strlen(sfile)) > DISPLEN) {
 683                         (void) mvprintw(4 + k, 39, "...%-13s",
 684                         sfile + len - DISPLEN + 3);
 685                 } else
 686                         (void) mvprintw(4 + k, 39, "%-16s", sfile);
 687 
 688                 k++;
 689         }
 690 
 691         k += 5;
 692         (void) attron(A_UNDERLINE);
 693         for (i = 0; i < 80; i++)
 694                 (void) mvprintw(k, i, " ");
 695         k += 2;
 696         (void) mvprintw(k,  0, "partition");
 697         (void) mvprintw(k, 16, "recovery needed");
 698         (void) mvprintw(k, 48, "recovery completed");
 699         (void) attroff(A_UNDERLINE);
 700         k += 2;
 701 
 702         for (rdcindex = 0; rdcindex < rdc_enabled_sets; rdcindex++)  {
 703                 if (!(rdc_info[rdcindex].flags & RDC_ENABLED) ||
 704                     !dual_on_off[rdcindex])
 705                         continue;
 706 
 707                 if (!(rdc_info[rdcindex].flags & RDC_PRIMARY)) {
 708                         continue;
 709                 }
 710                 if (!(rdc_info[rdcindex].flags & RDC_SLAVE) &&
 711                     !(rdc_info[rdcindex].flags & RDC_SYNCING) &&
 712                     !(rdc_info[rdcindex].flags & RDC_LOGGING)) {
 713                         continue;
 714                 }
 715 
 716                 len = strlen(rdc_info[rdcindex].secondary.file);
 717                 if (len > 15) {
 718                         (void) strcpy(fn, "...");
 719                         (void) strcat(fn,
 720                             rdc_info[rdcindex].secondary.file + len - 12);
 721                 } else
 722                         (void) strcpy(fn, rdc_info[rdcindex].secondary.file);
 723                 (void) mvprintw(k, 0, "%-15s", fn);
 724 
 725                 segs = FBA_TO_LOG_LEN(rdc_info[rdcindex].volume_size);
 726                 pct  = segs ?
 727                     ((float)rdc_info[rdcindex].bits_set / (float)segs) : 0.0;
 728                 stars = (int)(pct * 20.0);
 729                 while (stars > 0) {
 730                         (void) mvprintw(k, 16 + stars, "*");
 731                         stars--;
 732                 }
 733                 (void) attron(A_BOLD);
 734                 (void) mvprintw(k, 16, "[");
 735                 (void) mvprintw(k, 37, "]");
 736                 (void) attroff(A_BOLD);
 737                 (void) mvprintw(k, 39, "%6.2f%%", pct * 100.0);
 738 
 739                 if (rdc_info[rdcindex].flags & RDC_SYNCING)
 740                         pct = ((float)rdc_info[rdcindex].sync_pos /
 741                             (float)rdc_info[rdcindex].volume_size);
 742                 else
 743                         pct = 0.0;
 744                 stars = (int)(pct * 20.0);
 745                 while (stars > 0) {
 746                         (void) mvprintw(k, 48 + stars, "*");
 747                         stars--;
 748                 }
 749                 (void) attron(A_BOLD);
 750                 (void) mvprintw(k, 48, "[");
 751                 (void) mvprintw(k, 69, "]");
 752                 (void) attroff(A_BOLD);
 753                 (void) mvprintw(k, 70, "%6.2f%%", pct * 100.0);
 754                 k++;
 755         }
 756         bright = !bright;
 757         return (0);
 758 }
 759 
 760 /*
 761  * Calculate a time interval in milliseconds using the
 762  * micosecond counter
 763  */
 764 void
 765 calc_time(void)
 766 {
 767         unsigned int cur;
 768 
 769         cur = USEC_READ();
 770         dc_delta_time = cur > dc_prev_time ? cur - dc_prev_time :
 771                 cur + 0xFFFFFFFF - dc_prev_time;
 772         dc_delta_time /= 1000;
 773         dc_prev_time = cur;
 774 }
 775 
 776 /*
 777  * Calculate estimated time of completion of resync
 778  */
 779 void
 780 calc_completion(int cd, int updates_left, int l)
 781 {
 782         int delta_done;
 783         double rate;
 784         long time_left;
 785         long hours;
 786         long minutes;
 787         static int initted = 0;
 788 
 789         if (!initted) {
 790                 updates_prev[cd] = updates_left;
 791                 initted = 1;
 792                 return;
 793         }
 794 
 795         /*
 796          * Caclulate updates since last check
 797          */
 798         delta_done = updates_prev[cd] - updates_left;
 799         updates_prev[cd] = updates_left;
 800 
 801         /*
 802          * If no updates, don't bother estimating completion time
 803          */
 804         if (delta_done <= 0) {
 805                 samples[cd] = 0;
 806                 return;
 807         }
 808 
 809         rate = delta_done * 1000.0 / dc_delta_time;
 810 
 811         /*
 812          * Calculate rate of updates as a weighted average
 813          * of previous and current rate
 814          */
 815         if (rate_prev[cd] && samples[cd] > SAMPLE_RATE)
 816                 rate = (rate_prev[cd] * 4.0 + rate) / 5.0;
 817         rate_prev[cd] = rate;
 818         samples[cd]++;
 819 
 820         /*
 821          * Get enough samples before making estimate
 822          */
 823         if (samples[cd]++ < SAMPLE_RATE)
 824                 return;
 825 
 826         time_left = (long)(updates_left/rate);   /* time left in seconds */
 827 
 828         if (time_left < 0)
 829                 return;
 830 
 831         hours = time_left / (60 * 60);
 832         time_left -= hours * (60 * 60);
 833         minutes = time_left / 60;
 834         time_left -= minutes * 60;
 835         (void) mvprintw(l, 67,
 836             "time %02d:%02d:%02d  \n", hours, minutes, time_left);
 837 }
 838 
 839 void
 840 disp_total_stats(void)
 841 {
 842         unsigned int    read_s, write_s, access_s;
 843         double readp, writep;
 844         unsigned int    rmiss_s, wmiss_s;
 845         double  kbps = 2.0;
 846         int     rtotal, wtotal, i, j;
 847         unsigned int throughput = 0, rthroughput = 0, creads = 0, cwrites = 0;
 848         char    status_bit, down = 0;
 849         int     len;
 850         char    fn[19];
 851 
 852         read_s  = cs_cur->st_rdhits;
 853         write_s = cs_cur->st_wrhits;
 854         rmiss_s = cs_cur->st_rdmiss;
 855         wmiss_s = cs_cur->st_wrmiss;
 856         access_s = (read_s + write_s + rmiss_s + wmiss_s);
 857 
 858         rtotal = cs_cur->st_rdhits + cs_cur->st_rdmiss;
 859         wtotal = cs_cur->st_wrhits + cs_cur->st_wrmiss;
 860         if (rtotal != 0)
 861                 readp = cs_cur->st_rdhits / (double)rtotal;
 862         else
 863                 readp = 0.0;
 864 
 865         if (wtotal != 0)
 866                 writep = cs_cur->st_wrhits / (double)wtotal;
 867         else
 868                 writep = 0.0;
 869 
 870         set_on_off();
 871         (void) mvprintw(0, 14,
 872             "******     Storage Cache (Cumulative)      ******");
 873         (void) mvprintw(2, 30, "disk_io                  cache");
 874         (void) attron(A_UNDERLINE);
 875         (void) mvprintw(3,  1,
 876             " cd cached_partition      reads     writes      reads     writes");
 877         (void) attroff(A_UNDERLINE);
 878         for (i = 0, j = 0; j < cs_cur->st_count; i++) {
 879                 if (i >= sdbc_max_devices)
 880                         break;
 881                 if (cs_cur->st_shared[i].sh_alloc)  {
 882                         cs_cur->st_shared[i].sh_disk_write /= kbps;
 883                         cs_cur->st_shared[i].sh_disk_read /= kbps;
 884                         cs_cur->st_shared[i].sh_cache_write /= kbps;
 885                         cs_cur->st_shared[i].sh_cache_read /= kbps;
 886                         rthroughput += cs_cur->st_shared[i].sh_disk_read;
 887                         throughput += cs_cur->st_shared[i].sh_disk_write;
 888                         creads += cs_cur->st_shared[i].sh_cache_read;
 889                         cwrites += cs_cur->st_shared[i].sh_cache_write;
 890                         if (!down)
 891                                 down = cs_cur->st_shared[i].sh_failed;
 892                         if (cs_cur->st_shared[i].sh_failed && bright)
 893                                 status_bit = '*';
 894                         else
 895                                 status_bit = ' ';
 896                         if ((len =
 897                             strlen(cs_cur->st_shared[i].sh_filename)) > 15) {
 898                                 (void) strcpy(fn, "...");
 899                                 (void) strcat(fn,
 900                                     cs_cur->st_shared[i].sh_filename +
 901                                     len - 12);
 902                         } else
 903                                 (void) strcpy(fn,
 904                                     cs_cur->st_shared[i].sh_filename);
 905 
 906                         if (on_off[i]) {
 907                                 (void) mvprintw(4 + j, 1,
 908                                     "%3d %-15s%c %10u %10u %10u %10u",
 909                                     cs_cur->st_shared[i].sh_cd,
 910                                     fn,
 911                                     status_bit,
 912                                     cs_cur->st_shared[i].sh_disk_read,
 913                                     cs_cur->st_shared[i].sh_disk_write,
 914                                     cs_cur->st_shared[i].sh_cache_read,
 915                                     cs_cur->st_shared[i].sh_cache_write);
 916                                 j++;
 917                         }
 918                 }
 919         }
 920         bright = !bright;
 921 
 922         (void) mvprintw(4 + j, 22,
 923             "---------- ---------- ---------- ----------");
 924         (void) mvprintw(5 + j, 8, " Kbytes total:%10u %10u %10u %10u",
 925             (int)rthroughput, (int)throughput,
 926             (int)creads, (int)cwrites);
 927         (void) mvprintw(7 + j, 1, " accesses");
 928         (void) mvprintw(7 + j, 18, "read        write    %%readh  %%writeh");
 929 
 930         (void) attron(A_UNDERLINE);
 931         (void) mvprintw(8 + j, 1, "            ");
 932         (void) mvprintw(8 + j, 13,
 933             "                                                ");
 934         (void) mvprintw(8 + j, 11, "(    misses) (    misses)");
 935         (void) attroff(A_UNDERLINE);
 936 
 937         (void) mvprintw(9 + j, 0, "%10u  %10u   %10u    %6.1f   %6.1f",
 938             access_s, read_s, write_s, readp*100.0, writep*100.0);
 939         (void) mvprintw(10 + j, 0,
 940             "           (%10u) (%10u)\n\n", rmiss_s, wmiss_s);
 941 
 942         (void) attron(A_UNDERLINE);
 943         (void) mvprintw(13 + j, 1, "cachesize  blocksize");
 944         (void) attroff(A_UNDERLINE);
 945         (void) mvprintw(14 + j, 1, "%8dK %10d", cs_cur->st_cachesize / 1024,
 946             cs_cur->st_blksize);
 947 
 948         (void) attron(A_UNDERLINE);
 949         (void) mvprintw(16 + j, 1, "Write blocks available:");
 950         (void) attroff(A_UNDERLINE);
 951         (void) mvprintw(17 + j, 1, "Net 0: %6d", cs_cur->st_wlru_inq);
 952 
 953         (void) attron(A_UNDERLINE);
 954         (void) mvprintw(19 + j, 1, "LRU stats:  Blocks  Requeued    Optimized");
 955         (void) attroff(A_UNDERLINE);
 956         (void) mvprintw(20 + j, 7, "%12d %12u %12u", cs_cur->st_lru_blocks,
 957             cs_cur->st_lru_req, cs_cur->st_lru_noreq);
 958 
 959         if (down)
 960                 (void) mvprintw(25 + j, 1, "* -- disk off-line");
 961 }