xref: /titanic_50/usr/src/lib/libdevinfo/devfsmap.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate #ifdef	lint
29*7c478bd9Sstevel@tonic-gate #define	_REENTRANT	/* for localtime_r */
30*7c478bd9Sstevel@tonic-gate #endif
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #include <stdio.h>
33*7c478bd9Sstevel@tonic-gate #include <ctype.h>
34*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
36*7c478bd9Sstevel@tonic-gate #include <strings.h>
37*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
39*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
40*7c478bd9Sstevel@tonic-gate #include <errno.h>
41*7c478bd9Sstevel@tonic-gate #include <unistd.h>
42*7c478bd9Sstevel@tonic-gate #include <stropts.h>
43*7c478bd9Sstevel@tonic-gate #include <time.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/vfstab.h>
46*7c478bd9Sstevel@tonic-gate #include <dirent.h>
47*7c478bd9Sstevel@tonic-gate #ifdef __sparc
48*7c478bd9Sstevel@tonic-gate #include <sys/scsi/adapters/scsi_vhci.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/sunmdi.h>
50*7c478bd9Sstevel@tonic-gate #endif /* __sparc */
51*7c478bd9Sstevel@tonic-gate #include "libdevinfo.h"
52*7c478bd9Sstevel@tonic-gate #include "device_info.h"
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate #define	isnewline(ch)	((ch) == '\n' || (ch) == '\r' || (ch) == '\f')
55*7c478bd9Sstevel@tonic-gate #define	isnamechar(ch)  (isalpha(ch) || isdigit(ch) || (ch) == '_' ||\
56*7c478bd9Sstevel@tonic-gate 	(ch) == '-')
57*7c478bd9Sstevel@tonic-gate #define	MAX_TOKEN_SIZE	1024
58*7c478bd9Sstevel@tonic-gate #define	BUFSIZE		1024
59*7c478bd9Sstevel@tonic-gate #define	STRVAL(s)	((s) ? (s) : "NULL")
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate #define	SCSI_VHCI_CONF		"/kernel/drv/scsi_vhci.conf"
62*7c478bd9Sstevel@tonic-gate #define	QLC_CONF		"/kernel/drv/qlc.conf"
63*7c478bd9Sstevel@tonic-gate #define	FP_CONF			"/kernel/drv/fp.conf"
64*7c478bd9Sstevel@tonic-gate #define	DRIVER_CLASSES		"/etc/driver_classes"
65*7c478bd9Sstevel@tonic-gate #define	FP_AT			"fp@"
66*7c478bd9Sstevel@tonic-gate #define	VHCI_CTL_NODE		"/devices/scsi_vhci:devctl"
67*7c478bd9Sstevel@tonic-gate #define	SLASH_DEVICES		"/devices"
68*7c478bd9Sstevel@tonic-gate #define	SLASH_DEVICES_SLASH	"/devices/"
69*7c478bd9Sstevel@tonic-gate #define	SLASH_FP_AT		"/fp@"
70*7c478bd9Sstevel@tonic-gate #define	SLASH_SCSI_VHCI		"/scsi_vhci"
71*7c478bd9Sstevel@tonic-gate #define	META_DEV		"/dev/md/dsk/"
72*7c478bd9Sstevel@tonic-gate #define	SLASH_DEV_SLASH		"/dev/"
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate /*
75*7c478bd9Sstevel@tonic-gate  * Macros to produce a quoted string containing the value of a
76*7c478bd9Sstevel@tonic-gate  * preprocessor macro. For example, if SIZE is defined to be 256,
77*7c478bd9Sstevel@tonic-gate  * VAL2STR(SIZE) is "256". This is used to construct format
78*7c478bd9Sstevel@tonic-gate  * strings for scanf-family functions below.
79*7c478bd9Sstevel@tonic-gate  */
80*7c478bd9Sstevel@tonic-gate #define	QUOTE(x)	#x
81*7c478bd9Sstevel@tonic-gate #define	VAL2STR(x)	QUOTE(x)
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate #ifdef __sparc
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate typedef enum {
86*7c478bd9Sstevel@tonic-gate 	CLIENT_TYPE_UNKNOWN,
87*7c478bd9Sstevel@tonic-gate 	CLIENT_TYPE_PHCI,
88*7c478bd9Sstevel@tonic-gate 	CLIENT_TYPE_VHCI
89*7c478bd9Sstevel@tonic-gate } client_type_t;
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate typedef enum {
92*7c478bd9Sstevel@tonic-gate 	T_EQUALS,
93*7c478bd9Sstevel@tonic-gate 	T_AMPERSAND,
94*7c478bd9Sstevel@tonic-gate 	T_BIT_OR,
95*7c478bd9Sstevel@tonic-gate 	T_STAR,
96*7c478bd9Sstevel@tonic-gate 	T_POUND,
97*7c478bd9Sstevel@tonic-gate 	T_COLON,
98*7c478bd9Sstevel@tonic-gate 	T_SEMICOLON,
99*7c478bd9Sstevel@tonic-gate 	T_COMMA,
100*7c478bd9Sstevel@tonic-gate 	T_SLASH,
101*7c478bd9Sstevel@tonic-gate 	T_WHITE_SPACE,
102*7c478bd9Sstevel@tonic-gate 	T_NEWLINE,
103*7c478bd9Sstevel@tonic-gate 	T_EOF,
104*7c478bd9Sstevel@tonic-gate 	T_STRING,
105*7c478bd9Sstevel@tonic-gate 	T_HEXVAL,
106*7c478bd9Sstevel@tonic-gate 	T_DECVAL,
107*7c478bd9Sstevel@tonic-gate 	T_NAME
108*7c478bd9Sstevel@tonic-gate } token_t;
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate typedef enum {
111*7c478bd9Sstevel@tonic-gate 	begin, parent, drvname, drvclass, prop,
112*7c478bd9Sstevel@tonic-gate 	parent_equals, name_equals, drvclass_equals,
113*7c478bd9Sstevel@tonic-gate 	parent_equals_string, name_equals_string,
114*7c478bd9Sstevel@tonic-gate 	drvclass_equals_string,
115*7c478bd9Sstevel@tonic-gate 	prop_equals, prop_equals_string, prop_equals_integer,
116*7c478bd9Sstevel@tonic-gate 	prop_equals_string_comma, prop_equals_integer_comma
117*7c478bd9Sstevel@tonic-gate } conf_state_t;
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate /* structure to hold entries with mpxio-disable property in driver.conf file */
120*7c478bd9Sstevel@tonic-gate struct conf_entry {
121*7c478bd9Sstevel@tonic-gate 	char *name;
122*7c478bd9Sstevel@tonic-gate 	char *parent;
123*7c478bd9Sstevel@tonic-gate 	char *class;
124*7c478bd9Sstevel@tonic-gate 	char *unit_address;
125*7c478bd9Sstevel@tonic-gate 	int port;
126*7c478bd9Sstevel@tonic-gate 	int mpxio_disable;
127*7c478bd9Sstevel@tonic-gate 	struct conf_entry *next;
128*7c478bd9Sstevel@tonic-gate };
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate struct conf_file {
131*7c478bd9Sstevel@tonic-gate 	char *filename;
132*7c478bd9Sstevel@tonic-gate 	FILE *fp;
133*7c478bd9Sstevel@tonic-gate 	int linenum;
134*7c478bd9Sstevel@tonic-gate };
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate static char *tok_err = "Unexpected token '%s'\n";
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate #endif /* __sparc */
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate /* #define	DEBUG */
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate int devfsmap_debug = 0;
145*7c478bd9Sstevel@tonic-gate /* /var/run is not mounted at install time. Therefore use /tmp */
146*7c478bd9Sstevel@tonic-gate char *devfsmap_logfile = "/tmp/devfsmap.log";
147*7c478bd9Sstevel@tonic-gate static FILE *logfp;
148*7c478bd9Sstevel@tonic-gate #define	logdmsg(args)	log_debug_msg args
149*7c478bd9Sstevel@tonic-gate static void vlog_debug_msg(char *, va_list);
150*7c478bd9Sstevel@tonic-gate static void log_debug_msg(char *, ...);
151*7c478bd9Sstevel@tonic-gate #ifdef __sparc
152*7c478bd9Sstevel@tonic-gate static void log_confent_list(char *, struct conf_entry *, int);
153*7c478bd9Sstevel@tonic-gate static void log_pathlist(char **);
154*7c478bd9Sstevel@tonic-gate #endif /* __sparc */
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate #else /* DEBUG */
157*7c478bd9Sstevel@tonic-gate #define	logdmsg(args)	/* nothing */
158*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate #ifdef __sparc
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate /*
163*7c478bd9Sstevel@tonic-gate  * Leave NEWLINE as the next character.
164*7c478bd9Sstevel@tonic-gate  */
165*7c478bd9Sstevel@tonic-gate static void
166*7c478bd9Sstevel@tonic-gate find_eol(FILE *fp)
167*7c478bd9Sstevel@tonic-gate {
168*7c478bd9Sstevel@tonic-gate 	int ch;
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	while ((ch = getc(fp)) != EOF) {
171*7c478bd9Sstevel@tonic-gate 		if (isnewline(ch)) {
172*7c478bd9Sstevel@tonic-gate 			(void) ungetc(ch, fp);
173*7c478bd9Sstevel@tonic-gate 			break;
174*7c478bd9Sstevel@tonic-gate 		}
175*7c478bd9Sstevel@tonic-gate 	}
176*7c478bd9Sstevel@tonic-gate }
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate /* ignore parsing errors */
179*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
180*7c478bd9Sstevel@tonic-gate static void
181*7c478bd9Sstevel@tonic-gate file_err(struct conf_file *filep, char *fmt, ...)
182*7c478bd9Sstevel@tonic-gate {
183*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
184*7c478bd9Sstevel@tonic-gate 	va_list ap;
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
187*7c478bd9Sstevel@tonic-gate 	log_debug_msg("WARNING: %s line # %d: ",
188*7c478bd9Sstevel@tonic-gate 	    filep->filename, filep->linenum);
189*7c478bd9Sstevel@tonic-gate 	vlog_debug_msg(fmt, ap);
190*7c478bd9Sstevel@tonic-gate 	va_end(ap);
191*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
192*7c478bd9Sstevel@tonic-gate }
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate /* return the next token from the given driver.conf file, or -1 on error */
195*7c478bd9Sstevel@tonic-gate static token_t
196*7c478bd9Sstevel@tonic-gate lex(struct conf_file *filep, char *val, size_t size)
197*7c478bd9Sstevel@tonic-gate {
198*7c478bd9Sstevel@tonic-gate 	char	*cp;
199*7c478bd9Sstevel@tonic-gate 	int	ch, oval, badquote;
200*7c478bd9Sstevel@tonic-gate 	size_t	remain;
201*7c478bd9Sstevel@tonic-gate 	token_t token;
202*7c478bd9Sstevel@tonic-gate 	FILE	*fp = filep->fp;
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	if (size < 2)
205*7c478bd9Sstevel@tonic-gate 		return (-1);
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 	cp = val;
208*7c478bd9Sstevel@tonic-gate 	while ((ch = getc(fp)) == ' ' || ch == '\t')
209*7c478bd9Sstevel@tonic-gate 		;
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 	remain = size - 1;
212*7c478bd9Sstevel@tonic-gate 	*cp++ = (char)ch;
213*7c478bd9Sstevel@tonic-gate 	switch (ch) {
214*7c478bd9Sstevel@tonic-gate 	case '=':
215*7c478bd9Sstevel@tonic-gate 		token = T_EQUALS;
216*7c478bd9Sstevel@tonic-gate 		break;
217*7c478bd9Sstevel@tonic-gate 	case '&':
218*7c478bd9Sstevel@tonic-gate 		token = T_AMPERSAND;
219*7c478bd9Sstevel@tonic-gate 		break;
220*7c478bd9Sstevel@tonic-gate 	case '|':
221*7c478bd9Sstevel@tonic-gate 		token = T_BIT_OR;
222*7c478bd9Sstevel@tonic-gate 		break;
223*7c478bd9Sstevel@tonic-gate 	case '*':
224*7c478bd9Sstevel@tonic-gate 		token = T_STAR;
225*7c478bd9Sstevel@tonic-gate 		break;
226*7c478bd9Sstevel@tonic-gate 	case '#':
227*7c478bd9Sstevel@tonic-gate 		token = T_POUND;
228*7c478bd9Sstevel@tonic-gate 		break;
229*7c478bd9Sstevel@tonic-gate 	case ':':
230*7c478bd9Sstevel@tonic-gate 		token = T_COLON;
231*7c478bd9Sstevel@tonic-gate 		break;
232*7c478bd9Sstevel@tonic-gate 	case ';':
233*7c478bd9Sstevel@tonic-gate 		token = T_SEMICOLON;
234*7c478bd9Sstevel@tonic-gate 		break;
235*7c478bd9Sstevel@tonic-gate 	case ',':
236*7c478bd9Sstevel@tonic-gate 		token = T_COMMA;
237*7c478bd9Sstevel@tonic-gate 		break;
238*7c478bd9Sstevel@tonic-gate 	case '/':
239*7c478bd9Sstevel@tonic-gate 		token = T_SLASH;
240*7c478bd9Sstevel@tonic-gate 		break;
241*7c478bd9Sstevel@tonic-gate 	case ' ':
242*7c478bd9Sstevel@tonic-gate 	case '\t':
243*7c478bd9Sstevel@tonic-gate 	case '\f':
244*7c478bd9Sstevel@tonic-gate 		while ((ch = getc(fp)) == ' ' ||
245*7c478bd9Sstevel@tonic-gate 		    ch == '\t' || ch == '\f') {
246*7c478bd9Sstevel@tonic-gate 			if (--remain == 0) {
247*7c478bd9Sstevel@tonic-gate 				*cp = '\0';
248*7c478bd9Sstevel@tonic-gate 				return (-1);
249*7c478bd9Sstevel@tonic-gate 			}
250*7c478bd9Sstevel@tonic-gate 			*cp++ = (char)ch;
251*7c478bd9Sstevel@tonic-gate 		}
252*7c478bd9Sstevel@tonic-gate 		(void) ungetc(ch, fp);
253*7c478bd9Sstevel@tonic-gate 		token = T_WHITE_SPACE;
254*7c478bd9Sstevel@tonic-gate 		break;
255*7c478bd9Sstevel@tonic-gate 	case '\n':
256*7c478bd9Sstevel@tonic-gate 	case '\r':
257*7c478bd9Sstevel@tonic-gate 		token = T_NEWLINE;
258*7c478bd9Sstevel@tonic-gate 		break;
259*7c478bd9Sstevel@tonic-gate 	case '"':
260*7c478bd9Sstevel@tonic-gate 		remain++;
261*7c478bd9Sstevel@tonic-gate 		cp--;
262*7c478bd9Sstevel@tonic-gate 		badquote = 0;
263*7c478bd9Sstevel@tonic-gate 		while (!badquote && (ch  = getc(fp)) != '"') {
264*7c478bd9Sstevel@tonic-gate 			switch (ch) {
265*7c478bd9Sstevel@tonic-gate 			case '\n':
266*7c478bd9Sstevel@tonic-gate 			case EOF:
267*7c478bd9Sstevel@tonic-gate 				file_err(filep, "Missing \"\n");
268*7c478bd9Sstevel@tonic-gate 				remain = size - 1;
269*7c478bd9Sstevel@tonic-gate 				cp = val;
270*7c478bd9Sstevel@tonic-gate 				*cp++ = '\n';
271*7c478bd9Sstevel@tonic-gate 				badquote = 1;
272*7c478bd9Sstevel@tonic-gate 				/* since we consumed the newline/EOF */
273*7c478bd9Sstevel@tonic-gate 				(void) ungetc(ch, fp);
274*7c478bd9Sstevel@tonic-gate 				break;
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 			case '\\':
277*7c478bd9Sstevel@tonic-gate 				if (--remain == 0) {
278*7c478bd9Sstevel@tonic-gate 					*cp = '\0';
279*7c478bd9Sstevel@tonic-gate 					return (-1);
280*7c478bd9Sstevel@tonic-gate 				}
281*7c478bd9Sstevel@tonic-gate 				ch = (char)getc(fp);
282*7c478bd9Sstevel@tonic-gate 				if (!isdigit(ch)) {
283*7c478bd9Sstevel@tonic-gate 					/* escape the character */
284*7c478bd9Sstevel@tonic-gate 					*cp++ = (char)ch;
285*7c478bd9Sstevel@tonic-gate 					break;
286*7c478bd9Sstevel@tonic-gate 				}
287*7c478bd9Sstevel@tonic-gate 				oval = 0;
288*7c478bd9Sstevel@tonic-gate 				while (ch >= '0' && ch <= '7') {
289*7c478bd9Sstevel@tonic-gate 					ch -= '0';
290*7c478bd9Sstevel@tonic-gate 					oval = (oval << 3) + ch;
291*7c478bd9Sstevel@tonic-gate 					ch = (char)getc(fp);
292*7c478bd9Sstevel@tonic-gate 				}
293*7c478bd9Sstevel@tonic-gate 				(void) ungetc(ch, fp);
294*7c478bd9Sstevel@tonic-gate 				/* check for character overflow? */
295*7c478bd9Sstevel@tonic-gate 				if (oval > 127) {
296*7c478bd9Sstevel@tonic-gate 					file_err(filep,
297*7c478bd9Sstevel@tonic-gate 					    "Character "
298*7c478bd9Sstevel@tonic-gate 					    "overflow detected.\n");
299*7c478bd9Sstevel@tonic-gate 				}
300*7c478bd9Sstevel@tonic-gate 				*cp++ = (char)oval;
301*7c478bd9Sstevel@tonic-gate 				break;
302*7c478bd9Sstevel@tonic-gate 			default:
303*7c478bd9Sstevel@tonic-gate 				if (--remain == 0) {
304*7c478bd9Sstevel@tonic-gate 					*cp = '\0';
305*7c478bd9Sstevel@tonic-gate 					return (-1);
306*7c478bd9Sstevel@tonic-gate 				}
307*7c478bd9Sstevel@tonic-gate 				*cp++ = (char)ch;
308*7c478bd9Sstevel@tonic-gate 				break;
309*7c478bd9Sstevel@tonic-gate 			}
310*7c478bd9Sstevel@tonic-gate 		}
311*7c478bd9Sstevel@tonic-gate 		token = T_STRING;
312*7c478bd9Sstevel@tonic-gate 		break;
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 	case EOF:
315*7c478bd9Sstevel@tonic-gate 		token = T_EOF;
316*7c478bd9Sstevel@tonic-gate 		break;
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	default:
319*7c478bd9Sstevel@tonic-gate 		/*
320*7c478bd9Sstevel@tonic-gate 		 * detect a lone '-' (including at the end of a line), and
321*7c478bd9Sstevel@tonic-gate 		 * identify it as a 'name'
322*7c478bd9Sstevel@tonic-gate 		 */
323*7c478bd9Sstevel@tonic-gate 		if (ch == '-') {
324*7c478bd9Sstevel@tonic-gate 			if (--remain == 0) {
325*7c478bd9Sstevel@tonic-gate 				*cp = '\0';
326*7c478bd9Sstevel@tonic-gate 				return (-1);
327*7c478bd9Sstevel@tonic-gate 			}
328*7c478bd9Sstevel@tonic-gate 			*cp++ = (char)(ch = getc(fp));
329*7c478bd9Sstevel@tonic-gate 			if (ch == ' ' || ch == '\t' || ch == '\n') {
330*7c478bd9Sstevel@tonic-gate 				(void) ungetc(ch, fp);
331*7c478bd9Sstevel@tonic-gate 				remain++;
332*7c478bd9Sstevel@tonic-gate 				cp--;
333*7c478bd9Sstevel@tonic-gate 				token = T_NAME;
334*7c478bd9Sstevel@tonic-gate 				break;
335*7c478bd9Sstevel@tonic-gate 			}
336*7c478bd9Sstevel@tonic-gate 		} else if (ch == '~' || ch == '-') {
337*7c478bd9Sstevel@tonic-gate 			if (--remain == 0) {
338*7c478bd9Sstevel@tonic-gate 				*cp = '\0';
339*7c478bd9Sstevel@tonic-gate 				return (-1);
340*7c478bd9Sstevel@tonic-gate 			}
341*7c478bd9Sstevel@tonic-gate 			*cp++ = (char)(ch = getc(fp));
342*7c478bd9Sstevel@tonic-gate 		}
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 		if (isdigit(ch)) {
346*7c478bd9Sstevel@tonic-gate 			if (ch == '0') {
347*7c478bd9Sstevel@tonic-gate 				if ((ch = getc(fp)) == 'x') {
348*7c478bd9Sstevel@tonic-gate 					if (--remain == 0) {
349*7c478bd9Sstevel@tonic-gate 						*cp = '\0';
350*7c478bd9Sstevel@tonic-gate 						return (-1);
351*7c478bd9Sstevel@tonic-gate 					}
352*7c478bd9Sstevel@tonic-gate 					*cp++ = (char)ch;
353*7c478bd9Sstevel@tonic-gate 					ch = getc(fp);
354*7c478bd9Sstevel@tonic-gate 					while (isxdigit(ch)) {
355*7c478bd9Sstevel@tonic-gate 						if (--remain == 0) {
356*7c478bd9Sstevel@tonic-gate 							*cp = '\0';
357*7c478bd9Sstevel@tonic-gate 							return (-1);
358*7c478bd9Sstevel@tonic-gate 						}
359*7c478bd9Sstevel@tonic-gate 						*cp++ = (char)ch;
360*7c478bd9Sstevel@tonic-gate 						ch = getc(fp);
361*7c478bd9Sstevel@tonic-gate 					}
362*7c478bd9Sstevel@tonic-gate 					(void) ungetc(ch, fp);
363*7c478bd9Sstevel@tonic-gate 					token = T_HEXVAL;
364*7c478bd9Sstevel@tonic-gate 				} else {
365*7c478bd9Sstevel@tonic-gate 					goto digit;
366*7c478bd9Sstevel@tonic-gate 				}
367*7c478bd9Sstevel@tonic-gate 			} else {
368*7c478bd9Sstevel@tonic-gate 				ch = getc(fp);
369*7c478bd9Sstevel@tonic-gate digit:
370*7c478bd9Sstevel@tonic-gate 				while (isdigit(ch)) {
371*7c478bd9Sstevel@tonic-gate 					if (--remain == 0) {
372*7c478bd9Sstevel@tonic-gate 						*cp = '\0';
373*7c478bd9Sstevel@tonic-gate 						return (-1);
374*7c478bd9Sstevel@tonic-gate 					}
375*7c478bd9Sstevel@tonic-gate 					*cp++ = (char)ch;
376*7c478bd9Sstevel@tonic-gate 					ch = getc(fp);
377*7c478bd9Sstevel@tonic-gate 				}
378*7c478bd9Sstevel@tonic-gate 				(void) ungetc(ch, fp);
379*7c478bd9Sstevel@tonic-gate 				token = T_DECVAL;
380*7c478bd9Sstevel@tonic-gate 			}
381*7c478bd9Sstevel@tonic-gate 		} else if (isalpha(ch) || ch == '\\') {
382*7c478bd9Sstevel@tonic-gate 			if (ch != '\\') {
383*7c478bd9Sstevel@tonic-gate 				ch = getc(fp);
384*7c478bd9Sstevel@tonic-gate 			} else {
385*7c478bd9Sstevel@tonic-gate 				/*
386*7c478bd9Sstevel@tonic-gate 				 * if the character was a backslash,
387*7c478bd9Sstevel@tonic-gate 				 * back up so we can overwrite it with
388*7c478bd9Sstevel@tonic-gate 				 * the next (i.e. escaped) character.
389*7c478bd9Sstevel@tonic-gate 				 */
390*7c478bd9Sstevel@tonic-gate 				remain++;
391*7c478bd9Sstevel@tonic-gate 				cp--;
392*7c478bd9Sstevel@tonic-gate 			}
393*7c478bd9Sstevel@tonic-gate 			while (isnamechar(ch) || ch == '\\') {
394*7c478bd9Sstevel@tonic-gate 				if (ch == '\\')
395*7c478bd9Sstevel@tonic-gate 					ch = getc(fp);
396*7c478bd9Sstevel@tonic-gate 				if (--remain == 0) {
397*7c478bd9Sstevel@tonic-gate 					*cp = '\0';
398*7c478bd9Sstevel@tonic-gate 					return (-1);
399*7c478bd9Sstevel@tonic-gate 				}
400*7c478bd9Sstevel@tonic-gate 				*cp++ = (char)ch;
401*7c478bd9Sstevel@tonic-gate 				ch = getc(fp);
402*7c478bd9Sstevel@tonic-gate 			}
403*7c478bd9Sstevel@tonic-gate 			(void) ungetc(ch, fp);
404*7c478bd9Sstevel@tonic-gate 			token = T_NAME;
405*7c478bd9Sstevel@tonic-gate 		} else {
406*7c478bd9Sstevel@tonic-gate 			return (-1);
407*7c478bd9Sstevel@tonic-gate 		}
408*7c478bd9Sstevel@tonic-gate 		break;
409*7c478bd9Sstevel@tonic-gate 	}
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	*cp = '\0';
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	return (token);
414*7c478bd9Sstevel@tonic-gate }
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate static void
417*7c478bd9Sstevel@tonic-gate free_confent(struct conf_entry *confent)
418*7c478bd9Sstevel@tonic-gate {
419*7c478bd9Sstevel@tonic-gate 	if (confent->name)
420*7c478bd9Sstevel@tonic-gate 		free(confent->name);
421*7c478bd9Sstevel@tonic-gate 	if (confent->parent)
422*7c478bd9Sstevel@tonic-gate 		free(confent->parent);
423*7c478bd9Sstevel@tonic-gate 	if (confent->class)
424*7c478bd9Sstevel@tonic-gate 		free(confent->class);
425*7c478bd9Sstevel@tonic-gate 	if (confent->unit_address)
426*7c478bd9Sstevel@tonic-gate 		free(confent->unit_address);
427*7c478bd9Sstevel@tonic-gate 	free(confent);
428*7c478bd9Sstevel@tonic-gate }
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate static void
431*7c478bd9Sstevel@tonic-gate free_confent_list(struct conf_entry *confent_list)
432*7c478bd9Sstevel@tonic-gate {
433*7c478bd9Sstevel@tonic-gate 	struct conf_entry *confent, *next;
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 	for (confent = confent_list; confent != NULL; confent = next) {
436*7c478bd9Sstevel@tonic-gate 		next = confent->next;
437*7c478bd9Sstevel@tonic-gate 		free_confent(confent);
438*7c478bd9Sstevel@tonic-gate 	}
439*7c478bd9Sstevel@tonic-gate }
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate /*
442*7c478bd9Sstevel@tonic-gate  * Parse the next entry from the driver.conf file and return in the form of
443*7c478bd9Sstevel@tonic-gate  * a pointer to the conf_entry.
444*7c478bd9Sstevel@tonic-gate  */
445*7c478bd9Sstevel@tonic-gate static struct conf_entry *
446*7c478bd9Sstevel@tonic-gate parse_conf_entry(struct conf_file *filep, char *tokbuf, size_t linesize)
447*7c478bd9Sstevel@tonic-gate {
448*7c478bd9Sstevel@tonic-gate 	char *prop_name, *string;
449*7c478bd9Sstevel@tonic-gate 	token_t token;
450*7c478bd9Sstevel@tonic-gate 	struct conf_entry *confent;
451*7c478bd9Sstevel@tonic-gate 	conf_state_t state;
452*7c478bd9Sstevel@tonic-gate 	int failed = 1;
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 	if ((confent = calloc(1, sizeof (*confent))) == NULL)
455*7c478bd9Sstevel@tonic-gate 		return (NULL);
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate 	confent->port = -1;
458*7c478bd9Sstevel@tonic-gate 	confent->mpxio_disable = -1;
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate 	state = begin;
461*7c478bd9Sstevel@tonic-gate 	token = T_NAME;
462*7c478bd9Sstevel@tonic-gate 	prop_name = NULL;
463*7c478bd9Sstevel@tonic-gate 	string = NULL;
464*7c478bd9Sstevel@tonic-gate 	do {
465*7c478bd9Sstevel@tonic-gate 		switch (token) {
466*7c478bd9Sstevel@tonic-gate 		case T_NAME:
467*7c478bd9Sstevel@tonic-gate 			switch (state) {
468*7c478bd9Sstevel@tonic-gate 			case prop_equals_string:
469*7c478bd9Sstevel@tonic-gate 			case prop_equals_integer:
470*7c478bd9Sstevel@tonic-gate 			case begin:
471*7c478bd9Sstevel@tonic-gate 				state = prop;
472*7c478bd9Sstevel@tonic-gate 				if ((prop_name = strdup(tokbuf)) == NULL)
473*7c478bd9Sstevel@tonic-gate 					goto bad;
474*7c478bd9Sstevel@tonic-gate 				break;
475*7c478bd9Sstevel@tonic-gate 			default:
476*7c478bd9Sstevel@tonic-gate 				file_err(filep, tok_err, tokbuf);
477*7c478bd9Sstevel@tonic-gate 			}
478*7c478bd9Sstevel@tonic-gate 			break;
479*7c478bd9Sstevel@tonic-gate 		case T_EQUALS:
480*7c478bd9Sstevel@tonic-gate 			switch (state) {
481*7c478bd9Sstevel@tonic-gate 			case prop:
482*7c478bd9Sstevel@tonic-gate 				state = prop_equals;
483*7c478bd9Sstevel@tonic-gate 				break;
484*7c478bd9Sstevel@tonic-gate 			default:
485*7c478bd9Sstevel@tonic-gate 				file_err(filep, tok_err, tokbuf);
486*7c478bd9Sstevel@tonic-gate 			}
487*7c478bd9Sstevel@tonic-gate 			break;
488*7c478bd9Sstevel@tonic-gate 		case T_STRING:
489*7c478bd9Sstevel@tonic-gate 			switch (state) {
490*7c478bd9Sstevel@tonic-gate 			case prop_equals:
491*7c478bd9Sstevel@tonic-gate 				if ((string = strdup(tokbuf)) == NULL)
492*7c478bd9Sstevel@tonic-gate 					goto bad;
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate 				state = begin;
495*7c478bd9Sstevel@tonic-gate 				if (strcmp(prop_name, "PARENT") == 0 ||
496*7c478bd9Sstevel@tonic-gate 				    strcmp(prop_name, "parent") == 0) {
497*7c478bd9Sstevel@tonic-gate 					if (confent->parent) {
498*7c478bd9Sstevel@tonic-gate 						file_err(filep,
499*7c478bd9Sstevel@tonic-gate 				"'parent' property already specified\n");
500*7c478bd9Sstevel@tonic-gate 						goto bad;
501*7c478bd9Sstevel@tonic-gate 					}
502*7c478bd9Sstevel@tonic-gate 					confent->parent = string;
503*7c478bd9Sstevel@tonic-gate 				} else if (strcmp(prop_name, "NAME") == 0 ||
504*7c478bd9Sstevel@tonic-gate 				    strcmp(prop_name, "name") == 0) {
505*7c478bd9Sstevel@tonic-gate 					if (confent->name) {
506*7c478bd9Sstevel@tonic-gate 						file_err(filep,
507*7c478bd9Sstevel@tonic-gate 				"'name' property already specified\n");
508*7c478bd9Sstevel@tonic-gate 						goto bad;
509*7c478bd9Sstevel@tonic-gate 					}
510*7c478bd9Sstevel@tonic-gate 					confent->name = string;
511*7c478bd9Sstevel@tonic-gate 				} else if (strcmp(prop_name, "CLASS") == 0 ||
512*7c478bd9Sstevel@tonic-gate 				    strcmp(prop_name, "class") == 0) {
513*7c478bd9Sstevel@tonic-gate 					if (confent->class) {
514*7c478bd9Sstevel@tonic-gate 						file_err(filep,
515*7c478bd9Sstevel@tonic-gate 				"'class' property already specified\n");
516*7c478bd9Sstevel@tonic-gate 						goto bad;
517*7c478bd9Sstevel@tonic-gate 					}
518*7c478bd9Sstevel@tonic-gate 					confent->class = string;
519*7c478bd9Sstevel@tonic-gate 				} else if (strcmp(prop_name, "unit-address")
520*7c478bd9Sstevel@tonic-gate 				    == 0) {
521*7c478bd9Sstevel@tonic-gate 					if (confent->unit_address) {
522*7c478bd9Sstevel@tonic-gate 						file_err(filep,
523*7c478bd9Sstevel@tonic-gate 				"'unit-address' property already specified\n");
524*7c478bd9Sstevel@tonic-gate 						goto bad;
525*7c478bd9Sstevel@tonic-gate 					}
526*7c478bd9Sstevel@tonic-gate 					confent->unit_address = string;
527*7c478bd9Sstevel@tonic-gate 				} else if (strcmp(prop_name, "mpxio-disable")
528*7c478bd9Sstevel@tonic-gate 				    == 0) {
529*7c478bd9Sstevel@tonic-gate 					if (confent->mpxio_disable != -1) {
530*7c478bd9Sstevel@tonic-gate 						file_err(filep,
531*7c478bd9Sstevel@tonic-gate 				"'mpxio-disable' property already specified\n");
532*7c478bd9Sstevel@tonic-gate 						goto bad;
533*7c478bd9Sstevel@tonic-gate 					}
534*7c478bd9Sstevel@tonic-gate 					if (strcmp(string, "yes") == 0)
535*7c478bd9Sstevel@tonic-gate 						confent->mpxio_disable = 1;
536*7c478bd9Sstevel@tonic-gate 					else if (strcmp(string, "no") == 0)
537*7c478bd9Sstevel@tonic-gate 						confent->mpxio_disable = 0;
538*7c478bd9Sstevel@tonic-gate 					else {
539*7c478bd9Sstevel@tonic-gate 						file_err(filep,
540*7c478bd9Sstevel@tonic-gate 				"'mpxio-disable' property setting is invalid. "
541*7c478bd9Sstevel@tonic-gate 				"The value must be either \"yes\" or \"no\"\n");
542*7c478bd9Sstevel@tonic-gate 						goto bad;
543*7c478bd9Sstevel@tonic-gate 					}
544*7c478bd9Sstevel@tonic-gate 					free(string);
545*7c478bd9Sstevel@tonic-gate 				} else {
546*7c478bd9Sstevel@tonic-gate 					free(string);
547*7c478bd9Sstevel@tonic-gate 					state = prop_equals_string;
548*7c478bd9Sstevel@tonic-gate 				}
549*7c478bd9Sstevel@tonic-gate 				string = NULL;
550*7c478bd9Sstevel@tonic-gate 				free(prop_name);
551*7c478bd9Sstevel@tonic-gate 				prop_name = NULL;
552*7c478bd9Sstevel@tonic-gate 				break;
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate 			case prop_equals_string_comma:
555*7c478bd9Sstevel@tonic-gate 				state = prop_equals_string;
556*7c478bd9Sstevel@tonic-gate 				break;
557*7c478bd9Sstevel@tonic-gate 			default:
558*7c478bd9Sstevel@tonic-gate 				file_err(filep, tok_err, tokbuf);
559*7c478bd9Sstevel@tonic-gate 			}
560*7c478bd9Sstevel@tonic-gate 			break;
561*7c478bd9Sstevel@tonic-gate 		case T_HEXVAL:
562*7c478bd9Sstevel@tonic-gate 		case T_DECVAL:
563*7c478bd9Sstevel@tonic-gate 			switch (state) {
564*7c478bd9Sstevel@tonic-gate 			case prop_equals:
565*7c478bd9Sstevel@tonic-gate 				if (strcmp(prop_name, "port") == 0) {
566*7c478bd9Sstevel@tonic-gate 					if (confent->port != -1) {
567*7c478bd9Sstevel@tonic-gate 						file_err(filep,
568*7c478bd9Sstevel@tonic-gate 					"'port' property already specified\n");
569*7c478bd9Sstevel@tonic-gate 						goto bad;
570*7c478bd9Sstevel@tonic-gate 					}
571*7c478bd9Sstevel@tonic-gate 					confent->port =
572*7c478bd9Sstevel@tonic-gate 					    (int)strtol(tokbuf, NULL, 0);
573*7c478bd9Sstevel@tonic-gate 					state = begin;
574*7c478bd9Sstevel@tonic-gate 				} else
575*7c478bd9Sstevel@tonic-gate 					state = prop_equals_integer;
576*7c478bd9Sstevel@tonic-gate 				free(prop_name);
577*7c478bd9Sstevel@tonic-gate 				prop_name = NULL;
578*7c478bd9Sstevel@tonic-gate 				break;
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 			case prop_equals_integer_comma:
581*7c478bd9Sstevel@tonic-gate 				state = prop_equals_integer;
582*7c478bd9Sstevel@tonic-gate 				break;
583*7c478bd9Sstevel@tonic-gate 			default:
584*7c478bd9Sstevel@tonic-gate 				file_err(filep, tok_err, tokbuf);
585*7c478bd9Sstevel@tonic-gate 			}
586*7c478bd9Sstevel@tonic-gate 			break;
587*7c478bd9Sstevel@tonic-gate 		case T_COMMA:
588*7c478bd9Sstevel@tonic-gate 			switch (state) {
589*7c478bd9Sstevel@tonic-gate 			case prop_equals_string:
590*7c478bd9Sstevel@tonic-gate 				state = prop_equals_string_comma;
591*7c478bd9Sstevel@tonic-gate 				break;
592*7c478bd9Sstevel@tonic-gate 			case prop_equals_integer:
593*7c478bd9Sstevel@tonic-gate 				state = prop_equals_integer_comma;
594*7c478bd9Sstevel@tonic-gate 				break;
595*7c478bd9Sstevel@tonic-gate 			default:
596*7c478bd9Sstevel@tonic-gate 				file_err(filep, tok_err, tokbuf);
597*7c478bd9Sstevel@tonic-gate 			}
598*7c478bd9Sstevel@tonic-gate 			break;
599*7c478bd9Sstevel@tonic-gate 		case T_NEWLINE:
600*7c478bd9Sstevel@tonic-gate 			filep->linenum++;
601*7c478bd9Sstevel@tonic-gate 			break;
602*7c478bd9Sstevel@tonic-gate 		case T_POUND:
603*7c478bd9Sstevel@tonic-gate 			find_eol(filep->fp);
604*7c478bd9Sstevel@tonic-gate 			break;
605*7c478bd9Sstevel@tonic-gate 		case T_EOF:
606*7c478bd9Sstevel@tonic-gate 			file_err(filep, "Unexpected EOF\n");
607*7c478bd9Sstevel@tonic-gate 			goto bad;
608*7c478bd9Sstevel@tonic-gate 		default:
609*7c478bd9Sstevel@tonic-gate 			file_err(filep, tok_err, tokbuf);
610*7c478bd9Sstevel@tonic-gate 			goto bad;
611*7c478bd9Sstevel@tonic-gate 		}
612*7c478bd9Sstevel@tonic-gate 	} while ((token = lex(filep, tokbuf, linesize)) != T_SEMICOLON);
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 	failed = 0;
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate bad:
617*7c478bd9Sstevel@tonic-gate 	if (prop_name)
618*7c478bd9Sstevel@tonic-gate 		free(prop_name);
619*7c478bd9Sstevel@tonic-gate 	if (string)
620*7c478bd9Sstevel@tonic-gate 		free(string);
621*7c478bd9Sstevel@tonic-gate 	if (failed == 1) {
622*7c478bd9Sstevel@tonic-gate 		free_confent(confent);
623*7c478bd9Sstevel@tonic-gate 		return (NULL);
624*7c478bd9Sstevel@tonic-gate 	}
625*7c478bd9Sstevel@tonic-gate 	return (confent);
626*7c478bd9Sstevel@tonic-gate }
627*7c478bd9Sstevel@tonic-gate 
628*7c478bd9Sstevel@tonic-gate /*
629*7c478bd9Sstevel@tonic-gate  * Parse all entries with mpxio-disable property in the given driver.conf
630*7c478bd9Sstevel@tonic-gate  * file.
631*7c478bd9Sstevel@tonic-gate  *
632*7c478bd9Sstevel@tonic-gate  * fname		driver.conf file name
633*7c478bd9Sstevel@tonic-gate  * confent_list		on return *confent_list will contain the list of
634*7c478bd9Sstevel@tonic-gate  *			driver.conf file entries with mpxio-disable property.
635*7c478bd9Sstevel@tonic-gate  * mpxio_disable	on return *mpxio_disable is set to the setting of the
636*7c478bd9Sstevel@tonic-gate  * 			driver global mpxio-dissable property as follows.
637*7c478bd9Sstevel@tonic-gate  *			0  if driver mpxio-disable="no"
638*7c478bd9Sstevel@tonic-gate  *			1  if driver mpxio-disable="yes"
639*7c478bd9Sstevel@tonic-gate  *			-1 if driver mpxio-disable property isn't specified.
640*7c478bd9Sstevel@tonic-gate  */
641*7c478bd9Sstevel@tonic-gate static void
642*7c478bd9Sstevel@tonic-gate parse_conf_file(char *fname, struct conf_entry **confent_list,
643*7c478bd9Sstevel@tonic-gate     int *mpxio_disable)
644*7c478bd9Sstevel@tonic-gate {
645*7c478bd9Sstevel@tonic-gate 	struct conf_entry *confent, *tail = NULL;
646*7c478bd9Sstevel@tonic-gate 	token_t token;
647*7c478bd9Sstevel@tonic-gate 	struct conf_file file;
648*7c478bd9Sstevel@tonic-gate 	char tokval[MAX_TOKEN_SIZE];
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate 	*confent_list = NULL;
651*7c478bd9Sstevel@tonic-gate 	*mpxio_disable = -1;
652*7c478bd9Sstevel@tonic-gate 	if ((file.fp = fopen(fname, "r")) == NULL)
653*7c478bd9Sstevel@tonic-gate 		return;
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 	file.filename = fname;
656*7c478bd9Sstevel@tonic-gate 	file.linenum = 1;
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 	while ((token = lex(&file, tokval, MAX_TOKEN_SIZE)) != T_EOF) {
659*7c478bd9Sstevel@tonic-gate 		switch (token) {
660*7c478bd9Sstevel@tonic-gate 		case T_POUND:
661*7c478bd9Sstevel@tonic-gate 			/*
662*7c478bd9Sstevel@tonic-gate 			 * Skip comments.
663*7c478bd9Sstevel@tonic-gate 			 */
664*7c478bd9Sstevel@tonic-gate 			find_eol(file.fp);
665*7c478bd9Sstevel@tonic-gate 			break;
666*7c478bd9Sstevel@tonic-gate 		case T_NAME:
667*7c478bd9Sstevel@tonic-gate 			if ((confent = parse_conf_entry(&file, tokval,
668*7c478bd9Sstevel@tonic-gate 			    MAX_TOKEN_SIZE)) == NULL)
669*7c478bd9Sstevel@tonic-gate 				break;
670*7c478bd9Sstevel@tonic-gate 			/*
671*7c478bd9Sstevel@tonic-gate 			 * No name indicates global property.
672*7c478bd9Sstevel@tonic-gate 			 * Make sure parent and class not NULL.
673*7c478bd9Sstevel@tonic-gate 			 */
674*7c478bd9Sstevel@tonic-gate 			if (confent->name == NULL) {
675*7c478bd9Sstevel@tonic-gate 				if (confent->parent ||
676*7c478bd9Sstevel@tonic-gate 				    confent->class) {
677*7c478bd9Sstevel@tonic-gate 					file_err(&file,
678*7c478bd9Sstevel@tonic-gate 					    "missing name attribute\n");
679*7c478bd9Sstevel@tonic-gate 				} else if (confent->mpxio_disable != -1) {
680*7c478bd9Sstevel@tonic-gate 					if (*mpxio_disable == -1)
681*7c478bd9Sstevel@tonic-gate 						*mpxio_disable =
682*7c478bd9Sstevel@tonic-gate 						    confent->mpxio_disable;
683*7c478bd9Sstevel@tonic-gate 					else
684*7c478bd9Sstevel@tonic-gate 						file_err(&file,
685*7c478bd9Sstevel@tonic-gate 				"'mpxio-disable' property already specified\n");
686*7c478bd9Sstevel@tonic-gate 				}
687*7c478bd9Sstevel@tonic-gate 				free_confent(confent);
688*7c478bd9Sstevel@tonic-gate 				break;
689*7c478bd9Sstevel@tonic-gate 			}
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 			/*
692*7c478bd9Sstevel@tonic-gate 			 * This is a node spec, either parent or class
693*7c478bd9Sstevel@tonic-gate 			 * must be specified.
694*7c478bd9Sstevel@tonic-gate 			 */
695*7c478bd9Sstevel@tonic-gate 			if (confent->parent == NULL && confent->class == NULL) {
696*7c478bd9Sstevel@tonic-gate 				file_err(&file,
697*7c478bd9Sstevel@tonic-gate 				    "missing parent or class attribute\n");
698*7c478bd9Sstevel@tonic-gate 				free_confent(confent);
699*7c478bd9Sstevel@tonic-gate 				break;
700*7c478bd9Sstevel@tonic-gate 			}
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate 			/* only need entries with mpxio_disable property */
703*7c478bd9Sstevel@tonic-gate 			if (confent->mpxio_disable == -1) {
704*7c478bd9Sstevel@tonic-gate 				free_confent(confent);
705*7c478bd9Sstevel@tonic-gate 				break;
706*7c478bd9Sstevel@tonic-gate 			}
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 			if (tail)
709*7c478bd9Sstevel@tonic-gate 				tail->next = confent;
710*7c478bd9Sstevel@tonic-gate 			else
711*7c478bd9Sstevel@tonic-gate 				*confent_list = confent;
712*7c478bd9Sstevel@tonic-gate 			tail = confent;
713*7c478bd9Sstevel@tonic-gate 			break;
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 		case T_NEWLINE:
716*7c478bd9Sstevel@tonic-gate 			file.linenum++;
717*7c478bd9Sstevel@tonic-gate 			break;
718*7c478bd9Sstevel@tonic-gate 		default:
719*7c478bd9Sstevel@tonic-gate 			break;
720*7c478bd9Sstevel@tonic-gate 		}
721*7c478bd9Sstevel@tonic-gate 	}
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 	(void) fclose(file.fp);
724*7c478bd9Sstevel@tonic-gate }
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate /*
727*7c478bd9Sstevel@tonic-gate  * Return the driver class of the given driver_name.
728*7c478bd9Sstevel@tonic-gate  * The memory for the driver class is allocated by this function and the
729*7c478bd9Sstevel@tonic-gate  * caller must free it.
730*7c478bd9Sstevel@tonic-gate  */
731*7c478bd9Sstevel@tonic-gate static char *
732*7c478bd9Sstevel@tonic-gate get_driver_class(char *rootdir, char *driver_name)
733*7c478bd9Sstevel@tonic-gate {
734*7c478bd9Sstevel@tonic-gate 	FILE *fp;
735*7c478bd9Sstevel@tonic-gate 	char buf[BUFSIZE];
736*7c478bd9Sstevel@tonic-gate 	char driver[BUFSIZE];
737*7c478bd9Sstevel@tonic-gate 	char class_name[BUFSIZE];
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate 	logdmsg(("get_driver_class: rootdir = %s, driver name = %s\n",
740*7c478bd9Sstevel@tonic-gate 	    rootdir, driver_name));
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%s%s", rootdir, DRIVER_CLASSES);
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(buf, "r")) == NULL) {
745*7c478bd9Sstevel@tonic-gate 		logdmsg(("get_driver_class: failed to open %s: %s\n",
746*7c478bd9Sstevel@tonic-gate 		    buf, strerror(errno)));
747*7c478bd9Sstevel@tonic-gate 		return (NULL);
748*7c478bd9Sstevel@tonic-gate 	}
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 	while (fgets(buf, sizeof (buf), fp) != NULL) {
751*7c478bd9Sstevel@tonic-gate 		/* LINTED - unbounded string specifier */
752*7c478bd9Sstevel@tonic-gate 		if ((sscanf(buf, "%s %s", driver, class_name) == 2) &&
753*7c478bd9Sstevel@tonic-gate 		    driver[0] != '#' && strcmp(driver, driver_name) == 0) {
754*7c478bd9Sstevel@tonic-gate 			logdmsg(("get_driver_class: driver class = %s\n",
755*7c478bd9Sstevel@tonic-gate 			    class_name));
756*7c478bd9Sstevel@tonic-gate 			(void) fclose(fp);
757*7c478bd9Sstevel@tonic-gate 			return (strdup(class_name));
758*7c478bd9Sstevel@tonic-gate 		}
759*7c478bd9Sstevel@tonic-gate 	}
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
762*7c478bd9Sstevel@tonic-gate 	return (NULL);
763*7c478bd9Sstevel@tonic-gate }
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate static int
766*7c478bd9Sstevel@tonic-gate lookup_in_confent_list(struct conf_entry *confent_list,
767*7c478bd9Sstevel@tonic-gate     int match_class, char *parent, char *unit_addr, int port)
768*7c478bd9Sstevel@tonic-gate {
769*7c478bd9Sstevel@tonic-gate 	struct conf_entry *confent;
770*7c478bd9Sstevel@tonic-gate 	char *par;
771*7c478bd9Sstevel@tonic-gate 
772*7c478bd9Sstevel@tonic-gate 	logdmsg(("lookup_in_confent_list: %s = \"%s\", unit_addr = \"%s\", "
773*7c478bd9Sstevel@tonic-gate 	    "port = %d\n", (match_class) ? "class" : "parent", parent,
774*7c478bd9Sstevel@tonic-gate 	    STRVAL(unit_addr), port));
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 	for (confent = confent_list; confent != NULL; confent = confent->next) {
777*7c478bd9Sstevel@tonic-gate 		par = (match_class) ? confent->class : confent->parent;
778*7c478bd9Sstevel@tonic-gate 		if (unit_addr) {
779*7c478bd9Sstevel@tonic-gate 			if (confent->unit_address != NULL &&
780*7c478bd9Sstevel@tonic-gate 			    strcmp(confent->unit_address, unit_addr) == 0 &&
781*7c478bd9Sstevel@tonic-gate 			    par != NULL && strcmp(par, parent) == 0)
782*7c478bd9Sstevel@tonic-gate 				return (confent->mpxio_disable);
783*7c478bd9Sstevel@tonic-gate 		} else {
784*7c478bd9Sstevel@tonic-gate 			if (confent->port == port &&
785*7c478bd9Sstevel@tonic-gate 			    par != NULL && strcmp(par, parent) == 0)
786*7c478bd9Sstevel@tonic-gate 				return (confent->mpxio_disable);
787*7c478bd9Sstevel@tonic-gate 		}
788*7c478bd9Sstevel@tonic-gate 	}
789*7c478bd9Sstevel@tonic-gate 	return (-1);
790*7c478bd9Sstevel@tonic-gate }
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate /*
793*7c478bd9Sstevel@tonic-gate  * lookup mpxio-disabled property setting for the given path in the given
794*7c478bd9Sstevel@tonic-gate  * driver.conf file. Match the entries from most specific to least specific.
795*7c478bd9Sstevel@tonic-gate  *
796*7c478bd9Sstevel@tonic-gate  * conf_file	the path name of either fp.conf, qlc.conf or scsi_vhci.conf
797*7c478bd9Sstevel@tonic-gate  * path		/devices node path without the /devices prefix.
798*7c478bd9Sstevel@tonic-gate  *		If the conf_file is fp.conf, path must be a fp node path
799*7c478bd9Sstevel@tonic-gate  *		if the conf_file is qlc.conf, path must be a qlc node path.
800*7c478bd9Sstevel@tonic-gate  *		if the conf_file is scsi_vhci.conf, path must be NULL.
801*7c478bd9Sstevel@tonic-gate  *		ex:	/pci@8,600000/SUNW,qlc@4/fp@0,0
802*7c478bd9Sstevel@tonic-gate  *			/pci@8,600000/SUNW,qlc@4
803*7c478bd9Sstevel@tonic-gate  *
804*7c478bd9Sstevel@tonic-gate  * returns:
805*7c478bd9Sstevel@tonic-gate  *	0	if mpxio-disable="no"
806*7c478bd9Sstevel@tonic-gate  *	1	if mpxio-disable="yes"
807*7c478bd9Sstevel@tonic-gate  *	-1	if mpxio-disable property isn't specified.
808*7c478bd9Sstevel@tonic-gate  */
809*7c478bd9Sstevel@tonic-gate static int
810*7c478bd9Sstevel@tonic-gate lookup_in_conf_file(char *rootdir, char *conf_file, char *path)
811*7c478bd9Sstevel@tonic-gate {
812*7c478bd9Sstevel@tonic-gate 	struct conf_entry *confent_list = NULL;
813*7c478bd9Sstevel@tonic-gate 	int mpxio_disable;
814*7c478bd9Sstevel@tonic-gate 	di_node_t par_node = DI_NODE_NIL;
815*7c478bd9Sstevel@tonic-gate 	char *node_name = NULL, *node_addr = NULL;
816*7c478bd9Sstevel@tonic-gate 	char *unit_addr = NULL;
817*7c478bd9Sstevel@tonic-gate 	int port = -1;
818*7c478bd9Sstevel@tonic-gate 	char *par_node_name = NULL, *par_node_addr = NULL;
819*7c478bd9Sstevel@tonic-gate 	char *par_binding_name = NULL, *par_driver_name = NULL;
820*7c478bd9Sstevel@tonic-gate 	char *par_driver_class = NULL, *par_node_name_addr;
821*7c478bd9Sstevel@tonic-gate 	int rv = -1;
822*7c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 	logdmsg(("lookup_in_conf_file: rootdir = \"%s\", conf_file = \"%s\", "
825*7c478bd9Sstevel@tonic-gate 	    "path = \"%s\"\n", rootdir, conf_file, STRVAL(path)));
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, MAXPATHLEN, "%s%s", rootdir, conf_file);
828*7c478bd9Sstevel@tonic-gate 	parse_conf_file(buf, &confent_list, &mpxio_disable);
829*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
830*7c478bd9Sstevel@tonic-gate 	log_confent_list(buf, confent_list, mpxio_disable);
831*7c478bd9Sstevel@tonic-gate #endif
832*7c478bd9Sstevel@tonic-gate 
833*7c478bd9Sstevel@tonic-gate 	/* if path is NULL, return driver global mpxio-disable setting */
834*7c478bd9Sstevel@tonic-gate 	if (path == NULL) {
835*7c478bd9Sstevel@tonic-gate 		rv = mpxio_disable;
836*7c478bd9Sstevel@tonic-gate 		goto done;
837*7c478bd9Sstevel@tonic-gate 	}
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 	if ((node_name = strrchr(path, '/')) == NULL)
840*7c478bd9Sstevel@tonic-gate 		goto done;
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 	*node_name = '\0';
843*7c478bd9Sstevel@tonic-gate 	node_name++;
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate 	if ((node_addr = strchr(node_name, '@')) == NULL)
846*7c478bd9Sstevel@tonic-gate 		goto done;
847*7c478bd9Sstevel@tonic-gate 
848*7c478bd9Sstevel@tonic-gate 	*node_addr = '\0';
849*7c478bd9Sstevel@tonic-gate 	node_addr++;
850*7c478bd9Sstevel@tonic-gate 
851*7c478bd9Sstevel@tonic-gate 	if (strcmp(node_name, "fp") == 0) {
852*7c478bd9Sstevel@tonic-gate 		/* get port number; encoded in the node addr as a hex number */
853*7c478bd9Sstevel@tonic-gate 		port = (int)strtol(node_addr, NULL, 16);
854*7c478bd9Sstevel@tonic-gate 	} else
855*7c478bd9Sstevel@tonic-gate 		unit_addr = node_addr;
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 	/*
858*7c478bd9Sstevel@tonic-gate 	 * Match from most specific to least specific;
859*7c478bd9Sstevel@tonic-gate 	 * first, start the lookup based on full path.
860*7c478bd9Sstevel@tonic-gate 	 */
861*7c478bd9Sstevel@tonic-gate 	if ((rv = lookup_in_confent_list(confent_list, 0, path,
862*7c478bd9Sstevel@tonic-gate 	    unit_addr, port)) != -1)
863*7c478bd9Sstevel@tonic-gate 		goto done;
864*7c478bd9Sstevel@tonic-gate 
865*7c478bd9Sstevel@tonic-gate 	/* lookup nodename@address */
866*7c478bd9Sstevel@tonic-gate 	if ((par_node_name_addr = strrchr(path, '/')) != NULL) {
867*7c478bd9Sstevel@tonic-gate 		par_node_name_addr++;
868*7c478bd9Sstevel@tonic-gate 		if ((rv = lookup_in_confent_list(confent_list, 0,
869*7c478bd9Sstevel@tonic-gate 		    par_node_name_addr, unit_addr, port)) != -1)
870*7c478bd9Sstevel@tonic-gate 			goto done;
871*7c478bd9Sstevel@tonic-gate 	}
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate 	/* di_init() doesn't work when 0 is passed in flags */
874*7c478bd9Sstevel@tonic-gate 	par_node = di_init(path, DINFOMINOR);
875*7c478bd9Sstevel@tonic-gate 	if (par_node != DI_NODE_NIL) {
876*7c478bd9Sstevel@tonic-gate 		par_node_name = di_node_name(par_node);
877*7c478bd9Sstevel@tonic-gate 		par_node_addr = di_bus_addr(par_node);
878*7c478bd9Sstevel@tonic-gate 		par_binding_name = di_binding_name(par_node);
879*7c478bd9Sstevel@tonic-gate 		par_driver_name = di_driver_name(par_node);
880*7c478bd9Sstevel@tonic-gate 	}
881*7c478bd9Sstevel@tonic-gate 
882*7c478bd9Sstevel@tonic-gate 	logdmsg(("par_node_name = %s\n", STRVAL(par_node_name)));
883*7c478bd9Sstevel@tonic-gate 	logdmsg(("par_node_addr = %s\n", STRVAL(par_node_addr)));
884*7c478bd9Sstevel@tonic-gate 	logdmsg(("par_binding_name = %s\n", STRVAL(par_binding_name)));
885*7c478bd9Sstevel@tonic-gate 	logdmsg(("par_driver_name = %s\n", STRVAL(par_driver_name)));
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate 	/* lookup bindingname@address */
888*7c478bd9Sstevel@tonic-gate 	if (par_binding_name != NULL && par_binding_name != par_node_name &&
889*7c478bd9Sstevel@tonic-gate 	    par_node_addr != NULL) {
890*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "%s@%s", par_binding_name,
891*7c478bd9Sstevel@tonic-gate 		    par_node_addr);
892*7c478bd9Sstevel@tonic-gate 		if ((rv = lookup_in_confent_list(confent_list, 0,
893*7c478bd9Sstevel@tonic-gate 		    buf, unit_addr, port)) != -1)
894*7c478bd9Sstevel@tonic-gate 			goto done;
895*7c478bd9Sstevel@tonic-gate 	}
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 	/* lookup binding name */
898*7c478bd9Sstevel@tonic-gate 	if (par_binding_name != NULL) {
899*7c478bd9Sstevel@tonic-gate 		if ((rv = lookup_in_confent_list(confent_list, 0,
900*7c478bd9Sstevel@tonic-gate 		    par_binding_name, unit_addr, port)) != -1)
901*7c478bd9Sstevel@tonic-gate 			goto done;
902*7c478bd9Sstevel@tonic-gate 	}
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate 	if (par_driver_name != NULL) {
905*7c478bd9Sstevel@tonic-gate 		/* lookup driver name */
906*7c478bd9Sstevel@tonic-gate 		if ((rv = lookup_in_confent_list(confent_list, 0,
907*7c478bd9Sstevel@tonic-gate 		    par_driver_name, unit_addr, port)) != -1)
908*7c478bd9Sstevel@tonic-gate 			goto done;
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate 		/* finally, lookup class name */
911*7c478bd9Sstevel@tonic-gate 		par_driver_class = get_driver_class(rootdir, par_driver_name);
912*7c478bd9Sstevel@tonic-gate 		if (par_driver_class != NULL) {
913*7c478bd9Sstevel@tonic-gate 			if ((rv = lookup_in_confent_list(confent_list, 1,
914*7c478bd9Sstevel@tonic-gate 			    par_driver_class, unit_addr, port)) != -1)
915*7c478bd9Sstevel@tonic-gate 				goto done;
916*7c478bd9Sstevel@tonic-gate 		}
917*7c478bd9Sstevel@tonic-gate 	}
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate 	/*
920*7c478bd9Sstevel@tonic-gate 	 * no match so far;
921*7c478bd9Sstevel@tonic-gate 	 * use the driver global mpxio-disable setting if exists.
922*7c478bd9Sstevel@tonic-gate 	 */
923*7c478bd9Sstevel@tonic-gate 	rv = mpxio_disable;
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate done:
926*7c478bd9Sstevel@tonic-gate 	if (node_name != NULL)
927*7c478bd9Sstevel@tonic-gate 		*(node_name - 1) = '/';
928*7c478bd9Sstevel@tonic-gate 	if (node_addr != NULL)
929*7c478bd9Sstevel@tonic-gate 		*(node_addr - 1) = '@';
930*7c478bd9Sstevel@tonic-gate 	if (par_driver_class != NULL)
931*7c478bd9Sstevel@tonic-gate 		free(par_driver_class);
932*7c478bd9Sstevel@tonic-gate 	if (confent_list != NULL)
933*7c478bd9Sstevel@tonic-gate 		free_confent_list(confent_list);
934*7c478bd9Sstevel@tonic-gate 	if (par_node != DI_NODE_NIL)
935*7c478bd9Sstevel@tonic-gate 		di_fini(par_node);
936*7c478bd9Sstevel@tonic-gate 
937*7c478bd9Sstevel@tonic-gate 	return (rv);
938*7c478bd9Sstevel@tonic-gate }
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate /*
941*7c478bd9Sstevel@tonic-gate  * Given client_name return whether it is a phci or vhci based name.
942*7c478bd9Sstevel@tonic-gate  * client_name is /devices name of a client without the /devices prefix.
943*7c478bd9Sstevel@tonic-gate  *
944*7c478bd9Sstevel@tonic-gate  * client_name			Return value
945*7c478bd9Sstevel@tonic-gate  * .../fp@xxx/ssd@yyy		CLIENT_TYPE_PHCI
946*7c478bd9Sstevel@tonic-gate  * .../scsi_vhci/ssd@yyy	CLIENT_TYPE_VHCI
947*7c478bd9Sstevel@tonic-gate  * other			CLIENT_TYPE_UNKNOWN
948*7c478bd9Sstevel@tonic-gate  */
949*7c478bd9Sstevel@tonic-gate static client_type_t
950*7c478bd9Sstevel@tonic-gate client_name_type(char *client_name)
951*7c478bd9Sstevel@tonic-gate {
952*7c478bd9Sstevel@tonic-gate 	client_type_t client_type;
953*7c478bd9Sstevel@tonic-gate 	char *p1, *p2;
954*7c478bd9Sstevel@tonic-gate 
955*7c478bd9Sstevel@tonic-gate 	logdmsg(("client_name_type: client_name = %s\n", client_name));
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate 	if (strncmp(client_name, SLASH_SCSI_VHCI,
958*7c478bd9Sstevel@tonic-gate 	    sizeof (SLASH_SCSI_VHCI) - 1) == 0)
959*7c478bd9Sstevel@tonic-gate 		return (CLIENT_TYPE_VHCI);
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate 	if (*client_name != '/')
962*7c478bd9Sstevel@tonic-gate 		return (CLIENT_TYPE_UNKNOWN);
963*7c478bd9Sstevel@tonic-gate 
964*7c478bd9Sstevel@tonic-gate 	if ((p1 = strrchr(client_name, '/')) == NULL)
965*7c478bd9Sstevel@tonic-gate 		return (CLIENT_TYPE_UNKNOWN);
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate 	*p1 = '\0';
968*7c478bd9Sstevel@tonic-gate 
969*7c478bd9Sstevel@tonic-gate 	if ((p2 = strrchr(client_name, '/')) != NULL &&
970*7c478bd9Sstevel@tonic-gate 	    strncmp(p2, SLASH_FP_AT, sizeof (SLASH_FP_AT) - 1) == 0)
971*7c478bd9Sstevel@tonic-gate 		client_type = CLIENT_TYPE_PHCI;
972*7c478bd9Sstevel@tonic-gate 	else
973*7c478bd9Sstevel@tonic-gate 		client_type = CLIENT_TYPE_UNKNOWN;
974*7c478bd9Sstevel@tonic-gate 
975*7c478bd9Sstevel@tonic-gate 	*p1 = '/';
976*7c478bd9Sstevel@tonic-gate 	return (client_type);
977*7c478bd9Sstevel@tonic-gate }
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate /*
980*7c478bd9Sstevel@tonic-gate  * Compare controller name portion of dev1 and dev2.
981*7c478bd9Sstevel@tonic-gate  *
982*7c478bd9Sstevel@tonic-gate  * rootdir	root directory of the target environment
983*7c478bd9Sstevel@tonic-gate  * dev1		can be either a /dev link or /devices name in the target
984*7c478bd9Sstevel@tonic-gate  *		environemnt
985*7c478bd9Sstevel@tonic-gate  * dev2		/devices name of a device without the /devices prefix
986*7c478bd9Sstevel@tonic-gate  *
987*7c478bd9Sstevel@tonic-gate  * Returns:
988*7c478bd9Sstevel@tonic-gate  *	0	if controller names match
989*7c478bd9Sstevel@tonic-gate  *	1	if controller names don't match
990*7c478bd9Sstevel@tonic-gate  *	-1	an error occurred.
991*7c478bd9Sstevel@tonic-gate  */
992*7c478bd9Sstevel@tonic-gate static int
993*7c478bd9Sstevel@tonic-gate compare_controller(char *rootdir, char *dev1, char *dev2)
994*7c478bd9Sstevel@tonic-gate {
995*7c478bd9Sstevel@tonic-gate 	int linksize;
996*7c478bd9Sstevel@tonic-gate 	char *p1, *p;
997*7c478bd9Sstevel@tonic-gate 	char physdev1[MAXPATHLEN];
998*7c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
999*7c478bd9Sstevel@tonic-gate 
1000*7c478bd9Sstevel@tonic-gate 	logdmsg(("compare_controller: rootdir = %s, dev1 = %s, dev2 = %s\n",
1001*7c478bd9Sstevel@tonic-gate 	    rootdir, dev1, dev2));
1002*7c478bd9Sstevel@tonic-gate 
1003*7c478bd9Sstevel@tonic-gate 	if (strncmp(dev1, SLASH_DEV_SLASH, sizeof (SLASH_DEV_SLASH) - 1)
1004*7c478bd9Sstevel@tonic-gate 	    == 0) {
1005*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, MAXPATHLEN, "%s%s", rootdir, dev1);
1006*7c478bd9Sstevel@tonic-gate 		if ((linksize = readlink(buf, physdev1, MAXPATHLEN)) > 0 &&
1007*7c478bd9Sstevel@tonic-gate 		    linksize < (MAXPATHLEN - 1)) {
1008*7c478bd9Sstevel@tonic-gate 			physdev1[linksize] = '\0';
1009*7c478bd9Sstevel@tonic-gate 			logdmsg(("compare_controller: physdev1 = %s\n",
1010*7c478bd9Sstevel@tonic-gate 			    physdev1));
1011*7c478bd9Sstevel@tonic-gate 		} else
1012*7c478bd9Sstevel@tonic-gate 			return (-1);
1013*7c478bd9Sstevel@tonic-gate 	} else
1014*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(physdev1, dev1, MAXPATHLEN);
1015*7c478bd9Sstevel@tonic-gate 
1016*7c478bd9Sstevel@tonic-gate 	if ((p1 = strstr(physdev1, SLASH_DEVICES)) == NULL)
1017*7c478bd9Sstevel@tonic-gate 		return (-1);
1018*7c478bd9Sstevel@tonic-gate 
1019*7c478bd9Sstevel@tonic-gate 	p1 += sizeof (SLASH_DEVICES) - 1;
1020*7c478bd9Sstevel@tonic-gate 	/* strip the device portion */
1021*7c478bd9Sstevel@tonic-gate 	if ((p = strrchr(p1, '/')) == NULL)
1022*7c478bd9Sstevel@tonic-gate 		return (-1);
1023*7c478bd9Sstevel@tonic-gate 	*p = '\0';
1024*7c478bd9Sstevel@tonic-gate 
1025*7c478bd9Sstevel@tonic-gate 	if ((p = strrchr(dev2, '/')) == NULL)
1026*7c478bd9Sstevel@tonic-gate 		return (-1);
1027*7c478bd9Sstevel@tonic-gate 	*p = '\0';
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate 	logdmsg(("compare_controller: path1 = %s, path2 = %s\n",
1030*7c478bd9Sstevel@tonic-gate 	    p1, dev2));
1031*7c478bd9Sstevel@tonic-gate 	if (strcmp(p1, dev2) == 0) {
1032*7c478bd9Sstevel@tonic-gate 		*p = '/';
1033*7c478bd9Sstevel@tonic-gate 		return (0);
1034*7c478bd9Sstevel@tonic-gate 	} else {
1035*7c478bd9Sstevel@tonic-gate 		*p = '/';
1036*7c478bd9Sstevel@tonic-gate 		return (1);
1037*7c478bd9Sstevel@tonic-gate 	}
1038*7c478bd9Sstevel@tonic-gate }
1039*7c478bd9Sstevel@tonic-gate 
1040*7c478bd9Sstevel@tonic-gate /*
1041*7c478bd9Sstevel@tonic-gate  * Check if the specified device path is on the root controller.
1042*7c478bd9Sstevel@tonic-gate  *
1043*7c478bd9Sstevel@tonic-gate  * rootdir	root directory of the target environment
1044*7c478bd9Sstevel@tonic-gate  * path		/devices name of a device without the /devices prefix
1045*7c478bd9Sstevel@tonic-gate  *
1046*7c478bd9Sstevel@tonic-gate  * Returns
1047*7c478bd9Sstevel@tonic-gate  *	1	if the path is on the root controller
1048*7c478bd9Sstevel@tonic-gate  *	0	if the path is not on the root controller
1049*7c478bd9Sstevel@tonic-gate  *	-1	if an error occurs
1050*7c478bd9Sstevel@tonic-gate  */
1051*7c478bd9Sstevel@tonic-gate static int
1052*7c478bd9Sstevel@tonic-gate is_root_controller(char *rootdir, char *path)
1053*7c478bd9Sstevel@tonic-gate {
1054*7c478bd9Sstevel@tonic-gate 	FILE *fp;
1055*7c478bd9Sstevel@tonic-gate 	char *tmpfile;
1056*7c478bd9Sstevel@tonic-gate 	int rv = -1;
1057*7c478bd9Sstevel@tonic-gate 	struct vfstab vfsent;
1058*7c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
1059*7c478bd9Sstevel@tonic-gate 	char ctd[MAXNAMELEN + 1];
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate 	logdmsg(("is_root_controller: rootdir = %s, path = %s\n", rootdir,
1062*7c478bd9Sstevel@tonic-gate 	    path));
1063*7c478bd9Sstevel@tonic-gate 
1064*7c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, MAXPATHLEN, "%s%s", rootdir, VFSTAB);
1065*7c478bd9Sstevel@tonic-gate 
1066*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(buf, "r")) == NULL) {
1067*7c478bd9Sstevel@tonic-gate 		logdmsg(("is_root_controller: failed to open %s: %s\n",
1068*7c478bd9Sstevel@tonic-gate 		    buf, strerror(errno)));
1069*7c478bd9Sstevel@tonic-gate 		return (-1);
1070*7c478bd9Sstevel@tonic-gate 	}
1071*7c478bd9Sstevel@tonic-gate 
1072*7c478bd9Sstevel@tonic-gate 	if (getvfsfile(fp, &vfsent, "/") != 0) {
1073*7c478bd9Sstevel@tonic-gate 		logdmsg(("is_root_controller: getvfsfile: failed to read "
1074*7c478bd9Sstevel@tonic-gate 		    "vfstab entry for mount point \"/\": %s\n",
1075*7c478bd9Sstevel@tonic-gate 		    strerror(errno)));
1076*7c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
1077*7c478bd9Sstevel@tonic-gate 		return (-1);
1078*7c478bd9Sstevel@tonic-gate 	}
1079*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
1080*7c478bd9Sstevel@tonic-gate 
1081*7c478bd9Sstevel@tonic-gate 	/* check if the root is an svm metadisk */
1082*7c478bd9Sstevel@tonic-gate 	if (strncmp(vfsent.vfs_special, META_DEV, sizeof (META_DEV) - 1) != 0) {
1083*7c478bd9Sstevel@tonic-gate 		if (compare_controller(rootdir, vfsent.vfs_special, path) == 0)
1084*7c478bd9Sstevel@tonic-gate 			return (1);
1085*7c478bd9Sstevel@tonic-gate 		else
1086*7c478bd9Sstevel@tonic-gate 			return (0);
1087*7c478bd9Sstevel@tonic-gate 	}
1088*7c478bd9Sstevel@tonic-gate 
1089*7c478bd9Sstevel@tonic-gate 	/* Don't use /var/run as it is not mounted in miniroot */
1090*7c478bd9Sstevel@tonic-gate 	if ((tmpfile = tempnam("/tmp", "diirc")) == NULL) {
1091*7c478bd9Sstevel@tonic-gate 		logdmsg(("is_root_controller: tempnam: failed: %s\n",
1092*7c478bd9Sstevel@tonic-gate 		    strerror(errno)));
1093*7c478bd9Sstevel@tonic-gate 		return (-1);
1094*7c478bd9Sstevel@tonic-gate 	}
1095*7c478bd9Sstevel@tonic-gate 
1096*7c478bd9Sstevel@tonic-gate 	/* get metadisk components using metastat command */
1097*7c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, MAXPATHLEN,
1098*7c478bd9Sstevel@tonic-gate 	    "/usr/sbin/metastat -p %s 2>/dev/null | "
1099*7c478bd9Sstevel@tonic-gate 	    "/usr/bin/grep ' 1 1 ' | "
1100*7c478bd9Sstevel@tonic-gate 	    "/usr/bin/sed -e 's/^.* 1 1 //' | "
1101*7c478bd9Sstevel@tonic-gate 	    "/usr/bin/cut -f1 -d ' ' > %s",
1102*7c478bd9Sstevel@tonic-gate 	    vfsent.vfs_special + sizeof (META_DEV) - 1, tmpfile);
1103*7c478bd9Sstevel@tonic-gate 
1104*7c478bd9Sstevel@tonic-gate 	logdmsg(("is_root_controller: command = %s\n", buf));
1105*7c478bd9Sstevel@tonic-gate 	fp = NULL;
1106*7c478bd9Sstevel@tonic-gate 	if (system(buf) == 0 && (fp = fopen(tmpfile, "r")) != NULL) {
1107*7c478bd9Sstevel@tonic-gate 		while (fscanf(fp, "%" VAL2STR(MAXNAMELEN) "s", ctd) == 1) {
1108*7c478bd9Sstevel@tonic-gate 			(void) snprintf(buf, MAXPATHLEN, "/dev/dsk/%s", ctd);
1109*7c478bd9Sstevel@tonic-gate 			if (compare_controller(rootdir, buf, path) == 0) {
1110*7c478bd9Sstevel@tonic-gate 				rv = 1;
1111*7c478bd9Sstevel@tonic-gate 				goto out;
1112*7c478bd9Sstevel@tonic-gate 			}
1113*7c478bd9Sstevel@tonic-gate 		}
1114*7c478bd9Sstevel@tonic-gate 		rv = 0;
1115*7c478bd9Sstevel@tonic-gate 	}
1116*7c478bd9Sstevel@tonic-gate 
1117*7c478bd9Sstevel@tonic-gate out:
1118*7c478bd9Sstevel@tonic-gate 	if (fp)
1119*7c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
1120*7c478bd9Sstevel@tonic-gate 	(void) unlink(tmpfile);
1121*7c478bd9Sstevel@tonic-gate 	free(tmpfile);
1122*7c478bd9Sstevel@tonic-gate 	return (rv);
1123*7c478bd9Sstevel@tonic-gate }
1124*7c478bd9Sstevel@tonic-gate 
1125*7c478bd9Sstevel@tonic-gate static int
1126*7c478bd9Sstevel@tonic-gate file_exists(char *rootdir, char *path)
1127*7c478bd9Sstevel@tonic-gate {
1128*7c478bd9Sstevel@tonic-gate 	struct stat stbuf;
1129*7c478bd9Sstevel@tonic-gate 	char fullpath[MAXPATHLEN];
1130*7c478bd9Sstevel@tonic-gate 	int x;
1131*7c478bd9Sstevel@tonic-gate 
1132*7c478bd9Sstevel@tonic-gate 	(void) snprintf(fullpath, MAXPATHLEN, "%s%s", rootdir, path);
1133*7c478bd9Sstevel@tonic-gate 
1134*7c478bd9Sstevel@tonic-gate 	x = stat(fullpath, &stbuf);
1135*7c478bd9Sstevel@tonic-gate 	logdmsg(("file_exists: %s: %s\n", fullpath, (x == 0) ? "yes" : "no"));
1136*7c478bd9Sstevel@tonic-gate 	if (x == 0)
1137*7c478bd9Sstevel@tonic-gate 		return (1);
1138*7c478bd9Sstevel@tonic-gate 	else
1139*7c478bd9Sstevel@tonic-gate 		return (0);
1140*7c478bd9Sstevel@tonic-gate }
1141*7c478bd9Sstevel@tonic-gate 
1142*7c478bd9Sstevel@tonic-gate /*
1143*7c478bd9Sstevel@tonic-gate  * Check if mpxio is enabled or disabled on the specified device path.
1144*7c478bd9Sstevel@tonic-gate  * Looks through the .conf files to determine the mpxio setting.
1145*7c478bd9Sstevel@tonic-gate  *
1146*7c478bd9Sstevel@tonic-gate  * rootdir	root directory of the target environment
1147*7c478bd9Sstevel@tonic-gate  * path		/devices name of a device without the /devices prefix and
1148*7c478bd9Sstevel@tonic-gate  *		minor name component.
1149*7c478bd9Sstevel@tonic-gate  *
1150*7c478bd9Sstevel@tonic-gate  * Returns
1151*7c478bd9Sstevel@tonic-gate  *	1	if mpxio is disabled
1152*7c478bd9Sstevel@tonic-gate  *	0	if mpxio is enabled
1153*7c478bd9Sstevel@tonic-gate  *	-1	if an error occurs
1154*7c478bd9Sstevel@tonic-gate  */
1155*7c478bd9Sstevel@tonic-gate static int
1156*7c478bd9Sstevel@tonic-gate is_mpxio_disabled(char *rootdir, char *path)
1157*7c478bd9Sstevel@tonic-gate {
1158*7c478bd9Sstevel@tonic-gate 	int mpxio_disable;
1159*7c478bd9Sstevel@tonic-gate 	char *p;
1160*7c478bd9Sstevel@tonic-gate 	int check_root_controller;
1161*7c478bd9Sstevel@tonic-gate 
1162*7c478bd9Sstevel@tonic-gate 	logdmsg(("is_mpxio_disabled: rootdir = %s, path = %s\n",
1163*7c478bd9Sstevel@tonic-gate 	    rootdir, path));
1164*7c478bd9Sstevel@tonic-gate 
1165*7c478bd9Sstevel@tonic-gate 	if (file_exists(rootdir, SCSI_VHCI_CONF) == 0) {
1166*7c478bd9Sstevel@tonic-gate 		/*
1167*7c478bd9Sstevel@tonic-gate 		 * scsi_vhci.conf doesn't exist:
1168*7c478bd9Sstevel@tonic-gate 		 *  if upgrading from a pre solaris 9 release. or
1169*7c478bd9Sstevel@tonic-gate 		 *  if this function is called during fresh or flash install
1170*7c478bd9Sstevel@tonic-gate 		 *  prior to installing scsi_vhci.conf file.
1171*7c478bd9Sstevel@tonic-gate 		 */
1172*7c478bd9Sstevel@tonic-gate 		if (file_exists(rootdir, "/kernel/drv"))
1173*7c478bd9Sstevel@tonic-gate 			/* upgrading from pre solaris 9 */
1174*7c478bd9Sstevel@tonic-gate 			return (1);
1175*7c478bd9Sstevel@tonic-gate 		else
1176*7c478bd9Sstevel@tonic-gate 			/* fresh or flash install */
1177*7c478bd9Sstevel@tonic-gate 			return (0);
1178*7c478bd9Sstevel@tonic-gate 	}
1179*7c478bd9Sstevel@tonic-gate 
1180*7c478bd9Sstevel@tonic-gate 	mpxio_disable = lookup_in_conf_file(rootdir, SCSI_VHCI_CONF, NULL);
1181*7c478bd9Sstevel@tonic-gate 
1182*7c478bd9Sstevel@tonic-gate 	/*
1183*7c478bd9Sstevel@tonic-gate 	 * scsi_vhci.conf contains mpxio-disable property only in s9 and
1184*7c478bd9Sstevel@tonic-gate 	 * s8+sfkpatch. This property is no longer present from s10 onwards.
1185*7c478bd9Sstevel@tonic-gate 	 */
1186*7c478bd9Sstevel@tonic-gate 	if (mpxio_disable == 1) {
1187*7c478bd9Sstevel@tonic-gate 		/* upgrading from s8 or s9 with mpxio globally disabled */
1188*7c478bd9Sstevel@tonic-gate 		return (1);
1189*7c478bd9Sstevel@tonic-gate 	} else if (mpxio_disable == 0) {
1190*7c478bd9Sstevel@tonic-gate 		/* upgrading from s8 or s9 with mpxio globally enabled */
1191*7c478bd9Sstevel@tonic-gate 		check_root_controller = 1;
1192*7c478bd9Sstevel@tonic-gate 	} else {
1193*7c478bd9Sstevel@tonic-gate 		/*
1194*7c478bd9Sstevel@tonic-gate 		 * We are looking at the s10 version of the file. This is
1195*7c478bd9Sstevel@tonic-gate 		 * the case if this function is called after installing the
1196*7c478bd9Sstevel@tonic-gate 		 * new scsi_vhci.conf file.
1197*7c478bd9Sstevel@tonic-gate 		 */
1198*7c478bd9Sstevel@tonic-gate 		check_root_controller = 0;
1199*7c478bd9Sstevel@tonic-gate 	}
1200*7c478bd9Sstevel@tonic-gate 
1201*7c478bd9Sstevel@tonic-gate 	if ((mpxio_disable = lookup_in_conf_file(rootdir, FP_CONF, path))
1202*7c478bd9Sstevel@tonic-gate 	    != -1)
1203*7c478bd9Sstevel@tonic-gate 		return (mpxio_disable);
1204*7c478bd9Sstevel@tonic-gate 
1205*7c478bd9Sstevel@tonic-gate 	if ((p = strrchr(path, '/')) == NULL)
1206*7c478bd9Sstevel@tonic-gate 		return (-1);
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate 	*p = '\0';
1209*7c478bd9Sstevel@tonic-gate 	if ((mpxio_disable = lookup_in_conf_file(rootdir, QLC_CONF, path))
1210*7c478bd9Sstevel@tonic-gate 	    != -1) {
1211*7c478bd9Sstevel@tonic-gate 		*p = '/';
1212*7c478bd9Sstevel@tonic-gate 		return (mpxio_disable);
1213*7c478bd9Sstevel@tonic-gate 	}
1214*7c478bd9Sstevel@tonic-gate 	*p = '/';
1215*7c478bd9Sstevel@tonic-gate 
1216*7c478bd9Sstevel@tonic-gate 	/*
1217*7c478bd9Sstevel@tonic-gate 	 * mpxio-disable setting is not found in the .conf files.
1218*7c478bd9Sstevel@tonic-gate 	 * The default is to enable mpxio, except if the path is on the root
1219*7c478bd9Sstevel@tonic-gate 	 * controller.
1220*7c478bd9Sstevel@tonic-gate 	 *
1221*7c478bd9Sstevel@tonic-gate 	 * In s8 and s9 mpxio is not supported on the root controller.
1222*7c478bd9Sstevel@tonic-gate 	 * NWS supplies a patch to enable root controller support in s8 and s9.
1223*7c478bd9Sstevel@tonic-gate 	 * If the system had the patch installed, the fp.conf file would have
1224*7c478bd9Sstevel@tonic-gate 	 * explicit "mpxio-disable=no" for the root controller. So we would
1225*7c478bd9Sstevel@tonic-gate 	 * have found the mpxio-disable setting when we looked up this property
1226*7c478bd9Sstevel@tonic-gate 	 * in the fp.conf file.
1227*7c478bd9Sstevel@tonic-gate 	 */
1228*7c478bd9Sstevel@tonic-gate 	if (check_root_controller) {
1229*7c478bd9Sstevel@tonic-gate 		mpxio_disable = is_root_controller(rootdir, path);
1230*7c478bd9Sstevel@tonic-gate 		logdmsg(("is_mpxio_disabled: is_root_controller returned %d\n",
1231*7c478bd9Sstevel@tonic-gate 		    mpxio_disable));
1232*7c478bd9Sstevel@tonic-gate 	} else
1233*7c478bd9Sstevel@tonic-gate 		mpxio_disable = 0;
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate 	return (mpxio_disable);
1236*7c478bd9Sstevel@tonic-gate }
1237*7c478bd9Sstevel@tonic-gate 
1238*7c478bd9Sstevel@tonic-gate static int
1239*7c478bd9Sstevel@tonic-gate vhci_ctl(sv_iocdata_t *iocp, int cmd)
1240*7c478bd9Sstevel@tonic-gate {
1241*7c478bd9Sstevel@tonic-gate 	int fd, rv;
1242*7c478bd9Sstevel@tonic-gate 
1243*7c478bd9Sstevel@tonic-gate 	if ((fd = open(VHCI_CTL_NODE, O_RDWR)) < 0)
1244*7c478bd9Sstevel@tonic-gate 		return (-1);
1245*7c478bd9Sstevel@tonic-gate 	rv = ioctl(fd, cmd, iocp);
1246*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
1247*7c478bd9Sstevel@tonic-gate 	return (rv);
1248*7c478bd9Sstevel@tonic-gate }
1249*7c478bd9Sstevel@tonic-gate 
1250*7c478bd9Sstevel@tonic-gate /*
1251*7c478bd9Sstevel@tonic-gate  * Convert a phci client name to vhci client name.
1252*7c478bd9Sstevel@tonic-gate  *
1253*7c478bd9Sstevel@tonic-gate  * phci_name	phci client /devices name without the /devices prefix and
1254*7c478bd9Sstevel@tonic-gate  *		minor name component.
1255*7c478bd9Sstevel@tonic-gate  *		ex: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
1256*7c478bd9Sstevel@tonic-gate  *
1257*7c478bd9Sstevel@tonic-gate  * Returns 	on success, vhci client name is returned. The memory for
1258*7c478bd9Sstevel@tonic-gate  *		the vhci name is allocated by this function and the caller
1259*7c478bd9Sstevel@tonic-gate  * 		must free it.
1260*7c478bd9Sstevel@tonic-gate  *		on failure, NULL is returned.
1261*7c478bd9Sstevel@tonic-gate  */
1262*7c478bd9Sstevel@tonic-gate static char *
1263*7c478bd9Sstevel@tonic-gate phci_to_vhci(char *phci_name)
1264*7c478bd9Sstevel@tonic-gate {
1265*7c478bd9Sstevel@tonic-gate 	sv_iocdata_t ioc;
1266*7c478bd9Sstevel@tonic-gate 	char *slash, *addr, *retp;
1267*7c478bd9Sstevel@tonic-gate 	char vhci_name_buf[MAXPATHLEN];
1268*7c478bd9Sstevel@tonic-gate 	char phci_name_buf[MAXPATHLEN];
1269*7c478bd9Sstevel@tonic-gate 	char addr_buf[MAXNAMELEN];
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate 	logdmsg(("phci_to_vhci: pchi_name =  %s\n", phci_name));
1272*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(phci_name_buf, phci_name, MAXPATHLEN);
1273*7c478bd9Sstevel@tonic-gate 
1274*7c478bd9Sstevel@tonic-gate 	if ((slash = strrchr(phci_name_buf, '/')) == NULL ||
1275*7c478bd9Sstevel@tonic-gate 	    (addr = strchr(slash, '@')) == NULL)
1276*7c478bd9Sstevel@tonic-gate 		return (NULL);
1277*7c478bd9Sstevel@tonic-gate 
1278*7c478bd9Sstevel@tonic-gate 	*slash = '\0';
1279*7c478bd9Sstevel@tonic-gate 	addr++;
1280*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(addr_buf, addr, MAXNAMELEN);
1281*7c478bd9Sstevel@tonic-gate 
1282*7c478bd9Sstevel@tonic-gate 	bzero(&ioc, sizeof (sv_iocdata_t));
1283*7c478bd9Sstevel@tonic-gate 	ioc.client = vhci_name_buf;
1284*7c478bd9Sstevel@tonic-gate 	ioc.phci = phci_name_buf;
1285*7c478bd9Sstevel@tonic-gate 	ioc.addr = addr_buf;
1286*7c478bd9Sstevel@tonic-gate 	if (vhci_ctl(&ioc, SCSI_VHCI_GET_CLIENT_NAME) != 0) {
1287*7c478bd9Sstevel@tonic-gate 		logdmsg(("phci_to_vhci: vhci_ctl failed: %s\n",
1288*7c478bd9Sstevel@tonic-gate 		    strerror(errno)));
1289*7c478bd9Sstevel@tonic-gate 		return (NULL);
1290*7c478bd9Sstevel@tonic-gate 	}
1291*7c478bd9Sstevel@tonic-gate 
1292*7c478bd9Sstevel@tonic-gate 	retp = strdup(vhci_name_buf);
1293*7c478bd9Sstevel@tonic-gate 	logdmsg(("phci_to_vhci: vhci name = %s\n", STRVAL(retp)));
1294*7c478bd9Sstevel@tonic-gate 	return (retp);
1295*7c478bd9Sstevel@tonic-gate }
1296*7c478bd9Sstevel@tonic-gate 
1297*7c478bd9Sstevel@tonic-gate static int
1298*7c478bd9Sstevel@tonic-gate add_to_phci_list(char **phci_list, sv_path_info_t *pi, int npaths, int state,
1299*7c478bd9Sstevel@tonic-gate     char *node_name)
1300*7c478bd9Sstevel@tonic-gate {
1301*7c478bd9Sstevel@tonic-gate 	int rv = 0;
1302*7c478bd9Sstevel@tonic-gate 	char name[MAXPATHLEN];
1303*7c478bd9Sstevel@tonic-gate 
1304*7c478bd9Sstevel@tonic-gate 	while (npaths--) {
1305*7c478bd9Sstevel@tonic-gate 		if (state == pi->ret_state) {
1306*7c478bd9Sstevel@tonic-gate 			(void) snprintf(name, MAXPATHLEN, "%s/%s@w%s",
1307*7c478bd9Sstevel@tonic-gate 			    pi->device.ret_phci, node_name, pi->ret_addr);
1308*7c478bd9Sstevel@tonic-gate 			if ((*phci_list = strdup(name)) == NULL)
1309*7c478bd9Sstevel@tonic-gate 				return (-1);
1310*7c478bd9Sstevel@tonic-gate 			phci_list++;
1311*7c478bd9Sstevel@tonic-gate 			rv++;
1312*7c478bd9Sstevel@tonic-gate 		}
1313*7c478bd9Sstevel@tonic-gate 		pi++;
1314*7c478bd9Sstevel@tonic-gate 	}
1315*7c478bd9Sstevel@tonic-gate 
1316*7c478bd9Sstevel@tonic-gate 	return (rv);
1317*7c478bd9Sstevel@tonic-gate }
1318*7c478bd9Sstevel@tonic-gate 
1319*7c478bd9Sstevel@tonic-gate static void
1320*7c478bd9Sstevel@tonic-gate free_pathlist(char **pathlist)
1321*7c478bd9Sstevel@tonic-gate {
1322*7c478bd9Sstevel@tonic-gate 	char **p;
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 	if (pathlist != NULL) {
1325*7c478bd9Sstevel@tonic-gate 		for (p = pathlist; *p != NULL; p++)
1326*7c478bd9Sstevel@tonic-gate 			free(*p);
1327*7c478bd9Sstevel@tonic-gate 		free(pathlist);
1328*7c478bd9Sstevel@tonic-gate 	}
1329*7c478bd9Sstevel@tonic-gate }
1330*7c478bd9Sstevel@tonic-gate 
1331*7c478bd9Sstevel@tonic-gate 
1332*7c478bd9Sstevel@tonic-gate /*
1333*7c478bd9Sstevel@tonic-gate  * Convert a vhci client name to phci client names.
1334*7c478bd9Sstevel@tonic-gate  *
1335*7c478bd9Sstevel@tonic-gate  * vhci_name	vhci client /devices name without the /devices prefix and
1336*7c478bd9Sstevel@tonic-gate  *		minor name component.
1337*7c478bd9Sstevel@tonic-gate  * num_paths	On return, *num_paths is set to the number paths in the
1338*7c478bd9Sstevel@tonic-gate  *		returned path list.
1339*7c478bd9Sstevel@tonic-gate  *
1340*7c478bd9Sstevel@tonic-gate  * Returns 	NULL terminated path list containing phci client paths is
1341*7c478bd9Sstevel@tonic-gate  *		returned on success. The memory for the path list is
1342*7c478bd9Sstevel@tonic-gate  *		allocated by this function and the caller must free it by
1343*7c478bd9Sstevel@tonic-gate  *		calling free_pathlist().
1344*7c478bd9Sstevel@tonic-gate  *		NULL is returned on failure.
1345*7c478bd9Sstevel@tonic-gate  */
1346*7c478bd9Sstevel@tonic-gate static char **
1347*7c478bd9Sstevel@tonic-gate vhci_to_phci(char *vhci_name, int *num_paths)
1348*7c478bd9Sstevel@tonic-gate {
1349*7c478bd9Sstevel@tonic-gate 	sv_iocdata_t ioc;
1350*7c478bd9Sstevel@tonic-gate 	uint_t npaths;
1351*7c478bd9Sstevel@tonic-gate 	int n;
1352*7c478bd9Sstevel@tonic-gate 	char **phci_list = NULL;
1353*7c478bd9Sstevel@tonic-gate 	char *node_name, *at;
1354*7c478bd9Sstevel@tonic-gate 	char vhci_name_buf[MAXPATHLEN];
1355*7c478bd9Sstevel@tonic-gate 
1356*7c478bd9Sstevel@tonic-gate 	logdmsg(("vhci_to_phci: vchi_name =  %s\n", vhci_name));
1357*7c478bd9Sstevel@tonic-gate 
1358*7c478bd9Sstevel@tonic-gate 	*num_paths = 0;
1359*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(vhci_name_buf, vhci_name, MAXPATHLEN);
1360*7c478bd9Sstevel@tonic-gate 
1361*7c478bd9Sstevel@tonic-gate 	/* first get the number paths */
1362*7c478bd9Sstevel@tonic-gate 	bzero(&ioc, sizeof (sv_iocdata_t));
1363*7c478bd9Sstevel@tonic-gate 	ioc.client = vhci_name_buf;
1364*7c478bd9Sstevel@tonic-gate 	ioc.ret_elem = &npaths;
1365*7c478bd9Sstevel@tonic-gate 	if (vhci_ctl(&ioc, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO) != 0 ||
1366*7c478bd9Sstevel@tonic-gate 	    npaths == 0) {
1367*7c478bd9Sstevel@tonic-gate 		logdmsg(("vhci_to_phci: vhci_ctl failed to get npaths: %s\n",
1368*7c478bd9Sstevel@tonic-gate 		    strerror(errno)));
1369*7c478bd9Sstevel@tonic-gate 		return (NULL);
1370*7c478bd9Sstevel@tonic-gate 	}
1371*7c478bd9Sstevel@tonic-gate 
1372*7c478bd9Sstevel@tonic-gate 	/* now allocate memory for the path information and get all paths */
1373*7c478bd9Sstevel@tonic-gate 	bzero(&ioc, sizeof (sv_iocdata_t));
1374*7c478bd9Sstevel@tonic-gate 	ioc.client = vhci_name_buf;
1375*7c478bd9Sstevel@tonic-gate 	ioc.buf_elem = npaths;
1376*7c478bd9Sstevel@tonic-gate 	ioc.ret_elem = &npaths;
1377*7c478bd9Sstevel@tonic-gate 	if ((ioc.ret_buf = (sv_path_info_t *)calloc(npaths,
1378*7c478bd9Sstevel@tonic-gate 	    sizeof (sv_path_info_t))) == NULL)
1379*7c478bd9Sstevel@tonic-gate 		return (NULL);
1380*7c478bd9Sstevel@tonic-gate 	if (vhci_ctl(&ioc, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO) != 0 ||
1381*7c478bd9Sstevel@tonic-gate 	    npaths == 0) {
1382*7c478bd9Sstevel@tonic-gate 		logdmsg(("vhci_to_phci: vhci_ctl failed: %s\n",
1383*7c478bd9Sstevel@tonic-gate 		    strerror(errno)));
1384*7c478bd9Sstevel@tonic-gate 		goto out;
1385*7c478bd9Sstevel@tonic-gate 	}
1386*7c478bd9Sstevel@tonic-gate 
1387*7c478bd9Sstevel@tonic-gate 	if (ioc.buf_elem < npaths)
1388*7c478bd9Sstevel@tonic-gate 		npaths = ioc.buf_elem;
1389*7c478bd9Sstevel@tonic-gate 
1390*7c478bd9Sstevel@tonic-gate 	if ((node_name = strrchr(vhci_name_buf, '/')) == NULL ||
1391*7c478bd9Sstevel@tonic-gate 	    (at = strchr(node_name, '@')) == NULL)
1392*7c478bd9Sstevel@tonic-gate 		goto out;
1393*7c478bd9Sstevel@tonic-gate 
1394*7c478bd9Sstevel@tonic-gate 	node_name++;
1395*7c478bd9Sstevel@tonic-gate 	*at = '\0';
1396*7c478bd9Sstevel@tonic-gate 
1397*7c478bd9Sstevel@tonic-gate 	/* allocate one more (than npaths) for the terminating NULL pointer */
1398*7c478bd9Sstevel@tonic-gate 	if ((phci_list = calloc(npaths + 1, sizeof (char *))) == NULL)
1399*7c478bd9Sstevel@tonic-gate 		goto out;
1400*7c478bd9Sstevel@tonic-gate 
1401*7c478bd9Sstevel@tonic-gate 	/*
1402*7c478bd9Sstevel@tonic-gate 	 * add only online paths as non-online paths may not be accessible
1403*7c478bd9Sstevel@tonic-gate 	 * in the target environment.
1404*7c478bd9Sstevel@tonic-gate 	 */
1405*7c478bd9Sstevel@tonic-gate 	if ((n = add_to_phci_list(phci_list, ioc.ret_buf, npaths,
1406*7c478bd9Sstevel@tonic-gate 	    MDI_PATHINFO_STATE_ONLINE, node_name)) <= 0)
1407*7c478bd9Sstevel@tonic-gate 		goto out;
1408*7c478bd9Sstevel@tonic-gate 
1409*7c478bd9Sstevel@tonic-gate 	free(ioc.ret_buf);
1410*7c478bd9Sstevel@tonic-gate 	*num_paths = n;
1411*7c478bd9Sstevel@tonic-gate 
1412*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1413*7c478bd9Sstevel@tonic-gate 	logdmsg(("vhci_to_phci: phci list:\n"));
1414*7c478bd9Sstevel@tonic-gate 	log_pathlist(phci_list);
1415*7c478bd9Sstevel@tonic-gate #endif
1416*7c478bd9Sstevel@tonic-gate 	return (phci_list);
1417*7c478bd9Sstevel@tonic-gate 
1418*7c478bd9Sstevel@tonic-gate out:
1419*7c478bd9Sstevel@tonic-gate 	free(ioc.ret_buf);
1420*7c478bd9Sstevel@tonic-gate 	if (phci_list)
1421*7c478bd9Sstevel@tonic-gate 		free_pathlist(phci_list);
1422*7c478bd9Sstevel@tonic-gate 	return (NULL);
1423*7c478bd9Sstevel@tonic-gate }
1424*7c478bd9Sstevel@tonic-gate 
1425*7c478bd9Sstevel@tonic-gate /*
1426*7c478bd9Sstevel@tonic-gate  * build list of paths accessible from the target environment
1427*7c478bd9Sstevel@tonic-gate  */
1428*7c478bd9Sstevel@tonic-gate static int
1429*7c478bd9Sstevel@tonic-gate build_pathlist(char *rootdir, char *vhcipath, char **pathlist, int npaths)
1430*7c478bd9Sstevel@tonic-gate {
1431*7c478bd9Sstevel@tonic-gate 	int mpxio_disabled;
1432*7c478bd9Sstevel@tonic-gate 	int i, j;
1433*7c478bd9Sstevel@tonic-gate 	char *vpath = NULL;
1434*7c478bd9Sstevel@tonic-gate 
1435*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < npaths; i++) {
1436*7c478bd9Sstevel@tonic-gate 		mpxio_disabled = is_mpxio_disabled(rootdir, pathlist[i]);
1437*7c478bd9Sstevel@tonic-gate 		logdmsg(("build_pathlist: mpxio_disabled = %d "
1438*7c478bd9Sstevel@tonic-gate 		    "on path %s\n", mpxio_disabled, pathlist[i]));
1439*7c478bd9Sstevel@tonic-gate 		if (mpxio_disabled == -1)
1440*7c478bd9Sstevel@tonic-gate 			return (-1);
1441*7c478bd9Sstevel@tonic-gate 		if (mpxio_disabled == 0) {
1442*7c478bd9Sstevel@tonic-gate 			/*
1443*7c478bd9Sstevel@tonic-gate 			 * mpxio is enabled on this phci path.
1444*7c478bd9Sstevel@tonic-gate 			 * So use vhci path instead of phci path.
1445*7c478bd9Sstevel@tonic-gate 			 */
1446*7c478bd9Sstevel@tonic-gate 			if (vpath == NULL) {
1447*7c478bd9Sstevel@tonic-gate 				if ((vpath = strdup(vhcipath)) == NULL)
1448*7c478bd9Sstevel@tonic-gate 					return (-1);
1449*7c478bd9Sstevel@tonic-gate 				free(pathlist[i]);
1450*7c478bd9Sstevel@tonic-gate 				/* keep vhci path at beginning of the list */
1451*7c478bd9Sstevel@tonic-gate 				for (j = i; j > 0; j--)
1452*7c478bd9Sstevel@tonic-gate 					pathlist[j] = pathlist[j - 1];
1453*7c478bd9Sstevel@tonic-gate 				pathlist[0] = vpath;
1454*7c478bd9Sstevel@tonic-gate 			} else {
1455*7c478bd9Sstevel@tonic-gate 				free(pathlist[i]);
1456*7c478bd9Sstevel@tonic-gate 				npaths--;
1457*7c478bd9Sstevel@tonic-gate 				for (j = i; j < npaths; j++)
1458*7c478bd9Sstevel@tonic-gate 					pathlist[j] = pathlist[j + 1];
1459*7c478bd9Sstevel@tonic-gate 				pathlist[npaths] = NULL;
1460*7c478bd9Sstevel@tonic-gate 				/* compensate for i++ in the for loop */
1461*7c478bd9Sstevel@tonic-gate 				i--;
1462*7c478bd9Sstevel@tonic-gate 			}
1463*7c478bd9Sstevel@tonic-gate 		}
1464*7c478bd9Sstevel@tonic-gate 	}
1465*7c478bd9Sstevel@tonic-gate 
1466*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1467*7c478bd9Sstevel@tonic-gate 	logdmsg(("build_pathlist: returning npaths = %d, pathlist:\n", npaths));
1468*7c478bd9Sstevel@tonic-gate 	log_pathlist(pathlist);
1469*7c478bd9Sstevel@tonic-gate #endif
1470*7c478bd9Sstevel@tonic-gate 	return (npaths);
1471*7c478bd9Sstevel@tonic-gate }
1472*7c478bd9Sstevel@tonic-gate 
1473*7c478bd9Sstevel@tonic-gate /*
1474*7c478bd9Sstevel@tonic-gate  * Check if the specified device is refenced in the vfstab file.
1475*7c478bd9Sstevel@tonic-gate  * Return 1 if referenced, 0 if not.
1476*7c478bd9Sstevel@tonic-gate  *
1477*7c478bd9Sstevel@tonic-gate  * rootdir	root directory of the target environment
1478*7c478bd9Sstevel@tonic-gate  * nodepath	/devices path of a device in the target environment without
1479*7c478bd9Sstevel@tonic-gate  *		the /devices prefix and minor component.
1480*7c478bd9Sstevel@tonic-gate  */
1481*7c478bd9Sstevel@tonic-gate static int
1482*7c478bd9Sstevel@tonic-gate is_dev_in_vfstab(char *rootdir, char *nodepath)
1483*7c478bd9Sstevel@tonic-gate {
1484*7c478bd9Sstevel@tonic-gate 	FILE *fp;
1485*7c478bd9Sstevel@tonic-gate 	int linksize;
1486*7c478bd9Sstevel@tonic-gate 	struct vfstab vfsent;
1487*7c478bd9Sstevel@tonic-gate 	char *abspath, *minor;
1488*7c478bd9Sstevel@tonic-gate 	char physpath[MAXPATHLEN];
1489*7c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
1490*7c478bd9Sstevel@tonic-gate 
1491*7c478bd9Sstevel@tonic-gate 	logdmsg(("is_dev_in_vfstab: rootdir = %s, nodepath = %s\n",
1492*7c478bd9Sstevel@tonic-gate 	    rootdir, nodepath));
1493*7c478bd9Sstevel@tonic-gate 
1494*7c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%s%s", rootdir, VFSTAB);
1495*7c478bd9Sstevel@tonic-gate 
1496*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(buf, "r")) == NULL)
1497*7c478bd9Sstevel@tonic-gate 		return (0);
1498*7c478bd9Sstevel@tonic-gate 
1499*7c478bd9Sstevel@tonic-gate 	/*
1500*7c478bd9Sstevel@tonic-gate 	 * read device specials from vfstab and compare names at physical
1501*7c478bd9Sstevel@tonic-gate 	 * node path level.
1502*7c478bd9Sstevel@tonic-gate 	 */
1503*7c478bd9Sstevel@tonic-gate 	while (getvfsent(fp, &vfsent) == 0) {
1504*7c478bd9Sstevel@tonic-gate 		if (strncmp(vfsent.vfs_special, SLASH_DEV_SLASH,
1505*7c478bd9Sstevel@tonic-gate 		    sizeof (SLASH_DEV_SLASH) - 1) == 0) {
1506*7c478bd9Sstevel@tonic-gate 			(void) snprintf(buf, MAXPATHLEN, "%s%s",
1507*7c478bd9Sstevel@tonic-gate 			    rootdir, vfsent.vfs_special);
1508*7c478bd9Sstevel@tonic-gate 			if ((linksize = readlink(buf, physpath,
1509*7c478bd9Sstevel@tonic-gate 			    MAXPATHLEN)) > 0 && linksize < (MAXPATHLEN - 1)) {
1510*7c478bd9Sstevel@tonic-gate 				physpath[linksize] = '\0';
1511*7c478bd9Sstevel@tonic-gate 				if ((abspath = strstr(physpath,
1512*7c478bd9Sstevel@tonic-gate 				    SLASH_DEVICES_SLASH)) == NULL)
1513*7c478bd9Sstevel@tonic-gate 					continue;
1514*7c478bd9Sstevel@tonic-gate 			} else
1515*7c478bd9Sstevel@tonic-gate 				continue;
1516*7c478bd9Sstevel@tonic-gate 		} else if (strncmp(vfsent.vfs_special, SLASH_DEVICES_SLASH,
1517*7c478bd9Sstevel@tonic-gate 		    sizeof (SLASH_DEVICES_SLASH) - 1) == 0) {
1518*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(physpath, vfsent.vfs_special,
1519*7c478bd9Sstevel@tonic-gate 			    MAXPATHLEN);
1520*7c478bd9Sstevel@tonic-gate 			abspath = physpath;
1521*7c478bd9Sstevel@tonic-gate 		} else
1522*7c478bd9Sstevel@tonic-gate 			continue;
1523*7c478bd9Sstevel@tonic-gate 
1524*7c478bd9Sstevel@tonic-gate 		/* point to / after /devices */
1525*7c478bd9Sstevel@tonic-gate 		abspath += sizeof (SLASH_DEVICES_SLASH) - 2;
1526*7c478bd9Sstevel@tonic-gate 		/* strip minor component */
1527*7c478bd9Sstevel@tonic-gate 		if ((minor = strrchr(abspath, ':')) != NULL)
1528*7c478bd9Sstevel@tonic-gate 			*minor = '\0';
1529*7c478bd9Sstevel@tonic-gate 
1530*7c478bd9Sstevel@tonic-gate 		if (strcmp(nodepath, abspath) == 0) {
1531*7c478bd9Sstevel@tonic-gate 			(void) fclose(fp);
1532*7c478bd9Sstevel@tonic-gate 			logdmsg(("is_dev_in_vfstab: returning 1\n"));
1533*7c478bd9Sstevel@tonic-gate 			return (1);
1534*7c478bd9Sstevel@tonic-gate 		}
1535*7c478bd9Sstevel@tonic-gate 	}
1536*7c478bd9Sstevel@tonic-gate 
1537*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
1538*7c478bd9Sstevel@tonic-gate 	return (0);
1539*7c478bd9Sstevel@tonic-gate }
1540*7c478bd9Sstevel@tonic-gate 
1541*7c478bd9Sstevel@tonic-gate #endif /* __sparc */
1542*7c478bd9Sstevel@tonic-gate 
1543*7c478bd9Sstevel@tonic-gate static int
1544*7c478bd9Sstevel@tonic-gate devlink_callback(di_devlink_t devlink, void *argp)
1545*7c478bd9Sstevel@tonic-gate {
1546*7c478bd9Sstevel@tonic-gate 	const char *link;
1547*7c478bd9Sstevel@tonic-gate 
1548*7c478bd9Sstevel@tonic-gate 	if ((link = di_devlink_path(devlink)) != NULL)
1549*7c478bd9Sstevel@tonic-gate 		(void) strlcpy((char *)argp, link, MAXPATHLEN);
1550*7c478bd9Sstevel@tonic-gate 
1551*7c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
1552*7c478bd9Sstevel@tonic-gate }
1553*7c478bd9Sstevel@tonic-gate 
1554*7c478bd9Sstevel@tonic-gate /*
1555*7c478bd9Sstevel@tonic-gate  * Get the /dev name in the install environment corresponding to physpath.
1556*7c478bd9Sstevel@tonic-gate  *
1557*7c478bd9Sstevel@tonic-gate  * physpath	/devices path in the install environment without the /devices
1558*7c478bd9Sstevel@tonic-gate  * 		prefix.
1559*7c478bd9Sstevel@tonic-gate  * buf		caller supplied buffer where the /dev name is placed on return
1560*7c478bd9Sstevel@tonic-gate  * bufsz	length of the buffer
1561*7c478bd9Sstevel@tonic-gate  *
1562*7c478bd9Sstevel@tonic-gate  * Returns	strlen of the /dev name on success, -1 on failure.
1563*7c478bd9Sstevel@tonic-gate  */
1564*7c478bd9Sstevel@tonic-gate static int
1565*7c478bd9Sstevel@tonic-gate get_install_devlink(char *physpath, char *buf, size_t bufsz)
1566*7c478bd9Sstevel@tonic-gate {
1567*7c478bd9Sstevel@tonic-gate 	di_devlink_handle_t devlink_hdl;
1568*7c478bd9Sstevel@tonic-gate 	char devname[MAXPATHLEN];
1569*7c478bd9Sstevel@tonic-gate 
1570*7c478bd9Sstevel@tonic-gate 	logdmsg(("get_install_devlink: physpath = %s\n", physpath));
1571*7c478bd9Sstevel@tonic-gate 
1572*7c478bd9Sstevel@tonic-gate 	if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
1573*7c478bd9Sstevel@tonic-gate 		logdmsg(("get_install_devlink: di_devlink_init() failed: %s\n",
1574*7c478bd9Sstevel@tonic-gate 		    strerror(errno)));
1575*7c478bd9Sstevel@tonic-gate 		return (-1);
1576*7c478bd9Sstevel@tonic-gate 	}
1577*7c478bd9Sstevel@tonic-gate 
1578*7c478bd9Sstevel@tonic-gate 	devname[0] = '\0';
1579*7c478bd9Sstevel@tonic-gate 	if (di_devlink_walk(devlink_hdl, NULL, physpath, DI_PRIMARY_LINK,
1580*7c478bd9Sstevel@tonic-gate 	    devname, devlink_callback) != 0 || devname[0] == '\0') {
1581*7c478bd9Sstevel@tonic-gate 		logdmsg(("get_install_devlink: di_devlink_walk failed: %s\n",
1582*7c478bd9Sstevel@tonic-gate 		    strerror(errno)));
1583*7c478bd9Sstevel@tonic-gate 		(void) di_devlink_fini(&devlink_hdl);
1584*7c478bd9Sstevel@tonic-gate 		return (-1);
1585*7c478bd9Sstevel@tonic-gate 	}
1586*7c478bd9Sstevel@tonic-gate 
1587*7c478bd9Sstevel@tonic-gate 	(void) di_devlink_fini(&devlink_hdl);
1588*7c478bd9Sstevel@tonic-gate 
1589*7c478bd9Sstevel@tonic-gate 	logdmsg(("get_install_devlink: devlink = %s\n", devname));
1590*7c478bd9Sstevel@tonic-gate 	return (strlcpy(buf, devname, bufsz));
1591*7c478bd9Sstevel@tonic-gate }
1592*7c478bd9Sstevel@tonic-gate 
1593*7c478bd9Sstevel@tonic-gate /*
1594*7c478bd9Sstevel@tonic-gate  * Get the /dev name in the target environment corresponding to physpath.
1595*7c478bd9Sstevel@tonic-gate  *
1596*7c478bd9Sstevel@tonic-gate  * rootdir	root directory of the target environment
1597*7c478bd9Sstevel@tonic-gate  * physpath	/devices path in the target environment without the /devices
1598*7c478bd9Sstevel@tonic-gate  * 		prefix.
1599*7c478bd9Sstevel@tonic-gate  * buf		caller supplied buffer where the /dev name is placed on return
1600*7c478bd9Sstevel@tonic-gate  * bufsz	length of the buffer
1601*7c478bd9Sstevel@tonic-gate  *
1602*7c478bd9Sstevel@tonic-gate  * Returns	strlen of the /dev name on success, -1 on failure.
1603*7c478bd9Sstevel@tonic-gate  */
1604*7c478bd9Sstevel@tonic-gate static int
1605*7c478bd9Sstevel@tonic-gate get_target_devlink(char *rootdir, char *physpath, char *buf, size_t bufsz)
1606*7c478bd9Sstevel@tonic-gate {
1607*7c478bd9Sstevel@tonic-gate 	char *p;
1608*7c478bd9Sstevel@tonic-gate 	int linksize;
1609*7c478bd9Sstevel@tonic-gate 	DIR *dirp;
1610*7c478bd9Sstevel@tonic-gate 	struct dirent *direntry;
1611*7c478bd9Sstevel@tonic-gate 	char dirpath[MAXPATHLEN];
1612*7c478bd9Sstevel@tonic-gate 	char devname[MAXPATHLEN];
1613*7c478bd9Sstevel@tonic-gate 	char physdev[MAXPATHLEN];
1614*7c478bd9Sstevel@tonic-gate 
1615*7c478bd9Sstevel@tonic-gate 	logdmsg(("get_target_devlink: rootdir = %s, physpath = %s\n",
1616*7c478bd9Sstevel@tonic-gate 	    rootdir, physpath));
1617*7c478bd9Sstevel@tonic-gate 
1618*7c478bd9Sstevel@tonic-gate 	if ((p = strrchr(physpath, '/')) == NULL)
1619*7c478bd9Sstevel@tonic-gate 		return (-1);
1620*7c478bd9Sstevel@tonic-gate 
1621*7c478bd9Sstevel@tonic-gate 	if (strstr(p, ",raw") != NULL) {
1622*7c478bd9Sstevel@tonic-gate 		(void) snprintf(dirpath, MAXPATHLEN, "%s/dev/rdsk", rootdir);
1623*7c478bd9Sstevel@tonic-gate 	} else {
1624*7c478bd9Sstevel@tonic-gate 		(void) snprintf(dirpath, MAXPATHLEN, "%s/dev/dsk", rootdir);
1625*7c478bd9Sstevel@tonic-gate 	}
1626*7c478bd9Sstevel@tonic-gate 
1627*7c478bd9Sstevel@tonic-gate 	if ((dirp = opendir(dirpath)) == NULL)
1628*7c478bd9Sstevel@tonic-gate 		return (-1);
1629*7c478bd9Sstevel@tonic-gate 
1630*7c478bd9Sstevel@tonic-gate 	while ((direntry = readdir(dirp)) != NULL) {
1631*7c478bd9Sstevel@tonic-gate 		if (strcmp(direntry->d_name, ".") == 0 ||
1632*7c478bd9Sstevel@tonic-gate 		    strcmp(direntry->d_name, "..") == 0)
1633*7c478bd9Sstevel@tonic-gate 			continue;
1634*7c478bd9Sstevel@tonic-gate 
1635*7c478bd9Sstevel@tonic-gate 		(void) snprintf(devname, MAXPATHLEN, "%s/%s",
1636*7c478bd9Sstevel@tonic-gate 		    dirpath, direntry->d_name);
1637*7c478bd9Sstevel@tonic-gate 
1638*7c478bd9Sstevel@tonic-gate 		if ((linksize = readlink(devname, physdev, MAXPATHLEN)) > 0 &&
1639*7c478bd9Sstevel@tonic-gate 		    linksize < (MAXPATHLEN - 1)) {
1640*7c478bd9Sstevel@tonic-gate 			physdev[linksize] = '\0';
1641*7c478bd9Sstevel@tonic-gate 			if ((p = strstr(physdev, SLASH_DEVICES_SLASH)) !=
1642*7c478bd9Sstevel@tonic-gate 			    NULL && strcmp(p + sizeof (SLASH_DEVICES) - 1,
1643*7c478bd9Sstevel@tonic-gate 			    physpath) == 0) {
1644*7c478bd9Sstevel@tonic-gate 				(void) closedir(dirp);
1645*7c478bd9Sstevel@tonic-gate 				logdmsg(("get_target_devlink: devlink = %s\n",
1646*7c478bd9Sstevel@tonic-gate 				    devname + strlen(rootdir)));
1647*7c478bd9Sstevel@tonic-gate 				return (strlcpy(buf, devname + strlen(rootdir),
1648*7c478bd9Sstevel@tonic-gate 				    bufsz));
1649*7c478bd9Sstevel@tonic-gate 			}
1650*7c478bd9Sstevel@tonic-gate 		}
1651*7c478bd9Sstevel@tonic-gate 	}
1652*7c478bd9Sstevel@tonic-gate 
1653*7c478bd9Sstevel@tonic-gate 	(void) closedir(dirp);
1654*7c478bd9Sstevel@tonic-gate 	return (-1);
1655*7c478bd9Sstevel@tonic-gate }
1656*7c478bd9Sstevel@tonic-gate 
1657*7c478bd9Sstevel@tonic-gate /*
1658*7c478bd9Sstevel@tonic-gate  * Convert device name to physpath.
1659*7c478bd9Sstevel@tonic-gate  *
1660*7c478bd9Sstevel@tonic-gate  * rootdir	root directory
1661*7c478bd9Sstevel@tonic-gate  * devname	a /dev name or /devices name under rootdir
1662*7c478bd9Sstevel@tonic-gate  * physpath	caller supplied buffer where the /devices path will be placed
1663*7c478bd9Sstevel@tonic-gate  *		on return (without the /devices prefix).
1664*7c478bd9Sstevel@tonic-gate  * physpathlen	length of the physpath buffer
1665*7c478bd9Sstevel@tonic-gate  *
1666*7c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
1667*7c478bd9Sstevel@tonic-gate  */
1668*7c478bd9Sstevel@tonic-gate static int
1669*7c478bd9Sstevel@tonic-gate devname2physpath(char *rootdir, char *devname, char *physpath, int physpathlen)
1670*7c478bd9Sstevel@tonic-gate {
1671*7c478bd9Sstevel@tonic-gate 	int linksize;
1672*7c478bd9Sstevel@tonic-gate 	char *p;
1673*7c478bd9Sstevel@tonic-gate 	char devlink[MAXPATHLEN];
1674*7c478bd9Sstevel@tonic-gate 	char tmpphyspath[MAXPATHLEN];
1675*7c478bd9Sstevel@tonic-gate 
1676*7c478bd9Sstevel@tonic-gate 	logdmsg(("devname2physpath: rootdir = %s, devname = %s\n",
1677*7c478bd9Sstevel@tonic-gate 	    rootdir, devname));
1678*7c478bd9Sstevel@tonic-gate 
1679*7c478bd9Sstevel@tonic-gate 	if (strncmp(devname, SLASH_DEVICES_SLASH,
1680*7c478bd9Sstevel@tonic-gate 	    sizeof (SLASH_DEVICES_SLASH) - 1) != 0) {
1681*7c478bd9Sstevel@tonic-gate 		if (*rootdir == '\0')
1682*7c478bd9Sstevel@tonic-gate 			linksize = readlink(devname, tmpphyspath, MAXPATHLEN);
1683*7c478bd9Sstevel@tonic-gate 		else {
1684*7c478bd9Sstevel@tonic-gate 			(void) snprintf(devlink, MAXPATHLEN, "%s%s",
1685*7c478bd9Sstevel@tonic-gate 			    rootdir, devname);
1686*7c478bd9Sstevel@tonic-gate 			linksize = readlink(devlink, tmpphyspath, MAXPATHLEN);
1687*7c478bd9Sstevel@tonic-gate 		}
1688*7c478bd9Sstevel@tonic-gate 		if (linksize > 0 && linksize < (MAXPATHLEN - 1)) {
1689*7c478bd9Sstevel@tonic-gate 			tmpphyspath[linksize] = '\0';
1690*7c478bd9Sstevel@tonic-gate 			if ((p = strstr(tmpphyspath, SLASH_DEVICES_SLASH))
1691*7c478bd9Sstevel@tonic-gate 			    == NULL)
1692*7c478bd9Sstevel@tonic-gate 				return (-1);
1693*7c478bd9Sstevel@tonic-gate 		} else
1694*7c478bd9Sstevel@tonic-gate 			return (-1);
1695*7c478bd9Sstevel@tonic-gate 	} else
1696*7c478bd9Sstevel@tonic-gate 		p = devname;
1697*7c478bd9Sstevel@tonic-gate 
1698*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(physpath, p + sizeof (SLASH_DEVICES) - 1, physpathlen);
1699*7c478bd9Sstevel@tonic-gate 	logdmsg(("devname2physpath: physpath = %s\n", physpath));
1700*7c478bd9Sstevel@tonic-gate 	return (0);
1701*7c478bd9Sstevel@tonic-gate }
1702*7c478bd9Sstevel@tonic-gate 
1703*7c478bd9Sstevel@tonic-gate /*
1704*7c478bd9Sstevel@tonic-gate  * Map a device name (devname) from the target environment to the
1705*7c478bd9Sstevel@tonic-gate  * install environment.
1706*7c478bd9Sstevel@tonic-gate  *
1707*7c478bd9Sstevel@tonic-gate  * rootdir	root directory of the target environment
1708*7c478bd9Sstevel@tonic-gate  * devname	/dev or /devices name under the target environment
1709*7c478bd9Sstevel@tonic-gate  * buf		caller supplied buffer where the mapped /dev name is placed
1710*7c478bd9Sstevel@tonic-gate  *		on return
1711*7c478bd9Sstevel@tonic-gate  * bufsz	length of the buffer
1712*7c478bd9Sstevel@tonic-gate  *
1713*7c478bd9Sstevel@tonic-gate  * Returns	strlen of the mapped /dev name on success, -1 on failure.
1714*7c478bd9Sstevel@tonic-gate  */
1715*7c478bd9Sstevel@tonic-gate int
1716*7c478bd9Sstevel@tonic-gate devfs_target2install(const char *rootdir, const char *devname, char *buf,
1717*7c478bd9Sstevel@tonic-gate     size_t bufsz)
1718*7c478bd9Sstevel@tonic-gate {
1719*7c478bd9Sstevel@tonic-gate 	char physpath[MAXPATHLEN];
1720*7c478bd9Sstevel@tonic-gate 
1721*7c478bd9Sstevel@tonic-gate 	logdmsg(("devfs_target2install: rootdir = %s, devname = %s\n",
1722*7c478bd9Sstevel@tonic-gate 	    STRVAL(rootdir), STRVAL(devname)));
1723*7c478bd9Sstevel@tonic-gate 
1724*7c478bd9Sstevel@tonic-gate 	if (rootdir == NULL || devname == NULL || buf == NULL || bufsz == 0)
1725*7c478bd9Sstevel@tonic-gate 		return (-1);
1726*7c478bd9Sstevel@tonic-gate 
1727*7c478bd9Sstevel@tonic-gate 	if (strcmp(rootdir, "/") == 0)
1728*7c478bd9Sstevel@tonic-gate 		rootdir = "";
1729*7c478bd9Sstevel@tonic-gate 
1730*7c478bd9Sstevel@tonic-gate 	if (devname2physpath((char *)rootdir, (char *)devname, physpath,
1731*7c478bd9Sstevel@tonic-gate 	    MAXPATHLEN) != 0)
1732*7c478bd9Sstevel@tonic-gate 		return (-1);
1733*7c478bd9Sstevel@tonic-gate 
1734*7c478bd9Sstevel@tonic-gate #ifdef __sparc
1735*7c478bd9Sstevel@tonic-gate 	if (client_name_type(physpath) == CLIENT_TYPE_PHCI) {
1736*7c478bd9Sstevel@tonic-gate 		char *mapped_node_path, *minor;
1737*7c478bd9Sstevel@tonic-gate 		char minorbuf[MAXNAMELEN];
1738*7c478bd9Sstevel@tonic-gate 
1739*7c478bd9Sstevel@tonic-gate 		/* strip minor component if present */
1740*7c478bd9Sstevel@tonic-gate 		if ((minor = strrchr(physpath, ':')) != NULL) {
1741*7c478bd9Sstevel@tonic-gate 			*minor = '\0';
1742*7c478bd9Sstevel@tonic-gate 			minor++;
1743*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(minorbuf, minor, MAXNAMELEN);
1744*7c478bd9Sstevel@tonic-gate 		}
1745*7c478bd9Sstevel@tonic-gate 		if ((mapped_node_path = phci_to_vhci(physpath)) != NULL) {
1746*7c478bd9Sstevel@tonic-gate 			if (minor)
1747*7c478bd9Sstevel@tonic-gate 				(void) snprintf(physpath, MAXPATHLEN,
1748*7c478bd9Sstevel@tonic-gate 				    "%s:%s", mapped_node_path, minorbuf);
1749*7c478bd9Sstevel@tonic-gate 			else
1750*7c478bd9Sstevel@tonic-gate 				(void) strlcpy(physpath, mapped_node_path,
1751*7c478bd9Sstevel@tonic-gate 				    MAXPATHLEN);
1752*7c478bd9Sstevel@tonic-gate 			free(mapped_node_path);
1753*7c478bd9Sstevel@tonic-gate 			logdmsg(("devfs_target2install: mapped physpath: %s\n",
1754*7c478bd9Sstevel@tonic-gate 			    physpath));
1755*7c478bd9Sstevel@tonic-gate 
1756*7c478bd9Sstevel@tonic-gate 		} else if (minor)
1757*7c478bd9Sstevel@tonic-gate 			*(minor - 1) = ':';
1758*7c478bd9Sstevel@tonic-gate 	}
1759*7c478bd9Sstevel@tonic-gate #endif /* __sparc */
1760*7c478bd9Sstevel@tonic-gate 
1761*7c478bd9Sstevel@tonic-gate 	return (get_install_devlink(physpath, buf, bufsz));
1762*7c478bd9Sstevel@tonic-gate }
1763*7c478bd9Sstevel@tonic-gate 
1764*7c478bd9Sstevel@tonic-gate /*
1765*7c478bd9Sstevel@tonic-gate  * Map a device name (devname) from the install environment to the target
1766*7c478bd9Sstevel@tonic-gate  * environment.
1767*7c478bd9Sstevel@tonic-gate  *
1768*7c478bd9Sstevel@tonic-gate  * rootdir	root directory of the target environment
1769*7c478bd9Sstevel@tonic-gate  * devname	/dev or /devices name under the install environment
1770*7c478bd9Sstevel@tonic-gate  * buf		caller supplied buffer where the mapped /dev name is placed
1771*7c478bd9Sstevel@tonic-gate  *		on return
1772*7c478bd9Sstevel@tonic-gate  * bufsz	length of the buffer
1773*7c478bd9Sstevel@tonic-gate  *
1774*7c478bd9Sstevel@tonic-gate  * Returns	strlen of the mapped /dev name on success, -1 on failure.
1775*7c478bd9Sstevel@tonic-gate  */
1776*7c478bd9Sstevel@tonic-gate int
1777*7c478bd9Sstevel@tonic-gate devfs_install2target(const char *rootdir, const char *devname, char *buf,
1778*7c478bd9Sstevel@tonic-gate     size_t bufsz)
1779*7c478bd9Sstevel@tonic-gate {
1780*7c478bd9Sstevel@tonic-gate 	char physpath[MAXPATHLEN];
1781*7c478bd9Sstevel@tonic-gate 
1782*7c478bd9Sstevel@tonic-gate 	logdmsg(("devfs_install2target: rootdir = %s, devname = %s\n",
1783*7c478bd9Sstevel@tonic-gate 	    STRVAL(rootdir), STRVAL(devname)));
1784*7c478bd9Sstevel@tonic-gate 
1785*7c478bd9Sstevel@tonic-gate 	if (rootdir == NULL || devname == NULL || buf == NULL || bufsz == 0)
1786*7c478bd9Sstevel@tonic-gate 		return (-1);
1787*7c478bd9Sstevel@tonic-gate 
1788*7c478bd9Sstevel@tonic-gate 	if (strcmp(rootdir, "/") == 0)
1789*7c478bd9Sstevel@tonic-gate 		rootdir = "";
1790*7c478bd9Sstevel@tonic-gate 
1791*7c478bd9Sstevel@tonic-gate 	if (devname2physpath("", (char *)devname, physpath, MAXPATHLEN) != 0)
1792*7c478bd9Sstevel@tonic-gate 		return (-1);
1793*7c478bd9Sstevel@tonic-gate 
1794*7c478bd9Sstevel@tonic-gate #ifdef __sparc
1795*7c478bd9Sstevel@tonic-gate 	if (client_name_type(physpath) == CLIENT_TYPE_VHCI) {
1796*7c478bd9Sstevel@tonic-gate 		char **pathlist;
1797*7c478bd9Sstevel@tonic-gate 		int npaths, i, j;
1798*7c478bd9Sstevel@tonic-gate 		char *minor;
1799*7c478bd9Sstevel@tonic-gate 		char minorbuf[MAXNAMELEN];
1800*7c478bd9Sstevel@tonic-gate 
1801*7c478bd9Sstevel@tonic-gate 		/* strip minor component if present */
1802*7c478bd9Sstevel@tonic-gate 		if ((minor = strrchr(physpath, ':')) != NULL) {
1803*7c478bd9Sstevel@tonic-gate 			*minor = '\0';
1804*7c478bd9Sstevel@tonic-gate 			minor++;
1805*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(minorbuf, minor, MAXNAMELEN);
1806*7c478bd9Sstevel@tonic-gate 		}
1807*7c478bd9Sstevel@tonic-gate 
1808*7c478bd9Sstevel@tonic-gate 		if ((pathlist = vhci_to_phci(physpath, &npaths)) == NULL)
1809*7c478bd9Sstevel@tonic-gate 			return (-1);
1810*7c478bd9Sstevel@tonic-gate 
1811*7c478bd9Sstevel@tonic-gate 		if ((npaths = build_pathlist((char *)rootdir, physpath,
1812*7c478bd9Sstevel@tonic-gate 		    pathlist, npaths)) <= 0) {
1813*7c478bd9Sstevel@tonic-gate 			free_pathlist(pathlist);
1814*7c478bd9Sstevel@tonic-gate 			return (-1);
1815*7c478bd9Sstevel@tonic-gate 		}
1816*7c478bd9Sstevel@tonic-gate 
1817*7c478bd9Sstevel@tonic-gate 		/*
1818*7c478bd9Sstevel@tonic-gate 		 * in case of more than one path, try to use the path
1819*7c478bd9Sstevel@tonic-gate 		 * referenced in the vfstab file, otherwise use the first path.
1820*7c478bd9Sstevel@tonic-gate 		 */
1821*7c478bd9Sstevel@tonic-gate 		j = 0;
1822*7c478bd9Sstevel@tonic-gate 		if (npaths > 1) {
1823*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < npaths; i++) {
1824*7c478bd9Sstevel@tonic-gate 				if (is_dev_in_vfstab((char *)rootdir,
1825*7c478bd9Sstevel@tonic-gate 				    pathlist[i])) {
1826*7c478bd9Sstevel@tonic-gate 					j = i;
1827*7c478bd9Sstevel@tonic-gate 					break;
1828*7c478bd9Sstevel@tonic-gate 				}
1829*7c478bd9Sstevel@tonic-gate 			}
1830*7c478bd9Sstevel@tonic-gate 		}
1831*7c478bd9Sstevel@tonic-gate 
1832*7c478bd9Sstevel@tonic-gate 		if (minor)
1833*7c478bd9Sstevel@tonic-gate 			(void) snprintf(physpath, MAXPATHLEN,
1834*7c478bd9Sstevel@tonic-gate 			    "%s:%s", pathlist[j], minorbuf);
1835*7c478bd9Sstevel@tonic-gate 		else
1836*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(physpath, pathlist[j], MAXPATHLEN);
1837*7c478bd9Sstevel@tonic-gate 		free_pathlist(pathlist);
1838*7c478bd9Sstevel@tonic-gate 	}
1839*7c478bd9Sstevel@tonic-gate #endif /* __sparc */
1840*7c478bd9Sstevel@tonic-gate 
1841*7c478bd9Sstevel@tonic-gate 	return (get_target_devlink((char *)rootdir, physpath, buf, bufsz));
1842*7c478bd9Sstevel@tonic-gate }
1843*7c478bd9Sstevel@tonic-gate 
1844*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1845*7c478bd9Sstevel@tonic-gate 
1846*7c478bd9Sstevel@tonic-gate static void
1847*7c478bd9Sstevel@tonic-gate vlog_debug_msg(char *fmt, va_list ap)
1848*7c478bd9Sstevel@tonic-gate {
1849*7c478bd9Sstevel@tonic-gate 	time_t clock;
1850*7c478bd9Sstevel@tonic-gate 	struct tm t;
1851*7c478bd9Sstevel@tonic-gate 
1852*7c478bd9Sstevel@tonic-gate 	if (!devfsmap_debug)
1853*7c478bd9Sstevel@tonic-gate 		return;
1854*7c478bd9Sstevel@tonic-gate 
1855*7c478bd9Sstevel@tonic-gate 	if (logfp == NULL) {
1856*7c478bd9Sstevel@tonic-gate 		if (*devfsmap_logfile != '\0') {
1857*7c478bd9Sstevel@tonic-gate 			logfp = fopen(devfsmap_logfile, "a");
1858*7c478bd9Sstevel@tonic-gate 			if (logfp)
1859*7c478bd9Sstevel@tonic-gate 				(void) fprintf(logfp, "\nNew Log:\n");
1860*7c478bd9Sstevel@tonic-gate 		}
1861*7c478bd9Sstevel@tonic-gate 
1862*7c478bd9Sstevel@tonic-gate 		if (logfp == NULL)
1863*7c478bd9Sstevel@tonic-gate 			logfp = stdout;
1864*7c478bd9Sstevel@tonic-gate 	}
1865*7c478bd9Sstevel@tonic-gate 
1866*7c478bd9Sstevel@tonic-gate 	clock = time(NULL);
1867*7c478bd9Sstevel@tonic-gate 	(void) localtime_r(&clock, &t);
1868*7c478bd9Sstevel@tonic-gate 	(void) fprintf(logfp, "%02d:%02d:%02d ", t.tm_hour, t.tm_min,
1869*7c478bd9Sstevel@tonic-gate 	    t.tm_sec);
1870*7c478bd9Sstevel@tonic-gate 	(void) vfprintf(logfp, fmt, ap);
1871*7c478bd9Sstevel@tonic-gate 	(void) fflush(logfp);
1872*7c478bd9Sstevel@tonic-gate }
1873*7c478bd9Sstevel@tonic-gate 
1874*7c478bd9Sstevel@tonic-gate static void
1875*7c478bd9Sstevel@tonic-gate log_debug_msg(char *fmt, ...)
1876*7c478bd9Sstevel@tonic-gate {
1877*7c478bd9Sstevel@tonic-gate 	va_list ap;
1878*7c478bd9Sstevel@tonic-gate 
1879*7c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
1880*7c478bd9Sstevel@tonic-gate 	vlog_debug_msg(fmt, ap);
1881*7c478bd9Sstevel@tonic-gate 	va_end(ap);
1882*7c478bd9Sstevel@tonic-gate }
1883*7c478bd9Sstevel@tonic-gate 
1884*7c478bd9Sstevel@tonic-gate #ifdef __sparc
1885*7c478bd9Sstevel@tonic-gate 
1886*7c478bd9Sstevel@tonic-gate static char *
1887*7c478bd9Sstevel@tonic-gate mpxio_disable_string(int mpxio_disable)
1888*7c478bd9Sstevel@tonic-gate {
1889*7c478bd9Sstevel@tonic-gate 	if (mpxio_disable == 0)
1890*7c478bd9Sstevel@tonic-gate 		return ("no");
1891*7c478bd9Sstevel@tonic-gate 	else if (mpxio_disable == 1)
1892*7c478bd9Sstevel@tonic-gate 		return ("yes");
1893*7c478bd9Sstevel@tonic-gate 	else
1894*7c478bd9Sstevel@tonic-gate 		return ("not specified");
1895*7c478bd9Sstevel@tonic-gate }
1896*7c478bd9Sstevel@tonic-gate 
1897*7c478bd9Sstevel@tonic-gate static void
1898*7c478bd9Sstevel@tonic-gate log_confent_list(char *filename, struct conf_entry *confent_list,
1899*7c478bd9Sstevel@tonic-gate     int global_mpxio_disable)
1900*7c478bd9Sstevel@tonic-gate {
1901*7c478bd9Sstevel@tonic-gate 	struct conf_entry *confent;
1902*7c478bd9Sstevel@tonic-gate 
1903*7c478bd9Sstevel@tonic-gate 	log_debug_msg("log_confent_list: filename = %s:\n", filename);
1904*7c478bd9Sstevel@tonic-gate 	if (global_mpxio_disable != -1)
1905*7c478bd9Sstevel@tonic-gate 		log_debug_msg("\tdriver global mpxio_disable = \"%s\"\n\n",
1906*7c478bd9Sstevel@tonic-gate 		    mpxio_disable_string(global_mpxio_disable));
1907*7c478bd9Sstevel@tonic-gate 
1908*7c478bd9Sstevel@tonic-gate 	for (confent = confent_list; confent != NULL; confent = confent->next) {
1909*7c478bd9Sstevel@tonic-gate 		if (confent->name)
1910*7c478bd9Sstevel@tonic-gate 			log_debug_msg("\tname = %s\n", confent->name);
1911*7c478bd9Sstevel@tonic-gate 		if (confent->parent)
1912*7c478bd9Sstevel@tonic-gate 			log_debug_msg("\tparent = %s\n", confent->parent);
1913*7c478bd9Sstevel@tonic-gate 		if (confent->class)
1914*7c478bd9Sstevel@tonic-gate 			log_debug_msg("\tclass = %s\n", confent->class);
1915*7c478bd9Sstevel@tonic-gate 		if (confent->unit_address)
1916*7c478bd9Sstevel@tonic-gate 			log_debug_msg("\tunit_address = %s\n",
1917*7c478bd9Sstevel@tonic-gate 			    confent->unit_address);
1918*7c478bd9Sstevel@tonic-gate 		if (confent->port != -1)
1919*7c478bd9Sstevel@tonic-gate 			log_debug_msg("\tport = %d\n", confent->port);
1920*7c478bd9Sstevel@tonic-gate 		log_debug_msg("\tmpxio_disable = \"%s\"\n\n",
1921*7c478bd9Sstevel@tonic-gate 			    mpxio_disable_string(confent->mpxio_disable));
1922*7c478bd9Sstevel@tonic-gate 	}
1923*7c478bd9Sstevel@tonic-gate }
1924*7c478bd9Sstevel@tonic-gate 
1925*7c478bd9Sstevel@tonic-gate static void
1926*7c478bd9Sstevel@tonic-gate log_pathlist(char **pathlist)
1927*7c478bd9Sstevel@tonic-gate {
1928*7c478bd9Sstevel@tonic-gate 	char **p;
1929*7c478bd9Sstevel@tonic-gate 
1930*7c478bd9Sstevel@tonic-gate 	for (p = pathlist; *p != NULL; p++)
1931*7c478bd9Sstevel@tonic-gate 		log_debug_msg("\t%s\n", *p);
1932*7c478bd9Sstevel@tonic-gate }
1933*7c478bd9Sstevel@tonic-gate 
1934*7c478bd9Sstevel@tonic-gate #endif /* __sparc */
1935*7c478bd9Sstevel@tonic-gate 
1936*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1937