xref: /titanic_44/usr/src/cmd/avs/dsstat/sndr_stats.c (revision 160124a620427e5bf36392463283ed0a830a4f47)
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 }
853