1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include "statcommon.h"
30*7c478bd9Sstevel@tonic-gate #include "dsr.h"
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #include <sys/dklabel.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
34*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
35*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
36*7c478bd9Sstevel@tonic-gate #include <unistd.h>
37*7c478bd9Sstevel@tonic-gate #include <strings.h>
38*7c478bd9Sstevel@tonic-gate #include <errno.h>
39*7c478bd9Sstevel@tonic-gate #include <limits.h>
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate static void insert_iodev(struct snapshot *ss, struct iodev_snapshot *iodev);
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate static struct iodev_snapshot *
44*7c478bd9Sstevel@tonic-gate make_controller(int cid)
45*7c478bd9Sstevel@tonic-gate {
46*7c478bd9Sstevel@tonic-gate 	struct iodev_snapshot *new;
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate 	new = safe_alloc(sizeof (struct iodev_snapshot));
49*7c478bd9Sstevel@tonic-gate 	(void) memset(new, 0, sizeof (struct iodev_snapshot));
50*7c478bd9Sstevel@tonic-gate 	new->is_type = IODEV_CONTROLLER;
51*7c478bd9Sstevel@tonic-gate 	new->is_id.id = cid;
52*7c478bd9Sstevel@tonic-gate 	new->is_parent_id.id = IODEV_NO_ID;
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate 	(void) snprintf(new->is_name, sizeof (new->is_name), "c%d", cid);
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate 	return (new);
57*7c478bd9Sstevel@tonic-gate }
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate static struct iodev_snapshot *
60*7c478bd9Sstevel@tonic-gate find_iodev_by_name(struct iodev_snapshot *list, const char *name)
61*7c478bd9Sstevel@tonic-gate {
62*7c478bd9Sstevel@tonic-gate 	struct iodev_snapshot *pos;
63*7c478bd9Sstevel@tonic-gate 	struct iodev_snapshot *pos2;
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate 	for (pos = list; pos; pos = pos->is_next) {
66*7c478bd9Sstevel@tonic-gate 		if (strcmp(pos->is_name, name) == 0)
67*7c478bd9Sstevel@tonic-gate 			return (pos);
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate 		pos2 = find_iodev_by_name(pos->is_children, name);
70*7c478bd9Sstevel@tonic-gate 		if (pos2 != NULL)
71*7c478bd9Sstevel@tonic-gate 			return (pos2);
72*7c478bd9Sstevel@tonic-gate 	}
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate 	return (NULL);
75*7c478bd9Sstevel@tonic-gate }
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate static enum iodev_type
78*7c478bd9Sstevel@tonic-gate parent_iodev_type(enum iodev_type type)
79*7c478bd9Sstevel@tonic-gate {
80*7c478bd9Sstevel@tonic-gate 	switch (type) {
81*7c478bd9Sstevel@tonic-gate 		case IODEV_CONTROLLER: return (0);
82*7c478bd9Sstevel@tonic-gate 		case IODEV_NFS: return (0);
83*7c478bd9Sstevel@tonic-gate 		case IODEV_TAPE: return (0);
84*7c478bd9Sstevel@tonic-gate 		case IODEV_IOPATH: return (IODEV_DISK);
85*7c478bd9Sstevel@tonic-gate 		case IODEV_DISK: return (IODEV_CONTROLLER);
86*7c478bd9Sstevel@tonic-gate 		case IODEV_PARTITION: return (IODEV_DISK);
87*7c478bd9Sstevel@tonic-gate 	}
88*7c478bd9Sstevel@tonic-gate 	return (IODEV_UNKNOWN);
89*7c478bd9Sstevel@tonic-gate }
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate static int
92*7c478bd9Sstevel@tonic-gate id_match(struct iodev_id *id1, struct iodev_id *id2)
93*7c478bd9Sstevel@tonic-gate {
94*7c478bd9Sstevel@tonic-gate 	return (id1->id == id2->id &&
95*7c478bd9Sstevel@tonic-gate 		strcmp(id1->tid, id2->tid) == 0);
96*7c478bd9Sstevel@tonic-gate }
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate static struct iodev_snapshot *
99*7c478bd9Sstevel@tonic-gate find_parent(struct snapshot *ss, struct iodev_snapshot *iodev)
100*7c478bd9Sstevel@tonic-gate {
101*7c478bd9Sstevel@tonic-gate 	enum iodev_type parent_type = parent_iodev_type(iodev->is_type);
102*7c478bd9Sstevel@tonic-gate 	struct iodev_snapshot *pos;
103*7c478bd9Sstevel@tonic-gate 	struct iodev_snapshot *pos2;
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate 	if (parent_type == 0 || parent_type == IODEV_UNKNOWN)
106*7c478bd9Sstevel@tonic-gate 		return (NULL);
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 	if (iodev->is_parent_id.id == IODEV_NO_ID &&
109*7c478bd9Sstevel@tonic-gate 	    iodev->is_parent_id.tid[0] == '\0')
110*7c478bd9Sstevel@tonic-gate 		return (NULL);
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 	if (parent_type == IODEV_CONTROLLER) {
113*7c478bd9Sstevel@tonic-gate 		for (pos = ss->s_iodevs; pos; pos = pos->is_next) {
114*7c478bd9Sstevel@tonic-gate 			if (pos->is_type != IODEV_CONTROLLER)
115*7c478bd9Sstevel@tonic-gate 				continue;
116*7c478bd9Sstevel@tonic-gate 			if (pos->is_id.id != iodev->is_parent_id.id)
117*7c478bd9Sstevel@tonic-gate 				continue;
118*7c478bd9Sstevel@tonic-gate 			return (pos);
119*7c478bd9Sstevel@tonic-gate 		}
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate 		if (!(ss->s_types & SNAP_CONTROLLERS))
122*7c478bd9Sstevel@tonic-gate 			return (NULL);
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 		pos = make_controller(iodev->is_parent_id.id);
125*7c478bd9Sstevel@tonic-gate 		insert_iodev(ss, pos);
126*7c478bd9Sstevel@tonic-gate 		return (pos);
127*7c478bd9Sstevel@tonic-gate 	}
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate 	/* IODEV_DISK parent */
130*7c478bd9Sstevel@tonic-gate 	for (pos = ss->s_iodevs; pos; pos = pos->is_next) {
131*7c478bd9Sstevel@tonic-gate 		if (id_match(&iodev->is_parent_id, &pos->is_id) &&
132*7c478bd9Sstevel@tonic-gate 		    pos->is_type == IODEV_DISK)
133*7c478bd9Sstevel@tonic-gate 			return (pos);
134*7c478bd9Sstevel@tonic-gate 		if (pos->is_type != IODEV_CONTROLLER)
135*7c478bd9Sstevel@tonic-gate 			continue;
136*7c478bd9Sstevel@tonic-gate 		for (pos2 = pos->is_children; pos2; pos2 = pos2->is_next) {
137*7c478bd9Sstevel@tonic-gate 			if (pos2->is_type != IODEV_DISK)
138*7c478bd9Sstevel@tonic-gate 				continue;
139*7c478bd9Sstevel@tonic-gate 			if (id_match(&iodev->is_parent_id, &pos2->is_id))
140*7c478bd9Sstevel@tonic-gate 				return (pos2);
141*7c478bd9Sstevel@tonic-gate 		}
142*7c478bd9Sstevel@tonic-gate 	}
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	return (NULL);
145*7c478bd9Sstevel@tonic-gate }
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate static void
148*7c478bd9Sstevel@tonic-gate list_del(struct iodev_snapshot **list, struct iodev_snapshot *pos)
149*7c478bd9Sstevel@tonic-gate {
150*7c478bd9Sstevel@tonic-gate 	if (*list == pos)
151*7c478bd9Sstevel@tonic-gate 		*list = pos->is_next;
152*7c478bd9Sstevel@tonic-gate 	if (pos->is_next)
153*7c478bd9Sstevel@tonic-gate 		pos->is_next->is_prev = pos->is_prev;
154*7c478bd9Sstevel@tonic-gate 	if (pos->is_prev)
155*7c478bd9Sstevel@tonic-gate 		pos->is_prev->is_next = pos->is_next;
156*7c478bd9Sstevel@tonic-gate 	pos->is_prev = pos->is_next = NULL;
157*7c478bd9Sstevel@tonic-gate }
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate static void
160*7c478bd9Sstevel@tonic-gate insert_before(struct iodev_snapshot **list, struct iodev_snapshot *pos,
161*7c478bd9Sstevel@tonic-gate     struct iodev_snapshot *new)
162*7c478bd9Sstevel@tonic-gate {
163*7c478bd9Sstevel@tonic-gate 	if (pos == NULL) {
164*7c478bd9Sstevel@tonic-gate 		new->is_prev = new->is_next = NULL;
165*7c478bd9Sstevel@tonic-gate 		*list = new;
166*7c478bd9Sstevel@tonic-gate 		return;
167*7c478bd9Sstevel@tonic-gate 	}
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 	new->is_next = pos;
170*7c478bd9Sstevel@tonic-gate 	new->is_prev = pos->is_prev;
171*7c478bd9Sstevel@tonic-gate 	if (pos->is_prev)
172*7c478bd9Sstevel@tonic-gate 		pos->is_prev->is_next = new;
173*7c478bd9Sstevel@tonic-gate 	else
174*7c478bd9Sstevel@tonic-gate 		*list = new;
175*7c478bd9Sstevel@tonic-gate 	pos->is_prev = new;
176*7c478bd9Sstevel@tonic-gate }
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate static void
179*7c478bd9Sstevel@tonic-gate insert_after(struct iodev_snapshot **list, struct iodev_snapshot *pos,
180*7c478bd9Sstevel@tonic-gate     struct iodev_snapshot *new)
181*7c478bd9Sstevel@tonic-gate {
182*7c478bd9Sstevel@tonic-gate 	if (pos == NULL) {
183*7c478bd9Sstevel@tonic-gate 		new->is_prev = new->is_next = NULL;
184*7c478bd9Sstevel@tonic-gate 		*list = new;
185*7c478bd9Sstevel@tonic-gate 		return;
186*7c478bd9Sstevel@tonic-gate 	}
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 	new->is_next = pos->is_next;
189*7c478bd9Sstevel@tonic-gate 	new->is_prev = pos;
190*7c478bd9Sstevel@tonic-gate 	if (pos->is_next)
191*7c478bd9Sstevel@tonic-gate 		pos->is_next->is_prev = new;
192*7c478bd9Sstevel@tonic-gate 	pos->is_next = new;
193*7c478bd9Sstevel@tonic-gate }
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate static void
196*7c478bd9Sstevel@tonic-gate insert_into(struct iodev_snapshot **list, struct iodev_snapshot *iodev)
197*7c478bd9Sstevel@tonic-gate {
198*7c478bd9Sstevel@tonic-gate 	struct iodev_snapshot *tmp = *list;
199*7c478bd9Sstevel@tonic-gate 	if (*list == NULL) {
200*7c478bd9Sstevel@tonic-gate 		*list = iodev;
201*7c478bd9Sstevel@tonic-gate 		return;
202*7c478bd9Sstevel@tonic-gate 	}
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	for (;;) {
205*7c478bd9Sstevel@tonic-gate 		if (iodev_cmp(tmp, iodev) > 0) {
206*7c478bd9Sstevel@tonic-gate 			insert_before(list, tmp, iodev);
207*7c478bd9Sstevel@tonic-gate 			return;
208*7c478bd9Sstevel@tonic-gate 		}
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 		if (tmp->is_next == NULL)
211*7c478bd9Sstevel@tonic-gate 			break;
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 		tmp = tmp->is_next;
214*7c478bd9Sstevel@tonic-gate 	}
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 	insert_after(list, tmp, iodev);
217*7c478bd9Sstevel@tonic-gate }
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate static int
220*7c478bd9Sstevel@tonic-gate disk_or_partition(enum iodev_type type)
221*7c478bd9Sstevel@tonic-gate {
222*7c478bd9Sstevel@tonic-gate 	return (type == IODEV_DISK || type == IODEV_PARTITION);
223*7c478bd9Sstevel@tonic-gate }
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate static void
226*7c478bd9Sstevel@tonic-gate insert_iodev(struct snapshot *ss, struct iodev_snapshot *iodev)
227*7c478bd9Sstevel@tonic-gate {
228*7c478bd9Sstevel@tonic-gate 	struct iodev_snapshot *parent = find_parent(ss, iodev);
229*7c478bd9Sstevel@tonic-gate 	struct iodev_snapshot **list;
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	if (parent != NULL) {
232*7c478bd9Sstevel@tonic-gate 		list = &parent->is_children;
233*7c478bd9Sstevel@tonic-gate 		parent->is_nr_children++;
234*7c478bd9Sstevel@tonic-gate 	} else {
235*7c478bd9Sstevel@tonic-gate 		list = &ss->s_iodevs;
236*7c478bd9Sstevel@tonic-gate 		ss->s_nr_iodevs++;
237*7c478bd9Sstevel@tonic-gate 	}
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	insert_into(list, iodev);
240*7c478bd9Sstevel@tonic-gate }
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate static int
243*7c478bd9Sstevel@tonic-gate iodev_match(struct iodev_snapshot *dev, struct iodev_filter *df)
244*7c478bd9Sstevel@tonic-gate {
245*7c478bd9Sstevel@tonic-gate 	size_t i;
246*7c478bd9Sstevel@tonic-gate 	int is_floppy = (strncmp(dev->is_name, "fd", 2) == 0);
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 	/* no filter, pass */
249*7c478bd9Sstevel@tonic-gate 	if (df == NULL)
250*7c478bd9Sstevel@tonic-gate 		return (1);
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	/* no filtered names, pass if not floppy and skipped */
253*7c478bd9Sstevel@tonic-gate 	if (df->if_nr_names == NULL)
254*7c478bd9Sstevel@tonic-gate 		return (!(df->if_skip_floppy && is_floppy));
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < df->if_nr_names; i++) {
257*7c478bd9Sstevel@tonic-gate 		if (strcmp(dev->is_name, df->if_names[i]) == 0)
258*7c478bd9Sstevel@tonic-gate 			return (1);
259*7c478bd9Sstevel@tonic-gate 		if (dev->is_pretty != NULL &&
260*7c478bd9Sstevel@tonic-gate 		    strcmp(dev->is_pretty, df->if_names[i]) == 0)
261*7c478bd9Sstevel@tonic-gate 			return (1);
262*7c478bd9Sstevel@tonic-gate 	}
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate 	/* not found in specified names, fail match */
265*7c478bd9Sstevel@tonic-gate 	return (0);
266*7c478bd9Sstevel@tonic-gate }
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate /* select which I/O devices to collect stats for */
269*7c478bd9Sstevel@tonic-gate static void
270*7c478bd9Sstevel@tonic-gate choose_iodevs(struct snapshot *ss, struct iodev_snapshot *iodevs,
271*7c478bd9Sstevel@tonic-gate     struct iodev_filter *df)
272*7c478bd9Sstevel@tonic-gate {
273*7c478bd9Sstevel@tonic-gate 	struct iodev_snapshot *pos = iodevs;
274*7c478bd9Sstevel@tonic-gate 	int nr_iodevs = df ? df->if_max_iodevs : UNLIMITED_IODEVS;
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 	if (nr_iodevs == UNLIMITED_IODEVS)
277*7c478bd9Sstevel@tonic-gate 		nr_iodevs = INT_MAX;
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate 	while (pos && nr_iodevs) {
280*7c478bd9Sstevel@tonic-gate 		struct iodev_snapshot *tmp = pos;
281*7c478bd9Sstevel@tonic-gate 		pos = pos->is_next;
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 		if (!iodev_match(tmp, df))
284*7c478bd9Sstevel@tonic-gate 			continue;
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 		list_del(&iodevs, tmp);
287*7c478bd9Sstevel@tonic-gate 		insert_iodev(ss, tmp);
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 		--nr_iodevs;
290*7c478bd9Sstevel@tonic-gate 	}
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate 	pos = iodevs;
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 	/* now insert any iodevs into the remaining slots */
295*7c478bd9Sstevel@tonic-gate 	while (pos && nr_iodevs) {
296*7c478bd9Sstevel@tonic-gate 		struct iodev_snapshot *tmp = pos;
297*7c478bd9Sstevel@tonic-gate 		pos = pos->is_next;
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 		if (df && df->if_skip_floppy &&
300*7c478bd9Sstevel@tonic-gate 			strncmp(tmp->is_name, "fd", 2) == 0)
301*7c478bd9Sstevel@tonic-gate 			continue;
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 		list_del(&iodevs, tmp);
304*7c478bd9Sstevel@tonic-gate 		insert_iodev(ss, tmp);
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 		--nr_iodevs;
307*7c478bd9Sstevel@tonic-gate 	}
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 	/* clear the unwanted ones */
310*7c478bd9Sstevel@tonic-gate 	pos = iodevs;
311*7c478bd9Sstevel@tonic-gate 	while (pos) {
312*7c478bd9Sstevel@tonic-gate 		struct iodev_snapshot *tmp = pos;
313*7c478bd9Sstevel@tonic-gate 		pos = pos->is_next;
314*7c478bd9Sstevel@tonic-gate 		free_iodev(tmp);
315*7c478bd9Sstevel@tonic-gate 	}
316*7c478bd9Sstevel@tonic-gate }
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate static int
319*7c478bd9Sstevel@tonic-gate collate_controller(struct iodev_snapshot *controller,
320*7c478bd9Sstevel@tonic-gate     struct iodev_snapshot *disk)
321*7c478bd9Sstevel@tonic-gate {
322*7c478bd9Sstevel@tonic-gate 	controller->is_stats.nread += disk->is_stats.nread;
323*7c478bd9Sstevel@tonic-gate 	controller->is_stats.nwritten += disk->is_stats.nwritten;
324*7c478bd9Sstevel@tonic-gate 	controller->is_stats.reads += disk->is_stats.reads;
325*7c478bd9Sstevel@tonic-gate 	controller->is_stats.writes += disk->is_stats.writes;
326*7c478bd9Sstevel@tonic-gate 	controller->is_stats.wtime += disk->is_stats.wtime;
327*7c478bd9Sstevel@tonic-gate 	controller->is_stats.wlentime += disk->is_stats.wlentime;
328*7c478bd9Sstevel@tonic-gate 	controller->is_stats.rtime += disk->is_stats.rtime;
329*7c478bd9Sstevel@tonic-gate 	controller->is_stats.rlentime += disk->is_stats.rlentime;
330*7c478bd9Sstevel@tonic-gate 	controller->is_crtime += disk->is_crtime;
331*7c478bd9Sstevel@tonic-gate 	controller->is_snaptime += disk->is_snaptime;
332*7c478bd9Sstevel@tonic-gate 	if (kstat_add(&disk->is_errors, &controller->is_errors))
333*7c478bd9Sstevel@tonic-gate 		return (errno);
334*7c478bd9Sstevel@tonic-gate 	return (0);
335*7c478bd9Sstevel@tonic-gate }
336*7c478bd9Sstevel@tonic-gate 
337*7c478bd9Sstevel@tonic-gate static int
338*7c478bd9Sstevel@tonic-gate acquire_iodev_stats(struct iodev_snapshot *list, kstat_ctl_t *kc)
339*7c478bd9Sstevel@tonic-gate {
340*7c478bd9Sstevel@tonic-gate 	struct iodev_snapshot *pos;
341*7c478bd9Sstevel@tonic-gate 	int err = 0;
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	for (pos = list; pos; pos = pos->is_next) {
344*7c478bd9Sstevel@tonic-gate 		/* controllers don't have stats (yet) */
345*7c478bd9Sstevel@tonic-gate 		if (pos->is_ksp != NULL) {
346*7c478bd9Sstevel@tonic-gate 			if (kstat_read(kc, pos->is_ksp, &pos->is_stats) == -1)
347*7c478bd9Sstevel@tonic-gate 				return (errno);
348*7c478bd9Sstevel@tonic-gate 			/* make sure crtime/snaptime is updated */
349*7c478bd9Sstevel@tonic-gate 			pos->is_crtime = pos->is_ksp->ks_crtime;
350*7c478bd9Sstevel@tonic-gate 			pos->is_snaptime = pos->is_ksp->ks_snaptime;
351*7c478bd9Sstevel@tonic-gate 		}
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 		if ((err = acquire_iodev_stats(pos->is_children, kc)))
354*7c478bd9Sstevel@tonic-gate 			return (err);
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 		if (pos->is_type == IODEV_CONTROLLER) {
357*7c478bd9Sstevel@tonic-gate 			struct iodev_snapshot *pos2 = pos->is_children;
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 			for (; pos2; pos2 = pos2->is_next) {
360*7c478bd9Sstevel@tonic-gate 				if ((err = collate_controller(pos, pos2)))
361*7c478bd9Sstevel@tonic-gate 					return (err);
362*7c478bd9Sstevel@tonic-gate 			}
363*7c478bd9Sstevel@tonic-gate 		}
364*7c478bd9Sstevel@tonic-gate 	}
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	return (0);
367*7c478bd9Sstevel@tonic-gate }
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate static int
370*7c478bd9Sstevel@tonic-gate acquire_iodev_errors(struct snapshot *ss, kstat_ctl_t *kc)
371*7c478bd9Sstevel@tonic-gate {
372*7c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 	if (!(ss->s_types && SNAP_IODEV_ERRORS))
375*7c478bd9Sstevel@tonic-gate 		return (0);
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
378*7c478bd9Sstevel@tonic-gate 		char kstat_name[KSTAT_STRLEN];
379*7c478bd9Sstevel@tonic-gate 		char *dname = kstat_name;
380*7c478bd9Sstevel@tonic-gate 		char *ename = ksp->ks_name;
381*7c478bd9Sstevel@tonic-gate 		struct iodev_snapshot *iodev;
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 		if (ksp->ks_type != KSTAT_TYPE_NAMED)
384*7c478bd9Sstevel@tonic-gate 			continue;
385*7c478bd9Sstevel@tonic-gate 		if (strncmp(ksp->ks_class, "device_error", 12) != 0 &&
386*7c478bd9Sstevel@tonic-gate 		    strncmp(ksp->ks_class, "iopath_error", 12) != 0)
387*7c478bd9Sstevel@tonic-gate 			continue;
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 		/*
390*7c478bd9Sstevel@tonic-gate 		 * Some drivers may not follow the naming convention
391*7c478bd9Sstevel@tonic-gate 		 * for error kstats (i.e., drivername,err) so
392*7c478bd9Sstevel@tonic-gate 		 * be sure we don't walk off the end.
393*7c478bd9Sstevel@tonic-gate 		 */
394*7c478bd9Sstevel@tonic-gate 		while (*ename && *ename != ',') {
395*7c478bd9Sstevel@tonic-gate 			*dname = *ename;
396*7c478bd9Sstevel@tonic-gate 			dname++;
397*7c478bd9Sstevel@tonic-gate 			ename++;
398*7c478bd9Sstevel@tonic-gate 		}
399*7c478bd9Sstevel@tonic-gate 		*dname = '\0';
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 		iodev = find_iodev_by_name(ss->s_iodevs, kstat_name);
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 		if (iodev == NULL)
404*7c478bd9Sstevel@tonic-gate 			continue;
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 		if (kstat_read(kc, ksp, NULL) == -1)
407*7c478bd9Sstevel@tonic-gate 			return (errno);
408*7c478bd9Sstevel@tonic-gate 		if (kstat_copy(ksp, &iodev->is_errors) == -1)
409*7c478bd9Sstevel@tonic-gate 			return (errno);
410*7c478bd9Sstevel@tonic-gate 	}
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate 	return (0);
413*7c478bd9Sstevel@tonic-gate }
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate static void
416*7c478bd9Sstevel@tonic-gate get_ids(struct iodev_snapshot *iodev, const char *pretty)
417*7c478bd9Sstevel@tonic-gate {
418*7c478bd9Sstevel@tonic-gate 	int ctr, disk, slice, ret;
419*7c478bd9Sstevel@tonic-gate 	char *target;
420*7c478bd9Sstevel@tonic-gate 	const char *p1;
421*7c478bd9Sstevel@tonic-gate 	const char *p2;
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 	if (pretty == NULL)
424*7c478bd9Sstevel@tonic-gate 		return;
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	if (sscanf(pretty, "c%d", &ctr) != 1)
427*7c478bd9Sstevel@tonic-gate 		return;
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	p1 = pretty;
430*7c478bd9Sstevel@tonic-gate 	while (*p1 && *p1 != 't')
431*7c478bd9Sstevel@tonic-gate 		++p1;
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	if (!*p1)
434*7c478bd9Sstevel@tonic-gate 		return;
435*7c478bd9Sstevel@tonic-gate 	++p1;
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 	p2 = p1;
438*7c478bd9Sstevel@tonic-gate 	while (*p2 && *p2 != 'd')
439*7c478bd9Sstevel@tonic-gate 		++p2;
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	if (!*p2 || p2 == p1)
442*7c478bd9Sstevel@tonic-gate 		return;
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 	target = safe_alloc(1 + p2 - p1);
445*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(target, p1, 1 + p2 - p1);
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 	ret = sscanf(p2, "d%d%*[sp]%d", &disk, &slice);
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	if (ret == 2 && iodev->is_type == IODEV_PARTITION) {
450*7c478bd9Sstevel@tonic-gate 		iodev->is_id.id = slice;
451*7c478bd9Sstevel@tonic-gate 		iodev->is_parent_id.id = disk;
452*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(iodev->is_parent_id.tid, target, KSTAT_STRLEN);
453*7c478bd9Sstevel@tonic-gate 	} else if (ret == 1) {
454*7c478bd9Sstevel@tonic-gate 		if (iodev->is_type == IODEV_DISK) {
455*7c478bd9Sstevel@tonic-gate 			iodev->is_id.id = disk;
456*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(iodev->is_id.tid, target, KSTAT_STRLEN);
457*7c478bd9Sstevel@tonic-gate 			iodev->is_parent_id.id = ctr;
458*7c478bd9Sstevel@tonic-gate 		} else if (iodev->is_type == IODEV_IOPATH) {
459*7c478bd9Sstevel@tonic-gate 			iodev->is_parent_id.id = disk;
460*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(iodev->is_parent_id.tid,
461*7c478bd9Sstevel@tonic-gate 				target, KSTAT_STRLEN);
462*7c478bd9Sstevel@tonic-gate 		}
463*7c478bd9Sstevel@tonic-gate 	}
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	free(target);
466*7c478bd9Sstevel@tonic-gate }
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate static char *
469*7c478bd9Sstevel@tonic-gate get_slice(int partition, disk_list_t *dl)
470*7c478bd9Sstevel@tonic-gate {
471*7c478bd9Sstevel@tonic-gate 	char *tmpbuf;
472*7c478bd9Sstevel@tonic-gate 	size_t tmplen;
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 	if (!(dl->flags & SLICES_OK))
475*7c478bd9Sstevel@tonic-gate 		return (NULL);
476*7c478bd9Sstevel@tonic-gate 	if (partition < 0 || partition >= NDKMAP)
477*7c478bd9Sstevel@tonic-gate 		return (NULL);
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 	/* space for 's', and integer < NDKMAP (16) */
480*7c478bd9Sstevel@tonic-gate 	tmplen = strlen(dl->dsk) + strlen("sXX") + 1;
481*7c478bd9Sstevel@tonic-gate 	tmpbuf = safe_alloc(tmplen);
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 	/*
484*7c478bd9Sstevel@tonic-gate 	 * This is a regular slice. Create the name and
485*7c478bd9Sstevel@tonic-gate 	 * copy it for use by the calling routine.
486*7c478bd9Sstevel@tonic-gate 	 */
487*7c478bd9Sstevel@tonic-gate 	(void) snprintf(tmpbuf, tmplen, "%ss%d", dl->dsk, partition);
488*7c478bd9Sstevel@tonic-gate 	return (tmpbuf);
489*7c478bd9Sstevel@tonic-gate }
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate static char *
492*7c478bd9Sstevel@tonic-gate get_intel_partition(int partition, disk_list_t *dl)
493*7c478bd9Sstevel@tonic-gate {
494*7c478bd9Sstevel@tonic-gate 	char *tmpbuf;
495*7c478bd9Sstevel@tonic-gate 	size_t tmplen;
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate 	if (partition <= 0 || !(dl->flags & PARTITIONS_OK))
498*7c478bd9Sstevel@tonic-gate 		return (NULL);
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate 	/*
501*7c478bd9Sstevel@tonic-gate 	 * See if it falls in the range of allowable partitions. The
502*7c478bd9Sstevel@tonic-gate 	 * fdisk partitions show up after the traditional slices so we
503*7c478bd9Sstevel@tonic-gate 	 * determine which partition we're in and return that.
504*7c478bd9Sstevel@tonic-gate 	 * The NUMPART + 1 is not a mistake. There are currently
505*7c478bd9Sstevel@tonic-gate 	 * FD_NUMPART + 1 partitions that show up in the device directory.
506*7c478bd9Sstevel@tonic-gate 	 */
507*7c478bd9Sstevel@tonic-gate 	partition -= NDKMAP;
508*7c478bd9Sstevel@tonic-gate 	if (partition < 0 || partition >= (FD_NUMPART + 1))
509*7c478bd9Sstevel@tonic-gate 		return (NULL);
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 	/* space for 'p', and integer < NDKMAP (16) */
512*7c478bd9Sstevel@tonic-gate 	tmplen = strlen(dl->dsk) + strlen("pXX") + 1;
513*7c478bd9Sstevel@tonic-gate 	tmpbuf = safe_alloc(tmplen);
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 	(void) snprintf(tmpbuf, tmplen, "%sp%d", dl->dsk, partition);
516*7c478bd9Sstevel@tonic-gate 	return (tmpbuf);
517*7c478bd9Sstevel@tonic-gate }
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate static void
520*7c478bd9Sstevel@tonic-gate get_pretty_name(enum snapshot_types types, struct iodev_snapshot *iodev,
521*7c478bd9Sstevel@tonic-gate 	kstat_ctl_t *kc)
522*7c478bd9Sstevel@tonic-gate {
523*7c478bd9Sstevel@tonic-gate 	disk_list_t *dl;
524*7c478bd9Sstevel@tonic-gate 	char *pretty = NULL;
525*7c478bd9Sstevel@tonic-gate 	char *tmp;
526*7c478bd9Sstevel@tonic-gate 	int partition;
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 	if (iodev->is_type == IODEV_NFS) {
529*7c478bd9Sstevel@tonic-gate 		if (!(types & SNAP_IODEV_PRETTY))
530*7c478bd9Sstevel@tonic-gate 			return;
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 		iodev->is_pretty = lookup_nfs_name(iodev->is_name, kc);
533*7c478bd9Sstevel@tonic-gate 		return;
534*7c478bd9Sstevel@tonic-gate 	}
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	if (iodev->is_type == IODEV_IOPATH) {
537*7c478bd9Sstevel@tonic-gate 		char buf[KSTAT_STRLEN];
538*7c478bd9Sstevel@tonic-gate 		size_t len;
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 		tmp = iodev->is_name;
541*7c478bd9Sstevel@tonic-gate 		while (*tmp && *tmp != '.')
542*7c478bd9Sstevel@tonic-gate 			tmp++;
543*7c478bd9Sstevel@tonic-gate 		if (!*tmp)
544*7c478bd9Sstevel@tonic-gate 			return;
545*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(buf, iodev->is_name, 1 + tmp - iodev->is_name);
546*7c478bd9Sstevel@tonic-gate 		dl = lookup_ks_name(buf);
547*7c478bd9Sstevel@tonic-gate 		if (dl == NULL || dl->dsk == NULL)
548*7c478bd9Sstevel@tonic-gate 			return;
549*7c478bd9Sstevel@tonic-gate 		len = strlen(dl->dsk) + strlen(tmp) + 1;
550*7c478bd9Sstevel@tonic-gate 		pretty = safe_alloc(len);
551*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(pretty, dl->dsk, len);
552*7c478bd9Sstevel@tonic-gate 		(void) strlcat(pretty, tmp, len);
553*7c478bd9Sstevel@tonic-gate 		goto out;
554*7c478bd9Sstevel@tonic-gate 	}
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate 	dl = lookup_ks_name(iodev->is_name);
557*7c478bd9Sstevel@tonic-gate 	if (dl == NULL)
558*7c478bd9Sstevel@tonic-gate 		return;
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 	if (dl->dsk)
561*7c478bd9Sstevel@tonic-gate 		pretty = safe_strdup(dl->dsk);
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 	if (types & SNAP_IODEV_PRETTY) {
564*7c478bd9Sstevel@tonic-gate 		if (dl->dname)
565*7c478bd9Sstevel@tonic-gate 			iodev->is_dname = safe_strdup(dl->dname);
566*7c478bd9Sstevel@tonic-gate 	}
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 	if (dl->devidstr)
569*7c478bd9Sstevel@tonic-gate 		iodev->is_devid = safe_strdup(dl->devidstr);
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 	/* look for a possible partition number */
572*7c478bd9Sstevel@tonic-gate 	tmp = iodev->is_name;
573*7c478bd9Sstevel@tonic-gate 	while (*tmp && *tmp != ',')
574*7c478bd9Sstevel@tonic-gate 		tmp++;
575*7c478bd9Sstevel@tonic-gate 	if (*tmp != ',')
576*7c478bd9Sstevel@tonic-gate 		goto out;
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	tmp++;
579*7c478bd9Sstevel@tonic-gate 	partition = (int)(*tmp - 'a');
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 	if (iodev->is_type == IODEV_PARTITION) {
582*7c478bd9Sstevel@tonic-gate 		char *part;
583*7c478bd9Sstevel@tonic-gate 		if ((part = get_slice(partition, dl)) == NULL)
584*7c478bd9Sstevel@tonic-gate 			part = get_intel_partition(partition, dl);
585*7c478bd9Sstevel@tonic-gate 		if (part != NULL) {
586*7c478bd9Sstevel@tonic-gate 			free(pretty);
587*7c478bd9Sstevel@tonic-gate 			pretty = part;
588*7c478bd9Sstevel@tonic-gate 		}
589*7c478bd9Sstevel@tonic-gate 	}
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate out:
592*7c478bd9Sstevel@tonic-gate 	get_ids(iodev, pretty);
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 	/* only fill in the pretty name if specifically asked for */
595*7c478bd9Sstevel@tonic-gate 	if (types & SNAP_IODEV_PRETTY) {
596*7c478bd9Sstevel@tonic-gate 		iodev->is_pretty = pretty;
597*7c478bd9Sstevel@tonic-gate 	} else {
598*7c478bd9Sstevel@tonic-gate 		free(pretty);
599*7c478bd9Sstevel@tonic-gate 	}
600*7c478bd9Sstevel@tonic-gate }
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate static enum iodev_type
603*7c478bd9Sstevel@tonic-gate get_iodev_type(kstat_t *ksp)
604*7c478bd9Sstevel@tonic-gate {
605*7c478bd9Sstevel@tonic-gate 	if (strcmp(ksp->ks_class, "disk") == 0)
606*7c478bd9Sstevel@tonic-gate 		return (IODEV_DISK);
607*7c478bd9Sstevel@tonic-gate 	if (strcmp(ksp->ks_class, "partition") == 0)
608*7c478bd9Sstevel@tonic-gate 		return (IODEV_PARTITION);
609*7c478bd9Sstevel@tonic-gate 	if (strcmp(ksp->ks_class, "nfs") == 0)
610*7c478bd9Sstevel@tonic-gate 		return (IODEV_NFS);
611*7c478bd9Sstevel@tonic-gate 	if (strcmp(ksp->ks_class, "iopath") == 0)
612*7c478bd9Sstevel@tonic-gate 		return (IODEV_IOPATH);
613*7c478bd9Sstevel@tonic-gate 	if (strcmp(ksp->ks_class, "tape") == 0)
614*7c478bd9Sstevel@tonic-gate 		return (IODEV_TAPE);
615*7c478bd9Sstevel@tonic-gate 	return (IODEV_UNKNOWN);
616*7c478bd9Sstevel@tonic-gate }
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate int
619*7c478bd9Sstevel@tonic-gate iodev_cmp(struct iodev_snapshot *io1, struct iodev_snapshot *io2)
620*7c478bd9Sstevel@tonic-gate {
621*7c478bd9Sstevel@tonic-gate 	/* neutral sort order between disk and part */
622*7c478bd9Sstevel@tonic-gate 	if (!disk_or_partition(io1->is_type) ||
623*7c478bd9Sstevel@tonic-gate 		!disk_or_partition(io2->is_type)) {
624*7c478bd9Sstevel@tonic-gate 		if (io1->is_type < io2->is_type)
625*7c478bd9Sstevel@tonic-gate 			return (-1);
626*7c478bd9Sstevel@tonic-gate 		if (io1->is_type > io2->is_type)
627*7c478bd9Sstevel@tonic-gate 			return (1);
628*7c478bd9Sstevel@tonic-gate 	}
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate 	/* controller doesn't have ksp */
631*7c478bd9Sstevel@tonic-gate 	if (io1->is_ksp && io2->is_ksp) {
632*7c478bd9Sstevel@tonic-gate 		if (strcmp(io1->is_module, io2->is_module) != 0)
633*7c478bd9Sstevel@tonic-gate 			return (strcmp(io1->is_module, io2->is_module));
634*7c478bd9Sstevel@tonic-gate 		if (io1->is_instance < io2->is_instance)
635*7c478bd9Sstevel@tonic-gate 			return (-1);
636*7c478bd9Sstevel@tonic-gate 		if (io1->is_instance > io2->is_instance)
637*7c478bd9Sstevel@tonic-gate 			return (1);
638*7c478bd9Sstevel@tonic-gate 	} else {
639*7c478bd9Sstevel@tonic-gate 		if (io1->is_id.id < io2->is_id.id)
640*7c478bd9Sstevel@tonic-gate 			return (-1);
641*7c478bd9Sstevel@tonic-gate 		if (io1->is_id.id > io2->is_id.id)
642*7c478bd9Sstevel@tonic-gate 			return (1);
643*7c478bd9Sstevel@tonic-gate 	}
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate 	return (strcmp(io1->is_name, io2->is_name));
646*7c478bd9Sstevel@tonic-gate }
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate int
649*7c478bd9Sstevel@tonic-gate acquire_iodevs(struct snapshot *ss, kstat_ctl_t *kc, struct iodev_filter *df)
650*7c478bd9Sstevel@tonic-gate {
651*7c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
652*7c478bd9Sstevel@tonic-gate 	int err = 0;
653*7c478bd9Sstevel@tonic-gate 	struct iodev_snapshot *pos;
654*7c478bd9Sstevel@tonic-gate 	struct iodev_snapshot *list = NULL;
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate 	ss->s_nr_iodevs = 0;
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
659*7c478bd9Sstevel@tonic-gate 		enum iodev_type type;
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate 		if (ksp->ks_type != KSTAT_TYPE_IO)
662*7c478bd9Sstevel@tonic-gate 			continue;
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 		/* e.g. "usb_byte_count" is not handled */
665*7c478bd9Sstevel@tonic-gate 		if ((type = get_iodev_type(ksp)) == IODEV_UNKNOWN)
666*7c478bd9Sstevel@tonic-gate 			continue;
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate 		if (df && !(type & df->if_allowed_types))
669*7c478bd9Sstevel@tonic-gate 			continue;
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 		if ((pos = malloc(sizeof (struct iodev_snapshot))) == NULL) {
672*7c478bd9Sstevel@tonic-gate 			err = errno;
673*7c478bd9Sstevel@tonic-gate 			goto out;
674*7c478bd9Sstevel@tonic-gate 		}
675*7c478bd9Sstevel@tonic-gate 
676*7c478bd9Sstevel@tonic-gate 		(void) memset(pos, 0, sizeof (struct iodev_snapshot));
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate 		pos->is_type = type;
679*7c478bd9Sstevel@tonic-gate 		pos->is_crtime = ksp->ks_crtime;
680*7c478bd9Sstevel@tonic-gate 		pos->is_snaptime = ksp->ks_snaptime;
681*7c478bd9Sstevel@tonic-gate 		pos->is_id.id = IODEV_NO_ID;
682*7c478bd9Sstevel@tonic-gate 		pos->is_parent_id.id = IODEV_NO_ID;
683*7c478bd9Sstevel@tonic-gate 		pos->is_ksp = ksp;
684*7c478bd9Sstevel@tonic-gate 		pos->is_instance = ksp->ks_instance;
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(pos->is_module, ksp->ks_module, KSTAT_STRLEN);
687*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(pos->is_name, ksp->ks_name, KSTAT_STRLEN);
688*7c478bd9Sstevel@tonic-gate 		get_pretty_name(ss->s_types, pos, kc);
689*7c478bd9Sstevel@tonic-gate 
690*7c478bd9Sstevel@tonic-gate 		/*
691*7c478bd9Sstevel@tonic-gate 		 * We must insert in sort order so e.g. vmstat -l
692*7c478bd9Sstevel@tonic-gate 		 * chooses in order.
693*7c478bd9Sstevel@tonic-gate 		 */
694*7c478bd9Sstevel@tonic-gate 		insert_into(&list, pos);
695*7c478bd9Sstevel@tonic-gate 	}
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 	choose_iodevs(ss, list, df);
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate 	/* before acquire_stats for collate_controller()'s benefit */
700*7c478bd9Sstevel@tonic-gate 	if (ss->s_types & SNAP_IODEV_ERRORS) {
701*7c478bd9Sstevel@tonic-gate 		if ((err = acquire_iodev_errors(ss, kc)) != 0)
702*7c478bd9Sstevel@tonic-gate 			goto out;
703*7c478bd9Sstevel@tonic-gate 	}
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate 	if ((err = acquire_iodev_stats(ss->s_iodevs, kc)) != 0)
706*7c478bd9Sstevel@tonic-gate 		goto out;
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	err = 0;
709*7c478bd9Sstevel@tonic-gate out:
710*7c478bd9Sstevel@tonic-gate 	return (err);
711*7c478bd9Sstevel@tonic-gate }
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate void
714*7c478bd9Sstevel@tonic-gate free_iodev(struct iodev_snapshot *iodev)
715*7c478bd9Sstevel@tonic-gate {
716*7c478bd9Sstevel@tonic-gate 	while (iodev->is_children) {
717*7c478bd9Sstevel@tonic-gate 		struct iodev_snapshot *tmp = iodev->is_children;
718*7c478bd9Sstevel@tonic-gate 		iodev->is_children = iodev->is_children->is_next;
719*7c478bd9Sstevel@tonic-gate 		free_iodev(tmp);
720*7c478bd9Sstevel@tonic-gate 	}
721*7c478bd9Sstevel@tonic-gate 
722*7c478bd9Sstevel@tonic-gate 	free(iodev->is_errors.ks_data);
723*7c478bd9Sstevel@tonic-gate 	free(iodev->is_pretty);
724*7c478bd9Sstevel@tonic-gate 	free(iodev->is_dname);
725*7c478bd9Sstevel@tonic-gate 	free(iodev->is_devid);
726*7c478bd9Sstevel@tonic-gate 	free(iodev);
727*7c478bd9Sstevel@tonic-gate }
728