diff options
| author | jiang wu - Sun Microsystems - Beijing China <Javen.Wu@Sun.COM> | 2008-08-27 14:01:14 +0800 |
|---|---|---|
| committer | jiang wu - Sun Microsystems - Beijing China <Javen.Wu@Sun.COM> | 2008-08-27 14:01:14 +0800 |
| commit | 38c67cbd88257a6cd4f0dc854d01cc278f86f1c9 (patch) | |
| tree | e398e8153bd0365b6a5b319e32b65efe1a6f1a93 /usr/src/uts/sparc/os/bootdev.c | |
| parent | aced7ad033ca9dc85b658d692d0054f5b8f69578 (diff) | |
| download | illumos-joyent-38c67cbd88257a6cd4f0dc854d01cc278f86f1c9.tar.gz | |
6616427 Support WWID based addressing of SAS, SATA devices
6740301 i_devname_to_promname() converts wrong promname for 2nd path of client node when mpxio enabled
6740310 The assumption for mpxio in bootdev.c:i_devname_to_promname() is wrong
Diffstat (limited to 'usr/src/uts/sparc/os/bootdev.c')
| -rw-r--r-- | usr/src/uts/sparc/os/bootdev.c | 362 |
1 files changed, 207 insertions, 155 deletions
diff --git a/usr/src/uts/sparc/os/bootdev.c b/usr/src/uts/sparc/os/bootdev.c index b45ae4835f..e562d3caf7 100644 --- a/usr/src/uts/sparc/os/bootdev.c +++ b/usr/src/uts/sparc/os/bootdev.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/systm.h> #include <sys/pathname.h> #include <sys/modctl.h> @@ -36,7 +33,6 @@ struct parinfo { dev_info_t *dip; - mdi_pathinfo_t *pip; dev_info_t *pdip; }; @@ -45,11 +41,12 @@ struct parinfo { */ static int resolve_devfs_name(char *, char *); static dev_info_t *find_alternate_node(dev_info_t *, major_t); -static dev_info_t *get_path_parent(dev_info_t *, struct parinfo *); +static dev_info_t *get_parent(dev_info_t *, struct parinfo *); +static int i_devi_to_promname(dev_info_t *, char *, dev_info_t **alt_dipp); /* internal global data */ static struct modlmisc modlmisc = { - &mod_miscops, "bootdev misc module 1.21" + &mod_miscops, "bootdev misc module 1.22" }; static struct modlinkage modlinkage = { @@ -94,6 +91,101 @@ i_promname_to_devname(char *prom_name, char *ret_buf) } /* + * The function is to get prom name according non-client dip node. + * And the function will set the alternate node of dip to alt_dip + * if it is exist which must be PROM node. + */ +static int +i_devi_to_promname(dev_info_t *dip, char *prom_path, dev_info_t **alt_dipp) +{ + dev_info_t *pdip, *cdip, *idip; + char *unit_address, *nodename; + major_t major; + int depth, old_depth = 0; + struct parinfo *parinfo = NULL; + struct parinfo *info; + int ret = 0; + + if (MDI_CLIENT(dip)) + return (EINVAL); + + if (ddi_pathname_obp(dip, prom_path) != NULL) { + return (0); + } + /* + * ddi_pathname_obp return NULL, but the obp path still could + * be different with the devfs path name, so need use a parents + * stack to compose the path name string layer by layer. + */ + + /* find the closest ancestor which is a prom node */ + pdip = dip; + parinfo = kmem_alloc(OBP_STACKDEPTH * sizeof (*parinfo), + KM_SLEEP); + for (depth = 0; ndi_dev_is_prom_node(pdip) == 0; depth++) { + if (depth == OBP_STACKDEPTH) { + ret = EINVAL; + /* must not have been an obp node */ + goto out; + } + pdip = get_parent(pdip, &parinfo[depth]); + } + old_depth = depth; + ASSERT(pdip); /* at least root is prom node */ + if (pdip) + (void) ddi_pathname(pdip, prom_path); + + ndi_hold_devi(pdip); + + for (depth = old_depth; depth > 0; depth--) { + info = &parinfo[depth - 1]; + idip = info->dip; + nodename = ddi_node_name(idip); + unit_address = ddi_get_name_addr(idip); + + if (pdip) { + major = ddi_driver_major(idip); + cdip = find_alternate_node(pdip, major); + ndi_rele_devi(pdip); + if (cdip) { + nodename = ddi_node_name(cdip); + } + } + + /* + * node name + unitaddr to the prom_path + */ + (void) strcat(prom_path, "/"); + (void) strcat(prom_path, nodename); + if (unit_address && (*unit_address)) { + (void) strcat(prom_path, "@"); + (void) strcat(prom_path, unit_address); + } + pdip = cdip; + } + + if (pdip) { + ndi_rele_devi(pdip); /* hold from find_alternate_node */ + } + /* + * Now pdip is the alternate node which is same hierarchy as dip + * if it exists. + */ + *alt_dipp = pdip; +out: + if (parinfo) { + /* release holds from get_parent() */ + for (depth = old_depth; depth > 0; depth--) { + info = &parinfo[depth - 1]; + if (info && info->pdip) + ndi_rele_devi(info->pdip); + } + kmem_free(parinfo, OBP_STACKDEPTH * sizeof (*parinfo)); + } + return (ret); +} + +/* * translate a devfs pathname to one that will be acceptable * by the prom. In most cases, there is no translation needed. * For systems supporting generically named devices, the prom @@ -108,7 +200,7 @@ i_promname_to_devname(char *prom_name, char *ret_buf) * prom is named "SUNW,ssd" but in /devices the name is "ssd". * * If MPxIO is enabled, the translation involves following - * pathinfo nodes to the "best" parent. See get_obp_parent(). + * pathinfo nodes to the "best" parent. * * return a 0 on success with the new device string in ret_buf. * Otherwise return the appropriate error code as we may be called @@ -117,15 +209,15 @@ i_promname_to_devname(char *prom_name, char *ret_buf) int i_devname_to_promname(char *dev_name, char *ret_buf, size_t len) { - dev_info_t *dip, *pdip, *cdip, *idip; + dev_info_t *dip, *pdip, *cdip, *alt_dip = NULL; + mdi_pathinfo_t *pip = NULL; char *dev_path, *prom_path; char *unit_address, *minorname, *nodename; major_t major; - int depth, old_depth; - struct parinfo *parinfo; - struct parinfo *info; char *rptr, *optr, *offline; size_t olen, rlen; + int circ; + int ret = 0; /* do some sanity checks */ if ((dev_name == NULL) || (ret_buf == NULL) || @@ -166,57 +258,77 @@ i_devname_to_promname(char *dev_name, char *ret_buf, size_t len) return (EINVAL); } - /* find the closest ancestor which is a prom node */ - pdip = dip; - parinfo = kmem_alloc(OBP_STACKDEPTH * sizeof (*parinfo), KM_SLEEP); - for (depth = 0; ndi_dev_is_prom_node(pdip) == 0; depth++) { - if (depth == OBP_STACKDEPTH) { - kmem_free(dev_path, MAXPATHLEN); - kmem_free(parinfo, OBP_STACKDEPTH * sizeof (*parinfo)); - return (EINVAL); /* must not have been an obp node */ - } - - pdip = get_path_parent(pdip, &parinfo[depth]); - } - ASSERT(pdip); /* at least root is prom node */ - ASSERT(depth > 0); - - prom_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); - - offline = kmem_zalloc(len, KM_SLEEP); /* offline paths */ - olen = len; + prom_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); rlen = len; - rptr = ret_buf; - optr = offline; - - old_depth = depth; - do { - bzero(prom_path, MAXPATHLEN); - if (pdip) - (void) ddi_pathname(pdip, prom_path); - ndi_hold_devi(pdip); - for (depth = old_depth; depth > 0; depth--) { - info = &parinfo[depth - 1]; - idip = info->dip; + if (!MDI_CLIENT(dip)) { + ret = i_devi_to_promname(dip, prom_path, &alt_dip); + if (ret == 0) { + minorname = strrchr(dev_name, ':'); + if (minorname && (minorname[1] != '\0')) { + (void) strcat(prom_path, minorname); + } + (void) snprintf(rptr, rlen, "%s", prom_path); + } + } else { + /* + * if get to here, means dip is a vhci client + */ + offline = kmem_zalloc(len, KM_SLEEP); /* offline paths */ + olen = len; + optr = offline; + /* + * The following code assumes that the phci client is at leaf + * level. + */ + ndi_devi_enter(dip, &circ); + while ((pip = mdi_get_next_phci_path(dip, pip)) != NULL) { + /* + * walk all paths associated to the client node + */ + bzero(prom_path, MAXPATHLEN); - nodename = ddi_node_name(idip); - if (info->pip) { - unit_address = MDI_PI(info->pip)->pi_addr; - } else { - unit_address = ddi_get_name_addr(idip); + /* + * replace with mdi_hold_path() when mpxio goes into + * genunix + */ + MDI_PI_LOCK(pip); + MDI_PI_HOLD(pip); + MDI_PI_UNLOCK(pip); + + if (mdi_pi_pathname_obp(pip, prom_path) != NULL) { + /* + * The path has different obp path + */ + goto minor_pathinfo; } - if (pdip) { - major = ddi_driver_major(idip); - cdip = find_alternate_node(pdip, major); + pdip = mdi_pi_get_phci(pip); + ndi_hold_devi(pdip); + + /* + * Get obp path name of the phci node firstly. + * NOTE: if the alternate node of pdip exists, + * the third argument of the i_devi_to_promname() + * would be set to the alternate node. + */ + (void) i_devi_to_promname(pdip, prom_path, &alt_dip); + if (alt_dip != NULL) { ndi_rele_devi(pdip); - if (cdip) { - nodename = ddi_node_name(cdip); - } + pdip = alt_dip; + ndi_hold_devi(pdip); } + nodename = ddi_node_name(dip); + unit_address = MDI_PI(pip)->pi_addr; + + major = ddi_driver_major(dip); + cdip = find_alternate_node(pdip, major); + + if (cdip) { + nodename = ddi_node_name(cdip); + } /* * node name + unitaddr to the prom_path */ @@ -226,81 +338,51 @@ i_devname_to_promname(char *dev_name, char *ret_buf, size_t len) (void) strcat(prom_path, "@"); (void) strcat(prom_path, unit_address); } - pdip = cdip; - } - - if (pdip) { - ndi_rele_devi(pdip); /* hold from find_alternate_node */ - } - - minorname = strrchr(dev_name, ':'); - if (minorname && (minorname[1] != '\0')) { - (void) strcat(prom_path, minorname); - } - - if (!info || !info->pip || MDI_PI_IS_ONLINE(info->pip)) { - (void) snprintf(rptr, rlen, "%s", prom_path); - rlen -= strlen(rptr) + 1; - rptr += strlen(rptr) + 1; - if (rlen <= 0) /* drop paths we can't store */ - break; - } else { /* path is offline */ - (void) snprintf(optr, olen, "%s", prom_path); - olen -= strlen(optr) + 1; - if (olen > 0) /* drop paths we can't store */ - optr += strlen(optr) + 1; - - } + if (cdip) { + /* hold from find_alternate_node */ + ndi_rele_devi(cdip); + } + ndi_rele_devi(pdip); +minor_pathinfo: + minorname = strrchr(dev_name, ':'); + if (minorname && (minorname[1] != '\0')) { + (void) strcat(prom_path, minorname); + } - /* - * The following code assumes that the phci client is at leaf - * level and that all phci nodes are prom nodes. - */ - info = &parinfo[0]; - if (info && info->dip && info->pip) { - info->pip = - (mdi_pathinfo_t *)MDI_PI(info->pip)->pi_client_link; - if (info->pip) { - pdip = mdi_pi_get_phci(info->pip); - pdip = ddi_get_parent(pdip); - } else { - break; + if (MDI_PI_IS_ONLINE(pip)) { + (void) snprintf(rptr, rlen, "%s", prom_path); + rlen -= strlen(rptr) + 1; + rptr += strlen(rptr) + 1; + if (rlen <= 0) /* drop paths we can't store */ + break; + } else { /* path is offline */ + (void) snprintf(optr, olen, "%s", prom_path); + olen -= strlen(optr) + 1; + if (olen > 0) /* drop paths we can't store */ + optr += strlen(optr) + 1; } - } else { - break; + MDI_PI_LOCK(pip); + MDI_PI_RELE(pip); + if (MDI_PI(pip)->pi_ref_cnt == 0) + cv_broadcast(&MDI_PI(pip)->pi_ref_cv); + MDI_PI_UNLOCK(pip); } - - } while (info && info->pip && pdip); - - ndi_rele_devi(dip); /* release hold from e_ddi_hold_devi_by_path() */ - - /* release holds from get_path_parent() */ - for (depth = old_depth; depth > 0; depth--) { - info = &parinfo[depth - 1]; - - /* replace with mdi_rele_path() when mpxio goes into genunix */ - if (info && info->pip) { - MDI_PI_LOCK(info->pip); - MDI_PI_RELE(info->pip); - if (MDI_PI(info->pip)->pi_ref_cnt == 0) - cv_broadcast(&MDI_PI(info->pip)->pi_ref_cv); - MDI_PI_UNLOCK(info->pip); + ndi_devi_exit(dip, circ); + ret = 0; + if (rlen > 0) { + /* now add as much of offline to ret_buf as possible */ + bcopy(offline, rptr, rlen); } - if (info && info->pdip) - ndi_rele_devi(info->pdip); + kmem_free(offline, len); } - - /* now add as much of offline to ret_buf as possible */ - bcopy(offline, rptr, rlen); - + /* release hold from e_ddi_hold_devi_by_path() */ + ndi_rele_devi(dip); ret_buf[len - 1] = '\0'; ret_buf[len - 2] = '\0'; - - kmem_free(offline, len); kmem_free(dev_path, MAXPATHLEN); kmem_free(prom_path, MAXPATHLEN); - kmem_free(parinfo, OBP_STACKDEPTH * sizeof (*parinfo)); - return (0); + + return (ret); } /* @@ -426,46 +508,16 @@ i_convert_boot_device_name(char *cur_path, char *new_path, size_t *len) } /* - * Get the parent dip. If dip is mpxio client, get the first online - * path and return the phci dip with both pathinfo and dip held - * otherwise just return with the dip held. + * Get the parent dip. */ static dev_info_t * -get_path_parent(dev_info_t *dip, struct parinfo *info) +get_parent(dev_info_t *dip, struct parinfo *info) { dev_info_t *pdip; - mdi_pathinfo_t *pip; - int circ; - - if (!MDI_CLIENT(dip)) { - pdip = ddi_get_parent(dip); - pip = NULL; - goto finish; - } - - /* find and hold the pathinfo */ - ndi_devi_enter(dip, &circ); - pip = mdi_get_next_phci_path(dip, NULL); - - if (pip == NULL) { - ndi_devi_exit(dip, circ); - return (NULL); - } - - /* replace with mdi_hold_path() when mpxio goes into genunix */ - MDI_PI_LOCK(pip); - MDI_PI_HOLD(pip); - MDI_PI_UNLOCK(pip); - - ndi_devi_exit(dip, circ); - pdip = mdi_pi_get_phci(pip); - -finish: + pdip = ddi_get_parent(dip); ndi_hold_devi(pdip); - info->dip = dip; - info->pip = pip; info->pdip = pdip; return (pdip); } |
