17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
5b6f77feas * Common Development and Distribution License (the "License").
6b6f77feas * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
217c478bdstevel@tonic-gate/*
22c279fc7sriman bhavanam - Sun Microsystems - Bangalore India * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bdstevel@tonic-gate * Use is subject to license terms.
247c478bdstevel@tonic-gate */
257c478bdstevel@tonic-gate
267c478bdstevel@tonic-gate
277c478bdstevel@tonic-gate#include <stdio.h>
287c478bdstevel@tonic-gate#include <string.h>
297c478bdstevel@tonic-gate#include <strings.h>
307c478bdstevel@tonic-gate#include <unistd.h>
317c478bdstevel@tonic-gate#include <stdlib.h>
327c478bdstevel@tonic-gate#include <thread.h>
337c478bdstevel@tonic-gate#include <synch.h>
347c478bdstevel@tonic-gate#include <sys/types.h>
357c478bdstevel@tonic-gate#include <ctype.h>
367c478bdstevel@tonic-gate#include <sys/stat.h>
377c478bdstevel@tonic-gate#include <fcntl.h>
387c478bdstevel@tonic-gate#include <sys/modctl.h>
397c478bdstevel@tonic-gate#include <errno.h>
407c478bdstevel@tonic-gate#include <sys/openpromio.h>
417c478bdstevel@tonic-gate#include <ftw.h>
427c478bdstevel@tonic-gate#include <sys/ddi.h>
437c478bdstevel@tonic-gate#include <sys/sunddi.h>
447c478bdstevel@tonic-gate#include <limits.h>
457c478bdstevel@tonic-gate
467c478bdstevel@tonic-gate#include "device_info.h"
477c478bdstevel@tonic-gate
487c478bdstevel@tonic-gate/*
497c478bdstevel@tonic-gate * #define's
507c478bdstevel@tonic-gate */
517c478bdstevel@tonic-gate
527c478bdstevel@tonic-gate/* alias node searching return values */
537c478bdstevel@tonic-gate#define	NO_MATCH	-1
547c478bdstevel@tonic-gate#define	EXACT_MATCH	1
557c478bdstevel@tonic-gate#define	INEXACT_MATCH	2
567c478bdstevel@tonic-gate
577c478bdstevel@tonic-gate/* for prom io operations */
587c478bdstevel@tonic-gate#define	BUFSIZE		4096
597c478bdstevel@tonic-gate#define	MAXPROPSIZE	256
607c478bdstevel@tonic-gate#define	MAXVALSIZE	(BUFSIZE - MAXPROPSIZE - sizeof (uint_t))
617c478bdstevel@tonic-gate
62b6f77feas/* prom_obp_vers() return values */
637c478bdstevel@tonic-gate#define	OBP_OF			0x4	/* versions OBP 3.x */
64b6f77feas#define	OBP_NO_ALIAS_NODE	0x8	/* No alias node */
657c478bdstevel@tonic-gate
667c478bdstevel@tonic-gate/* for nftw call */
677c478bdstevel@tonic-gate#define	FT_DEPTH	15
687c478bdstevel@tonic-gate
697c478bdstevel@tonic-gate/* default logical and physical device name space */
707c478bdstevel@tonic-gate#define	DEV	"/dev"
717c478bdstevel@tonic-gate#define	DEVICES	"/devices"
727c478bdstevel@tonic-gate
737c478bdstevel@tonic-gate/* for boot device identification on x86 */
747c478bdstevel@tonic-gate#define	CREATE_DISKMAP		"/boot/solaris/bin/create_diskmap"
757c478bdstevel@tonic-gate#define	GRUBDISK_MAP		"/var/run/solaris_grubdisk.map"
767c478bdstevel@tonic-gate
777c478bdstevel@tonic-gate/*
787c478bdstevel@tonic-gate * internal structure declarations
797c478bdstevel@tonic-gate */
807c478bdstevel@tonic-gate
817c478bdstevel@tonic-gate/* for prom io functions */
827c478bdstevel@tonic-gatetypedef union {
837c478bdstevel@tonic-gate	char buf[BUFSIZE];
847c478bdstevel@tonic-gate	struct openpromio opp;
857c478bdstevel@tonic-gate} Oppbuf;
867c478bdstevel@tonic-gate
877c478bdstevel@tonic-gate/* used to manage lists of devices and aliases */
887c478bdstevel@tonic-gatestruct name_list {
897c478bdstevel@tonic-gate	char *name;
907c478bdstevel@tonic-gate	struct name_list *next;
917c478bdstevel@tonic-gate};
927c478bdstevel@tonic-gate
937c478bdstevel@tonic-gate/*
947c478bdstevel@tonic-gate * internal global data
957c478bdstevel@tonic-gate */
967c478bdstevel@tonic-gate
977c478bdstevel@tonic-gate/* global since nftw does not let you pass args to be updated */
987c478bdstevel@tonic-gatestatic struct name_list **dev_list;
997c478bdstevel@tonic-gate
1007c478bdstevel@tonic-gate/* global since nftw does not let you pass args to be updated */
1017c478bdstevel@tonic-gatestatic struct boot_dev **bootdev_list;
1027c478bdstevel@tonic-gate
1037c478bdstevel@tonic-gate/* mutex to protect bootdev_list and dev_list */
1047c478bdstevel@tonic-gatestatic mutex_t dev_lists_lk = DEFAULTMUTEX;
1057c478bdstevel@tonic-gate
1067c478bdstevel@tonic-gate/*
1077c478bdstevel@tonic-gate * internal function prototypes
1087c478bdstevel@tonic-gate */
1097c478bdstevel@tonic-gate
1107c478bdstevel@tonic-gatestatic int prom_open(int);
1117c478bdstevel@tonic-gatestatic void prom_close(int);
1127c478bdstevel@tonic-gatestatic int is_openprom(int);
1137c478bdstevel@tonic-gate
1147c478bdstevel@tonic-gatestatic int prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf);
115b6f77feasstatic int alias_to_prom_dev(char *alias, char *ret_buf);
1167c478bdstevel@tonic-gatestatic int prom_srch_aliases_by_def(char *, struct name_list **,
1177c478bdstevel@tonic-gate    struct name_list **, int);
118b6f77feasstatic int prom_find_aliases_node(int fd);
1197c478bdstevel@tonic-gatestatic int prom_compare_devs(char *prom_dev1, char *prom_dev2);
1207c478bdstevel@tonic-gatestatic int _prom_strcmp(char *s1, char *s2);
121b6f77feasstatic int prom_srch_node(int fd, char *prop_name, char *ret_buf);
122b6f77feasstatic uint_t prom_next_node(int fd, uint_t node_id);
123b6f77feasstatic uint_t prom_child_node(int fd, uint_t node_id);
1247c478bdstevel@tonic-gate
1257c478bdstevel@tonic-gatestatic int prom_obp_vers(void);
1267c478bdstevel@tonic-gate
1277c478bdstevel@tonic-gatestatic void parse_name(char *, char **, char **, char **);
1287c478bdstevel@tonic-gatestatic int process_bootdev(const char *, const char *, struct boot_dev ***);
1297c478bdstevel@tonic-gatestatic int process_minor_name(char *dev_path, const char *default_root);
1307c478bdstevel@tonic-gatestatic void options_override(char *prom_path, char *alias_name);
1317c478bdstevel@tonic-gatestatic int devfs_phys_to_logical(struct boot_dev **bootdev_array,
1327c478bdstevel@tonic-gate	const int array_size, const char *default_root);
1337c478bdstevel@tonic-gatestatic int check_logical_dev(const char *, const struct stat *, int,
1347c478bdstevel@tonic-gate	struct FTW *);
1357c478bdstevel@tonic-gatestatic struct boot_dev *alloc_bootdev(char *);
1367c478bdstevel@tonic-gatestatic void free_name_list(struct name_list *list, int free_name);
1377c478bdstevel@tonic-gatestatic int insert_alias_list(struct name_list **list,
1387c478bdstevel@tonic-gate	char *alias_name);
1397c478bdstevel@tonic-gatestatic int get_boot_dev_var(struct openpromio *opp);
1407c478bdstevel@tonic-gatestatic int set_boot_dev_var(struct openpromio *opp, char *bootdev);
1417c478bdstevel@tonic-gatestatic int devfs_prom_to_dev_name(char *prom_path, char *dev_path);
1427c478bdstevel@tonic-gatestatic int devfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len);
1437c478bdstevel@tonic-gate
1447c478bdstevel@tonic-gate/*
1457c478bdstevel@tonic-gate * frees a list of paths from devfs_get_prom_name_list
1467c478bdstevel@tonic-gate */
1477c478bdstevel@tonic-gatestatic void
1487c478bdstevel@tonic-gateprom_list_free(char **prom_list)
1497c478bdstevel@tonic-gate{
1507c478bdstevel@tonic-gate	int i = 0;
1517c478bdstevel@tonic-gate
1527c478bdstevel@tonic-gate	if (!prom_list)
1537c478bdstevel@tonic-gate		return;
1547c478bdstevel@tonic-gate
1557c478bdstevel@tonic-gate	while (prom_list[i]) {
1567c478bdstevel@tonic-gate		free(prom_list[i]);
1577c478bdstevel@tonic-gate		i++;
1587c478bdstevel@tonic-gate	}
1597c478bdstevel@tonic-gate	free(prom_list);
1607c478bdstevel@tonic-gate}
1617c478bdstevel@tonic-gate
1627c478bdstevel@tonic-gatestatic int
1637c478bdstevel@tonic-gatedevfs_get_prom_name_list(const char *dev_name, char ***prom_list)
1647c478bdstevel@tonic-gate{
1657c478bdstevel@tonic-gate	char *prom_path = NULL;
1667c478bdstevel@tonic-gate	int count = 0;		/* # of slots we will need in prom_list */
1677c478bdstevel@tonic-gate	int ret, i, len;
1687c478bdstevel@tonic-gate	char **list;
1697c478bdstevel@tonic-gate	char *ptr;
1707c478bdstevel@tonic-gate
1717c478bdstevel@tonic-gate	if (dev_name == NULL)
1727c478bdstevel@tonic-gate		return (DEVFS_INVAL);
1737c478bdstevel@tonic-gate	if (*dev_name != '/')
1747c478bdstevel@tonic-gate		return (DEVFS_INVAL);
1757c478bdstevel@tonic-gate	if (prom_list == NULL)
1767c478bdstevel@tonic-gate		return (DEVFS_INVAL);
1777c478bdstevel@tonic-gate
1787c478bdstevel@tonic-gate	/*
1797c478bdstevel@tonic-gate	 * make sure we are on a machine which supports a prom
1807c478bdstevel@tonic-gate	 * and we have permission to use /dev/openprom
1817c478bdstevel@tonic-gate	 */
1827c478bdstevel@tonic-gate	if ((ret = prom_obp_vers()) < 0)
1837c478bdstevel@tonic-gate		return (ret);
1847c478bdstevel@tonic-gate	if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL)
1857c478bdstevel@tonic-gate		return (DEVFS_NOMEM);
1867c478bdstevel@tonic-gate	/*
1877c478bdstevel@tonic-gate	 * get the prom path name
1887c478bdstevel@tonic-gate	 */
1897c478bdstevel@tonic-gate	ret = devfs_dev_to_prom_names((char *)dev_name, prom_path, MAXVALSIZE);
1907c478bdstevel@tonic-gate	if (ret < 0) {
1917c478bdstevel@tonic-gate		free(prom_path);
1927c478bdstevel@tonic-gate		return (ret);
1937c478bdstevel@tonic-gate	}
1947c478bdstevel@tonic-gate	/* deal with list of names */
1957c478bdstevel@tonic-gate	for (i = 0; i < ret; i++)
1967c478bdstevel@tonic-gate		if (prom_path[i] == '\0')
1977c478bdstevel@tonic-gate			count++;
1987c478bdstevel@tonic-gate
1997c478bdstevel@tonic-gate	if ((list = (char **)calloc(count + 1, sizeof (char *))) == NULL) {
2007c478bdstevel@tonic-gate		free(prom_path);
2017c478bdstevel@tonic-gate		return (DEVFS_NOMEM);
2027c478bdstevel@tonic-gate	}
2037c478bdstevel@tonic-gate
2047c478bdstevel@tonic-gate	ptr = prom_path;
2057c478bdstevel@tonic-gate	for (i = 0; i < count; i++) {
2067c478bdstevel@tonic-gate		len = strlen(ptr) + 1;
2077c478bdstevel@tonic-gate		if ((list[i] = (char *)malloc(len)) == NULL) {
2087c478bdstevel@tonic-gate			free(prom_path);
2097c478bdstevel@tonic-gate			free(list);
2107c478bdstevel@tonic-gate			return (DEVFS_NOMEM);
2117c478bdstevel@tonic-gate		}
2127c478bdstevel@tonic-gate		(void) snprintf(list[i], len, "%s", ptr);
2137c478bdstevel@tonic-gate		ptr += len;
2147c478bdstevel@tonic-gate	}
2157c478bdstevel@tonic-gate
2167c478bdstevel@tonic-gate	free(prom_path);
2177c478bdstevel@tonic-gate
2187c478bdstevel@tonic-gate	*prom_list = list;
2197c478bdstevel@tonic-gate	return (0);
2207c478bdstevel@tonic-gate}
2217c478bdstevel@tonic-gate
2227c478bdstevel@tonic-gate/*
2237c478bdstevel@tonic-gate * retrieve the list of prom representations for a given device name
2247c478bdstevel@tonic-gate * the list will be sorted in the following order: exact aliases,
2257c478bdstevel@tonic-gate * inexact aliases, prom device path name.  If multiple matches occur
2267c478bdstevel@tonic-gate * for exact or inexact aliases, then these are sorted in collating
2277c478bdstevel@tonic-gate * order. The list is returned in prom_list
2287c478bdstevel@tonic-gate *
2297c478bdstevel@tonic-gate * the list may be restricted by specifying the correct flags in options.
2307c478bdstevel@tonic-gate */
2317c478bdstevel@tonic-gateint
2327c478bdstevel@tonic-gatedevfs_get_prom_names(const char *dev_name, uint_t options, char ***prom_list)
2337c478bdstevel@tonic-gate{
2347c478bdstevel@tonic-gate	char *prom_path = NULL;
2357c478bdstevel@tonic-gate	int count = 0;		/* # of slots we will need in prom_list */
2367c478bdstevel@tonic-gate	char **alias_list = NULL;
2377c478bdstevel@tonic-gate	char **list;
2387c478bdstevel@tonic-gate	int ret;
2397c478bdstevel@tonic-gate
2407c478bdstevel@tonic-gate	if (dev_name == NULL) {
2417c478bdstevel@tonic-gate		return (DEVFS_INVAL);
2427c478bdstevel@tonic-gate	}
2437c478bdstevel@tonic-gate	if (*dev_name != '/') {
2447c478bdstevel@tonic-gate		return (DEVFS_INVAL);
2457c478bdstevel@tonic-gate	}
2467c478bdstevel@tonic-gate	if (prom_list == NULL) {
2477c478bdstevel@tonic-gate		return (DEVFS_INVAL);
2487c478bdstevel@tonic-gate	}
2497c478bdstevel@tonic-gate	/*
2507c478bdstevel@tonic-gate	 * make sure we are on a machine which supports a prom
2517c478bdstevel@tonic-gate	 * and we have permission to use /dev/openprom
2527c478bdstevel@tonic-gate	 */
2537c478bdstevel@tonic-gate	if ((ret = prom_obp_vers()) < 0) {
2547c478bdstevel@tonic-gate		return (ret);
2557c478bdstevel@tonic-gate	}
2567c478bdstevel@tonic-gate	if ((prom_path = (char *)malloc(MAXPATHLEN)) == NULL) {
2577c478bdstevel@tonic-gate		return (DEVFS_NOMEM);
2587c478bdstevel@tonic-gate	}
2597c478bdstevel@tonic-gate	/*
2607c478bdstevel@tonic-gate	 * get the prom path name
2617c478bdstevel@tonic-gate	 */
2627c478bdstevel@tonic-gate	ret = devfs_dev_to_prom_name((char *)dev_name, prom_path);
2637c478bdstevel@tonic-gate	if (ret < 0) {
2647c478bdstevel@tonic-gate		free(prom_path);
2657c478bdstevel@tonic-gate		return (ret);
2667c478bdstevel@tonic-gate	}
2677c478bdstevel@tonic-gate	/* get the list of aliases (exact and inexact) */
2687c478bdstevel@tonic-gate	if ((ret = prom_dev_to_alias(prom_path, options, &alias_list)) < 0) {
2697c478bdstevel@tonic-gate		free(prom_path);
2707c478bdstevel@tonic-gate		return (ret);
2717c478bdstevel@tonic-gate	}
2727c478bdstevel@tonic-gate	/* now figure out how big the return array must be */
2737c478bdstevel@tonic-gate	if (alias_list != NULL) {
2747c478bdstevel@tonic-gate		while (alias_list[count] != NULL) {
2757c478bdstevel@tonic-gate			count++;
2767c478bdstevel@tonic-gate		}
2777c478bdstevel@tonic-gate	}
2787c478bdstevel@tonic-gate	if ((options & BOOTDEV_NO_PROM_PATH) == 0) {
2797c478bdstevel@tonic-gate		count++;	/* # of slots we will need in prom_list */
2807c478bdstevel@tonic-gate	}
2817c478bdstevel@tonic-gate	count++;	/* for the null terminator */
2827c478bdstevel@tonic-gate
2837c478bdstevel@tonic-gate	/* allocate space for the list */
2847c478bdstevel@tonic-gate	if ((list = (char **)calloc(count, sizeof (char *))) == NULL) {
2857c478bdstevel@tonic-gate		count = 0;
2867c478bdstevel@tonic-gate		while ((alias_list) && (alias_list[count] != NULL)) {
2877c478bdstevel@tonic-gate			free(alias_list[count]);
2887c478bdstevel@tonic-gate			count++;
2897c478bdstevel@tonic-gate		}
2907c478bdstevel@tonic-gate		free(alias_list);
2917c478bdstevel@tonic-gate		free(prom_path);
2927c478bdstevel@tonic-gate		return (DEVFS_NOMEM);
2937c478bdstevel@tonic-gate	}
2947c478bdstevel@tonic-gate	/* fill in the array and free the name list of aliases. */
2957c478bdstevel@tonic-gate	count = 0;
2967c478bdstevel@tonic-gate	while ((alias_list) && (alias_list[count] != NULL)) {
2977c478bdstevel@tonic-gate		list[count] = alias_list[count];
2987c478bdstevel@tonic-gate		count++;
2997c478bdstevel@tonic-gate	}
3007c478bdstevel@tonic-gate	if ((options & BOOTDEV_NO_PROM_PATH) == 0) {
3017c478bdstevel@tonic-gate		list[count] = prom_path;
3027c478bdstevel@tonic-gate	}
3037c478bdstevel@tonic-gate	if (alias_list != NULL) {
3047c478bdstevel@tonic-gate		free(alias_list);
3057c478bdstevel@tonic-gate	}
3067c478bdstevel@tonic-gate	*prom_list = list;
3077c478bdstevel@tonic-gate	return (0);
3087c478bdstevel@tonic-gate}
3097c478bdstevel@tonic-gate
3107c478bdstevel@tonic-gate/*
3117c478bdstevel@tonic-gate * Get a list prom-path translations for a solaris device.
3127c478bdstevel@tonic-gate *
3137c478bdstevel@tonic-gate * Returns the number of and all OBP paths and alias variants that
3147c478bdstevel@tonic-gate * reference the Solaris device path passed in.
3157c478bdstevel@tonic-gate */
3167c478bdstevel@tonic-gateint
3177c478bdstevel@tonic-gatedevfs_get_all_prom_names(const char *solaris_path, uint_t flags,
3187c478bdstevel@tonic-gate    struct devfs_prom_path **paths)
3197c478bdstevel@tonic-gate{
3207c478bdstevel@tonic-gate	int ret, len, i, count = 0;
3217c478bdstevel@tonic-gate	char *ptr, *prom_path;
3227c478bdstevel@tonic-gate	struct devfs_prom_path *cur = NULL, *new;
3237c478bdstevel@tonic-gate
3247c478bdstevel@tonic-gate	if ((ret = prom_obp_vers()) < 0)
3257c478bdstevel@tonic-gate		return (ret);
3267c478bdstevel@tonic-gate	if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL)
3277c478bdstevel@tonic-gate		return (DEVFS_NOMEM);
3287c478bdstevel@tonic-gate
3297c478bdstevel@tonic-gate	if ((ret = devfs_dev_to_prom_names((char *)solaris_path,
3307c478bdstevel@tonic-gate	    prom_path, MAXVALSIZE)) < 0) {
3317c478bdstevel@tonic-gate		free(prom_path);
3327c478bdstevel@tonic-gate		return (ret);
3337c478bdstevel@tonic-gate	}
3347c478bdstevel@tonic-gate
3357c478bdstevel@tonic-gate	for (i = 0; i < ret; i++)
3367c478bdstevel@tonic-gate		if (prom_path[i] == '\0')
3377c478bdstevel@tonic-gate			count++;
3387c478bdstevel@tonic-gate
3397c478bdstevel@tonic-gate	*paths = NULL;
3407c478bdstevel@tonic-gate	ptr = prom_path;
3417c478bdstevel@tonic-gate	for (i = 0; i < count; i++) {
3427c478bdstevel@tonic-gate		if ((new = (struct devfs_prom_path *)calloc(
3437c478bdstevel@tonic-gate		    sizeof (struct devfs_prom_path), 1)) == NULL) {
3447c478bdstevel@tonic-gate			free(prom_path);
3457c478bdstevel@tonic-gate			devfs_free_all_prom_names(*paths);
3467c478bdstevel@tonic-gate			return (DEVFS_NOMEM);
3477c478bdstevel@tonic-gate		}
3487c478bdstevel@tonic-gate
3497c478bdstevel@tonic-gate		if (cur == NULL)
3507c478bdstevel@tonic-gate			*paths = new;
3517c478bdstevel@tonic-gate		else
3527c478bdstevel@tonic-gate			cur->next = new;
3537c478bdstevel@tonic-gate		cur = new;
3547c478bdstevel@tonic-gate
3557c478bdstevel@tonic-gate		len = strlen(ptr) + 1;
3567c478bdstevel@tonic-gate		if ((cur->obp_path = (char *)calloc(len, 1)) == NULL) {
3577c478bdstevel@tonic-gate			free(prom_path);
3587c478bdstevel@tonic-gate			devfs_free_all_prom_names(*paths);
3597c478bdstevel@tonic-gate			return (DEVFS_NOMEM);
3607c478bdstevel@tonic-gate		}
3617c478bdstevel@tonic-gate
3627c478bdstevel@tonic-gate		(void) snprintf(cur->obp_path, len, "%s", ptr);
3637c478bdstevel@tonic-gate		ptr += len;
3647c478bdstevel@tonic-gate		if ((ret = prom_dev_to_alias(cur->obp_path, flags,
3657c478bdstevel@tonic-gate		    &(cur->alias_list))) < 0) {
3667c478bdstevel@tonic-gate			free(prom_path);
3677c478bdstevel@tonic-gate			devfs_free_all_prom_names(*paths);
3687c478bdstevel@tonic-gate			return (ret);
3697c478bdstevel@tonic-gate		}
3707c478bdstevel@tonic-gate	}
3717c478bdstevel@tonic-gate
3727c478bdstevel@tonic-gate	free(prom_path);
3737c478bdstevel@tonic-gate	return (count);
3747c478bdstevel@tonic-gate}
3757c478bdstevel@tonic-gate
3767c478bdstevel@tonic-gatevoid
3777c478bdstevel@tonic-gatedevfs_free_all_prom_names(struct devfs_prom_path *paths)
3787c478bdstevel@tonic-gate{
3797c478bdstevel@tonic-gate	int i;
3807c478bdstevel@tonic-gate
3817c478bdstevel@tonic-gate	if (paths == NULL)
3827c478bdstevel@tonic-gate		return;
3837c478bdstevel@tonic-gate
3847c478bdstevel@tonic-gate	devfs_free_all_prom_names(paths->next);
3857c478bdstevel@tonic-gate
3867c478bdstevel@tonic-gate	if (paths->obp_path != NULL)
3877c478bdstevel@tonic-gate		free(paths->obp_path);
3887c478bdstevel@tonic-gate
3897c478bdstevel@tonic-gate	if (paths->alias_list != NULL) {
3907c478bdstevel@tonic-gate		for (i = 0; paths->alias_list[i] != NULL; i++)
3917c478bdstevel@tonic-gate			if (paths->alias_list[i] != NULL)
3927c478bdstevel@tonic-gate				free(paths->alias_list[i]);
3937c478bdstevel@tonic-gate
3947c478bdstevel@tonic-gate		free(paths->alias_list);
3957c478bdstevel@tonic-gate	}
3967c478bdstevel@tonic-gate
3977c478bdstevel@tonic-gate	free(paths);
3987c478bdstevel@tonic-gate}
3997c478bdstevel@tonic-gate
4007c478bdstevel@tonic-gate/*
4017c478bdstevel@tonic-gate * Accepts a device name as an input argument.  Uses this to set the
4027c478bdstevel@tonic-gate * boot-device (or like) variable
4037c478bdstevel@tonic-gate *
4047c478bdstevel@tonic-gate * By default, this routine prepends to the list and converts the
4057c478bdstevel@tonic-gate * logical device name to its most compact prom representation.
4067c478bdstevel@tonic-gate * Available options include: converting the device name to a prom
4077c478bdstevel@tonic-gate * path name (but not an alias) or performing no conversion at all;
4087c478bdstevel@tonic-gate * overwriting the existing contents of boot-device rather than
4097c478bdstevel@tonic-gate * prepending.
4107c478bdstevel@tonic-gate */
4117c478bdstevel@tonic-gateint
4127c478bdstevel@tonic-gatedevfs_bootdev_set_list(const char *dev_name, const uint_t options)
4137c478bdstevel@tonic-gate{
4147c478bdstevel@tonic-gate	char *prom_path;
4157c478bdstevel@tonic-gate	char *new_bootdev;
4167c478bdstevel@tonic-gate	char *ptr;
4177c478bdstevel@tonic-gate	char **alias_list = NULL;
4187c478bdstevel@tonic-gate	char **prom_list = NULL;
4197c478bdstevel@tonic-gate	Oppbuf  oppbuf;
4207c478bdstevel@tonic-gate	struct openpromio *opp = &(oppbuf.opp);
4217c478bdstevel@tonic-gate	int ret, len, i, j;
4227c478bdstevel@tonic-gate
4237c478bdstevel@tonic-gate	if (devfs_bootdev_modifiable() != 0) {
4247c478bdstevel@tonic-gate		return (DEVFS_NOTSUP);
4257c478bdstevel@tonic-gate	}
4267c478bdstevel@tonic-gate	if (dev_name == NULL) {
4277c478bdstevel@tonic-gate		return (DEVFS_INVAL);
4287c478bdstevel@tonic-gate	}
4297c478bdstevel@tonic-gate	if (strlen(dev_name) >= MAXPATHLEN)
4307c478bdstevel@tonic-gate		return (DEVFS_INVAL);
4317c478bdstevel@tonic-gate
4327c478bdstevel@tonic-gate	if ((*dev_name != '/') && !(options & BOOTDEV_LITERAL)) {
4337c478bdstevel@tonic-gate		return (DEVFS_INVAL);
4347c478bdstevel@tonic-gate	}
4357c478bdstevel@tonic-gate	if ((options & BOOTDEV_LITERAL) && (options & BOOTDEV_PROMDEV)) {
4367c478bdstevel@tonic-gate		return (DEVFS_INVAL);
4377c478bdstevel@tonic-gate	}
4387c478bdstevel@tonic-gate	/*
4397c478bdstevel@tonic-gate	 * if we are prepending, make sure that this obp rev
4407c478bdstevel@tonic-gate	 * supports multiple boot device entries.
4417c478bdstevel@tonic-gate	 */
4427c478bdstevel@tonic-gate	ret = prom_obp_vers();
4437c478bdstevel@tonic-gate	if (ret < 0) {
4447c478bdstevel@tonic-gate		return (ret);
4457c478bdstevel@tonic-gate	}
4467c478bdstevel@tonic-gate
4477c478bdstevel@tonic-gate	if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL) {
4487c478bdstevel@tonic-gate		return (DEVFS_NOMEM);
4497c478bdstevel@tonic-gate	}
4507c478bdstevel@tonic-gate	if (options & BOOTDEV_LITERAL) {
4517c478bdstevel@tonic-gate		(void) strcpy(prom_path, dev_name);
4527c478bdstevel@tonic-gate	} else {
4537c478bdstevel@tonic-gate		/* need to convert to prom representation */
4547c478bdstevel@tonic-gate		ret = devfs_get_prom_name_list(dev_name, &prom_list);
4557c478bdstevel@tonic-gate		if (ret < 0) {
4567c478bdstevel@tonic-gate			free(prom_path);
4577c478bdstevel@tonic-gate			return (ret);
4587c478bdstevel@tonic-gate		}
4597c478bdstevel@tonic-gate
4607c478bdstevel@tonic-gate		len = MAXVALSIZE;
4617c478bdstevel@tonic-gate		i = 0;
4627c478bdstevel@tonic-gate		ptr = prom_path;
4637c478bdstevel@tonic-gate		while (prom_list && prom_list[i]) {
4647c478bdstevel@tonic-gate			if (!(options & BOOTDEV_PROMDEV)) {
4657c478bdstevel@tonic-gate				ret = prom_dev_to_alias(prom_list[i], 0,
466c279fc7sriman bhavanam - Sun Microsystems - Bangalore India				    &alias_list);
4677c478bdstevel@tonic-gate				if (ret < 0) {
4687c478bdstevel@tonic-gate					free(prom_path);
4697c478bdstevel@tonic-gate					prom_list_free(prom_list);
4707c478bdstevel@tonic-gate					return (ret);
4717c478bdstevel@tonic-gate				}
4727c478bdstevel@tonic-gate				if ((alias_list != NULL) &&
4737c478bdstevel@tonic-gate				    (alias_list[0] != NULL)) {
4747c478bdstevel@tonic-gate					(void) snprintf(ptr, len, "%s ",
4757c478bdstevel@tonic-gate					    alias_list[0]);
4767c478bdstevel@tonic-gate					for (ret = 0; alias_list[ret] != NULL;
4777c478bdstevel@tonic-gate					    ret++)
4787c478bdstevel@tonic-gate						free(alias_list[ret]);
4797c478bdstevel@tonic-gate				} else {
4807c478bdstevel@tonic-gate					(void) snprintf(ptr, len, "%s ",
4817c478bdstevel@tonic-gate					    prom_list[i]);
4827c478bdstevel@tonic-gate				}
4837c478bdstevel@tonic-gate				if (alias_list != NULL)
4847c478bdstevel@tonic-gate					free(alias_list);
4857c478bdstevel@tonic-gate			} else {
4867c478bdstevel@tonic-gate				(void) snprintf(ptr, len, "%s ", prom_list[i]);
4877c478bdstevel@tonic-gate			}
4887c478bdstevel@tonic-gate			j = strlen(ptr);
4897c478bdstevel@tonic-gate			len -= j;
4907c478bdstevel@tonic-gate			ptr += j;
4917c478bdstevel@tonic-gate			i++;
4927c478bdstevel@tonic-gate		}
4937c478bdstevel@tonic-gate		ptr--;
494f00128dToomas Soome		*ptr = 0;
4957c478bdstevel@tonic-gate
4967c478bdstevel@tonic-gate		prom_list_free(prom_list);
4977c478bdstevel@tonic-gate	}
4987c478bdstevel@tonic-gate	if (options & BOOTDEV_OVERWRITE) {
4997c478bdstevel@tonic-gate		new_bootdev = prom_path;
5007c478bdstevel@tonic-gate	} else {
5017c478bdstevel@tonic-gate		/* retrieve the current value of boot-device */
5027c478bdstevel@tonic-gate		ret = get_boot_dev_var(opp);
5037c478bdstevel@tonic-gate		if (ret < 0) {
5047c478bdstevel@tonic-gate			free(prom_path);
5057c478bdstevel@tonic-gate			return (ret);
5067c478bdstevel@tonic-gate		}
5077c478bdstevel@tonic-gate		/* prepend new entry - deal with duplicates */
5087c478bdstevel@tonic-gate		new_bootdev = (char *)malloc(strlen(opp->oprom_array)
5097c478bdstevel@tonic-gate		    + strlen(prom_path) + 2);
5107c478bdstevel@tonic-gate		if (new_bootdev == NULL) {
5117c478bdstevel@tonic-gate			free(prom_path);
5127c478bdstevel@tonic-gate			return (DEVFS_NOMEM);
5137c478bdstevel@tonic-gate		}
5147c478bdstevel@tonic-gate		(void) strcpy(new_bootdev, prom_path);
5157c478bdstevel@tonic-gate		if (opp->oprom_size > 0) {
5167c478bdstevel@tonic-gate			for (ptr = strtok(opp->oprom_array, " "); ptr != NULL;
5177c478bdstevel@tonic-gate			    ptr = strtok(NULL, " ")) {
5187c478bdstevel@tonic-gate				/* we strip out duplicates */
5197c478bdstevel@tonic-gate				if (strcmp(prom_path, ptr) == 0) {
5207c478bdstevel@tonic-gate					continue;
5217c478bdstevel@tonic-gate				}
5227c478bdstevel@tonic-gate				(void) strcat(new_bootdev, " ");
5237c478bdstevel@tonic-gate				(void) strcat(new_bootdev, ptr);
5247c478bdstevel@tonic-gate			}
5257c478bdstevel@tonic-gate		}
5267c478bdstevel@tonic-gate	}
5277c478bdstevel@tonic-gate
5287c478bdstevel@tonic-gate	/* now set the new value */
5297c478bdstevel@tonic-gate	ret = set_boot_dev_var(opp, new_bootdev);
5307c478bdstevel@tonic-gate
5317c478bdstevel@tonic-gate	if (options & BOOTDEV_OVERWRITE) {
5327c478bdstevel@tonic-gate		free(prom_path);
5337c478bdstevel@tonic-gate	} else {
5347c478bdstevel@tonic-gate		free(new_bootdev);
5357c478bdstevel@tonic-gate		free(prom_path);
5367c478bdstevel@tonic-gate	}
5377c478bdstevel@tonic-gate
5387c478bdstevel@tonic-gate	return (ret);
5397c478bdstevel@tonic-gate}
5407c478bdstevel@tonic-gate
5417c478bdstevel@tonic-gate/*
5427c478bdstevel@tonic-gate * sets the string bootdev as the new value for boot-device
5437c478bdstevel@tonic-gate */
5447c478bdstevel@tonic-gatestatic int
5457c478bdstevel@tonic-gateset_boot_dev_var(struct openpromio *opp, char *bootdev)
5467c478bdstevel@tonic-gate{
5477c478bdstevel@tonic-gate	int prom_fd;
5487c478bdstevel@tonic-gate	int i;
5497c478bdstevel@tonic-gate	int ret;
5507c478bdstevel@tonic-gate	char *valbuf;
5517c478bdstevel@tonic-gate	char *save_bootdev;
5527c478bdstevel@tonic-gate	char *bootdev_variables[] = {
5537c478bdstevel@tonic-gate		"boot-device",
5547c478bdstevel@tonic-gate		"bootdev",
5557c478bdstevel@tonic-gate		"boot-from",
5567c478bdstevel@tonic-gate		NULL
5577c478bdstevel@tonic-gate	};
5587c478bdstevel@tonic-gate	int found = 0;
5597c478bdstevel@tonic-gate	int *ip = (int *)((void *)opp->oprom_array);
5607c478bdstevel@tonic-gate
5617c478bdstevel@tonic-gate	/* query the prom */
5627c478bdstevel@tonic-gate	prom_fd = prom_open(O_RDWR);
5637c478bdstevel@tonic-gate	if (prom_fd < 0) {
5647c478bdstevel@tonic-gate		return (prom_fd);
5657c478bdstevel@tonic-gate	}
5667c478bdstevel@tonic-gate
5677c478bdstevel@tonic-gate	/* get the diagnostic-mode? property */
5687c478bdstevel@tonic-gate	(void) strcpy(opp->oprom_array, "diagnostic-mode?");
5697c478bdstevel@tonic-gate	opp->oprom_size = MAXVALSIZE;
5707c478bdstevel@tonic-gate	if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
5717c478bdstevel@tonic-gate		if ((opp->oprom_size > 0) &&
5727c478bdstevel@tonic-gate		    (strcmp(opp->oprom_array, "true") == 0)) {
5737c478bdstevel@tonic-gate			prom_close(prom_fd);
5747c478bdstevel@tonic-gate			return (DEVFS_ERR);
5757c478bdstevel@tonic-gate		}
5767c478bdstevel@tonic-gate	}
5777c478bdstevel@tonic-gate	/* get the diag-switch? property */
5787c478bdstevel@tonic-gate	(void) strcpy(opp->oprom_array, "diag-switch?");
5797c478bdstevel@tonic-gate	opp->oprom_size = MAXVALSIZE;
5807c478bdstevel@tonic-gate	if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
5817c478bdstevel@tonic-gate		if ((opp->oprom_size > 0) &&
5827c478bdstevel@tonic-gate		    (strcmp(opp->oprom_array, "true") == 0)) {
5837c478bdstevel@tonic-gate			prom_close(prom_fd);
5847c478bdstevel@tonic-gate			return (DEVFS_ERR);
5857c478bdstevel@tonic-gate		}
5867c478bdstevel@tonic-gate	}
5877c478bdstevel@tonic-gate	/*
5887c478bdstevel@tonic-gate	 * look for one of the following properties in order:
5897c478bdstevel@tonic-gate	 *	boot-device
5907c478bdstevel@tonic-gate	 *	bootdev
5917c478bdstevel@tonic-gate	 *	boot-from
5927c478bdstevel@tonic-gate	 *
5937c478bdstevel@tonic-gate	 * Use the first one that we find.
5947c478bdstevel@tonic-gate	 */
5957c478bdstevel@tonic-gate	*ip = 0;
5967c478bdstevel@tonic-gate	opp->oprom_size = MAXPROPSIZE;
5977c478bdstevel@tonic-gate	while ((opp->oprom_size != 0) && (!found)) {
5987c478bdstevel@tonic-gate		opp->oprom_size = MAXPROPSIZE;
5997c478bdstevel@tonic-gate		if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) {
6007c478bdstevel@tonic-gate			break;
6017c478bdstevel@tonic-gate		}
6027c478bdstevel@tonic-gate		for (i = 0; bootdev_variables[i] != NULL; i++) {
6037c478bdstevel@tonic-gate			if (strcmp(opp->oprom_array, bootdev_variables[i])
6047c478bdstevel@tonic-gate			    == 0) {
6057c478bdstevel@tonic-gate				found = 1;
6067c478bdstevel@tonic-gate				break;
6077c478bdstevel@tonic-gate			}
6087c478bdstevel@tonic-gate		}
6097c478bdstevel@tonic-gate	}
6107c478bdstevel@tonic-gate	if (found) {
6117c478bdstevel@tonic-gate		(void) strcpy(opp->oprom_array, bootdev_variables[i]);
6127c478bdstevel@tonic-gate		opp->oprom_size = MAXVALSIZE;
6137c478bdstevel@tonic-gate		if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
6147c478bdstevel@tonic-gate			prom_close(prom_fd);
6157c478bdstevel@tonic-gate			return (DEVFS_NOTSUP);
6167c478bdstevel@tonic-gate		}
6177c478bdstevel@tonic-gate	} else {
6187c478bdstevel@tonic-gate		prom_close(prom_fd);
6197c478bdstevel@tonic-gate		return (DEVFS_NOTSUP);
6207c478bdstevel@tonic-gate	}
6217c478bdstevel@tonic-gate
6227c478bdstevel@tonic-gate	/* save the old copy in case we fail */
6237c478bdstevel@tonic-gate	if ((save_bootdev = strdup(opp->oprom_array)) == NULL) {
6247c478bdstevel@tonic-gate		prom_close(prom_fd);
6257c478bdstevel@tonic-gate		return (DEVFS_NOMEM);
6267c478bdstevel@tonic-gate	}
6277c478bdstevel@tonic-gate	/* set up the new value of boot-device */
6287c478bdstevel@tonic-gate	(void) strcpy(opp->oprom_array, bootdev_variables[i]);
6297c478bdstevel@tonic-gate	valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1;
6307c478bdstevel@tonic-gate	(void) strcpy(valbuf, bootdev);
6317c478bdstevel@tonic-gate
6327c478bdstevel@tonic-gate	opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2;
6337c478bdstevel@tonic-gate
6347c478bdstevel@tonic-gate	if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) {
6357c478bdstevel@tonic-gate		free(save_bootdev);
6367c478bdstevel@tonic-gate		prom_close(prom_fd);
6377c478bdstevel@tonic-gate		return (DEVFS_ERR);
6387c478bdstevel@tonic-gate	}
6397c478bdstevel@tonic-gate
6407c478bdstevel@tonic-gate	/*
6417c478bdstevel@tonic-gate	 * now read it back to make sure it took
6427c478bdstevel@tonic-gate	 */
6437c478bdstevel@tonic-gate	(void) strcpy(opp->oprom_array, bootdev_variables[i]);
6447c478bdstevel@tonic-gate	opp->oprom_size = MAXVALSIZE;
6457c478bdstevel@tonic-gate	if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
6467c478bdstevel@tonic-gate		if (_prom_strcmp(opp->oprom_array, bootdev) == 0) {
6477c478bdstevel@tonic-gate			/* success */
6487c478bdstevel@tonic-gate			free(save_bootdev);
6497c478bdstevel@tonic-gate			prom_close(prom_fd);
6507c478bdstevel@tonic-gate			return (0);
6517c478bdstevel@tonic-gate		}
6527c478bdstevel@tonic-gate		/* deal with setting it to "" */
6537c478bdstevel@tonic-gate		if ((strlen(bootdev) == 0) && (opp->oprom_size == 0)) {
6547c478bdstevel@tonic-gate			/* success */
6557c478bdstevel@tonic-gate			free(save_bootdev);
6567c478bdstevel@tonic-gate			prom_close(prom_fd);
6577c478bdstevel@tonic-gate			return (0);
6587c478bdstevel@tonic-gate		}
6597c478bdstevel@tonic-gate	}
6607c478bdstevel@tonic-gate	/*
6617c478bdstevel@tonic-gate	 * something did not take - write out the old value and
6627c478bdstevel@tonic-gate	 * hope that we can restore things...
6637c478bdstevel@tonic-gate	 *
6647c478bdstevel@tonic-gate	 * unfortunately, there is no way for us to differentiate
6657c478bdstevel@tonic-gate	 * whether we exceeded the maximum number of characters
6667c478bdstevel@tonic-gate	 * allowable.  The limit varies from prom rev to prom
6677c478bdstevel@tonic-gate	 * rev, and on some proms, when the limit is
6687c478bdstevel@tonic-gate	 * exceeded, whatever was in the
6697c478bdstevel@tonic-gate	 * boot-device variable becomes unreadable.
6707c478bdstevel@tonic-gate	 *
6717c478bdstevel@tonic-gate	 * so if we fail, we will assume we ran out of room.  If we
6727c478bdstevel@tonic-gate	 * not able to restore the original setting, then we will
6737c478bdstevel@tonic-gate	 * return DEVFS_ERR instead.
6747c478bdstevel@tonic-gate	 */
6757c478bdstevel@tonic-gate	ret = DEVFS_LIMIT;
6767c478bdstevel@tonic-gate	(void) strcpy(opp->oprom_array, bootdev_variables[i]);
6777c478bdstevel@tonic-gate	valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1;
6787c478bdstevel@tonic-gate	(void) strcpy(valbuf, save_bootdev);
6797c478bdstevel@tonic-gate
6807c478bdstevel@tonic-gate	opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2;
6817c478bdstevel@tonic-gate
6827c478bdstevel@tonic-gate	if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) {
6837c478bdstevel@tonic-gate		ret = DEVFS_ERR;
6847c478bdstevel@tonic-gate	}
6857c478bdstevel@tonic-gate	free(save_bootdev);
6867c478bdstevel@tonic-gate	prom_close(prom_fd);
6877c478bdstevel@tonic-gate	return (ret);
6887c478bdstevel@tonic-gate}
6897c478bdstevel@tonic-gate/*
6907c478bdstevel@tonic-gate * retrieve the current value for boot-device
6917c478bdstevel@tonic-gate */
6927c478bdstevel@tonic-gatestatic int
6937c478bdstevel@tonic-gateget_boot_dev_var(struct openpromio *opp)
6947c478bdstevel@tonic-gate{
6957c478bdstevel@tonic-gate	int prom_fd;
6967c478bdstevel@tonic-gate	int i;
6977c478bdstevel@tonic-gate	char *bootdev_variables[] = {
6987c478bdstevel@tonic-gate		"boot-device",
6997c478bdstevel@tonic-gate		"bootdev",
7007c478bdstevel@tonic-gate		"boot-from",
7017c478bdstevel@tonic-gate		NULL
7027c478bdstevel@tonic-gate	};
7037c478bdstevel@tonic-gate	int found = 0;
7047c478bdstevel@tonic-gate	int *ip = (int *)((void *)opp->oprom_array);
7057c478bdstevel@tonic-gate
7067c478bdstevel@tonic-gate	/* query the prom */
7077c478bdstevel@tonic-gate	prom_fd = prom_open(O_RDONLY);
7087c478bdstevel@tonic-gate	if (prom_fd < 0) {
7097c478bdstevel@tonic-gate		return (prom_fd);
7107c478bdstevel@tonic-gate	}
7117c478bdstevel@tonic-gate
7127c478bdstevel@tonic-gate	/* get the diagnostic-mode? property */
7137c478bdstevel@tonic-gate	(void) strcpy(opp->oprom_array, "diagnostic-mode?");
7147c478bdstevel@tonic-gate	opp->oprom_size = MAXVALSIZE;
7157c478bdstevel@tonic-gate	if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
7167c478bdstevel@tonic-gate		if ((opp->oprom_size > 0) &&
7177c478bdstevel@tonic-gate		    (strcmp(opp->oprom_array, "true") == 0)) {
7187c478bdstevel@tonic-gate			prom_close(prom_fd);
7197c478bdstevel@tonic-gate			return (DEVFS_ERR);
7207c478bdstevel@tonic-gate		}
7217c478bdstevel@tonic-gate	}
7227c478bdstevel@tonic-gate	/* get the diag-switch? property */
7237c478bdstevel@tonic-gate	(void) strcpy(opp->oprom_array, "diag-switch?");
7247c478bdstevel@tonic-gate	opp->oprom_size = MAXVALSIZE;
7257c478bdstevel@tonic-gate	if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
7267c478bdstevel@tonic-gate		if ((opp->oprom_size > 0) &&
7277c478bdstevel@tonic-gate		    (strcmp(opp->oprom_array, "true") == 0)) {
7287c478bdstevel@tonic-gate			prom_close(prom_fd);
7297c478bdstevel@tonic-gate			return (DEVFS_ERR);
7307c478bdstevel@tonic-gate		}
7317c478bdstevel@tonic-gate	}
7327c478bdstevel@tonic-gate	/*
7337c478bdstevel@tonic-gate	 * look for one of the following properties in order:
7347c478bdstevel@tonic-gate	 *	boot-device
7357c478bdstevel@tonic-gate	 *	bootdev
7367c478bdstevel@tonic-gate	 *	boot-from
7377c478bdstevel@tonic-gate	 *
7387c478bdstevel@tonic-gate	 * Use the first one that we find.
7397c478bdstevel@tonic-gate	 */
7407c478bdstevel@tonic-gate	*ip = 0;
7417c478bdstevel@tonic-gate	opp->oprom_size = MAXPROPSIZE;
7427c478bdstevel@tonic-gate	while ((opp->oprom_size != 0) && (!found)) {
7437c478bdstevel@tonic-gate		opp->oprom_size = MAXPROPSIZE;
7447c478bdstevel@tonic-gate		if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) {
7457c478bdstevel@tonic-gate			break;
7467c478bdstevel@tonic-gate		}
7477c478bdstevel@tonic-gate		for (i = 0; bootdev_variables[i] != NULL; i++) {
7487c478bdstevel@tonic-gate			if (strcmp(opp->oprom_array, bootdev_variables[i])
7497c478bdstevel@tonic-gate			    == 0) {
7507c478bdstevel@tonic-gate				found = 1;
7517c478bdstevel@tonic-gate				break;
7527c478bdstevel@tonic-gate			}
7537c478bdstevel@tonic-gate		}
7547c478bdstevel@tonic-gate	}
7557c478bdstevel@tonic-gate	if (found) {
7567c478bdstevel@tonic-gate		(void) strcpy(opp->oprom_array, bootdev_variables[i]);
7577c478bdstevel@tonic-gate		opp->oprom_size = MAXVALSIZE;
7587c478bdstevel@tonic-gate		if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
7597c478bdstevel@tonic-gate			prom_close(prom_fd);
7607c478bdstevel@tonic-gate			return (DEVFS_ERR);
7617c478bdstevel@tonic-gate		}
7627c478bdstevel@tonic-gate		/* boot-device exists but contains nothing */
7637c478bdstevel@tonic-gate		if (opp->oprom_size == 0) {
7647c478bdstevel@tonic-gate			*opp->oprom_array = '\0';
7657c478bdstevel@tonic-gate		}
7667c478bdstevel@tonic-gate	} else {
7677c478bdstevel@tonic-gate		prom_close(prom_fd);
7687c478bdstevel@tonic-gate		return (DEVFS_NOTSUP);
7697c478bdstevel@tonic-gate	}
7707c478bdstevel@tonic-gate	prom_close(prom_fd);
7717c478bdstevel@tonic-gate	return (0);
7727c478bdstevel@tonic-gate}
7737c478bdstevel@tonic-gate
7747c478bdstevel@tonic-gate#ifndef __sparc
7757c478bdstevel@tonic-gatestatic FILE *
7767c478bdstevel@tonic-gateopen_diskmap(void)
7777c478bdstevel@tonic-gate{
7787c478bdstevel@tonic-gate	FILE *fp;
7797c478bdstevel@tonic-gate	char cmd[PATH_MAX];
7807c478bdstevel@tonic-gate
7817c478bdstevel@tonic-gate	/* make sure we have a map file */
7827c478bdstevel@tonic-gate	fp = fopen(GRUBDISK_MAP, "r");
7837c478bdstevel@tonic-gate	if (fp == NULL) {
7847c478bdstevel@tonic-gate		(void) snprintf(cmd, sizeof (cmd),
7857c478bdstevel@tonic-gate		    "%s > /dev/null", CREATE_DISKMAP);
7867c478bdstevel@tonic-gate		(void) system(cmd);
7877c478bdstevel@tonic-gate		fp = fopen(GRUBDISK_MAP, "r");
7887c478bdstevel@tonic-gate	}
7897c478bdstevel@tonic-gate	return (fp);
7907c478bdstevel@tonic-gate}
7917c478bdstevel@tonic-gate
7927c478bdstevel@tonic-gatestatic int
7937c478bdstevel@tonic-gatefind_x86_boot_device(struct openpromio *opp)
7947c478bdstevel@tonic-gate{
7957c478bdstevel@tonic-gate	int ret = DEVFS_ERR;
7967c478bdstevel@tonic-gate	char *cp, line[MAXVALSIZE + 6];
7977c478bdstevel@tonic-gate	FILE *file;
7987c478bdstevel@tonic-gate
7997c478bdstevel@tonic-gate	file = open_diskmap();
8007c478bdstevel@tonic-gate	if (file == NULL)
8017c478bdstevel@tonic-gate		return (DEVFS_ERR);
8027c478bdstevel@tonic-gate
8037c478bdstevel@tonic-gate	while (fgets(line, MAXVALSIZE + 6, file)) {
8047c478bdstevel@tonic-gate		if (strncmp(line, "0 ", 2) != 0)
8057c478bdstevel@tonic-gate			continue;
8067c478bdstevel@tonic-gate		/* drop new-line */
8077c478bdstevel@tonic-gate		line[strlen(line) - 1] = '\0';
8087c478bdstevel@tonic-gate		/*
8097c478bdstevel@tonic-gate		 * an x86 BIOS only boots a disk, not a partition
8107c478bdstevel@tonic-gate		 * or a slice, so hard-code :q (p0)
8117c478bdstevel@tonic-gate		 */
8127c478bdstevel@tonic-gate		cp = strchr(line + 2, ' ');
8137c478bdstevel@tonic-gate		if (cp == NULL)
8147c478bdstevel@tonic-gate			break;
8157c478bdstevel@tonic-gate		(void) snprintf(opp->oprom_array, MAXVALSIZE,
8167c478bdstevel@tonic-gate		    "%s:q", cp + 1);
8177c478bdstevel@tonic-gate		opp->oprom_size = MAXVALSIZE;
8187c478bdstevel@tonic-gate		ret = 0;
8197c478bdstevel@tonic-gate		break;
8207c478bdstevel@tonic-gate	}
8217c478bdstevel@tonic-gate	(void) fclose(file);
8227c478bdstevel@tonic-gate	return (ret);
8237c478bdstevel@tonic-gate}
8247c478bdstevel@tonic-gate#endif /* ndef __sparc */
8257c478bdstevel@tonic-gate
8267c478bdstevel@tonic-gate/*
8277c478bdstevel@tonic-gate * retrieve the list of entries in the boot-device configuration
8287c478bdstevel@tonic-gate * variable.  An array of boot_dev structs will be created, one entry
8297c478bdstevel@tonic-gate * for each device name in the boot-device variable.  Each entry
8307c478bdstevel@tonic-gate * in the array will contain the logical device representation of the
8317c478bdstevel@tonic-gate * boot-device entry, if any.
8327c478bdstevel@tonic-gate *
8337c478bdstevel@tonic-gate * default_root. if set, is used to locate logical device entries in
8347c478bdstevel@tonic-gate * directories other than /dev
8357c478bdstevel@tonic-gate */
8367c478bdstevel@tonic-gateint
8377c478bdstevel@tonic-gatedevfs_bootdev_get_list(const char *default_root,
838f00128dToomas Soome    struct boot_dev ***bootdev_list)
8397c478bdstevel@tonic-gate{
8407c478bdstevel@tonic-gate	Oppbuf  oppbuf;
8417c478bdstevel@tonic-gate	struct openpromio *opp = &(oppbuf.opp);
8427c478bdstevel@tonic-gate	int i;
8437c478bdstevel@tonic-gate	struct boot_dev **tmp_list;
8447c478bdstevel@tonic-gate
8457c478bdstevel@tonic-gate	if (default_root == NULL) {
8467c478bdstevel@tonic-gate		default_root = "";
8477c478bdstevel@tonic-gate	} else if (*default_root != '/') {
8487c478bdstevel@tonic-gate		return (DEVFS_INVAL);
8497c478bdstevel@tonic-gate	}
8507c478bdstevel@tonic-gate
8517c478bdstevel@tonic-gate	if (bootdev_list == NULL) {
8527c478bdstevel@tonic-gate		return (DEVFS_INVAL);
8537c478bdstevel@tonic-gate	}
8547c478bdstevel@tonic-gate
8557c478bdstevel@tonic-gate	/* get the boot-device variable */
8567c478bdstevel@tonic-gate#if defined(sparc)
8577c478bdstevel@tonic-gate	i = get_boot_dev_var(opp);
8587c478bdstevel@tonic-gate#else
8597c478bdstevel@tonic-gate	i = find_x86_boot_device(opp);
8607c478bdstevel@tonic-gate#endif
8617c478bdstevel@tonic-gate	if (i < 0) {
8627c478bdstevel@tonic-gate		return (i);
8637c478bdstevel@tonic-gate	}
8647c478bdstevel@tonic-gate	/* now try to translate each entry to a logical device. */
8657c478bdstevel@tonic-gate	i = process_bootdev(opp->oprom_array, default_root, &tmp_list);
8667c478bdstevel@tonic-gate	if (i == 0) {
8677c478bdstevel@tonic-gate		*bootdev_list = tmp_list;
8687c478bdstevel@tonic-gate		return (0);
8697c478bdstevel@tonic-gate	} else {
8707c478bdstevel@tonic-gate		return (i);
8717c478bdstevel@tonic-gate	}
8727c478bdstevel@tonic-gate}
8737c478bdstevel@tonic-gate
8747c478bdstevel@tonic-gate/*
8757c478bdstevel@tonic-gate * loop thru the list of entries in a boot-device configuration
8767c478bdstevel@tonic-gate * variable.
8777c478bdstevel@tonic-gate */
8787c478bdstevel@tonic-gatestatic int
8797c478bdstevel@tonic-gateprocess_bootdev(const char *bootdevice, const char *default_root,
880f00128dToomas Soome    struct boot_dev ***list)
8817c478bdstevel@tonic-gate{
8827c478bdstevel@tonic-gate	int i;
8837c478bdstevel@tonic-gate	char *entry, *ptr;
8847c478bdstevel@tonic-gate	char prom_path[MAXPATHLEN];
8857c478bdstevel@tonic-gate	char ret_buf[MAXPATHLEN];
8867c478bdstevel@tonic-gate	struct boot_dev **bootdev_array;
8877c478bdstevel@tonic-gate	int num_entries = 0;
8887c478bdstevel@tonic-gate	int found = 0;
8897c478bdstevel@tonic-gate	int vers;
8907c478bdstevel@tonic-gate
8917c478bdstevel@tonic-gate	if ((entry = (char *)malloc(strlen(bootdevice) + 1)) == NULL) {
8927c478bdstevel@tonic-gate		return (DEVFS_NOMEM);
8937c478bdstevel@tonic-gate	}
8947c478bdstevel@tonic-gate	/* count the number of entries */
8957c478bdstevel@tonic-gate	(void) strcpy(entry, bootdevice);
8967c478bdstevel@tonic-gate	for (ptr = strtok(entry, " "); ptr != NULL;
8977c478bdstevel@tonic-gate	    ptr = strtok(NULL, " ")) {
8987c478bdstevel@tonic-gate		num_entries++;
8997c478bdstevel@tonic-gate	}
9007c478bdstevel@tonic-gate	(void) strcpy(entry, bootdevice);
9017c478bdstevel@tonic-gate
9027c478bdstevel@tonic-gate	bootdev_array = (struct boot_dev **)
9037c478bdstevel@tonic-gate	    calloc((size_t)num_entries + 1, sizeof (struct boot_dev *));
9047c478bdstevel@tonic-gate
9057c478bdstevel@tonic-gate	if (bootdev_array == NULL) {
9067c478bdstevel@tonic-gate		free(entry);
9077c478bdstevel@tonic-gate		return (DEVFS_NOMEM);
9087c478bdstevel@tonic-gate	}
9097c478bdstevel@tonic-gate
9107c478bdstevel@tonic-gate	vers = prom_obp_vers();
9117c478bdstevel@tonic-gate	if (vers < 0) {
9127c478bdstevel@tonic-gate		free(entry);
9137c478bdstevel@tonic-gate		return (vers);
9147c478bdstevel@tonic-gate	}
9157c478bdstevel@tonic-gate
9167c478bdstevel@tonic-gate	/* for each entry in boot-device, do... */
9177c478bdstevel@tonic-gate	for (ptr = strtok(entry, " "), i = 0; ptr != NULL;
9187c478bdstevel@tonic-gate	    ptr = strtok(NULL, " "), i++) {
9197c478bdstevel@tonic-gate
9207c478bdstevel@tonic-gate		if ((bootdev_array[i] = alloc_bootdev(ptr)) == NULL) {
9217c478bdstevel@tonic-gate			devfs_bootdev_free_list(bootdev_array);
9227c478bdstevel@tonic-gate			free(entry);
9237c478bdstevel@tonic-gate			return (DEVFS_NOMEM);
9247c478bdstevel@tonic-gate		}
9257c478bdstevel@tonic-gate
926b6f77feas		/*
927b6f77feas		 * prom boot-device may be aliased, so we need to do
928b6f77feas		 * the necessary prom alias to dev translation.
929b6f77feas		 */
930b6f77feas		if (*ptr != '/') {
931b6f77feas			if (alias_to_prom_dev(ptr, prom_path) < 0) {
932b6f77feas				continue;
933b6f77feas			}
934b6f77feas		} else {
935b6f77feas			(void) strcpy(prom_path, ptr);
936b6f77feas		}
937b6f77feas
9387c478bdstevel@tonic-gate		/* now we have a prom device path - convert to a devfs name */
9397c478bdstevel@tonic-gate		if (devfs_prom_to_dev_name(prom_path, ret_buf) < 0) {
940c279fc7sriman bhavanam - Sun Microsystems - Bangalore India			continue;
9417c478bdstevel@tonic-gate		}
942b6f77feas
9437c478bdstevel@tonic-gate		/* append any default minor names necessary */
9447c478bdstevel@tonic-gate		if (process_minor_name(ret_buf, default_root) < 0) {
945c279fc7sriman bhavanam - Sun Microsystems - Bangalore India			continue;
9467c478bdstevel@tonic-gate		}
9477c478bdstevel@tonic-gate		found = 1;
948b6f77feas
9497c478bdstevel@tonic-gate		/*
9507c478bdstevel@tonic-gate		 * store the physical device path for now - when
9517c478bdstevel@tonic-gate		 * we are all done with the entries, we will convert
9527c478bdstevel@tonic-gate		 * these to their logical device name equivalents
9537c478bdstevel@tonic-gate		 */
9547c478bdstevel@tonic-gate		bootdev_array[i]->bootdev_trans[0] = strdup(ret_buf);
9557c478bdstevel@tonic-gate	}
9567c478bdstevel@tonic-gate	/*
9577c478bdstevel@tonic-gate	 * Convert all of the boot-device entries that translated to a
9587c478bdstevel@tonic-gate	 * physical device path in /devices to a logical device path
9597c478bdstevel@tonic-gate	 * in /dev (note that there may be several logical device paths
9607c478bdstevel@tonic-gate	 * associated with a single physical device path - return them all
9617c478bdstevel@tonic-gate	 */
9627c478bdstevel@tonic-gate	if (found) {
9637c478bdstevel@tonic-gate		if (devfs_phys_to_logical(bootdev_array, num_entries,
9647c478bdstevel@tonic-gate		    default_root) < 0) {
9657c478bdstevel@tonic-gate			devfs_bootdev_free_list(bootdev_array);
9667c478bdstevel@tonic-gate			bootdev_array = NULL;
9677c478bdstevel@tonic-gate		}
9687c478bdstevel@tonic-gate	}
9697c478bdstevel@tonic-gate	free(entry);
9707c478bdstevel@tonic-gate	*list = bootdev_array;
9717c478bdstevel@tonic-gate	return (0);
9727c478bdstevel@tonic-gate}
9737c478bdstevel@tonic-gate
9747c478bdstevel@tonic-gate/*
9757c478bdstevel@tonic-gate * We may get a device path from the prom that has no minor name
9767c478bdstevel@tonic-gate * information included in it.  Since this device name will not
9777c478bdstevel@tonic-gate * correspond directly to a physical device in /devices, we do our
9787c478bdstevel@tonic-gate * best to append what the default minor name should be and try this.
9797c478bdstevel@tonic-gate *
9807c478bdstevel@tonic-gate * For sparc: we append slice 0 (:a).
9817c478bdstevel@tonic-gate * For x86: we append fdisk partition 0 (:q).
9827c478bdstevel@tonic-gate */
9837c478bdstevel@tonic-gatestatic int
9847c478bdstevel@tonic-gateprocess_minor_name(char *dev_path, const char *root)
9857c478bdstevel@tonic-gate{
9867c478bdstevel@tonic-gate	char *cp;
9877c478bdstevel@tonic-gate#if defined(sparc)
9887c478bdstevel@tonic-gate	const char *default_minor_name = "a";
9897c478bdstevel@tonic-gate#else
9907c478bdstevel@tonic-gate	const char *default_minor_name = "q";
9917c478bdstevel@tonic-gate#endif
9927c478bdstevel@tonic-gate	int n;
9937c478bdstevel@tonic-gate	struct stat stat_buf;
9947c478bdstevel@tonic-gate	char path[MAXPATHLEN];
9957c478bdstevel@tonic-gate
9967c478bdstevel@tonic-gate	(void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path);
9977c478bdstevel@tonic-gate	/*
9987c478bdstevel@tonic-gate	 * if the device file already exists as given to us, there
9997c478bdstevel@tonic-gate	 * is nothing to do but return.
10007c478bdstevel@tonic-gate	 */
10017c478bdstevel@tonic-gate	if (stat(path, &stat_buf) == 0) {
10027c478bdstevel@tonic-gate		return (0);
10037c478bdstevel@tonic-gate	}
10047c478bdstevel@tonic-gate	/*
10057c478bdstevel@tonic-gate	 * if there is no ':' after the last '/' character, or if there is
10067c478bdstevel@tonic-gate	 * a ':' with no specifier, append the default segment specifier
10077c478bdstevel@tonic-gate	 * ; if there is a ':' followed by a digit, this indicates
10087c478bdstevel@tonic-gate	 * a partition number (which does not map into the /devices name
10097c478bdstevel@tonic-gate	 * space), so strip the number and replace it with the letter
10107c478bdstevel@tonic-gate	 * that represents the partition index
10117c478bdstevel@tonic-gate	 */
10127c478bdstevel@tonic-gate	if ((cp = strrchr(dev_path, '/')) != NULL) {
10137c478bdstevel@tonic-gate		if ((cp = strchr(cp, ':')) == NULL) {
10147c478bdstevel@tonic-gate			(void) strcat(dev_path, ":");
10157c478bdstevel@tonic-gate			(void) strcat(dev_path, default_minor_name);
10167c478bdstevel@tonic-gate		} else if (*++cp == '\0') {
10177c478bdstevel@tonic-gate			(void) strcat(dev_path, default_minor_name);
10187c478bdstevel@tonic-gate		} else if (isdigit(*cp)) {
10197c478bdstevel@tonic-gate			n = atoi(cp);
10207c478bdstevel@tonic-gate			/* make sure to squash the digit */
10217c478bdstevel@tonic-gate			*cp = '\0';
10227c478bdstevel@tonic-gate			switch (n) {
1023c279fc7sriman bhavanam - Sun Microsystems - Bangalore India			case 0:	(void) strcat(dev_path, "q");
10247c478bdstevel@tonic-gate					break;
1025c279fc7sriman bhavanam - Sun Microsystems - Bangalore India			case 1:	(void) strcat(dev_path, "r");
10267c478bdstevel@tonic-gate					break;
1027c279fc7sriman bhavanam - Sun Microsystems - Bangalore India			case 2:	(void) strcat(dev_path, "s");
10287c478bdstevel@tonic-gate					break;
1029c279fc7sriman bhavanam - Sun Microsystems - Bangalore India			case 3:	(void) strcat(dev_path, "t");
10307c478bdstevel@tonic-gate					break;
1031c279fc7sriman bhavanam - Sun Microsystems - Bangalore India			case 4:	(void) strcat(dev_path, "u");
10327c478bdstevel@tonic-gate					break;
1033c279fc7sriman bhavanam - Sun Microsystems - Bangalore India			default: (void) strcat(dev_path, "a");
10347c478bdstevel@tonic-gate					break;
10357c478bdstevel@tonic-gate			}
10367c478bdstevel@tonic-gate		}
10377c478bdstevel@tonic-gate	}
10387c478bdstevel@tonic-gate	/*
10397c478bdstevel@tonic-gate	 * see if we can find something now.
10407c478bdstevel@tonic-gate	 */
10417c478bdstevel@tonic-gate	(void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path);
10427c478bdstevel@tonic-gate
10437c478bdstevel@tonic-gate	if (stat(path, &stat_buf) == 0) {
10447c478bdstevel@tonic-gate		return (0);
10457c478bdstevel@tonic-gate	} else {
10467c478bdstevel@tonic-gate		return (-1);
10477c478bdstevel@tonic-gate	}
10487c478bdstevel@tonic-gate}
10497c478bdstevel@tonic-gate
10507c478bdstevel@tonic-gate/*
10517c478bdstevel@tonic-gate * for each entry in bootdev_array, convert the physical device
10527c478bdstevel@tonic-gate * representation of the boot-device entry to one or more logical device
10537c478bdstevel@tonic-gate * entries.  We use the hammer method - walk through the logical device
10547c478bdstevel@tonic-gate * name space looking for matches (/dev).  We use nftw to do this.
10557c478bdstevel@tonic-gate */
10567c478bdstevel@tonic-gatestatic int
10577c478bdstevel@tonic-gatedevfs_phys_to_logical(struct boot_dev **bootdev_array, const int array_size,
10587c478bdstevel@tonic-gate    const char *default_root)
10597c478bdstevel@tonic-gate{
10607c478bdstevel@tonic-gate	int walk_flags = FTW_PHYS | FTW_MOUNT;
10617c478bdstevel@tonic-gate	char *full_path;
10627c478bdstevel@tonic-gate	struct name_list *list;
10637c478bdstevel@tonic-gate	int count, i;
10647c478bdstevel@tonic-gate	char **dev_name_array;
10657c478bdstevel@tonic-gate	size_t default_root_len;
10667c478bdstevel@tonic-gate	char *dev_dir = DEV;
10677c478bdstevel@tonic-gate	int len;
10687c478bdstevel@tonic-gate
10697c478bdstevel@tonic-gate	if (array_size < 0) {
10707c478bdstevel@tonic-gate		return (-1);
10717c478bdstevel@tonic-gate	}
10727c478bdstevel@tonic-gate
10737c478bdstevel@tonic-gate	if (bootdev_array == NULL) {
10747c478bdstevel@tonic-gate		return (-1);
10757c478bdstevel@tonic-gate	}
10767c478bdstevel@tonic-gate	if (default_root == NULL) {
10777c478bdstevel@tonic-gate		return (-1);
10787c478bdstevel@tonic-gate	}
10797c478bdstevel@tonic-gate	default_root_len = strlen(default_root);
10807c478bdstevel@tonic-gate	if ((default_root_len != 0) && (*default_root != '/')) {
10817c478bdstevel@tonic-gate		return (-1);
10827c478bdstevel@tonic-gate	}
1083b6f77feas
10847c478bdstevel@tonic-gate	/* short cut for an empty array */
10857c478bdstevel@tonic-gate	if (*bootdev_array == NULL) {
10867c478bdstevel@tonic-gate		return (0);
10877c478bdstevel@tonic-gate	}
10887c478bdstevel@tonic-gate
10897c478bdstevel@tonic-gate	/* tell nftw where to start (default: /dev) */
10907c478bdstevel@tonic-gate	len = default_root_len + strlen(dev_dir) + 1;
10917c478bdstevel@tonic-gate	if ((full_path = (char *)malloc(len)) == NULL) {
10927c478bdstevel@tonic-gate		return (-1);
10937c478bdstevel@tonic-gate	}
1094b6f77feas
10957c478bdstevel@tonic-gate	/*
10967c478bdstevel@tonic-gate	 * if the default root path is terminated with a /, we have to
10977c478bdstevel@tonic-gate	 * make sure we don't end up with one too many slashes in the
10987c478bdstevel@tonic-gate	 * path we are building.
10997c478bdstevel@tonic-gate	 */
11007c478bdstevel@tonic-gate	if ((default_root_len > (size_t)0) &&
11017c478bdstevel@tonic-gate	    (default_root[default_root_len - 1] == '/')) {
11027c478bdstevel@tonic-gate		(void) snprintf(full_path, len, "%s%s", default_root,
11037c478bdstevel@tonic-gate		    &dev_dir[1]);
11047c478bdstevel@tonic-gate	} else {
11057c478bdstevel@tonic-gate		(void) snprintf(full_path, len, "%s%s", default_root, dev_dir);
11067c478bdstevel@tonic-gate	}
11077c478bdstevel@tonic-gate
11087c478bdstevel@tonic-gate	/*
11097c478bdstevel@tonic-gate	 * we need to muck with global data to make nftw work
11107c478bdstevel@tonic-gate	 * so single thread access
11117c478bdstevel@tonic-gate	 */
11127c478bdstevel@tonic-gate	(void) mutex_lock(&dev_lists_lk);
11137c478bdstevel@tonic-gate
11147c478bdstevel@tonic-gate	/*
11157c478bdstevel@tonic-gate	 * set the global vars bootdev_list and dev_list for use by nftw
11167c478bdstevel@tonic-gate	 * dev_list is an array of lists - one for each boot-device
11177c478bdstevel@tonic-gate	 * entry.  The nftw function will create a list of logical device
11187c478bdstevel@tonic-gate	 * entries for each boot-device and put all of the lists in
11197c478bdstevel@tonic-gate	 * dev_list.
11207c478bdstevel@tonic-gate	 */
11217c478bdstevel@tonic-gate	dev_list = (struct name_list **)
11227c478bdstevel@tonic-gate	    calloc(array_size, sizeof (struct name_list *));
11237c478bdstevel@tonic-gate	if (dev_list == NULL) {
11247c478bdstevel@tonic-gate		free(full_path);
11257c478bdstevel@tonic-gate		(void) mutex_unlock(&dev_lists_lk);
11267c478bdstevel@tonic-gate		return (-1);
11277c478bdstevel@tonic-gate	}
11287c478bdstevel@tonic-gate	bootdev_list = bootdev_array;
11297c478bdstevel@tonic-gate
11307c478bdstevel@tonic-gate	if (nftw(full_path, check_logical_dev, FT_DEPTH, walk_flags) == -1) {
11317c478bdstevel@tonic-gate		bootdev_list = NULL;
11327c478bdstevel@tonic-gate		free(full_path);
11337c478bdstevel@tonic-gate		for (i = 0; i < array_size; i++) {
11347c478bdstevel@tonic-gate			free_name_list(dev_list[i], 1);
11357c478bdstevel@tonic-gate		}
11367c478bdstevel@tonic-gate		/* don't free dev_list here because it's been handed off */
11377c478bdstevel@tonic-gate		dev_list = NULL;
11387c478bdstevel@tonic-gate		(void) mutex_unlock(&dev_lists_lk);
11397c478bdstevel@tonic-gate		return (-1);
11407c478bdstevel@tonic-gate	}
1141b6f77feas
11427c478bdstevel@tonic-gate	/*
11437c478bdstevel@tonic-gate	 * now we have a filled in dev_list.  So for each logical device
11447c478bdstevel@tonic-gate	 * list in dev_list, count the number of entries in the list,
11457c478bdstevel@tonic-gate	 * create an array of strings of logical devices, and save in the
11467c478bdstevel@tonic-gate	 * corresponding boot_dev structure.
11477c478bdstevel@tonic-gate	 */
11487c478bdstevel@tonic-gate	for (i = 0; i < array_size; i++) {
11497c478bdstevel@tonic-gate		/* get the next list */
11507c478bdstevel@tonic-gate		list = dev_list[i];
11517c478bdstevel@tonic-gate		count = 0;
11527c478bdstevel@tonic-gate
11537c478bdstevel@tonic-gate		/* count the number of entries in the list */
11547c478bdstevel@tonic-gate		while (list != NULL) {
11557c478bdstevel@tonic-gate			count++;
11567c478bdstevel@tonic-gate			list = list->next;
11577c478bdstevel@tonic-gate		}
11587c478bdstevel@tonic-gate		if ((dev_name_array =
11597c478bdstevel@tonic-gate		    (char **)malloc((count + 1) * sizeof (char *)))
11607c478bdstevel@tonic-gate		    == NULL) {
11617c478bdstevel@tonic-gate			continue;
11627c478bdstevel@tonic-gate		}
11637c478bdstevel@tonic-gate		list = dev_list[i];
11647c478bdstevel@tonic-gate		count = 0;
11657c478bdstevel@tonic-gate
11667c478bdstevel@tonic-gate		/* fill in the array */
11677c478bdstevel@tonic-gate		while (list != NULL) {
11687c478bdstevel@tonic-gate			dev_name_array[count] = list->name;
11697c478bdstevel@tonic-gate			count++;
11707c478bdstevel@tonic-gate			list = list->next;
11717c478bdstevel@tonic-gate		}
1172b6f77feas
11737c478bdstevel@tonic-gate		/*
11747c478bdstevel@tonic-gate		 * null terminate the array
11757c478bdstevel@tonic-gate		 */
11767c478bdstevel@tonic-gate		dev_name_array[count] = NULL;
1177b6f77feas		if ((bootdev_array[i] != NULL) && (bootdev_array[i]->
1178b6f77feas		    bootdev_trans[0] != NULL)) {
11797c478bdstevel@tonic-gate			free(bootdev_array[i]->bootdev_trans[0]);
11807c478bdstevel@tonic-gate		}
1181b6f77feas		if (bootdev_array[i] != NULL) {
1182b6f77feas			free(bootdev_array[i]->bootdev_trans);
1183b6f77feas			bootdev_array[i]->bootdev_trans = dev_name_array;
1184b6f77feas		}
11857c478bdstevel@tonic-gate	}
11867c478bdstevel@tonic-gate	bootdev_list = NULL;
11877c478bdstevel@tonic-gate	free(full_path);
11887c478bdstevel@tonic-gate	for (i = 0; i < array_size; i++) {
11897c478bdstevel@tonic-gate		free_name_list(dev_list[i], 0);
11907c478bdstevel@tonic-gate	}
11917c478bdstevel@tonic-gate	free(dev_list);
11927c478bdstevel@tonic-gate	dev_list = NULL;
11937c478bdstevel@tonic-gate	(void) mutex_unlock(&dev_lists_lk);
11947c478bdstevel@tonic-gate	return (0);
11957c478bdstevel@tonic-gate}
11967c478bdstevel@tonic-gate/*
11977c478bdstevel@tonic-gate * nftw function
11987c478bdstevel@tonic-gate * for a logical dev entry, it walks the list of boot-devices and
11997c478bdstevel@tonic-gate * sees if there are any matches.  If so, it saves the logical device
12007c478bdstevel@tonic-gate * name off in the appropriate list in dev_list
12017c478bdstevel@tonic-gate */
12027c478bdstevel@tonic-gate/* ARGSUSED */
12037c478bdstevel@tonic-gatestatic int
12047c478bdstevel@tonic-gatecheck_logical_dev(const char *node, const struct stat *node_stat, int flags,
1205f00128dToomas Soome    struct FTW *ftw_info)
12067c478bdstevel@tonic-gate{
12077c478bdstevel@tonic-gate	char link_buf[MAXPATHLEN];
12087c478bdstevel@tonic-gate	int link_buf_len;
12097c478bdstevel@tonic-gate	char *name;
12107c478bdstevel@tonic-gate	struct name_list *dev;
12117c478bdstevel@tonic-gate	char *physdev;
12127c478bdstevel@tonic-gate	int i;
12137c478bdstevel@tonic-gate
12147c478bdstevel@tonic-gate	if (flags != FTW_SL) {
12157c478bdstevel@tonic-gate		return (0);
12167c478bdstevel@tonic-gate	}
12177c478bdstevel@tonic-gate
12187c478bdstevel@tonic-gate	if ((link_buf_len = readlink(node, (void *)link_buf, MAXPATHLEN))
12197c478bdstevel@tonic-gate	    == -1) {
12207c478bdstevel@tonic-gate		return (0);
12217c478bdstevel@tonic-gate	}
12227c478bdstevel@tonic-gate	link_buf[link_buf_len] = '\0';
12237c478bdstevel@tonic-gate	if ((name = strstr(link_buf, DEVICES)) == NULL) {
12247c478bdstevel@tonic-gate		return (0);
12257c478bdstevel@tonic-gate	}
12267c478bdstevel@tonic-gate	name = (char *)(name + strlen(DEVICES));
12277c478bdstevel@tonic-gate
12287c478bdstevel@tonic-gate	for (i = 0; bootdev_list[i] != NULL; i++) {
12297c478bdstevel@tonic-gate		if (bootdev_list[i]->bootdev_trans[0] == NULL) {
12307c478bdstevel@tonic-gate			continue;
12317c478bdstevel@tonic-gate		}
12327c478bdstevel@tonic-gate		/*
12337c478bdstevel@tonic-gate		 * compare the contents of the link with the physical
12347c478bdstevel@tonic-gate		 * device representation of this boot device
12357c478bdstevel@tonic-gate		 */
12367c478bdstevel@tonic-gate		physdev = bootdev_list[i]->bootdev_trans[0];
12377c478bdstevel@tonic-gate		if ((strcmp(name, physdev) == 0) &&
12387c478bdstevel@tonic-gate		    (strlen(name) == strlen(physdev))) {
12397c478bdstevel@tonic-gate			if ((dev = (struct name_list *)
12407c478bdstevel@tonic-gate			    malloc(sizeof (struct name_list))) == NULL) {
12417c478bdstevel@tonic-gate				return (-1);
12427c478bdstevel@tonic-gate			}
12437c478bdstevel@tonic-gate			if ((dev->name = strdup(node)) == NULL) {
12447c478bdstevel@tonic-gate				free(dev);
12457c478bdstevel@tonic-gate				return (-1);
12467c478bdstevel@tonic-gate			}
12477c478bdstevel@tonic-gate			if (dev_list[i] == NULL) {
12487c478bdstevel@tonic-gate				dev_list[i] = dev;
12497c478bdstevel@tonic-gate				dev_list[i]->next = NULL;
12507c478bdstevel@tonic-gate			} else {
12517c478bdstevel@tonic-gate				dev->next = dev_list[i];
12527c478bdstevel@tonic-gate				dev_list[i] = dev;
12537c478bdstevel@tonic-gate			}
12547c478bdstevel@tonic-gate		}
12557c478bdstevel@tonic-gate	}
12567c478bdstevel@tonic-gate	return (0);
12577c478bdstevel@tonic-gate}
12587c478bdstevel@tonic-gate
12597c478bdstevel@tonic-gate/*
12607c478bdstevel@tonic-gate * frees a list of boot_dev struct pointers
12617c478bdstevel@tonic-gate */
12627c478bdstevel@tonic-gatevoid
12637c478bdstevel@tonic-gatedevfs_bootdev_free_list(struct boot_dev **array)
12647c478bdstevel@tonic-gate{
12657c478bdstevel@tonic-gate	int i = 0;
12667c478bdstevel@tonic-gate	int j;
12677c478bdstevel@tonic-gate
12687c478bdstevel@tonic-gate	if (array == NULL) {
12697c478bdstevel@tonic-gate		return;
12707c478bdstevel@tonic-gate	}
12717c478bdstevel@tonic-gate
12727c478bdstevel@tonic-gate	while (array[i] != NULL) {
12737c478bdstevel@tonic-gate		free(array[i]->bootdev_element);
12747c478bdstevel@tonic-gate		j = 0;
12757c478bdstevel@tonic-gate		while (array[i]->bootdev_trans[j] != NULL) {
12767c478bdstevel@tonic-gate			free(array[i]->bootdev_trans[j++]);
12777c478bdstevel@tonic-gate		}
12787c478bdstevel@tonic-gate		free(array[i]->bootdev_trans);
12797c478bdstevel@tonic-gate		free(array[i]);
12807c478bdstevel@tonic-gate		i++;
12817c478bdstevel@tonic-gate	}
12827c478bdstevel@tonic-gate	free(array);
12837c478bdstevel@tonic-gate}
12847c478bdstevel@tonic-gate/*
12857c478bdstevel@tonic-gate * allocates a boot_dev struct and fills in the bootdev_element portion
12867c478bdstevel@tonic-gate */
12877c478bdstevel@tonic-gatestatic struct boot_dev *
12887c478bdstevel@tonic-gatealloc_bootdev(char *entry_name)
12897c478bdstevel@tonic-gate{
12907c478bdstevel@tonic-gate	struct boot_dev *entry;
12917c478bdstevel@tonic-gate
12927c478bdstevel@tonic-gate	entry = (struct boot_dev *)calloc(1, sizeof (struct boot_dev));
12937c478bdstevel@tonic-gate
12947c478bdstevel@tonic-gate	if (entry == NULL) {
12957c478bdstevel@tonic-gate		return (NULL);
12967c478bdstevel@tonic-gate	}
12977c478bdstevel@tonic-gate	if ((entry->bootdev_element = strdup(entry_name)) == NULL) {
12987c478bdstevel@tonic-gate		free(entry);
12997c478bdstevel@tonic-gate		return (NULL);
13007c478bdstevel@tonic-gate	}
13017c478bdstevel@tonic-gate	/*
13027c478bdstevel@tonic-gate	 * Allocate room for 1 name and a null terminator - the caller of
13037c478bdstevel@tonic-gate	 * this function will need the first slot right away.
13047c478bdstevel@tonic-gate	 */
13057c478bdstevel@tonic-gate	if ((entry->bootdev_trans = (char **)calloc(2, sizeof (char *)))
13067c478bdstevel@tonic-gate	    == NULL) {
13077c478bdstevel@tonic-gate		free(entry->bootdev_element);
13087c478bdstevel@tonic-gate		free(entry);
13097c478bdstevel@tonic-gate		return (NULL);
13107c478bdstevel@tonic-gate	}
13117c478bdstevel@tonic-gate	return (entry);
13127c478bdstevel@tonic-gate}
13137c478bdstevel@tonic-gate
13147c478bdstevel@tonic-gate/*
13157c478bdstevel@tonic-gate * will come back with a concatenated list of paths
13167c478bdstevel@tonic-gate */
13177c478bdstevel@tonic-gateint
13187c478bdstevel@tonic-gatedevfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len)
13197c478bdstevel@tonic-gate{
13207c478bdstevel@tonic-gate	Oppbuf oppbuf;
13217c478bdstevel@tonic-gate	struct openpromio *opp = &(oppbuf.opp);
13227c478bdstevel@tonic-gate	int prom_fd;
13237c478bdstevel@tonic-gate	int ret = DEVFS_INVAL;
13247c478bdstevel@tonic-gate	int i;
13257c478bdstevel@tonic-gate
13267c478bdstevel@tonic-gate	if (prom_path == NULL) {
13277c478bdstevel@tonic-gate		return (DEVFS_INVAL);
13287c478bdstevel@tonic-gate	}
13297c478bdstevel@tonic-gate	if (dev_path == NULL) {
13307c478bdstevel@tonic-gate		return (DEVFS_INVAL);
13317c478bdstevel@tonic-gate	}
13327c478bdstevel@tonic-gate	if (strlen(dev_path) >= MAXPATHLEN)
13337c478bdstevel@tonic-gate		return (DEVFS_INVAL);
13347c478bdstevel@tonic-gate
13357c478bdstevel@tonic-gate	if (*dev_path != '/')
13367c478bdstevel@tonic-gate		return (DEVFS_INVAL);
13377c478bdstevel@tonic-gate
13387c478bdstevel@tonic-gate	prom_fd = prom_open(O_RDONLY);
13397c478bdstevel@tonic-gate	if (prom_fd < 0) {
13407c478bdstevel@tonic-gate		return (prom_fd);
13417c478bdstevel@tonic-gate	}
13427c478bdstevel@tonic-gate
13437c478bdstevel@tonic-gate	/* query the prom */
13447c478bdstevel@tonic-gate	(void) snprintf(opp->oprom_array, MAXVALSIZE, "%s", dev_path);
13457c478bdstevel@tonic-gate	opp->oprom_size = MAXVALSIZE;
13467c478bdstevel@tonic-gate
13477c478bdstevel@tonic-gate	if (ioctl(prom_fd, OPROMDEV2PROMNAME, opp) == 0) {
13487c478bdstevel@tonic-gate		prom_close(prom_fd);
13497c478bdstevel@tonic-gate
13507c478bdstevel@tonic-gate		/* return the prom path in prom_path */
13517c478bdstevel@tonic-gate
13527c478bdstevel@tonic-gate		i = len - opp->oprom_size;
13537c478bdstevel@tonic-gate		if (i < 0) {
13547c478bdstevel@tonic-gate			bcopy(opp->oprom_array, prom_path, len);
1355f00128dToomas Soome			prom_path[len - 1] = '\0';
13567c478bdstevel@tonic-gate			return (len);
13577c478bdstevel@tonic-gate		} else {
13587c478bdstevel@tonic-gate			bcopy(opp->oprom_array, prom_path, len);
13597c478bdstevel@tonic-gate			return (opp->oprom_size);
13607c478bdstevel@tonic-gate		}
13617c478bdstevel@tonic-gate	}
13627c478bdstevel@tonic-gate	/*
13637c478bdstevel@tonic-gate	 * either the prom does not support this ioctl or the argument
13647c478bdstevel@tonic-gate	 * was invalid.
13657c478bdstevel@tonic-gate	 */
13667c478bdstevel@tonic-gate	if (errno == ENXIO) {
13677c478bdstevel@tonic-gate		ret = DEVFS_NOTSUP;
13687c478bdstevel@tonic-gate	}
13697c478bdstevel@tonic-gate	prom_close(prom_fd);
13707c478bdstevel@tonic-gate	return (ret);
13717c478bdstevel@tonic-gate}
13727c478bdstevel@tonic-gate
13737c478bdstevel@tonic-gate/*
13747c478bdstevel@tonic-gate * Convert a physical or logical device name to a name the prom would
13757c478bdstevel@tonic-gate * understand.  Fail if this platform does not support a prom or if
13767c478bdstevel@tonic-gate * the device does not correspond to a valid prom device.
13777c478bdstevel@tonic-gate *      dev_path should be the name of a device in the logical or
13787c478bdstevel@tonic-gate *              physical device namespace.
13797c478bdstevel@tonic-gate *      prom_path is the prom version of the device name
13807c478bdstevel@tonic-gate *      prom_path must be large enough to contain the result and is
13817c478bdstevel@tonic-gate *      supplied by the user.
13827c478bdstevel@tonic-gate *
13837c478bdstevel@tonic-gate * This routine only supports converting leaf device paths
13847c478bdstevel@tonic-gate */
13857c478bdstevel@tonic-gateint
13867c478bdstevel@tonic-gatedevfs_dev_to_prom_name(char *dev_path, char *prom_path)
13877c478bdstevel@tonic-gate{
13887c478bdstevel@tonic-gate	int rval;
13897c478bdstevel@tonic-gate
13907c478bdstevel@tonic-gate	rval = devfs_dev_to_prom_names(dev_path, prom_path, MAXPATHLEN);
13917c478bdstevel@tonic-gate
13927c478bdstevel@tonic-gate	if (rval < 0)
13937c478bdstevel@tonic-gate		return (rval);
13947c478bdstevel@tonic-gate	else
13957c478bdstevel@tonic-gate		return (0);
13967c478bdstevel@tonic-gate}
13977c478bdstevel@tonic-gate
13987c478bdstevel@tonic-gate/*
13997c478bdstevel@tonic-gate * Use the openprom driver's OPROMPATH2DRV ioctl to convert a devfs
14007c478bdstevel@tonic-gate * path to a driver name.
14017c478bdstevel@tonic-gate * devfs_path - the pathname of interest.  This must be the physcical device
14027c478bdstevel@tonic-gate * path with the mount point prefix (ie. /devices) stripped off.
14037c478bdstevel@tonic-gate * drv_buf - user supplied buffer - the driver name will be stored here.
14047c478bdstevel@tonic-gate *
14057c478bdstevel@tonic-gate * If the prom lookup fails, we return the name of the last component in
14067c478bdstevel@tonic-gate * the pathname.  This routine is useful for looking up driver names
14077c478bdstevel@tonic-gate * associated with generically named devices.
14087c478bdstevel@tonic-gate *
14097c478bdstevel@tonic-gate * This routine returns driver names that have aliases resolved.
14107c478bdstevel@tonic-gate */
14117c478bdstevel@tonic-gateint
14127c478bdstevel@tonic-gatedevfs_path_to_drv(char *devfs_path, char *drv_buf)
14137c478bdstevel@tonic-gate{
14147c478bdstevel@tonic-gate	Oppbuf oppbuf;
14157c478bdstevel@tonic-gate	struct openpromio *opp = &(oppbuf.opp);
14167c478bdstevel@tonic-gate	char *slash, *colon, *dev_addr;
14177c478bdstevel@tonic-gate	char driver_path[MAXPATHLEN];
14187c478bdstevel@tonic-gate	int prom_fd;
14197c478bdstevel@tonic-gate
14207c478bdstevel@tonic-gate	if (drv_buf == NULL) {
14217c478bdstevel@tonic-gate		return (-1);
14227c478bdstevel@tonic-gate	}
14237c478bdstevel@tonic-gate	if (devfs_path == NULL) {
14247c478bdstevel@tonic-gate		return (-1);
14257c478bdstevel@tonic-gate	}
14267c478bdstevel@tonic-gate
14277c478bdstevel@tonic-gate	if (strlen(devfs_path) >= MAXPATHLEN)
14287c478bdstevel@tonic-gate		return (-1);
14297c478bdstevel@tonic-gate
14307c478bdstevel@tonic-gate	if (*devfs_path != '/')
14317c478bdstevel@tonic-gate		return (-1);
14327c478bdstevel@tonic-gate
14337c478bdstevel@tonic-gate
14347c478bdstevel@tonic-gate	/* strip off any minor node info at the end of the path */
14357c478bdstevel@tonic-gate	(void) strcpy(driver_path, devfs_path);
14367c478bdstevel@tonic-gate	slash = strrchr(driver_path, '/');
14377c478bdstevel@tonic-gate	if (slash == NULL)
14387c478bdstevel@tonic-gate		return (-1);
14397c478bdstevel@tonic-gate	colon = strrchr(slash, ':');
14407c478bdstevel@tonic-gate	if (colon != NULL)
14417c478bdstevel@tonic-gate		*colon = '\0';
14427c478bdstevel@tonic-gate
14437c478bdstevel@tonic-gate	/* query the prom */
14447c478bdstevel@tonic-gate	if ((prom_fd = prom_open(O_RDONLY)) >= 0) {
14457c478bdstevel@tonic-gate		(void) strcpy(opp->oprom_array, driver_path);
14467c478bdstevel@tonic-gate		opp->oprom_size = MAXVALSIZE;
14477c478bdstevel@tonic-gate
14487c478bdstevel@tonic-gate		if (ioctl(prom_fd, OPROMPATH2DRV, opp) == 0) {
14497c478bdstevel@tonic-gate			prom_close(prom_fd);
14507c478bdstevel@tonic-gate			/* return the driver name in drv_buf */
14517c478bdstevel@tonic-gate			(void) strcpy(drv_buf, opp->oprom_array);
14527c478bdstevel@tonic-gate			return (0);
14537c478bdstevel@tonic-gate		}
14547c478bdstevel@tonic-gate		prom_close(prom_fd);
14557c478bdstevel@tonic-gate	} else if (prom_fd != DEVFS_NOTSUP)
14567c478bdstevel@tonic-gate		return (-1);
14577c478bdstevel@tonic-gate	/*
14587c478bdstevel@tonic-gate	 * If we get here, then either:
14597c478bdstevel@tonic-gate	 *	1. this platform does not support an openprom driver
14607c478bdstevel@tonic-gate	 *	2. we were asked to look up a device the prom does
14617c478bdstevel@tonic-gate	 *	   not know about (e.g. a pseudo device)
14627c478bdstevel@tonic-gate	 * In this case, we use the last component of the devfs path
14637c478bdstevel@tonic-gate	 * name and try to derive the driver name
14647c478bdstevel@tonic-gate	 */
14657c478bdstevel@tonic-gate
14667c478bdstevel@tonic-gate	/* use the last component of devfs_path as the driver name */
14677c478bdstevel@tonic-gate	if ((dev_addr = strrchr(slash, '@')) != NULL)
14687c478bdstevel@tonic-gate		*dev_addr = '\0';
14697c478bdstevel@tonic-gate	slash++;
14707c478bdstevel@tonic-gate
14717c478bdstevel@tonic-gate	/* use opp->oprom_array as a buffer */
14727c478bdstevel@tonic-gate	(void) strcpy(opp->oprom_array, slash);
14737c478bdstevel@tonic-gate	if (devfs_resolve_aliases(opp->oprom_array) == NULL)
14747c478bdstevel@tonic-gate		return (-1);
14757c478bdstevel@tonic-gate	(void) strcpy(drv_buf, opp->oprom_array);
14767c478bdstevel@tonic-gate	return (0);
14777c478bdstevel@tonic-gate}
14787c478bdstevel@tonic-gate
14797c478bdstevel@tonic-gate/*
14807c478bdstevel@tonic-gate * These modctl calls do the equivalent of:
14817c478bdstevel@tonic-gate *	ddi_name_to_major()
14827c478bdstevel@tonic-gate *	ddi_major_to_name()
14837c478bdstevel@tonic-gate * This results in two things:
14847c478bdstevel@tonic-gate *	- the driver name must be a valid one
14857c478bdstevel@tonic-gate *	- any driver aliases are resolved.
14867c478bdstevel@tonic-gate * drv is overwritten with the resulting name.
14877c478bdstevel@tonic-gate */
14887c478bdstevel@tonic-gatechar *
14897c478bdstevel@tonic-gatedevfs_resolve_aliases(char *drv)
14907c478bdstevel@tonic-gate{
14917c478bdstevel@tonic-gate	major_t maj;
14927c478bdstevel@tonic-gate	char driver_name[MAXNAMELEN + 1];
14937c478bdstevel@tonic-gate
14947c478bdstevel@tonic-gate	if (drv == NULL) {
14957c478bdstevel@tonic-gate		return (NULL);
14967c478bdstevel@tonic-gate	}
14977c478bdstevel@tonic-gate
14987c478bdstevel@tonic-gate	if (modctl(MODGETMAJBIND, drv, strlen(drv) + 1, &maj) < 0)
14997c478bdstevel@tonic-gate		return (NULL);
15007c478bdstevel@tonic-gate	else if (modctl(MODGETNAME, driver_name, sizeof (driver_name), &maj)
15017c478bdstevel@tonic-gate	    < 0) {
15027c478bdstevel@tonic-gate		return (NULL);
15037c478bdstevel@tonic-gate	} else {
15047c478bdstevel@tonic-gate		(void) strcpy(drv, driver_name);
15057c478bdstevel@tonic-gate		return (drv);
15067c478bdstevel@tonic-gate	}
15077c478bdstevel@tonic-gate}
15087c478bdstevel@tonic-gate
15097c478bdstevel@tonic-gate/*
15107c478bdstevel@tonic-gate * open the openprom device.  and verify that we are on an
15117c478bdstevel@tonic-gate * OBP/1275 OF machine.  If the prom does not exist, then we
15127c478bdstevel@tonic-gate * return an error
15137c478bdstevel@tonic-gate */
15147c478bdstevel@tonic-gatestatic int
15157c478bdstevel@tonic-gateprom_open(int oflag)
15167c478bdstevel@tonic-gate{
15177c478bdstevel@tonic-gate	int prom_fd = -1;
15187c478bdstevel@tonic-gate	char *promdev = "/dev/openprom";
15197c478bdstevel@tonic-gate
15207c478bdstevel@tonic-gate	while (prom_fd < 0) {
15217c478bdstevel@tonic-gate		if ((prom_fd = open(promdev, oflag)) < 0)  {
15227c478bdstevel@tonic-gate			if (errno == EAGAIN)   {
15237c478bdstevel@tonic-gate				(void) sleep(5);
15247c478bdstevel@tonic-gate				continue;
15257c478bdstevel@tonic-gate			}
15267c478bdstevel@tonic-gate			if ((errno == ENXIO) || (errno == ENOENT)) {
15277c478bdstevel@tonic-gate				return (DEVFS_NOTSUP);
15287c478bdstevel@tonic-gate			}
15297c478bdstevel@tonic-gate			if ((errno == EPERM) || (errno == EACCES)) {
15307c478bdstevel@tonic-gate				return (DEVFS_PERM);
15317c478bdstevel@tonic-gate			}
15327c478bdstevel@tonic-gate			return (DEVFS_ERR);
15337c478bdstevel@tonic-gate		} else
15347c478bdstevel@tonic-gate			break;
15357c478bdstevel@tonic-gate	}
15367c478bdstevel@tonic-gate	if (is_openprom(prom_fd))
15377c478bdstevel@tonic-gate		return (prom_fd);
15387c478bdstevel@tonic-gate	else {
15397c478bdstevel@tonic-gate		prom_close(prom_fd);
15407c478bdstevel@tonic-gate		return (DEVFS_ERR);
15417c478bdstevel@tonic-gate	}
15427c478bdstevel@tonic-gate}
15437c478bdstevel@tonic-gate
15447c478bdstevel@tonic-gatestatic void
15457c478bdstevel@tonic-gateprom_close(int prom_fd)
15467c478bdstevel@tonic-gate{
15477c478bdstevel@tonic-gate	(void) close(prom_fd);
15487c478bdstevel@tonic-gate}
15497c478bdstevel@tonic-gate
15507c478bdstevel@tonic-gate/*
15517c478bdstevel@tonic-gate * is this an OBP/1275 OF machine?
15527c478bdstevel@tonic-gate */
15537c478bdstevel@tonic-gatestatic int
15547c478bdstevel@tonic-gateis_openprom(int prom_fd)
15557c478bdstevel@tonic-gate{
15567c478bdstevel@tonic-gate	Oppbuf  oppbuf;
15577c478bdstevel@tonic-gate	struct openpromio *opp = &(oppbuf.opp);
15587c478bdstevel@tonic-gate	unsigned int i;
15597c478bdstevel@tonic-gate
15607c478bdstevel@tonic-gate	opp->oprom_size = MAXVALSIZE;
15617c478bdstevel@tonic-gate	if (ioctl(prom_fd, OPROMGETCONS, opp) < 0)
15627c478bdstevel@tonic-gate		return (0);
15637c478bdstevel@tonic-gate
15647c478bdstevel@tonic-gate	i = (unsigned int)((unsigned char)opp->oprom_array[0]);
15657c478bdstevel@tonic-gate	return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM);
15667c478bdstevel@tonic-gate}
15677c478bdstevel@tonic-gate
15687c478bdstevel@tonic-gate/*
15697c478bdstevel@tonic-gate * convert a prom device path name to an equivalent physical device
15707c478bdstevel@tonic-gate * path in the kernel.
15717c478bdstevel@tonic-gate */
15727c478bdstevel@tonic-gatestatic int
15737c478bdstevel@tonic-gatedevfs_prom_to_dev_name(char *prom_path, char *dev_path)
15747c478bdstevel@tonic-gate{
15757c478bdstevel@tonic-gate	Oppbuf oppbuf;
15767c478bdstevel@tonic-gate	struct openpromio *opp = &(oppbuf.opp);
15777c478bdstevel@tonic-gate	int prom_fd;
15787c478bdstevel@tonic-gate	int ret = DEVFS_INVAL;
15797c478bdstevel@tonic-gate
15807c478bdstevel@tonic-gate	if (dev_path == NULL) {
15817c478bdstevel@tonic-gate		return (DEVFS_INVAL);
15827c478bdstevel@tonic-gate	}
15837c478bdstevel@tonic-gate	if (prom_path == NULL) {
15847c478bdstevel@tonic-gate		return (DEVFS_INVAL);
15857c478bdstevel@tonic-gate	}
15867c478bdstevel@tonic-gate	if (strlen(prom_path) >= MAXPATHLEN)
15877c478bdstevel@tonic-gate		return (DEVFS_INVAL);
15887c478bdstevel@tonic-gate
15897c478bdstevel@tonic-gate	if (*prom_path != '/') {
15907c478bdstevel@tonic-gate		return (DEVFS_INVAL);
15917c478bdstevel@tonic-gate	}
15927c478bdstevel@tonic-gate
15937c478bdstevel@tonic-gate	/* query the prom */
15947c478bdstevel@tonic-gate	prom_fd = prom_open(O_RDONLY);
15957c478bdstevel@tonic-gate	if (prom_fd < 0) {
15967c478bdstevel@tonic-gate		return (prom_fd);
15977c478bdstevel@tonic-gate	}
15987c478bdstevel@tonic-gate	(void) strcpy(opp->oprom_array, prom_path);
15997c478bdstevel@tonic-gate	opp->oprom_size = MAXVALSIZE;
16007c478bdstevel@tonic-gate
16017c478bdstevel@tonic-gate	if (ioctl(prom_fd, OPROMPROM2DEVNAME, opp) == 0) {
16027c478bdstevel@tonic-gate		prom_close(prom_fd);
16037c478bdstevel@tonic-gate		/*
16047c478bdstevel@tonic-gate		 * success
16057c478bdstevel@tonic-gate		 * return the prom path in prom_path
16067c478bdstevel@tonic-gate		 */
16077c478bdstevel@tonic-gate		(void) strcpy(dev_path, opp->oprom_array);
16087c478bdstevel@tonic-gate		return (0);
16097c478bdstevel@tonic-gate	}
16107c478bdstevel@tonic-gate	/*
16117c478bdstevel@tonic-gate	 * either the argument was not a valid name or the openprom
16127c478bdstevel@tonic-gate	 * driver does not support this ioctl.
16137c478bdstevel@tonic-gate	 */
16147c478bdstevel@tonic-gate	if (errno == ENXIO) {
16157c478bdstevel@tonic-gate		ret = DEVFS_NOTSUP;
16167c478bdstevel@tonic-gate	}
16177c478bdstevel@tonic-gate	prom_close(prom_fd);
16187c478bdstevel@tonic-gate	return (ret);
16197c478bdstevel@tonic-gate}
16207c478bdstevel@tonic-gate/*
16217c478bdstevel@tonic-gate * convert a prom device path to a list of equivalent alias names
16227c478bdstevel@tonic-gate * If there is no alias node, or there are no aliases that correspond
16237c478bdstevel@tonic-gate * to dev, we return empty lists.
16247c478bdstevel@tonic-gate */
16257c478bdstevel@tonic-gatestatic int
16267c478bdstevel@tonic-gateprom_dev_to_alias(char *dev, uint_t options, char ***ret_buf)
16277c478bdstevel@tonic-gate{
16287c478bdstevel@tonic-gate	struct name_list *exact_list;
16297c478bdstevel@tonic-gate	struct name_list *inexact_list;
16307c478bdstevel@tonic-gate	struct name_list *list;
16317c478bdstevel@tonic-gate	char *ptr;
16327c478bdstevel@tonic-gate	char **array;
16337c478bdstevel@tonic-gate	int prom_fd;
16347c478bdstevel@tonic-gate	int count;
16357c478bdstevel@tonic-gate	int vers;
16367c478bdstevel@tonic-gate
16377c478bdstevel@tonic-gate	vers = prom_obp_vers();
16387c478bdstevel@tonic-gate	if (vers < 0) {
16397c478bdstevel@tonic-gate		return (vers);
16407c478bdstevel@tonic-gate	}
16417c478bdstevel@tonic-gate
16427c478bdstevel@tonic-gate	if (dev == NULL) {
16437c478bdstevel@tonic-gate		return (DEVFS_INVAL);
16447c478bdstevel@tonic-gate	}
16457c478bdstevel@tonic-gate
16467c478bdstevel@tonic-gate	if (*dev != '/')
16477c478bdstevel@tonic-gate		return (DEVFS_INVAL);
16487c478bdstevel@tonic-gate
16497c478bdstevel@tonic-gate	if (strlen(dev) >= MAXPATHLEN)
16507c478bdstevel@tonic-gate		return (DEVFS_INVAL);
16517c478bdstevel@tonic-gate
16527c478bdstevel@tonic-gate	if ((ptr = strchr(dev, ':')) != NULL) {
16537c478bdstevel@tonic-gate		if (strchr(ptr, '/') != NULL)
16547c478bdstevel@tonic-gate			return (DEVFS_INVAL);
16557c478bdstevel@tonic-gate	}
16567c478bdstevel@tonic-gate	if (ret_buf == NULL) {
16577c478bdstevel@tonic-gate		return (DEVFS_INVAL);
16587c478bdstevel@tonic-gate	}
16597c478bdstevel@tonic-gate
16607c478bdstevel@tonic-gate	prom_fd = prom_open(O_RDONLY);
16617c478bdstevel@tonic-gate	if (prom_fd < 0) {
16627c478bdstevel@tonic-gate		return (prom_fd);
16637c478bdstevel@tonic-gate	}
16647c478bdstevel@tonic-gate
16657c478bdstevel@tonic-gate	(void) prom_srch_aliases_by_def(dev, &exact_list,
16667c478bdstevel@tonic-gate	    &inexact_list,  prom_fd);
16677c478bdstevel@tonic-gate
16687c478bdstevel@tonic-gate	prom_close(prom_fd);
16697c478bdstevel@tonic-gate
16707c478bdstevel@tonic-gate	if ((options & BOOTDEV_NO_EXACT_ALIAS) != 0) {
16717c478bdstevel@tonic-gate		free_name_list(exact_list, 1);
16727c478bdstevel@tonic-gate		exact_list = NULL;
16737c478bdstevel@tonic-gate	}
16747c478bdstevel@tonic-gate
16757c478bdstevel@tonic-gate	if ((options & BOOTDEV_NO_INEXACT_ALIAS) != 0) {
16767c478bdstevel@tonic-gate		free_name_list(inexact_list, 1);
16777c478bdstevel@tonic-gate		inexact_list = NULL;
16787c478bdstevel@tonic-gate	}
16797c478bdstevel@tonic-gate
16807c478bdstevel@tonic-gate	count = 0;
16817c478bdstevel@tonic-gate	list = exact_list;
16827c478bdstevel@tonic-gate	while (list != NULL) {
16837c478bdstevel@tonic-gate		list = list->next;
16847c478bdstevel@tonic-gate		count++;
16857c478bdstevel@tonic-gate	}
16867c478bdstevel@tonic-gate	list = inexact_list;
16877c478bdstevel@tonic-gate	while (list != NULL) {
16887c478bdstevel@tonic-gate		list = list->next;
16897c478bdstevel@tonic-gate		count++;
16907c478bdstevel@tonic-gate	}
16917c478bdstevel@tonic-gate
16927c478bdstevel@tonic-gate	if ((*ret_buf = (char **)malloc((count + 1) * sizeof (char *)))
16937c478bdstevel@tonic-gate	    == NULL) {
16947c478bdstevel@tonic-gate		free_name_list(inexact_list, 1);
16957c478bdstevel@tonic-gate		free_name_list(exact_list, 1);
16967c478bdstevel@tonic-gate		return (DEVFS_NOMEM);
16977c478bdstevel@tonic-gate	}
16987c478bdstevel@tonic-gate
16997c478bdstevel@tonic-gate	array = *ret_buf;
17007c478bdstevel@tonic-gate	count = 0;
17017c478bdstevel@tonic-gate	list = exact_list;
17027c478bdstevel@tonic-gate	while (list != NULL) {
17037c478bdstevel@tonic-gate		array[count] = list->name;
17047c478bdstevel@tonic-gate		list = list->next;
17057c478bdstevel@tonic-gate		count++;
17067c478bdstevel@tonic-gate	}
17077c478bdstevel@tonic-gate	list = inexact_list;
17087c478bdstevel@tonic-gate	while (list != NULL) {
17097c478bdstevel@tonic-gate		array[count] = list->name;
17107c478bdstevel@tonic-gate		list = list->next;
17117c478bdstevel@tonic-gate		count++;
17127c478bdstevel@tonic-gate	}
17137c478bdstevel@tonic-gate	array[count] = NULL;
17147c478bdstevel@tonic-gate	free_name_list(inexact_list, 0);
17157c478bdstevel@tonic-gate	free_name_list(exact_list, 0);
17167c478bdstevel@tonic-gate
17177c478bdstevel@tonic-gate	return (0);
17187c478bdstevel@tonic-gate}
17197c478bdstevel@tonic-gate
17207c478bdstevel@tonic-gate/*
17217c478bdstevel@tonic-gate * determine the version of prom we are running on.
17227c478bdstevel@tonic-gate * Also include any prom revision specific information.
17237c478bdstevel@tonic-gate */
17247c478bdstevel@tonic-gatestatic int
17257c478bdstevel@tonic-gateprom_obp_vers(void)
17267c478bdstevel@tonic-gate{
17277c478bdstevel@tonic-gate	Oppbuf  oppbuf;
17287c478bdstevel@tonic-gate	struct openpromio *opp = &(oppbuf.opp);
17297c478bdstevel@tonic-gate	int prom_fd;
17307c478bdstevel@tonic-gate	static int version = 0;
17317c478bdstevel@tonic-gate
17327c478bdstevel@tonic-gate	/* cache version */
17337c478bdstevel@tonic-gate	if (version > 0) {
17347c478bdstevel@tonic-gate		return (version);
17357c478bdstevel@tonic-gate	}
17367c478bdstevel@tonic-gate
17377c478bdstevel@tonic-gate	prom_fd = prom_open(O_RDONLY);
17387c478bdstevel@tonic-gate	if (prom_fd < 0) {
17397c478bdstevel@tonic-gate		return (prom_fd);
17407c478bdstevel@tonic-gate	}
17417c478bdstevel@tonic-gate
17427c478bdstevel@tonic-gate	opp->oprom_size = MAXVALSIZE;
17437c478bdstevel@tonic-gate
17447c478bdstevel@tonic-gate	if ((ioctl(prom_fd, OPROMGETVERSION, opp)) < 0) {
17457c478bdstevel@tonic-gate		prom_close(prom_fd);
17467c478bdstevel@tonic-gate		return (DEVFS_ERR);
17477c478bdstevel@tonic-gate	}
17487c478bdstevel@tonic-gate	prom_close(prom_fd);
17497c478bdstevel@tonic-gate
17507c478bdstevel@tonic-gate	version |= OBP_OF;
17517c478bdstevel@tonic-gate
17527c478bdstevel@tonic-gate	return (version);
17537c478bdstevel@tonic-gate}
17547c478bdstevel@tonic-gate/*
17557c478bdstevel@tonic-gate * search the aliases node by definition - compile a list of
17567c478bdstevel@tonic-gate * alias names that are both exact and inexact matches.
17577c478bdstevel@tonic-gate */
17587c478bdstevel@tonic-gatestatic int
17597c478bdstevel@tonic-gateprom_srch_aliases_by_def(char *promdev_def, struct name_list **exact_list,
17607c478bdstevel@tonic-gate    struct name_list **inexact_list, int prom_fd)
17617c478bdstevel@tonic-gate{
17627c478bdstevel@tonic-gate	Oppbuf  oppbuf;
17637c478bdstevel@tonic-gate	Oppbuf  propdef_oppbuf;
17647c478bdstevel@tonic-gate	struct openpromio *opp = &(oppbuf.opp);
17657c478bdstevel@tonic-gate	struct openpromio *propdef_opp = &(propdef_oppbuf.opp);
17667c478bdstevel@tonic-gate	int *ip = (int *)((void *)opp->oprom_array);
17677c478bdstevel@tonic-gate	int ret;
17687c478bdstevel@tonic-gate	struct name_list *inexact_match = *inexact_list = NULL;
17697c478bdstevel@tonic-gate	struct name_list *exact_match = *exact_list = NULL;
17707c478bdstevel@tonic-gate	char alias_buf[MAXNAMELEN];
17717c478bdstevel@tonic-gate	int found = 0;
17727c478bdstevel@tonic-gate
1773c279fc7sriman bhavanam - Sun Microsystems - Bangalore India	if ((ret = prom_find_aliases_node(prom_fd)) < 0)
1774c279fc7sriman bhavanam - Sun Microsystems - Bangalore India		return (0);
1775c279fc7sriman bhavanam - Sun Microsystems - Bangalore India
17767c478bdstevel@tonic-gate	(void) memset(oppbuf.buf, 0, BUFSIZE);
17777c478bdstevel@tonic-gate	opp->oprom_size = MAXPROPSIZE;
17787c478bdstevel@tonic-gate	*ip = 0;
17797c478bdstevel@tonic-gate
17807c478bdstevel@tonic-gate	if ((ret = ioctl(prom_fd, OPROMNXTPROP, opp)) < 0)
17817c478bdstevel@tonic-gate		return (0);
17827c478bdstevel@tonic-gate	if (opp->oprom_size == 0)
17837c478bdstevel@tonic-gate		return (0);
17847c478bdstevel@tonic-gate
17857c478bdstevel@tonic-gate	while ((ret >= 0) && (opp->oprom_size > 0)) {
17867c478bdstevel@tonic-gate		(void) strcpy(propdef_opp->oprom_array, opp->oprom_array);
17877c478bdstevel@tonic-gate		opp->oprom_size = MAXPROPSIZE;
17887c478bdstevel@tonic-gate		propdef_opp->oprom_size = MAXVALSIZE;
17897c478bdstevel@tonic-gate		if ((ioctl(prom_fd, OPROMGETPROP, propdef_opp) < 0) ||
17907c478bdstevel@tonic-gate		    (propdef_opp->oprom_size == 0)) {
17917c478bdstevel@tonic-gate			ret = ioctl(prom_fd, OPROMNXTPROP, opp);
17927c478bdstevel@tonic-gate			continue;
17937c478bdstevel@tonic-gate		}
17947c478bdstevel@tonic-gate		ret = prom_compare_devs(promdev_def, propdef_opp->oprom_array);
17957c478bdstevel@tonic-gate		if (ret == EXACT_MATCH) {
17967c478bdstevel@tonic-gate			found++;
17977c478bdstevel@tonic-gate			if (insert_alias_list(exact_list, opp->oprom_array)
17987c478bdstevel@tonic-gate			    != 0) {
17997c478bdstevel@tonic-gate				free_name_list(exact_match, 1);
18007c478bdstevel@tonic-gate				free_name_list(inexact_match, 1);
18017c478bdstevel@tonic-gate				return (-1);
18027c478bdstevel@tonic-gate			}
18037c478bdstevel@tonic-gate		}
18047c478bdstevel@tonic-gate		if (ret == INEXACT_MATCH) {
18057c478bdstevel@tonic-gate			found++;
18067c478bdstevel@tonic-gate			(void) strcpy(alias_buf, opp->oprom_array);
18077c478bdstevel@tonic-gate			options_override(promdev_def, alias_buf);
18087c478bdstevel@tonic-gate			if (insert_alias_list(inexact_list, alias_buf)
18097c478bdstevel@tonic-gate			    != 0) {
18107c478bdstevel@tonic-gate				free_name_list(exact_match, 1);
18117c478bdstevel@tonic-gate				free_name_list(inexact_match, 1);
18127c478bdstevel@tonic-gate				return (-1);
18137c478bdstevel@tonic-gate			}
18147c478bdstevel@tonic-gate		}
18157c478bdstevel@tonic-gate		ret = ioctl(prom_fd, OPROMNXTPROP, opp);
18167c478bdstevel@tonic-gate	}
18177c478bdstevel@tonic-gate	if (found) {
18187c478bdstevel@tonic-gate		return (0);
18197c478bdstevel@tonic-gate	} else {
18207c478bdstevel@tonic-gate		return (-1);
18217c478bdstevel@tonic-gate	}
18227c478bdstevel@tonic-gate}
18237c478bdstevel@tonic-gate
18247c478bdstevel@tonic-gate/*
18257c478bdstevel@tonic-gate * free a list of name_list structs and optionally
18267c478bdstevel@tonic-gate * free the strings they contain.
18277c478bdstevel@tonic-gate */
18287c478bdstevel@tonic-gatestatic void
18297c478bdstevel@tonic-gatefree_name_list(struct name_list *list, int free_name)
18307c478bdstevel@tonic-gate{
18317c478bdstevel@tonic-gate	struct name_list *next = list;
18327c478bdstevel@tonic-gate
18337c478bdstevel@tonic-gate	while (next != NULL) {
18347c478bdstevel@tonic-gate		list = list->next;
18357c478bdstevel@tonic-gate		if (free_name)
18367c478bdstevel@tonic-gate			free(next->name);
18377c478bdstevel@tonic-gate		free(next);
18387c478bdstevel@tonic-gate		next = list;
18397c478bdstevel@tonic-gate	}
18407c478bdstevel@tonic-gate}
18417c478bdstevel@tonic-gate
18427c478bdstevel@tonic-gate/*
18437c478bdstevel@tonic-gate * insert a new alias in a list of aliases - the list is sorted
18447c478bdstevel@tonic-gate * in collating order (ignoring anything that comes after the
18457c478bdstevel@tonic-gate * ':' in the name).
18467c478bdstevel@tonic-gate */
18477c478bdstevel@tonic-gatestatic int
18487c478bdstevel@tonic-gateinsert_alias_list(struct name_list **list, char *alias_name)
18497c478bdstevel@tonic-gate{
18507c478bdstevel@tonic-gate	struct name_list *entry = *list;
18517c478bdstevel@tonic-gate	struct name_list *new_entry, *prev_entry;
18527c478bdstevel@tonic-gate	int ret;
18537c478bdstevel@tonic-gate	char *colon1, *colon2;
18547c478bdstevel@tonic-gate
18557c478bdstevel@tonic-gate	if ((new_entry =
18567c478bdstevel@tonic-gate	    (struct name_list *)malloc(sizeof (struct name_list)))
18577c478bdstevel@tonic-gate	    == NULL) {
18587c478bdstevel@tonic-gate		return (-1);
18597c478bdstevel@tonic-gate	}
18607c478bdstevel@tonic-gate	if ((new_entry->name = strdup(alias_name)) == NULL) {
18617c478bdstevel@tonic-gate		free(new_entry);
18627c478bdstevel@tonic-gate		return (-1);
18637c478bdstevel@tonic-gate	}
18647c478bdstevel@tonic-gate	new_entry->next = NULL;
18657c478bdstevel@tonic-gate
18667c478bdstevel@tonic-gate	if (entry == NULL) {
18677c478bdstevel@tonic-gate		*list = new_entry;
18687c478bdstevel@tonic-gate		return (0);
18697c478bdstevel@tonic-gate	}
18707c478bdstevel@tonic-gate
18717c478bdstevel@tonic-gate	if ((colon1 = strchr(alias_name, ':')) != NULL) {
18727c478bdstevel@tonic-gate		*colon1 = '\0';
18737c478bdstevel@tonic-gate	}
18747c478bdstevel@tonic-gate	prev_entry = NULL;
18757c478bdstevel@tonic-gate	while (entry != NULL) {
18767c478bdstevel@tonic-gate		if ((colon2 = strchr(entry->name, ':')) != NULL) {
18777c478bdstevel@tonic-gate			*colon2 = '\0';
18787c478bdstevel@tonic-gate		}
18797c478bdstevel@tonic-gate		ret = strcmp(alias_name, entry->name);
18807c478bdstevel@tonic-gate		if (colon2 != NULL) {
18817c478bdstevel@tonic-gate			*colon2 = ':';
18827c478bdstevel@tonic-gate		}
18837c478bdstevel@tonic-gate		/* duplicate */
18847c478bdstevel@tonic-gate		if (ret == 0) {
18857c478bdstevel@tonic-gate			free(new_entry->name);
18867c478bdstevel@tonic-gate			free(new_entry);
18877c478bdstevel@tonic-gate			if (colon1 != NULL) {
18887c478bdstevel@tonic-gate				*colon1 = ':';
18897c478bdstevel@tonic-gate			}
18907c478bdstevel@tonic-gate			return (0);
18917c478bdstevel@tonic-gate		}
18927c478bdstevel@tonic-gate		if (ret < 0) {
18937c478bdstevel@tonic-gate			new_entry->next = entry;
18947c478bdstevel@tonic-gate			if (prev_entry == NULL) {
18957c478bdstevel@tonic-gate				/* in beginning of list */
18967c478bdstevel@tonic-gate				*list = new_entry;
18977c478bdstevel@tonic-gate			} else {
18987c478bdstevel@tonic-gate				/* in middle of list */
18997c478bdstevel@tonic-gate				prev_entry->next = new_entry;
19007c478bdstevel@tonic-gate			}
19017c478bdstevel@tonic-gate			if (colon1 != NULL) {
19027c478bdstevel@tonic-gate				*colon1 = ':';
19037c478bdstevel@tonic-gate			}
19047c478bdstevel@tonic-gate			return (0);
19057c478bdstevel@tonic-gate		}
19067c478bdstevel@tonic-gate		prev_entry = entry;
19077c478bdstevel@tonic-gate		entry = entry->next;
19087c478bdstevel@tonic-gate	}
19097c478bdstevel@tonic-gate	/* at end of list */
19107c478bdstevel@tonic-gate	prev_entry->next = new_entry;
19117c478bdstevel@tonic-gate	new_entry->next = NULL;
19127c478bdstevel@tonic-gate	if (colon1 != NULL) {
19137c478bdstevel@tonic-gate		*colon1 = ':';
19147c478bdstevel@tonic-gate	}
19157c478bdstevel@tonic-gate	return (0);
19167c478bdstevel@tonic-gate}
19177c478bdstevel@tonic-gate/*
19187c478bdstevel@tonic-gate * append :x to alias_name to override any default minor name options
19197c478bdstevel@tonic-gate */
19207c478bdstevel@tonic-gatestatic void
19217c478bdstevel@tonic-gateoptions_override(char *prom_path, char *alias_name)
19227c478bdstevel@tonic-gate{
19237c478bdstevel@tonic-gate	char *colon;
19247c478bdstevel@tonic-gate
19257c478bdstevel@tonic-gate	if ((colon = strrchr(alias_name, ':')) != NULL) {
19267c478bdstevel@tonic-gate		/*
19277c478bdstevel@tonic-gate		 * XXX - should alias names in /aliases ever have a
19287c478bdstevel@tonic-gate		 * : embedded in them?
19297c478bdstevel@tonic-gate		 * If so we ignore it.
19307c478bdstevel@tonic-gate		 */
19317c478bdstevel@tonic-gate		*colon = '\0';
19327c478bdstevel@tonic-gate	}
19337c478bdstevel@tonic-gate
19347c478bdstevel@tonic-gate	if ((colon = strrchr(prom_path, ':')) != NULL) {
19357c478bdstevel@tonic-gate		(void) strcat(alias_name, colon);
19367c478bdstevel@tonic-gate	}
19377c478bdstevel@tonic-gate}
19387c478bdstevel@tonic-gate
19397c478bdstevel@tonic-gate/*
19407c478bdstevel@tonic-gate * compare to prom device names.
19417c478bdstevel@tonic-gate * if the device names are not fully qualified. we convert them -
19427c478bdstevel@tonic-gate * we only do this as a last resort though since it requires
19437c478bdstevel@tonic-gate * jumping into the kernel.
19447c478bdstevel@tonic-gate */
19457c478bdstevel@tonic-gatestatic int
19467c478bdstevel@tonic-gateprom_compare_devs(char *prom_dev1, char *prom_dev2)
19477c478bdstevel@tonic-gate{
19487c478bdstevel@tonic-gate	char *dev1, *dev2;
19497c478bdstevel@tonic-gate	char *ptr1, *ptr2;
19507c478bdstevel@tonic-gate	char *drvname1, *addrname1, *minorname1;
19517c478bdstevel@tonic-gate	char *drvname2, *addrname2, *minorname2;
19527c478bdstevel@tonic-gate	char component1[MAXNAMELEN], component2[MAXNAMELEN];
19537c478bdstevel@tonic-gate	char devname1[MAXPATHLEN], devname2[MAXPATHLEN];
19547c478bdstevel@tonic-gate	int unqualified_name = 0;
19557c478bdstevel@tonic-gate	int error = EXACT_MATCH;
19567c478bdstevel@tonic-gate	int len1, len2;
19577c478bdstevel@tonic-gate	char *wildcard = ",0";
19587c478bdstevel@tonic-gate
19597c478bdstevel@tonic-gate	ptr1 = prom_dev1;
19607c478bdstevel@tonic-gate	ptr2 = prom_dev2;
19617c478bdstevel@tonic-gate
19627c478bdstevel@tonic-gate	if ((ptr1 == NULL) || (*ptr1 != '/')) {
19637c478bdstevel@tonic-gate		return (NO_MATCH);
19647c478bdstevel@tonic-gate	}
19657c478bdstevel@tonic-gate	if ((ptr2 == NULL) || (*ptr2 != '/')) {
19667c478bdstevel@tonic-gate		return (NO_MATCH);
19677c478bdstevel@tonic-gate	}
19687c478bdstevel@tonic-gate
19697c478bdstevel@tonic-gate	/*
19707c478bdstevel@tonic-gate	 * compare device names one component at a time.
19717c478bdstevel@tonic-gate	 */
19727c478bdstevel@tonic-gate	while ((ptr1 != NULL) && (ptr2 != NULL)) {
19737c478bdstevel@tonic-gate		*ptr1 = *ptr2 = '/';
19747c478bdstevel@tonic-gate		dev1 = ptr1 + 1;
19757c478bdstevel@tonic-gate		dev2 = ptr2 + 1;
19767c478bdstevel@tonic-gate		if ((ptr1 = strchr(dev1, '/')) != NULL)
19777c478bdstevel@tonic-gate			*ptr1 = '\0';
19787c478bdstevel@tonic-gate		if ((ptr2 = strchr(dev2, '/')) != NULL)
19797c478bdstevel@tonic-gate			*ptr2 = '\0';
19807c478bdstevel@tonic-gate
19817c478bdstevel@tonic-gate		(void) strcpy(component1, dev1);
19827c478bdstevel@tonic-gate		(void) strcpy(component2, dev2);
19837c478bdstevel@tonic-gate
19847c478bdstevel@tonic-gate		parse_name(component1, &drvname1, &addrname1, &minorname1);
19857c478bdstevel@tonic-gate		parse_name(component2, &drvname2, &addrname2, &minorname2);
19867c478bdstevel@tonic-gate
19877c478bdstevel@tonic-gate		if ((drvname1 == NULL) && (addrname1 == NULL)) {
19887c478bdstevel@tonic-gate			error = NO_MATCH;
19897c478bdstevel@tonic-gate			break;
19907c478bdstevel@tonic-gate		}
19917c478bdstevel@tonic-gate
19927c478bdstevel@tonic-gate		if ((drvname2 == NULL) && (addrname2 == NULL)) {
19937c478bdstevel@tonic-gate			error = NO_MATCH;
19947c478bdstevel@tonic-gate			break;
19957c478bdstevel@tonic-gate		}
19967c478bdstevel@tonic-gate
19977c478bdstevel@tonic-gate		if (_prom_strcmp(drvname1, drvname2) != 0) {
19987c478bdstevel@tonic-gate			error = NO_MATCH;
19997c478bdstevel@tonic-gate			break;
20007c478bdstevel@tonic-gate		}
20017c478bdstevel@tonic-gate
20027c478bdstevel@tonic-gate		/*
20037c478bdstevel@tonic-gate		 * a possible name is driver_name@address.  The address
20047c478bdstevel@tonic-gate		 * portion is optional (i.e. the name is not fully
20057c478bdstevel@tonic-gate		 * qualified.).  We have to deal with the case where
20067c478bdstevel@tonic-gate		 * the component name is either driver_name or
20077c478bdstevel@tonic-gate		 * driver_name@address
20087c478bdstevel@tonic-gate		 */
20097c478bdstevel@tonic-gate		if ((addrname1 == NULL) ^ (addrname2 == NULL)) {
20107c478bdstevel@tonic-gate			unqualified_name = 1;
20117c478bdstevel@tonic-gate		} else if (addrname1 &&
20127c478bdstevel@tonic-gate		    (_prom_strcmp(addrname1, addrname2) != 0)) {
20137c478bdstevel@tonic-gate			/*
20147c478bdstevel@tonic-gate			 * check to see if appending a ",0" to the
20157c478bdstevel@tonic-gate			 * shorter address causes a match to occur.
20167c478bdstevel@tonic-gate			 * If so succeed.
20177c478bdstevel@tonic-gate			 */
20187c478bdstevel@tonic-gate			len1 = strlen(addrname1);
20197c478bdstevel@tonic-gate			len2 = strlen(addrname2);
20207c478bdstevel@tonic-gate			if ((len1 < len2) &&
20217c478bdstevel@tonic-gate			    (strncmp(addrname1, addrname2, len1) == 0) &&
20227c478bdstevel@tonic-gate			    (strcmp(wildcard, &addrname2[len1]) == 0)) {
20237c478bdstevel@tonic-gate				continue;
20247c478bdstevel@tonic-gate			} else if ((len2 < len1) &&
20257c478bdstevel@tonic-gate			    (strncmp(addrname1, addrname2, len2) == 0) &&
20267c478bdstevel@tonic-gate			    (strcmp(wildcard, &addrname1[len2]) == 0)) {
20277c478bdstevel@tonic-gate				continue;
20287c478bdstevel@tonic-gate			}
20297c478bdstevel@tonic-gate			error = NO_MATCH;
20307c478bdstevel@tonic-gate			break;
20317c478bdstevel@tonic-gate		}
20327c478bdstevel@tonic-gate	}
20337c478bdstevel@tonic-gate
20347c478bdstevel@tonic-gate	/*
20357c478bdstevel@tonic-gate	 * if either of the two device paths still has more components,
20367c478bdstevel@tonic-gate	 * then we do not have a match.
20377c478bdstevel@tonic-gate	 */
20387c478bdstevel@tonic-gate	if (ptr1 != NULL) {
20397c478bdstevel@tonic-gate		*ptr1 = '/';
20407c478bdstevel@tonic-gate		error = NO_MATCH;
20417c478bdstevel@tonic-gate	}
20427c478bdstevel@tonic-gate	if (ptr2 != NULL) {
20437c478bdstevel@tonic-gate		*ptr2 = '/';
20447c478bdstevel@tonic-gate		error = NO_MATCH;
20457c478bdstevel@tonic-gate	}
20467c478bdstevel@tonic-gate	if (error == NO_MATCH) {
20477c478bdstevel@tonic-gate		return (error);
20487c478bdstevel@tonic-gate	}
20497c478bdstevel@tonic-gate
20507c478bdstevel@tonic-gate	/*
20517c478bdstevel@tonic-gate	 * OK - we found a possible match but one or more of the
20527c478bdstevel@tonic-gate	 * path components was not fully qualified (did not have any
20537c478bdstevel@tonic-gate	 * address information.  So we need to convert it to a form
20547c478bdstevel@tonic-gate	 * that is fully qualified and then compare the resulting
20557c478bdstevel@tonic-gate	 * strings.
20567c478bdstevel@tonic-gate	 */
20577c478bdstevel@tonic-gate	if (unqualified_name != 0) {
20587c478bdstevel@tonic-gate		if ((devfs_prom_to_dev_name(prom_dev1, devname1) < 0) ||
20597c478bdstevel@tonic-gate		    (devfs_prom_to_dev_name(prom_dev2, devname2) < 0)) {
20607c478bdstevel@tonic-gate			return (NO_MATCH);
20617c478bdstevel@tonic-gate		}
20627c478bdstevel@tonic-gate		if ((dev1 = strrchr(devname1, ':')) != NULL) {
20637c478bdstevel@tonic-gate			*dev1 = '\0';
20647c478bdstevel@tonic-gate		}
20657c478bdstevel@tonic-gate		if ((dev2 = strrchr(devname2, ':')) != NULL) {
20667c478bdstevel@tonic-gate			*dev2 = '\0';
20677c478bdstevel@tonic-gate		}
20687c478bdstevel@tonic-gate		if (strcmp(devname1, devname2) != 0) {
20697c478bdstevel@tonic-gate			return (NO_MATCH);
20707c478bdstevel@tonic-gate		}
20717c478bdstevel@tonic-gate	}
20727c478bdstevel@tonic-gate	/*
20737c478bdstevel@tonic-gate	 * the resulting strings matched.  If the minorname information
20747c478bdstevel@tonic-gate	 * matches, then we have an exact match, otherwise an inexact match
20757c478bdstevel@tonic-gate	 */
20767c478bdstevel@tonic-gate	if (_prom_strcmp(minorname1, minorname2) == 0) {
20777c478bdstevel@tonic-gate		return (EXACT_MATCH);
20787c478bdstevel@tonic-gate	} else {
20797c478bdstevel@tonic-gate		return (INEXACT_MATCH);
20807c478bdstevel@tonic-gate	}
20817c478bdstevel@tonic-gate}
20827c478bdstevel@tonic-gate
20837c478bdstevel@tonic-gate/*
20847c478bdstevel@tonic-gate * wrapper or strcmp - deals with null strings.
20857c478bdstevel@tonic-gate */
20867c478bdstevel@tonic-gatestatic int
20877c478bdstevel@tonic-gate_prom_strcmp(char *s1, char *s2)
20887c478bdstevel@tonic-gate{
20897c478bdstevel@tonic-gate	if ((s1 == NULL) && (s2 == NULL))
20907c478bdstevel@tonic-gate		return (0);
20917c478bdstevel@tonic-gate	if ((s1 == NULL) && (s2 != NULL)) {
20927c478bdstevel@tonic-gate		return (-1);
20937c478bdstevel@tonic-gate	}
20947c478bdstevel@tonic-gate	if ((s1 != NULL) && (s2 == NULL)) {
20957c478bdstevel@tonic-gate		return (1);
20967c478bdstevel@tonic-gate	}
20977c478bdstevel@tonic-gate	return (strcmp(s1, s2));
20987c478bdstevel@tonic-gate}
20997c478bdstevel@tonic-gate/*
21007c478bdstevel@tonic-gate * break device@a,b:minor into components
21017c478bdstevel@tonic-gate */
21027c478bdstevel@tonic-gatestatic void
21037c478bdstevel@tonic-gateparse_name(char *name, char **drvname, char **addrname, char **minorname)
21047c478bdstevel@tonic-gate{
21057c478bdstevel@tonic-gate	char *cp, ch;
21067c478bdstevel@tonic-gate
21077c478bdstevel@tonic-gate	cp = *drvname = name;
21087c478bdstevel@tonic-gate	*addrname = *minorname = NULL;
21097c478bdstevel@tonic-gate	if (*name == '@')
21107c478bdstevel@tonic-gate		*drvname = NULL;
21117c478bdstevel@tonic-gate
21127c478bdstevel@tonic-gate	while ((ch = *cp) != '\0') {
21137c478bdstevel@tonic-gate		if (ch == '@')
21147c478bdstevel@tonic-gate			*addrname = ++cp;
21157c478bdstevel@tonic-gate		else if (ch == ':')
21167c478bdstevel@tonic-gate			*minorname = ++cp;
21177c478bdstevel@tonic-gate		++cp;
21187c478bdstevel@tonic-gate	}
21197c478bdstevel@tonic-gate	if (*addrname) {
21207c478bdstevel@tonic-gate		*((*addrname)-1) = '\0';
21217c478bdstevel@tonic-gate	}
21227c478bdstevel@tonic-gate	if (*minorname) {
21237c478bdstevel@tonic-gate		*((*minorname)-1) = '\0';
21247c478bdstevel@tonic-gate	}
21257c478bdstevel@tonic-gate}
21267c478bdstevel@tonic-gate
21277c478bdstevel@tonic-gate/*
2128b6f77feas * converts a prom alias to a prom device name.
2129b6f77feas * if we find no matching device, then we fail since if were
2130b6f77feas * given a valid alias, then by definition, there must be a
2131b6f77feas * device pathname associated with it in the /aliases node.
2132b6f77feas */
2133b6f77feasstatic int
2134b6f77feasalias_to_prom_dev(char *alias, char *ret_buf)
2135b6f77feas{
2136b6f77feas	char *options_ptr;
2137b6f77feas	char alias_buf[MAXNAMELEN];
2138b6f77feas	char alias_def[MAXPATHLEN];
2139b6f77feas	char options[16] = "";
2140b6f77feas	int prom_fd = -1;
2141b6f77feas	int ret;
2142b6f77feas	int i;
2143b6f77feas
2144b6f77feas	if (strchr(alias, '/') != NULL)
2145b6f77feas		return (DEVFS_INVAL);
2146b6f77feas
2147b6f77feas	if (strlen(alias) > (MAXNAMELEN - 1))
2148b6f77feas		return (DEVFS_INVAL);
2149b6f77feas
2150b6f77feas	if (ret_buf == NULL) {
2151b6f77feas		return (DEVFS_INVAL);
2152b6f77feas	}
2153b6f77feas
2154b6f77feas	prom_fd = prom_open(O_RDONLY);
2155b6f77feas	if (prom_fd < 0) {
2156b6f77feas		return (prom_fd);
2157b6f77feas	}
2158b6f77feas
2159b6f77feas	(void) strlcpy(alias_buf, alias, sizeof (alias_buf));
2160b6f77feas
2161b6f77feas	/*
2162b6f77feas	 * save off any options (minor name info) that is
2163b6f77feas	 * explicitly called out in the alias name
2164b6f77feas	 */
2165b6f77feas	if ((options_ptr = strchr(alias_buf, ':')) != NULL) {
2166b6f77feas		*options_ptr = '\0';
2167b6f77feas		(void) strlcpy(options, ++options_ptr, sizeof (options));
2168b6f77feas	}
2169b6f77feas
2170b6f77feas	*alias_def = '\0';
2171b6f77feas
2172b6f77feas	ret = prom_find_aliases_node(prom_fd);
2173b6f77feas	if (ret == 0) {
2174b6f77feas		/*
2175b6f77feas		 * we loop because one alias may define another... we have
2176b6f77feas		 * to work our way down to an actual device definition.
2177b6f77feas		 */
2178b6f77feas		for (i = 0; i <= 10; i++) {
2179b6f77feas			ret = prom_srch_node(prom_fd, alias_buf, alias_def);
2180b6f77feas			if (ret == -1) {
2181b6f77feas				break;
2182b6f77feas			}
2183b6f77feas			(void) strlcpy(alias_buf, alias_def,
2184b6f77feas			    sizeof (alias_buf));
2185b6f77feas			if (*alias_def == '/') {
2186b6f77feas				break;
2187b6f77feas			}
2188b6f77feas
2189b6f77feas			/*
2190b6f77feas			 * save off any explicit options (minor name info)
2191b6f77feas			 * if none has been encountered yet
2192b6f77feas			 */
2193b6f77feas			if (options_ptr == NULL) {
2194b6f77feas				options_ptr = strchr(alias_buf, ':');
2195b6f77feas				if (options_ptr != NULL) {
2196c279fc7sriman bhavanam - Sun Microsystems - Bangalore India					*options_ptr = '\0';
2197c279fc7sriman bhavanam - Sun Microsystems - Bangalore India					(void) strlcpy(options, ++options_ptr,
2198b6f77feas					    sizeof (options));
2199b6f77feas				}
2200b6f77feas			}
2201b6f77feas		}
2202b6f77feas	}
2203b6f77feas	prom_close(prom_fd);
2204b6f77feas
2205b6f77feas	/* error */
2206b6f77feas	if (ret == -1) {
2207b6f77feas		return (ret);
2208b6f77feas	}
2209b6f77feas
221095fa951as	(void) strlcpy(ret_buf, alias_def, MAXPATHLEN);
2211b6f77feas
2212b6f77feas	/* override minor name information */
2213b6f77feas	if (options_ptr != NULL) {
2214b6f77feas		if ((options_ptr = strrchr(ret_buf, ':')) == NULL) {
2215b6f77feas			(void) strcat(ret_buf, ":");
2216b6f77feas		} else {
2217b6f77feas			*(++options_ptr) = '\0';
2218b6f77feas		}
2219b6f77feas		(void) strcat(ret_buf, options);
2220b6f77feas	}
2221b6f77feas	return (0);
2222b6f77feas}
2223b6f77feas
2224b6f77feas/*
2225b6f77feas * search a prom node for a property name
2226b6f77feas */
2227b6f77feasstatic int
2228b6f77feasprom_srch_node(int fd, char *prop_name, char *ret_buf)
2229b6f77feas{
2230b6f77feas	Oppbuf  oppbuf;
2231b6f77feas	struct openpromio *opp = &(oppbuf.opp);
2232b6f77feas	int *ip = (int *)((void *)opp->oprom_array);
2233b6f77feas
2234b6f77feas	(void) memset(oppbuf.buf, 0, BUFSIZE);
2235b6f77feas	opp->oprom_size = MAXPROPSIZE;
2236b6f77feas	*ip = 0;
2237b6f77feas
2238b6f77feas	if (ioctl(fd, OPROMNXTPROP, opp) < 0)
2239b6f77feas		return (-1);
2240b6f77feas	if (opp->oprom_size == 0)
2241b6f77feas		return (-1);
2242b6f77feas
2243b6f77feas	while (strcmp(prop_name, opp->oprom_array) != 0) {
2244b6f77feas		opp->oprom_size = MAXPROPSIZE;
2245b6f77feas		if (ioctl(fd, OPROMNXTPROP, opp) < 0)
2246b6f77feas			return (-1);
2247b6f77feas		if (opp->oprom_size == 0)
2248b6f77feas			return (-1);
2249b6f77feas	}
2250b6f77feas	opp->oprom_size = MAXVALSIZE;
2251b6f77feas	if (ioctl(fd, OPROMGETPROP, opp) < 0)
2252b6f77feas		return (-1);
2253b6f77feas
2254b6f77feas	if (opp->oprom_size == 0)
2255b6f77feas		return (-1);
225695fa951as	(void) strlcpy(ret_buf, opp->oprom_array, MAXPATHLEN);
2257b6f77feas	return (0);
2258b6f77feas}
2259b6f77feas
2260b6f77feas/*
2261b6f77feas * return the aliases node.
2262b6f77feas */
2263b6f77feasstatic int
2264b6f77feasprom_find_aliases_node(int fd)
2265b6f77feas{
2266b6f77feas	uint_t child_id;
226795fa951as	char buf[MAXPATHLEN];
2268b6f77feas
2269b6f77feas	if ((child_id = prom_next_node(fd, 0)) == 0)
2270b6f77feas		return (-1);
2271b6f77feas	if ((child_id = prom_child_node(fd, child_id)) == 0)
2272b6f77feas		return (-1);
2273b6f77feas
2274b6f77feas	while (child_id != 0) {
2275b6f77feas		if (prom_srch_node(fd, "name", buf) == 0) {
2276b6f77feas			if (strcmp(buf, "aliases") == 0) {
2277b6f77feas				return (0);
2278b6f77feas			}
2279b6f77feas		}
2280b6f77feas		child_id = prom_next_node(fd, child_id);
2281b6f77feas	}
2282b6f77feas	return (-1);
2283b6f77feas}
2284b6f77feas
2285b6f77feas/*
2286b6f77feas * get sibling
2287b6f77feas */
2288b6f77feasstatic uint_t
2289b6f77feasprom_next_node(int fd, uint_t node_id)
2290b6f77feas{
2291b6f77feas	Oppbuf  oppbuf;
2292b6f77feas	struct openpromio *opp = &(oppbuf.opp);
2293b6f77feas	uint_t *ip = (uint_t *)((void *)opp->oprom_array);
2294b6f77feas
2295b6f77feas	(void) memset(oppbuf.buf, 0, BUFSIZE);
2296b6f77feas	opp->oprom_size = MAXVALSIZE;
2297b6f77feas	*ip = node_id;
2298b6f77feas
2299b6f77feas	if (ioctl(fd, OPROMNEXT, opp) < 0)
2300b6f77feas		return (0);
2301b6f77feas
2302b6f77feas	return (*(uint_t *)((void *)opp->oprom_array));
2303b6f77feas}
2304b6f77feas
2305b6f77feas/*
2306b6f77feas * get child
2307b6f77feas */
2308b6f77feasstatic uint_t
2309b6f77feasprom_child_node(int fd, uint_t node_id)
2310b6f77feas{
2311b6f77feas	Oppbuf  oppbuf;
2312b6f77feas	struct openpromio *opp = &(oppbuf.opp);
2313b6f77feas	uint_t *ip = (uint_t *)((void *)opp->oprom_array);
2314b6f77feas
2315b6f77feas	(void) memset(oppbuf.buf, 0, BUFSIZE);
2316b6f77feas	opp->oprom_size = MAXVALSIZE;
2317b6f77feas	*ip = node_id;
2318b6f77feas
2319b6f77feas	if (ioctl(fd, OPROMCHILD, opp) < 0)
2320b6f77feas		return (0);
2321b6f77feas
2322b6f77feas	return (*(uint_t *)((void *)opp->oprom_array));
2323b6f77feas}
2324b6f77feas
2325b6f77feas/*
23267c478bdstevel@tonic-gate * only on sparc for now
23277c478bdstevel@tonic-gate */
23287c478bdstevel@tonic-gateint
23297c478bdstevel@tonic-gatedevfs_bootdev_modifiable(void)
23307c478bdstevel@tonic-gate{
23317c478bdstevel@tonic-gate#if defined(sparc)
23327c478bdstevel@tonic-gate	return (0);
23337c478bdstevel@tonic-gate#else
23347c478bdstevel@tonic-gate	return (DEVFS_NOTSUP);
23357c478bdstevel@tonic-gate#endif
23367c478bdstevel@tonic-gate}
2337