diff options
author | cth <none@none> | 2006-10-12 10:18:45 -0700 |
---|---|---|
committer | cth <none@none> | 2006-10-12 10:18:45 -0700 |
commit | 37fbbce5257519d600faa3d23d464b42b71c1605 (patch) | |
tree | c0f2a50b50b97964740ab5a7586f74bd87560678 /usr/src/cmd/stat/common/dsr.c | |
parent | 2bc4236aac4fe3a3ba80139bc39ee9f1e356ab55 (diff) | |
download | illumos-gate-37fbbce5257519d600faa3d23d464b42b71c1605.tar.gz |
PSARC 2005/574 MPxIO iostat improvements
4261677 iostat -x shows extra output
6316660 device name gets truncated after 9 chars with iostat -xX option.
6318308 extend support in mpxio and iostat to show I/T/L based path stats
Diffstat (limited to 'usr/src/cmd/stat/common/dsr.c')
-rw-r--r-- | usr/src/cmd/stat/common/dsr.c | 210 |
1 files changed, 154 insertions, 56 deletions
diff --git a/usr/src/cmd/stat/common/dsr.c b/usr/src/cmd/stat/common/dsr.c index b25637a73b..5d6f51f835 100644 --- a/usr/src/cmd/stat/common/dsr.c +++ b/usr/src/cmd/stat/common/dsr.c @@ -49,30 +49,38 @@ #include <limits.h> #include <stdlib.h> #include <string.h> +#include <strings.h> #include <unistd.h> #include <errno.h> #include <devid.h> +#include <sys/scsi/adapters/scsi_vhci.h> #include "dsr.h" #include "statcommon.h" -/* disk/tape info */ -static di_node_t di_root; /* for devid */ -static di_dim_t di_dim; /* for /dev names */ +/* where we get kstat name translation information from */ +static di_node_t di_root; /* from di_init: for devid */ +static di_dim_t di_dim; /* from di_dim_init: for /dev names */ +static int scsi_vhci_fd = -1; /* from scsi_vhci: for mpxio path */ + +/* disk/tape/misc info */ typedef struct { char *minor_name; int minor_isdisk; } minor_match_t; static minor_match_t mm_disk = {"a", 1}; static minor_match_t mm_tape = {"", 0}; +static minor_match_t mm_misc = {"0", 0}; static char md_minor_name[MAXPATHLEN]; static minor_match_t mm_md = {md_minor_name, 0}; -static minor_match_t *mma_disk_tape[] = {&mm_disk, &mm_tape, NULL}; +static minor_match_t *mma_disk_tape_misc[] = + {&mm_disk, &mm_tape, &mm_misc, NULL}; static minor_match_t *mma_md[] = {&mm_md, NULL}; static char *mdsetno2name(int setno); #define DISKLIST_MOD 256 /* ^2 instunit mod hash */ static disk_list_t *disklist[DISKLIST_MOD]; + /* nfs info */ extern kstat_ctl_t *kc; extern mnt_t *nfs; @@ -108,8 +116,8 @@ cleanup_iodevs_snapshot() * name is the same as public name: the caller will just use kstat name. */ static int -drvinstunit2dev(char *driver, int instunit, - char **devpathp, char **adevpathp, char **devidp, int *isdiskp) +drvinstunitpart2dev(char *driver, int instunit, char *part, + char **devpathp, char **adevpathp, char **devidp) { int instance; minor_match_t **mma; @@ -123,7 +131,6 @@ drvinstunit2dev(char *driver, int instunit, char *devicespath; di_node_t node; - /* setup "no result" return values */ if (devpathp) *devpathp = NULL; @@ -131,8 +138,6 @@ drvinstunit2dev(char *driver, int instunit, *adevpathp = NULL; if (devidp) *devidp = NULL; - if (isdiskp) - *isdiskp = 0; /* take <driver><instance><minor_name> snapshot if not established */ if (di_dim == NULL) { @@ -173,14 +178,18 @@ drvinstunit2dev(char *driver, int instunit, "%d,%d,blk", mdsetno, instunit); } else { instance = instunit; - mma = mma_disk_tape; /* disk/tape minors */ + mma = mma_disk_tape_misc; /* disk/tape/misc minors */ } - /* Try to find a minor_match that works */ - for (mm = *mma++; mm; mm = *mma++) { - if ((devpath = di_dim_path_dev(di_dim, - driver, instance, mm->minor_name)) != NULL) - break; + if (part) { + devpath = di_dim_path_dev(di_dim, driver, instance, part); + } else { + /* Try to find a minor_match that works */ + for (mm = *mma++; mm; mm = *mma++) { + if ((devpath = di_dim_path_dev(di_dim, + driver, instance, mm->minor_name)) != NULL) + break; + } } if (devpath == NULL) return (0); @@ -193,10 +202,11 @@ drvinstunit2dev(char *driver, int instunit, *devpathp = safe_strdup(devpath); if (adevpathp) { /* abbreviated devpath */ - if (mm->minor_isdisk) { + if ((part == NULL) && mm->minor_isdisk) { /* - * For disks we return the last component (with - * trailing "s#" or "p#" stripped off for disks). + * For disk kstats without a partition we return the + * last component with trailing "s#" or "p#" stripped + * off (i.e. partition/slice information is removed). * For example for devpath of "/dev/dsk/c0t0d0s0" the * abbreviated devpath would be "c0t0d0". */ @@ -249,7 +259,7 @@ drvinstunit2dev(char *driver, int instunit, } if (devidp) { /* lookup the devid */ - /* take snapshots if not established */ + /* take snapshot if not established */ if (di_root == DI_NODE_NIL) { di_root = di_init("/", DINFOCACHE); } @@ -270,17 +280,58 @@ drvinstunit2dev(char *driver, int instunit, } } - if (isdiskp) - *isdiskp = mm->minor_isdisk; - free(devpath); return (1); /* success */ } /* - * Find/create a disk_list entry for "<driver><instunit>" given a kstat name. - * The basic format of a kstat name is "<driver><instunit>,<partition>". The - * <instunit> is a base10 number, and the ",<partition>" part is optional. + * Do <pid> to 'target-port' translation + */ +static int +drvpid2port(uint_t pid, char **target_portp) +{ + sv_iocdata_t ioc; + char target_port[MAXNAMELEN]; + + /* setup "no result" return values */ + *target_portp = NULL; + + /* open scsi_vhci if not already done */ + if (scsi_vhci_fd == -1) { + scsi_vhci_fd = open("/devices/scsi_vhci:devctl", O_RDONLY); + if (scsi_vhci_fd == -1) + return (0); /* failure */ + } + + /* + * Perform ioctl for <pid> -> 'target-port' translation. + * + * NOTE: it is legimite for this ioctl to fail for transports + * that use mpxio, but don't set a 'target-port' pathinfo property. + * On failure we return the the "<pid>" as the target port string. + */ + bzero(&ioc, sizeof (sv_iocdata_t)); + ioc.buf_elem = pid; + ioc.addr = target_port; + if (ioctl(scsi_vhci_fd, SCSI_VHCI_GET_TARGET_LONGNAME, &ioc) < 0) { + (void) snprintf(target_port, sizeof (target_port), "%d", pid); + } + + *target_portp = safe_strdup(target_port); + return (1); /* success */ +} + +/* + * Find/create a disk_list entry for given a kstat name. + * The basic format of a kstat name is + * + * "<driver><instunit>.<pid>.<phci-driver><instance>,<partition>". + * + * The <instunit> is a decimal number. The ".<pid>.<phci-driver><instance>", + * which describes mpxio path stat information, and ",<partition>" parts are + * optional. The <pid> consists of the letter 't' followed by a decimal number. + * When available, we use the <pid> to find the 'target-port' via ioctls to + * the scsi_vhci driver. * * NOTE: In the case of non-local metadevices, the format of "<driver>" in * a kstat name is acutally "<setno>/md". @@ -288,75 +339,122 @@ drvinstunit2dev(char *driver, int instunit, disk_list_t * lookup_ks_name(char *ks_name, int want_devid) { + char *pidp; /* ".<pid>... */ + char *part; /* ",partition... */ + char *initiator; /* ".<phci-driver>... */ char *p; int len; - char driver[MAXNAMELEN]; + char driver[KSTAT_STRLEN]; int instunit; disk_list_t **dlhp; /* disklist head */ disk_list_t *entry; - char *devpath; + char *devpath = NULL; char *adevpath = NULL; char *devid = NULL; - int isdisk; + int pid; + char *target_port = NULL; + char portform[MAXPATHLEN]; - /* - * Extract <driver> and <instunit> from kstat name. - * Filter out illegal forms (like all digits). - */ + /* Filter out illegal forms (like all digits). */ if ((ks_name == NULL) || (*ks_name == 0) || (strspn(ks_name, "0123456789") == strlen(ks_name))) - return (NULL); - p = strrchr(ks_name, ','); /* start of ",partition" */ + goto fail; + + /* parse ks_name to create new entry */ + pidp = strchr(ks_name, '.'); /* start of ".<pid>" */ + initiator = strrchr(ks_name, '.'); /* start of ".<pHCI-driver>" */ + if (pidp && (pidp == initiator)) /* can't have same start */ + goto fail; + + part = strchr(ks_name, ','); /* start of ",<partition>" */ + p = strchr(ks_name, ':'); /* start of ":<partition>" */ + if (part && p) + goto fail; /* can't have both */ + if (p) + part = p; + if (part && pidp) + goto fail; /* <pid> and partition: bad */ + + p = part ? part : pidp; if (p == NULL) p = &ks_name[strlen(ks_name) - 1]; /* last char */ else - p--; /* before ",partition" */ + p--; /* before ',' or '.' */ while ((p >= ks_name) && isdigit(*p)) p--; /* backwards over digits */ p++; /* start of instunit */ - if ((*p == '\0') || (*p == ',')) - return (NULL); /* no <instunit> */ + if ((*p == '\0') || (*p == ',') || (*p == '.') || (*p == ':')) + goto fail; /* no <instunit> */ len = p - ks_name; (void) strncpy(driver, ks_name, len); driver[len] = '\0'; instunit = atoi(p); + if (part) + part++; /* skip ',' */ - /* hash and search for existing disklist entry */ + /* hash by instunit and search for existing entry */ dlhp = &disklist[instunit & (DISKLIST_MOD - 1)]; for (entry = *dlhp; entry; entry = entry->next) { - if ((strcmp(entry->dtype, driver) == 0) && - (entry->dnum == instunit)) { + if (strcmp(entry->ks_name, ks_name) == 0) { return (entry); } } - /* not found, try to get dev information */ - if (drvinstunit2dev(driver, instunit, &devpath, &adevpath, - want_devid ? &devid : NULL, &isdisk) == 0) { - return (NULL); + /* not found, translate kstat_name components and create new entry */ + + /* translate kstat_name dev information */ + if (drvinstunitpart2dev(driver, instunit, part, + &devpath, &adevpath, want_devid ? &devid : NULL) == 0) { + goto fail; } - /* and make a new disklist entry ... */ + /* parse and translate path information */ + if (pidp) { + /* parse path information: ".t#.<phci-driver><instance>" */ + pidp++; /* skip '.' */ + initiator++; /* skip '.' */ + if ((*pidp != 't') || !isdigit(pidp[1])) + goto fail; /* not ".t#" */ + pid = atoi(&pidp[1]); + + /* translate <pid> to 'target-port' */ + if (drvpid2port(pid, &target_port) == 0) + goto fail; + + /* Establish 'target-port' form. */ + (void) snprintf(portform, sizeof (portform), + "%s.t%s.%s", adevpath, target_port, initiator); + free(target_port); + free(adevpath); + adevpath = strdup(portform); + } + + /* make a new entry ... */ entry = safe_alloc(sizeof (disk_list_t)); - entry->dtype = safe_strdup(driver); - entry->dnum = instunit; + entry->ks_name = safe_strdup(ks_name); entry->dname = devpath; entry->dsk = adevpath; entry->devidstr = devid; - entry->flags = 0; - if (isdisk) { - entry->flags |= SLICES_OK; -#if defined(__i386) - entry->flags |= PARTITIONS_OK; -#endif - } - entry->seen = 0; - /* add new entry to head of instunit hashed list */ +#ifdef DEBUG + (void) printf("lookup_ks_name: new: %s %s\n", + ks_name, entry->dsk ? entry->dsk : "NULL"); +#endif /* DEBUG */ + + /* add new entry to head of hashed list */ entry->next = *dlhp; *dlhp = entry; return (entry); + +fail: + free(devpath); + free(adevpath); + free(devid); +#ifdef DEBUG + (void) printf("lookup_ks_name: failed: %s\n", ks_name); +#endif /* DEBUG */ + return (NULL); } /* |