diff --git a/mdadm.h b/mdadm.h index 79ec5e2..f29cf01 100644 --- a/mdadm.h +++ b/mdadm.h @@ -346,7 +346,7 @@ extern int sysfs_get_ll(struct mdinfo *sra, struct mdinfo *dev, extern int sysfs_set_array(struct mdinfo *sra, struct mdinfo *info); extern int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd); - +extern int sysfs_disk_to_sg(int fd); diff --git a/super-intel.c b/super-intel.c index 2da4514..4052aa6 100644 --- a/super-intel.c +++ b/super-intel.c @@ -544,26 +544,19 @@ static int imsm_read_serial(int fd, char *devname, __u8 serial[MAX_RAID_SERIAL_LEN]) { unsigned char scsi_serial[255]; - struct stat stb; int sg_fd; - int minor; - char sg_path[20]; int rv; int rsp_len; int i, cnt; memset(scsi_serial, 0, sizeof(scsi_serial)); - fstat(fd, &stb); - minor = minor(stb.st_rdev); - minor /= 16; - sprintf(sg_path, "/dev/sg%d", minor); - sg_fd = open(sg_path, O_RDONLY); + sg_fd = sysfs_disk_to_sg(fd); if (sg_fd < 0) { if (devname) fprintf(stderr, - Name ": Failed to open %s for %s: %s\n", - sg_path, devname, strerror(errno)); + Name ": Failed to open sg interface for %s: %s\n", + devname, strerror(errno)); return 1; } diff --git a/sysfs.c b/sysfs.c index bbb9cd3..37b8b09 100644 --- a/sysfs.c +++ b/sysfs.c @@ -399,3 +399,68 @@ int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd) } return rv; } + +int sysfs_disk_to_sg(int fd) +{ + /* from an open block device, try find and open its corresponding + * scsi_generic interface + */ + struct stat st; + char path[256]; + char sg_path[256]; + char sg_major_minor[8]; + char *c; + DIR *dir; + struct dirent *de; + int major, minor, rv; + + if (fstat(fd, &st)) + return -1; + + snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/device", + major(st.st_rdev), minor(st.st_rdev)); + + dir = opendir(path); + if (!dir) + return -1; + + de = readdir(dir); + while (de) { + if (strncmp("scsi_generic:", de->d_name, + strlen("scsi_generic:")) == 0) + break; + de = readdir(dir); + } + closedir(dir); + + if (!de) + return -1; + + snprintf(sg_path, sizeof(sg_path), "%s/%s/dev", path, de->d_name); + fd = open(sg_path, O_RDONLY); + if (fd < 0) + return fd; + + rv = read(fd, sg_major_minor, sizeof(sg_major_minor)); + close(fd); + if (rv < 0) + return -1; + else + sg_major_minor[rv - 1] = '\0'; + + c = strchr(sg_major_minor, ':'); + *c = '\0'; + c++; + major = strtol(sg_major_minor, NULL, 10); + minor = strtol(c, NULL, 10); + snprintf(path, sizeof(path), "/dev/.tmp.md.%d:%d:%d", + (int) getpid(), major, minor); + if (mknod(path, S_IFCHR|0600, makedev(major, minor))==0) { + fd = open(path, O_RDONLY); + unlink(path); + return fd; + } + + return -1; +} +