xref: /titanic_50/usr/src/uts/sparc/os/bootdev.c (revision 38c67cbd88257a6cd4f0dc854d01cc278f86f1c9)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*38c67cbdSjiang wu - Sun Microsystems - Beijing China  * Common Development and Distribution License (the "License").
6*38c67cbdSjiang wu - Sun Microsystems - Beijing China  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*38c67cbdSjiang wu - Sun Microsystems - Beijing China  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/systm.h>
277c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
287c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
297c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
307c478bd9Sstevel@tonic-gate #include <sys/sunmdi.h>
317c478bd9Sstevel@tonic-gate #include <sys/mdi_impldefs.h>
327c478bd9Sstevel@tonic-gate #include <sys/promif.h>
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate struct parinfo {
357c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
367c478bd9Sstevel@tonic-gate 	dev_info_t *pdip;
377c478bd9Sstevel@tonic-gate };
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate  * internal functions
417c478bd9Sstevel@tonic-gate  */
427c478bd9Sstevel@tonic-gate static int resolve_devfs_name(char *, char *);
437c478bd9Sstevel@tonic-gate static dev_info_t *find_alternate_node(dev_info_t *, major_t);
44*38c67cbdSjiang wu - Sun Microsystems - Beijing China static dev_info_t *get_parent(dev_info_t *, struct parinfo *);
45*38c67cbdSjiang wu - Sun Microsystems - Beijing China static int i_devi_to_promname(dev_info_t *, char *, dev_info_t **alt_dipp);
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate /* internal global data */
487c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = {
49*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	&mod_miscops, "bootdev misc module 1.22"
507c478bd9Sstevel@tonic-gate };
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
537c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modlmisc, NULL
547c478bd9Sstevel@tonic-gate };
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate int
_init()577c478bd9Sstevel@tonic-gate _init()
587c478bd9Sstevel@tonic-gate {
597c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
607c478bd9Sstevel@tonic-gate }
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate int
_fini()637c478bd9Sstevel@tonic-gate _fini()
647c478bd9Sstevel@tonic-gate {
657c478bd9Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
667c478bd9Sstevel@tonic-gate }
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)697c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
707c478bd9Sstevel@tonic-gate {
717c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
727c478bd9Sstevel@tonic-gate }
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate  * convert a prom device path to an equivalent path in /devices
767c478bd9Sstevel@tonic-gate  * Does not deal with aliases.  Does deal with pathnames which
777c478bd9Sstevel@tonic-gate  * are not fully qualified.  This routine is generalized
787c478bd9Sstevel@tonic-gate  * to work across several flavors of OBP
797c478bd9Sstevel@tonic-gate  */
807c478bd9Sstevel@tonic-gate int
i_promname_to_devname(char * prom_name,char * ret_buf)817c478bd9Sstevel@tonic-gate i_promname_to_devname(char *prom_name, char *ret_buf)
827c478bd9Sstevel@tonic-gate {
837c478bd9Sstevel@tonic-gate 	if (prom_name == NULL || ret_buf == NULL ||
847c478bd9Sstevel@tonic-gate 	    (strlen(prom_name) >= MAXPATHLEN)) {
857c478bd9Sstevel@tonic-gate 		return (EINVAL);
867c478bd9Sstevel@tonic-gate 	}
877c478bd9Sstevel@tonic-gate 	if (i_ddi_prompath_to_devfspath(prom_name, ret_buf) != DDI_SUCCESS)
887c478bd9Sstevel@tonic-gate 		return (EINVAL);
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	return (0);
917c478bd9Sstevel@tonic-gate }
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /*
94*38c67cbdSjiang wu - Sun Microsystems - Beijing China  * The function is to get prom name according non-client dip node.
95*38c67cbdSjiang wu - Sun Microsystems - Beijing China  * And the function will set the alternate node of dip to alt_dip
96*38c67cbdSjiang wu - Sun Microsystems - Beijing China  * if it is exist which must be PROM node.
97*38c67cbdSjiang wu - Sun Microsystems - Beijing China  */
98*38c67cbdSjiang wu - Sun Microsystems - Beijing China static int
i_devi_to_promname(dev_info_t * dip,char * prom_path,dev_info_t ** alt_dipp)99*38c67cbdSjiang wu - Sun Microsystems - Beijing China i_devi_to_promname(dev_info_t *dip, char *prom_path, dev_info_t **alt_dipp)
100*38c67cbdSjiang wu - Sun Microsystems - Beijing China {
101*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	dev_info_t *pdip, *cdip, *idip;
102*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	char *unit_address, *nodename;
103*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	major_t major;
104*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	int depth, old_depth = 0;
105*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	struct parinfo *parinfo = NULL;
106*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	struct parinfo *info;
107*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	int ret = 0;
108*38c67cbdSjiang wu - Sun Microsystems - Beijing China 
109*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	if (MDI_CLIENT(dip))
110*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		return (EINVAL);
111*38c67cbdSjiang wu - Sun Microsystems - Beijing China 
112*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	if (ddi_pathname_obp(dip, prom_path) != NULL) {
113*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		return (0);
114*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	}
115*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	/*
116*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	 * ddi_pathname_obp return NULL, but the obp path still could
117*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	 * be different with the devfs path name, so need use a parents
118*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	 * stack to compose the path name string layer by layer.
119*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	 */
120*38c67cbdSjiang wu - Sun Microsystems - Beijing China 
121*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	/* find the closest ancestor which is a prom node */
122*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	pdip = dip;
123*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	parinfo = kmem_alloc(OBP_STACKDEPTH * sizeof (*parinfo),
124*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	    KM_SLEEP);
125*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	for (depth = 0; ndi_dev_is_prom_node(pdip) == 0; depth++) {
126*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		if (depth == OBP_STACKDEPTH) {
127*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			ret = EINVAL;
128*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			/* must not have been an obp node */
129*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			goto out;
130*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		}
131*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		pdip = get_parent(pdip, &parinfo[depth]);
132*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	}
133*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	old_depth = depth;
134*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	ASSERT(pdip);	/* at least root is prom node */
135*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	if (pdip)
136*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		(void) ddi_pathname(pdip, prom_path);
137*38c67cbdSjiang wu - Sun Microsystems - Beijing China 
138*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	ndi_hold_devi(pdip);
139*38c67cbdSjiang wu - Sun Microsystems - Beijing China 
140*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	for (depth = old_depth; depth > 0; depth--) {
141*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		info = &parinfo[depth - 1];
142*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		idip = info->dip;
143*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		nodename = ddi_node_name(idip);
144*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		unit_address = ddi_get_name_addr(idip);
145*38c67cbdSjiang wu - Sun Microsystems - Beijing China 
146*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		if (pdip) {
147*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			major = ddi_driver_major(idip);
148*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			cdip = find_alternate_node(pdip, major);
149*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			ndi_rele_devi(pdip);
150*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			if (cdip) {
151*38c67cbdSjiang wu - Sun Microsystems - Beijing China 				nodename = ddi_node_name(cdip);
152*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			}
153*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		}
154*38c67cbdSjiang wu - Sun Microsystems - Beijing China 
155*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		/*
156*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		 * node name + unitaddr to the prom_path
157*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		 */
158*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		(void) strcat(prom_path, "/");
159*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		(void) strcat(prom_path, nodename);
160*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		if (unit_address && (*unit_address)) {
161*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			(void) strcat(prom_path, "@");
162*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			(void) strcat(prom_path, unit_address);
163*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		}
164*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		pdip = cdip;
165*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	}
166*38c67cbdSjiang wu - Sun Microsystems - Beijing China 
167*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	if (pdip) {
168*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		ndi_rele_devi(pdip); /* hold from find_alternate_node */
169*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	}
170*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	/*
171*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	 * Now pdip is the alternate node which is same hierarchy as dip
172*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	 * if it exists.
173*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	 */
174*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	*alt_dipp = pdip;
175*38c67cbdSjiang wu - Sun Microsystems - Beijing China out:
176*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	if (parinfo) {
177*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		/* release holds from get_parent() */
178*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		for (depth = old_depth; depth > 0; depth--) {
179*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			info = &parinfo[depth - 1];
180*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			if (info && info->pdip)
181*38c67cbdSjiang wu - Sun Microsystems - Beijing China 				ndi_rele_devi(info->pdip);
182*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		}
183*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		kmem_free(parinfo, OBP_STACKDEPTH * sizeof (*parinfo));
184*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	}
185*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	return (ret);
186*38c67cbdSjiang wu - Sun Microsystems - Beijing China }
187*38c67cbdSjiang wu - Sun Microsystems - Beijing China 
188*38c67cbdSjiang wu - Sun Microsystems - Beijing China /*
1897c478bd9Sstevel@tonic-gate  * translate a devfs pathname to one that will be acceptable
1907c478bd9Sstevel@tonic-gate  * by the prom.  In most cases, there is no translation needed.
1917c478bd9Sstevel@tonic-gate  * For systems supporting generically named devices, the prom
1927c478bd9Sstevel@tonic-gate  * may support nodes such as 'disk' that do not have any unit
1937c478bd9Sstevel@tonic-gate  * address information (i.e. target,lun info).  If this is the
1947c478bd9Sstevel@tonic-gate  * case, the ddi framework will reject the node as invalid and
1957c478bd9Sstevel@tonic-gate  * populate the devinfo tree with nodes froms the .conf file
1967c478bd9Sstevel@tonic-gate  * (e.g. sd).  In this case, the names that show up in /devices
1977c478bd9Sstevel@tonic-gate  * are sd - since the prom only knows about 'disk' nodes, this
1987c478bd9Sstevel@tonic-gate  * routine detects this situation and does the conversion
1997c478bd9Sstevel@tonic-gate  * There are also cases such as pluto where the disk node in the
2007c478bd9Sstevel@tonic-gate  * prom is named "SUNW,ssd" but in /devices the name is "ssd".
2017c478bd9Sstevel@tonic-gate  *
2027c478bd9Sstevel@tonic-gate  * If MPxIO is enabled, the translation involves following
203*38c67cbdSjiang wu - Sun Microsystems - Beijing China  * pathinfo nodes to the "best" parent.
2047c478bd9Sstevel@tonic-gate  *
2057c478bd9Sstevel@tonic-gate  * return a 0 on success with the new device string in ret_buf.
2067c478bd9Sstevel@tonic-gate  * Otherwise return the appropriate error code as we may be called
2077c478bd9Sstevel@tonic-gate  * from the openprom driver.
2087c478bd9Sstevel@tonic-gate  */
2097c478bd9Sstevel@tonic-gate int
i_devname_to_promname(char * dev_name,char * ret_buf,size_t len)2107c478bd9Sstevel@tonic-gate i_devname_to_promname(char *dev_name, char *ret_buf, size_t len)
2117c478bd9Sstevel@tonic-gate {
212*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	dev_info_t *dip, *pdip, *cdip, *alt_dip = NULL;
213*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	mdi_pathinfo_t *pip = NULL;
2147c478bd9Sstevel@tonic-gate 	char *dev_path, *prom_path;
2157c478bd9Sstevel@tonic-gate 	char *unit_address, *minorname, *nodename;
2167c478bd9Sstevel@tonic-gate 	major_t major;
2177c478bd9Sstevel@tonic-gate 	char *rptr, *optr, *offline;
2187c478bd9Sstevel@tonic-gate 	size_t olen, rlen;
219*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	int circ;
220*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	int ret = 0;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	/* do some sanity checks */
2237c478bd9Sstevel@tonic-gate 	if ((dev_name == NULL) || (ret_buf == NULL) ||
2247c478bd9Sstevel@tonic-gate 	    (strlen(dev_name) > MAXPATHLEN)) {
2257c478bd9Sstevel@tonic-gate 		return (EINVAL);
2267c478bd9Sstevel@tonic-gate 	}
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	/*
2297c478bd9Sstevel@tonic-gate 	 * Convert to a /devices name. Fail the translation if
2307c478bd9Sstevel@tonic-gate 	 * the name doesn't exist.
2317c478bd9Sstevel@tonic-gate 	 */
2327c478bd9Sstevel@tonic-gate 	dev_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
2337c478bd9Sstevel@tonic-gate 	if (resolve_devfs_name(dev_name, dev_path) != 0 ||
2347c478bd9Sstevel@tonic-gate 	    strncmp(dev_path, "/devices/", 9) != 0) {
2357c478bd9Sstevel@tonic-gate 		kmem_free(dev_path, MAXPATHLEN);
2367c478bd9Sstevel@tonic-gate 		return (EINVAL);
2377c478bd9Sstevel@tonic-gate 	}
2387c478bd9Sstevel@tonic-gate 	dev_name = dev_path + sizeof ("/devices") - 1;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	bzero(ret_buf, len);
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	if (prom_finddevice(dev_name) != OBP_BADNODE) {
2437c478bd9Sstevel@tonic-gate 		/* we are done */
2447c478bd9Sstevel@tonic-gate 		(void) snprintf(ret_buf, len, "%s", dev_name);
2457c478bd9Sstevel@tonic-gate 		kmem_free(dev_path, MAXPATHLEN);
2467c478bd9Sstevel@tonic-gate 		return (0);
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	/*
2507c478bd9Sstevel@tonic-gate 	 * if we get here, then some portion of the device path is
2517c478bd9Sstevel@tonic-gate 	 * not understood by the prom.  We need to look for alternate
2527c478bd9Sstevel@tonic-gate 	 * names (e.g. replace ssd by disk) and mpxio enabled devices.
2537c478bd9Sstevel@tonic-gate 	 */
2547c478bd9Sstevel@tonic-gate 	dip = e_ddi_hold_devi_by_path(dev_name, 0);
2557c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
2567c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "cannot find dip for %s", dev_name);
2577c478bd9Sstevel@tonic-gate 		kmem_free(dev_path, MAXPATHLEN);
2587c478bd9Sstevel@tonic-gate 		return (EINVAL);
2597c478bd9Sstevel@tonic-gate 	}
2607c478bd9Sstevel@tonic-gate 
261*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	prom_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
262*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	rlen = len;
263*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	rptr = ret_buf;
264*38c67cbdSjiang wu - Sun Microsystems - Beijing China 
265*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	if (!MDI_CLIENT(dip)) {
266*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		ret = i_devi_to_promname(dip, prom_path, &alt_dip);
267*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		if (ret == 0) {
268*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			minorname = strrchr(dev_name, ':');
269*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			if (minorname && (minorname[1] != '\0')) {
270*38c67cbdSjiang wu - Sun Microsystems - Beijing China 				(void) strcat(prom_path, minorname);
2717c478bd9Sstevel@tonic-gate 			}
272*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			(void) snprintf(rptr, rlen, "%s", prom_path);
2737c478bd9Sstevel@tonic-gate 		}
274*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	} else {
275*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		/*
276*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		 * if get to here, means dip is a vhci client
277*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		 */
2787c478bd9Sstevel@tonic-gate 		offline = kmem_zalloc(len, KM_SLEEP); /* offline paths */
2797c478bd9Sstevel@tonic-gate 		olen = len;
2807c478bd9Sstevel@tonic-gate 		optr = offline;
281*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		/*
282*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		 * The following code assumes that the phci client is at leaf
283*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		 * level.
284*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		 */
285*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		ndi_devi_enter(dip, &circ);
286*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		while ((pip = mdi_get_next_phci_path(dip, pip)) != NULL) {
287*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			/*
288*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			 * walk all paths associated to the client node
289*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			 */
2907c478bd9Sstevel@tonic-gate 			bzero(prom_path, MAXPATHLEN);
2917c478bd9Sstevel@tonic-gate 
292*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			/*
293*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			 * replace with mdi_hold_path() when mpxio goes into
294*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			 * genunix
295*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			 */
296*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			MDI_PI_LOCK(pip);
297*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			MDI_PI_HOLD(pip);
298*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			MDI_PI_UNLOCK(pip);
2997c478bd9Sstevel@tonic-gate 
300*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			if (mdi_pi_pathname_obp(pip, prom_path) != NULL) {
301*38c67cbdSjiang wu - Sun Microsystems - Beijing China 				/*
302*38c67cbdSjiang wu - Sun Microsystems - Beijing China 				 * The path has different obp path
303*38c67cbdSjiang wu - Sun Microsystems - Beijing China 				 */
304*38c67cbdSjiang wu - Sun Microsystems - Beijing China 				goto minor_pathinfo;
3057c478bd9Sstevel@tonic-gate 			}
3067c478bd9Sstevel@tonic-gate 
307*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			pdip = mdi_pi_get_phci(pip);
308*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			ndi_hold_devi(pdip);
309*38c67cbdSjiang wu - Sun Microsystems - Beijing China 
310*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			/*
311*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			 * Get obp path name of the phci node firstly.
312*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			 * NOTE: if the alternate node of pdip exists,
313*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			 * the third argument of the i_devi_to_promname()
314*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			 * would be set to the alternate node.
315*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			 */
316*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			(void) i_devi_to_promname(pdip, prom_path, &alt_dip);
317*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			if (alt_dip != NULL) {
3187c478bd9Sstevel@tonic-gate 				ndi_rele_devi(pdip);
319*38c67cbdSjiang wu - Sun Microsystems - Beijing China 				pdip = alt_dip;
320*38c67cbdSjiang wu - Sun Microsystems - Beijing China 				ndi_hold_devi(pdip);
321*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			}
322*38c67cbdSjiang wu - Sun Microsystems - Beijing China 
323*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			nodename = ddi_node_name(dip);
324*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			unit_address = MDI_PI(pip)->pi_addr;
325*38c67cbdSjiang wu - Sun Microsystems - Beijing China 
326*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			major = ddi_driver_major(dip);
327*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			cdip = find_alternate_node(pdip, major);
328*38c67cbdSjiang wu - Sun Microsystems - Beijing China 
3297c478bd9Sstevel@tonic-gate 			if (cdip) {
3307c478bd9Sstevel@tonic-gate 				nodename = ddi_node_name(cdip);
3317c478bd9Sstevel@tonic-gate 			}
3327c478bd9Sstevel@tonic-gate 			/*
3337c478bd9Sstevel@tonic-gate 			 * node name + unitaddr to the prom_path
3347c478bd9Sstevel@tonic-gate 			 */
3357c478bd9Sstevel@tonic-gate 			(void) strcat(prom_path, "/");
3367c478bd9Sstevel@tonic-gate 			(void) strcat(prom_path, nodename);
3377c478bd9Sstevel@tonic-gate 			if (unit_address && (*unit_address)) {
3387c478bd9Sstevel@tonic-gate 				(void) strcat(prom_path, "@");
3397c478bd9Sstevel@tonic-gate 				(void) strcat(prom_path, unit_address);
3407c478bd9Sstevel@tonic-gate 			}
341*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			if (cdip) {
342*38c67cbdSjiang wu - Sun Microsystems - Beijing China 				/* hold from find_alternate_node */
343*38c67cbdSjiang wu - Sun Microsystems - Beijing China 				ndi_rele_devi(cdip);
3447c478bd9Sstevel@tonic-gate 			}
345*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			ndi_rele_devi(pdip);
346*38c67cbdSjiang wu - Sun Microsystems - Beijing China minor_pathinfo:
3477c478bd9Sstevel@tonic-gate 			minorname = strrchr(dev_name, ':');
3487c478bd9Sstevel@tonic-gate 			if (minorname && (minorname[1] != '\0')) {
3497c478bd9Sstevel@tonic-gate 				(void) strcat(prom_path, minorname);
3507c478bd9Sstevel@tonic-gate 			}
3517c478bd9Sstevel@tonic-gate 
352*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			if (MDI_PI_IS_ONLINE(pip)) {
3537c478bd9Sstevel@tonic-gate 				(void) snprintf(rptr, rlen, "%s", prom_path);
3547c478bd9Sstevel@tonic-gate 				rlen -= strlen(rptr) + 1;
3557c478bd9Sstevel@tonic-gate 				rptr += strlen(rptr) + 1;
3567c478bd9Sstevel@tonic-gate 				if (rlen <= 0) /* drop paths we can't store */
3577c478bd9Sstevel@tonic-gate 					break;
3587c478bd9Sstevel@tonic-gate 			} else {	/* path is offline */
3597c478bd9Sstevel@tonic-gate 				(void) snprintf(optr, olen, "%s", prom_path);
3607c478bd9Sstevel@tonic-gate 				olen -= strlen(optr) + 1;
3617c478bd9Sstevel@tonic-gate 				if (olen > 0) /* drop paths we can't store */
3627c478bd9Sstevel@tonic-gate 					optr += strlen(optr) + 1;
3637c478bd9Sstevel@tonic-gate 			}
364*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			MDI_PI_LOCK(pip);
365*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			MDI_PI_RELE(pip);
366*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			if (MDI_PI(pip)->pi_ref_cnt == 0)
367*38c67cbdSjiang wu - Sun Microsystems - Beijing China 				cv_broadcast(&MDI_PI(pip)->pi_ref_cv);
368*38c67cbdSjiang wu - Sun Microsystems - Beijing China 			MDI_PI_UNLOCK(pip);
3697c478bd9Sstevel@tonic-gate 		}
370*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		ndi_devi_exit(dip, circ);
371*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		ret = 0;
372*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		if (rlen > 0) {
3737c478bd9Sstevel@tonic-gate 			/* now add as much of offline to ret_buf as possible */
3747c478bd9Sstevel@tonic-gate 			bcopy(offline, rptr, rlen);
375*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		}
376*38c67cbdSjiang wu - Sun Microsystems - Beijing China 		kmem_free(offline, len);
377*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	}
378*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	/* release hold from e_ddi_hold_devi_by_path() */
379*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	ndi_rele_devi(dip);
3807c478bd9Sstevel@tonic-gate 	ret_buf[len - 1] = '\0';
3817c478bd9Sstevel@tonic-gate 	ret_buf[len - 2] = '\0';
3827c478bd9Sstevel@tonic-gate 	kmem_free(dev_path, MAXPATHLEN);
3837c478bd9Sstevel@tonic-gate 	kmem_free(prom_path, MAXPATHLEN);
384*38c67cbdSjiang wu - Sun Microsystems - Beijing China 
385*38c67cbdSjiang wu - Sun Microsystems - Beijing China 	return (ret);
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate /*
3897c478bd9Sstevel@tonic-gate  * check for a possible substitute node.  This routine searches the
3907c478bd9Sstevel@tonic-gate  * children of parent_dip, looking for a node that:
3917c478bd9Sstevel@tonic-gate  *	1. is a prom node
3927c478bd9Sstevel@tonic-gate  *	2. binds to the same major number
3937c478bd9Sstevel@tonic-gate  *	3. there is no need to verify that the unit-address information
3947c478bd9Sstevel@tonic-gate  *		match since it is likely that the substitute node
3957c478bd9Sstevel@tonic-gate  *		will have none (e.g. disk) - this would be the reason the
3967c478bd9Sstevel@tonic-gate  *		framework rejected it in the first place.
3977c478bd9Sstevel@tonic-gate  *
3987c478bd9Sstevel@tonic-gate  * assumes parent_dip is held
3997c478bd9Sstevel@tonic-gate  */
4007c478bd9Sstevel@tonic-gate static dev_info_t *
find_alternate_node(dev_info_t * parent_dip,major_t major)4017c478bd9Sstevel@tonic-gate find_alternate_node(dev_info_t *parent_dip, major_t major)
4027c478bd9Sstevel@tonic-gate {
4037c478bd9Sstevel@tonic-gate 	int circ;
4047c478bd9Sstevel@tonic-gate 	dev_info_t *child_dip;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	/* lock down parent to keep children from being removed */
4077c478bd9Sstevel@tonic-gate 	ndi_devi_enter(parent_dip, &circ);
4087c478bd9Sstevel@tonic-gate 	for (child_dip = ddi_get_child(parent_dip); child_dip != NULL;
4097c478bd9Sstevel@tonic-gate 	    child_dip = ddi_get_next_sibling(child_dip)) {
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 		/* look for obp node with matching major */
4127c478bd9Sstevel@tonic-gate 		if ((ndi_dev_is_prom_node(child_dip) != 0) &&
4137c478bd9Sstevel@tonic-gate 		    (ddi_driver_major(child_dip) == major)) {
4147c478bd9Sstevel@tonic-gate 			ndi_hold_devi(child_dip);
4157c478bd9Sstevel@tonic-gate 			break;
4167c478bd9Sstevel@tonic-gate 		}
4177c478bd9Sstevel@tonic-gate 	}
4187c478bd9Sstevel@tonic-gate 	ndi_devi_exit(parent_dip, circ);
4197c478bd9Sstevel@tonic-gate 	return (child_dip);
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate /*
4237c478bd9Sstevel@tonic-gate  * given an absolute pathname, convert it, if possible, to a devfs
4247c478bd9Sstevel@tonic-gate  * name.  Examples:
4257c478bd9Sstevel@tonic-gate  * /dev/rsd3a to /pci@1f,4000/glm@3/sd@0,0:a
4267c478bd9Sstevel@tonic-gate  * /dev/dsk/c0t0d0s0 to /pci@1f,4000/glm@3/sd@0,0:a
4277c478bd9Sstevel@tonic-gate  * /devices/pci@1f,4000/glm@3/sd@0,0:a to /pci@1f,4000/glm@3/sd@0,0:a
4287c478bd9Sstevel@tonic-gate  * /pci@1f,4000/glm@3/sd@0,0:a unchanged
4297c478bd9Sstevel@tonic-gate  *
4307c478bd9Sstevel@tonic-gate  * This routine deals with symbolic links, physical pathname with and
4317c478bd9Sstevel@tonic-gate  * without /devices stripped. Returns 0 on success or -1 on failure.
4327c478bd9Sstevel@tonic-gate  */
4337c478bd9Sstevel@tonic-gate static int
resolve_devfs_name(char * name,char * buffer)4347c478bd9Sstevel@tonic-gate resolve_devfs_name(char *name, char *buffer)
4357c478bd9Sstevel@tonic-gate {
4367c478bd9Sstevel@tonic-gate 	int error;
4377c478bd9Sstevel@tonic-gate 	char *fullname = NULL;
4387c478bd9Sstevel@tonic-gate 	struct pathname pn, rpn;
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	/* if not a /dev or /device name, prepend /devices */
4417c478bd9Sstevel@tonic-gate 	if (strncmp(name, "/dev/", 5) != 0 &&
4427c478bd9Sstevel@tonic-gate 	    strncmp(name, "/devices/", 9) != 0) {
4437c478bd9Sstevel@tonic-gate 		fullname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
4447c478bd9Sstevel@tonic-gate 		(void) snprintf(fullname, MAXPATHLEN, "/devices%s", name);
4457c478bd9Sstevel@tonic-gate 		name = fullname;
4467c478bd9Sstevel@tonic-gate 	}
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	if (pn_get(name, UIO_SYSSPACE, &pn) != 0) {
4497c478bd9Sstevel@tonic-gate 		if (fullname)
4507c478bd9Sstevel@tonic-gate 			kmem_free(fullname, MAXPATHLEN);
4517c478bd9Sstevel@tonic-gate 		return (-1);
4527c478bd9Sstevel@tonic-gate 	}
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	pn_alloc(&rpn);
4557c478bd9Sstevel@tonic-gate 	error = lookuppn(&pn, &rpn, FOLLOW, NULL, NULL);
4567c478bd9Sstevel@tonic-gate 	if (error == 0)
4577c478bd9Sstevel@tonic-gate 		bcopy(rpn.pn_path, buffer, rpn.pn_pathlen);
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	pn_free(&pn);
4607c478bd9Sstevel@tonic-gate 	pn_free(&rpn);
4617c478bd9Sstevel@tonic-gate 	if (fullname)
4627c478bd9Sstevel@tonic-gate 		kmem_free(fullname, MAXPATHLEN);
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	return (error);
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate /*
4687c478bd9Sstevel@tonic-gate  * If bootstring contains a device path, we need to convert to a format
4697c478bd9Sstevel@tonic-gate  * the prom will understand.  To do so, we convert the existing path to
4707c478bd9Sstevel@tonic-gate  * a prom-compatible path and return the value of new_path.  If the
4717c478bd9Sstevel@tonic-gate  * caller specifies new_path as NULL, we allocate an appropriately
4727c478bd9Sstevel@tonic-gate  * sized new_path on behalf of the caller.  If the caller invokes this
4737c478bd9Sstevel@tonic-gate  * function with new_path = NULL, they must do so from a context in
4747c478bd9Sstevel@tonic-gate  * which it is safe to perform a sleeping memory allocation.
4757c478bd9Sstevel@tonic-gate  */
4767c478bd9Sstevel@tonic-gate char *
i_convert_boot_device_name(char * cur_path,char * new_path,size_t * len)4777c478bd9Sstevel@tonic-gate i_convert_boot_device_name(char *cur_path, char *new_path, size_t *len)
4787c478bd9Sstevel@tonic-gate {
4797c478bd9Sstevel@tonic-gate 	char *ptr;
4807c478bd9Sstevel@tonic-gate 	int rval;
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	ASSERT(cur_path != NULL && len != NULL);
4837c478bd9Sstevel@tonic-gate 	ASSERT(new_path == NULL || *len >= MAXPATHLEN);
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	if (new_path == NULL) {
4867c478bd9Sstevel@tonic-gate 		*len = MAXPATHLEN + MAXNAMELEN;
4877c478bd9Sstevel@tonic-gate 		new_path = kmem_alloc(*len, KM_SLEEP);
4887c478bd9Sstevel@tonic-gate 	}
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	if ((ptr = strchr(cur_path, ' ')) != NULL)
4917c478bd9Sstevel@tonic-gate 		*ptr = '\0';
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	rval = i_devname_to_promname(cur_path, new_path, *len);
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	if (ptr != NULL)
4967c478bd9Sstevel@tonic-gate 		*ptr = ' ';
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	if (rval == 0) {
4997c478bd9Sstevel@tonic-gate 		if (ptr != NULL) {
5007c478bd9Sstevel@tonic-gate 			(void) snprintf(new_path + strlen(new_path),
5017c478bd9Sstevel@tonic-gate 			    *len - strlen(new_path), "%s", ptr);
5027c478bd9Sstevel@tonic-gate 		}
5037c478bd9Sstevel@tonic-gate 	} else {		/* the conversion failed */
5047c478bd9Sstevel@tonic-gate 		(void) snprintf(new_path, *len, "%s", cur_path);
5057c478bd9Sstevel@tonic-gate 	}
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	return (new_path);
5087c478bd9Sstevel@tonic-gate }
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate /*
511*38c67cbdSjiang wu - Sun Microsystems - Beijing China  * Get the parent dip.
5127c478bd9Sstevel@tonic-gate  */
5137c478bd9Sstevel@tonic-gate static dev_info_t *
get_parent(dev_info_t * dip,struct parinfo * info)514*38c67cbdSjiang wu - Sun Microsystems - Beijing China get_parent(dev_info_t *dip, struct parinfo *info)
5157c478bd9Sstevel@tonic-gate {
5167c478bd9Sstevel@tonic-gate 	dev_info_t *pdip;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	pdip = ddi_get_parent(dip);
5197c478bd9Sstevel@tonic-gate 	ndi_hold_devi(pdip);
5207c478bd9Sstevel@tonic-gate 	info->dip = dip;
5217c478bd9Sstevel@tonic-gate 	info->pdip = pdip;
5227c478bd9Sstevel@tonic-gate 	return (pdip);
5237c478bd9Sstevel@tonic-gate }
524