xref: /titanic_52/usr/src/cmd/avs/dsstat/ii_stats.c (revision 8de5c4f463386063e184a851437d58080c6c626c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <errno.h>
31 
32 #include <sys/mutex.h>
33 
34 #include <kstat.h>
35 
36 #include <sys/unistat/spcs_s.h>
37 #include <sys/nsctl/dsw.h>
38 #include "../../../uts/common/avs/ns/dsw/dsw_dev.h"
39 #include <sys/nsctl/dsw_dev.h>
40 
41 #include "sdbc_stats.h"
42 #include "ii_stats.h"
43 
44 #include "dsstat.h"
45 #include "common.h"
46 #include "report.h"
47 
48 static iistat_t *ii_top = NULL;
49 
50 void ii_add_stat(iistat_t *);
51 iistat_t *ii_del_stat(iistat_t *);
52 
53 int ii_value_check(iistat_t *iistat);
54 int ii_validate(kstat_t *ksp);
55 int ii_vol_selected(kstat_t *);
56 
57 /*
58  * ii_discover() - looks for new statistics to be monitored.
59  * Verifies that any statistics found are now already being
60  * monitored.
61  *
62  */
63 int
64 ii_discover(kstat_ctl_t *kc)
65 {
66 	static int validated = 0;
67 
68 	kstat_t *ksp;
69 
70 	/* Loop on all kstats */
71 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
72 		char *kname;
73 		iistat_t *cur;
74 		iistat_t *iistat = NULL;
75 		kstat_t *mst_ksp;
76 		kstat_t *shd_ksp;
77 		kstat_t *bmp_ksp;
78 		kstat_t *ovr_ksp;
79 
80 		/* Search for II set */
81 		if (strcmp(ksp->ks_class, II_KSTAT_CLASS) != 0)
82 			continue;
83 
84 		if (kstat_read(kc, ksp, NULL) == -1)
85 			continue;
86 
87 		/*
88 		 * Validate kstat structure
89 		 */
90 		if (! validated) {
91 			if (ii_validate(ksp))
92 				return (EINVAL);
93 
94 			validated++;
95 		}
96 
97 		/*
98 		 * Duplicate check
99 		 */
100 		for (cur = ii_top; cur != NULL; cur = cur->next) {
101 			char *cur_vname, *tst_vname;
102 			uint32_t cur_inst, tst_inst;
103 
104 			cur_vname = cur->pre_set->ks_name;
105 			cur_inst = cur->pre_set->ks_instance;
106 
107 			tst_vname = ksp->ks_name;
108 			tst_inst = ksp->ks_instance;
109 
110 			if (strcmp(cur_vname, tst_vname) == 0 &&
111 			    cur_inst == tst_inst)
112 				goto next;
113 		}
114 
115 		/*
116 		 * Initialize new record
117 		 */
118 		iistat = (iistat_t *)calloc(1, sizeof (iistat_t));
119 
120 		/*
121 		 * Set kstat
122 		 */
123 		iistat->pre_set = kstat_retrieve(kc, ksp);
124 
125 		if (iistat->pre_set == NULL)
126 			goto next;
127 
128 		iistat->collected |= GOT_SETSTAT;
129 
130 		/*
131 		 * Master kstat
132 		 */
133 		kname = kstat_value(iistat->pre_set, DSW_SKSTAT_MSTIO);
134 
135 		mst_ksp = kstat_lookup(kc, II_KSTAT_MODULE, -1, kname);
136 		iistat->pre_mst = kstat_retrieve(kc, mst_ksp);
137 
138 		if (iistat->pre_mst == NULL)
139 			goto next;
140 
141 		iistat->collected |= GOT_MSTSTAT;
142 
143 		/*
144 		 * Shadow kstat
145 		 */
146 		kname = kstat_value(iistat->pre_set, DSW_SKSTAT_SHDIO);
147 
148 		shd_ksp = kstat_lookup(kc, II_KSTAT_MODULE, -1, kname);
149 		iistat->pre_shd = kstat_retrieve(kc, shd_ksp);
150 
151 		if (iistat->pre_shd == NULL)
152 			goto next;
153 
154 		iistat->collected |= GOT_SHDSTAT;
155 
156 		/*
157 		 * Bitmap kstat
158 		 */
159 		kname = kstat_value(iistat->pre_set, DSW_SKSTAT_BMPIO);
160 
161 		bmp_ksp = kstat_lookup(kc, II_KSTAT_MODULE, -1, kname);
162 		iistat->pre_bmp = kstat_retrieve(kc, bmp_ksp);
163 
164 		if (iistat->pre_bmp == NULL)
165 			goto next;
166 
167 		iistat->collected |= GOT_BMPSTAT;
168 
169 		/*
170 		 * Overflow kstat
171 		 */
172 		kname = kstat_value(iistat->pre_set, DSW_SKSTAT_OVRIO);
173 
174 		ovr_ksp = kstat_lookup(kc, II_KSTAT_MODULE, -1, kname);
175 		iistat->pre_ovr = kstat_retrieve(kc, ovr_ksp);
176 
177 		if (iistat->pre_ovr == NULL)
178 			goto next;
179 
180 		iistat->collected |= GOT_OVRSTAT;
181 
182 next:
183 		/*
184 		 * Check if we got a complete set of stats
185 		 */
186 		if (iistat == NULL)
187 			continue;
188 
189 		if (IIMG_COMPLETE(iistat->collected)) {
190 			(void) ii_del_stat(iistat);
191 			continue;
192 		}
193 
194 		/*
195 		 * Add to linked list
196 		 */
197 		ii_add_stat(iistat);
198 	}
199 
200 	if (ii_top == NULL)
201 		return (EAGAIN);
202 
203 	return (0);
204 }
205 
206 /*
207  * ii_update() - updates all of the statistics currently being monitored.
208  *
209  */
210 int
211 ii_update(kstat_ctl_t *kc)
212 {
213 	iistat_t *cur;
214 
215 	for (cur = ii_top; cur != NULL; cur = cur->next) {
216 		char volname[KSTAT_STRLEN + 1];
217 		char *kname;
218 
219 		kstat_t *ksp = NULL;
220 
221 		cur->collected = 0;
222 
223 		/*
224 		 * Age off old stats
225 		 */
226 		if (cur->cur_set != NULL) {
227 			kstat_free(cur->pre_set);
228 			kstat_free(cur->pre_mst);
229 			kstat_free(cur->pre_shd);
230 			kstat_free(cur->pre_bmp);
231 
232 			cur->pre_set = cur->cur_set;
233 			cur->pre_mst = cur->cur_mst;
234 			cur->pre_shd = cur->cur_shd;
235 			cur->pre_bmp = cur->cur_bmp;
236 
237 			if (cur->cur_ovr != NULL) {
238 				kstat_free(cur->pre_ovr);
239 				cur->pre_ovr = cur->cur_ovr;
240 			}
241 		}
242 
243 		/*
244 		 * Set kstat
245 		 */
246 		strncpy(volname, cur->pre_set->ks_name, KSTAT_STRLEN);
247 		volname[KSTAT_STRLEN] = '\0';
248 
249 		ksp = kstat_lookup(kc, II_KSTAT_MODULE, -1, volname);
250 
251 		if ((cur->cur_set = kstat_retrieve(kc, ksp)) == NULL)
252 			continue;
253 
254 		cur->collected |= GOT_SETSTAT;
255 
256 		/*
257 		 * Validate set
258 		 */
259 		if (strcmp(cur->pre_set->ks_name, cur->cur_set->ks_name) != 0 ||
260 		    cur->pre_set->ks_instance != cur->cur_set->ks_instance)
261 			continue;
262 
263 		/*
264 		 * Master kstat
265 		 */
266 		kname = kstat_value(cur->cur_set, DSW_SKSTAT_MSTIO);
267 
268 		ksp = kstat_lookup(kc, II_KSTAT_MODULE, -1, kname);
269 
270 		if ((cur->cur_mst = kstat_retrieve(kc, ksp)) == NULL)
271 			continue;
272 
273 		cur->collected |= GOT_MSTSTAT;
274 
275 		/*
276 		 * Shadow kstat
277 		 */
278 		kname = kstat_value(cur->cur_set, DSW_SKSTAT_SHDIO);
279 
280 		ksp = kstat_lookup(kc, II_KSTAT_MODULE, -1, kname);
281 
282 		if ((cur->cur_shd = kstat_retrieve(kc, ksp)) == NULL)
283 			continue;
284 
285 		cur->collected |= GOT_SHDSTAT;
286 
287 		/*
288 		 * Bitmap kstat
289 		 */
290 		kname = kstat_value(cur->pre_set, DSW_SKSTAT_BMPIO);
291 
292 		ksp = kstat_lookup(kc, II_KSTAT_MODULE, -1, kname);
293 
294 		if ((cur->cur_bmp = kstat_retrieve(kc, ksp)) == NULL)
295 			continue;
296 
297 		cur->collected |= GOT_BMPSTAT;
298 
299 		/*
300 		 * Overflow kstat
301 		 */
302 		kname = kstat_value(cur->cur_set, DSW_SKSTAT_OVRIO);
303 
304 		ksp = kstat_lookup(kc, II_KSTAT_MODULE, -1, kname);
305 
306 		if (ksp == NULL) {
307 			if (cur->pre_ovr != NULL) {
308 				kstat_free(cur->pre_ovr);
309 				cur->pre_ovr = NULL;
310 			}
311 			if (cur->cur_ovr != NULL) {
312 				kstat_free(cur->cur_ovr);
313 				cur->cur_ovr = NULL;
314 			}
315 			continue;
316 		}
317 
318 		if (cur->pre_ovr == NULL) {
319 			if ((cur->pre_ovr = kstat_retrieve(kc, ksp)) == NULL)
320 				continue;
321 		} else {
322 			if ((cur->cur_ovr = kstat_retrieve(kc, ksp)) == NULL)
323 				continue;
324 		}
325 
326 		cur->collected |= GOT_OVRSTAT;
327 	}
328 
329 	return (0);
330 }
331 
332 /*
333  * ii_report() - outputs statistics for the statistics currently being
334  * monitored.  Deletes statistics for volumes that have been disabled.
335  *
336  */
337 int
338 ii_report()
339 {
340 	uint32_t *flags;
341 	int padsz = 0;
342 	char pad[20] = {0};
343 	iistat_t *cur, *pre = NULL;
344 
345 	if (ii_top == NULL) {
346 		return (0);
347 	}
348 
349 	/* Create padding string for secondary report lines */
350 	if (dflags & FLAGS) {
351 		padsz += STAT_HDR_SIZE;
352 		padsz += STAT_HDR_SIZE;
353 	}
354 
355 	if (dflags & PCTS)
356 		padsz += PCT_HDR_SIZE;
357 
358 	if (padsz) {
359 		char fmt[20];
360 		sprintf(fmt, "%%%ds", padsz);
361 		sprintf(pad, fmt, "");
362 	}
363 
364 	for (cur = ii_top; cur; /* CSTYLED */) {
365 		int first = 1;
366 		char data[20] = {0};
367 
368 		/* Check to see if this is this a complete */
369 		if (IIMG_COMPLETE(cur->collected)) {
370 			char *c;
371 			char vol[(NAMED_LEN * 4) + 1] = {0};
372 			int offset;
373 			iistat_t *next;
374 
375 			/* notify user of set being disabled */
376 			c = kstat_value(cur->pre_set, DSW_SKSTAT_SETA);
377 			strncpy(vol, c, NAMED_LEN);
378 			c = kstat_value(cur->pre_set, DSW_SKSTAT_SETB);
379 			strncat(vol, c, NAMED_LEN);
380 			c = kstat_value(cur->pre_set, DSW_SKSTAT_SETC);
381 			strncat(vol, c, NAMED_LEN);
382 			c = kstat_value(cur->pre_set, DSW_SKSTAT_SETD);
383 			strncat(vol, c, NAMED_LEN);
384 
385 			offset = strlen(vol) - NAMED_LEN;
386 
387 			if (offset < 0)
388 				offset = 0;
389 
390 			printf(DATA_C16, vol + offset);
391 			printf(" %s\n", II_DISABLED);
392 
393 			/* free memory and remove stat from list */
394 			next = ii_del_stat(cur);
395 
396 			if (! pre)
397 				cur = ii_top = next;
398 			else
399 				cur = pre->next = next;
400 
401 			continue;
402 		}
403 
404 		/* Check to see if the user specified this volume */
405 		if (! ii_vol_selected(cur->pre_set))
406 			goto next;
407 
408 		/* Check to see if zflag applies */
409 		if (zflag && ii_value_check(cur) == 0)
410 			goto next;
411 
412 		/* Calculate flags */
413 		flags = kstat_value(cur->cur_set, DSW_SKSTAT_FLAGS);
414 
415 		if (dflags & FLAGS) {
416 
417 			char c[STAT_HDR_SIZE];
418 			char vtype[STAT_HDR_SIZE];
419 			char vstat[STAT_HDR_SIZE];
420 
421 			if (*flags & DSW_GOLDEN)
422 				strcpy(c, II_INDEPENDENT);
423 			else
424 				strcpy(c, II_DEPENDENT);
425 
426 			sprintf(vtype, DATA_C2, c);
427 			strcat(data, vtype);
428 
429 			if (*flags & DSW_COPYINGP)
430 				strcpy(c, II_COPYING);
431 			else
432 				strcpy(c, NO_INFO);
433 
434 
435 			sprintf(vstat, DATA_C2, c);
436 			strcat(data, vstat);
437 		}
438 
439 		/* Calculate sync needed precentage */
440 		if (dflags & PCTS) {
441 			char snpct[10];
442 			uint32_t *chkbits;
443 			uint32_t *cpybits;
444 			uint32_t *shdbits;
445 			uint32_t *volsize;
446 			float pct;
447 
448 			cpybits =
449 			    kstat_value(cur->cur_set, DSW_SKSTAT_COPYBITS);
450 
451 			shdbits =
452 			    kstat_value(cur->cur_set, DSW_SKSTAT_SHDBITS);
453 
454 			volsize =
455 			    kstat_value(cur->cur_set, DSW_SKSTAT_SIZE);
456 
457 			*volsize /= DSW_SIZE;
458 
459 			chkbits = *cpybits >= *shdbits ? cpybits : shdbits;
460 
461 			pct = ((float)*chkbits / *volsize) * 100.0;
462 
463 			sprintf(snpct, DATA_F62, pct);
464 
465 			strcat(data, snpct);
466 		}
467 
468 		/* Master statistics */
469 		if (rflags & IIMG_MST) {
470 			char *c;
471 			char vol[(NAMED_LEN * 4) + 1] = {0};
472 			int offset;
473 
474 			c = kstat_value(cur->cur_set, DSW_SKSTAT_MSTA);
475 			strncat(vol, c, NAMED_LEN);
476 			c = kstat_value(cur->cur_set, DSW_SKSTAT_MSTB);
477 			strncat(vol, c, NAMED_LEN);
478 			c = kstat_value(cur->cur_set, DSW_SKSTAT_MSTC);
479 			strncat(vol, c, NAMED_LEN);
480 			c = kstat_value(cur->cur_set, DSW_SKSTAT_MSTD);
481 			strncat(vol, c, NAMED_LEN);
482 
483 			offset = strlen(vol) - NAMED_LEN;
484 
485 			if (offset < 0)
486 				offset = 0;
487 
488 			header();
489 			printf(DATA_C16, vol + offset);
490 			printf("%s", data);
491 			printf(ROLE_INF_FMT, II_MASTER);
492 
493 			if (*flags & DSW_MSTOFFLINE) {
494 				printf(" <<offline>>");
495 				linesout++;
496 			} else {
497 				io_report(cur->cur_mst, cur->pre_mst,
498 				    sdbc_getstat(vol + offset));
499 			}
500 
501 			printf("\n");
502 
503 			if (first) {
504 				strcpy(data, strlen(pad) > 0 ? pad : "");
505 				first = 0;
506 			}
507 		}
508 
509 		/* Shadow statistics */
510 		if (rflags & IIMG_SHD) {
511 			char *c;
512 			char vol[(NAMED_LEN * 4) + 1] = {0};
513 			int offset;
514 
515 			c = kstat_value(cur->cur_set, DSW_SKSTAT_SETA);
516 			strncat(vol, c, NAMED_LEN);
517 			c = kstat_value(cur->cur_set, DSW_SKSTAT_SETB);
518 			strncat(vol, c, NAMED_LEN);
519 			c = kstat_value(cur->cur_set, DSW_SKSTAT_SETC);
520 			strncat(vol, c, NAMED_LEN);
521 			c = kstat_value(cur->cur_set, DSW_SKSTAT_SETD);
522 			strncat(vol, c, NAMED_LEN);
523 
524 			offset = strlen(vol) - NAMED_LEN;
525 
526 			if (offset < 0)
527 				offset = 0;
528 
529 			header();
530 			printf(DATA_C16, vol + offset);
531 			printf("%s", data);
532 			printf(ROLE_INF_FMT, II_SHADOW);
533 
534 			if (*flags & DSW_SHDOFFLINE) {
535 				printf(" <<offline>>");
536 				linesout++;
537 			} else {
538 				io_report(cur->cur_shd, cur->pre_shd,
539 				    sdbc_getstat(vol + offset));
540 			}
541 
542 			printf("\n");
543 
544 			if (first) {
545 				strcpy(data, strlen(pad) > 0 ? pad : "");
546 				first = 0;
547 			}
548 		}
549 
550 		/* Bitmap statistics */
551 		if (rflags & IIMG_BMP) {
552 			char *c;
553 			char vol[(NAMED_LEN * 4) + 1] = {0};
554 			int offset;
555 
556 			c = kstat_value(cur->cur_set, DSW_SKSTAT_BMPA);
557 			strncat(vol, c, NAMED_LEN);
558 			c = kstat_value(cur->cur_set, DSW_SKSTAT_BMPB);
559 			strncat(vol, c, NAMED_LEN);
560 			c = kstat_value(cur->cur_set, DSW_SKSTAT_BMPC);
561 			strncat(vol, c, NAMED_LEN);
562 			c = kstat_value(cur->cur_set, DSW_SKSTAT_BMPD);
563 			strncat(vol, c, NAMED_LEN);
564 
565 			offset = strlen(vol) - NAMED_LEN;
566 
567 			if (offset < 0)
568 				offset = 0;
569 
570 			header();
571 			printf(DATA_C16, vol + offset);
572 			printf("%s", data);
573 			printf(ROLE_INF_FMT, II_BITMAP);
574 
575 			if (*flags & DSW_BMPOFFLINE) {
576 				printf(" <<offline>>");
577 				linesout++;
578 			} else {
579 				io_report(cur->cur_bmp, cur->pre_bmp,
580 				    sdbc_getstat(vol + offset));
581 			}
582 			printf("\n");
583 
584 			if (first) {
585 				strcpy(data, strlen(pad) > 0 ? pad : "");
586 				first = 0;
587 			}
588 		}
589 
590 		/* Overflow statistics */
591 		if (rflags & IIMG_OVR) {
592 			char *c;
593 			char msg[20] = {0};
594 			char vol[(NAMED_LEN * 4) + 1] = {0};
595 			int offset;
596 
597 			if (cur->cur_ovr == NULL && cur->pre_ovr != NULL)
598 				strcpy(msg, " <<attached>>");
599 
600 			if (! (cur->collected & GOT_OVRSTAT))
601 				strcpy(msg, " <<not attached>>");
602 
603 			c = kstat_value(cur->cur_set, DSW_SKSTAT_OVRA);
604 			strncpy(vol, c, NAMED_LEN);
605 			c = kstat_value(cur->cur_set, DSW_SKSTAT_OVRB);
606 			strncat(vol, c, NAMED_LEN);
607 			c = kstat_value(cur->cur_set, DSW_SKSTAT_OVRC);
608 			strncat(vol, c, NAMED_LEN);
609 			c = kstat_value(cur->cur_set, DSW_SKSTAT_OVRD);
610 			strncat(vol, c, NAMED_LEN);
611 
612 			offset = strlen(vol) - NAMED_LEN;
613 
614 			if (offset < 0)
615 				offset = 0;
616 
617 			header();
618 			printf(DATA_C16, vol + offset);
619 			printf("%s", data);
620 			printf(ROLE_INF_FMT, II_OVERFLOW);
621 
622 			if (strlen(msg)) {
623 				printf("%s\n", msg);
624 				linesout++;
625 				goto next;
626 			}
627 
628 			if (*flags & DSW_OVROFFLINE) {
629 				printf(" <<offline>>");
630 				linesout++;
631 			} else {
632 				io_report(cur->cur_ovr, cur->pre_ovr,
633 				    sdbc_getstat(vol + offset));
634 			}
635 
636 			printf("\n");
637 
638 			if (first) {
639 				strcpy(data, strlen(pad) > 0 ? pad : "");
640 				first = 0;
641 			}
642 		}
643 
644 
645 next:
646 		pre = cur;
647 		cur = cur->next;
648 	}
649 
650 	return (0);
651 }
652 
653 /*
654  * ii_add_stat() - adds a fully populated iistat_t structure
655  * to the linked list of currently monitored kstats.  The structure
656  * will be added in alphabetical order, using the volume name of
657  * the shadow volume as the key.
658  *
659  */
660 void
661 ii_add_stat(iistat_t *iistat)
662 {
663 
664 	iistat_t *cur;
665 
666 	if (ii_top == NULL) {
667 		ii_top = iistat;
668 		return;
669 	}
670 
671 	for (cur = ii_top; cur != NULL; cur = cur->next) {
672 		if (strcmp(cur->pre_set->ks_name,
673 		    iistat->pre_set->ks_name) <= 0) {
674 			/*
675 			 * If we get to the last item in the list, then just
676 			 * add this one to the end
677 			 */
678 			if (cur->next == NULL) {
679 				cur->next = iistat;
680 				return;
681 			}
682 
683 			if (strcmp(cur->next->pre_set->ks_name,
684 			    iistat->pre_set->ks_name) > 0) {
685 				iistat->next = cur->next;
686 				cur->next = iistat;
687 				return;
688 			}
689 		} else {
690 			if (cur == ii_top)
691 				ii_top = iistat;
692 
693 			iistat->next = cur;
694 
695 			return;
696 		}
697 	}
698 }
699 
700 /*
701  * ii_del_stat() - deallocate memory for the structure being
702  * passed in.
703  *
704  * parameters
705  * 	iistat_t *iistat - structure to be deallocated
706  *
707  * returns
708  * 	iistat_t * - pointer to the "next" structures in the
709  * 	linked list. May be NULL if we are removing the last
710  * 	structure in the linked list.
711  *
712  */
713 iistat_t *
714 ii_del_stat(iistat_t *iistat)
715 {
716 
717 	iistat_t *next = iistat->next;
718 
719 	kstat_free(iistat->pre_set);
720 	kstat_free(iistat->pre_mst);
721 	kstat_free(iistat->pre_shd);
722 	kstat_free(iistat->pre_bmp);
723 	kstat_free(iistat->pre_ovr);
724 	kstat_free(iistat->cur_set);
725 	kstat_free(iistat->cur_mst);
726 	kstat_free(iistat->cur_shd);
727 	kstat_free(iistat->cur_bmp);
728 	kstat_free(iistat->cur_ovr);
729 
730 	free(iistat);
731 
732 	return (next);
733 }
734 
735 int
736 ii_value_check(iistat_t *iistat)
737 {
738 	if (IIMG_COMPLETE(iistat->collected))
739 		return (1);
740 
741 	if (io_value_check(iistat->pre_mst->ks_data,
742 	    iistat->cur_mst->ks_data)) {
743 		return (1);
744 	}
745 
746 	if (io_value_check(iistat->pre_shd->ks_data,
747 	    iistat->cur_shd->ks_data)) {
748 		return (1);
749 	}
750 
751 	if (io_value_check(iistat->pre_bmp->ks_data,
752 	    iistat->cur_bmp->ks_data)) {
753 		return (1);
754 	}
755 
756 	if (iistat->pre_ovr && iistat->cur_ovr) {
757 		if (io_value_check(iistat->pre_ovr->ks_data,
758 		    iistat->cur_ovr->ks_data)) {
759 			return (1);
760 		}
761 	}
762 
763 	return (0);
764 }
765 
766 int
767 ii_validate(kstat_t *ksp)
768 {
769 	if (! kstat_value(ksp, DSW_SKSTAT_MSTIO) ||
770 	    ! kstat_value(ksp, DSW_SKSTAT_SHDIO) ||
771 	    ! kstat_value(ksp, DSW_SKSTAT_BMPIO) ||
772 	    ! kstat_value(ksp, DSW_SKSTAT_OVRIO) ||
773 	    ! kstat_value(ksp, DSW_SKSTAT_FLAGS) ||
774 	    ! kstat_value(ksp, DSW_SKSTAT_MSTA) ||
775 	    ! kstat_value(ksp, DSW_SKSTAT_SETA) ||
776 	    ! kstat_value(ksp, DSW_SKSTAT_BMPA) ||
777 	    ! kstat_value(ksp, DSW_SKSTAT_OVRA) ||
778 	    ! kstat_value(ksp, DSW_SKSTAT_SHDBITS) ||
779 	    ! kstat_value(ksp, DSW_SKSTAT_COPYBITS) ||
780 	    ! kstat_value(ksp, DSW_SKSTAT_SIZE))
781 		return (1);
782 
783 	return (0);
784 }
785 
786 int
787 ii_vol_selected(kstat_t *ksp)
788 {
789 	vslist_t *vslist = vs_top;
790 
791 	for (vslist = vs_top; vslist != NULL; vslist = vslist->next) {
792 		char *vn;
793 		int off = 0;
794 
795 		vn = ksp->ks_name;
796 
797 		if ((off = strlen(vn) - NAMED_LEN) <= 0) {
798 			off = 0;
799 		}
800 
801 		if (strcmp(vslist->volname, &vn[off]) == 0) {
802 			break;
803 		}
804 	}
805 
806 	if (vs_top != NULL && vslist == NULL) {
807 		return (0);
808 	} else {
809 		return (1);
810 	}
811 }
812