xref: /titanic_53/usr/src/cmd/stat/common/dsr.c (revision 37fbbce5257519d600faa3d23d464b42b71c1605)
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