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
538c67cbdSjiang wu - Sun Microsystems - Beijing China * Common Development and Distribution License (the "License").
638c67cbdSjiang 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 /*
2238c67cbdSjiang 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
26*3fe80ca4SDan Cross /*
27*3fe80ca4SDan Cross * Copyright 2023 Oxide Computer Company
28*3fe80ca4SDan Cross */
29*3fe80ca4SDan Cross
307c478bd9Sstevel@tonic-gate #include <sys/systm.h>
317c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
327c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
337c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
347c478bd9Sstevel@tonic-gate #include <sys/sunmdi.h>
357c478bd9Sstevel@tonic-gate #include <sys/mdi_impldefs.h>
367c478bd9Sstevel@tonic-gate #include <sys/promif.h>
377c478bd9Sstevel@tonic-gate
387c478bd9Sstevel@tonic-gate struct parinfo {
397c478bd9Sstevel@tonic-gate dev_info_t *dip;
407c478bd9Sstevel@tonic-gate dev_info_t *pdip;
417c478bd9Sstevel@tonic-gate };
427c478bd9Sstevel@tonic-gate
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate * internal functions
457c478bd9Sstevel@tonic-gate */
467c478bd9Sstevel@tonic-gate static int resolve_devfs_name(char *, char *);
477c478bd9Sstevel@tonic-gate static dev_info_t *find_alternate_node(dev_info_t *, major_t);
4838c67cbdSjiang wu - Sun Microsystems - Beijing China static dev_info_t *get_parent(dev_info_t *, struct parinfo *);
4938c67cbdSjiang wu - Sun Microsystems - Beijing China static int i_devi_to_promname(dev_info_t *, char *, dev_info_t **alt_dipp);
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate /* internal global data */
527c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = {
5338c67cbdSjiang wu - Sun Microsystems - Beijing China &mod_miscops, "bootdev misc module 1.22"
547c478bd9Sstevel@tonic-gate };
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
577c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modlmisc, NULL
587c478bd9Sstevel@tonic-gate };
597c478bd9Sstevel@tonic-gate
607c478bd9Sstevel@tonic-gate int
_init()617c478bd9Sstevel@tonic-gate _init()
627c478bd9Sstevel@tonic-gate {
637c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage));
647c478bd9Sstevel@tonic-gate }
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate int
_fini()677c478bd9Sstevel@tonic-gate _fini()
687c478bd9Sstevel@tonic-gate {
697c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage));
707c478bd9Sstevel@tonic-gate }
717c478bd9Sstevel@tonic-gate
727c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)737c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
747c478bd9Sstevel@tonic-gate {
757c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
767c478bd9Sstevel@tonic-gate }
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate * convert a prom device path to an equivalent path in /devices
807c478bd9Sstevel@tonic-gate * Does not deal with aliases. Does deal with pathnames which
817c478bd9Sstevel@tonic-gate * are not fully qualified. This routine is generalized
827c478bd9Sstevel@tonic-gate * to work across several flavors of OBP
837c478bd9Sstevel@tonic-gate */
847c478bd9Sstevel@tonic-gate int
i_promname_to_devname(char * prom_name,char * ret_buf)857c478bd9Sstevel@tonic-gate i_promname_to_devname(char *prom_name, char *ret_buf)
867c478bd9Sstevel@tonic-gate {
877c478bd9Sstevel@tonic-gate if (prom_name == NULL || ret_buf == NULL ||
887c478bd9Sstevel@tonic-gate (strlen(prom_name) >= MAXPATHLEN)) {
897c478bd9Sstevel@tonic-gate return (EINVAL);
907c478bd9Sstevel@tonic-gate }
917c478bd9Sstevel@tonic-gate if (i_ddi_prompath_to_devfspath(prom_name, ret_buf) != DDI_SUCCESS)
927c478bd9Sstevel@tonic-gate return (EINVAL);
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate return (0);
957c478bd9Sstevel@tonic-gate }
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate /*
9838c67cbdSjiang wu - Sun Microsystems - Beijing China * The function is to get prom name according non-client dip node.
9938c67cbdSjiang wu - Sun Microsystems - Beijing China * And the function will set the alternate node of dip to alt_dip
10038c67cbdSjiang wu - Sun Microsystems - Beijing China * if it is exist which must be PROM node.
10138c67cbdSjiang wu - Sun Microsystems - Beijing China */
10238c67cbdSjiang wu - Sun Microsystems - Beijing China static int
i_devi_to_promname(dev_info_t * dip,char * prom_path,dev_info_t ** alt_dipp)10338c67cbdSjiang wu - Sun Microsystems - Beijing China i_devi_to_promname(dev_info_t *dip, char *prom_path, dev_info_t **alt_dipp)
10438c67cbdSjiang wu - Sun Microsystems - Beijing China {
10538c67cbdSjiang wu - Sun Microsystems - Beijing China dev_info_t *pdip, *cdip, *idip;
10638c67cbdSjiang wu - Sun Microsystems - Beijing China char *unit_address, *nodename;
10738c67cbdSjiang wu - Sun Microsystems - Beijing China major_t major;
10838c67cbdSjiang wu - Sun Microsystems - Beijing China int depth, old_depth = 0;
10938c67cbdSjiang wu - Sun Microsystems - Beijing China struct parinfo *parinfo = NULL;
11038c67cbdSjiang wu - Sun Microsystems - Beijing China struct parinfo *info;
11138c67cbdSjiang wu - Sun Microsystems - Beijing China int ret = 0;
11238c67cbdSjiang wu - Sun Microsystems - Beijing China
11338c67cbdSjiang wu - Sun Microsystems - Beijing China if (MDI_CLIENT(dip))
11438c67cbdSjiang wu - Sun Microsystems - Beijing China return (EINVAL);
11538c67cbdSjiang wu - Sun Microsystems - Beijing China
11638c67cbdSjiang wu - Sun Microsystems - Beijing China if (ddi_pathname_obp(dip, prom_path) != NULL) {
11738c67cbdSjiang wu - Sun Microsystems - Beijing China return (0);
11838c67cbdSjiang wu - Sun Microsystems - Beijing China }
11938c67cbdSjiang wu - Sun Microsystems - Beijing China /*
12038c67cbdSjiang wu - Sun Microsystems - Beijing China * ddi_pathname_obp return NULL, but the obp path still could
12138c67cbdSjiang wu - Sun Microsystems - Beijing China * be different with the devfs path name, so need use a parents
12238c67cbdSjiang wu - Sun Microsystems - Beijing China * stack to compose the path name string layer by layer.
12338c67cbdSjiang wu - Sun Microsystems - Beijing China */
12438c67cbdSjiang wu - Sun Microsystems - Beijing China
12538c67cbdSjiang wu - Sun Microsystems - Beijing China /* find the closest ancestor which is a prom node */
12638c67cbdSjiang wu - Sun Microsystems - Beijing China pdip = dip;
12738c67cbdSjiang wu - Sun Microsystems - Beijing China parinfo = kmem_alloc(OBP_STACKDEPTH * sizeof (*parinfo),
12838c67cbdSjiang wu - Sun Microsystems - Beijing China KM_SLEEP);
12938c67cbdSjiang wu - Sun Microsystems - Beijing China for (depth = 0; ndi_dev_is_prom_node(pdip) == 0; depth++) {
13038c67cbdSjiang wu - Sun Microsystems - Beijing China if (depth == OBP_STACKDEPTH) {
13138c67cbdSjiang wu - Sun Microsystems - Beijing China ret = EINVAL;
13238c67cbdSjiang wu - Sun Microsystems - Beijing China /* must not have been an obp node */
13338c67cbdSjiang wu - Sun Microsystems - Beijing China goto out;
13438c67cbdSjiang wu - Sun Microsystems - Beijing China }
13538c67cbdSjiang wu - Sun Microsystems - Beijing China pdip = get_parent(pdip, &parinfo[depth]);
13638c67cbdSjiang wu - Sun Microsystems - Beijing China }
13738c67cbdSjiang wu - Sun Microsystems - Beijing China old_depth = depth;
13838c67cbdSjiang wu - Sun Microsystems - Beijing China ASSERT(pdip); /* at least root is prom node */
13938c67cbdSjiang wu - Sun Microsystems - Beijing China if (pdip)
14038c67cbdSjiang wu - Sun Microsystems - Beijing China (void) ddi_pathname(pdip, prom_path);
14138c67cbdSjiang wu - Sun Microsystems - Beijing China
14238c67cbdSjiang wu - Sun Microsystems - Beijing China ndi_hold_devi(pdip);
14338c67cbdSjiang wu - Sun Microsystems - Beijing China
14438c67cbdSjiang wu - Sun Microsystems - Beijing China for (depth = old_depth; depth > 0; depth--) {
14538c67cbdSjiang wu - Sun Microsystems - Beijing China info = &parinfo[depth - 1];
14638c67cbdSjiang wu - Sun Microsystems - Beijing China idip = info->dip;
14738c67cbdSjiang wu - Sun Microsystems - Beijing China nodename = ddi_node_name(idip);
14838c67cbdSjiang wu - Sun Microsystems - Beijing China unit_address = ddi_get_name_addr(idip);
14938c67cbdSjiang wu - Sun Microsystems - Beijing China
15038c67cbdSjiang wu - Sun Microsystems - Beijing China if (pdip) {
15138c67cbdSjiang wu - Sun Microsystems - Beijing China major = ddi_driver_major(idip);
15238c67cbdSjiang wu - Sun Microsystems - Beijing China cdip = find_alternate_node(pdip, major);
15338c67cbdSjiang wu - Sun Microsystems - Beijing China ndi_rele_devi(pdip);
15438c67cbdSjiang wu - Sun Microsystems - Beijing China if (cdip) {
15538c67cbdSjiang wu - Sun Microsystems - Beijing China nodename = ddi_node_name(cdip);
15638c67cbdSjiang wu - Sun Microsystems - Beijing China }
15738c67cbdSjiang wu - Sun Microsystems - Beijing China }
15838c67cbdSjiang wu - Sun Microsystems - Beijing China
15938c67cbdSjiang wu - Sun Microsystems - Beijing China /*
16038c67cbdSjiang wu - Sun Microsystems - Beijing China * node name + unitaddr to the prom_path
16138c67cbdSjiang wu - Sun Microsystems - Beijing China */
16238c67cbdSjiang wu - Sun Microsystems - Beijing China (void) strcat(prom_path, "/");
16338c67cbdSjiang wu - Sun Microsystems - Beijing China (void) strcat(prom_path, nodename);
16438c67cbdSjiang wu - Sun Microsystems - Beijing China if (unit_address && (*unit_address)) {
16538c67cbdSjiang wu - Sun Microsystems - Beijing China (void) strcat(prom_path, "@");
16638c67cbdSjiang wu - Sun Microsystems - Beijing China (void) strcat(prom_path, unit_address);
16738c67cbdSjiang wu - Sun Microsystems - Beijing China }
16838c67cbdSjiang wu - Sun Microsystems - Beijing China pdip = cdip;
16938c67cbdSjiang wu - Sun Microsystems - Beijing China }
17038c67cbdSjiang wu - Sun Microsystems - Beijing China
17138c67cbdSjiang wu - Sun Microsystems - Beijing China if (pdip) {
17238c67cbdSjiang wu - Sun Microsystems - Beijing China ndi_rele_devi(pdip); /* hold from find_alternate_node */
17338c67cbdSjiang wu - Sun Microsystems - Beijing China }
17438c67cbdSjiang wu - Sun Microsystems - Beijing China /*
17538c67cbdSjiang wu - Sun Microsystems - Beijing China * Now pdip is the alternate node which is same hierarchy as dip
17638c67cbdSjiang wu - Sun Microsystems - Beijing China * if it exists.
17738c67cbdSjiang wu - Sun Microsystems - Beijing China */
17838c67cbdSjiang wu - Sun Microsystems - Beijing China *alt_dipp = pdip;
17938c67cbdSjiang wu - Sun Microsystems - Beijing China out:
18038c67cbdSjiang wu - Sun Microsystems - Beijing China if (parinfo) {
18138c67cbdSjiang wu - Sun Microsystems - Beijing China /* release holds from get_parent() */
18238c67cbdSjiang wu - Sun Microsystems - Beijing China for (depth = old_depth; depth > 0; depth--) {
18338c67cbdSjiang wu - Sun Microsystems - Beijing China info = &parinfo[depth - 1];
18438c67cbdSjiang wu - Sun Microsystems - Beijing China if (info && info->pdip)
18538c67cbdSjiang wu - Sun Microsystems - Beijing China ndi_rele_devi(info->pdip);
18638c67cbdSjiang wu - Sun Microsystems - Beijing China }
18738c67cbdSjiang wu - Sun Microsystems - Beijing China kmem_free(parinfo, OBP_STACKDEPTH * sizeof (*parinfo));
18838c67cbdSjiang wu - Sun Microsystems - Beijing China }
18938c67cbdSjiang wu - Sun Microsystems - Beijing China return (ret);
19038c67cbdSjiang wu - Sun Microsystems - Beijing China }
19138c67cbdSjiang wu - Sun Microsystems - Beijing China
19238c67cbdSjiang wu - Sun Microsystems - Beijing China /*
1937c478bd9Sstevel@tonic-gate * translate a devfs pathname to one that will be acceptable
1947c478bd9Sstevel@tonic-gate * by the prom. In most cases, there is no translation needed.
1957c478bd9Sstevel@tonic-gate * For systems supporting generically named devices, the prom
1967c478bd9Sstevel@tonic-gate * may support nodes such as 'disk' that do not have any unit
1977c478bd9Sstevel@tonic-gate * address information (i.e. target,lun info). If this is the
1987c478bd9Sstevel@tonic-gate * case, the ddi framework will reject the node as invalid and
1997c478bd9Sstevel@tonic-gate * populate the devinfo tree with nodes froms the .conf file
2007c478bd9Sstevel@tonic-gate * (e.g. sd). In this case, the names that show up in /devices
2017c478bd9Sstevel@tonic-gate * are sd - since the prom only knows about 'disk' nodes, this
2027c478bd9Sstevel@tonic-gate * routine detects this situation and does the conversion
2037c478bd9Sstevel@tonic-gate * There are also cases such as pluto where the disk node in the
2047c478bd9Sstevel@tonic-gate * prom is named "SUNW,ssd" but in /devices the name is "ssd".
2057c478bd9Sstevel@tonic-gate *
2067c478bd9Sstevel@tonic-gate * If MPxIO is enabled, the translation involves following
20738c67cbdSjiang wu - Sun Microsystems - Beijing China * pathinfo nodes to the "best" parent.
2087c478bd9Sstevel@tonic-gate *
2097c478bd9Sstevel@tonic-gate * return a 0 on success with the new device string in ret_buf.
2107c478bd9Sstevel@tonic-gate * Otherwise return the appropriate error code as we may be called
2117c478bd9Sstevel@tonic-gate * from the openprom driver.
2127c478bd9Sstevel@tonic-gate */
2137c478bd9Sstevel@tonic-gate int
i_devname_to_promname(char * dev_name,char * ret_buf,size_t len)2147c478bd9Sstevel@tonic-gate i_devname_to_promname(char *dev_name, char *ret_buf, size_t len)
2157c478bd9Sstevel@tonic-gate {
21638c67cbdSjiang wu - Sun Microsystems - Beijing China dev_info_t *dip, *pdip, *cdip, *alt_dip = NULL;
21738c67cbdSjiang wu - Sun Microsystems - Beijing China mdi_pathinfo_t *pip = NULL;
2187c478bd9Sstevel@tonic-gate char *dev_path, *prom_path;
2197c478bd9Sstevel@tonic-gate char *unit_address, *minorname, *nodename;
2207c478bd9Sstevel@tonic-gate major_t major;
2217c478bd9Sstevel@tonic-gate char *rptr, *optr, *offline;
2227c478bd9Sstevel@tonic-gate size_t olen, rlen;
22338c67cbdSjiang wu - Sun Microsystems - Beijing China int ret = 0;
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate /* do some sanity checks */
2267c478bd9Sstevel@tonic-gate if ((dev_name == NULL) || (ret_buf == NULL) ||
2277c478bd9Sstevel@tonic-gate (strlen(dev_name) > MAXPATHLEN)) {
2287c478bd9Sstevel@tonic-gate return (EINVAL);
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate /*
2327c478bd9Sstevel@tonic-gate * Convert to a /devices name. Fail the translation if
2337c478bd9Sstevel@tonic-gate * the name doesn't exist.
2347c478bd9Sstevel@tonic-gate */
2357c478bd9Sstevel@tonic-gate dev_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
2367c478bd9Sstevel@tonic-gate if (resolve_devfs_name(dev_name, dev_path) != 0 ||
2377c478bd9Sstevel@tonic-gate strncmp(dev_path, "/devices/", 9) != 0) {
2387c478bd9Sstevel@tonic-gate kmem_free(dev_path, MAXPATHLEN);
2397c478bd9Sstevel@tonic-gate return (EINVAL);
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate dev_name = dev_path + sizeof ("/devices") - 1;
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate bzero(ret_buf, len);
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate if (prom_finddevice(dev_name) != OBP_BADNODE) {
2467c478bd9Sstevel@tonic-gate /* we are done */
2477c478bd9Sstevel@tonic-gate (void) snprintf(ret_buf, len, "%s", dev_name);
2487c478bd9Sstevel@tonic-gate kmem_free(dev_path, MAXPATHLEN);
2497c478bd9Sstevel@tonic-gate return (0);
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate /*
2537c478bd9Sstevel@tonic-gate * if we get here, then some portion of the device path is
2547c478bd9Sstevel@tonic-gate * not understood by the prom. We need to look for alternate
2557c478bd9Sstevel@tonic-gate * names (e.g. replace ssd by disk) and mpxio enabled devices.
2567c478bd9Sstevel@tonic-gate */
2577c478bd9Sstevel@tonic-gate dip = e_ddi_hold_devi_by_path(dev_name, 0);
2587c478bd9Sstevel@tonic-gate if (dip == NULL) {
2597c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "cannot find dip for %s", dev_name);
2607c478bd9Sstevel@tonic-gate kmem_free(dev_path, MAXPATHLEN);
2617c478bd9Sstevel@tonic-gate return (EINVAL);
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate
26438c67cbdSjiang wu - Sun Microsystems - Beijing China prom_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
26538c67cbdSjiang wu - Sun Microsystems - Beijing China rlen = len;
26638c67cbdSjiang wu - Sun Microsystems - Beijing China rptr = ret_buf;
26738c67cbdSjiang wu - Sun Microsystems - Beijing China
26838c67cbdSjiang wu - Sun Microsystems - Beijing China if (!MDI_CLIENT(dip)) {
26938c67cbdSjiang wu - Sun Microsystems - Beijing China ret = i_devi_to_promname(dip, prom_path, &alt_dip);
27038c67cbdSjiang wu - Sun Microsystems - Beijing China if (ret == 0) {
27138c67cbdSjiang wu - Sun Microsystems - Beijing China minorname = strrchr(dev_name, ':');
27238c67cbdSjiang wu - Sun Microsystems - Beijing China if (minorname && (minorname[1] != '\0')) {
27338c67cbdSjiang wu - Sun Microsystems - Beijing China (void) strcat(prom_path, minorname);
2747c478bd9Sstevel@tonic-gate }
27538c67cbdSjiang wu - Sun Microsystems - Beijing China (void) snprintf(rptr, rlen, "%s", prom_path);
2767c478bd9Sstevel@tonic-gate }
27738c67cbdSjiang wu - Sun Microsystems - Beijing China } else {
27838c67cbdSjiang wu - Sun Microsystems - Beijing China /*
27938c67cbdSjiang wu - Sun Microsystems - Beijing China * if get to here, means dip is a vhci client
28038c67cbdSjiang wu - Sun Microsystems - Beijing China */
2817c478bd9Sstevel@tonic-gate offline = kmem_zalloc(len, KM_SLEEP); /* offline paths */
2827c478bd9Sstevel@tonic-gate olen = len;
2837c478bd9Sstevel@tonic-gate optr = offline;
28438c67cbdSjiang wu - Sun Microsystems - Beijing China /*
28538c67cbdSjiang wu - Sun Microsystems - Beijing China * The following code assumes that the phci client is at leaf
28638c67cbdSjiang wu - Sun Microsystems - Beijing China * level.
28738c67cbdSjiang wu - Sun Microsystems - Beijing China */
288*3fe80ca4SDan Cross ndi_devi_enter(dip);
28938c67cbdSjiang wu - Sun Microsystems - Beijing China while ((pip = mdi_get_next_phci_path(dip, pip)) != NULL) {
29038c67cbdSjiang wu - Sun Microsystems - Beijing China /*
29138c67cbdSjiang wu - Sun Microsystems - Beijing China * walk all paths associated to the client node
29238c67cbdSjiang wu - Sun Microsystems - Beijing China */
2937c478bd9Sstevel@tonic-gate bzero(prom_path, MAXPATHLEN);
2947c478bd9Sstevel@tonic-gate
29538c67cbdSjiang wu - Sun Microsystems - Beijing China /*
29638c67cbdSjiang wu - Sun Microsystems - Beijing China * replace with mdi_hold_path() when mpxio goes into
29738c67cbdSjiang wu - Sun Microsystems - Beijing China * genunix
29838c67cbdSjiang wu - Sun Microsystems - Beijing China */
29938c67cbdSjiang wu - Sun Microsystems - Beijing China MDI_PI_LOCK(pip);
30038c67cbdSjiang wu - Sun Microsystems - Beijing China MDI_PI_HOLD(pip);
30138c67cbdSjiang wu - Sun Microsystems - Beijing China MDI_PI_UNLOCK(pip);
3027c478bd9Sstevel@tonic-gate
30338c67cbdSjiang wu - Sun Microsystems - Beijing China if (mdi_pi_pathname_obp(pip, prom_path) != NULL) {
30438c67cbdSjiang wu - Sun Microsystems - Beijing China /*
30538c67cbdSjiang wu - Sun Microsystems - Beijing China * The path has different obp path
30638c67cbdSjiang wu - Sun Microsystems - Beijing China */
30738c67cbdSjiang wu - Sun Microsystems - Beijing China goto minor_pathinfo;
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate
31038c67cbdSjiang wu - Sun Microsystems - Beijing China pdip = mdi_pi_get_phci(pip);
31138c67cbdSjiang wu - Sun Microsystems - Beijing China ndi_hold_devi(pdip);
31238c67cbdSjiang wu - Sun Microsystems - Beijing China
31338c67cbdSjiang wu - Sun Microsystems - Beijing China /*
31438c67cbdSjiang wu - Sun Microsystems - Beijing China * Get obp path name of the phci node firstly.
31538c67cbdSjiang wu - Sun Microsystems - Beijing China * NOTE: if the alternate node of pdip exists,
31638c67cbdSjiang wu - Sun Microsystems - Beijing China * the third argument of the i_devi_to_promname()
31738c67cbdSjiang wu - Sun Microsystems - Beijing China * would be set to the alternate node.
31838c67cbdSjiang wu - Sun Microsystems - Beijing China */
31938c67cbdSjiang wu - Sun Microsystems - Beijing China (void) i_devi_to_promname(pdip, prom_path, &alt_dip);
32038c67cbdSjiang wu - Sun Microsystems - Beijing China if (alt_dip != NULL) {
3217c478bd9Sstevel@tonic-gate ndi_rele_devi(pdip);
32238c67cbdSjiang wu - Sun Microsystems - Beijing China pdip = alt_dip;
32338c67cbdSjiang wu - Sun Microsystems - Beijing China ndi_hold_devi(pdip);
32438c67cbdSjiang wu - Sun Microsystems - Beijing China }
32538c67cbdSjiang wu - Sun Microsystems - Beijing China
32638c67cbdSjiang wu - Sun Microsystems - Beijing China nodename = ddi_node_name(dip);
32738c67cbdSjiang wu - Sun Microsystems - Beijing China unit_address = MDI_PI(pip)->pi_addr;
32838c67cbdSjiang wu - Sun Microsystems - Beijing China
32938c67cbdSjiang wu - Sun Microsystems - Beijing China major = ddi_driver_major(dip);
33038c67cbdSjiang wu - Sun Microsystems - Beijing China cdip = find_alternate_node(pdip, major);
33138c67cbdSjiang wu - Sun Microsystems - Beijing China
3327c478bd9Sstevel@tonic-gate if (cdip) {
3337c478bd9Sstevel@tonic-gate nodename = ddi_node_name(cdip);
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate /*
3367c478bd9Sstevel@tonic-gate * node name + unitaddr to the prom_path
3377c478bd9Sstevel@tonic-gate */
3387c478bd9Sstevel@tonic-gate (void) strcat(prom_path, "/");
3397c478bd9Sstevel@tonic-gate (void) strcat(prom_path, nodename);
3407c478bd9Sstevel@tonic-gate if (unit_address && (*unit_address)) {
3417c478bd9Sstevel@tonic-gate (void) strcat(prom_path, "@");
3427c478bd9Sstevel@tonic-gate (void) strcat(prom_path, unit_address);
3437c478bd9Sstevel@tonic-gate }
34438c67cbdSjiang wu - Sun Microsystems - Beijing China if (cdip) {
34538c67cbdSjiang wu - Sun Microsystems - Beijing China /* hold from find_alternate_node */
34638c67cbdSjiang wu - Sun Microsystems - Beijing China ndi_rele_devi(cdip);
3477c478bd9Sstevel@tonic-gate }
34838c67cbdSjiang wu - Sun Microsystems - Beijing China ndi_rele_devi(pdip);
34938c67cbdSjiang wu - Sun Microsystems - Beijing China minor_pathinfo:
3507c478bd9Sstevel@tonic-gate minorname = strrchr(dev_name, ':');
3517c478bd9Sstevel@tonic-gate if (minorname && (minorname[1] != '\0')) {
3527c478bd9Sstevel@tonic-gate (void) strcat(prom_path, minorname);
3537c478bd9Sstevel@tonic-gate }
3547c478bd9Sstevel@tonic-gate
35538c67cbdSjiang wu - Sun Microsystems - Beijing China if (MDI_PI_IS_ONLINE(pip)) {
3567c478bd9Sstevel@tonic-gate (void) snprintf(rptr, rlen, "%s", prom_path);
3577c478bd9Sstevel@tonic-gate rlen -= strlen(rptr) + 1;
3587c478bd9Sstevel@tonic-gate rptr += strlen(rptr) + 1;
3597c478bd9Sstevel@tonic-gate if (rlen <= 0) /* drop paths we can't store */
3607c478bd9Sstevel@tonic-gate break;
3617c478bd9Sstevel@tonic-gate } else { /* path is offline */
3627c478bd9Sstevel@tonic-gate (void) snprintf(optr, olen, "%s", prom_path);
3637c478bd9Sstevel@tonic-gate olen -= strlen(optr) + 1;
3647c478bd9Sstevel@tonic-gate if (olen > 0) /* drop paths we can't store */
3657c478bd9Sstevel@tonic-gate optr += strlen(optr) + 1;
3667c478bd9Sstevel@tonic-gate }
36738c67cbdSjiang wu - Sun Microsystems - Beijing China MDI_PI_LOCK(pip);
36838c67cbdSjiang wu - Sun Microsystems - Beijing China MDI_PI_RELE(pip);
36938c67cbdSjiang wu - Sun Microsystems - Beijing China if (MDI_PI(pip)->pi_ref_cnt == 0)
37038c67cbdSjiang wu - Sun Microsystems - Beijing China cv_broadcast(&MDI_PI(pip)->pi_ref_cv);
37138c67cbdSjiang wu - Sun Microsystems - Beijing China MDI_PI_UNLOCK(pip);
3727c478bd9Sstevel@tonic-gate }
373*3fe80ca4SDan Cross ndi_devi_exit(dip);
37438c67cbdSjiang wu - Sun Microsystems - Beijing China ret = 0;
37538c67cbdSjiang wu - Sun Microsystems - Beijing China if (rlen > 0) {
3767c478bd9Sstevel@tonic-gate /* now add as much of offline to ret_buf as possible */
3777c478bd9Sstevel@tonic-gate bcopy(offline, rptr, rlen);
37838c67cbdSjiang wu - Sun Microsystems - Beijing China }
37938c67cbdSjiang wu - Sun Microsystems - Beijing China kmem_free(offline, len);
38038c67cbdSjiang wu - Sun Microsystems - Beijing China }
38138c67cbdSjiang wu - Sun Microsystems - Beijing China /* release hold from e_ddi_hold_devi_by_path() */
38238c67cbdSjiang wu - Sun Microsystems - Beijing China ndi_rele_devi(dip);
3837c478bd9Sstevel@tonic-gate ret_buf[len - 1] = '\0';
3847c478bd9Sstevel@tonic-gate ret_buf[len - 2] = '\0';
3857c478bd9Sstevel@tonic-gate kmem_free(dev_path, MAXPATHLEN);
3867c478bd9Sstevel@tonic-gate kmem_free(prom_path, MAXPATHLEN);
38738c67cbdSjiang wu - Sun Microsystems - Beijing China
38838c67cbdSjiang wu - Sun Microsystems - Beijing China return (ret);
3897c478bd9Sstevel@tonic-gate }
3907c478bd9Sstevel@tonic-gate
3917c478bd9Sstevel@tonic-gate /*
3927c478bd9Sstevel@tonic-gate * check for a possible substitute node. This routine searches the
3937c478bd9Sstevel@tonic-gate * children of parent_dip, looking for a node that:
3947c478bd9Sstevel@tonic-gate * 1. is a prom node
3957c478bd9Sstevel@tonic-gate * 2. binds to the same major number
3967c478bd9Sstevel@tonic-gate * 3. there is no need to verify that the unit-address information
3977c478bd9Sstevel@tonic-gate * match since it is likely that the substitute node
3987c478bd9Sstevel@tonic-gate * will have none (e.g. disk) - this would be the reason the
3997c478bd9Sstevel@tonic-gate * framework rejected it in the first place.
4007c478bd9Sstevel@tonic-gate *
4017c478bd9Sstevel@tonic-gate * assumes parent_dip is held
4027c478bd9Sstevel@tonic-gate */
4037c478bd9Sstevel@tonic-gate static dev_info_t *
find_alternate_node(dev_info_t * parent_dip,major_t major)4047c478bd9Sstevel@tonic-gate find_alternate_node(dev_info_t *parent_dip, major_t major)
4057c478bd9Sstevel@tonic-gate {
4067c478bd9Sstevel@tonic-gate dev_info_t *child_dip;
4077c478bd9Sstevel@tonic-gate
4087c478bd9Sstevel@tonic-gate /* lock down parent to keep children from being removed */
409*3fe80ca4SDan Cross ndi_devi_enter(parent_dip);
4107c478bd9Sstevel@tonic-gate for (child_dip = ddi_get_child(parent_dip); child_dip != NULL;
4117c478bd9Sstevel@tonic-gate child_dip = ddi_get_next_sibling(child_dip)) {
4127c478bd9Sstevel@tonic-gate
4137c478bd9Sstevel@tonic-gate /* look for obp node with matching major */
4147c478bd9Sstevel@tonic-gate if ((ndi_dev_is_prom_node(child_dip) != 0) &&
4157c478bd9Sstevel@tonic-gate (ddi_driver_major(child_dip) == major)) {
4167c478bd9Sstevel@tonic-gate ndi_hold_devi(child_dip);
4177c478bd9Sstevel@tonic-gate break;
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate }
420*3fe80ca4SDan Cross ndi_devi_exit(parent_dip);
4217c478bd9Sstevel@tonic-gate return (child_dip);
4227c478bd9Sstevel@tonic-gate }
4237c478bd9Sstevel@tonic-gate
4247c478bd9Sstevel@tonic-gate /*
4257c478bd9Sstevel@tonic-gate * given an absolute pathname, convert it, if possible, to a devfs
4267c478bd9Sstevel@tonic-gate * name. Examples:
4277c478bd9Sstevel@tonic-gate * /dev/rsd3a to /pci@1f,4000/glm@3/sd@0,0:a
4287c478bd9Sstevel@tonic-gate * /dev/dsk/c0t0d0s0 to /pci@1f,4000/glm@3/sd@0,0:a
4297c478bd9Sstevel@tonic-gate * /devices/pci@1f,4000/glm@3/sd@0,0:a to /pci@1f,4000/glm@3/sd@0,0:a
4307c478bd9Sstevel@tonic-gate * /pci@1f,4000/glm@3/sd@0,0:a unchanged
4317c478bd9Sstevel@tonic-gate *
4327c478bd9Sstevel@tonic-gate * This routine deals with symbolic links, physical pathname with and
4337c478bd9Sstevel@tonic-gate * without /devices stripped. Returns 0 on success or -1 on failure.
4347c478bd9Sstevel@tonic-gate */
4357c478bd9Sstevel@tonic-gate static int
resolve_devfs_name(char * name,char * buffer)4367c478bd9Sstevel@tonic-gate resolve_devfs_name(char *name, char *buffer)
4377c478bd9Sstevel@tonic-gate {
4387c478bd9Sstevel@tonic-gate int error;
4397c478bd9Sstevel@tonic-gate char *fullname = NULL;
4407c478bd9Sstevel@tonic-gate struct pathname pn, rpn;
4417c478bd9Sstevel@tonic-gate
4427c478bd9Sstevel@tonic-gate /* if not a /dev or /device name, prepend /devices */
4437c478bd9Sstevel@tonic-gate if (strncmp(name, "/dev/", 5) != 0 &&
4447c478bd9Sstevel@tonic-gate strncmp(name, "/devices/", 9) != 0) {
4457c478bd9Sstevel@tonic-gate fullname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
4467c478bd9Sstevel@tonic-gate (void) snprintf(fullname, MAXPATHLEN, "/devices%s", name);
4477c478bd9Sstevel@tonic-gate name = fullname;
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate if (pn_get(name, UIO_SYSSPACE, &pn) != 0) {
4517c478bd9Sstevel@tonic-gate if (fullname)
4527c478bd9Sstevel@tonic-gate kmem_free(fullname, MAXPATHLEN);
4537c478bd9Sstevel@tonic-gate return (-1);
4547c478bd9Sstevel@tonic-gate }
4557c478bd9Sstevel@tonic-gate
4567c478bd9Sstevel@tonic-gate pn_alloc(&rpn);
4577c478bd9Sstevel@tonic-gate error = lookuppn(&pn, &rpn, FOLLOW, NULL, NULL);
4587c478bd9Sstevel@tonic-gate if (error == 0)
4597c478bd9Sstevel@tonic-gate bcopy(rpn.pn_path, buffer, rpn.pn_pathlen);
4607c478bd9Sstevel@tonic-gate
4617c478bd9Sstevel@tonic-gate pn_free(&pn);
4627c478bd9Sstevel@tonic-gate pn_free(&rpn);
4637c478bd9Sstevel@tonic-gate if (fullname)
4647c478bd9Sstevel@tonic-gate kmem_free(fullname, MAXPATHLEN);
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate return (error);
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate
4697c478bd9Sstevel@tonic-gate /*
4707c478bd9Sstevel@tonic-gate * If bootstring contains a device path, we need to convert to a format
4717c478bd9Sstevel@tonic-gate * the prom will understand. To do so, we convert the existing path to
4727c478bd9Sstevel@tonic-gate * a prom-compatible path and return the value of new_path. If the
4737c478bd9Sstevel@tonic-gate * caller specifies new_path as NULL, we allocate an appropriately
4747c478bd9Sstevel@tonic-gate * sized new_path on behalf of the caller. If the caller invokes this
4757c478bd9Sstevel@tonic-gate * function with new_path = NULL, they must do so from a context in
4767c478bd9Sstevel@tonic-gate * which it is safe to perform a sleeping memory allocation.
4777c478bd9Sstevel@tonic-gate */
4787c478bd9Sstevel@tonic-gate char *
i_convert_boot_device_name(char * cur_path,char * new_path,size_t * len)4797c478bd9Sstevel@tonic-gate i_convert_boot_device_name(char *cur_path, char *new_path, size_t *len)
4807c478bd9Sstevel@tonic-gate {
4817c478bd9Sstevel@tonic-gate char *ptr;
4827c478bd9Sstevel@tonic-gate int rval;
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate ASSERT(cur_path != NULL && len != NULL);
4857c478bd9Sstevel@tonic-gate ASSERT(new_path == NULL || *len >= MAXPATHLEN);
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate if (new_path == NULL) {
4887c478bd9Sstevel@tonic-gate *len = MAXPATHLEN + MAXNAMELEN;
4897c478bd9Sstevel@tonic-gate new_path = kmem_alloc(*len, KM_SLEEP);
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate
4927c478bd9Sstevel@tonic-gate if ((ptr = strchr(cur_path, ' ')) != NULL)
4937c478bd9Sstevel@tonic-gate *ptr = '\0';
4947c478bd9Sstevel@tonic-gate
4957c478bd9Sstevel@tonic-gate rval = i_devname_to_promname(cur_path, new_path, *len);
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate if (ptr != NULL)
4987c478bd9Sstevel@tonic-gate *ptr = ' ';
4997c478bd9Sstevel@tonic-gate
5007c478bd9Sstevel@tonic-gate if (rval == 0) {
5017c478bd9Sstevel@tonic-gate if (ptr != NULL) {
5027c478bd9Sstevel@tonic-gate (void) snprintf(new_path + strlen(new_path),
5037c478bd9Sstevel@tonic-gate *len - strlen(new_path), "%s", ptr);
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate } else { /* the conversion failed */
5067c478bd9Sstevel@tonic-gate (void) snprintf(new_path, *len, "%s", cur_path);
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate
5097c478bd9Sstevel@tonic-gate return (new_path);
5107c478bd9Sstevel@tonic-gate }
5117c478bd9Sstevel@tonic-gate
5127c478bd9Sstevel@tonic-gate /*
51338c67cbdSjiang wu - Sun Microsystems - Beijing China * Get the parent dip.
5147c478bd9Sstevel@tonic-gate */
5157c478bd9Sstevel@tonic-gate static dev_info_t *
get_parent(dev_info_t * dip,struct parinfo * info)51638c67cbdSjiang wu - Sun Microsystems - Beijing China get_parent(dev_info_t *dip, struct parinfo *info)
5177c478bd9Sstevel@tonic-gate {
5187c478bd9Sstevel@tonic-gate dev_info_t *pdip;
5197c478bd9Sstevel@tonic-gate
5207c478bd9Sstevel@tonic-gate pdip = ddi_get_parent(dip);
5217c478bd9Sstevel@tonic-gate ndi_hold_devi(pdip);
5227c478bd9Sstevel@tonic-gate info->dip = dip;
5237c478bd9Sstevel@tonic-gate info->pdip = pdip;
5247c478bd9Sstevel@tonic-gate return (pdip);
5257c478bd9Sstevel@tonic-gate }
526