1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/sunmdi.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/mdi_impldefs.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate struct parinfo { 38*7c478bd9Sstevel@tonic-gate dev_info_t *dip; 39*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 40*7c478bd9Sstevel@tonic-gate dev_info_t *pdip; 41*7c478bd9Sstevel@tonic-gate }; 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate /* 44*7c478bd9Sstevel@tonic-gate * internal functions 45*7c478bd9Sstevel@tonic-gate */ 46*7c478bd9Sstevel@tonic-gate static int resolve_devfs_name(char *, char *); 47*7c478bd9Sstevel@tonic-gate static dev_info_t *find_alternate_node(dev_info_t *, major_t); 48*7c478bd9Sstevel@tonic-gate static dev_info_t *get_path_parent(dev_info_t *, struct parinfo *); 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate /* internal global data */ 51*7c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = { 52*7c478bd9Sstevel@tonic-gate &mod_miscops, "bootdev misc module 1.21" 53*7c478bd9Sstevel@tonic-gate }; 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 56*7c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modlmisc, NULL 57*7c478bd9Sstevel@tonic-gate }; 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate int 60*7c478bd9Sstevel@tonic-gate _init() 61*7c478bd9Sstevel@tonic-gate { 62*7c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 63*7c478bd9Sstevel@tonic-gate } 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate int 66*7c478bd9Sstevel@tonic-gate _fini() 67*7c478bd9Sstevel@tonic-gate { 68*7c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 69*7c478bd9Sstevel@tonic-gate } 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate int 72*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 73*7c478bd9Sstevel@tonic-gate { 74*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 75*7c478bd9Sstevel@tonic-gate } 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate /* 78*7c478bd9Sstevel@tonic-gate * convert a prom device path to an equivalent path in /devices 79*7c478bd9Sstevel@tonic-gate * Does not deal with aliases. Does deal with pathnames which 80*7c478bd9Sstevel@tonic-gate * are not fully qualified. This routine is generalized 81*7c478bd9Sstevel@tonic-gate * to work across several flavors of OBP 82*7c478bd9Sstevel@tonic-gate */ 83*7c478bd9Sstevel@tonic-gate int 84*7c478bd9Sstevel@tonic-gate i_promname_to_devname(char *prom_name, char *ret_buf) 85*7c478bd9Sstevel@tonic-gate { 86*7c478bd9Sstevel@tonic-gate if (prom_name == NULL || ret_buf == NULL || 87*7c478bd9Sstevel@tonic-gate (strlen(prom_name) >= MAXPATHLEN)) { 88*7c478bd9Sstevel@tonic-gate return (EINVAL); 89*7c478bd9Sstevel@tonic-gate } 90*7c478bd9Sstevel@tonic-gate if (i_ddi_prompath_to_devfspath(prom_name, ret_buf) != DDI_SUCCESS) 91*7c478bd9Sstevel@tonic-gate return (EINVAL); 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate return (0); 94*7c478bd9Sstevel@tonic-gate } 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate /* 97*7c478bd9Sstevel@tonic-gate * translate a devfs pathname to one that will be acceptable 98*7c478bd9Sstevel@tonic-gate * by the prom. In most cases, there is no translation needed. 99*7c478bd9Sstevel@tonic-gate * For systems supporting generically named devices, the prom 100*7c478bd9Sstevel@tonic-gate * may support nodes such as 'disk' that do not have any unit 101*7c478bd9Sstevel@tonic-gate * address information (i.e. target,lun info). If this is the 102*7c478bd9Sstevel@tonic-gate * case, the ddi framework will reject the node as invalid and 103*7c478bd9Sstevel@tonic-gate * populate the devinfo tree with nodes froms the .conf file 104*7c478bd9Sstevel@tonic-gate * (e.g. sd). In this case, the names that show up in /devices 105*7c478bd9Sstevel@tonic-gate * are sd - since the prom only knows about 'disk' nodes, this 106*7c478bd9Sstevel@tonic-gate * routine detects this situation and does the conversion 107*7c478bd9Sstevel@tonic-gate * There are also cases such as pluto where the disk node in the 108*7c478bd9Sstevel@tonic-gate * prom is named "SUNW,ssd" but in /devices the name is "ssd". 109*7c478bd9Sstevel@tonic-gate * 110*7c478bd9Sstevel@tonic-gate * If MPxIO is enabled, the translation involves following 111*7c478bd9Sstevel@tonic-gate * pathinfo nodes to the "best" parent. See get_obp_parent(). 112*7c478bd9Sstevel@tonic-gate * 113*7c478bd9Sstevel@tonic-gate * return a 0 on success with the new device string in ret_buf. 114*7c478bd9Sstevel@tonic-gate * Otherwise return the appropriate error code as we may be called 115*7c478bd9Sstevel@tonic-gate * from the openprom driver. 116*7c478bd9Sstevel@tonic-gate */ 117*7c478bd9Sstevel@tonic-gate int 118*7c478bd9Sstevel@tonic-gate i_devname_to_promname(char *dev_name, char *ret_buf, size_t len) 119*7c478bd9Sstevel@tonic-gate { 120*7c478bd9Sstevel@tonic-gate dev_info_t *dip, *pdip, *cdip, *idip; 121*7c478bd9Sstevel@tonic-gate char *dev_path, *prom_path; 122*7c478bd9Sstevel@tonic-gate char *unit_address, *minorname, *nodename; 123*7c478bd9Sstevel@tonic-gate major_t major; 124*7c478bd9Sstevel@tonic-gate int depth, old_depth; 125*7c478bd9Sstevel@tonic-gate struct parinfo *parinfo; 126*7c478bd9Sstevel@tonic-gate struct parinfo *info; 127*7c478bd9Sstevel@tonic-gate char *rptr, *optr, *offline; 128*7c478bd9Sstevel@tonic-gate size_t olen, rlen; 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate /* do some sanity checks */ 131*7c478bd9Sstevel@tonic-gate if ((dev_name == NULL) || (ret_buf == NULL) || 132*7c478bd9Sstevel@tonic-gate (strlen(dev_name) > MAXPATHLEN)) { 133*7c478bd9Sstevel@tonic-gate return (EINVAL); 134*7c478bd9Sstevel@tonic-gate } 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate /* 137*7c478bd9Sstevel@tonic-gate * Convert to a /devices name. Fail the translation if 138*7c478bd9Sstevel@tonic-gate * the name doesn't exist. 139*7c478bd9Sstevel@tonic-gate */ 140*7c478bd9Sstevel@tonic-gate dev_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 141*7c478bd9Sstevel@tonic-gate if (resolve_devfs_name(dev_name, dev_path) != 0 || 142*7c478bd9Sstevel@tonic-gate strncmp(dev_path, "/devices/", 9) != 0) { 143*7c478bd9Sstevel@tonic-gate kmem_free(dev_path, MAXPATHLEN); 144*7c478bd9Sstevel@tonic-gate return (EINVAL); 145*7c478bd9Sstevel@tonic-gate } 146*7c478bd9Sstevel@tonic-gate dev_name = dev_path + sizeof ("/devices") - 1; 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate bzero(ret_buf, len); 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate if (prom_finddevice(dev_name) != OBP_BADNODE) { 151*7c478bd9Sstevel@tonic-gate /* we are done */ 152*7c478bd9Sstevel@tonic-gate (void) snprintf(ret_buf, len, "%s", dev_name); 153*7c478bd9Sstevel@tonic-gate kmem_free(dev_path, MAXPATHLEN); 154*7c478bd9Sstevel@tonic-gate return (0); 155*7c478bd9Sstevel@tonic-gate } 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate /* 158*7c478bd9Sstevel@tonic-gate * if we get here, then some portion of the device path is 159*7c478bd9Sstevel@tonic-gate * not understood by the prom. We need to look for alternate 160*7c478bd9Sstevel@tonic-gate * names (e.g. replace ssd by disk) and mpxio enabled devices. 161*7c478bd9Sstevel@tonic-gate */ 162*7c478bd9Sstevel@tonic-gate dip = e_ddi_hold_devi_by_path(dev_name, 0); 163*7c478bd9Sstevel@tonic-gate if (dip == NULL) { 164*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "cannot find dip for %s", dev_name); 165*7c478bd9Sstevel@tonic-gate kmem_free(dev_path, MAXPATHLEN); 166*7c478bd9Sstevel@tonic-gate return (EINVAL); 167*7c478bd9Sstevel@tonic-gate } 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate /* find the closest ancestor which is a prom node */ 170*7c478bd9Sstevel@tonic-gate pdip = dip; 171*7c478bd9Sstevel@tonic-gate parinfo = kmem_alloc(OBP_STACKDEPTH * sizeof (*parinfo), KM_SLEEP); 172*7c478bd9Sstevel@tonic-gate for (depth = 0; ndi_dev_is_prom_node(pdip) == 0; depth++) { 173*7c478bd9Sstevel@tonic-gate if (depth == OBP_STACKDEPTH) { 174*7c478bd9Sstevel@tonic-gate kmem_free(dev_path, MAXPATHLEN); 175*7c478bd9Sstevel@tonic-gate kmem_free(parinfo, OBP_STACKDEPTH * sizeof (*parinfo)); 176*7c478bd9Sstevel@tonic-gate return (EINVAL); /* must not have been an obp node */ 177*7c478bd9Sstevel@tonic-gate } 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate pdip = get_path_parent(pdip, &parinfo[depth]); 180*7c478bd9Sstevel@tonic-gate } 181*7c478bd9Sstevel@tonic-gate ASSERT(pdip); /* at least root is prom node */ 182*7c478bd9Sstevel@tonic-gate ASSERT(depth > 0); 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate prom_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate offline = kmem_zalloc(len, KM_SLEEP); /* offline paths */ 187*7c478bd9Sstevel@tonic-gate olen = len; 188*7c478bd9Sstevel@tonic-gate rlen = len; 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate rptr = ret_buf; 191*7c478bd9Sstevel@tonic-gate optr = offline; 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate old_depth = depth; 194*7c478bd9Sstevel@tonic-gate do { 195*7c478bd9Sstevel@tonic-gate bzero(prom_path, MAXPATHLEN); 196*7c478bd9Sstevel@tonic-gate if (pdip) 197*7c478bd9Sstevel@tonic-gate (void) ddi_pathname(pdip, prom_path); 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate ndi_hold_devi(pdip); 200*7c478bd9Sstevel@tonic-gate for (depth = old_depth; depth > 0; depth--) { 201*7c478bd9Sstevel@tonic-gate info = &parinfo[depth - 1]; 202*7c478bd9Sstevel@tonic-gate idip = info->dip; 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate nodename = ddi_node_name(idip); 205*7c478bd9Sstevel@tonic-gate if (info->pip) { 206*7c478bd9Sstevel@tonic-gate unit_address = MDI_PI(info->pip)->pi_addr; 207*7c478bd9Sstevel@tonic-gate } else { 208*7c478bd9Sstevel@tonic-gate unit_address = ddi_get_name_addr(idip); 209*7c478bd9Sstevel@tonic-gate } 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate if (pdip) { 212*7c478bd9Sstevel@tonic-gate major = ddi_driver_major(idip); 213*7c478bd9Sstevel@tonic-gate cdip = find_alternate_node(pdip, major); 214*7c478bd9Sstevel@tonic-gate ndi_rele_devi(pdip); 215*7c478bd9Sstevel@tonic-gate if (cdip) { 216*7c478bd9Sstevel@tonic-gate nodename = ddi_node_name(cdip); 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate } 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate /* 221*7c478bd9Sstevel@tonic-gate * node name + unitaddr to the prom_path 222*7c478bd9Sstevel@tonic-gate */ 223*7c478bd9Sstevel@tonic-gate (void) strcat(prom_path, "/"); 224*7c478bd9Sstevel@tonic-gate (void) strcat(prom_path, nodename); 225*7c478bd9Sstevel@tonic-gate if (unit_address && (*unit_address)) { 226*7c478bd9Sstevel@tonic-gate (void) strcat(prom_path, "@"); 227*7c478bd9Sstevel@tonic-gate (void) strcat(prom_path, unit_address); 228*7c478bd9Sstevel@tonic-gate } 229*7c478bd9Sstevel@tonic-gate pdip = cdip; 230*7c478bd9Sstevel@tonic-gate } 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate if (pdip) { 233*7c478bd9Sstevel@tonic-gate ndi_rele_devi(pdip); /* hold from find_alternate_node */ 234*7c478bd9Sstevel@tonic-gate } 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate minorname = strrchr(dev_name, ':'); 237*7c478bd9Sstevel@tonic-gate if (minorname && (minorname[1] != '\0')) { 238*7c478bd9Sstevel@tonic-gate (void) strcat(prom_path, minorname); 239*7c478bd9Sstevel@tonic-gate } 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate if (!info || !info->pip || MDI_PI_IS_ONLINE(info->pip)) { 242*7c478bd9Sstevel@tonic-gate (void) snprintf(rptr, rlen, "%s", prom_path); 243*7c478bd9Sstevel@tonic-gate rlen -= strlen(rptr) + 1; 244*7c478bd9Sstevel@tonic-gate rptr += strlen(rptr) + 1; 245*7c478bd9Sstevel@tonic-gate if (rlen <= 0) /* drop paths we can't store */ 246*7c478bd9Sstevel@tonic-gate break; 247*7c478bd9Sstevel@tonic-gate } else { /* path is offline */ 248*7c478bd9Sstevel@tonic-gate (void) snprintf(optr, olen, "%s", prom_path); 249*7c478bd9Sstevel@tonic-gate olen -= strlen(optr) + 1; 250*7c478bd9Sstevel@tonic-gate if (olen > 0) /* drop paths we can't store */ 251*7c478bd9Sstevel@tonic-gate optr += strlen(optr) + 1; 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate } 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate /* 256*7c478bd9Sstevel@tonic-gate * The following code assumes that the phci client is at leaf 257*7c478bd9Sstevel@tonic-gate * level and that all phci nodes are prom nodes. 258*7c478bd9Sstevel@tonic-gate */ 259*7c478bd9Sstevel@tonic-gate info = &parinfo[0]; 260*7c478bd9Sstevel@tonic-gate if (info && info->dip && info->pip) { 261*7c478bd9Sstevel@tonic-gate info->pip = 262*7c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(info->pip)->pi_client_link; 263*7c478bd9Sstevel@tonic-gate if (info->pip) { 264*7c478bd9Sstevel@tonic-gate pdip = mdi_pi_get_phci(info->pip); 265*7c478bd9Sstevel@tonic-gate pdip = ddi_get_parent(pdip); 266*7c478bd9Sstevel@tonic-gate } else { 267*7c478bd9Sstevel@tonic-gate break; 268*7c478bd9Sstevel@tonic-gate } 269*7c478bd9Sstevel@tonic-gate } else { 270*7c478bd9Sstevel@tonic-gate break; 271*7c478bd9Sstevel@tonic-gate } 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate } while (info && info->pip && pdip); 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate ndi_rele_devi(dip); /* release hold from e_ddi_hold_devi_by_path() */ 276*7c478bd9Sstevel@tonic-gate 277*7c478bd9Sstevel@tonic-gate /* release holds from get_path_parent() */ 278*7c478bd9Sstevel@tonic-gate for (depth = old_depth; depth > 0; depth--) { 279*7c478bd9Sstevel@tonic-gate info = &parinfo[depth - 1]; 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate /* replace with mdi_rele_path() when mpxio goes into genunix */ 282*7c478bd9Sstevel@tonic-gate if (info && info->pip) { 283*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(info->pip); 284*7c478bd9Sstevel@tonic-gate MDI_PI_RELE(info->pip); 285*7c478bd9Sstevel@tonic-gate if (MDI_PI(info->pip)->pi_ref_cnt == 0) 286*7c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(info->pip)->pi_ref_cv); 287*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(info->pip); 288*7c478bd9Sstevel@tonic-gate } 289*7c478bd9Sstevel@tonic-gate if (info && info->pdip) 290*7c478bd9Sstevel@tonic-gate ndi_rele_devi(info->pdip); 291*7c478bd9Sstevel@tonic-gate } 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate /* now add as much of offline to ret_buf as possible */ 294*7c478bd9Sstevel@tonic-gate bcopy(offline, rptr, rlen); 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate ret_buf[len - 1] = '\0'; 297*7c478bd9Sstevel@tonic-gate ret_buf[len - 2] = '\0'; 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate kmem_free(offline, len); 300*7c478bd9Sstevel@tonic-gate kmem_free(dev_path, MAXPATHLEN); 301*7c478bd9Sstevel@tonic-gate kmem_free(prom_path, MAXPATHLEN); 302*7c478bd9Sstevel@tonic-gate kmem_free(parinfo, OBP_STACKDEPTH * sizeof (*parinfo)); 303*7c478bd9Sstevel@tonic-gate return (0); 304*7c478bd9Sstevel@tonic-gate } 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate /* 307*7c478bd9Sstevel@tonic-gate * check for a possible substitute node. This routine searches the 308*7c478bd9Sstevel@tonic-gate * children of parent_dip, looking for a node that: 309*7c478bd9Sstevel@tonic-gate * 1. is a prom node 310*7c478bd9Sstevel@tonic-gate * 2. binds to the same major number 311*7c478bd9Sstevel@tonic-gate * 3. there is no need to verify that the unit-address information 312*7c478bd9Sstevel@tonic-gate * match since it is likely that the substitute node 313*7c478bd9Sstevel@tonic-gate * will have none (e.g. disk) - this would be the reason the 314*7c478bd9Sstevel@tonic-gate * framework rejected it in the first place. 315*7c478bd9Sstevel@tonic-gate * 316*7c478bd9Sstevel@tonic-gate * assumes parent_dip is held 317*7c478bd9Sstevel@tonic-gate */ 318*7c478bd9Sstevel@tonic-gate static dev_info_t * 319*7c478bd9Sstevel@tonic-gate find_alternate_node(dev_info_t *parent_dip, major_t major) 320*7c478bd9Sstevel@tonic-gate { 321*7c478bd9Sstevel@tonic-gate int circ; 322*7c478bd9Sstevel@tonic-gate dev_info_t *child_dip; 323*7c478bd9Sstevel@tonic-gate 324*7c478bd9Sstevel@tonic-gate /* lock down parent to keep children from being removed */ 325*7c478bd9Sstevel@tonic-gate ndi_devi_enter(parent_dip, &circ); 326*7c478bd9Sstevel@tonic-gate for (child_dip = ddi_get_child(parent_dip); child_dip != NULL; 327*7c478bd9Sstevel@tonic-gate child_dip = ddi_get_next_sibling(child_dip)) { 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate /* look for obp node with matching major */ 330*7c478bd9Sstevel@tonic-gate if ((ndi_dev_is_prom_node(child_dip) != 0) && 331*7c478bd9Sstevel@tonic-gate (ddi_driver_major(child_dip) == major)) { 332*7c478bd9Sstevel@tonic-gate ndi_hold_devi(child_dip); 333*7c478bd9Sstevel@tonic-gate break; 334*7c478bd9Sstevel@tonic-gate } 335*7c478bd9Sstevel@tonic-gate } 336*7c478bd9Sstevel@tonic-gate ndi_devi_exit(parent_dip, circ); 337*7c478bd9Sstevel@tonic-gate return (child_dip); 338*7c478bd9Sstevel@tonic-gate } 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate /* 341*7c478bd9Sstevel@tonic-gate * given an absolute pathname, convert it, if possible, to a devfs 342*7c478bd9Sstevel@tonic-gate * name. Examples: 343*7c478bd9Sstevel@tonic-gate * /dev/rsd3a to /pci@1f,4000/glm@3/sd@0,0:a 344*7c478bd9Sstevel@tonic-gate * /dev/dsk/c0t0d0s0 to /pci@1f,4000/glm@3/sd@0,0:a 345*7c478bd9Sstevel@tonic-gate * /devices/pci@1f,4000/glm@3/sd@0,0:a to /pci@1f,4000/glm@3/sd@0,0:a 346*7c478bd9Sstevel@tonic-gate * /pci@1f,4000/glm@3/sd@0,0:a unchanged 347*7c478bd9Sstevel@tonic-gate * 348*7c478bd9Sstevel@tonic-gate * This routine deals with symbolic links, physical pathname with and 349*7c478bd9Sstevel@tonic-gate * without /devices stripped. Returns 0 on success or -1 on failure. 350*7c478bd9Sstevel@tonic-gate */ 351*7c478bd9Sstevel@tonic-gate static int 352*7c478bd9Sstevel@tonic-gate resolve_devfs_name(char *name, char *buffer) 353*7c478bd9Sstevel@tonic-gate { 354*7c478bd9Sstevel@tonic-gate int error; 355*7c478bd9Sstevel@tonic-gate char *fullname = NULL; 356*7c478bd9Sstevel@tonic-gate struct pathname pn, rpn; 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate /* if not a /dev or /device name, prepend /devices */ 359*7c478bd9Sstevel@tonic-gate if (strncmp(name, "/dev/", 5) != 0 && 360*7c478bd9Sstevel@tonic-gate strncmp(name, "/devices/", 9) != 0) { 361*7c478bd9Sstevel@tonic-gate fullname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 362*7c478bd9Sstevel@tonic-gate (void) snprintf(fullname, MAXPATHLEN, "/devices%s", name); 363*7c478bd9Sstevel@tonic-gate name = fullname; 364*7c478bd9Sstevel@tonic-gate } 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate if (pn_get(name, UIO_SYSSPACE, &pn) != 0) { 367*7c478bd9Sstevel@tonic-gate if (fullname) 368*7c478bd9Sstevel@tonic-gate kmem_free(fullname, MAXPATHLEN); 369*7c478bd9Sstevel@tonic-gate return (-1); 370*7c478bd9Sstevel@tonic-gate } 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate pn_alloc(&rpn); 373*7c478bd9Sstevel@tonic-gate error = lookuppn(&pn, &rpn, FOLLOW, NULL, NULL); 374*7c478bd9Sstevel@tonic-gate if (error == 0) 375*7c478bd9Sstevel@tonic-gate bcopy(rpn.pn_path, buffer, rpn.pn_pathlen); 376*7c478bd9Sstevel@tonic-gate 377*7c478bd9Sstevel@tonic-gate pn_free(&pn); 378*7c478bd9Sstevel@tonic-gate pn_free(&rpn); 379*7c478bd9Sstevel@tonic-gate if (fullname) 380*7c478bd9Sstevel@tonic-gate kmem_free(fullname, MAXPATHLEN); 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate return (error); 383*7c478bd9Sstevel@tonic-gate } 384*7c478bd9Sstevel@tonic-gate 385*7c478bd9Sstevel@tonic-gate /* 386*7c478bd9Sstevel@tonic-gate * If bootstring contains a device path, we need to convert to a format 387*7c478bd9Sstevel@tonic-gate * the prom will understand. To do so, we convert the existing path to 388*7c478bd9Sstevel@tonic-gate * a prom-compatible path and return the value of new_path. If the 389*7c478bd9Sstevel@tonic-gate * caller specifies new_path as NULL, we allocate an appropriately 390*7c478bd9Sstevel@tonic-gate * sized new_path on behalf of the caller. If the caller invokes this 391*7c478bd9Sstevel@tonic-gate * function with new_path = NULL, they must do so from a context in 392*7c478bd9Sstevel@tonic-gate * which it is safe to perform a sleeping memory allocation. 393*7c478bd9Sstevel@tonic-gate */ 394*7c478bd9Sstevel@tonic-gate char * 395*7c478bd9Sstevel@tonic-gate i_convert_boot_device_name(char *cur_path, char *new_path, size_t *len) 396*7c478bd9Sstevel@tonic-gate { 397*7c478bd9Sstevel@tonic-gate char *ptr; 398*7c478bd9Sstevel@tonic-gate int rval; 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate ASSERT(cur_path != NULL && len != NULL); 401*7c478bd9Sstevel@tonic-gate ASSERT(new_path == NULL || *len >= MAXPATHLEN); 402*7c478bd9Sstevel@tonic-gate 403*7c478bd9Sstevel@tonic-gate if (new_path == NULL) { 404*7c478bd9Sstevel@tonic-gate *len = MAXPATHLEN + MAXNAMELEN; 405*7c478bd9Sstevel@tonic-gate new_path = kmem_alloc(*len, KM_SLEEP); 406*7c478bd9Sstevel@tonic-gate } 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate if ((ptr = strchr(cur_path, ' ')) != NULL) 409*7c478bd9Sstevel@tonic-gate *ptr = '\0'; 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate rval = i_devname_to_promname(cur_path, new_path, *len); 412*7c478bd9Sstevel@tonic-gate 413*7c478bd9Sstevel@tonic-gate if (ptr != NULL) 414*7c478bd9Sstevel@tonic-gate *ptr = ' '; 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate if (rval == 0) { 417*7c478bd9Sstevel@tonic-gate if (ptr != NULL) { 418*7c478bd9Sstevel@tonic-gate (void) snprintf(new_path + strlen(new_path), 419*7c478bd9Sstevel@tonic-gate *len - strlen(new_path), "%s", ptr); 420*7c478bd9Sstevel@tonic-gate } 421*7c478bd9Sstevel@tonic-gate } else { /* the conversion failed */ 422*7c478bd9Sstevel@tonic-gate (void) snprintf(new_path, *len, "%s", cur_path); 423*7c478bd9Sstevel@tonic-gate } 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate return (new_path); 426*7c478bd9Sstevel@tonic-gate } 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate /* 429*7c478bd9Sstevel@tonic-gate * Get the parent dip. If dip is mpxio client, get the first online 430*7c478bd9Sstevel@tonic-gate * path and return the phci dip with both pathinfo and dip held 431*7c478bd9Sstevel@tonic-gate * otherwise just return with the dip held. 432*7c478bd9Sstevel@tonic-gate */ 433*7c478bd9Sstevel@tonic-gate static dev_info_t * 434*7c478bd9Sstevel@tonic-gate get_path_parent(dev_info_t *dip, struct parinfo *info) 435*7c478bd9Sstevel@tonic-gate { 436*7c478bd9Sstevel@tonic-gate dev_info_t *pdip; 437*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 438*7c478bd9Sstevel@tonic-gate int circ; 439*7c478bd9Sstevel@tonic-gate 440*7c478bd9Sstevel@tonic-gate if (!MDI_CLIENT(dip)) { 441*7c478bd9Sstevel@tonic-gate pdip = ddi_get_parent(dip); 442*7c478bd9Sstevel@tonic-gate pip = NULL; 443*7c478bd9Sstevel@tonic-gate goto finish; 444*7c478bd9Sstevel@tonic-gate } 445*7c478bd9Sstevel@tonic-gate 446*7c478bd9Sstevel@tonic-gate /* find and hold the pathinfo */ 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate ndi_devi_enter(dip, &circ); 449*7c478bd9Sstevel@tonic-gate pip = mdi_get_next_phci_path(dip, NULL); 450*7c478bd9Sstevel@tonic-gate 451*7c478bd9Sstevel@tonic-gate if (pip == NULL) { 452*7c478bd9Sstevel@tonic-gate ndi_devi_exit(dip, circ); 453*7c478bd9Sstevel@tonic-gate return (NULL); 454*7c478bd9Sstevel@tonic-gate } 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate /* replace with mdi_hold_path() when mpxio goes into genunix */ 457*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 458*7c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 459*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate ndi_devi_exit(dip, circ); 462*7c478bd9Sstevel@tonic-gate pdip = mdi_pi_get_phci(pip); 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate finish: 465*7c478bd9Sstevel@tonic-gate ndi_hold_devi(pdip); 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate info->dip = dip; 468*7c478bd9Sstevel@tonic-gate info->pip = pip; 469*7c478bd9Sstevel@tonic-gate info->pdip = pdip; 470*7c478bd9Sstevel@tonic-gate return (pdip); 471*7c478bd9Sstevel@tonic-gate } 472