xref: /titanic_51/usr/src/cmd/stmsboot/stmsboot_util.c (revision 8cecff49db8e75ebf1858567ff985fdf50f1b899)
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
580ab886dSwesolows  * Common Development and Distribution License (the "License").
680ab886dSwesolows  * 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  */
2180ab886dSwesolows 
227c478bd9Sstevel@tonic-gate /*
235a4c37c9Sqh201292  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <stdio.h>
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <stdarg.h>
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/stat.h>
347c478bd9Sstevel@tonic-gate #include <fcntl.h>
357c478bd9Sstevel@tonic-gate #include <errno.h>
367c478bd9Sstevel@tonic-gate #include <unistd.h>
377c478bd9Sstevel@tonic-gate #include <stropts.h>
387c478bd9Sstevel@tonic-gate #include <strings.h>
397c478bd9Sstevel@tonic-gate #include <dirent.h>
407c478bd9Sstevel@tonic-gate #include <sys/param.h>
417c478bd9Sstevel@tonic-gate #include <sys/scsi/adapters/scsi_vhci.h>
427c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
437c478bd9Sstevel@tonic-gate #include <libgen.h>
447c478bd9Sstevel@tonic-gate #include <dlfcn.h>
457c478bd9Sstevel@tonic-gate #include <link.h>
467c478bd9Sstevel@tonic-gate #include <locale.h>
477c478bd9Sstevel@tonic-gate #include <libintl.h>
487c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
49*8cecff49Sgp87344 #include <sys/mnttab.h>
507c478bd9Sstevel@tonic-gate #include <sys/vfstab.h>
517c478bd9Sstevel@tonic-gate #include <sys/mount.h>
527c478bd9Sstevel@tonic-gate #include <devid.h>
537c478bd9Sstevel@tonic-gate #include <sys/libdevid.h>
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #define	VHCI_CTL_NODE	"/devices/scsi_vhci:devctl"
567c478bd9Sstevel@tonic-gate #define	SLASH_DEVICES	"/devices/"
575a4c37c9Sqh201292 
585a4c37c9Sqh201292 #ifdef	sparc
595a4c37c9Sqh201292 #define	DISK_NODE_NAME	"ssd"
605a4c37c9Sqh201292 #define	DISK_DRV_NAME	"ssd"
615a4c37c9Sqh201292 #else	/* sparc */
625a4c37c9Sqh201292 #define	DISK_NODE_NAME	"disk"
635a4c37c9Sqh201292 #define	DISK_DRV_NAME	"sd"
645a4c37c9Sqh201292 #endif
655a4c37c9Sqh201292 
6660fffc19Sjw149990 #define	DISK_AT_G	"disk@g"
677c478bd9Sstevel@tonic-gate #define	SLASH_FP_AT	"/fp@"
687c478bd9Sstevel@tonic-gate #define	SLASH_SCSI_VHCI	"/scsi_vhci"
697c478bd9Sstevel@tonic-gate #define	DEV_DSK		"/dev/dsk/"
707c478bd9Sstevel@tonic-gate #define	DEV_RDSK	"/dev/rdsk/"
717c478bd9Sstevel@tonic-gate #define	SYS_FILENAME_LEN	256
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate  * Save directory is the directory in which system files are saved.
757c478bd9Sstevel@tonic-gate  * Save directory must be under the root filesystem, as this program is
767c478bd9Sstevel@tonic-gate  * typically run before any other filesystems are mounted.
777c478bd9Sstevel@tonic-gate  */
787c478bd9Sstevel@tonic-gate #define	SAVE_DIR	"/etc/mpxio"
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate /* fcp driver publishes this property */
817c478bd9Sstevel@tonic-gate #define	NODE_WWN_PROP	"node-wwn"
827c478bd9Sstevel@tonic-gate 
8360fffc19Sjw149990 /*
8460fffc19Sjw149990  * For SAS, we look for "sas-$drivername", eg sas-mpt, but
8560fffc19Sjw149990  * we strncat the driver name later once we've parsed the
8660fffc19Sjw149990  * args passed in from the shell.
8760fffc19Sjw149990  */
8860fffc19Sjw149990 #define	SASPROP	 "sas-"
8960fffc19Sjw149990 
9060fffc19Sjw149990 
917c478bd9Sstevel@tonic-gate typedef enum {
927c478bd9Sstevel@tonic-gate 	CLIENT_TYPE_UNKNOWN,
937c478bd9Sstevel@tonic-gate 	CLIENT_TYPE_PHCI,
947c478bd9Sstevel@tonic-gate 	CLIENT_TYPE_VHCI
957c478bd9Sstevel@tonic-gate } client_type_t;
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate struct devlink_cbarg {
987c478bd9Sstevel@tonic-gate 	char *devlink;
997c478bd9Sstevel@tonic-gate 	size_t len;
1007c478bd9Sstevel@tonic-gate };
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate static di_node_t devinfo_root = DI_NODE_NIL;
1037c478bd9Sstevel@tonic-gate static di_devlink_handle_t devlink_hdl = NULL;
1047c478bd9Sstevel@tonic-gate static int vhci_fd = -1;
1057c478bd9Sstevel@tonic-gate static int patch_vfstab, cap_m_option, debug;
1067c478bd9Sstevel@tonic-gate static int list_option, list_guid_mappings, list_controllernum = -1;
1077c478bd9Sstevel@tonic-gate static char *mapdev = "";
1085a4c37c9Sqh201292 static char *map_vhciname = "";
1097c478bd9Sstevel@tonic-gate static char *stmsboot = "stmsboot";
1107c478bd9Sstevel@tonic-gate 
11160fffc19Sjw149990 char *drvname = (char *)NULL; /* "fp" or "mpt" or ... */
11260fffc19Sjw149990 /* "node-wwn" if drvname=fp, or "sas-$drivername" otherwise */
11360fffc19Sjw149990 char *drvprop = (char *)NULL;
11460fffc19Sjw149990 static int parent = 0; /* for "-n" usage */
11560fffc19Sjw149990 
1167c478bd9Sstevel@tonic-gate static int make_temp(char *, char *, char *, size_t);
1177c478bd9Sstevel@tonic-gate static void commit_change(char *, char *, char *, int);
1187c478bd9Sstevel@tonic-gate static int map_devname(char *, char *, size_t, int);
1197c478bd9Sstevel@tonic-gate static int update_vfstab(char *, char *);
1207c478bd9Sstevel@tonic-gate static int list_mappings(int, int);
1217c478bd9Sstevel@tonic-gate static int canopen(char *);
12260fffc19Sjw149990 static client_type_t client_by_props(char *path);
12360fffc19Sjw149990 static void list_nodes(char *drivername);
124*8cecff49Sgp87344 static int canread(char *, char *);
12560fffc19Sjw149990 
1267c478bd9Sstevel@tonic-gate static void logerr(char *, ...);
1277c478bd9Sstevel@tonic-gate static void logdmsg(char *, ...);
1287c478bd9Sstevel@tonic-gate static void *s_malloc(const size_t);
1297c478bd9Sstevel@tonic-gate static char *s_strdup(const char *);
1307c478bd9Sstevel@tonic-gate static void s_strlcpy(char *, const char *, size_t);
131cfcc3aa4Sqh201292 static int map_openable_vhciname(char *, char *, size_t);
132264d6c47Seota /*
133264d6c47Seota  * Using an exit function not marked __NORETURN causes a warning with gcc.
134264d6c47Seota  * To suppress the warning, use __NORETURN attribute.
135264d6c47Seota  */
136264d6c47Seota static void clean_exit(int)__NORETURN;
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate /*
1397c478bd9Sstevel@tonic-gate  * Print usage and exit.
1407c478bd9Sstevel@tonic-gate  */
1417c478bd9Sstevel@tonic-gate static void
1427c478bd9Sstevel@tonic-gate usage(char *argv0)
1437c478bd9Sstevel@tonic-gate {
1447c478bd9Sstevel@tonic-gate 	char *progname;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	progname = strrchr(argv0, '/');
1477c478bd9Sstevel@tonic-gate 	if (progname != NULL)
1487c478bd9Sstevel@tonic-gate 		progname++;
1497c478bd9Sstevel@tonic-gate 	else
1507c478bd9Sstevel@tonic-gate 		progname = argv0;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	/*
1537c478bd9Sstevel@tonic-gate 	 * -u	update /etc/vfstab
1547c478bd9Sstevel@tonic-gate 	 * -m devname
1557c478bd9Sstevel@tonic-gate 	 *	if devname is phci based name and not open-able, map it to
1567c478bd9Sstevel@tonic-gate 	 *	vhci based /devices name.
1577c478bd9Sstevel@tonic-gate 	 *	if devname is vhci based name and not open-able, map it to
1587c478bd9Sstevel@tonic-gate 	 *	phci based /devices name.
1597c478bd9Sstevel@tonic-gate 	 * -M devname
1607c478bd9Sstevel@tonic-gate 	 *	same as -m except that /dev link is printed instead of
1617c478bd9Sstevel@tonic-gate 	 *	/devices name.
1627c478bd9Sstevel@tonic-gate 	 * -l controller
1637c478bd9Sstevel@tonic-gate 	 *	list non-STMS to STMS device name mappings for the specific
1647c478bd9Sstevel@tonic-gate 	 *	controller
1657c478bd9Sstevel@tonic-gate 	 * -L	list non-STMS to STMS device name mappings for all controllers
1665a4c37c9Sqh201292 	 * -p devname
1675a4c37c9Sqh201292 	 *	if devname is vhci based name and open-able, get the first
1685a4c37c9Sqh201292 	 *	onlined phci based name without /devices prefix.
1695a4c37c9Sqh201292 	 *	Used in stmsboot to update the phci based bootpath.
17060fffc19Sjw149990 	 * -D drvname
17160fffc19Sjw149990 	 *	if supplied, indicates that we're going to operate on
17260fffc19Sjw149990 	 *	devices attached to this driver
17360fffc19Sjw149990 	 * -n
17460fffc19Sjw149990 	 *	if supplied, returns name of the node containing "fp" or
17560fffc19Sjw149990 	 *	"sas-$driver", appends "sd@" or "ssd@" or "disk@". Can only
17660fffc19Sjw149990 	 *	be used if -D drv is specified as well
1777c478bd9Sstevel@tonic-gate 	 */
1787c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("usage: %s -u | -m devname | "
17960fffc19Sjw149990 	    "-M devname | -l controller | -L | \n"
18060fffc19Sjw149990 	    "\t\t-p devname | -D { fp | mpt } | -n\n"), progname);
1817c478bd9Sstevel@tonic-gate 	exit(2);
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate /*
1857c478bd9Sstevel@tonic-gate  * Parse command line arguments.
1867c478bd9Sstevel@tonic-gate  */
1877c478bd9Sstevel@tonic-gate static void
1887c478bd9Sstevel@tonic-gate parse_args(int argc, char *argv[])
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate 	char opt;
1917c478bd9Sstevel@tonic-gate 	int n = 0;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	if (argc == 1) {
1947c478bd9Sstevel@tonic-gate 		usage(argv[0]);
1957c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
1967c478bd9Sstevel@tonic-gate 	}
1977c478bd9Sstevel@tonic-gate 
19860fffc19Sjw149990 	while ((opt = getopt(argc, argv, "udm:M:Ll:gp:D:n")) != EOF) {
1997c478bd9Sstevel@tonic-gate 		switch (opt) {
2007c478bd9Sstevel@tonic-gate 		case 'u':
2017c478bd9Sstevel@tonic-gate 			patch_vfstab = 1;
2027c478bd9Sstevel@tonic-gate 			n++;
2037c478bd9Sstevel@tonic-gate 			break;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 		case 'd':
2067c478bd9Sstevel@tonic-gate 			debug = 1;
2077c478bd9Sstevel@tonic-gate 			break;
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 		case 'm':
2107c478bd9Sstevel@tonic-gate 			mapdev = s_strdup(optarg);
2117c478bd9Sstevel@tonic-gate 			n++;
2127c478bd9Sstevel@tonic-gate 			break;
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 		case 'M':
2157c478bd9Sstevel@tonic-gate 			mapdev = s_strdup(optarg);
2167c478bd9Sstevel@tonic-gate 			cap_m_option = 1;
2177c478bd9Sstevel@tonic-gate 			n++;
2187c478bd9Sstevel@tonic-gate 			break;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 		case 'L':
2217c478bd9Sstevel@tonic-gate 			list_option = 1;
2227c478bd9Sstevel@tonic-gate 			n++;
2237c478bd9Sstevel@tonic-gate 			break;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 		case 'l':
2267c478bd9Sstevel@tonic-gate 			list_option = 1;
2277c478bd9Sstevel@tonic-gate 			list_controllernum = (int)atol(optarg);
2287c478bd9Sstevel@tonic-gate 			if (list_controllernum < 0) {
2297c478bd9Sstevel@tonic-gate 				logerr(gettext("controller number %d is "
2307c478bd9Sstevel@tonic-gate 				    "invalid\n"), list_controllernum);
2317c478bd9Sstevel@tonic-gate 				clean_exit(1);
2327c478bd9Sstevel@tonic-gate 			}
2337c478bd9Sstevel@tonic-gate 			n++;
2347c478bd9Sstevel@tonic-gate 			break;
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 		case 'g':
2377c478bd9Sstevel@tonic-gate 			/*
2387c478bd9Sstevel@tonic-gate 			 * private option to display non-STMS device name
2397c478bd9Sstevel@tonic-gate 			 * to GUID mappings.
2407c478bd9Sstevel@tonic-gate 			 */
2417c478bd9Sstevel@tonic-gate 			list_guid_mappings = 1;
2427c478bd9Sstevel@tonic-gate 			break;
24360fffc19Sjw149990 
2445a4c37c9Sqh201292 		case 'p':
2455a4c37c9Sqh201292 			/*
2465a4c37c9Sqh201292 			 * map openable vhci based name to phci base name
2475a4c37c9Sqh201292 			 */
2485a4c37c9Sqh201292 			map_vhciname = s_strdup(optarg);
2495a4c37c9Sqh201292 			n++;
2505a4c37c9Sqh201292 			break;
2517c478bd9Sstevel@tonic-gate 
25260fffc19Sjw149990 		case 'D':
25360fffc19Sjw149990 			/*
25460fffc19Sjw149990 			 * Grab the driver name we need to look for. Each
25560fffc19Sjw149990 			 * time we add support for a new SAS or FC driver
25660fffc19Sjw149990 			 * to this utility, make sure that its driver name
25760fffc19Sjw149990 			 * is checked here.
25860fffc19Sjw149990 			 */
25960fffc19Sjw149990 			drvname = s_malloc(sizeof (optarg) + 1);
26060fffc19Sjw149990 			drvname = s_strdup(optarg);
26160fffc19Sjw149990 			if (strcmp(drvname, "fp") == 0) {
26260fffc19Sjw149990 				drvprop = s_malloc(sizeof (NODE_WWN_PROP));
26360fffc19Sjw149990 				(void) snprintf(drvprop, sizeof (NODE_WWN_PROP),
26460fffc19Sjw149990 				    NODE_WWN_PROP);
26560fffc19Sjw149990 			} else if (strcmp(drvname, "mpt") == 0) {
26660fffc19Sjw149990 				drvprop = s_malloc(sizeof (SASPROP) +
26760fffc19Sjw149990 				    sizeof (drvname) + 1);
26860fffc19Sjw149990 				(void) snprintf(drvprop, sizeof (SASPROP) +
26960fffc19Sjw149990 				    sizeof (drvname), "%s%s",
27060fffc19Sjw149990 				    SASPROP, drvname);
27160fffc19Sjw149990 			} else {
27260fffc19Sjw149990 				logerr(gettext("Driver %s is not supported\n"),
27360fffc19Sjw149990 				    drvname);
27460fffc19Sjw149990 				clean_exit(1);
27560fffc19Sjw149990 			}
27660fffc19Sjw149990 
27760fffc19Sjw149990 			break;
27860fffc19Sjw149990 
27960fffc19Sjw149990 		case 'n':
28060fffc19Sjw149990 			++parent;
28160fffc19Sjw149990 			n++;
28260fffc19Sjw149990 			break;
28360fffc19Sjw149990 
2847c478bd9Sstevel@tonic-gate 		default:
2857c478bd9Sstevel@tonic-gate 			usage(argv[0]);
2867c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
2877c478bd9Sstevel@tonic-gate 		}
2887c478bd9Sstevel@tonic-gate 	}
2897c478bd9Sstevel@tonic-gate 
29060fffc19Sjw149990 	if (n != 1) {
2917c478bd9Sstevel@tonic-gate 		usage(argv[0]);
2927c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
2937c478bd9Sstevel@tonic-gate 	}
29460fffc19Sjw149990 }
2957c478bd9Sstevel@tonic-gate 
29680ab886dSwesolows int
2977c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
2987c478bd9Sstevel@tonic-gate {
2997c478bd9Sstevel@tonic-gate 	char save_vfstab[SYS_FILENAME_LEN], tmp_vfstab[SYS_FILENAME_LEN];
3007c478bd9Sstevel@tonic-gate 	int vfstab_updated;
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
3037c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	if (getuid() != 0) {
3067c478bd9Sstevel@tonic-gate 		logerr(gettext("must be super-user to run this program\n"));
3077c478bd9Sstevel@tonic-gate 		clean_exit(1);
3087c478bd9Sstevel@tonic-gate 	}
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	parse_args(argc, argv);
3117c478bd9Sstevel@tonic-gate 	(void) umask(022);
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	/*
3147c478bd9Sstevel@tonic-gate 	 * NOTE: The mpxio boot-up script executes this program with the
3157c478bd9Sstevel@tonic-gate 	 * mapping (-m) option before the /usr is even mounted and when the
3167c478bd9Sstevel@tonic-gate 	 * root filesystem is still mounted read-only.
3177c478bd9Sstevel@tonic-gate 	 */
3187c478bd9Sstevel@tonic-gate 	if (*mapdev != '\0') {
3197c478bd9Sstevel@tonic-gate 		char newname[MAXPATHLEN];
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 		if (map_devname(mapdev, newname, sizeof (newname),
3227c478bd9Sstevel@tonic-gate 		    cap_m_option) == 0) {
3237c478bd9Sstevel@tonic-gate 			(void) printf("%s\n", newname);
3247c478bd9Sstevel@tonic-gate 			clean_exit(0);
3257c478bd9Sstevel@tonic-gate 		}
3267c478bd9Sstevel@tonic-gate 		clean_exit(1);
3277c478bd9Sstevel@tonic-gate 	}
3285a4c37c9Sqh201292 	if (*map_vhciname != '\0') {
3295a4c37c9Sqh201292 		char newname[MAXPATHLEN];
3305a4c37c9Sqh201292 
3315a4c37c9Sqh201292 		if (map_openable_vhciname(map_vhciname, newname,
3325a4c37c9Sqh201292 		    sizeof (newname)) == 0) {
3335a4c37c9Sqh201292 			(void) printf("%s\n", newname);
3345a4c37c9Sqh201292 			clean_exit(0);
3355a4c37c9Sqh201292 		}
3365a4c37c9Sqh201292 		clean_exit(1);
3375a4c37c9Sqh201292 	}
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	if (list_option || list_guid_mappings) {
3407c478bd9Sstevel@tonic-gate 		if (list_mappings(list_controllernum, list_guid_mappings) == 0)
3417c478bd9Sstevel@tonic-gate 			clean_exit(0);
3427c478bd9Sstevel@tonic-gate 		clean_exit(1);
3437c478bd9Sstevel@tonic-gate 	}
3447c478bd9Sstevel@tonic-gate 
34560fffc19Sjw149990 	if (parent > 0) {
34660fffc19Sjw149990 		if (strcmp(drvname, "") == 0) {
34760fffc19Sjw149990 			usage(argv[0]);
34860fffc19Sjw149990 			clean_exit(1);
34960fffc19Sjw149990 		} else {
35060fffc19Sjw149990 			list_nodes(drvname);
35160fffc19Sjw149990 			clean_exit(0);
35260fffc19Sjw149990 		}
35360fffc19Sjw149990 	}
35460fffc19Sjw149990 
3557c478bd9Sstevel@tonic-gate 	/* create a directory where a copy of the system files are saved */
3567c478bd9Sstevel@tonic-gate 	if (patch_vfstab) {
3577c478bd9Sstevel@tonic-gate 		if (mkdirp(SAVE_DIR, 0755) != 0 && errno != EEXIST) {
3587c478bd9Sstevel@tonic-gate 			logerr(gettext("mkdirp: failed to create %1$s: %2$s\n"),
3597c478bd9Sstevel@tonic-gate 			    SAVE_DIR, strerror(errno));
3607c478bd9Sstevel@tonic-gate 			clean_exit(1);
3617c478bd9Sstevel@tonic-gate 		}
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 		if (make_temp(VFSTAB, save_vfstab, tmp_vfstab,
3647c478bd9Sstevel@tonic-gate 		    SYS_FILENAME_LEN) != 0)
3657c478bd9Sstevel@tonic-gate 			clean_exit(1);
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 		/* build new vfstab without modifying the existing one */
3687c478bd9Sstevel@tonic-gate 		if ((vfstab_updated = update_vfstab(VFSTAB, tmp_vfstab))
3697c478bd9Sstevel@tonic-gate 		    == -1) {
3707c478bd9Sstevel@tonic-gate 			logerr(gettext("failed to update %s\n"), VFSTAB);
3717c478bd9Sstevel@tonic-gate 			clean_exit(1);
3727c478bd9Sstevel@tonic-gate 		}
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 		commit_change(VFSTAB, save_vfstab, tmp_vfstab, vfstab_updated);
3757c478bd9Sstevel@tonic-gate 	}
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	clean_exit(0);
378815dd917Sjmcp 	/*NOTREACHED*/
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate /*
3827c478bd9Sstevel@tonic-gate  * Make saved and temporary filenames in SAVE_DIR.
3837c478bd9Sstevel@tonic-gate  *
3847c478bd9Sstevel@tonic-gate  * ex: if the filename is /etc/vfstab then the save_filename and tmp_filename
3857c478bd9Sstevel@tonic-gate  * would be SAVE_DIR/vfstab and SAVE_DIR/vfstab.tmp respectively.
3867c478bd9Sstevel@tonic-gate  *
3877c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
3887c478bd9Sstevel@tonic-gate  */
3897c478bd9Sstevel@tonic-gate static int
3907c478bd9Sstevel@tonic-gate make_temp(char *filename, char *save_filename, char *tmp_filename, size_t len)
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate 	char *ptr;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	if ((ptr = strrchr(filename, '/')) == NULL) {
3957c478bd9Sstevel@tonic-gate 		logdmsg("invalid file %s\n", filename);
3967c478bd9Sstevel@tonic-gate 		return (-1);
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate 	(void) snprintf(save_filename, len, "%s%s", SAVE_DIR, ptr);
3997c478bd9Sstevel@tonic-gate 	(void) snprintf(tmp_filename, len, "%s%s.tmp", SAVE_DIR, ptr);
4007c478bd9Sstevel@tonic-gate 	logdmsg("make_temp: %s: save = %s, temp = %s\n", filename,
4017c478bd9Sstevel@tonic-gate 	    save_filename, tmp_filename);
4027c478bd9Sstevel@tonic-gate 	return (0);
4037c478bd9Sstevel@tonic-gate }
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate /*
4067c478bd9Sstevel@tonic-gate  * Commit the changes made to the system file
4077c478bd9Sstevel@tonic-gate  */
4087c478bd9Sstevel@tonic-gate static void
4097c478bd9Sstevel@tonic-gate commit_change(char *filename, char *save_filename, char *tmp_filename,
4107c478bd9Sstevel@tonic-gate     int updated)
4117c478bd9Sstevel@tonic-gate {
4127c478bd9Sstevel@tonic-gate 	int x;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	if (updated) {
4157c478bd9Sstevel@tonic-gate 		/* save the original */
4167c478bd9Sstevel@tonic-gate 		if ((x = rename(filename, save_filename)) != 0) {
4177c478bd9Sstevel@tonic-gate 			logerr(gettext("rename %1$s to %2$s failed: %3$s\n"),
4187c478bd9Sstevel@tonic-gate 			    filename, save_filename, strerror(errno));
4197c478bd9Sstevel@tonic-gate 		}
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 		/* now rename the new file to the actual file */
4227c478bd9Sstevel@tonic-gate 		if (rename(tmp_filename, filename) != 0) {
4237c478bd9Sstevel@tonic-gate 			logerr(gettext("rename %1$s to %2$s failed: %3$s\n"),
4247c478bd9Sstevel@tonic-gate 			    tmp_filename, filename, strerror(errno));
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 			/* restore the original */
4277c478bd9Sstevel@tonic-gate 			if (x == 0 && rename(save_filename, filename) != 0) {
4287c478bd9Sstevel@tonic-gate 				logerr(
4297c478bd9Sstevel@tonic-gate 				    gettext("rename %1$s to %2$s failed: %3$s\n"
4307c478bd9Sstevel@tonic-gate 				    "%4$s is a copy of the original %5$s file"
4317c478bd9Sstevel@tonic-gate 				    "\n"),
4327c478bd9Sstevel@tonic-gate 				    save_filename, filename, strerror(errno),
4337c478bd9Sstevel@tonic-gate 				    save_filename, filename);
4347c478bd9Sstevel@tonic-gate 			}
4357c478bd9Sstevel@tonic-gate 		} else
4367c478bd9Sstevel@tonic-gate 			(void) printf(gettext("%1$s: %2$s has been updated.\n"),
4377c478bd9Sstevel@tonic-gate 			    stmsboot, filename);
4387c478bd9Sstevel@tonic-gate 	} else {
4397c478bd9Sstevel@tonic-gate 		/* remove the temp file */
4407c478bd9Sstevel@tonic-gate 		(void) unlink(tmp_filename);
4417c478bd9Sstevel@tonic-gate 		(void) printf(gettext("%1$s: %2$s was not modified as no "
4427c478bd9Sstevel@tonic-gate 		    "changes were needed.\n"), stmsboot, filename);
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate /*
4477c478bd9Sstevel@tonic-gate  * Get the GUID of the device.
4487c478bd9Sstevel@tonic-gate  *
4497c478bd9Sstevel@tonic-gate  * physpath	/devices name without the /devices prefix and minor name
4507c478bd9Sstevel@tonic-gate  *		component.
4517c478bd9Sstevel@tonic-gate  * guid		caller supplied buffer where the GUID will be placed on return
4527c478bd9Sstevel@tonic-gate  * guid_len	length of the caller supplied guid buffer.
45360fffc19Sjw149990  * no_delay_flag if set open the device with O_NDELAY
4547c478bd9Sstevel@tonic-gate  * node		di_node corresponding to physpath if already available,
4557c478bd9Sstevel@tonic-gate  *		otherwise pass DI_NODE_NIL.
4567c478bd9Sstevel@tonic-gate  *
4577c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
4587c478bd9Sstevel@tonic-gate  */
4597c478bd9Sstevel@tonic-gate static int
4607c478bd9Sstevel@tonic-gate get_guid(char *physpath, char *guid, int guid_len, int no_delay_flag,
4617c478bd9Sstevel@tonic-gate 	di_node_t node)
4627c478bd9Sstevel@tonic-gate {
4637c478bd9Sstevel@tonic-gate 	int		fd;
4647c478bd9Sstevel@tonic-gate 	ddi_devid_t	devid;
4657c478bd9Sstevel@tonic-gate 	int		rv	= -1;
4667c478bd9Sstevel@tonic-gate 	char		*i_guid	= NULL;
4677c478bd9Sstevel@tonic-gate 	char		physpath_raw[MAXPATHLEN];
4687c478bd9Sstevel@tonic-gate 	uchar_t		*wwnp;
4697c478bd9Sstevel@tonic-gate 	int		i, n, snapshot_taken = 0;
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	logdmsg("get_guid: physpath = %s\n", physpath);
4727c478bd9Sstevel@tonic-gate 
4735a4c37c9Sqh201292 #ifdef sparc
4747c478bd9Sstevel@tonic-gate 	(void) snprintf(physpath_raw, MAXPATHLEN,
4757c478bd9Sstevel@tonic-gate 	    "/devices%s:a,raw", physpath);
4765a4c37c9Sqh201292 #else
4775a4c37c9Sqh201292 	(void) snprintf(physpath_raw, MAXPATHLEN,
4785a4c37c9Sqh201292 	    "/devices%s:c,raw", physpath);
4795a4c37c9Sqh201292 #endif
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	*guid = '\0';
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	if (no_delay_flag)
4847c478bd9Sstevel@tonic-gate 		no_delay_flag = O_NDELAY;
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	/*
4877c478bd9Sstevel@tonic-gate 	 * Open the raw device
4887c478bd9Sstevel@tonic-gate 	 * Without the O_DELAY flag, the open will fail on standby paths of
4897c478bd9Sstevel@tonic-gate 	 * T3 if its mp_support mode is "mpxio".
4907c478bd9Sstevel@tonic-gate 	 */
4917c478bd9Sstevel@tonic-gate 	if ((fd = open(physpath_raw, O_RDONLY | no_delay_flag)) == -1) {
4927c478bd9Sstevel@tonic-gate 		logdmsg("get_guid: failed to open %s: %s\n", physpath_raw,
4937c478bd9Sstevel@tonic-gate 		    strerror(errno));
4947c478bd9Sstevel@tonic-gate 		return (-1);
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	if (devid_get(fd, &devid) == 0) {
4987c478bd9Sstevel@tonic-gate 		i_guid = devid_to_guid(devid);
4997c478bd9Sstevel@tonic-gate 		devid_free(devid);
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 		if (i_guid != NULL) {
5027c478bd9Sstevel@tonic-gate 			s_strlcpy(guid, i_guid, guid_len);
5037c478bd9Sstevel@tonic-gate 			devid_free_guid(i_guid);
5047c478bd9Sstevel@tonic-gate 			rv = 0;
5057c478bd9Sstevel@tonic-gate 			goto out;
50660fffc19Sjw149990 		} else {
5077c478bd9Sstevel@tonic-gate 			logdmsg("get_guid: devid_to_guid() failed\n");
50860fffc19Sjw149990 			logdmsg("Unable to get a GUID for device "
50960fffc19Sjw149990 			    "%s\n", physpath_raw);
51060fffc19Sjw149990 		}
51160fffc19Sjw149990 
5127c478bd9Sstevel@tonic-gate 	} else
5137c478bd9Sstevel@tonic-gate 		logdmsg("get_guid: devid_get() failed: %s\n", strerror(errno));
5147c478bd9Sstevel@tonic-gate 
51560fffc19Sjw149990 	/*
51660fffc19Sjw149990 	 * Unless we're looking at an fp-attached device, we now
51760fffc19Sjw149990 	 * fallback to node name as the guid as this is what the
51860fffc19Sjw149990 	 * fcp driver does. A sas-attached device will have the
51960fffc19Sjw149990 	 * client-guid property set.
52060fffc19Sjw149990 	 */
5217c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
5227c478bd9Sstevel@tonic-gate 		if ((node = di_init(physpath, DINFOCPYALL | DINFOFORCE))
5237c478bd9Sstevel@tonic-gate 		    == DI_NODE_NIL) {
5247c478bd9Sstevel@tonic-gate 			logdmsg("get_guid: di_init on %s failed: %s\n",
5257c478bd9Sstevel@tonic-gate 			    physpath, strerror(errno));
5267c478bd9Sstevel@tonic-gate 			goto out;
5277c478bd9Sstevel@tonic-gate 		}
5287c478bd9Sstevel@tonic-gate 		snapshot_taken = 1;
5297c478bd9Sstevel@tonic-gate 	}
5307c478bd9Sstevel@tonic-gate 
53160fffc19Sjw149990 	/* non-fp fallout */
53260fffc19Sjw149990 	if (strstr(physpath, "fp") == (char *)NULL) {
53360fffc19Sjw149990 		if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
53460fffc19Sjw149990 		    "client-guid", &guid) < 0) {
53560fffc19Sjw149990 			logdmsg("get_guid: non-fp-attached device, "
53660fffc19Sjw149990 			    "bailing out\n");
53760fffc19Sjw149990 			goto out;
53860fffc19Sjw149990 		}
53960fffc19Sjw149990 	}
54060fffc19Sjw149990 
5417c478bd9Sstevel@tonic-gate 	if ((n = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, NODE_WWN_PROP,
5427c478bd9Sstevel@tonic-gate 	    &wwnp)) == -1) {
5437c478bd9Sstevel@tonic-gate 		logdmsg("get_guid: di_prop_lookup_bytes() failed to lookup "
5447c478bd9Sstevel@tonic-gate 		    "%s: %s\n", NODE_WWN_PROP, strerror(errno));
5457c478bd9Sstevel@tonic-gate 		goto out;
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	if (guid_len >= ((n * 2) + 1)) {
5497c478bd9Sstevel@tonic-gate 		for (i = 0; i < n; i++) {
5507c478bd9Sstevel@tonic-gate 			(void) sprintf(guid + (i * 2), "%02x", (uint_t)(*wwnp));
5517c478bd9Sstevel@tonic-gate 			wwnp++;
5527c478bd9Sstevel@tonic-gate 		}
5537c478bd9Sstevel@tonic-gate 		rv = 0;
5547c478bd9Sstevel@tonic-gate 	} else
5557c478bd9Sstevel@tonic-gate 		logerr(gettext("insufficient buffer size: need %1$d "
5567c478bd9Sstevel@tonic-gate 		    "bytes, passed %2$d bytes\n"), (n * 2) + 1, guid_len);
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate out:
5597c478bd9Sstevel@tonic-gate 	if (snapshot_taken)
5607c478bd9Sstevel@tonic-gate 		di_fini(node);
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	(void) close(fd);
5637c478bd9Sstevel@tonic-gate 	logdmsg("get_guid: GUID = %s\n", guid);
5647c478bd9Sstevel@tonic-gate 	return (rv);
5657c478bd9Sstevel@tonic-gate }
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate /*
5687c478bd9Sstevel@tonic-gate  * Given client_name return whether it is a phci or vhci based name.
5697c478bd9Sstevel@tonic-gate  * client_name is /devices name of a client without the /devices prefix.
5707c478bd9Sstevel@tonic-gate  *
5717c478bd9Sstevel@tonic-gate  * client_name				Return value
5725a4c37c9Sqh201292  * on sparc:
57360fffc19Sjw149990  * .../fp@xxx/ssd@yyy			CLIENT_TYPE_PHCI (fc)
57460fffc19Sjw149990  * .../LSILogic,sas@xxx/sd@yyy		CLIENT_TYPE_PHCI (sas)
57560fffc19Sjw149990  * .../scsi_vhci/ssd@yyy		CLIENT_TYPE_VHCI (fc)
57660fffc19Sjw149990  * .../scsi_vhci/disk@yyy		CLIENT_TYPE_VHCI (sas)
5777c478bd9Sstevel@tonic-gate  * other				CLIENT_TYPE_UNKNOWN
5785a4c37c9Sqh201292  * on x86:
57960fffc19Sjw149990  * .../fp@xxx/disk@yyy			CLIENT_TYPE_PHCI (fc)
58060fffc19Sjw149990  * .../pci1000,????@xxx/sd@yyy		CLIENT_TYPE_PHCI (sas)
5815a4c37c9Sqh201292  * .../scsi_vhci/disk@yyy		CLIENT_TYPE_VHCI
5825a4c37c9Sqh201292  * other				CLIENT_TYPE_UNKNOWN
5837c478bd9Sstevel@tonic-gate  */
5847c478bd9Sstevel@tonic-gate static client_type_t
5857c478bd9Sstevel@tonic-gate client_name_type(char *client_name)
5867c478bd9Sstevel@tonic-gate {
5877c478bd9Sstevel@tonic-gate 	client_type_t client_type = CLIENT_TYPE_UNKNOWN;
58860fffc19Sjw149990 	char *p1;
58960fffc19Sjw149990 	char *client_path;
59060fffc19Sjw149990 
59160fffc19Sjw149990 	client_path = s_strdup(client_name);
59260fffc19Sjw149990 	logdmsg("client_name_type: client is %s\n", client_path);
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	if (*client_name != '/')
5957c478bd9Sstevel@tonic-gate 		return (CLIENT_TYPE_UNKNOWN);
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	if ((p1 = strrchr(client_name, '/')) == NULL ||
59860fffc19Sjw149990 	    ((strncmp(p1, "/ssd@", sizeof ("/ssd@") - 1) != 0) &&
59960fffc19Sjw149990 	    (strncmp(p1, "/sd@", sizeof ("/sd@") - 1) != 0) &&
60060fffc19Sjw149990 	    (strncmp(p1, "/disk@", sizeof ("/disk@") - 1) != 0))) {
60160fffc19Sjw149990 		logdmsg("client_name_type: p1 = %s\n", p1);
6027c478bd9Sstevel@tonic-gate 		return (CLIENT_TYPE_UNKNOWN);
60360fffc19Sjw149990 	}
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	*p1 = '\0';
6067c478bd9Sstevel@tonic-gate 
60760fffc19Sjw149990 	/*
60860fffc19Sjw149990 	 * Courtesy of the if (..) block above, we know that any
60960fffc19Sjw149990 	 * device path we have now is either PHCI or VHCI
61060fffc19Sjw149990 	 */
61160fffc19Sjw149990 	client_type = client_by_props(client_path);
61260fffc19Sjw149990 
61360fffc19Sjw149990 	logdmsg("client_name_type: client_type = %d\n", client_type);
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	*p1 = '/';
6167c478bd9Sstevel@tonic-gate 	return (client_type);
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate /*
62060fffc19Sjw149990  * client_by_props() is called to determine what the client type
62160fffc19Sjw149990  * is, based on properties in the device tree:
62260fffc19Sjw149990  *
62360fffc19Sjw149990  * drivername	property	type
62460fffc19Sjw149990  * -------------------------------------
62560fffc19Sjw149990  *  fp		node-wwn	CLIENT_TYPE_PHCI
62660fffc19Sjw149990  *  mpt		sas-mpt		CLIENT_TYPE_PHCI
62760fffc19Sjw149990  *  mpt		client-guid	CLIENT_TYPE_PHCI (corner case)
62860fffc19Sjw149990  *
62960fffc19Sjw149990  * Normally, the "client-guid" property only shows up for a node
63060fffc19Sjw149990  * if we've enumerated that node under scsi_vhci. During testing
63160fffc19Sjw149990  * of this function, one particular corner case was found which
63260fffc19Sjw149990  * requires an exception handler.
63360fffc19Sjw149990  */
63460fffc19Sjw149990 
63560fffc19Sjw149990 static client_type_t
63660fffc19Sjw149990 client_by_props(char *path) {
63760fffc19Sjw149990 
63860fffc19Sjw149990 	di_node_t clientnode = DI_NODE_NIL;
63960fffc19Sjw149990 	di_node_t parentnode = DI_NODE_NIL;
64060fffc19Sjw149990 	unsigned int rval = CLIENT_TYPE_UNKNOWN;
64160fffc19Sjw149990 	uchar_t *byteprop[32];
64260fffc19Sjw149990 	char *charprop = NULL;
64360fffc19Sjw149990 	char *physpath;
64460fffc19Sjw149990 	char *parentpath;
64560fffc19Sjw149990 
64660fffc19Sjw149990 	physpath = s_malloc(MAXPATHLEN);
64760fffc19Sjw149990 	bzero(physpath, MAXPATHLEN);
64860fffc19Sjw149990 
64960fffc19Sjw149990 	physpath = s_strdup(path);
65060fffc19Sjw149990 
65160fffc19Sjw149990 	logdmsg("client_by_props: physpath = (%s)\n", physpath);
65260fffc19Sjw149990 
65360fffc19Sjw149990 	/* easy short-circuits */
65460fffc19Sjw149990 	if (strstr(physpath, "scsi_vhci") != (char *)NULL) {
65560fffc19Sjw149990 		logdmsg("client_by_props: found "
65660fffc19Sjw149990 		    "'scsi_vhci' on path (%s)\n", physpath);
65760fffc19Sjw149990 		rval = CLIENT_TYPE_VHCI;
65860fffc19Sjw149990 		goto out;
65960fffc19Sjw149990 	} else if ((strstr(physpath, "ide") != (char *)NULL) ||
66060fffc19Sjw149990 	    (strstr(physpath, "storage") != (char *)NULL)) {
66160fffc19Sjw149990 		logdmsg("client_by_props: ignoring this device\n");
66260fffc19Sjw149990 		goto out;
66360fffc19Sjw149990 	}
66460fffc19Sjw149990 
66560fffc19Sjw149990 	parentpath = s_malloc(MAXPATHLEN);
66660fffc19Sjw149990 	bzero(parentpath, MAXPATHLEN);
66760fffc19Sjw149990 
66860fffc19Sjw149990 	(void) strncpy(parentpath, physpath, strlen(physpath) -
66960fffc19Sjw149990 	    strlen(strrchr(physpath, '/')));
67060fffc19Sjw149990 
67160fffc19Sjw149990 	if ((parentnode = di_init(parentpath, DINFOCPYALL |
67260fffc19Sjw149990 	    DINFOFORCE)) == DI_NODE_NIL) {
67360fffc19Sjw149990 		logdmsg("client_by_props: unable to di_init(%s)\n",
67460fffc19Sjw149990 		    parentpath);
67560fffc19Sjw149990 		goto out;
67660fffc19Sjw149990 	}
67760fffc19Sjw149990 
67860fffc19Sjw149990 	if (strstr(physpath, "fp") != (char *)NULL) {
67960fffc19Sjw149990 		if (drvprop == (char *)NULL) {
68060fffc19Sjw149990 			drvprop = s_malloc(strlen(NODE_WWN_PROP) + 1);
68160fffc19Sjw149990 		}
68260fffc19Sjw149990 		logdmsg("NODE_WWN_PROP\n");
68360fffc19Sjw149990 		(void) snprintf(drvprop, strlen(NODE_WWN_PROP) + 1,
68460fffc19Sjw149990 		    NODE_WWN_PROP);
68560fffc19Sjw149990 	} else {
68660fffc19Sjw149990 		if (drvname == (char *)NULL) {
68760fffc19Sjw149990 			drvname = di_driver_name(parentnode);
68860fffc19Sjw149990 			logdmsg("client_by_props: drvname = %s\n", drvname);
68960fffc19Sjw149990 		}
69060fffc19Sjw149990 
69160fffc19Sjw149990 		if (drvprop == (char *)NULL) {
69260fffc19Sjw149990 			drvprop = s_malloc(sizeof (SASPROP) +
69360fffc19Sjw149990 			    sizeof (drvname) + 1);
69460fffc19Sjw149990 		}
69560fffc19Sjw149990 		(void) snprintf(drvprop, sizeof (SASPROP) +
69660fffc19Sjw149990 		    sizeof (drvname), "%s%s", SASPROP, drvname);
69760fffc19Sjw149990 
69860fffc19Sjw149990 		logdmsg("parentpath: %s\nphyspath: %s\n"
69960fffc19Sjw149990 		    "length %d, strrchr: %d\n",
70060fffc19Sjw149990 		    parentpath, physpath, strlen(physpath),
70160fffc19Sjw149990 		    strlen(strrchr(physpath, '/')));
70260fffc19Sjw149990 	}
70360fffc19Sjw149990 
70460fffc19Sjw149990 	logdmsg("client_by_props: searching for property '%s'\n", drvprop);
70560fffc19Sjw149990 
70660fffc19Sjw149990 	if ((clientnode = di_init(physpath, DINFOCPYALL | DINFOFORCE)) ==
70760fffc19Sjw149990 	    DI_NODE_NIL) {
70860fffc19Sjw149990 		logdmsg("client_by_props: unable to di_init(%s)\n",
70960fffc19Sjw149990 		    physpath);
71060fffc19Sjw149990 
71160fffc19Sjw149990 		/*
71260fffc19Sjw149990 		 * On x86/x64 systems, we won't be able to di_init() the
71360fffc19Sjw149990 		 * node we want in the device tree, however the parent
71460fffc19Sjw149990 		 * node will still have 'mpxio-disable' set, so we can
71560fffc19Sjw149990 		 * check for that property and make our decision on type
71660fffc19Sjw149990 		 */
71760fffc19Sjw149990 
71860fffc19Sjw149990 		if (di_prop_lookup_strings(DDI_DEV_T_ANY, parentnode,
71960fffc19Sjw149990 		    "mpxio-disable", &charprop) > -1) {
72060fffc19Sjw149990 			rval = CLIENT_TYPE_PHCI;
72160fffc19Sjw149990 			di_fini(parentnode);
72260fffc19Sjw149990 			logdmsg("client_by_props: device %s is PHCI\n",
72360fffc19Sjw149990 			    physpath);
72460fffc19Sjw149990 		}
72560fffc19Sjw149990 		goto out;
72660fffc19Sjw149990 	}
72760fffc19Sjw149990 
72860fffc19Sjw149990 	if (di_prop_lookup_bytes(DDI_DEV_T_ANY,
72960fffc19Sjw149990 	    clientnode, drvprop, byteprop) > -1) {
73060fffc19Sjw149990 		logdmsg("client_by_props: found prop %s on "
73160fffc19Sjw149990 		    "path %s\n", drvprop, physpath);
73260fffc19Sjw149990 		rval = CLIENT_TYPE_PHCI;
73360fffc19Sjw149990 	} else if (di_prop_lookup_strings(DDI_DEV_T_ANY,
73460fffc19Sjw149990 	    clientnode, "client-guid", &charprop) > -1) {
73560fffc19Sjw149990 			/*
73660fffc19Sjw149990 			 * A corner case was seen during testing where
73760fffc19Sjw149990 			 * scsi_vhci was loaded, but not all applicable
73860fffc19Sjw149990 			 * devices were enumerated under it. That left
73960fffc19Sjw149990 			 * the phci mapping along with the "client-guid"
74060fffc19Sjw149990 			 * property.
74160fffc19Sjw149990 			 */
74260fffc19Sjw149990 			logdmsg("client_by_props: weird... \n");
74360fffc19Sjw149990 			rval = CLIENT_TYPE_PHCI;
74460fffc19Sjw149990 	} else {
74560fffc19Sjw149990 		logdmsg("client_by_props: unable to find "
74660fffc19Sjw149990 		    "property 'client-guid', 'mpxio-disable' "
74760fffc19Sjw149990 		    "or '%s' anywhere on path (%s)\n",
74860fffc19Sjw149990 		    drvprop, physpath);
74960fffc19Sjw149990 		logdmsg("client_by_props: this node is unknown\n");
75060fffc19Sjw149990 	}
75160fffc19Sjw149990 
75260fffc19Sjw149990 	di_fini(parentnode);
75360fffc19Sjw149990 	di_fini(clientnode);
75460fffc19Sjw149990 out:
75560fffc19Sjw149990 	free(physpath);
75660fffc19Sjw149990 	return (rval);
75760fffc19Sjw149990 }
75860fffc19Sjw149990 
75960fffc19Sjw149990 
76060fffc19Sjw149990 /*
761*8cecff49Sgp87344  * Given a phci or vhci devname which is either a /dev link or /devices name
762*8cecff49Sgp87344  * get the corresponding physical node path (without the /devices prefix)
763*8cecff49Sgp87344  * and minor name.
764*8cecff49Sgp87344  *
765*8cecff49Sgp87344  * Returns 0 on success, -1 on failure.
766*8cecff49Sgp87344  */
767*8cecff49Sgp87344 static int
768*8cecff49Sgp87344 get_physname_minor(char *devname, char *physname, int physname_len,
769*8cecff49Sgp87344     char *minorname, int minorname_len)
770*8cecff49Sgp87344 {
771*8cecff49Sgp87344 	int linksize;
772*8cecff49Sgp87344 	char buf[MAXPATHLEN];
773*8cecff49Sgp87344 	char *p, *m;
774*8cecff49Sgp87344 
775*8cecff49Sgp87344 	if (strncmp(devname, DEV_DSK, sizeof (DEV_DSK) - 1) == 0 ||
776*8cecff49Sgp87344 	    strncmp(devname, DEV_RDSK, sizeof (DEV_RDSK) - 1) == 0) {
777*8cecff49Sgp87344 		if ((linksize = readlink(devname, buf, MAXPATHLEN))
778*8cecff49Sgp87344 		    > 0 && linksize <= (MAXPATHLEN - 1)) {
779*8cecff49Sgp87344 			buf[linksize] = '\0';
780*8cecff49Sgp87344 		} else
781*8cecff49Sgp87344 			return (-1);
782*8cecff49Sgp87344 	} else
783*8cecff49Sgp87344 		s_strlcpy(buf, devname, MAXPATHLEN);
784*8cecff49Sgp87344 
785*8cecff49Sgp87344 	if ((p = strstr(buf, SLASH_DEVICES)) == NULL)
786*8cecff49Sgp87344 		return (-1);
787*8cecff49Sgp87344 
788*8cecff49Sgp87344 	/* point to '/' after /devices */
789*8cecff49Sgp87344 	p += sizeof (SLASH_DEVICES) - 2;
790*8cecff49Sgp87344 
791*8cecff49Sgp87344 	if ((m = strrchr(p, ':')) == NULL) {
792*8cecff49Sgp87344 		logdmsg("get_physname_minor: no minor name component in %s\n",
793*8cecff49Sgp87344 		    buf);
794*8cecff49Sgp87344 		return (-1);
795*8cecff49Sgp87344 	}
796*8cecff49Sgp87344 
797*8cecff49Sgp87344 	*m = '\0';
798*8cecff49Sgp87344 	m++;
799*8cecff49Sgp87344 
800*8cecff49Sgp87344 	if (client_name_type(p) == CLIENT_TYPE_UNKNOWN)
801*8cecff49Sgp87344 		return (-1);
802*8cecff49Sgp87344 
803*8cecff49Sgp87344 	s_strlcpy(physname, p, physname_len);
804*8cecff49Sgp87344 	s_strlcpy(minorname, m, minorname_len);
805*8cecff49Sgp87344 	logdmsg("get_physname_minor: %s: physname = %s, minor = %s\n",
806*8cecff49Sgp87344 	    devname, physname, minorname);
807*8cecff49Sgp87344 	return (0);
808*8cecff49Sgp87344 }
809*8cecff49Sgp87344 
810*8cecff49Sgp87344 
811*8cecff49Sgp87344 /*
8127c478bd9Sstevel@tonic-gate  * Map phci based client name to vhci based client name.
8137c478bd9Sstevel@tonic-gate  *
8147c478bd9Sstevel@tonic-gate  * phci_name
8157c478bd9Sstevel@tonic-gate  *	phci based client /devices name without the /devices prefix and
8167c478bd9Sstevel@tonic-gate  *	minor name component.
8175a4c37c9Sqh201292  *	ex:
81860fffc19Sjw149990  *
81960fffc19Sjw149990  *	(FC)
8205a4c37c9Sqh201292  *	for sparc: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
8215a4c37c9Sqh201292  *	for x86: /pci@8,600000/SUNW,qlc@4/fp@0,0/disk@w2100002037cd9f72,0
8227c478bd9Sstevel@tonic-gate  *
82360fffc19Sjw149990  *	(SAS)
82460fffc19Sjw149990  *	for sparc: /pci@0,2/LSILogic,sas@1/disk@6,0
82560fffc19Sjw149990  *	for x86: /pci1000,3060@3/sd@0,0
82660fffc19Sjw149990  *
8277c478bd9Sstevel@tonic-gate  * vhci_name
8287c478bd9Sstevel@tonic-gate  *	Caller supplied buffer where vhci /devices name will be placed on
8297c478bd9Sstevel@tonic-gate  *	return (without the /devices prefix and minor name component).
8305a4c37c9Sqh201292  *	ex:
83160fffc19Sjw149990  *
83260fffc19Sjw149990  *	(FC)
8335a4c37c9Sqh201292  *	for sparc: /scsi_vhci/ssd@g2000002037cd9f72
8345a4c37c9Sqh201292  *	for x86: /scsi_vhci/disk@g2000002037cd9f72
8357c478bd9Sstevel@tonic-gate  *
83660fffc19Sjw149990  *	(SAS)
83760fffc19Sjw149990  *	both: /scsi_vhci/disk@g600a0b8000254d3e00000284453ed8ac
83860fffc19Sjw149990  *
8397c478bd9Sstevel@tonic-gate  * vhci_name_len
8407c478bd9Sstevel@tonic-gate  *	Length of the caller supplied vhci_name buffer.
8417c478bd9Sstevel@tonic-gate  *
8427c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
8437c478bd9Sstevel@tonic-gate  */
8447c478bd9Sstevel@tonic-gate static int
8457c478bd9Sstevel@tonic-gate phci_to_vhci(char *phci_name, char *vhci_name, size_t vhci_name_len)
8467c478bd9Sstevel@tonic-gate {
8477c478bd9Sstevel@tonic-gate 	sv_iocdata_t ioc;
84860fffc19Sjw149990 	char *slash, *at;
8497c478bd9Sstevel@tonic-gate 	char vhci_name_buf[MAXPATHLEN];
8507c478bd9Sstevel@tonic-gate 	char phci_name_buf[MAXPATHLEN];
8517c478bd9Sstevel@tonic-gate 	char addr_buf[MAXNAMELEN];
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	logdmsg("phci_to_vhci: client = %s\n", phci_name);
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 	s_strlcpy(phci_name_buf, phci_name, MAXPATHLEN);
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	if (client_name_type(phci_name_buf) != CLIENT_TYPE_PHCI ||
8587c478bd9Sstevel@tonic-gate 	    (slash = strrchr(phci_name_buf, '/')) == NULL ||
85960fffc19Sjw149990 	    ((strncmp(slash, "/ssd@", sizeof ("/ssd@") - 1) != 0) &&
86060fffc19Sjw149990 	    (strncmp(slash, "/sd@", sizeof ("/sd@") - 1) != 0) &&
86160fffc19Sjw149990 	    (strncmp(slash, "/disk@", sizeof ("/disk@") - 1) != 0))) {
8627c478bd9Sstevel@tonic-gate 		logdmsg("phci_to_vhci: %s is not of CLIENT_TYPE_PHCI\n",
8637c478bd9Sstevel@tonic-gate 		    phci_name);
8647c478bd9Sstevel@tonic-gate 		return (-1);
8657c478bd9Sstevel@tonic-gate 	}
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	if (vhci_fd < 0) {
8687c478bd9Sstevel@tonic-gate 		if ((vhci_fd = open(VHCI_CTL_NODE, O_RDWR)) < 0)
8697c478bd9Sstevel@tonic-gate 			return (-1);
8707c478bd9Sstevel@tonic-gate 	}
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	*slash = '\0';
87360fffc19Sjw149990 
87460fffc19Sjw149990 	at = strchr(slash + 1, '@');
87560fffc19Sjw149990 	s_strlcpy(addr_buf, at + 1, MAXNAMELEN);
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	bzero(&ioc, sizeof (sv_iocdata_t));
8787c478bd9Sstevel@tonic-gate 	ioc.client = vhci_name_buf;
8797c478bd9Sstevel@tonic-gate 	ioc.phci = phci_name_buf;
8807c478bd9Sstevel@tonic-gate 	ioc.addr = addr_buf;
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	if (ioctl(vhci_fd, SCSI_VHCI_GET_CLIENT_NAME, &ioc) != 0) {
8837c478bd9Sstevel@tonic-gate 		logdmsg("SCSI_VHCI_GET_CLIENT_NAME on %s "
8847c478bd9Sstevel@tonic-gate 		    "failed: %s\n", phci_name, strerror(errno));
8857c478bd9Sstevel@tonic-gate 		return (-1);
8867c478bd9Sstevel@tonic-gate 	}
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	s_strlcpy(vhci_name, vhci_name_buf, vhci_name_len);
8897c478bd9Sstevel@tonic-gate 	logdmsg("phci_to_vhci: %s maps to %s\n", phci_name, vhci_name);
8907c478bd9Sstevel@tonic-gate 	return (0);
8917c478bd9Sstevel@tonic-gate }
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate /*
8947c478bd9Sstevel@tonic-gate  * Map vhci based client name to phci based client name.
8957c478bd9Sstevel@tonic-gate  * If the client has multiple paths, only one of the paths with which client
8967c478bd9Sstevel@tonic-gate  * can be accessed is returned. This function does not use SCSI_VHCI ioctls
8977c478bd9Sstevel@tonic-gate  * as it is called on mpxio disabled paths.
8987c478bd9Sstevel@tonic-gate  *
8997c478bd9Sstevel@tonic-gate  * vhci_name
9007c478bd9Sstevel@tonic-gate  *	vhci based client /devices name without the /devices prefix and
9017c478bd9Sstevel@tonic-gate  *	minor name component.
9025a4c37c9Sqh201292  *	ex:
9035a4c37c9Sqh201292  *	sparc: /scsi_vhci/ssd@g2000002037cd9f72
9045a4c37c9Sqh201292  *	x86: /scsi_vhci/disk@g2000002037cd9f72
9057c478bd9Sstevel@tonic-gate  *
9067c478bd9Sstevel@tonic-gate  * phci_name
9077c478bd9Sstevel@tonic-gate  *	Caller supplied buffer where phci /devices name will be placed on
9087c478bd9Sstevel@tonic-gate  *	return (without the /devices prefix and minor name component).
9095a4c37c9Sqh201292  *	ex:
9105a4c37c9Sqh201292  *	sparc: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
9115a4c37c9Sqh201292  *	x86: /pci@8,600000/SUNW,qlc@4/fp@0,0/disk@w2100002037cd9f72,0
9127c478bd9Sstevel@tonic-gate  *
9137c478bd9Sstevel@tonic-gate  * phci_name_len
9147c478bd9Sstevel@tonic-gate  *	Length of the caller supplied phci_name buffer.
9157c478bd9Sstevel@tonic-gate  *
916*8cecff49Sgp87344  * minor
917*8cecff49Sgp87344  *	The slice of the disk of interest.
918*8cecff49Sgp87344  *
9197c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
9207c478bd9Sstevel@tonic-gate  */
9217c478bd9Sstevel@tonic-gate static int
922*8cecff49Sgp87344 vhci_to_phci(char *vhci_name, char *phci_name, size_t phci_name_len,
923*8cecff49Sgp87344     char *minor)
9247c478bd9Sstevel@tonic-gate {
92560fffc19Sjw149990 	di_node_t node = DI_NODE_NIL;
9267c478bd9Sstevel@tonic-gate 	char *vhci_guid, *devfspath;
9277c478bd9Sstevel@tonic-gate 	char phci_guid[MAXPATHLEN];
928*8cecff49Sgp87344 	char root_guid[MAXPATHLEN];
929*8cecff49Sgp87344 	char root_phys[MAXPATHLEN];
930*8cecff49Sgp87344 	char root_minor[MAXPATHLEN];
931*8cecff49Sgp87344 	char root_path[MAXPATHLEN];
93260fffc19Sjw149990 	char *node_name;
933*8cecff49Sgp87344 	FILE *mntfp;
934*8cecff49Sgp87344 	struct mnttab mntpref, rootmnt;
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 	logdmsg("vhci_to_phci: client = %s\n", vhci_name);
9377c478bd9Sstevel@tonic-gate 
938*8cecff49Sgp87344 	bzero(&mntpref, sizeof (mntpref));
939*8cecff49Sgp87344 	mntpref.mnt_mountp = "/";
940*8cecff49Sgp87344 
941*8cecff49Sgp87344 	if (!(mntfp = fopen(MNTTAB, "r"))) {
942*8cecff49Sgp87344 		logdmsg("vhci_to_phci: can't open %s\n", MNTTAB);
943*8cecff49Sgp87344 		return (-1);
944*8cecff49Sgp87344 	}
945*8cecff49Sgp87344 
946*8cecff49Sgp87344 	if (getmntany(mntfp, &rootmnt, &mntpref)) {
947*8cecff49Sgp87344 		logdmsg("vhci_to_phci: can't find / in %s\n", MNTTAB);
948*8cecff49Sgp87344 		return (-1);
949*8cecff49Sgp87344 	}
950*8cecff49Sgp87344 
951*8cecff49Sgp87344 	(void) fclose(mntfp);
952*8cecff49Sgp87344 
9537c478bd9Sstevel@tonic-gate 	if (client_name_type(vhci_name) != CLIENT_TYPE_VHCI) {
9547c478bd9Sstevel@tonic-gate 		logdmsg("vhci_to_phci: %s is not of CLIENT_TYPE_VHCI\n",
9557c478bd9Sstevel@tonic-gate 		    vhci_name);
9567c478bd9Sstevel@tonic-gate 		return (-1);
9577c478bd9Sstevel@tonic-gate 	}
9587c478bd9Sstevel@tonic-gate 
95960fffc19Sjw149990 
9607c478bd9Sstevel@tonic-gate 	if ((vhci_guid = strrchr(vhci_name, '@')) == NULL ||
9617c478bd9Sstevel@tonic-gate 	    *(++vhci_guid) != 'g') {
9627c478bd9Sstevel@tonic-gate 		logerr(gettext("couldn't get guid from %s\n"), vhci_name);
9637c478bd9Sstevel@tonic-gate 		return (-1);
9647c478bd9Sstevel@tonic-gate 	}
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	/* point to guid */
9677c478bd9Sstevel@tonic-gate 	++vhci_guid;
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	/*
9707c478bd9Sstevel@tonic-gate 	 * Get devinfo snapshot and walk all ssd nodes whose parent is fp.
9717c478bd9Sstevel@tonic-gate 	 * For each node get the guid and match it with vhci_guid.
9727c478bd9Sstevel@tonic-gate 	 */
9737c478bd9Sstevel@tonic-gate 	if (devinfo_root == DI_NODE_NIL) {
9747c478bd9Sstevel@tonic-gate 		logdmsg("vhci_to_phci: taking devinfo snapshot\n");
9757c478bd9Sstevel@tonic-gate 		if ((devinfo_root = di_init("/", DINFOCPYALL | DINFOFORCE))
9767c478bd9Sstevel@tonic-gate 		    == DI_NODE_NIL) {
9777c478bd9Sstevel@tonic-gate 			logerr(gettext("di_init failed: %s\n"),
9787c478bd9Sstevel@tonic-gate 			    strerror(errno));
9797c478bd9Sstevel@tonic-gate 			return (-1);
9807c478bd9Sstevel@tonic-gate 		}
9817c478bd9Sstevel@tonic-gate 		logdmsg("vhci_to_phci: done taking devinfo snapshot\n");
9827c478bd9Sstevel@tonic-gate 	}
9837c478bd9Sstevel@tonic-gate 
984*8cecff49Sgp87344 	if (strncmp(rootmnt.mnt_special, SLASH_DEVICES,
985*8cecff49Sgp87344 	    sizeof (SLASH_DEVICES)-1))
986*8cecff49Sgp87344 		(void) snprintf(root_path, sizeof (root_path), "/devices%s",
987*8cecff49Sgp87344 		    rootmnt.mnt_special);
988*8cecff49Sgp87344 	else
989*8cecff49Sgp87344 		(void) strcpy(root_path, rootmnt.mnt_special);
990*8cecff49Sgp87344 
991*8cecff49Sgp87344 	/*
992*8cecff49Sgp87344 	 * remove the /devices and minor components to call get_guid()
993*8cecff49Sgp87344 	 * if we can't get the guid, drop through to the regular processing.
994*8cecff49Sgp87344 	 */
995*8cecff49Sgp87344 	if ((get_physname_minor(root_path, root_phys, sizeof (root_phys),
996*8cecff49Sgp87344 	    root_minor, sizeof (root_minor)) ||
997*8cecff49Sgp87344 	    (get_guid(root_phys, root_guid, sizeof (root_guid), 0,
998*8cecff49Sgp87344 	    node) != 0))) {
999*8cecff49Sgp87344 		logdmsg("vhci_to_phci: can't get_guid for / (%s)\n",
1000*8cecff49Sgp87344 		    rootmnt.mnt_special);
1001*8cecff49Sgp87344 		(void) strcpy(root_guid, "");
1002*8cecff49Sgp87344 	}
1003*8cecff49Sgp87344 
1004*8cecff49Sgp87344 	/*
1005*8cecff49Sgp87344 	 * We check the guid of the root device against the vhci guid so we
1006*8cecff49Sgp87344 	 * can return a preferred path.
1007*8cecff49Sgp87344 	 */
1008*8cecff49Sgp87344 	if ((strcmp(root_guid, vhci_guid) == 0) &&
1009*8cecff49Sgp87344 	    (canread(root_phys, minor))) {
1010*8cecff49Sgp87344 		s_strlcpy(phci_name, root_phys, phci_name_len);
1011*8cecff49Sgp87344 		logdmsg("vhci_to_phci: %s maps to %s preferred path\n",
1012*8cecff49Sgp87344 		    vhci_name, phci_name);
1013*8cecff49Sgp87344 		return (0);
1014*8cecff49Sgp87344 	}
101560fffc19Sjw149990 
101660fffc19Sjw149990 	/*
101760fffc19Sjw149990 	 * When we finally get a unified "sd" driver for all
101860fffc19Sjw149990 	 * architectures that Solaris runs on, we can remove this
101960fffc19Sjw149990 	 * first loop around for "ssd"
102060fffc19Sjw149990 	 */
102160fffc19Sjw149990 	for (node = di_drv_first_node("ssd", devinfo_root);
10227c478bd9Sstevel@tonic-gate 	    node != DI_NODE_NIL; node = di_drv_next_node(node)) {
102360fffc19Sjw149990 
102460fffc19Sjw149990 		if ((node_name = di_node_name(node)) == NULL)
102560fffc19Sjw149990 			continue;
102660fffc19Sjw149990 
102760fffc19Sjw149990 		if ((strcmp(node_name, "disk") != 0) &&
102860fffc19Sjw149990 		    (strcmp(node_name, "sd") != 0) &&
102960fffc19Sjw149990 		    (strcmp(node_name, "ssd") != 0))
103060fffc19Sjw149990 			continue;
103160fffc19Sjw149990 
103260fffc19Sjw149990 		if (di_parent_node(node) == DI_NODE_NIL)
103360fffc19Sjw149990 			continue;
103460fffc19Sjw149990 
103560fffc19Sjw149990 		if ((devfspath = di_devfs_path(node)) == NULL)
10367c478bd9Sstevel@tonic-gate 			continue;
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 		/*
10397c478bd9Sstevel@tonic-gate 		 * Don't set no_delay_flag to have get_guid() fail on
10407c478bd9Sstevel@tonic-gate 		 * standby paths of T3. So we'll find the preferred paths.
10417c478bd9Sstevel@tonic-gate 		 */
10427c478bd9Sstevel@tonic-gate 		if (get_guid(devfspath, phci_guid,
104360fffc19Sjw149990 		    sizeof (phci_guid), 0, node) != 0)
104460fffc19Sjw149990 			continue;
104560fffc19Sjw149990 
1046*8cecff49Sgp87344 		/*
1047*8cecff49Sgp87344 		 * If the GUID's match, and we can read data from the path of
1048*8cecff49Sgp87344 		 * interest, we conclude we have the correct path to use.
1049*8cecff49Sgp87344 		 */
1050*8cecff49Sgp87344 		if ((strcmp(phci_guid, vhci_guid) == 0) &&
1051*8cecff49Sgp87344 		    (canread(devfspath, minor)))  {
105260fffc19Sjw149990 			s_strlcpy(phci_name, devfspath, phci_name_len);
105360fffc19Sjw149990 			di_devfs_path_free(devfspath);
105460fffc19Sjw149990 			logdmsg("vhci_to_phci: %s maps to %s\n", vhci_name,
105560fffc19Sjw149990 			    phci_name);
105660fffc19Sjw149990 			return (0);
105760fffc19Sjw149990 		}
105860fffc19Sjw149990 
105960fffc19Sjw149990 		di_devfs_path_free(devfspath);
106060fffc19Sjw149990 	}
106160fffc19Sjw149990 
106260fffc19Sjw149990 	for (node = di_drv_first_node("sd", devinfo_root);
106360fffc19Sjw149990 	    node != DI_NODE_NIL; node = di_drv_next_node(node)) {
106460fffc19Sjw149990 
106560fffc19Sjw149990 		if ((node_name = di_node_name(node)) == NULL)
106660fffc19Sjw149990 			continue;
106760fffc19Sjw149990 
106860fffc19Sjw149990 		if ((strcmp(node_name, "disk") != 0) &&
106960fffc19Sjw149990 		    (strcmp(node_name, "sd") != 0) &&
107060fffc19Sjw149990 		    (strcmp(node_name, "ssd") != 0))
107160fffc19Sjw149990 			continue;
107260fffc19Sjw149990 
107360fffc19Sjw149990 		if (di_parent_node(node) == DI_NODE_NIL)
107460fffc19Sjw149990 			continue;
107560fffc19Sjw149990 
107660fffc19Sjw149990 		if ((devfspath = di_devfs_path(node)) == NULL)
107760fffc19Sjw149990 			continue;
107860fffc19Sjw149990 
107960fffc19Sjw149990 		/*
108060fffc19Sjw149990 		 * Don't set no_delay_flag to have get_guid() fail on
108160fffc19Sjw149990 		 * standby paths of T3. So we'll find the preferred paths.
108260fffc19Sjw149990 		 */
108360fffc19Sjw149990 		if (get_guid(devfspath, phci_guid,
108460fffc19Sjw149990 		    sizeof (phci_guid), 0, node) != 0)
108560fffc19Sjw149990 			continue;
108660fffc19Sjw149990 
1087*8cecff49Sgp87344 		/*
1088*8cecff49Sgp87344 		 * If the GUID's match, and we can read data from the path of
1089*8cecff49Sgp87344 		 * interest, we conclude we have the correct path to use.
1090*8cecff49Sgp87344 		 */
1091*8cecff49Sgp87344 		if ((strcmp(phci_guid, vhci_guid) == 0) &&
1092*8cecff49Sgp87344 		    (canread(devfspath, minor))) {
10937c478bd9Sstevel@tonic-gate 			s_strlcpy(phci_name, devfspath, phci_name_len);
10947c478bd9Sstevel@tonic-gate 			di_devfs_path_free(devfspath);
10957c478bd9Sstevel@tonic-gate 			logdmsg("vhci_to_phci: %s maps to %s\n", vhci_name,
10967c478bd9Sstevel@tonic-gate 			    phci_name);
10977c478bd9Sstevel@tonic-gate 			return (0);
10987c478bd9Sstevel@tonic-gate 		}
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
11017c478bd9Sstevel@tonic-gate 	}
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 	logdmsg("vhci_to_phci: couldn't get phci name for %s\n", vhci_name);
11047c478bd9Sstevel@tonic-gate 	return (-1);
11057c478bd9Sstevel@tonic-gate }
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate /*
11085a4c37c9Sqh201292  * Map vhci based client name to phci based client name.
11095a4c37c9Sqh201292  * If the client has multiple paths, only one of the paths with which client
11105a4c37c9Sqh201292  * can be accessed is returned.
11115a4c37c9Sqh201292  * This function uses SCSI_VHCI ioctls to get the phci paths
11125a4c37c9Sqh201292  *
11135a4c37c9Sqh201292  * vhci_name
11145a4c37c9Sqh201292  *	vhci based client /devices name without the /devices prefix and
11155a4c37c9Sqh201292  *	minor name component.
11165a4c37c9Sqh201292  *	ex:
11175a4c37c9Sqh201292  *	sparc: /scsi_vhci/ssd@g2000002037cd9f72
11185a4c37c9Sqh201292  *	x86: /scsi_vhci/disk@g2000002037cd9f72
11195a4c37c9Sqh201292  *
11205a4c37c9Sqh201292  * phci_name
11215a4c37c9Sqh201292  *	Caller supplied buffer where phci /devices name will be placed on
11225a4c37c9Sqh201292  *	return (without the /devices prefix and minor name component).
11235a4c37c9Sqh201292  *	ex:
11245a4c37c9Sqh201292  *	sparc: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
11255a4c37c9Sqh201292  *	x86: /pci@8,600000/SUNW,qlc@4/fp@0,0/disk@w2100002037cd9f72,0
11265a4c37c9Sqh201292  *
11275a4c37c9Sqh201292  * phci_name_len
11285a4c37c9Sqh201292  *	Length of the caller supplied phci_name buffer.
11295a4c37c9Sqh201292  *
11305a4c37c9Sqh201292  * Returns 0 on success, -1 on failure.
11315a4c37c9Sqh201292  */
11325a4c37c9Sqh201292 
11335a4c37c9Sqh201292 static int
11345a4c37c9Sqh201292 vhci_to_phci_by_ioctl(char *vhci_name, char *phci_name, size_t phci_name_len)
11355a4c37c9Sqh201292 {
11365a4c37c9Sqh201292 	sv_iocdata_t	ioc;
11375a4c37c9Sqh201292 	uint_t npaths;
11385a4c37c9Sqh201292 	char *node_name, *at;
11395a4c37c9Sqh201292 	char vhci_name_buf[MAXPATHLEN];
11405a4c37c9Sqh201292 	int  ret;
11415a4c37c9Sqh201292 	sv_path_info_t *pi;
11425a4c37c9Sqh201292 
11435a4c37c9Sqh201292 	logdmsg("vhci_to_phci_by_ioctl: client = %s\n", vhci_name);
11445a4c37c9Sqh201292 
11455a4c37c9Sqh201292 	if (vhci_fd < 0) {
11465a4c37c9Sqh201292 		if ((vhci_fd = open(VHCI_CTL_NODE, O_RDWR)) < 0)
11475a4c37c9Sqh201292 			return (-1);
11485a4c37c9Sqh201292 	}
11495a4c37c9Sqh201292 
11505a4c37c9Sqh201292 	(void) strlcpy(vhci_name_buf, vhci_name, MAXPATHLEN);
11515a4c37c9Sqh201292 
11525a4c37c9Sqh201292 	/* first get the number paths */
11535a4c37c9Sqh201292 	bzero(&ioc, sizeof (sv_iocdata_t));
11545a4c37c9Sqh201292 	ioc.client = vhci_name_buf;
11555a4c37c9Sqh201292 	ioc.ret_elem = &npaths;
11565a4c37c9Sqh201292 	if ((ret = ioctl(vhci_fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO,
11575a4c37c9Sqh201292 	    &ioc)) != 0 || npaths == 0) {
11585a4c37c9Sqh201292 		logdmsg("SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO on %s "
11595a4c37c9Sqh201292 		    "failed: %s\n", vhci_name,
11605a4c37c9Sqh201292 		    ret?strerror(errno):"got 0 paths");
11615a4c37c9Sqh201292 		return (-1);
11625a4c37c9Sqh201292 	}
11635a4c37c9Sqh201292 
11645a4c37c9Sqh201292 	/* now allocate memory for the path information and get all paths */
11655a4c37c9Sqh201292 	bzero(&ioc, sizeof (sv_iocdata_t));
11665a4c37c9Sqh201292 	ioc.client = vhci_name_buf;
11675a4c37c9Sqh201292 	ioc.buf_elem = npaths;
11685a4c37c9Sqh201292 	ioc.ret_elem = &npaths;
11695a4c37c9Sqh201292 	if ((ioc.ret_buf = (sv_path_info_t *)calloc(npaths,
11705a4c37c9Sqh201292 	    sizeof (sv_path_info_t))) == NULL)
11715a4c37c9Sqh201292 		return (-1);
11725a4c37c9Sqh201292 	if ((ret = ioctl(vhci_fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO,
11735a4c37c9Sqh201292 	    &ioc)) != 0 || npaths == 0) {
11745a4c37c9Sqh201292 		logdmsg("SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO on %s "
11755a4c37c9Sqh201292 		    "failed: %s\n", vhci_name,
11765a4c37c9Sqh201292 		    ret?strerror(errno):"got 0 paths");
11775a4c37c9Sqh201292 		goto out;
11785a4c37c9Sqh201292 	}
11795a4c37c9Sqh201292 
11805a4c37c9Sqh201292 	if (ioc.buf_elem < npaths)
11815a4c37c9Sqh201292 		npaths = ioc.buf_elem;
11825a4c37c9Sqh201292 	if ((node_name = strrchr(vhci_name_buf, '/')) == NULL ||
11835a4c37c9Sqh201292 	    (at = strchr(node_name, '@')) == NULL)
11845a4c37c9Sqh201292 		goto out;
11855a4c37c9Sqh201292 
11865a4c37c9Sqh201292 	node_name++;
11875a4c37c9Sqh201292 	*at = '\0';
11885a4c37c9Sqh201292 
118960fffc19Sjw149990 	logdmsg("vhci_to_phci_by_ioctl: node_name is %s\n", node_name);
119060fffc19Sjw149990 #ifndef sparc
119160fffc19Sjw149990 	/*
119260fffc19Sjw149990 	 * We need to use a libdevinfo call to get this info
119360fffc19Sjw149990 	 * in an architecturally-neutral fashion. Phase-II for sure!
119460fffc19Sjw149990 	 */
119560fffc19Sjw149990 	node_name = "sd";
119660fffc19Sjw149990 #endif
119760fffc19Sjw149990 
11985a4c37c9Sqh201292 	/*
11995a4c37c9Sqh201292 	 * return the first online paths as non-online paths may
12005a4c37c9Sqh201292 	 * not be accessible in the target environment.
12015a4c37c9Sqh201292 	 */
12025a4c37c9Sqh201292 	pi = (sv_path_info_t *)ioc.ret_buf;
12035a4c37c9Sqh201292 	while (npaths--) {
12045a4c37c9Sqh201292 		if (MDI_PATHINFO_STATE_ONLINE == pi->ret_state) {
12055a4c37c9Sqh201292 			(void) snprintf(phci_name, phci_name_len, "%s/%s@%s",
12065a4c37c9Sqh201292 			    pi->device.ret_phci, node_name,
12075a4c37c9Sqh201292 			    pi->ret_addr);
12085a4c37c9Sqh201292 			logdmsg("vhci_to_phci_by_ioctl: %s maps to %s\n",
12095a4c37c9Sqh201292 			    vhci_name, phci_name);
12105a4c37c9Sqh201292 			free(ioc.ret_buf);
12115a4c37c9Sqh201292 			return (0);
12125a4c37c9Sqh201292 		}
12135a4c37c9Sqh201292 		pi++;
12145a4c37c9Sqh201292 	}
12155a4c37c9Sqh201292 
12165a4c37c9Sqh201292 out:
12175a4c37c9Sqh201292 	logdmsg("vhci_to_phci_by_ioctl: couldn't get phci name for %s\n",
12185a4c37c9Sqh201292 	    vhci_name);
12195a4c37c9Sqh201292 	free(ioc.ret_buf);
12205a4c37c9Sqh201292 	return (-1);
12215a4c37c9Sqh201292 
12225a4c37c9Sqh201292 }
12235a4c37c9Sqh201292 
12245a4c37c9Sqh201292 /*
12257c478bd9Sstevel@tonic-gate  * Map physname from phci name space to vhci name space or vice-versa
12267c478bd9Sstevel@tonic-gate  *
12277c478bd9Sstevel@tonic-gate  * physname
12287c478bd9Sstevel@tonic-gate  *	phci or vhci based client /devices name without the /devices prefix and
12297c478bd9Sstevel@tonic-gate  *	minor name component.
12307c478bd9Sstevel@tonic-gate  *
12317c478bd9Sstevel@tonic-gate  * new_physname
12327c478bd9Sstevel@tonic-gate  *	Caller supplied buffer where the mapped physical name is stored on
12337c478bd9Sstevel@tonic-gate  *	return (without the /devices prefix and minor name component).
12347c478bd9Sstevel@tonic-gate  *
12357c478bd9Sstevel@tonic-gate  * len
12367c478bd9Sstevel@tonic-gate  *	Length of the caller supplied new_physname buffer.
12377c478bd9Sstevel@tonic-gate  *
1238*8cecff49Sgp87344  * minor
1239*8cecff49Sgp87344  *	The slice of the disk of interest.
1240*8cecff49Sgp87344  *
12417c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
12427c478bd9Sstevel@tonic-gate  */
12437c478bd9Sstevel@tonic-gate static int
1244*8cecff49Sgp87344 map_physname(char *physname, char *new_physname, size_t len, char *minor)
12457c478bd9Sstevel@tonic-gate {
12467c478bd9Sstevel@tonic-gate 	int type;
12477c478bd9Sstevel@tonic-gate 	int rv;
12487c478bd9Sstevel@tonic-gate 
124960fffc19Sjw149990 	type = client_name_type(physname);
125060fffc19Sjw149990 	logdmsg("map_physname: type (%d) physname = %s\n",
125160fffc19Sjw149990 	    type, physname);
125260fffc19Sjw149990 
125360fffc19Sjw149990 	if (type == CLIENT_TYPE_VHCI)
1254*8cecff49Sgp87344 		rv = vhci_to_phci(physname, new_physname, len, minor);
12557c478bd9Sstevel@tonic-gate 	else if (type == CLIENT_TYPE_PHCI)
12567c478bd9Sstevel@tonic-gate 		rv = phci_to_vhci(physname, new_physname, len);
12577c478bd9Sstevel@tonic-gate 	else
12587c478bd9Sstevel@tonic-gate 		rv = -1;
12597c478bd9Sstevel@tonic-gate 
126060fffc19Sjw149990 	logdmsg("map_physname: returning %d\n", rv);
12617c478bd9Sstevel@tonic-gate 	return (rv);
12627c478bd9Sstevel@tonic-gate }
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate static int
12657c478bd9Sstevel@tonic-gate devlink_callback(di_devlink_t devlink, void *argptr)
12667c478bd9Sstevel@tonic-gate {
12677c478bd9Sstevel@tonic-gate 	const char *link;
12687c478bd9Sstevel@tonic-gate 	struct devlink_cbarg *argp = argptr;
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	if ((link = di_devlink_path(devlink)) != NULL) {
12717c478bd9Sstevel@tonic-gate 		s_strlcpy(argp->devlink, link, argp->len);
12727c478bd9Sstevel@tonic-gate 		return (DI_WALK_TERMINATE);
12737c478bd9Sstevel@tonic-gate 	}
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
12767c478bd9Sstevel@tonic-gate }
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate /*
12797c478bd9Sstevel@tonic-gate  * Lookup the /dev link corresponding to physname and minorname.
12807c478bd9Sstevel@tonic-gate  *
12817c478bd9Sstevel@tonic-gate  * physname	client /devices path without the /devices prefix and minor
12827c478bd9Sstevel@tonic-gate  *		name component.
12837c478bd9Sstevel@tonic-gate  * minorname	client minor name.
12847c478bd9Sstevel@tonic-gate  * devlink	caller supplied buffer where the /dev link is placed on return.
12857c478bd9Sstevel@tonic-gate  * len		caller supplied devlink buffer length
12867c478bd9Sstevel@tonic-gate  *
12877c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
12887c478bd9Sstevel@tonic-gate  */
12897c478bd9Sstevel@tonic-gate static int
12907c478bd9Sstevel@tonic-gate lookup_devlink(char *physname, char *minorname, char *devlink, size_t len)
12917c478bd9Sstevel@tonic-gate {
12927c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
12937c478bd9Sstevel@tonic-gate 	struct devlink_cbarg arg;
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate 	if (devlink_hdl == NULL) {
12967c478bd9Sstevel@tonic-gate 		logdmsg("lookup_devlink: taking devlink snapshot\n");
12977c478bd9Sstevel@tonic-gate 		if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
12987c478bd9Sstevel@tonic-gate 			logerr(gettext("di_devlink_init failed: %s\n"),
12997c478bd9Sstevel@tonic-gate 			    strerror(errno));
13007c478bd9Sstevel@tonic-gate 			clean_exit(1);
13017c478bd9Sstevel@tonic-gate 		}
13027c478bd9Sstevel@tonic-gate 	}
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 	*devlink = '\0';
13057c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, MAXPATHLEN, "%s:%s", physname, minorname);
13067c478bd9Sstevel@tonic-gate 	arg.devlink = devlink;
13077c478bd9Sstevel@tonic-gate 	arg.len = len;
13087c478bd9Sstevel@tonic-gate 	if (di_devlink_walk(devlink_hdl, NULL, buf, DI_PRIMARY_LINK, &arg,
13097c478bd9Sstevel@tonic-gate 	    devlink_callback) != 0) {
13107c478bd9Sstevel@tonic-gate 		logdmsg("lookup_devlink: di_devlink_walk on %s failed: %s\n",
13117c478bd9Sstevel@tonic-gate 		    buf, strerror(errno));
13127c478bd9Sstevel@tonic-gate 		return (-1);
13137c478bd9Sstevel@tonic-gate 	}
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 	if (*devlink == '\0') {
13167c478bd9Sstevel@tonic-gate 		logdmsg("lookup_devlink: failed to lookup devlink for %s\n",
13177c478bd9Sstevel@tonic-gate 		    buf);
13187c478bd9Sstevel@tonic-gate 		return (-1);
13197c478bd9Sstevel@tonic-gate 	}
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 	logdmsg("lookup_devlink: /dev link for %s:%s = %s\n", physname,
13227c478bd9Sstevel@tonic-gate 	    minorname, devlink);
13237c478bd9Sstevel@tonic-gate 	return (0);
13247c478bd9Sstevel@tonic-gate }
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate /*
13277c478bd9Sstevel@tonic-gate  * open infile for reading and return its file pointer in *fp_in.
13287c478bd9Sstevel@tonic-gate  * open outfile for writing and return its file pointer in *fp_out.
13297c478bd9Sstevel@tonic-gate  *
13307c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
13317c478bd9Sstevel@tonic-gate  */
13327c478bd9Sstevel@tonic-gate static int
13337c478bd9Sstevel@tonic-gate open_in_out_files(char *infile, char *outfile, FILE **fp_in, FILE **fp_out)
13347c478bd9Sstevel@tonic-gate {
13357c478bd9Sstevel@tonic-gate 	FILE *fin = NULL;
13367c478bd9Sstevel@tonic-gate 	FILE *fout = NULL;
13377c478bd9Sstevel@tonic-gate 	struct stat sbuf;
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 	if ((fin = fopen(infile, "r")) == NULL) {
13407c478bd9Sstevel@tonic-gate 		logerr(gettext("failed to fopen %1$s: %2$s\n"),
13417c478bd9Sstevel@tonic-gate 		    infile, strerror(errno));
13427c478bd9Sstevel@tonic-gate 		goto out;
13437c478bd9Sstevel@tonic-gate 	}
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 	if (fstat(fileno(fin), &sbuf) != 0) {
13467c478bd9Sstevel@tonic-gate 		logerr(gettext("fstat failed on %1$s: %2$s\n"),
13477c478bd9Sstevel@tonic-gate 		    infile, strerror(errno));
13487c478bd9Sstevel@tonic-gate 		goto out;
13497c478bd9Sstevel@tonic-gate 	}
13507c478bd9Sstevel@tonic-gate 
13517c478bd9Sstevel@tonic-gate 	if ((fout = fopen(outfile, "w")) == NULL) {
13527c478bd9Sstevel@tonic-gate 		logerr(gettext("failed to fopen %1$s: %2$s\n"),
13537c478bd9Sstevel@tonic-gate 		    outfile, strerror(errno));
13547c478bd9Sstevel@tonic-gate 		goto out;
13557c478bd9Sstevel@tonic-gate 	}
13567c478bd9Sstevel@tonic-gate 
13577c478bd9Sstevel@tonic-gate 	if (fchmod(fileno(fout), (sbuf.st_mode & 0777)) != 0) {
13587c478bd9Sstevel@tonic-gate 		logerr(gettext("failed to fchmod %1$s to 0%2$o: %3$s\n"),
13597c478bd9Sstevel@tonic-gate 		    outfile, sbuf.st_mode & 0777, strerror(errno));
13607c478bd9Sstevel@tonic-gate 		goto out;
13617c478bd9Sstevel@tonic-gate 	}
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 	if (fchown(fileno(fout), sbuf.st_uid, sbuf.st_gid) != 0) {
13647c478bd9Sstevel@tonic-gate 		logerr(gettext("failed to fchown %1$s to uid %2$d and "
13657c478bd9Sstevel@tonic-gate 		    "gid %3$d: %4$s\n"),
13667c478bd9Sstevel@tonic-gate 		    outfile, sbuf.st_uid, sbuf.st_gid, strerror(errno));
13677c478bd9Sstevel@tonic-gate 		goto out;
13687c478bd9Sstevel@tonic-gate 	}
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate 	*fp_in = fin;
13717c478bd9Sstevel@tonic-gate 	*fp_out = fout;
13727c478bd9Sstevel@tonic-gate 	return (0);
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate out:
13757c478bd9Sstevel@tonic-gate 	if (fin != NULL)
13767c478bd9Sstevel@tonic-gate 		(void) fclose(fin);
13777c478bd9Sstevel@tonic-gate 	if (fout != NULL)
13787c478bd9Sstevel@tonic-gate 		(void) fclose(fout);
13797c478bd9Sstevel@tonic-gate 	return (-1);
13807c478bd9Sstevel@tonic-gate }
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate /*
13837c478bd9Sstevel@tonic-gate  * If the devname is a phci based name and not open-able, map it to vhci
13847c478bd9Sstevel@tonic-gate  * based name. If the devname is a vhci based name and not open-able, map it
13857c478bd9Sstevel@tonic-gate  * to phci based name.
13867c478bd9Sstevel@tonic-gate  *
13877c478bd9Sstevel@tonic-gate  * devname	either a /dev link or /devices name to client device
13887c478bd9Sstevel@tonic-gate  * new_devname	caller supplied buffer where the mapped device name is
13897c478bd9Sstevel@tonic-gate  *		placed on return.
13907c478bd9Sstevel@tonic-gate  * len		caller supplied new_devname buffer length
13917c478bd9Sstevel@tonic-gate  * devlink_flag	pass 1 if requesting the /dev link to the mapped device.
13927c478bd9Sstevel@tonic-gate  *		pass 0 if requesting the /devices name of the mapped device.
13937c478bd9Sstevel@tonic-gate  *
13947c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
13957c478bd9Sstevel@tonic-gate  */
13967c478bd9Sstevel@tonic-gate static int
13977c478bd9Sstevel@tonic-gate map_devname(char *devname, char *new_devname, size_t len, int devlink_flag)
13987c478bd9Sstevel@tonic-gate {
13997c478bd9Sstevel@tonic-gate 	char physname[MAXPATHLEN];
14007c478bd9Sstevel@tonic-gate 	char minor[MAXNAMELEN];
14015a4c37c9Sqh201292 	char new_physname[MAXPATHLEN];
14027c478bd9Sstevel@tonic-gate 
140360fffc19Sjw149990 	logdmsg("map_devname: checking devname %s\n", devname);
140460fffc19Sjw149990 	if ((get_physname_minor(devname, physname, sizeof (physname),
140560fffc19Sjw149990 	    minor, sizeof (minor)) == 0) &&
140660fffc19Sjw149990 	    (canopen(devname) == 0) &&
140760fffc19Sjw149990 	    (map_physname(physname, new_physname,
1408*8cecff49Sgp87344 	    sizeof (new_physname), minor) == 0)) {
140960fffc19Sjw149990 
141060fffc19Sjw149990 		logdmsg("map_devname: now looking up devlink\n");
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate 		if (devlink_flag) {
14137c478bd9Sstevel@tonic-gate 			if (lookup_devlink(new_physname, minor, new_devname,
14147c478bd9Sstevel@tonic-gate 			    len) == 0)
14157c478bd9Sstevel@tonic-gate 				return (0);
14167c478bd9Sstevel@tonic-gate 		} else {
14177c478bd9Sstevel@tonic-gate 			(void) snprintf(new_devname, len, "/devices%s:%s",
14187c478bd9Sstevel@tonic-gate 			    new_physname, minor);
14197c478bd9Sstevel@tonic-gate 			return (0);
14207c478bd9Sstevel@tonic-gate 		}
14217c478bd9Sstevel@tonic-gate 	}
14227c478bd9Sstevel@tonic-gate 
142360fffc19Sjw149990 	logdmsg("map_devname: failed to find mapping for %s\n", devname);
14247c478bd9Sstevel@tonic-gate 	return (-1);
14257c478bd9Sstevel@tonic-gate }
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate /*
14285a4c37c9Sqh201292  * If the devname is a vhci based name and open-able, map it to phci
14295a4c37c9Sqh201292  * based name.
14305a4c37c9Sqh201292  *
14315a4c37c9Sqh201292  * devname	either a /dev link or /devices name to client device
14325a4c37c9Sqh201292  * new_devname	caller supplied buffer where the mapped device name without
14335a4c37c9Sqh201292  *		/devices prefix is placed on return.
14345a4c37c9Sqh201292  * len		caller supplied new_devname buffer length
14355a4c37c9Sqh201292  */
14365a4c37c9Sqh201292 static int
14375a4c37c9Sqh201292 map_openable_vhciname(char *devname, char *new_devname, size_t len)
14385a4c37c9Sqh201292 {
14395a4c37c9Sqh201292 	char physname[MAXPATHLEN];
14405a4c37c9Sqh201292 	char minor[MAXNAMELEN];
14415a4c37c9Sqh201292 	char new_physname[MAXPATHLEN];
14425a4c37c9Sqh201292 
14435a4c37c9Sqh201292 	if (get_physname_minor(devname, physname, sizeof (physname),
14445a4c37c9Sqh201292 	    minor, sizeof (minor)) == 0 &&
14455a4c37c9Sqh201292 	    canopen(devname) == 1 &&
14465a4c37c9Sqh201292 	    client_name_type(physname) == CLIENT_TYPE_VHCI &&
14475a4c37c9Sqh201292 	    vhci_to_phci_by_ioctl(physname, new_physname,
14485a4c37c9Sqh201292 		sizeof (new_physname)) == 0) {
14495a4c37c9Sqh201292 		(void) snprintf(new_devname, len, "%s:%s",
14505a4c37c9Sqh201292 		    new_physname, minor);
14515a4c37c9Sqh201292 		return (0);
14525a4c37c9Sqh201292 	}
14535a4c37c9Sqh201292 
14545a4c37c9Sqh201292 	return (-1);
14555a4c37c9Sqh201292 }
14565a4c37c9Sqh201292 /*
14577c478bd9Sstevel@tonic-gate  * Make a new /etc/vfstab:
14587c478bd9Sstevel@tonic-gate  * Read vfstab_in, convert the device name entries to appropriate vhci or phci
14597c478bd9Sstevel@tonic-gate  * based names, and write to vfstab_out. Only device names whose physical
14607c478bd9Sstevel@tonic-gate  * paths are either phci or vhci based names and not open-able are considered
14617c478bd9Sstevel@tonic-gate  * for conversion. Open-able device name entries are not converted as it
14627c478bd9Sstevel@tonic-gate  * means that the device is already accessible; hence no need to convert.
14637c478bd9Sstevel@tonic-gate  *
14647c478bd9Sstevel@tonic-gate  * Returns:
14657c478bd9Sstevel@tonic-gate  * 	0	successful but vfstab_out contents are the same as vfstab_in
14667c478bd9Sstevel@tonic-gate  *	1	successful and vfstab_out changed from vfstab_in
14677c478bd9Sstevel@tonic-gate  *	-1	failed
14687c478bd9Sstevel@tonic-gate  */
14697c478bd9Sstevel@tonic-gate static int
14707c478bd9Sstevel@tonic-gate update_vfstab(char *vfstab_in, char *vfstab_out)
14717c478bd9Sstevel@tonic-gate {
14727c478bd9Sstevel@tonic-gate 	FILE *fp_in, *fp_out;
14737c478bd9Sstevel@tonic-gate 	char *buf, *tmpbuf;
14747c478bd9Sstevel@tonic-gate 	char *vfs_cache[2];
14757c478bd9Sstevel@tonic-gate 	int idx = 0, count = 0;
14767c478bd9Sstevel@tonic-gate 	int rv = -1;
14777c478bd9Sstevel@tonic-gate 	int vfstab_updated = 0;
14787c478bd9Sstevel@tonic-gate 	int i;
14797c478bd9Sstevel@tonic-gate 	char cdev[MAXPATHLEN];
14807c478bd9Sstevel@tonic-gate 	char bdev[MAXPATHLEN];
14817c478bd9Sstevel@tonic-gate 	char mntpt[MAXPATHLEN];
14827c478bd9Sstevel@tonic-gate 	char fstype[512];
14837c478bd9Sstevel@tonic-gate 	char fsckpass[512];
14847c478bd9Sstevel@tonic-gate 	char mntboot[512];
14857c478bd9Sstevel@tonic-gate 	char mntopt[MAX_MNTOPT_STR];
14867c478bd9Sstevel@tonic-gate 	char phys_bdev[MAXPATHLEN], phys_cdev[MAXPATHLEN];
14877c478bd9Sstevel@tonic-gate 	char bdev_minor[MAXNAMELEN], cdev_minor[MAXNAMELEN];
14887c478bd9Sstevel@tonic-gate 	char new_physname[MAXPATHLEN];
14897c478bd9Sstevel@tonic-gate 	char new_bdevlink[MAXPATHLEN], new_cdevlink[MAXPATHLEN];
14907c478bd9Sstevel@tonic-gate 	char fmt[80];
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate 	if (open_in_out_files(vfstab_in, vfstab_out, &fp_in, &fp_out) != 0)
14937c478bd9Sstevel@tonic-gate 		return (-1);
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 	/*
14967c478bd9Sstevel@tonic-gate 	 * Read one line at time from vfstab_in. If no conversion is needed
14977c478bd9Sstevel@tonic-gate 	 * for the line simply write the line to vfstab_out. If conversion is
14987c478bd9Sstevel@tonic-gate 	 * needed, first write the existing line as a comment to vfstab_out
14997c478bd9Sstevel@tonic-gate 	 * and then write the converted line.
15007c478bd9Sstevel@tonic-gate 	 *
15017c478bd9Sstevel@tonic-gate 	 * To avoid commented entries piling up in vfstab in case if the
15027c478bd9Sstevel@tonic-gate 	 * user runs stmsboot multiple times to switch on and off from mpxio,
15037c478bd9Sstevel@tonic-gate 	 * add the commented line only if not already there. To do this
15047c478bd9Sstevel@tonic-gate 	 * cache the last two vfstab lines processed and add the commented
15057c478bd9Sstevel@tonic-gate 	 * entry only if it is not found in the cache. We only need to cache
15067c478bd9Sstevel@tonic-gate 	 * the last two lines because a device can have at most two names -
15077c478bd9Sstevel@tonic-gate 	 * one mpxio and one non-mpxio name. Therefore for any device name
15087c478bd9Sstevel@tonic-gate 	 * entry we at most add two comments - one with mpxio name and one
15097c478bd9Sstevel@tonic-gate 	 * with non-mpxio name - no matter how many times stmsboot is run.
15107c478bd9Sstevel@tonic-gate 	 */
15117c478bd9Sstevel@tonic-gate 	buf = (char *)s_malloc(VFS_LINE_MAX);
15127c478bd9Sstevel@tonic-gate 	tmpbuf = (char *)s_malloc(VFS_LINE_MAX);
15137c478bd9Sstevel@tonic-gate 	vfs_cache[0] = (char *)s_malloc(VFS_LINE_MAX);
15147c478bd9Sstevel@tonic-gate 	vfs_cache[1] = (char *)s_malloc(VFS_LINE_MAX);
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate 	(void) snprintf(fmt, sizeof (fmt),
15177c478bd9Sstevel@tonic-gate 	    "%%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds", sizeof (bdev) - 1,
15187c478bd9Sstevel@tonic-gate 	    sizeof (cdev) - 1, sizeof (mntpt) - 1, sizeof (fstype) - 1,
15197c478bd9Sstevel@tonic-gate 	    sizeof (fsckpass) - 1, sizeof (mntboot) - 1, sizeof (mntopt) - 1);
15207c478bd9Sstevel@tonic-gate 
15217c478bd9Sstevel@tonic-gate 	while (fgets(buf, VFS_LINE_MAX, fp_in) != NULL) {
15227c478bd9Sstevel@tonic-gate 		if (strlen(buf) == (VFS_LINE_MAX - 1) &&
15237c478bd9Sstevel@tonic-gate 		    buf[VFS_LINE_MAX-2] != '\n') {
15247c478bd9Sstevel@tonic-gate 			logerr(gettext("%1$s line size too long, "
15257c478bd9Sstevel@tonic-gate 			    "exceeded %2$d: \"%3$s\"\n"),
15267c478bd9Sstevel@tonic-gate 			    VFSTAB, VFS_LINE_MAX - 2, buf);
15277c478bd9Sstevel@tonic-gate 			goto out;
15287c478bd9Sstevel@tonic-gate 		}
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 		/* LINTED - format specifier */
15317c478bd9Sstevel@tonic-gate 		if ((sscanf(buf, fmt, bdev, cdev, mntpt,
15327c478bd9Sstevel@tonic-gate 		    fstype, fsckpass, mntboot, mntopt) != 7) ||
15337c478bd9Sstevel@tonic-gate 		    (bdev[0] == '#') ||
15347c478bd9Sstevel@tonic-gate 		    (get_physname_minor(bdev, phys_bdev, sizeof (phys_bdev),
15357c478bd9Sstevel@tonic-gate 		    bdev_minor, sizeof (bdev_minor)) != 0) ||
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 		    (strcmp(fstype, "swap") != 0 &&
15387c478bd9Sstevel@tonic-gate 		    ((get_physname_minor(cdev, phys_cdev, sizeof (phys_cdev),
15397c478bd9Sstevel@tonic-gate 		    cdev_minor, sizeof (cdev_minor)) != 0) ||
15407c478bd9Sstevel@tonic-gate 		    (strcmp(phys_bdev, phys_cdev) != 0))) ||
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 		    canopen(bdev) ||
15437c478bd9Sstevel@tonic-gate 		    (map_physname(phys_bdev, new_physname,
1544*8cecff49Sgp87344 		    sizeof (new_physname), bdev_minor) != 0) ||
15457c478bd9Sstevel@tonic-gate 		    (lookup_devlink(new_physname, bdev_minor, new_bdevlink,
15467c478bd9Sstevel@tonic-gate 		    sizeof (new_bdevlink)) != 0) ||
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 		    (strcmp(fstype, "swap") != 0 &&
15497c478bd9Sstevel@tonic-gate 		    (lookup_devlink(new_physname, cdev_minor, new_cdevlink,
15507c478bd9Sstevel@tonic-gate 		    sizeof (new_cdevlink)) != 0))) {
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate 			/* cache the last two entries */
15537c478bd9Sstevel@tonic-gate 			(void) strlcpy(vfs_cache[idx], buf, VFS_LINE_MAX);
15547c478bd9Sstevel@tonic-gate 			idx = (idx == 0) ? 1 : 0;
15557c478bd9Sstevel@tonic-gate 			if (count < 2)
15567c478bd9Sstevel@tonic-gate 				count++;
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 			if (fputs(buf, fp_out) == EOF) {
15597c478bd9Sstevel@tonic-gate 				logerr(gettext("fputs \"%1$s\" to %2$s "
15607c478bd9Sstevel@tonic-gate 				    "failed: %3$s\n"),
15617c478bd9Sstevel@tonic-gate 				    buf, vfstab_out, strerror(errno));
15627c478bd9Sstevel@tonic-gate 				goto out;
15637c478bd9Sstevel@tonic-gate 			}
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 		} else {
15667c478bd9Sstevel@tonic-gate 			/*
15677c478bd9Sstevel@tonic-gate 			 * comment the entry in vfstab only if it is not
15687c478bd9Sstevel@tonic-gate 			 * already in the cache.
15697c478bd9Sstevel@tonic-gate 			 */
15707c478bd9Sstevel@tonic-gate 			if (client_name_type(phys_bdev) == CLIENT_TYPE_VHCI)
15717c478bd9Sstevel@tonic-gate 				(void) snprintf(tmpbuf, VFS_LINE_MAX,
15727c478bd9Sstevel@tonic-gate 				    "# mpxio: %s", buf);
15737c478bd9Sstevel@tonic-gate 			else
15747c478bd9Sstevel@tonic-gate 				(void) snprintf(tmpbuf, VFS_LINE_MAX,
15757c478bd9Sstevel@tonic-gate 				    "# non-mpxio: %s", buf);
15767c478bd9Sstevel@tonic-gate 
15777c478bd9Sstevel@tonic-gate 			for (i = 0; i < count; i++) {
15787c478bd9Sstevel@tonic-gate 				if (strcmp(vfs_cache[i], tmpbuf) == 0)
15797c478bd9Sstevel@tonic-gate 					break;
15807c478bd9Sstevel@tonic-gate 			}
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate 			if (i == count) {
15837c478bd9Sstevel@tonic-gate 				if (fputs(tmpbuf, fp_out) == EOF) {
15847c478bd9Sstevel@tonic-gate 					logerr(gettext("fputs \"%1$s\" to %2$s "
15857c478bd9Sstevel@tonic-gate 					    "failed: %3$s\n"), tmpbuf,
15867c478bd9Sstevel@tonic-gate 					    vfstab_out, strerror(errno));
15877c478bd9Sstevel@tonic-gate 					goto out;
15887c478bd9Sstevel@tonic-gate 				}
15897c478bd9Sstevel@tonic-gate 			}
15907c478bd9Sstevel@tonic-gate 
15917c478bd9Sstevel@tonic-gate 			count = 0;
15927c478bd9Sstevel@tonic-gate 			idx = 0;
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 			if (fprintf(fp_out, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
15957c478bd9Sstevel@tonic-gate 			    new_bdevlink,
15967c478bd9Sstevel@tonic-gate 			    (strcmp(fstype, "swap") != 0) ? new_cdevlink : cdev,
15977c478bd9Sstevel@tonic-gate 			    mntpt, fstype, fsckpass, mntboot, mntopt) < 0) {
15987c478bd9Sstevel@tonic-gate 				logerr(gettext("fprintf failed to write to "
15997c478bd9Sstevel@tonic-gate 				    "%1$s: %2$s\n"),
16007c478bd9Sstevel@tonic-gate 				    vfstab_out, strerror(errno));
16017c478bd9Sstevel@tonic-gate 				goto out;
16027c478bd9Sstevel@tonic-gate 			}
16037c478bd9Sstevel@tonic-gate 			vfstab_updated = 1;
16047c478bd9Sstevel@tonic-gate 		}
16057c478bd9Sstevel@tonic-gate 	}
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate 	rv = vfstab_updated;
16087c478bd9Sstevel@tonic-gate out:
16097c478bd9Sstevel@tonic-gate 	(void) fclose(fp_in);
16107c478bd9Sstevel@tonic-gate 	(void) fclose(fp_out);
16117c478bd9Sstevel@tonic-gate 	free(buf);
16127c478bd9Sstevel@tonic-gate 	free(tmpbuf);
16137c478bd9Sstevel@tonic-gate 	free(vfs_cache[0]);
16147c478bd9Sstevel@tonic-gate 	free(vfs_cache[1]);
16157c478bd9Sstevel@tonic-gate 	return (rv);
16167c478bd9Sstevel@tonic-gate }
16177c478bd9Sstevel@tonic-gate 
16187c478bd9Sstevel@tonic-gate /*
16197c478bd9Sstevel@tonic-gate  * if guidmap is 0, list non-STMS to STMS device name mappings for the
16207c478bd9Sstevel@tonic-gate  * specified controller.
16217c478bd9Sstevel@tonic-gate  * if guidmap is 1, list non-STMS to GUID mappings for the specified controller.
16227c478bd9Sstevel@tonic-gate  * If controller is -1 list mappings for all controllers.
16237c478bd9Sstevel@tonic-gate  *
16247c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
16257c478bd9Sstevel@tonic-gate  */
16267c478bd9Sstevel@tonic-gate static int
16277c478bd9Sstevel@tonic-gate list_mappings(int controller, int guidmap)
16287c478bd9Sstevel@tonic-gate {
16297c478bd9Sstevel@tonic-gate 	int cnum, len, mapped;
16307c478bd9Sstevel@tonic-gate 	int header = 1;
16317c478bd9Sstevel@tonic-gate 	char *p1, *p2;
16327c478bd9Sstevel@tonic-gate 	DIR *dirp;
16337c478bd9Sstevel@tonic-gate 	struct dirent *direntry;
16347c478bd9Sstevel@tonic-gate 	char devname[MAXPATHLEN];
16357c478bd9Sstevel@tonic-gate 	char physname[MAXPATHLEN];
16367c478bd9Sstevel@tonic-gate 	char new_devname[MAXPATHLEN];
16377c478bd9Sstevel@tonic-gate 	char new_physname[MAXPATHLEN];
16387c478bd9Sstevel@tonic-gate 	char guid[MAXPATHLEN];
16397c478bd9Sstevel@tonic-gate 	char minor[MAXNAMELEN];
16407c478bd9Sstevel@tonic-gate 
16417c478bd9Sstevel@tonic-gate 	if ((dirp = opendir("/dev/rdsk")) == NULL)
16427c478bd9Sstevel@tonic-gate 		return (-1);
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate 	while ((direntry = readdir(dirp)) != NULL) {
16457c478bd9Sstevel@tonic-gate 		if (strcmp(direntry->d_name, ".") == 0 ||
16467c478bd9Sstevel@tonic-gate 		    strcmp(direntry->d_name, "..") == 0 ||
16477c478bd9Sstevel@tonic-gate 		    (len = strlen(direntry->d_name)) < 2 ||
16487c478bd9Sstevel@tonic-gate 		    strcmp(direntry->d_name + len - 2, "s0") != 0 ||
16497c478bd9Sstevel@tonic-gate 		    sscanf(direntry->d_name, "c%dt", &cnum) != 1 ||
16507c478bd9Sstevel@tonic-gate 		    (controller != -1 && controller != cnum))
16517c478bd9Sstevel@tonic-gate 			continue;
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate 		(void) snprintf(devname, MAXPATHLEN, "/dev/rdsk/%s",
16547c478bd9Sstevel@tonic-gate 		    direntry->d_name);
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 		if (get_physname_minor(devname, physname, sizeof (physname),
16577c478bd9Sstevel@tonic-gate 		    minor, sizeof (minor)) != 0 ||
165860fffc19Sjw149990 		    client_name_type(physname) != CLIENT_TYPE_PHCI) {
165960fffc19Sjw149990 			logdmsg("list_mappings: continuing\n");
16607c478bd9Sstevel@tonic-gate 			continue;
166160fffc19Sjw149990 		}
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 		/*
16647c478bd9Sstevel@tonic-gate 		 * First try phci_to_vhci() mapping. It will work if the
16657c478bd9Sstevel@tonic-gate 		 * device is under MPxIO control. If the device is not under
16667c478bd9Sstevel@tonic-gate 		 * MPxIO, phci_to_vhci() will fail in which case try to lookup
16677c478bd9Sstevel@tonic-gate 		 * if an old mapping exists using guid lookup.
16687c478bd9Sstevel@tonic-gate 		 */
16697c478bd9Sstevel@tonic-gate 		mapped = 1;
16707c478bd9Sstevel@tonic-gate 		if (phci_to_vhci(physname, new_physname,
16717c478bd9Sstevel@tonic-gate 		    sizeof (new_physname)) != 0) {
16727c478bd9Sstevel@tonic-gate 			if (get_guid(physname, guid, sizeof (guid), 1,
16737c478bd9Sstevel@tonic-gate 			    DI_NODE_NIL) == 0)
16747c478bd9Sstevel@tonic-gate 				(void) snprintf(new_physname, MAXPATHLEN,
16755a4c37c9Sqh201292 				    "/scsi_vhci/%s%s", DISK_AT_G, guid);
16767c478bd9Sstevel@tonic-gate 			else
16777c478bd9Sstevel@tonic-gate 				mapped = 0;
16787c478bd9Sstevel@tonic-gate 		}
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 		if (mapped == 0)
16817c478bd9Sstevel@tonic-gate 			continue;
16827c478bd9Sstevel@tonic-gate 
16837c478bd9Sstevel@tonic-gate 		/* strip the slice number part */
16847c478bd9Sstevel@tonic-gate 		devname[strlen(devname) - 2] = '\0';
16857c478bd9Sstevel@tonic-gate 
16867c478bd9Sstevel@tonic-gate 		if (guidmap == 0) {
16877c478bd9Sstevel@tonic-gate 			if (lookup_devlink(new_physname, minor,
16887c478bd9Sstevel@tonic-gate 			    new_devname, sizeof (new_devname)) != 0)
16897c478bd9Sstevel@tonic-gate 				continue;
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate 			/* strip the slice number part */
16927c478bd9Sstevel@tonic-gate 			new_devname[strlen(new_devname) - 2] = '\0';
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 			if (header) {
16957c478bd9Sstevel@tonic-gate 				(void) printf(
16967c478bd9Sstevel@tonic-gate 				    gettext("non-STMS device name\t\t\t"
16977c478bd9Sstevel@tonic-gate 				    "STMS device name\n"
16987c478bd9Sstevel@tonic-gate 				    "------------------------------------------"
16997c478bd9Sstevel@tonic-gate 				    "------------------------\n"));
17007c478bd9Sstevel@tonic-gate 				header = 0;
17017c478bd9Sstevel@tonic-gate 			}
17027c478bd9Sstevel@tonic-gate 			(void) printf("%s\t\t%s\n", devname, new_devname);
17037c478bd9Sstevel@tonic-gate 		} else {
17047c478bd9Sstevel@tonic-gate 			/* extract guid part */
170560fffc19Sjw149990 			/* we should be using a getguid() call instead */
170660fffc19Sjw149990 			if ((p1 = strstr(new_physname, "@"))
170760fffc19Sjw149990 			    == NULL) {
17087c478bd9Sstevel@tonic-gate 				logdmsg("invalid vhci: %s\n", new_physname);
17097c478bd9Sstevel@tonic-gate 				continue;
17107c478bd9Sstevel@tonic-gate 			}
171160fffc19Sjw149990 
171260fffc19Sjw149990 			logdmsg("\tp1 = %s\n", p1);
171360fffc19Sjw149990 
171460fffc19Sjw149990 			p1 += 2; /* "@" + [nwg] */
17157c478bd9Sstevel@tonic-gate 			if ((p2 = strrchr(p1, ':')) != NULL)
17167c478bd9Sstevel@tonic-gate 				*p2 = '\0';
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate 			if (header) {
17197c478bd9Sstevel@tonic-gate 				(void) printf(
17207c478bd9Sstevel@tonic-gate 				    gettext("non-STMS device name\t\t\tGUID\n"
17217c478bd9Sstevel@tonic-gate 				    "------------------------------------------"
17227c478bd9Sstevel@tonic-gate 				    "------------------------\n"));
17237c478bd9Sstevel@tonic-gate 				header = 0;
17247c478bd9Sstevel@tonic-gate 			}
17257c478bd9Sstevel@tonic-gate 			(void) printf("%s\t\t%s\n", devname, p1);
17267c478bd9Sstevel@tonic-gate 		}
17277c478bd9Sstevel@tonic-gate 	}
17287c478bd9Sstevel@tonic-gate 
17297c478bd9Sstevel@tonic-gate 	(void) closedir(dirp);
17307c478bd9Sstevel@tonic-gate 	return (0);
17317c478bd9Sstevel@tonic-gate }
17327c478bd9Sstevel@tonic-gate 
17337c478bd9Sstevel@tonic-gate /*
17347c478bd9Sstevel@tonic-gate  * Check if the file can be opened.
17357c478bd9Sstevel@tonic-gate  *
17367c478bd9Sstevel@tonic-gate  * Return 1 if the file can be opened, 0 otherwise.
17377c478bd9Sstevel@tonic-gate  */
17387c478bd9Sstevel@tonic-gate static int
17397c478bd9Sstevel@tonic-gate canopen(char *filename)
17407c478bd9Sstevel@tonic-gate {
17417c478bd9Sstevel@tonic-gate 	int fd;
17427c478bd9Sstevel@tonic-gate 
17437c478bd9Sstevel@tonic-gate 	if ((fd = open(filename, O_RDONLY)) == -1)
17447c478bd9Sstevel@tonic-gate 		return (0);
17457c478bd9Sstevel@tonic-gate 
174660fffc19Sjw149990 	logdmsg("canopen: was able to open %s\n", filename);
17477c478bd9Sstevel@tonic-gate 	(void) close(fd);
17487c478bd9Sstevel@tonic-gate 	return (1);
17497c478bd9Sstevel@tonic-gate }
17507c478bd9Sstevel@tonic-gate 
175160fffc19Sjw149990 
175260fffc19Sjw149990 /*
175360fffc19Sjw149990  * This function traverses the device tree looking for nodes
175460fffc19Sjw149990  * which have "drivername" as a property. We return a list of
1755815dd917Sjmcp  * these nodes, without duplicate entries.
175660fffc19Sjw149990  * Since there can be many different pci/pcie devices that all
175760fffc19Sjw149990  * share the same driver but which have different pci vid/did
175860fffc19Sjw149990  * combinations, we have to be smart about returning only those
175960fffc19Sjw149990  * pci vid/dids which have the "sas-*" property unless the
176060fffc19Sjw149990  * drivername is "fp", in which case we're searching for "node-wwn"
176160fffc19Sjw149990  */
176260fffc19Sjw149990 static void
176360fffc19Sjw149990 list_nodes(char *drivername)
176460fffc19Sjw149990 {
176560fffc19Sjw149990 	di_node_t devroot = DI_NODE_NIL;
176660fffc19Sjw149990 	di_node_t thisnode = DI_NODE_NIL;
1767815dd917Sjmcp 	char *aliaslist;
1768815dd917Sjmcp 	char *iitype = NULL; /* the "initiator-interconnect-type" property */
176960fffc19Sjw149990 	int *intprop = NULL;
177060fffc19Sjw149990 	int i = 1; /* fencepost */
1771815dd917Sjmcp 	int irval = 0;
1772815dd917Sjmcp 	int crval = 0;
177360fffc19Sjw149990 
177460fffc19Sjw149990 	/*
177560fffc19Sjw149990 	 * Since the "fp" driver enumerates with its own name,
177660fffc19Sjw149990 	 * we can special-case its handling.
177760fffc19Sjw149990 	 */
177860fffc19Sjw149990 	if (strcmp(drvname, "fp") == 0) {
177960fffc19Sjw149990 		(void) fprintf(stdout, "fp\n");
178060fffc19Sjw149990 	} else {
178160fffc19Sjw149990 
178260fffc19Sjw149990 		if ((devroot = di_init("/", DINFOCPYALL | DINFOFORCE))
178360fffc19Sjw149990 		    == DI_NODE_NIL) {
178460fffc19Sjw149990 			logerr(gettext("list_nodes: di_init failed: "
178560fffc19Sjw149990 			"%s\n"), strerror(errno));
178660fffc19Sjw149990 		}
178760fffc19Sjw149990 
178860fffc19Sjw149990 		if ((thisnode = di_drv_first_node(drivername, devroot))
178960fffc19Sjw149990 		    != NULL) {
179060fffc19Sjw149990 			logdmsg("list_nodes: searching for property "
179160fffc19Sjw149990 			    "%s\n", drvprop);
179260fffc19Sjw149990 
179360fffc19Sjw149990 			aliaslist = s_malloc(1024 * sizeof (char));
179460fffc19Sjw149990 			bzero(aliaslist, 1024);
179560fffc19Sjw149990 			while (thisnode != DI_NODE_NIL) {
179660fffc19Sjw149990 				logdmsg("devfs-name %s driver-name %s "
179760fffc19Sjw149990 				    "node-name %s\n",
179860fffc19Sjw149990 				    di_devfs_path(thisnode),
179960fffc19Sjw149990 				    di_driver_name(thisnode),
180060fffc19Sjw149990 				    di_node_name(thisnode));
180160fffc19Sjw149990 
180260fffc19Sjw149990 			/* We check the child node for drvprop */
1803815dd917Sjmcp 			irval = di_prop_lookup_ints(DDI_DEV_T_ANY,
1804815dd917Sjmcp 			    di_child_node(thisnode), drvprop, &intprop);
1805815dd917Sjmcp 			/* and this node for the correct initiator type */
1806815dd917Sjmcp 			crval = di_prop_lookup_strings(DDI_DEV_T_ANY,
1807815dd917Sjmcp 			    thisnode, "initiator-interconnect-type", &iitype);
1808815dd917Sjmcp 
1809815dd917Sjmcp 			/*
1810815dd917Sjmcp 			 * examine the return codes from di_prop_lookup*()
1811815dd917Sjmcp 			 * functions to guard against library errors
1812815dd917Sjmcp 			 */
1813815dd917Sjmcp 			if ((irval > -1) || ((crval > -1) &&
1814815dd917Sjmcp 			    (strncmp(iitype, "SATA", 4) == 0))) {
181560fffc19Sjw149990 
181660fffc19Sjw149990 				if (strstr(aliaslist,
1817815dd917Sjmcp 				    di_node_name(thisnode)) == (char *)NULL) {
181860fffc19Sjw149990 					char *nname;
181960fffc19Sjw149990 
182060fffc19Sjw149990 					nname = di_node_name(thisnode);
182160fffc19Sjw149990 
182260fffc19Sjw149990 					if (i) {
182360fffc19Sjw149990 					(void) snprintf(aliaslist,
1824815dd917Sjmcp 					    strlen(nname) + 1, "%s", nname);
182560fffc19Sjw149990 						--i;
182660fffc19Sjw149990 					} else {
182760fffc19Sjw149990 					if (strstr(aliaslist,
182860fffc19Sjw149990 					    di_node_name(thisnode)) ==
182960fffc19Sjw149990 					    (char *)NULL) {
1830815dd917Sjmcp 						/* add 2 for the n-1 + "|" */
183160fffc19Sjw149990 						(void) snprintf(aliaslist,
1832815dd917Sjmcp 						    strlen(nname) + 2 +
183360fffc19Sjw149990 						    strlen(aliaslist),
183460fffc19Sjw149990 						    "%s|%s", aliaslist,
183560fffc19Sjw149990 						    nname);
183660fffc19Sjw149990 						}
183760fffc19Sjw149990 					}
183860fffc19Sjw149990 				}
183960fffc19Sjw149990 			} else {
184060fffc19Sjw149990 				logdmsg("unable to lookup property %s "
184160fffc19Sjw149990 				    "for node %s. Error %d: %s\n",
184260fffc19Sjw149990 				    drvprop, di_devfs_path(thisnode),
184360fffc19Sjw149990 				    errno, strerror(errno));
184460fffc19Sjw149990 			}
184560fffc19Sjw149990 			thisnode = di_drv_next_node(thisnode);
184660fffc19Sjw149990 		}
184760fffc19Sjw149990 		(void) fprintf(stdout, "%s\n", aliaslist);
184860fffc19Sjw149990 		}
184960fffc19Sjw149990 
185060fffc19Sjw149990 		di_fini(devroot);
185160fffc19Sjw149990 	}
185260fffc19Sjw149990 }
185360fffc19Sjw149990 
18547c478bd9Sstevel@tonic-gate static void
18557c478bd9Sstevel@tonic-gate logerr(char *msg, ...)
18567c478bd9Sstevel@tonic-gate {
18577c478bd9Sstevel@tonic-gate 	va_list ap;
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s: ", stmsboot);
18607c478bd9Sstevel@tonic-gate 	va_start(ap, msg);
18617c478bd9Sstevel@tonic-gate 	/* LINTED - format specifier */
18627c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, msg, ap);
18637c478bd9Sstevel@tonic-gate 	va_end(ap);
18647c478bd9Sstevel@tonic-gate }
18657c478bd9Sstevel@tonic-gate 
18667c478bd9Sstevel@tonic-gate /* log debug message */
18677c478bd9Sstevel@tonic-gate static void
18687c478bd9Sstevel@tonic-gate logdmsg(char *msg, ...)
18697c478bd9Sstevel@tonic-gate {
18707c478bd9Sstevel@tonic-gate 	va_list ap;
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 	if (debug) {
18737c478bd9Sstevel@tonic-gate 		va_start(ap, msg);
18747c478bd9Sstevel@tonic-gate 		/* LINTED - format specifier */
18757c478bd9Sstevel@tonic-gate 		(void) vprintf(msg, ap);
18767c478bd9Sstevel@tonic-gate 		va_end(ap);
18777c478bd9Sstevel@tonic-gate 	}
18787c478bd9Sstevel@tonic-gate }
18797c478bd9Sstevel@tonic-gate 
18807c478bd9Sstevel@tonic-gate static void *
18817c478bd9Sstevel@tonic-gate s_malloc(const size_t size)
18827c478bd9Sstevel@tonic-gate {
18837c478bd9Sstevel@tonic-gate 	void *rp;
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate 	if ((rp = malloc(size)) == NULL) {
18867c478bd9Sstevel@tonic-gate 		logerr(gettext("malloc failed to allocate %d bytes\n"), size);
18877c478bd9Sstevel@tonic-gate 		clean_exit(1);
18887c478bd9Sstevel@tonic-gate 	}
18897c478bd9Sstevel@tonic-gate 	return (rp);
18907c478bd9Sstevel@tonic-gate }
18917c478bd9Sstevel@tonic-gate 
18927c478bd9Sstevel@tonic-gate static char *
18937c478bd9Sstevel@tonic-gate s_strdup(const char *ptr)
18947c478bd9Sstevel@tonic-gate {
18957c478bd9Sstevel@tonic-gate 	void *rp;
18967c478bd9Sstevel@tonic-gate 
18977c478bd9Sstevel@tonic-gate 	if ((rp = strdup(ptr)) == NULL) {
18987c478bd9Sstevel@tonic-gate 		logerr(gettext("strdup failed to dup %s\n"), ptr);
18997c478bd9Sstevel@tonic-gate 		clean_exit(1);
19007c478bd9Sstevel@tonic-gate 	}
19017c478bd9Sstevel@tonic-gate 	return (rp);
19027c478bd9Sstevel@tonic-gate }
19037c478bd9Sstevel@tonic-gate 
19047c478bd9Sstevel@tonic-gate static void
19057c478bd9Sstevel@tonic-gate s_strlcpy(char *dst, const char *src, size_t dstsize)
19067c478bd9Sstevel@tonic-gate {
19077c478bd9Sstevel@tonic-gate 	int n;
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate 	if ((n = strlcpy(dst, src, dstsize)) >= dstsize) {
19107c478bd9Sstevel@tonic-gate 		logerr(gettext("strlcpy: destination buffer size is %1$d "
19117c478bd9Sstevel@tonic-gate 		    "bytes, need to at least %2$d bytes\n"), dstsize, n + 1);
19127c478bd9Sstevel@tonic-gate 		clean_exit(1);
19137c478bd9Sstevel@tonic-gate 	}
19147c478bd9Sstevel@tonic-gate }
19157c478bd9Sstevel@tonic-gate 
19167c478bd9Sstevel@tonic-gate static void
19177c478bd9Sstevel@tonic-gate clean_exit(int status)
19187c478bd9Sstevel@tonic-gate {
19197c478bd9Sstevel@tonic-gate 	if (devinfo_root != DI_NODE_NIL)
19207c478bd9Sstevel@tonic-gate 		di_fini(devinfo_root);
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate 	if (devlink_hdl != NULL)
19237c478bd9Sstevel@tonic-gate 		(void) di_devlink_fini(&devlink_hdl);
19247c478bd9Sstevel@tonic-gate 
19257c478bd9Sstevel@tonic-gate 	if (vhci_fd != -1)
19267c478bd9Sstevel@tonic-gate 		(void) close(vhci_fd);
19277c478bd9Sstevel@tonic-gate 
19287c478bd9Sstevel@tonic-gate 	exit(status);
19297c478bd9Sstevel@tonic-gate }
1930*8cecff49Sgp87344 
1931*8cecff49Sgp87344 /*
1932*8cecff49Sgp87344  * Attempt to read some data from the specified slice from the device.
1933*8cecff49Sgp87344  */
1934*8cecff49Sgp87344 static int
1935*8cecff49Sgp87344 canread(char *physname, char *minor)
1936*8cecff49Sgp87344 {
1937*8cecff49Sgp87344 	char    devname[MAXPATHLEN];
1938*8cecff49Sgp87344 	int	fd, rv = 0;
1939*8cecff49Sgp87344 	char    tbuf[512];
1940*8cecff49Sgp87344 
1941*8cecff49Sgp87344 	(void) snprintf(devname, MAXPATHLEN, "/devices%s:%s", physname, minor);
1942*8cecff49Sgp87344 	if ((fd = open(devname, O_RDONLY)) == -1) {
1943*8cecff49Sgp87344 		logdmsg("canread: failed to open %s: %s\n", devname,
1944*8cecff49Sgp87344 		    strerror(errno));
1945*8cecff49Sgp87344 		return (rv);
1946*8cecff49Sgp87344 	}
1947*8cecff49Sgp87344 
1948*8cecff49Sgp87344 	if (read(fd, tbuf, sizeof (tbuf)) < 0)
1949*8cecff49Sgp87344 		logdmsg("canread: failed to read %s: %s\n", devname,
1950*8cecff49Sgp87344 		    strerror(errno));
1951*8cecff49Sgp87344 	else
1952*8cecff49Sgp87344 		rv = 1;
1953*8cecff49Sgp87344 
1954*8cecff49Sgp87344 	(void) close(fd);
1955*8cecff49Sgp87344 	return (rv);
1956*8cecff49Sgp87344 }
1957