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