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
USEC_START(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
USEC_READ()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
wrefresh_file(WINDOW * win,int fd)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
higher(int high)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
is_dirty()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
display_cache(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
total_display(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
range_first()247 range_first()
248 {
249 rnum = 0;
250 return (ranges[rnum].lb);
251 }
252
253 int
range_next(int cd)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
range_last()266 range_last() {
267 return (ranges[range_num].ub);
268 }
269
270
271 void
set_dual_on_off()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
set_on_off()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
disp_stats(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
do_calc(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
init_dual(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
rdc_get_maxsets(void)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
dual_stats()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
calc_time(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
calc_completion(int cd,int updates_left,int l)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
disp_total_stats(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 }
962