xref: /onnv-gate/usr/src/lib/libdevinfo/devfsmap.c (revision 12627:14a7fd60c4c5)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54870Sjg  * Common Development and Distribution License (the "License").
64870Sjg  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*12627SGangadhar.M@Sun.COM  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate #ifdef	lint
260Sstevel@tonic-gate #define	_REENTRANT	/* for localtime_r */
270Sstevel@tonic-gate #endif
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <stdio.h>
300Sstevel@tonic-gate #include <ctype.h>
310Sstevel@tonic-gate #include <stdlib.h>
320Sstevel@tonic-gate #include <sys/types.h>
330Sstevel@tonic-gate #include <strings.h>
340Sstevel@tonic-gate #include <stdarg.h>
350Sstevel@tonic-gate #include <sys/stat.h>
360Sstevel@tonic-gate #include <fcntl.h>
370Sstevel@tonic-gate #include <errno.h>
380Sstevel@tonic-gate #include <unistd.h>
390Sstevel@tonic-gate #include <stropts.h>
400Sstevel@tonic-gate #include <time.h>
410Sstevel@tonic-gate #include <sys/param.h>
420Sstevel@tonic-gate #include <sys/vfstab.h>
430Sstevel@tonic-gate #include <dirent.h>
440Sstevel@tonic-gate #ifdef __sparc
450Sstevel@tonic-gate #include <sys/scsi/adapters/scsi_vhci.h>
460Sstevel@tonic-gate #include <sys/sunmdi.h>
470Sstevel@tonic-gate #endif /* __sparc */
480Sstevel@tonic-gate #include "libdevinfo.h"
490Sstevel@tonic-gate #include "device_info.h"
504870Sjg #include <regex.h>
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #define	isnewline(ch)	((ch) == '\n' || (ch) == '\r' || (ch) == '\f')
530Sstevel@tonic-gate #define	isnamechar(ch)  (isalpha(ch) || isdigit(ch) || (ch) == '_' ||\
540Sstevel@tonic-gate 	(ch) == '-')
550Sstevel@tonic-gate #define	MAX_TOKEN_SIZE	1024
560Sstevel@tonic-gate #define	BUFSIZE		1024
570Sstevel@tonic-gate #define	STRVAL(s)	((s) ? (s) : "NULL")
580Sstevel@tonic-gate 
590Sstevel@tonic-gate #define	SCSI_VHCI_CONF		"/kernel/drv/scsi_vhci.conf"
600Sstevel@tonic-gate #define	QLC_CONF		"/kernel/drv/qlc.conf"
610Sstevel@tonic-gate #define	FP_CONF			"/kernel/drv/fp.conf"
620Sstevel@tonic-gate #define	DRIVER_CLASSES		"/etc/driver_classes"
630Sstevel@tonic-gate #define	FP_AT			"fp@"
640Sstevel@tonic-gate #define	VHCI_CTL_NODE		"/devices/scsi_vhci:devctl"
650Sstevel@tonic-gate #define	SLASH_DEVICES		"/devices"
660Sstevel@tonic-gate #define	SLASH_DEVICES_SLASH	"/devices/"
670Sstevel@tonic-gate #define	SLASH_FP_AT		"/fp@"
680Sstevel@tonic-gate #define	SLASH_SCSI_VHCI		"/scsi_vhci"
690Sstevel@tonic-gate #define	META_DEV		"/dev/md/dsk/"
700Sstevel@tonic-gate #define	SLASH_DEV_SLASH		"/dev/"
710Sstevel@tonic-gate 
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate  * Macros to produce a quoted string containing the value of a
740Sstevel@tonic-gate  * preprocessor macro. For example, if SIZE is defined to be 256,
750Sstevel@tonic-gate  * VAL2STR(SIZE) is "256". This is used to construct format
760Sstevel@tonic-gate  * strings for scanf-family functions below.
770Sstevel@tonic-gate  */
780Sstevel@tonic-gate #define	QUOTE(x)	#x
790Sstevel@tonic-gate #define	VAL2STR(x)	QUOTE(x)
800Sstevel@tonic-gate 
810Sstevel@tonic-gate typedef enum {
820Sstevel@tonic-gate 	CLIENT_TYPE_UNKNOWN,
830Sstevel@tonic-gate 	CLIENT_TYPE_PHCI,
840Sstevel@tonic-gate 	CLIENT_TYPE_VHCI
850Sstevel@tonic-gate } client_type_t;
860Sstevel@tonic-gate 
870Sstevel@tonic-gate typedef enum {
880Sstevel@tonic-gate 	T_EQUALS,
890Sstevel@tonic-gate 	T_AMPERSAND,
900Sstevel@tonic-gate 	T_BIT_OR,
910Sstevel@tonic-gate 	T_STAR,
920Sstevel@tonic-gate 	T_POUND,
930Sstevel@tonic-gate 	T_COLON,
940Sstevel@tonic-gate 	T_SEMICOLON,
950Sstevel@tonic-gate 	T_COMMA,
960Sstevel@tonic-gate 	T_SLASH,
970Sstevel@tonic-gate 	T_WHITE_SPACE,
980Sstevel@tonic-gate 	T_NEWLINE,
990Sstevel@tonic-gate 	T_EOF,
1000Sstevel@tonic-gate 	T_STRING,
1010Sstevel@tonic-gate 	T_HEXVAL,
1020Sstevel@tonic-gate 	T_DECVAL,
1030Sstevel@tonic-gate 	T_NAME
1040Sstevel@tonic-gate } token_t;
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate typedef enum {
1070Sstevel@tonic-gate 	begin, parent, drvname, drvclass, prop,
1080Sstevel@tonic-gate 	parent_equals, name_equals, drvclass_equals,
1090Sstevel@tonic-gate 	parent_equals_string, name_equals_string,
1100Sstevel@tonic-gate 	drvclass_equals_string,
1110Sstevel@tonic-gate 	prop_equals, prop_equals_string, prop_equals_integer,
1120Sstevel@tonic-gate 	prop_equals_string_comma, prop_equals_integer_comma
1130Sstevel@tonic-gate } conf_state_t;
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate /* structure to hold entries with mpxio-disable property in driver.conf file */
1160Sstevel@tonic-gate struct conf_entry {
1170Sstevel@tonic-gate 	char *name;
1180Sstevel@tonic-gate 	char *parent;
1190Sstevel@tonic-gate 	char *class;
1200Sstevel@tonic-gate 	char *unit_address;
1210Sstevel@tonic-gate 	int port;
1220Sstevel@tonic-gate 	int mpxio_disable;
1230Sstevel@tonic-gate 	struct conf_entry *next;
1240Sstevel@tonic-gate };
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate struct conf_file {
1270Sstevel@tonic-gate 	char *filename;
1280Sstevel@tonic-gate 	FILE *fp;
1290Sstevel@tonic-gate 	int linenum;
1300Sstevel@tonic-gate };
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate static char *tok_err = "Unexpected token '%s'\n";
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate /* #define	DEBUG */
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate #ifdef DEBUG
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate int devfsmap_debug = 0;
1400Sstevel@tonic-gate /* /var/run is not mounted at install time. Therefore use /tmp */
1410Sstevel@tonic-gate char *devfsmap_logfile = "/tmp/devfsmap.log";
1420Sstevel@tonic-gate static FILE *logfp;
1430Sstevel@tonic-gate #define	logdmsg(args)	log_debug_msg args
1440Sstevel@tonic-gate static void vlog_debug_msg(char *, va_list);
1450Sstevel@tonic-gate static void log_debug_msg(char *, ...);
1460Sstevel@tonic-gate #ifdef __sparc
1470Sstevel@tonic-gate static void log_confent_list(char *, struct conf_entry *, int);
1480Sstevel@tonic-gate static void log_pathlist(char **);
1490Sstevel@tonic-gate #endif /* __sparc */
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate #else /* DEBUG */
1520Sstevel@tonic-gate #define	logdmsg(args)	/* nothing */
1530Sstevel@tonic-gate #endif /* DEBUG */
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate /*
1570Sstevel@tonic-gate  * Leave NEWLINE as the next character.
1580Sstevel@tonic-gate  */
1590Sstevel@tonic-gate static void
find_eol(FILE * fp)1600Sstevel@tonic-gate find_eol(FILE *fp)
1610Sstevel@tonic-gate {
1620Sstevel@tonic-gate 	int ch;
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	while ((ch = getc(fp)) != EOF) {
1650Sstevel@tonic-gate 		if (isnewline(ch)) {
1660Sstevel@tonic-gate 			(void) ungetc(ch, fp);
1670Sstevel@tonic-gate 			break;
1680Sstevel@tonic-gate 		}
1690Sstevel@tonic-gate 	}
1700Sstevel@tonic-gate }
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate /* ignore parsing errors */
1730Sstevel@tonic-gate /*ARGSUSED*/
1740Sstevel@tonic-gate static void
file_err(struct conf_file * filep,char * fmt,...)1750Sstevel@tonic-gate file_err(struct conf_file *filep, char *fmt, ...)
1760Sstevel@tonic-gate {
1770Sstevel@tonic-gate #ifdef DEBUG
1780Sstevel@tonic-gate 	va_list ap;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	va_start(ap, fmt);
1810Sstevel@tonic-gate 	log_debug_msg("WARNING: %s line # %d: ",
1820Sstevel@tonic-gate 	    filep->filename, filep->linenum);
1830Sstevel@tonic-gate 	vlog_debug_msg(fmt, ap);
1840Sstevel@tonic-gate 	va_end(ap);
1850Sstevel@tonic-gate #endif /* DEBUG */
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate /* return the next token from the given driver.conf file, or -1 on error */
1890Sstevel@tonic-gate static token_t
lex(struct conf_file * filep,char * val,size_t size)1900Sstevel@tonic-gate lex(struct conf_file *filep, char *val, size_t size)
1910Sstevel@tonic-gate {
1920Sstevel@tonic-gate 	char	*cp;
1930Sstevel@tonic-gate 	int	ch, oval, badquote;
1940Sstevel@tonic-gate 	size_t	remain;
1950Sstevel@tonic-gate 	token_t token;
1960Sstevel@tonic-gate 	FILE	*fp = filep->fp;
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	if (size < 2)
1990Sstevel@tonic-gate 		return (-1);
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	cp = val;
2020Sstevel@tonic-gate 	while ((ch = getc(fp)) == ' ' || ch == '\t')
2030Sstevel@tonic-gate 		;
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	remain = size - 1;
2060Sstevel@tonic-gate 	*cp++ = (char)ch;
2070Sstevel@tonic-gate 	switch (ch) {
2080Sstevel@tonic-gate 	case '=':
2090Sstevel@tonic-gate 		token = T_EQUALS;
2100Sstevel@tonic-gate 		break;
2110Sstevel@tonic-gate 	case '&':
2120Sstevel@tonic-gate 		token = T_AMPERSAND;
2130Sstevel@tonic-gate 		break;
2140Sstevel@tonic-gate 	case '|':
2150Sstevel@tonic-gate 		token = T_BIT_OR;
2160Sstevel@tonic-gate 		break;
2170Sstevel@tonic-gate 	case '*':
2180Sstevel@tonic-gate 		token = T_STAR;
2190Sstevel@tonic-gate 		break;
2200Sstevel@tonic-gate 	case '#':
2210Sstevel@tonic-gate 		token = T_POUND;
2220Sstevel@tonic-gate 		break;
2230Sstevel@tonic-gate 	case ':':
2240Sstevel@tonic-gate 		token = T_COLON;
2250Sstevel@tonic-gate 		break;
2260Sstevel@tonic-gate 	case ';':
2270Sstevel@tonic-gate 		token = T_SEMICOLON;
2280Sstevel@tonic-gate 		break;
2290Sstevel@tonic-gate 	case ',':
2300Sstevel@tonic-gate 		token = T_COMMA;
2310Sstevel@tonic-gate 		break;
2320Sstevel@tonic-gate 	case '/':
2330Sstevel@tonic-gate 		token = T_SLASH;
2340Sstevel@tonic-gate 		break;
2350Sstevel@tonic-gate 	case ' ':
2360Sstevel@tonic-gate 	case '\t':
2370Sstevel@tonic-gate 	case '\f':
2380Sstevel@tonic-gate 		while ((ch = getc(fp)) == ' ' ||
2390Sstevel@tonic-gate 		    ch == '\t' || ch == '\f') {
2400Sstevel@tonic-gate 			if (--remain == 0) {
2410Sstevel@tonic-gate 				*cp = '\0';
2420Sstevel@tonic-gate 				return (-1);
2430Sstevel@tonic-gate 			}
2440Sstevel@tonic-gate 			*cp++ = (char)ch;
2450Sstevel@tonic-gate 		}
2460Sstevel@tonic-gate 		(void) ungetc(ch, fp);
2470Sstevel@tonic-gate 		token = T_WHITE_SPACE;
2480Sstevel@tonic-gate 		break;
2490Sstevel@tonic-gate 	case '\n':
2500Sstevel@tonic-gate 	case '\r':
2510Sstevel@tonic-gate 		token = T_NEWLINE;
2520Sstevel@tonic-gate 		break;
2530Sstevel@tonic-gate 	case '"':
2540Sstevel@tonic-gate 		remain++;
2550Sstevel@tonic-gate 		cp--;
2560Sstevel@tonic-gate 		badquote = 0;
2570Sstevel@tonic-gate 		while (!badquote && (ch  = getc(fp)) != '"') {
2580Sstevel@tonic-gate 			switch (ch) {
2590Sstevel@tonic-gate 			case '\n':
2600Sstevel@tonic-gate 			case EOF:
2610Sstevel@tonic-gate 				file_err(filep, "Missing \"\n");
2620Sstevel@tonic-gate 				remain = size - 1;
2630Sstevel@tonic-gate 				cp = val;
2640Sstevel@tonic-gate 				*cp++ = '\n';
2650Sstevel@tonic-gate 				badquote = 1;
2660Sstevel@tonic-gate 				/* since we consumed the newline/EOF */
2670Sstevel@tonic-gate 				(void) ungetc(ch, fp);
2680Sstevel@tonic-gate 				break;
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 			case '\\':
2710Sstevel@tonic-gate 				if (--remain == 0) {
2720Sstevel@tonic-gate 					*cp = '\0';
2730Sstevel@tonic-gate 					return (-1);
2740Sstevel@tonic-gate 				}
2750Sstevel@tonic-gate 				ch = (char)getc(fp);
2760Sstevel@tonic-gate 				if (!isdigit(ch)) {
2770Sstevel@tonic-gate 					/* escape the character */
2780Sstevel@tonic-gate 					*cp++ = (char)ch;
2790Sstevel@tonic-gate 					break;
2800Sstevel@tonic-gate 				}
2810Sstevel@tonic-gate 				oval = 0;
2820Sstevel@tonic-gate 				while (ch >= '0' && ch <= '7') {
2830Sstevel@tonic-gate 					ch -= '0';
2840Sstevel@tonic-gate 					oval = (oval << 3) + ch;
2850Sstevel@tonic-gate 					ch = (char)getc(fp);
2860Sstevel@tonic-gate 				}
2870Sstevel@tonic-gate 				(void) ungetc(ch, fp);
2880Sstevel@tonic-gate 				/* check for character overflow? */
2890Sstevel@tonic-gate 				if (oval > 127) {
2900Sstevel@tonic-gate 					file_err(filep,
2910Sstevel@tonic-gate 					    "Character "
2920Sstevel@tonic-gate 					    "overflow detected.\n");
2930Sstevel@tonic-gate 				}
2940Sstevel@tonic-gate 				*cp++ = (char)oval;
2950Sstevel@tonic-gate 				break;
2960Sstevel@tonic-gate 			default:
2970Sstevel@tonic-gate 				if (--remain == 0) {
2980Sstevel@tonic-gate 					*cp = '\0';
2990Sstevel@tonic-gate 					return (-1);
3000Sstevel@tonic-gate 				}
3010Sstevel@tonic-gate 				*cp++ = (char)ch;
3020Sstevel@tonic-gate 				break;
3030Sstevel@tonic-gate 			}
3040Sstevel@tonic-gate 		}
3050Sstevel@tonic-gate 		token = T_STRING;
3060Sstevel@tonic-gate 		break;
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	case EOF:
3090Sstevel@tonic-gate 		token = T_EOF;
3100Sstevel@tonic-gate 		break;
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	default:
3130Sstevel@tonic-gate 		/*
3140Sstevel@tonic-gate 		 * detect a lone '-' (including at the end of a line), and
3150Sstevel@tonic-gate 		 * identify it as a 'name'
3160Sstevel@tonic-gate 		 */
3170Sstevel@tonic-gate 		if (ch == '-') {
3180Sstevel@tonic-gate 			if (--remain == 0) {
3190Sstevel@tonic-gate 				*cp = '\0';
3200Sstevel@tonic-gate 				return (-1);
3210Sstevel@tonic-gate 			}
3220Sstevel@tonic-gate 			*cp++ = (char)(ch = getc(fp));
3230Sstevel@tonic-gate 			if (ch == ' ' || ch == '\t' || ch == '\n') {
3240Sstevel@tonic-gate 				(void) ungetc(ch, fp);
3250Sstevel@tonic-gate 				remain++;
3260Sstevel@tonic-gate 				cp--;
3270Sstevel@tonic-gate 				token = T_NAME;
3280Sstevel@tonic-gate 				break;
3290Sstevel@tonic-gate 			}
3300Sstevel@tonic-gate 		} else if (ch == '~' || ch == '-') {
3310Sstevel@tonic-gate 			if (--remain == 0) {
3320Sstevel@tonic-gate 				*cp = '\0';
3330Sstevel@tonic-gate 				return (-1);
3340Sstevel@tonic-gate 			}
3350Sstevel@tonic-gate 			*cp++ = (char)(ch = getc(fp));
3360Sstevel@tonic-gate 		}
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 		if (isdigit(ch)) {
3400Sstevel@tonic-gate 			if (ch == '0') {
3410Sstevel@tonic-gate 				if ((ch = getc(fp)) == 'x') {
3420Sstevel@tonic-gate 					if (--remain == 0) {
3430Sstevel@tonic-gate 						*cp = '\0';
3440Sstevel@tonic-gate 						return (-1);
3450Sstevel@tonic-gate 					}
3460Sstevel@tonic-gate 					*cp++ = (char)ch;
3470Sstevel@tonic-gate 					ch = getc(fp);
3480Sstevel@tonic-gate 					while (isxdigit(ch)) {
3490Sstevel@tonic-gate 						if (--remain == 0) {
3500Sstevel@tonic-gate 							*cp = '\0';
3510Sstevel@tonic-gate 							return (-1);
3520Sstevel@tonic-gate 						}
3530Sstevel@tonic-gate 						*cp++ = (char)ch;
3540Sstevel@tonic-gate 						ch = getc(fp);
3550Sstevel@tonic-gate 					}
3560Sstevel@tonic-gate 					(void) ungetc(ch, fp);
3570Sstevel@tonic-gate 					token = T_HEXVAL;
3580Sstevel@tonic-gate 				} else {
3590Sstevel@tonic-gate 					goto digit;
3600Sstevel@tonic-gate 				}
3610Sstevel@tonic-gate 			} else {
3620Sstevel@tonic-gate 				ch = getc(fp);
3630Sstevel@tonic-gate digit:
3640Sstevel@tonic-gate 				while (isdigit(ch)) {
3650Sstevel@tonic-gate 					if (--remain == 0) {
3660Sstevel@tonic-gate 						*cp = '\0';
3670Sstevel@tonic-gate 						return (-1);
3680Sstevel@tonic-gate 					}
3690Sstevel@tonic-gate 					*cp++ = (char)ch;
3700Sstevel@tonic-gate 					ch = getc(fp);
3710Sstevel@tonic-gate 				}
3720Sstevel@tonic-gate 				(void) ungetc(ch, fp);
3730Sstevel@tonic-gate 				token = T_DECVAL;
3740Sstevel@tonic-gate 			}
3750Sstevel@tonic-gate 		} else if (isalpha(ch) || ch == '\\') {
3760Sstevel@tonic-gate 			if (ch != '\\') {
3770Sstevel@tonic-gate 				ch = getc(fp);
3780Sstevel@tonic-gate 			} else {
3790Sstevel@tonic-gate 				/*
3800Sstevel@tonic-gate 				 * if the character was a backslash,
3810Sstevel@tonic-gate 				 * back up so we can overwrite it with
3820Sstevel@tonic-gate 				 * the next (i.e. escaped) character.
3830Sstevel@tonic-gate 				 */
3840Sstevel@tonic-gate 				remain++;
3850Sstevel@tonic-gate 				cp--;
3860Sstevel@tonic-gate 			}
3870Sstevel@tonic-gate 			while (isnamechar(ch) || ch == '\\') {
3880Sstevel@tonic-gate 				if (ch == '\\')
3890Sstevel@tonic-gate 					ch = getc(fp);
3900Sstevel@tonic-gate 				if (--remain == 0) {
3910Sstevel@tonic-gate 					*cp = '\0';
3920Sstevel@tonic-gate 					return (-1);
3930Sstevel@tonic-gate 				}
3940Sstevel@tonic-gate 				*cp++ = (char)ch;
3950Sstevel@tonic-gate 				ch = getc(fp);
3960Sstevel@tonic-gate 			}
3970Sstevel@tonic-gate 			(void) ungetc(ch, fp);
3980Sstevel@tonic-gate 			token = T_NAME;
3990Sstevel@tonic-gate 		} else {
4000Sstevel@tonic-gate 			return (-1);
4010Sstevel@tonic-gate 		}
4020Sstevel@tonic-gate 		break;
4030Sstevel@tonic-gate 	}
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	*cp = '\0';
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	return (token);
4080Sstevel@tonic-gate }
4090Sstevel@tonic-gate 
4104870Sjg #ifdef __sparc
4114870Sjg 
4120Sstevel@tonic-gate static void
free_confent(struct conf_entry * confent)4130Sstevel@tonic-gate free_confent(struct conf_entry *confent)
4140Sstevel@tonic-gate {
4150Sstevel@tonic-gate 	if (confent->name)
4160Sstevel@tonic-gate 		free(confent->name);
4170Sstevel@tonic-gate 	if (confent->parent)
4180Sstevel@tonic-gate 		free(confent->parent);
4190Sstevel@tonic-gate 	if (confent->class)
4200Sstevel@tonic-gate 		free(confent->class);
4210Sstevel@tonic-gate 	if (confent->unit_address)
4220Sstevel@tonic-gate 		free(confent->unit_address);
4230Sstevel@tonic-gate 	free(confent);
4240Sstevel@tonic-gate }
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate static void
free_confent_list(struct conf_entry * confent_list)4270Sstevel@tonic-gate free_confent_list(struct conf_entry *confent_list)
4280Sstevel@tonic-gate {
4290Sstevel@tonic-gate 	struct conf_entry *confent, *next;
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	for (confent = confent_list; confent != NULL; confent = next) {
4320Sstevel@tonic-gate 		next = confent->next;
4330Sstevel@tonic-gate 		free_confent(confent);
4340Sstevel@tonic-gate 	}
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate /*
4380Sstevel@tonic-gate  * Parse the next entry from the driver.conf file and return in the form of
4390Sstevel@tonic-gate  * a pointer to the conf_entry.
4400Sstevel@tonic-gate  */
4410Sstevel@tonic-gate static struct conf_entry *
parse_conf_entry(struct conf_file * filep,char * tokbuf,size_t linesize)4420Sstevel@tonic-gate parse_conf_entry(struct conf_file *filep, char *tokbuf, size_t linesize)
4430Sstevel@tonic-gate {
4440Sstevel@tonic-gate 	char *prop_name, *string;
4450Sstevel@tonic-gate 	token_t token;
4460Sstevel@tonic-gate 	struct conf_entry *confent;
4470Sstevel@tonic-gate 	conf_state_t state;
4480Sstevel@tonic-gate 	int failed = 1;
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	if ((confent = calloc(1, sizeof (*confent))) == NULL)
4510Sstevel@tonic-gate 		return (NULL);
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	confent->port = -1;
4540Sstevel@tonic-gate 	confent->mpxio_disable = -1;
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	state = begin;
4570Sstevel@tonic-gate 	token = T_NAME;
4580Sstevel@tonic-gate 	prop_name = NULL;
4590Sstevel@tonic-gate 	string = NULL;
4600Sstevel@tonic-gate 	do {
4610Sstevel@tonic-gate 		switch (token) {
4620Sstevel@tonic-gate 		case T_NAME:
4630Sstevel@tonic-gate 			switch (state) {
4640Sstevel@tonic-gate 			case prop_equals_string:
4650Sstevel@tonic-gate 			case prop_equals_integer:
4660Sstevel@tonic-gate 			case begin:
4670Sstevel@tonic-gate 				state = prop;
4680Sstevel@tonic-gate 				if ((prop_name = strdup(tokbuf)) == NULL)
4690Sstevel@tonic-gate 					goto bad;
4700Sstevel@tonic-gate 				break;
4710Sstevel@tonic-gate 			default:
4720Sstevel@tonic-gate 				file_err(filep, tok_err, tokbuf);
4730Sstevel@tonic-gate 			}
4740Sstevel@tonic-gate 			break;
4750Sstevel@tonic-gate 		case T_EQUALS:
4760Sstevel@tonic-gate 			switch (state) {
4770Sstevel@tonic-gate 			case prop:
4780Sstevel@tonic-gate 				state = prop_equals;
4790Sstevel@tonic-gate 				break;
4800Sstevel@tonic-gate 			default:
4810Sstevel@tonic-gate 				file_err(filep, tok_err, tokbuf);
4820Sstevel@tonic-gate 			}
4830Sstevel@tonic-gate 			break;
4840Sstevel@tonic-gate 		case T_STRING:
4850Sstevel@tonic-gate 			switch (state) {
4860Sstevel@tonic-gate 			case prop_equals:
4870Sstevel@tonic-gate 				if ((string = strdup(tokbuf)) == NULL)
4880Sstevel@tonic-gate 					goto bad;
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 				state = begin;
4910Sstevel@tonic-gate 				if (strcmp(prop_name, "PARENT") == 0 ||
4920Sstevel@tonic-gate 				    strcmp(prop_name, "parent") == 0) {
4930Sstevel@tonic-gate 					if (confent->parent) {
4940Sstevel@tonic-gate 						file_err(filep,
4950Sstevel@tonic-gate 				"'parent' property already specified\n");
4960Sstevel@tonic-gate 						goto bad;
4970Sstevel@tonic-gate 					}
4980Sstevel@tonic-gate 					confent->parent = string;
4990Sstevel@tonic-gate 				} else if (strcmp(prop_name, "NAME") == 0 ||
5000Sstevel@tonic-gate 				    strcmp(prop_name, "name") == 0) {
5010Sstevel@tonic-gate 					if (confent->name) {
5020Sstevel@tonic-gate 						file_err(filep,
5030Sstevel@tonic-gate 				"'name' property already specified\n");
5040Sstevel@tonic-gate 						goto bad;
5050Sstevel@tonic-gate 					}
5060Sstevel@tonic-gate 					confent->name = string;
5070Sstevel@tonic-gate 				} else if (strcmp(prop_name, "CLASS") == 0 ||
5080Sstevel@tonic-gate 				    strcmp(prop_name, "class") == 0) {
5090Sstevel@tonic-gate 					if (confent->class) {
5100Sstevel@tonic-gate 						file_err(filep,
5110Sstevel@tonic-gate 				"'class' property already specified\n");
5120Sstevel@tonic-gate 						goto bad;
5130Sstevel@tonic-gate 					}
5140Sstevel@tonic-gate 					confent->class = string;
5150Sstevel@tonic-gate 				} else if (strcmp(prop_name, "unit-address")
5160Sstevel@tonic-gate 				    == 0) {
5170Sstevel@tonic-gate 					if (confent->unit_address) {
5180Sstevel@tonic-gate 						file_err(filep,
5190Sstevel@tonic-gate 				"'unit-address' property already specified\n");
5200Sstevel@tonic-gate 						goto bad;
5210Sstevel@tonic-gate 					}
5220Sstevel@tonic-gate 					confent->unit_address = string;
5230Sstevel@tonic-gate 				} else if (strcmp(prop_name, "mpxio-disable")
5240Sstevel@tonic-gate 				    == 0) {
5250Sstevel@tonic-gate 					if (confent->mpxio_disable != -1) {
5260Sstevel@tonic-gate 						file_err(filep,
5270Sstevel@tonic-gate 				"'mpxio-disable' property already specified\n");
5280Sstevel@tonic-gate 						goto bad;
5290Sstevel@tonic-gate 					}
5300Sstevel@tonic-gate 					if (strcmp(string, "yes") == 0)
5310Sstevel@tonic-gate 						confent->mpxio_disable = 1;
5320Sstevel@tonic-gate 					else if (strcmp(string, "no") == 0)
5330Sstevel@tonic-gate 						confent->mpxio_disable = 0;
5340Sstevel@tonic-gate 					else {
5350Sstevel@tonic-gate 						file_err(filep,
5360Sstevel@tonic-gate 				"'mpxio-disable' property setting is invalid. "
5370Sstevel@tonic-gate 				"The value must be either \"yes\" or \"no\"\n");
5380Sstevel@tonic-gate 						goto bad;
5390Sstevel@tonic-gate 					}
5400Sstevel@tonic-gate 					free(string);
5410Sstevel@tonic-gate 				} else {
5420Sstevel@tonic-gate 					free(string);
5430Sstevel@tonic-gate 					state = prop_equals_string;
5440Sstevel@tonic-gate 				}
5450Sstevel@tonic-gate 				string = NULL;
5460Sstevel@tonic-gate 				free(prop_name);
5470Sstevel@tonic-gate 				prop_name = NULL;
5480Sstevel@tonic-gate 				break;
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 			case prop_equals_string_comma:
5510Sstevel@tonic-gate 				state = prop_equals_string;
5520Sstevel@tonic-gate 				break;
5530Sstevel@tonic-gate 			default:
5540Sstevel@tonic-gate 				file_err(filep, tok_err, tokbuf);
5550Sstevel@tonic-gate 			}
5560Sstevel@tonic-gate 			break;
5570Sstevel@tonic-gate 		case T_HEXVAL:
5580Sstevel@tonic-gate 		case T_DECVAL:
5590Sstevel@tonic-gate 			switch (state) {
5600Sstevel@tonic-gate 			case prop_equals:
5610Sstevel@tonic-gate 				if (strcmp(prop_name, "port") == 0) {
5620Sstevel@tonic-gate 					if (confent->port != -1) {
5630Sstevel@tonic-gate 						file_err(filep,
5640Sstevel@tonic-gate 					"'port' property already specified\n");
5650Sstevel@tonic-gate 						goto bad;
5660Sstevel@tonic-gate 					}
5670Sstevel@tonic-gate 					confent->port =
5680Sstevel@tonic-gate 					    (int)strtol(tokbuf, NULL, 0);
5690Sstevel@tonic-gate 					state = begin;
5700Sstevel@tonic-gate 				} else
5710Sstevel@tonic-gate 					state = prop_equals_integer;
5720Sstevel@tonic-gate 				free(prop_name);
5730Sstevel@tonic-gate 				prop_name = NULL;
5740Sstevel@tonic-gate 				break;
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 			case prop_equals_integer_comma:
5770Sstevel@tonic-gate 				state = prop_equals_integer;
5780Sstevel@tonic-gate 				break;
5790Sstevel@tonic-gate 			default:
5800Sstevel@tonic-gate 				file_err(filep, tok_err, tokbuf);
5810Sstevel@tonic-gate 			}
5820Sstevel@tonic-gate 			break;
5830Sstevel@tonic-gate 		case T_COMMA:
5840Sstevel@tonic-gate 			switch (state) {
5850Sstevel@tonic-gate 			case prop_equals_string:
5860Sstevel@tonic-gate 				state = prop_equals_string_comma;
5870Sstevel@tonic-gate 				break;
5880Sstevel@tonic-gate 			case prop_equals_integer:
5890Sstevel@tonic-gate 				state = prop_equals_integer_comma;
5900Sstevel@tonic-gate 				break;
5910Sstevel@tonic-gate 			default:
5920Sstevel@tonic-gate 				file_err(filep, tok_err, tokbuf);
5930Sstevel@tonic-gate 			}
5940Sstevel@tonic-gate 			break;
5950Sstevel@tonic-gate 		case T_NEWLINE:
5960Sstevel@tonic-gate 			filep->linenum++;
5970Sstevel@tonic-gate 			break;
5980Sstevel@tonic-gate 		case T_POUND:
5990Sstevel@tonic-gate 			find_eol(filep->fp);
6000Sstevel@tonic-gate 			break;
6010Sstevel@tonic-gate 		case T_EOF:
6020Sstevel@tonic-gate 			file_err(filep, "Unexpected EOF\n");
6030Sstevel@tonic-gate 			goto bad;
6040Sstevel@tonic-gate 		default:
6050Sstevel@tonic-gate 			file_err(filep, tok_err, tokbuf);
6060Sstevel@tonic-gate 			goto bad;
6070Sstevel@tonic-gate 		}
6080Sstevel@tonic-gate 	} while ((token = lex(filep, tokbuf, linesize)) != T_SEMICOLON);
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	failed = 0;
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate bad:
6130Sstevel@tonic-gate 	if (prop_name)
6140Sstevel@tonic-gate 		free(prop_name);
6150Sstevel@tonic-gate 	if (string)
6160Sstevel@tonic-gate 		free(string);
6170Sstevel@tonic-gate 	if (failed == 1) {
6180Sstevel@tonic-gate 		free_confent(confent);
6190Sstevel@tonic-gate 		return (NULL);
6200Sstevel@tonic-gate 	}
6210Sstevel@tonic-gate 	return (confent);
6220Sstevel@tonic-gate }
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate /*
6250Sstevel@tonic-gate  * Parse all entries with mpxio-disable property in the given driver.conf
6260Sstevel@tonic-gate  * file.
6270Sstevel@tonic-gate  *
6280Sstevel@tonic-gate  * fname		driver.conf file name
6290Sstevel@tonic-gate  * confent_list		on return *confent_list will contain the list of
6300Sstevel@tonic-gate  *			driver.conf file entries with mpxio-disable property.
6310Sstevel@tonic-gate  * mpxio_disable	on return *mpxio_disable is set to the setting of the
6320Sstevel@tonic-gate  * 			driver global mpxio-dissable property as follows.
6330Sstevel@tonic-gate  *			0  if driver mpxio-disable="no"
6340Sstevel@tonic-gate  *			1  if driver mpxio-disable="yes"
6350Sstevel@tonic-gate  *			-1 if driver mpxio-disable property isn't specified.
6360Sstevel@tonic-gate  */
6370Sstevel@tonic-gate static void
parse_conf_file(char * fname,struct conf_entry ** confent_list,int * mpxio_disable)6380Sstevel@tonic-gate parse_conf_file(char *fname, struct conf_entry **confent_list,
6390Sstevel@tonic-gate     int *mpxio_disable)
6400Sstevel@tonic-gate {
6410Sstevel@tonic-gate 	struct conf_entry *confent, *tail = NULL;
6420Sstevel@tonic-gate 	token_t token;
6430Sstevel@tonic-gate 	struct conf_file file;
6440Sstevel@tonic-gate 	char tokval[MAX_TOKEN_SIZE];
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	*confent_list = NULL;
6470Sstevel@tonic-gate 	*mpxio_disable = -1;
6480Sstevel@tonic-gate 	if ((file.fp = fopen(fname, "r")) == NULL)
6490Sstevel@tonic-gate 		return;
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	file.filename = fname;
6520Sstevel@tonic-gate 	file.linenum = 1;
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	while ((token = lex(&file, tokval, MAX_TOKEN_SIZE)) != T_EOF) {
6550Sstevel@tonic-gate 		switch (token) {
6560Sstevel@tonic-gate 		case T_POUND:
6570Sstevel@tonic-gate 			/*
6580Sstevel@tonic-gate 			 * Skip comments.
6590Sstevel@tonic-gate 			 */
6600Sstevel@tonic-gate 			find_eol(file.fp);
6610Sstevel@tonic-gate 			break;
6620Sstevel@tonic-gate 		case T_NAME:
6630Sstevel@tonic-gate 			if ((confent = parse_conf_entry(&file, tokval,
6640Sstevel@tonic-gate 			    MAX_TOKEN_SIZE)) == NULL)
6650Sstevel@tonic-gate 				break;
6660Sstevel@tonic-gate 			/*
6670Sstevel@tonic-gate 			 * No name indicates global property.
6680Sstevel@tonic-gate 			 * Make sure parent and class not NULL.
6690Sstevel@tonic-gate 			 */
6700Sstevel@tonic-gate 			if (confent->name == NULL) {
6710Sstevel@tonic-gate 				if (confent->parent ||
6720Sstevel@tonic-gate 				    confent->class) {
6730Sstevel@tonic-gate 					file_err(&file,
6740Sstevel@tonic-gate 					    "missing name attribute\n");
6750Sstevel@tonic-gate 				} else if (confent->mpxio_disable != -1) {
6760Sstevel@tonic-gate 					if (*mpxio_disable == -1)
6770Sstevel@tonic-gate 						*mpxio_disable =
6780Sstevel@tonic-gate 						    confent->mpxio_disable;
6790Sstevel@tonic-gate 					else
6800Sstevel@tonic-gate 						file_err(&file,
6810Sstevel@tonic-gate 				"'mpxio-disable' property already specified\n");
6820Sstevel@tonic-gate 				}
6830Sstevel@tonic-gate 				free_confent(confent);
6840Sstevel@tonic-gate 				break;
6850Sstevel@tonic-gate 			}
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 			/*
6880Sstevel@tonic-gate 			 * This is a node spec, either parent or class
6890Sstevel@tonic-gate 			 * must be specified.
6900Sstevel@tonic-gate 			 */
6910Sstevel@tonic-gate 			if (confent->parent == NULL && confent->class == NULL) {
6920Sstevel@tonic-gate 				file_err(&file,
6930Sstevel@tonic-gate 				    "missing parent or class attribute\n");
6940Sstevel@tonic-gate 				free_confent(confent);
6950Sstevel@tonic-gate 				break;
6960Sstevel@tonic-gate 			}
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 			/* only need entries with mpxio_disable property */
6990Sstevel@tonic-gate 			if (confent->mpxio_disable == -1) {
7000Sstevel@tonic-gate 				free_confent(confent);
7010Sstevel@tonic-gate 				break;
7020Sstevel@tonic-gate 			}
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 			if (tail)
7050Sstevel@tonic-gate 				tail->next = confent;
7060Sstevel@tonic-gate 			else
7070Sstevel@tonic-gate 				*confent_list = confent;
7080Sstevel@tonic-gate 			tail = confent;
7090Sstevel@tonic-gate 			break;
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 		case T_NEWLINE:
7120Sstevel@tonic-gate 			file.linenum++;
7130Sstevel@tonic-gate 			break;
7140Sstevel@tonic-gate 		default:
7150Sstevel@tonic-gate 			break;
7160Sstevel@tonic-gate 		}
7170Sstevel@tonic-gate 	}
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	(void) fclose(file.fp);
7200Sstevel@tonic-gate }
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate /*
7230Sstevel@tonic-gate  * Return the driver class of the given driver_name.
7240Sstevel@tonic-gate  * The memory for the driver class is allocated by this function and the
7250Sstevel@tonic-gate  * caller must free it.
7260Sstevel@tonic-gate  */
7270Sstevel@tonic-gate static char *
get_driver_class(char * rootdir,char * driver_name)7280Sstevel@tonic-gate get_driver_class(char *rootdir, char *driver_name)
7290Sstevel@tonic-gate {
7300Sstevel@tonic-gate 	FILE *fp;
7310Sstevel@tonic-gate 	char buf[BUFSIZE];
7320Sstevel@tonic-gate 	char driver[BUFSIZE];
7330Sstevel@tonic-gate 	char class_name[BUFSIZE];
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	logdmsg(("get_driver_class: rootdir = %s, driver name = %s\n",
7360Sstevel@tonic-gate 	    rootdir, driver_name));
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%s%s", rootdir, DRIVER_CLASSES);
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	if ((fp = fopen(buf, "r")) == NULL) {
7410Sstevel@tonic-gate 		logdmsg(("get_driver_class: failed to open %s: %s\n",
7420Sstevel@tonic-gate 		    buf, strerror(errno)));
7430Sstevel@tonic-gate 		return (NULL);
7440Sstevel@tonic-gate 	}
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	while (fgets(buf, sizeof (buf), fp) != NULL) {
7470Sstevel@tonic-gate 		/* LINTED - unbounded string specifier */
7480Sstevel@tonic-gate 		if ((sscanf(buf, "%s %s", driver, class_name) == 2) &&
7490Sstevel@tonic-gate 		    driver[0] != '#' && strcmp(driver, driver_name) == 0) {
7500Sstevel@tonic-gate 			logdmsg(("get_driver_class: driver class = %s\n",
7510Sstevel@tonic-gate 			    class_name));
7520Sstevel@tonic-gate 			(void) fclose(fp);
7530Sstevel@tonic-gate 			return (strdup(class_name));
7540Sstevel@tonic-gate 		}
7550Sstevel@tonic-gate 	}
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	(void) fclose(fp);
7580Sstevel@tonic-gate 	return (NULL);
7590Sstevel@tonic-gate }
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate static int
lookup_in_confent_list(struct conf_entry * confent_list,int match_class,char * parent,char * unit_addr,int port)7620Sstevel@tonic-gate lookup_in_confent_list(struct conf_entry *confent_list,
7630Sstevel@tonic-gate     int match_class, char *parent, char *unit_addr, int port)
7640Sstevel@tonic-gate {
7650Sstevel@tonic-gate 	struct conf_entry *confent;
7660Sstevel@tonic-gate 	char *par;
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	logdmsg(("lookup_in_confent_list: %s = \"%s\", unit_addr = \"%s\", "
7690Sstevel@tonic-gate 	    "port = %d\n", (match_class) ? "class" : "parent", parent,
7700Sstevel@tonic-gate 	    STRVAL(unit_addr), port));
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	for (confent = confent_list; confent != NULL; confent = confent->next) {
7730Sstevel@tonic-gate 		par = (match_class) ? confent->class : confent->parent;
7740Sstevel@tonic-gate 		if (unit_addr) {
7750Sstevel@tonic-gate 			if (confent->unit_address != NULL &&
7760Sstevel@tonic-gate 			    strcmp(confent->unit_address, unit_addr) == 0 &&
7770Sstevel@tonic-gate 			    par != NULL && strcmp(par, parent) == 0)
7780Sstevel@tonic-gate 				return (confent->mpxio_disable);
7790Sstevel@tonic-gate 		} else {
7800Sstevel@tonic-gate 			if (confent->port == port &&
7810Sstevel@tonic-gate 			    par != NULL && strcmp(par, parent) == 0)
7820Sstevel@tonic-gate 				return (confent->mpxio_disable);
7830Sstevel@tonic-gate 		}
7840Sstevel@tonic-gate 	}
7850Sstevel@tonic-gate 	return (-1);
7860Sstevel@tonic-gate }
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate /*
7890Sstevel@tonic-gate  * lookup mpxio-disabled property setting for the given path in the given
7900Sstevel@tonic-gate  * driver.conf file. Match the entries from most specific to least specific.
7910Sstevel@tonic-gate  *
7920Sstevel@tonic-gate  * conf_file	the path name of either fp.conf, qlc.conf or scsi_vhci.conf
7930Sstevel@tonic-gate  * path		/devices node path without the /devices prefix.
7940Sstevel@tonic-gate  *		If the conf_file is fp.conf, path must be a fp node path
7950Sstevel@tonic-gate  *		if the conf_file is qlc.conf, path must be a qlc node path.
7960Sstevel@tonic-gate  *		if the conf_file is scsi_vhci.conf, path must be NULL.
7970Sstevel@tonic-gate  *		ex:	/pci@8,600000/SUNW,qlc@4/fp@0,0
7980Sstevel@tonic-gate  *			/pci@8,600000/SUNW,qlc@4
7990Sstevel@tonic-gate  *
8000Sstevel@tonic-gate  * returns:
8010Sstevel@tonic-gate  *	0	if mpxio-disable="no"
8020Sstevel@tonic-gate  *	1	if mpxio-disable="yes"
8030Sstevel@tonic-gate  *	-1	if mpxio-disable property isn't specified.
8040Sstevel@tonic-gate  */
8050Sstevel@tonic-gate static int
lookup_in_conf_file(char * rootdir,char * conf_file,char * path)8060Sstevel@tonic-gate lookup_in_conf_file(char *rootdir, char *conf_file, char *path)
8070Sstevel@tonic-gate {
8080Sstevel@tonic-gate 	struct conf_entry *confent_list = NULL;
8090Sstevel@tonic-gate 	int mpxio_disable;
8100Sstevel@tonic-gate 	di_node_t par_node = DI_NODE_NIL;
8110Sstevel@tonic-gate 	char *node_name = NULL, *node_addr = NULL;
8120Sstevel@tonic-gate 	char *unit_addr = NULL;
8130Sstevel@tonic-gate 	int port = -1;
8140Sstevel@tonic-gate 	char *par_node_name = NULL, *par_node_addr = NULL;
8150Sstevel@tonic-gate 	char *par_binding_name = NULL, *par_driver_name = NULL;
8160Sstevel@tonic-gate 	char *par_driver_class = NULL, *par_node_name_addr;
8170Sstevel@tonic-gate 	int rv = -1;
8180Sstevel@tonic-gate 	char buf[MAXPATHLEN];
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	logdmsg(("lookup_in_conf_file: rootdir = \"%s\", conf_file = \"%s\", "
8210Sstevel@tonic-gate 	    "path = \"%s\"\n", rootdir, conf_file, STRVAL(path)));
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	(void) snprintf(buf, MAXPATHLEN, "%s%s", rootdir, conf_file);
8240Sstevel@tonic-gate 	parse_conf_file(buf, &confent_list, &mpxio_disable);
8250Sstevel@tonic-gate #ifdef DEBUG
8260Sstevel@tonic-gate 	log_confent_list(buf, confent_list, mpxio_disable);
8270Sstevel@tonic-gate #endif
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 	/* if path is NULL, return driver global mpxio-disable setting */
8300Sstevel@tonic-gate 	if (path == NULL) {
8310Sstevel@tonic-gate 		rv = mpxio_disable;
8320Sstevel@tonic-gate 		goto done;
8330Sstevel@tonic-gate 	}
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	if ((node_name = strrchr(path, '/')) == NULL)
8360Sstevel@tonic-gate 		goto done;
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	*node_name = '\0';
8390Sstevel@tonic-gate 	node_name++;
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 	if ((node_addr = strchr(node_name, '@')) == NULL)
8420Sstevel@tonic-gate 		goto done;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 	*node_addr = '\0';
8450Sstevel@tonic-gate 	node_addr++;
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	if (strcmp(node_name, "fp") == 0) {
8480Sstevel@tonic-gate 		/* get port number; encoded in the node addr as a hex number */
8490Sstevel@tonic-gate 		port = (int)strtol(node_addr, NULL, 16);
8500Sstevel@tonic-gate 	} else
8510Sstevel@tonic-gate 		unit_addr = node_addr;
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 	/*
8540Sstevel@tonic-gate 	 * Match from most specific to least specific;
8550Sstevel@tonic-gate 	 * first, start the lookup based on full path.
8560Sstevel@tonic-gate 	 */
8570Sstevel@tonic-gate 	if ((rv = lookup_in_confent_list(confent_list, 0, path,
8580Sstevel@tonic-gate 	    unit_addr, port)) != -1)
8590Sstevel@tonic-gate 		goto done;
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	/* lookup nodename@address */
8620Sstevel@tonic-gate 	if ((par_node_name_addr = strrchr(path, '/')) != NULL) {
8630Sstevel@tonic-gate 		par_node_name_addr++;
8640Sstevel@tonic-gate 		if ((rv = lookup_in_confent_list(confent_list, 0,
8650Sstevel@tonic-gate 		    par_node_name_addr, unit_addr, port)) != -1)
8660Sstevel@tonic-gate 			goto done;
8670Sstevel@tonic-gate 	}
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 	/* di_init() doesn't work when 0 is passed in flags */
8700Sstevel@tonic-gate 	par_node = di_init(path, DINFOMINOR);
8710Sstevel@tonic-gate 	if (par_node != DI_NODE_NIL) {
8720Sstevel@tonic-gate 		par_node_name = di_node_name(par_node);
8730Sstevel@tonic-gate 		par_node_addr = di_bus_addr(par_node);
8740Sstevel@tonic-gate 		par_binding_name = di_binding_name(par_node);
8750Sstevel@tonic-gate 		par_driver_name = di_driver_name(par_node);
8760Sstevel@tonic-gate 	}
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	logdmsg(("par_node_name = %s\n", STRVAL(par_node_name)));
8790Sstevel@tonic-gate 	logdmsg(("par_node_addr = %s\n", STRVAL(par_node_addr)));
8800Sstevel@tonic-gate 	logdmsg(("par_binding_name = %s\n", STRVAL(par_binding_name)));
8810Sstevel@tonic-gate 	logdmsg(("par_driver_name = %s\n", STRVAL(par_driver_name)));
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	/* lookup bindingname@address */
8840Sstevel@tonic-gate 	if (par_binding_name != NULL && par_binding_name != par_node_name &&
8850Sstevel@tonic-gate 	    par_node_addr != NULL) {
8860Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "%s@%s", par_binding_name,
8870Sstevel@tonic-gate 		    par_node_addr);
8880Sstevel@tonic-gate 		if ((rv = lookup_in_confent_list(confent_list, 0,
8890Sstevel@tonic-gate 		    buf, unit_addr, port)) != -1)
8900Sstevel@tonic-gate 			goto done;
8910Sstevel@tonic-gate 	}
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 	/* lookup binding name */
8940Sstevel@tonic-gate 	if (par_binding_name != NULL) {
8950Sstevel@tonic-gate 		if ((rv = lookup_in_confent_list(confent_list, 0,
8960Sstevel@tonic-gate 		    par_binding_name, unit_addr, port)) != -1)
8970Sstevel@tonic-gate 			goto done;
8980Sstevel@tonic-gate 	}
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	if (par_driver_name != NULL) {
9010Sstevel@tonic-gate 		/* lookup driver name */
9020Sstevel@tonic-gate 		if ((rv = lookup_in_confent_list(confent_list, 0,
9030Sstevel@tonic-gate 		    par_driver_name, unit_addr, port)) != -1)
9040Sstevel@tonic-gate 			goto done;
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 		/* finally, lookup class name */
9070Sstevel@tonic-gate 		par_driver_class = get_driver_class(rootdir, par_driver_name);
9080Sstevel@tonic-gate 		if (par_driver_class != NULL) {
9090Sstevel@tonic-gate 			if ((rv = lookup_in_confent_list(confent_list, 1,
9100Sstevel@tonic-gate 			    par_driver_class, unit_addr, port)) != -1)
9110Sstevel@tonic-gate 				goto done;
9120Sstevel@tonic-gate 		}
9130Sstevel@tonic-gate 	}
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 	/*
9160Sstevel@tonic-gate 	 * no match so far;
9170Sstevel@tonic-gate 	 * use the driver global mpxio-disable setting if exists.
9180Sstevel@tonic-gate 	 */
9190Sstevel@tonic-gate 	rv = mpxio_disable;
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate done:
9220Sstevel@tonic-gate 	if (node_name != NULL)
9230Sstevel@tonic-gate 		*(node_name - 1) = '/';
9240Sstevel@tonic-gate 	if (node_addr != NULL)
9250Sstevel@tonic-gate 		*(node_addr - 1) = '@';
9260Sstevel@tonic-gate 	if (par_driver_class != NULL)
9270Sstevel@tonic-gate 		free(par_driver_class);
9280Sstevel@tonic-gate 	if (confent_list != NULL)
9290Sstevel@tonic-gate 		free_confent_list(confent_list);
9300Sstevel@tonic-gate 	if (par_node != DI_NODE_NIL)
9310Sstevel@tonic-gate 		di_fini(par_node);
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 	return (rv);
9340Sstevel@tonic-gate }
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate /*
9370Sstevel@tonic-gate  * Given client_name return whether it is a phci or vhci based name.
9380Sstevel@tonic-gate  * client_name is /devices name of a client without the /devices prefix.
9390Sstevel@tonic-gate  *
9400Sstevel@tonic-gate  * client_name			Return value
9410Sstevel@tonic-gate  * .../fp@xxx/ssd@yyy		CLIENT_TYPE_PHCI
9420Sstevel@tonic-gate  * .../scsi_vhci/ssd@yyy	CLIENT_TYPE_VHCI
9430Sstevel@tonic-gate  * other			CLIENT_TYPE_UNKNOWN
9440Sstevel@tonic-gate  */
9450Sstevel@tonic-gate static client_type_t
client_name_type(char * client_name)9460Sstevel@tonic-gate client_name_type(char *client_name)
9470Sstevel@tonic-gate {
9480Sstevel@tonic-gate 	client_type_t client_type;
9490Sstevel@tonic-gate 	char *p1, *p2;
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 	logdmsg(("client_name_type: client_name = %s\n", client_name));
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 	if (strncmp(client_name, SLASH_SCSI_VHCI,
9540Sstevel@tonic-gate 	    sizeof (SLASH_SCSI_VHCI) - 1) == 0)
9550Sstevel@tonic-gate 		return (CLIENT_TYPE_VHCI);
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 	if (*client_name != '/')
9580Sstevel@tonic-gate 		return (CLIENT_TYPE_UNKNOWN);
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 	if ((p1 = strrchr(client_name, '/')) == NULL)
9610Sstevel@tonic-gate 		return (CLIENT_TYPE_UNKNOWN);
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate 	*p1 = '\0';
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	if ((p2 = strrchr(client_name, '/')) != NULL &&
9660Sstevel@tonic-gate 	    strncmp(p2, SLASH_FP_AT, sizeof (SLASH_FP_AT) - 1) == 0)
9670Sstevel@tonic-gate 		client_type = CLIENT_TYPE_PHCI;
9680Sstevel@tonic-gate 	else
9690Sstevel@tonic-gate 		client_type = CLIENT_TYPE_UNKNOWN;
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	*p1 = '/';
9720Sstevel@tonic-gate 	return (client_type);
9730Sstevel@tonic-gate }
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate /*
9760Sstevel@tonic-gate  * Compare controller name portion of dev1 and dev2.
9770Sstevel@tonic-gate  *
9780Sstevel@tonic-gate  * rootdir	root directory of the target environment
9790Sstevel@tonic-gate  * dev1		can be either a /dev link or /devices name in the target
9800Sstevel@tonic-gate  *		environemnt
9810Sstevel@tonic-gate  * dev2		/devices name of a device without the /devices prefix
9820Sstevel@tonic-gate  *
9830Sstevel@tonic-gate  * Returns:
9840Sstevel@tonic-gate  *	0	if controller names match
9850Sstevel@tonic-gate  *	1	if controller names don't match
9860Sstevel@tonic-gate  *	-1	an error occurred.
9870Sstevel@tonic-gate  */
9880Sstevel@tonic-gate static int
compare_controller(char * rootdir,char * dev1,char * dev2)9890Sstevel@tonic-gate compare_controller(char *rootdir, char *dev1, char *dev2)
9900Sstevel@tonic-gate {
9910Sstevel@tonic-gate 	int linksize;
9920Sstevel@tonic-gate 	char *p1, *p;
9930Sstevel@tonic-gate 	char physdev1[MAXPATHLEN];
9940Sstevel@tonic-gate 	char buf[MAXPATHLEN];
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 	logdmsg(("compare_controller: rootdir = %s, dev1 = %s, dev2 = %s\n",
9970Sstevel@tonic-gate 	    rootdir, dev1, dev2));
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	if (strncmp(dev1, SLASH_DEV_SLASH, sizeof (SLASH_DEV_SLASH) - 1)
10000Sstevel@tonic-gate 	    == 0) {
10010Sstevel@tonic-gate 		(void) snprintf(buf, MAXPATHLEN, "%s%s", rootdir, dev1);
10020Sstevel@tonic-gate 		if ((linksize = readlink(buf, physdev1, MAXPATHLEN)) > 0 &&
10030Sstevel@tonic-gate 		    linksize < (MAXPATHLEN - 1)) {
10040Sstevel@tonic-gate 			physdev1[linksize] = '\0';
10050Sstevel@tonic-gate 			logdmsg(("compare_controller: physdev1 = %s\n",
10060Sstevel@tonic-gate 			    physdev1));
10070Sstevel@tonic-gate 		} else
10080Sstevel@tonic-gate 			return (-1);
10090Sstevel@tonic-gate 	} else
10100Sstevel@tonic-gate 		(void) strlcpy(physdev1, dev1, MAXPATHLEN);
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 	if ((p1 = strstr(physdev1, SLASH_DEVICES)) == NULL)
10130Sstevel@tonic-gate 		return (-1);
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	p1 += sizeof (SLASH_DEVICES) - 1;
10160Sstevel@tonic-gate 	/* strip the device portion */
10170Sstevel@tonic-gate 	if ((p = strrchr(p1, '/')) == NULL)
10180Sstevel@tonic-gate 		return (-1);
10190Sstevel@tonic-gate 	*p = '\0';
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	if ((p = strrchr(dev2, '/')) == NULL)
10220Sstevel@tonic-gate 		return (-1);
10230Sstevel@tonic-gate 	*p = '\0';
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 	logdmsg(("compare_controller: path1 = %s, path2 = %s\n",
10260Sstevel@tonic-gate 	    p1, dev2));
10270Sstevel@tonic-gate 	if (strcmp(p1, dev2) == 0) {
10280Sstevel@tonic-gate 		*p = '/';
10290Sstevel@tonic-gate 		return (0);
10300Sstevel@tonic-gate 	} else {
10310Sstevel@tonic-gate 		*p = '/';
10320Sstevel@tonic-gate 		return (1);
10330Sstevel@tonic-gate 	}
10340Sstevel@tonic-gate }
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate /*
10370Sstevel@tonic-gate  * Check if the specified device path is on the root controller.
10380Sstevel@tonic-gate  *
10390Sstevel@tonic-gate  * rootdir	root directory of the target environment
10400Sstevel@tonic-gate  * path		/devices name of a device without the /devices prefix
10410Sstevel@tonic-gate  *
10420Sstevel@tonic-gate  * Returns
10430Sstevel@tonic-gate  *	1	if the path is on the root controller
10440Sstevel@tonic-gate  *	0	if the path is not on the root controller
10450Sstevel@tonic-gate  *	-1	if an error occurs
10460Sstevel@tonic-gate  */
10470Sstevel@tonic-gate static int
is_root_controller(char * rootdir,char * path)10480Sstevel@tonic-gate is_root_controller(char *rootdir, char *path)
10490Sstevel@tonic-gate {
10500Sstevel@tonic-gate 	FILE *fp;
10510Sstevel@tonic-gate 	char *tmpfile;
10520Sstevel@tonic-gate 	int rv = -1;
10530Sstevel@tonic-gate 	struct vfstab vfsent;
10540Sstevel@tonic-gate 	char buf[MAXPATHLEN];
10550Sstevel@tonic-gate 	char ctd[MAXNAMELEN + 1];
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	logdmsg(("is_root_controller: rootdir = %s, path = %s\n", rootdir,
10580Sstevel@tonic-gate 	    path));
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate 	(void) snprintf(buf, MAXPATHLEN, "%s%s", rootdir, VFSTAB);
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 	if ((fp = fopen(buf, "r")) == NULL) {
10630Sstevel@tonic-gate 		logdmsg(("is_root_controller: failed to open %s: %s\n",
10640Sstevel@tonic-gate 		    buf, strerror(errno)));
10650Sstevel@tonic-gate 		return (-1);
10660Sstevel@tonic-gate 	}
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	if (getvfsfile(fp, &vfsent, "/") != 0) {
10690Sstevel@tonic-gate 		logdmsg(("is_root_controller: getvfsfile: failed to read "
10700Sstevel@tonic-gate 		    "vfstab entry for mount point \"/\": %s\n",
10710Sstevel@tonic-gate 		    strerror(errno)));
10720Sstevel@tonic-gate 		(void) fclose(fp);
10730Sstevel@tonic-gate 		return (-1);
10740Sstevel@tonic-gate 	}
10750Sstevel@tonic-gate 	(void) fclose(fp);
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate 	/* check if the root is an svm metadisk */
10780Sstevel@tonic-gate 	if (strncmp(vfsent.vfs_special, META_DEV, sizeof (META_DEV) - 1) != 0) {
10790Sstevel@tonic-gate 		if (compare_controller(rootdir, vfsent.vfs_special, path) == 0)
10800Sstevel@tonic-gate 			return (1);
10810Sstevel@tonic-gate 		else
10820Sstevel@tonic-gate 			return (0);
10830Sstevel@tonic-gate 	}
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 	/* Don't use /var/run as it is not mounted in miniroot */
10860Sstevel@tonic-gate 	if ((tmpfile = tempnam("/tmp", "diirc")) == NULL) {
10870Sstevel@tonic-gate 		logdmsg(("is_root_controller: tempnam: failed: %s\n",
10880Sstevel@tonic-gate 		    strerror(errno)));
10890Sstevel@tonic-gate 		return (-1);
10900Sstevel@tonic-gate 	}
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 	/* get metadisk components using metastat command */
10930Sstevel@tonic-gate 	(void) snprintf(buf, MAXPATHLEN,
10940Sstevel@tonic-gate 	    "/usr/sbin/metastat -p %s 2>/dev/null | "
10950Sstevel@tonic-gate 	    "/usr/bin/grep ' 1 1 ' | "
10960Sstevel@tonic-gate 	    "/usr/bin/sed -e 's/^.* 1 1 //' | "
10970Sstevel@tonic-gate 	    "/usr/bin/cut -f1 -d ' ' > %s",
10980Sstevel@tonic-gate 	    vfsent.vfs_special + sizeof (META_DEV) - 1, tmpfile);
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	logdmsg(("is_root_controller: command = %s\n", buf));
11010Sstevel@tonic-gate 	fp = NULL;
11020Sstevel@tonic-gate 	if (system(buf) == 0 && (fp = fopen(tmpfile, "r")) != NULL) {
11030Sstevel@tonic-gate 		while (fscanf(fp, "%" VAL2STR(MAXNAMELEN) "s", ctd) == 1) {
11040Sstevel@tonic-gate 			(void) snprintf(buf, MAXPATHLEN, "/dev/dsk/%s", ctd);
11050Sstevel@tonic-gate 			if (compare_controller(rootdir, buf, path) == 0) {
11060Sstevel@tonic-gate 				rv = 1;
11070Sstevel@tonic-gate 				goto out;
11080Sstevel@tonic-gate 			}
11090Sstevel@tonic-gate 		}
11100Sstevel@tonic-gate 		rv = 0;
11110Sstevel@tonic-gate 	}
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate out:
11140Sstevel@tonic-gate 	if (fp)
11150Sstevel@tonic-gate 		(void) fclose(fp);
11160Sstevel@tonic-gate 	(void) unlink(tmpfile);
11170Sstevel@tonic-gate 	free(tmpfile);
11180Sstevel@tonic-gate 	return (rv);
11190Sstevel@tonic-gate }
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate static int
file_exists(char * rootdir,char * path)11220Sstevel@tonic-gate file_exists(char *rootdir, char *path)
11230Sstevel@tonic-gate {
11240Sstevel@tonic-gate 	struct stat stbuf;
11250Sstevel@tonic-gate 	char fullpath[MAXPATHLEN];
11260Sstevel@tonic-gate 	int x;
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 	(void) snprintf(fullpath, MAXPATHLEN, "%s%s", rootdir, path);
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 	x = stat(fullpath, &stbuf);
11310Sstevel@tonic-gate 	logdmsg(("file_exists: %s: %s\n", fullpath, (x == 0) ? "yes" : "no"));
11320Sstevel@tonic-gate 	if (x == 0)
11330Sstevel@tonic-gate 		return (1);
11340Sstevel@tonic-gate 	else
11350Sstevel@tonic-gate 		return (0);
11360Sstevel@tonic-gate }
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate /*
11390Sstevel@tonic-gate  * Check if mpxio is enabled or disabled on the specified device path.
11400Sstevel@tonic-gate  * Looks through the .conf files to determine the mpxio setting.
11410Sstevel@tonic-gate  *
11420Sstevel@tonic-gate  * rootdir	root directory of the target environment
11430Sstevel@tonic-gate  * path		/devices name of a device without the /devices prefix and
11440Sstevel@tonic-gate  *		minor name component.
11450Sstevel@tonic-gate  *
11460Sstevel@tonic-gate  * Returns
11470Sstevel@tonic-gate  *	1	if mpxio is disabled
11480Sstevel@tonic-gate  *	0	if mpxio is enabled
11490Sstevel@tonic-gate  *	-1	if an error occurs
11500Sstevel@tonic-gate  */
11510Sstevel@tonic-gate static int
is_mpxio_disabled(char * rootdir,char * path)11520Sstevel@tonic-gate is_mpxio_disabled(char *rootdir, char *path)
11530Sstevel@tonic-gate {
11540Sstevel@tonic-gate 	int mpxio_disable;
11550Sstevel@tonic-gate 	char *p;
11560Sstevel@tonic-gate 	int check_root_controller;
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 	logdmsg(("is_mpxio_disabled: rootdir = %s, path = %s\n",
11590Sstevel@tonic-gate 	    rootdir, path));
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 	if (file_exists(rootdir, SCSI_VHCI_CONF) == 0) {
11620Sstevel@tonic-gate 		/*
11630Sstevel@tonic-gate 		 * scsi_vhci.conf doesn't exist:
11640Sstevel@tonic-gate 		 *  if upgrading from a pre solaris 9 release. or
11650Sstevel@tonic-gate 		 *  if this function is called during fresh or flash install
11660Sstevel@tonic-gate 		 *  prior to installing scsi_vhci.conf file.
11670Sstevel@tonic-gate 		 */
11680Sstevel@tonic-gate 		if (file_exists(rootdir, "/kernel/drv"))
11690Sstevel@tonic-gate 			/* upgrading from pre solaris 9 */
11700Sstevel@tonic-gate 			return (1);
11710Sstevel@tonic-gate 		else
11720Sstevel@tonic-gate 			/* fresh or flash install */
11730Sstevel@tonic-gate 			return (0);
11740Sstevel@tonic-gate 	}
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 	mpxio_disable = lookup_in_conf_file(rootdir, SCSI_VHCI_CONF, NULL);
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 	/*
11790Sstevel@tonic-gate 	 * scsi_vhci.conf contains mpxio-disable property only in s9 and
11800Sstevel@tonic-gate 	 * s8+sfkpatch. This property is no longer present from s10 onwards.
11810Sstevel@tonic-gate 	 */
11820Sstevel@tonic-gate 	if (mpxio_disable == 1) {
11830Sstevel@tonic-gate 		/* upgrading from s8 or s9 with mpxio globally disabled */
11840Sstevel@tonic-gate 		return (1);
11850Sstevel@tonic-gate 	} else if (mpxio_disable == 0) {
11860Sstevel@tonic-gate 		/* upgrading from s8 or s9 with mpxio globally enabled */
11870Sstevel@tonic-gate 		check_root_controller = 1;
11880Sstevel@tonic-gate 	} else {
11890Sstevel@tonic-gate 		/*
11900Sstevel@tonic-gate 		 * We are looking at the s10 version of the file. This is
11910Sstevel@tonic-gate 		 * the case if this function is called after installing the
11920Sstevel@tonic-gate 		 * new scsi_vhci.conf file.
11930Sstevel@tonic-gate 		 */
11940Sstevel@tonic-gate 		check_root_controller = 0;
11950Sstevel@tonic-gate 	}
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 	if ((mpxio_disable = lookup_in_conf_file(rootdir, FP_CONF, path))
11980Sstevel@tonic-gate 	    != -1)
11990Sstevel@tonic-gate 		return (mpxio_disable);
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 	if ((p = strrchr(path, '/')) == NULL)
12020Sstevel@tonic-gate 		return (-1);
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 	*p = '\0';
12050Sstevel@tonic-gate 	if ((mpxio_disable = lookup_in_conf_file(rootdir, QLC_CONF, path))
12060Sstevel@tonic-gate 	    != -1) {
12070Sstevel@tonic-gate 		*p = '/';
12080Sstevel@tonic-gate 		return (mpxio_disable);
12090Sstevel@tonic-gate 	}
12100Sstevel@tonic-gate 	*p = '/';
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 	/*
12130Sstevel@tonic-gate 	 * mpxio-disable setting is not found in the .conf files.
12140Sstevel@tonic-gate 	 * The default is to enable mpxio, except if the path is on the root
12150Sstevel@tonic-gate 	 * controller.
12160Sstevel@tonic-gate 	 *
12170Sstevel@tonic-gate 	 * In s8 and s9 mpxio is not supported on the root controller.
12180Sstevel@tonic-gate 	 * NWS supplies a patch to enable root controller support in s8 and s9.
12190Sstevel@tonic-gate 	 * If the system had the patch installed, the fp.conf file would have
12200Sstevel@tonic-gate 	 * explicit "mpxio-disable=no" for the root controller. So we would
12210Sstevel@tonic-gate 	 * have found the mpxio-disable setting when we looked up this property
12220Sstevel@tonic-gate 	 * in the fp.conf file.
12230Sstevel@tonic-gate 	 */
12240Sstevel@tonic-gate 	if (check_root_controller) {
12250Sstevel@tonic-gate 		mpxio_disable = is_root_controller(rootdir, path);
12260Sstevel@tonic-gate 		logdmsg(("is_mpxio_disabled: is_root_controller returned %d\n",
12270Sstevel@tonic-gate 		    mpxio_disable));
12280Sstevel@tonic-gate 	} else
12290Sstevel@tonic-gate 		mpxio_disable = 0;
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 	return (mpxio_disable);
12320Sstevel@tonic-gate }
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate static int
vhci_ctl(sv_iocdata_t * iocp,int cmd)12350Sstevel@tonic-gate vhci_ctl(sv_iocdata_t *iocp, int cmd)
12360Sstevel@tonic-gate {
12370Sstevel@tonic-gate 	int fd, rv;
12380Sstevel@tonic-gate 
12390Sstevel@tonic-gate 	if ((fd = open(VHCI_CTL_NODE, O_RDWR)) < 0)
12400Sstevel@tonic-gate 		return (-1);
12410Sstevel@tonic-gate 	rv = ioctl(fd, cmd, iocp);
12420Sstevel@tonic-gate 	(void) close(fd);
12430Sstevel@tonic-gate 	return (rv);
12440Sstevel@tonic-gate }
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate /*
12470Sstevel@tonic-gate  * Convert a phci client name to vhci client name.
12480Sstevel@tonic-gate  *
12490Sstevel@tonic-gate  * phci_name	phci client /devices name without the /devices prefix and
12500Sstevel@tonic-gate  *		minor name component.
12510Sstevel@tonic-gate  *		ex: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
12520Sstevel@tonic-gate  *
12530Sstevel@tonic-gate  * Returns 	on success, vhci client name is returned. The memory for
12540Sstevel@tonic-gate  *		the vhci name is allocated by this function and the caller
12550Sstevel@tonic-gate  * 		must free it.
12560Sstevel@tonic-gate  *		on failure, NULL is returned.
12570Sstevel@tonic-gate  */
12580Sstevel@tonic-gate static char *
phci_to_vhci(char * phci_name)12590Sstevel@tonic-gate phci_to_vhci(char *phci_name)
12600Sstevel@tonic-gate {
12610Sstevel@tonic-gate 	sv_iocdata_t ioc;
12620Sstevel@tonic-gate 	char *slash, *addr, *retp;
12630Sstevel@tonic-gate 	char vhci_name_buf[MAXPATHLEN];
12640Sstevel@tonic-gate 	char phci_name_buf[MAXPATHLEN];
12650Sstevel@tonic-gate 	char addr_buf[MAXNAMELEN];
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 	logdmsg(("phci_to_vhci: pchi_name =  %s\n", phci_name));
12680Sstevel@tonic-gate 	(void) strlcpy(phci_name_buf, phci_name, MAXPATHLEN);
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	if ((slash = strrchr(phci_name_buf, '/')) == NULL ||
12710Sstevel@tonic-gate 	    (addr = strchr(slash, '@')) == NULL)
12720Sstevel@tonic-gate 		return (NULL);
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate 	*slash = '\0';
12750Sstevel@tonic-gate 	addr++;
12760Sstevel@tonic-gate 	(void) strlcpy(addr_buf, addr, MAXNAMELEN);
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate 	bzero(&ioc, sizeof (sv_iocdata_t));
12790Sstevel@tonic-gate 	ioc.client = vhci_name_buf;
12800Sstevel@tonic-gate 	ioc.phci = phci_name_buf;
12810Sstevel@tonic-gate 	ioc.addr = addr_buf;
12820Sstevel@tonic-gate 	if (vhci_ctl(&ioc, SCSI_VHCI_GET_CLIENT_NAME) != 0) {
12830Sstevel@tonic-gate 		logdmsg(("phci_to_vhci: vhci_ctl failed: %s\n",
12840Sstevel@tonic-gate 		    strerror(errno)));
12850Sstevel@tonic-gate 		return (NULL);
12860Sstevel@tonic-gate 	}
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 	retp = strdup(vhci_name_buf);
12890Sstevel@tonic-gate 	logdmsg(("phci_to_vhci: vhci name = %s\n", STRVAL(retp)));
12900Sstevel@tonic-gate 	return (retp);
12910Sstevel@tonic-gate }
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate static int
add_to_phci_list(char ** phci_list,sv_path_info_t * pi,int npaths,int state,char * node_name)12940Sstevel@tonic-gate add_to_phci_list(char **phci_list, sv_path_info_t *pi, int npaths, int state,
12950Sstevel@tonic-gate     char *node_name)
12960Sstevel@tonic-gate {
12970Sstevel@tonic-gate 	int rv = 0;
12980Sstevel@tonic-gate 	char name[MAXPATHLEN];
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 	while (npaths--) {
13010Sstevel@tonic-gate 		if (state == pi->ret_state) {
130282Scth 			(void) snprintf(name, MAXPATHLEN, "%s/%s@%s",
13030Sstevel@tonic-gate 			    pi->device.ret_phci, node_name, pi->ret_addr);
13040Sstevel@tonic-gate 			if ((*phci_list = strdup(name)) == NULL)
13050Sstevel@tonic-gate 				return (-1);
13060Sstevel@tonic-gate 			phci_list++;
13070Sstevel@tonic-gate 			rv++;
13080Sstevel@tonic-gate 		}
13090Sstevel@tonic-gate 		pi++;
13100Sstevel@tonic-gate 	}
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate 	return (rv);
13130Sstevel@tonic-gate }
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate static void
free_pathlist(char ** pathlist)13160Sstevel@tonic-gate free_pathlist(char **pathlist)
13170Sstevel@tonic-gate {
13180Sstevel@tonic-gate 	char **p;
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate 	if (pathlist != NULL) {
13210Sstevel@tonic-gate 		for (p = pathlist; *p != NULL; p++)
13220Sstevel@tonic-gate 			free(*p);
13230Sstevel@tonic-gate 		free(pathlist);
13240Sstevel@tonic-gate 	}
13250Sstevel@tonic-gate }
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate /*
13290Sstevel@tonic-gate  * Convert a vhci client name to phci client names.
13300Sstevel@tonic-gate  *
13310Sstevel@tonic-gate  * vhci_name	vhci client /devices name without the /devices prefix and
13320Sstevel@tonic-gate  *		minor name component.
13330Sstevel@tonic-gate  * num_paths	On return, *num_paths is set to the number paths in the
13340Sstevel@tonic-gate  *		returned path list.
13350Sstevel@tonic-gate  *
13360Sstevel@tonic-gate  * Returns 	NULL terminated path list containing phci client paths is
13370Sstevel@tonic-gate  *		returned on success. The memory for the path list is
13380Sstevel@tonic-gate  *		allocated by this function and the caller must free it by
13390Sstevel@tonic-gate  *		calling free_pathlist().
13400Sstevel@tonic-gate  *		NULL is returned on failure.
13410Sstevel@tonic-gate  */
13420Sstevel@tonic-gate static char **
vhci_to_phci(char * vhci_name,int * num_paths)13430Sstevel@tonic-gate vhci_to_phci(char *vhci_name, int *num_paths)
13440Sstevel@tonic-gate {
13450Sstevel@tonic-gate 	sv_iocdata_t ioc;
13460Sstevel@tonic-gate 	uint_t npaths;
13470Sstevel@tonic-gate 	int n;
13480Sstevel@tonic-gate 	char **phci_list = NULL;
13490Sstevel@tonic-gate 	char *node_name, *at;
13500Sstevel@tonic-gate 	char vhci_name_buf[MAXPATHLEN];
13510Sstevel@tonic-gate 
13520Sstevel@tonic-gate 	logdmsg(("vhci_to_phci: vchi_name =  %s\n", vhci_name));
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate 	*num_paths = 0;
13550Sstevel@tonic-gate 	(void) strlcpy(vhci_name_buf, vhci_name, MAXPATHLEN);
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate 	/* first get the number paths */
13580Sstevel@tonic-gate 	bzero(&ioc, sizeof (sv_iocdata_t));
13590Sstevel@tonic-gate 	ioc.client = vhci_name_buf;
13600Sstevel@tonic-gate 	ioc.ret_elem = &npaths;
13610Sstevel@tonic-gate 	if (vhci_ctl(&ioc, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO) != 0 ||
13620Sstevel@tonic-gate 	    npaths == 0) {
13630Sstevel@tonic-gate 		logdmsg(("vhci_to_phci: vhci_ctl failed to get npaths: %s\n",
13640Sstevel@tonic-gate 		    strerror(errno)));
13650Sstevel@tonic-gate 		return (NULL);
13660Sstevel@tonic-gate 	}
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 	/* now allocate memory for the path information and get all paths */
13690Sstevel@tonic-gate 	bzero(&ioc, sizeof (sv_iocdata_t));
13700Sstevel@tonic-gate 	ioc.client = vhci_name_buf;
13710Sstevel@tonic-gate 	ioc.buf_elem = npaths;
13720Sstevel@tonic-gate 	ioc.ret_elem = &npaths;
13730Sstevel@tonic-gate 	if ((ioc.ret_buf = (sv_path_info_t *)calloc(npaths,
13740Sstevel@tonic-gate 	    sizeof (sv_path_info_t))) == NULL)
13750Sstevel@tonic-gate 		return (NULL);
13760Sstevel@tonic-gate 	if (vhci_ctl(&ioc, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO) != 0 ||
13770Sstevel@tonic-gate 	    npaths == 0) {
13780Sstevel@tonic-gate 		logdmsg(("vhci_to_phci: vhci_ctl failed: %s\n",
13790Sstevel@tonic-gate 		    strerror(errno)));
13800Sstevel@tonic-gate 		goto out;
13810Sstevel@tonic-gate 	}
13820Sstevel@tonic-gate 
13830Sstevel@tonic-gate 	if (ioc.buf_elem < npaths)
13840Sstevel@tonic-gate 		npaths = ioc.buf_elem;
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 	if ((node_name = strrchr(vhci_name_buf, '/')) == NULL ||
13870Sstevel@tonic-gate 	    (at = strchr(node_name, '@')) == NULL)
13880Sstevel@tonic-gate 		goto out;
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate 	node_name++;
13910Sstevel@tonic-gate 	*at = '\0';
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate 	/* allocate one more (than npaths) for the terminating NULL pointer */
13940Sstevel@tonic-gate 	if ((phci_list = calloc(npaths + 1, sizeof (char *))) == NULL)
13950Sstevel@tonic-gate 		goto out;
13960Sstevel@tonic-gate 
13970Sstevel@tonic-gate 	/*
13980Sstevel@tonic-gate 	 * add only online paths as non-online paths may not be accessible
13990Sstevel@tonic-gate 	 * in the target environment.
14000Sstevel@tonic-gate 	 */
14010Sstevel@tonic-gate 	if ((n = add_to_phci_list(phci_list, ioc.ret_buf, npaths,
14020Sstevel@tonic-gate 	    MDI_PATHINFO_STATE_ONLINE, node_name)) <= 0)
14030Sstevel@tonic-gate 		goto out;
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate 	free(ioc.ret_buf);
14060Sstevel@tonic-gate 	*num_paths = n;
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate #ifdef DEBUG
14090Sstevel@tonic-gate 	logdmsg(("vhci_to_phci: phci list:\n"));
14100Sstevel@tonic-gate 	log_pathlist(phci_list);
14110Sstevel@tonic-gate #endif
14120Sstevel@tonic-gate 	return (phci_list);
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate out:
14150Sstevel@tonic-gate 	free(ioc.ret_buf);
14160Sstevel@tonic-gate 	if (phci_list)
14170Sstevel@tonic-gate 		free_pathlist(phci_list);
14180Sstevel@tonic-gate 	return (NULL);
14190Sstevel@tonic-gate }
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate /*
14220Sstevel@tonic-gate  * build list of paths accessible from the target environment
14230Sstevel@tonic-gate  */
14240Sstevel@tonic-gate static int
build_pathlist(char * rootdir,char * vhcipath,char ** pathlist,int npaths)14250Sstevel@tonic-gate build_pathlist(char *rootdir, char *vhcipath, char **pathlist, int npaths)
14260Sstevel@tonic-gate {
14270Sstevel@tonic-gate 	int mpxio_disabled;
14280Sstevel@tonic-gate 	int i, j;
14290Sstevel@tonic-gate 	char *vpath = NULL;
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate 	for (i = 0; i < npaths; i++) {
14320Sstevel@tonic-gate 		mpxio_disabled = is_mpxio_disabled(rootdir, pathlist[i]);
14330Sstevel@tonic-gate 		logdmsg(("build_pathlist: mpxio_disabled = %d "
14340Sstevel@tonic-gate 		    "on path %s\n", mpxio_disabled, pathlist[i]));
14350Sstevel@tonic-gate 		if (mpxio_disabled == -1)
14360Sstevel@tonic-gate 			return (-1);
14370Sstevel@tonic-gate 		if (mpxio_disabled == 0) {
14380Sstevel@tonic-gate 			/*
14390Sstevel@tonic-gate 			 * mpxio is enabled on this phci path.
14400Sstevel@tonic-gate 			 * So use vhci path instead of phci path.
14410Sstevel@tonic-gate 			 */
14420Sstevel@tonic-gate 			if (vpath == NULL) {
14430Sstevel@tonic-gate 				if ((vpath = strdup(vhcipath)) == NULL)
14440Sstevel@tonic-gate 					return (-1);
14450Sstevel@tonic-gate 				free(pathlist[i]);
14460Sstevel@tonic-gate 				/* keep vhci path at beginning of the list */
14470Sstevel@tonic-gate 				for (j = i; j > 0; j--)
14480Sstevel@tonic-gate 					pathlist[j] = pathlist[j - 1];
14490Sstevel@tonic-gate 				pathlist[0] = vpath;
14500Sstevel@tonic-gate 			} else {
14510Sstevel@tonic-gate 				free(pathlist[i]);
14520Sstevel@tonic-gate 				npaths--;
14530Sstevel@tonic-gate 				for (j = i; j < npaths; j++)
14540Sstevel@tonic-gate 					pathlist[j] = pathlist[j + 1];
14550Sstevel@tonic-gate 				pathlist[npaths] = NULL;
14560Sstevel@tonic-gate 				/* compensate for i++ in the for loop */
14570Sstevel@tonic-gate 				i--;
14580Sstevel@tonic-gate 			}
14590Sstevel@tonic-gate 		}
14600Sstevel@tonic-gate 	}
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate #ifdef DEBUG
14630Sstevel@tonic-gate 	logdmsg(("build_pathlist: returning npaths = %d, pathlist:\n", npaths));
14640Sstevel@tonic-gate 	log_pathlist(pathlist);
14650Sstevel@tonic-gate #endif
14660Sstevel@tonic-gate 	return (npaths);
14670Sstevel@tonic-gate }
14680Sstevel@tonic-gate 
14690Sstevel@tonic-gate /*
14700Sstevel@tonic-gate  * Check if the specified device is refenced in the vfstab file.
14710Sstevel@tonic-gate  * Return 1 if referenced, 0 if not.
14720Sstevel@tonic-gate  *
14730Sstevel@tonic-gate  * rootdir	root directory of the target environment
14740Sstevel@tonic-gate  * nodepath	/devices path of a device in the target environment without
14750Sstevel@tonic-gate  *		the /devices prefix and minor component.
14760Sstevel@tonic-gate  */
14770Sstevel@tonic-gate static int
is_dev_in_vfstab(char * rootdir,char * nodepath)14780Sstevel@tonic-gate is_dev_in_vfstab(char *rootdir, char *nodepath)
14790Sstevel@tonic-gate {
14800Sstevel@tonic-gate 	FILE *fp;
14810Sstevel@tonic-gate 	int linksize;
14820Sstevel@tonic-gate 	struct vfstab vfsent;
14830Sstevel@tonic-gate 	char *abspath, *minor;
14840Sstevel@tonic-gate 	char physpath[MAXPATHLEN];
14850Sstevel@tonic-gate 	char buf[MAXPATHLEN];
14860Sstevel@tonic-gate 
14870Sstevel@tonic-gate 	logdmsg(("is_dev_in_vfstab: rootdir = %s, nodepath = %s\n",
14880Sstevel@tonic-gate 	    rootdir, nodepath));
14890Sstevel@tonic-gate 
14900Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%s%s", rootdir, VFSTAB);
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 	if ((fp = fopen(buf, "r")) == NULL)
14930Sstevel@tonic-gate 		return (0);
14940Sstevel@tonic-gate 
14950Sstevel@tonic-gate 	/*
14960Sstevel@tonic-gate 	 * read device specials from vfstab and compare names at physical
14970Sstevel@tonic-gate 	 * node path level.
14980Sstevel@tonic-gate 	 */
14990Sstevel@tonic-gate 	while (getvfsent(fp, &vfsent) == 0) {
15000Sstevel@tonic-gate 		if (strncmp(vfsent.vfs_special, SLASH_DEV_SLASH,
15010Sstevel@tonic-gate 		    sizeof (SLASH_DEV_SLASH) - 1) == 0) {
15020Sstevel@tonic-gate 			(void) snprintf(buf, MAXPATHLEN, "%s%s",
15030Sstevel@tonic-gate 			    rootdir, vfsent.vfs_special);
15040Sstevel@tonic-gate 			if ((linksize = readlink(buf, physpath,
15050Sstevel@tonic-gate 			    MAXPATHLEN)) > 0 && linksize < (MAXPATHLEN - 1)) {
15060Sstevel@tonic-gate 				physpath[linksize] = '\0';
15070Sstevel@tonic-gate 				if ((abspath = strstr(physpath,
15080Sstevel@tonic-gate 				    SLASH_DEVICES_SLASH)) == NULL)
15090Sstevel@tonic-gate 					continue;
15100Sstevel@tonic-gate 			} else
15110Sstevel@tonic-gate 				continue;
15120Sstevel@tonic-gate 		} else if (strncmp(vfsent.vfs_special, SLASH_DEVICES_SLASH,
15130Sstevel@tonic-gate 		    sizeof (SLASH_DEVICES_SLASH) - 1) == 0) {
15140Sstevel@tonic-gate 			(void) strlcpy(physpath, vfsent.vfs_special,
15150Sstevel@tonic-gate 			    MAXPATHLEN);
15160Sstevel@tonic-gate 			abspath = physpath;
15170Sstevel@tonic-gate 		} else
15180Sstevel@tonic-gate 			continue;
15190Sstevel@tonic-gate 
15200Sstevel@tonic-gate 		/* point to / after /devices */
15210Sstevel@tonic-gate 		abspath += sizeof (SLASH_DEVICES_SLASH) - 2;
15220Sstevel@tonic-gate 		/* strip minor component */
15230Sstevel@tonic-gate 		if ((minor = strrchr(abspath, ':')) != NULL)
15240Sstevel@tonic-gate 			*minor = '\0';
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 		if (strcmp(nodepath, abspath) == 0) {
15270Sstevel@tonic-gate 			(void) fclose(fp);
15280Sstevel@tonic-gate 			logdmsg(("is_dev_in_vfstab: returning 1\n"));
15290Sstevel@tonic-gate 			return (1);
15300Sstevel@tonic-gate 		}
15310Sstevel@tonic-gate 	}
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 	(void) fclose(fp);
15340Sstevel@tonic-gate 	return (0);
15350Sstevel@tonic-gate }
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate #endif /* __sparc */
15380Sstevel@tonic-gate 
15390Sstevel@tonic-gate static int
devlink_callback(di_devlink_t devlink,void * argp)15400Sstevel@tonic-gate devlink_callback(di_devlink_t devlink, void *argp)
15410Sstevel@tonic-gate {
15420Sstevel@tonic-gate 	const char *link;
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate 	if ((link = di_devlink_path(devlink)) != NULL)
15450Sstevel@tonic-gate 		(void) strlcpy((char *)argp, link, MAXPATHLEN);
15460Sstevel@tonic-gate 
15470Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
15480Sstevel@tonic-gate }
15490Sstevel@tonic-gate 
15500Sstevel@tonic-gate /*
15510Sstevel@tonic-gate  * Get the /dev name in the install environment corresponding to physpath.
15520Sstevel@tonic-gate  *
15530Sstevel@tonic-gate  * physpath	/devices path in the install environment without the /devices
15540Sstevel@tonic-gate  * 		prefix.
15550Sstevel@tonic-gate  * buf		caller supplied buffer where the /dev name is placed on return
15560Sstevel@tonic-gate  * bufsz	length of the buffer
15570Sstevel@tonic-gate  *
15580Sstevel@tonic-gate  * Returns	strlen of the /dev name on success, -1 on failure.
15590Sstevel@tonic-gate  */
15600Sstevel@tonic-gate static int
get_install_devlink(char * physpath,char * buf,size_t bufsz)15610Sstevel@tonic-gate get_install_devlink(char *physpath, char *buf, size_t bufsz)
15620Sstevel@tonic-gate {
15630Sstevel@tonic-gate 	di_devlink_handle_t devlink_hdl;
15640Sstevel@tonic-gate 	char devname[MAXPATHLEN];
1565*12627SGangadhar.M@Sun.COM 	int tries = 0;
1566*12627SGangadhar.M@Sun.COM 	int sleeptime = 2; /* number of seconds to sleep between retries */
1567*12627SGangadhar.M@Sun.COM 	int maxtries = 10; /* maximum number of tries */
15680Sstevel@tonic-gate 
15690Sstevel@tonic-gate 	logdmsg(("get_install_devlink: physpath = %s\n", physpath));
15700Sstevel@tonic-gate 
1571*12627SGangadhar.M@Sun.COM 	/*
1572*12627SGangadhar.M@Sun.COM 	 * devlink_db sync happens after MINOR_FINI_TIMEOUT_DEFAULT secs
1573*12627SGangadhar.M@Sun.COM 	 * after dev link creation. So wait for minimum that amout of time.
1574*12627SGangadhar.M@Sun.COM 	 */
1575*12627SGangadhar.M@Sun.COM 
1576*12627SGangadhar.M@Sun.COM retry:
1577*12627SGangadhar.M@Sun.COM 	(void) sleep(sleeptime);
1578*12627SGangadhar.M@Sun.COM 
15790Sstevel@tonic-gate 	if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
15800Sstevel@tonic-gate 		logdmsg(("get_install_devlink: di_devlink_init() failed: %s\n",
15810Sstevel@tonic-gate 		    strerror(errno)));
15820Sstevel@tonic-gate 		return (-1);
15830Sstevel@tonic-gate 	}
15840Sstevel@tonic-gate 
15850Sstevel@tonic-gate 	devname[0] = '\0';
15860Sstevel@tonic-gate 	if (di_devlink_walk(devlink_hdl, NULL, physpath, DI_PRIMARY_LINK,
1587*12627SGangadhar.M@Sun.COM 	    devname, devlink_callback) == 0) {
1588*12627SGangadhar.M@Sun.COM 		if (devname[0] == '\0' && tries < maxtries) {
1589*12627SGangadhar.M@Sun.COM 			tries++;
1590*12627SGangadhar.M@Sun.COM 			(void) di_devlink_fini(&devlink_hdl);
1591*12627SGangadhar.M@Sun.COM 			goto retry;
1592*12627SGangadhar.M@Sun.COM 		} else if (devname[0] == '\0') {
1593*12627SGangadhar.M@Sun.COM 			logdmsg(("get_install_devlink: di_devlink_walk"
1594*12627SGangadhar.M@Sun.COM 			    " failed: %s\n", strerror(errno)));
1595*12627SGangadhar.M@Sun.COM 			(void) di_devlink_fini(&devlink_hdl);
1596*12627SGangadhar.M@Sun.COM 			return (-1);
1597*12627SGangadhar.M@Sun.COM 		}
1598*12627SGangadhar.M@Sun.COM 	} else {
15990Sstevel@tonic-gate 		logdmsg(("get_install_devlink: di_devlink_walk failed: %s\n",
16000Sstevel@tonic-gate 		    strerror(errno)));
16010Sstevel@tonic-gate 		(void) di_devlink_fini(&devlink_hdl);
16020Sstevel@tonic-gate 		return (-1);
16030Sstevel@tonic-gate 	}
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 	(void) di_devlink_fini(&devlink_hdl);
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate 	logdmsg(("get_install_devlink: devlink = %s\n", devname));
16080Sstevel@tonic-gate 	return (strlcpy(buf, devname, bufsz));
16090Sstevel@tonic-gate }
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate /*
16120Sstevel@tonic-gate  * Get the /dev name in the target environment corresponding to physpath.
16130Sstevel@tonic-gate  *
16140Sstevel@tonic-gate  * rootdir	root directory of the target environment
16150Sstevel@tonic-gate  * physpath	/devices path in the target environment without the /devices
16160Sstevel@tonic-gate  * 		prefix.
16170Sstevel@tonic-gate  * buf		caller supplied buffer where the /dev name is placed on return
16180Sstevel@tonic-gate  * bufsz	length of the buffer
16190Sstevel@tonic-gate  *
16200Sstevel@tonic-gate  * Returns	strlen of the /dev name on success, -1 on failure.
16210Sstevel@tonic-gate  */
16220Sstevel@tonic-gate static int
get_target_devlink(char * rootdir,char * physpath,char * buf,size_t bufsz)16230Sstevel@tonic-gate get_target_devlink(char *rootdir, char *physpath, char *buf, size_t bufsz)
16240Sstevel@tonic-gate {
16250Sstevel@tonic-gate 	char *p;
16260Sstevel@tonic-gate 	int linksize;
16270Sstevel@tonic-gate 	DIR *dirp;
16280Sstevel@tonic-gate 	struct dirent *direntry;
16290Sstevel@tonic-gate 	char dirpath[MAXPATHLEN];
16300Sstevel@tonic-gate 	char devname[MAXPATHLEN];
16310Sstevel@tonic-gate 	char physdev[MAXPATHLEN];
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate 	logdmsg(("get_target_devlink: rootdir = %s, physpath = %s\n",
16340Sstevel@tonic-gate 	    rootdir, physpath));
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 	if ((p = strrchr(physpath, '/')) == NULL)
16370Sstevel@tonic-gate 		return (-1);
16380Sstevel@tonic-gate 
16390Sstevel@tonic-gate 	if (strstr(p, ",raw") != NULL) {
16400Sstevel@tonic-gate 		(void) snprintf(dirpath, MAXPATHLEN, "%s/dev/rdsk", rootdir);
16410Sstevel@tonic-gate 	} else {
16420Sstevel@tonic-gate 		(void) snprintf(dirpath, MAXPATHLEN, "%s/dev/dsk", rootdir);
16430Sstevel@tonic-gate 	}
16440Sstevel@tonic-gate 
16450Sstevel@tonic-gate 	if ((dirp = opendir(dirpath)) == NULL)
16460Sstevel@tonic-gate 		return (-1);
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate 	while ((direntry = readdir(dirp)) != NULL) {
16490Sstevel@tonic-gate 		if (strcmp(direntry->d_name, ".") == 0 ||
16500Sstevel@tonic-gate 		    strcmp(direntry->d_name, "..") == 0)
16510Sstevel@tonic-gate 			continue;
16520Sstevel@tonic-gate 
16530Sstevel@tonic-gate 		(void) snprintf(devname, MAXPATHLEN, "%s/%s",
16540Sstevel@tonic-gate 		    dirpath, direntry->d_name);
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 		if ((linksize = readlink(devname, physdev, MAXPATHLEN)) > 0 &&
16570Sstevel@tonic-gate 		    linksize < (MAXPATHLEN - 1)) {
16580Sstevel@tonic-gate 			physdev[linksize] = '\0';
16590Sstevel@tonic-gate 			if ((p = strstr(physdev, SLASH_DEVICES_SLASH)) !=
16600Sstevel@tonic-gate 			    NULL && strcmp(p + sizeof (SLASH_DEVICES) - 1,
16610Sstevel@tonic-gate 			    physpath) == 0) {
16620Sstevel@tonic-gate 				(void) closedir(dirp);
16630Sstevel@tonic-gate 				logdmsg(("get_target_devlink: devlink = %s\n",
16640Sstevel@tonic-gate 				    devname + strlen(rootdir)));
16650Sstevel@tonic-gate 				return (strlcpy(buf, devname + strlen(rootdir),
16660Sstevel@tonic-gate 				    bufsz));
16670Sstevel@tonic-gate 			}
16680Sstevel@tonic-gate 		}
16690Sstevel@tonic-gate 	}
16700Sstevel@tonic-gate 
16710Sstevel@tonic-gate 	(void) closedir(dirp);
16720Sstevel@tonic-gate 	return (-1);
16730Sstevel@tonic-gate }
16740Sstevel@tonic-gate 
16750Sstevel@tonic-gate /*
16760Sstevel@tonic-gate  * Convert device name to physpath.
16770Sstevel@tonic-gate  *
16780Sstevel@tonic-gate  * rootdir	root directory
16790Sstevel@tonic-gate  * devname	a /dev name or /devices name under rootdir
16800Sstevel@tonic-gate  * physpath	caller supplied buffer where the /devices path will be placed
16810Sstevel@tonic-gate  *		on return (without the /devices prefix).
16820Sstevel@tonic-gate  * physpathlen	length of the physpath buffer
16830Sstevel@tonic-gate  *
16840Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
16850Sstevel@tonic-gate  */
16860Sstevel@tonic-gate static int
devname2physpath(char * rootdir,char * devname,char * physpath,int physpathlen)16870Sstevel@tonic-gate devname2physpath(char *rootdir, char *devname, char *physpath, int physpathlen)
16880Sstevel@tonic-gate {
16890Sstevel@tonic-gate 	int linksize;
16900Sstevel@tonic-gate 	char *p;
16910Sstevel@tonic-gate 	char devlink[MAXPATHLEN];
16920Sstevel@tonic-gate 	char tmpphyspath[MAXPATHLEN];
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate 	logdmsg(("devname2physpath: rootdir = %s, devname = %s\n",
16950Sstevel@tonic-gate 	    rootdir, devname));
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate 	if (strncmp(devname, SLASH_DEVICES_SLASH,
16980Sstevel@tonic-gate 	    sizeof (SLASH_DEVICES_SLASH) - 1) != 0) {
16990Sstevel@tonic-gate 		if (*rootdir == '\0')
17000Sstevel@tonic-gate 			linksize = readlink(devname, tmpphyspath, MAXPATHLEN);
17010Sstevel@tonic-gate 		else {
17020Sstevel@tonic-gate 			(void) snprintf(devlink, MAXPATHLEN, "%s%s",
17030Sstevel@tonic-gate 			    rootdir, devname);
17040Sstevel@tonic-gate 			linksize = readlink(devlink, tmpphyspath, MAXPATHLEN);
17050Sstevel@tonic-gate 		}
17060Sstevel@tonic-gate 		if (linksize > 0 && linksize < (MAXPATHLEN - 1)) {
17070Sstevel@tonic-gate 			tmpphyspath[linksize] = '\0';
17080Sstevel@tonic-gate 			if ((p = strstr(tmpphyspath, SLASH_DEVICES_SLASH))
17090Sstevel@tonic-gate 			    == NULL)
17100Sstevel@tonic-gate 				return (-1);
17110Sstevel@tonic-gate 		} else
17120Sstevel@tonic-gate 			return (-1);
17130Sstevel@tonic-gate 	} else
17140Sstevel@tonic-gate 		p = devname;
17150Sstevel@tonic-gate 
17160Sstevel@tonic-gate 	(void) strlcpy(physpath, p + sizeof (SLASH_DEVICES) - 1, physpathlen);
17170Sstevel@tonic-gate 	logdmsg(("devname2physpath: physpath = %s\n", physpath));
17180Sstevel@tonic-gate 	return (0);
17190Sstevel@tonic-gate }
17200Sstevel@tonic-gate 
17210Sstevel@tonic-gate /*
17220Sstevel@tonic-gate  * Map a device name (devname) from the target environment to the
17230Sstevel@tonic-gate  * install environment.
17240Sstevel@tonic-gate  *
17250Sstevel@tonic-gate  * rootdir	root directory of the target environment
17260Sstevel@tonic-gate  * devname	/dev or /devices name under the target environment
17270Sstevel@tonic-gate  * buf		caller supplied buffer where the mapped /dev name is placed
17280Sstevel@tonic-gate  *		on return
17290Sstevel@tonic-gate  * bufsz	length of the buffer
17300Sstevel@tonic-gate  *
17310Sstevel@tonic-gate  * Returns	strlen of the mapped /dev name on success, -1 on failure.
17320Sstevel@tonic-gate  */
17330Sstevel@tonic-gate int
devfs_target2install(const char * rootdir,const char * devname,char * buf,size_t bufsz)17340Sstevel@tonic-gate devfs_target2install(const char *rootdir, const char *devname, char *buf,
17350Sstevel@tonic-gate     size_t bufsz)
17360Sstevel@tonic-gate {
17370Sstevel@tonic-gate 	char physpath[MAXPATHLEN];
17380Sstevel@tonic-gate 
17390Sstevel@tonic-gate 	logdmsg(("devfs_target2install: rootdir = %s, devname = %s\n",
17400Sstevel@tonic-gate 	    STRVAL(rootdir), STRVAL(devname)));
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate 	if (rootdir == NULL || devname == NULL || buf == NULL || bufsz == 0)
17430Sstevel@tonic-gate 		return (-1);
17440Sstevel@tonic-gate 
17450Sstevel@tonic-gate 	if (strcmp(rootdir, "/") == 0)
17460Sstevel@tonic-gate 		rootdir = "";
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 	if (devname2physpath((char *)rootdir, (char *)devname, physpath,
17490Sstevel@tonic-gate 	    MAXPATHLEN) != 0)
17500Sstevel@tonic-gate 		return (-1);
17510Sstevel@tonic-gate 
17520Sstevel@tonic-gate #ifdef __sparc
17530Sstevel@tonic-gate 	if (client_name_type(physpath) == CLIENT_TYPE_PHCI) {
17540Sstevel@tonic-gate 		char *mapped_node_path, *minor;
17550Sstevel@tonic-gate 		char minorbuf[MAXNAMELEN];
17560Sstevel@tonic-gate 
17570Sstevel@tonic-gate 		/* strip minor component if present */
17580Sstevel@tonic-gate 		if ((minor = strrchr(physpath, ':')) != NULL) {
17590Sstevel@tonic-gate 			*minor = '\0';
17600Sstevel@tonic-gate 			minor++;
17610Sstevel@tonic-gate 			(void) strlcpy(minorbuf, minor, MAXNAMELEN);
17620Sstevel@tonic-gate 		}
17630Sstevel@tonic-gate 		if ((mapped_node_path = phci_to_vhci(physpath)) != NULL) {
17640Sstevel@tonic-gate 			if (minor)
17650Sstevel@tonic-gate 				(void) snprintf(physpath, MAXPATHLEN,
17660Sstevel@tonic-gate 				    "%s:%s", mapped_node_path, minorbuf);
17670Sstevel@tonic-gate 			else
17680Sstevel@tonic-gate 				(void) strlcpy(physpath, mapped_node_path,
17690Sstevel@tonic-gate 				    MAXPATHLEN);
17700Sstevel@tonic-gate 			free(mapped_node_path);
17710Sstevel@tonic-gate 			logdmsg(("devfs_target2install: mapped physpath: %s\n",
17720Sstevel@tonic-gate 			    physpath));
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate 		} else if (minor)
17750Sstevel@tonic-gate 			*(minor - 1) = ':';
17760Sstevel@tonic-gate 	}
17770Sstevel@tonic-gate #endif /* __sparc */
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate 	return (get_install_devlink(physpath, buf, bufsz));
17800Sstevel@tonic-gate }
17810Sstevel@tonic-gate 
17820Sstevel@tonic-gate /*
17830Sstevel@tonic-gate  * Map a device name (devname) from the install environment to the target
17840Sstevel@tonic-gate  * environment.
17850Sstevel@tonic-gate  *
17860Sstevel@tonic-gate  * rootdir	root directory of the target environment
17870Sstevel@tonic-gate  * devname	/dev or /devices name under the install environment
17880Sstevel@tonic-gate  * buf		caller supplied buffer where the mapped /dev name is placed
17890Sstevel@tonic-gate  *		on return
17900Sstevel@tonic-gate  * bufsz	length of the buffer
17910Sstevel@tonic-gate  *
17920Sstevel@tonic-gate  * Returns	strlen of the mapped /dev name on success, -1 on failure.
17930Sstevel@tonic-gate  */
17940Sstevel@tonic-gate int
devfs_install2target(const char * rootdir,const char * devname,char * buf,size_t bufsz)17950Sstevel@tonic-gate devfs_install2target(const char *rootdir, const char *devname, char *buf,
17960Sstevel@tonic-gate     size_t bufsz)
17970Sstevel@tonic-gate {
17980Sstevel@tonic-gate 	char physpath[MAXPATHLEN];
17990Sstevel@tonic-gate 
18000Sstevel@tonic-gate 	logdmsg(("devfs_install2target: rootdir = %s, devname = %s\n",
18010Sstevel@tonic-gate 	    STRVAL(rootdir), STRVAL(devname)));
18020Sstevel@tonic-gate 
18030Sstevel@tonic-gate 	if (rootdir == NULL || devname == NULL || buf == NULL || bufsz == 0)
18040Sstevel@tonic-gate 		return (-1);
18050Sstevel@tonic-gate 
18060Sstevel@tonic-gate 	if (strcmp(rootdir, "/") == 0)
18070Sstevel@tonic-gate 		rootdir = "";
18080Sstevel@tonic-gate 
18090Sstevel@tonic-gate 	if (devname2physpath("", (char *)devname, physpath, MAXPATHLEN) != 0)
18100Sstevel@tonic-gate 		return (-1);
18110Sstevel@tonic-gate 
18120Sstevel@tonic-gate #ifdef __sparc
18130Sstevel@tonic-gate 	if (client_name_type(physpath) == CLIENT_TYPE_VHCI) {
18140Sstevel@tonic-gate 		char **pathlist;
18150Sstevel@tonic-gate 		int npaths, i, j;
18160Sstevel@tonic-gate 		char *minor;
18170Sstevel@tonic-gate 		char minorbuf[MAXNAMELEN];
18180Sstevel@tonic-gate 
18190Sstevel@tonic-gate 		/* strip minor component if present */
18200Sstevel@tonic-gate 		if ((minor = strrchr(physpath, ':')) != NULL) {
18210Sstevel@tonic-gate 			*minor = '\0';
18220Sstevel@tonic-gate 			minor++;
18230Sstevel@tonic-gate 			(void) strlcpy(minorbuf, minor, MAXNAMELEN);
18240Sstevel@tonic-gate 		}
18250Sstevel@tonic-gate 
18260Sstevel@tonic-gate 		if ((pathlist = vhci_to_phci(physpath, &npaths)) == NULL)
18270Sstevel@tonic-gate 			return (-1);
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate 		if ((npaths = build_pathlist((char *)rootdir, physpath,
18300Sstevel@tonic-gate 		    pathlist, npaths)) <= 0) {
18310Sstevel@tonic-gate 			free_pathlist(pathlist);
18320Sstevel@tonic-gate 			return (-1);
18330Sstevel@tonic-gate 		}
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate 		/*
18360Sstevel@tonic-gate 		 * in case of more than one path, try to use the path
18370Sstevel@tonic-gate 		 * referenced in the vfstab file, otherwise use the first path.
18380Sstevel@tonic-gate 		 */
18390Sstevel@tonic-gate 		j = 0;
18400Sstevel@tonic-gate 		if (npaths > 1) {
18410Sstevel@tonic-gate 			for (i = 0; i < npaths; i++) {
18420Sstevel@tonic-gate 				if (is_dev_in_vfstab((char *)rootdir,
18430Sstevel@tonic-gate 				    pathlist[i])) {
18440Sstevel@tonic-gate 					j = i;
18450Sstevel@tonic-gate 					break;
18460Sstevel@tonic-gate 				}
18470Sstevel@tonic-gate 			}
18480Sstevel@tonic-gate 		}
18490Sstevel@tonic-gate 
18500Sstevel@tonic-gate 		if (minor)
18510Sstevel@tonic-gate 			(void) snprintf(physpath, MAXPATHLEN,
18520Sstevel@tonic-gate 			    "%s:%s", pathlist[j], minorbuf);
18530Sstevel@tonic-gate 		else
18540Sstevel@tonic-gate 			(void) strlcpy(physpath, pathlist[j], MAXPATHLEN);
18550Sstevel@tonic-gate 		free_pathlist(pathlist);
18560Sstevel@tonic-gate 	}
18570Sstevel@tonic-gate #endif /* __sparc */
18580Sstevel@tonic-gate 
18590Sstevel@tonic-gate 	return (get_target_devlink((char *)rootdir, physpath, buf, bufsz));
18600Sstevel@tonic-gate }
18610Sstevel@tonic-gate 
18624870Sjg /*
18634870Sjg  * A parser for /etc/path_to_inst.
18644870Sjg  * The user-supplied callback is called once for each entry in the file.
18654870Sjg  * Returns 0 on success, ENOMEM/ENOENT/EINVAL on error.
18664870Sjg  * Callback may return DI_WALK_TERMINATE to terminate the walk,
18674870Sjg  * otherwise DI_WALK_CONTINUE.
18684870Sjg  */
18694870Sjg int
devfs_parse_binding_file(const char * binding_file,int (* callback)(void *,const char *,int,const char *),void * cb_arg)18704870Sjg devfs_parse_binding_file(const char *binding_file,
18714870Sjg 	int (*callback)(void *, const char *, int,
18724870Sjg 	    const char *), void *cb_arg)
18734870Sjg {
18744870Sjg 	token_t token;
18754870Sjg 	struct conf_file file;
18764870Sjg 	char tokval[MAX_TOKEN_SIZE];
18774870Sjg 	enum { STATE_RESET, STATE_DEVPATH, STATE_INSTVAL } state;
18784870Sjg 	char *devpath;
18794870Sjg 	char *bindname;
18804870Sjg 	int instval = 0;
18814870Sjg 	int rv;
18824870Sjg 
18834870Sjg 	if ((devpath = calloc(1, MAXPATHLEN)) == NULL)
18844870Sjg 		return (ENOMEM);
18855467Sethindra 	if ((bindname = calloc(1, MAX_TOKEN_SIZE)) == NULL) {
18865467Sethindra 		free(devpath);
18874870Sjg 		return (ENOMEM);
18885467Sethindra 	}
18894870Sjg 
18904870Sjg 	if ((file.fp = fopen(binding_file, "r")) == NULL) {
18914870Sjg 		free(devpath);
18924870Sjg 		free(bindname);
18934870Sjg 		return (errno);
18944870Sjg 	}
18954870Sjg 
18964870Sjg 	file.filename = (char *)binding_file;
18974870Sjg 	file.linenum = 1;
18984870Sjg 
18994870Sjg 	state = STATE_RESET;
19004870Sjg 	while ((token = lex(&file, tokval, MAX_TOKEN_SIZE)) != T_EOF) {
19014870Sjg 		switch (token) {
19024870Sjg 		case T_POUND:
19034870Sjg 			/*
19044870Sjg 			 * Skip comments.
19054870Sjg 			 */
19064870Sjg 			find_eol(file.fp);
19074870Sjg 			break;
19084870Sjg 		case T_NAME:
19094870Sjg 		case T_STRING:
19104870Sjg 			switch (state) {
19114870Sjg 			case STATE_RESET:
19124870Sjg 				if (strlcpy(devpath, tokval,
19134870Sjg 				    MAXPATHLEN) >= MAXPATHLEN)
19144870Sjg 					goto err;
19154870Sjg 				state = STATE_DEVPATH;
19164870Sjg 				break;
19174870Sjg 			case STATE_INSTVAL:
19184870Sjg 				if (strlcpy(bindname, tokval,
19194870Sjg 				    MAX_TOKEN_SIZE) >= MAX_TOKEN_SIZE)
19204870Sjg 					goto err;
19214870Sjg 				rv = callback(cb_arg,
19224870Sjg 				    devpath, instval, bindname);
19234870Sjg 				if (rv == DI_WALK_TERMINATE)
19244870Sjg 					goto done;
19254870Sjg 				if (rv != DI_WALK_CONTINUE)
19264870Sjg 					goto err;
19274870Sjg 				state = STATE_RESET;
19284870Sjg 				break;
19294870Sjg 			default:
19304870Sjg 				file_err(&file, tok_err, tokval);
19314870Sjg 				state = STATE_RESET;
19324870Sjg 				break;
19334870Sjg 			}
19344870Sjg 			break;
19354870Sjg 		case T_DECVAL:
19364870Sjg 		case T_HEXVAL:
19374870Sjg 			switch (state) {
19384870Sjg 			case STATE_DEVPATH:
19394870Sjg 				instval = (int)strtol(tokval, NULL, 0);
19404870Sjg 				state = STATE_INSTVAL;
19414870Sjg 				break;
19424870Sjg 			default:
19434870Sjg 				file_err(&file, tok_err, tokval);
19444870Sjg 				state = STATE_RESET;
19454870Sjg 				break;
19464870Sjg 			}
19474870Sjg 			break;
19484870Sjg 		case T_NEWLINE:
19494870Sjg 			file.linenum++;
19504870Sjg 			state = STATE_RESET;
19514870Sjg 			break;
19524870Sjg 		default:
19534870Sjg 			file_err(&file, tok_err, tokval);
19544870Sjg 			state = STATE_RESET;
19554870Sjg 			break;
19564870Sjg 		}
19574870Sjg 	}
19584870Sjg 
19594870Sjg done:
19604870Sjg 	(void) fclose(file.fp);
19614870Sjg 	free(devpath);
19624870Sjg 	free(bindname);
19634870Sjg 	return (0);
19644870Sjg 
19654870Sjg err:
19664870Sjg 	(void) fclose(file.fp);
19674870Sjg 	free(devpath);
19684870Sjg 	free(bindname);
19694870Sjg 	return (EINVAL);
19704870Sjg }
19714870Sjg 
19724870Sjg /*
19734870Sjg  * Walk the minor nodes of all children below the specified device
19744870Sjg  * by calling the provided callback with the path to each minor.
19754870Sjg  */
19764870Sjg static int
devfs_walk_children_minors(const char * device_path,struct stat * st,int (* callback)(void *,const char *),void * cb_arg,int * terminate)19774870Sjg devfs_walk_children_minors(const char *device_path, struct stat *st,
19784870Sjg     int (*callback)(void *, const char *), void *cb_arg, int *terminate)
19794870Sjg {
19804870Sjg 	DIR *dir;
19814870Sjg 	struct dirent *dp;
19824870Sjg 	char *minor_path = NULL;
19834870Sjg 	int need_close = 0;
19844870Sjg 	int rv;
19854870Sjg 
19864870Sjg 	if ((minor_path = calloc(1, MAXPATHLEN)) == NULL)
19874870Sjg 		return (ENOMEM);
19884870Sjg 
19894870Sjg 	if ((dir = opendir(device_path)) == NULL) {
19904870Sjg 		rv = ENOENT;
19914870Sjg 		goto err;
19924870Sjg 	}
19934870Sjg 	need_close = 1;
19944870Sjg 
19954870Sjg 	while ((dp = readdir(dir)) != NULL) {
19964870Sjg 		if ((strcmp(dp->d_name, ".") == 0) ||
19974870Sjg 		    (strcmp(dp->d_name, "..") == 0))
19984870Sjg 			continue;
19994870Sjg 		(void) snprintf(minor_path, MAXPATHLEN,
20004870Sjg 		    "%s/%s", device_path, dp->d_name);
20014870Sjg 		if (stat(minor_path, st) == -1)
20024870Sjg 			continue;
20034870Sjg 		if (S_ISDIR(st->st_mode)) {
20044870Sjg 			rv = devfs_walk_children_minors(
20054870Sjg 			    (const char *)minor_path, st,
20064870Sjg 			    callback, cb_arg, terminate);
20074870Sjg 			if (rv != 0)
20084870Sjg 				goto err;
20094870Sjg 			if (*terminate)
20104870Sjg 				break;
20114870Sjg 		} else {
20124870Sjg 			rv = callback(cb_arg, minor_path);
20134870Sjg 			if (rv == DI_WALK_TERMINATE) {
20144870Sjg 				*terminate = 1;
20154870Sjg 				break;
20164870Sjg 			}
20174870Sjg 			if (rv != DI_WALK_CONTINUE) {
20184870Sjg 				rv = EINVAL;
20194870Sjg 				goto err;
20204870Sjg 			}
20214870Sjg 		}
20224870Sjg 	}
20234870Sjg 
20244870Sjg 	rv = 0;
20254870Sjg err:
20264870Sjg 	if (need_close)
20274870Sjg 		(void) closedir(dir);
20284870Sjg 	if (minor_path)
20294870Sjg 		free(minor_path);
20304870Sjg 	return (rv);
20314870Sjg }
20324870Sjg 
20334870Sjg /*
20344870Sjg  * Return the path to each minor node for a device by
20354870Sjg  * calling the provided callback.
20364870Sjg  */
20374870Sjg static int
devfs_walk_device_minors(const char * device_path,struct stat * st,int (* callback)(void *,const char *),void * cb_arg,int * terminate)20384870Sjg devfs_walk_device_minors(const char *device_path, struct stat *st,
20394870Sjg     int (*callback)(void *, const char *), void *cb_arg, int *terminate)
20404870Sjg {
20414870Sjg 	char *minor_path;
20424870Sjg 	char *devpath;
20434870Sjg 	char *expr;
20444870Sjg 	regex_t regex;
20454870Sjg 	int need_regfree = 0;
20464870Sjg 	int need_close = 0;
20474870Sjg 	DIR *dir;
20484870Sjg 	struct dirent *dp;
20494870Sjg 	int rv;
20504870Sjg 	char *p;
20514870Sjg 
20524870Sjg 	minor_path = calloc(1, MAXPATHLEN);
20534870Sjg 	devpath = calloc(1, MAXPATHLEN);
20544870Sjg 	expr = calloc(1, MAXNAMELEN);
20554870Sjg 	if (devpath == NULL || expr == NULL || minor_path == NULL) {
20564870Sjg 		rv = ENOMEM;
20574870Sjg 		goto err;
20584870Sjg 	}
20594870Sjg 
20604870Sjg 	rv = EINVAL;
20614870Sjg 	if (strlcpy(devpath, device_path, MAXPATHLEN) >= MAXPATHLEN)
20624870Sjg 		goto err;
20634870Sjg 	if ((p = strrchr(devpath, '/')) == NULL)
20644870Sjg 		goto err;
20654870Sjg 	*p++ = 0;
20664870Sjg 	if (strlen(p) == 0)
20674870Sjg 		goto err;
20684870Sjg 	if (snprintf(expr, MAXNAMELEN, "%s:.*", p) >= MAXNAMELEN)
20694870Sjg 		goto err;
20704870Sjg 	if (regcomp(&regex, expr, REG_EXTENDED) != 0)
20714870Sjg 		goto err;
20724870Sjg 	need_regfree = 1;
20734870Sjg 
20744870Sjg 	if ((dir = opendir(devpath)) == NULL) {
20754870Sjg 		rv = ENOENT;
20764870Sjg 		goto err;
20774870Sjg 	}
20784870Sjg 	need_close = 1;
20794870Sjg 
20804870Sjg 	while ((dp = readdir(dir)) != NULL) {
20814870Sjg 		if ((strcmp(dp->d_name, ".") == 0) ||
20824870Sjg 		    (strcmp(dp->d_name, "..") == 0))
20834870Sjg 			continue;
20844870Sjg 		(void) snprintf(minor_path, MAXPATHLEN,
20854870Sjg 		    "%s/%s", devpath, dp->d_name);
20864870Sjg 		if (stat(minor_path, st) == -1)
20874870Sjg 			continue;
20884870Sjg 		if ((S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) &&
20894870Sjg 		    regexec(&regex, dp->d_name, 0, NULL, 0) == 0) {
20904870Sjg 			rv = callback(cb_arg, minor_path);
20914870Sjg 			if (rv == DI_WALK_TERMINATE) {
20924870Sjg 				*terminate = 1;
20934870Sjg 				break;
20944870Sjg 			}
20954870Sjg 			if (rv != DI_WALK_CONTINUE) {
20964870Sjg 				rv = EINVAL;
20974870Sjg 				goto err;
20984870Sjg 			}
20994870Sjg 		}
21004870Sjg 	}
21014870Sjg 
21024870Sjg 	rv = 0;
21034870Sjg err:
21044870Sjg 	if (need_close)
21054870Sjg 		(void) closedir(dir);
21064870Sjg 	if (need_regfree)
21074870Sjg 		regfree(&regex);
21084870Sjg 	if (devpath)
21094870Sjg 		free(devpath);
21104870Sjg 	if (minor_path)
21114870Sjg 		free(minor_path);
21124870Sjg 	if (expr)
21134870Sjg 		free(expr);
21144870Sjg 	return (rv);
21154870Sjg }
21164870Sjg 
21174870Sjg /*
21184870Sjg  * Perform a walk of all minor nodes for the specified device,
21194870Sjg  * and minor nodes below the device.
21204870Sjg  */
21214870Sjg int
devfs_walk_minor_nodes(const char * device_path,int (* callback)(void *,const char *),void * cb_arg)21224870Sjg devfs_walk_minor_nodes(const char *device_path,
21234870Sjg 	int (*callback)(void *, const char *), void *cb_arg)
21244870Sjg {
21254870Sjg 	struct stat stbuf;
21264870Sjg 	int rv;
21274870Sjg 	int terminate = 0;
21284870Sjg 
21294870Sjg 	rv = devfs_walk_device_minors(device_path,
21304870Sjg 	    &stbuf, callback, cb_arg, &terminate);
21314870Sjg 	if (rv == 0 && terminate == 0) {
21324870Sjg 		rv = devfs_walk_children_minors(device_path,
21334870Sjg 		    &stbuf, callback, cb_arg, &terminate);
21344870Sjg 	}
21354870Sjg 	return (rv);
21364870Sjg }
21374870Sjg 
21380Sstevel@tonic-gate #ifdef DEBUG
21390Sstevel@tonic-gate 
21400Sstevel@tonic-gate static void
vlog_debug_msg(char * fmt,va_list ap)21410Sstevel@tonic-gate vlog_debug_msg(char *fmt, va_list ap)
21420Sstevel@tonic-gate {
21430Sstevel@tonic-gate 	time_t clock;
21440Sstevel@tonic-gate 	struct tm t;
21450Sstevel@tonic-gate 
21460Sstevel@tonic-gate 	if (!devfsmap_debug)
21470Sstevel@tonic-gate 		return;
21480Sstevel@tonic-gate 
21490Sstevel@tonic-gate 	if (logfp == NULL) {
21500Sstevel@tonic-gate 		if (*devfsmap_logfile != '\0') {
21510Sstevel@tonic-gate 			logfp = fopen(devfsmap_logfile, "a");
21520Sstevel@tonic-gate 			if (logfp)
21530Sstevel@tonic-gate 				(void) fprintf(logfp, "\nNew Log:\n");
21540Sstevel@tonic-gate 		}
21550Sstevel@tonic-gate 
21560Sstevel@tonic-gate 		if (logfp == NULL)
21570Sstevel@tonic-gate 			logfp = stdout;
21580Sstevel@tonic-gate 	}
21590Sstevel@tonic-gate 
21600Sstevel@tonic-gate 	clock = time(NULL);
21610Sstevel@tonic-gate 	(void) localtime_r(&clock, &t);
21620Sstevel@tonic-gate 	(void) fprintf(logfp, "%02d:%02d:%02d ", t.tm_hour, t.tm_min,
21630Sstevel@tonic-gate 	    t.tm_sec);
21640Sstevel@tonic-gate 	(void) vfprintf(logfp, fmt, ap);
21650Sstevel@tonic-gate 	(void) fflush(logfp);
21660Sstevel@tonic-gate }
21670Sstevel@tonic-gate 
21680Sstevel@tonic-gate static void
log_debug_msg(char * fmt,...)21690Sstevel@tonic-gate log_debug_msg(char *fmt, ...)
21700Sstevel@tonic-gate {
21710Sstevel@tonic-gate 	va_list ap;
21720Sstevel@tonic-gate 
21730Sstevel@tonic-gate 	va_start(ap, fmt);
21740Sstevel@tonic-gate 	vlog_debug_msg(fmt, ap);
21750Sstevel@tonic-gate 	va_end(ap);
21760Sstevel@tonic-gate }
21770Sstevel@tonic-gate 
21780Sstevel@tonic-gate #ifdef __sparc
21790Sstevel@tonic-gate 
21800Sstevel@tonic-gate static char *
mpxio_disable_string(int mpxio_disable)21810Sstevel@tonic-gate mpxio_disable_string(int mpxio_disable)
21820Sstevel@tonic-gate {
21830Sstevel@tonic-gate 	if (mpxio_disable == 0)
21840Sstevel@tonic-gate 		return ("no");
21850Sstevel@tonic-gate 	else if (mpxio_disable == 1)
21860Sstevel@tonic-gate 		return ("yes");
21870Sstevel@tonic-gate 	else
21880Sstevel@tonic-gate 		return ("not specified");
21890Sstevel@tonic-gate }
21900Sstevel@tonic-gate 
21910Sstevel@tonic-gate static void
log_confent_list(char * filename,struct conf_entry * confent_list,int global_mpxio_disable)21920Sstevel@tonic-gate log_confent_list(char *filename, struct conf_entry *confent_list,
21930Sstevel@tonic-gate     int global_mpxio_disable)
21940Sstevel@tonic-gate {
21950Sstevel@tonic-gate 	struct conf_entry *confent;
21960Sstevel@tonic-gate 
21970Sstevel@tonic-gate 	log_debug_msg("log_confent_list: filename = %s:\n", filename);
21980Sstevel@tonic-gate 	if (global_mpxio_disable != -1)
21990Sstevel@tonic-gate 		log_debug_msg("\tdriver global mpxio_disable = \"%s\"\n\n",
22000Sstevel@tonic-gate 		    mpxio_disable_string(global_mpxio_disable));
22010Sstevel@tonic-gate 
22020Sstevel@tonic-gate 	for (confent = confent_list; confent != NULL; confent = confent->next) {
22030Sstevel@tonic-gate 		if (confent->name)
22040Sstevel@tonic-gate 			log_debug_msg("\tname = %s\n", confent->name);
22050Sstevel@tonic-gate 		if (confent->parent)
22060Sstevel@tonic-gate 			log_debug_msg("\tparent = %s\n", confent->parent);
22070Sstevel@tonic-gate 		if (confent->class)
22080Sstevel@tonic-gate 			log_debug_msg("\tclass = %s\n", confent->class);
22090Sstevel@tonic-gate 		if (confent->unit_address)
22100Sstevel@tonic-gate 			log_debug_msg("\tunit_address = %s\n",
22110Sstevel@tonic-gate 			    confent->unit_address);
22120Sstevel@tonic-gate 		if (confent->port != -1)
22130Sstevel@tonic-gate 			log_debug_msg("\tport = %d\n", confent->port);
22140Sstevel@tonic-gate 		log_debug_msg("\tmpxio_disable = \"%s\"\n\n",
22154870Sjg 		    mpxio_disable_string(confent->mpxio_disable));
22160Sstevel@tonic-gate 	}
22170Sstevel@tonic-gate }
22180Sstevel@tonic-gate 
22190Sstevel@tonic-gate static void
log_pathlist(char ** pathlist)22200Sstevel@tonic-gate log_pathlist(char **pathlist)
22210Sstevel@tonic-gate {
22220Sstevel@tonic-gate 	char **p;
22230Sstevel@tonic-gate 
22240Sstevel@tonic-gate 	for (p = pathlist; *p != NULL; p++)
22250Sstevel@tonic-gate 		log_debug_msg("\t%s\n", *p);
22260Sstevel@tonic-gate }
22270Sstevel@tonic-gate 
22280Sstevel@tonic-gate #endif /* __sparc */
22290Sstevel@tonic-gate 
22300Sstevel@tonic-gate #endif /* DEBUG */
2231