xref: /titanic_53/usr/src/cmd/stmsboot/stmsboot_util.c (revision a0261a438a8e91bafb5c9fc9a8c06a2cf682ab37)
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 /*
23*a0261a43SJames C. McPherson  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <stdio.h>
287c478bd9Sstevel@tonic-gate #include <stdlib.h>
297c478bd9Sstevel@tonic-gate #include <stdarg.h>
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <sys/stat.h>
327c478bd9Sstevel@tonic-gate #include <fcntl.h>
337c478bd9Sstevel@tonic-gate #include <errno.h>
347c478bd9Sstevel@tonic-gate #include <unistd.h>
357c478bd9Sstevel@tonic-gate #include <stropts.h>
367c478bd9Sstevel@tonic-gate #include <strings.h>
377c478bd9Sstevel@tonic-gate #include <sys/param.h>
387c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
397c478bd9Sstevel@tonic-gate #include <locale.h>
407c478bd9Sstevel@tonic-gate #include <libintl.h>
417c478bd9Sstevel@tonic-gate #include <devid.h>
42*a0261a43SJames C. McPherson #include <sys/modctl.h> /* for MAXMODCONFNAME */
43*a0261a43SJames C. McPherson #include <sys/scsi/adapters/scsi_vhci.h>
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /*
46*a0261a43SJames C. McPherson  * SAVE_DIR is the directory in which system files are saved.
47*a0261a43SJames C. McPherson  * SAVE_DIR must be under the root filesystem, as this program is
487c478bd9Sstevel@tonic-gate  * typically run before any other filesystems are mounted.
497c478bd9Sstevel@tonic-gate  */
507c478bd9Sstevel@tonic-gate #define	SAVE_DIR	"/etc/mpxio"
51*a0261a43SJames C. McPherson #define	VHCI_CTL_NODE	"/devices/scsi_vhci:devctl"
527c478bd9Sstevel@tonic-gate 
53*a0261a43SJames C. McPherson /* nvlist property names, these are ALL string types */
54*a0261a43SJames C. McPherson #define	NVL_DEVID 	"nvl-devid"
55*a0261a43SJames C. McPherson #define	NVL_PATH 	"nvl-path"
56*a0261a43SJames C. McPherson #define	NVL_PHYSPATH	"nvl-physpath"
57*a0261a43SJames C. McPherson #define	NVL_MPXPATH	"nvl-mpxiopath"
58*a0261a43SJames C. McPherson #define	NVL_MPXEN	"nvl-mpxioenabled"
597c478bd9Sstevel@tonic-gate 
60*a0261a43SJames C. McPherson #define	MPX_LIST		0x01
61*a0261a43SJames C. McPherson #define	MPX_MAP			0x02
62*a0261a43SJames C. McPherson #define	MPX_CAPABLE_CTRL	0x04
63*a0261a43SJames C. McPherson #define	MPX_INIT		0x08
64*a0261a43SJames C. McPherson #define	MPX_PHYSICAL		0x10
65*a0261a43SJames C. McPherson #define	MPX_BOOTPATH		0x20
66*a0261a43SJames C. McPherson #define	MPX_UPDATEVFSTAB	0x40
67*a0261a43SJames C. McPherson #define	MPX_USAGE		0x80
68*a0261a43SJames C. McPherson #define	MSG_INFO		0x01
69*a0261a43SJames C. McPherson #define	MSG_ERROR		0x02
70*a0261a43SJames C. McPherson #define	MSG_PANIC		0x04
7160fffc19Sjw149990 
72*a0261a43SJames C. McPherson #define	BOOT			0x01
73*a0261a43SJames C. McPherson #define	NONBOOT			0x00
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate static di_node_t devinfo_root = DI_NODE_NIL;
76*a0261a43SJames C. McPherson static char *ondiskname = "/etc/mpxio/devid_path.cache";
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
79*a0261a43SJames C. McPherson  * We use devid-keyed nvlists to keep track of the guid, traditional and
80*a0261a43SJames C. McPherson  * MPxIO-enabled /dev/rdsk paths. Each of these nvlists is eventually
81*a0261a43SJames C. McPherson  * added to our global nvlist and our on-disk nvlist.
827c478bd9Sstevel@tonic-gate  */
83*a0261a43SJames C. McPherson static nvlist_t *mapnvl;
84*a0261a43SJames C. McPherson static int mpxenabled = 0;
85*a0261a43SJames C. McPherson static int limctrl = -1;
86*a0261a43SJames C. McPherson static int guid = 0;
87*a0261a43SJames C. McPherson static char *drvlimit;
88*a0261a43SJames C. McPherson static int globarg = 0;
89*a0261a43SJames C. McPherson static int debugflag = 0;
90*a0261a43SJames C. McPherson static char *devicep;
91*a0261a43SJames C. McPherson static int readonlyroot = 0;
92*a0261a43SJames C. McPherson static int cap_N_option = 0;
93*a0261a43SJames C. McPherson 
94*a0261a43SJames C. McPherson static void print_mpx_capable(di_node_t curnode);
95*a0261a43SJames C. McPherson static int popcheck_devnvl(di_node_t thisnode, nvlist_t *devnvl,
96*a0261a43SJames C. McPherson     char *strdevid);
97*a0261a43SJames C. McPherson static int mpxio_nvl_boilerplate(di_node_t curnode);
98*a0261a43SJames C. McPherson static int validate_devnvl();
99*a0261a43SJames C. McPherson static void report_map(char *argdev, int physpath);
100*a0261a43SJames C. McPherson static void list_devs(int listguids, int ctrl);
101*a0261a43SJames C. McPherson static void logmsg(int level, const char *msg, ...);
102*a0261a43SJames C. McPherson static char *find_link(di_node_t cnode);
103*a0261a43SJames C. McPherson static void usage();
104*a0261a43SJames C. McPherson static void parse_args(int argc, char *argv[]);
105*a0261a43SJames C. McPherson static void get_devid(di_node_t node, ddi_devid_t *thisdevid);
106*a0261a43SJames C. McPherson static int print_bootpath();
107*a0261a43SJames C. McPherson static void vhci_to_phci(char *devpath, char *physpath);
108*a0261a43SJames C. McPherson static int update_vfstab();
109*a0261a43SJames C. McPherson 
110*a0261a43SJames C. McPherson int
111*a0261a43SJames C. McPherson main(int argc, char **argv)
1127c478bd9Sstevel@tonic-gate {
113*a0261a43SJames C. McPherson 	struct stat cachestat;
114*a0261a43SJames C. McPherson 	int mapfd = 0;
115*a0261a43SJames C. McPherson 	int rv = 0;
116*a0261a43SJames C. McPherson 	char *ondiskbuf;
117*a0261a43SJames C. McPherson 	size_t newsz = 0;
1187c478bd9Sstevel@tonic-gate 
119*a0261a43SJames C. McPherson 	parse_args(argc, argv);
120*a0261a43SJames C. McPherson 	errno = 0;
121*a0261a43SJames C. McPherson 	devinfo_root = di_init("/", DINFOCPYALL|DINFOFORCE);
122*a0261a43SJames C. McPherson 	logmsg(MSG_INFO, "errno = %d after "
123*a0261a43SJames C. McPherson 	    "di_init(/,DINFOCPYALL|DINFOFORCE)\n", errno);
124*a0261a43SJames C. McPherson 	if (devinfo_root == NULL) {
125*a0261a43SJames C. McPherson 		logmsg(MSG_ERROR,
126*a0261a43SJames C. McPherson 		    gettext("Unable to take device tree snapshot "
127*a0261a43SJames C. McPherson 		    "(%s: %d)\n"), strerror(errno), errno);
128*a0261a43SJames C. McPherson 		return (-1);
129*a0261a43SJames C. McPherson 	}
130*a0261a43SJames C. McPherson 	logmsg(MSG_INFO, "opened root di_node\n");
1317c478bd9Sstevel@tonic-gate 
132*a0261a43SJames C. McPherson 	if (globarg == MPX_CAPABLE_CTRL) {
133*a0261a43SJames C. McPherson 		/* we just want to find MPxIO-capable controllers and exit */
134*a0261a43SJames C. McPherson 		if (drvlimit != NULL) {
135*a0261a43SJames C. McPherson 			print_mpx_capable(di_drv_first_node(drvlimit,
136*a0261a43SJames C. McPherson 			    devinfo_root));
137*a0261a43SJames C. McPherson 		} else {
138*a0261a43SJames C. McPherson 			print_mpx_capable(di_drv_first_node("fp",
139*a0261a43SJames C. McPherson 			    devinfo_root));
140*a0261a43SJames C. McPherson 			print_mpx_capable(di_drv_first_node("mpt",
141*a0261a43SJames C. McPherson 			    devinfo_root));
142*a0261a43SJames C. McPherson 		}
143*a0261a43SJames C. McPherson 		di_fini(devinfo_root);
144*a0261a43SJames C. McPherson 		return (0);
145*a0261a43SJames C. McPherson 	}
146*a0261a43SJames C. McPherson 
147*a0261a43SJames C. McPherson 	mapfd = open(ondiskname, O_RDWR|O_CREAT|O_SYNC, S_IRUSR | S_IWUSR);
148*a0261a43SJames C. McPherson 	if (mapfd < 0) {
149*a0261a43SJames C. McPherson 		/* we could be in single-user, so try for RO */
150*a0261a43SJames C. McPherson 		if ((mapfd = open(ondiskname, O_RDONLY)) < 0) {
151*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR,
152*a0261a43SJames C. McPherson 			    gettext("Unable to open or create %s:%s\n"),
153*a0261a43SJames C. McPherson 			    ondiskname, strerror(errno));
154*a0261a43SJames C. McPherson 			return (errno);
155*a0261a43SJames C. McPherson 		}
156*a0261a43SJames C. McPherson 		readonlyroot = 1;
157*a0261a43SJames C. McPherson 	}
158*a0261a43SJames C. McPherson 
159*a0261a43SJames C. McPherson 	if (stat(ondiskname, &cachestat) != 0) {
160*a0261a43SJames C. McPherson 		logmsg(MSG_ERROR,
161*a0261a43SJames C. McPherson 		    gettext("Unable to stat() %s: %s\n"),
162*a0261a43SJames C. McPherson 		    ondiskname, strerror(errno));
163*a0261a43SJames C. McPherson 		return (errno);
164*a0261a43SJames C. McPherson 	}
165*a0261a43SJames C. McPherson 	ondiskbuf = calloc(1, cachestat.st_size);
166*a0261a43SJames C. McPherson 	if (ondiskbuf == NULL) {
167*a0261a43SJames C. McPherson 		logmsg(MSG_ERROR,
168*a0261a43SJames C. McPherson 		    gettext("Unable to allocate memory for the devid "
169*a0261a43SJames C. McPherson 		    "cache file: %s\n"), strerror(errno));
170*a0261a43SJames C. McPherson 		return (errno);
171*a0261a43SJames C. McPherson 	}
172*a0261a43SJames C. McPherson 	rv = read(mapfd, ondiskbuf, cachestat.st_size);
173*a0261a43SJames C. McPherson 	if (rv != cachestat.st_size) {
174*a0261a43SJames C. McPherson 		logmsg(MSG_ERROR,
175*a0261a43SJames C. McPherson 		    gettext("Unable to read all of devid cache file (got %d "
176*a0261a43SJames C. McPherson 		    "from expected %d bytes): %s\n"),
177*a0261a43SJames C. McPherson 		    rv, cachestat.st_size, strerror(errno));
178*a0261a43SJames C. McPherson 		return (errno);
179*a0261a43SJames C. McPherson 	}
180*a0261a43SJames C. McPherson 	errno = 0;
181*a0261a43SJames C. McPherson 	rv = nvlist_unpack(ondiskbuf, cachestat.st_size, &mapnvl, 0);
182*a0261a43SJames C. McPherson 	if (rv) {
183*a0261a43SJames C. McPherson 		logmsg(MSG_INFO,
184*a0261a43SJames C. McPherson 		    "Unable to unpack devid cache file %s: %s (%d)\n",
185*a0261a43SJames C. McPherson 		    ondiskname, strerror(rv), rv);
186*a0261a43SJames C. McPherson 		if (nvlist_alloc(&mapnvl, NV_UNIQUE_NAME, 0) != 0) {
187*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR,
188*a0261a43SJames C. McPherson 			    gettext("Unable to allocate root property"
189*a0261a43SJames C. McPherson 			    "list\n"));
190*a0261a43SJames C. McPherson 			return (errno);
191*a0261a43SJames C. McPherson 		}
192*a0261a43SJames C. McPherson 	}
193*a0261a43SJames C. McPherson 	free(ondiskbuf);
194*a0261a43SJames C. McPherson 
195*a0261a43SJames C. McPherson 	if (validate_devnvl() < 0) {
196*a0261a43SJames C. McPherson 		logmsg(MSG_ERROR,
197*a0261a43SJames C. McPherson 		    gettext("unable to validate kernel with on-disk devid "
198*a0261a43SJames C. McPherson 		    "cache file\n"));
199*a0261a43SJames C. McPherson 		return (errno);
2007c478bd9Sstevel@tonic-gate 	}
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	/*
203*a0261a43SJames C. McPherson 	 * If we're in single-user mode or maintenance mode, we won't
204*a0261a43SJames C. McPherson 	 * necessarily have a writable root device (ZFSroot; ufs root is
205*a0261a43SJames C. McPherson 	 * different in that we _do_ have a writable root device.
206*a0261a43SJames C. McPherson 	 * This causes problems for the devlink calls (see
207*a0261a43SJames C. McPherson 	 * $SRC/lib/libdevinfo/devinfo_devlink.c) and we do not try to
208*a0261a43SJames C. McPherson 	 * write out the devnvl if root is readonly.
2097c478bd9Sstevel@tonic-gate 	 */
210*a0261a43SJames C. McPherson 	if (!readonlyroot) {
211*a0261a43SJames C. McPherson 		rv = nvlist_size(mapnvl, &newsz, NV_ENCODE_NATIVE);
212*a0261a43SJames C. McPherson 		if (rv) {
213*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR,
214*a0261a43SJames C. McPherson 			    gettext("Unable to determine size of packed "
215*a0261a43SJames C. McPherson 			    "on-disk devid cache file %s: %s (%d).\n"),
216*a0261a43SJames C. McPherson 			    ondiskname, strerror(rv), rv);
217*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR, gettext("Terminating\n"));
218*a0261a43SJames C. McPherson 			nvlist_free(mapnvl);
219*a0261a43SJames C. McPherson 			(void) close(mapfd);
220*a0261a43SJames C. McPherson 			return (rv);
221*a0261a43SJames C. McPherson 		}
222*a0261a43SJames C. McPherson 
223*a0261a43SJames C. McPherson 		if ((ondiskbuf = calloc(1, newsz)) == NULL) {
224*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR,
225*a0261a43SJames C. McPherson 			    "Unable to allocate space for writing out new "
226*a0261a43SJames C. McPherson 			    "on-disk devid cache file: %s\n", strerror(errno));
227*a0261a43SJames C. McPherson 			(void) close(mapfd);
228*a0261a43SJames C. McPherson 			nvlist_free(mapnvl);
229*a0261a43SJames C. McPherson 			return (errno);
230*a0261a43SJames C. McPherson 		}
231*a0261a43SJames C. McPherson 
232*a0261a43SJames C. McPherson 		rv = nvlist_pack(mapnvl, &ondiskbuf, &newsz,
233*a0261a43SJames C. McPherson 		    NV_ENCODE_NATIVE, 0);
234*a0261a43SJames C. McPherson 		if (rv) {
235*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR,
236*a0261a43SJames C. McPherson 			    gettext("Unable to pack on-disk devid cache "
237*a0261a43SJames C. McPherson 			    "file: %s (%d)\n"), strerror(rv), rv);
238*a0261a43SJames C. McPherson 			(void) close(mapfd);
239*a0261a43SJames C. McPherson 			free(ondiskbuf);
240*a0261a43SJames C. McPherson 			nvlist_free(mapnvl);
241*a0261a43SJames C. McPherson 			return (rv);
242*a0261a43SJames C. McPherson 		}
243*a0261a43SJames C. McPherson 
244*a0261a43SJames C. McPherson 		rv = lseek(mapfd, 0, 0);
245*a0261a43SJames C. McPherson 		if (rv == -1) {
246*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR,
247*a0261a43SJames C. McPherson 			    gettext("Unable to seek to start of devid cache "
248*a0261a43SJames C. McPherson 			    "file: %s (%d)\n"), strerror(errno), errno);
249*a0261a43SJames C. McPherson 			(void) close(mapfd);
250*a0261a43SJames C. McPherson 			free(ondiskbuf);
251*a0261a43SJames C. McPherson 			nvlist_free(mapnvl);
252*a0261a43SJames C. McPherson 			return (-1);
253*a0261a43SJames C. McPherson 		}
254*a0261a43SJames C. McPherson 
255*a0261a43SJames C. McPherson 		if (write(mapfd, ondiskbuf, newsz) != newsz) {
256*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR,
257*a0261a43SJames C. McPherson 			    gettext("Unable to completely write out "
258*a0261a43SJames C. McPherson 			    "on-disk devid cache file: %s\n"), strerror(errno));
259*a0261a43SJames C. McPherson 			(void) close(mapfd);
260*a0261a43SJames C. McPherson 			nvlist_free(mapnvl);
261*a0261a43SJames C. McPherson 			free(ondiskbuf);
262*a0261a43SJames C. McPherson 			return (errno);
263*a0261a43SJames C. McPherson 		}
264*a0261a43SJames C. McPherson 	} /* !readonlyroot */
265*a0261a43SJames C. McPherson 
266*a0261a43SJames C. McPherson 	/* Now we can process the command line args */
267*a0261a43SJames C. McPherson 	if (globarg == MPX_PHYSICAL) {
268*a0261a43SJames C. McPherson 		report_map(devicep, BOOT);
269*a0261a43SJames C. McPherson 	} else if (globarg == MPX_BOOTPATH) {
270*a0261a43SJames C. McPherson 		rv = print_bootpath();
271*a0261a43SJames C. McPherson 		di_fini(devinfo_root);
272*a0261a43SJames C. McPherson 		return (rv);
273*a0261a43SJames C. McPherson 	} else if (globarg == MPX_UPDATEVFSTAB) {
274*a0261a43SJames C. McPherson 		rv = update_vfstab();
275*a0261a43SJames C. McPherson 		di_fini(devinfo_root);
276*a0261a43SJames C. McPherson 		return (rv);
277*a0261a43SJames C. McPherson 	} else if (globarg != MPX_INIT) {
278*a0261a43SJames C. McPherson 		if (globarg & MPX_LIST)
279*a0261a43SJames C. McPherson 			list_devs(guid, limctrl);
280*a0261a43SJames C. McPherson 
281*a0261a43SJames C. McPherson 		if (globarg == MPX_MAP)
282*a0261a43SJames C. McPherson 			report_map(devicep, NONBOOT);
283*a0261a43SJames C. McPherson 	} else {
284*a0261a43SJames C. McPherson 		logmsg(MSG_INFO, "\nprivate devid cache file initialised\n");
285*a0261a43SJames C. McPherson 	}
286*a0261a43SJames C. McPherson 
287*a0261a43SJames C. McPherson 	nvlist_free(mapnvl);
288*a0261a43SJames C. McPherson 	di_fini(devinfo_root);
289*a0261a43SJames C. McPherson 	return (0);
290*a0261a43SJames C. McPherson }
291*a0261a43SJames C. McPherson 
292*a0261a43SJames C. McPherson static void
293*a0261a43SJames C. McPherson usage()
294*a0261a43SJames C. McPherson {
295*a0261a43SJames C. McPherson 	(void) fprintf(stderr,
296*a0261a43SJames C. McPherson 	    gettext("usage: stmsboot_util -b | -m devname | "
297*a0261a43SJames C. McPherson 	    "-l <ctrl> | -L | [-g] | -n | -N | -i | -p devname\n"));
298*a0261a43SJames C. McPherson 	(void) fprintf(stderr, "\n\n");
299*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t-h\tprint this usage message\n"));
300*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t-b\tretrieve the system's bootpath "
301*a0261a43SJames C. McPherson 	    "setting\n"));
302*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t-m devname\n"));
303*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t\tReports the current mapping for "
304*a0261a43SJames C. McPherson 	    "devname\n"));
305*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t-g\tprint the GUID for MPxIO-capable "
306*a0261a43SJames C. McPherson 	    "devices. This\n"));
307*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t\toption is only valid with the -L "
308*a0261a43SJames C. McPherson 	    "or -l options\n"));
309*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t-L | -l <ctrl>\n"));
310*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t\tList the 'native' to 'MPxIO' "
311*a0261a43SJames C. McPherson 	    "device mappings. If <ctrl>\n"));
312*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t\tis specified, only print mappings "
313*a0261a43SJames C. McPherson 	    "for those devices\n"));
314*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t\tattached via the specified "
315*a0261a43SJames C. McPherson 	    "controller.\n"));
316*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t-i\tinitialise the private devid "
317*a0261a43SJames C. McPherson 	    "cache file and exit\n"));
318*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t\tThis option excludes all "
319*a0261a43SJames C. McPherson 	    "others.\n"));
320*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t-n\tprint the devfs paths for "
321*a0261a43SJames C. McPherson 	    "multipath-capable\n"));
322*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t\tcontroller ports.\n"));
323*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t-N\tprint the device aliases of "
324*a0261a43SJames C. McPherson 	    "multipath-capable\n"));
325*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t\tcontroller ports.\n"));
326*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t-p\tdevname\n"));
327*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t\tThis option provides the physical "
328*a0261a43SJames C. McPherson 	    "devfs path for\n"));
329*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t\ta specific device (devname). Used "
330*a0261a43SJames C. McPherson 	    "to set the bootpath\n"));
331*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t\tvariable on x86/x64 systems\n"));
332*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t-u\ttranslates device mappings in "
333*a0261a43SJames C. McPherson 	    "/etc/vfstab as \n"));
334*a0261a43SJames C. McPherson 	(void) fprintf(stderr, gettext("\t\trequired. The output is written "
335*a0261a43SJames C. McPherson 	    "to /etc/mpxio/vfstab.new\n\n"));
336*a0261a43SJames C. McPherson 	exit(2);
337*a0261a43SJames C. McPherson }
338*a0261a43SJames C. McPherson 
3397c478bd9Sstevel@tonic-gate static void
3407c478bd9Sstevel@tonic-gate parse_args(int argc, char *argv[])
3417c478bd9Sstevel@tonic-gate {
3427c478bd9Sstevel@tonic-gate 	char opt;
3437c478bd9Sstevel@tonic-gate 
344*a0261a43SJames C. McPherson 	if (argc == 1)
345*a0261a43SJames C. McPherson 		usage();
3467c478bd9Sstevel@tonic-gate 
347*a0261a43SJames C. McPherson 	/*
348*a0261a43SJames C. McPherson 	 * -b	prints the bootpath property
349*a0261a43SJames C. McPherson 	 * -d	turns on debug mode for this utility (copious output!)
350*a0261a43SJames C. McPherson 	 * -D drvname
351*a0261a43SJames C. McPherson 	 *	if supplied, indicates that we're going to operate on
352*a0261a43SJames C. McPherson 	 *	devices attached to this driver.
353*a0261a43SJames C. McPherson 	 * -g	if (-l or -L), prints guids for devices rather than paths
354*a0261a43SJames C. McPherson 	 * -h	prints the usage() help text.
355*a0261a43SJames C. McPherson 	 * -i	initialises the cache file and exits.
356*a0261a43SJames C. McPherson 	 * -l controller
357*a0261a43SJames C. McPherson 	 *	list non-STMS to STMS device name mappings for the specific
358*a0261a43SJames C. McPherson 	 *	controller, when MPxIO is enabled only.
359*a0261a43SJames C. McPherson 	 * -L	list non-STMS to STMS device name mappings for all controllers
360*a0261a43SJames C. McPherson 	 *	when MPxIO is enabled only.
361*a0261a43SJames C. McPherson 	 * -m devname
362*a0261a43SJames C. McPherson 	 *	prints the device path (/dev/rdsk) that devname maps to
363*a0261a43SJames C. McPherson 	 *	in the currently-running system.
364*a0261a43SJames C. McPherson 	 * -n
365*a0261a43SJames C. McPherson 	 *	if supplied, returns name of STMS-capable controller nodes.
366*a0261a43SJames C. McPherson 	 *	If the -D drvname option is specified as well, we only report
367*a0261a43SJames C. McPherson 	 *	nodes attached with drvname.
368*a0261a43SJames C. McPherson 	 * -N
369*a0261a43SJames C. McPherson 	 *	same as the -n option, except that we only print the
370*a0261a43SJames C. McPherson 	 *	node-name (dev_info :: devi_node_name). Multiple instances
371*a0261a43SJames C. McPherson 	 *	through the libdevinfo snapshot are uniqified and separated
372*a0261a43SJames C. McPherson 	 *	by the "|" character for direct use by egrep(1).
373*a0261a43SJames C. McPherson 	 * -p devname
374*a0261a43SJames C. McPherson 	 *	prints the physical devfs path for devname. Only used to
375*a0261a43SJames C. McPherson 	 *	determine the bootpath.
376*a0261a43SJames C. McPherson 	 * -u
377*a0261a43SJames C. McPherson 	 *	remaps devices in /etc/vfstab, saving the newly generated
378*a0261a43SJames C. McPherson 	 *	file to /etc/mpxio/vfstab.new. If we have any remapped
379*a0261a43SJames C. McPherson 	 *	devices, exit with status 0, otherwise -1 for error.
380*a0261a43SJames C. McPherson 	 */
381*a0261a43SJames C. McPherson 	while ((opt = getopt(argc, argv, "bdD:ghil:Lm:nNp:u")) != EOF) {
3827c478bd9Sstevel@tonic-gate 		switch (opt) {
383*a0261a43SJames C. McPherson 		case 'b':
384*a0261a43SJames C. McPherson 			globarg = MPX_BOOTPATH;
3857c478bd9Sstevel@tonic-gate 			break;
3867c478bd9Sstevel@tonic-gate 		case 'd':
387*a0261a43SJames C. McPherson 			debugflag = 1;
3887c478bd9Sstevel@tonic-gate 			break;
38960fffc19Sjw149990 		case 'D':
390*a0261a43SJames C. McPherson 			if ((drvlimit = calloc(1, MAXMODCONFNAME)) == NULL) {
391*a0261a43SJames C. McPherson 				logmsg(MSG_ERROR,
392*a0261a43SJames C. McPherson 				    gettext("Unable to allocate memory for a "
393*a0261a43SJames C. McPherson 				    "driver name: %s\n"), strerror(errno));
394*a0261a43SJames C. McPherson 				exit(errno);
39560fffc19Sjw149990 			}
396*a0261a43SJames C. McPherson 			bcopy(optarg, drvlimit, strlen(optarg));
397*a0261a43SJames C. McPherson 			/* update this if adding support for a new driver */
398*a0261a43SJames C. McPherson 			if ((strncmp(drvlimit, "fp", 2) == NULL) &&
399*a0261a43SJames C. McPherson 			    (strncmp(drvlimit, "mpt", 3) == NULL)) {
400*a0261a43SJames C. McPherson 				logmsg(MSG_ERROR,
401*a0261a43SJames C. McPherson 				    gettext("invalid parent driver (%s) "
402*a0261a43SJames C. McPherson 				    "specified"), drvlimit);
403*a0261a43SJames C. McPherson 				usage();
404*a0261a43SJames C. McPherson 			}
40560fffc19Sjw149990 			break;
406*a0261a43SJames C. McPherson 		case 'h':
407*a0261a43SJames C. McPherson 			/* Just drop out and print the usage() output */
408*a0261a43SJames C. McPherson 			globarg = MPX_USAGE;
409*a0261a43SJames C. McPherson 			break;
410*a0261a43SJames C. McPherson 		case 'i':
411*a0261a43SJames C. McPherson 			globarg = MPX_INIT;
412*a0261a43SJames C. McPherson 			break;
413*a0261a43SJames C. McPherson 		case 'l':
414*a0261a43SJames C. McPherson 			globarg |= MPX_LIST;
415*a0261a43SJames C. McPherson 			limctrl = (int)atol(optarg);
416*a0261a43SJames C. McPherson 			if (limctrl < 0) {
417*a0261a43SJames C. McPherson 				logmsg(MSG_INFO,
418*a0261a43SJames C. McPherson 				    gettext("invalid controller number "
419*a0261a43SJames C. McPherson 				    "(%d), checking all controllers\n"),
420*a0261a43SJames C. McPherson 				    limctrl);
421*a0261a43SJames C. McPherson 			}
422*a0261a43SJames C. McPherson 			break;
423*a0261a43SJames C. McPherson 		case 'L':
424*a0261a43SJames C. McPherson 			globarg |= MPX_LIST;
425*a0261a43SJames C. McPherson 			break;
426*a0261a43SJames C. McPherson 		case 'g':
427*a0261a43SJames C. McPherson 			guid = 1;
428*a0261a43SJames C. McPherson 			break;
429*a0261a43SJames C. McPherson 		case 'm':
430*a0261a43SJames C. McPherson 			globarg = MPX_MAP;
431*a0261a43SJames C. McPherson 			if ((devicep = calloc(1, MAXPATHLEN)) == NULL) {
432*a0261a43SJames C. McPherson 				logmsg(MSG_ERROR,
433*a0261a43SJames C. McPherson 				    gettext("Unable to allocate space for a "
434*a0261a43SJames C. McPherson 				    "device name\n"));
435*a0261a43SJames C. McPherson 				exit(errno);
436*a0261a43SJames C. McPherson 			}
437*a0261a43SJames C. McPherson 			devicep = strdup(optarg);
438*a0261a43SJames C. McPherson 			break;
439*a0261a43SJames C. McPherson 		case 'N':
440*a0261a43SJames C. McPherson 			cap_N_option = 1;
441*a0261a43SJames C. McPherson 			globarg = MPX_CAPABLE_CTRL;
442*a0261a43SJames C. McPherson 			break;
44360fffc19Sjw149990 		case 'n':
444*a0261a43SJames C. McPherson 			globarg = MPX_CAPABLE_CTRL;
44560fffc19Sjw149990 			break;
446*a0261a43SJames C. McPherson 		case 'p':
447*a0261a43SJames C. McPherson 			globarg = MPX_PHYSICAL;
448*a0261a43SJames C. McPherson 			if ((devicep = calloc(1, MAXPATHLEN)) == NULL) {
449*a0261a43SJames C. McPherson 				logmsg(MSG_ERROR,
450*a0261a43SJames C. McPherson 				    gettext("Unable to allocate space for a "
451*a0261a43SJames C. McPherson 				    "device name\n"));
452*a0261a43SJames C. McPherson 				exit(errno);
453*a0261a43SJames C. McPherson 			}
454*a0261a43SJames C. McPherson 			devicep = strdup(optarg);
455*a0261a43SJames C. McPherson 			break;
456*a0261a43SJames C. McPherson 		case 'u':
457*a0261a43SJames C. McPherson 			globarg = MPX_UPDATEVFSTAB;
458*a0261a43SJames C. McPherson 			break;
4597c478bd9Sstevel@tonic-gate 		default:
460*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR,
461*a0261a43SJames C. McPherson 			    gettext("Invalid command line option (%c)\n"),
462*a0261a43SJames C. McPherson 			    opt);
463*a0261a43SJames C. McPherson 			usage();
4647c478bd9Sstevel@tonic-gate 		}
4657c478bd9Sstevel@tonic-gate 	}
4667c478bd9Sstevel@tonic-gate 
467*a0261a43SJames C. McPherson 	if ((globarg >= MPX_USAGE) || (guid && (globarg != MPX_LIST)))
468*a0261a43SJames C. McPherson 		usage();
469*a0261a43SJames C. McPherson 
470*a0261a43SJames C. McPherson 	if ((drvlimit != NULL) &&
471*a0261a43SJames C. McPherson 	    ((globarg != MPX_LIST) &&
472*a0261a43SJames C. McPherson 	    (globarg != MPX_CAPABLE_CTRL)))
473*a0261a43SJames C. McPherson 		usage();
47460fffc19Sjw149990 }
4757c478bd9Sstevel@tonic-gate 
476*a0261a43SJames C. McPherson static void
477*a0261a43SJames C. McPherson logmsg(int level, const char *msg, ...)
4787c478bd9Sstevel@tonic-gate {
479*a0261a43SJames C. McPherson 	va_list ap;
4807c478bd9Sstevel@tonic-gate 
481*a0261a43SJames C. McPherson 	if ((level >= MSG_ERROR) ||
482*a0261a43SJames C. McPherson 	    ((debugflag > 0) && (level >= MSG_INFO))) {
483*a0261a43SJames C. McPherson 		(void) fprintf(stdout, "stmsboot: ");
484*a0261a43SJames C. McPherson 		va_start(ap, msg);
485*a0261a43SJames C. McPherson 		(void) vfprintf(stdout, msg, ap);
486*a0261a43SJames C. McPherson 		va_end(ap);
4877c478bd9Sstevel@tonic-gate 	}
4887c478bd9Sstevel@tonic-gate }
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate /*
491*a0261a43SJames C. McPherson  * It's up to the caller to do any sorting or pretty-printing of the device
492*a0261a43SJames C. McPherson  * mappings we report. Since we're storing the device links as just the cXtYdZ
493*a0261a43SJames C. McPherson  * part, we'll add /dev/rdsk/ back on when we print the listing so we maintain
494*a0261a43SJames C. McPherson  * compatibility with previous versions of this tool. There's a little bit
495*a0261a43SJames C. McPherson  * of footwork involved to make sure that we show all the paths to a device
496*a0261a43SJames C. McPherson  * rather than just the first one we stashed away.
4977c478bd9Sstevel@tonic-gate  */
4987c478bd9Sstevel@tonic-gate static void
499*a0261a43SJames C. McPherson list_devs(int listguids, int ctrl)
5007c478bd9Sstevel@tonic-gate {
501*a0261a43SJames C. McPherson 	nvlist_t *thisdevnvl;
502*a0261a43SJames C. McPherson 	nvpair_t *pair;
503*a0261a43SJames C. McPherson 	char *diskpath, *livepath, *key, *querydev;
504*a0261a43SJames C. McPherson 	char *matchctrl = NULL;
505*a0261a43SJames C. McPherson 	char checkctrl[MAXPATHLEN];
506*a0261a43SJames C. McPherson 	int rv;
5077c478bd9Sstevel@tonic-gate 
508*a0261a43SJames C. McPherson 	if (!mpxenabled) {
509*a0261a43SJames C. McPherson 		logmsg(MSG_ERROR, gettext("MPxIO is not enabled\n"));
510*a0261a43SJames C. McPherson 		return;
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate 
513*a0261a43SJames C. McPherson 	if (listguids) {
514*a0261a43SJames C. McPherson 		(void) printf(gettext("non-STMS device name\t\t\tGUID\n"
515*a0261a43SJames C. McPherson 		    "------------------------------------------"
516*a0261a43SJames C. McPherson 		    "------------------------\n"));
5177c478bd9Sstevel@tonic-gate 	} else {
518*a0261a43SJames C. McPherson 		(void) printf(gettext("non-STMS device name\t\t\t"
519*a0261a43SJames C. McPherson 		    "STMS device name\n"
520*a0261a43SJames C. McPherson 		    "------------------------------------------"
521*a0261a43SJames C. McPherson 		    "------------------------\n"));
522*a0261a43SJames C. McPherson 	}
523*a0261a43SJames C. McPherson 
524*a0261a43SJames C. McPherson 	bzero(checkctrl, MAXPATHLEN);
525*a0261a43SJames C. McPherson 	pair = NULL;
526*a0261a43SJames C. McPherson 	while ((pair = nvlist_next_nvpair(mapnvl, pair))
527*a0261a43SJames C. McPherson 	    != NULL) {
528*a0261a43SJames C. McPherson 		boolean_t livescsivhcip = B_FALSE;
529*a0261a43SJames C. McPherson 
530*a0261a43SJames C. McPherson 		if ((((rv = nvpair_value_string(pair, &querydev)) < 0) ||
531*a0261a43SJames C. McPherson 		    ((key = nvpair_name(pair)) == NULL)) ||
532*a0261a43SJames C. McPherson 		    ((strstr(key, "/pci") != NULL) ||
533*a0261a43SJames C. McPherson 		    (strstr(key, "/sbus") != NULL) ||
534*a0261a43SJames C. McPherson 		    (strstr(key, "/scsi_vhci") != NULL) ||
535*a0261a43SJames C. McPherson 		    (strncmp(key, "id1", 3) == 0))) {
536*a0261a43SJames C. McPherson 			logmsg(MSG_INFO,
537*a0261a43SJames C. McPherson 			    "list_devs: rv = %d; (%s) is not a devlink, "
538*a0261a43SJames C. McPherson 			    "continuing.\n", rv,
539*a0261a43SJames C. McPherson 			    (key != NULL) ? key : "null");
540*a0261a43SJames C. McPherson 			querydev = NULL;
541*a0261a43SJames C. McPherson 			continue;
542*a0261a43SJames C. McPherson 		}
543*a0261a43SJames C. McPherson 
544*a0261a43SJames C. McPherson 		(void) nvlist_lookup_nvlist(mapnvl, querydev, &thisdevnvl);
545*a0261a43SJames C. McPherson 		(void) nvlist_lookup_boolean_value(thisdevnvl, NVL_MPXEN,
546*a0261a43SJames C. McPherson 		    &livescsivhcip);
547*a0261a43SJames C. McPherson 		(void) nvlist_lookup_string(thisdevnvl, NVL_MPXPATH,
548*a0261a43SJames C. McPherson 		    &livepath);
549*a0261a43SJames C. McPherson 
550*a0261a43SJames C. McPherson 		if ((!livescsivhcip) ||
551*a0261a43SJames C. McPherson 		    (livescsivhcip &&
552*a0261a43SJames C. McPherson 		    (strncmp(key, livepath, strlen(key)) == 0)))
553*a0261a43SJames C. McPherson 			continue;
554*a0261a43SJames C. McPherson 
555*a0261a43SJames C. McPherson 		(void) nvlist_lookup_string(thisdevnvl, NVL_PATH,
556*a0261a43SJames C. McPherson 		    &diskpath);
557*a0261a43SJames C. McPherson 
558*a0261a43SJames C. McPherson 		logmsg(MSG_INFO,
559*a0261a43SJames C. McPherson 		    "list_devs: %s :: %s ::%s :: MPXEN (%s)\n",
560*a0261a43SJames C. McPherson 		    key, diskpath, livepath,
561*a0261a43SJames C. McPherson 		    ((livescsivhcip) ? "TRUE" : "FALSE"));
562*a0261a43SJames C. McPherson 
563*a0261a43SJames C. McPherson 		if (ctrl > -1) {
564*a0261a43SJames C. McPherson 			(void) sprintf(checkctrl, "c%dt", ctrl);
565*a0261a43SJames C. McPherson 			matchctrl = strstr(key, checkctrl);
566*a0261a43SJames C. McPherson 			if (matchctrl == NULL)
567*a0261a43SJames C. McPherson 				continue;
568*a0261a43SJames C. McPherson 		}
569*a0261a43SJames C. McPherson 		if (listguids != 0) {
570*a0261a43SJames C. McPherson 			char *tempguid;
571*a0261a43SJames C. McPherson 			ddi_devid_t curdevid;
572*a0261a43SJames C. McPherson 			int rv;
573*a0261a43SJames C. McPherson 
574*a0261a43SJames C. McPherson 			rv = devid_str_decode(querydev, &curdevid, NULL);
575*a0261a43SJames C. McPherson 			if (rv == -1) {
576*a0261a43SJames C. McPherson 				logmsg(MSG_INFO, "Unable to decode devid %s\n",
577*a0261a43SJames C. McPherson 				    key);
578*a0261a43SJames C. McPherson 				continue;
579*a0261a43SJames C. McPherson 			}
580*a0261a43SJames C. McPherson 			tempguid = devid_to_guid(curdevid);
581*a0261a43SJames C. McPherson 			if (tempguid != NULL)
582*a0261a43SJames C. McPherson 				(void) printf("/dev/rdsk/%s\t%s\n",
583*a0261a43SJames C. McPherson 				    diskpath, tempguid);
584*a0261a43SJames C. McPherson 
585*a0261a43SJames C. McPherson 			devid_free_guid(tempguid);
586*a0261a43SJames C. McPherson 			devid_free(curdevid);
587*a0261a43SJames C. McPherson 			continue;
588*a0261a43SJames C. McPherson 		}
589*a0261a43SJames C. McPherson 
590*a0261a43SJames C. McPherson 		(void) printf("/dev/rdsk/%s\t/dev/rdsk/%s\n",
591*a0261a43SJames C. McPherson 		    (strstr(key, diskpath) == NULL) ? key : diskpath,
592*a0261a43SJames C. McPherson 		    livepath);
5937c478bd9Sstevel@tonic-gate 	}
5947c478bd9Sstevel@tonic-gate }
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate /*
597*a0261a43SJames C. McPherson  * We get passed a device name which we search the mapnvl for. If we find
598*a0261a43SJames C. McPherson  * it, we print the mapping as it is found. It is up to the caller of this
599*a0261a43SJames C. McPherson  * utility to do any pretty-printing of the results. If a device listed on
600*a0261a43SJames C. McPherson  * the command line does not exist in the mapnvl, then we print NOT_MAPPED.
601*a0261a43SJames C. McPherson  * Otherwise we print the command-line device name as it maps to what is
602*a0261a43SJames C. McPherson  * stashed in the mapnvl - even if that's a "no change" device mapping.
6037c478bd9Sstevel@tonic-gate  *
604*a0261a43SJames C. McPherson  * Example output (-p maps to physpath=BOOT)
605*a0261a43SJames C. McPherson  * # /lib/mpxio/stmsboot_util -p \
606*a0261a43SJames C. McPherson  *	/pci@0,0/pci1022,7450@2/pci1000,3060@3/sd@1,0:a
607*a0261a43SJames C. McPherson  * /scsi_vhci/disk@g500000e011e17720:a
6087c478bd9Sstevel@tonic-gate  *
609*a0261a43SJames C. McPherson  * Or the reverse:
610*a0261a43SJames C. McPherson  * # /lib/mpxio/stmsboot_util -p /scsi_vhci/disk@g500000e011e17720:a
611*a0261a43SJames C. McPherson  * /pci@0,0/pci1022,7450@2/pci1000,3060@3/sd@1,0:a
612*a0261a43SJames C. McPherson  *
613*a0261a43SJames C. McPherson  * For the -m option, used when we're trying to find the root device mapping:
614*a0261a43SJames C. McPherson  *
615*a0261a43SJames C. McPherson  * # /lib/mpxio/stmsboot_util -m /dev/dsk/c2t0d0s2
616*a0261a43SJames C. McPherson  * /dev/dsk/c3t500000E011637CF0d0s2
617*a0261a43SJames C. McPherson  */
618*a0261a43SJames C. McPherson static void
619*a0261a43SJames C. McPherson report_map(char *argdev, int physpath)
620*a0261a43SJames C. McPherson {
621*a0261a43SJames C. McPherson 	nvlist_t *thisdev;
622*a0261a43SJames C. McPherson 	int rv = 0;
623*a0261a43SJames C. McPherson 	char *thisdevid;
624*a0261a43SJames C. McPherson 	char *mpxpath = NULL;
625*a0261a43SJames C. McPherson 	char *prefixt = NULL;
626*a0261a43SJames C. McPherson 	char *prefixp = NULL;
627*a0261a43SJames C. McPherson 	char *stripdev = NULL;
628*a0261a43SJames C. McPherson 	char *slice = NULL;
629*a0261a43SJames C. McPherson 	boolean_t mpxenp;
630*a0261a43SJames C. McPherson 	uint_t slicelen = 0;
631*a0261a43SJames C. McPherson 
632*a0261a43SJames C. McPherson 	mpxenp = B_FALSE;
633*a0261a43SJames C. McPherson 
634*a0261a43SJames C. McPherson 	if ((prefixt = calloc(1, strlen(argdev) + 1)) == NULL) {
635*a0261a43SJames C. McPherson 		logmsg(MSG_INFO, "Unable to allocate memory\n");
636*a0261a43SJames C. McPherson 		(void) printf("NOT_MAPPED\n");
637*a0261a43SJames C. McPherson 		return;
638*a0261a43SJames C. McPherson 	}
639*a0261a43SJames C. McPherson 
640*a0261a43SJames C. McPherson 	(void) strlcpy(prefixt, argdev, strlen(argdev) + 1);
641*a0261a43SJames C. McPherson 
642*a0261a43SJames C. McPherson 	slice = strrchr(argdev, (physpath == BOOT) ? ':' : 's');
643*a0261a43SJames C. McPherson 	if (slice != NULL) {
644*a0261a43SJames C. McPherson 		slicelen = strlen(slice);
645*a0261a43SJames C. McPherson 		if (slicelen > 3)
646*a0261a43SJames C. McPherson 			/* invalid size - max is 3 chars */
647*a0261a43SJames C. McPherson 			slicelen = 0;
648*a0261a43SJames C. McPherson 	}
649*a0261a43SJames C. McPherson 
650*a0261a43SJames C. McPherson 	if ((stripdev = calloc(1, strlen(prefixt) + 1)) == NULL) {
651*a0261a43SJames C. McPherson 		logmsg(MSG_INFO, "Unable to allocate memory\n");
652*a0261a43SJames C. McPherson 		(void) printf("NOT_MAPPED\n");
653*a0261a43SJames C. McPherson 		free(prefixt);
654*a0261a43SJames C. McPherson 		return;
655*a0261a43SJames C. McPherson 	}
656*a0261a43SJames C. McPherson 
657*a0261a43SJames C. McPherson 	if ((strstr(prefixt, "/scsi_vhci") == NULL) &&
658*a0261a43SJames C. McPherson 	    (strstr(prefixt, "/pci") == NULL) &&
659*a0261a43SJames C. McPherson 	    (strstr(prefixt, "/sbus") == NULL)) {
660*a0261a43SJames C. McPherson 		prefixp = strrchr(prefixt, '/');
661*a0261a43SJames C. McPherson 		(void) strlcpy(stripdev,
662*a0261a43SJames C. McPherson 		    (prefixp == NULL) ? prefixt : prefixp + 1,
663*a0261a43SJames C. McPherson 		    (prefixp == NULL) ?
664*a0261a43SJames C. McPherson 		    strlen(prefixt) + 1: strlen(prefixp) + 1);
665*a0261a43SJames C. McPherson 		if (prefixp != NULL)
666*a0261a43SJames C. McPherson 			prefixt[strlen(argdev) - strlen(prefixp) + 1] = '\0';
667*a0261a43SJames C. McPherson 	} else {
668*a0261a43SJames C. McPherson 		if (physpath != BOOT) {
669*a0261a43SJames C. McPherson 			logmsg(MSG_INFO, "Invalid device path provided\n");
670*a0261a43SJames C. McPherson 			(void) printf("NOT_MAPPED\n");
671*a0261a43SJames C. McPherson 			free(stripdev);
672*a0261a43SJames C. McPherson 			free(prefixt);
673*a0261a43SJames C. McPherson 			return;
674*a0261a43SJames C. McPherson 		}
675*a0261a43SJames C. McPherson 		(void) strlcpy(stripdev, argdev, strlen(argdev) + 1);
676*a0261a43SJames C. McPherson 	}
677*a0261a43SJames C. McPherson 
678*a0261a43SJames C. McPherson 	logmsg(MSG_INFO,
679*a0261a43SJames C. McPherson 	    "stripdev (%s), prefixt(%s), prefixp(%s), slice(%s)\n",
680*a0261a43SJames C. McPherson 	    (stripdev == NULL) ? "null" : stripdev,
681*a0261a43SJames C. McPherson 	    (prefixt == NULL) ? "null" : prefixt,
682*a0261a43SJames C. McPherson 	    (prefixp == NULL) ? "null" : prefixp,
683*a0261a43SJames C. McPherson 	    (slice == NULL) ? "null" : slice);
684*a0261a43SJames C. McPherson 
685*a0261a43SJames C. McPherson 	if (slicelen > 0)
686*a0261a43SJames C. McPherson 		stripdev[strlen(stripdev) - slicelen] = '\0';
687*a0261a43SJames C. McPherson 
688*a0261a43SJames C. McPherson 	/* search for the shortened version */
689*a0261a43SJames C. McPherson 	rv = nvlist_lookup_string(mapnvl, stripdev, &thisdevid);
690*a0261a43SJames C. McPherson 	if (rv) {
691*a0261a43SJames C. McPherson 		if (physpath != BOOT) {
692*a0261a43SJames C. McPherson 			logmsg(MSG_INFO,
693*a0261a43SJames C. McPherson 			    "searched mapnvl for '%s', got %s (%d)\n",
694*a0261a43SJames C. McPherson 			    stripdev, strerror(rv), rv);
695*a0261a43SJames C. McPherson 			(void) printf("NOT_MAPPED\n");
696*a0261a43SJames C. McPherson 			free(stripdev);
697*a0261a43SJames C. McPherson 			free(prefixt);
698*a0261a43SJames C. McPherson 			return;
699*a0261a43SJames C. McPherson 		}
700*a0261a43SJames C. McPherson 	}
701*a0261a43SJames C. McPherson 
702*a0261a43SJames C. McPherson 	logmsg(MSG_INFO, "device %s has devid %s\n", stripdev, thisdevid);
703*a0261a43SJames C. McPherson 
704*a0261a43SJames C. McPherson 	if (nvlist_lookup_nvlist(mapnvl, thisdevid, &thisdev) != 0) {
705*a0261a43SJames C. McPherson 		logmsg(MSG_INFO, "device (%s) in mapnvl but "
706*a0261a43SJames C. McPherson 		    "not mapped!\n", thisdevid);
707*a0261a43SJames C. McPherson 		(void) printf("NOT_MAPPED\n");
708*a0261a43SJames C. McPherson 		free(stripdev);
709*a0261a43SJames C. McPherson 		free(prefixt);
710*a0261a43SJames C. McPherson 		return;
711*a0261a43SJames C. McPherson 	}
712*a0261a43SJames C. McPherson 
713*a0261a43SJames C. McPherson 	/* quick exit */
714*a0261a43SJames C. McPherson 	if (!mpxenabled && (strstr(argdev, "/pci") != NULL ||
715*a0261a43SJames C. McPherson 	    strstr(argdev, "/sbus") != NULL)) {
716*a0261a43SJames C. McPherson 		(void) printf("%s\n", argdev);
717*a0261a43SJames C. McPherson 		free(stripdev);
718*a0261a43SJames C. McPherson 		free(prefixt);
719*a0261a43SJames C. McPherson 		return;
720*a0261a43SJames C. McPherson 	}
721*a0261a43SJames C. McPherson 
722*a0261a43SJames C. McPherson 	(void) nvlist_lookup_boolean_value(thisdev, NVL_MPXEN, &mpxenp);
723*a0261a43SJames C. McPherson 
724*a0261a43SJames C. McPherson 	if (physpath == BOOT) {
725*a0261a43SJames C. McPherson 		(void) nvlist_lookup_string(thisdev, NVL_PHYSPATH, &mpxpath);
726*a0261a43SJames C. McPherson 		if ((strstr(argdev, "/scsi_vhci") != NULL) &&
727*a0261a43SJames C. McPherson 		    (strncmp(argdev, mpxpath, strlen(mpxpath)) == 0)) {
728*a0261a43SJames C. McPherson 			/* Need to translate vhci to phci */
729*a0261a43SJames C. McPherson 			char *realpath;
730*a0261a43SJames C. McPherson 
731*a0261a43SJames C. McPherson 			if ((realpath = calloc(1, MAXPATHLEN + 1)) == NULL) {
732*a0261a43SJames C. McPherson 				logmsg(MSG_ERROR,
733*a0261a43SJames C. McPherson 				    gettext("Unable to allocate "
734*a0261a43SJames C. McPherson 				    "memory for a path element\n"));
735*a0261a43SJames C. McPherson 				free(stripdev);
736*a0261a43SJames C. McPherson 				free(prefixt);
737*a0261a43SJames C. McPherson 				return;
738*a0261a43SJames C. McPherson 			}
739*a0261a43SJames C. McPherson 			vhci_to_phci(stripdev, realpath);
740*a0261a43SJames C. McPherson 			(void) printf("%s%s\n", realpath,
741*a0261a43SJames C. McPherson 			    ((slicelen > 0) && slice != NULL) ? slice : "");
742*a0261a43SJames C. McPherson 			free(realpath);
743*a0261a43SJames C. McPherson 		} else {
744*a0261a43SJames C. McPherson 			(void) printf("%s%s\n", mpxpath,
745*a0261a43SJames C. McPherson 			    ((slicelen > 0) && slice != NULL) ? slice : "");
746*a0261a43SJames C. McPherson 		}
747*a0261a43SJames C. McPherson 	} else {
748*a0261a43SJames C. McPherson 		(void) nvlist_lookup_string(thisdev,
749*a0261a43SJames C. McPherson 		    ((readonlyroot) ? NVL_PHYSPATH :
750*a0261a43SJames C. McPherson 		    ((mpxenp == B_TRUE) ? NVL_MPXPATH : NVL_PATH)),
751*a0261a43SJames C. McPherson 		    &mpxpath);
752*a0261a43SJames C. McPherson 		logmsg(MSG_INFO, "mpxpath = %s\n",
753*a0261a43SJames C. McPherson 		    (mpxpath == NULL) ? "null" : mpxpath);
754*a0261a43SJames C. McPherson 		if (readonlyroot ||
755*a0261a43SJames C. McPherson 		    (strstr(mpxpath, "/scsi_vhci") != NULL) ||
756*a0261a43SJames C. McPherson 		    (strstr(mpxpath, "/pci") != NULL) ||
757*a0261a43SJames C. McPherson 		    (strstr(mpxpath, "/sbus") != NULL)) {
758*a0261a43SJames C. McPherson 			/*
759*a0261a43SJames C. McPherson 			 * If we see a physical path here it means that
760*a0261a43SJames C. McPherson 			 * devlinks aren't fully initialised yet, so we
761*a0261a43SJames C. McPherson 			 * are still in maintenance/single-user mode.
762*a0261a43SJames C. McPherson 			 */
763*a0261a43SJames C. McPherson 			(void) printf("/devices%s:%c\n", mpxpath,
764*a0261a43SJames C. McPherson 			    slice[1] + '1');
765*a0261a43SJames C. McPherson 		} else {
766*a0261a43SJames C. McPherson 			(void) printf("%s%s%s\n",
767*a0261a43SJames C. McPherson 			    (prefixt[0] == '/') ? prefixt : "",
768*a0261a43SJames C. McPherson 			    mpxpath,
769*a0261a43SJames C. McPherson 			    ((slicelen > 0) && slice != NULL) ? slice : "");
770*a0261a43SJames C. McPherson 		}
771*a0261a43SJames C. McPherson 	}
772*a0261a43SJames C. McPherson 	free(prefixt);
773*a0261a43SJames C. McPherson 	free(stripdev);
774*a0261a43SJames C. McPherson }
775*a0261a43SJames C. McPherson 
776*a0261a43SJames C. McPherson /*
777*a0261a43SJames C. McPherson  * Validate the in-kernel and on-disk forms of our devid cache,
778*a0261a43SJames C. McPherson  * returns  -1 for unfixable error and 0 for success.
7797c478bd9Sstevel@tonic-gate  */
7807c478bd9Sstevel@tonic-gate static int
781*a0261a43SJames C. McPherson validate_devnvl()
782*a0261a43SJames C. McPherson {
783*a0261a43SJames C. McPherson 	di_node_t	curnode;
784*a0261a43SJames C. McPherson 	int		rv1 = -1;
785*a0261a43SJames C. McPherson 	int		rv2 = -1;
786*a0261a43SJames C. McPherson 
787*a0261a43SJames C. McPherson 	/*
788*a0261a43SJames C. McPherson 	 * Method: we walk through the kernel's concept of the device tree
789*a0261a43SJames C. McPherson 	 * looking for "ssd" then "sd" nodes.
790*a0261a43SJames C. McPherson 	 * We check to see whether the device's devid is already in our nvlist
791*a0261a43SJames C. McPherson 	 * (on disk) nvlist cache file. If it is, we check that it's components
792*a0261a43SJames C. McPherson 	 * match what we've got already and fill any missing fields.
793*a0261a43SJames C. McPherson 	 * If the devid isn't in our on-disk nvlist already then we add it
794*a0261a43SJames C. McPherson 	 * and populate the property nvpairs.
795*a0261a43SJames C. McPherson 	 *
796*a0261a43SJames C. McPherson 	 * At the end of this function we should have this program's concept
797*a0261a43SJames C. McPherson 	 * of the devid-keyed nvlist matching what is in the ondisk form which
798*a0261a43SJames C. McPherson 	 * is ready to be written out.
799*a0261a43SJames C. McPherson 	 * If we can't do this, then we return -1.
800*a0261a43SJames C. McPherson 	 */
801*a0261a43SJames C. McPherson 	curnode = di_drv_first_node("ssd", devinfo_root);
802*a0261a43SJames C. McPherson 	if (curnode != DI_NODE_NIL)
803*a0261a43SJames C. McPherson 		rv1 = mpxio_nvl_boilerplate(curnode);
804*a0261a43SJames C. McPherson 
805*a0261a43SJames C. McPherson 	curnode = di_drv_first_node("sd", devinfo_root);
806*a0261a43SJames C. McPherson 	if (curnode != DI_NODE_NIL)
807*a0261a43SJames C. McPherson 		rv2 = mpxio_nvl_boilerplate(curnode);
808*a0261a43SJames C. McPherson 
809*a0261a43SJames C. McPherson 	if (rv1 + rv2 == -2)
810*a0261a43SJames C. McPherson 		return (-1);
811*a0261a43SJames C. McPherson 
812*a0261a43SJames C. McPherson 	return (0);
813*a0261a43SJames C. McPherson }
814*a0261a43SJames C. McPherson 
815*a0261a43SJames C. McPherson static int
816*a0261a43SJames C. McPherson mpxio_nvl_boilerplate(di_node_t curnode)
817*a0261a43SJames C. McPherson {
818*a0261a43SJames C. McPherson 	int		rv;
819*a0261a43SJames C. McPherson 	char		*strdevid;
820*a0261a43SJames C. McPherson 	ddi_devid_t	curdevid;
821*a0261a43SJames C. McPherson 	nvlist_t	*newnvl;
822*a0261a43SJames C. McPherson 
823*a0261a43SJames C. McPherson 	for (; curnode != DI_NODE_NIL; curnode = di_drv_next_node(curnode)) {
824*a0261a43SJames C. McPherson 		errno = 0;
825*a0261a43SJames C. McPherson 
826*a0261a43SJames C. McPherson 		curdevid = NULL;
827*a0261a43SJames C. McPherson 		get_devid(curnode, &curdevid);
828*a0261a43SJames C. McPherson 		if (curdevid == NULL)
829*a0261a43SJames C. McPherson 			/*
830*a0261a43SJames C. McPherson 			 * There's no devid registered for this device
831*a0261a43SJames C. McPherson 			 * so it's not cool enough to play with us
832*a0261a43SJames C. McPherson 			 */
833*a0261a43SJames C. McPherson 			continue;
834*a0261a43SJames C. McPherson 
835*a0261a43SJames C. McPherson 		strdevid = devid_str_encode(curdevid, NULL);
836*a0261a43SJames C. McPherson 		/* does this exist in the on-disk cache? */
837*a0261a43SJames C. McPherson 		rv = nvlist_lookup_nvlist(mapnvl, strdevid, &newnvl);
838*a0261a43SJames C. McPherson 		if (rv == ENOENT) {
839*a0261a43SJames C. McPherson 			logmsg(MSG_INFO, "nvlist for %s not found\n", strdevid);
840*a0261a43SJames C. McPherson 			/* no, so alloc a new nvl to store it */
841*a0261a43SJames C. McPherson 			if (nvlist_alloc(&newnvl, NV_UNIQUE_NAME, 0) != 0) {
842*a0261a43SJames C. McPherson 				logmsg(MSG_ERROR,
843*a0261a43SJames C. McPherson 				    gettext("Unable to allocate space for "
844*a0261a43SJames C. McPherson 				    "a devid property list: %s\n"),
845*a0261a43SJames C. McPherson 				    strerror(errno));
846*a0261a43SJames C. McPherson 				return (-1);
847*a0261a43SJames C. McPherson 			}
848*a0261a43SJames C. McPherson 		} else {
849*a0261a43SJames C. McPherson 			if ((rv != ENOTSUP) && (rv != EINVAL))
850*a0261a43SJames C. McPherson 				logmsg(MSG_INFO,
851*a0261a43SJames C. McPherson 				    "%s exists in ondisknvl, verifying\n",
852*a0261a43SJames C. McPherson 				    strdevid);
853*a0261a43SJames C. McPherson 		}
854*a0261a43SJames C. McPherson 
855*a0261a43SJames C. McPherson 		if (popcheck_devnvl(curnode, newnvl, strdevid) != 0) {
856*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR,
857*a0261a43SJames C. McPherson 			    gettext("Unable to populate devid nvpair "
858*a0261a43SJames C. McPherson 			    "for device with devid %s\n"),
859*a0261a43SJames C. McPherson 			    strdevid);
860*a0261a43SJames C. McPherson 			devid_str_free(strdevid);
861*a0261a43SJames C. McPherson 			nvlist_free(newnvl);
862*a0261a43SJames C. McPherson 			return (-1);
863*a0261a43SJames C. McPherson 		}
864*a0261a43SJames C. McPherson 
865*a0261a43SJames C. McPherson 		/* Now add newnvl into our cache. */
866*a0261a43SJames C. McPherson 		errno = 0;
867*a0261a43SJames C. McPherson 		rv = nvlist_add_nvlist(mapnvl, strdevid, newnvl);
868*a0261a43SJames C. McPherson 		if (rv) {
869*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR,
870*a0261a43SJames C. McPherson 			    gettext("Unable to add device (devid %s) "
871*a0261a43SJames C. McPherson 			    "to in-kernel nvl: %s (%d)\n"),
872*a0261a43SJames C. McPherson 			    strdevid, strerror(rv), rv);
873*a0261a43SJames C. McPherson 			devid_str_free(strdevid);
874*a0261a43SJames C. McPherson 			nvlist_free(newnvl);
875*a0261a43SJames C. McPherson 			return (-1);
876*a0261a43SJames C. McPherson 		}
877*a0261a43SJames C. McPherson 		logmsg(MSG_INFO,
878*a0261a43SJames C. McPherson 		    gettext("added device (devid %s) to mapnvl\n\n"),
879*a0261a43SJames C. McPherson 		    strdevid);
880*a0261a43SJames C. McPherson 		devid_str_free(strdevid);
881*a0261a43SJames C. McPherson 	}
882*a0261a43SJames C. McPherson 	return (0);
883*a0261a43SJames C. McPherson }
884*a0261a43SJames C. McPherson 
885*a0261a43SJames C. McPherson /*
886*a0261a43SJames C. McPherson  * Operates on a single di_node_t, collecting all the device properties
887*a0261a43SJames C. McPherson  * that we need. devnvl is allocated by the caller, and we add our nvpairs
888*a0261a43SJames C. McPherson  * to it if they don't already exist.
889*a0261a43SJames C. McPherson  *
890*a0261a43SJames C. McPherson  * We are _only_ interested in devices which have a devid. We pull in
891*a0261a43SJames C. McPherson  * devices even when they're excluded via stmsboot -D (driver), because
892*a0261a43SJames C. McPherson  * we don't want to miss out on any devid data that might be handy later.
893*a0261a43SJames C. McPherson  */
894*a0261a43SJames C. McPherson static int
895*a0261a43SJames C. McPherson popcheck_devnvl(di_node_t thisnode, nvlist_t *devnvl, char *strdevid)
896*a0261a43SJames C. McPherson {
897*a0261a43SJames C. McPherson 	char *path = NULL;
898*a0261a43SJames C. McPherson 	char *curpath = NULL;
899*a0261a43SJames C. McPherson 	char *devfspath = NULL;
900*a0261a43SJames C. McPherson 	int scsivhciparent = 0;
901*a0261a43SJames C. McPherson 	int rv = 0;
902*a0261a43SJames C. McPherson 	boolean_t mpxenp = B_FALSE;
903*a0261a43SJames C. McPherson 
904*a0261a43SJames C. McPherson 	errno = 0;
905*a0261a43SJames C. McPherson 	devfspath = di_devfs_path(thisnode);
906*a0261a43SJames C. McPherson 	if (devfspath == NULL) {
907*a0261a43SJames C. McPherson 		logmsg(MSG_ERROR,
908*a0261a43SJames C. McPherson 		    gettext("Unable to determine devfs path for node: %s\n"),
909*a0261a43SJames C. McPherson 		    strerror(errno));
910*a0261a43SJames C. McPherson 		return (-1);
911*a0261a43SJames C. McPherson 	}
912*a0261a43SJames C. McPherson 
913*a0261a43SJames C. McPherson 	/* Add a convenient devfspath to devid inverse map */
914*a0261a43SJames C. McPherson 	if (nvlist_add_string(mapnvl, devfspath, strdevid) != 0) {
915*a0261a43SJames C. McPherson 		logmsg(MSG_ERROR,
916*a0261a43SJames C. McPherson 		    gettext("Unable to add device path %s with devid "
917*a0261a43SJames C. McPherson 		    "%s to mapnvl\n"), devfspath, strdevid);
918*a0261a43SJames C. McPherson 		return (-1);
919*a0261a43SJames C. McPherson 	}
920*a0261a43SJames C. McPherson 	if (strncmp(di_driver_name(di_parent_node(thisnode)),
921*a0261a43SJames C. McPherson 	    "scsi_vhci", 9) == 0) {
922*a0261a43SJames C. McPherson 		scsivhciparent = 1;
923*a0261a43SJames C. McPherson 		if (!mpxenabled)
924*a0261a43SJames C. McPherson 			mpxenabled++;
925*a0261a43SJames C. McPherson 
926*a0261a43SJames C. McPherson 		rv = nvlist_lookup_boolean_value(devnvl, NVL_MPXEN, &mpxenp);
927*a0261a43SJames C. McPherson 		if (rv || (mpxenp == B_FALSE)) {
928*a0261a43SJames C. McPherson 			rv = nvlist_add_boolean_value(devnvl,
929*a0261a43SJames C. McPherson 			    NVL_MPXEN, B_TRUE);
930*a0261a43SJames C. McPherson 			if (rv) {
931*a0261a43SJames C. McPherson 				logmsg(MSG_ERROR,
932*a0261a43SJames C. McPherson 				    gettext("Unable to add property %s "
933*a0261a43SJames C. McPherson 				    "(set to B_TRUE) for device %s: "
934*a0261a43SJames C. McPherson 				    "%s (%d)\n"),
935*a0261a43SJames C. McPherson 				    NVL_MPXEN, devfspath,
936*a0261a43SJames C. McPherson 				    strerror(rv), rv);
937*a0261a43SJames C. McPherson 				return (-1);
938*a0261a43SJames C. McPherson 			}
939*a0261a43SJames C. McPherson 			logmsg(MSG_INFO, "NVL_MPXEN :: (B_FALSE->B_TRUE)\n");
940*a0261a43SJames C. McPherson 		}
941*a0261a43SJames C. McPherson 	} else {
942*a0261a43SJames C. McPherson 		/* turn _off_ the flag if it was enabled */
943*a0261a43SJames C. McPherson 		rv = nvlist_add_boolean_value(devnvl, NVL_MPXEN, B_FALSE);
944*a0261a43SJames C. McPherson 		if (rv) {
945*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR,
946*a0261a43SJames C. McPherson 			    gettext("Unable to add property %s "
947*a0261a43SJames C. McPherson 			    "(set to B_FALSE) for device %s: %s (%d)\n"),
948*a0261a43SJames C. McPherson 			    NVL_MPXEN, devfspath,
949*a0261a43SJames C. McPherson 			    strerror(rv), rv);
950*a0261a43SJames C. McPherson 			return (-1);
951*a0261a43SJames C. McPherson 		}
952*a0261a43SJames C. McPherson 		logmsg(MSG_INFO, "NVL_MPXEN :: (B_TRUE-> B_FALSE)\n");
953*a0261a43SJames C. McPherson 	}
954*a0261a43SJames C. McPherson 
955*a0261a43SJames C. McPherson 	rv = nvlist_add_string(devnvl, NVL_PHYSPATH, devfspath);
956*a0261a43SJames C. McPherson 	if (rv) {
957*a0261a43SJames C. McPherson 		logmsg(MSG_ERROR,
958*a0261a43SJames C. McPherson 		    gettext("Unable to add physical device path (%s) "
959*a0261a43SJames C. McPherson 		    "property to nvl\n"));
960*a0261a43SJames C. McPherson 		return (-1);
961*a0261a43SJames C. McPherson 	}
962*a0261a43SJames C. McPherson 
963*a0261a43SJames C. McPherson 	if ((curpath = calloc(1, MAXPATHLEN)) == NULL) {
964*a0261a43SJames C. McPherson 		logmsg(MSG_ERROR,
965*a0261a43SJames C. McPherson 		    gettext("Unable to allocate space for current path\n"));
966*a0261a43SJames C. McPherson 		return (-1);
967*a0261a43SJames C. McPherson 	}
968*a0261a43SJames C. McPherson 	curpath = find_link(thisnode);
969*a0261a43SJames C. McPherson 	if (curpath == NULL) {
970*a0261a43SJames C. McPherson 		if (readonlyroot) {
971*a0261a43SJames C. McPherson 			return (0);
972*a0261a43SJames C. McPherson 		}
973*a0261a43SJames C. McPherson 		logmsg(MSG_ERROR,
974*a0261a43SJames C. McPherson 		    gettext("Unable to determine device path for node %s\n"),
975*a0261a43SJames C. McPherson 		    devfspath);
976*a0261a43SJames C. McPherson 		return (-1);
977*a0261a43SJames C. McPherson 	}
978*a0261a43SJames C. McPherson 
979*a0261a43SJames C. McPherson 	rv = nvlist_lookup_string(devnvl, NVL_MPXPATH, &path);
980*a0261a43SJames C. McPherson 
981*a0261a43SJames C. McPherson 	if (path == NULL && scsivhciparent)
982*a0261a43SJames C. McPherson 		(void) nvlist_add_string(devnvl, NVL_MPXPATH, curpath);
983*a0261a43SJames C. McPherson 
984*a0261a43SJames C. McPherson 	if (!scsivhciparent) {
985*a0261a43SJames C. McPherson 		(void) nvlist_add_string(devnvl, NVL_PATH, curpath);
986*a0261a43SJames C. McPherson 		path = curpath;
987*a0261a43SJames C. McPherson 	}
988*a0261a43SJames C. McPherson 
989*a0261a43SJames C. McPherson 	/*
990*a0261a43SJames C. McPherson 	 * This next block provides the path to devid inverse mapping
991*a0261a43SJames C. McPherson 	 * that other functions require
992*a0261a43SJames C. McPherson 	 */
993*a0261a43SJames C. McPherson 	if (path != NULL) {
994*a0261a43SJames C. McPherson 		if (nvlist_add_string(mapnvl, path, strdevid) != 0) {
995*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR,
996*a0261a43SJames C. McPherson 			    gettext("Unable to add device %s with devid "
997*a0261a43SJames C. McPherson 			    "%s to mapnvl\n"), path, strdevid);
998*a0261a43SJames C. McPherson 			return (-1);
999*a0261a43SJames C. McPherson 		}
1000*a0261a43SJames C. McPherson 		logmsg(MSG_INFO, "popcheck_devnvl: added path %s :: %s\n",
1001*a0261a43SJames C. McPherson 		    path, strdevid);
1002*a0261a43SJames C. McPherson 		if (nvlist_add_string(mapnvl, curpath, strdevid) != 0) {
1003*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR,
1004*a0261a43SJames C. McPherson 			    gettext("Unable to add device %s with devid "
1005*a0261a43SJames C. McPherson 			    "%s to mapnvl: %s\n"),
1006*a0261a43SJames C. McPherson 			    curpath, strdevid, strerror(errno));
1007*a0261a43SJames C. McPherson 			return (-1);
1008*a0261a43SJames C. McPherson 		}
1009*a0261a43SJames C. McPherson 		logmsg(MSG_INFO, "popcheck_devnvl: added curpath %s :: %s\n",
1010*a0261a43SJames C. McPherson 		    curpath, strdevid);
1011*a0261a43SJames C. McPherson 	}
1012*a0261a43SJames C. McPherson 	if (scsivhciparent) {
1013*a0261a43SJames C. McPherson 		if (nvlist_add_string(devnvl, NVL_MPXPATH, curpath) != 0) {
1014*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR,
1015*a0261a43SJames C. McPherson 			    gettext("Unable to add property %s for device "
1016*a0261a43SJames C. McPherson 			    "%s: %s\n"),
1017*a0261a43SJames C. McPherson 			    NVL_MPXPATH, devfspath, strerror(errno));
1018*a0261a43SJames C. McPherson 			return (-1);
1019*a0261a43SJames C. McPherson 		} else {
1020*a0261a43SJames C. McPherson 			logmsg(MSG_INFO, "added curpath (%s) as NVL_MPXPATH "
1021*a0261a43SJames C. McPherson 			    "to devnvl for devid %s\n", curpath, strdevid);
1022*a0261a43SJames C. McPherson 		}
1023*a0261a43SJames C. McPherson 	}
1024*a0261a43SJames C. McPherson 	return (0);
1025*a0261a43SJames C. McPherson }
1026*a0261a43SJames C. McPherson 
1027*a0261a43SJames C. McPherson static void
1028*a0261a43SJames C. McPherson print_mpx_capable(di_node_t curnode)
1029*a0261a43SJames C. McPherson {
1030*a0261a43SJames C. McPherson 	char *prop;
1031*a0261a43SJames C. McPherson 	char *path;
1032*a0261a43SJames C. McPherson 	char *aliases = NULL;
1033*a0261a43SJames C. McPherson 
1034*a0261a43SJames C. McPherson 	if (cap_N_option) {
1035*a0261a43SJames C. McPherson 		aliases = calloc(1, MAXPATHLEN + 1);
1036*a0261a43SJames C. McPherson 		if (aliases == NULL) {
1037*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR,
1038*a0261a43SJames C. McPherson 			    gettext("Unable to allocate memory for a device "
1039*a0261a43SJames C. McPherson 			    "alias list\n"));
1040*a0261a43SJames C. McPherson 			return;
1041*a0261a43SJames C. McPherson 		}
1042*a0261a43SJames C. McPherson 	}
1043*a0261a43SJames C. McPherson 
1044*a0261a43SJames C. McPherson 	for (; curnode != DI_NODE_NIL; curnode = di_drv_next_node(curnode)) {
1045*a0261a43SJames C. McPherson 		if (di_prop_lookup_strings(DDI_DEV_T_ANY, curnode,
1046*a0261a43SJames C. McPherson 		    "initiator-port", &prop) >= 0) {
1047*a0261a43SJames C. McPherson 			if ((path = di_devfs_path(curnode)) == NULL) {
1048*a0261a43SJames C. McPherson 				logmsg(MSG_INFO,
1049*a0261a43SJames C. McPherson 				    "Unable to find devfs path for device "
1050*a0261a43SJames C. McPherson 				    "%s: %s\n", &curnode, strerror(errno));
1051*a0261a43SJames C. McPherson 				continue;
1052*a0261a43SJames C. McPherson 			}
1053*a0261a43SJames C. McPherson 			if (cap_N_option) {
1054*a0261a43SJames C. McPherson 				char *nodename = di_node_name(curnode);
1055*a0261a43SJames C. McPherson 				/* nodename is never going to be null */
1056*a0261a43SJames C. McPherson 				if (strstr(aliases, nodename) == NULL)
1057*a0261a43SJames C. McPherson 					/* haven't seen this nodename before */
1058*a0261a43SJames C. McPherson 					(void) snprintf(aliases,
1059*a0261a43SJames C. McPherson 					    MAXPATHLEN + 1, "%s|%s",
1060*a0261a43SJames C. McPherson 					    ((aliases != NULL) ? aliases : ""),
1061*a0261a43SJames C. McPherson 					    nodename);
1062*a0261a43SJames C. McPherson 			} else
1063*a0261a43SJames C. McPherson 				(void) printf("%s\n", path);
1064*a0261a43SJames C. McPherson 		}
1065*a0261a43SJames C. McPherson 	}
1066*a0261a43SJames C. McPherson 	if (cap_N_option)
1067*a0261a43SJames C. McPherson 		(void) printf("%s\n", aliases);
1068*a0261a43SJames C. McPherson }
1069*a0261a43SJames C. McPherson 
1070*a0261a43SJames C. McPherson static int
1071*a0261a43SJames C. McPherson link_cb(di_devlink_t devlink, void *arg)
1072*a0261a43SJames C. McPherson {
1073*a0261a43SJames C. McPherson 	const char *result;
1074*a0261a43SJames C. McPherson 
1075*a0261a43SJames C. McPherson 	result = di_devlink_path(devlink);
1076*a0261a43SJames C. McPherson 	if (result == NULL) {
1077*a0261a43SJames C. McPherson 		arg = (void *)"(null)";
1078*a0261a43SJames C. McPherson 	} else {
1079*a0261a43SJames C. McPherson 		(void) strlcpy(arg, result, strlen(result));
1080*a0261a43SJames C. McPherson 	}
1081*a0261a43SJames C. McPherson 	logmsg(MSG_INFO, "\nlink_cb::linkdata->resultstr = %s\n",
1082*a0261a43SJames C. McPherson 	    ((result != NULL) ? result : "(null)"));
1083*a0261a43SJames C. McPherson 	return (DI_WALK_CONTINUE);
1084*a0261a43SJames C. McPherson }
1085*a0261a43SJames C. McPherson 
1086*a0261a43SJames C. McPherson static char *
1087*a0261a43SJames C. McPherson find_link(di_node_t cnode)
1088*a0261a43SJames C. McPherson {
1089*a0261a43SJames C. McPherson 	di_minor_t devminor = DI_MINOR_NIL;
1090*a0261a43SJames C. McPherson 	di_devlink_handle_t	hdl;
1091*a0261a43SJames C. McPherson 	char *devfspath = NULL;
1092*a0261a43SJames C. McPherson 	char *minorpath = NULL;
1093*a0261a43SJames C. McPherson 	char *linkname = NULL;
1094*a0261a43SJames C. McPherson 	char *cbresult = NULL;
1095*a0261a43SJames C. McPherson 
1096*a0261a43SJames C. McPherson 	devfspath = di_devfs_path(cnode);
1097*a0261a43SJames C. McPherson 	if (cnode == DI_NODE_NIL) {
1098*a0261a43SJames C. McPherson 		logmsg(MSG_ERROR,
1099*a0261a43SJames C. McPherson 		    gettext("find_ctrl must be called with non-null "
1100*a0261a43SJames C. McPherson 		    "di_node_t\n"));
1101*a0261a43SJames C. McPherson 		return (NULL);
1102*a0261a43SJames C. McPherson 	}
1103*a0261a43SJames C. McPherson 	logmsg(MSG_INFO, "find_link: devfspath %s\n", devfspath);
1104*a0261a43SJames C. McPherson 
1105*a0261a43SJames C. McPherson 	if (((cbresult = calloc(1, MAXPATHLEN)) == NULL) ||
1106*a0261a43SJames C. McPherson 	    ((minorpath = calloc(1, MAXPATHLEN)) == NULL) ||
1107*a0261a43SJames C. McPherson 	    ((linkname = calloc(1, MAXPATHLEN)) == NULL)) {
1108*a0261a43SJames C. McPherson 		logmsg(MSG_ERROR, "unable to allocate space for dev link\n");
1109*a0261a43SJames C. McPherson 		return (NULL);
1110*a0261a43SJames C. McPherson 	}
1111*a0261a43SJames C. McPherson 
1112*a0261a43SJames C. McPherson 	devminor = di_minor_next(cnode, devminor);
1113*a0261a43SJames C. McPherson 	hdl = di_devlink_init(di_devfs_minor_path(devminor), DI_MAKE_LINK);
1114*a0261a43SJames C. McPherson 	if (hdl == NULL) {
1115*a0261a43SJames C. McPherson 		logmsg((readonlyroot ? MSG_INFO : MSG_ERROR),
1116*a0261a43SJames C. McPherson 		    gettext("unable to take devlink snapshot: %s\n"),
1117*a0261a43SJames C. McPherson 		    strerror(errno));
1118*a0261a43SJames C. McPherson 		return (NULL);
1119*a0261a43SJames C. McPherson 	}
1120*a0261a43SJames C. McPherson 
1121*a0261a43SJames C. McPherson 	linkname = "^dsk/";
1122*a0261a43SJames C. McPherson 	(void) snprintf(minorpath, MAXPATHLEN, "%s:c", devfspath);
1123*a0261a43SJames C. McPherson 
1124*a0261a43SJames C. McPherson 	errno = 0;
1125*a0261a43SJames C. McPherson 	if (di_devlink_walk(hdl, linkname, minorpath, DI_PRIMARY_LINK,
1126*a0261a43SJames C. McPherson 	    (void *)cbresult, link_cb) < 0) {
1127*a0261a43SJames C. McPherson 		logmsg(MSG_ERROR,
1128*a0261a43SJames C. McPherson 		    gettext("Unable to walk devlink snapshot for %s: %s\n"),
1129*a0261a43SJames C. McPherson 		    minorpath, strerror(errno));
1130*a0261a43SJames C. McPherson 		return (NULL);
1131*a0261a43SJames C. McPherson 	}
1132*a0261a43SJames C. McPherson 
1133*a0261a43SJames C. McPherson 	if (di_devlink_fini(&hdl) < 0) {
1134*a0261a43SJames C. McPherson 		logmsg(MSG_ERROR,
1135*a0261a43SJames C. McPherson 		    gettext("Unable to close devlink snapshot: %s\n"),
1136*a0261a43SJames C. McPherson 		    strerror(errno));
1137*a0261a43SJames C. McPherson 	}
1138*a0261a43SJames C. McPherson 	if (strstr(cbresult, "dsk/") == NULL)
1139*a0261a43SJames C. McPherson 		return (devfspath);
1140*a0261a43SJames C. McPherson 
1141*a0261a43SJames C. McPherson 	bzero(minorpath, MAXPATHLEN);
1142*a0261a43SJames C. McPherson 	/* strip off the trailing "s2" */
1143*a0261a43SJames C. McPherson 	bcopy(cbresult, minorpath, strlen(cbresult) - 1);
1144*a0261a43SJames C. McPherson 	/* Now strip off the /dev/dsk/ prefix for output flexibility */
1145*a0261a43SJames C. McPherson 	linkname = strrchr(minorpath, '/');
1146*a0261a43SJames C. McPherson 	return (++linkname);
1147*a0261a43SJames C. McPherson }
1148*a0261a43SJames C. McPherson 
1149*a0261a43SJames C. McPherson /*
1150*a0261a43SJames C. McPherson  * handle case where device has been probed but its target driver is not
1151*a0261a43SJames C. McPherson  * attached so enumeration has not quite finished. Opening the /devices
1152*a0261a43SJames C. McPherson  * pathname will force the kernel to finish the enumeration process and
1153*a0261a43SJames C. McPherson  * let us get the data we need.
1154*a0261a43SJames C. McPherson  */
1155*a0261a43SJames C. McPherson static void
1156*a0261a43SJames C. McPherson get_devid(di_node_t node, ddi_devid_t *thisdevid)
11577c478bd9Sstevel@tonic-gate {
11587c478bd9Sstevel@tonic-gate 	int fd;
1159*a0261a43SJames C. McPherson 	char realpath[MAXPATHLEN];
1160*a0261a43SJames C. McPherson 	char *openpath = di_devfs_path(node);
11617c478bd9Sstevel@tonic-gate 
1162*a0261a43SJames C. McPherson 	errno = 0;
1163*a0261a43SJames C. McPherson 	bzero(realpath, MAXPATHLEN);
1164*a0261a43SJames C. McPherson 	if (strstr(openpath, "/devices") == NULL) {
1165*a0261a43SJames C. McPherson 		(void) snprintf(realpath, MAXPATHLEN,
1166*a0261a43SJames C. McPherson 		    "/devices%s:c,raw", openpath);
1167*a0261a43SJames C. McPherson 		fd = open(realpath, O_RDONLY|O_NDELAY);
116860fffc19Sjw149990 	} else {
1169*a0261a43SJames C. McPherson 		fd = open(openpath, O_RDONLY|O_NDELAY);
117060fffc19Sjw149990 	}
117160fffc19Sjw149990 
1172*a0261a43SJames C. McPherson 	if (fd < 0) {
1173*a0261a43SJames C. McPherson 		logmsg(MSG_INFO, "Unable to open path %s: %s\n",
1174*a0261a43SJames C. McPherson 		    openpath, strerror(errno));
1175*a0261a43SJames C. McPherson 		return;
11767c478bd9Sstevel@tonic-gate 	}
11777c478bd9Sstevel@tonic-gate 
1178*a0261a43SJames C. McPherson 	if (devid_get(fd, thisdevid) != 0) {
1179*a0261a43SJames C. McPherson 		logmsg(MSG_INFO,
1180*a0261a43SJames C. McPherson 		    "'%s' node (%s) without a devid registered\n",
1181*a0261a43SJames C. McPherson 		    di_driver_name(node), di_devfs_path(node));
118260fffc19Sjw149990 	}
11837c478bd9Sstevel@tonic-gate 	(void) close(fd);
11847c478bd9Sstevel@tonic-gate }
11857c478bd9Sstevel@tonic-gate 
11868cecff49Sgp87344 static int
1187*a0261a43SJames C. McPherson print_bootpath()
11888cecff49Sgp87344 {
1189*a0261a43SJames C. McPherson 	char *bootprop = NULL;
11908cecff49Sgp87344 
1191*a0261a43SJames C. McPherson 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, devinfo_root,
1192*a0261a43SJames C. McPherson 	    "bootpath", &bootprop) >= 0) {
1193*a0261a43SJames C. McPherson 		(void) printf("%s\n", bootprop);
11948cecff49Sgp87344 		return (0);
1195*a0261a43SJames C. McPherson 	} else if (di_prop_lookup_strings(DDI_DEV_T_ANY, devinfo_root,
1196*a0261a43SJames C. McPherson 	    "boot-path", &bootprop) >= 0) {
1197*a0261a43SJames C. McPherson 		(void) printf("%s\n", bootprop);
1198*a0261a43SJames C. McPherson 		return (0);
1199*a0261a43SJames C. McPherson 	} else {
1200*a0261a43SJames C. McPherson 		(void) printf("ERROR: no bootpath/boot-path property found\n");
1201*a0261a43SJames C. McPherson 		return (ENOENT);
1202*a0261a43SJames C. McPherson 	}
12038cecff49Sgp87344 }
12048cecff49Sgp87344 
12058cecff49Sgp87344 /*
1206*a0261a43SJames C. McPherson  * We only call this routine if we have a scsi_vhci node and must
1207*a0261a43SJames C. McPherson  * determine the actual physical path of its first online client
1208*a0261a43SJames C. McPherson  * path.
12097c478bd9Sstevel@tonic-gate  */
1210*a0261a43SJames C. McPherson static void
1211*a0261a43SJames C. McPherson vhci_to_phci(char *devpath, char *physpath)
12127c478bd9Sstevel@tonic-gate {
12137c478bd9Sstevel@tonic-gate 	sv_iocdata_t	ioc;
12145a4c37c9Sqh201292 	sv_path_info_t	*pi;
1215*a0261a43SJames C. McPherson 	int		vhci_fd;
1216*a0261a43SJames C. McPherson 	int		rv;
1217*a0261a43SJames C. McPherson 	uint_t		npaths = 0;
12185a4c37c9Sqh201292 
1219*a0261a43SJames C. McPherson 	vhci_fd = open(VHCI_CTL_NODE, O_RDWR);
1220*a0261a43SJames C. McPherson 	if (vhci_fd < 0)
1221*a0261a43SJames C. McPherson 		goto failure;
12225a4c37c9Sqh201292 
12235a4c37c9Sqh201292 	bzero(&ioc, sizeof (sv_iocdata_t));
1224*a0261a43SJames C. McPherson 	ioc.client = devpath;
12255a4c37c9Sqh201292 	ioc.ret_elem = &npaths;
1226*a0261a43SJames C. McPherson 	rv = ioctl(vhci_fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, &ioc);
1227*a0261a43SJames C. McPherson 	if (rv || npaths == 0) {
1228*a0261a43SJames C. McPherson 		logmsg(MSG_INFO,
1229*a0261a43SJames C. McPherson 		    "SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO ioctl() failed, "
1230*a0261a43SJames C. McPherson 		    "%s (%d)\n", strerror(rv), rv);
1231*a0261a43SJames C. McPherson 		goto failure;
12325a4c37c9Sqh201292 	}
12335a4c37c9Sqh201292 
12345a4c37c9Sqh201292 	bzero(&ioc, sizeof (sv_iocdata_t));
1235*a0261a43SJames C. McPherson 	ioc.client = devpath;
12365a4c37c9Sqh201292 	ioc.buf_elem = npaths;
12375a4c37c9Sqh201292 	ioc.ret_elem = &npaths;
1238*a0261a43SJames C. McPherson 	if ((ioc.ret_buf = calloc(npaths, sizeof (sv_path_info_t)))
1239*a0261a43SJames C. McPherson 	    == NULL)
1240*a0261a43SJames C. McPherson 		goto failure;
1241*a0261a43SJames C. McPherson 	rv = ioctl(vhci_fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, &ioc);
1242*a0261a43SJames C. McPherson 	if (rv || npaths == 0) {
1243*a0261a43SJames C. McPherson 		logmsg(MSG_INFO,
1244*a0261a43SJames C. McPherson 		    "SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO ioctl() (#2) "
1245*a0261a43SJames C. McPherson 		    "failed, %s (%d)\n", strerror(rv), rv);
1246*a0261a43SJames C. McPherson 		goto failure;
12475a4c37c9Sqh201292 	}
12485a4c37c9Sqh201292 
12495a4c37c9Sqh201292 	if (ioc.buf_elem < npaths)
12505a4c37c9Sqh201292 		npaths = ioc.buf_elem;
12515a4c37c9Sqh201292 
12525a4c37c9Sqh201292 	pi = (sv_path_info_t *)ioc.ret_buf;
12535a4c37c9Sqh201292 	while (npaths--) {
1254*a0261a43SJames C. McPherson 		if (pi->ret_state == MDI_PATHINFO_STATE_ONLINE) {
1255*a0261a43SJames C. McPherson 			char nodename[4];
1256*a0261a43SJames C. McPherson 
1257*a0261a43SJames C. McPherson 			bzero(nodename, 4);
1258*a0261a43SJames C. McPherson 			/* A hack, but nicer than a platform-specific ifdef */
1259*a0261a43SJames C. McPherson 			if (strstr(devpath, "ssd") != NULL) {
1260*a0261a43SJames C. McPherson 				(void) snprintf(nodename, 4, "ssd");
1261*a0261a43SJames C. McPherson 			} else {
1262*a0261a43SJames C. McPherson 				(void) snprintf(nodename, 4, "sd");
1263*a0261a43SJames C. McPherson 			}
1264*a0261a43SJames C. McPherson 			(void) snprintf(physpath, MAXPATHLEN, "%s/%s@%s",
1265*a0261a43SJames C. McPherson 			    pi->device.ret_phci, nodename, pi->ret_addr);
12665a4c37c9Sqh201292 			free(ioc.ret_buf);
1267*a0261a43SJames C. McPherson 			return;
12685a4c37c9Sqh201292 		}
12695a4c37c9Sqh201292 		pi++;
12705a4c37c9Sqh201292 	}
12715a4c37c9Sqh201292 
1272*a0261a43SJames C. McPherson failure:
1273*a0261a43SJames C. McPherson 	(void) snprintf(physpath, MAXPATHLEN, "NOT_MAPPED");
12745a4c37c9Sqh201292 }
12755a4c37c9Sqh201292 
12765a4c37c9Sqh201292 /*
1277*a0261a43SJames C. McPherson  * Write /etc/vfstab to /etc/vfstab.new, with any remapped device
1278*a0261a43SJames C. McPherson  * names substituted.
12797c478bd9Sstevel@tonic-gate  *
12807c478bd9Sstevel@tonic-gate  * Returns:
1281*a0261a43SJames C. McPherson  * 	0	successful operation
12827c478bd9Sstevel@tonic-gate  *	-1	failed
12837c478bd9Sstevel@tonic-gate  */
12847c478bd9Sstevel@tonic-gate static int
1285*a0261a43SJames C. McPherson update_vfstab()
12867c478bd9Sstevel@tonic-gate {
1287*a0261a43SJames C. McPherson 	FILE *fdin, *fdout;
12887c478bd9Sstevel@tonic-gate 	char *buf, *tmpbuf;
1289*a0261a43SJames C. McPherson 	char fname[MAXPATHLEN];
1290*a0261a43SJames C. McPherson 	int rv = -1, rval = -1;
12917c478bd9Sstevel@tonic-gate 	char cdev[MAXPATHLEN];
12927c478bd9Sstevel@tonic-gate 	char bdev[MAXPATHLEN];
12937c478bd9Sstevel@tonic-gate 	char mntpt[MAXPATHLEN];
12947c478bd9Sstevel@tonic-gate 	char fstype[512];
12957c478bd9Sstevel@tonic-gate 	char fsckpass[512];
12967c478bd9Sstevel@tonic-gate 	char mntboot[512];
1297*a0261a43SJames C. McPherson 	char mntopt[MAXPATHLEN];
12987c478bd9Sstevel@tonic-gate 	char fmt[80];
1299*a0261a43SJames C. McPherson 	char *prefixt = NULL;
1300*a0261a43SJames C. McPherson 	char *curdev = NULL;
1301*a0261a43SJames C. McPherson 	char *thisdevid = NULL;
1302*a0261a43SJames C. McPherson 	char *slice = NULL;
1303*a0261a43SJames C. McPherson 	nvlist_t *thisdev;
1304*a0261a43SJames C. McPherson 	boolean_t devmpx = B_FALSE;
13057c478bd9Sstevel@tonic-gate 
1306*a0261a43SJames C. McPherson 	buf = calloc(1, MAXPATHLEN);
1307*a0261a43SJames C. McPherson 	tmpbuf = calloc(1, MAXPATHLEN);
1308*a0261a43SJames C. McPherson 	if (buf == NULL || tmpbuf == NULL)
13097c478bd9Sstevel@tonic-gate 		return (-1);
13107c478bd9Sstevel@tonic-gate 
1311*a0261a43SJames C. McPherson 	(void) snprintf(fname, MAXPATHLEN, "/etc/mpxio/vfstab.new");
1312*a0261a43SJames C. McPherson 
1313*a0261a43SJames C. McPherson 	fdin = fopen("/etc/vfstab", "r");
1314*a0261a43SJames C. McPherson 	fdout = fopen(fname, "w+");
1315*a0261a43SJames C. McPherson 	if (fdin == NULL || fdout == NULL) {
1316*a0261a43SJames C. McPherson 		logmsg(MSG_INFO, "Unable to open vfstab or create a backup "
1317*a0261a43SJames C. McPherson 		    "vfstab %s\n");
1318*a0261a43SJames C. McPherson 		return (-1);
1319*a0261a43SJames C. McPherson 	}
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 	(void) snprintf(fmt, sizeof (fmt),
13227c478bd9Sstevel@tonic-gate 	    "%%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds", sizeof (bdev) - 1,
13237c478bd9Sstevel@tonic-gate 	    sizeof (cdev) - 1, sizeof (mntpt) - 1, sizeof (fstype) - 1,
13247c478bd9Sstevel@tonic-gate 	    sizeof (fsckpass) - 1, sizeof (mntboot) - 1, sizeof (mntopt) - 1);
13257c478bd9Sstevel@tonic-gate 
1326*a0261a43SJames C. McPherson 	while (fgets(buf, MAXPATHLEN, fdin) != NULL) {
1327*a0261a43SJames C. McPherson 		if (strlen(buf) == (MAXPATHLEN - 1) &&
1328*a0261a43SJames C. McPherson 		    buf[MAXPATHLEN-2] != '\n') {
1329*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR,
1330*a0261a43SJames C. McPherson 			    gettext("/etc/vfstab line length too long, "
13317c478bd9Sstevel@tonic-gate 			    "exceeded %2$d: \"%3$s\"\n"),
1332*a0261a43SJames C. McPherson 			    MAXPATHLEN - 2, buf);
13337c478bd9Sstevel@tonic-gate 			goto out;
13347c478bd9Sstevel@tonic-gate 		}
13357c478bd9Sstevel@tonic-gate 
1336*a0261a43SJames C. McPherson 		prefixt = NULL;
1337*a0261a43SJames C. McPherson 		curdev = NULL;
1338*a0261a43SJames C. McPherson 		slice = NULL;
1339*a0261a43SJames C. McPherson 		thisdevid = NULL;
1340*a0261a43SJames C. McPherson 		thisdev = NULL;
13417c478bd9Sstevel@tonic-gate 
1342*a0261a43SJames C. McPherson 		/* LINTED - variable format specifier */
1343*a0261a43SJames C. McPherson 		rv = sscanf(buf, fmt, bdev, cdev, mntpt, fstype, fsckpass,
1344*a0261a43SJames C. McPherson 		    mntboot, mntopt);
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate 		/*
1347*a0261a43SJames C. McPherson 		 * Walk through the lines in the input file (/etc/vfstab),
1348*a0261a43SJames C. McPherson 		 * skipping anything which is _not_ a COGD (common or garden
1349*a0261a43SJames C. McPherson 		 * disk), ie all the /devices, /system, /dev/md, /dev/vx and
1350*a0261a43SJames C. McPherson 		 * /dev/zvol and so forth.
13517c478bd9Sstevel@tonic-gate 		 */
1352*a0261a43SJames C. McPherson 		if ((rv == 7) && (bdev[0] == '/') &&
1353*a0261a43SJames C. McPherson 		    (strstr(bdev, "/dev/dsk"))) {
1354*a0261a43SJames C. McPherson 			slice = strrchr(bdev, 's');
1355*a0261a43SJames C. McPherson 			/* take a copy, strip off /dev/dsk/ */
1356*a0261a43SJames C. McPherson 			prefixt = strrchr(bdev, 'c');
1357*a0261a43SJames C. McPherson 			prefixt[strlen(bdev) - 9 - strlen(slice)] = '\0';
1358*a0261a43SJames C. McPherson 			slice++; /* advance past the s */
1359*a0261a43SJames C. McPherson 			rval = nvlist_lookup_string(mapnvl, prefixt,
1360*a0261a43SJames C. McPherson 			    &thisdevid);
1361*a0261a43SJames C. McPherson 			if (rval) {
1362*a0261a43SJames C. McPherson 				/* Whoa, where did this device go?! */
1363*a0261a43SJames C. McPherson 				logmsg(MSG_INFO,
1364*a0261a43SJames C. McPherson 				    "error looking up device %s\n", prefixt);
1365*a0261a43SJames C. McPherson 				/* Comment-out this line in the new version */
1366*a0261a43SJames C. McPherson 				(void) snprintf(tmpbuf, MAXPATHLEN,
1367*a0261a43SJames C. McPherson 				    "# DEVICE NOT FOUND %s", buf);
1368*a0261a43SJames C. McPherson 				(void) fprintf(fdout, "%s", tmpbuf);
1369*a0261a43SJames C. McPherson 				continue;
1370*a0261a43SJames C. McPherson 			} else {
1371*a0261a43SJames C. McPherson 				/* The device exists in our mapnvl */
1372*a0261a43SJames C. McPherson 				(void) nvlist_lookup_nvlist(mapnvl, thisdevid,
1373*a0261a43SJames C. McPherson 				    &thisdev);
1374*a0261a43SJames C. McPherson 				(void) nvlist_lookup_boolean_value(thisdev,
1375*a0261a43SJames C. McPherson 				    NVL_MPXEN, &devmpx);
1376*a0261a43SJames C. McPherson 				(void) nvlist_lookup_string(thisdev,
1377*a0261a43SJames C. McPherson 				    ((devmpx == B_TRUE)
1378*a0261a43SJames C. McPherson 				    ? NVL_MPXPATH : NVL_PATH),
1379*a0261a43SJames C. McPherson 				    &curdev);
1380*a0261a43SJames C. McPherson 			}
13817c478bd9Sstevel@tonic-gate 		}
13827c478bd9Sstevel@tonic-gate 
1383*a0261a43SJames C. McPherson 		if ((prefixt != NULL) && (curdev != NULL) &&
1384*a0261a43SJames C. McPherson 		    (rv = (strncmp(prefixt, curdev, strlen(prefixt)) != 0))) {
1385*a0261a43SJames C. McPherson 			/* Mapping change for this device */
1386*a0261a43SJames C. McPherson 			if (strcmp(fstype, "swap") == 0) {
1387*a0261a43SJames C. McPherson 				(void) snprintf(tmpbuf, MAXPATHLEN,
1388*a0261a43SJames C. McPherson 				    "/dev/dsk/%ss%s\t-\t-\tswap\t"
1389*a0261a43SJames C. McPherson 				    "%s\t%s\t%s\n",
1390*a0261a43SJames C. McPherson 				    curdev, slice, fsckpass, mntboot, mntopt);
1391*a0261a43SJames C. McPherson 			} else {
1392*a0261a43SJames C. McPherson 				(void) snprintf(tmpbuf, MAXPATHLEN,
1393*a0261a43SJames C. McPherson 				    "/dev/dsk/%ss%s\t/dev/rdsk/%ss%s\t"
1394*a0261a43SJames C. McPherson 				    "%s\t%s\t%s\t%s\t%s\n",
1395*a0261a43SJames C. McPherson 				    curdev, slice, curdev, slice,
1396*a0261a43SJames C. McPherson 				    mntpt, fstype, fsckpass, mntboot, mntopt);
1397*a0261a43SJames C. McPherson 			}
1398*a0261a43SJames C. McPherson 			errno = 0;
1399*a0261a43SJames C. McPherson 			(void) fprintf(fdout, "%s", tmpbuf);
1400*a0261a43SJames C. McPherson 		} else {
1401*a0261a43SJames C. McPherson 			(void) fprintf(fdout, "%s", buf);
1402*a0261a43SJames C. McPherson 		}
1403*a0261a43SJames C. McPherson 
1404*a0261a43SJames C. McPherson 		errno = 0;
1405*a0261a43SJames C. McPherson 		if (fflush(fdout) != 0) {
1406*a0261a43SJames C. McPherson 			logmsg(MSG_ERROR,
1407*a0261a43SJames C. McPherson 			    gettext("fprintf failed to write to %s: %s (%d)\n"),
1408*a0261a43SJames C. McPherson 			    fname, strerror(errno), errno);
14097c478bd9Sstevel@tonic-gate 			goto out;
14107c478bd9Sstevel@tonic-gate 		}
14117c478bd9Sstevel@tonic-gate 	}
14127c478bd9Sstevel@tonic-gate out:
1413*a0261a43SJames C. McPherson 	(void) fclose(fdin);
1414*a0261a43SJames C. McPherson 	(void) fclose(fdout);
14157c478bd9Sstevel@tonic-gate 	free(buf);
14167c478bd9Sstevel@tonic-gate 	free(tmpbuf);
1417*a0261a43SJames C. McPherson 	return (errno);
14188cecff49Sgp87344 }
1419