+
+int sysfs_set_array(struct mdinfo *sra,
+ struct mdinfo *info)
+{
+ int rv = 0;
+ sra->array = info->array;
+
+ if (info->array.level < 0)
+ return 0; /* FIXME */
+ rv |= sysfs_set_str(sra, NULL, "level",
+ map_num(pers, info->array.level));
+ rv |= sysfs_set_num(sra, NULL, "raid_disks", info->array.raid_disks);
+ rv |= sysfs_set_num(sra, NULL, "chunk_size", info->array.chunk_size);
+ rv |= sysfs_set_num(sra, NULL, "layout", info->array.layout);
+ rv |= sysfs_set_num(sra, NULL, "component_size", info->component_size);
+ rv |= sysfs_set_num(sra, NULL, "resync_start", info->resync_start);
+ sra->array = info->array;
+ return rv;
+}
+
+int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd)
+{
+ char dv[100];
+ char nm[100];
+ struct mdinfo *sd2;
+ char *dname;
+ int rv;
+
+ sprintf(dv, "%d:%d", sd->disk.major, sd->disk.minor);
+ rv = sysfs_set_str(sra, NULL, "new_dev", dv);
+ if (rv)
+ return rv;
+
+ memset(nm, 0, sizeof(nm));
+ sprintf(dv, "/sys/dev/block/%d:%d", sd->disk.major, sd->disk.minor);
+ if (readlink(dv, nm, sizeof(nm)) < 0)
+ return -1;
+ dname = strrchr(nm, '/');
+ if (dname) dname++;
+ strcpy(sd->sys_name, "dev-");
+ strcpy(sd->sys_name+4, dname);
+
+ rv |= sysfs_set_num(sra, sd, "offset", sd->data_offset);
+ rv |= sysfs_set_num(sra, sd, "size", (sd->component_size+1) / 2);
+ if (sra->array.level != LEVEL_CONTAINER) {
+ rv |= sysfs_set_num(sra, sd, "slot", sd->disk.raid_disk);
+// rv |= sysfs_set_str(sra, sd, "state", "in_sync");
+ }
+ if (! rv) {
+ sd2 = malloc(sizeof(*sd2));
+ *sd2 = *sd;
+ sd2->next = sra->devs;
+ sra->devs = sd2;
+ }
+ 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;
+}
+
+int sysfs_disk_to_scsi_id(int fd, __u32 *id)
+{
+ /* from an open block device, try to retrieve it scsi_id */
+ struct stat st;
+ char path[256];
+ char *c1, *c2;
+ DIR *dir;
+ struct dirent *de;
+
+ 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_disk:", de->d_name,
+ strlen("scsi_disk:")) == 0)
+ break;
+ de = readdir(dir);
+ }
+ closedir(dir);
+
+ if (!de)
+ return 1;
+
+ c1 = strchr(de->d_name, ':');
+ c1++;
+ c2 = strchr(c1, ':');
+ *c2 = '\0';
+ *id = strtol(c1, NULL, 10) << 24; /* host */
+ c1 = c2 + 1;
+ c2 = strchr(c1, ':');
+ *c2 = '\0';
+ *id |= strtol(c1, NULL, 10) << 16; /* channel */
+ c1 = c2 + 1;
+ c2 = strchr(c1, ':');
+ *c2 = '\0';
+ *id |= strtol(c1, NULL, 10) << 8; /* lun */
+ c1 = c2 + 1;
+ *id |= strtol(c1, NULL, 10); /* id */
+
+ return 0;
+}