17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 54e78ab0bScth * Common Development and Distribution License (the "License"). 64e78ab0bScth * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 224e78ab0bScth * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <sys/stat.h> 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate /* 327c478bd9Sstevel@tonic-gate * Dependent on types.h, but not including it... 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate #include <stdio.h> 357c478bd9Sstevel@tonic-gate #include <sys/types.h> 367c478bd9Sstevel@tonic-gate #include <sys/dkio.h> 377c478bd9Sstevel@tonic-gate #include <sys/dktp/fdisk.h> 387c478bd9Sstevel@tonic-gate #include <sys/mnttab.h> 397c478bd9Sstevel@tonic-gate #include <sys/mntent.h> 407c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 417c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 427c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 437c478bd9Sstevel@tonic-gate #include <nfs/nfs.h> 447c478bd9Sstevel@tonic-gate #include <nfs/nfs_clnt.h> 457c478bd9Sstevel@tonic-gate #include <kstat.h> 467c478bd9Sstevel@tonic-gate #include <ctype.h> 477c478bd9Sstevel@tonic-gate #include <dirent.h> 487c478bd9Sstevel@tonic-gate #include <libdevinfo.h> 497c478bd9Sstevel@tonic-gate #include <limits.h> 507c478bd9Sstevel@tonic-gate #include <stdlib.h> 517c478bd9Sstevel@tonic-gate #include <string.h> 52*37fbbce5Scth #include <strings.h> 537c478bd9Sstevel@tonic-gate #include <unistd.h> 547c478bd9Sstevel@tonic-gate #include <errno.h> 557c478bd9Sstevel@tonic-gate #include <devid.h> 56*37fbbce5Scth #include <sys/scsi/adapters/scsi_vhci.h> 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #include "dsr.h" 597c478bd9Sstevel@tonic-gate #include "statcommon.h" 607c478bd9Sstevel@tonic-gate 61*37fbbce5Scth /* where we get kstat name translation information from */ 62*37fbbce5Scth static di_node_t di_root; /* from di_init: for devid */ 63*37fbbce5Scth static di_dim_t di_dim; /* from di_dim_init: for /dev names */ 64*37fbbce5Scth static int scsi_vhci_fd = -1; /* from scsi_vhci: for mpxio path */ 65*37fbbce5Scth 66*37fbbce5Scth /* disk/tape/misc info */ 67a08731ecScth typedef struct { 68a08731ecScth char *minor_name; 69a08731ecScth int minor_isdisk; 70a08731ecScth } minor_match_t; 71a08731ecScth static minor_match_t mm_disk = {"a", 1}; 72a08731ecScth static minor_match_t mm_tape = {"", 0}; 73*37fbbce5Scth static minor_match_t mm_misc = {"0", 0}; 74a08731ecScth static char md_minor_name[MAXPATHLEN]; 75a08731ecScth static minor_match_t mm_md = {md_minor_name, 0}; 76*37fbbce5Scth static minor_match_t *mma_disk_tape_misc[] = 77*37fbbce5Scth {&mm_disk, &mm_tape, &mm_misc, NULL}; 78a08731ecScth static minor_match_t *mma_md[] = {&mm_md, NULL}; 79a08731ecScth static char *mdsetno2name(int setno); 80a08731ecScth #define DISKLIST_MOD 256 /* ^2 instunit mod hash */ 81a08731ecScth static disk_list_t *disklist[DISKLIST_MOD]; 827c478bd9Sstevel@tonic-gate 83*37fbbce5Scth 84a08731ecScth /* nfs info */ 85a08731ecScth extern kstat_ctl_t *kc; 86a08731ecScth extern mnt_t *nfs; 87a08731ecScth static int nfs_tried; 887c478bd9Sstevel@tonic-gate static char *get_nfs_by_minor(uint_t); 897c478bd9Sstevel@tonic-gate static char *cur_hostname(uint_t, kstat_ctl_t *); 907c478bd9Sstevel@tonic-gate static char *cur_special(char *, char *); 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* 93a08731ecScth * Clear the snapshot so a cache miss in lookup_ks_name() will cause a fresh 94a08731ecScth * snapshot in drvinstunit2dev(). 957c478bd9Sstevel@tonic-gate */ 96a08731ecScth void 97a08731ecScth cleanup_iodevs_snapshot() 987c478bd9Sstevel@tonic-gate { 99a08731ecScth if (di_dim) { 100a08731ecScth di_dim_fini(di_dim); 101a08731ecScth di_dim = NULL; 102a08731ecScth } 1037c478bd9Sstevel@tonic-gate 104a08731ecScth if (di_root) { 105a08731ecScth di_fini(di_root); 106a08731ecScth di_root = DI_NODE_NIL; 107a08731ecScth } 108a08731ecScth 109a08731ecScth nfs_tried = 0; 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate /* 113a08731ecScth * Find information for (driver, instunit) device: return zero on failure. 1147c478bd9Sstevel@tonic-gate * 115a08731ecScth * NOTE: Failure of drvinstunit2dev works out OK for the caller if the kstat 116a08731ecScth * name is the same as public name: the caller will just use kstat name. 1177c478bd9Sstevel@tonic-gate */ 1187c478bd9Sstevel@tonic-gate static int 119*37fbbce5Scth drvinstunitpart2dev(char *driver, int instunit, char *part, 120*37fbbce5Scth char **devpathp, char **adevpathp, char **devidp) 1217c478bd9Sstevel@tonic-gate { 122a08731ecScth int instance; 123a08731ecScth minor_match_t **mma; 124a08731ecScth minor_match_t *mm; 125a08731ecScth char *devpath; 126a08731ecScth char *devid; 127a08731ecScth char *a, *s; 128a08731ecScth int mdsetno; 129a08731ecScth char *mdsetname = NULL; 130a08731ecScth char amdsetname[MAXPATHLEN]; 131a08731ecScth char *devicespath; 132a08731ecScth di_node_t node; 133a08731ecScth 134a08731ecScth /* setup "no result" return values */ 135a08731ecScth if (devpathp) 136a08731ecScth *devpathp = NULL; 137a08731ecScth if (adevpathp) 138a08731ecScth *adevpathp = NULL; 139a08731ecScth if (devidp) 140a08731ecScth *devidp = NULL; 141a08731ecScth 142a08731ecScth /* take <driver><instance><minor_name> snapshot if not established */ 143a08731ecScth if (di_dim == NULL) { 144a08731ecScth di_dim = di_dim_init(); 145a08731ecScth if (di_dim == NULL) 1467c478bd9Sstevel@tonic-gate return (0); 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate /* 150a08731ecScth * Determine if 'instunit' is an 'instance' or 'unit' based on the 151a08731ecScth * 'driver'. The current code only detects 'md' metadevice 'units', 152a08731ecScth * and defaults to 'instance' for everything else. 153a08731ecScth * 154a08731ecScth * For a metadevice, 'driver' is either "md" or "<setno>/md". 1557c478bd9Sstevel@tonic-gate */ 156a08731ecScth s = strstr(driver, "/md"); 157a08731ecScth if ((strcmp(driver, "md") == 0) || 158a08731ecScth (s && isdigit(*driver) && (strcmp(s, "/md") == 0))) { 1597c478bd9Sstevel@tonic-gate /* 160a08731ecScth * "md" unit: Special case translation of "md" kstat names. 161a08731ecScth * For the local set the kstat name is "md<unit>", and for 162a08731ecScth * a shared set the kstat name is "<setno>/md<unit>": we map 163a08731ecScth * these to the minor paths "/pseudo/md@0:<unit>,blk" and 164a08731ecScth * "/pseudo/md@0:<set>,<unit>,blk" respectively. 1657c478bd9Sstevel@tonic-gate */ 166a08731ecScth if (isdigit(*driver)) { 167a08731ecScth mdsetno = atoi(driver); 168a08731ecScth 169a08731ecScth /* convert setno to setname */ 170a08731ecScth mdsetname = mdsetno2name(mdsetno); 171a08731ecScth } else 172a08731ecScth mdsetno = 0; 173a08731ecScth 174a08731ecScth driver = "md"; 175a08731ecScth instance = 0; 176a08731ecScth mma = mma_md; /* metadevice dynamic minor */ 177a08731ecScth (void) snprintf(md_minor_name, sizeof (md_minor_name), 178a08731ecScth "%d,%d,blk", mdsetno, instunit); 179a08731ecScth } else { 180a08731ecScth instance = instunit; 181*37fbbce5Scth mma = mma_disk_tape_misc; /* disk/tape/misc minors */ 182a08731ecScth } 183a08731ecScth 184*37fbbce5Scth if (part) { 185*37fbbce5Scth devpath = di_dim_path_dev(di_dim, driver, instance, part); 186*37fbbce5Scth } else { 187a08731ecScth /* Try to find a minor_match that works */ 188a08731ecScth for (mm = *mma++; mm; mm = *mma++) { 189a08731ecScth if ((devpath = di_dim_path_dev(di_dim, 190a08731ecScth driver, instance, mm->minor_name)) != NULL) 191a08731ecScth break; 192a08731ecScth } 193*37fbbce5Scth } 194a08731ecScth if (devpath == NULL) 195a08731ecScth return (0); 196a08731ecScth 197a08731ecScth /* 198a08731ecScth * At this point we have a devpath result. Return the information about 199a08731ecScth * the result that the caller is asking for. 200a08731ecScth */ 201a08731ecScth if (devpathp) /* devpath */ 202a08731ecScth *devpathp = safe_strdup(devpath); 203a08731ecScth 204a08731ecScth if (adevpathp) { /* abbreviated devpath */ 205*37fbbce5Scth if ((part == NULL) && mm->minor_isdisk) { 206a08731ecScth /* 207*37fbbce5Scth * For disk kstats without a partition we return the 208*37fbbce5Scth * last component with trailing "s#" or "p#" stripped 209*37fbbce5Scth * off (i.e. partition/slice information is removed). 210a08731ecScth * For example for devpath of "/dev/dsk/c0t0d0s0" the 211a08731ecScth * abbreviated devpath would be "c0t0d0". 212a08731ecScth */ 213a08731ecScth a = strrchr(devpath, '/'); 214a08731ecScth if (a == NULL) { 215a08731ecScth free(devpath); 216a08731ecScth return (0); 217a08731ecScth } 218a08731ecScth a++; 219a08731ecScth s = strrchr(a, 's'); 220a08731ecScth if (s == NULL) { 221a08731ecScth s = strrchr(a, 'p'); 222a08731ecScth if (s == NULL) { 223a08731ecScth free(devpath); 224a08731ecScth return (0); 225a08731ecScth } 226a08731ecScth } 227a08731ecScth /* don't include slice information in devpath */ 228a08731ecScth *s = '\0'; 229a08731ecScth } else { 230a08731ecScth /* 231a08731ecScth * remove "/dev/", and "/dsk/", from 'devpath' (like 232a08731ecScth * "/dev/md/dsk/d0") to form the abbreviated devpath 233a08731ecScth * (like "md/d0"). 234a08731ecScth */ 235a08731ecScth if ((s = strstr(devpath, "/dev/")) != NULL) 236a08731ecScth (void) strcpy(s + 1, s + 5); 237a08731ecScth if ((s = strstr(devpath, "/dsk/")) != NULL) 238a08731ecScth (void) strcpy(s + 1, s + 5); 239a08731ecScth 240a08731ecScth /* 241a08731ecScth * If we have an mdsetname, convert abbreviated setno 242a08731ecScth * notation (like "md/shared/1/d0" to abbreviated 243a08731ecScth * setname notation (like "md/red/d0"). 244a08731ecScth */ 245a08731ecScth if (mdsetname) { 246a08731ecScth a = strrchr(devpath, '/'); 247a08731ecScth (void) snprintf(amdsetname, sizeof (amdsetname), 248a08731ecScth "md/%s%s", mdsetname, a); 249a08731ecScth free(mdsetname); 250a08731ecScth a = amdsetname; 251a08731ecScth } else { 252a08731ecScth if (*devpath == '/') 253a08731ecScth a = devpath + 1; 2547c478bd9Sstevel@tonic-gate else 255a08731ecScth a = devpath; 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate } 258a08731ecScth *adevpathp = safe_strdup(a); 259a08731ecScth } 260a08731ecScth 261a08731ecScth if (devidp) { /* lookup the devid */ 262*37fbbce5Scth /* take snapshot if not established */ 263a08731ecScth if (di_root == DI_NODE_NIL) { 264a08731ecScth di_root = di_init("/", DINFOCACHE); 265a08731ecScth } 266a08731ecScth if (di_root) { 267a08731ecScth /* get path to /devices devinfo node */ 268a08731ecScth devicespath = di_dim_path_devices(di_dim, 269a08731ecScth driver, instance, NULL); 270a08731ecScth if (devicespath) { 271a08731ecScth /* find the node in the snapshot */ 272a08731ecScth node = di_lookup_node(di_root, devicespath); 273a08731ecScth free(devicespath); 274a08731ecScth 275a08731ecScth /* and lookup devid property on the node */ 276a08731ecScth if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, 277a08731ecScth DEVID_PROP_NAME, &devid) != -1) 278a08731ecScth *devidp = devid; 279a08731ecScth } 280a08731ecScth } 281a08731ecScth } 282a08731ecScth 283a08731ecScth free(devpath); 284a08731ecScth return (1); /* success */ 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate /* 288*37fbbce5Scth * Do <pid> to 'target-port' translation 289*37fbbce5Scth */ 290*37fbbce5Scth static int 291*37fbbce5Scth drvpid2port(uint_t pid, char **target_portp) 292*37fbbce5Scth { 293*37fbbce5Scth sv_iocdata_t ioc; 294*37fbbce5Scth char target_port[MAXNAMELEN]; 295*37fbbce5Scth 296*37fbbce5Scth /* setup "no result" return values */ 297*37fbbce5Scth *target_portp = NULL; 298*37fbbce5Scth 299*37fbbce5Scth /* open scsi_vhci if not already done */ 300*37fbbce5Scth if (scsi_vhci_fd == -1) { 301*37fbbce5Scth scsi_vhci_fd = open("/devices/scsi_vhci:devctl", O_RDONLY); 302*37fbbce5Scth if (scsi_vhci_fd == -1) 303*37fbbce5Scth return (0); /* failure */ 304*37fbbce5Scth } 305*37fbbce5Scth 306*37fbbce5Scth /* 307*37fbbce5Scth * Perform ioctl for <pid> -> 'target-port' translation. 308*37fbbce5Scth * 309*37fbbce5Scth * NOTE: it is legimite for this ioctl to fail for transports 310*37fbbce5Scth * that use mpxio, but don't set a 'target-port' pathinfo property. 311*37fbbce5Scth * On failure we return the the "<pid>" as the target port string. 312*37fbbce5Scth */ 313*37fbbce5Scth bzero(&ioc, sizeof (sv_iocdata_t)); 314*37fbbce5Scth ioc.buf_elem = pid; 315*37fbbce5Scth ioc.addr = target_port; 316*37fbbce5Scth if (ioctl(scsi_vhci_fd, SCSI_VHCI_GET_TARGET_LONGNAME, &ioc) < 0) { 317*37fbbce5Scth (void) snprintf(target_port, sizeof (target_port), "%d", pid); 318*37fbbce5Scth } 319*37fbbce5Scth 320*37fbbce5Scth *target_portp = safe_strdup(target_port); 321*37fbbce5Scth return (1); /* success */ 322*37fbbce5Scth } 323*37fbbce5Scth 324*37fbbce5Scth /* 325*37fbbce5Scth * Find/create a disk_list entry for given a kstat name. 326*37fbbce5Scth * The basic format of a kstat name is 327*37fbbce5Scth * 328*37fbbce5Scth * "<driver><instunit>.<pid>.<phci-driver><instance>,<partition>". 329*37fbbce5Scth * 330*37fbbce5Scth * The <instunit> is a decimal number. The ".<pid>.<phci-driver><instance>", 331*37fbbce5Scth * which describes mpxio path stat information, and ",<partition>" parts are 332*37fbbce5Scth * optional. The <pid> consists of the letter 't' followed by a decimal number. 333*37fbbce5Scth * When available, we use the <pid> to find the 'target-port' via ioctls to 334*37fbbce5Scth * the scsi_vhci driver. 335a08731ecScth * 336a08731ecScth * NOTE: In the case of non-local metadevices, the format of "<driver>" in 337a08731ecScth * a kstat name is acutally "<setno>/md". 3387c478bd9Sstevel@tonic-gate */ 339a08731ecScth disk_list_t * 340a08731ecScth lookup_ks_name(char *ks_name, int want_devid) 3417c478bd9Sstevel@tonic-gate { 342*37fbbce5Scth char *pidp; /* ".<pid>... */ 343*37fbbce5Scth char *part; /* ",partition... */ 344*37fbbce5Scth char *initiator; /* ".<phci-driver>... */ 345a08731ecScth char *p; 346a08731ecScth int len; 347*37fbbce5Scth char driver[KSTAT_STRLEN]; 348a08731ecScth int instunit; 349a08731ecScth disk_list_t **dlhp; /* disklist head */ 3507c478bd9Sstevel@tonic-gate disk_list_t *entry; 351*37fbbce5Scth char *devpath = NULL; 352a08731ecScth char *adevpath = NULL; 353a08731ecScth char *devid = NULL; 354*37fbbce5Scth int pid; 355*37fbbce5Scth char *target_port = NULL; 356*37fbbce5Scth char portform[MAXPATHLEN]; 3577c478bd9Sstevel@tonic-gate 358*37fbbce5Scth /* Filter out illegal forms (like all digits). */ 359a08731ecScth if ((ks_name == NULL) || (*ks_name == 0) || 360a08731ecScth (strspn(ks_name, "0123456789") == strlen(ks_name))) 361*37fbbce5Scth goto fail; 362*37fbbce5Scth 363*37fbbce5Scth /* parse ks_name to create new entry */ 364*37fbbce5Scth pidp = strchr(ks_name, '.'); /* start of ".<pid>" */ 365*37fbbce5Scth initiator = strrchr(ks_name, '.'); /* start of ".<pHCI-driver>" */ 366*37fbbce5Scth if (pidp && (pidp == initiator)) /* can't have same start */ 367*37fbbce5Scth goto fail; 368*37fbbce5Scth 369*37fbbce5Scth part = strchr(ks_name, ','); /* start of ",<partition>" */ 370*37fbbce5Scth p = strchr(ks_name, ':'); /* start of ":<partition>" */ 371*37fbbce5Scth if (part && p) 372*37fbbce5Scth goto fail; /* can't have both */ 373*37fbbce5Scth if (p) 374*37fbbce5Scth part = p; 375*37fbbce5Scth if (part && pidp) 376*37fbbce5Scth goto fail; /* <pid> and partition: bad */ 377*37fbbce5Scth 378*37fbbce5Scth p = part ? part : pidp; 379a08731ecScth if (p == NULL) 380a08731ecScth p = &ks_name[strlen(ks_name) - 1]; /* last char */ 381a08731ecScth else 382*37fbbce5Scth p--; /* before ',' or '.' */ 383a08731ecScth 384a08731ecScth while ((p >= ks_name) && isdigit(*p)) 385a08731ecScth p--; /* backwards over digits */ 386a08731ecScth p++; /* start of instunit */ 387*37fbbce5Scth if ((*p == '\0') || (*p == ',') || (*p == '.') || (*p == ':')) 388*37fbbce5Scth goto fail; /* no <instunit> */ 389a08731ecScth len = p - ks_name; 390a08731ecScth (void) strncpy(driver, ks_name, len); 391a08731ecScth driver[len] = '\0'; 392a08731ecScth instunit = atoi(p); 393*37fbbce5Scth if (part) 394*37fbbce5Scth part++; /* skip ',' */ 395a08731ecScth 396*37fbbce5Scth /* hash by instunit and search for existing entry */ 397a08731ecScth dlhp = &disklist[instunit & (DISKLIST_MOD - 1)]; 398a08731ecScth for (entry = *dlhp; entry; entry = entry->next) { 399*37fbbce5Scth if (strcmp(entry->ks_name, ks_name) == 0) { 400a08731ecScth return (entry); 401a08731ecScth } 402a08731ecScth } 403a08731ecScth 404*37fbbce5Scth /* not found, translate kstat_name components and create new entry */ 405*37fbbce5Scth 406*37fbbce5Scth /* translate kstat_name dev information */ 407*37fbbce5Scth if (drvinstunitpart2dev(driver, instunit, part, 408*37fbbce5Scth &devpath, &adevpath, want_devid ? &devid : NULL) == 0) { 409*37fbbce5Scth goto fail; 410a08731ecScth } 411a08731ecScth 412*37fbbce5Scth /* parse and translate path information */ 413*37fbbce5Scth if (pidp) { 414*37fbbce5Scth /* parse path information: ".t#.<phci-driver><instance>" */ 415*37fbbce5Scth pidp++; /* skip '.' */ 416*37fbbce5Scth initiator++; /* skip '.' */ 417*37fbbce5Scth if ((*pidp != 't') || !isdigit(pidp[1])) 418*37fbbce5Scth goto fail; /* not ".t#" */ 419*37fbbce5Scth pid = atoi(&pidp[1]); 420*37fbbce5Scth 421*37fbbce5Scth /* translate <pid> to 'target-port' */ 422*37fbbce5Scth if (drvpid2port(pid, &target_port) == 0) 423*37fbbce5Scth goto fail; 424*37fbbce5Scth 425*37fbbce5Scth /* Establish 'target-port' form. */ 426*37fbbce5Scth (void) snprintf(portform, sizeof (portform), 427*37fbbce5Scth "%s.t%s.%s", adevpath, target_port, initiator); 428*37fbbce5Scth free(target_port); 429*37fbbce5Scth free(adevpath); 430*37fbbce5Scth adevpath = strdup(portform); 431*37fbbce5Scth } 432*37fbbce5Scth 433*37fbbce5Scth /* make a new entry ... */ 4347c478bd9Sstevel@tonic-gate entry = safe_alloc(sizeof (disk_list_t)); 435*37fbbce5Scth entry->ks_name = safe_strdup(ks_name); 436a08731ecScth entry->dname = devpath; 437a08731ecScth entry->dsk = adevpath; 438a08731ecScth entry->devidstr = devid; 439a08731ecScth 440*37fbbce5Scth #ifdef DEBUG 441*37fbbce5Scth (void) printf("lookup_ks_name: new: %s %s\n", 442*37fbbce5Scth ks_name, entry->dsk ? entry->dsk : "NULL"); 443*37fbbce5Scth #endif /* DEBUG */ 444*37fbbce5Scth 445*37fbbce5Scth /* add new entry to head of hashed list */ 446a08731ecScth entry->next = *dlhp; 447a08731ecScth *dlhp = entry; 4487c478bd9Sstevel@tonic-gate return (entry); 449*37fbbce5Scth 450*37fbbce5Scth fail: 451*37fbbce5Scth free(devpath); 452*37fbbce5Scth free(adevpath); 453*37fbbce5Scth free(devid); 454*37fbbce5Scth #ifdef DEBUG 455*37fbbce5Scth (void) printf("lookup_ks_name: failed: %s\n", ks_name); 456*37fbbce5Scth #endif /* DEBUG */ 457*37fbbce5Scth return (NULL); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate /* 461a08731ecScth * Convert metadevice setno to setname by looking in /dev/md for symlinks 462a08731ecScth * that point to "shared/setno" - the name of such a symlink is the setname. 463a08731ecScth * The caller is responsible for freeing the returned string. 4647c478bd9Sstevel@tonic-gate */ 4657c478bd9Sstevel@tonic-gate static char * 466a08731ecScth mdsetno2name(int setno) 4677c478bd9Sstevel@tonic-gate { 468a08731ecScth char setlink[MAXPATHLEN + 1]; 469a08731ecScth char link[MAXPATHLEN + 1]; 470a08731ecScth char path[MAXPATHLEN + 1]; 471a08731ecScth char *p; 472a08731ecScth DIR *dirp; 473a08731ecScth struct dirent *dp; 474a08731ecScth size_t len; 475a08731ecScth char *mdsetname = NULL; 4767c478bd9Sstevel@tonic-gate 477a08731ecScth /* we are looking for a link to setlink */ 478a08731ecScth (void) snprintf(setlink, MAXPATHLEN, "shared/%d", setno); 4797c478bd9Sstevel@tonic-gate 480a08731ecScth /* in the directory /dev/md */ 481a08731ecScth (void) strcpy(path, "/dev/md/"); 482a08731ecScth p = path + strlen(path); 483a08731ecScth dirp = opendir(path); 484a08731ecScth if (dirp == NULL) 4857c478bd9Sstevel@tonic-gate return (NULL); 4867c478bd9Sstevel@tonic-gate 487a08731ecScth /* loop through /dev/md directory entries */ 488a08731ecScth while ((dp = readdir(dirp)) != NULL) { 4897c478bd9Sstevel@tonic-gate 490a08731ecScth /* doing a readlink of entry (fails for non-symlinks) */ 491a08731ecScth *p = '\0'; 492a08731ecScth (void) strcpy(p, dp->d_name); 493a08731ecScth if ((len = readlink(path, link, MAXPATHLEN)) == (size_t)-1) 494a08731ecScth continue; 4957c478bd9Sstevel@tonic-gate 496a08731ecScth /* and looking for a link to setlink */ 497a08731ecScth link[len] = '\0'; 498a08731ecScth if (strcmp(setlink, link)) 499a08731ecScth continue; 500a08731ecScth 501a08731ecScth /* found- name of link is the setname */ 502a08731ecScth mdsetname = safe_strdup(dp->d_name); 5037c478bd9Sstevel@tonic-gate break; 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate 506a08731ecScth (void) closedir(dirp); 507a08731ecScth return (mdsetname); 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate char * 5117c478bd9Sstevel@tonic-gate lookup_nfs_name(char *ks, kstat_ctl_t *kc) 5127c478bd9Sstevel@tonic-gate { 5137c478bd9Sstevel@tonic-gate uint_t minor; 5147c478bd9Sstevel@tonic-gate char *host, *path; 5157c478bd9Sstevel@tonic-gate char *cp; 5167c478bd9Sstevel@tonic-gate char *rstr = 0; 5177c478bd9Sstevel@tonic-gate size_t len; 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate if (sscanf(ks, "nfs%u", &minor) == 1) { 5207c478bd9Sstevel@tonic-gate retry: 5217c478bd9Sstevel@tonic-gate cp = get_nfs_by_minor(minor); 5227c478bd9Sstevel@tonic-gate if (cp) { 5237c478bd9Sstevel@tonic-gate if (strchr(cp, ',') == NULL) { 5247c478bd9Sstevel@tonic-gate rstr = safe_strdup(cp); 5257c478bd9Sstevel@tonic-gate return (rstr); 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate host = cur_hostname(minor, kc); 5287c478bd9Sstevel@tonic-gate if (host) { 5297c478bd9Sstevel@tonic-gate if (*host) { 5307c478bd9Sstevel@tonic-gate path = cur_special(host, cp); 5317c478bd9Sstevel@tonic-gate if (path) { 5327c478bd9Sstevel@tonic-gate len = strlen(host); 5337c478bd9Sstevel@tonic-gate len += strlen(path); 5347c478bd9Sstevel@tonic-gate len += 2; 5357c478bd9Sstevel@tonic-gate rstr = safe_alloc(len); 5367c478bd9Sstevel@tonic-gate (void) snprintf(rstr, len, 5377c478bd9Sstevel@tonic-gate "%s:%s", host, path); 5387c478bd9Sstevel@tonic-gate } else { 5397c478bd9Sstevel@tonic-gate rstr = safe_strdup(cp); 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate } else { 5427c478bd9Sstevel@tonic-gate rstr = safe_strdup(ks); 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate free(host); 5457c478bd9Sstevel@tonic-gate } else { 5467c478bd9Sstevel@tonic-gate rstr = safe_strdup(cp); 5477c478bd9Sstevel@tonic-gate } 548a08731ecScth } else if (nfs_tried == 0) { 549a08731ecScth nfs_tried = 1; 5507c478bd9Sstevel@tonic-gate do_mnttab(); 5517c478bd9Sstevel@tonic-gate goto retry; 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate return (rstr); 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate static char * 5587c478bd9Sstevel@tonic-gate get_nfs_by_minor(uint_t minor) 5597c478bd9Sstevel@tonic-gate { 5607c478bd9Sstevel@tonic-gate mnt_t *localnfs; 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate localnfs = nfs; 5637c478bd9Sstevel@tonic-gate while (localnfs) { 5647c478bd9Sstevel@tonic-gate if (localnfs->minor == minor) { 5657c478bd9Sstevel@tonic-gate return (localnfs->device_name); 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate localnfs = localnfs->next; 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate return (0); 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate /* 5737c478bd9Sstevel@tonic-gate * Read the cur_hostname from the mntinfo kstat 5747c478bd9Sstevel@tonic-gate */ 5757c478bd9Sstevel@tonic-gate static char * 5767c478bd9Sstevel@tonic-gate cur_hostname(uint_t minor, kstat_ctl_t *kc) 5777c478bd9Sstevel@tonic-gate { 5787c478bd9Sstevel@tonic-gate kstat_t *ksp; 5797c478bd9Sstevel@tonic-gate static struct mntinfo_kstat mik; 5807c478bd9Sstevel@tonic-gate char *rstr; 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 5837c478bd9Sstevel@tonic-gate if (ksp->ks_type != KSTAT_TYPE_RAW) 5847c478bd9Sstevel@tonic-gate continue; 5857c478bd9Sstevel@tonic-gate if (ksp->ks_instance != minor) 5867c478bd9Sstevel@tonic-gate continue; 5877c478bd9Sstevel@tonic-gate if (strcmp(ksp->ks_module, "nfs")) 5887c478bd9Sstevel@tonic-gate continue; 5897c478bd9Sstevel@tonic-gate if (strcmp(ksp->ks_name, "mntinfo")) 5907c478bd9Sstevel@tonic-gate continue; 5917c478bd9Sstevel@tonic-gate if (ksp->ks_flags & KSTAT_FLAG_INVALID) 5927c478bd9Sstevel@tonic-gate return (NULL); 5937c478bd9Sstevel@tonic-gate if (kstat_read(kc, ksp, &mik) == -1) 5947c478bd9Sstevel@tonic-gate return (NULL); 5957c478bd9Sstevel@tonic-gate rstr = safe_strdup(mik.mik_curserver); 5967c478bd9Sstevel@tonic-gate return (rstr); 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate return (NULL); 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate /* 6027c478bd9Sstevel@tonic-gate * Given the hostname of the mounted server, extract the server 6037c478bd9Sstevel@tonic-gate * mount point from the mnttab string. 6047c478bd9Sstevel@tonic-gate * 6057c478bd9Sstevel@tonic-gate * Common forms: 6067c478bd9Sstevel@tonic-gate * server1,server2,server3:/path 6077c478bd9Sstevel@tonic-gate * server1:/path,server2:/path 6087c478bd9Sstevel@tonic-gate * or a hybrid of the two 6097c478bd9Sstevel@tonic-gate */ 6107c478bd9Sstevel@tonic-gate static char * 6117c478bd9Sstevel@tonic-gate cur_special(char *hostname, char *special) 6127c478bd9Sstevel@tonic-gate { 6137c478bd9Sstevel@tonic-gate char *cp; 6147c478bd9Sstevel@tonic-gate char *path; 6157c478bd9Sstevel@tonic-gate size_t hlen = strlen(hostname); 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate /* 6187c478bd9Sstevel@tonic-gate * find hostname in string 6197c478bd9Sstevel@tonic-gate */ 6207c478bd9Sstevel@tonic-gate again: 6217c478bd9Sstevel@tonic-gate if ((cp = strstr(special, hostname)) == NULL) 6227c478bd9Sstevel@tonic-gate return (NULL); 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate /* 6257c478bd9Sstevel@tonic-gate * hostname must be followed by ',' or ':' 6267c478bd9Sstevel@tonic-gate */ 6277c478bd9Sstevel@tonic-gate if (cp[hlen] != ',' && cp[hlen] != ':') { 6287c478bd9Sstevel@tonic-gate special = &cp[hlen]; 6297c478bd9Sstevel@tonic-gate goto again; 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate /* 6337c478bd9Sstevel@tonic-gate * If hostname is followed by a ',' eat all characters until a ':' 6347c478bd9Sstevel@tonic-gate */ 6357c478bd9Sstevel@tonic-gate cp = &cp[hlen]; 6367c478bd9Sstevel@tonic-gate if (*cp == ',') { 6377c478bd9Sstevel@tonic-gate cp++; 6387c478bd9Sstevel@tonic-gate while (*cp != ':') { 6397c478bd9Sstevel@tonic-gate if (*cp == NULL) 6407c478bd9Sstevel@tonic-gate return (NULL); 6417c478bd9Sstevel@tonic-gate cp++; 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate } 6447c478bd9Sstevel@tonic-gate path = ++cp; /* skip ':' */ 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate /* 6477c478bd9Sstevel@tonic-gate * path is terminated by either 0, or space or ',' 6487c478bd9Sstevel@tonic-gate */ 6497c478bd9Sstevel@tonic-gate while (*cp) { 6507c478bd9Sstevel@tonic-gate if (isspace(*cp) || *cp == ',') { 6517c478bd9Sstevel@tonic-gate *cp = NULL; 6527c478bd9Sstevel@tonic-gate return (path); 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate cp++; 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate return (path); 6577c478bd9Sstevel@tonic-gate } 658