]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
Change some "fprintf(stderr,"s to pr_err.
[thirdparty/mdadm.git] / super-intel.c
index 2ecb9589c196ff8d0abf6c0415c41d70e35855a4..5a0250eecc02d44ca115710b23a9fc079043587e 100644 (file)
@@ -431,9 +431,9 @@ struct imsm_update_activate_spare {
 };
 
 struct geo_params {
-       int dev_id;
+       char devnm[32];
        char *dev_name;
-       long long size;
+       unsigned long long size;
        int level;
        int layout;
        int chunksize;
@@ -525,14 +525,14 @@ const char *get_sys_dev_type(enum sys_dev_type type)
 
 static struct intel_hba * alloc_intel_hba(struct sys_dev *device)
 {
-       struct intel_hba *result = malloc(sizeof(*result));
-       if (result) {
-               result->type = device->type;
-               result->path = strdup(device->path);
-               result->next = NULL;
-               if (result->path && (result->pci_id = strrchr(result->path, '/')) != NULL)
-                       result->pci_id++;
-       }
+       struct intel_hba *result = xmalloc(sizeof(*result));
+
+       result->type = device->type;
+       result->path = xstrdup(device->path);
+       result->next = NULL;
+       if (result->path && (result->pci_id = strrchr(result->path, '/')) != NULL)
+               result->pci_id++;
+
        return result;
 }
 
@@ -558,25 +558,16 @@ static int attach_hba_to_super(struct intel_super *super, struct sys_dev *device
        if (super->hba == NULL) {
                super->hba = alloc_intel_hba(device);
                return 1;
-       }
-
-       hba = super->hba;
-       /* Intel metadata allows for all disks attached to the same type HBA.
-        * Do not sypport odf HBA types mixing
-        */
-       if (device->type != hba->type)
+       } else
+               /* IMSM metadata disallows to attach disks to multiple
+                * controllers.
+                */
                return 2;
-
-       while (hba->next)
-               hba = hba->next;
-
-       hba->next = alloc_intel_hba(device);
-       return 1;
 }
 
 static struct sys_dev* find_disk_attached_hba(int fd, const char *devname)
 {
-       struct sys_dev *list, *elem, *prev;
+       struct sys_dev *list, *elem;
        char *disk_path;
 
        if ((list = find_intel_devices()) == NULL)
@@ -587,27 +578,15 @@ static struct sys_dev* find_disk_attached_hba(int fd, const char *devname)
        else
                disk_path = diskfd_to_devpath(fd);
 
-       if (!disk_path) {
-               free_sys_dev(&list);
+       if (!disk_path)
                return 0;
-       }
 
-       for (prev = NULL, elem = list; elem; prev = elem, elem = elem->next) {
-               if (path_attached_to_hba(disk_path, elem->path)) {
-                       if (prev == NULL)
-                               list = list->next;
-                       else
-                               prev->next = elem->next;
-                       elem->next = NULL;
-                       if (disk_path != devname)
-                               free(disk_path);
-                       free_sys_dev(&list);
+       for (elem = list; elem; elem = elem->next)
+               if (path_attached_to_hba(disk_path, elem->path))
                        return elem;
-               }
-       }
+
        if (disk_path != devname)
                free(disk_path);
-       free_sys_dev(&list);
 
        return NULL;
 }
@@ -625,11 +604,7 @@ static struct supertype *match_metadata_desc_imsm(char *arg)
                )
                return NULL;
 
-       st = malloc(sizeof(*st));
-       if (!st)
-               return NULL;
-       memset(st, 0, sizeof(*st));
-       st->container_dev = NoMdDev;
+       st = xcalloc(1, sizeof(*st));
        st->ss = &super_imsm;
        st->max_devs = IMSM_MAX_DEVICES;
        st->minor_version = 0;
@@ -688,12 +663,12 @@ static __u32 __gen_imsm_checksum(struct imsm_super *mpb)
        __u32 *p = (__u32 *) mpb;
        __u32 sum = 0;
 
-        while (end--) {
-                sum += __le32_to_cpu(*p);
+       while (end--) {
+               sum += __le32_to_cpu(*p);
                p++;
        }
 
-        return sum - __le32_to_cpu(mpb->check_sum);
+       return sum - __le32_to_cpu(mpb->check_sum);
 }
 
 static size_t sizeof_imsm_map(struct imsm_map *map)
@@ -964,9 +939,7 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl)
        else
                reservation = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
 
-       rv = malloc(sizeof(struct extent) * (memberships + 1));
-       if (!rv)
-               return NULL;
+       rv = xcalloc(sizeof(struct extent), (memberships + 1));
        e = rv;
 
        for (i = 0; i < super->anchor->num_raid_devs; i++) {
@@ -1537,6 +1510,59 @@ static void export_examine_super_imsm(struct supertype *st)
        printf("MD_DEVICES=%u\n", mpb->num_disks);
 }
 
+static int copy_metadata_imsm(struct supertype *st, int from, int to)
+{
+       /* The second last 512byte sector of the device contains
+        * the "struct imsm_super" metadata.
+        * This contains mpb_size which is the size in bytes of the
+        * extended metadata.  This is located immediately before
+        * the imsm_super.
+        * We want to read all that, plus the last sector which
+        * may contain a migration record, and write it all
+        * to the target.
+        */
+       void *buf;
+       unsigned long long dsize, offset;
+       int sectors;
+       struct imsm_super *sb;
+       int written = 0;
+
+       if (posix_memalign(&buf, 4096, 4096) != 0)
+               return 1;
+
+       if (!get_dev_size(from, NULL, &dsize))
+               goto err;
+
+       if (lseek64(from, dsize-1024, 0) < 0)
+               goto err;
+       if (read(from, buf, 512) != 512)
+               goto err;
+       sb = buf;
+       if (strncmp((char*)sb->sig, MPB_SIGNATURE, MPB_SIG_LEN) != 0)
+               goto err;
+
+       sectors = mpb_sectors(sb) + 2;
+       offset = dsize - sectors * 512;
+       if (lseek64(from, offset, 0) < 0 ||
+           lseek64(to, offset, 0) < 0)
+               goto err;
+       while (written < sectors * 512) {
+               int n = sectors*512 - written;
+               if (n > 4096)
+                       n = 4096;
+               if (read(from, buf, n) != n)
+                       goto err;
+               if (write(to, buf, n) != n)
+                       goto err;
+               written += n;
+       }
+       free(buf);
+       return 0;
+err:
+       free(buf);
+       return 1;
+}
+
 static void detail_super_imsm(struct supertype *st, char *homehost)
 {
        struct mdinfo info;
@@ -1572,7 +1598,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
        unsigned long port_mask = (1 << port_count) - 1;
 
        if (port_count > (int)sizeof(port_mask) * 8) {
-               if (verbose)
+               if (verbose > 0)
                        pr_err("port_count %d out of range\n", port_count);
                return 2;
        }
@@ -1605,14 +1631,14 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
 
                /* retrieve the scsi device type */
                if (asprintf(&device, "/sys/dev/block/%d:%d/device/xxxxxxx", major, minor) < 0) {
-                       if (verbose)
+                       if (verbose > 0)
                                pr_err("failed to allocate 'device'\n");
                        err = 2;
                        break;
                }
                sprintf(device, "/sys/dev/block/%d:%d/device/type", major, minor);
                if (load_sys(device, buf) != 0) {
-                       if (verbose)
+                       if (verbose > 0)
                                pr_err("failed to read device type for %s\n",
                                        path);
                        err = 2;
@@ -1665,7 +1691,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
                /* chop device path to 'host%d' and calculate the port number */
                c = strchr(&path[hba_len], '/');
                if (!c) {
-                       if (verbose)
+                       if (verbose > 0)
                                pr_err("%s - invalid path name\n", path + hba_len);
                        err = 2;
                        break;
@@ -1674,7 +1700,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
                if (sscanf(&path[hba_len], "host%d", &port) == 1)
                        port -= host_base;
                else {
-                       if (verbose) {
+                       if (verbose > 0) {
                                *c = '/'; /* repair the full string */
                                pr_err("failed to determine port number for %s\n",
                                        path);
@@ -1803,7 +1829,42 @@ static void print_imsm_capability(const struct imsm_orom *orom)
        return;
 }
 
-static int detail_platform_imsm(int verbose, int enumerate_only)
+static void print_imsm_capability_export(const struct imsm_orom *orom)
+{
+       printf("MD_FIRMWARE_TYPE=imsm\n");
+       printf("IMSM_VERSION=%d.%d.%d.%d\n",orom->major_ver, orom->minor_ver,
+                       orom->hotfix_ver, orom->build);
+       printf("IMSM_SUPPORTED_RAID_LEVELS=%s%s%s%s%s\n",
+                       imsm_orom_has_raid0(orom) ? "raid0 " : "",
+                       imsm_orom_has_raid1(orom) ? "raid1 " : "",
+                       imsm_orom_has_raid1e(orom) ? "raid1e " : "",
+                       imsm_orom_has_raid5(orom) ? "raid10 " : "",
+                       imsm_orom_has_raid10(orom) ? "raid5 " : "");
+       printf("IMSM_SUPPORTED_CHUNK_SIZES=%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+                       imsm_orom_has_chunk(orom, 2) ? "2k " : "",
+                       imsm_orom_has_chunk(orom, 4) ? "4k " : "",
+                       imsm_orom_has_chunk(orom, 8) ? "8k " : "",
+                       imsm_orom_has_chunk(orom, 16) ? "16k " : "",
+                       imsm_orom_has_chunk(orom, 32) ? "32k " : "",
+                       imsm_orom_has_chunk(orom, 64) ? "64k " : "",
+                       imsm_orom_has_chunk(orom, 128) ? "128k " : "",
+                       imsm_orom_has_chunk(orom, 256) ? "256k " : "",
+                       imsm_orom_has_chunk(orom, 512) ? "512k " : "",
+                       imsm_orom_has_chunk(orom, 1024*1) ? "1M " : "",
+                       imsm_orom_has_chunk(orom, 1024*2) ? "2M " : "",
+                       imsm_orom_has_chunk(orom, 1024*4) ? "4M " : "",
+                       imsm_orom_has_chunk(orom, 1024*8) ? "8M " : "",
+                       imsm_orom_has_chunk(orom, 1024*16) ? "16M " : "",
+                       imsm_orom_has_chunk(orom, 1024*32) ? "32M " : "",
+                       imsm_orom_has_chunk(orom, 1024*64) ? "64M " : "");
+       printf("IMSM_2TB_VOLUMES=%s\n",(orom->attr & IMSM_OROM_ATTR_2TB) ? "yes" : "no");
+       printf("IMSM_2TB_DISKS=%s\n",(orom->attr & IMSM_OROM_ATTR_2TB_DISK) ? "yes" : "no");
+       printf("IMSM_MAX_DISKS=%d\n",orom->tds);
+       printf("IMSM_MAX_VOLUMES_PER_ARRAY=%d\n",orom->vpa);
+       printf("IMSM_MAX_VOLUMES_PER_CONTROLLER=%d\n",orom->vphba);
+}
+
+static int detail_platform_imsm(int verbose, int enumerate_only, char *controller_path)
 {
        /* There are two components to imsm platform support, the ahci SATA
         * controller and the option-rom.  To find the SATA controller we
@@ -1820,7 +1881,7 @@ static int detail_platform_imsm(int verbose, int enumerate_only)
        struct sys_dev *list, *hba;
        int host_base = 0;
        int port_count = 0;
-       int result=0;
+       int result=1;
 
        if (enumerate_only) {
                if (check_env("IMSM_NO_PLATFORM"))
@@ -1834,48 +1895,83 @@ static int detail_platform_imsm(int verbose, int enumerate_only)
                                result = 2;
                                break;
                        }
+                       else
+                               result = 0;
                }
-               free_sys_dev(&list);
                return result;
        }
 
        list = find_intel_devices();
        if (!list) {
-               if (verbose)
+               if (verbose > 0)
                        pr_err("no active Intel(R) RAID "
                                "controller found.\n");
-               free_sys_dev(&list);
                return 2;
-       } else if (verbose)
+       } else if (verbose > 0)
                print_found_intel_controllers(list);
 
        for (hba = list; hba; hba = hba->next) {
+               if (controller_path && (compare_paths(hba->path,controller_path) != 0))
+                       continue;
                orom = find_imsm_capability(hba->type);
                if (!orom)
                        pr_err("imsm capabilities not found for controller: %s (type %s)\n",
                                hba->path, get_sys_dev_type(hba->type));
-               else
+               else {
+                       result = 0;
                        print_imsm_capability(orom);
+                       printf(" I/O Controller : %s (%s)\n",
+                               hba->path, get_sys_dev_type(hba->type));
+                       if (hba->type == SYS_DEV_SATA) {
+                               host_base = ahci_get_port_count(hba->path, &port_count);
+                               if (ahci_enumerate_ports(hba->path, port_count, host_base, verbose)) {
+                                       if (verbose > 0)
+                                               pr_err("failed to enumerate "
+                                                       "ports on SATA controller at %s.\n", hba->pci_id);
+                                       result |= 2;
+                               }
+                       }
+               }
+       }
+
+       if (controller_path && result == 1)
+               pr_err("no active Intel(R) RAID "
+                               "controller found under %s\n",controller_path);
+
+       return result;
+}
+
+static int export_detail_platform_imsm(int verbose, char *controller_path)
+{
+       const struct imsm_orom *orom;
+       struct sys_dev *list, *hba;
+       int result=1;
+
+       list = find_intel_devices();
+       if (!list) {
+               if (verbose > 0)
+                       pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_INTEL_DEVICES\n");
+               result = 2;
+               return result;
        }
 
        for (hba = list; hba; hba = hba->next) {
-               printf(" I/O Controller : %s (%s)\n",
-                       hba->path, get_sys_dev_type(hba->type));
-
-               if (hba->type == SYS_DEV_SATA) {
-                       host_base = ahci_get_port_count(hba->path, &port_count);
-                       if (ahci_enumerate_ports(hba->path, port_count, host_base, verbose)) {
-                               if (verbose)
-                                       pr_err("failed to enumerate "
-                                               "ports on SATA controller at %s.", hba->pci_id);
-                               result |= 2;
-                       }
+               if (controller_path && (compare_paths(hba->path,controller_path) != 0))
+                       continue;
+               orom = find_imsm_capability(hba->type);
+               if (!orom) {
+                       if (verbose > 0)
+                               pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_IMSM_CAPABLE_DEVICE_UNDER_%s\n",hba->path);
+               }
+               else {
+                       print_imsm_capability_export(orom);
+                       result = 0;
                }
        }
 
-       free_sys_dev(&list);
        return result;
 }
+
 #endif
 
 static int match_home_imsm(struct supertype *st, char *homehost)
@@ -2317,7 +2413,7 @@ static int imsm_create_metadata_checkpoint_update(
        update_memory_size =
                sizeof(struct imsm_update_general_migration_checkpoint);
 
-       *u = calloc(1, update_memory_size);
+       *u = xcalloc(1, update_memory_size);
        if (*u == NULL) {
                dprintf("error: cannot get memory for "
                        "imsm_create_metadata_checkpoint_update update\n");
@@ -2488,7 +2584,6 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
        struct imsm_map *prev_map = get_imsm_map(dev, MAP_1);
        struct imsm_map *map_to_analyse = map;
        struct dl *dl;
-       char *devname;
        int map_disks = info->array.raid_disks;
 
        memset(info, 0, sizeof(*info));
@@ -2650,11 +2745,7 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
 
        info->array.major_version = -1;
        info->array.minor_version = -2;
-       devname = devnum2devname(st->container_dev);
-       *info->text_version = '\0';
-       if (devname)
-               sprintf(info->text_version, "/%s/%d", devname, info->container_member);
-       free(devname);
+       sprintf(info->text_version, "/%s/%d", st->container_devnm, info->container_member);
        info->safe_mode_delay = 4000;  /* 4 secs like the Matrix driver */
        uuid_from_super_imsm(st, info->uuid);
 
@@ -2845,23 +2936,11 @@ struct mdinfo *getinfo_super_disks_imsm(struct supertype *st)
        if (!super || !super->disks)
                return NULL;
        dl = super->disks;
-       mddev = malloc(sizeof(*mddev));
-       if (!mddev) {
-               pr_err("Failed to allocate memory.\n");
-               return NULL;
-       }
-       memset(mddev, 0, sizeof(*mddev));
+       mddev = xcalloc(1, sizeof(*mddev));
        while (dl) {
                struct mdinfo *tmp;
                disk = &dl->disk;
-               tmp = malloc(sizeof(*tmp));
-               if (!tmp) {
-                       pr_err("Failed to allocate memory.\n");
-                       if (mddev)
-                               sysfs_free(mddev);
-                       return NULL;
-               }
-               memset(tmp, 0, sizeof(*tmp));
+               tmp = xcalloc(1, sizeof(*tmp));
                if (mddev->devs)
                        tmp->next = mddev->devs;
                mddev->devs = tmp;
@@ -2967,7 +3046,8 @@ static size_t disks_to_mpb_size(int disks)
        return size;
 }
 
-static __u64 avail_size_imsm(struct supertype *st, __u64 devsize)
+static __u64 avail_size_imsm(struct supertype *st, __u64 devsize,
+                            unsigned long long data_offset)
 {
        if (devsize < (MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS))
                return 0;
@@ -3004,21 +3084,22 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst)
        struct intel_super *first = st->sb;
        struct intel_super *sec = tst->sb;
 
-        if (!first) {
-                st->sb = tst->sb;
-                tst->sb = NULL;
-                return 0;
-        }
+       if (!first) {
+               st->sb = tst->sb;
+               tst->sb = NULL;
+               return 0;
+       }
        /* in platform dependent environment test if the disks
         * use the same Intel hba
+        * If not on Intel hba at all, allow anything.
         */
        if (!check_env("IMSM_NO_PLATFORM")) {
-               if (!first->hba || !sec->hba ||
-                   (first->hba->type != sec->hba->type))  {
+               if (first->hba && sec->hba &&
+                   strcmp(first->hba->path, sec->hba->path) != 0)  {
                        fprintf(stderr,
                                "HBAs of devices does not match %s != %s\n",
-                               first->hba ? get_sys_dev_type(first->hba->type) : NULL,
-                               sec->hba ? get_sys_dev_type(sec->hba->type) : NULL);
+                               first->hba ? first->hba->path : NULL,
+                               sec->hba ? sec->hba->path : NULL);
                        return 3;
                }
        }
@@ -3063,14 +3144,8 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst)
                 * fails here we don't associate the spare
                 */
                for (i = 0; i < sec->anchor->num_raid_devs; i++) {
-                       dv = malloc(sizeof(*dv));
-                       if (!dv)
-                               break;
-                       dev = malloc(sizeof_imsm_dev(get_imsm_dev(sec, i), 1));
-                       if (!dev) {
-                               free(dv);
-                               break;
-                       }
+                       dv = xmalloc(sizeof(*dv));
+                       dev = xmalloc(sizeof_imsm_dev(get_imsm_dev(sec, i), 1));
                        dv->dev = dev;
                        dv->index = i;
                        dv->next = first->devlist;
@@ -3243,13 +3318,7 @@ load_imsm_disk(int fd, struct intel_super *super, char *devname, int keep_fd)
        if (rv != 0)
                return 2;
 
-       dl = calloc(1, sizeof(*dl));
-       if (!dl) {
-               if (devname)
-                       pr_err("failed to allocate disk buffer for %s\n",
-                              devname);
-               return 2;
-       }
+       dl = xcalloc(1, sizeof(*dl));
 
        fstat(fd, &stb);
        dl->major = major(stb.st_rdev);
@@ -3263,9 +3332,9 @@ load_imsm_disk(int fd, struct intel_super *super, char *devname, int keep_fd)
        dl->e = NULL;
        fd2devname(fd, name);
        if (devname)
-               dl->devname = strdup(devname);
+               dl->devname = xstrdup(devname);
        else
-               dl->devname = strdup(name);
+               dl->devname = xstrdup(name);
 
        /* look up this disk's index in the current anchor */
        disk = __serial_to_disk(dl->serial, super->anchor, &dl->index);
@@ -3392,18 +3461,12 @@ static int parse_raid_devices(struct intel_super *super)
                if (len_migr > len)
                        space_needed += len_migr - len;
 
-               dv = malloc(sizeof(*dv));
-               if (!dv)
-                       return 1;
+               dv = xmalloc(sizeof(*dv));
                if (max_len < len_migr)
                        max_len = len_migr;
                if (max_len > len_migr)
                        space_needed += max_len - len_migr;
-               dev_new = malloc(max_len);
-               if (!dev_new) {
-                       free(dv);
-                       return 1;
-               }
+               dev_new = xmalloc(max_len);
                imsm_copy_dev(dev_new, dev_iter);
                dv->dev = dev_new;
                dv->index = i;
@@ -3729,13 +3792,10 @@ static void free_super_imsm(struct supertype *st)
 
 static struct intel_super *alloc_super(void)
 {
-       struct intel_super *super = malloc(sizeof(*super));
+       struct intel_super *super = xcalloc(1, sizeof(*super));
 
-       if (super) {
-               memset(super, 0, sizeof(*super));
-               super->current_vol = -1;
-               super->create_offset = ~((unsigned long long) 0);
-       }
+       super->current_vol = -1;
+       super->create_offset = ~((unsigned long long) 0);
        return super;
 }
 
@@ -3781,14 +3841,12 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
                        }
 
                        fprintf(stderr, ").\n"
-                               "    Mixing devices attached to different controllers "
+                               "    Mixing devices attached to multiple controllers "
                                "is not allowed.\n");
                }
-               free_sys_dev(&hba_name);
                return 2;
        }
        super->orom = find_imsm_capability(hba_name->type);
-       free_sys_dev(&hba_name);
        if (!super->orom)
                return 3;
        return 0;
@@ -3811,13 +3869,11 @@ static int find_missing(struct intel_super *super)
                if (dl)
                        continue;
 
-               dl = malloc(sizeof(*dl));
-               if (!dl)
-                       return 1;
+               dl = xmalloc(sizeof(*dl));
                dl->major = 0;
                dl->minor = 0;
                dl->fd = -1;
-               dl->devname = strdup("missing");
+               dl->devname = xstrdup("missing");
                dl->index = i;
                serialcpy(dl->serial, disk->serial);
                dl->disk = *disk;
@@ -3932,9 +3988,7 @@ static int __prep_thunderdome(struct intel_super **table, int tbl_size,
                            is_failed(&idisk->disk))
                                idisk->disk.status &= ~(SPARE_DISK);
                } else {
-                       idisk = calloc(1, sizeof(*idisk));
-                       if (!idisk)
-                               return -1;
+                       idisk = xcalloc(1, sizeof(*idisk));
                        idisk->owner = IMSM_UNKNOWN_OWNER;
                        idisk->disk = *disk;
                        idisk->next = *disk_list;
@@ -4151,7 +4205,7 @@ imsm_thunderdome(struct intel_super **super_list, int len)
 
 static int
 get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int *max, int keep_fd);
-static int get_super_block(struct intel_super **super_list, int devnum, char *devname,
+static int get_super_block(struct intel_super **super_list, char *devnm, char *devname,
                           int major, int minor, int keep_fd);
 static int
 get_devlist_super_block(struct md_list *devlist, struct intel_super **super_list,
@@ -4226,9 +4280,9 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
 
        *sbp = super;
        if (fd >= 0)
-               st->container_dev = fd2devnum(fd);
+               strcpy(st->container_devnm, fd2devnm(fd));
        else
-               st->container_dev = NoMdDev;
+               st->container_devnm[0] = 0;
        if (err == 0 && st->ss == NULL) {
                st->ss = &super_imsm;
                st->minor_version = 0;
@@ -4271,7 +4325,7 @@ get_devlist_super_block(struct md_list *devlist, struct intel_super **super_list
                        int major = major(tmpdev->st_rdev);
                        int minor = minor(tmpdev->st_rdev);
                        err = get_super_block(super_list,
-                                             -1,
+                                             NULL,
                                              tmpdev->devname,
                                              major, minor,
                                              keep_fd);
@@ -4287,13 +4341,12 @@ get_devlist_super_block(struct md_list *devlist, struct intel_super **super_list
        return err;
 }
 
-static int get_super_block(struct intel_super **super_list, int devnum, char *devname,
+static int get_super_block(struct intel_super **super_list, char *devnm, char *devname,
                           int major, int minor, int keep_fd)
 {
        struct intel_super*s = NULL;
        char nm[32];
        int dfd = -1;
-       int rv;
        int err = 0;
        int retry;
 
@@ -4310,17 +4363,11 @@ static int get_super_block(struct intel_super **super_list, int devnum, char *de
                goto error;
        }
 
-       rv = find_intel_hba_capability(dfd, s, devname);
-       /* no orom/efi or non-intel hba of the disk */
-       if (rv != 0) {
-               err = 4;
-               goto error;
-       }
-
+       find_intel_hba_capability(dfd, s, devname);
        err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
 
        /* retry the load if we might have raced against mdmon */
-       if (err == 3 && (devnum != -1) && mdmon_running(devnum))
+       if (err == 3 && devnm && mdmon_running(devnm))
                for (retry = 0; retry < 3; retry++) {
                        usleep(3000);
                        err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
@@ -4347,11 +4394,11 @@ static int
 get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int *max, int keep_fd)
 {
        struct mdinfo *sra;
-       int devnum;
+       char *devnm;
        struct mdinfo *sd;
        int err = 0;
        int i = 0;
-       sra = sysfs_read(fd, 0, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE);
+       sra = sysfs_read(fd, NULL, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE);
        if (!sra)
                return 1;
 
@@ -4362,9 +4409,9 @@ get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int
                goto error;
        }
        /* load all mpbs */
-       devnum = fd2devnum(fd);
+       devnm = fd2devnm(fd);
        for (sd = sra->devs, i = 0; sd; sd = sd->next, i++) {
-               if (get_super_block(super_list, devnum, devname,
+               if (get_super_block(super_list, devnm, devname,
                                    sd->disk.major, sd->disk.minor, keep_fd) != 0) {
                        err = 7;
                        goto error;
@@ -4387,18 +4434,13 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
        struct intel_super *super;
        int rv;
 
-       if (test_partition(fd))
+       if (!st->ignore_hw_compat && test_partition(fd))
                /* IMSM not allowed on partitions */
                return 1;
 
        free_super_imsm(st);
 
        super = alloc_super();
-       if (!super) {
-               pr_err("malloc of %zu failed.\n",
-                      sizeof(*super));
-               return 1;
-       }
        /* Load hba and capabilities if they exist.
         * But do not preclude loading metadata in case capabilities or hba are
         * non-compliant and ignore_hw_compat is set.
@@ -4533,7 +4575,8 @@ static int check_name(struct intel_super *super, char *name, int quiet)
 
 static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                                  unsigned long long size, char *name,
-                                 char *homehost, int *uuid)
+                                 char *homehost, int *uuid,
+                                 long long data_offset)
 {
        /* We are creating a volume inside a pre-existing container.
         * so st->sb is already set.
@@ -4621,18 +4664,8 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
 
        if (!check_name(super, name, 0))
                return 0;
-       dv = malloc(sizeof(*dv));
-       if (!dv) {
-               pr_err("failed to allocate device list entry\n");
-               return 0;
-       }
-       dev = calloc(1, sizeof(*dev) + sizeof(__u32) * (info->raid_disks - 1));
-       if (!dev) {
-               free(dv);
-               pr_err("could not allocate raid device\n");
-               return 0;
-       }
-
+       dv = xmalloc(sizeof(*dv));
+       dev = xcalloc(1, sizeof(*dev) + sizeof(__u32) * (info->raid_disks - 1));
        strncpy((char *) dev->volume, name, MAX_RAID_SERIAL_LEN);
        array_blocks = calc_array_size(info->level, info->raid_disks,
                                               info->layout, info->chunk_size,
@@ -4654,7 +4687,8 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info));
        map->failed_disk_num = ~0;
        if (info->level > 0)
-               map->map_state = IMSM_T_STATE_UNINITIALIZED;
+               map->map_state = (info->state ? IMSM_T_STATE_NORMAL
+                                 : IMSM_T_STATE_UNINITIALIZED);
        else
                map->map_state = info->failed_disks ? IMSM_T_STATE_FAILED :
                                                      IMSM_T_STATE_NORMAL;
@@ -4701,7 +4735,8 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
 
 static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
                           unsigned long long size, char *name,
-                          char *homehost, int *uuid)
+                          char *homehost, int *uuid,
+                          unsigned long long data_offset)
 {
        /* This is primarily called by Create when creating a new array.
         * We will then get add_to_super called for each component, and then
@@ -4716,8 +4751,14 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
        size_t mpb_size;
        char *version;
 
+       if (data_offset != INVALID_SECTORS) {
+               pr_err("data-offset not supported by imsm\n");
+               return 0;
+       }
+
        if (st->sb)
-               return init_super_imsm_volume(st, info, size, name, homehost, uuid);
+               return init_super_imsm_volume(st, info, size, name, homehost, uuid,
+                                             data_offset);
 
        if (info)
                mpb_size = disks_to_mpb_size(info->nr_disks);
@@ -4911,7 +4952,8 @@ int mark_spare(struct dl *disk)
 }
 
 static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
-                            int fd, char *devname)
+                            int fd, char *devname,
+                            unsigned long long data_offset)
 {
        struct intel_super *super = st->sb;
        struct dl *dd;
@@ -4937,15 +4979,10 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
                return add_to_super_imsm_volume(st, dk, fd, devname);
 
        fstat(fd, &stb);
-       dd = malloc(sizeof(*dd));
-       if (!dd) {
-               pr_err("malloc failed %s:%d.\n", __func__, __LINE__);
-               return 1;
-       }
-       memset(dd, 0, sizeof(*dd));
+       dd = xcalloc(sizeof(*dd), 1);
        dd->major = major(stb.st_rdev);
        dd->minor = minor(stb.st_rdev);
-       dd->devname = devname ? strdup(devname) : NULL;
+       dd->devname = devname ? xstrdup(devname) : NULL;
        dd->fd = fd;
        dd->e = NULL;
        dd->action = DISK_ADD;
@@ -4997,12 +5034,7 @@ static int remove_from_super_imsm(struct supertype *st, mdu_disk_info_t *dk)
                       "(line %d).\n", __func__, __LINE__);
                return 1;
        }
-       dd = malloc(sizeof(*dd));
-       if (!dd) {
-               pr_err("malloc failed %s:%d.\n", __func__, __LINE__);
-               return 1;
-       }
-       memset(dd, 0, sizeof(*dd));
+       dd = xcalloc(1, sizeof(*dd));
        dd->major = dk->major;
        dd->minor = dk->minor;
        dd->fd = -1;
@@ -5183,13 +5215,7 @@ static int create_array(struct supertype *st, int dev_idx)
 
        len = sizeof(*u) - sizeof(*dev) + sizeof_imsm_dev(dev, 0) +
              sizeof(*inf) * map->num_members;
-       u = malloc(len);
-       if (!u) {
-               fprintf(stderr, "%s: failed to allocate update buffer\n",
-                       __func__);
-               return 1;
-       }
-
+       u = xmalloc(len);
        u->type = update_create_array;
        u->dev_idx = dev_idx;
        imsm_copy_dev(&u->dev, dev);
@@ -5215,13 +5241,7 @@ static int mgmt_disk(struct supertype *st)
                return 0;
 
        len = sizeof(*u);
-       u = malloc(len);
-       if (!u) {
-               fprintf(stderr, "%s: failed to allocate update buffer\n",
-                       __func__);
-               return 1;
-       }
-
+       u = xmalloc(len);
        u->type = update_add_remove_disk;
        append_metadata_update(st, u, len);
 
@@ -5254,7 +5274,7 @@ static int write_init_super_imsm(struct supertype *st)
        } else {
                struct dl *d;
                for (d = super->disks; d; d = d->next)
-                       Kill(d->devname, NULL, 0, 1, 1);
+                       Kill(d->devname, NULL, 0, -1, 1);
                return write_super_imsm(st, 1);
        }
 }
@@ -5283,7 +5303,9 @@ static int imsm_bbm_log_size(struct imsm_super *mpb)
 #ifndef MDASSEMBLE
 static int validate_geometry_imsm_container(struct supertype *st, int level,
                                            int layout, int raiddisks, int chunk,
-                                           unsigned long long size, char *dev,
+                                           unsigned long long size,
+                                           unsigned long long data_offset,
+                                           char *dev,
                                            unsigned long long *freesize,
                                            int verbose)
 {
@@ -5299,7 +5321,7 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
 
        fd = open(dev, O_RDONLY|O_EXCL, 0);
        if (fd < 0) {
-               if (verbose)
+               if (verbose > 0)
                        pr_err("imsm: Cannot open %s: %s\n",
                                dev, strerror(errno));
                return 0;
@@ -5313,14 +5335,7 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
         * note that there is no fd for the disks in array.
         */
        super = alloc_super();
-       if (!super) {
-               pr_err("malloc of %zu failed.\n",
-                      sizeof(*super));
-               close(fd);
-               return 0;
-       }
-
-       rv = find_intel_hba_capability(fd, super, verbose ? dev : NULL);
+       rv = find_intel_hba_capability(fd, super, verbose > 0 ? dev : NULL);
        if (rv != 0) {
 #if DEBUG
                char str[256];
@@ -5352,7 +5367,7 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
                }
        }
 
-       *freesize = avail_size_imsm(st, ldsize >> 9);
+       *freesize = avail_size_imsm(st, ldsize >> 9, data_offset);
        free_imsm(super);
 
        return 1;
@@ -5391,7 +5406,7 @@ static unsigned long long merge_extents(struct intel_super *super, int sum_exten
         * 'maxsize' given the "all disks in an array must share a common start
         * offset" constraint
         */
-       struct extent *e = calloc(sum_extents, sizeof(*e));
+       struct extent *e = xcalloc(sum_extents, sizeof(*e));
        struct dl *dl;
        int i, j;
        int start_extent;
@@ -5400,9 +5415,6 @@ static unsigned long long merge_extents(struct intel_super *super, int sum_exten
        unsigned long long maxsize;
        unsigned long reserve;
 
-       if (!e)
-               return 0;
-
        /* coalesce and sort all extents. also, check to see if we need to
         * reserve space between member arrays
         */
@@ -5509,17 +5521,15 @@ active_arrays_by_format(char *name, char* hba, struct md_list **devlist,
                        struct dev_member *dev = memb->members;
                        int fd = -1;
                        while(dev && (fd < 0)) {
-                               char *path = malloc(strlen(dev->name) + strlen("/dev/") + 1);
-                               if (path) {
-                                       num = sprintf(path, "%s%s", "/dev/", dev->name);
-                                       if (num > 0)
-                                               fd = open(path, O_RDONLY, 0);
-                                       if ((num <= 0) || (fd < 0)) {
-                                               pr_vrb(": Cannot open %s: %s\n",
-                                                      dev->name, strerror(errno));
-                                       }
-                                       free(path);
+                               char *path = xmalloc(strlen(dev->name) + strlen("/dev/") + 1);
+                               num = sprintf(path, "%s%s", "/dev/", dev->name);
+                               if (num > 0)
+                                       fd = open(path, O_RDONLY, 0);
+                               if ((num <= 0) || (fd < 0)) {
+                                       pr_vrb(": Cannot open %s: %s\n",
+                                              dev->name, strerror(errno));
                                }
+                               free(path);
                                dev = dev->next;
                        }
                        found = 0;
@@ -5534,20 +5544,13 @@ active_arrays_by_format(char *name, char* hba, struct md_list **devlist,
                                        }
                                }
                                if (*devlist && (found < dpa)) {
-                                 dv = calloc(1, sizeof(*dv));
-                                       if (dv == NULL)
-                                               pr_err("calloc failed\n");
-                                       else {
-                                               dv->devname = malloc(strlen(memb->dev) + strlen("/dev/") + 1);
-                                               if (dv->devname != NULL) {
-                                                       sprintf(dv->devname, "%s%s", "/dev/", memb->dev);
-                                                       dv->found = found;
-                                                       dv->used = 0;
-                                                       dv->next = *devlist;
-                                                       *devlist = dv;
-                                               } else
-                                                       free(dv);
-                                       }
+                                       dv = xcalloc(1, sizeof(*dv));
+                                       dv->devname = xmalloc(strlen(memb->dev) + strlen("/dev/") + 1);
+                                       sprintf(dv->devname, "%s%s", "/dev/", memb->dev);
+                                       dv->found = found;
+                                       dv->used = 0;
+                                       dv->next = *devlist;
+                                       *devlist = dv;
                                }
                        }
                        if (fd >= 0)
@@ -5567,17 +5570,8 @@ get_loop_devices(void)
        struct md_list *dv = NULL;
 
        for(i = 0; i < 12; i++) {
-               dv = calloc(1, sizeof(*dv));
-               if (dv == NULL) {
-                       pr_err("calloc failed\n");
-                       break;
-               }
-               dv->devname = malloc(40);
-               if (dv->devname == NULL) {
-                       pr_err("malloc failed\n");
-                       free(dv);
-                       break;
-               }
+               dv = xcalloc(1, sizeof(*dv));
+               dv->devname = xmalloc(40);
                sprintf(dv->devname, "/dev/loop%d", i);
                dv->next = devlist;
                devlist = dv;
@@ -5631,19 +5625,8 @@ get_devices(const char *hba_path)
                }
 
 
-               dv = calloc(1, sizeof(*dv));
-               if (dv == NULL) {
-                       pr_err("malloc failed\n");
-                       err = 1;
-                       break;
-               }
-               dv->devname = strdup(buf);
-               if (dv->devname == NULL) {
-                       pr_err("malloc failed\n");
-                       err = 1;
-                       free(dv);
-                       break;
-               }
+               dv = xcalloc(1, sizeof(*dv));
+               dv->devname = xstrdup(buf);
                dv->next = devlist;
                devlist = dv;
        }
@@ -5881,7 +5864,7 @@ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
                return 0;
        }
 
-        /* capabilities of OROM tested - copied from validate_geometry_imsm_volume */
+       /* 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" : "");
@@ -5921,7 +5904,9 @@ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
  */
 static int validate_geometry_imsm_volume(struct supertype *st, int level,
                                         int layout, int raiddisks, int *chunk,
-                                        unsigned long long size, char *dev,
+                                        unsigned long long size,
+                                        unsigned long long data_offset,
+                                        char *dev,
                                         unsigned long long *freesize,
                                         int verbose)
 {
@@ -6204,6 +6189,7 @@ static int reserve_space(struct supertype *st, int raiddisks,
 
 static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                                  int raiddisks, int *chunk, unsigned long long size,
+                                 unsigned long long data_offset,
                                  char *dev, unsigned long long *freesize,
                                  int verbose)
 {
@@ -6219,7 +6205,8 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                /* Must be a fresh device to add to a container */
                return validate_geometry_imsm_container(st, level, layout,
                                                        raiddisks,
-                                                       chunk?*chunk:0, size,
+                                                       chunk?*chunk:0,
+                                                       size, data_offset,
                                                        dev, freesize,
                                                        verbose);
        }
@@ -6262,6 +6249,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                /* creating in a given container */
                return validate_geometry_imsm_volume(st, level, layout,
                                                     raiddisks, chunk, size,
+                                                    data_offset,
                                                     dev, freesize, verbose);
        }
 
@@ -6289,7 +6277,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                                dev);
                return 0;
        }
-       sra = sysfs_read(cfd, 0, GET_VERSION);
+       sra = sysfs_read(cfd, NULL, GET_VERSION);
        if (sra && sra->array.major_version == -1 &&
            strcmp(sra->text_version, "imsm") == 0)
                is_member = 1;
@@ -6302,11 +6290,11 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
 
                if (load_super_imsm_all(st, cfd, (void **) &super, NULL, NULL, 1) == 0) {
                        st->sb = super;
-                       st->container_dev = fd2devnum(cfd);
+                       strcpy(st->container_devnm, fd2devnm(cfd));
                        close(cfd);
                        return validate_geometry_imsm_volume(st, level, layout,
                                                             raiddisks, chunk,
-                                                            size, dev,
+                                                            size, data_offset, dev,
                                                             freesize, 1)
                                ? 1 : -1;
                }
@@ -6360,7 +6348,7 @@ static int kill_subarray_imsm(struct supertype *st)
                if (i < current_vol)
                        continue;
                sprintf(subarray, "%u", i);
-               if (is_subarray_active(subarray, st->devname)) {
+               if (is_subarray_active(subarray, st->devnm)) {
                        pr_err("deleting subarray-%d would change the UUID of active subarray-%d, aborting\n",
                               current_vol, i);
 
@@ -6369,10 +6357,8 @@ static int kill_subarray_imsm(struct supertype *st)
        }
 
        if (st->update_tail) {
-               struct imsm_update_kill_array *u = malloc(sizeof(*u));
+               struct imsm_update_kill_array *u = xmalloc(sizeof(*u));
 
-               if (!u)
-                       return 2;
                u->type = update_kill_array;
                u->dev_idx = current_vol;
                append_metadata_update(st, u, sizeof(*u));
@@ -6418,7 +6404,7 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
                char *ep;
                int vol;
 
-               if (is_subarray_active(subarray, st->devname)) {
+               if (is_subarray_active(subarray, st->devnm)) {
                        pr_err("Unable to update name of active subarray\n");
                        return 2;
                }
@@ -6431,10 +6417,8 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
                        return 2;
 
                if (st->update_tail) {
-                       struct imsm_update_rename_array *u = malloc(sizeof(*u));
+                       struct imsm_update_rename_array *u = xmalloc(sizeof(*u));
 
-                       if (!u)
-                               return 2;
                        u->type = update_rename_array;
                        u->dev_idx = vol;
                        snprintf((char *) u->name, MAX_RAID_SERIAL_LEN, "%s", name);
@@ -6619,12 +6603,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                 * OROM/EFI
                 */
 
-               this = malloc(sizeof(*this));
-               if (!this) {
-                       pr_err("failed to allocate %zu bytes\n",
-                               sizeof(*this));
-                       break;
-               }
+               this = xmalloc(sizeof(*this));
 
                super->current_vol = i;
                getinfo_super_imsm_volume(st, this, NULL);
@@ -6688,21 +6667,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                        if (skip)
                                continue;
 
-                       info_d = calloc(1, sizeof(*info_d));
-                       if (!info_d) {
-                               pr_err("failed to allocate disk"
-                                      " for volume %.16s\n", dev->volume);
-                               info_d = this->devs;
-                               while (info_d) {
-                                       struct mdinfo *d = info_d->next;
-
-                                       free(info_d);
-                                       info_d = d;
-                               }
-                               free(this);
-                               this = rest;
-                               break;
-                       }
+                       info_d = xcalloc(1, sizeof(*info_d));
                        info_d->next = this->devs;
                        this->devs = info_d;
 
@@ -6974,6 +6939,12 @@ static void handle_missing(struct intel_super *super, struct imsm_dev *dev)
        if (!super->missing)
                return;
 
+       /* When orom adds replacement for missing disk it does
+        * not remove entry of missing disk, but just updates map with
+        * new added disk. So it is not enough just to test if there is
+        * any missing disk, we have to look if there are any failed disks
+        * in map to stop migration */
+
        dprintf("imsm: mark missing\n");
        /* end process for initialization and rebuild only
         */
@@ -6984,7 +6955,8 @@ static void handle_missing(struct intel_super *super, struct imsm_dev *dev)
                failed = imsm_count_failed(super, dev, MAP_0);
                map_state = imsm_check_degraded(super, dev, failed, MAP_0);
 
-               end_migration(dev, super, map_state);
+               if (failed)
+                       end_migration(dev, super, map_state);
        }
        for (dl = super->missing; dl; dl = dl->next)
                mark_missing(dev, &dl->disk, dl->index);
@@ -7699,10 +7671,7 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
                        continue;
  
                /* found a usable disk with enough space */
-               di = malloc(sizeof(*di));
-               if (!di)
-                       continue;
-               memset(di, 0, sizeof(*di));
+               di = xcalloc(1, sizeof(*di));
 
                /* dl->index will be -1 in the case we are activating a
                 * pristine spare.  imsm_process_update() will create a
@@ -7740,24 +7709,9 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
         * Create a metadata_update record to update the
         * disk_ord_tbl for the array
         */
-       mu = malloc(sizeof(*mu));
-       if (mu) {
-               mu->buf = malloc(sizeof(struct imsm_update_activate_spare) * num_spares);
-               if (mu->buf == NULL) {
-                       free(mu);
-                       mu = NULL;
-               }
-       }
-       if (!mu) {
-               while (rv) {
-                       struct mdinfo *n = rv->next;
-
-                       free(rv);
-                       rv = n;
-               }
-               return NULL;
-       }
-
+       mu = xmalloc(sizeof(*mu));
+       mu->buf = xcalloc(num_spares, 
+                         sizeof(struct imsm_update_activate_spare));
        mu->space = NULL;
        mu->space_list = NULL;
        mu->len = sizeof(struct imsm_update_activate_spare) * num_spares;
@@ -8687,15 +8641,10 @@ static void imsm_prepare_update(struct supertype *st,
                        int num_members = map->num_members;
                        void *space;
                        int size, i;
-                       int err = 0;
                        /* allocate memory for added disks */
                        for (i = 0; i < num_members; i++) {
                                size = sizeof(struct dl);
-                               space = malloc(size);
-                               if (!space) {
-                                       err++;
-                                       break;
-                               }
+                               space = xmalloc(size);
                                *tail = space;
                                tail = space;
                                *tail = NULL;
@@ -8703,24 +8652,11 @@ static void imsm_prepare_update(struct supertype *st,
                        /* allocate memory for new device */
                        size = sizeof_imsm_dev(super->devlist->dev, 0) +
                                (num_members * sizeof(__u32));
-                       space = malloc(size);
-                       if (!space)
-                               err++;
-                       else {
-                               *tail = space;
-                               tail = space;
-                               *tail = NULL;
-                       }
-                       if (!err) {
-                               len = disks_to_mpb_size(num_members * 2);
-                       } else {
-                               /* if allocation didn't success, free buffer */
-                               while (update->space_list) {
-                                       void **sp = update->space_list;
-                                       update->space_list = *sp;
-                                       free(sp);
-                               }
-                       }
+                       space = xmalloc(size);
+                       *tail = space;
+                       tail = space;
+                       *tail = NULL;
+                       len = disks_to_mpb_size(num_members * 2);
                }
 
                break;
@@ -8746,9 +8682,7 @@ static void imsm_prepare_update(struct supertype *st,
                        if (u->new_raid_disks > u->old_raid_disks)
                                size += sizeof(__u32)*2*
                                        (u->new_raid_disks - u->old_raid_disks);
-                       s = malloc(size);
-                       if (!s)
-                               break;
+                       s = xmalloc(size);
                        *space_tail = s;
                        space_tail = s;
                        *space_tail = NULL;
@@ -8782,9 +8716,7 @@ static void imsm_prepare_update(struct supertype *st,
                                if (u->new_raid_disks > u->old_raid_disks)
                                        size += sizeof(__u32)*2*
                                        (u->new_raid_disks - u->old_raid_disks);
-                               s = malloc(size);
-                               if (!s)
-                                       break;
+                               s = xmalloc(size);
                                *space_tail = s;
                                space_tail = s;
                                *space_tail = NULL;
@@ -8797,12 +8729,7 @@ static void imsm_prepare_update(struct supertype *st,
                /* add space for disk in update
                 */
                size = sizeof(struct dl);
-               s = malloc(size);
-               if (!s) {
-                       free(update->space_list);
-                       update->space_list = NULL;
-                       break;
-               }
+               s = xmalloc(size);
                *space_tail = s;
                space_tail = s;
                *space_tail = NULL;
@@ -8861,16 +8788,9 @@ static void imsm_prepare_update(struct supertype *st,
                inf = get_disk_info(u);
                len = sizeof_imsm_dev(dev, 1);
                /* allocate a new super->devlist entry */
-               dv = malloc(sizeof(*dv));
-               if (dv) {
-                       dv->dev = malloc(len);
-                       if (dv->dev)
-                               update->space = dv;
-                       else {
-                               free(dv);
-                               update->space = NULL;
-                       }
-               }
+               dv = xmalloc(sizeof(*dv));
+               dv->dev = xmalloc(len);
+               update->space = dv;
 
                /* count how many spares will be converted to members */
                for (i = 0; i < map->num_members; i++) {
@@ -9202,16 +9122,12 @@ int save_backup_imsm(struct supertype *st,
        unsigned long long start;
        int data_disks = imsm_num_data_members(dev, MAP_0);
 
-       targets = malloc(new_disks * sizeof(int));
-       if (!targets)
-               goto abort;
+       targets = xmalloc(new_disks * sizeof(int));
 
        for (i = 0; i < new_disks; i++)
                targets[i] = -1;
 
-       target_offsets = malloc(new_disks * sizeof(unsigned long long));
-       if (!target_offsets)
-               goto abort;
+       target_offsets = xcalloc(new_disks, sizeof(unsigned long long));
 
        start = info->reshape_progress * 512;
        for (i = 0; i < new_disks; i++) {
@@ -9373,9 +9289,7 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
        unit_len = __le32_to_cpu(migr_rec->dest_depth_per_unit) * 512;
        if (posix_memalign((void **)&buf, 512, unit_len) != 0)
                goto abort;
-       targets = malloc(new_disks * sizeof(int));
-       if (!targets)
-               goto abort;
+       targets = xcalloc(new_disks, sizeof(int));
 
        if (open_backup_targets(info, new_disks, targets, super, id->dev)) {
                pr_err("Cannot open some devices belonging to array.\n");
@@ -9468,25 +9382,24 @@ static const char *imsm_get_disk_controller_domain(const char *path)
                dprintf("path: %s hba: %s attached: %s\n",
                        path, (hba) ? hba->path : "NULL", drv);
                free(path);
-               if (hba)
-                       free_sys_dev(&hba);
        }
        return drv;
 }
 
-static int imsm_find_array_minor_by_subdev(int subdev, int container, int *minor)
+static char *imsm_find_array_devnm_by_subdev(int subdev, char *container)
 {
+       static char devnm[32];
        char subdev_name[20];
        struct mdstat_ent *mdstat;
 
        sprintf(subdev_name, "%d", subdev);
        mdstat = mdstat_by_subdev(subdev_name, container);
        if (!mdstat)
-               return -1;
+               return NULL;
 
-       *minor = mdstat->devnum;
+       strcpy(devnm, mdstat->devnm);
        free_mdstat(mdstat);
-       return 0;
+       return devnm;
 }
 
 static int imsm_reshape_is_allowed_on_container(struct supertype *st,
@@ -9503,10 +9416,9 @@ static int imsm_reshape_is_allowed_on_container(struct supertype *st,
        int devices_that_can_grow = 0;
 
        dprintf("imsm: imsm_reshape_is_allowed_on_container(ENTER): "
-               "st->devnum = (%i)\n",
-               st->devnum);
+               "st->devnm = (%s)\n", st->devnm);
 
-       if (geo->size != -1 ||
+       if (geo->size > 0 ||
            geo->level != UnSet ||
            geo->layout != UnSet ||
            geo->chunksize != 0 ||
@@ -9524,8 +9436,7 @@ static int imsm_reshape_is_allowed_on_container(struct supertype *st,
 
        info = container_content_imsm(st, NULL);
        for (member = info; member; member = member->next) {
-               int result;
-               int minor;
+               char *result;
 
                dprintf("imsm: checking device_num: %i\n",
                        member->container_member);
@@ -9582,10 +9493,9 @@ static int imsm_reshape_is_allowed_on_container(struct supertype *st,
                 * so they need to be assembled.  We have already
                 * checked that no recovery etc is happening.
                 */
-               result = imsm_find_array_minor_by_subdev(member->container_member,
-                                                        st->container_dev,
-                                                        &minor);
-               if (result < 0) {
+               result = imsm_find_array_devnm_by_subdev(member->container_member,
+                                                        st->container_devnm);
+               if (result == NULL) {
                        dprintf("imsm: cannot find array\n");
                        break;
                }
@@ -9647,12 +9557,7 @@ static int imsm_create_metadata_update_for_reshape(
        /* now add space for spare disks that we need to add. */
        update_memory_size += sizeof(u->new_disks[0]) * (delta_disks - 1);
 
-       u = calloc(1, update_memory_size);
-       if (u == NULL) {
-               dprintf("error: "
-                       "cannot get memory for imsm_update_reshape update\n");
-               return 0;
-       }
+       u = xcalloc(1, update_memory_size);
        u->type = update_reshape_container_disks;
        u->old_raid_disks = old_raid_disks;
        u->new_raid_disks = geo->raid_disks;
@@ -9727,12 +9632,7 @@ static int imsm_create_metadata_update_for_size_change(
        /* size of all update data without anchor */
        update_memory_size = sizeof(struct imsm_update_size_change);
 
-       u = calloc(1, update_memory_size);
-       if (u == NULL) {
-               dprintf("error: cannot get memory for "
-                       "imsm_create_metadata_update_for_size_change\n");
-               return 0;
-       }
+       u = xcalloc(1, update_memory_size);
        u->type = update_size_change;
        u->subdev = super->current_vol;
        u->new_size = geo->size;
@@ -9765,12 +9665,7 @@ static int imsm_create_metadata_update_for_migration(
        /* size of all update data without anchor */
        update_memory_size = sizeof(struct imsm_update_reshape_migration);
 
-       u = calloc(1, update_memory_size);
-       if (u == NULL) {
-               dprintf("error: cannot get memory for "
-                       "imsm_create_metadata_update_for_migration\n");
-               return 0;
-       }
+       u = xcalloc(1, update_memory_size);
        u->type = update_reshape_migration;
        u->subdev = super->current_vol;
        u->new_level = geo->level;
@@ -9861,9 +9756,9 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
        int data_disks;
        struct imsm_dev *dev;
        struct intel_super *super;
-       long long current_size;
+       unsigned long long current_size;
        unsigned long long free_size;
-       long long max_size;
+       unsigned long long max_size;
        int rv;
 
        getinfo_super_imsm_volume(st, &info, NULL);
@@ -9951,16 +9846,23 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
         */
        current_size = info.custom_array_size / data_disks;
 
-       if (geo->size > 0) {
+       if ((geo->size > 0) && (geo->size != MAX_SIZE)) {
                /* align component size
                 */
                geo->size = imsm_component_size_aligment_check(
                                    get_imsm_raid_level(dev->vol.map),
                                    chunk * 1024,
                                    geo->size * 2);
+               if (geo->size == 0) {
+                       pr_err("Error. Size expansion is " \
+                                  "supported only (current size is %llu, " \
+                                  "requested size /rounded/ is 0).\n",
+                                  current_size);
+                       goto analyse_change_exit;
+               }
        }
 
-       if ((current_size != geo->size) && (geo->size >= 0)) {
+       if ((current_size != geo->size) && (geo->size > 0)) {
                if (change != -1) {
                        pr_err("Error. Size change should be the only "
                                "one at a time.\n");
@@ -9969,8 +9871,8 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                }
                if ((super->current_vol + 1) != super->anchor->num_raid_devs) {
                        pr_err("Error. The last volume in container "
-                              "can be expanded only (%i/%i).\n",
-                              super->current_vol, st->devnum);
+                              "can be expanded only (%i/%s).\n",
+                              super->current_vol, st->devnm);
                        goto analyse_change_exit;
                }
                /* check the maximum available size
@@ -9990,7 +9892,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                                        chunk * 1024,
                                        max_size);
                }
-               if (geo->size == 0) {
+               if (geo->size == MAX_SIZE) {
                        /* requested size change to the maximum available size
                         */
                        if (max_size == 0) {
@@ -10037,7 +9939,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                                    imsm_layout,
                                    geo->raid_disks + devNumChange,
                                    &chunk,
-                                   geo->size,
+                                   geo->size, INVALID_SECTORS,
                                    0, 0, 1))
                change = -1;
 
@@ -10069,9 +9971,7 @@ int imsm_takeover(struct supertype *st, struct geo_params *geo)
        struct intel_super *super = st->sb;
        struct imsm_update_takeover *u;
 
-       u = malloc(sizeof(struct imsm_update_takeover));
-       if (u == NULL)
-               return 1;
+       u = xmalloc(sizeof(struct imsm_update_takeover));
 
        u->type = update_takeover;
        u->subarray = super->current_vol;
@@ -10097,7 +9997,8 @@ int imsm_takeover(struct supertype *st, struct geo_params *geo)
        return 0;
 }
 
-static int imsm_reshape_super(struct supertype *st, long long size, int level,
+static int imsm_reshape_super(struct supertype *st, unsigned long long size,
+                             int level,
                              int layout, int chunksize, int raid_disks,
                              int delta_disks, char *backup, char *dev,
                              int direction, int verbose)
@@ -10110,7 +10011,7 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
        memset(&geo, 0, sizeof(struct geo_params));
 
        geo.dev_name = dev;
-       geo.dev_id = st->devnum;
+       strcpy(geo.devnm, st->devnm);
        geo.size = size;
        geo.level = level;
        geo.layout = layout;
@@ -10125,7 +10026,7 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
        if (experimental() == 0)
                return ret_val;
 
-       if (st->container_dev == st->devnum) {
+       if (strcmp(st->container_devnm, st->devnm) == 0) {
                /* On container level we can only increase number of devices. */
                dprintf("imsm: info: Container operation\n");
                int old_raid_disks = 0;
@@ -10164,19 +10065,20 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
                 */
                struct intel_super *super = st->sb;
                struct intel_dev *dev = super->devlist;
-               int change, devnum;
+               int change;
                dprintf("imsm: info: Volume operation\n");
                /* find requested device */
                while (dev) {
-                       if (imsm_find_array_minor_by_subdev(
-                                   dev->index, st->container_dev, &devnum) == 0
-                           && devnum == geo.dev_id)
+                       char *devnm = 
+                               imsm_find_array_devnm_by_subdev(
+                                       dev->index, st->container_devnm);
+                       if (devnm && strcmp(devnm, geo.devnm) == 0)
                                break;
                        dev = dev->next;
                }
                if (dev == NULL) {
-                       pr_err("Cannot find %s (%i) subarray\n",
-                               geo.dev_name, geo.dev_id);
+                       pr_err("Cannot find %s (%s) subarray\n",
+                               geo.dev_name, geo.devnm);
                        goto exit_imsm_reshape_super;
                }
                super->current_vol = dev->index;
@@ -10605,6 +10507,7 @@ struct superswitch super_imsm = {
        .add_to_super   = add_to_super_imsm,
        .remove_from_super = remove_from_super_imsm,
        .detail_platform = detail_platform_imsm,
+       .export_detail_platform = export_detail_platform_imsm,
        .kill_subarray = kill_subarray_imsm,
        .update_subarray = update_subarray_imsm,
        .load_container = load_container_imsm,
@@ -10613,6 +10516,7 @@ struct superswitch super_imsm = {
        .reshape_super  = imsm_reshape_super,
        .manage_reshape = imsm_manage_reshape,
        .recover_backup = recover_backup_imsm,
+       .copy_metadata = copy_metadata_imsm,
 #endif
        .match_home     = match_home_imsm,
        .uuid_from_super= uuid_from_super_imsm,