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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
34 #include <sys/types.h>
38 #include <sys/modctl.h>
40 #include <sys/openpromio.h>
43 #include <sys/sunddi.h>
46 #include "device_info.h"
52 /* alias node searching return values */
55 #define INEXACT_MATCH 2
57 /* for prom io operations */
59 #define MAXPROPSIZE 256
60 #define MAXVALSIZE (BUFSIZE - MAXPROPSIZE - sizeof (uint_t))
62 /* prom_obp_vers() return values */
63 #define OBP_OF 0x4 /* versions OBP 3.x */
64 #define OBP_NO_ALIAS_NODE 0x8 /* No alias node */
69 /* default logical and physical device name space */
71 #define DEVICES "/devices"
74 * internal structure declarations
77 /* for prom io functions */
80 struct openpromio opp
;
83 /* used to manage lists of devices and aliases */
86 struct name_list
*next
;
90 * internal global data
93 /* global since nftw does not let you pass args to be updated */
94 static struct name_list
**dev_list
;
96 /* global since nftw does not let you pass args to be updated */
97 static struct boot_dev
**bootdev_list
;
99 /* mutex to protect bootdev_list and dev_list */
100 static mutex_t dev_lists_lk
= DEFAULTMUTEX
;
103 * internal function prototypes
106 static int prom_open(int);
107 static void prom_close(int);
108 static int is_openprom(int);
110 static int prom_dev_to_alias(char *dev
, uint_t options
, char ***ret_buf
);
111 static int alias_to_prom_dev(char *alias
, char *ret_buf
);
112 static int prom_srch_aliases_by_def(char *, struct name_list
**,
113 struct name_list
**, int);
114 static int prom_find_aliases_node(int fd
);
115 static int prom_compare_devs(char *prom_dev1
, char *prom_dev2
);
116 static int _prom_strcmp(char *s1
, char *s2
);
117 static int prom_srch_node(int fd
, char *prop_name
, char *ret_buf
);
118 static uint_t
prom_next_node(int fd
, uint_t node_id
);
119 static uint_t
prom_child_node(int fd
, uint_t node_id
);
121 static int prom_obp_vers(void);
123 static void parse_name(char *, char **, char **, char **);
124 static int process_bootdev(const char *, const char *, struct boot_dev
***);
125 static int process_minor_name(char *dev_path
, const char *default_root
);
126 static void options_override(char *prom_path
, char *alias_name
);
127 static int devfs_phys_to_logical(struct boot_dev
**bootdev_array
,
128 const int array_size
, const char *default_root
);
129 static int check_logical_dev(const char *, const struct stat
*, int,
131 static struct boot_dev
*alloc_bootdev(char *);
132 static void free_name_list(struct name_list
*list
, int free_name
);
133 static int insert_alias_list(struct name_list
**list
,
135 static int get_boot_dev_var(struct openpromio
*opp
);
136 static int set_boot_dev_var(struct openpromio
*opp
, char *bootdev
);
137 static int devfs_prom_to_dev_name(char *prom_path
, char *dev_path
);
138 static int devfs_dev_to_prom_names(char *dev_path
, char *prom_path
, size_t len
);
141 * frees a list of paths from devfs_get_prom_name_list
144 prom_list_free(char **prom_list
)
151 while (prom_list
[i
]) {
159 devfs_get_prom_name_list(const char *dev_name
, char ***prom_list
)
161 char *prom_path
= NULL
;
162 int count
= 0; /* # of slots we will need in prom_list */
167 if (dev_name
== NULL
)
168 return (DEVFS_INVAL
);
169 if (*dev_name
!= '/')
170 return (DEVFS_INVAL
);
171 if (prom_list
== NULL
)
172 return (DEVFS_INVAL
);
175 * make sure we are on a machine which supports a prom
176 * and we have permission to use /dev/openprom
178 if ((ret
= prom_obp_vers()) < 0)
180 if ((prom_path
= (char *)malloc(MAXVALSIZE
)) == NULL
)
181 return (DEVFS_NOMEM
);
183 * get the prom path name
185 ret
= devfs_dev_to_prom_names((char *)dev_name
, prom_path
, MAXVALSIZE
);
190 /* deal with list of names */
191 for (i
= 0; i
< ret
; i
++)
192 if (prom_path
[i
] == '\0')
195 if ((list
= (char **)calloc(count
+ 1, sizeof (char *))) == NULL
) {
197 return (DEVFS_NOMEM
);
201 for (i
= 0; i
< count
; i
++) {
202 len
= strlen(ptr
) + 1;
203 if ((list
[i
] = (char *)malloc(len
)) == NULL
) {
206 return (DEVFS_NOMEM
);
208 (void) snprintf(list
[i
], len
, "%s", ptr
);
219 * retrieve the list of prom representations for a given device name
220 * the list will be sorted in the following order: exact aliases,
221 * inexact aliases, prom device path name. If multiple matches occur
222 * for exact or inexact aliases, then these are sorted in collating
223 * order. The list is returned in prom_list
225 * the list may be restricted by specifying the correct flags in options.
228 devfs_get_prom_names(const char *dev_name
, uint_t options
, char ***prom_list
)
230 char *prom_path
= NULL
;
231 int count
= 0; /* # of slots we will need in prom_list */
232 char **alias_list
= NULL
;
236 if (dev_name
== NULL
) {
237 return (DEVFS_INVAL
);
239 if (*dev_name
!= '/') {
240 return (DEVFS_INVAL
);
242 if (prom_list
== NULL
) {
243 return (DEVFS_INVAL
);
246 * make sure we are on a machine which supports a prom
247 * and we have permission to use /dev/openprom
249 if ((ret
= prom_obp_vers()) < 0) {
252 if ((prom_path
= (char *)malloc(MAXPATHLEN
)) == NULL
) {
253 return (DEVFS_NOMEM
);
256 * get the prom path name
258 ret
= devfs_dev_to_prom_name((char *)dev_name
, prom_path
);
263 /* get the list of aliases (exact and inexact) */
264 if ((ret
= prom_dev_to_alias(prom_path
, options
, &alias_list
)) < 0) {
268 /* now figure out how big the return array must be */
269 if (alias_list
!= NULL
) {
270 while (alias_list
[count
] != NULL
) {
274 if ((options
& BOOTDEV_NO_PROM_PATH
) == 0) {
275 count
++; /* # of slots we will need in prom_list */
277 count
++; /* for the null terminator */
279 /* allocate space for the list */
280 if ((list
= (char **)calloc(count
, sizeof (char *))) == NULL
) {
282 while ((alias_list
) && (alias_list
[count
] != NULL
)) {
283 free(alias_list
[count
]);
288 return (DEVFS_NOMEM
);
290 /* fill in the array and free the name list of aliases. */
292 while ((alias_list
) && (alias_list
[count
] != NULL
)) {
293 list
[count
] = alias_list
[count
];
296 if ((options
& BOOTDEV_NO_PROM_PATH
) == 0) {
297 list
[count
] = prom_path
;
299 if (alias_list
!= NULL
) {
307 * Get a list prom-path translations for a solaris device.
309 * Returns the number of and all OBP paths and alias variants that
310 * reference the Solaris device path passed in.
313 devfs_get_all_prom_names(const char *solaris_path
, uint_t flags
,
314 struct devfs_prom_path
**paths
)
316 int ret
, len
, i
, count
= 0;
317 char *ptr
, *prom_path
;
318 struct devfs_prom_path
*cur
= NULL
, *new;
320 if ((ret
= prom_obp_vers()) < 0)
322 if ((prom_path
= (char *)malloc(MAXVALSIZE
)) == NULL
)
323 return (DEVFS_NOMEM
);
325 if ((ret
= devfs_dev_to_prom_names((char *)solaris_path
,
326 prom_path
, MAXVALSIZE
)) < 0) {
331 for (i
= 0; i
< ret
; i
++)
332 if (prom_path
[i
] == '\0')
337 for (i
= 0; i
< count
; i
++) {
338 if ((new = (struct devfs_prom_path
*)calloc(
339 sizeof (struct devfs_prom_path
), 1)) == NULL
) {
341 devfs_free_all_prom_names(*paths
);
342 return (DEVFS_NOMEM
);
351 len
= strlen(ptr
) + 1;
352 if ((cur
->obp_path
= (char *)calloc(len
, 1)) == NULL
) {
354 devfs_free_all_prom_names(*paths
);
355 return (DEVFS_NOMEM
);
358 (void) snprintf(cur
->obp_path
, len
, "%s", ptr
);
360 if ((ret
= prom_dev_to_alias(cur
->obp_path
, flags
,
361 &(cur
->alias_list
))) < 0) {
363 devfs_free_all_prom_names(*paths
);
373 devfs_free_all_prom_names(struct devfs_prom_path
*paths
)
380 devfs_free_all_prom_names(paths
->next
);
382 free(paths
->obp_path
);
384 if (paths
->alias_list
!= NULL
) {
385 for (i
= 0; paths
->alias_list
[i
] != NULL
; i
++)
386 free(paths
->alias_list
[i
]);
388 free(paths
->alias_list
);
395 * Accepts a device name as an input argument. Uses this to set the
396 * boot-device (or like) variable
398 * By default, this routine prepends to the list and converts the
399 * logical device name to its most compact prom representation.
400 * Available options include: converting the device name to a prom
401 * path name (but not an alias) or performing no conversion at all;
402 * overwriting the existing contents of boot-device rather than
406 devfs_bootdev_set_list(const char *dev_name
, const uint_t options
)
411 char **alias_list
= NULL
;
412 char **prom_list
= NULL
;
414 struct openpromio
*opp
= &(oppbuf
.opp
);
417 if (devfs_bootdev_modifiable() != 0) {
418 return (DEVFS_NOTSUP
);
420 if (dev_name
== NULL
) {
421 return (DEVFS_INVAL
);
423 if (strlen(dev_name
) >= MAXPATHLEN
)
424 return (DEVFS_INVAL
);
426 if ((*dev_name
!= '/') && !(options
& BOOTDEV_LITERAL
)) {
427 return (DEVFS_INVAL
);
429 if ((options
& BOOTDEV_LITERAL
) && (options
& BOOTDEV_PROMDEV
)) {
430 return (DEVFS_INVAL
);
433 * if we are prepending, make sure that this obp rev
434 * supports multiple boot device entries.
436 ret
= prom_obp_vers();
441 if ((prom_path
= (char *)malloc(MAXVALSIZE
)) == NULL
) {
442 return (DEVFS_NOMEM
);
444 if (options
& BOOTDEV_LITERAL
) {
445 (void) strcpy(prom_path
, dev_name
);
447 /* need to convert to prom representation */
448 ret
= devfs_get_prom_name_list(dev_name
, &prom_list
);
457 while (prom_list
&& prom_list
[i
]) {
458 if (!(options
& BOOTDEV_PROMDEV
)) {
459 ret
= prom_dev_to_alias(prom_list
[i
], 0,
463 prom_list_free(prom_list
);
466 if ((alias_list
!= NULL
) &&
467 (alias_list
[0] != NULL
)) {
468 (void) snprintf(ptr
, len
, "%s ",
470 for (ret
= 0; alias_list
[ret
] != NULL
;
472 free(alias_list
[ret
]);
474 (void) snprintf(ptr
, len
, "%s ",
479 (void) snprintf(ptr
, len
, "%s ", prom_list
[i
]);
489 prom_list_free(prom_list
);
491 if (options
& BOOTDEV_OVERWRITE
) {
492 new_bootdev
= prom_path
;
494 /* retrieve the current value of boot-device */
495 ret
= get_boot_dev_var(opp
);
500 /* prepend new entry - deal with duplicates */
501 new_bootdev
= (char *)malloc(strlen(opp
->oprom_array
)
502 + strlen(prom_path
) + 2);
503 if (new_bootdev
== NULL
) {
505 return (DEVFS_NOMEM
);
507 (void) strcpy(new_bootdev
, prom_path
);
508 if (opp
->oprom_size
> 0) {
509 for (ptr
= strtok(opp
->oprom_array
, " "); ptr
!= NULL
;
510 ptr
= strtok(NULL
, " ")) {
511 /* we strip out duplicates */
512 if (strcmp(prom_path
, ptr
) == 0) {
515 (void) strcat(new_bootdev
, " ");
516 (void) strcat(new_bootdev
, ptr
);
521 /* now set the new value */
522 ret
= set_boot_dev_var(opp
, new_bootdev
);
524 if (options
& BOOTDEV_OVERWRITE
) {
535 * sets the string bootdev as the new value for boot-device
538 set_boot_dev_var(struct openpromio
*opp
, char *bootdev
)
545 char *bootdev_variables
[] = {
552 int *ip
= (int *)((void *)opp
->oprom_array
);
555 prom_fd
= prom_open(O_RDWR
);
560 /* get the diagnostic-mode? property */
561 (void) strcpy(opp
->oprom_array
, "diagnostic-mode?");
562 opp
->oprom_size
= MAXVALSIZE
;
563 if (ioctl(prom_fd
, OPROMGETOPT
, opp
) >= 0) {
564 if ((opp
->oprom_size
> 0) &&
565 (strcmp(opp
->oprom_array
, "true") == 0)) {
570 /* get the diag-switch? property */
571 (void) strcpy(opp
->oprom_array
, "diag-switch?");
572 opp
->oprom_size
= MAXVALSIZE
;
573 if (ioctl(prom_fd
, OPROMGETOPT
, opp
) >= 0) {
574 if ((opp
->oprom_size
> 0) &&
575 (strcmp(opp
->oprom_array
, "true") == 0)) {
581 * look for one of the following properties in order:
586 * Use the first one that we find.
589 opp
->oprom_size
= MAXPROPSIZE
;
590 while ((opp
->oprom_size
!= 0) && (!found
)) {
591 opp
->oprom_size
= MAXPROPSIZE
;
592 if (ioctl(prom_fd
, OPROMNXTOPT
, opp
) < 0) {
595 for (i
= 0; bootdev_variables
[i
] != NULL
; i
++) {
596 if (strcmp(opp
->oprom_array
, bootdev_variables
[i
])
604 (void) strcpy(opp
->oprom_array
, bootdev_variables
[i
]);
605 opp
->oprom_size
= MAXVALSIZE
;
606 if (ioctl(prom_fd
, OPROMGETOPT
, opp
) < 0) {
608 return (DEVFS_NOTSUP
);
612 return (DEVFS_NOTSUP
);
615 /* save the old copy in case we fail */
616 if ((save_bootdev
= strdup(opp
->oprom_array
)) == NULL
) {
618 return (DEVFS_NOMEM
);
620 /* set up the new value of boot-device */
621 (void) strcpy(opp
->oprom_array
, bootdev_variables
[i
]);
622 valbuf
= opp
->oprom_array
+ strlen(opp
->oprom_array
) + 1;
623 (void) strcpy(valbuf
, bootdev
);
625 opp
->oprom_size
= strlen(valbuf
) + strlen(opp
->oprom_array
) + 2;
627 if (ioctl(prom_fd
, OPROMSETOPT
, opp
) < 0) {
634 * now read it back to make sure it took
636 (void) strcpy(opp
->oprom_array
, bootdev_variables
[i
]);
637 opp
->oprom_size
= MAXVALSIZE
;
638 if (ioctl(prom_fd
, OPROMGETOPT
, opp
) >= 0) {
639 if (_prom_strcmp(opp
->oprom_array
, bootdev
) == 0) {
645 /* deal with setting it to "" */
646 if ((strlen(bootdev
) == 0) && (opp
->oprom_size
== 0)) {
654 * something did not take - write out the old value and
655 * hope that we can restore things...
657 * unfortunately, there is no way for us to differentiate
658 * whether we exceeded the maximum number of characters
659 * allowable. The limit varies from prom rev to prom
660 * rev, and on some proms, when the limit is
661 * exceeded, whatever was in the
662 * boot-device variable becomes unreadable.
664 * so if we fail, we will assume we ran out of room. If we
665 * not able to restore the original setting, then we will
666 * return DEVFS_ERR instead.
669 (void) strcpy(opp
->oprom_array
, bootdev_variables
[i
]);
670 valbuf
= opp
->oprom_array
+ strlen(opp
->oprom_array
) + 1;
671 (void) strcpy(valbuf
, save_bootdev
);
673 opp
->oprom_size
= strlen(valbuf
) + strlen(opp
->oprom_array
) + 2;
675 if (ioctl(prom_fd
, OPROMSETOPT
, opp
) < 0) {
683 * retrieve the current value for boot-device
686 get_boot_dev_var(struct openpromio
*opp
)
690 char *bootdev_variables
[] = {
697 int *ip
= (int *)((void *)opp
->oprom_array
);
700 prom_fd
= prom_open(O_RDONLY
);
705 /* get the diagnostic-mode? property */
706 (void) strcpy(opp
->oprom_array
, "diagnostic-mode?");
707 opp
->oprom_size
= MAXVALSIZE
;
708 if (ioctl(prom_fd
, OPROMGETOPT
, opp
) >= 0) {
709 if ((opp
->oprom_size
> 0) &&
710 (strcmp(opp
->oprom_array
, "true") == 0)) {
715 /* get the diag-switch? property */
716 (void) strcpy(opp
->oprom_array
, "diag-switch?");
717 opp
->oprom_size
= MAXVALSIZE
;
718 if (ioctl(prom_fd
, OPROMGETOPT
, opp
) >= 0) {
719 if ((opp
->oprom_size
> 0) &&
720 (strcmp(opp
->oprom_array
, "true") == 0)) {
726 * look for one of the following properties in order:
731 * Use the first one that we find.
734 opp
->oprom_size
= MAXPROPSIZE
;
735 while ((opp
->oprom_size
!= 0) && (!found
)) {
736 opp
->oprom_size
= MAXPROPSIZE
;
737 if (ioctl(prom_fd
, OPROMNXTOPT
, opp
) < 0) {
740 for (i
= 0; bootdev_variables
[i
] != NULL
; i
++) {
741 if (strcmp(opp
->oprom_array
, bootdev_variables
[i
])
749 (void) strcpy(opp
->oprom_array
, bootdev_variables
[i
]);
750 opp
->oprom_size
= MAXVALSIZE
;
751 if (ioctl(prom_fd
, OPROMGETOPT
, opp
) < 0) {
755 /* boot-device exists but contains nothing */
756 if (opp
->oprom_size
== 0) {
757 *opp
->oprom_array
= '\0';
761 return (DEVFS_NOTSUP
);
768 * Just return error from it, at least for now.
769 * This is part of private interface, no consumers on gate.
772 find_x86_boot_device(struct openpromio
*opp
)
778 * retrieve the list of entries in the boot-device configuration
779 * variable. An array of boot_dev structs will be created, one entry
780 * for each device name in the boot-device variable. Each entry
781 * in the array will contain the logical device representation of the
782 * boot-device entry, if any.
784 * default_root. if set, is used to locate logical device entries in
785 * directories other than /dev
788 devfs_bootdev_get_list(const char *default_root
,
789 struct boot_dev
***bootdev_list
)
792 struct openpromio
*opp
= &(oppbuf
.opp
);
794 struct boot_dev
**tmp_list
;
796 if (default_root
== NULL
) {
798 } else if (*default_root
!= '/') {
799 return (DEVFS_INVAL
);
802 if (bootdev_list
== NULL
) {
803 return (DEVFS_INVAL
);
806 /* get the boot-device variable */
808 i
= get_boot_dev_var(opp
);
810 i
= find_x86_boot_device(opp
);
815 /* now try to translate each entry to a logical device. */
816 i
= process_bootdev(opp
->oprom_array
, default_root
, &tmp_list
);
818 *bootdev_list
= tmp_list
;
826 * loop thru the list of entries in a boot-device configuration
830 process_bootdev(const char *bootdevice
, const char *default_root
,
831 struct boot_dev
***list
)
835 char prom_path
[MAXPATHLEN
];
836 char ret_buf
[MAXPATHLEN
];
837 struct boot_dev
**bootdev_array
;
842 if ((entry
= (char *)malloc(strlen(bootdevice
) + 1)) == NULL
) {
843 return (DEVFS_NOMEM
);
845 /* count the number of entries */
846 (void) strcpy(entry
, bootdevice
);
847 for (ptr
= strtok(entry
, " "); ptr
!= NULL
;
848 ptr
= strtok(NULL
, " ")) {
851 (void) strcpy(entry
, bootdevice
);
853 bootdev_array
= (struct boot_dev
**)
854 calloc((size_t)num_entries
+ 1, sizeof (struct boot_dev
*));
856 if (bootdev_array
== NULL
) {
858 return (DEVFS_NOMEM
);
861 vers
= prom_obp_vers();
867 /* for each entry in boot-device, do... */
868 for (ptr
= strtok(entry
, " "), i
= 0; ptr
!= NULL
;
869 ptr
= strtok(NULL
, " "), i
++) {
871 if ((bootdev_array
[i
] = alloc_bootdev(ptr
)) == NULL
) {
872 devfs_bootdev_free_list(bootdev_array
);
874 return (DEVFS_NOMEM
);
878 * prom boot-device may be aliased, so we need to do
879 * the necessary prom alias to dev translation.
882 if (alias_to_prom_dev(ptr
, prom_path
) < 0) {
886 (void) strcpy(prom_path
, ptr
);
889 /* now we have a prom device path - convert to a devfs name */
890 if (devfs_prom_to_dev_name(prom_path
, ret_buf
) < 0) {
894 /* append any default minor names necessary */
895 if (process_minor_name(ret_buf
, default_root
) < 0) {
901 * store the physical device path for now - when
902 * we are all done with the entries, we will convert
903 * these to their logical device name equivalents
905 bootdev_array
[i
]->bootdev_trans
[0] = strdup(ret_buf
);
908 * Convert all of the boot-device entries that translated to a
909 * physical device path in /devices to a logical device path
910 * in /dev (note that there may be several logical device paths
911 * associated with a single physical device path - return them all
914 if (devfs_phys_to_logical(bootdev_array
, num_entries
,
916 devfs_bootdev_free_list(bootdev_array
);
917 bootdev_array
= NULL
;
921 *list
= bootdev_array
;
926 * We may get a device path from the prom that has no minor name
927 * information included in it. Since this device name will not
928 * correspond directly to a physical device in /devices, we do our
929 * best to append what the default minor name should be and try this.
931 * For sparc: we append slice 0 (:a).
932 * For x86: we append fdisk partition 0 (:q).
935 process_minor_name(char *dev_path
, const char *root
)
939 const char *default_minor_name
= "a";
941 const char *default_minor_name
= "q";
944 struct stat stat_buf
;
945 char path
[MAXPATHLEN
];
947 (void) snprintf(path
, sizeof (path
), "%s%s%s", root
, DEVICES
, dev_path
);
949 * if the device file already exists as given to us, there
950 * is nothing to do but return.
952 if (stat(path
, &stat_buf
) == 0) {
956 * if there is no ':' after the last '/' character, or if there is
957 * a ':' with no specifier, append the default segment specifier
958 * ; if there is a ':' followed by a digit, this indicates
959 * a partition number (which does not map into the /devices name
960 * space), so strip the number and replace it with the letter
961 * that represents the partition index
963 if ((cp
= strrchr(dev_path
, '/')) != NULL
) {
964 if ((cp
= strchr(cp
, ':')) == NULL
) {
965 (void) strcat(dev_path
, ":");
966 (void) strcat(dev_path
, default_minor_name
);
967 } else if (*++cp
== '\0') {
968 (void) strcat(dev_path
, default_minor_name
);
969 } else if (isdigit(*cp
)) {
971 /* make sure to squash the digit */
974 case 0: (void) strcat(dev_path
, "q");
976 case 1: (void) strcat(dev_path
, "r");
978 case 2: (void) strcat(dev_path
, "s");
980 case 3: (void) strcat(dev_path
, "t");
982 case 4: (void) strcat(dev_path
, "u");
984 default: (void) strcat(dev_path
, "a");
990 * see if we can find something now.
992 (void) snprintf(path
, sizeof (path
), "%s%s%s", root
, DEVICES
, dev_path
);
994 if (stat(path
, &stat_buf
) == 0) {
1002 * for each entry in bootdev_array, convert the physical device
1003 * representation of the boot-device entry to one or more logical device
1004 * entries. We use the hammer method - walk through the logical device
1005 * name space looking for matches (/dev). We use nftw to do this.
1008 devfs_phys_to_logical(struct boot_dev
**bootdev_array
, const int array_size
,
1009 const char *default_root
)
1011 int walk_flags
= FTW_PHYS
| FTW_MOUNT
;
1013 struct name_list
*list
;
1015 char **dev_name_array
;
1016 size_t default_root_len
;
1017 char *dev_dir
= DEV
;
1020 if (array_size
< 0) {
1024 if (bootdev_array
== NULL
) {
1027 if (default_root
== NULL
) {
1030 default_root_len
= strlen(default_root
);
1031 if ((default_root_len
!= 0) && (*default_root
!= '/')) {
1035 /* short cut for an empty array */
1036 if (*bootdev_array
== NULL
) {
1040 /* tell nftw where to start (default: /dev) */
1041 len
= default_root_len
+ strlen(dev_dir
) + 1;
1042 if ((full_path
= (char *)malloc(len
)) == NULL
) {
1047 * if the default root path is terminated with a /, we have to
1048 * make sure we don't end up with one too many slashes in the
1049 * path we are building.
1051 if ((default_root_len
> (size_t)0) &&
1052 (default_root
[default_root_len
- 1] == '/')) {
1053 (void) snprintf(full_path
, len
, "%s%s", default_root
,
1056 (void) snprintf(full_path
, len
, "%s%s", default_root
, dev_dir
);
1060 * we need to muck with global data to make nftw work
1061 * so single thread access
1063 (void) mutex_lock(&dev_lists_lk
);
1066 * set the global vars bootdev_list and dev_list for use by nftw
1067 * dev_list is an array of lists - one for each boot-device
1068 * entry. The nftw function will create a list of logical device
1069 * entries for each boot-device and put all of the lists in
1072 dev_list
= (struct name_list
**)
1073 calloc(array_size
, sizeof (struct name_list
*));
1074 if (dev_list
== NULL
) {
1076 (void) mutex_unlock(&dev_lists_lk
);
1079 bootdev_list
= bootdev_array
;
1081 if (nftw(full_path
, check_logical_dev
, FT_DEPTH
, walk_flags
) == -1) {
1082 bootdev_list
= NULL
;
1084 for (i
= 0; i
< array_size
; i
++) {
1085 free_name_list(dev_list
[i
], 1);
1087 /* don't free dev_list here because it's been handed off */
1089 (void) mutex_unlock(&dev_lists_lk
);
1094 * now we have a filled in dev_list. So for each logical device
1095 * list in dev_list, count the number of entries in the list,
1096 * create an array of strings of logical devices, and save in the
1097 * corresponding boot_dev structure.
1099 for (i
= 0; i
< array_size
; i
++) {
1100 /* get the next list */
1104 /* count the number of entries in the list */
1105 while (list
!= NULL
) {
1109 if ((dev_name_array
=
1110 (char **)malloc((count
+ 1) * sizeof (char *)))
1117 /* fill in the array */
1118 while (list
!= NULL
) {
1119 dev_name_array
[count
] = list
->name
;
1125 * null terminate the array
1127 dev_name_array
[count
] = NULL
;
1128 if ((bootdev_array
[i
] != NULL
) && (bootdev_array
[i
]->
1129 bootdev_trans
[0] != NULL
)) {
1130 free(bootdev_array
[i
]->bootdev_trans
[0]);
1132 if (bootdev_array
[i
] != NULL
) {
1133 free(bootdev_array
[i
]->bootdev_trans
);
1134 bootdev_array
[i
]->bootdev_trans
= dev_name_array
;
1137 bootdev_list
= NULL
;
1139 for (i
= 0; i
< array_size
; i
++) {
1140 free_name_list(dev_list
[i
], 0);
1144 (void) mutex_unlock(&dev_lists_lk
);
1149 * for a logical dev entry, it walks the list of boot-devices and
1150 * sees if there are any matches. If so, it saves the logical device
1151 * name off in the appropriate list in dev_list
1155 check_logical_dev(const char *node
, const struct stat
*node_stat
, int flags
,
1156 struct FTW
*ftw_info
)
1158 char link_buf
[MAXPATHLEN
];
1161 struct name_list
*dev
;
1165 if (flags
!= FTW_SL
) {
1169 if ((link_buf_len
= readlink(node
, (void *)link_buf
, MAXPATHLEN
))
1173 link_buf
[link_buf_len
] = '\0';
1174 if ((name
= strstr(link_buf
, DEVICES
)) == NULL
) {
1177 name
= (char *)(name
+ strlen(DEVICES
));
1179 for (i
= 0; bootdev_list
[i
] != NULL
; i
++) {
1180 if (bootdev_list
[i
]->bootdev_trans
[0] == NULL
) {
1184 * compare the contents of the link with the physical
1185 * device representation of this boot device
1187 physdev
= bootdev_list
[i
]->bootdev_trans
[0];
1188 if ((strcmp(name
, physdev
) == 0) &&
1189 (strlen(name
) == strlen(physdev
))) {
1190 if ((dev
= (struct name_list
*)
1191 malloc(sizeof (struct name_list
))) == NULL
) {
1194 if ((dev
->name
= strdup(node
)) == NULL
) {
1198 if (dev_list
[i
] == NULL
) {
1200 dev_list
[i
]->next
= NULL
;
1202 dev
->next
= dev_list
[i
];
1211 * frees a list of boot_dev struct pointers
1214 devfs_bootdev_free_list(struct boot_dev
**array
)
1219 if (array
== NULL
) {
1223 while (array
[i
] != NULL
) {
1224 free(array
[i
]->bootdev_element
);
1226 while (array
[i
]->bootdev_trans
[j
] != NULL
) {
1227 free(array
[i
]->bootdev_trans
[j
++]);
1229 free(array
[i
]->bootdev_trans
);
1236 * allocates a boot_dev struct and fills in the bootdev_element portion
1238 static struct boot_dev
*
1239 alloc_bootdev(char *entry_name
)
1241 struct boot_dev
*entry
;
1243 entry
= (struct boot_dev
*)calloc(1, sizeof (struct boot_dev
));
1245 if (entry
== NULL
) {
1248 if ((entry
->bootdev_element
= strdup(entry_name
)) == NULL
) {
1253 * Allocate room for 1 name and a null terminator - the caller of
1254 * this function will need the first slot right away.
1256 if ((entry
->bootdev_trans
= (char **)calloc(2, sizeof (char *)))
1258 free(entry
->bootdev_element
);
1266 * will come back with a concatenated list of paths
1269 devfs_dev_to_prom_names(char *dev_path
, char *prom_path
, size_t len
)
1272 struct openpromio
*opp
= &(oppbuf
.opp
);
1274 int ret
= DEVFS_INVAL
;
1277 if (prom_path
== NULL
) {
1278 return (DEVFS_INVAL
);
1280 if (dev_path
== NULL
) {
1281 return (DEVFS_INVAL
);
1283 if (strlen(dev_path
) >= MAXPATHLEN
)
1284 return (DEVFS_INVAL
);
1286 if (*dev_path
!= '/')
1287 return (DEVFS_INVAL
);
1289 prom_fd
= prom_open(O_RDONLY
);
1294 /* query the prom */
1295 (void) snprintf(opp
->oprom_array
, MAXVALSIZE
, "%s", dev_path
);
1296 opp
->oprom_size
= MAXVALSIZE
;
1298 if (ioctl(prom_fd
, OPROMDEV2PROMNAME
, opp
) == 0) {
1299 prom_close(prom_fd
);
1301 /* return the prom path in prom_path */
1303 i
= len
- opp
->oprom_size
;
1305 bcopy(opp
->oprom_array
, prom_path
, len
);
1306 prom_path
[len
- 1] = '\0';
1309 bcopy(opp
->oprom_array
, prom_path
, len
);
1310 return (opp
->oprom_size
);
1314 * either the prom does not support this ioctl or the argument
1317 if (errno
== ENXIO
) {
1320 prom_close(prom_fd
);
1325 * Convert a physical or logical device name to a name the prom would
1326 * understand. Fail if this platform does not support a prom or if
1327 * the device does not correspond to a valid prom device.
1328 * dev_path should be the name of a device in the logical or
1329 * physical device namespace.
1330 * prom_path is the prom version of the device name
1331 * prom_path must be large enough to contain the result and is
1332 * supplied by the user.
1334 * This routine only supports converting leaf device paths
1337 devfs_dev_to_prom_name(char *dev_path
, char *prom_path
)
1341 rval
= devfs_dev_to_prom_names(dev_path
, prom_path
, MAXPATHLEN
);
1350 * Use the openprom driver's OPROMPATH2DRV ioctl to convert a devfs
1351 * path to a driver name.
1352 * devfs_path - the pathname of interest. This must be the physcical device
1353 * path with the mount point prefix (ie. /devices) stripped off.
1354 * drv_buf - user supplied buffer - the driver name will be stored here.
1356 * If the prom lookup fails, we return the name of the last component in
1357 * the pathname. This routine is useful for looking up driver names
1358 * associated with generically named devices.
1360 * This routine returns driver names that have aliases resolved.
1363 devfs_path_to_drv(char *devfs_path
, char *drv_buf
)
1366 struct openpromio
*opp
= &(oppbuf
.opp
);
1367 char *slash
, *colon
, *dev_addr
;
1368 char driver_path
[MAXPATHLEN
];
1371 if (drv_buf
== NULL
) {
1374 if (devfs_path
== NULL
) {
1378 if (strlen(devfs_path
) >= MAXPATHLEN
)
1381 if (*devfs_path
!= '/')
1385 /* strip off any minor node info at the end of the path */
1386 (void) strcpy(driver_path
, devfs_path
);
1387 slash
= strrchr(driver_path
, '/');
1390 colon
= strrchr(slash
, ':');
1394 /* query the prom */
1395 if ((prom_fd
= prom_open(O_RDONLY
)) >= 0) {
1396 (void) strcpy(opp
->oprom_array
, driver_path
);
1397 opp
->oprom_size
= MAXVALSIZE
;
1399 if (ioctl(prom_fd
, OPROMPATH2DRV
, opp
) == 0) {
1400 prom_close(prom_fd
);
1401 /* return the driver name in drv_buf */
1402 (void) strcpy(drv_buf
, opp
->oprom_array
);
1405 prom_close(prom_fd
);
1406 } else if (prom_fd
!= DEVFS_NOTSUP
)
1409 * If we get here, then either:
1410 * 1. this platform does not support an openprom driver
1411 * 2. we were asked to look up a device the prom does
1412 * not know about (e.g. a pseudo device)
1413 * In this case, we use the last component of the devfs path
1414 * name and try to derive the driver name
1417 /* use the last component of devfs_path as the driver name */
1418 if ((dev_addr
= strrchr(slash
, '@')) != NULL
)
1422 /* use opp->oprom_array as a buffer */
1423 (void) strcpy(opp
->oprom_array
, slash
);
1424 if (devfs_resolve_aliases(opp
->oprom_array
) == NULL
)
1426 (void) strcpy(drv_buf
, opp
->oprom_array
);
1431 * These modctl calls do the equivalent of:
1432 * ddi_name_to_major()
1433 * ddi_major_to_name()
1434 * This results in two things:
1435 * - the driver name must be a valid one
1436 * - any driver aliases are resolved.
1437 * drv is overwritten with the resulting name.
1440 devfs_resolve_aliases(char *drv
)
1443 char driver_name
[MAXNAMELEN
+ 1];
1449 if (modctl(MODGETMAJBIND
, drv
, strlen(drv
) + 1, &maj
) < 0)
1451 else if (modctl(MODGETNAME
, driver_name
, sizeof (driver_name
), &maj
)
1455 (void) strcpy(drv
, driver_name
);
1461 * open the openprom device. and verify that we are on an
1462 * OBP/1275 OF machine. If the prom does not exist, then we
1466 prom_open(int oflag
)
1469 char *promdev
= "/dev/openprom";
1471 while (prom_fd
< 0) {
1472 if ((prom_fd
= open(promdev
, oflag
)) < 0) {
1473 if (errno
== EAGAIN
) {
1477 if ((errno
== ENXIO
) || (errno
== ENOENT
)) {
1478 return (DEVFS_NOTSUP
);
1480 if ((errno
== EPERM
) || (errno
== EACCES
)) {
1481 return (DEVFS_PERM
);
1487 if (is_openprom(prom_fd
))
1490 prom_close(prom_fd
);
1496 prom_close(int prom_fd
)
1498 (void) close(prom_fd
);
1502 * is this an OBP/1275 OF machine?
1505 is_openprom(int prom_fd
)
1508 struct openpromio
*opp
= &(oppbuf
.opp
);
1511 opp
->oprom_size
= MAXVALSIZE
;
1512 if (ioctl(prom_fd
, OPROMGETCONS
, opp
) < 0)
1515 i
= (unsigned int)((unsigned char)opp
->oprom_array
[0]);
1516 return ((i
& OPROMCONS_OPENPROM
) == OPROMCONS_OPENPROM
);
1520 * convert a prom device path name to an equivalent physical device
1521 * path in the kernel.
1524 devfs_prom_to_dev_name(char *prom_path
, char *dev_path
)
1527 struct openpromio
*opp
= &(oppbuf
.opp
);
1529 int ret
= DEVFS_INVAL
;
1531 if (dev_path
== NULL
) {
1532 return (DEVFS_INVAL
);
1534 if (prom_path
== NULL
) {
1535 return (DEVFS_INVAL
);
1537 if (strlen(prom_path
) >= MAXPATHLEN
)
1538 return (DEVFS_INVAL
);
1540 if (*prom_path
!= '/') {
1541 return (DEVFS_INVAL
);
1544 /* query the prom */
1545 prom_fd
= prom_open(O_RDONLY
);
1549 (void) strcpy(opp
->oprom_array
, prom_path
);
1550 opp
->oprom_size
= MAXVALSIZE
;
1552 if (ioctl(prom_fd
, OPROMPROM2DEVNAME
, opp
) == 0) {
1553 prom_close(prom_fd
);
1556 * return the prom path in prom_path
1558 (void) strcpy(dev_path
, opp
->oprom_array
);
1562 * either the argument was not a valid name or the openprom
1563 * driver does not support this ioctl.
1565 if (errno
== ENXIO
) {
1568 prom_close(prom_fd
);
1572 * convert a prom device path to a list of equivalent alias names
1573 * If there is no alias node, or there are no aliases that correspond
1574 * to dev, we return empty lists.
1577 prom_dev_to_alias(char *dev
, uint_t options
, char ***ret_buf
)
1579 struct name_list
*exact_list
;
1580 struct name_list
*inexact_list
;
1581 struct name_list
*list
;
1588 vers
= prom_obp_vers();
1594 return (DEVFS_INVAL
);
1598 return (DEVFS_INVAL
);
1600 if (strlen(dev
) >= MAXPATHLEN
)
1601 return (DEVFS_INVAL
);
1603 if ((ptr
= strchr(dev
, ':')) != NULL
) {
1604 if (strchr(ptr
, '/') != NULL
)
1605 return (DEVFS_INVAL
);
1607 if (ret_buf
== NULL
) {
1608 return (DEVFS_INVAL
);
1611 prom_fd
= prom_open(O_RDONLY
);
1616 (void) prom_srch_aliases_by_def(dev
, &exact_list
,
1617 &inexact_list
, prom_fd
);
1619 prom_close(prom_fd
);
1621 if ((options
& BOOTDEV_NO_EXACT_ALIAS
) != 0) {
1622 free_name_list(exact_list
, 1);
1626 if ((options
& BOOTDEV_NO_INEXACT_ALIAS
) != 0) {
1627 free_name_list(inexact_list
, 1);
1628 inexact_list
= NULL
;
1633 while (list
!= NULL
) {
1637 list
= inexact_list
;
1638 while (list
!= NULL
) {
1643 if ((*ret_buf
= (char **)malloc((count
+ 1) * sizeof (char *)))
1645 free_name_list(inexact_list
, 1);
1646 free_name_list(exact_list
, 1);
1647 return (DEVFS_NOMEM
);
1653 while (list
!= NULL
) {
1654 array
[count
] = list
->name
;
1658 list
= inexact_list
;
1659 while (list
!= NULL
) {
1660 array
[count
] = list
->name
;
1664 array
[count
] = NULL
;
1665 free_name_list(inexact_list
, 0);
1666 free_name_list(exact_list
, 0);
1672 * determine the version of prom we are running on.
1673 * Also include any prom revision specific information.
1679 struct openpromio
*opp
= &(oppbuf
.opp
);
1681 static int version
= 0;
1688 prom_fd
= prom_open(O_RDONLY
);
1693 opp
->oprom_size
= MAXVALSIZE
;
1695 if ((ioctl(prom_fd
, OPROMGETVERSION
, opp
)) < 0) {
1696 prom_close(prom_fd
);
1699 prom_close(prom_fd
);
1706 * search the aliases node by definition - compile a list of
1707 * alias names that are both exact and inexact matches.
1710 prom_srch_aliases_by_def(char *promdev_def
, struct name_list
**exact_list
,
1711 struct name_list
**inexact_list
, int prom_fd
)
1714 Oppbuf propdef_oppbuf
;
1715 struct openpromio
*opp
= &(oppbuf
.opp
);
1716 struct openpromio
*propdef_opp
= &(propdef_oppbuf
.opp
);
1717 int *ip
= (int *)((void *)opp
->oprom_array
);
1719 struct name_list
*inexact_match
= *inexact_list
= NULL
;
1720 struct name_list
*exact_match
= *exact_list
= NULL
;
1721 char alias_buf
[MAXNAMELEN
];
1724 if ((ret
= prom_find_aliases_node(prom_fd
)) < 0)
1727 (void) memset(oppbuf
.buf
, 0, BUFSIZE
);
1728 opp
->oprom_size
= MAXPROPSIZE
;
1731 if ((ret
= ioctl(prom_fd
, OPROMNXTPROP
, opp
)) < 0)
1733 if (opp
->oprom_size
== 0)
1736 while ((ret
>= 0) && (opp
->oprom_size
> 0)) {
1737 (void) strcpy(propdef_opp
->oprom_array
, opp
->oprom_array
);
1738 opp
->oprom_size
= MAXPROPSIZE
;
1739 propdef_opp
->oprom_size
= MAXVALSIZE
;
1740 if ((ioctl(prom_fd
, OPROMGETPROP
, propdef_opp
) < 0) ||
1741 (propdef_opp
->oprom_size
== 0)) {
1742 ret
= ioctl(prom_fd
, OPROMNXTPROP
, opp
);
1745 ret
= prom_compare_devs(promdev_def
, propdef_opp
->oprom_array
);
1746 if (ret
== EXACT_MATCH
) {
1748 if (insert_alias_list(exact_list
, opp
->oprom_array
)
1750 free_name_list(exact_match
, 1);
1751 free_name_list(inexact_match
, 1);
1755 if (ret
== INEXACT_MATCH
) {
1757 (void) strcpy(alias_buf
, opp
->oprom_array
);
1758 options_override(promdev_def
, alias_buf
);
1759 if (insert_alias_list(inexact_list
, alias_buf
)
1761 free_name_list(exact_match
, 1);
1762 free_name_list(inexact_match
, 1);
1766 ret
= ioctl(prom_fd
, OPROMNXTPROP
, opp
);
1776 * free a list of name_list structs and optionally
1777 * free the strings they contain.
1780 free_name_list(struct name_list
*list
, int free_name
)
1782 struct name_list
*next
= list
;
1784 while (next
!= NULL
) {
1794 * insert a new alias in a list of aliases - the list is sorted
1795 * in collating order (ignoring anything that comes after the
1799 insert_alias_list(struct name_list
**list
, char *alias_name
)
1801 struct name_list
*entry
= *list
;
1802 struct name_list
*new_entry
, *prev_entry
;
1804 char *colon1
, *colon2
;
1807 (struct name_list
*)malloc(sizeof (struct name_list
)))
1811 if ((new_entry
->name
= strdup(alias_name
)) == NULL
) {
1815 new_entry
->next
= NULL
;
1817 if (entry
== NULL
) {
1822 if ((colon1
= strchr(alias_name
, ':')) != NULL
) {
1826 while (entry
!= NULL
) {
1827 if ((colon2
= strchr(entry
->name
, ':')) != NULL
) {
1830 ret
= strcmp(alias_name
, entry
->name
);
1831 if (colon2
!= NULL
) {
1836 free(new_entry
->name
);
1838 if (colon1
!= NULL
) {
1844 new_entry
->next
= entry
;
1845 if (prev_entry
== NULL
) {
1846 /* in beginning of list */
1849 /* in middle of list */
1850 prev_entry
->next
= new_entry
;
1852 if (colon1
!= NULL
) {
1858 entry
= entry
->next
;
1860 /* at end of list */
1861 prev_entry
->next
= new_entry
;
1862 new_entry
->next
= NULL
;
1863 if (colon1
!= NULL
) {
1869 * append :x to alias_name to override any default minor name options
1872 options_override(char *prom_path
, char *alias_name
)
1876 if ((colon
= strrchr(alias_name
, ':')) != NULL
) {
1878 * XXX - should alias names in /aliases ever have a
1879 * : embedded in them?
1880 * If so we ignore it.
1885 if ((colon
= strrchr(prom_path
, ':')) != NULL
) {
1886 (void) strcat(alias_name
, colon
);
1891 * compare to prom device names.
1892 * if the device names are not fully qualified. we convert them -
1893 * we only do this as a last resort though since it requires
1894 * jumping into the kernel.
1897 prom_compare_devs(char *prom_dev1
, char *prom_dev2
)
1901 char *drvname1
, *addrname1
, *minorname1
;
1902 char *drvname2
, *addrname2
, *minorname2
;
1903 char component1
[MAXNAMELEN
], component2
[MAXNAMELEN
];
1904 char devname1
[MAXPATHLEN
], devname2
[MAXPATHLEN
];
1905 int unqualified_name
= 0;
1906 int error
= EXACT_MATCH
;
1908 char *wildcard
= ",0";
1913 if ((ptr1
== NULL
) || (*ptr1
!= '/')) {
1916 if ((ptr2
== NULL
) || (*ptr2
!= '/')) {
1921 * compare device names one component at a time.
1923 while ((ptr1
!= NULL
) && (ptr2
!= NULL
)) {
1924 *ptr1
= *ptr2
= '/';
1927 if ((ptr1
= strchr(dev1
, '/')) != NULL
)
1929 if ((ptr2
= strchr(dev2
, '/')) != NULL
)
1932 (void) strcpy(component1
, dev1
);
1933 (void) strcpy(component2
, dev2
);
1935 parse_name(component1
, &drvname1
, &addrname1
, &minorname1
);
1936 parse_name(component2
, &drvname2
, &addrname2
, &minorname2
);
1938 if ((drvname1
== NULL
) && (addrname1
== NULL
)) {
1943 if ((drvname2
== NULL
) && (addrname2
== NULL
)) {
1948 if (_prom_strcmp(drvname1
, drvname2
) != 0) {
1954 * a possible name is driver_name@address. The address
1955 * portion is optional (i.e. the name is not fully
1956 * qualified.). We have to deal with the case where
1957 * the component name is either driver_name or
1958 * driver_name@address
1960 if ((addrname1
== NULL
) ^ (addrname2
== NULL
)) {
1961 unqualified_name
= 1;
1962 } else if (addrname1
&&
1963 (_prom_strcmp(addrname1
, addrname2
) != 0)) {
1965 * check to see if appending a ",0" to the
1966 * shorter address causes a match to occur.
1969 len1
= strlen(addrname1
);
1970 len2
= strlen(addrname2
);
1971 if ((len1
< len2
) &&
1972 (strncmp(addrname1
, addrname2
, len1
) == 0) &&
1973 (strcmp(wildcard
, &addrname2
[len1
]) == 0)) {
1975 } else if ((len2
< len1
) &&
1976 (strncmp(addrname1
, addrname2
, len2
) == 0) &&
1977 (strcmp(wildcard
, &addrname1
[len2
]) == 0)) {
1986 * if either of the two device paths still has more components,
1987 * then we do not have a match.
1997 if (error
== NO_MATCH
) {
2002 * OK - we found a possible match but one or more of the
2003 * path components was not fully qualified (did not have any
2004 * address information. So we need to convert it to a form
2005 * that is fully qualified and then compare the resulting
2008 if (unqualified_name
!= 0) {
2009 if ((devfs_prom_to_dev_name(prom_dev1
, devname1
) < 0) ||
2010 (devfs_prom_to_dev_name(prom_dev2
, devname2
) < 0)) {
2013 if ((dev1
= strrchr(devname1
, ':')) != NULL
) {
2016 if ((dev2
= strrchr(devname2
, ':')) != NULL
) {
2019 if (strcmp(devname1
, devname2
) != 0) {
2024 * the resulting strings matched. If the minorname information
2025 * matches, then we have an exact match, otherwise an inexact match
2027 if (_prom_strcmp(minorname1
, minorname2
) == 0) {
2028 return (EXACT_MATCH
);
2030 return (INEXACT_MATCH
);
2035 * wrapper or strcmp - deals with null strings.
2038 _prom_strcmp(char *s1
, char *s2
)
2040 if ((s1
== NULL
) && (s2
== NULL
))
2042 if ((s1
== NULL
) && (s2
!= NULL
)) {
2045 if ((s1
!= NULL
) && (s2
== NULL
)) {
2048 return (strcmp(s1
, s2
));
2051 * break device@a,b:minor into components
2054 parse_name(char *name
, char **drvname
, char **addrname
, char **minorname
)
2058 cp
= *drvname
= name
;
2059 *addrname
= *minorname
= NULL
;
2063 while ((ch
= *cp
) != '\0') {
2071 *((*addrname
)-1) = '\0';
2074 *((*minorname
)-1) = '\0';
2079 * converts a prom alias to a prom device name.
2080 * if we find no matching device, then we fail since if were
2081 * given a valid alias, then by definition, there must be a
2082 * device pathname associated with it in the /aliases node.
2085 alias_to_prom_dev(char *alias
, char *ret_buf
)
2088 char alias_buf
[MAXNAMELEN
];
2089 char alias_def
[MAXPATHLEN
];
2090 char options
[16] = "";
2095 if (strchr(alias
, '/') != NULL
)
2096 return (DEVFS_INVAL
);
2098 if (strlen(alias
) > (MAXNAMELEN
- 1))
2099 return (DEVFS_INVAL
);
2101 if (ret_buf
== NULL
) {
2102 return (DEVFS_INVAL
);
2105 prom_fd
= prom_open(O_RDONLY
);
2110 (void) strlcpy(alias_buf
, alias
, sizeof (alias_buf
));
2113 * save off any options (minor name info) that is
2114 * explicitly called out in the alias name
2116 if ((options_ptr
= strchr(alias_buf
, ':')) != NULL
) {
2117 *options_ptr
= '\0';
2118 (void) strlcpy(options
, ++options_ptr
, sizeof (options
));
2123 ret
= prom_find_aliases_node(prom_fd
);
2126 * we loop because one alias may define another... we have
2127 * to work our way down to an actual device definition.
2129 for (i
= 0; i
<= 10; i
++) {
2130 ret
= prom_srch_node(prom_fd
, alias_buf
, alias_def
);
2134 (void) strlcpy(alias_buf
, alias_def
,
2135 sizeof (alias_buf
));
2136 if (*alias_def
== '/') {
2141 * save off any explicit options (minor name info)
2142 * if none has been encountered yet
2144 if (options_ptr
== NULL
) {
2145 options_ptr
= strchr(alias_buf
, ':');
2146 if (options_ptr
!= NULL
) {
2147 *options_ptr
= '\0';
2148 (void) strlcpy(options
, ++options_ptr
,
2154 prom_close(prom_fd
);
2161 (void) strlcpy(ret_buf
, alias_def
, MAXPATHLEN
);
2163 /* override minor name information */
2164 if (options_ptr
!= NULL
) {
2165 if ((options_ptr
= strrchr(ret_buf
, ':')) == NULL
) {
2166 (void) strcat(ret_buf
, ":");
2168 *(++options_ptr
) = '\0';
2170 (void) strcat(ret_buf
, options
);
2176 * search a prom node for a property name
2179 prom_srch_node(int fd
, char *prop_name
, char *ret_buf
)
2182 struct openpromio
*opp
= &(oppbuf
.opp
);
2183 int *ip
= (int *)((void *)opp
->oprom_array
);
2185 (void) memset(oppbuf
.buf
, 0, BUFSIZE
);
2186 opp
->oprom_size
= MAXPROPSIZE
;
2189 if (ioctl(fd
, OPROMNXTPROP
, opp
) < 0)
2191 if (opp
->oprom_size
== 0)
2194 while (strcmp(prop_name
, opp
->oprom_array
) != 0) {
2195 opp
->oprom_size
= MAXPROPSIZE
;
2196 if (ioctl(fd
, OPROMNXTPROP
, opp
) < 0)
2198 if (opp
->oprom_size
== 0)
2201 opp
->oprom_size
= MAXVALSIZE
;
2202 if (ioctl(fd
, OPROMGETPROP
, opp
) < 0)
2205 if (opp
->oprom_size
== 0)
2207 (void) strlcpy(ret_buf
, opp
->oprom_array
, MAXPATHLEN
);
2212 * return the aliases node.
2215 prom_find_aliases_node(int fd
)
2218 char buf
[MAXPATHLEN
];
2220 if ((child_id
= prom_next_node(fd
, 0)) == 0)
2222 if ((child_id
= prom_child_node(fd
, child_id
)) == 0)
2225 while (child_id
!= 0) {
2226 if (prom_srch_node(fd
, "name", buf
) == 0) {
2227 if (strcmp(buf
, "aliases") == 0) {
2231 child_id
= prom_next_node(fd
, child_id
);
2240 prom_next_node(int fd
, uint_t node_id
)
2243 struct openpromio
*opp
= &(oppbuf
.opp
);
2244 uint_t
*ip
= (uint_t
*)((void *)opp
->oprom_array
);
2246 (void) memset(oppbuf
.buf
, 0, BUFSIZE
);
2247 opp
->oprom_size
= MAXVALSIZE
;
2250 if (ioctl(fd
, OPROMNEXT
, opp
) < 0)
2253 return (*(uint_t
*)((void *)opp
->oprom_array
));
2260 prom_child_node(int fd
, uint_t node_id
)
2263 struct openpromio
*opp
= &(oppbuf
.opp
);
2264 uint_t
*ip
= (uint_t
*)((void *)opp
->oprom_array
);
2266 (void) memset(oppbuf
.buf
, 0, BUFSIZE
);
2267 opp
->oprom_size
= MAXVALSIZE
;
2270 if (ioctl(fd
, OPROMCHILD
, opp
) < 0)
2273 return (*(uint_t
*)((void *)opp
->oprom_array
));
2277 * only on sparc for now
2280 devfs_bootdev_modifiable(void)
2285 return (DEVFS_NOTSUP
);