diff options
author | jveta <none@none> | 2007-03-13 19:54:36 -0700 |
---|---|---|
committer | jveta <none@none> | 2007-03-13 19:54:36 -0700 |
commit | 3ebafc43f8c876353693c0e5a9e759edd91165b6 (patch) | |
tree | 3631ba01d8396cda3f593516aca2d788a3ef3e5a | |
parent | 27e6fb2101ae37ba3de6dbb1567bf7558ffaccad (diff) | |
download | illumos-joyent-3ebafc43f8c876353693c0e5a9e759edd91165b6.tar.gz |
6525765 pcie link generator cannot handle arbitrary slot-names property length
-rw-r--r-- | usr/src/cmd/devfsadm/cfg_link.c | 132 | ||||
-rw-r--r-- | usr/src/cmd/devfsadm/cfg_link.h | 8 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/devinfo.c | 125 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/devinfo_prop_decode.c | 108 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/libdevinfo.h | 37 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/mapfile-vers | 9 |
6 files changed, 328 insertions, 91 deletions
diff --git a/usr/src/cmd/devfsadm/cfg_link.c b/usr/src/cmd/devfsadm/cfg_link.c index f6259f0b9d..662ebea88a 100644 --- a/usr/src/cmd/devfsadm/cfg_link.c +++ b/usr/src/cmd/devfsadm/cfg_link.c @@ -88,6 +88,8 @@ static int di_propall_lookup_ints(di_prom_handle_t, int, static int di_propall_lookup_strings(di_prom_handle_t, int, dev_t, di_node_t, const char *, char **); static int serid_printable(uint64_t *seridp); +static int di_propall_lookup_slot_names(di_prom_handle_t, int, + dev_t, di_node_t, di_slot_name_t **); /* @@ -399,7 +401,7 @@ pci_cfg_chassis_node(di_node_t node, di_prom_handle_t ph) do { if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, curnode, - PROP_FIRST_CHAS, &firstchas) >= 0) + DI_PROP_FIRST_CHAS, &firstchas) >= 0) return (curnode); } while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL); @@ -407,18 +409,28 @@ pci_cfg_chassis_node(di_node_t node, di_prom_handle_t ph) } +static int +di_propall_lookup_slot_names(di_prom_handle_t ph, int flags, + dev_t dev, di_node_t node, di_slot_name_t **prop_data) +{ + int rv; + + if (flags & DIPROP_PRI_PROM) { + rv = di_prom_prop_lookup_slot_names(ph, node, prop_data); + if (rv < 0) + rv = di_prop_lookup_slot_names(dev, node, prop_data); + } else { + rv = di_prop_lookup_slot_names(dev, node, prop_data); + if (rv < 0) + rv = di_prom_prop_lookup_slot_names(ph, node, + prop_data); + } + return (rv); +} + /* - * yet another redundant common routine to: - * decode the ieee1275 "slot-names" property and returns the string matching - * the pci device number <pci_dev>, if any. - * - * callers must NOT free the returned string - * - * "slot-names" format: [int][string1][string2]...[stringN] - * - each bit position in [int] represent a pci device number - * - [string1]...[stringN] are concatenated null-terminated strings - * - the number of bits set in [int] == the number of strings that follow - * - each bit that is set corresponds to a string in the following segment + * returns an allocated string containing the slot name for the slot with + * device number <pci_dev> on bus <node> */ static char * pci_cfg_slotname(di_node_t node, di_prom_handle_t ph, minor_t pci_dev) @@ -426,54 +438,29 @@ pci_cfg_slotname(di_node_t node, di_prom_handle_t ph, minor_t pci_dev) #ifdef DEBUG char *fnm = "pci_cfg_slotname"; #endif - int *snp; - int snlen; - int snentlen = sizeof (int); - int i, max, len, place, curplace; - char *str; - - snlen = di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, - PROP_SLOT_NAMES, &snp); - if (snlen < 1) - return (NULL); - if ((snp[0] & (1 << pci_dev)) == 0) - return (NULL); + int i, count; + char *name = NULL; + di_slot_name_t *slot_names = NULL; - /* - * pci device number must be less than the amount of bits in the first - * [int] component of slot-names - */ - if (pci_dev >= snentlen * 8) { - dprint(("%s: pci_dev out of range for %s%d\n", - fnm, DRVINST(node))); + count = di_propall_lookup_slot_names(ph, 0, DDI_DEV_T_ANY, node, + &slot_names); + if (count < 0) return (NULL); - } - - place = 0; - for (i = 0; i < pci_dev; i++) { - if (snp[0] & (1 << i)) - place++; - } - max = (snlen * snentlen) - snentlen; - str = (char *)&snp[1]; - i = 0; - curplace = 0; - while (i < max && curplace < place) { - len = strlen(str); - if (len <= 0) + for (i = 0; i < count; i++) { + if (slot_names[i].num == (int)pci_dev) { + name = strdup(slot_names[i].name); break; - str += len + 1; - i += len + 1; - curplace++; - } - /* the following condition indicates a badly formed slot-names */ - if (i >= max || *str == '\0') { - dprint(("%s: badly formed slot-names for %s%d\n", - fnm, DRVINST(node))); - str = NULL; + } } - return (str); +#ifdef DEBUG + if (name == NULL) + dprint(("%s: slot w/ pci_dev %d not found in %s for %s%d\n", + fnm, (int)pci_dev, DI_PROP_SLOT_NAMES, DRVINST(node))); +#endif + if (count > 0) + di_slot_names_free(count, slot_names); + return (name); } @@ -482,11 +469,11 @@ pci_cfg_slotname(di_node_t node, di_prom_handle_t ph, minor_t pci_dev) * for its slot identified by child pci device number <pci_dev>, through <buf> * * prioritized naming scheme: - * 1) <PROP_SLOT_NAMES property> (see pci_cfg_slotname()) - * 2) <device-type><PROP_PHYS_SLOT property> + * 1) <DI_PROP_SLOT_NAMES property> (see pci_cfg_slotname()) + * 2) <device-type><DI_PROP_PHYS_SLOT property> * 3) <drv name><drv inst>.<device-type><pci_dev> * - * where <device-type> is derived from the PROP_DEV_TYPE property: + * where <device-type> is derived from the DI_PROP_DEV_TYPE property: * if its value is "pciex" then <device-type> is "pcie" * else the raw value is used * @@ -501,7 +488,7 @@ pci_cfg_ap_node(minor_t pci_dev, di_node_t node, di_prom_handle_t ph, char *str, *devtype; rv = di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, node, - PROP_DEV_TYPE, &devtype); + DI_PROP_DEV_TYPE, &devtype); if (rv < 1) return (0); @@ -514,11 +501,12 @@ pci_cfg_ap_node(minor_t pci_dev, di_node_t node, di_prom_handle_t ph, str = pci_cfg_slotname(node, ph, pci_dev); if (str != NULL) { (void) strlcpy(buf, str, bufsz); + free(str); return (1); } - if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, PROP_PHYS_SLOT, - &nump) > 0) { + if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, + DI_PROP_PHYS_SLOT, &nump) > 0) { if (*nump > 0) { (void) snprintf(buf, bufsz, "%s%d", devtype, *nump); return (1); @@ -537,11 +525,11 @@ DEF: * through <buf> * * prioritized naming scheme: - * 1) <IOB_PRE string><PROP_SERID property: sun specific portion> - * 2) <IOB_PRE string><full PROP_SERID property in hex> + * 1) <IOB_PRE string><DI_PROP_SERID property: sun specific portion> + * 2) <IOB_PRE string><full DI_PROP_SERID property in hex> * 3) <IOB_PRE string> * - * PROP_SERID encoding <64-bit int: msb ... lsb>: + * DI_PROP_SERID encoding <64-bit int: msb ... lsb>: * <24 bits: IEEE company id><40 bits: serial number> * * sun encoding of 40 bit serial number: @@ -560,7 +548,7 @@ pci_cfg_iob_name(di_minor_t minor, di_node_t node, di_prom_handle_t ph, uint64_t serid; char *idstr; - if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, PROP_SERID, + if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, DI_PROP_SERID, &seridp) < 1) { (void) strlcpy(buf, IOB_PRE, bufsz); return (1); @@ -599,12 +587,12 @@ pci_cfg_pcidev(di_node_t node, di_prom_handle_t ph) int rv; int *regp; - rv = di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, PROP_REG, + rv = di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_REG, ®p); if (rv < 1) { dprint(("pci_cfg_pcidev: property %s not found " - "for %s%d\n", PROP_REG, DRVINST(node))); + "for %s%d\n", DI_PROP_REG, DRVINST(node))); return (PCIDEV_NIL); } @@ -624,7 +612,7 @@ pci_cfg_pcidev(di_node_t node, di_prom_handle_t ph) * each component using pci_cfg_ap_node(). If we detect that a certain * segment is contained within an expansion chassis, then we skip any bus * nodes in between our current node and the topmost node of the chassis, - * which is identified by the PROP_FIRST_CHAS property, and prepend the name + * which is identified by the DI_PROP_FIRST_CHAS property, and prepend the name * of the expansion chassis as given by pci_cfg_iob_name() * * This scheme is always used for <pathret>. If however, the size of @@ -815,12 +803,12 @@ OUT: /* - * the PROP_AP_NAMES property contains the first integer section of the + * the DI_PROP_AP_NAMES property contains the first integer section of the * ieee1275 "slot-names" property and functions as a bitmask; see comment for * pci_cfg_slotname() * * we use the name of the attachment point minor node if its pci device - * number (encoded in the minor number) is allowed by PROP_AP_NAMES + * number (encoded in the minor number) is allowed by DI_PROP_AP_NAMES * * returns non-zero if we return a valid attachment point through <path> */ @@ -831,7 +819,7 @@ pci_cfg_ap_legacy(di_minor_t minor, di_node_t node, di_prom_handle_t ph, minor_t pci_dev; int *anp; - if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, PROP_AP_NAMES, + if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_AP_NAMES, &anp) < 1) return (0); @@ -855,7 +843,7 @@ pci_cfg_is_ap_path(di_node_t node, di_prom_handle_t ph) do { if (di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, curnode, - PROP_DEV_TYPE, &devtype) > 0) + DI_PROP_DEV_TYPE, &devtype) > 0) if (strcmp(devtype, PROPVAL_PCIEX) == 0) return (1); } while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL); diff --git a/usr/src/cmd/devfsadm/cfg_link.h b/usr/src/cmd/devfsadm/cfg_link.h index 94efac89d0..ad7b5a949d 100644 --- a/usr/src/cmd/devfsadm/cfg_link.h +++ b/usr/src/cmd/devfsadm/cfg_link.h @@ -47,14 +47,6 @@ extern "C" { #define CFG_DIRNAME "cfg" -#define PROP_FIRST_CHAS "first-in-chassis" -#define PROP_SLOT_NAMES "slot-names" -#define PROP_PHYS_SLOT "physical-slot#" -#define PROP_DEV_TYPE "device_type" -#define PROP_BUS_RANGE "bus-range" -#define PROP_SERID "serialid#" -#define PROP_REG "reg" -#define PROP_AP_NAMES "ap-names" #define PROPVAL_PCIEX "pciex" #define DEVTYPE_PCIE "pcie" #define IOB_PRE "iob" diff --git a/usr/src/lib/libdevinfo/devinfo.c b/usr/src/lib/libdevinfo/devinfo.c index ee33c2d518..e37e207474 100644 --- a/usr/src/lib/libdevinfo/devinfo.c +++ b/usr/src/lib/libdevinfo/devinfo.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. @@ -19,9 +18,8 @@ * * CDDL HEADER END */ - /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1488,6 +1486,31 @@ di_prop_search(dev_t match_dev, di_node_t node, const char *name, return (DI_PROP_NIL); } +di_prop_t +di_prop_find(dev_t match_dev, di_node_t node, const char *name) +{ + di_prop_t prop = DI_PROP_NIL; + + if ((node == DI_NODE_NIL) || (name == NULL) || (strlen(name) == 0) || + (match_dev == DDI_DEV_T_NONE)) { + errno = EINVAL; + return (DI_PROP_NIL); + } + + while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) { + DPRINTF((DI_TRACE1, "found prop name %s, devt 0x%lx, type %d\n", + di_prop_name(prop), di_prop_devt(prop), + di_prop_type(prop))); + + if (strcmp(name, di_prop_name(prop)) == 0 && + (match_dev == DDI_DEV_T_ANY || + di_prop_devt(prop) == match_dev)) + return (prop); + } + + return (DI_PROP_NIL); +} + int di_prop_lookup_ints(dev_t dev, di_node_t node, const char *prop_name, int **prop_data) @@ -2688,6 +2711,98 @@ di_prom_prop_lookup_bytes(di_prom_handle_t ph, di_node_t node, return (len); } +/* + * returns an allocated array through <prop_data> only when its count > 0 + * and the number of entries (count) as the function return value; + * use di_slot_names_free() to free the array + */ +int +di_prop_slot_names(di_prop_t prop, di_slot_name_t **prop_data) +{ + int rawlen, count; + uchar_t *rawdata; + char *nm = di_prop_name(prop); + + if (nm == NULL || strcmp(DI_PROP_SLOT_NAMES, nm) != 0) + goto ERROUT; + + rawlen = di_prop_rawdata(prop, &rawdata); + if (rawlen <= 0 || rawdata == NULL) + goto ERROUT; + + count = di_slot_names_decode(rawdata, rawlen, prop_data); + if (count < 0 || *prop_data == NULL) + goto ERROUT; + + return (count); + /*NOTREACHED*/ +ERROUT: + errno = EFAULT; + *prop_data = NULL; + return (-1); +} + +int +di_prop_lookup_slot_names(dev_t dev, di_node_t node, + di_slot_name_t **prop_data) +{ + di_prop_t prop; + + /* + * change this if and when DI_PROP_TYPE_COMPOSITE is implemented + * and slot-names is properly flagged as such + */ + if ((prop = di_prop_find(dev, node, DI_PROP_SLOT_NAMES)) == + DI_PROP_NIL) { + *prop_data = NULL; + return (-1); + } + + return (di_prop_slot_names(prop, (void *)prop_data)); +} + +/* + * returns an allocated array through <prop_data> only when its count > 0 + * and the number of entries (count) as the function return value; + * use di_slot_names_free() to free the array + */ +int +di_prom_prop_slot_names(di_prom_prop_t prom_prop, di_slot_name_t **prop_data) +{ + int rawlen, count; + uchar_t *rawdata; + + rawlen = di_prom_prop_data(prom_prop, &rawdata); + if (rawlen <= 0 || rawdata == NULL) + goto ERROUT; + + count = di_slot_names_decode(rawdata, rawlen, prop_data); + if (count < 0 || *prop_data == NULL) + goto ERROUT; + + return (count); + /*NOTREACHED*/ +ERROUT: + errno = EFAULT; + *prop_data = NULL; + return (-1); +} + +int +di_prom_prop_lookup_slot_names(di_prom_handle_t ph, di_node_t node, + di_slot_name_t **prop_data) +{ + struct di_prom_prop *prom_prop; + + prom_prop = di_prom_prop_lookup_common(ph, node, DI_PROP_SLOT_NAMES); + if (prom_prop == NULL) { + *prop_data = NULL; + return (-1); + } + + return (di_prom_prop_slot_names(prom_prop, prop_data)); +} + di_lnode_t di_link_to_lnode(di_link_t link, uint_t endpoint) { diff --git a/usr/src/lib/libdevinfo/devinfo_prop_decode.c b/usr/src/lib/libdevinfo/devinfo_prop_decode.c index 542cb54d52..cc8b0d00ce 100644 --- a/usr/src/lib/libdevinfo/devinfo_prop_decode.c +++ b/usr/src/lib/libdevinfo/devinfo_prop_decode.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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -932,4 +931,103 @@ di_prop_decode_common(void *data, int size, int prop_type, int prom) return (nelements); } -/* end of devinfo_prop_decode.c */ +void +di_slot_names_free(int count, di_slot_name_t *slot_names) +{ + if (slot_names == NULL) + return; + + while (--count >= 0) { + if (slot_names[count].name != NULL) + free(slot_names[count].name); + } + free(slot_names); +} + +/* + * 1275 "slot-names" format: [int][string1][string2]...[stringN] + * - [int] is a 1275 encoded integer + * - [string1]...[stringN] are concatenated null-terminated strings + * - each bit position in [int] represents a pci device number + * - each bit which is set in [int] represents a slot with a device + * number of that bit position + * - each string in [string1]...[stringN] identifies a slot name only + * for the bits which are set in [int] + * - the ordering of strings follow the ordering of bits set in [int] + * + * an allocated array of di_slot_name_t is returned through prop_data if + * [int] is non-zero and the number of entries as the return value; + * use di_slot_names_free() to free the array + */ +int +di_slot_names_decode(uchar_t *rawdata, int rawlen, + di_slot_name_t **prop_data) +{ + char *sp, *maxsp; + int count, i; + size_t len; + int slots; + int maxcount = 0; + int maxslots = 0; + di_slot_name_t *slot_names = NULL; + + if (rawlen < sizeof (slots)) + goto ERROUT; + + slots = impl_di_prop_int_from_prom(rawdata, sizeof (slots)); + if (slots == 0) { + *prop_data = NULL; + return (0); + } + + maxslots = sizeof (slots) * 8; + count = 0; + for (i = 0; i < maxslots; i++) { + if (slots & (1 << i)) + count++; + } + maxslots = i; + maxcount = count; + slot_names = malloc(sizeof (*slot_names) * maxcount); + bzero(slot_names, sizeof (*slot_names) * maxcount); + + /* also handle unterminated strings */ + sp = (char *)(rawdata + sizeof (slots)); + maxsp = sp + (rawlen - sizeof (slots)); + count = 0; + for (i = 0; i < maxslots; i++) { + if (slots & (1 << i)) { + if (sp > maxsp) + break; + len = strnlen(sp, (maxsp - sp) + 1); + if (len == 0) + break; + + slot_names[count].name = + malloc(sizeof (char) * (len + 1)); + (void) strlcpy(slot_names[count].name, sp, len + 1); + + slot_names[count].num = i; + + sp += len + 1; + count++; + } + } + + /* + * check if the number of strings match with the number of slots; + * we can also get a lesser string count even when there appears to be + * the correct number of strings if one or more pair of strings are + * seperated by more than one NULL byte + */ + if (count != maxcount) + goto ERROUT; + + *prop_data = slot_names; + return (maxcount); + /*NOTREACHED*/ +ERROUT: + di_slot_names_free(maxcount, slot_names); + *prop_data = NULL; + return (-1); +} diff --git a/usr/src/lib/libdevinfo/libdevinfo.h b/usr/src/lib/libdevinfo/libdevinfo.h index d570e8e714..ad08502628 100644 --- a/usr/src/lib/libdevinfo/libdevinfo.h +++ b/usr/src/lib/libdevinfo/libdevinfo.h @@ -126,6 +126,19 @@ typedef struct di_lnode *di_lnode_t; /* opaque handle to endpoint */ #define DI_PROM_HANDLE_NIL NULL #define DI_PATH_NIL NULL +/* + * IEEE 1275 properties and other standardized property names + */ +#define DI_PROP_FIRST_CHAS "first-in-chassis" +#define DI_PROP_SLOT_NAMES "slot-names" +#define DI_PROP_PHYS_SLOT "physical-slot#" +#define DI_PROP_DEV_TYPE "device_type" +#define DI_PROP_BUS_RANGE "bus-range" +#define DI_PROP_SERID "serialid#" +#define DI_PROP_REG "reg" +#define DI_PROP_AP_NAMES "ap-names" + + /* Interface Prototypes */ /* @@ -267,6 +280,30 @@ extern int di_prom_prop_lookup_bytes(di_prom_handle_t prom, di_node_t node, * to run on future releases. */ +extern di_prop_t di_prop_find(dev_t match_dev, di_node_t node, + const char *name); + +/* + * Interfaces for handling IEEE 1275 and other standardized properties + */ + +/* structure for a single slot */ +typedef struct di_slot_name { + int num; /* corresponding pci device number */ + char *name; +} di_slot_name_t; + +extern void di_slot_names_free(int count, di_slot_name_t *slot_names); +extern int di_slot_names_decode(uchar_t *rawdata, int rawlen, + di_slot_name_t **prop_data); +extern int di_prop_slot_names(di_prop_t prop, di_slot_name_t **prop_data); +extern int di_prom_prop_slot_names(di_prom_prop_t prom_prop, + di_slot_name_t **prop_data); +extern int di_prop_lookup_slot_names(dev_t dev, di_node_t node, + di_slot_name_t **prop_data); +extern int di_prom_prop_lookup_slot_names(di_prom_handle_t ph, di_node_t node, + di_slot_name_t **prop_data); + /* * Interfaces for accessing I/O multipathing data */ diff --git a/usr/src/lib/libdevinfo/mapfile-vers b/usr/src/lib/libdevinfo/mapfile-vers index 34251800bd..f94882dcae 100644 --- a/usr/src/lib/libdevinfo/mapfile-vers +++ b/usr/src/lib/libdevinfo/mapfile-vers @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -199,6 +199,13 @@ SUNWprivate_1.1 { di_dli_openr; di_dli_openw; di_dli_close; + di_slot_names_free; + di_slot_names_decode; + di_prop_slot_names; + di_prom_prop_slot_names; + di_prop_lookup_slot_names; + di_prom_prop_lookup_slot_names; + di_prop_find; device_exists; finddev_readdir; finddev_close; |