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