xref: /illumos-gate/usr/src/lib/libdevinfo/devfsmap.c (revision 72916ffb)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51aef0e11Sjg  * Common Development and Distribution License (the "License").
61aef0e11Sjg  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*72916ffbSGangadhar Mylapuram  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #ifdef	lint
267c478bd9Sstevel@tonic-gate #define	_REENTRANT	/* for localtime_r */
277c478bd9Sstevel@tonic-gate #endif
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <stdio.h>
307c478bd9Sstevel@tonic-gate #include <ctype.h>
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <strings.h>
347c478bd9Sstevel@tonic-gate #include <stdarg.h>
357c478bd9Sstevel@tonic-gate #include <sys/stat.h>
367c478bd9Sstevel@tonic-gate #include <fcntl.h>
377c478bd9Sstevel@tonic-gate #include <errno.h>
387c478bd9Sstevel@tonic-gate #include <unistd.h>
397c478bd9Sstevel@tonic-gate #include <stropts.h>
407c478bd9Sstevel@tonic-gate #include <time.h>
417c478bd9Sstevel@tonic-gate #include <sys/param.h>
427c478bd9Sstevel@tonic-gate #include <sys/vfstab.h>
437c478bd9Sstevel@tonic-gate #include <dirent.h>
447c478bd9Sstevel@tonic-gate #ifdef __sparc
457c478bd9Sstevel@tonic-gate #include <sys/scsi/adapters/scsi_vhci.h>
467c478bd9Sstevel@tonic-gate #include <sys/sunmdi.h>
477c478bd9Sstevel@tonic-gate #endif /* __sparc */
487c478bd9Sstevel@tonic-gate #include "libdevinfo.h"
497c478bd9Sstevel@tonic-gate #include "device_info.h"
501aef0e11Sjg #include <regex.h>
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #define	isnewline(ch)	((ch) == '\n' || (ch) == '\r' || (ch) == '\f')
537c478bd9Sstevel@tonic-gate #define	isnamechar(ch)  (isalpha(ch) || isdigit(ch) || (ch) == '_' ||\
547c478bd9Sstevel@tonic-gate 	(ch) == '-')
557c478bd9Sstevel@tonic-gate #define	MAX_TOKEN_SIZE	1024
567c478bd9Sstevel@tonic-gate #define	BUFSIZE		1024
577c478bd9Sstevel@tonic-gate #define	STRVAL(s)	((s) ? (s) : "NULL")
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate #define	SCSI_VHCI_CONF		"/kernel/drv/scsi_vhci.conf"
607c478bd9Sstevel@tonic-gate #define	QLC_CONF		"/kernel/drv/qlc.conf"
617c478bd9Sstevel@tonic-gate #define	FP_CONF			"/kernel/drv/fp.conf"
627c478bd9Sstevel@tonic-gate #define	DRIVER_CLASSES		"/etc/driver_classes"
637c478bd9Sstevel@tonic-gate #define	FP_AT			"fp@"
647c478bd9Sstevel@tonic-gate #define	VHCI_CTL_NODE		"/devices/scsi_vhci:devctl"
657c478bd9Sstevel@tonic-gate #define	SLASH_DEVICES		"/devices"
667c478bd9Sstevel@tonic-gate #define	SLASH_DEVICES_SLASH	"/devices/"
677c478bd9Sstevel@tonic-gate #define	SLASH_FP_AT		"/fp@"
687c478bd9Sstevel@tonic-gate #define	SLASH_SCSI_VHCI		"/scsi_vhci"
697c478bd9Sstevel@tonic-gate #define	META_DEV		"/dev/md/dsk/"
707c478bd9Sstevel@tonic-gate #define	SLASH_DEV_SLASH		"/dev/"
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate /*
737c478bd9Sstevel@tonic-gate  * Macros to produce a quoted string containing the value of a
747c478bd9Sstevel@tonic-gate  * preprocessor macro. For example, if SIZE is defined to be 256,
757c478bd9Sstevel@tonic-gate  * VAL2STR(SIZE) is "256". This is used to construct format
767c478bd9Sstevel@tonic-gate  * strings for scanf-family functions below.
777c478bd9Sstevel@tonic-gate  */
787c478bd9Sstevel@tonic-gate #define	QUOTE(x)	#x
797c478bd9Sstevel@tonic-gate #define	VAL2STR(x)	QUOTE(x)
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate typedef enum {
827c478bd9Sstevel@tonic-gate 	CLIENT_TYPE_UNKNOWN,
837c478bd9Sstevel@tonic-gate 	CLIENT_TYPE_PHCI,
847c478bd9Sstevel@tonic-gate 	CLIENT_TYPE_VHCI
857c478bd9Sstevel@tonic-gate } client_type_t;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate typedef enum {
887c478bd9Sstevel@tonic-gate 	T_EQUALS,
897c478bd9Sstevel@tonic-gate 	T_AMPERSAND,
907c478bd9Sstevel@tonic-gate 	T_BIT_OR,
917c478bd9Sstevel@tonic-gate 	T_STAR,
927c478bd9Sstevel@tonic-gate 	T_POUND,
937c478bd9Sstevel@tonic-gate 	T_COLON,
947c478bd9Sstevel@tonic-gate 	T_SEMICOLON,
957c478bd9Sstevel@tonic-gate 	T_COMMA,
967c478bd9Sstevel@tonic-gate 	T_SLASH,
977c478bd9Sstevel@tonic-gate 	T_WHITE_SPACE,
987c478bd9Sstevel@tonic-gate 	T_NEWLINE,
997c478bd9Sstevel@tonic-gate 	T_EOF,
1007c478bd9Sstevel@tonic-gate 	T_STRING,
1017c478bd9Sstevel@tonic-gate 	T_HEXVAL,
1027c478bd9Sstevel@tonic-gate 	T_DECVAL,
1037c478bd9Sstevel@tonic-gate 	T_NAME
1047c478bd9Sstevel@tonic-gate } token_t;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate typedef enum {
1077c478bd9Sstevel@tonic-gate 	begin, parent, drvname, drvclass, prop,
1087c478bd9Sstevel@tonic-gate 	parent_equals, name_equals, drvclass_equals,
1097c478bd9Sstevel@tonic-gate 	parent_equals_string, name_equals_string,
1107c478bd9Sstevel@tonic-gate 	drvclass_equals_string,
1117c478bd9Sstevel@tonic-gate 	prop_equals, prop_equals_string, prop_equals_integer,
1127c478bd9Sstevel@tonic-gate 	prop_equals_string_comma, prop_equals_integer_comma
1137c478bd9Sstevel@tonic-gate } conf_state_t;
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /* structure to hold entries with mpxio-disable property in driver.conf file */
1167c478bd9Sstevel@tonic-gate struct conf_entry {
1177c478bd9Sstevel@tonic-gate 	char *name;
1187c478bd9Sstevel@tonic-gate 	char *parent;
1197c478bd9Sstevel@tonic-gate 	char *class;
1207c478bd9Sstevel@tonic-gate 	char *unit_address;
1217c478bd9Sstevel@tonic-gate 	int port;
1227c478bd9Sstevel@tonic-gate 	int mpxio_disable;
1237c478bd9Sstevel@tonic-gate 	struct conf_entry *next;
1247c478bd9Sstevel@tonic-gate };
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate struct conf_file {
1277c478bd9Sstevel@tonic-gate 	char *filename;
1287c478bd9Sstevel@tonic-gate 	FILE *fp;
1297c478bd9Sstevel@tonic-gate 	int linenum;
1307c478bd9Sstevel@tonic-gate };
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate static char *tok_err = "Unexpected token '%s'\n";
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate /* #define	DEBUG */
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate #ifdef DEBUG
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate int devfsmap_debug = 0;
1407c478bd9Sstevel@tonic-gate /* /var/run is not mounted at install time. Therefore use /tmp */
1417c478bd9Sstevel@tonic-gate char *devfsmap_logfile = "/tmp/devfsmap.log";
1427c478bd9Sstevel@tonic-gate static FILE *logfp;
1437c478bd9Sstevel@tonic-gate #define	logdmsg(args)	log_debug_msg args
1447c478bd9Sstevel@tonic-gate static void vlog_debug_msg(char *, va_list);
1457c478bd9Sstevel@tonic-gate static void log_debug_msg(char *, ...);
1467c478bd9Sstevel@tonic-gate #ifdef __sparc
1477c478bd9Sstevel@tonic-gate static void log_confent_list(char *, struct conf_entry *, int);
1487c478bd9Sstevel@tonic-gate static void log_pathlist(char **);
1497c478bd9Sstevel@tonic-gate #endif /* __sparc */
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate #else /* DEBUG */
1527c478bd9Sstevel@tonic-gate #define	logdmsg(args)	/* nothing */
1537c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate /*
1577c478bd9Sstevel@tonic-gate  * Leave NEWLINE as the next character.
1587c478bd9Sstevel@tonic-gate  */
1597c478bd9Sstevel@tonic-gate static void
find_eol(FILE * fp)1607c478bd9Sstevel@tonic-gate find_eol(FILE *fp)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate 	int ch;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	while ((ch = getc(fp)) != EOF) {
1657c478bd9Sstevel@tonic-gate 		if (isnewline(ch)) {
1667c478bd9Sstevel@tonic-gate 			(void) ungetc(ch, fp);
1677c478bd9Sstevel@tonic-gate 			break;
1687c478bd9Sstevel@tonic-gate 		}
1697c478bd9Sstevel@tonic-gate 	}
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate /* ignore parsing errors */
1737c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1747c478bd9Sstevel@tonic-gate static void
file_err(struct conf_file * filep,char * fmt,...)1757c478bd9Sstevel@tonic-gate file_err(struct conf_file *filep, char *fmt, ...)
1767c478bd9Sstevel@tonic-gate {
1777c478bd9Sstevel@tonic-gate #ifdef DEBUG
1787c478bd9Sstevel@tonic-gate 	va_list ap;
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
1817c478bd9Sstevel@tonic-gate 	log_debug_msg("WARNING: %s line # %d: ",
1827c478bd9Sstevel@tonic-gate 	    filep->filename, filep->linenum);
1837c478bd9Sstevel@tonic-gate 	vlog_debug_msg(fmt, ap);
1847c478bd9Sstevel@tonic-gate 	va_end(ap);
1857c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate /* return the next token from the given driver.conf file, or -1 on error */
1897c478bd9Sstevel@tonic-gate static token_t
lex(struct conf_file * filep,char * val,size_t size)1907c478bd9Sstevel@tonic-gate lex(struct conf_file *filep, char *val, size_t size)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate 	char	*cp;
1937c478bd9Sstevel@tonic-gate 	int	ch, oval, badquote;
1947c478bd9Sstevel@tonic-gate 	size_t	remain;
1957c478bd9Sstevel@tonic-gate 	token_t token;
1967c478bd9Sstevel@tonic-gate 	FILE	*fp = filep->fp;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	if (size < 2)
1997c478bd9Sstevel@tonic-gate 		return (-1);
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	cp = val;
2027c478bd9Sstevel@tonic-gate 	while ((ch = getc(fp)) == ' ' || ch == '\t')
2037c478bd9Sstevel@tonic-gate 		;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	remain = size - 1;
2067c478bd9Sstevel@tonic-gate 	*cp++ = (char)ch;
2077c478bd9Sstevel@tonic-gate 	switch (ch) {
2087c478bd9Sstevel@tonic-gate 	case '=':
2097c478bd9Sstevel@tonic-gate 		token = T_EQUALS;
2107c478bd9Sstevel@tonic-gate 		break;
2117c478bd9Sstevel@tonic-gate 	case '&':
2127c478bd9Sstevel@tonic-gate 		token = T_AMPERSAND;
2137c478bd9Sstevel@tonic-gate 		break;
2147c478bd9Sstevel@tonic-gate 	case '|':
2157c478bd9Sstevel@tonic-gate 		token = T_BIT_OR;
2167c478bd9Sstevel@tonic-gate 		break;
2177c478bd9Sstevel@tonic-gate 	case '*':
2187c478bd9Sstevel@tonic-gate 		token = T_STAR;
2197c478bd9Sstevel@tonic-gate 		break;
2207c478bd9Sstevel@tonic-gate 	case '#':
2217c478bd9Sstevel@tonic-gate 		token = T_POUND;
2227c478bd9Sstevel@tonic-gate 		break;
2237c478bd9Sstevel@tonic-gate 	case ':':
2247c478bd9Sstevel@tonic-gate 		token = T_COLON;
2257c478bd9Sstevel@tonic-gate 		break;
2267c478bd9Sstevel@tonic-gate 	case ';':
2277c478bd9Sstevel@tonic-gate 		token = T_SEMICOLON;
2287c478bd9Sstevel@tonic-gate 		break;
2297c478bd9Sstevel@tonic-gate 	case ',':
2307c478bd9Sstevel@tonic-gate 		token = T_COMMA;
2317c478bd9Sstevel@tonic-gate 		break;
2327c478bd9Sstevel@tonic-gate 	case '/':
2337c478bd9Sstevel@tonic-gate 		token = T_SLASH;
2347c478bd9Sstevel@tonic-gate 		break;
2357c478bd9Sstevel@tonic-gate 	case ' ':
2367c478bd9Sstevel@tonic-gate 	case '\t':
2377c478bd9Sstevel@tonic-gate 	case '\f':
2387c478bd9Sstevel@tonic-gate 		while ((ch = getc(fp)) == ' ' ||
2397c478bd9Sstevel@tonic-gate 		    ch == '\t' || ch == '\f') {
2407c478bd9Sstevel@tonic-gate 			if (--remain == 0) {
2417c478bd9Sstevel@tonic-gate 				*cp = '\0';
2427c478bd9Sstevel@tonic-gate 				return (-1);
2437c478bd9Sstevel@tonic-gate 			}
2447c478bd9Sstevel@tonic-gate 			*cp++ = (char)ch;
2457c478bd9Sstevel@tonic-gate 		}
2467c478bd9Sstevel@tonic-gate 		(void) ungetc(ch, fp);
2477c478bd9Sstevel@tonic-gate 		token = T_WHITE_SPACE;
2487c478bd9Sstevel@tonic-gate 		break;
2497c478bd9Sstevel@tonic-gate 	case '\n':
2507c478bd9Sstevel@tonic-gate 	case '\r':
2517c478bd9Sstevel@tonic-gate 		token = T_NEWLINE;
2527c478bd9Sstevel@tonic-gate 		break;
2537c478bd9Sstevel@tonic-gate 	case '"':
2547c478bd9Sstevel@tonic-gate 		remain++;
2557c478bd9Sstevel@tonic-gate 		cp--;
2567c478bd9Sstevel@tonic-gate 		badquote = 0;
2577c478bd9Sstevel@tonic-gate 		while (!badquote && (ch  = getc(fp)) != '"') {
2587c478bd9Sstevel@tonic-gate 			switch (ch) {
2597c478bd9Sstevel@tonic-gate 			case '\n':
2607c478bd9Sstevel@tonic-gate 			case EOF:
2617c478bd9Sstevel@tonic-gate 				file_err(filep, "Missing \"\n");
2627c478bd9Sstevel@tonic-gate 				remain = size - 1;
2637c478bd9Sstevel@tonic-gate 				cp = val;
2647c478bd9Sstevel@tonic-gate 				*cp++ = '\n';
2657c478bd9Sstevel@tonic-gate 				badquote = 1;
2667c478bd9Sstevel@tonic-gate 				/* since we consumed the newline/EOF */
2677c478bd9Sstevel@tonic-gate 				(void) ungetc(ch, fp);
2687c478bd9Sstevel@tonic-gate 				break;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 			case '\\':
2717c478bd9Sstevel@tonic-gate 				if (--remain == 0) {
2727c478bd9Sstevel@tonic-gate 					*cp = '\0';
2737c478bd9Sstevel@tonic-gate 					return (-1);
2747c478bd9Sstevel@tonic-gate 				}
2757c478bd9Sstevel@tonic-gate 				ch = (char)getc(fp);
2767c478bd9Sstevel@tonic-gate 				if (!isdigit(ch)) {
2777c478bd9Sstevel@tonic-gate 					/* escape the character */
2787c478bd9Sstevel@tonic-gate 					*cp++ = (char)ch;
2797c478bd9Sstevel@tonic-gate 					break;
2807c478bd9Sstevel@tonic-gate 				}
2817c478bd9Sstevel@tonic-gate 				oval = 0;
2827c478bd9Sstevel@tonic-gate 				while (ch >= '0' && ch <= '7') {
2837c478bd9Sstevel@tonic-gate 					ch -= '0';
2847c478bd9Sstevel@tonic-gate 					oval = (oval << 3) + ch;
2857c478bd9Sstevel@tonic-gate 					ch = (char)getc(fp);
2867c478bd9Sstevel@tonic-gate 				}
2877c478bd9Sstevel@tonic-gate 				(void) ungetc(ch, fp);
2887c478bd9Sstevel@tonic-gate 				/* check for character overflow? */
2897c478bd9Sstevel@tonic-gate 				if (oval > 127) {
2907c478bd9Sstevel@tonic-gate 					file_err(filep,
2917c478bd9Sstevel@tonic-gate 					    "Character "
2927c478bd9Sstevel@tonic-gate 					    "overflow detected.\n");
2937c478bd9Sstevel@tonic-gate 				}
2947c478bd9Sstevel@tonic-gate 				*cp++ = (char)oval;
2957c478bd9Sstevel@tonic-gate 				break;
2967c478bd9Sstevel@tonic-gate 			default:
2977c478bd9Sstevel@tonic-gate 				if (--remain == 0) {
2987c478bd9Sstevel@tonic-gate 					*cp = '\0';
2997c478bd9Sstevel@tonic-gate 					return (-1);
3007c478bd9Sstevel@tonic-gate 				}
3017c478bd9Sstevel@tonic-gate 				*cp++ = (char)ch;
3027c478bd9Sstevel@tonic-gate 				break;
3037c478bd9Sstevel@tonic-gate 			}
3047c478bd9Sstevel@tonic-gate 		}
3057c478bd9Sstevel@tonic-gate 		token = T_STRING;
3067c478bd9Sstevel@tonic-gate 		break;
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	case EOF:
3097c478bd9Sstevel@tonic-gate 		token = T_EOF;
3107c478bd9Sstevel@tonic-gate 		break;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	default:
3137c478bd9Sstevel@tonic-gate 		/*
3147c478bd9Sstevel@tonic-gate 		 * detect a lone '-' (including at the end of a line), and
3157c478bd9Sstevel@tonic-gate 		 * identify it as a 'name'
3167c478bd9Sstevel@tonic-gate 		 */
3177c478bd9Sstevel@tonic-gate 		if (ch == '-') {
3187c478bd9Sstevel@tonic-gate 			if (--remain == 0) {
3197c478bd9Sstevel@tonic-gate 				*cp = '\0';
3207c478bd9Sstevel@tonic-gate 				return (-1);
3217c478bd9Sstevel@tonic-gate 			}
3227c478bd9Sstevel@tonic-gate 			*cp++ = (char)(ch = getc(fp));
3237c478bd9Sstevel@tonic-gate 			if (ch == ' ' || ch == '\t' || ch == '\n') {
3247c478bd9Sstevel@tonic-gate 				(void) ungetc(ch, fp);
3257c478bd9Sstevel@tonic-gate 				remain++;
3267c478bd9Sstevel@tonic-gate 				cp--;
3277c478bd9Sstevel@tonic-gate 				token = T_NAME;
3287c478bd9Sstevel@tonic-gate 				break;
3297c478bd9Sstevel@tonic-gate 			}
3307c478bd9Sstevel@tonic-gate 		} else if (ch == '~' || ch == '-') {
3317c478bd9Sstevel@tonic-gate 			if (--remain == 0) {
3327c478bd9Sstevel@tonic-gate 				*cp = '\0';
3337c478bd9Sstevel@tonic-gate 				return (-1);
3347c478bd9Sstevel@tonic-gate 			}
3357c478bd9Sstevel@tonic-gate 			*cp++ = (char)(ch = getc(fp));
3367c478bd9Sstevel@tonic-gate 		}
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 		if (isdigit(ch)) {
3407c478bd9Sstevel@tonic-gate 			if (ch == '0') {
3417c478bd9Sstevel@tonic-gate 				if ((ch = getc(fp)) == 'x') {
3427c478bd9Sstevel@tonic-gate 					if (--remain == 0) {
3437c478bd9Sstevel@tonic-gate 						*cp = '\0';
3447c478bd9Sstevel@tonic-gate 						return (-1);
3457c478bd9Sstevel@tonic-gate 					}
3467c478bd9Sstevel@tonic-gate 					*cp++ = (char)ch;
3477c478bd9Sstevel@tonic-gate 					ch = getc(fp);
3487c478bd9Sstevel@tonic-gate 					while (isxdigit(ch)) {
3497c478bd9Sstevel@tonic-gate 						if (--remain == 0) {
3507c478bd9Sstevel@tonic-gate 							*cp = '\0';
3517c478bd9Sstevel@tonic-gate 							return (-1);
3527c478bd9Sstevel@tonic-gate 						}
3537c478bd9Sstevel@tonic-gate 						*cp++ = (char)ch;
3547c478bd9Sstevel@tonic-gate 						ch = getc(fp);
3557c478bd9Sstevel@tonic-gate 					}
3567c478bd9Sstevel@tonic-gate 					(void) ungetc(ch, fp);
3577c478bd9Sstevel@tonic-gate 					token = T_HEXVAL;
3587c478bd9Sstevel@tonic-gate 				} else {
3597c478bd9Sstevel@tonic-gate 					goto digit;
3607c478bd9Sstevel@tonic-gate 				}
3617c478bd9Sstevel@tonic-gate 			} else {
3627c478bd9Sstevel@tonic-gate 				ch = getc(fp);
3637c478bd9Sstevel@tonic-gate digit:
3647c478bd9Sstevel@tonic-gate 				while (isdigit(ch)) {
3657c478bd9Sstevel@tonic-gate 					if (--remain == 0) {
3667c478bd9Sstevel@tonic-gate 						*cp = '\0';
3677c478bd9Sstevel@tonic-gate 						return (-1);
3687c478bd9Sstevel@tonic-gate 					}
3697c478bd9Sstevel@tonic-gate 					*cp++ = (char)ch;
3707c478bd9Sstevel@tonic-gate 					ch = getc(fp);
3717c478bd9Sstevel@tonic-gate 				}
3727c478bd9Sstevel@tonic-gate 				(void) ungetc(ch, fp);
3737c478bd9Sstevel@tonic-gate 				token = T_DECVAL;
3747c478bd9Sstevel@tonic-gate 			}
3757c478bd9Sstevel@tonic-gate 		} else if (isalpha(ch) || ch == '\\') {
3767c478bd9Sstevel@tonic-gate 			if (ch != '\\') {
3777c478bd9Sstevel@tonic-gate 				ch = getc(fp);
3787c478bd9Sstevel@tonic-gate 			} else {
3797c478bd9Sstevel@tonic-gate 				/*
3807c478bd9Sstevel@tonic-gate 				 * if the character was a backslash,
3817c478bd9Sstevel@tonic-gate 				 * back up so we can overwrite it with
3827c478bd9Sstevel@tonic-gate 				 * the next (i.e. escaped) character.
3837c478bd9Sstevel@tonic-gate 				 */
3847c478bd9Sstevel@tonic-gate 				remain++;
3857c478bd9Sstevel@tonic-gate 				cp--;
3867c478bd9Sstevel@tonic-gate 			}
3877c478bd9Sstevel@tonic-gate 			while (isnamechar(ch) || ch == '\\') {
3887c478bd9Sstevel@tonic-gate 				if (ch == '\\')
3897c478bd9Sstevel@tonic-gate 					ch = getc(fp);
3907c478bd9Sstevel@tonic-gate 				if (--remain == 0) {
3917c478bd9Sstevel@tonic-gate 					*cp = '\0';
3927c478bd9Sstevel@tonic-gate 					return (-1);
3937c478bd9Sstevel@tonic-gate 				}
3947c478bd9Sstevel@tonic-gate 				*cp++ = (char)ch;
3957c478bd9Sstevel@tonic-gate 				ch = getc(fp);
3967c478bd9Sstevel@tonic-gate 			}
3977c478bd9Sstevel@tonic-gate 			(void) ungetc(ch, fp);
3987c478bd9Sstevel@tonic-gate 			token = T_NAME;
3997c478bd9Sstevel@tonic-gate 		} else {
4007c478bd9Sstevel@tonic-gate 			return (-1);
4017c478bd9Sstevel@tonic-gate 		}
4027c478bd9Sstevel@tonic-gate 		break;
4037c478bd9Sstevel@tonic-gate 	}
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	*cp = '\0';
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	return (token);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate 
4101aef0e11Sjg #ifdef __sparc
4111aef0e11Sjg 
4127c478bd9Sstevel@tonic-gate static void
free_confent(struct conf_entry * confent)4137c478bd9Sstevel@tonic-gate free_confent(struct conf_entry *confent)
4147c478bd9Sstevel@tonic-gate {
4157c478bd9Sstevel@tonic-gate 	if (confent->name)
4167c478bd9Sstevel@tonic-gate 		free(confent->name);
4177c478bd9Sstevel@tonic-gate 	if (confent->parent)
4187c478bd9Sstevel@tonic-gate 		free(confent->parent);
4197c478bd9Sstevel@tonic-gate 	if (confent->class)
4207c478bd9Sstevel@tonic-gate 		free(confent->class);
4217c478bd9Sstevel@tonic-gate 	if (confent->unit_address)
4227c478bd9Sstevel@tonic-gate 		free(confent->unit_address);
4237c478bd9Sstevel@tonic-gate 	free(confent);
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate static void
free_confent_list(struct conf_entry * confent_list)4277c478bd9Sstevel@tonic-gate free_confent_list(struct conf_entry *confent_list)
4287c478bd9Sstevel@tonic-gate {
4297c478bd9Sstevel@tonic-gate 	struct conf_entry *confent, *next;
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	for (confent = confent_list; confent != NULL; confent = next) {
4327c478bd9Sstevel@tonic-gate 		next = confent->next;
4337c478bd9Sstevel@tonic-gate 		free_confent(confent);
4347c478bd9Sstevel@tonic-gate 	}
4357c478bd9Sstevel@tonic-gate }
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate /*
4387c478bd9Sstevel@tonic-gate  * Parse the next entry from the driver.conf file and return in the form of
4397c478bd9Sstevel@tonic-gate  * a pointer to the conf_entry.
4407c478bd9Sstevel@tonic-gate  */
4417c478bd9Sstevel@tonic-gate static struct conf_entry *
parse_conf_entry(struct conf_file * filep,char * tokbuf,size_t linesize)4427c478bd9Sstevel@tonic-gate parse_conf_entry(struct conf_file *filep, char *tokbuf, size_t linesize)
4437c478bd9Sstevel@tonic-gate {
4447c478bd9Sstevel@tonic-gate 	char *prop_name, *string;
4457c478bd9Sstevel@tonic-gate 	token_t token;
4467c478bd9Sstevel@tonic-gate 	struct conf_entry *confent;
4477c478bd9Sstevel@tonic-gate 	conf_state_t state;
4487c478bd9Sstevel@tonic-gate 	int failed = 1;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	if ((confent = calloc(1, sizeof (*confent))) == NULL)
4517c478bd9Sstevel@tonic-gate 		return (NULL);
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	confent->port = -1;
4547c478bd9Sstevel@tonic-gate 	confent->mpxio_disable = -1;
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	state = begin;
4577c478bd9Sstevel@tonic-gate 	token = T_NAME;
4587c478bd9Sstevel@tonic-gate 	prop_name = NULL;
4597c478bd9Sstevel@tonic-gate 	string = NULL;
4607c478bd9Sstevel@tonic-gate 	do {
4617c478bd9Sstevel@tonic-gate 		switch (token) {
4627c478bd9Sstevel@tonic-gate 		case T_NAME:
4637c478bd9Sstevel@tonic-gate 			switch (state) {
4647c478bd9Sstevel@tonic-gate 			case prop_equals_string:
4657c478bd9Sstevel@tonic-gate 			case prop_equals_integer:
4667c478bd9Sstevel@tonic-gate 			case begin:
4677c478bd9Sstevel@tonic-gate 				state = prop;
4687c478bd9Sstevel@tonic-gate 				if ((prop_name = strdup(tokbuf)) == NULL)
4697c478bd9Sstevel@tonic-gate 					goto bad;
4707c478bd9Sstevel@tonic-gate 				break;
4717c478bd9Sstevel@tonic-gate 			default:
4727c478bd9Sstevel@tonic-gate 				file_err(filep, tok_err, tokbuf);
4737c478bd9Sstevel@tonic-gate 			}
4747c478bd9Sstevel@tonic-gate 			break;
4757c478bd9Sstevel@tonic-gate 		case T_EQUALS:
4767c478bd9Sstevel@tonic-gate 			switch (state) {
4777c478bd9Sstevel@tonic-gate 			case prop:
4787c478bd9Sstevel@tonic-gate 				state = prop_equals;
4797c478bd9Sstevel@tonic-gate 				break;
4807c478bd9Sstevel@tonic-gate 			default:
4817c478bd9Sstevel@tonic-gate 				file_err(filep, tok_err, tokbuf);
4827c478bd9Sstevel@tonic-gate 			}
4837c478bd9Sstevel@tonic-gate 			break;
4847c478bd9Sstevel@tonic-gate 		case T_STRING:
4857c478bd9Sstevel@tonic-gate 			switch (state) {
4867c478bd9Sstevel@tonic-gate 			case prop_equals:
4877c478bd9Sstevel@tonic-gate 				if ((string = strdup(tokbuf)) == NULL)
4887c478bd9Sstevel@tonic-gate 					goto bad;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 				state = begin;
4917c478bd9Sstevel@tonic-gate 				if (strcmp(prop_name, "PARENT") == 0 ||
4927c478bd9Sstevel@tonic-gate 				    strcmp(prop_name, "parent") == 0) {
4937c478bd9Sstevel@tonic-gate 					if (confent->parent) {
4947c478bd9Sstevel@tonic-gate 						file_err(filep,
4957c478bd9Sstevel@tonic-gate 				"'parent' property already specified\n");
4967c478bd9Sstevel@tonic-gate 						goto bad;
4977c478bd9Sstevel@tonic-gate 					}
4987c478bd9Sstevel@tonic-gate 					confent->parent = string;
4997c478bd9Sstevel@tonic-gate 				} else if (strcmp(prop_name, "NAME") == 0 ||
5007c478bd9Sstevel@tonic-gate 				    strcmp(prop_name, "name") == 0) {
5017c478bd9Sstevel@tonic-gate 					if (confent->name) {
5027c478bd9Sstevel@tonic-gate 						file_err(filep,
5037c478bd9Sstevel@tonic-gate 				"'name' property already specified\n");
5047c478bd9Sstevel@tonic-gate 						goto bad;
5057c478bd9Sstevel@tonic-gate 					}
5067c478bd9Sstevel@tonic-gate 					confent->name = string;
5077c478bd9Sstevel@tonic-gate 				} else if (strcmp(prop_name, "CLASS") == 0 ||
5087c478bd9Sstevel@tonic-gate 				    strcmp(prop_name, "class") == 0) {
5097c478bd9Sstevel@tonic-gate 					if (confent->class) {
5107c478bd9Sstevel@tonic-gate 						file_err(filep,
5117c478bd9Sstevel@tonic-gate 				"'class' property already specified\n");
5127c478bd9Sstevel@tonic-gate 						goto bad;
5137c478bd9Sstevel@tonic-gate 					}
5147c478bd9Sstevel@tonic-gate 					confent->class = string;
5157c478bd9Sstevel@tonic-gate 				} else if (strcmp(prop_name, "unit-address")
5167c478bd9Sstevel@tonic-gate 				    == 0) {
5177c478bd9Sstevel@tonic-gate 					if (confent->unit_address) {
5187c478bd9Sstevel@tonic-gate 						file_err(filep,
5197c478bd9Sstevel@tonic-gate 				"'unit-address' property already specified\n");
5207c478bd9Sstevel@tonic-gate 						goto bad;
5217c478bd9Sstevel@tonic-gate 					}
5227c478bd9Sstevel@tonic-gate 					confent->unit_address = string;
5237c478bd9Sstevel@tonic-gate 				} else if (strcmp(prop_name, "mpxio-disable")
5247c478bd9Sstevel@tonic-gate 				    == 0) {
5257c478bd9Sstevel@tonic-gate 					if (confent->mpxio_disable != -1) {
5267c478bd9Sstevel@tonic-gate 						file_err(filep,
5277c478bd9Sstevel@tonic-gate 				"'mpxio-disable' property already specified\n");
5287c478bd9Sstevel@tonic-gate 						goto bad;
5297c478bd9Sstevel@tonic-gate 					}
5307c478bd9Sstevel@tonic-gate 					if (strcmp(string, "yes") == 0)
5317c478bd9Sstevel@tonic-gate 						confent->mpxio_disable = 1;
5327c478bd9Sstevel@tonic-gate 					else if (strcmp(string, "no") == 0)
5337c478bd9Sstevel@tonic-gate 						confent->mpxio_disable = 0;
5347c478bd9Sstevel@tonic-gate 					else {
5357c478bd9Sstevel@tonic-gate 						file_err(filep,
5367c478bd9Sstevel@tonic-gate 				"'mpxio-disable' property setting is invalid. "
5377c478bd9Sstevel@tonic-gate 				"The value must be either \"yes\" or \"no\"\n");
5387c478bd9Sstevel@tonic-gate 						goto bad;
5397c478bd9Sstevel@tonic-gate 					}
5407c478bd9Sstevel@tonic-gate 					free(string);
5417c478bd9Sstevel@tonic-gate 				} else {
5427c478bd9Sstevel@tonic-gate 					free(string);
5437c478bd9Sstevel@tonic-gate 					state = prop_equals_string;
5447c478bd9Sstevel@tonic-gate 				}
5457c478bd9Sstevel@tonic-gate 				string = NULL;
5467c478bd9Sstevel@tonic-gate 				free(prop_name);
5477c478bd9Sstevel@tonic-gate 				prop_name = NULL;
5487c478bd9Sstevel@tonic-gate 				break;
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 			case prop_equals_string_comma:
5517c478bd9Sstevel@tonic-gate 				state = prop_equals_string;
5527c478bd9Sstevel@tonic-gate 				break;
5537c478bd9Sstevel@tonic-gate 			default:
5547c478bd9Sstevel@tonic-gate 				file_err(filep, tok_err, tokbuf);
5557c478bd9Sstevel@tonic-gate 			}
5567c478bd9Sstevel@tonic-gate 			break;
5577c478bd9Sstevel@tonic-gate 		case T_HEXVAL:
5587c478bd9Sstevel@tonic-gate 		case T_DECVAL:
5597c478bd9Sstevel@tonic-gate 			switch (state) {
5607c478bd9Sstevel@tonic-gate 			case prop_equals:
5617c478bd9Sstevel@tonic-gate 				if (strcmp(prop_name, "port") == 0) {
5627c478bd9Sstevel@tonic-gate 					if (confent->port != -1) {
5637c478bd9Sstevel@tonic-gate 						file_err(filep,
5647c478bd9Sstevel@tonic-gate 					"'port' property already specified\n");
5657c478bd9Sstevel@tonic-gate 						goto bad;
5667c478bd9Sstevel@tonic-gate 					}
5677c478bd9Sstevel@tonic-gate 					confent->port =
5687c478bd9Sstevel@tonic-gate 					    (int)strtol(tokbuf, NULL, 0);
5697c478bd9Sstevel@tonic-gate 					state = begin;
5707c478bd9Sstevel@tonic-gate 				} else
5717c478bd9Sstevel@tonic-gate 					state = prop_equals_integer;
5727c478bd9Sstevel@tonic-gate 				free(prop_name);
5737c478bd9Sstevel@tonic-gate 				prop_name = NULL;
5747c478bd9Sstevel@tonic-gate 				break;
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 			case prop_equals_integer_comma:
5777c478bd9Sstevel@tonic-gate 				state = prop_equals_integer;
5787c478bd9Sstevel@tonic-gate 				break;
5797c478bd9Sstevel@tonic-gate 			default:
5807c478bd9Sstevel@tonic-gate 				file_err(filep, tok_err, tokbuf);
5817c478bd9Sstevel@tonic-gate 			}
5827c478bd9Sstevel@tonic-gate 			break;
5837c478bd9Sstevel@tonic-gate 		case T_COMMA:
5847c478bd9Sstevel@tonic-gate 			switch (state) {
5857c478bd9Sstevel@tonic-gate 			case prop_equals_string:
5867c478bd9Sstevel@tonic-gate 				state = prop_equals_string_comma;
5877c478bd9Sstevel@tonic-gate 				break;
5887c478bd9Sstevel@tonic-gate 			case prop_equals_integer:
5897c478bd9Sstevel@tonic-gate 				state = prop_equals_integer_comma;
5907c478bd9Sstevel@tonic-gate 				break;
5917c478bd9Sstevel@tonic-gate 			default:
5927c478bd9Sstevel@tonic-gate 				file_err(filep, tok_err, tokbuf);
5937c478bd9Sstevel@tonic-gate 			}
5947c478bd9Sstevel@tonic-gate 			break;
5957c478bd9Sstevel@tonic-gate 		case T_NEWLINE:
5967c478bd9Sstevel@tonic-gate 			filep->linenum++;
5977c478bd9Sstevel@tonic-gate 			break;
5987c478bd9Sstevel@tonic-gate 		case T_POUND:
5997c478bd9Sstevel@tonic-gate 			find_eol(filep->fp);
6007c478bd9Sstevel@tonic-gate 			break;
6017c478bd9Sstevel@tonic-gate 		case T_EOF:
6027c478bd9Sstevel@tonic-gate 			file_err(filep, "Unexpected EOF\n");
6037c478bd9Sstevel@tonic-gate 			goto bad;
6047c478bd9Sstevel@tonic-gate 		default:
6057c478bd9Sstevel@tonic-gate 			file_err(filep, tok_err, tokbuf);
6067c478bd9Sstevel@tonic-gate 			goto bad;
6077c478bd9Sstevel@tonic-gate 		}
6087c478bd9Sstevel@tonic-gate 	} while ((token = lex(filep, tokbuf, linesize)) != T_SEMICOLON);
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	failed = 0;
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate bad:
6137c478bd9Sstevel@tonic-gate 	if (prop_name)
6147c478bd9Sstevel@tonic-gate 		free(prop_name);
6157c478bd9Sstevel@tonic-gate 	if (string)
6167c478bd9Sstevel@tonic-gate 		free(string);
6177c478bd9Sstevel@tonic-gate 	if (failed == 1) {
6187c478bd9Sstevel@tonic-gate 		free_confent(confent);
6197c478bd9Sstevel@tonic-gate 		return (NULL);
6207c478bd9Sstevel@tonic-gate 	}
6217c478bd9Sstevel@tonic-gate 	return (confent);
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate /*
6257c478bd9Sstevel@tonic-gate  * Parse all entries with mpxio-disable property in the given driver.conf
6267c478bd9Sstevel@tonic-gate  * file.
6277c478bd9Sstevel@tonic-gate  *
6287c478bd9Sstevel@tonic-gate  * fname		driver.conf file name
6297c478bd9Sstevel@tonic-gate  * confent_list		on return *confent_list will contain the list of
6307c478bd9Sstevel@tonic-gate  *			driver.conf file entries with mpxio-disable property.
6317c478bd9Sstevel@tonic-gate  * mpxio_disable	on return *mpxio_disable is set to the setting of the
6327c478bd9Sstevel@tonic-gate  * 			driver global mpxio-dissable property as follows.
6337c478bd9Sstevel@tonic-gate  *			0  if driver mpxio-disable="no"
6347c478bd9Sstevel@tonic-gate  *			1  if driver mpxio-disable="yes"
6357c478bd9Sstevel@tonic-gate  *			-1 if driver mpxio-disable property isn't specified.
6367c478bd9Sstevel@tonic-gate  */
6377c478bd9Sstevel@tonic-gate static void
parse_conf_file(char * fname,struct conf_entry ** confent_list,int * mpxio_disable)6387c478bd9Sstevel@tonic-gate parse_conf_file(char *fname, struct conf_entry **confent_list,
6397c478bd9Sstevel@tonic-gate     int *mpxio_disable)
6407c478bd9Sstevel@tonic-gate {
6417c478bd9Sstevel@tonic-gate 	struct conf_entry *confent, *tail = NULL;
6427c478bd9Sstevel@tonic-gate 	token_t token;
6437c478bd9Sstevel@tonic-gate 	struct conf_file file;
6447c478bd9Sstevel@tonic-gate 	char tokval[MAX_TOKEN_SIZE];
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	*confent_list = NULL;
6477c478bd9Sstevel@tonic-gate 	*mpxio_disable = -1;
6487c478bd9Sstevel@tonic-gate 	if ((file.fp = fopen(fname, "r")) == NULL)
6497c478bd9Sstevel@tonic-gate 		return;
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	file.filename = fname;
6527c478bd9Sstevel@tonic-gate 	file.linenum = 1;
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	while ((token = lex(&file, tokval, MAX_TOKEN_SIZE)) != T_EOF) {
6557c478bd9Sstevel@tonic-gate 		switch (token) {
6567c478bd9Sstevel@tonic-gate 		case T_POUND:
6577c478bd9Sstevel@tonic-gate 			/*
6587c478bd9Sstevel@tonic-gate 			 * Skip comments.
6597c478bd9Sstevel@tonic-gate 			 */
6607c478bd9Sstevel@tonic-gate 			find_eol(file.fp);
6617c478bd9Sstevel@tonic-gate 			break;
6627c478bd9Sstevel@tonic-gate 		case T_NAME:
6637c478bd9Sstevel@tonic-gate 			if ((confent = parse_conf_entry(&file, tokval,
6647c478bd9Sstevel@tonic-gate 			    MAX_TOKEN_SIZE)) == NULL)
6657c478bd9Sstevel@tonic-gate 				break;
6667c478bd9Sstevel@tonic-gate 			/*
6677c478bd9Sstevel@tonic-gate 			 * No name indicates global property.
6687c478bd9Sstevel@tonic-gate 			 * Make sure parent and class not NULL.
6697c478bd9Sstevel@tonic-gate 			 */
6707c478bd9Sstevel@tonic-gate 			if (confent->name == NULL) {
6717c478bd9Sstevel@tonic-gate 				if (confent->parent ||
6727c478bd9Sstevel@tonic-gate 				    confent->class) {
6737c478bd9Sstevel@tonic-gate 					file_err(&file,
6747c478bd9Sstevel@tonic-gate 					    "missing name attribute\n");
6757c478bd9Sstevel@tonic-gate 				} else if (confent->mpxio_disable != -1) {
6767c478bd9Sstevel@tonic-gate 					if (*mpxio_disable == -1)
6777c478bd9Sstevel@tonic-gate 						*mpxio_disable =
6787c478bd9Sstevel@tonic-gate 						    confent->mpxio_disable;
6797c478bd9Sstevel@tonic-gate 					else
6807c478bd9Sstevel@tonic-gate 						file_err(&file,
6817c478bd9Sstevel@tonic-gate 				"'mpxio-disable' property already specified\n");
6827c478bd9Sstevel@tonic-gate 				}
6837c478bd9Sstevel@tonic-gate 				free_confent(confent);
6847c478bd9Sstevel@tonic-gate 				break;
6857c478bd9Sstevel@tonic-gate 			}
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 			/*
6887c478bd9Sstevel@tonic-gate 			 * This is a node spec, either parent or class
6897c478bd9Sstevel@tonic-gate 			 * must be specified.
6907c478bd9Sstevel@tonic-gate 			 */
6917c478bd9Sstevel@tonic-gate 			if (confent->parent == NULL && confent->class == NULL) {
6927c478bd9Sstevel@tonic-gate 				file_err(&file,
6937c478bd9Sstevel@tonic-gate 				    "missing parent or class attribute\n");
6947c478bd9Sstevel@tonic-gate 				free_confent(confent);
6957c478bd9Sstevel@tonic-gate 				break;
6967c478bd9Sstevel@tonic-gate 			}
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 			/* only need entries with mpxio_disable property */
6997c478bd9Sstevel@tonic-gate 			if (confent->mpxio_disable == -1) {
7007c478bd9Sstevel@tonic-gate 				free_confent(confent);
7017c478bd9Sstevel@tonic-gate 				break;
7027c478bd9Sstevel@tonic-gate 			}
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 			if (tail)
7057c478bd9Sstevel@tonic-gate 				tail->next = confent;
7067c478bd9Sstevel@tonic-gate 			else
7077c478bd9Sstevel@tonic-gate 				*confent_list = confent;
7087c478bd9Sstevel@tonic-gate 			tail = confent;
7097c478bd9Sstevel@tonic-gate 			break;
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 		case T_NEWLINE:
7127c478bd9Sstevel@tonic-gate 			file.linenum++;
7137c478bd9Sstevel@tonic-gate 			break;
7147c478bd9Sstevel@tonic-gate 		default:
7157c478bd9Sstevel@tonic-gate 			break;
7167c478bd9Sstevel@tonic-gate 		}
7177c478bd9Sstevel@tonic-gate 	}
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	(void) fclose(file.fp);
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate /*
7237c478bd9Sstevel@tonic-gate  * Return the driver class of the given driver_name.
7247c478bd9Sstevel@tonic-gate  * The memory for the driver class is allocated by this function and the
7257c478bd9Sstevel@tonic-gate  * caller must free it.
7267c478bd9Sstevel@tonic-gate  */
7277c478bd9Sstevel@tonic-gate static char *
get_driver_class(char * rootdir,char * driver_name)7287c478bd9Sstevel@tonic-gate get_driver_class(char *rootdir, char *driver_name)
7297c478bd9Sstevel@tonic-gate {
7307c478bd9Sstevel@tonic-gate 	FILE *fp;
7317c478bd9Sstevel@tonic-gate 	char buf[BUFSIZE];
7327c478bd9Sstevel@tonic-gate 	char driver[BUFSIZE];
7337c478bd9Sstevel@tonic-gate 	char class_name[BUFSIZE];
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	logdmsg(("get_driver_class: rootdir = %s, driver name = %s\n",
7367c478bd9Sstevel@tonic-gate 	    rootdir, driver_name));
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%s%s", rootdir, DRIVER_CLASSES);
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	if ((fp = fopen(buf, "r")) == NULL) {
7417c478bd9Sstevel@tonic-gate 		logdmsg(("get_driver_class: failed to open %s: %s\n",
7427c478bd9Sstevel@tonic-gate 		    buf, strerror(errno)));
7437c478bd9Sstevel@tonic-gate 		return (NULL);
7447c478bd9Sstevel@tonic-gate 	}
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	while (fgets(buf, sizeof (buf), fp) != NULL) {
7477c478bd9Sstevel@tonic-gate 		/* LINTED - unbounded string specifier */
7487c478bd9Sstevel@tonic-gate 		if ((sscanf(buf, "%s %s", driver, class_name) == 2) &&
7497c478bd9Sstevel@tonic-gate 		    driver[0] != '#' && strcmp(driver, driver_name) == 0) {
7507c478bd9Sstevel@tonic-gate 			logdmsg(("get_driver_class: driver class = %s\n",
7517c478bd9Sstevel@tonic-gate 			    class_name));
7527c478bd9Sstevel@tonic-gate 			(void) fclose(fp);
7537c478bd9Sstevel@tonic-gate 			return (strdup(class_name));
7547c478bd9Sstevel@tonic-gate 		}
7557c478bd9Sstevel@tonic-gate 	}
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
7587c478bd9Sstevel@tonic-gate 	return (NULL);
7597c478bd9Sstevel@tonic-gate }
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate static int
lookup_in_confent_list(struct conf_entry * confent_list,int match_class,char * parent,char * unit_addr,int port)7627c478bd9Sstevel@tonic-gate lookup_in_confent_list(struct conf_entry *confent_list,
7637c478bd9Sstevel@tonic-gate     int match_class, char *parent, char *unit_addr, int port)
7647c478bd9Sstevel@tonic-gate {
7657c478bd9Sstevel@tonic-gate 	struct conf_entry *confent;
7667c478bd9Sstevel@tonic-gate 	char *par;
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	logdmsg(("lookup_in_confent_list: %s = \"%s\", unit_addr = \"%s\", "
7697c478bd9Sstevel@tonic-gate 	    "port = %d\n", (match_class) ? "class" : "parent", parent,
7707c478bd9Sstevel@tonic-gate 	    STRVAL(unit_addr), port));
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	for (confent = confent_list; confent != NULL; confent = confent->next) {
7737c478bd9Sstevel@tonic-gate 		par = (match_class) ? confent->class : confent->parent;
7747c478bd9Sstevel@tonic-gate 		if (unit_addr) {
7757c478bd9Sstevel@tonic-gate 			if (confent->unit_address != NULL &&
7767c478bd9Sstevel@tonic-gate 			    strcmp(confent->unit_address, unit_addr) == 0 &&
7777c478bd9Sstevel@tonic-gate 			    par != NULL && strcmp(par, parent) == 0)
7787c478bd9Sstevel@tonic-gate 				return (confent->mpxio_disable);
7797c478bd9Sstevel@tonic-gate 		} else {
7807c478bd9Sstevel@tonic-gate 			if (confent->port == port &&
7817c478bd9Sstevel@tonic-gate 			    par != NULL && strcmp(par, parent) == 0)
7827c478bd9Sstevel@tonic-gate 				return (confent->mpxio_disable);
7837c478bd9Sstevel@tonic-gate 		}
7847c478bd9Sstevel@tonic-gate 	}
7857c478bd9Sstevel@tonic-gate 	return (-1);
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate /*
7897c478bd9Sstevel@tonic-gate  * lookup mpxio-disabled property setting for the given path in the given
7907c478bd9Sstevel@tonic-gate  * driver.conf file. Match the entries from most specific to least specific.
7917c478bd9Sstevel@tonic-gate  *
7927c478bd9Sstevel@tonic-gate  * conf_file	the path name of either fp.conf, qlc.conf or scsi_vhci.conf
7937c478bd9Sstevel@tonic-gate  * path		/devices node path without the /devices prefix.
7947c478bd9Sstevel@tonic-gate  *		If the conf_file is fp.conf, path must be a fp node path
7957c478bd9Sstevel@tonic-gate  *		if the conf_file is qlc.conf, path must be a qlc node path.
7967c478bd9Sstevel@tonic-gate  *		if the conf_file is scsi_vhci.conf, path must be NULL.
7977c478bd9Sstevel@tonic-gate  *		ex:	/pci@8,600000/SUNW,qlc@4/fp@0,0
7987c478bd9Sstevel@tonic-gate  *			/pci@8,600000/SUNW,qlc@4
7997c478bd9Sstevel@tonic-gate  *
8007c478bd9Sstevel@tonic-gate  * returns:
8017c478bd9Sstevel@tonic-gate  *	0	if mpxio-disable="no"
8027c478bd9Sstevel@tonic-gate  *	1	if mpxio-disable="yes"
8037c478bd9Sstevel@tonic-gate  *	-1	if mpxio-disable property isn't specified.
8047c478bd9Sstevel@tonic-gate  */
8057c478bd9Sstevel@tonic-gate static int
lookup_in_conf_file(char * rootdir,char * conf_file,char * path)8067c478bd9Sstevel@tonic-gate lookup_in_conf_file(char *rootdir, char *conf_file, char *path)
8077c478bd9Sstevel@tonic-gate {
8087c478bd9Sstevel@tonic-gate 	struct conf_entry *confent_list = NULL;
8097c478bd9Sstevel@tonic-gate 	int mpxio_disable;
8107c478bd9Sstevel@tonic-gate 	di_node_t par_node = DI_NODE_NIL;
8117c478bd9Sstevel@tonic-gate 	char *node_name = NULL, *node_addr = NULL;
8127c478bd9Sstevel@tonic-gate 	char *unit_addr = NULL;
8137c478bd9Sstevel@tonic-gate 	int port = -1;
8147c478bd9Sstevel@tonic-gate 	char *par_node_name = NULL, *par_node_addr = NULL;
8157c478bd9Sstevel@tonic-gate 	char *par_binding_name = NULL, *par_driver_name = NULL;
8167c478bd9Sstevel@tonic-gate 	char *par_driver_class = NULL, *par_node_name_addr;
8177c478bd9Sstevel@tonic-gate 	int rv = -1;
8187c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	logdmsg(("lookup_in_conf_file: rootdir = \"%s\", conf_file = \"%s\", "
8217c478bd9Sstevel@tonic-gate 	    "path = \"%s\"\n", rootdir, conf_file, STRVAL(path)));
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, MAXPATHLEN, "%s%s", rootdir, conf_file);
8247c478bd9Sstevel@tonic-gate 	parse_conf_file(buf, &confent_list, &mpxio_disable);
8257c478bd9Sstevel@tonic-gate #ifdef DEBUG
8267c478bd9Sstevel@tonic-gate 	log_confent_list(buf, confent_list, mpxio_disable);
8277c478bd9Sstevel@tonic-gate #endif
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	/* if path is NULL, return driver global mpxio-disable setting */
8307c478bd9Sstevel@tonic-gate 	if (path == NULL) {
8317c478bd9Sstevel@tonic-gate 		rv = mpxio_disable;
8327c478bd9Sstevel@tonic-gate 		goto done;
8337c478bd9Sstevel@tonic-gate 	}
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	if ((node_name = strrchr(path, '/')) == NULL)
8367c478bd9Sstevel@tonic-gate 		goto done;
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	*node_name = '\0';
8397c478bd9Sstevel@tonic-gate 	node_name++;
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 	if ((node_addr = strchr(node_name, '@')) == NULL)
8427c478bd9Sstevel@tonic-gate 		goto done;
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 	*node_addr = '\0';
8457c478bd9Sstevel@tonic-gate 	node_addr++;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	if (strcmp(node_name, "fp") == 0) {
8487c478bd9Sstevel@tonic-gate 		/* get port number; encoded in the node addr as a hex number */
8497c478bd9Sstevel@tonic-gate 		port = (int)strtol(node_addr, NULL, 16);
8507c478bd9Sstevel@tonic-gate 	} else
8517c478bd9Sstevel@tonic-gate 		unit_addr = node_addr;
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	/*
8547c478bd9Sstevel@tonic-gate 	 * Match from most specific to least specific;
8557c478bd9Sstevel@tonic-gate 	 * first, start the lookup based on full path.
8567c478bd9Sstevel@tonic-gate 	 */
8577c478bd9Sstevel@tonic-gate 	if ((rv = lookup_in_confent_list(confent_list, 0, path,
8587c478bd9Sstevel@tonic-gate 	    unit_addr, port)) != -1)
8597c478bd9Sstevel@tonic-gate 		goto done;
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	/* lookup nodename@address */
8627c478bd9Sstevel@tonic-gate 	if ((par_node_name_addr = strrchr(path, '/')) != NULL) {
8637c478bd9Sstevel@tonic-gate 		par_node_name_addr++;
8647c478bd9Sstevel@tonic-gate 		if ((rv = lookup_in_confent_list(confent_list, 0,
8657c478bd9Sstevel@tonic-gate 		    par_node_name_addr, unit_addr, port)) != -1)
8667c478bd9Sstevel@tonic-gate 			goto done;
8677c478bd9Sstevel@tonic-gate 	}
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 	/* di_init() doesn't work when 0 is passed in flags */
8707c478bd9Sstevel@tonic-gate 	par_node = di_init(path, DINFOMINOR);
8717c478bd9Sstevel@tonic-gate 	if (par_node != DI_NODE_NIL) {
8727c478bd9Sstevel@tonic-gate 		par_node_name = di_node_name(par_node);
8737c478bd9Sstevel@tonic-gate 		par_node_addr = di_bus_addr(par_node);
8747c478bd9Sstevel@tonic-gate 		par_binding_name = di_binding_name(par_node);
8757c478bd9Sstevel@tonic-gate 		par_driver_name = di_driver_name(par_node);
8767c478bd9Sstevel@tonic-gate 	}
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	logdmsg(("par_node_name = %s\n", STRVAL(par_node_name)));
8797c478bd9Sstevel@tonic-gate 	logdmsg(("par_node_addr = %s\n", STRVAL(par_node_addr)));
8807c478bd9Sstevel@tonic-gate 	logdmsg(("par_binding_name = %s\n", STRVAL(par_binding_name)));
8817c478bd9Sstevel@tonic-gate 	logdmsg(("par_driver_name = %s\n", STRVAL(par_driver_name)));
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	/* lookup bindingname@address */
8847c478bd9Sstevel@tonic-gate 	if (par_binding_name != NULL && par_binding_name != par_node_name &&
8857c478bd9Sstevel@tonic-gate 	    par_node_addr != NULL) {
8867c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "%s@%s", par_binding_name,
8877c478bd9Sstevel@tonic-gate 		    par_node_addr);
8887c478bd9Sstevel@tonic-gate 		if ((rv = lookup_in_confent_list(confent_list, 0,
8897c478bd9Sstevel@tonic-gate 		    buf, unit_addr, port)) != -1)
8907c478bd9Sstevel@tonic-gate 			goto done;
8917c478bd9Sstevel@tonic-gate 	}
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	/* lookup binding name */
8947c478bd9Sstevel@tonic-gate 	if (par_binding_name != NULL) {
8957c478bd9Sstevel@tonic-gate 		if ((rv = lookup_in_confent_list(confent_list, 0,
8967c478bd9Sstevel@tonic-gate 		    par_binding_name, unit_addr, port)) != -1)
8977c478bd9Sstevel@tonic-gate 			goto done;
8987c478bd9Sstevel@tonic-gate 	}
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	if (par_driver_name != NULL) {
9017c478bd9Sstevel@tonic-gate 		/* lookup driver name */
9027c478bd9Sstevel@tonic-gate 		if ((rv = lookup_in_confent_list(confent_list, 0,
9037c478bd9Sstevel@tonic-gate 		    par_driver_name, unit_addr, port)) != -1)
9047c478bd9Sstevel@tonic-gate 			goto done;
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 		/* finally, lookup class name */
9077c478bd9Sstevel@tonic-gate 		par_driver_class = get_driver_class(rootdir, par_driver_name);
9087c478bd9Sstevel@tonic-gate 		if (par_driver_class != NULL) {
9097c478bd9Sstevel@tonic-gate 			if ((rv = lookup_in_confent_list(confent_list, 1,
9107c478bd9Sstevel@tonic-gate 			    par_driver_class, unit_addr, port)) != -1)
9117c478bd9Sstevel@tonic-gate 				goto done;
9127c478bd9Sstevel@tonic-gate 		}
9137c478bd9Sstevel@tonic-gate 	}
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 	/*
9167c478bd9Sstevel@tonic-gate 	 * no match so far;
9177c478bd9Sstevel@tonic-gate 	 * use the driver global mpxio-disable setting if exists.
9187c478bd9Sstevel@tonic-gate 	 */
9197c478bd9Sstevel@tonic-gate 	rv = mpxio_disable;
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate done:
9227c478bd9Sstevel@tonic-gate 	if (node_name != NULL)
9237c478bd9Sstevel@tonic-gate 		*(node_name - 1) = '/';
9247c478bd9Sstevel@tonic-gate 	if (node_addr != NULL)
9257c478bd9Sstevel@tonic-gate 		*(node_addr - 1) = '@';
9267c478bd9Sstevel@tonic-gate 	if (par_driver_class != NULL)
9277c478bd9Sstevel@tonic-gate 		free(par_driver_class);
9287c478bd9Sstevel@tonic-gate 	if (confent_list != NULL)
9297c478bd9Sstevel@tonic-gate 		free_confent_list(confent_list);
9307c478bd9Sstevel@tonic-gate 	if (par_node != DI_NODE_NIL)
9317c478bd9Sstevel@tonic-gate 		di_fini(par_node);
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	return (rv);
9347c478bd9Sstevel@tonic-gate }
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate /*
9377c478bd9Sstevel@tonic-gate  * Given client_name return whether it is a phci or vhci based name.
9387c478bd9Sstevel@tonic-gate  * client_name is /devices name of a client without the /devices prefix.
9397c478bd9Sstevel@tonic-gate  *
9407c478bd9Sstevel@tonic-gate  * client_name			Return value
9417c478bd9Sstevel@tonic-gate  * .../fp@xxx/ssd@yyy		CLIENT_TYPE_PHCI
9427c478bd9Sstevel@tonic-gate  * .../scsi_vhci/ssd@yyy	CLIENT_TYPE_VHCI
9437c478bd9Sstevel@tonic-gate  * other			CLIENT_TYPE_UNKNOWN
9447c478bd9Sstevel@tonic-gate  */
9457c478bd9Sstevel@tonic-gate static client_type_t
client_name_type(char * client_name)9467c478bd9Sstevel@tonic-gate client_name_type(char *client_name)
9477c478bd9Sstevel@tonic-gate {
9487c478bd9Sstevel@tonic-gate 	client_type_t client_type;
9497c478bd9Sstevel@tonic-gate 	char *p1, *p2;
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	logdmsg(("client_name_type: client_name = %s\n", client_name));
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	if (strncmp(client_name, SLASH_SCSI_VHCI,
9547c478bd9Sstevel@tonic-gate 	    sizeof (SLASH_SCSI_VHCI) - 1) == 0)
9557c478bd9Sstevel@tonic-gate 		return (CLIENT_TYPE_VHCI);
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	if (*client_name != '/')
9587c478bd9Sstevel@tonic-gate 		return (CLIENT_TYPE_UNKNOWN);
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate 	if ((p1 = strrchr(client_name, '/')) == NULL)
9617c478bd9Sstevel@tonic-gate 		return (CLIENT_TYPE_UNKNOWN);
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	*p1 = '\0';
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	if ((p2 = strrchr(client_name, '/')) != NULL &&
9667c478bd9Sstevel@tonic-gate 	    strncmp(p2, SLASH_FP_AT, sizeof (SLASH_FP_AT) - 1) == 0)
9677c478bd9Sstevel@tonic-gate 		client_type = CLIENT_TYPE_PHCI;
9687c478bd9Sstevel@tonic-gate 	else
9697c478bd9Sstevel@tonic-gate 		client_type = CLIENT_TYPE_UNKNOWN;
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	*p1 = '/';
9727c478bd9Sstevel@tonic-gate 	return (client_type);
9737c478bd9Sstevel@tonic-gate }
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate /*
9767c478bd9Sstevel@tonic-gate  * Compare controller name portion of dev1 and dev2.
9777c478bd9Sstevel@tonic-gate  *
9787c478bd9Sstevel@tonic-gate  * rootdir	root directory of the target environment
9797c478bd9Sstevel@tonic-gate  * dev1		can be either a /dev link or /devices name in the target
9807c478bd9Sstevel@tonic-gate  *		environemnt
9817c478bd9Sstevel@tonic-gate  * dev2		/devices name of a device without the /devices prefix
9827c478bd9Sstevel@tonic-gate  *
9837c478bd9Sstevel@tonic-gate  * Returns:
9847c478bd9Sstevel@tonic-gate  *	0	if controller names match
9857c478bd9Sstevel@tonic-gate  *	1	if controller names don't match
9867c478bd9Sstevel@tonic-gate  *	-1	an error occurred.
9877c478bd9Sstevel@tonic-gate  */
9887c478bd9Sstevel@tonic-gate static int
compare_controller(char * rootdir,char * dev1,char * dev2)9897c478bd9Sstevel@tonic-gate compare_controller(char *rootdir, char *dev1, char *dev2)
9907c478bd9Sstevel@tonic-gate {
9917c478bd9Sstevel@tonic-gate 	int linksize;
9927c478bd9Sstevel@tonic-gate 	char *p1, *p;
9937c478bd9Sstevel@tonic-gate 	char physdev1[MAXPATHLEN];
9947c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	logdmsg(("compare_controller: rootdir = %s, dev1 = %s, dev2 = %s\n",
9977c478bd9Sstevel@tonic-gate 	    rootdir, dev1, dev2));
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	if (strncmp(dev1, SLASH_DEV_SLASH, sizeof (SLASH_DEV_SLASH) - 1)
10007c478bd9Sstevel@tonic-gate 	    == 0) {
10017c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, MAXPATHLEN, "%s%s", rootdir, dev1);
10027c478bd9Sstevel@tonic-gate 		if ((linksize = readlink(buf, physdev1, MAXPATHLEN)) > 0 &&
10037c478bd9Sstevel@tonic-gate 		    linksize < (MAXPATHLEN - 1)) {
10047c478bd9Sstevel@tonic-gate 			physdev1[linksize] = '\0';
10057c478bd9Sstevel@tonic-gate 			logdmsg(("compare_controller: physdev1 = %s\n",
10067c478bd9Sstevel@tonic-gate 			    physdev1));
10077c478bd9Sstevel@tonic-gate 		} else
10087c478bd9Sstevel@tonic-gate 			return (-1);
10097c478bd9Sstevel@tonic-gate 	} else
10107c478bd9Sstevel@tonic-gate 		(void) strlcpy(physdev1, dev1, MAXPATHLEN);
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 	if ((p1 = strstr(physdev1, SLASH_DEVICES)) == NULL)
10137c478bd9Sstevel@tonic-gate 		return (-1);
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	p1 += sizeof (SLASH_DEVICES) - 1;
10167c478bd9Sstevel@tonic-gate 	/* strip the device portion */
10177c478bd9Sstevel@tonic-gate 	if ((p = strrchr(p1, '/')) == NULL)
10187c478bd9Sstevel@tonic-gate 		return (-1);
10197c478bd9Sstevel@tonic-gate 	*p = '\0';
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	if ((p = strrchr(dev2, '/')) == NULL)
10227c478bd9Sstevel@tonic-gate 		return (-1);
10237c478bd9Sstevel@tonic-gate 	*p = '\0';
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 	logdmsg(("compare_controller: path1 = %s, path2 = %s\n",
10267c478bd9Sstevel@tonic-gate 	    p1, dev2));
10277c478bd9Sstevel@tonic-gate 	if (strcmp(p1, dev2) == 0) {
10287c478bd9Sstevel@tonic-gate 		*p = '/';
10297c478bd9Sstevel@tonic-gate 		return (0);
10307c478bd9Sstevel@tonic-gate 	} else {
10317c478bd9Sstevel@tonic-gate 		*p = '/';
10327c478bd9Sstevel@tonic-gate 		return (1);
10337c478bd9Sstevel@tonic-gate 	}
10347c478bd9Sstevel@tonic-gate }
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate /*
10377c478bd9Sstevel@tonic-gate  * Check if the specified device path is on the root controller.
10387c478bd9Sstevel@tonic-gate  *
10397c478bd9Sstevel@tonic-gate  * rootdir	root directory of the target environment
10407c478bd9Sstevel@tonic-gate  * path		/devices name of a device without the /devices prefix
10417c478bd9Sstevel@tonic-gate  *
10427c478bd9Sstevel@tonic-gate  * Returns
10437c478bd9Sstevel@tonic-gate  *	1	if the path is on the root controller
10447c478bd9Sstevel@tonic-gate  *	0	if the path is not on the root controller
10457c478bd9Sstevel@tonic-gate  *	-1	if an error occurs
10467c478bd9Sstevel@tonic-gate  */
10477c478bd9Sstevel@tonic-gate static int
is_root_controller(char * rootdir,char * path)10487c478bd9Sstevel@tonic-gate is_root_controller(char *rootdir, char *path)
10497c478bd9Sstevel@tonic-gate {
10507c478bd9Sstevel@tonic-gate 	FILE *fp;
10517c478bd9Sstevel@tonic-gate 	char *tmpfile;
10527c478bd9Sstevel@tonic-gate 	int rv = -1;
10537c478bd9Sstevel@tonic-gate 	struct vfstab vfsent;
10547c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
10557c478bd9Sstevel@tonic-gate 	char ctd[MAXNAMELEN + 1];
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	logdmsg(("is_root_controller: rootdir = %s, path = %s\n", rootdir,
10587c478bd9Sstevel@tonic-gate 	    path));
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, MAXPATHLEN, "%s%s", rootdir, VFSTAB);
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	if ((fp = fopen(buf, "r")) == NULL) {
10637c478bd9Sstevel@tonic-gate 		logdmsg(("is_root_controller: failed to open %s: %s\n",
10647c478bd9Sstevel@tonic-gate 		    buf, strerror(errno)));
10657c478bd9Sstevel@tonic-gate 		return (-1);
10667c478bd9Sstevel@tonic-gate 	}
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 	if (getvfsfile(fp, &vfsent, "/") != 0) {
10697c478bd9Sstevel@tonic-gate 		logdmsg(("is_root_controller: getvfsfile: failed to read "
10707c478bd9Sstevel@tonic-gate 		    "vfstab entry for mount point \"/\": %s\n",
10717c478bd9Sstevel@tonic-gate 		    strerror(errno)));
10727c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
10737c478bd9Sstevel@tonic-gate 		return (-1);
10747c478bd9Sstevel@tonic-gate 	}
10757c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate 	/* check if the root is an svm metadisk */
10787c478bd9Sstevel@tonic-gate 	if (strncmp(vfsent.vfs_special, META_DEV, sizeof (META_DEV) - 1) != 0) {
10797c478bd9Sstevel@tonic-gate 		if (compare_controller(rootdir, vfsent.vfs_special, path) == 0)
10807c478bd9Sstevel@tonic-gate 			return (1);
10817c478bd9Sstevel@tonic-gate 		else
10827c478bd9Sstevel@tonic-gate 			return (0);
10837c478bd9Sstevel@tonic-gate 	}
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	/* Don't use /var/run as it is not mounted in miniroot */
10867c478bd9Sstevel@tonic-gate 	if ((tmpfile = tempnam("/tmp", "diirc")) == NULL) {
10877c478bd9Sstevel@tonic-gate 		logdmsg(("is_root_controller: tempnam: failed: %s\n",
10887c478bd9Sstevel@tonic-gate 		    strerror(errno)));
10897c478bd9Sstevel@tonic-gate 		return (-1);
10907c478bd9Sstevel@tonic-gate 	}
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 	/* get metadisk components using metastat command */
10937c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, MAXPATHLEN,
10947c478bd9Sstevel@tonic-gate 	    "/usr/sbin/metastat -p %s 2>/dev/null | "
10957c478bd9Sstevel@tonic-gate 	    "/usr/bin/grep ' 1 1 ' | "
10967c478bd9Sstevel@tonic-gate 	    "/usr/bin/sed -e 's/^.* 1 1 //' | "
10977c478bd9Sstevel@tonic-gate 	    "/usr/bin/cut -f1 -d ' ' > %s",
10987c478bd9Sstevel@tonic-gate 	    vfsent.vfs_special + sizeof (META_DEV) - 1, tmpfile);
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	logdmsg(("is_root_controller: command = %s\n", buf));
11017c478bd9Sstevel@tonic-gate 	fp = NULL;
11027c478bd9Sstevel@tonic-gate 	if (system(buf) == 0 && (fp = fopen(tmpfile, "r")) != NULL) {
11037c478bd9Sstevel@tonic-gate 		while (fscanf(fp, "%" VAL2STR(MAXNAMELEN) "s", ctd) == 1) {
11047c478bd9Sstevel@tonic-gate 			(void) snprintf(buf, MAXPATHLEN, "/dev/dsk/%s", ctd);
11057c478bd9Sstevel@tonic-gate 			if (compare_controller(rootdir, buf, path) == 0) {
11067c478bd9Sstevel@tonic-gate 				rv = 1;
11077c478bd9Sstevel@tonic-gate 				goto out;
11087c478bd9Sstevel@tonic-gate 			}
11097c478bd9Sstevel@tonic-gate 		}
11107c478bd9Sstevel@tonic-gate 		rv = 0;
11117c478bd9Sstevel@tonic-gate 	}
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate out:
11147c478bd9Sstevel@tonic-gate 	if (fp)
11157c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
11167c478bd9Sstevel@tonic-gate 	(void) unlink(tmpfile);
11177c478bd9Sstevel@tonic-gate 	free(tmpfile);
11187c478bd9Sstevel@tonic-gate 	return (rv);
11197c478bd9Sstevel@tonic-gate }
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate static int
file_exists(char * rootdir,char * path)11227c478bd9Sstevel@tonic-gate file_exists(char *rootdir, char *path)
11237c478bd9Sstevel@tonic-gate {
11247c478bd9Sstevel@tonic-gate 	struct stat stbuf;
11257c478bd9Sstevel@tonic-gate 	char fullpath[MAXPATHLEN];
11267c478bd9Sstevel@tonic-gate 	int x;
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 	(void) snprintf(fullpath, MAXPATHLEN, "%s%s", rootdir, path);
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	x = stat(fullpath, &stbuf);
11317c478bd9Sstevel@tonic-gate 	logdmsg(("file_exists: %s: %s\n", fullpath, (x == 0) ? "yes" : "no"));
11327c478bd9Sstevel@tonic-gate 	if (x == 0)
11337c478bd9Sstevel@tonic-gate 		return (1);
11347c478bd9Sstevel@tonic-gate 	else
11357c478bd9Sstevel@tonic-gate 		return (0);
11367c478bd9Sstevel@tonic-gate }
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate /*
11397c478bd9Sstevel@tonic-gate  * Check if mpxio is enabled or disabled on the specified device path.
11407c478bd9Sstevel@tonic-gate  * Looks through the .conf files to determine the mpxio setting.
11417c478bd9Sstevel@tonic-gate  *
11427c478bd9Sstevel@tonic-gate  * rootdir	root directory of the target environment
11437c478bd9Sstevel@tonic-gate  * path		/devices name of a device without the /devices prefix and
11447c478bd9Sstevel@tonic-gate  *		minor name component.
11457c478bd9Sstevel@tonic-gate  *
11467c478bd9Sstevel@tonic-gate  * Returns
11477c478bd9Sstevel@tonic-gate  *	1	if mpxio is disabled
11487c478bd9Sstevel@tonic-gate  *	0	if mpxio is enabled
11497c478bd9Sstevel@tonic-gate  *	-1	if an error occurs
11507c478bd9Sstevel@tonic-gate  */
11517c478bd9Sstevel@tonic-gate static int
is_mpxio_disabled(char * rootdir,char * path)11527c478bd9Sstevel@tonic-gate is_mpxio_disabled(char *rootdir, char *path)
11537c478bd9Sstevel@tonic-gate {
11547c478bd9Sstevel@tonic-gate 	int mpxio_disable;
11557c478bd9Sstevel@tonic-gate 	char *p;
11567c478bd9Sstevel@tonic-gate 	int check_root_controller;
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 	logdmsg(("is_mpxio_disabled: rootdir = %s, path = %s\n",
11597c478bd9Sstevel@tonic-gate 	    rootdir, path));
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	if (file_exists(rootdir, SCSI_VHCI_CONF) == 0) {
11627c478bd9Sstevel@tonic-gate 		/*
11637c478bd9Sstevel@tonic-gate 		 * scsi_vhci.conf doesn't exist:
11647c478bd9Sstevel@tonic-gate 		 *  if upgrading from a pre solaris 9 release. or
11657c478bd9Sstevel@tonic-gate 		 *  if this function is called during fresh or flash install
11667c478bd9Sstevel@tonic-gate 		 *  prior to installing scsi_vhci.conf file.
11677c478bd9Sstevel@tonic-gate 		 */
11687c478bd9Sstevel@tonic-gate 		if (file_exists(rootdir, "/kernel/drv"))
11697c478bd9Sstevel@tonic-gate 			/* upgrading from pre solaris 9 */
11707c478bd9Sstevel@tonic-gate 			return (1);
11717c478bd9Sstevel@tonic-gate 		else
11727c478bd9Sstevel@tonic-gate 			/* fresh or flash install */
11737c478bd9Sstevel@tonic-gate 			return (0);
11747c478bd9Sstevel@tonic-gate 	}
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	mpxio_disable = lookup_in_conf_file(rootdir, SCSI_VHCI_CONF, NULL);
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 	/*
11797c478bd9Sstevel@tonic-gate 	 * scsi_vhci.conf contains mpxio-disable property only in s9 and
11807c478bd9Sstevel@tonic-gate 	 * s8+sfkpatch. This property is no longer present from s10 onwards.
11817c478bd9Sstevel@tonic-gate 	 */
11827c478bd9Sstevel@tonic-gate 	if (mpxio_disable == 1) {
11837c478bd9Sstevel@tonic-gate 		/* upgrading from s8 or s9 with mpxio globally disabled */
11847c478bd9Sstevel@tonic-gate 		return (1);
11857c478bd9Sstevel@tonic-gate 	} else if (mpxio_disable == 0) {
11867c478bd9Sstevel@tonic-gate 		/* upgrading from s8 or s9 with mpxio globally enabled */
11877c478bd9Sstevel@tonic-gate 		check_root_controller = 1;
11887c478bd9Sstevel@tonic-gate 	} else {
11897c478bd9Sstevel@tonic-gate 		/*
11907c478bd9Sstevel@tonic-gate 		 * We are looking at the s10 version of the file. This is
11917c478bd9Sstevel@tonic-gate 		 * the case if this function is called after installing the
11927c478bd9Sstevel@tonic-gate 		 * new scsi_vhci.conf file.
11937c478bd9Sstevel@tonic-gate 		 */
11947c478bd9Sstevel@tonic-gate 		check_root_controller = 0;
11957c478bd9Sstevel@tonic-gate 	}
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 	if ((mpxio_disable = lookup_in_conf_file(rootdir, FP_CONF, path))
11987c478bd9Sstevel@tonic-gate 	    != -1)
11997c478bd9Sstevel@tonic-gate 		return (mpxio_disable);
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	if ((p = strrchr(path, '/')) == NULL)
12027c478bd9Sstevel@tonic-gate 		return (-1);
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 	*p = '\0';
12057c478bd9Sstevel@tonic-gate 	if ((mpxio_disable = lookup_in_conf_file(rootdir, QLC_CONF, path))
12067c478bd9Sstevel@tonic-gate 	    != -1) {
12077c478bd9Sstevel@tonic-gate 		*p = '/';
12087c478bd9Sstevel@tonic-gate 		return (mpxio_disable);
12097c478bd9Sstevel@tonic-gate 	}
12107c478bd9Sstevel@tonic-gate 	*p = '/';
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 	/*
12137c478bd9Sstevel@tonic-gate 	 * mpxio-disable setting is not found in the .conf files.
12147c478bd9Sstevel@tonic-gate 	 * The default is to enable mpxio, except if the path is on the root
12157c478bd9Sstevel@tonic-gate 	 * controller.
12167c478bd9Sstevel@tonic-gate 	 *
12177c478bd9Sstevel@tonic-gate 	 * In s8 and s9 mpxio is not supported on the root controller.
12187c478bd9Sstevel@tonic-gate 	 * NWS supplies a patch to enable root controller support in s8 and s9.
12197c478bd9Sstevel@tonic-gate 	 * If the system had the patch installed, the fp.conf file would have
12207c478bd9Sstevel@tonic-gate 	 * explicit "mpxio-disable=no" for the root controller. So we would
12217c478bd9Sstevel@tonic-gate 	 * have found the mpxio-disable setting when we looked up this property
12227c478bd9Sstevel@tonic-gate 	 * in the fp.conf file.
12237c478bd9Sstevel@tonic-gate 	 */
12247c478bd9Sstevel@tonic-gate 	if (check_root_controller) {
12257c478bd9Sstevel@tonic-gate 		mpxio_disable = is_root_controller(rootdir, path);
12267c478bd9Sstevel@tonic-gate 		logdmsg(("is_mpxio_disabled: is_root_controller returned %d\n",
12277c478bd9Sstevel@tonic-gate 		    mpxio_disable));
12287c478bd9Sstevel@tonic-gate 	} else
12297c478bd9Sstevel@tonic-gate 		mpxio_disable = 0;
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	return (mpxio_disable);
12327c478bd9Sstevel@tonic-gate }
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate static int
vhci_ctl(sv_iocdata_t * iocp,int cmd)12357c478bd9Sstevel@tonic-gate vhci_ctl(sv_iocdata_t *iocp, int cmd)
12367c478bd9Sstevel@tonic-gate {
12377c478bd9Sstevel@tonic-gate 	int fd, rv;
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate 	if ((fd = open(VHCI_CTL_NODE, O_RDWR)) < 0)
12407c478bd9Sstevel@tonic-gate 		return (-1);
12417c478bd9Sstevel@tonic-gate 	rv = ioctl(fd, cmd, iocp);
12427c478bd9Sstevel@tonic-gate 	(void) close(fd);
12437c478bd9Sstevel@tonic-gate 	return (rv);
12447c478bd9Sstevel@tonic-gate }
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate /*
12477c478bd9Sstevel@tonic-gate  * Convert a phci client name to vhci client name.
12487c478bd9Sstevel@tonic-gate  *
12497c478bd9Sstevel@tonic-gate  * phci_name	phci client /devices name without the /devices prefix and
12507c478bd9Sstevel@tonic-gate  *		minor name component.
12517c478bd9Sstevel@tonic-gate  *		ex: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
12527c478bd9Sstevel@tonic-gate  *
12537c478bd9Sstevel@tonic-gate  * Returns 	on success, vhci client name is returned. The memory for
12547c478bd9Sstevel@tonic-gate  *		the vhci name is allocated by this function and the caller
12557c478bd9Sstevel@tonic-gate  * 		must free it.
12567c478bd9Sstevel@tonic-gate  *		on failure, NULL is returned.
12577c478bd9Sstevel@tonic-gate  */
12587c478bd9Sstevel@tonic-gate static char *
phci_to_vhci(char * phci_name)12597c478bd9Sstevel@tonic-gate phci_to_vhci(char *phci_name)
12607c478bd9Sstevel@tonic-gate {
12617c478bd9Sstevel@tonic-gate 	sv_iocdata_t ioc;
12627c478bd9Sstevel@tonic-gate 	char *slash, *addr, *retp;
12637c478bd9Sstevel@tonic-gate 	char vhci_name_buf[MAXPATHLEN];
12647c478bd9Sstevel@tonic-gate 	char phci_name_buf[MAXPATHLEN];
12657c478bd9Sstevel@tonic-gate 	char addr_buf[MAXNAMELEN];
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 	logdmsg(("phci_to_vhci: pchi_name =  %s\n", phci_name));
12687c478bd9Sstevel@tonic-gate 	(void) strlcpy(phci_name_buf, phci_name, MAXPATHLEN);
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	if ((slash = strrchr(phci_name_buf, '/')) == NULL ||
12717c478bd9Sstevel@tonic-gate 	    (addr = strchr(slash, '@')) == NULL)
12727c478bd9Sstevel@tonic-gate 		return (NULL);
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 	*slash = '\0';
12757c478bd9Sstevel@tonic-gate 	addr++;
12767c478bd9Sstevel@tonic-gate 	(void) strlcpy(addr_buf, addr, MAXNAMELEN);
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 	bzero(&ioc, sizeof (sv_iocdata_t));
12797c478bd9Sstevel@tonic-gate 	ioc.client = vhci_name_buf;
12807c478bd9Sstevel@tonic-gate 	ioc.phci = phci_name_buf;
12817c478bd9Sstevel@tonic-gate 	ioc.addr = addr_buf;
12827c478bd9Sstevel@tonic-gate 	if (vhci_ctl(&ioc, SCSI_VHCI_GET_CLIENT_NAME) != 0) {
12837c478bd9Sstevel@tonic-gate 		logdmsg(("phci_to_vhci: vhci_ctl failed: %s\n",
12847c478bd9Sstevel@tonic-gate 		    strerror(errno)));
12857c478bd9Sstevel@tonic-gate 		return (NULL);
12867c478bd9Sstevel@tonic-gate 	}
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 	retp = strdup(vhci_name_buf);
12897c478bd9Sstevel@tonic-gate 	logdmsg(("phci_to_vhci: vhci name = %s\n", STRVAL(retp)));
12907c478bd9Sstevel@tonic-gate 	return (retp);
12917c478bd9Sstevel@tonic-gate }
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate static int
add_to_phci_list(char ** phci_list,sv_path_info_t * pi,int npaths,int state,char * node_name)12947c478bd9Sstevel@tonic-gate add_to_phci_list(char **phci_list, sv_path_info_t *pi, int npaths, int state,
12957c478bd9Sstevel@tonic-gate     char *node_name)
12967c478bd9Sstevel@tonic-gate {
12977c478bd9Sstevel@tonic-gate 	int rv = 0;
12987c478bd9Sstevel@tonic-gate 	char name[MAXPATHLEN];
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 	while (npaths--) {
13017c478bd9Sstevel@tonic-gate 		if (state == pi->ret_state) {
130272a50065Scth 			(void) snprintf(name, MAXPATHLEN, "%s/%s@%s",
13037c478bd9Sstevel@tonic-gate 			    pi->device.ret_phci, node_name, pi->ret_addr);
13047c478bd9Sstevel@tonic-gate 			if ((*phci_list = strdup(name)) == NULL)
13057c478bd9Sstevel@tonic-gate 				return (-1);
13067c478bd9Sstevel@tonic-gate 			phci_list++;
13077c478bd9Sstevel@tonic-gate 			rv++;
13087c478bd9Sstevel@tonic-gate 		}
13097c478bd9Sstevel@tonic-gate 		pi++;
13107c478bd9Sstevel@tonic-gate 	}
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 	return (rv);
13137c478bd9Sstevel@tonic-gate }
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate static void
free_pathlist(char ** pathlist)13167c478bd9Sstevel@tonic-gate free_pathlist(char **pathlist)
13177c478bd9Sstevel@tonic-gate {
13187c478bd9Sstevel@tonic-gate 	char **p;
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate 	if (pathlist != NULL) {
13217c478bd9Sstevel@tonic-gate 		for (p = pathlist; *p != NULL; p++)
13227c478bd9Sstevel@tonic-gate 			free(*p);
13237c478bd9Sstevel@tonic-gate 		free(pathlist);
13247c478bd9Sstevel@tonic-gate 	}
13257c478bd9Sstevel@tonic-gate }
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 
13287c478bd9Sstevel@tonic-gate /*
13297c478bd9Sstevel@tonic-gate  * Convert a vhci client name to phci client names.
13307c478bd9Sstevel@tonic-gate  *
13317c478bd9Sstevel@tonic-gate  * vhci_name	vhci client /devices name without the /devices prefix and
13327c478bd9Sstevel@tonic-gate  *		minor name component.
13337c478bd9Sstevel@tonic-gate  * num_paths	On return, *num_paths is set to the number paths in the
13347c478bd9Sstevel@tonic-gate  *		returned path list.
13357c478bd9Sstevel@tonic-gate  *
13367c478bd9Sstevel@tonic-gate  * Returns 	NULL terminated path list containing phci client paths is
13377c478bd9Sstevel@tonic-gate  *		returned on success. The memory for the path list is
13387c478bd9Sstevel@tonic-gate  *		allocated by this function and the caller must free it by
13397c478bd9Sstevel@tonic-gate  *		calling free_pathlist().
13407c478bd9Sstevel@tonic-gate  *		NULL is returned on failure.
13417c478bd9Sstevel@tonic-gate  */
13427c478bd9Sstevel@tonic-gate static char **
vhci_to_phci(char * vhci_name,int * num_paths)13437c478bd9Sstevel@tonic-gate vhci_to_phci(char *vhci_name, int *num_paths)
13447c478bd9Sstevel@tonic-gate {
13457c478bd9Sstevel@tonic-gate 	sv_iocdata_t ioc;
13467c478bd9Sstevel@tonic-gate 	uint_t npaths;
13477c478bd9Sstevel@tonic-gate 	int n;
13487c478bd9Sstevel@tonic-gate 	char **phci_list = NULL;
13497c478bd9Sstevel@tonic-gate 	char *node_name, *at;
13507c478bd9Sstevel@tonic-gate 	char vhci_name_buf[MAXPATHLEN];
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 	logdmsg(("vhci_to_phci: vchi_name =  %s\n", vhci_name));
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate 	*num_paths = 0;
13557c478bd9Sstevel@tonic-gate 	(void) strlcpy(vhci_name_buf, vhci_name, MAXPATHLEN);
13567c478bd9Sstevel@tonic-gate 
13577c478bd9Sstevel@tonic-gate 	/* first get the number paths */
13587c478bd9Sstevel@tonic-gate 	bzero(&ioc, sizeof (sv_iocdata_t));
13597c478bd9Sstevel@tonic-gate 	ioc.client = vhci_name_buf;
13607c478bd9Sstevel@tonic-gate 	ioc.ret_elem = &npaths;
13617c478bd9Sstevel@tonic-gate 	if (vhci_ctl(&ioc, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO) != 0 ||
13627c478bd9Sstevel@tonic-gate 	    npaths == 0) {
13637c478bd9Sstevel@tonic-gate 		logdmsg(("vhci_to_phci: vhci_ctl failed to get npaths: %s\n",
13647c478bd9Sstevel@tonic-gate 		    strerror(errno)));
13657c478bd9Sstevel@tonic-gate 		return (NULL);
13667c478bd9Sstevel@tonic-gate 	}
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 	/* now allocate memory for the path information and get all paths */
13697c478bd9Sstevel@tonic-gate 	bzero(&ioc, sizeof (sv_iocdata_t));
13707c478bd9Sstevel@tonic-gate 	ioc.client = vhci_name_buf;
13717c478bd9Sstevel@tonic-gate 	ioc.buf_elem = npaths;
13727c478bd9Sstevel@tonic-gate 	ioc.ret_elem = &npaths;
13737c478bd9Sstevel@tonic-gate 	if ((ioc.ret_buf = (sv_path_info_t *)calloc(npaths,
13747c478bd9Sstevel@tonic-gate 	    sizeof (sv_path_info_t))) == NULL)
13757c478bd9Sstevel@tonic-gate 		return (NULL);
13767c478bd9Sstevel@tonic-gate 	if (vhci_ctl(&ioc, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO) != 0 ||
13777c478bd9Sstevel@tonic-gate 	    npaths == 0) {
13787c478bd9Sstevel@tonic-gate 		logdmsg(("vhci_to_phci: vhci_ctl failed: %s\n",
13797c478bd9Sstevel@tonic-gate 		    strerror(errno)));
13807c478bd9Sstevel@tonic-gate 		goto out;
13817c478bd9Sstevel@tonic-gate 	}
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 	if (ioc.buf_elem < npaths)
13847c478bd9Sstevel@tonic-gate 		npaths = ioc.buf_elem;
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 	if ((node_name = strrchr(vhci_name_buf, '/')) == NULL ||
13877c478bd9Sstevel@tonic-gate 	    (at = strchr(node_name, '@')) == NULL)
13887c478bd9Sstevel@tonic-gate 		goto out;
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 	node_name++;
13917c478bd9Sstevel@tonic-gate 	*at = '\0';
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 	/* allocate one more (than npaths) for the terminating NULL pointer */
13947c478bd9Sstevel@tonic-gate 	if ((phci_list = calloc(npaths + 1, sizeof (char *))) == NULL)
13957c478bd9Sstevel@tonic-gate 		goto out;
13967c478bd9Sstevel@tonic-gate 
13977c478bd9Sstevel@tonic-gate 	/*
13987c478bd9Sstevel@tonic-gate 	 * add only online paths as non-online paths may not be accessible
13997c478bd9Sstevel@tonic-gate 	 * in the target environment.
14007c478bd9Sstevel@tonic-gate 	 */
14017c478bd9Sstevel@tonic-gate 	if ((n = add_to_phci_list(phci_list, ioc.ret_buf, npaths,
14027c478bd9Sstevel@tonic-gate 	    MDI_PATHINFO_STATE_ONLINE, node_name)) <= 0)
14037c478bd9Sstevel@tonic-gate 		goto out;
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 	free(ioc.ret_buf);
14067c478bd9Sstevel@tonic-gate 	*num_paths = n;
14077c478bd9Sstevel@tonic-gate 
14087c478bd9Sstevel@tonic-gate #ifdef DEBUG
14097c478bd9Sstevel@tonic-gate 	logdmsg(("vhci_to_phci: phci list:\n"));
14107c478bd9Sstevel@tonic-gate 	log_pathlist(phci_list);
14117c478bd9Sstevel@tonic-gate #endif
14127c478bd9Sstevel@tonic-gate 	return (phci_list);
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate out:
14157c478bd9Sstevel@tonic-gate 	free(ioc.ret_buf);
14167c478bd9Sstevel@tonic-gate 	if (phci_list)
14177c478bd9Sstevel@tonic-gate 		free_pathlist(phci_list);
14187c478bd9Sstevel@tonic-gate 	return (NULL);
14197c478bd9Sstevel@tonic-gate }
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate /*
14227c478bd9Sstevel@tonic-gate  * build list of paths accessible from the target environment
14237c478bd9Sstevel@tonic-gate  */
14247c478bd9Sstevel@tonic-gate static int
build_pathlist(char * rootdir,char * vhcipath,char ** pathlist,int npaths)14257c478bd9Sstevel@tonic-gate build_pathlist(char *rootdir, char *vhcipath, char **pathlist, int npaths)
14267c478bd9Sstevel@tonic-gate {
14277c478bd9Sstevel@tonic-gate 	int mpxio_disabled;
14287c478bd9Sstevel@tonic-gate 	int i, j;
14297c478bd9Sstevel@tonic-gate 	char *vpath = NULL;
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 	for (i = 0; i < npaths; i++) {
14327c478bd9Sstevel@tonic-gate 		mpxio_disabled = is_mpxio_disabled(rootdir, pathlist[i]);
14337c478bd9Sstevel@tonic-gate 		logdmsg(("build_pathlist: mpxio_disabled = %d "
14347c478bd9Sstevel@tonic-gate 		    "on path %s\n", mpxio_disabled, pathlist[i]));
14357c478bd9Sstevel@tonic-gate 		if (mpxio_disabled == -1)
14367c478bd9Sstevel@tonic-gate 			return (-1);
14377c478bd9Sstevel@tonic-gate 		if (mpxio_disabled == 0) {
14387c478bd9Sstevel@tonic-gate 			/*
14397c478bd9Sstevel@tonic-gate 			 * mpxio is enabled on this phci path.
14407c478bd9Sstevel@tonic-gate 			 * So use vhci path instead of phci path.
14417c478bd9Sstevel@tonic-gate 			 */
14427c478bd9Sstevel@tonic-gate 			if (vpath == NULL) {
14437c478bd9Sstevel@tonic-gate 				if ((vpath = strdup(vhcipath)) == NULL)
14447c478bd9Sstevel@tonic-gate 					return (-1);
14457c478bd9Sstevel@tonic-gate 				free(pathlist[i]);
14467c478bd9Sstevel@tonic-gate 				/* keep vhci path at beginning of the list */
14477c478bd9Sstevel@tonic-gate 				for (j = i; j > 0; j--)
14487c478bd9Sstevel@tonic-gate 					pathlist[j] = pathlist[j - 1];
14497c478bd9Sstevel@tonic-gate 				pathlist[0] = vpath;
14507c478bd9Sstevel@tonic-gate 			} else {
14517c478bd9Sstevel@tonic-gate 				free(pathlist[i]);
14527c478bd9Sstevel@tonic-gate 				npaths--;
14537c478bd9Sstevel@tonic-gate 				for (j = i; j < npaths; j++)
14547c478bd9Sstevel@tonic-gate 					pathlist[j] = pathlist[j + 1];
14557c478bd9Sstevel@tonic-gate 				pathlist[npaths] = NULL;
14567c478bd9Sstevel@tonic-gate 				/* compensate for i++ in the for loop */
14577c478bd9Sstevel@tonic-gate 				i--;
14587c478bd9Sstevel@tonic-gate 			}
14597c478bd9Sstevel@tonic-gate 		}
14607c478bd9Sstevel@tonic-gate 	}
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate #ifdef DEBUG
14637c478bd9Sstevel@tonic-gate 	logdmsg(("build_pathlist: returning npaths = %d, pathlist:\n", npaths));
14647c478bd9Sstevel@tonic-gate 	log_pathlist(pathlist);
14657c478bd9Sstevel@tonic-gate #endif
14667c478bd9Sstevel@tonic-gate 	return (npaths);
14677c478bd9Sstevel@tonic-gate }
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate /*
14707c478bd9Sstevel@tonic-gate  * Check if the specified device is refenced in the vfstab file.
14717c478bd9Sstevel@tonic-gate  * Return 1 if referenced, 0 if not.
14727c478bd9Sstevel@tonic-gate  *
14737c478bd9Sstevel@tonic-gate  * rootdir	root directory of the target environment
14747c478bd9Sstevel@tonic-gate  * nodepath	/devices path of a device in the target environment without
14757c478bd9Sstevel@tonic-gate  *		the /devices prefix and minor component.
14767c478bd9Sstevel@tonic-gate  */
14777c478bd9Sstevel@tonic-gate static int
is_dev_in_vfstab(char * rootdir,char * nodepath)14787c478bd9Sstevel@tonic-gate is_dev_in_vfstab(char *rootdir, char *nodepath)
14797c478bd9Sstevel@tonic-gate {
14807c478bd9Sstevel@tonic-gate 	FILE *fp;
14817c478bd9Sstevel@tonic-gate 	int linksize;
14827c478bd9Sstevel@tonic-gate 	struct vfstab vfsent;
14837c478bd9Sstevel@tonic-gate 	char *abspath, *minor;
14847c478bd9Sstevel@tonic-gate 	char physpath[MAXPATHLEN];
14857c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate 	logdmsg(("is_dev_in_vfstab: rootdir = %s, nodepath = %s\n",
14887c478bd9Sstevel@tonic-gate 	    rootdir, nodepath));
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%s%s", rootdir, VFSTAB);
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate 	if ((fp = fopen(buf, "r")) == NULL)
14937c478bd9Sstevel@tonic-gate 		return (0);
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 	/*
14967c478bd9Sstevel@tonic-gate 	 * read device specials from vfstab and compare names at physical
14977c478bd9Sstevel@tonic-gate 	 * node path level.
14987c478bd9Sstevel@tonic-gate 	 */
14997c478bd9Sstevel@tonic-gate 	while (getvfsent(fp, &vfsent) == 0) {
15007c478bd9Sstevel@tonic-gate 		if (strncmp(vfsent.vfs_special, SLASH_DEV_SLASH,
15017c478bd9Sstevel@tonic-gate 		    sizeof (SLASH_DEV_SLASH) - 1) == 0) {
15027c478bd9Sstevel@tonic-gate 			(void) snprintf(buf, MAXPATHLEN, "%s%s",
15037c478bd9Sstevel@tonic-gate 			    rootdir, vfsent.vfs_special);
15047c478bd9Sstevel@tonic-gate 			if ((linksize = readlink(buf, physpath,
15057c478bd9Sstevel@tonic-gate 			    MAXPATHLEN)) > 0 && linksize < (MAXPATHLEN - 1)) {
15067c478bd9Sstevel@tonic-gate 				physpath[linksize] = '\0';
15077c478bd9Sstevel@tonic-gate 				if ((abspath = strstr(physpath,
15087c478bd9Sstevel@tonic-gate 				    SLASH_DEVICES_SLASH)) == NULL)
15097c478bd9Sstevel@tonic-gate 					continue;
15107c478bd9Sstevel@tonic-gate 			} else
15117c478bd9Sstevel@tonic-gate 				continue;
15127c478bd9Sstevel@tonic-gate 		} else if (strncmp(vfsent.vfs_special, SLASH_DEVICES_SLASH,
15137c478bd9Sstevel@tonic-gate 		    sizeof (SLASH_DEVICES_SLASH) - 1) == 0) {
15147c478bd9Sstevel@tonic-gate 			(void) strlcpy(physpath, vfsent.vfs_special,
15157c478bd9Sstevel@tonic-gate 			    MAXPATHLEN);
15167c478bd9Sstevel@tonic-gate 			abspath = physpath;
15177c478bd9Sstevel@tonic-gate 		} else
15187c478bd9Sstevel@tonic-gate 			continue;
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 		/* point to / after /devices */
15217c478bd9Sstevel@tonic-gate 		abspath += sizeof (SLASH_DEVICES_SLASH) - 2;
15227c478bd9Sstevel@tonic-gate 		/* strip minor component */
15237c478bd9Sstevel@tonic-gate 		if ((minor = strrchr(abspath, ':')) != NULL)
15247c478bd9Sstevel@tonic-gate 			*minor = '\0';
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 		if (strcmp(nodepath, abspath) == 0) {
15277c478bd9Sstevel@tonic-gate 			(void) fclose(fp);
15287c478bd9Sstevel@tonic-gate 			logdmsg(("is_dev_in_vfstab: returning 1\n"));
15297c478bd9Sstevel@tonic-gate 			return (1);
15307c478bd9Sstevel@tonic-gate 		}
15317c478bd9Sstevel@tonic-gate 	}
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
15347c478bd9Sstevel@tonic-gate 	return (0);
15357c478bd9Sstevel@tonic-gate }
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate #endif /* __sparc */
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate static int
devlink_callback(di_devlink_t devlink,void * argp)15407c478bd9Sstevel@tonic-gate devlink_callback(di_devlink_t devlink, void *argp)
15417c478bd9Sstevel@tonic-gate {
15427c478bd9Sstevel@tonic-gate 	const char *link;
15437c478bd9Sstevel@tonic-gate 
15447c478bd9Sstevel@tonic-gate 	if ((link = di_devlink_path(devlink)) != NULL)
15457c478bd9Sstevel@tonic-gate 		(void) strlcpy((char *)argp, link, MAXPATHLEN);
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
15487c478bd9Sstevel@tonic-gate }
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate /*
15517c478bd9Sstevel@tonic-gate  * Get the /dev name in the install environment corresponding to physpath.
15527c478bd9Sstevel@tonic-gate  *
15537c478bd9Sstevel@tonic-gate  * physpath	/devices path in the install environment without the /devices
15547c478bd9Sstevel@tonic-gate  * 		prefix.
15557c478bd9Sstevel@tonic-gate  * buf		caller supplied buffer where the /dev name is placed on return
15567c478bd9Sstevel@tonic-gate  * bufsz	length of the buffer
15577c478bd9Sstevel@tonic-gate  *
15587c478bd9Sstevel@tonic-gate  * Returns	strlen of the /dev name on success, -1 on failure.
15597c478bd9Sstevel@tonic-gate  */
15607c478bd9Sstevel@tonic-gate static int
get_install_devlink(char * physpath,char * buf,size_t bufsz)15617c478bd9Sstevel@tonic-gate get_install_devlink(char *physpath, char *buf, size_t bufsz)
15627c478bd9Sstevel@tonic-gate {
15637c478bd9Sstevel@tonic-gate 	di_devlink_handle_t devlink_hdl;
15647c478bd9Sstevel@tonic-gate 	char devname[MAXPATHLEN];
1565*72916ffbSGangadhar Mylapuram 	int tries = 0;
1566*72916ffbSGangadhar Mylapuram 	int sleeptime = 2; /* number of seconds to sleep between retries */
1567*72916ffbSGangadhar Mylapuram 	int maxtries = 10; /* maximum number of tries */
15687c478bd9Sstevel@tonic-gate 
15697c478bd9Sstevel@tonic-gate 	logdmsg(("get_install_devlink: physpath = %s\n", physpath));
15707c478bd9Sstevel@tonic-gate 
1571*72916ffbSGangadhar Mylapuram 	/*
1572*72916ffbSGangadhar Mylapuram 	 * devlink_db sync happens after MINOR_FINI_TIMEOUT_DEFAULT secs
1573*72916ffbSGangadhar Mylapuram 	 * after dev link creation. So wait for minimum that amout of time.
1574*72916ffbSGangadhar Mylapuram 	 */
1575*72916ffbSGangadhar Mylapuram 
1576*72916ffbSGangadhar Mylapuram retry:
1577*72916ffbSGangadhar Mylapuram 	(void) sleep(sleeptime);
1578*72916ffbSGangadhar Mylapuram 
15797c478bd9Sstevel@tonic-gate 	if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
15807c478bd9Sstevel@tonic-gate 		logdmsg(("get_install_devlink: di_devlink_init() failed: %s\n",
15817c478bd9Sstevel@tonic-gate 		    strerror(errno)));
15827c478bd9Sstevel@tonic-gate 		return (-1);
15837c478bd9Sstevel@tonic-gate 	}
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate 	devname[0] = '\0';
15867c478bd9Sstevel@tonic-gate 	if (di_devlink_walk(devlink_hdl, NULL, physpath, DI_PRIMARY_LINK,
1587*72916ffbSGangadhar Mylapuram 	    devname, devlink_callback) == 0) {
1588*72916ffbSGangadhar Mylapuram 		if (devname[0] == '\0' && tries < maxtries) {
1589*72916ffbSGangadhar Mylapuram 			tries++;
1590*72916ffbSGangadhar Mylapuram 			(void) di_devlink_fini(&devlink_hdl);
1591*72916ffbSGangadhar Mylapuram 			goto retry;
1592*72916ffbSGangadhar Mylapuram 		} else if (devname[0] == '\0') {
1593*72916ffbSGangadhar Mylapuram 			logdmsg(("get_install_devlink: di_devlink_walk"
1594*72916ffbSGangadhar Mylapuram 			    " failed: %s\n", strerror(errno)));
1595*72916ffbSGangadhar Mylapuram 			(void) di_devlink_fini(&devlink_hdl);
1596*72916ffbSGangadhar Mylapuram 			return (-1);
1597*72916ffbSGangadhar Mylapuram 		}
1598*72916ffbSGangadhar Mylapuram 	} else {
15997c478bd9Sstevel@tonic-gate 		logdmsg(("get_install_devlink: di_devlink_walk failed: %s\n",
16007c478bd9Sstevel@tonic-gate 		    strerror(errno)));
16017c478bd9Sstevel@tonic-gate 		(void) di_devlink_fini(&devlink_hdl);
16027c478bd9Sstevel@tonic-gate 		return (-1);
16037c478bd9Sstevel@tonic-gate 	}
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate 	(void) di_devlink_fini(&devlink_hdl);
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate 	logdmsg(("get_install_devlink: devlink = %s\n", devname));
16087c478bd9Sstevel@tonic-gate 	return (strlcpy(buf, devname, bufsz));
16097c478bd9Sstevel@tonic-gate }
16107c478bd9Sstevel@tonic-gate 
16117c478bd9Sstevel@tonic-gate /*
16127c478bd9Sstevel@tonic-gate  * Get the /dev name in the target environment corresponding to physpath.
16137c478bd9Sstevel@tonic-gate  *
16147c478bd9Sstevel@tonic-gate  * rootdir	root directory of the target environment
16157c478bd9Sstevel@tonic-gate  * physpath	/devices path in the target environment without the /devices
16167c478bd9Sstevel@tonic-gate  * 		prefix.
16177c478bd9Sstevel@tonic-gate  * buf		caller supplied buffer where the /dev name is placed on return
16187c478bd9Sstevel@tonic-gate  * bufsz	length of the buffer
16197c478bd9Sstevel@tonic-gate  *
16207c478bd9Sstevel@tonic-gate  * Returns	strlen of the /dev name on success, -1 on failure.
16217c478bd9Sstevel@tonic-gate  */
16227c478bd9Sstevel@tonic-gate static int
get_target_devlink(char * rootdir,char * physpath,char * buf,size_t bufsz)16237c478bd9Sstevel@tonic-gate get_target_devlink(char *rootdir, char *physpath, char *buf, size_t bufsz)
16247c478bd9Sstevel@tonic-gate {
16257c478bd9Sstevel@tonic-gate 	char *p;
16267c478bd9Sstevel@tonic-gate 	int linksize;
16277c478bd9Sstevel@tonic-gate 	DIR *dirp;
16287c478bd9Sstevel@tonic-gate 	struct dirent *direntry;
16297c478bd9Sstevel@tonic-gate 	char dirpath[MAXPATHLEN];
16307c478bd9Sstevel@tonic-gate 	char devname[MAXPATHLEN];
16317c478bd9Sstevel@tonic-gate 	char physdev[MAXPATHLEN];
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate 	logdmsg(("get_target_devlink: rootdir = %s, physpath = %s\n",
16347c478bd9Sstevel@tonic-gate 	    rootdir, physpath));
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 	if ((p = strrchr(physpath, '/')) == NULL)
16377c478bd9Sstevel@tonic-gate 		return (-1);
16387c478bd9Sstevel@tonic-gate 
16397c478bd9Sstevel@tonic-gate 	if (strstr(p, ",raw") != NULL) {
16407c478bd9Sstevel@tonic-gate 		(void) snprintf(dirpath, MAXPATHLEN, "%s/dev/rdsk", rootdir);
16417c478bd9Sstevel@tonic-gate 	} else {
16427c478bd9Sstevel@tonic-gate 		(void) snprintf(dirpath, MAXPATHLEN, "%s/dev/dsk", rootdir);
16437c478bd9Sstevel@tonic-gate 	}
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate 	if ((dirp = opendir(dirpath)) == NULL)
16467c478bd9Sstevel@tonic-gate 		return (-1);
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate 	while ((direntry = readdir(dirp)) != NULL) {
16497c478bd9Sstevel@tonic-gate 		if (strcmp(direntry->d_name, ".") == 0 ||
16507c478bd9Sstevel@tonic-gate 		    strcmp(direntry->d_name, "..") == 0)
16517c478bd9Sstevel@tonic-gate 			continue;
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate 		(void) snprintf(devname, MAXPATHLEN, "%s/%s",
16547c478bd9Sstevel@tonic-gate 		    dirpath, direntry->d_name);
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 		if ((linksize = readlink(devname, physdev, MAXPATHLEN)) > 0 &&
16577c478bd9Sstevel@tonic-gate 		    linksize < (MAXPATHLEN - 1)) {
16587c478bd9Sstevel@tonic-gate 			physdev[linksize] = '\0';
16597c478bd9Sstevel@tonic-gate 			if ((p = strstr(physdev, SLASH_DEVICES_SLASH)) !=
16607c478bd9Sstevel@tonic-gate 			    NULL && strcmp(p + sizeof (SLASH_DEVICES) - 1,
16617c478bd9Sstevel@tonic-gate 			    physpath) == 0) {
16627c478bd9Sstevel@tonic-gate 				(void) closedir(dirp);
16637c478bd9Sstevel@tonic-gate 				logdmsg(("get_target_devlink: devlink = %s\n",
16647c478bd9Sstevel@tonic-gate 				    devname + strlen(rootdir)));
16657c478bd9Sstevel@tonic-gate 				return (strlcpy(buf, devname + strlen(rootdir),
16667c478bd9Sstevel@tonic-gate 				    bufsz));
16677c478bd9Sstevel@tonic-gate 			}
16687c478bd9Sstevel@tonic-gate 		}
16697c478bd9Sstevel@tonic-gate 	}
16707c478bd9Sstevel@tonic-gate 
16717c478bd9Sstevel@tonic-gate 	(void) closedir(dirp);
16727c478bd9Sstevel@tonic-gate 	return (-1);
16737c478bd9Sstevel@tonic-gate }
16747c478bd9Sstevel@tonic-gate 
16757c478bd9Sstevel@tonic-gate /*
16767c478bd9Sstevel@tonic-gate  * Convert device name to physpath.
16777c478bd9Sstevel@tonic-gate  *
16787c478bd9Sstevel@tonic-gate  * rootdir	root directory
16797c478bd9Sstevel@tonic-gate  * devname	a /dev name or /devices name under rootdir
16807c478bd9Sstevel@tonic-gate  * physpath	caller supplied buffer where the /devices path will be placed
16817c478bd9Sstevel@tonic-gate  *		on return (without the /devices prefix).
16827c478bd9Sstevel@tonic-gate  * physpathlen	length of the physpath buffer
16837c478bd9Sstevel@tonic-gate  *
16847c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
16857c478bd9Sstevel@tonic-gate  */
16867c478bd9Sstevel@tonic-gate static int
devname2physpath(char * rootdir,char * devname,char * physpath,int physpathlen)16877c478bd9Sstevel@tonic-gate devname2physpath(char *rootdir, char *devname, char *physpath, int physpathlen)
16887c478bd9Sstevel@tonic-gate {
16897c478bd9Sstevel@tonic-gate 	int linksize;
16907c478bd9Sstevel@tonic-gate 	char *p;
16917c478bd9Sstevel@tonic-gate 	char devlink[MAXPATHLEN];
16927c478bd9Sstevel@tonic-gate 	char tmpphyspath[MAXPATHLEN];
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 	logdmsg(("devname2physpath: rootdir = %s, devname = %s\n",
16957c478bd9Sstevel@tonic-gate 	    rootdir, devname));
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 	if (strncmp(devname, SLASH_DEVICES_SLASH,
16987c478bd9Sstevel@tonic-gate 	    sizeof (SLASH_DEVICES_SLASH) - 1) != 0) {
16997c478bd9Sstevel@tonic-gate 		if (*rootdir == '\0')
17007c478bd9Sstevel@tonic-gate 			linksize = readlink(devname, tmpphyspath, MAXPATHLEN);
17017c478bd9Sstevel@tonic-gate 		else {
17027c478bd9Sstevel@tonic-gate 			(void) snprintf(devlink, MAXPATHLEN, "%s%s",
17037c478bd9Sstevel@tonic-gate 			    rootdir, devname);
17047c478bd9Sstevel@tonic-gate 			linksize = readlink(devlink, tmpphyspath, MAXPATHLEN);
17057c478bd9Sstevel@tonic-gate 		}
17067c478bd9Sstevel@tonic-gate 		if (linksize > 0 && linksize < (MAXPATHLEN - 1)) {
17077c478bd9Sstevel@tonic-gate 			tmpphyspath[linksize] = '\0';
17087c478bd9Sstevel@tonic-gate 			if ((p = strstr(tmpphyspath, SLASH_DEVICES_SLASH))
17097c478bd9Sstevel@tonic-gate 			    == NULL)
17107c478bd9Sstevel@tonic-gate 				return (-1);
17117c478bd9Sstevel@tonic-gate 		} else
17127c478bd9Sstevel@tonic-gate 			return (-1);
17137c478bd9Sstevel@tonic-gate 	} else
17147c478bd9Sstevel@tonic-gate 		p = devname;
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 	(void) strlcpy(physpath, p + sizeof (SLASH_DEVICES) - 1, physpathlen);
17177c478bd9Sstevel@tonic-gate 	logdmsg(("devname2physpath: physpath = %s\n", physpath));
17187c478bd9Sstevel@tonic-gate 	return (0);
17197c478bd9Sstevel@tonic-gate }
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate /*
17227c478bd9Sstevel@tonic-gate  * Map a device name (devname) from the target environment to the
17237c478bd9Sstevel@tonic-gate  * install environment.
17247c478bd9Sstevel@tonic-gate  *
17257c478bd9Sstevel@tonic-gate  * rootdir	root directory of the target environment
17267c478bd9Sstevel@tonic-gate  * devname	/dev or /devices name under the target environment
17277c478bd9Sstevel@tonic-gate  * buf		caller supplied buffer where the mapped /dev name is placed
17287c478bd9Sstevel@tonic-gate  *		on return
17297c478bd9Sstevel@tonic-gate  * bufsz	length of the buffer
17307c478bd9Sstevel@tonic-gate  *
17317c478bd9Sstevel@tonic-gate  * Returns	strlen of the mapped /dev name on success, -1 on failure.
17327c478bd9Sstevel@tonic-gate  */
17337c478bd9Sstevel@tonic-gate int
devfs_target2install(const char * rootdir,const char * devname,char * buf,size_t bufsz)17347c478bd9Sstevel@tonic-gate devfs_target2install(const char *rootdir, const char *devname, char *buf,
17357c478bd9Sstevel@tonic-gate     size_t bufsz)
17367c478bd9Sstevel@tonic-gate {
17377c478bd9Sstevel@tonic-gate 	char physpath[MAXPATHLEN];
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 	logdmsg(("devfs_target2install: rootdir = %s, devname = %s\n",
17407c478bd9Sstevel@tonic-gate 	    STRVAL(rootdir), STRVAL(devname)));
17417c478bd9Sstevel@tonic-gate 
17427c478bd9Sstevel@tonic-gate 	if (rootdir == NULL || devname == NULL || buf == NULL || bufsz == 0)
17437c478bd9Sstevel@tonic-gate 		return (-1);
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 	if (strcmp(rootdir, "/") == 0)
17467c478bd9Sstevel@tonic-gate 		rootdir = "";
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate 	if (devname2physpath((char *)rootdir, (char *)devname, physpath,
17497c478bd9Sstevel@tonic-gate 	    MAXPATHLEN) != 0)
17507c478bd9Sstevel@tonic-gate 		return (-1);
17517c478bd9Sstevel@tonic-gate 
17527c478bd9Sstevel@tonic-gate #ifdef __sparc
17537c478bd9Sstevel@tonic-gate 	if (client_name_type(physpath) == CLIENT_TYPE_PHCI) {
17547c478bd9Sstevel@tonic-gate 		char *mapped_node_path, *minor;
17557c478bd9Sstevel@tonic-gate 		char minorbuf[MAXNAMELEN];
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate 		/* strip minor component if present */
17587c478bd9Sstevel@tonic-gate 		if ((minor = strrchr(physpath, ':')) != NULL) {
17597c478bd9Sstevel@tonic-gate 			*minor = '\0';
17607c478bd9Sstevel@tonic-gate 			minor++;
17617c478bd9Sstevel@tonic-gate 			(void) strlcpy(minorbuf, minor, MAXNAMELEN);
17627c478bd9Sstevel@tonic-gate 		}
17637c478bd9Sstevel@tonic-gate 		if ((mapped_node_path = phci_to_vhci(physpath)) != NULL) {
17647c478bd9Sstevel@tonic-gate 			if (minor)
17657c478bd9Sstevel@tonic-gate 				(void) snprintf(physpath, MAXPATHLEN,
17667c478bd9Sstevel@tonic-gate 				    "%s:%s", mapped_node_path, minorbuf);
17677c478bd9Sstevel@tonic-gate 			else
17687c478bd9Sstevel@tonic-gate 				(void) strlcpy(physpath, mapped_node_path,
17697c478bd9Sstevel@tonic-gate 				    MAXPATHLEN);
17707c478bd9Sstevel@tonic-gate 			free(mapped_node_path);
17717c478bd9Sstevel@tonic-gate 			logdmsg(("devfs_target2install: mapped physpath: %s\n",
17727c478bd9Sstevel@tonic-gate 			    physpath));
17737c478bd9Sstevel@tonic-gate 
17747c478bd9Sstevel@tonic-gate 		} else if (minor)
17757c478bd9Sstevel@tonic-gate 			*(minor - 1) = ':';
17767c478bd9Sstevel@tonic-gate 	}
17777c478bd9Sstevel@tonic-gate #endif /* __sparc */
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate 	return (get_install_devlink(physpath, buf, bufsz));
17807c478bd9Sstevel@tonic-gate }
17817c478bd9Sstevel@tonic-gate 
17827c478bd9Sstevel@tonic-gate /*
17837c478bd9Sstevel@tonic-gate  * Map a device name (devname) from the install environment to the target
17847c478bd9Sstevel@tonic-gate  * environment.
17857c478bd9Sstevel@tonic-gate  *
17867c478bd9Sstevel@tonic-gate  * rootdir	root directory of the target environment
17877c478bd9Sstevel@tonic-gate  * devname	/dev or /devices name under the install environment
17887c478bd9Sstevel@tonic-gate  * buf		caller supplied buffer where the mapped /dev name is placed
17897c478bd9Sstevel@tonic-gate  *		on return
17907c478bd9Sstevel@tonic-gate  * bufsz	length of the buffer
17917c478bd9Sstevel@tonic-gate  *
17927c478bd9Sstevel@tonic-gate  * Returns	strlen of the mapped /dev name on success, -1 on failure.
17937c478bd9Sstevel@tonic-gate  */
17947c478bd9Sstevel@tonic-gate int
devfs_install2target(const char * rootdir,const char * devname,char * buf,size_t bufsz)17957c478bd9Sstevel@tonic-gate devfs_install2target(const char *rootdir, const char *devname, char *buf,
17967c478bd9Sstevel@tonic-gate     size_t bufsz)
17977c478bd9Sstevel@tonic-gate {
17987c478bd9Sstevel@tonic-gate 	char physpath[MAXPATHLEN];
17997c478bd9Sstevel@tonic-gate 
18007c478bd9Sstevel@tonic-gate 	logdmsg(("devfs_install2target: rootdir = %s, devname = %s\n",
18017c478bd9Sstevel@tonic-gate 	    STRVAL(rootdir), STRVAL(devname)));
18027c478bd9Sstevel@tonic-gate 
18037c478bd9Sstevel@tonic-gate 	if (rootdir == NULL || devname == NULL || buf == NULL || bufsz == 0)
18047c478bd9Sstevel@tonic-gate 		return (-1);
18057c478bd9Sstevel@tonic-gate 
18067c478bd9Sstevel@tonic-gate 	if (strcmp(rootdir, "/") == 0)
18077c478bd9Sstevel@tonic-gate 		rootdir = "";
18087c478bd9Sstevel@tonic-gate 
18097c478bd9Sstevel@tonic-gate 	if (devname2physpath("", (char *)devname, physpath, MAXPATHLEN) != 0)
18107c478bd9Sstevel@tonic-gate 		return (-1);
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate #ifdef __sparc
18137c478bd9Sstevel@tonic-gate 	if (client_name_type(physpath) == CLIENT_TYPE_VHCI) {
18147c478bd9Sstevel@tonic-gate 		char **pathlist;
18157c478bd9Sstevel@tonic-gate 		int npaths, i, j;
18167c478bd9Sstevel@tonic-gate 		char *minor;
18177c478bd9Sstevel@tonic-gate 		char minorbuf[MAXNAMELEN];
18187c478bd9Sstevel@tonic-gate 
18197c478bd9Sstevel@tonic-gate 		/* strip minor component if present */
18207c478bd9Sstevel@tonic-gate 		if ((minor = strrchr(physpath, ':')) != NULL) {
18217c478bd9Sstevel@tonic-gate 			*minor = '\0';
18227c478bd9Sstevel@tonic-gate 			minor++;
18237c478bd9Sstevel@tonic-gate 			(void) strlcpy(minorbuf, minor, MAXNAMELEN);
18247c478bd9Sstevel@tonic-gate 		}
18257c478bd9Sstevel@tonic-gate 
18267c478bd9Sstevel@tonic-gate 		if ((pathlist = vhci_to_phci(physpath, &npaths)) == NULL)
18277c478bd9Sstevel@tonic-gate 			return (-1);
18287c478bd9Sstevel@tonic-gate 
18297c478bd9Sstevel@tonic-gate 		if ((npaths = build_pathlist((char *)rootdir, physpath,
18307c478bd9Sstevel@tonic-gate 		    pathlist, npaths)) <= 0) {
18317c478bd9Sstevel@tonic-gate 			free_pathlist(pathlist);
18327c478bd9Sstevel@tonic-gate 			return (-1);
18337c478bd9Sstevel@tonic-gate 		}
18347c478bd9Sstevel@tonic-gate 
18357c478bd9Sstevel@tonic-gate 		/*
18367c478bd9Sstevel@tonic-gate 		 * in case of more than one path, try to use the path
18377c478bd9Sstevel@tonic-gate 		 * referenced in the vfstab file, otherwise use the first path.
18387c478bd9Sstevel@tonic-gate 		 */
18397c478bd9Sstevel@tonic-gate 		j = 0;
18407c478bd9Sstevel@tonic-gate 		if (npaths > 1) {
18417c478bd9Sstevel@tonic-gate 			for (i = 0; i < npaths; i++) {
18427c478bd9Sstevel@tonic-gate 				if (is_dev_in_vfstab((char *)rootdir,
18437c478bd9Sstevel@tonic-gate 				    pathlist[i])) {
18447c478bd9Sstevel@tonic-gate 					j = i;
18457c478bd9Sstevel@tonic-gate 					break;
18467c478bd9Sstevel@tonic-gate 				}
18477c478bd9Sstevel@tonic-gate 			}
18487c478bd9Sstevel@tonic-gate 		}
18497c478bd9Sstevel@tonic-gate 
18507c478bd9Sstevel@tonic-gate 		if (minor)
18517c478bd9Sstevel@tonic-gate 			(void) snprintf(physpath, MAXPATHLEN,
18527c478bd9Sstevel@tonic-gate 			    "%s:%s", pathlist[j], minorbuf);
18537c478bd9Sstevel@tonic-gate 		else
18547c478bd9Sstevel@tonic-gate 			(void) strlcpy(physpath, pathlist[j], MAXPATHLEN);
18557c478bd9Sstevel@tonic-gate 		free_pathlist(pathlist);
18567c478bd9Sstevel@tonic-gate 	}
18577c478bd9Sstevel@tonic-gate #endif /* __sparc */
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate 	return (get_target_devlink((char *)rootdir, physpath, buf, bufsz));
18607c478bd9Sstevel@tonic-gate }
18617c478bd9Sstevel@tonic-gate 
18621aef0e11Sjg /*
18631aef0e11Sjg  * A parser for /etc/path_to_inst.
18641aef0e11Sjg  * The user-supplied callback is called once for each entry in the file.
18651aef0e11Sjg  * Returns 0 on success, ENOMEM/ENOENT/EINVAL on error.
18661aef0e11Sjg  * Callback may return DI_WALK_TERMINATE to terminate the walk,
18671aef0e11Sjg  * otherwise DI_WALK_CONTINUE.
18681aef0e11Sjg  */
18691aef0e11Sjg int
devfs_parse_binding_file(const char * binding_file,int (* callback)(void *,const char *,int,const char *),void * cb_arg)18701aef0e11Sjg devfs_parse_binding_file(const char *binding_file,
18711aef0e11Sjg 	int (*callback)(void *, const char *, int,
18721aef0e11Sjg 	    const char *), void *cb_arg)
18731aef0e11Sjg {
18741aef0e11Sjg 	token_t token;
18751aef0e11Sjg 	struct conf_file file;
18761aef0e11Sjg 	char tokval[MAX_TOKEN_SIZE];
18771aef0e11Sjg 	enum { STATE_RESET, STATE_DEVPATH, STATE_INSTVAL } state;
18781aef0e11Sjg 	char *devpath;
18791aef0e11Sjg 	char *bindname;
18801aef0e11Sjg 	int instval = 0;
18811aef0e11Sjg 	int rv;
18821aef0e11Sjg 
18831aef0e11Sjg 	if ((devpath = calloc(1, MAXPATHLEN)) == NULL)
18841aef0e11Sjg 		return (ENOMEM);
1885da3b42e9Sethindra 	if ((bindname = calloc(1, MAX_TOKEN_SIZE)) == NULL) {
1886da3b42e9Sethindra 		free(devpath);
18871aef0e11Sjg 		return (ENOMEM);
1888da3b42e9Sethindra 	}
18891aef0e11Sjg 
18901aef0e11Sjg 	if ((file.fp = fopen(binding_file, "r")) == NULL) {
18911aef0e11Sjg 		free(devpath);
18921aef0e11Sjg 		free(bindname);
18931aef0e11Sjg 		return (errno);
18941aef0e11Sjg 	}
18951aef0e11Sjg 
18961aef0e11Sjg 	file.filename = (char *)binding_file;
18971aef0e11Sjg 	file.linenum = 1;
18981aef0e11Sjg 
18991aef0e11Sjg 	state = STATE_RESET;
19001aef0e11Sjg 	while ((token = lex(&file, tokval, MAX_TOKEN_SIZE)) != T_EOF) {
19011aef0e11Sjg 		switch (token) {
19021aef0e11Sjg 		case T_POUND:
19031aef0e11Sjg 			/*
19041aef0e11Sjg 			 * Skip comments.
19051aef0e11Sjg 			 */
19061aef0e11Sjg 			find_eol(file.fp);
19071aef0e11Sjg 			break;
19081aef0e11Sjg 		case T_NAME:
19091aef0e11Sjg 		case T_STRING:
19101aef0e11Sjg 			switch (state) {
19111aef0e11Sjg 			case STATE_RESET:
19121aef0e11Sjg 				if (strlcpy(devpath, tokval,
19131aef0e11Sjg 				    MAXPATHLEN) >= MAXPATHLEN)
19141aef0e11Sjg 					goto err;
19151aef0e11Sjg 				state = STATE_DEVPATH;
19161aef0e11Sjg 				break;
19171aef0e11Sjg 			case STATE_INSTVAL:
19181aef0e11Sjg 				if (strlcpy(bindname, tokval,
19191aef0e11Sjg 				    MAX_TOKEN_SIZE) >= MAX_TOKEN_SIZE)
19201aef0e11Sjg 					goto err;
19211aef0e11Sjg 				rv = callback(cb_arg,
19221aef0e11Sjg 				    devpath, instval, bindname);
19231aef0e11Sjg 				if (rv == DI_WALK_TERMINATE)
19241aef0e11Sjg 					goto done;
19251aef0e11Sjg 				if (rv != DI_WALK_CONTINUE)
19261aef0e11Sjg 					goto err;
19271aef0e11Sjg 				state = STATE_RESET;
19281aef0e11Sjg 				break;
19291aef0e11Sjg 			default:
19301aef0e11Sjg 				file_err(&file, tok_err, tokval);
19311aef0e11Sjg 				state = STATE_RESET;
19321aef0e11Sjg 				break;
19331aef0e11Sjg 			}
19341aef0e11Sjg 			break;
19351aef0e11Sjg 		case T_DECVAL:
19361aef0e11Sjg 		case T_HEXVAL:
19371aef0e11Sjg 			switch (state) {
19381aef0e11Sjg 			case STATE_DEVPATH:
19391aef0e11Sjg 				instval = (int)strtol(tokval, NULL, 0);
19401aef0e11Sjg 				state = STATE_INSTVAL;
19411aef0e11Sjg 				break;
19421aef0e11Sjg 			default:
19431aef0e11Sjg 				file_err(&file, tok_err, tokval);
19441aef0e11Sjg 				state = STATE_RESET;
19451aef0e11Sjg 				break;
19461aef0e11Sjg 			}
19471aef0e11Sjg 			break;
19481aef0e11Sjg 		case T_NEWLINE:
19491aef0e11Sjg 			file.linenum++;
19501aef0e11Sjg 			state = STATE_RESET;
19511aef0e11Sjg 			break;
19521aef0e11Sjg 		default:
19531aef0e11Sjg 			file_err(&file, tok_err, tokval);
19541aef0e11Sjg 			state = STATE_RESET;
19551aef0e11Sjg 			break;
19561aef0e11Sjg 		}
19571aef0e11Sjg 	}
19581aef0e11Sjg 
19591aef0e11Sjg done:
19601aef0e11Sjg 	(void) fclose(file.fp);
19611aef0e11Sjg 	free(devpath);
19621aef0e11Sjg 	free(bindname);
19631aef0e11Sjg 	return (0);
19641aef0e11Sjg 
19651aef0e11Sjg err:
19661aef0e11Sjg 	(void) fclose(file.fp);
19671aef0e11Sjg 	free(devpath);
19681aef0e11Sjg 	free(bindname);
19691aef0e11Sjg 	return (EINVAL);
19701aef0e11Sjg }
19711aef0e11Sjg 
19721aef0e11Sjg /*
19731aef0e11Sjg  * Walk the minor nodes of all children below the specified device
19741aef0e11Sjg  * by calling the provided callback with the path to each minor.
19751aef0e11Sjg  */
19761aef0e11Sjg static int
devfs_walk_children_minors(const char * device_path,struct stat * st,int (* callback)(void *,const char *),void * cb_arg,int * terminate)19771aef0e11Sjg devfs_walk_children_minors(const char *device_path, struct stat *st,
19781aef0e11Sjg     int (*callback)(void *, const char *), void *cb_arg, int *terminate)
19791aef0e11Sjg {
19801aef0e11Sjg 	DIR *dir;
19811aef0e11Sjg 	struct dirent *dp;
19821aef0e11Sjg 	char *minor_path = NULL;
19831aef0e11Sjg 	int need_close = 0;
19841aef0e11Sjg 	int rv;
19851aef0e11Sjg 
19861aef0e11Sjg 	if ((minor_path = calloc(1, MAXPATHLEN)) == NULL)
19871aef0e11Sjg 		return (ENOMEM);
19881aef0e11Sjg 
19891aef0e11Sjg 	if ((dir = opendir(device_path)) == NULL) {
19901aef0e11Sjg 		rv = ENOENT;
19911aef0e11Sjg 		goto err;
19921aef0e11Sjg 	}
19931aef0e11Sjg 	need_close = 1;
19941aef0e11Sjg 
19951aef0e11Sjg 	while ((dp = readdir(dir)) != NULL) {
19961aef0e11Sjg 		if ((strcmp(dp->d_name, ".") == 0) ||
19971aef0e11Sjg 		    (strcmp(dp->d_name, "..") == 0))
19981aef0e11Sjg 			continue;
19991aef0e11Sjg 		(void) snprintf(minor_path, MAXPATHLEN,
20001aef0e11Sjg 		    "%s/%s", device_path, dp->d_name);
20011aef0e11Sjg 		if (stat(minor_path, st) == -1)
20021aef0e11Sjg 			continue;
20031aef0e11Sjg 		if (S_ISDIR(st->st_mode)) {
20041aef0e11Sjg 			rv = devfs_walk_children_minors(
20051aef0e11Sjg 			    (const char *)minor_path, st,
20061aef0e11Sjg 			    callback, cb_arg, terminate);
20071aef0e11Sjg 			if (rv != 0)
20081aef0e11Sjg 				goto err;
20091aef0e11Sjg 			if (*terminate)
20101aef0e11Sjg 				break;
20111aef0e11Sjg 		} else {
20121aef0e11Sjg 			rv = callback(cb_arg, minor_path);
20131aef0e11Sjg 			if (rv == DI_WALK_TERMINATE) {
20141aef0e11Sjg 				*terminate = 1;
20151aef0e11Sjg 				break;
20161aef0e11Sjg 			}
20171aef0e11Sjg 			if (rv != DI_WALK_CONTINUE) {
20181aef0e11Sjg 				rv = EINVAL;
20191aef0e11Sjg 				goto err;
20201aef0e11Sjg 			}
20211aef0e11Sjg 		}
20221aef0e11Sjg 	}
20231aef0e11Sjg 
20241aef0e11Sjg 	rv = 0;
20251aef0e11Sjg err:
20261aef0e11Sjg 	if (need_close)
20271aef0e11Sjg 		(void) closedir(dir);
20281aef0e11Sjg 	if (minor_path)
20291aef0e11Sjg 		free(minor_path);
20301aef0e11Sjg 	return (rv);
20311aef0e11Sjg }
20321aef0e11Sjg 
20331aef0e11Sjg /*
20341aef0e11Sjg  * Return the path to each minor node for a device by
20351aef0e11Sjg  * calling the provided callback.
20361aef0e11Sjg  */
20371aef0e11Sjg static int
devfs_walk_device_minors(const char * device_path,struct stat * st,int (* callback)(void *,const char *),void * cb_arg,int * terminate)20381aef0e11Sjg devfs_walk_device_minors(const char *device_path, struct stat *st,
20391aef0e11Sjg     int (*callback)(void *, const char *), void *cb_arg, int *terminate)
20401aef0e11Sjg {
20411aef0e11Sjg 	char *minor_path;
20421aef0e11Sjg 	char *devpath;
20431aef0e11Sjg 	char *expr;
20441aef0e11Sjg 	regex_t regex;
20451aef0e11Sjg 	int need_regfree = 0;
20461aef0e11Sjg 	int need_close = 0;
20471aef0e11Sjg 	DIR *dir;
20481aef0e11Sjg 	struct dirent *dp;
20491aef0e11Sjg 	int rv;
20501aef0e11Sjg 	char *p;
20511aef0e11Sjg 
20521aef0e11Sjg 	minor_path = calloc(1, MAXPATHLEN);
20531aef0e11Sjg 	devpath = calloc(1, MAXPATHLEN);
20541aef0e11Sjg 	expr = calloc(1, MAXNAMELEN);
20551aef0e11Sjg 	if (devpath == NULL || expr == NULL || minor_path == NULL) {
20561aef0e11Sjg 		rv = ENOMEM;
20571aef0e11Sjg 		goto err;
20581aef0e11Sjg 	}
20591aef0e11Sjg 
20601aef0e11Sjg 	rv = EINVAL;
20611aef0e11Sjg 	if (strlcpy(devpath, device_path, MAXPATHLEN) >= MAXPATHLEN)
20621aef0e11Sjg 		goto err;
20631aef0e11Sjg 	if ((p = strrchr(devpath, '/')) == NULL)
20641aef0e11Sjg 		goto err;
20651aef0e11Sjg 	*p++ = 0;
20661aef0e11Sjg 	if (strlen(p) == 0)
20671aef0e11Sjg 		goto err;
20681aef0e11Sjg 	if (snprintf(expr, MAXNAMELEN, "%s:.*", p) >= MAXNAMELEN)
20691aef0e11Sjg 		goto err;
20701aef0e11Sjg 	if (regcomp(&regex, expr, REG_EXTENDED) != 0)
20711aef0e11Sjg 		goto err;
20721aef0e11Sjg 	need_regfree = 1;
20731aef0e11Sjg 
20741aef0e11Sjg 	if ((dir = opendir(devpath)) == NULL) {
20751aef0e11Sjg 		rv = ENOENT;
20761aef0e11Sjg 		goto err;
20771aef0e11Sjg 	}
20781aef0e11Sjg 	need_close = 1;
20791aef0e11Sjg 
20801aef0e11Sjg 	while ((dp = readdir(dir)) != NULL) {
20811aef0e11Sjg 		if ((strcmp(dp->d_name, ".") == 0) ||
20821aef0e11Sjg 		    (strcmp(dp->d_name, "..") == 0))
20831aef0e11Sjg 			continue;
20841aef0e11Sjg 		(void) snprintf(minor_path, MAXPATHLEN,
20851aef0e11Sjg 		    "%s/%s", devpath, dp->d_name);
20861aef0e11Sjg 		if (stat(minor_path, st) == -1)
20871aef0e11Sjg 			continue;
20881aef0e11Sjg 		if ((S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) &&
20891aef0e11Sjg 		    regexec(&regex, dp->d_name, 0, NULL, 0) == 0) {
20901aef0e11Sjg 			rv = callback(cb_arg, minor_path);
20911aef0e11Sjg 			if (rv == DI_WALK_TERMINATE) {
20921aef0e11Sjg 				*terminate = 1;
20931aef0e11Sjg 				break;
20941aef0e11Sjg 			}
20951aef0e11Sjg 			if (rv != DI_WALK_CONTINUE) {
20961aef0e11Sjg 				rv = EINVAL;
20971aef0e11Sjg 				goto err;
20981aef0e11Sjg 			}
20991aef0e11Sjg 		}
21001aef0e11Sjg 	}
21011aef0e11Sjg 
21021aef0e11Sjg 	rv = 0;
21031aef0e11Sjg err:
21041aef0e11Sjg 	if (need_close)
21051aef0e11Sjg 		(void) closedir(dir);
21061aef0e11Sjg 	if (need_regfree)
21071aef0e11Sjg 		regfree(&regex);
21081aef0e11Sjg 	if (devpath)
21091aef0e11Sjg 		free(devpath);
21101aef0e11Sjg 	if (minor_path)
21111aef0e11Sjg 		free(minor_path);
21121aef0e11Sjg 	if (expr)
21131aef0e11Sjg 		free(expr);
21141aef0e11Sjg 	return (rv);
21151aef0e11Sjg }
21161aef0e11Sjg 
21171aef0e11Sjg /*
21181aef0e11Sjg  * Perform a walk of all minor nodes for the specified device,
21191aef0e11Sjg  * and minor nodes below the device.
21201aef0e11Sjg  */
21211aef0e11Sjg int
devfs_walk_minor_nodes(const char * device_path,int (* callback)(void *,const char *),void * cb_arg)21221aef0e11Sjg devfs_walk_minor_nodes(const char *device_path,
21231aef0e11Sjg 	int (*callback)(void *, const char *), void *cb_arg)
21241aef0e11Sjg {
21251aef0e11Sjg 	struct stat stbuf;
21261aef0e11Sjg 	int rv;
21271aef0e11Sjg 	int terminate = 0;
21281aef0e11Sjg 
21291aef0e11Sjg 	rv = devfs_walk_device_minors(device_path,
21301aef0e11Sjg 	    &stbuf, callback, cb_arg, &terminate);
21311aef0e11Sjg 	if (rv == 0 && terminate == 0) {
21321aef0e11Sjg 		rv = devfs_walk_children_minors(device_path,
21331aef0e11Sjg 		    &stbuf, callback, cb_arg, &terminate);
21341aef0e11Sjg 	}
21351aef0e11Sjg 	return (rv);
21361aef0e11Sjg }
21371aef0e11Sjg 
21387c478bd9Sstevel@tonic-gate #ifdef DEBUG
21397c478bd9Sstevel@tonic-gate 
21407c478bd9Sstevel@tonic-gate static void
vlog_debug_msg(char * fmt,va_list ap)21417c478bd9Sstevel@tonic-gate vlog_debug_msg(char *fmt, va_list ap)
21427c478bd9Sstevel@tonic-gate {
21437c478bd9Sstevel@tonic-gate 	time_t clock;
21447c478bd9Sstevel@tonic-gate 	struct tm t;
21457c478bd9Sstevel@tonic-gate 
21467c478bd9Sstevel@tonic-gate 	if (!devfsmap_debug)
21477c478bd9Sstevel@tonic-gate 		return;
21487c478bd9Sstevel@tonic-gate 
21497c478bd9Sstevel@tonic-gate 	if (logfp == NULL) {
21507c478bd9Sstevel@tonic-gate 		if (*devfsmap_logfile != '\0') {
21517c478bd9Sstevel@tonic-gate 			logfp = fopen(devfsmap_logfile, "a");
21527c478bd9Sstevel@tonic-gate 			if (logfp)
21537c478bd9Sstevel@tonic-gate 				(void) fprintf(logfp, "\nNew Log:\n");
21547c478bd9Sstevel@tonic-gate 		}
21557c478bd9Sstevel@tonic-gate 
21567c478bd9Sstevel@tonic-gate 		if (logfp == NULL)
21577c478bd9Sstevel@tonic-gate 			logfp = stdout;
21587c478bd9Sstevel@tonic-gate 	}
21597c478bd9Sstevel@tonic-gate 
21607c478bd9Sstevel@tonic-gate 	clock = time(NULL);
21617c478bd9Sstevel@tonic-gate 	(void) localtime_r(&clock, &t);
21627c478bd9Sstevel@tonic-gate 	(void) fprintf(logfp, "%02d:%02d:%02d ", t.tm_hour, t.tm_min,
21637c478bd9Sstevel@tonic-gate 	    t.tm_sec);
21647c478bd9Sstevel@tonic-gate 	(void) vfprintf(logfp, fmt, ap);
21657c478bd9Sstevel@tonic-gate 	(void) fflush(logfp);
21667c478bd9Sstevel@tonic-gate }
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate static void
log_debug_msg(char * fmt,...)21697c478bd9Sstevel@tonic-gate log_debug_msg(char *fmt, ...)
21707c478bd9Sstevel@tonic-gate {
21717c478bd9Sstevel@tonic-gate 	va_list ap;
21727c478bd9Sstevel@tonic-gate 
21737c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
21747c478bd9Sstevel@tonic-gate 	vlog_debug_msg(fmt, ap);
21757c478bd9Sstevel@tonic-gate 	va_end(ap);
21767c478bd9Sstevel@tonic-gate }
21777c478bd9Sstevel@tonic-gate 
21787c478bd9Sstevel@tonic-gate #ifdef __sparc
21797c478bd9Sstevel@tonic-gate 
21807c478bd9Sstevel@tonic-gate static char *
mpxio_disable_string(int mpxio_disable)21817c478bd9Sstevel@tonic-gate mpxio_disable_string(int mpxio_disable)
21827c478bd9Sstevel@tonic-gate {
21837c478bd9Sstevel@tonic-gate 	if (mpxio_disable == 0)
21847c478bd9Sstevel@tonic-gate 		return ("no");
21857c478bd9Sstevel@tonic-gate 	else if (mpxio_disable == 1)
21867c478bd9Sstevel@tonic-gate 		return ("yes");
21877c478bd9Sstevel@tonic-gate 	else
21887c478bd9Sstevel@tonic-gate 		return ("not specified");
21897c478bd9Sstevel@tonic-gate }
21907c478bd9Sstevel@tonic-gate 
21917c478bd9Sstevel@tonic-gate static void
log_confent_list(char * filename,struct conf_entry * confent_list,int global_mpxio_disable)21927c478bd9Sstevel@tonic-gate log_confent_list(char *filename, struct conf_entry *confent_list,
21937c478bd9Sstevel@tonic-gate     int global_mpxio_disable)
21947c478bd9Sstevel@tonic-gate {
21957c478bd9Sstevel@tonic-gate 	struct conf_entry *confent;
21967c478bd9Sstevel@tonic-gate 
21977c478bd9Sstevel@tonic-gate 	log_debug_msg("log_confent_list: filename = %s:\n", filename);
21987c478bd9Sstevel@tonic-gate 	if (global_mpxio_disable != -1)
21997c478bd9Sstevel@tonic-gate 		log_debug_msg("\tdriver global mpxio_disable = \"%s\"\n\n",
22007c478bd9Sstevel@tonic-gate 		    mpxio_disable_string(global_mpxio_disable));
22017c478bd9Sstevel@tonic-gate 
22027c478bd9Sstevel@tonic-gate 	for (confent = confent_list; confent != NULL; confent = confent->next) {
22037c478bd9Sstevel@tonic-gate 		if (confent->name)
22047c478bd9Sstevel@tonic-gate 			log_debug_msg("\tname = %s\n", confent->name);
22057c478bd9Sstevel@tonic-gate 		if (confent->parent)
22067c478bd9Sstevel@tonic-gate 			log_debug_msg("\tparent = %s\n", confent->parent);
22077c478bd9Sstevel@tonic-gate 		if (confent->class)
22087c478bd9Sstevel@tonic-gate 			log_debug_msg("\tclass = %s\n", confent->class);
22097c478bd9Sstevel@tonic-gate 		if (confent->unit_address)
22107c478bd9Sstevel@tonic-gate 			log_debug_msg("\tunit_address = %s\n",
22117c478bd9Sstevel@tonic-gate 			    confent->unit_address);
22127c478bd9Sstevel@tonic-gate 		if (confent->port != -1)
22137c478bd9Sstevel@tonic-gate 			log_debug_msg("\tport = %d\n", confent->port);
22147c478bd9Sstevel@tonic-gate 		log_debug_msg("\tmpxio_disable = \"%s\"\n\n",
22151aef0e11Sjg 		    mpxio_disable_string(confent->mpxio_disable));
22167c478bd9Sstevel@tonic-gate 	}
22177c478bd9Sstevel@tonic-gate }
22187c478bd9Sstevel@tonic-gate 
22197c478bd9Sstevel@tonic-gate static void
log_pathlist(char ** pathlist)22207c478bd9Sstevel@tonic-gate log_pathlist(char **pathlist)
22217c478bd9Sstevel@tonic-gate {
22227c478bd9Sstevel@tonic-gate 	char **p;
22237c478bd9Sstevel@tonic-gate 
22247c478bd9Sstevel@tonic-gate 	for (p = pathlist; *p != NULL; p++)
22257c478bd9Sstevel@tonic-gate 		log_debug_msg("\t%s\n", *p);
22267c478bd9Sstevel@tonic-gate }
22277c478bd9Sstevel@tonic-gate 
22287c478bd9Sstevel@tonic-gate #endif /* __sparc */
22297c478bd9Sstevel@tonic-gate 
22307c478bd9Sstevel@tonic-gate #endif /* DEBUG */
2231