From: Robert Milasan Date: Thu, 12 Jul 2012 15:56:34 +0000 Subject: re-enable by_path links for ata devices Fix by-path links for ATA transport (bnc#770910) --- src/udev/udev-builtin-path_id.c | 92 +++++++++++++++++++++++++++++++++++------ 1 file changed, 80 insertions(+), 12 deletions(-) --- systemd-206.orig/src/udev/udev-builtin-path_id.c +++ systemd-206/src/udev/udev-builtin-path_id.c @@ -338,6 +338,85 @@ static struct udev_device *handle_scsi_h return parent; } +static struct udev_device *handle_ata(struct udev_device *parent, char **path) +{ + struct udev_device *hostdev; + int host, bus, target, lun; + const char *name; + char *base; + char *pos; + DIR *dir; + struct dirent *dent; + int basenum, len; + + hostdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host"); + if (hostdev == NULL) + return NULL; + + name = udev_device_get_sysname(parent); + if (sscanf(name, "%d:%d:%d:%d", &host, &bus, &target, &lun) != 4) + return NULL; + + /* rebase ata offset to get the local relative number */ + basenum = -1; + base = strdup(udev_device_get_syspath(hostdev)); + if (base == NULL) + return NULL; + pos = strrchr(base, '/'); + if (pos == NULL) { + parent = NULL; + goto out; + } + pos[0] = '\0'; + len = strlen(base) - 5; + if (len <= 0) { + parent = NULL; + goto out; + } + base[len] = '\0'; + dir = opendir(base); + if (dir == NULL) { + parent = NULL; + goto out; + } + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + char *rest; + int i; + + if (dent->d_name[0] == '.') + continue; + if (dent->d_type != DT_DIR && dent->d_type != DT_LNK) + continue; + if (strncmp(dent->d_name, "ata", 3) != 0) + continue; + i = strtoul(&dent->d_name[3], &rest, 10); + + /* ata devices start with 1, so decrease by 1 if i is bigger then 0 */ + if (i > 0) + i--; + if (rest[0] != '\0') + continue; + /* + * find the smallest number; the host really needs to export its + * own instance number per parent device; relying on the global host + * enumeration and plainly rebasing the numbers sounds unreliable + */ + if (basenum == -1 || i < basenum) + basenum = i; + } + closedir(dir); + if (basenum == -1) { + parent = NULL; + goto out; + } + host -= basenum; + + path_prepend(path, "scsi-%u:%u:%u:%u", host, bus, target, lun); +out: + free(base); + return hostdev; +} + static struct udev_device *handle_scsi(struct udev_device *parent, char **path) { const char *devtype; @@ -374,19 +453,8 @@ static struct udev_device *handle_scsi(s goto out; } - /* - * We do not support the ATA transport class, it uses global counters - * to name the ata devices which numbers spread across multiple - * controllers. - * - * The real link numbers are not exported. Also, possible chains of ports - * behind port multipliers cannot be composed that way. - * - * Until all that is solved at the kernel level, there are no by-path/ - * links for ATA devices. - */ if (strstr(name, "/ata") != NULL) { - parent = NULL; + parent = handle_ata(parent, path); goto out; }