4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
28 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/vfstab.h>
41 #include <sys/scsi/adapters/scsi_vhci.h>
42 #include <sys/sunmdi.h>
44 #include "libdevinfo.h"
45 #include "device_info.h"
48 #define isnewline(ch) ((ch) == '\n' || (ch) == '\r' || (ch) == '\f')
49 #define isnamechar(ch) (isalpha(ch) || isdigit(ch) || (ch) == '_' ||\
51 #define MAX_TOKEN_SIZE 1024
53 #define STRVAL(s) ((s) ? (s) : "NULL")
55 #define SCSI_VHCI_CONF "/kernel/drv/scsi_vhci.conf"
56 #define QLC_CONF "/kernel/drv/qlc.conf"
57 #define FP_CONF "/kernel/drv/fp.conf"
58 #define DRIVER_CLASSES "/etc/driver_classes"
60 #define VHCI_CTL_NODE "/devices/scsi_vhci:devctl"
61 #define SLASH_DEVICES "/devices"
62 #define SLASH_DEVICES_SLASH "/devices/"
63 #define SLASH_FP_AT "/fp@"
64 #define SLASH_SCSI_VHCI "/scsi_vhci"
65 #define META_DEV "/dev/md/dsk/"
66 #define SLASH_DEV_SLASH "/dev/"
69 * Macros to produce a quoted string containing the value of a
70 * preprocessor macro. For example, if SIZE is defined to be 256,
71 * VAL2STR(SIZE) is "256". This is used to construct format
72 * strings for scanf-family functions below.
75 #define VAL2STR(x) QUOTE(x)
103 begin
, parent
, drvname
, drvclass
, prop
,
104 parent_equals
, name_equals
, drvclass_equals
,
105 parent_equals_string
, name_equals_string
,
106 drvclass_equals_string
,
107 prop_equals
, prop_equals_string
, prop_equals_integer
,
108 prop_equals_string_comma
, prop_equals_integer_comma
111 /* structure to hold entries with mpxio-disable property in driver.conf file */
119 struct conf_entry
*next
;
128 static char *tok_err
= "Unexpected token '%s'\n";
135 int devfsmap_debug
= 0;
136 /* /var/run is not mounted at install time. Therefore use /tmp */
137 char *devfsmap_logfile
= "/tmp/devfsmap.log";
139 #define logdmsg(args) log_debug_msg args
140 static void vlog_debug_msg(char *, va_list);
141 static void log_debug_msg(char *, ...);
143 static void log_confent_list(char *, struct conf_entry
*, int);
144 static void log_pathlist(char **);
148 #define logdmsg(args) /* nothing */
153 * Leave NEWLINE as the next character.
160 while ((ch
= getc(fp
)) != EOF
) {
162 (void) ungetc(ch
, fp
);
168 /* ignore parsing errors */
171 file_err(struct conf_file
*filep
, char *fmt
, ...)
177 log_debug_msg("WARNING: %s line # %d: ",
178 filep
->filename
, filep
->linenum
);
179 vlog_debug_msg(fmt
, ap
);
184 /* return the next token from the given driver.conf file, or -1 on error */
186 lex(struct conf_file
*filep
, char *val
, size_t size
)
189 int ch
, oval
, badquote
;
192 FILE *fp
= filep
->fp
;
198 while ((ch
= getc(fp
)) == ' ' || ch
== '\t')
234 while ((ch
= getc(fp
)) == ' ' ||
235 ch
== '\t' || ch
== '\f') {
242 (void) ungetc(ch
, fp
);
243 token
= T_WHITE_SPACE
;
253 while (!badquote
&& (ch
= getc(fp
)) != '"') {
257 file_err(filep
, "Missing \"\n");
262 /* since we consumed the newline/EOF */
263 (void) ungetc(ch
, fp
);
273 /* escape the character */
278 while (ch
>= '0' && ch
<= '7') {
280 oval
= (oval
<< 3) + ch
;
283 (void) ungetc(ch
, fp
);
284 /* check for character overflow? */
288 "overflow detected.\n");
310 * detect a lone '-' (including at the end of a line), and
311 * identify it as a 'name'
318 *cp
++ = (char)(ch
= getc(fp
));
319 if (ch
== ' ' || ch
== '\t' || ch
== '\n') {
320 (void) ungetc(ch
, fp
);
326 } else if (ch
== '~' || ch
== '-') {
331 *cp
++ = (char)(ch
= getc(fp
));
337 if ((ch
= getc(fp
)) == 'x') {
344 while (isxdigit(ch
)) {
352 (void) ungetc(ch
, fp
);
360 while (isdigit(ch
)) {
368 (void) ungetc(ch
, fp
);
371 } else if (isalpha(ch
) || ch
== '\\') {
376 * if the character was a backslash,
377 * back up so we can overwrite it with
378 * the next (i.e. escaped) character.
383 while (isnamechar(ch
) || ch
== '\\') {
393 (void) ungetc(ch
, fp
);
409 free_confent(struct conf_entry
*confent
)
412 free(confent
->parent
);
413 free(confent
->class);
414 free(confent
->unit_address
);
419 free_confent_list(struct conf_entry
*confent_list
)
421 struct conf_entry
*confent
, *next
;
423 for (confent
= confent_list
; confent
!= NULL
; confent
= next
) {
424 next
= confent
->next
;
425 free_confent(confent
);
430 * Parse the next entry from the driver.conf file and return in the form of
431 * a pointer to the conf_entry.
433 static struct conf_entry
*
434 parse_conf_entry(struct conf_file
*filep
, char *tokbuf
, size_t linesize
)
436 char *prop_name
, *string
;
438 struct conf_entry
*confent
;
442 if ((confent
= calloc(1, sizeof (*confent
))) == NULL
)
446 confent
->mpxio_disable
= -1;
456 case prop_equals_string
:
457 case prop_equals_integer
:
460 if ((prop_name
= strdup(tokbuf
)) == NULL
)
464 file_err(filep
, tok_err
, tokbuf
);
473 file_err(filep
, tok_err
, tokbuf
);
479 if ((string
= strdup(tokbuf
)) == NULL
)
483 if (strcmp(prop_name
, "PARENT") == 0 ||
484 strcmp(prop_name
, "parent") == 0) {
485 if (confent
->parent
) {
487 "'parent' property already specified\n");
490 confent
->parent
= string
;
491 } else if (strcmp(prop_name
, "NAME") == 0 ||
492 strcmp(prop_name
, "name") == 0) {
495 "'name' property already specified\n");
498 confent
->name
= string
;
499 } else if (strcmp(prop_name
, "CLASS") == 0 ||
500 strcmp(prop_name
, "class") == 0) {
501 if (confent
->class) {
503 "'class' property already specified\n");
506 confent
->class = string
;
507 } else if (strcmp(prop_name
, "unit-address")
509 if (confent
->unit_address
) {
511 "'unit-address' property already specified\n");
514 confent
->unit_address
= string
;
515 } else if (strcmp(prop_name
, "mpxio-disable")
517 if (confent
->mpxio_disable
!= -1) {
519 "'mpxio-disable' property already specified\n");
522 if (strcmp(string
, "yes") == 0)
523 confent
->mpxio_disable
= 1;
524 else if (strcmp(string
, "no") == 0)
525 confent
->mpxio_disable
= 0;
528 "'mpxio-disable' property setting is invalid. "
529 "The value must be either \"yes\" or \"no\"\n");
535 state
= prop_equals_string
;
542 case prop_equals_string_comma
:
543 state
= prop_equals_string
;
546 file_err(filep
, tok_err
, tokbuf
);
553 if (strcmp(prop_name
, "port") == 0) {
554 if (confent
->port
!= -1) {
556 "'port' property already specified\n");
560 (int)strtol(tokbuf
, NULL
, 0);
563 state
= prop_equals_integer
;
568 case prop_equals_integer_comma
:
569 state
= prop_equals_integer
;
572 file_err(filep
, tok_err
, tokbuf
);
577 case prop_equals_string
:
578 state
= prop_equals_string_comma
;
580 case prop_equals_integer
:
581 state
= prop_equals_integer_comma
;
584 file_err(filep
, tok_err
, tokbuf
);
594 file_err(filep
, "Unexpected EOF\n");
597 file_err(filep
, tok_err
, tokbuf
);
600 } while ((token
= lex(filep
, tokbuf
, linesize
)) != T_SEMICOLON
);
608 free_confent(confent
);
615 * Parse all entries with mpxio-disable property in the given driver.conf
618 * fname driver.conf file name
619 * confent_list on return *confent_list will contain the list of
620 * driver.conf file entries with mpxio-disable property.
621 * mpxio_disable on return *mpxio_disable is set to the setting of the
622 * driver global mpxio-dissable property as follows.
623 * 0 if driver mpxio-disable="no"
624 * 1 if driver mpxio-disable="yes"
625 * -1 if driver mpxio-disable property isn't specified.
628 parse_conf_file(char *fname
, struct conf_entry
**confent_list
,
631 struct conf_entry
*confent
, *tail
= NULL
;
633 struct conf_file file
;
634 char tokval
[MAX_TOKEN_SIZE
];
636 *confent_list
= NULL
;
638 if ((file
.fp
= fopen(fname
, "r")) == NULL
)
641 file
.filename
= fname
;
644 while ((token
= lex(&file
, tokval
, MAX_TOKEN_SIZE
)) != T_EOF
) {
653 if ((confent
= parse_conf_entry(&file
, tokval
,
654 MAX_TOKEN_SIZE
)) == NULL
)
657 * No name indicates global property.
658 * Make sure parent and class not NULL.
660 if (confent
->name
== NULL
) {
661 if (confent
->parent
||
664 "missing name attribute\n");
665 } else if (confent
->mpxio_disable
!= -1) {
666 if (*mpxio_disable
== -1)
668 confent
->mpxio_disable
;
671 "'mpxio-disable' property already specified\n");
673 free_confent(confent
);
678 * This is a node spec, either parent or class
681 if (confent
->parent
== NULL
&& confent
->class == NULL
) {
683 "missing parent or class attribute\n");
684 free_confent(confent
);
688 /* only need entries with mpxio_disable property */
689 if (confent
->mpxio_disable
== -1) {
690 free_confent(confent
);
695 tail
->next
= confent
;
697 *confent_list
= confent
;
709 (void) fclose(file
.fp
);
713 * Return the driver class of the given driver_name.
714 * The memory for the driver class is allocated by this function and the
715 * caller must free it.
718 get_driver_class(char *rootdir
, char *driver_name
)
722 char driver
[BUFSIZE
];
723 char class_name
[BUFSIZE
];
725 logdmsg(("get_driver_class: rootdir = %s, driver name = %s\n",
726 rootdir
, driver_name
));
728 (void) snprintf(buf
, sizeof (buf
), "%s%s", rootdir
, DRIVER_CLASSES
);
730 if ((fp
= fopen(buf
, "r")) == NULL
) {
731 logdmsg(("get_driver_class: failed to open %s: %s\n",
732 buf
, strerror(errno
)));
736 while (fgets(buf
, sizeof (buf
), fp
) != NULL
) {
737 /* LINTED - unbounded string specifier */
738 if ((sscanf(buf
, "%s %s", driver
, class_name
) == 2) &&
739 driver
[0] != '#' && strcmp(driver
, driver_name
) == 0) {
740 logdmsg(("get_driver_class: driver class = %s\n",
743 return (strdup(class_name
));
752 lookup_in_confent_list(struct conf_entry
*confent_list
,
753 int match_class
, char *parent
, char *unit_addr
, int port
)
755 struct conf_entry
*confent
;
758 logdmsg(("lookup_in_confent_list: %s = \"%s\", unit_addr = \"%s\", "
759 "port = %d\n", (match_class
) ? "class" : "parent", parent
,
760 STRVAL(unit_addr
), port
));
762 for (confent
= confent_list
; confent
!= NULL
; confent
= confent
->next
) {
763 par
= (match_class
) ? confent
->class : confent
->parent
;
765 if (confent
->unit_address
!= NULL
&&
766 strcmp(confent
->unit_address
, unit_addr
) == 0 &&
767 par
!= NULL
&& strcmp(par
, parent
) == 0)
768 return (confent
->mpxio_disable
);
770 if (confent
->port
== port
&&
771 par
!= NULL
&& strcmp(par
, parent
) == 0)
772 return (confent
->mpxio_disable
);
779 * lookup mpxio-disabled property setting for the given path in the given
780 * driver.conf file. Match the entries from most specific to least specific.
782 * conf_file the path name of either fp.conf, qlc.conf or scsi_vhci.conf
783 * path /devices node path without the /devices prefix.
784 * If the conf_file is fp.conf, path must be a fp node path
785 * if the conf_file is qlc.conf, path must be a qlc node path.
786 * if the conf_file is scsi_vhci.conf, path must be NULL.
787 * ex: /pci@8,600000/SUNW,qlc@4/fp@0,0
788 * /pci@8,600000/SUNW,qlc@4
791 * 0 if mpxio-disable="no"
792 * 1 if mpxio-disable="yes"
793 * -1 if mpxio-disable property isn't specified.
796 lookup_in_conf_file(char *rootdir
, char *conf_file
, char *path
)
798 struct conf_entry
*confent_list
= NULL
;
800 di_node_t par_node
= DI_NODE_NIL
;
801 char *node_name
= NULL
, *node_addr
= NULL
;
802 char *unit_addr
= NULL
;
804 char *par_node_name
= NULL
, *par_node_addr
= NULL
;
805 char *par_binding_name
= NULL
, *par_driver_name
= NULL
;
806 char *par_driver_class
= NULL
, *par_node_name_addr
;
808 char buf
[MAXPATHLEN
];
810 logdmsg(("lookup_in_conf_file: rootdir = \"%s\", conf_file = \"%s\", "
811 "path = \"%s\"\n", rootdir
, conf_file
, STRVAL(path
)));
813 (void) snprintf(buf
, MAXPATHLEN
, "%s%s", rootdir
, conf_file
);
814 parse_conf_file(buf
, &confent_list
, &mpxio_disable
);
816 log_confent_list(buf
, confent_list
, mpxio_disable
);
819 /* if path is NULL, return driver global mpxio-disable setting */
825 if ((node_name
= strrchr(path
, '/')) == NULL
)
831 if ((node_addr
= strchr(node_name
, '@')) == NULL
)
837 if (strcmp(node_name
, "fp") == 0) {
838 /* get port number; encoded in the node addr as a hex number */
839 port
= (int)strtol(node_addr
, NULL
, 16);
841 unit_addr
= node_addr
;
844 * Match from most specific to least specific;
845 * first, start the lookup based on full path.
847 if ((rv
= lookup_in_confent_list(confent_list
, 0, path
,
848 unit_addr
, port
)) != -1)
851 /* lookup nodename@address */
852 if ((par_node_name_addr
= strrchr(path
, '/')) != NULL
) {
853 par_node_name_addr
++;
854 if ((rv
= lookup_in_confent_list(confent_list
, 0,
855 par_node_name_addr
, unit_addr
, port
)) != -1)
859 /* di_init() doesn't work when 0 is passed in flags */
860 par_node
= di_init(path
, DINFOMINOR
);
861 if (par_node
!= DI_NODE_NIL
) {
862 par_node_name
= di_node_name(par_node
);
863 par_node_addr
= di_bus_addr(par_node
);
864 par_binding_name
= di_binding_name(par_node
);
865 par_driver_name
= di_driver_name(par_node
);
868 logdmsg(("par_node_name = %s\n", STRVAL(par_node_name
)));
869 logdmsg(("par_node_addr = %s\n", STRVAL(par_node_addr
)));
870 logdmsg(("par_binding_name = %s\n", STRVAL(par_binding_name
)));
871 logdmsg(("par_driver_name = %s\n", STRVAL(par_driver_name
)));
873 /* lookup bindingname@address */
874 if (par_binding_name
!= NULL
&& par_binding_name
!= par_node_name
&&
875 par_node_addr
!= NULL
) {
876 (void) snprintf(buf
, sizeof (buf
), "%s@%s", par_binding_name
,
878 if ((rv
= lookup_in_confent_list(confent_list
, 0,
879 buf
, unit_addr
, port
)) != -1)
883 /* lookup binding name */
884 if (par_binding_name
!= NULL
) {
885 if ((rv
= lookup_in_confent_list(confent_list
, 0,
886 par_binding_name
, unit_addr
, port
)) != -1)
890 if (par_driver_name
!= NULL
) {
891 /* lookup driver name */
892 if ((rv
= lookup_in_confent_list(confent_list
, 0,
893 par_driver_name
, unit_addr
, port
)) != -1)
896 /* finally, lookup class name */
897 par_driver_class
= get_driver_class(rootdir
, par_driver_name
);
898 if (par_driver_class
!= NULL
) {
899 if ((rv
= lookup_in_confent_list(confent_list
, 1,
900 par_driver_class
, unit_addr
, port
)) != -1)
907 * use the driver global mpxio-disable setting if exists.
912 if (node_name
!= NULL
)
913 *(node_name
- 1) = '/';
914 if (node_addr
!= NULL
)
915 *(node_addr
- 1) = '@';
916 free(par_driver_class
);
917 if (confent_list
!= NULL
)
918 free_confent_list(confent_list
);
919 if (par_node
!= DI_NODE_NIL
)
926 * Given client_name return whether it is a phci or vhci based name.
927 * client_name is /devices name of a client without the /devices prefix.
929 * client_name Return value
930 * .../fp@xxx/ssd@yyy CLIENT_TYPE_PHCI
931 * .../scsi_vhci/ssd@yyy CLIENT_TYPE_VHCI
932 * other CLIENT_TYPE_UNKNOWN
935 client_name_type(char *client_name
)
937 client_type_t client_type
;
940 logdmsg(("client_name_type: client_name = %s\n", client_name
));
942 if (strncmp(client_name
, SLASH_SCSI_VHCI
,
943 sizeof (SLASH_SCSI_VHCI
) - 1) == 0)
944 return (CLIENT_TYPE_VHCI
);
946 if (*client_name
!= '/')
947 return (CLIENT_TYPE_UNKNOWN
);
949 if ((p1
= strrchr(client_name
, '/')) == NULL
)
950 return (CLIENT_TYPE_UNKNOWN
);
954 if ((p2
= strrchr(client_name
, '/')) != NULL
&&
955 strncmp(p2
, SLASH_FP_AT
, sizeof (SLASH_FP_AT
) - 1) == 0)
956 client_type
= CLIENT_TYPE_PHCI
;
958 client_type
= CLIENT_TYPE_UNKNOWN
;
961 return (client_type
);
965 * Compare controller name portion of dev1 and dev2.
967 * rootdir root directory of the target environment
968 * dev1 can be either a /dev link or /devices name in the target
970 * dev2 /devices name of a device without the /devices prefix
973 * 0 if controller names match
974 * 1 if controller names don't match
975 * -1 an error occurred.
978 compare_controller(char *rootdir
, char *dev1
, char *dev2
)
982 char physdev1
[MAXPATHLEN
];
983 char buf
[MAXPATHLEN
];
985 logdmsg(("compare_controller: rootdir = %s, dev1 = %s, dev2 = %s\n",
986 rootdir
, dev1
, dev2
));
988 if (strncmp(dev1
, SLASH_DEV_SLASH
, sizeof (SLASH_DEV_SLASH
) - 1)
990 (void) snprintf(buf
, MAXPATHLEN
, "%s%s", rootdir
, dev1
);
991 if ((linksize
= readlink(buf
, physdev1
, MAXPATHLEN
)) > 0 &&
992 linksize
< (MAXPATHLEN
- 1)) {
993 physdev1
[linksize
] = '\0';
994 logdmsg(("compare_controller: physdev1 = %s\n",
999 (void) strlcpy(physdev1
, dev1
, MAXPATHLEN
);
1001 if ((p1
= strstr(physdev1
, SLASH_DEVICES
)) == NULL
)
1004 p1
+= sizeof (SLASH_DEVICES
) - 1;
1005 /* strip the device portion */
1006 if ((p
= strrchr(p1
, '/')) == NULL
)
1010 if ((p
= strrchr(dev2
, '/')) == NULL
)
1014 logdmsg(("compare_controller: path1 = %s, path2 = %s\n",
1016 if (strcmp(p1
, dev2
) == 0) {
1026 * Check if the specified device path is on the root controller.
1028 * rootdir root directory of the target environment
1029 * path /devices name of a device without the /devices prefix
1032 * 1 if the path is on the root controller
1033 * 0 if the path is not on the root controller
1034 * -1 if an error occurs
1037 is_root_controller(char *rootdir
, char *path
)
1042 struct vfstab vfsent
;
1043 char buf
[MAXPATHLEN
];
1044 char ctd
[MAXNAMELEN
+ 1];
1046 logdmsg(("is_root_controller: rootdir = %s, path = %s\n", rootdir
,
1049 (void) snprintf(buf
, MAXPATHLEN
, "%s%s", rootdir
, VFSTAB
);
1051 if ((fp
= fopen(buf
, "r")) == NULL
) {
1052 logdmsg(("is_root_controller: failed to open %s: %s\n",
1053 buf
, strerror(errno
)));
1057 if (getvfsfile(fp
, &vfsent
, "/") != 0) {
1058 logdmsg(("is_root_controller: getvfsfile: failed to read "
1059 "vfstab entry for mount point \"/\": %s\n",
1066 /* check if the root is an svm metadisk */
1067 if (strncmp(vfsent
.vfs_special
, META_DEV
, sizeof (META_DEV
) - 1) != 0) {
1068 if (compare_controller(rootdir
, vfsent
.vfs_special
, path
) == 0)
1074 /* Don't use /var/run as it is not mounted in miniroot */
1075 if ((tmpfile
= tempnam("/tmp", "diirc")) == NULL
) {
1076 logdmsg(("is_root_controller: tempnam: failed: %s\n",
1081 /* get metadisk components using metastat command */
1082 (void) snprintf(buf
, MAXPATHLEN
,
1083 "/usr/sbin/metastat -p %s 2>/dev/null | "
1084 "/usr/bin/grep ' 1 1 ' | "
1085 "/usr/bin/sed -e 's/^.* 1 1 //' | "
1086 "/usr/bin/cut -f1 -d ' ' > %s",
1087 vfsent
.vfs_special
+ sizeof (META_DEV
) - 1, tmpfile
);
1089 logdmsg(("is_root_controller: command = %s\n", buf
));
1091 if (system(buf
) == 0 && (fp
= fopen(tmpfile
, "r")) != NULL
) {
1092 while (fscanf(fp
, "%" VAL2STR(MAXNAMELEN
) "s", ctd
) == 1) {
1093 (void) snprintf(buf
, MAXPATHLEN
, "/dev/dsk/%s", ctd
);
1094 if (compare_controller(rootdir
, buf
, path
) == 0) {
1105 (void) unlink(tmpfile
);
1111 file_exists(char *rootdir
, char *path
)
1114 char fullpath
[MAXPATHLEN
];
1117 (void) snprintf(fullpath
, MAXPATHLEN
, "%s%s", rootdir
, path
);
1119 x
= stat(fullpath
, &stbuf
);
1120 logdmsg(("file_exists: %s: %s\n", fullpath
, (x
== 0) ? "yes" : "no"));
1128 * Check if mpxio is enabled or disabled on the specified device path.
1129 * Looks through the .conf files to determine the mpxio setting.
1131 * rootdir root directory of the target environment
1132 * path /devices name of a device without the /devices prefix and
1133 * minor name component.
1136 * 1 if mpxio is disabled
1137 * 0 if mpxio is enabled
1138 * -1 if an error occurs
1141 is_mpxio_disabled(char *rootdir
, char *path
)
1145 int check_root_controller
;
1147 logdmsg(("is_mpxio_disabled: rootdir = %s, path = %s\n",
1150 if (file_exists(rootdir
, SCSI_VHCI_CONF
) == 0) {
1152 * scsi_vhci.conf doesn't exist:
1153 * if upgrading from a pre solaris 9 release. or
1154 * if this function is called during fresh or flash install
1155 * prior to installing scsi_vhci.conf file.
1157 if (file_exists(rootdir
, "/kernel/drv"))
1158 /* upgrading from pre solaris 9 */
1161 /* fresh or flash install */
1165 mpxio_disable
= lookup_in_conf_file(rootdir
, SCSI_VHCI_CONF
, NULL
);
1168 * scsi_vhci.conf contains mpxio-disable property only in s9 and
1169 * s8+sfkpatch. This property is no longer present from s10 onwards.
1171 if (mpxio_disable
== 1) {
1172 /* upgrading from s8 or s9 with mpxio globally disabled */
1174 } else if (mpxio_disable
== 0) {
1175 /* upgrading from s8 or s9 with mpxio globally enabled */
1176 check_root_controller
= 1;
1179 * We are looking at the s10 version of the file. This is
1180 * the case if this function is called after installing the
1181 * new scsi_vhci.conf file.
1183 check_root_controller
= 0;
1186 if ((mpxio_disable
= lookup_in_conf_file(rootdir
, FP_CONF
, path
))
1188 return (mpxio_disable
);
1190 if ((p
= strrchr(path
, '/')) == NULL
)
1194 if ((mpxio_disable
= lookup_in_conf_file(rootdir
, QLC_CONF
, path
))
1197 return (mpxio_disable
);
1202 * mpxio-disable setting is not found in the .conf files.
1203 * The default is to enable mpxio, except if the path is on the root
1206 * In s8 and s9 mpxio is not supported on the root controller.
1207 * NWS supplies a patch to enable root controller support in s8 and s9.
1208 * If the system had the patch installed, the fp.conf file would have
1209 * explicit "mpxio-disable=no" for the root controller. So we would
1210 * have found the mpxio-disable setting when we looked up this property
1211 * in the fp.conf file.
1213 if (check_root_controller
) {
1214 mpxio_disable
= is_root_controller(rootdir
, path
);
1215 logdmsg(("is_mpxio_disabled: is_root_controller returned %d\n",
1220 return (mpxio_disable
);
1224 vhci_ctl(sv_iocdata_t
*iocp
, int cmd
)
1228 if ((fd
= open(VHCI_CTL_NODE
, O_RDWR
)) < 0)
1230 rv
= ioctl(fd
, cmd
, iocp
);
1236 * Convert a phci client name to vhci client name.
1238 * phci_name phci client /devices name without the /devices prefix and
1239 * minor name component.
1240 * ex: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
1242 * Returns on success, vhci client name is returned. The memory for
1243 * the vhci name is allocated by this function and the caller
1245 * on failure, NULL is returned.
1248 phci_to_vhci(char *phci_name
)
1251 char *slash
, *addr
, *retp
;
1252 char vhci_name_buf
[MAXPATHLEN
];
1253 char phci_name_buf
[MAXPATHLEN
];
1254 char addr_buf
[MAXNAMELEN
];
1256 logdmsg(("phci_to_vhci: pchi_name = %s\n", phci_name
));
1257 (void) strlcpy(phci_name_buf
, phci_name
, MAXPATHLEN
);
1259 if ((slash
= strrchr(phci_name_buf
, '/')) == NULL
||
1260 (addr
= strchr(slash
, '@')) == NULL
)
1265 (void) strlcpy(addr_buf
, addr
, MAXNAMELEN
);
1267 bzero(&ioc
, sizeof (sv_iocdata_t
));
1268 ioc
.client
= vhci_name_buf
;
1269 ioc
.phci
= phci_name_buf
;
1270 ioc
.addr
= addr_buf
;
1271 if (vhci_ctl(&ioc
, SCSI_VHCI_GET_CLIENT_NAME
) != 0) {
1272 logdmsg(("phci_to_vhci: vhci_ctl failed: %s\n",
1277 retp
= strdup(vhci_name_buf
);
1278 logdmsg(("phci_to_vhci: vhci name = %s\n", STRVAL(retp
)));
1283 add_to_phci_list(char **phci_list
, sv_path_info_t
*pi
, int npaths
, int state
,
1287 char name
[MAXPATHLEN
];
1290 if (state
== pi
->ret_state
) {
1291 (void) snprintf(name
, MAXPATHLEN
, "%s/%s@%s",
1292 pi
->device
.ret_phci
, node_name
, pi
->ret_addr
);
1293 if ((*phci_list
= strdup(name
)) == NULL
)
1305 free_pathlist(char **pathlist
)
1309 if (pathlist
!= NULL
) {
1310 for (p
= pathlist
; *p
!= NULL
; p
++)
1318 * Convert a vhci client name to phci client names.
1320 * vhci_name vhci client /devices name without the /devices prefix and
1321 * minor name component.
1322 * num_paths On return, *num_paths is set to the number paths in the
1323 * returned path list.
1325 * Returns NULL terminated path list containing phci client paths is
1326 * returned on success. The memory for the path list is
1327 * allocated by this function and the caller must free it by
1328 * calling free_pathlist().
1329 * NULL is returned on failure.
1332 vhci_to_phci(char *vhci_name
, int *num_paths
)
1337 char **phci_list
= NULL
;
1338 char *node_name
, *at
;
1339 char vhci_name_buf
[MAXPATHLEN
];
1341 logdmsg(("vhci_to_phci: vchi_name = %s\n", vhci_name
));
1344 (void) strlcpy(vhci_name_buf
, vhci_name
, MAXPATHLEN
);
1346 /* first get the number paths */
1347 bzero(&ioc
, sizeof (sv_iocdata_t
));
1348 ioc
.client
= vhci_name_buf
;
1349 ioc
.ret_elem
= &npaths
;
1350 if (vhci_ctl(&ioc
, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO
) != 0 ||
1352 logdmsg(("vhci_to_phci: vhci_ctl failed to get npaths: %s\n",
1357 /* now allocate memory for the path information and get all paths */
1358 bzero(&ioc
, sizeof (sv_iocdata_t
));
1359 ioc
.client
= vhci_name_buf
;
1360 ioc
.buf_elem
= npaths
;
1361 ioc
.ret_elem
= &npaths
;
1362 if ((ioc
.ret_buf
= (sv_path_info_t
*)calloc(npaths
,
1363 sizeof (sv_path_info_t
))) == NULL
)
1365 if (vhci_ctl(&ioc
, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO
) != 0 ||
1367 logdmsg(("vhci_to_phci: vhci_ctl failed: %s\n",
1372 if (ioc
.buf_elem
< npaths
)
1373 npaths
= ioc
.buf_elem
;
1375 if ((node_name
= strrchr(vhci_name_buf
, '/')) == NULL
||
1376 (at
= strchr(node_name
, '@')) == NULL
)
1382 /* allocate one more (than npaths) for the terminating NULL pointer */
1383 if ((phci_list
= calloc(npaths
+ 1, sizeof (char *))) == NULL
)
1387 * add only online paths as non-online paths may not be accessible
1388 * in the target environment.
1390 if ((n
= add_to_phci_list(phci_list
, ioc
.ret_buf
, npaths
,
1391 MDI_PATHINFO_STATE_ONLINE
, node_name
)) <= 0)
1398 logdmsg(("vhci_to_phci: phci list:\n"));
1399 log_pathlist(phci_list
);
1406 free_pathlist(phci_list
);
1411 * build list of paths accessible from the target environment
1414 build_pathlist(char *rootdir
, char *vhcipath
, char **pathlist
, int npaths
)
1420 for (i
= 0; i
< npaths
; i
++) {
1421 mpxio_disabled
= is_mpxio_disabled(rootdir
, pathlist
[i
]);
1422 logdmsg(("build_pathlist: mpxio_disabled = %d "
1423 "on path %s\n", mpxio_disabled
, pathlist
[i
]));
1424 if (mpxio_disabled
== -1)
1426 if (mpxio_disabled
== 0) {
1428 * mpxio is enabled on this phci path.
1429 * So use vhci path instead of phci path.
1431 if (vpath
== NULL
) {
1432 if ((vpath
= strdup(vhcipath
)) == NULL
)
1435 /* keep vhci path at beginning of the list */
1436 for (j
= i
; j
> 0; j
--)
1437 pathlist
[j
] = pathlist
[j
- 1];
1438 pathlist
[0] = vpath
;
1442 for (j
= i
; j
< npaths
; j
++)
1443 pathlist
[j
] = pathlist
[j
+ 1];
1444 pathlist
[npaths
] = NULL
;
1445 /* compensate for i++ in the for loop */
1452 logdmsg(("build_pathlist: returning npaths = %d, pathlist:\n", npaths
));
1453 log_pathlist(pathlist
);
1459 * Check if the specified device is refenced in the vfstab file.
1460 * Return 1 if referenced, 0 if not.
1462 * rootdir root directory of the target environment
1463 * nodepath /devices path of a device in the target environment without
1464 * the /devices prefix and minor component.
1467 is_dev_in_vfstab(char *rootdir
, char *nodepath
)
1471 struct vfstab vfsent
;
1472 char *abspath
, *minor
;
1473 char physpath
[MAXPATHLEN
];
1474 char buf
[MAXPATHLEN
];
1476 logdmsg(("is_dev_in_vfstab: rootdir = %s, nodepath = %s\n",
1477 rootdir
, nodepath
));
1479 (void) snprintf(buf
, sizeof (buf
), "%s%s", rootdir
, VFSTAB
);
1481 if ((fp
= fopen(buf
, "r")) == NULL
)
1485 * read device specials from vfstab and compare names at physical
1488 while (getvfsent(fp
, &vfsent
) == 0) {
1489 if (strncmp(vfsent
.vfs_special
, SLASH_DEV_SLASH
,
1490 sizeof (SLASH_DEV_SLASH
) - 1) == 0) {
1491 (void) snprintf(buf
, MAXPATHLEN
, "%s%s",
1492 rootdir
, vfsent
.vfs_special
);
1493 if ((linksize
= readlink(buf
, physpath
,
1494 MAXPATHLEN
)) > 0 && linksize
< (MAXPATHLEN
- 1)) {
1495 physpath
[linksize
] = '\0';
1496 if ((abspath
= strstr(physpath
,
1497 SLASH_DEVICES_SLASH
)) == NULL
)
1501 } else if (strncmp(vfsent
.vfs_special
, SLASH_DEVICES_SLASH
,
1502 sizeof (SLASH_DEVICES_SLASH
) - 1) == 0) {
1503 (void) strlcpy(physpath
, vfsent
.vfs_special
,
1509 /* point to / after /devices */
1510 abspath
+= sizeof (SLASH_DEVICES_SLASH
) - 2;
1511 /* strip minor component */
1512 if ((minor
= strrchr(abspath
, ':')) != NULL
)
1515 if (strcmp(nodepath
, abspath
) == 0) {
1517 logdmsg(("is_dev_in_vfstab: returning 1\n"));
1526 #endif /* __sparc */
1529 devlink_callback(di_devlink_t devlink
, void *argp
)
1533 if ((link
= di_devlink_path(devlink
)) != NULL
)
1534 (void) strlcpy((char *)argp
, link
, MAXPATHLEN
);
1536 return (DI_WALK_CONTINUE
);
1540 * Get the /dev name in the install environment corresponding to physpath.
1542 * physpath /devices path in the install environment without the /devices
1544 * buf caller supplied buffer where the /dev name is placed on return
1545 * bufsz length of the buffer
1547 * Returns strlen of the /dev name on success, -1 on failure.
1550 get_install_devlink(char *physpath
, char *buf
, size_t bufsz
)
1552 di_devlink_handle_t devlink_hdl
;
1553 char devname
[MAXPATHLEN
];
1555 int sleeptime
= 2; /* number of seconds to sleep between retries */
1556 int maxtries
= 10; /* maximum number of tries */
1558 logdmsg(("get_install_devlink: physpath = %s\n", physpath
));
1561 * devlink_db sync happens after MINOR_FINI_TIMEOUT_DEFAULT secs
1562 * after dev link creation. So wait for minimum that amout of time.
1566 (void) sleep(sleeptime
);
1568 if ((devlink_hdl
= di_devlink_init(NULL
, 0)) == NULL
) {
1569 logdmsg(("get_install_devlink: di_devlink_init() failed: %s\n",
1575 if (di_devlink_walk(devlink_hdl
, NULL
, physpath
, DI_PRIMARY_LINK
,
1576 devname
, devlink_callback
) == 0) {
1577 if (devname
[0] == '\0' && tries
< maxtries
) {
1579 (void) di_devlink_fini(&devlink_hdl
);
1581 } else if (devname
[0] == '\0') {
1582 logdmsg(("get_install_devlink: di_devlink_walk"
1583 " failed: %s\n", strerror(errno
)));
1584 (void) di_devlink_fini(&devlink_hdl
);
1588 logdmsg(("get_install_devlink: di_devlink_walk failed: %s\n",
1590 (void) di_devlink_fini(&devlink_hdl
);
1594 (void) di_devlink_fini(&devlink_hdl
);
1596 logdmsg(("get_install_devlink: devlink = %s\n", devname
));
1597 return (strlcpy(buf
, devname
, bufsz
));
1601 * Get the /dev name in the target environment corresponding to physpath.
1603 * rootdir root directory of the target environment
1604 * physpath /devices path in the target environment without the /devices
1606 * buf caller supplied buffer where the /dev name is placed on return
1607 * bufsz length of the buffer
1609 * Returns strlen of the /dev name on success, -1 on failure.
1612 get_target_devlink(char *rootdir
, char *physpath
, char *buf
, size_t bufsz
)
1617 struct dirent
*direntry
;
1618 char dirpath
[MAXPATHLEN
];
1619 char devname
[MAXPATHLEN
];
1620 char physdev
[MAXPATHLEN
];
1622 logdmsg(("get_target_devlink: rootdir = %s, physpath = %s\n",
1623 rootdir
, physpath
));
1625 if ((p
= strrchr(physpath
, '/')) == NULL
)
1628 if (strstr(p
, ",raw") != NULL
) {
1629 (void) snprintf(dirpath
, MAXPATHLEN
, "%s/dev/rdsk", rootdir
);
1631 (void) snprintf(dirpath
, MAXPATHLEN
, "%s/dev/dsk", rootdir
);
1634 if ((dirp
= opendir(dirpath
)) == NULL
)
1637 while ((direntry
= readdir(dirp
)) != NULL
) {
1638 if (strcmp(direntry
->d_name
, ".") == 0 ||
1639 strcmp(direntry
->d_name
, "..") == 0)
1642 (void) snprintf(devname
, MAXPATHLEN
, "%s/%s",
1643 dirpath
, direntry
->d_name
);
1645 if ((linksize
= readlink(devname
, physdev
, MAXPATHLEN
)) > 0 &&
1646 linksize
< (MAXPATHLEN
- 1)) {
1647 physdev
[linksize
] = '\0';
1648 if ((p
= strstr(physdev
, SLASH_DEVICES_SLASH
)) !=
1649 NULL
&& strcmp(p
+ sizeof (SLASH_DEVICES
) - 1,
1651 (void) closedir(dirp
);
1652 logdmsg(("get_target_devlink: devlink = %s\n",
1653 devname
+ strlen(rootdir
)));
1654 return (strlcpy(buf
, devname
+ strlen(rootdir
),
1660 (void) closedir(dirp
);
1665 * Convert device name to physpath.
1667 * rootdir root directory
1668 * devname a /dev name or /devices name under rootdir
1669 * physpath caller supplied buffer where the /devices path will be placed
1670 * on return (without the /devices prefix).
1671 * physpathlen length of the physpath buffer
1673 * Returns 0 on success, -1 on failure.
1676 devname2physpath(char *rootdir
, char *devname
, char *physpath
, int physpathlen
)
1680 char devlink
[MAXPATHLEN
];
1681 char tmpphyspath
[MAXPATHLEN
];
1683 logdmsg(("devname2physpath: rootdir = %s, devname = %s\n",
1686 if (strncmp(devname
, SLASH_DEVICES_SLASH
,
1687 sizeof (SLASH_DEVICES_SLASH
) - 1) != 0) {
1688 if (*rootdir
== '\0')
1689 linksize
= readlink(devname
, tmpphyspath
, MAXPATHLEN
);
1691 (void) snprintf(devlink
, MAXPATHLEN
, "%s%s",
1693 linksize
= readlink(devlink
, tmpphyspath
, MAXPATHLEN
);
1695 if (linksize
> 0 && linksize
< (MAXPATHLEN
- 1)) {
1696 tmpphyspath
[linksize
] = '\0';
1697 if ((p
= strstr(tmpphyspath
, SLASH_DEVICES_SLASH
))
1705 (void) strlcpy(physpath
, p
+ sizeof (SLASH_DEVICES
) - 1, physpathlen
);
1706 logdmsg(("devname2physpath: physpath = %s\n", physpath
));
1711 * Map a device name (devname) from the target environment to the
1712 * install environment.
1714 * rootdir root directory of the target environment
1715 * devname /dev or /devices name under the target environment
1716 * buf caller supplied buffer where the mapped /dev name is placed
1718 * bufsz length of the buffer
1720 * Returns strlen of the mapped /dev name on success, -1 on failure.
1723 devfs_target2install(const char *rootdir
, const char *devname
, char *buf
,
1726 char physpath
[MAXPATHLEN
];
1728 logdmsg(("devfs_target2install: rootdir = %s, devname = %s\n",
1729 STRVAL(rootdir
), STRVAL(devname
)));
1731 if (rootdir
== NULL
|| devname
== NULL
|| buf
== NULL
|| bufsz
== 0)
1734 if (strcmp(rootdir
, "/") == 0)
1737 if (devname2physpath((char *)rootdir
, (char *)devname
, physpath
,
1742 if (client_name_type(physpath
) == CLIENT_TYPE_PHCI
) {
1743 char *mapped_node_path
, *minor
;
1744 char minorbuf
[MAXNAMELEN
];
1746 /* strip minor component if present */
1747 if ((minor
= strrchr(physpath
, ':')) != NULL
) {
1750 (void) strlcpy(minorbuf
, minor
, MAXNAMELEN
);
1752 if ((mapped_node_path
= phci_to_vhci(physpath
)) != NULL
) {
1754 (void) snprintf(physpath
, MAXPATHLEN
,
1755 "%s:%s", mapped_node_path
, minorbuf
);
1757 (void) strlcpy(physpath
, mapped_node_path
,
1759 free(mapped_node_path
);
1760 logdmsg(("devfs_target2install: mapped physpath: %s\n",
1766 #endif /* __sparc */
1768 return (get_install_devlink(physpath
, buf
, bufsz
));
1772 * Map a device name (devname) from the install environment to the target
1775 * rootdir root directory of the target environment
1776 * devname /dev or /devices name under the install environment
1777 * buf caller supplied buffer where the mapped /dev name is placed
1779 * bufsz length of the buffer
1781 * Returns strlen of the mapped /dev name on success, -1 on failure.
1784 devfs_install2target(const char *rootdir
, const char *devname
, char *buf
,
1787 char physpath
[MAXPATHLEN
];
1789 logdmsg(("devfs_install2target: rootdir = %s, devname = %s\n",
1790 STRVAL(rootdir
), STRVAL(devname
)));
1792 if (rootdir
== NULL
|| devname
== NULL
|| buf
== NULL
|| bufsz
== 0)
1795 if (strcmp(rootdir
, "/") == 0)
1798 if (devname2physpath("", (char *)devname
, physpath
, MAXPATHLEN
) != 0)
1802 if (client_name_type(physpath
) == CLIENT_TYPE_VHCI
) {
1806 char minorbuf
[MAXNAMELEN
];
1808 /* strip minor component if present */
1809 if ((minor
= strrchr(physpath
, ':')) != NULL
) {
1812 (void) strlcpy(minorbuf
, minor
, MAXNAMELEN
);
1815 if ((pathlist
= vhci_to_phci(physpath
, &npaths
)) == NULL
)
1818 if ((npaths
= build_pathlist((char *)rootdir
, physpath
,
1819 pathlist
, npaths
)) <= 0) {
1820 free_pathlist(pathlist
);
1825 * in case of more than one path, try to use the path
1826 * referenced in the vfstab file, otherwise use the first path.
1830 for (i
= 0; i
< npaths
; i
++) {
1831 if (is_dev_in_vfstab((char *)rootdir
,
1840 (void) snprintf(physpath
, MAXPATHLEN
,
1841 "%s:%s", pathlist
[j
], minorbuf
);
1843 (void) strlcpy(physpath
, pathlist
[j
], MAXPATHLEN
);
1844 free_pathlist(pathlist
);
1846 #endif /* __sparc */
1848 return (get_target_devlink((char *)rootdir
, physpath
, buf
, bufsz
));
1852 * A parser for /etc/path_to_inst.
1853 * The user-supplied callback is called once for each entry in the file.
1854 * Returns 0 on success, ENOMEM/ENOENT/EINVAL on error.
1855 * Callback may return DI_WALK_TERMINATE to terminate the walk,
1856 * otherwise DI_WALK_CONTINUE.
1859 devfs_parse_binding_file(const char *binding_file
,
1860 int (*callback
)(void *, const char *, int,
1861 const char *), void *cb_arg
)
1864 struct conf_file file
;
1865 char tokval
[MAX_TOKEN_SIZE
];
1866 enum { STATE_RESET
, STATE_DEVPATH
, STATE_INSTVAL
} state
;
1872 if ((devpath
= calloc(1, MAXPATHLEN
)) == NULL
)
1874 if ((bindname
= calloc(1, MAX_TOKEN_SIZE
)) == NULL
) {
1879 if ((file
.fp
= fopen(binding_file
, "r")) == NULL
) {
1885 file
.filename
= (char *)binding_file
;
1888 state
= STATE_RESET
;
1889 while ((token
= lex(&file
, tokval
, MAX_TOKEN_SIZE
)) != T_EOF
) {
1901 if (strlcpy(devpath
, tokval
,
1902 MAXPATHLEN
) >= MAXPATHLEN
)
1904 state
= STATE_DEVPATH
;
1907 if (strlcpy(bindname
, tokval
,
1908 MAX_TOKEN_SIZE
) >= MAX_TOKEN_SIZE
)
1910 rv
= callback(cb_arg
,
1911 devpath
, instval
, bindname
);
1912 if (rv
== DI_WALK_TERMINATE
)
1914 if (rv
!= DI_WALK_CONTINUE
)
1916 state
= STATE_RESET
;
1919 file_err(&file
, tok_err
, tokval
);
1920 state
= STATE_RESET
;
1928 instval
= (int)strtol(tokval
, NULL
, 0);
1929 state
= STATE_INSTVAL
;
1932 file_err(&file
, tok_err
, tokval
);
1933 state
= STATE_RESET
;
1939 state
= STATE_RESET
;
1942 file_err(&file
, tok_err
, tokval
);
1943 state
= STATE_RESET
;
1949 (void) fclose(file
.fp
);
1955 (void) fclose(file
.fp
);
1962 * Walk the minor nodes of all children below the specified device
1963 * by calling the provided callback with the path to each minor.
1966 devfs_walk_children_minors(const char *device_path
, struct stat
*st
,
1967 int (*callback
)(void *, const char *), void *cb_arg
, int *terminate
)
1971 char *minor_path
= NULL
;
1975 if ((minor_path
= calloc(1, MAXPATHLEN
)) == NULL
)
1978 if ((dir
= opendir(device_path
)) == NULL
) {
1984 while ((dp
= readdir(dir
)) != NULL
) {
1985 if ((strcmp(dp
->d_name
, ".") == 0) ||
1986 (strcmp(dp
->d_name
, "..") == 0))
1988 (void) snprintf(minor_path
, MAXPATHLEN
,
1989 "%s/%s", device_path
, dp
->d_name
);
1990 if (stat(minor_path
, st
) == -1)
1992 if (S_ISDIR(st
->st_mode
)) {
1993 rv
= devfs_walk_children_minors(
1994 (const char *)minor_path
, st
,
1995 callback
, cb_arg
, terminate
);
2001 rv
= callback(cb_arg
, minor_path
);
2002 if (rv
== DI_WALK_TERMINATE
) {
2006 if (rv
!= DI_WALK_CONTINUE
) {
2016 (void) closedir(dir
);
2022 * Return the path to each minor node for a device by
2023 * calling the provided callback.
2026 devfs_walk_device_minors(const char *device_path
, struct stat
*st
,
2027 int (*callback
)(void *, const char *), void *cb_arg
, int *terminate
)
2033 int need_regfree
= 0;
2040 minor_path
= calloc(1, MAXPATHLEN
);
2041 devpath
= calloc(1, MAXPATHLEN
);
2042 expr
= calloc(1, MAXNAMELEN
);
2043 if (devpath
== NULL
|| expr
== NULL
|| minor_path
== NULL
) {
2049 if (strlcpy(devpath
, device_path
, MAXPATHLEN
) >= MAXPATHLEN
)
2051 if ((p
= strrchr(devpath
, '/')) == NULL
)
2056 if (snprintf(expr
, MAXNAMELEN
, "%s:.*", p
) >= MAXNAMELEN
)
2058 if (regcomp(®ex
, expr
, REG_EXTENDED
) != 0)
2062 if ((dir
= opendir(devpath
)) == NULL
) {
2068 while ((dp
= readdir(dir
)) != NULL
) {
2069 if ((strcmp(dp
->d_name
, ".") == 0) ||
2070 (strcmp(dp
->d_name
, "..") == 0))
2072 (void) snprintf(minor_path
, MAXPATHLEN
,
2073 "%s/%s", devpath
, dp
->d_name
);
2074 if (stat(minor_path
, st
) == -1)
2076 if ((S_ISBLK(st
->st_mode
) || S_ISCHR(st
->st_mode
)) &&
2077 regexec(®ex
, dp
->d_name
, 0, NULL
, 0) == 0) {
2078 rv
= callback(cb_arg
, minor_path
);
2079 if (rv
== DI_WALK_TERMINATE
) {
2083 if (rv
!= DI_WALK_CONTINUE
) {
2093 (void) closedir(dir
);
2103 * Perform a walk of all minor nodes for the specified device,
2104 * and minor nodes below the device.
2107 devfs_walk_minor_nodes(const char *device_path
,
2108 int (*callback
)(void *, const char *), void *cb_arg
)
2114 rv
= devfs_walk_device_minors(device_path
,
2115 &stbuf
, callback
, cb_arg
, &terminate
);
2116 if (rv
== 0 && terminate
== 0) {
2117 rv
= devfs_walk_children_minors(device_path
,
2118 &stbuf
, callback
, cb_arg
, &terminate
);
2126 vlog_debug_msg(char *fmt
, va_list ap
)
2131 if (!devfsmap_debug
)
2134 if (logfp
== NULL
) {
2135 if (*devfsmap_logfile
!= '\0') {
2136 logfp
= fopen(devfsmap_logfile
, "a");
2138 (void) fprintf(logfp
, "\nNew Log:\n");
2146 (void) localtime_r(&clock
, &t
);
2147 (void) fprintf(logfp
, "%02d:%02d:%02d ", t
.tm_hour
, t
.tm_min
,
2149 (void) vfprintf(logfp
, fmt
, ap
);
2150 (void) fflush(logfp
);
2154 log_debug_msg(char *fmt
, ...)
2159 vlog_debug_msg(fmt
, ap
);
2166 mpxio_disable_string(int mpxio_disable
)
2168 if (mpxio_disable
== 0)
2170 else if (mpxio_disable
== 1)
2173 return ("not specified");
2177 log_confent_list(char *filename
, struct conf_entry
*confent_list
,
2178 int global_mpxio_disable
)
2180 struct conf_entry
*confent
;
2182 log_debug_msg("log_confent_list: filename = %s:\n", filename
);
2183 if (global_mpxio_disable
!= -1)
2184 log_debug_msg("\tdriver global mpxio_disable = \"%s\"\n\n",
2185 mpxio_disable_string(global_mpxio_disable
));
2187 for (confent
= confent_list
; confent
!= NULL
; confent
= confent
->next
) {
2189 log_debug_msg("\tname = %s\n", confent
->name
);
2190 if (confent
->parent
)
2191 log_debug_msg("\tparent = %s\n", confent
->parent
);
2193 log_debug_msg("\tclass = %s\n", confent
->class);
2194 if (confent
->unit_address
)
2195 log_debug_msg("\tunit_address = %s\n",
2196 confent
->unit_address
);
2197 if (confent
->port
!= -1)
2198 log_debug_msg("\tport = %d\n", confent
->port
);
2199 log_debug_msg("\tmpxio_disable = \"%s\"\n\n",
2200 mpxio_disable_string(confent
->mpxio_disable
));
2205 log_pathlist(char **pathlist
)
2209 for (p
= pathlist
; *p
!= NULL
; p
++)
2210 log_debug_msg("\t%s\n", *p
);
2213 #endif /* __sparc */