10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52723Scth * Common Development and Distribution License (the "License").
62723Scth * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*12920SJonathan.Ca@Sun.COM * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate #include "statcommon.h"
260Sstevel@tonic-gate #include "dsr.h"
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include <sys/dklabel.h>
290Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
300Sstevel@tonic-gate #include <stdlib.h>
310Sstevel@tonic-gate #include <stdarg.h>
320Sstevel@tonic-gate #include <unistd.h>
330Sstevel@tonic-gate #include <strings.h>
340Sstevel@tonic-gate #include <errno.h>
350Sstevel@tonic-gate #include <limits.h>
360Sstevel@tonic-gate
370Sstevel@tonic-gate static void insert_iodev(struct snapshot *ss, struct iodev_snapshot *iodev);
380Sstevel@tonic-gate
390Sstevel@tonic-gate static struct iodev_snapshot *
make_controller(int cid)400Sstevel@tonic-gate make_controller(int cid)
410Sstevel@tonic-gate {
420Sstevel@tonic-gate struct iodev_snapshot *new;
430Sstevel@tonic-gate
440Sstevel@tonic-gate new = safe_alloc(sizeof (struct iodev_snapshot));
450Sstevel@tonic-gate (void) memset(new, 0, sizeof (struct iodev_snapshot));
460Sstevel@tonic-gate new->is_type = IODEV_CONTROLLER;
470Sstevel@tonic-gate new->is_id.id = cid;
480Sstevel@tonic-gate new->is_parent_id.id = IODEV_NO_ID;
490Sstevel@tonic-gate
500Sstevel@tonic-gate (void) snprintf(new->is_name, sizeof (new->is_name), "c%d", cid);
510Sstevel@tonic-gate
520Sstevel@tonic-gate return (new);
530Sstevel@tonic-gate }
540Sstevel@tonic-gate
550Sstevel@tonic-gate static struct iodev_snapshot *
find_iodev_by_name(struct iodev_snapshot * list,const char * name)560Sstevel@tonic-gate find_iodev_by_name(struct iodev_snapshot *list, const char *name)
570Sstevel@tonic-gate {
580Sstevel@tonic-gate struct iodev_snapshot *pos;
590Sstevel@tonic-gate struct iodev_snapshot *pos2;
600Sstevel@tonic-gate
610Sstevel@tonic-gate for (pos = list; pos; pos = pos->is_next) {
620Sstevel@tonic-gate if (strcmp(pos->is_name, name) == 0)
630Sstevel@tonic-gate return (pos);
640Sstevel@tonic-gate
650Sstevel@tonic-gate pos2 = find_iodev_by_name(pos->is_children, name);
660Sstevel@tonic-gate if (pos2 != NULL)
670Sstevel@tonic-gate return (pos2);
680Sstevel@tonic-gate }
690Sstevel@tonic-gate
700Sstevel@tonic-gate return (NULL);
710Sstevel@tonic-gate }
720Sstevel@tonic-gate
730Sstevel@tonic-gate static enum iodev_type
parent_iodev_type(enum iodev_type type)740Sstevel@tonic-gate parent_iodev_type(enum iodev_type type)
750Sstevel@tonic-gate {
760Sstevel@tonic-gate switch (type) {
770Sstevel@tonic-gate case IODEV_CONTROLLER: return (0);
782907Scth case IODEV_IOPATH_LT: return (0);
792907Scth case IODEV_IOPATH_LI: return (0);
800Sstevel@tonic-gate case IODEV_NFS: return (0);
810Sstevel@tonic-gate case IODEV_TAPE: return (0);
822907Scth case IODEV_IOPATH_LTI: return (IODEV_DISK);
830Sstevel@tonic-gate case IODEV_DISK: return (IODEV_CONTROLLER);
840Sstevel@tonic-gate case IODEV_PARTITION: return (IODEV_DISK);
850Sstevel@tonic-gate }
860Sstevel@tonic-gate return (IODEV_UNKNOWN);
870Sstevel@tonic-gate }
880Sstevel@tonic-gate
890Sstevel@tonic-gate static int
id_match(struct iodev_id * id1,struct iodev_id * id2)900Sstevel@tonic-gate id_match(struct iodev_id *id1, struct iodev_id *id2)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate return (id1->id == id2->id &&
935957Swroche strcmp(id1->tid, id2->tid) == 0);
940Sstevel@tonic-gate }
950Sstevel@tonic-gate
960Sstevel@tonic-gate static struct iodev_snapshot *
find_parent(struct snapshot * ss,struct iodev_snapshot * iodev)970Sstevel@tonic-gate find_parent(struct snapshot *ss, struct iodev_snapshot *iodev)
980Sstevel@tonic-gate {
990Sstevel@tonic-gate enum iodev_type parent_type = parent_iodev_type(iodev->is_type);
1000Sstevel@tonic-gate struct iodev_snapshot *pos;
1010Sstevel@tonic-gate struct iodev_snapshot *pos2;
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate if (parent_type == 0 || parent_type == IODEV_UNKNOWN)
1040Sstevel@tonic-gate return (NULL);
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate if (iodev->is_parent_id.id == IODEV_NO_ID &&
1070Sstevel@tonic-gate iodev->is_parent_id.tid[0] == '\0')
1080Sstevel@tonic-gate return (NULL);
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate if (parent_type == IODEV_CONTROLLER) {
1110Sstevel@tonic-gate for (pos = ss->s_iodevs; pos; pos = pos->is_next) {
1120Sstevel@tonic-gate if (pos->is_type != IODEV_CONTROLLER)
1130Sstevel@tonic-gate continue;
1140Sstevel@tonic-gate if (pos->is_id.id != iodev->is_parent_id.id)
1150Sstevel@tonic-gate continue;
1160Sstevel@tonic-gate return (pos);
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate if (!(ss->s_types & SNAP_CONTROLLERS))
1200Sstevel@tonic-gate return (NULL);
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate pos = make_controller(iodev->is_parent_id.id);
1230Sstevel@tonic-gate insert_iodev(ss, pos);
1240Sstevel@tonic-gate return (pos);
1250Sstevel@tonic-gate }
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate /* IODEV_DISK parent */
1280Sstevel@tonic-gate for (pos = ss->s_iodevs; pos; pos = pos->is_next) {
1290Sstevel@tonic-gate if (id_match(&iodev->is_parent_id, &pos->is_id) &&
1300Sstevel@tonic-gate pos->is_type == IODEV_DISK)
1310Sstevel@tonic-gate return (pos);
1320Sstevel@tonic-gate if (pos->is_type != IODEV_CONTROLLER)
1330Sstevel@tonic-gate continue;
1340Sstevel@tonic-gate for (pos2 = pos->is_children; pos2; pos2 = pos2->is_next) {
1350Sstevel@tonic-gate if (pos2->is_type != IODEV_DISK)
1360Sstevel@tonic-gate continue;
1370Sstevel@tonic-gate if (id_match(&iodev->is_parent_id, &pos2->is_id))
1380Sstevel@tonic-gate return (pos2);
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate }
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate return (NULL);
1430Sstevel@tonic-gate }
1440Sstevel@tonic-gate
1455957Swroche /*
1465957Swroche * Introduce an index into the list to speed up insert_into looking for the
1475957Swroche * right position in the list. This index is an AVL tree of all the
1485957Swroche * iodev_snapshot in the list.
1495957Swroche */
1505957Swroche
1515957Swroche #define offsetof(s, m) (size_t)(&(((s *)0)->m)) /* for avl_create */
1525957Swroche
1535957Swroche static int
avl_iodev_cmp(const void * is1,const void * is2)1545957Swroche avl_iodev_cmp(const void* is1, const void* is2)
1555957Swroche {
1565957Swroche int c = iodev_cmp((struct iodev_snapshot *)is1,
1575957Swroche (struct iodev_snapshot *)is2);
1585957Swroche
1595957Swroche if (c > 0)
1605957Swroche return (1);
1615957Swroche
1625957Swroche if (c < 0)
1635957Swroche return (-1);
1645957Swroche
1655957Swroche return (0);
1665957Swroche }
1675957Swroche
1685957Swroche static void
ix_new_list(struct iodev_snapshot * elem)1695957Swroche ix_new_list(struct iodev_snapshot *elem)
1705957Swroche {
1715957Swroche avl_tree_t *l = malloc(sizeof (avl_tree_t));
1725957Swroche
1735957Swroche elem->avl_list = l;
1745957Swroche if (l == NULL)
1755957Swroche return;
1765957Swroche
1775957Swroche avl_create(l, avl_iodev_cmp, sizeof (struct iodev_snapshot),
1785957Swroche offsetof(struct iodev_snapshot, avl_link));
1795957Swroche
1805957Swroche avl_add(l, elem);
1815957Swroche }
1825957Swroche
1835957Swroche static void
ix_list_del(struct iodev_snapshot * elem)1845957Swroche ix_list_del(struct iodev_snapshot *elem)
1855957Swroche {
1865957Swroche avl_tree_t *l = elem->avl_list;
1875957Swroche
1885957Swroche if (l == NULL)
1895957Swroche return;
1905957Swroche
1915957Swroche elem->avl_list = NULL;
1925957Swroche
1935957Swroche avl_remove(l, elem);
1945957Swroche if (avl_numnodes(l) == 0) {
1955957Swroche avl_destroy(l);
1965957Swroche free(l);
1975957Swroche }
1985957Swroche }
1995957Swroche
2005957Swroche static void
ix_insert_here(struct iodev_snapshot * pos,struct iodev_snapshot * elem,int ba)2015957Swroche ix_insert_here(struct iodev_snapshot *pos, struct iodev_snapshot *elem, int ba)
2025957Swroche {
2035957Swroche avl_tree_t *l = pos->avl_list;
2045957Swroche elem->avl_list = l;
2055957Swroche
2065957Swroche if (l == NULL)
2075957Swroche return;
2085957Swroche
2095957Swroche avl_insert_here(l, elem, pos, ba);
2105957Swroche }
2115957Swroche
2120Sstevel@tonic-gate static void
list_del(struct iodev_snapshot ** list,struct iodev_snapshot * pos)2130Sstevel@tonic-gate list_del(struct iodev_snapshot **list, struct iodev_snapshot *pos)
2140Sstevel@tonic-gate {
2155957Swroche ix_list_del(pos);
2165957Swroche
2170Sstevel@tonic-gate if (*list == pos)
2180Sstevel@tonic-gate *list = pos->is_next;
2190Sstevel@tonic-gate if (pos->is_next)
2200Sstevel@tonic-gate pos->is_next->is_prev = pos->is_prev;
2210Sstevel@tonic-gate if (pos->is_prev)
2220Sstevel@tonic-gate pos->is_prev->is_next = pos->is_next;
2230Sstevel@tonic-gate pos->is_prev = pos->is_next = NULL;
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate static void
insert_before(struct iodev_snapshot ** list,struct iodev_snapshot * pos,struct iodev_snapshot * new)2270Sstevel@tonic-gate insert_before(struct iodev_snapshot **list, struct iodev_snapshot *pos,
2280Sstevel@tonic-gate struct iodev_snapshot *new)
2290Sstevel@tonic-gate {
2300Sstevel@tonic-gate if (pos == NULL) {
2310Sstevel@tonic-gate new->is_prev = new->is_next = NULL;
2320Sstevel@tonic-gate *list = new;
2335957Swroche ix_new_list(new);
2340Sstevel@tonic-gate return;
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate new->is_next = pos;
2380Sstevel@tonic-gate new->is_prev = pos->is_prev;
2390Sstevel@tonic-gate if (pos->is_prev)
2400Sstevel@tonic-gate pos->is_prev->is_next = new;
2410Sstevel@tonic-gate else
2420Sstevel@tonic-gate *list = new;
2430Sstevel@tonic-gate pos->is_prev = new;
2445957Swroche
2455957Swroche ix_insert_here(pos, new, AVL_BEFORE);
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate static void
insert_after(struct iodev_snapshot ** list,struct iodev_snapshot * pos,struct iodev_snapshot * new)2490Sstevel@tonic-gate insert_after(struct iodev_snapshot **list, struct iodev_snapshot *pos,
2500Sstevel@tonic-gate struct iodev_snapshot *new)
2510Sstevel@tonic-gate {
2520Sstevel@tonic-gate if (pos == NULL) {
2530Sstevel@tonic-gate new->is_prev = new->is_next = NULL;
2540Sstevel@tonic-gate *list = new;
2555957Swroche ix_new_list(new);
2560Sstevel@tonic-gate return;
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate
2590Sstevel@tonic-gate new->is_next = pos->is_next;
2600Sstevel@tonic-gate new->is_prev = pos;
2610Sstevel@tonic-gate if (pos->is_next)
2620Sstevel@tonic-gate pos->is_next->is_prev = new;
2630Sstevel@tonic-gate pos->is_next = new;
2645957Swroche
2655957Swroche ix_insert_here(pos, new, AVL_AFTER);
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate static void
insert_into(struct iodev_snapshot ** list,struct iodev_snapshot * iodev)2690Sstevel@tonic-gate insert_into(struct iodev_snapshot **list, struct iodev_snapshot *iodev)
2700Sstevel@tonic-gate {
2710Sstevel@tonic-gate struct iodev_snapshot *tmp = *list;
2725957Swroche avl_tree_t *l;
2735957Swroche void *p;
2745957Swroche avl_index_t where;
2755957Swroche
2760Sstevel@tonic-gate if (*list == NULL) {
2770Sstevel@tonic-gate *list = iodev;
2785957Swroche ix_new_list(iodev);
2790Sstevel@tonic-gate return;
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate
2825957Swroche /*
2835957Swroche * Optimize the search: instead of walking the entire list
2845957Swroche * (which can contain thousands of nodes), search in the AVL
2855957Swroche * tree the nearest node and reposition the startup point to
2865957Swroche * this node rather than always starting from the beginning
2875957Swroche * of the list.
2885957Swroche */
2895957Swroche l = tmp->avl_list;
2905957Swroche if (l != NULL) {
2915957Swroche p = avl_find(l, iodev, &where);
2925957Swroche if (p == NULL) {
2935957Swroche p = avl_nearest(l, where, AVL_BEFORE);
2945957Swroche }
2955957Swroche if (p != NULL) {
2965957Swroche tmp = (struct iodev_snapshot *)p;
2975957Swroche }
2985957Swroche }
2995957Swroche
3000Sstevel@tonic-gate for (;;) {
3010Sstevel@tonic-gate if (iodev_cmp(tmp, iodev) > 0) {
3020Sstevel@tonic-gate insert_before(list, tmp, iodev);
3030Sstevel@tonic-gate return;
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate
3060Sstevel@tonic-gate if (tmp->is_next == NULL)
3070Sstevel@tonic-gate break;
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate tmp = tmp->is_next;
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate
3120Sstevel@tonic-gate insert_after(list, tmp, iodev);
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate
3150Sstevel@tonic-gate static int
disk_or_partition(enum iodev_type type)3160Sstevel@tonic-gate disk_or_partition(enum iodev_type type)
3170Sstevel@tonic-gate {
3180Sstevel@tonic-gate return (type == IODEV_DISK || type == IODEV_PARTITION);
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate
3212907Scth static int
disk_or_partition_or_iopath(enum iodev_type type)3222907Scth disk_or_partition_or_iopath(enum iodev_type type)
3232907Scth {
3242907Scth return (type == IODEV_DISK || type == IODEV_PARTITION ||
3252907Scth type == IODEV_IOPATH_LTI);
3262907Scth }
3272907Scth
3280Sstevel@tonic-gate static void
insert_iodev(struct snapshot * ss,struct iodev_snapshot * iodev)3290Sstevel@tonic-gate insert_iodev(struct snapshot *ss, struct iodev_snapshot *iodev)
3300Sstevel@tonic-gate {
3310Sstevel@tonic-gate struct iodev_snapshot *parent = find_parent(ss, iodev);
3320Sstevel@tonic-gate struct iodev_snapshot **list;
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate if (parent != NULL) {
3350Sstevel@tonic-gate list = &parent->is_children;
3360Sstevel@tonic-gate parent->is_nr_children++;
3370Sstevel@tonic-gate } else {
3380Sstevel@tonic-gate list = &ss->s_iodevs;
3390Sstevel@tonic-gate ss->s_nr_iodevs++;
3400Sstevel@tonic-gate }
3410Sstevel@tonic-gate
3420Sstevel@tonic-gate insert_into(list, iodev);
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate
3452907Scth /* return 1 if dev passes filter */
3460Sstevel@tonic-gate static int
iodev_match(struct iodev_snapshot * dev,struct iodev_filter * df)3470Sstevel@tonic-gate iodev_match(struct iodev_snapshot *dev, struct iodev_filter *df)
3480Sstevel@tonic-gate {
3492907Scth int is_floppy = (strncmp(dev->is_name, "fd", 2) == 0);
3502907Scth char *isn, *ispn, *ifn;
3512907Scth char *path;
3522907Scth int ifnl;
3532907Scth size_t i;
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate /* no filter, pass */
3560Sstevel@tonic-gate if (df == NULL)
3572907Scth return (1); /* pass */
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate /* no filtered names, pass if not floppy and skipped */
3600Sstevel@tonic-gate if (df->if_nr_names == NULL)
3610Sstevel@tonic-gate return (!(df->if_skip_floppy && is_floppy));
3620Sstevel@tonic-gate
3632907Scth isn = dev->is_name;
3642907Scth ispn = dev->is_pretty;
3650Sstevel@tonic-gate for (i = 0; i < df->if_nr_names; i++) {
3662907Scth ifn = df->if_names[i];
3672907Scth ifnl = strlen(ifn);
3682907Scth path = strchr(ifn, '.');
3692907Scth
3702907Scth if ((strcmp(isn, ifn) == 0) ||
3712907Scth (ispn && (strcmp(ispn, ifn) == 0)))
3722907Scth return (1); /* pass */
3732907Scth
3742907Scth /* if filter is a path allow partial match */
3752907Scth if (path &&
3762907Scth ((strncmp(isn, ifn, ifnl) == 0) ||
3772907Scth (ispn && (strncmp(ispn, ifn, ifnl) == 0))))
3782907Scth return (1); /* pass */
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate
3812907Scth return (0); /* fail */
3822907Scth }
3832907Scth
3842907Scth /* return 1 if path is an mpxio path associated with dev */
3852907Scth static int
iodev_path_match(struct iodev_snapshot * dev,struct iodev_snapshot * path)3862907Scth iodev_path_match(struct iodev_snapshot *dev, struct iodev_snapshot *path)
3872907Scth {
3882907Scth char *dn, *pn;
3892907Scth int dnl;
3902907Scth
3912907Scth dn = dev->is_name;
3922907Scth pn = path->is_name;
3932907Scth dnl = strlen(dn);
3942907Scth
3952907Scth if ((strncmp(pn, dn, dnl) == 0) && (pn[dnl] == '.'))
3962907Scth return (1); /* yes */
3972907Scth
3982907Scth return (0); /* no */
3990Sstevel@tonic-gate }
4000Sstevel@tonic-gate
4010Sstevel@tonic-gate /* select which I/O devices to collect stats for */
4020Sstevel@tonic-gate static void
choose_iodevs(struct snapshot * ss,struct iodev_snapshot * iodevs,struct iodev_filter * df)4030Sstevel@tonic-gate choose_iodevs(struct snapshot *ss, struct iodev_snapshot *iodevs,
4040Sstevel@tonic-gate struct iodev_filter *df)
4050Sstevel@tonic-gate {
4062907Scth struct iodev_snapshot *pos, *ppos, *tmp, *ptmp;
4072907Scth int nr_iodevs;
4082907Scth int nr_iodevs_orig;
4092907Scth
4102907Scth nr_iodevs = df ? df->if_max_iodevs : UNLIMITED_IODEVS;
4112907Scth nr_iodevs_orig = nr_iodevs;
4120Sstevel@tonic-gate
4130Sstevel@tonic-gate if (nr_iodevs == UNLIMITED_IODEVS)
4140Sstevel@tonic-gate nr_iodevs = INT_MAX;
4150Sstevel@tonic-gate
4162907Scth /* add the full matches */
4172907Scth pos = iodevs;
4180Sstevel@tonic-gate while (pos && nr_iodevs) {
4192907Scth tmp = pos;
4200Sstevel@tonic-gate pos = pos->is_next;
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate if (!iodev_match(tmp, df))
4232907Scth continue; /* failed full match */
4240Sstevel@tonic-gate
4250Sstevel@tonic-gate list_del(&iodevs, tmp);
4260Sstevel@tonic-gate insert_iodev(ss, tmp);
4270Sstevel@tonic-gate
4282907Scth /*
4292907Scth * Add all mpxio paths associated with match above. Added
4302907Scth * paths don't count against nr_iodevs.
4312907Scth */
4322907Scth if (strchr(tmp->is_name, '.') == NULL) {
4332907Scth ppos = iodevs;
4342907Scth while (ppos) {
4352907Scth ptmp = ppos;
4362907Scth ppos = ppos->is_next;
4372907Scth
4382907Scth if (!iodev_path_match(tmp, ptmp))
4392907Scth continue; /* not an mpxio path */
4402907Scth
4412907Scth list_del(&iodevs, ptmp);
4422907Scth insert_iodev(ss, ptmp);
4432907Scth if (pos == ptmp)
4442907Scth pos = ppos;
4452907Scth }
4462907Scth }
4472907Scth
4482907Scth nr_iodevs--;
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate
4512907Scth /*
4522907Scth * If we had a filter, and *nothing* passed the filter then we
4532907Scth * don't want to fill the remaining slots - it is just confusing
4542907Scth * if we don that, it makes it look like the filter code is broken.
4552907Scth */
4562907Scth if ((df->if_nr_names == NULL) || (nr_iodevs != nr_iodevs_orig)) {
4572907Scth /* now insert any iodevs into the remaining slots */
4582907Scth pos = iodevs;
4592907Scth while (pos && nr_iodevs) {
4602907Scth tmp = pos;
4612907Scth pos = pos->is_next;
4620Sstevel@tonic-gate
4632907Scth if (df && df->if_skip_floppy &&
4645957Swroche strncmp(tmp->is_name, "fd", 2) == 0)
4652907Scth continue;
4660Sstevel@tonic-gate
4672907Scth list_del(&iodevs, tmp);
4682907Scth insert_iodev(ss, tmp);
4690Sstevel@tonic-gate
4702907Scth --nr_iodevs;
4712907Scth }
4720Sstevel@tonic-gate }
4730Sstevel@tonic-gate
4740Sstevel@tonic-gate /* clear the unwanted ones */
4750Sstevel@tonic-gate pos = iodevs;
4760Sstevel@tonic-gate while (pos) {
4770Sstevel@tonic-gate struct iodev_snapshot *tmp = pos;
4780Sstevel@tonic-gate pos = pos->is_next;
4790Sstevel@tonic-gate free_iodev(tmp);
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate }
4820Sstevel@tonic-gate
4830Sstevel@tonic-gate static int
collate_controller(struct iodev_snapshot * controller,struct iodev_snapshot * disk)4840Sstevel@tonic-gate collate_controller(struct iodev_snapshot *controller,
4850Sstevel@tonic-gate struct iodev_snapshot *disk)
4860Sstevel@tonic-gate {
4870Sstevel@tonic-gate controller->is_stats.nread += disk->is_stats.nread;
4880Sstevel@tonic-gate controller->is_stats.nwritten += disk->is_stats.nwritten;
4890Sstevel@tonic-gate controller->is_stats.reads += disk->is_stats.reads;
4900Sstevel@tonic-gate controller->is_stats.writes += disk->is_stats.writes;
4910Sstevel@tonic-gate controller->is_stats.wtime += disk->is_stats.wtime;
4920Sstevel@tonic-gate controller->is_stats.wlentime += disk->is_stats.wlentime;
4930Sstevel@tonic-gate controller->is_stats.rtime += disk->is_stats.rtime;
4940Sstevel@tonic-gate controller->is_stats.rlentime += disk->is_stats.rlentime;
4950Sstevel@tonic-gate controller->is_crtime += disk->is_crtime;
4960Sstevel@tonic-gate controller->is_snaptime += disk->is_snaptime;
4970Sstevel@tonic-gate if (kstat_add(&disk->is_errors, &controller->is_errors))
4980Sstevel@tonic-gate return (errno);
4990Sstevel@tonic-gate return (0);
5000Sstevel@tonic-gate }
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate static int
acquire_iodev_stats(struct iodev_snapshot * list,kstat_ctl_t * kc)5030Sstevel@tonic-gate acquire_iodev_stats(struct iodev_snapshot *list, kstat_ctl_t *kc)
5040Sstevel@tonic-gate {
5050Sstevel@tonic-gate struct iodev_snapshot *pos;
5060Sstevel@tonic-gate int err = 0;
5070Sstevel@tonic-gate
5080Sstevel@tonic-gate for (pos = list; pos; pos = pos->is_next) {
5090Sstevel@tonic-gate /* controllers don't have stats (yet) */
5100Sstevel@tonic-gate if (pos->is_ksp != NULL) {
5110Sstevel@tonic-gate if (kstat_read(kc, pos->is_ksp, &pos->is_stats) == -1)
5120Sstevel@tonic-gate return (errno);
5130Sstevel@tonic-gate /* make sure crtime/snaptime is updated */
5140Sstevel@tonic-gate pos->is_crtime = pos->is_ksp->ks_crtime;
5150Sstevel@tonic-gate pos->is_snaptime = pos->is_ksp->ks_snaptime;
5160Sstevel@tonic-gate }
5170Sstevel@tonic-gate
5180Sstevel@tonic-gate if ((err = acquire_iodev_stats(pos->is_children, kc)))
5190Sstevel@tonic-gate return (err);
5200Sstevel@tonic-gate
5210Sstevel@tonic-gate if (pos->is_type == IODEV_CONTROLLER) {
5220Sstevel@tonic-gate struct iodev_snapshot *pos2 = pos->is_children;
5230Sstevel@tonic-gate
5240Sstevel@tonic-gate for (; pos2; pos2 = pos2->is_next) {
5250Sstevel@tonic-gate if ((err = collate_controller(pos, pos2)))
5260Sstevel@tonic-gate return (err);
5270Sstevel@tonic-gate }
5280Sstevel@tonic-gate }
5290Sstevel@tonic-gate }
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate return (0);
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate static int
acquire_iodev_errors(struct snapshot * ss,kstat_ctl_t * kc)5350Sstevel@tonic-gate acquire_iodev_errors(struct snapshot *ss, kstat_ctl_t *kc)
5360Sstevel@tonic-gate {
5370Sstevel@tonic-gate kstat_t *ksp;
5380Sstevel@tonic-gate
5390Sstevel@tonic-gate if (!(ss->s_types && SNAP_IODEV_ERRORS))
5400Sstevel@tonic-gate return (0);
5410Sstevel@tonic-gate
5420Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
5430Sstevel@tonic-gate char kstat_name[KSTAT_STRLEN];
5440Sstevel@tonic-gate char *dname = kstat_name;
5450Sstevel@tonic-gate char *ename = ksp->ks_name;
5460Sstevel@tonic-gate struct iodev_snapshot *iodev;
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate if (ksp->ks_type != KSTAT_TYPE_NAMED)
5490Sstevel@tonic-gate continue;
5500Sstevel@tonic-gate if (strncmp(ksp->ks_class, "device_error", 12) != 0 &&
5510Sstevel@tonic-gate strncmp(ksp->ks_class, "iopath_error", 12) != 0)
5520Sstevel@tonic-gate continue;
5530Sstevel@tonic-gate
5540Sstevel@tonic-gate /*
5550Sstevel@tonic-gate * Some drivers may not follow the naming convention
5560Sstevel@tonic-gate * for error kstats (i.e., drivername,err) so
5570Sstevel@tonic-gate * be sure we don't walk off the end.
5580Sstevel@tonic-gate */
5590Sstevel@tonic-gate while (*ename && *ename != ',') {
5600Sstevel@tonic-gate *dname = *ename;
5610Sstevel@tonic-gate dname++;
5620Sstevel@tonic-gate ename++;
5630Sstevel@tonic-gate }
5640Sstevel@tonic-gate *dname = '\0';
5650Sstevel@tonic-gate
5660Sstevel@tonic-gate iodev = find_iodev_by_name(ss->s_iodevs, kstat_name);
5670Sstevel@tonic-gate
5680Sstevel@tonic-gate if (iodev == NULL)
5690Sstevel@tonic-gate continue;
5700Sstevel@tonic-gate
5710Sstevel@tonic-gate if (kstat_read(kc, ksp, NULL) == -1)
5720Sstevel@tonic-gate return (errno);
5730Sstevel@tonic-gate if (kstat_copy(ksp, &iodev->is_errors) == -1)
5740Sstevel@tonic-gate return (errno);
5750Sstevel@tonic-gate }
5760Sstevel@tonic-gate
5770Sstevel@tonic-gate return (0);
5780Sstevel@tonic-gate }
5790Sstevel@tonic-gate
5800Sstevel@tonic-gate static void
get_ids(struct iodev_snapshot * iodev,const char * pretty)5810Sstevel@tonic-gate get_ids(struct iodev_snapshot *iodev, const char *pretty)
5820Sstevel@tonic-gate {
5830Sstevel@tonic-gate int ctr, disk, slice, ret;
5840Sstevel@tonic-gate char *target;
5850Sstevel@tonic-gate const char *p1;
5860Sstevel@tonic-gate const char *p2;
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate if (pretty == NULL)
5890Sstevel@tonic-gate return;
5900Sstevel@tonic-gate
5910Sstevel@tonic-gate if (sscanf(pretty, "c%d", &ctr) != 1)
5920Sstevel@tonic-gate return;
5930Sstevel@tonic-gate
5940Sstevel@tonic-gate p1 = pretty;
5950Sstevel@tonic-gate while (*p1 && *p1 != 't')
5960Sstevel@tonic-gate ++p1;
5970Sstevel@tonic-gate
5980Sstevel@tonic-gate if (!*p1)
5990Sstevel@tonic-gate return;
6000Sstevel@tonic-gate ++p1;
6010Sstevel@tonic-gate
6020Sstevel@tonic-gate p2 = p1;
6030Sstevel@tonic-gate while (*p2 && *p2 != 'd')
6040Sstevel@tonic-gate ++p2;
6050Sstevel@tonic-gate
6060Sstevel@tonic-gate if (!*p2 || p2 == p1)
6070Sstevel@tonic-gate return;
6080Sstevel@tonic-gate
6090Sstevel@tonic-gate target = safe_alloc(1 + p2 - p1);
6100Sstevel@tonic-gate (void) strlcpy(target, p1, 1 + p2 - p1);
6110Sstevel@tonic-gate
6120Sstevel@tonic-gate ret = sscanf(p2, "d%d%*[sp]%d", &disk, &slice);
6130Sstevel@tonic-gate
6140Sstevel@tonic-gate if (ret == 2 && iodev->is_type == IODEV_PARTITION) {
6150Sstevel@tonic-gate iodev->is_id.id = slice;
6160Sstevel@tonic-gate iodev->is_parent_id.id = disk;
6170Sstevel@tonic-gate (void) strlcpy(iodev->is_parent_id.tid, target, KSTAT_STRLEN);
6180Sstevel@tonic-gate } else if (ret == 1) {
6190Sstevel@tonic-gate if (iodev->is_type == IODEV_DISK) {
6200Sstevel@tonic-gate iodev->is_id.id = disk;
6210Sstevel@tonic-gate (void) strlcpy(iodev->is_id.tid, target, KSTAT_STRLEN);
6220Sstevel@tonic-gate iodev->is_parent_id.id = ctr;
6232907Scth } else if (iodev->is_type == IODEV_IOPATH_LTI) {
6240Sstevel@tonic-gate iodev->is_parent_id.id = disk;
6250Sstevel@tonic-gate (void) strlcpy(iodev->is_parent_id.tid,
6265957Swroche target, KSTAT_STRLEN);
6270Sstevel@tonic-gate }
6280Sstevel@tonic-gate }
6290Sstevel@tonic-gate
6300Sstevel@tonic-gate free(target);
6310Sstevel@tonic-gate }
6320Sstevel@tonic-gate
6330Sstevel@tonic-gate static void
get_pretty_name(enum snapshot_types types,struct iodev_snapshot * iodev,kstat_ctl_t * kc)6340Sstevel@tonic-gate get_pretty_name(enum snapshot_types types, struct iodev_snapshot *iodev,
6350Sstevel@tonic-gate kstat_ctl_t *kc)
6360Sstevel@tonic-gate {
6372907Scth disk_list_t *dl;
6382907Scth char *pretty = NULL;
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate if (iodev->is_type == IODEV_NFS) {
6410Sstevel@tonic-gate if (!(types & SNAP_IODEV_PRETTY))
6420Sstevel@tonic-gate return;
6430Sstevel@tonic-gate
6440Sstevel@tonic-gate iodev->is_pretty = lookup_nfs_name(iodev->is_name, kc);
6450Sstevel@tonic-gate return;
6460Sstevel@tonic-gate }
6470Sstevel@tonic-gate
6482907Scth /* lookup/translate the kstat name */
6492723Scth dl = lookup_ks_name(iodev->is_name, (types & SNAP_IODEV_DEVID) ? 1 : 0);
6500Sstevel@tonic-gate if (dl == NULL)
6510Sstevel@tonic-gate return;
6520Sstevel@tonic-gate
6530Sstevel@tonic-gate if (dl->dsk)
6540Sstevel@tonic-gate pretty = safe_strdup(dl->dsk);
6550Sstevel@tonic-gate
6560Sstevel@tonic-gate if (types & SNAP_IODEV_PRETTY) {
6570Sstevel@tonic-gate if (dl->dname)
6580Sstevel@tonic-gate iodev->is_dname = safe_strdup(dl->dname);
6590Sstevel@tonic-gate }
6600Sstevel@tonic-gate
6610Sstevel@tonic-gate if (dl->devidstr)
6620Sstevel@tonic-gate iodev->is_devid = safe_strdup(dl->devidstr);
6630Sstevel@tonic-gate
6640Sstevel@tonic-gate get_ids(iodev, pretty);
6650Sstevel@tonic-gate
6662907Scth /*
6672907Scth * we fill in pretty name wether it is asked for or not because
6682907Scth * it could be used in a filter by match_iodevs.
6692907Scth */
6702907Scth iodev->is_pretty = pretty;
6710Sstevel@tonic-gate }
6720Sstevel@tonic-gate
6730Sstevel@tonic-gate static enum iodev_type
get_iodev_type(kstat_t * ksp)6740Sstevel@tonic-gate get_iodev_type(kstat_t *ksp)
6750Sstevel@tonic-gate {
6760Sstevel@tonic-gate if (strcmp(ksp->ks_class, "disk") == 0)
6770Sstevel@tonic-gate return (IODEV_DISK);
6780Sstevel@tonic-gate if (strcmp(ksp->ks_class, "partition") == 0)
6790Sstevel@tonic-gate return (IODEV_PARTITION);
6800Sstevel@tonic-gate if (strcmp(ksp->ks_class, "nfs") == 0)
6810Sstevel@tonic-gate return (IODEV_NFS);
6820Sstevel@tonic-gate if (strcmp(ksp->ks_class, "iopath") == 0)
6832907Scth return (IODEV_IOPATH_LTI);
6840Sstevel@tonic-gate if (strcmp(ksp->ks_class, "tape") == 0)
6850Sstevel@tonic-gate return (IODEV_TAPE);
6860Sstevel@tonic-gate return (IODEV_UNKNOWN);
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate
6892907Scth /* get the lun/target/initiator from the name, return 1 on success */
6902907Scth static int
get_lti(char * s,char * lname,int * l,char * tname,int * t,char * iname,int * i)6912907Scth get_lti(char *s,
6922907Scth char *lname, int *l, char *tname, int *t, char *iname, int *i)
6932907Scth {
6942907Scth int num = 0;
6952907Scth
6969782SChris.Liu@Sun.COM num = sscanf(s, "%[a-z]%d%*[.]%[a-z]%d%*[.]%[a-z_]%d", lname, l,
6972907Scth tname, t, iname, i);
6982907Scth return ((num == 6) ? 1 : 0);
6992907Scth }
7002907Scth
7012907Scth
7022907Scth /* get the lun, target, and initiator name and instance */
7032907Scth static void
get_path_info(struct iodev_snapshot * io,char * mod,size_t modlen,int * type,int * inst,char * name,size_t size)704*12920SJonathan.Ca@Sun.COM get_path_info(struct iodev_snapshot *io, char *mod, size_t modlen, int *type,
705*12920SJonathan.Ca@Sun.COM int *inst, char *name, size_t size)
7062907Scth {
7072907Scth
7082907Scth /*
7092907Scth * If it is iopath or ssd then pad the name with i/t/l so we can sort
7102907Scth * by alpha order and set type for IOPATH to DISK since we want to
7112907Scth * have it grouped with its ssd parent. The lun can be 5 digits,
7122907Scth * the target can be 4 digits, and the initiator can be 3 digits and
7132907Scth * the padding is done appropriately for string comparisons.
7142907Scth */
7152907Scth if (disk_or_partition_or_iopath(io->is_type)) {
7162907Scth int i1, t1, l1;
7172907Scth char tname[KSTAT_STRLEN], iname[KSTAT_STRLEN];
7182907Scth char *ptr, lname[KSTAT_STRLEN];
7192907Scth
7202907Scth i1 = t1 = l1 = 0;
7212907Scth (void) get_lti(io->is_name, lname, &l1, tname, &t1, iname, &i1);
7222907Scth *type = io->is_type;
7232907Scth if (io->is_type == IODEV_DISK) {
7242907Scth (void) snprintf(name, size, "%s%05d", lname, l1);
7252907Scth } else if (io->is_type == IODEV_PARTITION) {
7262907Scth ptr = strchr(io->is_name, ',');
7272907Scth (void) snprintf(name, size, "%s%05d%s", lname, l1, ptr);
7282907Scth } else {
7292907Scth (void) snprintf(name, size, "%s%05d.%s%04d.%s%03d",
7302907Scth lname, l1, tname, t1, iname, i1);
7312907Scth /* set to disk so we sort with disks */
7322907Scth *type = IODEV_DISK;
7332907Scth }
734*12920SJonathan.Ca@Sun.COM (void) strlcpy(mod, lname, modlen);
7352907Scth *inst = l1;
7362907Scth } else {
737*12920SJonathan.Ca@Sun.COM (void) strlcpy(mod, io->is_module, modlen);
738*12920SJonathan.Ca@Sun.COM (void) strlcpy(name, io->is_name, size);
7392907Scth *type = io->is_type;
7402907Scth *inst = io->is_instance;
7412907Scth }
7422907Scth }
7432907Scth
7440Sstevel@tonic-gate int
iodev_cmp(struct iodev_snapshot * io1,struct iodev_snapshot * io2)7450Sstevel@tonic-gate iodev_cmp(struct iodev_snapshot *io1, struct iodev_snapshot *io2)
7460Sstevel@tonic-gate {
7472907Scth int type1, type2;
7482907Scth int inst1, inst2;
7492907Scth char name1[KSTAT_STRLEN], name2[KSTAT_STRLEN];
7502907Scth char mod1[KSTAT_STRLEN], mod2[KSTAT_STRLEN];
7512907Scth
752*12920SJonathan.Ca@Sun.COM get_path_info(io1, mod1, sizeof (mod1), &type1, &inst1, name1,
753*12920SJonathan.Ca@Sun.COM sizeof (name1));
754*12920SJonathan.Ca@Sun.COM get_path_info(io2, mod2, sizeof (mod2), &type2, &inst2, name2,
755*12920SJonathan.Ca@Sun.COM sizeof (name2));
7562907Scth if ((!disk_or_partition(type1)) ||
7572907Scth (!disk_or_partition(type2))) {
7582907Scth /* neutral sort order between disk and part */
7592907Scth if (type1 < type2) {
7600Sstevel@tonic-gate return (-1);
7612907Scth }
7622907Scth if (type1 > type2) {
7630Sstevel@tonic-gate return (1);
7642907Scth }
7650Sstevel@tonic-gate }
7660Sstevel@tonic-gate
7670Sstevel@tonic-gate /* controller doesn't have ksp */
7680Sstevel@tonic-gate if (io1->is_ksp && io2->is_ksp) {
7692907Scth if (strcmp(mod1, mod2) != 0) {
7702907Scth return (strcmp(mod1, mod2));
7712907Scth }
7722907Scth if (inst1 < inst2) {
7730Sstevel@tonic-gate return (-1);
7742907Scth }
7752907Scth if (inst1 > inst2) {
7760Sstevel@tonic-gate return (1);
7772907Scth }
7780Sstevel@tonic-gate } else {
7792907Scth if (io1->is_id.id < io2->is_id.id) {
7800Sstevel@tonic-gate return (-1);
7812907Scth }
7822907Scth if (io1->is_id.id > io2->is_id.id) {
7830Sstevel@tonic-gate return (1);
7842907Scth }
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate
7872907Scth return (strcmp(name1, name2));
7882907Scth }
7892907Scth
7902907Scth /* update the target reads and writes */
7912907Scth static void
update_target(struct iodev_snapshot * tgt,struct iodev_snapshot * path)7922907Scth update_target(struct iodev_snapshot *tgt, struct iodev_snapshot *path)
7932907Scth {
7942907Scth tgt->is_stats.reads += path->is_stats.reads;
7952907Scth tgt->is_stats.writes += path->is_stats.writes;
7962907Scth tgt->is_stats.nread += path->is_stats.nread;
7972907Scth tgt->is_stats.nwritten += path->is_stats.nwritten;
7982907Scth tgt->is_stats.wcnt += path->is_stats.wcnt;
7992907Scth tgt->is_stats.rcnt += path->is_stats.rcnt;
8002907Scth
8012907Scth /*
8022907Scth * Stash the t_delta in the crtime for use in show_disk
8032907Scth * NOTE: this can't be done in show_disk because the
8042907Scth * itl entry is removed for the old format
8052907Scth */
8062907Scth tgt->is_crtime += hrtime_delta(path->is_crtime, path->is_snaptime);
8072907Scth tgt->is_snaptime += path->is_snaptime;
8082907Scth tgt->is_nr_children += 1;
8092907Scth }
8102907Scth
8112907Scth /*
8122907Scth * Create a new synthetic device entry of the specified type. The supported
8132907Scth * synthetic types are IODEV_IOPATH_LT and IODEV_IOPATH_LI.
8142907Scth */
8152907Scth static struct iodev_snapshot *
make_extended_device(int type,struct iodev_snapshot * old)8162907Scth make_extended_device(int type, struct iodev_snapshot *old)
8172907Scth {
8182907Scth struct iodev_snapshot *tptr = NULL;
8192907Scth char *ptr;
8202907Scth int lun, tgt, initiator;
8212907Scth char lun_name[KSTAT_STRLEN];
8222907Scth char tgt_name[KSTAT_STRLEN];
8232907Scth char initiator_name[KSTAT_STRLEN];
8242907Scth
8252907Scth if (old == NULL)
8262907Scth return (NULL);
8272907Scth if (get_lti(old->is_name,
8282907Scth lun_name, &lun, tgt_name, &tgt, initiator_name, &initiator) != 1) {
8292907Scth return (NULL);
8302907Scth }
8312907Scth tptr = safe_alloc(sizeof (*old));
8322907Scth bzero(tptr, sizeof (*old));
8332907Scth if (old->is_pretty != NULL) {
8342907Scth tptr->is_pretty = safe_alloc(strlen(old->is_pretty) + 1);
8352907Scth (void) strcpy(tptr->is_pretty, old->is_pretty);
8362907Scth }
8372907Scth bcopy(&old->is_parent_id, &tptr->is_parent_id,
8385957Swroche sizeof (old->is_parent_id));
8392907Scth
8402907Scth tptr->is_type = type;
8412907Scth
8422907Scth if (type == IODEV_IOPATH_LT) {
8432907Scth /* make new synthetic entry that is the LT */
8442907Scth /* set the id to the target id */
8452907Scth tptr->is_id.id = tgt;
8462907Scth (void) snprintf(tptr->is_id.tid, sizeof (tptr->is_id.tid),
8472907Scth "%s%d", tgt_name, tgt);
8482907Scth (void) snprintf(tptr->is_name, sizeof (tptr->is_name),
8492907Scth "%s%d.%s%d", lun_name, lun, tgt_name, tgt);
8502907Scth
8512907Scth if (old->is_pretty) {
8522907Scth ptr = strrchr(tptr->is_pretty, '.');
8532907Scth if (ptr)
8542907Scth *ptr = '\0';
8552907Scth }
8562907Scth } else if (type == IODEV_IOPATH_LI) {
8572907Scth /* make new synthetic entry that is the LI */
8582907Scth /* set the id to the initiator number */
8592907Scth tptr->is_id.id = initiator;
8602907Scth (void) snprintf(tptr->is_id.tid, sizeof (tptr->is_id.tid),
8612907Scth "%s%d", initiator_name, initiator);
8622907Scth (void) snprintf(tptr->is_name, sizeof (tptr->is_name),
8632907Scth "%s%d.%s%d", lun_name, lun, initiator_name, initiator);
8642907Scth
8652907Scth if (old->is_pretty) {
8662907Scth ptr = strchr(tptr->is_pretty, '.');
8672907Scth if (ptr)
8682907Scth (void) snprintf(ptr + 1,
8692907Scth strlen(tptr->is_pretty) + 1,
8702907Scth "%s%d", initiator_name, initiator);
8712907Scth }
8722907Scth }
8732907Scth return (tptr);
8742907Scth }
8752907Scth
8762907Scth /*
8772907Scth * This is to get the original -X LI format (e.g. ssd1.fp0). When an LTI kstat
8782907Scth * is found - traverse the children looking for the same initiator and sum
8792907Scth * them up. Add an LI entry and delete all of the LTI entries with the same
8802907Scth * initiator.
8812907Scth */
8822907Scth static int
create_li_delete_lti(struct snapshot * ss,struct iodev_snapshot * list)8832907Scth create_li_delete_lti(struct snapshot *ss, struct iodev_snapshot *list)
8842907Scth {
8852907Scth struct iodev_snapshot *pos, *entry, *parent;
8862907Scth int lun, tgt, initiator;
8872907Scth char lun_name[KSTAT_STRLEN];
8882907Scth char tgt_name[KSTAT_STRLEN];
8892907Scth char initiator_name[KSTAT_STRLEN];
8902907Scth int err;
8912907Scth
8922907Scth for (entry = list; entry; entry = entry->is_next) {
8932907Scth if ((err = create_li_delete_lti(ss, entry->is_children)) != 0)
8942907Scth return (err);
8952907Scth
8962907Scth if (entry->is_type == IODEV_IOPATH_LTI) {
8972907Scth parent = find_parent(ss, entry);
8982907Scth if (get_lti(entry->is_name, lun_name, &lun,
8992907Scth tgt_name, &tgt, initiator_name, &initiator) != 1) {
9002907Scth return (1);
9012907Scth }
9022907Scth
9032907Scth pos = (parent == NULL) ? NULL : parent->is_children;
9042907Scth for (; pos; pos = pos->is_next) {
9052907Scth if (pos->is_id.id != -1 &&
9062907Scth pos->is_id.id == initiator &&
9072907Scth pos->is_type == IODEV_IOPATH_LI) {
9082907Scth /* found the same initiator */
9092907Scth update_target(pos, entry);
9102907Scth list_del(&parent->is_children, entry);
9112907Scth free_iodev(entry);
9122907Scth parent->is_nr_children--;
9132907Scth entry = pos;
9142907Scth break;
9152907Scth }
9162907Scth }
9172907Scth
9182907Scth if (!pos) {
9192907Scth /* make the first LI entry */
9202907Scth pos = make_extended_device(
9212907Scth IODEV_IOPATH_LI, entry);
9222907Scth update_target(pos, entry);
9232907Scth
9242907Scth if (parent) {
9252907Scth insert_before(&parent->is_children,
9262907Scth entry, pos);
9272907Scth list_del(&parent->is_children, entry);
9282907Scth free_iodev(entry);
9292907Scth } else {
9302907Scth insert_before(&ss->s_iodevs, entry,
9312907Scth pos);
9322907Scth list_del(&ss->s_iodevs, entry);
9332907Scth free_iodev(entry);
9342907Scth }
9352907Scth entry = pos;
9362907Scth }
9372907Scth }
9382907Scth }
9392907Scth return (0);
9402907Scth }
9412907Scth
9422907Scth /*
9432907Scth * We have the LTI kstat, now add an entry for the LT that sums up all of
9442907Scth * the LTI's with the same target(t).
9452907Scth */
9462907Scth static int
create_lt(struct snapshot * ss,struct iodev_snapshot * list)9472907Scth create_lt(struct snapshot *ss, struct iodev_snapshot *list)
9482907Scth {
9492907Scth struct iodev_snapshot *entry, *parent, *pos;
9502907Scth int lun, tgt, initiator;
9512907Scth char lun_name[KSTAT_STRLEN];
9522907Scth char tgt_name[KSTAT_STRLEN];
9532907Scth char initiator_name[KSTAT_STRLEN];
9542907Scth int err;
9552907Scth
9562907Scth for (entry = list; entry; entry = entry->is_next) {
9572907Scth if ((err = create_lt(ss, entry->is_children)) != 0)
9582907Scth return (err);
9592907Scth
9602907Scth if (entry->is_type == IODEV_IOPATH_LTI) {
9612907Scth parent = find_parent(ss, entry);
9622907Scth if (get_lti(entry->is_name, lun_name, &lun,
9632907Scth tgt_name, &tgt, initiator_name, &initiator) != 1) {
9642907Scth return (1);
9652907Scth }
9662907Scth
9672907Scth pos = (parent == NULL) ? NULL : parent->is_children;
9682907Scth for (; pos; pos = pos->is_next) {
9692907Scth if (pos->is_id.id != -1 &&
9702907Scth pos->is_id.id == tgt &&
9712907Scth pos->is_type == IODEV_IOPATH_LT) {
9722907Scth /* found the same target */
9732907Scth update_target(pos, entry);
9742907Scth break;
9752907Scth }
9762907Scth }
9772907Scth
9782907Scth if (!pos) {
9792907Scth pos = make_extended_device(
9802907Scth IODEV_IOPATH_LT, entry);
9812907Scth update_target(pos, entry);
9822907Scth
9832907Scth if (parent) {
9842907Scth insert_before(&parent->is_children,
9852907Scth entry, pos);
9862907Scth parent->is_nr_children++;
9872907Scth } else {
9882907Scth insert_before(&ss->s_iodevs,
9892907Scth entry, pos);
9902907Scth }
9912907Scth }
9922907Scth }
9932907Scth }
9942907Scth return (0);
9952907Scth }
9962907Scth
9972907Scth /* Find the longest is_name field to aid formatting of output */
9982907Scth static int
iodevs_is_name_maxlen(struct iodev_snapshot * list)9992907Scth iodevs_is_name_maxlen(struct iodev_snapshot *list)
10002907Scth {
10012907Scth struct iodev_snapshot *entry;
10022907Scth int max = 0, cmax, len;
10032907Scth
10042907Scth for (entry = list; entry; entry = entry->is_next) {
10052907Scth cmax = iodevs_is_name_maxlen(entry->is_children);
10062907Scth max = (cmax > max) ? cmax : max;
10072907Scth len = strlen(entry->is_name);
10082907Scth max = (len > max) ? len : max;
10092907Scth }
10102907Scth return (max);
10110Sstevel@tonic-gate }
10120Sstevel@tonic-gate
10130Sstevel@tonic-gate int
acquire_iodevs(struct snapshot * ss,kstat_ctl_t * kc,struct iodev_filter * df)10140Sstevel@tonic-gate acquire_iodevs(struct snapshot *ss, kstat_ctl_t *kc, struct iodev_filter *df)
10150Sstevel@tonic-gate {
10162907Scth kstat_t *ksp;
10172907Scth struct iodev_snapshot *pos;
10182907Scth struct iodev_snapshot *list = NULL;
10192907Scth int err = 0;
10200Sstevel@tonic-gate
10210Sstevel@tonic-gate ss->s_nr_iodevs = 0;
10222907Scth ss->s_iodevs_is_name_maxlen = 0;
10230Sstevel@tonic-gate
10242723Scth /*
10252723Scth * Call cleanup_iodevs_snapshot() so that a cache miss in
10262723Scth * lookup_ks_name() will result in a fresh snapshot.
10272723Scth */
10282723Scth cleanup_iodevs_snapshot();
10292723Scth
10300Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
10310Sstevel@tonic-gate enum iodev_type type;
10320Sstevel@tonic-gate
10330Sstevel@tonic-gate if (ksp->ks_type != KSTAT_TYPE_IO)
10340Sstevel@tonic-gate continue;
10350Sstevel@tonic-gate
10360Sstevel@tonic-gate /* e.g. "usb_byte_count" is not handled */
10370Sstevel@tonic-gate if ((type = get_iodev_type(ksp)) == IODEV_UNKNOWN)
10380Sstevel@tonic-gate continue;
10390Sstevel@tonic-gate
10400Sstevel@tonic-gate if (df && !(type & df->if_allowed_types))
10410Sstevel@tonic-gate continue;
10420Sstevel@tonic-gate
10430Sstevel@tonic-gate if ((pos = malloc(sizeof (struct iodev_snapshot))) == NULL) {
10440Sstevel@tonic-gate err = errno;
10450Sstevel@tonic-gate goto out;
10460Sstevel@tonic-gate }
10470Sstevel@tonic-gate
10480Sstevel@tonic-gate (void) memset(pos, 0, sizeof (struct iodev_snapshot));
10490Sstevel@tonic-gate
10500Sstevel@tonic-gate pos->is_type = type;
10510Sstevel@tonic-gate pos->is_crtime = ksp->ks_crtime;
10520Sstevel@tonic-gate pos->is_snaptime = ksp->ks_snaptime;
10530Sstevel@tonic-gate pos->is_id.id = IODEV_NO_ID;
10540Sstevel@tonic-gate pos->is_parent_id.id = IODEV_NO_ID;
10550Sstevel@tonic-gate pos->is_ksp = ksp;
10560Sstevel@tonic-gate pos->is_instance = ksp->ks_instance;
10570Sstevel@tonic-gate
10580Sstevel@tonic-gate (void) strlcpy(pos->is_module, ksp->ks_module, KSTAT_STRLEN);
10590Sstevel@tonic-gate (void) strlcpy(pos->is_name, ksp->ks_name, KSTAT_STRLEN);
10600Sstevel@tonic-gate get_pretty_name(ss->s_types, pos, kc);
10610Sstevel@tonic-gate
10620Sstevel@tonic-gate /*
10630Sstevel@tonic-gate * We must insert in sort order so e.g. vmstat -l
10640Sstevel@tonic-gate * chooses in order.
10650Sstevel@tonic-gate */
10660Sstevel@tonic-gate insert_into(&list, pos);
10670Sstevel@tonic-gate }
10680Sstevel@tonic-gate
10690Sstevel@tonic-gate choose_iodevs(ss, list, df);
10700Sstevel@tonic-gate
10710Sstevel@tonic-gate /* before acquire_stats for collate_controller()'s benefit */
10720Sstevel@tonic-gate if (ss->s_types & SNAP_IODEV_ERRORS) {
10730Sstevel@tonic-gate if ((err = acquire_iodev_errors(ss, kc)) != 0)
10740Sstevel@tonic-gate goto out;
10750Sstevel@tonic-gate }
10760Sstevel@tonic-gate
10770Sstevel@tonic-gate if ((err = acquire_iodev_stats(ss->s_iodevs, kc)) != 0)
10780Sstevel@tonic-gate goto out;
10790Sstevel@tonic-gate
10802907Scth if (ss->s_types & SNAP_IOPATHS_LTI) {
10812907Scth /*
10822907Scth * -Y: kstats are LTI, need to create a synthetic LT
10832907Scth * for -Y output.
10842907Scth */
10852907Scth if ((err = create_lt(ss, ss->s_iodevs)) != 0) {
10862907Scth return (err);
10872907Scth }
10882907Scth }
10892907Scth if (ss->s_types & SNAP_IOPATHS_LI) {
10902907Scth /*
10912907Scth * -X: kstats are LTI, need to create a synthetic LI and
10922907Scth * delete the LTI for -X output
10932907Scth */
10942907Scth if ((err = create_li_delete_lti(ss, ss->s_iodevs)) != 0) {
10952907Scth return (err);
10962907Scth }
10972907Scth }
10982907Scth
10992907Scth /* determine width of longest is_name */
11002907Scth ss->s_iodevs_is_name_maxlen = iodevs_is_name_maxlen(ss->s_iodevs);
11012907Scth
11020Sstevel@tonic-gate err = 0;
11030Sstevel@tonic-gate out:
11040Sstevel@tonic-gate return (err);
11050Sstevel@tonic-gate }
11060Sstevel@tonic-gate
11070Sstevel@tonic-gate void
free_iodev(struct iodev_snapshot * iodev)11080Sstevel@tonic-gate free_iodev(struct iodev_snapshot *iodev)
11090Sstevel@tonic-gate {
11100Sstevel@tonic-gate while (iodev->is_children) {
11110Sstevel@tonic-gate struct iodev_snapshot *tmp = iodev->is_children;
11120Sstevel@tonic-gate iodev->is_children = iodev->is_children->is_next;
11130Sstevel@tonic-gate free_iodev(tmp);
11140Sstevel@tonic-gate }
11150Sstevel@tonic-gate
11165957Swroche if (iodev->avl_list) {
11175957Swroche avl_remove(iodev->avl_list, iodev);
11185957Swroche if (avl_numnodes(iodev->avl_list) == 0) {
11195957Swroche avl_destroy(iodev->avl_list);
11205957Swroche free(iodev->avl_list);
11215957Swroche }
11225957Swroche }
11235957Swroche
11240Sstevel@tonic-gate free(iodev->is_errors.ks_data);
11250Sstevel@tonic-gate free(iodev->is_pretty);
11260Sstevel@tonic-gate free(iodev->is_dname);
11270Sstevel@tonic-gate free(iodev->is_devid);
11280Sstevel@tonic-gate free(iodev);
11290Sstevel@tonic-gate }
1130