diff --git a/include/lib/pci_list.h b/include/lib/pci_list.h index 5b2918bc..226a82d9 100644 --- a/include/lib/pci_list.h +++ b/include/lib/pci_list.h @@ -17,6 +17,8 @@ #include "util_list.h" +#define PCI_BDF_LEN 13 /* DDDD:BB:dd.f\0 */ + enum zpci_pft { ZPCI_PFT_UNCLASSIFIED = 0x00, @@ -96,4 +98,6 @@ operstate_t zpci_operstate_from_str(const char *oper_str); struct zpci_dev *zpci_find_by_netdev(struct util_list *zpci_list, char *netdev_name, struct zpci_netdev **netdev); +char *zpci_get_nvme_device_node(const char *pci_addr); + #endif /* LIB_ZPCI_PCI_LIST_H */ diff --git a/libzpci/pci_list.c b/libzpci/pci_list.c index e0d56e44..e81bb4b8 100644 --- a/libzpci/pci_list.c +++ b/libzpci/pci_list.c @@ -20,6 +20,7 @@ #include "lib/util_list.h" #include "lib/util_path.h" #include "lib/util_scandir.h" +#include "lib/util_sys.h" /** * Get the function type name for the given device @@ -137,7 +138,7 @@ const char *zpci_operstate_str(operstate_t state) static int zpci_populate_from_slot_dir(struct zpci_dev *zdev, const char *slot_dir, const char *slot_name) { - char buf_addr[11]; /* "dddd:bb:dd\0" */ + char buf_addr[PCI_BDF_LEN]; uint8_t bus, df; uint32_t domain; int val, rc; @@ -387,3 +388,46 @@ struct zpci_dev *zpci_find_by_netdev(struct util_list *zpci_list, char *netdev_n } return NULL; } + +/** + * Get the NVMe device file name given a PCI address + * + * This function retrieves the NVMe device file "/dev/nvmeX" + * for a given PCI address. The device name can be used to construct + * the path /dev/nvmeX which is the NVMe's controller's character + * device used for example to retrieve S.M.A.R.T. data. + * + * @param[in] pci_addr The "DDDD:bb:dd.f" format PCI address + * + * @return The NVMe device file name if one is found NULL otherwise + */ +char *zpci_get_nvme_device_node(const char *pci_addr) +{ + char *path, *dev = NULL; + char dev_addr[PCI_BDF_LEN]; + struct dirent **de_vec; + int count, i; + + path = util_path_sysfs("bus/pci/devices/%s/nvme", pci_addr); + count = util_scandir(&de_vec, alphasort, path, "nvme*"); + if (count == -1) { + warnx("Could not read directory %s: %s", path, strerror(errno)); + goto exit_path; + } + + for (i = 0; i < count; i++) { + util_asprintf(&dev, "/dev/%s", de_vec[i]->d_name); + if (util_sys_get_dev_addr(dev, dev_addr) != 0) + goto free_continue; + if (strcmp(dev_addr, pci_addr) == 0) + break; +free_continue: + free(dev); + dev = NULL; + } + + util_scandir_free(de_vec, count); +exit_path: + free(path); + return dev; +} diff --git a/zpcictl/zpcictl.c b/zpcictl/zpcictl.c index 421403ac..8c8ce482 100644 --- a/zpcictl/zpcictl.c +++ b/zpcictl/zpcictl.c @@ -18,8 +18,8 @@ #include "lib/util_opt.h" #include "lib/util_path.h" #include "lib/util_prg.h" -#include "lib/util_scandir.h" #include "lib/util_sys.h" +#include "lib/pci_list.h" #include "lib/pci_sclp.h" #include "zpcictl.h" @@ -187,35 +187,6 @@ static void sysfs_write_value(struct zpci_device *pdev, const char *attr, free(path); } -static void get_device_node(struct zpci_device *pdev) -{ - struct dirent **de_vec; - char *path, *dev; - char slot[13]; - int count, i; - - path = util_path_sysfs("bus/pci/devices/%s/nvme", pdev->slot); - count = util_scandir(&de_vec, alphasort, path, "nvme*"); - if (count == -1) { - warnx("Could not read directory %s: %s", path, strerror(errno)); - free(path); - return; - } - - for (i = 0; i < count; i++) { - util_asprintf(&dev, "/dev/%s", de_vec[i]->d_name); - if (util_sys_get_dev_addr(dev, slot) != 0) - continue; - if (strcmp(slot, pdev->slot) == 0) { - pdev->device = dev; - break; - } - } - - util_scandir_free(de_vec, count); - free(path); -} - static int device_exists(char *dev) { char *path; @@ -258,7 +229,7 @@ static void get_device_info(struct zpci_device *pdev, char *dev) * S.M.A.R.T. data at a later point. */ if (!pdev->device && pdev->class == PCI_CLASS_NVME) - get_device_node(pdev); + pdev->device = zpci_get_nvme_device_node(pdev->slot); } /*