diff -Nru biosdevname-0.4.1/debian/changelog biosdevname-0.4.1/debian/changelog --- biosdevname-0.4.1/debian/changelog 2014-02-19 06:28:52.000000000 -0500 +++ biosdevname-0.4.1/debian/changelog 2014-05-30 12:05:53.000000000 -0400 @@ -1,3 +1,10 @@ +biosdevname (0.4.1-0ubuntu7) trusty; urgency=high + + * Fix for biosdevname returns identical names for two different devices (LP: #1324558) + + + -- Jorge Niedbalski Fri, 30 May 2014 12:04:33 -0400 + biosdevname (0.4.1-0ubuntu6) trusty; urgency=medium * Create initramfs hook that copies the rule and the binary to the initramfs diff -Nru biosdevname-0.4.1/debian/patches/fix_addslot_function_rename.patch biosdevname-0.4.1/debian/patches/fix_addslot_function_rename.patch --- biosdevname-0.4.1/debian/patches/fix_addslot_function_rename.patch 1969-12-31 19:00:00.000000000 -0500 +++ biosdevname-0.4.1/debian/patches/fix_addslot_function_rename.patch 2014-05-30 12:04:23.000000000 -0400 @@ -0,0 +1,1116 @@ +Description: The commits introduced addslot function to implement naming for +devices which have more than one physical port sharing the same +PCI b/d/f. But the port determination logic in 'addslot' function could +result in more than one interface on a given PCI slot getting same +port number when renames are happening in parallel. This patch +restores the logic that existed in version 0.3.11 to determine +port number of an interface. + +Author: Narendra K +Origin: upstream, http://linux.dell.com/cgi-bin/gitweb/gitweb.cgi?p=biosdevname.git;a=commit;h=0bc6ce6d8da61153e7bfd1c3444ab06c0c83d0af +Bug: https://bugzilla.redhat.com/show_bug.cgi?id=782145 +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/biosdevname/+bug/1324558 + +--- biosdevname-0.4.1.orig/src/naming_policy.c ++++ biosdevname-0.4.1/src/naming_policy.c +@@ -59,8 +59,8 @@ static void use_physical(const struct li + portnum = vf->sysfs_index; + else if (vf->uses_smbios & HAS_SMBIOS_INSTANCE && is_pci_smbios_type_ethernet(vf)) + portnum = vf->smbios_instance; +- else if (dev->port_num != -1) +- portnum = dev->port_num; ++ else if (vf->embedded_index_valid) ++ portnum = vf->embedded_index; + if (portnum != INT_MAX) { + snprintf(location, sizeof(location), "%s%u", prefix, portnum); + known=1; +@@ -70,8 +70,6 @@ static void use_physical(const struct li + snprintf(location, sizeof(location), "p%u", dev->pcidev->physical_slot); + if (dev->pcidev->vpd_port < INT_MAX) + portnum = dev->pcidev->vpd_port; +- else if (dev->port_num != -1) +- portnum = dev->port_num; + else if (!dev->pcidev->is_sriov_virtual_function) + portnum = dev->pcidev->index_in_slot; + else +--- biosdevname-0.4.1.orig/src/bios_device.c ++++ biosdevname-0.4.1/src/bios_device.c +@@ -217,32 +217,6 @@ static void match_pci_and_eth_devs(struc + struct pci_device *p; + struct bios_device *b; + struct network_device *n; +- +- list_for_each_entry(n, &state->network_devices, node) { +- p = find_dev_by_pci_name(state, n->drvinfo.bus_info); +- if (!p) +- continue; +- +- b = malloc(sizeof(*b)); +- if (!b) +- continue; +- memset(b, 0, sizeof(*b)); +- INIT_LIST_HEAD(&b->node); +- b->pcidev = p; +- b->netdev = n; +- b->slot_num = -1; +- b->port_num = -1; +- claim_netdev(b->netdev); +- list_add(&b->node, &state->bios_devices); +- } +-} +- +- +-static void match_eth_and_pci_devs(struct libbiosdevname_state *state) +-{ +- struct pci_device *p; +- struct bios_device *b; +- struct network_device *n; + char pci_name[40]; + + list_for_each_entry(p, &state->pci_devices, node) { +@@ -261,8 +235,6 @@ static void match_eth_and_pci_devs(struc + INIT_LIST_HEAD(&b->node); + b->pcidev = p; + b->netdev = n; +- b->slot_num = -1; +- b->port_num = -1; + claim_netdev(b->netdev); + list_add(&b->node, &state->bios_devices); + } +@@ -286,8 +258,6 @@ static void match_unknown_eths(struct li + memset(b, 0, sizeof(*b)); + INIT_LIST_HEAD(&b->node); + b->netdev = n; +- b->slot_num = -1; +- b->port_num = -1; + list_add(&b->node, &state->bios_devices); + } + } +@@ -355,26 +325,6 @@ static void find_duplicates(struct libbi + } + } + +-extern int addslot(struct libbiosdevname_state *state, int slot); +- +-/* Fix for RHBZ 816536/757743/756164/: Cards with same PCI but multiple ports +- * chelsio, mellanox */ +-static void check_ports(struct libbiosdevname_state *state) +-{ +- struct pci_device *dev; +- struct bios_device *a; +- +- list_for_each_entry(a, &state->bios_devices, node) { +- dev = a->pcidev; +- if (dev == NULL || dev->is_sriov_virtual_function || dev->vpd_port != INT_MAX) +- continue; +- if (dev->physical_slot != PHYSICAL_SLOT_UNKNOWN) { +- a->slot_num = dev->physical_slot; +- a->port_num = addslot(state, 0x1000 + dev->physical_slot); +- } +- } +-} +- + void * setup_bios_devices(int namingpolicy, const char *prefix) + { + int rc=1; +@@ -390,7 +340,6 @@ void * setup_bios_devices(int namingpoli + get_eths(state); + match_all(state); + sort_device_list(state); +- check_ports(state); + rc = assign_bios_network_names(state, namingpolicy, prefix); + if (rc) + goto out; +--- biosdevname-0.4.1.orig/src/bios_device.h ++++ biosdevname-0.4.1/src/bios_device.h +@@ -19,9 +19,6 @@ struct bios_device { + struct pci_device *pcidev; + char *bios_name; + int duplicate; +- +- int slot_num; +- int port_num; + }; + + static inline int is_pci(const struct bios_device *dev) +--- biosdevname-0.4.1.orig/src/pci.c ++++ biosdevname-0.4.1/src/pci.c +@@ -618,24 +618,6 @@ void free_pci_devices(struct libbiosdevn + } + } + +-int addslot(struct libbiosdevname_state *state, int slot) +-{ +- struct slotlist *s; +- +- list_for_each_entry(s, &state->slots, node) { +- if (s->slot == slot) { +- return ++s->count; +- } +- } +- s = malloc(sizeof(*s)); +- INIT_LIST_HEAD(&s->node); +- s->slot = slot; +- s->count = 0; +- list_add(&s->node, &state->slots); +- +- return ++s->count; +-} +- + static void set_pci_slots(struct libbiosdevname_state *state) + { + struct pci_device *dev; +@@ -643,21 +625,55 @@ static void set_pci_slots(struct libbios + list_for_each_entry(dev, &state->pci_devices, node) { + dev_to_slot(state, dev); + } ++} + +- /* Get mapping for each slot */ +- list_for_each_entry(dev, &state->pci_devices, node) { +- if (dev->is_sriov_virtual_function || !is_pci_network(dev) || dev->vpd_port != INT_MAX) { ++static int set_pci_slot_index(struct libbiosdevname_state *state) ++{ ++ struct pci_device *pcidev; ++ int prevslot=-1; ++ int index=1; ++ ++ /* only iterate over the PCI devices, because the bios_device list may be incomplete due to renames happening in parallel */ ++ list_for_each_entry(pcidev, &state->pci_devices, node) { ++ if (pcidev->physical_slot == 0) /* skip embedded devices */ + continue; ++ if (!is_pci_network(pcidev)) /* only look at PCI network devices */ ++ continue; ++ if (pcidev->is_sriov_virtual_function) /* skip sriov VFs, they're handled later */ ++ continue; ++ if (pcidev->physical_slot != prevslot) { ++ index=1; ++ prevslot = pcidev->physical_slot; + } +- if (dev->physical_slot == 0) { +- dev->embedded_index_valid = 1; +- dev->embedded_index = addslot(state, 0); +- } else if (dev->physical_slot != PHYSICAL_SLOT_UNKNOWN) { +- dev->index_in_slot = addslot(state, dev->physical_slot); +- } ++ else ++ index++; ++ pcidev->index_in_slot = index; + } ++ return 0; ++} ++ ++static int set_embedded_index(struct libbiosdevname_state *state) ++{ ++ struct pci_device *pcidev; ++ int index=1; ++ ++ list_for_each_entry(pcidev, &state->pci_devices, node) { ++ if (pcidev->physical_slot != 0) /* skip non-embedded devices */ ++ continue; ++ if (!is_pci_network(pcidev)) /* only look at PCI network devices */ ++ continue; ++ if (pcidev->is_sriov_virtual_function) /* skip sriov VFs, they're handled later */ ++ continue; ++ if (pcidev->vpd_port != INT_MAX) ++ continue; ++ pcidev->embedded_index = index; ++ pcidev->embedded_index_valid = 1; ++ index++; ++ } ++ return 0; + } + ++ + static void set_sriov_pf_vf(struct libbiosdevname_state *state) + { + struct pci_device *vf; +@@ -738,6 +754,8 @@ int get_pci_devices(struct libbiosdevnam + sort_device_list(state); + set_pci_vpd_instance(state); + set_pci_slots(state); ++ set_embedded_index(state); ++ set_pci_slot_index(state); + set_sriov_pf_vf(state); + + return rc; +--- /dev/null ++++ biosdevname-0.4.1/src/pci.c.orig +@@ -0,0 +1,877 @@ ++/* ++ * Copyright (c) 2006-2010 Dell, Inc. ++ * by Matt Domsch ++ * Licensed under the GNU General Public license, version 2. ++ */ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "pci.h" ++#include "sysfs.h" ++#include "dmidecode/dmidecode.h" ++#include "pirq.h" ++ ++extern int is_valid_smbios; ++ ++#ifndef PCI_CB_CAPABILITY_LIST ++#define PCI_CB_CAPABILITY_LIST 0x14 ++#endif ++ ++/* Borrowed from kernel vpd code */ ++#define PCI_VPD_LRDT 0x80 ++#define PCI_VPD_SRDT_END 0x78 ++ ++#define PCI_VPD_SRDT_LEN_MASK 0x7 ++#define PCI_VPD_LRDT_TAG_SIZE 3 ++#define PCI_VPD_SRDT_TAG_SIZE 1 ++#define PCI_VPD_INFO_FLD_HDR_SIZE 3 ++ ++static inline u16 pci_vpd_lrdt_size(const u8 *lrdt) ++{ ++ return (u16)lrdt[1] + ((u16)lrdt[2] << 8L); ++} ++ ++static inline u8 pci_vpd_srdt_size(const u8* srdt) ++{ ++ return (*srdt) & PCI_VPD_SRDT_LEN_MASK; ++} ++ ++static inline u8 pci_vpd_info_field_size(const u8 *info_field) ++{ ++ return info_field[2]; ++} ++ ++static int pci_vpd_size(struct pci_device *pdev, int fd) ++{ ++ uint8_t buf[3], tag; ++ int off; ++ ++ if (!is_pci_network(pdev)) ++ return 0; ++ off = 0; ++ for(;;) { ++ if (pread(fd, buf, 1, off) != 1) ++ break; ++ if (buf[0] & PCI_VPD_LRDT) { ++ tag = buf[0]; ++ if (pread(fd, buf, 3, off) != 3) ++ break; ++ off += PCI_VPD_LRDT_TAG_SIZE + pci_vpd_lrdt_size(buf); ++ } else { ++ tag = buf[0] & ~PCI_VPD_SRDT_LEN_MASK; ++ off += PCI_VPD_SRDT_TAG_SIZE + pci_vpd_srdt_size(buf); ++ } ++ if (tag == 0 || tag == 0xFF || tag == PCI_VPD_SRDT_END) ++ break; ++ } ++ return off; ++} ++ ++static int pci_vpd_find_tag(const u8 *buf, unsigned int off, unsigned int len, u8 rdt) ++{ ++ int i; ++ ++ for (i = off; i < len;) { ++ u8 val = buf[i]; ++ ++ if (val & PCI_VPD_LRDT) { ++ if (i + PCI_VPD_LRDT_TAG_SIZE > len) ++ break; ++ if (val == rdt) ++ return i; ++ i += PCI_VPD_LRDT_TAG_SIZE + pci_vpd_lrdt_size(&buf[i]); ++ } else { ++ u8 tag = val & ~PCI_VPD_SRDT_LEN_MASK; ++ ++ if (tag == rdt) ++ return i; ++ if (tag == PCI_VPD_SRDT_END) ++ break; ++ i += PCI_VPD_SRDT_TAG_SIZE + pci_vpd_srdt_size(&buf[i]); ++ } ++ } ++ return -1; ++} ++ ++/* Search for matching key/subkey in the VPD data */ ++static int pci_vpd_find_info_subkey(const u8 *buf, unsigned int off, unsigned int len, ++ const char *kw, const char *skw) ++{ ++ int i; ++ ++ for (i = off; i + PCI_VPD_INFO_FLD_HDR_SIZE <= off+len;) { ++ /* Match key and subkey names, can use * for regex */ ++ if ((kw[0] == '*' || buf[i+0] == kw[0]) && ++ (kw[1] == '*' || buf[i+1] == kw[1]) && ++ (skw[0] == '*' || !memcmp(&buf[i+3], skw, 3))) ++ return i; ++ i += PCI_VPD_INFO_FLD_HDR_SIZE + pci_vpd_info_field_size(&buf[i]); ++ } ++ return -1; ++} ++ ++static int parse_vpd(struct libbiosdevname_state *state, struct pci_device *pdev, int len, unsigned char *vpd) ++{ ++ int i, j, k, isz, jsz, port, func, pfi; ++ struct pci_device *vf; ++ ++ i = pci_vpd_find_tag(vpd, 0, len, 0x90); ++ if (i < 0) ++ return 1; ++ isz = pci_vpd_lrdt_size(&vpd[i]); ++ i += PCI_VPD_LRDT_TAG_SIZE; ++ ++ /* Lookup Version */ ++ j = pci_vpd_find_info_subkey(vpd, i, isz, "**", "DSV"); ++ if (j < 0) ++ return 1; ++ jsz = pci_vpd_info_field_size(&vpd[j]); ++ j += PCI_VPD_INFO_FLD_HDR_SIZE; ++ if (memcmp(vpd+j+3, "1028VPDR.VER1.0", 15)) ++ return 1; ++ ++ /* Lookup Port Mappings */ ++ j = pci_vpd_find_info_subkey(vpd, i, isz, "**", "DCM"); ++ if (j < 0) ++ return 1; ++ jsz = pci_vpd_info_field_size(&vpd[j]); ++ j += PCI_VPD_INFO_FLD_HDR_SIZE; ++ ++ for (k=3; kpci_dev->domain, ++ pdev->pci_dev->bus, ++ pdev->pci_dev->dev, ++ func)) != NULL) { ++ if (vf->vpd_port == INT_MAX) { ++ vf->vpd_port = port; ++ vf->vpd_pfi = pfi; ++ } ++ } ++ } ++ return 0; ++} ++ ++/* Read and parse PCI VPD section if it exists */ ++static int read_pci_vpd(struct libbiosdevname_state *state, struct pci_device *pdev) ++{ ++ char path[PATH_MAX]; ++ char pci_name[16]; ++ int fd, rc=1; ++ unsigned char *vpd; ++ off_t size; ++ ssize_t nrd; ++ ++ unparse_pci_name(pci_name, sizeof(pci_name), pdev->pci_dev); ++ snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/vpd", pci_name); ++ if ((fd = open(path, O_RDONLY|O_SYNC)) >= 0) { ++ size = pci_vpd_size(pdev, fd); ++ if (size > 0) { ++ vpd = malloc(size); ++ if (vpd != NULL) { ++ if ((nrd = pread(fd, vpd, size, 0)) > 0) ++ rc = parse_vpd(state, pdev, nrd, vpd); ++ free(vpd); ++ } ++ } ++ close(fd); ++ } ++ return rc; ++} ++ ++static void set_pci_vpd_instance(struct libbiosdevname_state *state) ++{ ++ struct pci_device *dev, *dev2; ++ int fd; ++ char sys_vendor[10] = {0}; ++ ++ /* Read VPD-R on Dell systems only */ ++ if ((fd = open("/sys/devices/virtual/dmi/id/sys_vendor", O_RDONLY)) >= 0) { ++ if (read(fd, sys_vendor, 9) != 9) ++ return; ++ if (strncmp(sys_vendor, "Dell Inc.", 9)) ++ return; ++ } else ++ return; ++ ++ /* Read VPD information for each device */ ++ list_for_each_entry(dev, &state->pci_devices, node) { ++ /* RedHat bugzilla 801885, 789635, 781572 */ ++ if (dev->pci_dev->vendor_id == 0x1969 || ++ dev->pci_dev->vendor_id == 0x168c) ++ continue; ++ read_pci_vpd(state, dev); ++ } ++ ++ /* Now match VPD master device */ ++ list_for_each_entry(dev, &state->pci_devices, node) { ++ if (dev->vpd_port == INT_MAX) ++ continue; ++ list_for_each_entry(dev2, &state->pci_devices, node) { ++ if (dev2->pci_dev->domain == dev->pci_dev->domain && ++ dev2->pci_dev->bus == dev->pci_dev->bus && ++ dev2->pci_dev->dev == dev->pci_dev->dev && ++ dev2->vpd_port == dev->vpd_port) { ++ dev2->vpd_count++; ++ dev->vpd_pf = dev2; ++ break; ++ } ++ } ++ } ++ ++ /* Delete all VPD devices with single function */ ++ list_for_each_entry(dev, &state->pci_devices, node) { ++ if (dev->vpd_count == 1) { ++ dev->vpd_port = INT_MAX; ++ dev->vpd_pfi = INT_MAX; ++ dev->vpd_pf = NULL; ++ } ++ } ++} ++ ++static int pci_find_capability(struct pci_dev *p, int cap) ++{ ++ u16 status; ++ u8 hdr, id; ++ int pos, ttl = 48; ++ ++ status = pci_read_word(p, PCI_STATUS); ++ if (!(status & PCI_STATUS_CAP_LIST)) ++ return 0; ++ hdr = pci_read_byte(p, PCI_HEADER_TYPE); ++ switch(hdr & 0x7F) { ++ case PCI_HEADER_TYPE_NORMAL: ++ case PCI_HEADER_TYPE_BRIDGE: ++ pos = PCI_CAPABILITY_LIST; ++ break; ++ case PCI_HEADER_TYPE_CARDBUS: ++ pos = PCI_CB_CAPABILITY_LIST; ++ break; ++ default: ++ return 0; ++ } ++ ++ while (ttl--) { ++ pos = pci_read_byte(p, pos); ++ if (pos < 0x40) ++ break; ++ pos &= ~3; ++ id = pci_read_byte(p, pos+PCI_CAP_LIST_ID); ++ if (id == 0xFF) ++ break; ++ if (id == cap) ++ return pos; ++ pos += PCI_CAP_LIST_NEXT; ++ } ++ return 0; ++} ++ ++static struct pci_device * ++find_parent(struct libbiosdevname_state *state, struct pci_device *dev); ++ ++static int pcie_get_slot(struct libbiosdevname_state *state, struct pci_device *p) ++{ ++ int pos; ++ u32 slot, flag; ++ ++ while (p) { ++ /* Return PCIE physical slot number */ ++ if ((pos = pci_find_capability(p->pci_dev, PCI_CAP_ID_EXP)) != 0) { ++ flag = pci_read_word(p->pci_dev, pos + PCI_EXP_FLAGS); ++ slot = (pci_read_long(p->pci_dev, pos + PCI_EXP_SLTCAP) >> 19); ++ if ((flag & PCI_EXP_FLAGS_SLOT) && slot) ++ return slot; ++ } ++ p = find_parent(state, p); ++ } ++ return PHYSICAL_SLOT_UNKNOWN; ++} ++ ++static int read_pci_sysfs_path(char *buf, size_t bufsize, const struct pci_dev *pdev) ++{ ++ char path[PATH_MAX]; ++ char pci_name[16]; ++ ssize_t size; ++ unparse_pci_name(pci_name, sizeof(pci_name), pdev); ++ snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s", pci_name); ++ size = readlink(path, buf, bufsize); ++ if (size == -1) ++ return 1; ++ return 0; ++} ++ ++static int read_pci_sysfs_physfn(char *buf, size_t bufsize, const struct pci_dev *pdev) ++{ ++ char path[PATH_MAX]; ++ char pci_name[16]; ++ ssize_t size; ++ unparse_pci_name(pci_name, sizeof(pci_name), pdev); ++ snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/physfn", pci_name); ++ size = readlink(path, buf, bufsize); ++ if (size == -1) ++ return 1; ++ return 0; ++} ++ ++static int virtfn_filter(const struct dirent *dent) ++{ ++ return (!strncmp(dent->d_name,"virtfn",6)); ++} ++ ++static int _read_virtfn_index(unsigned int *index, const char *path, const char *basename, const char *pci_name) ++{ ++ char buf[PATH_MAX], *b; ++ char fullpath[PATH_MAX]; ++ ssize_t size; ++ unsigned int u=INT_MAX; ++ int scanned, rc=1; ++ ++ snprintf(fullpath, sizeof(fullpath), "%s/%s", path, basename); ++ size = readlink(fullpath, buf, sizeof(buf)); ++ if (size > 0) { ++ /* form is ../0000:05:10.0 */ ++ b=buf+3; /* skip ../ */ ++ if (strlen(b) == strlen(pci_name) && ++ !strncmp(b, pci_name, strlen(pci_name))) { ++ scanned = sscanf(basename, "virtfn%u", &u); ++ if (scanned == 1) { ++ rc = 0; ++ *index = u; ++ } ++ } ++ } ++ return rc; ++} ++ ++static int read_virtfn_index(unsigned int *index, const struct pci_dev *pdev) ++{ ++ char pci_name[16]; ++ char path[PATH_MAX]; ++ char cpath[PATH_MAX]; ++ struct dirent **namelist; ++ int n, rc=1; ++ ++ unparse_pci_name(pci_name, sizeof(pci_name), pdev); ++ snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/physfn", pci_name); ++ if (realpath(path, cpath) == NULL) ++ return rc; ++ ++ n = scandir(cpath, &namelist, virtfn_filter, versionsort); ++ if (n < 0) ++ return rc; ++ else { ++ while (n--) { ++ if (rc) ++ rc = _read_virtfn_index(index, cpath, namelist[n]->d_name, pci_name); ++ free(namelist[n]); ++ } ++ free(namelist); ++ } ++ ++ return rc; ++} ++ ++static int parse_pci_name(const char *s, int *domain, int *bus, int *dev, int *func) ++{ ++ int err; ++/* The domain part was added in 2.6 kernels. Test for that first. */ ++ err = sscanf(s, "%x:%2x:%2x.%x", domain, bus, dev, func); ++ if (err != 4) { ++ err = sscanf(s, "%2x:%2x.%x", bus, dev, func); ++ if (err != 3) { ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++static struct pci_dev * find_pdev_by_pci_name(struct pci_access *pacc, const char *s) ++{ ++ int domain=0, bus=0, device=0, func=0; ++ if (parse_pci_name(s, &domain, &bus, &device, &func)) ++ return NULL; ++ return pci_get_dev(pacc, domain, bus, device, func); ++} ++ ++static struct pci_device * ++find_physfn(struct libbiosdevname_state *state, struct pci_device *dev) ++{ ++ int rc; ++ char path[PATH_MAX]; ++ char *c; ++ struct pci_dev *pdev; ++ memset(path, 0, sizeof(path)); ++ rc = read_pci_sysfs_physfn(path, sizeof(path), dev->pci_dev); ++ if (rc != 0) ++ return NULL; ++ /* we get back a string like ++ ../0000:05:0.0 ++ where the last component is the parent device ++ */ ++ /* find the last backslash */ ++ c = rindex(path, '/'); ++ c++; ++ pdev = find_pdev_by_pci_name(state->pacc, c); ++ dev = find_dev_by_pci(state, pdev); ++ return dev; ++} ++ ++static int is_same_pci(const struct pci_dev *a, const struct pci_dev *b) ++{ ++ if (pci_domain_nr(a) == pci_domain_nr(b) && ++ a->bus == b->bus && ++ a->dev == b->dev && ++ a->func == b->func) ++ return 1; ++ return 0; ++} ++ ++static void try_add_vf_to_pf(struct libbiosdevname_state *state, struct pci_device *vf) ++{ ++ struct pci_device *pf; ++ unsigned int index=0; ++ int rc; ++ pf = find_physfn(state, vf); ++ ++ if (!pf) ++ return; ++ list_add_tail(&vf->vfnode, &pf->vfs); ++ rc = read_virtfn_index(&index, vf->pci_dev); ++ if (!rc) { ++ vf->vf_index = index; ++ pf->is_sriov_physical_function = 1; ++ } ++ vf->pf = pf; ++ vf->physical_slot = pf->physical_slot; ++} ++ ++static struct pci_device * ++find_parent(struct libbiosdevname_state *state, struct pci_device *dev) ++{ ++ int rc; ++ char path[PATH_MAX]; ++ char *c; ++ struct pci_device *physfn; ++ struct pci_dev *pdev; ++ memset(path, 0, sizeof(path)); ++ /* if this device has a physfn pointer, then treat _that_ as the parent */ ++ physfn = find_physfn(state, dev); ++ if (physfn) { ++ dev->is_sriov_virtual_function=1; ++ return physfn; ++ } ++ ++ rc = read_pci_sysfs_path(path, sizeof(path), dev->pci_dev); ++ if (rc != 0) ++ return NULL; ++ /* we get back a string like ++ ../../../devices/pci0000:00/0000:00:09.0/0000:05:17.4 ++ where the last component is the device we asked for ++ */ ++ /* find the last backslash */ ++ c = rindex(path, '/'); ++ *c = '\0'; ++ /* find the last backslash again */ ++ c = rindex(path, '/'); ++ c++; ++ pdev = find_pdev_by_pci_name(state->pacc, c); ++ if (pdev) { ++ dev = find_dev_by_pci(state, pdev); ++ return dev; ++ } ++ return NULL; ++} ++ ++/* ++ * Check our parents in case the device itself isn't listed ++ * in the SMBIOS table. This has a problem, as ++ * our parent bridge on a card may not be included ++ * in the SMBIOS table. In that case, it falls back to "unknown". ++ */ ++static inline int pci_dev_to_slot(struct libbiosdevname_state *state, struct pci_device *dev) ++{ ++ return dev->physical_slot; ++} ++ ++static inline int pirq_dev_to_slot(struct libbiosdevname_state *state, struct pci_device *dev) ++{ ++ return pirq_pci_dev_to_slot(state->pirq_table, pci_domain_nr(dev->pci_dev), dev->pci_dev->bus, dev->pci_dev->dev); ++} ++ ++static void dev_to_slot(struct libbiosdevname_state *state, struct pci_device *dev) ++{ ++ struct pci_device *d = dev; ++ int slot; ++ do { ++ slot = pci_dev_to_slot(state, d); ++ if (slot == PHYSICAL_SLOT_UNKNOWN && is_valid_smbios) ++ slot = pcie_get_slot(state, d); ++ if (slot == PHYSICAL_SLOT_UNKNOWN) ++ slot = pirq_dev_to_slot(state, d); ++ if (slot == PHYSICAL_SLOT_UNKNOWN) ++ d = find_parent(state, d); ++ } while (d && slot == PHYSICAL_SLOT_UNKNOWN); ++ ++ dev->physical_slot = slot; ++} ++ ++static char *read_pci_sysfs_label(const struct pci_dev *pdev) ++{ ++ char path[PATH_MAX]; ++ char pci_name[16]; ++ int rc; ++ char *label = NULL; ++ ++ unparse_pci_name(pci_name, sizeof(pci_name), pdev); ++ snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/label", pci_name); ++ rc = sysfs_read_file(path, &label); ++ if (rc == 0) ++ return label; ++ return NULL; ++} ++ ++static int read_pci_sysfs_index(unsigned int *index, const struct pci_dev *pdev) ++{ ++ char path[PATH_MAX]; ++ char pci_name[16]; ++ int rc; ++ char *indexstr = NULL; ++ unsigned int i; ++ unparse_pci_name(pci_name, sizeof(pci_name), pdev); ++ snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/index", pci_name); ++ rc = sysfs_read_file(path, &indexstr); ++ if (rc == 0) { ++ rc = sscanf(indexstr, "%u", &i); ++ if (rc == 1) { ++ *index = i; ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++static void fill_pci_dev_sysfs(struct pci_device *dev, struct pci_dev *p) ++{ ++ int rc; ++ unsigned int index = 0; ++ char *label = NULL; ++ char buf[PATH_MAX]; ++ unparse_pci_name(buf, sizeof(buf), p); ++ rc = read_pci_sysfs_index(&index, p); ++ if (!rc) { ++ dev->sysfs_index = index; ++ dev->uses_sysfs |= HAS_SYSFS_INDEX; ++ } ++ label = read_pci_sysfs_label(p); ++ if (label) { ++ dev->sysfs_label = label; ++ dev->uses_sysfs |= HAS_SYSFS_LABEL; ++ } ++} ++ ++ ++static void add_pci_dev(struct libbiosdevname_state *state, ++ struct pci_dev *p) ++{ ++ struct pci_device *dev; ++ dev = malloc(sizeof(*dev)); ++ if (!dev) { ++ fprintf(stderr, "out of memory\n"); ++ return; ++ } ++ memset(dev, 0, sizeof(*dev)); ++ INIT_LIST_HEAD(&dev->node); ++ INIT_LIST_HEAD(&dev->vfnode); ++ INIT_LIST_HEAD(&dev->vfs); ++ dev->pci_dev = p; ++ dev->physical_slot = PHYSICAL_SLOT_UNKNOWN; ++ dev->class = pci_read_word(p, PCI_CLASS_DEVICE); ++ dev->vf_index = INT_MAX; ++ dev->vpd_port = INT_MAX; ++ dev->vpd_pfi = INT_MAX; ++ dev->vpd_pf = NULL; ++ fill_pci_dev_sysfs(dev, p); ++ list_add(&dev->node, &state->pci_devices); ++} ++ ++void free_pci_devices(struct libbiosdevname_state *state) ++{ ++ struct pci_device *pos, *next; ++ list_for_each_entry_safe(pos, next, &state->pci_devices, node) { ++ if (pos->smbios_label) ++ free(pos->smbios_label); ++ if (pos->sysfs_label) ++ free(pos->sysfs_label); ++ list_del(&pos->node); ++ free(pos); ++ } ++} ++ ++int addslot(struct libbiosdevname_state *state, int slot) ++{ ++ struct slotlist *s; ++ ++ list_for_each_entry(s, &state->slots, node) { ++ if (s->slot == slot) { ++ return ++s->count; ++ } ++ } ++ s = malloc(sizeof(*s)); ++ INIT_LIST_HEAD(&s->node); ++ s->slot = slot; ++ s->count = 0; ++ list_add(&s->node, &state->slots); ++ ++ return ++s->count; ++} ++ ++static void set_pci_slots(struct libbiosdevname_state *state) ++{ ++ struct pci_device *dev; ++ ++ list_for_each_entry(dev, &state->pci_devices, node) { ++ dev_to_slot(state, dev); ++ } ++ ++ /* Get mapping for each slot */ ++ list_for_each_entry(dev, &state->pci_devices, node) { ++ if (dev->is_sriov_virtual_function || !is_pci_network(dev) || dev->vpd_port != INT_MAX) { ++ continue; ++ } ++ if (dev->physical_slot == 0) { ++ dev->embedded_index_valid = 1; ++ dev->embedded_index = addslot(state, 0); ++ } else if (dev->physical_slot != PHYSICAL_SLOT_UNKNOWN) { ++ dev->index_in_slot = addslot(state, dev->physical_slot); ++ } ++ } ++} ++ ++static void set_sriov_pf_vf(struct libbiosdevname_state *state) ++{ ++ struct pci_device *vf; ++ list_for_each_entry(vf, &state->pci_devices, node) { ++ if (!vf->is_sriov_virtual_function) ++ continue; ++ try_add_vf_to_pf(state, vf); ++ } ++} ++ ++/* ++ * This sorts the PCI devices by breadth-first domain/bus/dev/fn. ++ */ ++static int sort_pci(const struct pci_device *a, const struct pci_device *b) ++{ ++ ++ if (pci_domain_nr(a->pci_dev) < pci_domain_nr(b->pci_dev)) return -1; ++ else if (pci_domain_nr(a->pci_dev) > pci_domain_nr(b->pci_dev)) return 1; ++ ++ if (a->pci_dev->bus < b->pci_dev->bus) return -1; ++ else if (a->pci_dev->bus > b->pci_dev->bus) return 1; ++ ++ if (a->pci_dev->dev < b->pci_dev->dev) return -1; ++ else if (a->pci_dev->dev > b->pci_dev->dev) return 1; ++ ++ if (a->pci_dev->func < b->pci_dev->func) return -1; ++ else if (a->pci_dev->func > b->pci_dev->func) return 1; ++ ++ return 0; ++} ++ ++static void insertion_sort_devices(struct pci_device *a, struct list_head *list, ++ int (*cmp)(const struct pci_device *, const struct pci_device *)) ++{ ++ struct pci_device *b; ++ list_for_each_entry(b, list, node) { ++ if (cmp(a, b) <= 0) { ++ list_move_tail(&a->node, &b->node); ++ return; ++ } ++ } ++ list_move_tail(&a->node, list); ++} ++ ++static void sort_device_list(struct libbiosdevname_state *state) ++{ ++ LIST_HEAD(sorted_devices); ++ struct pci_device *dev, *tmp; ++ list_for_each_entry_safe(dev, tmp, &state->pci_devices, node) { ++ insertion_sort_devices(dev, &sorted_devices, sort_pci); ++ } ++ list_splice(&sorted_devices, &state->pci_devices); ++} ++ ++int get_pci_devices(struct libbiosdevname_state *state) ++{ ++ struct pci_access *pacc; ++ struct pci_dev *p; ++ struct routing_table *table; ++ int rc=0; ++ ++ table = pirq_alloc_read_table(); ++ if (table) ++ state->pirq_table = table; ++ ++ pacc = pci_alloc(); ++ if (!pacc) ++ return rc; ++ state->pacc = pacc; ++ pci_init(pacc); ++ pci_scan_bus(pacc); ++ ++ for (p=pacc->devices; p; p=p->next) { ++ add_pci_dev(state, p); ++ } ++ /* ordering here is important */ ++ dmidecode_main(state); /* this will fail on Xen guests, that's OK */ ++ sort_device_list(state); ++ set_pci_vpd_instance(state); ++ set_pci_slots(state); ++ set_sriov_pf_vf(state); ++ ++ return rc; ++} ++ ++int unparse_pci_name(char *buf, int size, const struct pci_dev *pdev) ++{ ++ return snprintf(buf, size, "%04x:%02x:%02x.%x", ++ pci_domain_nr(pdev), pdev->bus, pdev->dev, pdev->func); ++} ++ ++static int unparse_location(char *buf, const int size, const int location) ++{ ++ char *s = buf; ++ if (location == 0) ++ s += snprintf(s, size-(s-buf), "embedded"); ++ else if (location == INT_MAX) ++ s += snprintf(s, size-(s-buf), "unknown"); ++ else if (location > 0) ++ s += snprintf(s, size-(s-buf), "%u", location); ++ else ++ s += snprintf(s, size-(s-buf), "unknown"); ++ return (s-buf); ++} ++ ++static int unparse_smbios_type41_type(char *buf, const int size, const int type) ++{ ++ char *s = buf; ++ const char *msg[] = {"Other", ++ "Unknown", ++ "Video", ++ "SCSI Controller", ++ "Ethernet", ++ "Token Ring", ++ "Sound", ++ "PATA Controller", ++ "SATA Controller", ++ "SAS Controller", ++ }; ++ if (type > 0 && type <= sizeof(msg)) ++ s += snprintf(s, size-(s-buf), "%s\n", msg[type-1]); ++ else ++ s += snprintf(s, size-(s-buf), "\n"); ++ return (s-buf); ++} ++ ++int unparse_pci_device(char *buf, const int size, const struct pci_device *p) ++{ ++ char *s = buf; ++ struct pci_device *dev; ++ char pci_name[16]; ++ s += snprintf(s, size-(s-buf), "PCI name : "); ++ s += unparse_pci_name(s, size-(s-buf), p->pci_dev); ++ s += snprintf(s, size-(s-buf), "\n"); ++ s += snprintf(s, size-(s-buf), "PCI Slot : "); ++ if (p->physical_slot < INT_MAX) ++ s += unparse_location(s, size-(s-buf), p->physical_slot); ++ else ++ s += snprintf(s, size-(s-buf), "Unknown"); ++ s += snprintf(s, size-(s-buf), "\n"); ++ if (p->smbios_type) { ++ s += snprintf(s, size-(s-buf), "SMBIOS Device Type: "); ++ s += unparse_smbios_type41_type(s, size-(s-buf), p->smbios_type); ++ if (p->smbios_instance) ++ s += snprintf(s, size-(s-buf), "SMBIOS Instance: %u\n", p->smbios_instance); ++ } ++ if (p->uses_smbios & HAS_SMBIOS_LABEL && p->smbios_label) ++ s += snprintf(s, size-(s-buf), "SMBIOS Label: %s\n", p->smbios_label); ++ if (p->uses_sysfs & HAS_SYSFS_INDEX) ++ s += snprintf(s, size-(s-buf), "sysfs Index: %u\n", p->sysfs_index); ++ if (p->uses_sysfs & HAS_SYSFS_LABEL) ++ s += snprintf(s, size-(s-buf), "sysfs Label: %s\n", p->sysfs_label); ++ if (p->physical_slot > 0 && !p->is_sriov_virtual_function) ++ s += snprintf(s, size-(s-buf), "Index in slot: %u\n", p->index_in_slot); ++ if (p->embedded_index_valid) ++ s += snprintf(s, size-(s-buf), "Embedded Index: %u\n", p->embedded_index); ++ if (p->vpd_port < INT_MAX) { ++ s += snprintf(s, size-(s-buf), "VPD Port: %u\n", p->vpd_port); ++ s += snprintf(s, size-(s-buf), "VPD Index: %u\n", p->vpd_pfi); ++ if (p->vpd_pf) { ++ s += snprintf(s, size-(s-buf), "VPD PCI master: "); ++ s += unparse_pci_name(s, size-(s-buf), p->vpd_pf->pci_dev); ++ s += snprintf(s, size-(s-buf), " count %d\n", p->vpd_pf->vpd_count); ++ } ++ } ++ if (!list_empty(&p->vfs)) { ++ s += snprintf(s, size-(s-buf), "Virtual Functions:\n"); ++ list_for_each_entry(dev, &p->vfs, vfnode) { ++ unparse_pci_name(pci_name, sizeof(pci_name), dev->pci_dev); ++ s += snprintf(s, size-(s-buf), "%s\n", pci_name); ++ } ++ } ++ ++ return (s-buf); ++} ++ ++struct pci_device * find_dev_by_pci(const struct libbiosdevname_state *state, ++ const struct pci_dev *p) ++{ ++ struct pci_device *dev; ++ list_for_each_entry(dev, &state->pci_devices, node) { ++ if (is_same_pci(p, dev->pci_dev)) ++ return dev; ++ } ++ return NULL; ++} ++ ++struct pci_device * find_pci_dev_by_pci_addr(const struct libbiosdevname_state *state, ++ const int domain, const int bus, const int device, const int func) ++{ ++ struct pci_device *dev; ++ struct pci_dev p; ++ memset(&p, 0, sizeof(p)); ++ ++#ifdef HAVE_STRUCT_PCI_DEV_DOMAIN ++ p.domain = domain; ++#endif ++ p.bus = bus; ++ p.dev = device; ++ p.func = func; ++ ++ list_for_each_entry(dev, &state->pci_devices, node) { ++ if (is_same_pci(&p, dev->pci_dev)) ++ return dev; ++ } ++ return NULL; ++} ++ ++struct pci_device * find_dev_by_pci_name(const struct libbiosdevname_state *state, ++ const char *s) ++{ ++ int domain=0, bus=0, device=0, func=0; ++ if (parse_pci_name(s, &domain, &bus, &device, &func)) ++ return NULL; ++ ++ return find_pci_dev_by_pci_addr(state, domain, bus, device, func); ++} diff -Nru biosdevname-0.4.1/debian/patches/series biosdevname-0.4.1/debian/patches/series --- biosdevname-0.4.1/debian/patches/series 2014-02-19 06:27:19.000000000 -0500 +++ biosdevname-0.4.1/debian/patches/series 2014-05-30 12:00:51.000000000 -0400 @@ -1 +1,2 @@ smbios-2.6-check.patch +fix_addslot_function_rename.patch