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.
26 #define _REENTRANT /* for localtime_r */
32 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/vfstab.h>
45 #include <sys/scsi/adapters/scsi_vhci.h>
46 #include <sys/sunmdi.h>
48 #include "libdevinfo.h"
49 #include "device_info.h"
52 #define isnewline(ch) ((ch) == '\n' || (ch) == '\r' || (ch) == '\f')
53 #define isnamechar(ch) (isalpha(ch) || isdigit(ch) || (ch) == '_' ||\
55 #define MAX_TOKEN_SIZE 1024
57 #define STRVAL(s) ((s) ? (s) : "NULL")
59 #define SCSI_VHCI_CONF "/kernel/drv/scsi_vhci.conf"
60 #define QLC_CONF "/kernel/drv/qlc.conf"
61 #define FP_CONF "/kernel/drv/fp.conf"
62 #define DRIVER_CLASSES "/etc/driver_classes"
64 #define VHCI_CTL_NODE "/devices/scsi_vhci:devctl"
65 #define SLASH_DEVICES "/devices"
66 #define SLASH_DEVICES_SLASH "/devices/"
67 #define SLASH_FP_AT "/fp@"
68 #define SLASH_SCSI_VHCI "/scsi_vhci"
69 #define META_DEV "/dev/md/dsk/"
70 #define SLASH_DEV_SLASH "/dev/"
73 * Macros to produce a quoted string containing the value of a
74 * preprocessor macro. For example, if SIZE is defined to be 256,
75 * VAL2STR(SIZE) is "256". This is used to construct format
76 * strings for scanf-family functions below.
79 #define VAL2STR(x) QUOTE(x)
107 begin
, parent
, drvname
, drvclass
, prop
,
108 parent_equals
, name_equals
, drvclass_equals
,
109 parent_equals_string
, name_equals_string
,
110 drvclass_equals_string
,
111 prop_equals
, prop_equals_string
, prop_equals_integer
,
112 prop_equals_string_comma
, prop_equals_integer_comma
115 /* structure to hold entries with mpxio-disable property in driver.conf file */
123 struct conf_entry
*next
;
132 static char *tok_err
= "Unexpected token '%s'\n";
139 int devfsmap_debug
= 0;
140 /* /var/run is not mounted at install time. Therefore use /tmp */
141 char *devfsmap_logfile
= "/tmp/devfsmap.log";
143 #define logdmsg(args) log_debug_msg args
144 static void vlog_debug_msg(char *, va_list);
145 static void log_debug_msg(char *, ...);
147 static void log_confent_list(char *, struct conf_entry
*, int);
148 static void log_pathlist(char **);
152 #define logdmsg(args) /* nothing */
157 * Leave NEWLINE as the next character.
164 while ((ch
= getc(fp
)) != EOF
) {
166 (void) ungetc(ch
, fp
);
172 /* ignore parsing errors */
175 file_err(struct conf_file
*filep
, char *fmt
, ...)
181 log_debug_msg("WARNING: %s line # %d: ",
182 filep
->filename
, filep
->linenum
);
183 vlog_debug_msg(fmt
, ap
);
188 /* return the next token from the given driver.conf file, or -1 on error */
190 lex(struct conf_file
*filep
, char *val
, size_t size
)
193 int ch
, oval
, badquote
;
196 FILE *fp
= filep
->fp
;
202 while ((ch
= getc(fp
)) == ' ' || ch
== '\t')
238 while ((ch
= getc(fp
)) == ' ' ||
239 ch
== '\t' || ch
== '\f') {
246 (void) ungetc(ch
, fp
);
247 token
= T_WHITE_SPACE
;
257 while (!badquote
&& (ch
= getc(fp
)) != '"') {
261 file_err(filep
, "Missing \"\n");
266 /* since we consumed the newline/EOF */
267 (void) ungetc(ch
, fp
);
277 /* escape the character */
282 while (ch
>= '0' && ch
<= '7') {
284 oval
= (oval
<< 3) + ch
;
287 (void) ungetc(ch
, fp
);
288 /* check for character overflow? */
292 "overflow detected.\n");
314 * detect a lone '-' (including at the end of a line), and
315 * identify it as a 'name'
322 *cp
++ = (char)(ch
= getc(fp
));
323 if (ch
== ' ' || ch
== '\t' || ch
== '\n') {
324 (void) ungetc(ch
, fp
);
330 } else if (ch
== '~' || ch
== '-') {
335 *cp
++ = (char)(ch
= getc(fp
));
341 if ((ch
= getc(fp
)) == 'x') {
348 while (isxdigit(ch
)) {
356 (void) ungetc(ch
, fp
);
364 while (isdigit(ch
)) {
372 (void) ungetc(ch
, fp
);
375 } else if (isalpha(ch
) || ch
== '\\') {
380 * if the character was a backslash,
381 * back up so we can overwrite it with
382 * the next (i.e. escaped) character.
387 while (isnamechar(ch
) || ch
== '\\') {
397 (void) ungetc(ch
, fp
);
413 free_confent(struct conf_entry
*confent
)
418 free(confent
->parent
);
420 free(confent
->class);
421 if (confent
->unit_address
)
422 free(confent
->unit_address
);
427 free_confent_list(struct conf_entry
*confent_list
)
429 struct conf_entry
*confent
, *next
;
431 for (confent
= confent_list
; confent
!= NULL
; confent
= next
) {
432 next
= confent
->next
;
433 free_confent(confent
);
438 * Parse the next entry from the driver.conf file and return in the form of
439 * a pointer to the conf_entry.
441 static struct conf_entry
*
442 parse_conf_entry(struct conf_file
*filep
, char *tokbuf
, size_t linesize
)
444 char *prop_name
, *string
;
446 struct conf_entry
*confent
;
450 if ((confent
= calloc(1, sizeof (*confent
))) == NULL
)
454 confent
->mpxio_disable
= -1;
464 case prop_equals_string
:
465 case prop_equals_integer
:
468 if ((prop_name
= strdup(tokbuf
)) == NULL
)
472 file_err(filep
, tok_err
, tokbuf
);
481 file_err(filep
, tok_err
, tokbuf
);
487 if ((string
= strdup(tokbuf
)) == NULL
)
491 if (strcmp(prop_name
, "PARENT") == 0 ||
492 strcmp(prop_name
, "parent") == 0) {
493 if (confent
->parent
) {
495 "'parent' property already specified\n");
498 confent
->parent
= string
;
499 } else if (strcmp(prop_name
, "NAME") == 0 ||
500 strcmp(prop_name
, "name") == 0) {
503 "'name' property already specified\n");
506 confent
->name
= string
;
507 } else if (strcmp(prop_name
, "CLASS") == 0 ||
508 strcmp(prop_name
, "class") == 0) {
509 if (confent
->class) {
511 "'class' property already specified\n");
514 confent
->class = string
;
515 } else if (strcmp(prop_name
, "unit-address")
517 if (confent
->unit_address
) {
519 "'unit-address' property already specified\n");
522 confent
->unit_address
= string
;
523 } else if (strcmp(prop_name
, "mpxio-disable")
525 if (confent
->mpxio_disable
!= -1) {
527 "'mpxio-disable' property already specified\n");
530 if (strcmp(string
, "yes") == 0)
531 confent
->mpxio_disable
= 1;
532 else if (strcmp(string
, "no") == 0)
533 confent
->mpxio_disable
= 0;
536 "'mpxio-disable' property setting is invalid. "
537 "The value must be either \"yes\" or \"no\"\n");
543 state
= prop_equals_string
;
550 case prop_equals_string_comma
:
551 state
= prop_equals_string
;
554 file_err(filep
, tok_err
, tokbuf
);
561 if (strcmp(prop_name
, "port") == 0) {
562 if (confent
->port
!= -1) {
564 "'port' property already specified\n");
568 (int)strtol(tokbuf
, NULL
, 0);
571 state
= prop_equals_integer
;
576 case prop_equals_integer_comma
:
577 state
= prop_equals_integer
;
580 file_err(filep
, tok_err
, tokbuf
);
585 case prop_equals_string
:
586 state
= prop_equals_string_comma
;
588 case prop_equals_integer
:
589 state
= prop_equals_integer_comma
;
592 file_err(filep
, tok_err
, tokbuf
);
602 file_err(filep
, "Unexpected EOF\n");
605 file_err(filep
, tok_err
, tokbuf
);
608 } while ((token
= lex(filep
, tokbuf
, linesize
)) != T_SEMICOLON
);
618 free_confent(confent
);
625 * Parse all entries with mpxio-disable property in the given driver.conf
628 * fname driver.conf file name
629 * confent_list on return *confent_list will contain the list of
630 * driver.conf file entries with mpxio-disable property.
631 * mpxio_disable on return *mpxio_disable is set to the setting of the
632 * driver global mpxio-dissable property as follows.
633 * 0 if driver mpxio-disable="no"
634 * 1 if driver mpxio-disable="yes"
635 * -1 if driver mpxio-disable property isn't specified.
638 parse_conf_file(char *fname
, struct conf_entry
**confent_list
,
641 struct conf_entry
*confent
, *tail
= NULL
;
643 struct conf_file file
;
644 char tokval
[MAX_TOKEN_SIZE
];
646 *confent_list
= NULL
;
648 if ((file
.fp
= fopen(fname
, "r")) == NULL
)
651 file
.filename
= fname
;
654 while ((token
= lex(&file
, tokval
, MAX_TOKEN_SIZE
)) != T_EOF
) {
663 if ((confent
= parse_conf_entry(&file
, tokval
,
664 MAX_TOKEN_SIZE
)) == NULL
)
667 * No name indicates global property.
668 * Make sure parent and class not NULL.
670 if (confent
->name
== NULL
) {
671 if (confent
->parent
||
674 "missing name attribute\n");
675 } else if (confent
->mpxio_disable
!= -1) {
676 if (*mpxio_disable
== -1)
678 confent
->mpxio_disable
;
681 "'mpxio-disable' property already specified\n");
683 free_confent(confent
);
688 * This is a node spec, either parent or class
691 if (confent
->parent
== NULL
&& confent
->class == NULL
) {
693 "missing parent or class attribute\n");
694 free_confent(confent
);
698 /* only need entries with mpxio_disable property */
699 if (confent
->mpxio_disable
== -1) {
700 free_confent(confent
);
705 tail
->next
= confent
;
707 *confent_list
= confent
;
719 (void) fclose(file
.fp
);
723 * Return the driver class of the given driver_name.
724 * The memory for the driver class is allocated by this function and the
725 * caller must free it.
728 get_driver_class(char *rootdir
, char *driver_name
)
732 char driver
[BUFSIZE
];
733 char class_name
[BUFSIZE
];
735 logdmsg(("get_driver_class: rootdir = %s, driver name = %s\n",
736 rootdir
, driver_name
));
738 (void) snprintf(buf
, sizeof (buf
), "%s%s", rootdir
, DRIVER_CLASSES
);
740 if ((fp
= fopen(buf
, "r")) == NULL
) {
741 logdmsg(("get_driver_class: failed to open %s: %s\n",
742 buf
, strerror(errno
)));
746 while (fgets(buf
, sizeof (buf
), fp
) != NULL
) {
747 /* LINTED - unbounded string specifier */
748 if ((sscanf(buf
, "%s %s", driver
, class_name
) == 2) &&
749 driver
[0] != '#' && strcmp(driver
, driver_name
) == 0) {
750 logdmsg(("get_driver_class: driver class = %s\n",
753 return (strdup(class_name
));
762 lookup_in_confent_list(struct conf_entry
*confent_list
,
763 int match_class
, char *parent
, char *unit_addr
, int port
)
765 struct conf_entry
*confent
;
768 logdmsg(("lookup_in_confent_list: %s = \"%s\", unit_addr = \"%s\", "
769 "port = %d\n", (match_class
) ? "class" : "parent", parent
,
770 STRVAL(unit_addr
), port
));
772 for (confent
= confent_list
; confent
!= NULL
; confent
= confent
->next
) {
773 par
= (match_class
) ? confent
->class : confent
->parent
;
775 if (confent
->unit_address
!= NULL
&&
776 strcmp(confent
->unit_address
, unit_addr
) == 0 &&
777 par
!= NULL
&& strcmp(par
, parent
) == 0)
778 return (confent
->mpxio_disable
);
780 if (confent
->port
== port
&&
781 par
!= NULL
&& strcmp(par
, parent
) == 0)
782 return (confent
->mpxio_disable
);
789 * lookup mpxio-disabled property setting for the given path in the given
790 * driver.conf file. Match the entries from most specific to least specific.
792 * conf_file the path name of either fp.conf, qlc.conf or scsi_vhci.conf
793 * path /devices node path without the /devices prefix.
794 * If the conf_file is fp.conf, path must be a fp node path
795 * if the conf_file is qlc.conf, path must be a qlc node path.
796 * if the conf_file is scsi_vhci.conf, path must be NULL.
797 * ex: /pci@8,600000/SUNW,qlc@4/fp@0,0
798 * /pci@8,600000/SUNW,qlc@4
801 * 0 if mpxio-disable="no"
802 * 1 if mpxio-disable="yes"
803 * -1 if mpxio-disable property isn't specified.
806 lookup_in_conf_file(char *rootdir
, char *conf_file
, char *path
)
808 struct conf_entry
*confent_list
= NULL
;
810 di_node_t par_node
= DI_NODE_NIL
;
811 char *node_name
= NULL
, *node_addr
= NULL
;
812 char *unit_addr
= NULL
;
814 char *par_node_name
= NULL
, *par_node_addr
= NULL
;
815 char *par_binding_name
= NULL
, *par_driver_name
= NULL
;
816 char *par_driver_class
= NULL
, *par_node_name_addr
;
818 char buf
[MAXPATHLEN
];
820 logdmsg(("lookup_in_conf_file: rootdir = \"%s\", conf_file = \"%s\", "
821 "path = \"%s\"\n", rootdir
, conf_file
, STRVAL(path
)));
823 (void) snprintf(buf
, MAXPATHLEN
, "%s%s", rootdir
, conf_file
);
824 parse_conf_file(buf
, &confent_list
, &mpxio_disable
);
826 log_confent_list(buf
, confent_list
, mpxio_disable
);
829 /* if path is NULL, return driver global mpxio-disable setting */
835 if ((node_name
= strrchr(path
, '/')) == NULL
)
841 if ((node_addr
= strchr(node_name
, '@')) == NULL
)
847 if (strcmp(node_name
, "fp") == 0) {
848 /* get port number; encoded in the node addr as a hex number */
849 port
= (int)strtol(node_addr
, NULL
, 16);
851 unit_addr
= node_addr
;
854 * Match from most specific to least specific;
855 * first, start the lookup based on full path.
857 if ((rv
= lookup_in_confent_list(confent_list
, 0, path
,
858 unit_addr
, port
)) != -1)
861 /* lookup nodename@address */
862 if ((par_node_name_addr
= strrchr(path
, '/')) != NULL
) {
863 par_node_name_addr
++;
864 if ((rv
= lookup_in_confent_list(confent_list
, 0,
865 par_node_name_addr
, unit_addr
, port
)) != -1)
869 /* di_init() doesn't work when 0 is passed in flags */
870 par_node
= di_init(path
, DINFOMINOR
);
871 if (par_node
!= DI_NODE_NIL
) {
872 par_node_name
= di_node_name(par_node
);
873 par_node_addr
= di_bus_addr(par_node
);
874 par_binding_name
= di_binding_name(par_node
);
875 par_driver_name
= di_driver_name(par_node
);
878 logdmsg(("par_node_name = %s\n", STRVAL(par_node_name
)));
879 logdmsg(("par_node_addr = %s\n", STRVAL(par_node_addr
)));
880 logdmsg(("par_binding_name = %s\n", STRVAL(par_binding_name
)));
881 logdmsg(("par_driver_name = %s\n", STRVAL(par_driver_name
)));
883 /* lookup bindingname@address */
884 if (par_binding_name
!= NULL
&& par_binding_name
!= par_node_name
&&
885 par_node_addr
!= NULL
) {
886 (void) snprintf(buf
, sizeof (buf
), "%s@%s", par_binding_name
,
888 if ((rv
= lookup_in_confent_list(confent_list
, 0,
889 buf
, unit_addr
, port
)) != -1)
893 /* lookup binding name */
894 if (par_binding_name
!= NULL
) {
895 if ((rv
= lookup_in_confent_list(confent_list
, 0,
896 par_binding_name
, unit_addr
, port
)) != -1)
900 if (par_driver_name
!= NULL
) {
901 /* lookup driver name */
902 if ((rv
= lookup_in_confent_list(confent_list
, 0,
903 par_driver_name
, unit_addr
, port
)) != -1)
906 /* finally, lookup class name */
907 par_driver_class
= get_driver_class(rootdir
, par_driver_name
);
908 if (par_driver_class
!= NULL
) {
909 if ((rv
= lookup_in_confent_list(confent_list
, 1,
910 par_driver_class
, unit_addr
, port
)) != -1)
917 * use the driver global mpxio-disable setting if exists.
922 if (node_name
!= NULL
)
923 *(node_name
- 1) = '/';
924 if (node_addr
!= NULL
)
925 *(node_addr
- 1) = '@';
926 if (par_driver_class
!= NULL
)
927 free(par_driver_class
);
928 if (confent_list
!= NULL
)
929 free_confent_list(confent_list
);
930 if (par_node
!= DI_NODE_NIL
)
937 * Given client_name return whether it is a phci or vhci based name.
938 * client_name is /devices name of a client without the /devices prefix.
940 * client_name Return value
941 * .../fp@xxx/ssd@yyy CLIENT_TYPE_PHCI
942 * .../scsi_vhci/ssd@yyy CLIENT_TYPE_VHCI
943 * other CLIENT_TYPE_UNKNOWN
946 client_name_type(char *client_name
)
948 client_type_t client_type
;
951 logdmsg(("client_name_type: client_name = %s\n", client_name
));
953 if (strncmp(client_name
, SLASH_SCSI_VHCI
,
954 sizeof (SLASH_SCSI_VHCI
) - 1) == 0)
955 return (CLIENT_TYPE_VHCI
);
957 if (*client_name
!= '/')
958 return (CLIENT_TYPE_UNKNOWN
);
960 if ((p1
= strrchr(client_name
, '/')) == NULL
)
961 return (CLIENT_TYPE_UNKNOWN
);
965 if ((p2
= strrchr(client_name
, '/')) != NULL
&&
966 strncmp(p2
, SLASH_FP_AT
, sizeof (SLASH_FP_AT
) - 1) == 0)
967 client_type
= CLIENT_TYPE_PHCI
;
969 client_type
= CLIENT_TYPE_UNKNOWN
;
972 return (client_type
);
976 * Compare controller name portion of dev1 and dev2.
978 * rootdir root directory of the target environment
979 * dev1 can be either a /dev link or /devices name in the target
981 * dev2 /devices name of a device without the /devices prefix
984 * 0 if controller names match
985 * 1 if controller names don't match
986 * -1 an error occurred.
989 compare_controller(char *rootdir
, char *dev1
, char *dev2
)
993 char physdev1
[MAXPATHLEN
];
994 char buf
[MAXPATHLEN
];
996 logdmsg(("compare_controller: rootdir = %s, dev1 = %s, dev2 = %s\n",
997 rootdir
, dev1
, dev2
));
999 if (strncmp(dev1
, SLASH_DEV_SLASH
, sizeof (SLASH_DEV_SLASH
) - 1)
1001 (void) snprintf(buf
, MAXPATHLEN
, "%s%s", rootdir
, dev1
);
1002 if ((linksize
= readlink(buf
, physdev1
, MAXPATHLEN
)) > 0 &&
1003 linksize
< (MAXPATHLEN
- 1)) {
1004 physdev1
[linksize
] = '\0';
1005 logdmsg(("compare_controller: physdev1 = %s\n",
1010 (void) strlcpy(physdev1
, dev1
, MAXPATHLEN
);
1012 if ((p1
= strstr(physdev1
, SLASH_DEVICES
)) == NULL
)
1015 p1
+= sizeof (SLASH_DEVICES
) - 1;
1016 /* strip the device portion */
1017 if ((p
= strrchr(p1
, '/')) == NULL
)
1021 if ((p
= strrchr(dev2
, '/')) == NULL
)
1025 logdmsg(("compare_controller: path1 = %s, path2 = %s\n",
1027 if (strcmp(p1
, dev2
) == 0) {
1037 * Check if the specified device path is on the root controller.
1039 * rootdir root directory of the target environment
1040 * path /devices name of a device without the /devices prefix
1043 * 1 if the path is on the root controller
1044 * 0 if the path is not on the root controller
1045 * -1 if an error occurs
1048 is_root_controller(char *rootdir
, char *path
)
1053 struct vfstab vfsent
;
1054 char buf
[MAXPATHLEN
];
1055 char ctd
[MAXNAMELEN
+ 1];
1057 logdmsg(("is_root_controller: rootdir = %s, path = %s\n", rootdir
,
1060 (void) snprintf(buf
, MAXPATHLEN
, "%s%s", rootdir
, VFSTAB
);
1062 if ((fp
= fopen(buf
, "r")) == NULL
) {
1063 logdmsg(("is_root_controller: failed to open %s: %s\n",
1064 buf
, strerror(errno
)));
1068 if (getvfsfile(fp
, &vfsent
, "/") != 0) {
1069 logdmsg(("is_root_controller: getvfsfile: failed to read "
1070 "vfstab entry for mount point \"/\": %s\n",
1077 /* check if the root is an svm metadisk */
1078 if (strncmp(vfsent
.vfs_special
, META_DEV
, sizeof (META_DEV
) - 1) != 0) {
1079 if (compare_controller(rootdir
, vfsent
.vfs_special
, path
) == 0)
1085 /* Don't use /var/run as it is not mounted in miniroot */
1086 if ((tmpfile
= tempnam("/tmp", "diirc")) == NULL
) {
1087 logdmsg(("is_root_controller: tempnam: failed: %s\n",
1092 /* get metadisk components using metastat command */
1093 (void) snprintf(buf
, MAXPATHLEN
,
1094 "/usr/sbin/metastat -p %s 2>/dev/null | "
1095 "/usr/bin/grep ' 1 1 ' | "
1096 "/usr/bin/sed -e 's/^.* 1 1 //' | "
1097 "/usr/bin/cut -f1 -d ' ' > %s",
1098 vfsent
.vfs_special
+ sizeof (META_DEV
) - 1, tmpfile
);
1100 logdmsg(("is_root_controller: command = %s\n", buf
));
1102 if (system(buf
) == 0 && (fp
= fopen(tmpfile
, "r")) != NULL
) {
1103 while (fscanf(fp
, "%" VAL2STR(MAXNAMELEN
) "s", ctd
) == 1) {
1104 (void) snprintf(buf
, MAXPATHLEN
, "/dev/dsk/%s", ctd
);
1105 if (compare_controller(rootdir
, buf
, path
) == 0) {
1116 (void) unlink(tmpfile
);
1122 file_exists(char *rootdir
, char *path
)
1125 char fullpath
[MAXPATHLEN
];
1128 (void) snprintf(fullpath
, MAXPATHLEN
, "%s%s", rootdir
, path
);
1130 x
= stat(fullpath
, &stbuf
);
1131 logdmsg(("file_exists: %s: %s\n", fullpath
, (x
== 0) ? "yes" : "no"));
1139 * Check if mpxio is enabled or disabled on the specified device path.
1140 * Looks through the .conf files to determine the mpxio setting.
1142 * rootdir root directory of the target environment
1143 * path /devices name of a device without the /devices prefix and
1144 * minor name component.
1147 * 1 if mpxio is disabled
1148 * 0 if mpxio is enabled
1149 * -1 if an error occurs
1152 is_mpxio_disabled(char *rootdir
, char *path
)
1156 int check_root_controller
;
1158 logdmsg(("is_mpxio_disabled: rootdir = %s, path = %s\n",
1161 if (file_exists(rootdir
, SCSI_VHCI_CONF
) == 0) {
1163 * scsi_vhci.conf doesn't exist:
1164 * if upgrading from a pre solaris 9 release. or
1165 * if this function is called during fresh or flash install
1166 * prior to installing scsi_vhci.conf file.
1168 if (file_exists(rootdir
, "/kernel/drv"))
1169 /* upgrading from pre solaris 9 */
1172 /* fresh or flash install */
1176 mpxio_disable
= lookup_in_conf_file(rootdir
, SCSI_VHCI_CONF
, NULL
);
1179 * scsi_vhci.conf contains mpxio-disable property only in s9 and
1180 * s8+sfkpatch. This property is no longer present from s10 onwards.
1182 if (mpxio_disable
== 1) {
1183 /* upgrading from s8 or s9 with mpxio globally disabled */
1185 } else if (mpxio_disable
== 0) {
1186 /* upgrading from s8 or s9 with mpxio globally enabled */
1187 check_root_controller
= 1;
1190 * We are looking at the s10 version of the file. This is
1191 * the case if this function is called after installing the
1192 * new scsi_vhci.conf file.
1194 check_root_controller
= 0;
1197 if ((mpxio_disable
= lookup_in_conf_file(rootdir
, FP_CONF
, path
))
1199 return (mpxio_disable
);
1201 if ((p
= strrchr(path
, '/')) == NULL
)
1205 if ((mpxio_disable
= lookup_in_conf_file(rootdir
, QLC_CONF
, path
))
1208 return (mpxio_disable
);
1213 * mpxio-disable setting is not found in the .conf files.
1214 * The default is to enable mpxio, except if the path is on the root
1217 * In s8 and s9 mpxio is not supported on the root controller.
1218 * NWS supplies a patch to enable root controller support in s8 and s9.
1219 * If the system had the patch installed, the fp.conf file would have
1220 * explicit "mpxio-disable=no" for the root controller. So we would
1221 * have found the mpxio-disable setting when we looked up this property
1222 * in the fp.conf file.
1224 if (check_root_controller
) {
1225 mpxio_disable
= is_root_controller(rootdir
, path
);
1226 logdmsg(("is_mpxio_disabled: is_root_controller returned %d\n",
1231 return (mpxio_disable
);
1235 vhci_ctl(sv_iocdata_t
*iocp
, int cmd
)
1239 if ((fd
= open(VHCI_CTL_NODE
, O_RDWR
)) < 0)
1241 rv
= ioctl(fd
, cmd
, iocp
);
1247 * Convert a phci client name to vhci client name.
1249 * phci_name phci client /devices name without the /devices prefix and
1250 * minor name component.
1251 * ex: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
1253 * Returns on success, vhci client name is returned. The memory for
1254 * the vhci name is allocated by this function and the caller
1256 * on failure, NULL is returned.
1259 phci_to_vhci(char *phci_name
)
1262 char *slash
, *addr
, *retp
;
1263 char vhci_name_buf
[MAXPATHLEN
];
1264 char phci_name_buf
[MAXPATHLEN
];
1265 char addr_buf
[MAXNAMELEN
];
1267 logdmsg(("phci_to_vhci: pchi_name = %s\n", phci_name
));
1268 (void) strlcpy(phci_name_buf
, phci_name
, MAXPATHLEN
);
1270 if ((slash
= strrchr(phci_name_buf
, '/')) == NULL
||
1271 (addr
= strchr(slash
, '@')) == NULL
)
1276 (void) strlcpy(addr_buf
, addr
, MAXNAMELEN
);
1278 bzero(&ioc
, sizeof (sv_iocdata_t
));
1279 ioc
.client
= vhci_name_buf
;
1280 ioc
.phci
= phci_name_buf
;
1281 ioc
.addr
= addr_buf
;
1282 if (vhci_ctl(&ioc
, SCSI_VHCI_GET_CLIENT_NAME
) != 0) {
1283 logdmsg(("phci_to_vhci: vhci_ctl failed: %s\n",
1288 retp
= strdup(vhci_name_buf
);
1289 logdmsg(("phci_to_vhci: vhci name = %s\n", STRVAL(retp
)));
1294 add_to_phci_list(char **phci_list
, sv_path_info_t
*pi
, int npaths
, int state
,
1298 char name
[MAXPATHLEN
];
1301 if (state
== pi
->ret_state
) {
1302 (void) snprintf(name
, MAXPATHLEN
, "%s/%s@%s",
1303 pi
->device
.ret_phci
, node_name
, pi
->ret_addr
);
1304 if ((*phci_list
= strdup(name
)) == NULL
)
1316 free_pathlist(char **pathlist
)
1320 if (pathlist
!= NULL
) {
1321 for (p
= pathlist
; *p
!= NULL
; p
++)
1329 * Convert a vhci client name to phci client names.
1331 * vhci_name vhci client /devices name without the /devices prefix and
1332 * minor name component.
1333 * num_paths On return, *num_paths is set to the number paths in the
1334 * returned path list.
1336 * Returns NULL terminated path list containing phci client paths is
1337 * returned on success. The memory for the path list is
1338 * allocated by this function and the caller must free it by
1339 * calling free_pathlist().
1340 * NULL is returned on failure.
1343 vhci_to_phci(char *vhci_name
, int *num_paths
)
1348 char **phci_list
= NULL
;
1349 char *node_name
, *at
;
1350 char vhci_name_buf
[MAXPATHLEN
];
1352 logdmsg(("vhci_to_phci: vchi_name = %s\n", vhci_name
));
1355 (void) strlcpy(vhci_name_buf
, vhci_name
, MAXPATHLEN
);
1357 /* first get the number paths */
1358 bzero(&ioc
, sizeof (sv_iocdata_t
));
1359 ioc
.client
= vhci_name_buf
;
1360 ioc
.ret_elem
= &npaths
;
1361 if (vhci_ctl(&ioc
, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO
) != 0 ||
1363 logdmsg(("vhci_to_phci: vhci_ctl failed to get npaths: %s\n",
1368 /* now allocate memory for the path information and get all paths */
1369 bzero(&ioc
, sizeof (sv_iocdata_t
));
1370 ioc
.client
= vhci_name_buf
;
1371 ioc
.buf_elem
= npaths
;
1372 ioc
.ret_elem
= &npaths
;
1373 if ((ioc
.ret_buf
= (sv_path_info_t
*)calloc(npaths
,
1374 sizeof (sv_path_info_t
))) == NULL
)
1376 if (vhci_ctl(&ioc
, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO
) != 0 ||
1378 logdmsg(("vhci_to_phci: vhci_ctl failed: %s\n",
1383 if (ioc
.buf_elem
< npaths
)
1384 npaths
= ioc
.buf_elem
;
1386 if ((node_name
= strrchr(vhci_name_buf
, '/')) == NULL
||
1387 (at
= strchr(node_name
, '@')) == NULL
)
1393 /* allocate one more (than npaths) for the terminating NULL pointer */
1394 if ((phci_list
= calloc(npaths
+ 1, sizeof (char *))) == NULL
)
1398 * add only online paths as non-online paths may not be accessible
1399 * in the target environment.
1401 if ((n
= add_to_phci_list(phci_list
, ioc
.ret_buf
, npaths
,
1402 MDI_PATHINFO_STATE_ONLINE
, node_name
)) <= 0)
1409 logdmsg(("vhci_to_phci: phci list:\n"));
1410 log_pathlist(phci_list
);
1417 free_pathlist(phci_list
);
1422 * build list of paths accessible from the target environment
1425 build_pathlist(char *rootdir
, char *vhcipath
, char **pathlist
, int npaths
)
1431 for (i
= 0; i
< npaths
; i
++) {
1432 mpxio_disabled
= is_mpxio_disabled(rootdir
, pathlist
[i
]);
1433 logdmsg(("build_pathlist: mpxio_disabled = %d "
1434 "on path %s\n", mpxio_disabled
, pathlist
[i
]));
1435 if (mpxio_disabled
== -1)
1437 if (mpxio_disabled
== 0) {
1439 * mpxio is enabled on this phci path.
1440 * So use vhci path instead of phci path.
1442 if (vpath
== NULL
) {
1443 if ((vpath
= strdup(vhcipath
)) == NULL
)
1446 /* keep vhci path at beginning of the list */
1447 for (j
= i
; j
> 0; j
--)
1448 pathlist
[j
] = pathlist
[j
- 1];
1449 pathlist
[0] = vpath
;
1453 for (j
= i
; j
< npaths
; j
++)
1454 pathlist
[j
] = pathlist
[j
+ 1];
1455 pathlist
[npaths
] = NULL
;
1456 /* compensate for i++ in the for loop */
1463 logdmsg(("build_pathlist: returning npaths = %d, pathlist:\n", npaths
));
1464 log_pathlist(pathlist
);
1470 * Check if the specified device is refenced in the vfstab file.
1471 * Return 1 if referenced, 0 if not.
1473 * rootdir root directory of the target environment
1474 * nodepath /devices path of a device in the target environment without
1475 * the /devices prefix and minor component.
1478 is_dev_in_vfstab(char *rootdir
, char *nodepath
)
1482 struct vfstab vfsent
;
1483 char *abspath
, *minor
;
1484 char physpath
[MAXPATHLEN
];
1485 char buf
[MAXPATHLEN
];
1487 logdmsg(("is_dev_in_vfstab: rootdir = %s, nodepath = %s\n",
1488 rootdir
, nodepath
));
1490 (void) snprintf(buf
, sizeof (buf
), "%s%s", rootdir
, VFSTAB
);
1492 if ((fp
= fopen(buf
, "r")) == NULL
)
1496 * read device specials from vfstab and compare names at physical
1499 while (getvfsent(fp
, &vfsent
) == 0) {
1500 if (strncmp(vfsent
.vfs_special
, SLASH_DEV_SLASH
,
1501 sizeof (SLASH_DEV_SLASH
) - 1) == 0) {
1502 (void) snprintf(buf
, MAXPATHLEN
, "%s%s",
1503 rootdir
, vfsent
.vfs_special
);
1504 if ((linksize
= readlink(buf
, physpath
,
1505 MAXPATHLEN
)) > 0 && linksize
< (MAXPATHLEN
- 1)) {
1506 physpath
[linksize
] = '\0';
1507 if ((abspath
= strstr(physpath
,
1508 SLASH_DEVICES_SLASH
)) == NULL
)
1512 } else if (strncmp(vfsent
.vfs_special
, SLASH_DEVICES_SLASH
,
1513 sizeof (SLASH_DEVICES_SLASH
) - 1) == 0) {
1514 (void) strlcpy(physpath
, vfsent
.vfs_special
,
1520 /* point to / after /devices */
1521 abspath
+= sizeof (SLASH_DEVICES_SLASH
) - 2;
1522 /* strip minor component */
1523 if ((minor
= strrchr(abspath
, ':')) != NULL
)
1526 if (strcmp(nodepath
, abspath
) == 0) {
1528 logdmsg(("is_dev_in_vfstab: returning 1\n"));
1537 #endif /* __sparc */
1540 devlink_callback(di_devlink_t devlink
, void *argp
)
1544 if ((link
= di_devlink_path(devlink
)) != NULL
)
1545 (void) strlcpy((char *)argp
, link
, MAXPATHLEN
);
1547 return (DI_WALK_CONTINUE
);
1551 * Get the /dev name in the install environment corresponding to physpath.
1553 * physpath /devices path in the install environment without the /devices
1555 * buf caller supplied buffer where the /dev name is placed on return
1556 * bufsz length of the buffer
1558 * Returns strlen of the /dev name on success, -1 on failure.
1561 get_install_devlink(char *physpath
, char *buf
, size_t bufsz
)
1563 di_devlink_handle_t devlink_hdl
;
1564 char devname
[MAXPATHLEN
];
1566 int sleeptime
= 2; /* number of seconds to sleep between retries */
1567 int maxtries
= 10; /* maximum number of tries */
1569 logdmsg(("get_install_devlink: physpath = %s\n", physpath
));
1572 * devlink_db sync happens after MINOR_FINI_TIMEOUT_DEFAULT secs
1573 * after dev link creation. So wait for minimum that amout of time.
1577 (void) sleep(sleeptime
);
1579 if ((devlink_hdl
= di_devlink_init(NULL
, 0)) == NULL
) {
1580 logdmsg(("get_install_devlink: di_devlink_init() failed: %s\n",
1586 if (di_devlink_walk(devlink_hdl
, NULL
, physpath
, DI_PRIMARY_LINK
,
1587 devname
, devlink_callback
) == 0) {
1588 if (devname
[0] == '\0' && tries
< maxtries
) {
1590 (void) di_devlink_fini(&devlink_hdl
);
1592 } else if (devname
[0] == '\0') {
1593 logdmsg(("get_install_devlink: di_devlink_walk"
1594 " failed: %s\n", strerror(errno
)));
1595 (void) di_devlink_fini(&devlink_hdl
);
1599 logdmsg(("get_install_devlink: di_devlink_walk failed: %s\n",
1601 (void) di_devlink_fini(&devlink_hdl
);
1605 (void) di_devlink_fini(&devlink_hdl
);
1607 logdmsg(("get_install_devlink: devlink = %s\n", devname
));
1608 return (strlcpy(buf
, devname
, bufsz
));
1612 * Get the /dev name in the target environment corresponding to physpath.
1614 * rootdir root directory of the target environment
1615 * physpath /devices path in the target environment without the /devices
1617 * buf caller supplied buffer where the /dev name is placed on return
1618 * bufsz length of the buffer
1620 * Returns strlen of the /dev name on success, -1 on failure.
1623 get_target_devlink(char *rootdir
, char *physpath
, char *buf
, size_t bufsz
)
1628 struct dirent
*direntry
;
1629 char dirpath
[MAXPATHLEN
];
1630 char devname
[MAXPATHLEN
];
1631 char physdev
[MAXPATHLEN
];
1633 logdmsg(("get_target_devlink: rootdir = %s, physpath = %s\n",
1634 rootdir
, physpath
));
1636 if ((p
= strrchr(physpath
, '/')) == NULL
)
1639 if (strstr(p
, ",raw") != NULL
) {
1640 (void) snprintf(dirpath
, MAXPATHLEN
, "%s/dev/rdsk", rootdir
);
1642 (void) snprintf(dirpath
, MAXPATHLEN
, "%s/dev/dsk", rootdir
);
1645 if ((dirp
= opendir(dirpath
)) == NULL
)
1648 while ((direntry
= readdir(dirp
)) != NULL
) {
1649 if (strcmp(direntry
->d_name
, ".") == 0 ||
1650 strcmp(direntry
->d_name
, "..") == 0)
1653 (void) snprintf(devname
, MAXPATHLEN
, "%s/%s",
1654 dirpath
, direntry
->d_name
);
1656 if ((linksize
= readlink(devname
, physdev
, MAXPATHLEN
)) > 0 &&
1657 linksize
< (MAXPATHLEN
- 1)) {
1658 physdev
[linksize
] = '\0';
1659 if ((p
= strstr(physdev
, SLASH_DEVICES_SLASH
)) !=
1660 NULL
&& strcmp(p
+ sizeof (SLASH_DEVICES
) - 1,
1662 (void) closedir(dirp
);
1663 logdmsg(("get_target_devlink: devlink = %s\n",
1664 devname
+ strlen(rootdir
)));
1665 return (strlcpy(buf
, devname
+ strlen(rootdir
),
1671 (void) closedir(dirp
);
1676 * Convert device name to physpath.
1678 * rootdir root directory
1679 * devname a /dev name or /devices name under rootdir
1680 * physpath caller supplied buffer where the /devices path will be placed
1681 * on return (without the /devices prefix).
1682 * physpathlen length of the physpath buffer
1684 * Returns 0 on success, -1 on failure.
1687 devname2physpath(char *rootdir
, char *devname
, char *physpath
, int physpathlen
)
1691 char devlink
[MAXPATHLEN
];
1692 char tmpphyspath
[MAXPATHLEN
];
1694 logdmsg(("devname2physpath: rootdir = %s, devname = %s\n",
1697 if (strncmp(devname
, SLASH_DEVICES_SLASH
,
1698 sizeof (SLASH_DEVICES_SLASH
) - 1) != 0) {
1699 if (*rootdir
== '\0')
1700 linksize
= readlink(devname
, tmpphyspath
, MAXPATHLEN
);
1702 (void) snprintf(devlink
, MAXPATHLEN
, "%s%s",
1704 linksize
= readlink(devlink
, tmpphyspath
, MAXPATHLEN
);
1706 if (linksize
> 0 && linksize
< (MAXPATHLEN
- 1)) {
1707 tmpphyspath
[linksize
] = '\0';
1708 if ((p
= strstr(tmpphyspath
, SLASH_DEVICES_SLASH
))
1716 (void) strlcpy(physpath
, p
+ sizeof (SLASH_DEVICES
) - 1, physpathlen
);
1717 logdmsg(("devname2physpath: physpath = %s\n", physpath
));
1722 * Map a device name (devname) from the target environment to the
1723 * install environment.
1725 * rootdir root directory of the target environment
1726 * devname /dev or /devices name under the target environment
1727 * buf caller supplied buffer where the mapped /dev name is placed
1729 * bufsz length of the buffer
1731 * Returns strlen of the mapped /dev name on success, -1 on failure.
1734 devfs_target2install(const char *rootdir
, const char *devname
, char *buf
,
1737 char physpath
[MAXPATHLEN
];
1739 logdmsg(("devfs_target2install: rootdir = %s, devname = %s\n",
1740 STRVAL(rootdir
), STRVAL(devname
)));
1742 if (rootdir
== NULL
|| devname
== NULL
|| buf
== NULL
|| bufsz
== 0)
1745 if (strcmp(rootdir
, "/") == 0)
1748 if (devname2physpath((char *)rootdir
, (char *)devname
, physpath
,
1753 if (client_name_type(physpath
) == CLIENT_TYPE_PHCI
) {
1754 char *mapped_node_path
, *minor
;
1755 char minorbuf
[MAXNAMELEN
];
1757 /* strip minor component if present */
1758 if ((minor
= strrchr(physpath
, ':')) != NULL
) {
1761 (void) strlcpy(minorbuf
, minor
, MAXNAMELEN
);
1763 if ((mapped_node_path
= phci_to_vhci(physpath
)) != NULL
) {
1765 (void) snprintf(physpath
, MAXPATHLEN
,
1766 "%s:%s", mapped_node_path
, minorbuf
);
1768 (void) strlcpy(physpath
, mapped_node_path
,
1770 free(mapped_node_path
);
1771 logdmsg(("devfs_target2install: mapped physpath: %s\n",
1777 #endif /* __sparc */
1779 return (get_install_devlink(physpath
, buf
, bufsz
));
1783 * Map a device name (devname) from the install environment to the target
1786 * rootdir root directory of the target environment
1787 * devname /dev or /devices name under the install environment
1788 * buf caller supplied buffer where the mapped /dev name is placed
1790 * bufsz length of the buffer
1792 * Returns strlen of the mapped /dev name on success, -1 on failure.
1795 devfs_install2target(const char *rootdir
, const char *devname
, char *buf
,
1798 char physpath
[MAXPATHLEN
];
1800 logdmsg(("devfs_install2target: rootdir = %s, devname = %s\n",
1801 STRVAL(rootdir
), STRVAL(devname
)));
1803 if (rootdir
== NULL
|| devname
== NULL
|| buf
== NULL
|| bufsz
== 0)
1806 if (strcmp(rootdir
, "/") == 0)
1809 if (devname2physpath("", (char *)devname
, physpath
, MAXPATHLEN
) != 0)
1813 if (client_name_type(physpath
) == CLIENT_TYPE_VHCI
) {
1817 char minorbuf
[MAXNAMELEN
];
1819 /* strip minor component if present */
1820 if ((minor
= strrchr(physpath
, ':')) != NULL
) {
1823 (void) strlcpy(minorbuf
, minor
, MAXNAMELEN
);
1826 if ((pathlist
= vhci_to_phci(physpath
, &npaths
)) == NULL
)
1829 if ((npaths
= build_pathlist((char *)rootdir
, physpath
,
1830 pathlist
, npaths
)) <= 0) {
1831 free_pathlist(pathlist
);
1836 * in case of more than one path, try to use the path
1837 * referenced in the vfstab file, otherwise use the first path.
1841 for (i
= 0; i
< npaths
; i
++) {
1842 if (is_dev_in_vfstab((char *)rootdir
,
1851 (void) snprintf(physpath
, MAXPATHLEN
,
1852 "%s:%s", pathlist
[j
], minorbuf
);
1854 (void) strlcpy(physpath
, pathlist
[j
], MAXPATHLEN
);
1855 free_pathlist(pathlist
);
1857 #endif /* __sparc */
1859 return (get_target_devlink((char *)rootdir
, physpath
, buf
, bufsz
));
1863 * A parser for /etc/path_to_inst.
1864 * The user-supplied callback is called once for each entry in the file.
1865 * Returns 0 on success, ENOMEM/ENOENT/EINVAL on error.
1866 * Callback may return DI_WALK_TERMINATE to terminate the walk,
1867 * otherwise DI_WALK_CONTINUE.
1870 devfs_parse_binding_file(const char *binding_file
,
1871 int (*callback
)(void *, const char *, int,
1872 const char *), void *cb_arg
)
1875 struct conf_file file
;
1876 char tokval
[MAX_TOKEN_SIZE
];
1877 enum { STATE_RESET
, STATE_DEVPATH
, STATE_INSTVAL
} state
;
1883 if ((devpath
= calloc(1, MAXPATHLEN
)) == NULL
)
1885 if ((bindname
= calloc(1, MAX_TOKEN_SIZE
)) == NULL
) {
1890 if ((file
.fp
= fopen(binding_file
, "r")) == NULL
) {
1896 file
.filename
= (char *)binding_file
;
1899 state
= STATE_RESET
;
1900 while ((token
= lex(&file
, tokval
, MAX_TOKEN_SIZE
)) != T_EOF
) {
1912 if (strlcpy(devpath
, tokval
,
1913 MAXPATHLEN
) >= MAXPATHLEN
)
1915 state
= STATE_DEVPATH
;
1918 if (strlcpy(bindname
, tokval
,
1919 MAX_TOKEN_SIZE
) >= MAX_TOKEN_SIZE
)
1921 rv
= callback(cb_arg
,
1922 devpath
, instval
, bindname
);
1923 if (rv
== DI_WALK_TERMINATE
)
1925 if (rv
!= DI_WALK_CONTINUE
)
1927 state
= STATE_RESET
;
1930 file_err(&file
, tok_err
, tokval
);
1931 state
= STATE_RESET
;
1939 instval
= (int)strtol(tokval
, NULL
, 0);
1940 state
= STATE_INSTVAL
;
1943 file_err(&file
, tok_err
, tokval
);
1944 state
= STATE_RESET
;
1950 state
= STATE_RESET
;
1953 file_err(&file
, tok_err
, tokval
);
1954 state
= STATE_RESET
;
1960 (void) fclose(file
.fp
);
1966 (void) fclose(file
.fp
);
1973 * Walk the minor nodes of all children below the specified device
1974 * by calling the provided callback with the path to each minor.
1977 devfs_walk_children_minors(const char *device_path
, struct stat
*st
,
1978 int (*callback
)(void *, const char *), void *cb_arg
, int *terminate
)
1982 char *minor_path
= NULL
;
1986 if ((minor_path
= calloc(1, MAXPATHLEN
)) == NULL
)
1989 if ((dir
= opendir(device_path
)) == NULL
) {
1995 while ((dp
= readdir(dir
)) != NULL
) {
1996 if ((strcmp(dp
->d_name
, ".") == 0) ||
1997 (strcmp(dp
->d_name
, "..") == 0))
1999 (void) snprintf(minor_path
, MAXPATHLEN
,
2000 "%s/%s", device_path
, dp
->d_name
);
2001 if (stat(minor_path
, st
) == -1)
2003 if (S_ISDIR(st
->st_mode
)) {
2004 rv
= devfs_walk_children_minors(
2005 (const char *)minor_path
, st
,
2006 callback
, cb_arg
, terminate
);
2012 rv
= callback(cb_arg
, minor_path
);
2013 if (rv
== DI_WALK_TERMINATE
) {
2017 if (rv
!= DI_WALK_CONTINUE
) {
2027 (void) closedir(dir
);
2034 * Return the path to each minor node for a device by
2035 * calling the provided callback.
2038 devfs_walk_device_minors(const char *device_path
, struct stat
*st
,
2039 int (*callback
)(void *, const char *), void *cb_arg
, int *terminate
)
2045 int need_regfree
= 0;
2052 minor_path
= calloc(1, MAXPATHLEN
);
2053 devpath
= calloc(1, MAXPATHLEN
);
2054 expr
= calloc(1, MAXNAMELEN
);
2055 if (devpath
== NULL
|| expr
== NULL
|| minor_path
== NULL
) {
2061 if (strlcpy(devpath
, device_path
, MAXPATHLEN
) >= MAXPATHLEN
)
2063 if ((p
= strrchr(devpath
, '/')) == NULL
)
2068 if (snprintf(expr
, MAXNAMELEN
, "%s:.*", p
) >= MAXNAMELEN
)
2070 if (regcomp(®ex
, expr
, REG_EXTENDED
) != 0)
2074 if ((dir
= opendir(devpath
)) == NULL
) {
2080 while ((dp
= readdir(dir
)) != NULL
) {
2081 if ((strcmp(dp
->d_name
, ".") == 0) ||
2082 (strcmp(dp
->d_name
, "..") == 0))
2084 (void) snprintf(minor_path
, MAXPATHLEN
,
2085 "%s/%s", devpath
, dp
->d_name
);
2086 if (stat(minor_path
, st
) == -1)
2088 if ((S_ISBLK(st
->st_mode
) || S_ISCHR(st
->st_mode
)) &&
2089 regexec(®ex
, dp
->d_name
, 0, NULL
, 0) == 0) {
2090 rv
= callback(cb_arg
, minor_path
);
2091 if (rv
== DI_WALK_TERMINATE
) {
2095 if (rv
!= DI_WALK_CONTINUE
) {
2105 (void) closedir(dir
);
2118 * Perform a walk of all minor nodes for the specified device,
2119 * and minor nodes below the device.
2122 devfs_walk_minor_nodes(const char *device_path
,
2123 int (*callback
)(void *, const char *), void *cb_arg
)
2129 rv
= devfs_walk_device_minors(device_path
,
2130 &stbuf
, callback
, cb_arg
, &terminate
);
2131 if (rv
== 0 && terminate
== 0) {
2132 rv
= devfs_walk_children_minors(device_path
,
2133 &stbuf
, callback
, cb_arg
, &terminate
);
2141 vlog_debug_msg(char *fmt
, va_list ap
)
2146 if (!devfsmap_debug
)
2149 if (logfp
== NULL
) {
2150 if (*devfsmap_logfile
!= '\0') {
2151 logfp
= fopen(devfsmap_logfile
, "a");
2153 (void) fprintf(logfp
, "\nNew Log:\n");
2161 (void) localtime_r(&clock
, &t
);
2162 (void) fprintf(logfp
, "%02d:%02d:%02d ", t
.tm_hour
, t
.tm_min
,
2164 (void) vfprintf(logfp
, fmt
, ap
);
2165 (void) fflush(logfp
);
2169 log_debug_msg(char *fmt
, ...)
2174 vlog_debug_msg(fmt
, ap
);
2181 mpxio_disable_string(int mpxio_disable
)
2183 if (mpxio_disable
== 0)
2185 else if (mpxio_disable
== 1)
2188 return ("not specified");
2192 log_confent_list(char *filename
, struct conf_entry
*confent_list
,
2193 int global_mpxio_disable
)
2195 struct conf_entry
*confent
;
2197 log_debug_msg("log_confent_list: filename = %s:\n", filename
);
2198 if (global_mpxio_disable
!= -1)
2199 log_debug_msg("\tdriver global mpxio_disable = \"%s\"\n\n",
2200 mpxio_disable_string(global_mpxio_disable
));
2202 for (confent
= confent_list
; confent
!= NULL
; confent
= confent
->next
) {
2204 log_debug_msg("\tname = %s\n", confent
->name
);
2205 if (confent
->parent
)
2206 log_debug_msg("\tparent = %s\n", confent
->parent
);
2208 log_debug_msg("\tclass = %s\n", confent
->class);
2209 if (confent
->unit_address
)
2210 log_debug_msg("\tunit_address = %s\n",
2211 confent
->unit_address
);
2212 if (confent
->port
!= -1)
2213 log_debug_msg("\tport = %d\n", confent
->port
);
2214 log_debug_msg("\tmpxio_disable = \"%s\"\n\n",
2215 mpxio_disable_string(confent
->mpxio_disable
));
2220 log_pathlist(char **pathlist
)
2224 for (p
= pathlist
; *p
!= NULL
; p
++)
2225 log_debug_msg("\t%s\n", *p
);
2228 #endif /* __sparc */