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