+static struct md_list*
+get_devices(const char *hba_path)
+{
+ struct md_list *devlist = NULL;
+ struct md_list *dv = NULL;
+ struct dirent *ent;
+ DIR *dir;
+ int err = 0;
+
+#if DEBUG_LOOP
+ devlist = get_loop_devices();
+ return devlist;
+#endif
+ /* scroll through /sys/dev/block looking for devices attached to
+ * this hba
+ */
+ dir = opendir("/sys/dev/block");
+ for (ent = dir ? readdir(dir) : NULL; ent; ent = readdir(dir)) {
+ int fd;
+ char buf[1024];
+ int major, minor;
+ char *path = NULL;
+ if (sscanf(ent->d_name, "%d:%d", &major, &minor) != 2)
+ continue;
+ path = devt_to_devpath(makedev(major, minor));
+ if (!path)
+ continue;
+ if (!path_attached_to_hba(path, hba_path)) {
+ free(path);
+ path = NULL;
+ continue;
+ }
+ free(path);
+ path = NULL;
+ fd = dev_open(ent->d_name, O_RDONLY);
+ if (fd >= 0) {
+ fd2devname(fd, buf);
+ close(fd);
+ } else {
+ pr_err("cannot open device: %s\n",
+ ent->d_name);
+ continue;
+ }
+
+
+ dv = xcalloc(1, sizeof(*dv));
+ dv->devname = xstrdup(buf);
+ dv->next = devlist;
+ devlist = dv;
+ }
+ if (err) {
+ while(devlist) {
+ dv = devlist;
+ devlist = devlist->next;
+ free(dv->devname);
+ free(dv);
+ }
+ }
+ closedir(dir);
+ return devlist;
+}
+
+static int
+count_volumes_list(struct md_list *devlist, char *homehost,
+ int verbose, int *found)
+{
+ struct md_list *tmpdev;
+ int count = 0;
+ struct supertype *st = NULL;
+
+ /* first walk the list of devices to find a consistent set
+ * that match the criterea, if that is possible.
+ * We flag the ones we like with 'used'.
+ */
+ *found = 0;
+ st = match_metadata_desc_imsm("imsm");
+ if (st == NULL) {
+ pr_vrb(": cannot allocate memory for imsm supertype\n");
+ return 0;
+ }
+
+ for (tmpdev = devlist; tmpdev; tmpdev = tmpdev->next) {
+ char *devname = tmpdev->devname;
+ struct stat stb;
+ struct supertype *tst;
+ int dfd;
+ if (tmpdev->used > 1)
+ continue;
+ tst = dup_super(st);
+ if (tst == NULL) {
+ pr_vrb(": cannot allocate memory for imsm supertype\n");
+ goto err_1;
+ }
+ tmpdev->container = 0;
+ dfd = dev_open(devname, O_RDONLY|O_EXCL);
+ if (dfd < 0) {
+ dprintf(": cannot open device %s: %s\n",
+ devname, strerror(errno));
+ tmpdev->used = 2;
+ } else if (fstat(dfd, &stb)< 0) {
+ /* Impossible! */
+ dprintf(": fstat failed for %s: %s\n",
+ devname, strerror(errno));
+ tmpdev->used = 2;
+ } else if ((stb.st_mode & S_IFMT) != S_IFBLK) {
+ dprintf(": %s is not a block device.\n",
+ devname);
+ tmpdev->used = 2;
+ } else if (must_be_container(dfd)) {
+ struct supertype *cst;
+ cst = super_by_fd(dfd, NULL);
+ if (cst == NULL) {
+ dprintf(": cannot recognize container type %s\n",
+ devname);
+ tmpdev->used = 2;
+ } else if (tst->ss != st->ss) {
+ dprintf(": non-imsm container - ignore it: %s\n",
+ devname);
+ tmpdev->used = 2;
+ } else if (!tst->ss->load_container ||
+ tst->ss->load_container(tst, dfd, NULL))
+ tmpdev->used = 2;
+ else {
+ tmpdev->container = 1;
+ }
+ if (cst)
+ cst->ss->free_super(cst);
+ } else {
+ tmpdev->st_rdev = stb.st_rdev;
+ if (tst->ss->load_super(tst,dfd, NULL)) {
+ dprintf(": no RAID superblock on %s\n",
+ devname);
+ tmpdev->used = 2;
+ } else if (tst->ss->compare_super == NULL) {
+ dprintf(": Cannot assemble %s metadata on %s\n",
+ tst->ss->name, devname);
+ tmpdev->used = 2;
+ }
+ }
+ if (dfd >= 0)
+ close(dfd);
+ if (tmpdev->used == 2 || tmpdev->used == 4) {
+ /* Ignore unrecognised devices during auto-assembly */
+ goto loop;
+ }
+ else {
+ struct mdinfo info;
+ tst->ss->getinfo_super(tst, &info, NULL);
+
+ if (st->minor_version == -1)
+ st->minor_version = tst->minor_version;
+
+ if (memcmp(info.uuid, uuid_zero,
+ sizeof(int[4])) == 0) {
+ /* this is a floating spare. It cannot define
+ * an array unless there are no more arrays of
+ * this type to be found. It can be included
+ * in an array of this type though.
+ */
+ tmpdev->used = 3;
+ goto loop;
+ }
+
+ if (st->ss != tst->ss ||
+ st->minor_version != tst->minor_version ||
+ st->ss->compare_super(st, tst) != 0) {
+ /* Some mismatch. If exactly one array matches this host,
+ * we can resolve on that one.
+ * Or, if we are auto assembling, we just ignore the second
+ * for now.
+ */
+ dprintf(": superblock on %s doesn't match others - assembly aborted\n",
+ devname);
+ goto loop;
+ }
+ tmpdev->used = 1;
+ *found = 1;
+ dprintf("found: devname: %s\n", devname);
+ }
+ loop:
+ if (tst)
+ tst->ss->free_super(tst);
+ }
+ if (*found != 0) {
+ int err;
+ if ((err = load_super_imsm_all(st, -1, &st->sb, NULL, devlist, 0)) == 0) {
+ struct mdinfo *iter, *head = st->ss->container_content(st, NULL);
+ for (iter = head; iter; iter = iter->next) {
+ dprintf("content->text_version: %s vol\n",
+ iter->text_version);
+ if (iter->array.state & (1<<MD_SB_BLOCK_VOLUME)) {
+ /* do not assemble arrays with unsupported
+ configurations */
+ dprintf(": Cannot activate member %s.\n",
+ iter->text_version);
+ } else
+ count++;
+ }
+ sysfs_free(head);
+
+ } else {
+ dprintf(" no valid super block on device list: err: %d %p\n",
+ err, st->sb);
+ }
+ } else {
+ dprintf(" no more devices to examin\n");
+ }
+
+ for (tmpdev = devlist; tmpdev; tmpdev = tmpdev->next) {
+ if ((tmpdev->used == 1) && (tmpdev->found)) {
+ if (count) {
+ if (count < tmpdev->found)
+ count = 0;
+ else
+ count -= tmpdev->found;
+ }
+ }
+ if (tmpdev->used == 1)
+ tmpdev->used = 4;
+ }
+ err_1:
+ if (st)
+ st->ss->free_super(st);
+ return count;
+}
+
+
+static int
+count_volumes(char *hba, int dpa, int verbose)
+{
+ struct md_list *devlist = NULL;
+ int count = 0;
+ int found = 0;;
+
+ devlist = get_devices(hba);
+ /* if no intel devices return zero volumes */
+ if (devlist == NULL)
+ return 0;
+
+ count = active_arrays_by_format("imsm", hba, &devlist, dpa, verbose);
+ dprintf(" path: %s active arrays: %d\n", hba, count);
+ if (devlist == NULL)
+ return 0;
+ do {
+ found = 0;
+ count += count_volumes_list(devlist,
+ NULL,
+ verbose,
+ &found);
+ dprintf("found %d count: %d\n", found, count);
+ } while (found);
+
+ dprintf("path: %s total number of volumes: %d\n", hba, count);
+
+ while(devlist) {
+ struct md_list *dv = devlist;
+ devlist = devlist->next;
+ free(dv->devname);
+ free(dv);
+ }
+ return count;
+}
+
+static int imsm_default_chunk(const struct imsm_orom *orom)
+{
+ /* up to 512 if the plaform supports it, otherwise the platform max.
+ * 128 if no platform detected
+ */
+ int fs = max(7, orom ? fls(orom->sss) : 0);
+
+ return min(512, (1 << fs));
+}
+
+static int
+validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
+ int raiddisks, int *chunk, unsigned long long size, int verbose)
+{
+ /* check/set platform and metadata limits/defaults */
+ if (super->orom && raiddisks > super->orom->dpa) {
+ pr_vrb(": platform supports a maximum of %d disks per array\n",
+ super->orom->dpa);
+ return 0;
+ }
+
+ /* capabilities of OROM tested - copied from validate_geometry_imsm_volume */
+ if (!is_raid_level_supported(super->orom, level, raiddisks)) {
+ pr_vrb(": platform does not support raid%d with %d disk%s\n",
+ level, raiddisks, raiddisks > 1 ? "s" : "");
+ return 0;
+ }
+
+ if (chunk && (*chunk == 0 || *chunk == UnSet))
+ *chunk = imsm_default_chunk(super->orom);
+
+ if (super->orom && chunk && !imsm_orom_has_chunk(super->orom, *chunk)) {
+ pr_vrb(": platform does not support a chunk size of: "
+ "%d\n", *chunk);
+ return 0;
+ }
+
+ if (layout != imsm_level_to_layout(level)) {
+ if (level == 5)
+ pr_vrb(": imsm raid 5 only supports the left-asymmetric layout\n");
+ else if (level == 10)
+ pr_vrb(": imsm raid 10 only supports the n2 layout\n");
+ else
+ pr_vrb(": imsm unknown layout %#x for this raid level %d\n",
+ layout, level);
+ return 0;
+ }
+
+ if (super->orom && (super->orom->attr & IMSM_OROM_ATTR_2TB) == 0 && chunk &&
+ (calc_array_size(level, raiddisks, layout, *chunk, size) >> 32) > 0) {
+ pr_vrb(": platform does not support a volume size over 2TB\n");
+ return 0;
+ }
+ return 1;
+}
+
+/* validate_geometry_imsm_volume - lifted from validate_geometry_ddf_bvd
+ * FIX ME add ahci details
+ */
+static int validate_geometry_imsm_volume(struct supertype *st, int level,
+ int layout, int raiddisks, int *chunk,
+ unsigned long long size, char *dev,