]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
Consistently print program Name and __func__ in debug messages.
[thirdparty/mdadm.git] / super-intel.c
index 8f075e0656eca5a46a995db345684d9da2c4c362..b400fded45c393ccd7093121c28bc7b1a5fbca27 100644 (file)
 #define IMSM_MAX_DEVICES 255
 struct imsm_disk {
        __u8 serial[MAX_RAID_SERIAL_LEN];/* 0xD8 - 0xE7 ascii serial number */
-       __u32 total_blocks;              /* 0xE8 - 0xEB total blocks */
+       __u32 total_blocks_lo;           /* 0xE8 - 0xEB total blocks lo */
        __u32 scsi_id;                   /* 0xEC - 0xEF scsi ID */
 #define SPARE_DISK      __cpu_to_le32(0x01)  /* Spare */
 #define CONFIGURED_DISK __cpu_to_le32(0x02)  /* Member of some RaidDev */
 #define FAILED_DISK     __cpu_to_le32(0x04)  /* Permanent failure */
        __u32 status;                    /* 0xF0 - 0xF3 */
-       __u32 owner_cfg_num; /* which config 0,1,2... owns this disk */ 
-#define        IMSM_DISK_FILLERS       4
-       __u32 filler[IMSM_DISK_FILLERS]; /* 0xF4 - 0x107 MPB_DISK_FILLERS for future expansion */
+       __u32 owner_cfg_num; /* which config 0,1,2... owns this disk */
+       __u32 total_blocks_hi;           /* 0xF4 - 0xF5 total blocks hi */
+#define        IMSM_DISK_FILLERS       3
+       __u32 filler[IMSM_DISK_FILLERS]; /* 0xF5 - 0x107 MPB_DISK_FILLERS for future expansion */
 };
 
 /* map selector for map managment
  */
-#define MAP_0          2
-#define MAP_1          4
+#define MAP_0          0
+#define MAP_1          1
+#define MAP_X          -1
 
 /* RAID map configuration infos. */
 struct imsm_map {
-       __u32 pba_of_lba0;      /* start address of partition */
-       __u32 blocks_per_member;/* blocks per member */
-       __u32 num_data_stripes; /* number of data stripes */
+       __u32 pba_of_lba0_lo;   /* start address of partition */
+       __u32 blocks_per_member_lo;/* blocks per member */
+       __u32 num_data_stripes_lo;      /* number of data stripes */
        __u16 blocks_per_strip;
        __u8  map_state;        /* Normal, Uninitialized, Degraded, Failed */
 #define IMSM_T_STATE_NORMAL 0
@@ -130,7 +132,10 @@ struct imsm_map {
        __u8  num_domains;      /* number of parity domains */
        __u8  failed_disk_num;  /* valid only when state is degraded */
        __u8  ddf;
-       __u32 filler[7];        /* expansion area */
+       __u32 pba_of_lba0_hi;
+       __u32 blocks_per_member_hi;
+       __u32 num_data_stripes_hi;
+       __u32 filler[4];        /* expansion area */
 #define IMSM_ORD_REBUILD (1 << 24)
        __u32 disk_ord_tbl[1];  /* disk_ord_tbl[num_members],
                                 * top byte contains some flags
@@ -230,7 +235,6 @@ struct bbm_log {
        struct bbm_log_entry mapped_block_entries[BBM_LOG_MAX_ENTRIES];
 } __attribute__ ((__packed__));
 
-
 #ifndef MDASSEMBLE
 static char *map_state_str[] = { "normal", "uninitialized", "degraded", "failed" };
 #endif
@@ -239,6 +243,11 @@ static char *map_state_str[] = { "normal", "uninitialized", "degraded", "failed"
 
 #define GEN_MIGR_AREA_SIZE 2048 /* General Migration Copy Area size in blocks */
 
+#define MIGR_REC_BUF_SIZE 512 /* size of migr_record i/o buffer */
+#define MIGR_REC_POSITION 512 /* migr_record position offset on disk,
+                              * MIGR_REC_BUF_SIZE <= MIGR_REC_POSITION
+                              */
+
 #define UNIT_SRC_NORMAL     0   /* Source data for curr_migr_unit must
                                 *  be recovered using srcMap */
 #define UNIT_SRC_IN_CP_AREA 1   /* Source data for curr_migr_unit has
@@ -270,6 +279,22 @@ struct migr_record {
                                     * (for recovered migrations) */
 } __attribute__ ((__packed__));
 
+struct md_list {
+       /* usage marker:
+        *  1: load metadata
+        *  2: metadata does not match
+        *  4: already checked
+        */
+       int   used;
+       char  *devname;
+       int   found;
+       int   container;
+       dev_t st_rdev;
+       struct md_list *next;
+};
+
+#define pr_vrb(fmt, arg...) (void) (verbose && pr_err(fmt, ##arg))
+
 static __u8 migr_type(struct imsm_dev *dev)
 {
        if (dev->vol.migr_type == MIGR_VERIFY &&
@@ -295,7 +320,7 @@ static void set_migr_type(struct imsm_dev *dev, __u8 migr_type)
 
 static unsigned int sector_count(__u32 bytes)
 {
-       return ((bytes + (512-1)) & (~(512-1))) / 512;
+       return ROUND_UP(bytes, 512) / 512;
 }
 
 static unsigned int mpb_sectors(struct imsm_super *mpb)
@@ -330,12 +355,15 @@ struct intel_super {
                void *migr_rec_buf; /* buffer for I/O operations */
                struct migr_record *migr_rec; /* migration record */
        };
+       int clean_migration_record_by_mdmon; /* when reshape is switched to next
+               array, it indicates that mdmon is allowed to clean migration
+               record */
        size_t len; /* size of the 'buf' allocation */
        void *next_buf; /* for realloc'ing buf from the manager */
        size_t next_len;
        int updates_pending; /* count of pending updates for mdmon */
        int current_vol; /* index of raid device undergoing creation */
-       __u32 create_offset; /* common start for 'current_vol' */
+       unsigned long long create_offset; /* common start for 'current_vol' */
        __u32 random; /* random data for seeding new family numbers */
        struct intel_dev *devlist;
        struct dl {
@@ -375,6 +403,7 @@ struct extent {
 enum imsm_reshape_type {
        CH_TAKEOVER,
        CH_MIGRATION,
+       CH_ARRAY_SIZE,
 };
 
 /* definition of messages passed to imsm_process_update */
@@ -388,6 +417,7 @@ enum imsm_update_type {
        update_reshape_migration,
        update_takeover,
        update_general_migration_checkpoint,
+       update_size_change,
 };
 
 struct imsm_update_activate_spare {
@@ -399,9 +429,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;
@@ -440,6 +470,12 @@ struct imsm_update_reshape_migration {
        int new_disks[1]; /* new_raid_disks - old_raid_disks makedev number */
 };
 
+struct imsm_update_size_change {
+       enum imsm_update_type type;
+       int subdev;
+       long long new_size;
+};
+
 struct imsm_update_general_migration_checkpoint {
        enum imsm_update_type type;
        __u32 curr_migr_unit;
@@ -470,11 +506,11 @@ struct imsm_update_add_remove_disk {
        enum imsm_update_type type;
 };
 
-
 static const char *_sys_dev_type[] = {
        [SYS_DEV_UNKNOWN] = "Unknown",
        [SYS_DEV_SAS] = "SAS",
-       [SYS_DEV_SATA] = "SATA"
+       [SYS_DEV_SATA] = "SATA",
+       [SYS_DEV_NVME] = "NVMe"
 };
 
 const char *get_sys_dev_type(enum sys_dev_type type)
@@ -487,14 +523,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;
 }
 
@@ -524,11 +560,17 @@ static int attach_hba_to_super(struct intel_super *super, struct sys_dev *device
 
        hba = super->hba;
        /* Intel metadata allows for all disks attached to the same type HBA.
-        * Do not sypport odf HBA types mixing
+        * Do not support HBA types mixing
         */
        if (device->type != hba->type)
                return 2;
 
+       /* Multiple same type HBAs can be used if they share the same OROM */
+       const struct imsm_orom *device_orom = get_orom_by_device_id(device->dev_id);
+
+       if (device_orom != super->orom)
+               return 2;
+
        while (hba->next)
                hba = hba->next;
 
@@ -538,7 +580,7 @@ static int attach_hba_to_super(struct intel_super *super, struct sys_dev *device
 
 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)
@@ -549,32 +591,19 @@ 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;
 }
 
-
 static int find_intel_hba_capability(int fd, struct intel_super *super,
                                     char *devname);
 
@@ -587,11 +616,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;
@@ -650,12 +675,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)
@@ -667,9 +692,9 @@ struct imsm_map *get_imsm_map(struct imsm_dev *dev, int second_map)
 {
        /* A device can have 2 maps if it is in the middle of a migration.
         * If second_map is:
-        *    MAP_0 or 0   - we return the first map
-        *    MAP_1 or 1   - we return the second map if it exists, else NULL
-        *   -1   - we return the second map if it exists, else the first
+        *    MAP_0 - we return the first map
+        *    MAP_1 - we return the second map if it exists, else NULL
+        *    MAP_X - we return the second map if it exists, else the first
         */
        struct imsm_map *map = &dev->vol.map[0];
        struct imsm_map *map2 = NULL;
@@ -679,13 +704,11 @@ struct imsm_map *get_imsm_map(struct imsm_dev *dev, int second_map)
 
        switch (second_map) {
        case MAP_0:
-       case 0:
                break;
        case MAP_1:
-       case 1:
                map = map2;
                break;
-       case -1:
+       case MAP_X:
                if (map2)
                        map = map2;
                break;
@@ -702,13 +725,13 @@ struct imsm_map *get_imsm_map(struct imsm_dev *dev, int second_map)
 static size_t sizeof_imsm_dev(struct imsm_dev *dev, int migr_state)
 {
        size_t size = sizeof(*dev) - sizeof(struct imsm_map) +
-                     sizeof_imsm_map(get_imsm_map(dev, 0));
+                     sizeof_imsm_map(get_imsm_map(dev, MAP_0));
 
        /* migrating means an additional map */
        if (dev->vol.migr_state)
-               size += sizeof_imsm_map(get_imsm_map(dev, 1));
+               size += sizeof_imsm_map(get_imsm_map(dev, MAP_1));
        else if (migr_state)
-               size += sizeof_imsm_map(get_imsm_map(dev, 0));
+               size += sizeof_imsm_map(get_imsm_map(dev, MAP_0));
 
        return size;
 }
@@ -762,9 +785,9 @@ static struct imsm_dev *get_imsm_dev(struct intel_super *super, __u8 index)
 
 /*
  * for second_map:
- *  == 0 get first map
- *  == 1 get second map
- *  == -1 than get map according to the current migr_state
+ *  == MAP_0 get first map
+ *  == MAP_1 get second map
+ *  == MAP_X than get map according to the current migr_state
  */
 static __u32 get_imsm_ord_tbl_ent(struct imsm_dev *dev,
                                  int slot,
@@ -835,7 +858,7 @@ static int count_memberships(struct dl *dl, struct intel_super *super)
 
        for (i = 0; i < super->anchor->num_raid_devs; i++) {
                struct imsm_dev *dev = get_imsm_dev(super, i);
-               struct imsm_map *map = get_imsm_map(dev, 0);
+               struct imsm_map *map = get_imsm_map(dev, MAP_0);
 
                if (get_imsm_disk_slot(map, dl->index) >= 0)
                        memberships++;
@@ -846,6 +869,71 @@ static int count_memberships(struct dl *dl, struct intel_super *super)
 
 static __u32 imsm_min_reserved_sectors(struct intel_super *super);
 
+static int split_ull(unsigned long long n, __u32 *lo, __u32 *hi)
+{
+       if (lo == 0 || hi == 0)
+               return 1;
+       *lo = __le32_to_cpu((unsigned)n);
+       *hi = __le32_to_cpu((unsigned)(n >> 32));
+       return 0;
+}
+
+static unsigned long long join_u32(__u32 lo, __u32 hi)
+{
+       return (unsigned long long)__le32_to_cpu(lo) |
+              (((unsigned long long)__le32_to_cpu(hi)) << 32);
+}
+
+static unsigned long long total_blocks(struct imsm_disk *disk)
+{
+       if (disk == NULL)
+               return 0;
+       return join_u32(disk->total_blocks_lo, disk->total_blocks_hi);
+}
+
+static unsigned long long pba_of_lba0(struct imsm_map *map)
+{
+       if (map == NULL)
+               return 0;
+       return join_u32(map->pba_of_lba0_lo, map->pba_of_lba0_hi);
+}
+
+static unsigned long long blocks_per_member(struct imsm_map *map)
+{
+       if (map == NULL)
+               return 0;
+       return join_u32(map->blocks_per_member_lo, map->blocks_per_member_hi);
+}
+
+#ifndef MDASSEMBLE
+static unsigned long long num_data_stripes(struct imsm_map *map)
+{
+       if (map == NULL)
+               return 0;
+       return join_u32(map->num_data_stripes_lo, map->num_data_stripes_hi);
+}
+
+static void set_total_blocks(struct imsm_disk *disk, unsigned long long n)
+{
+       split_ull(n, &disk->total_blocks_lo, &disk->total_blocks_hi);
+}
+#endif
+
+static void set_pba_of_lba0(struct imsm_map *map, unsigned long long n)
+{
+       split_ull(n, &map->pba_of_lba0_lo, &map->pba_of_lba0_hi);
+}
+
+static void set_blocks_per_member(struct imsm_map *map, unsigned long long n)
+{
+       split_ull(n, &map->blocks_per_member_lo, &map->blocks_per_member_hi);
+}
+
+static void set_num_data_stripes(struct imsm_map *map, unsigned long long n)
+{
+       split_ull(n, &map->num_data_stripes_lo, &map->num_data_stripes_hi);
+}
+
 static struct extent *get_extents(struct intel_super *super, struct dl *dl)
 {
        /* find a list of used extents on the given physical device */
@@ -863,34 +951,31 @@ 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++) {
                struct imsm_dev *dev = get_imsm_dev(super, i);
-               struct imsm_map *map = get_imsm_map(dev, 0);
+               struct imsm_map *map = get_imsm_map(dev, MAP_0);
 
                if (get_imsm_disk_slot(map, dl->index) >= 0) {
-                       e->start = __le32_to_cpu(map->pba_of_lba0);
-                       e->size = __le32_to_cpu(map->blocks_per_member);
+                       e->start = pba_of_lba0(map);
+                       e->size = blocks_per_member(map);
                        e++;
                }
        }
        qsort(rv, memberships, sizeof(*rv), cmp_extent);
 
-       /* determine the start of the metadata 
+       /* determine the start of the metadata
         * when no raid devices are defined use the default
         * ...otherwise allow the metadata to truncate the value
         * as is the case with older versions of imsm
         */
        if (memberships) {
                struct extent *last = &rv[memberships - 1];
-               __u32 remainder;
+               unsigned long long remainder;
 
-               remainder = __le32_to_cpu(dl->disk.total_blocks) - 
-                           (last->start + last->size);
+               remainder = total_blocks(&dl->disk) - (last->start + last->size);
                /* round down to 1k block to satisfy precision of the kernel
                 * 'size' interface
                 */
@@ -901,7 +986,7 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl)
                if (reservation > remainder)
                        reservation = remainder;
        }
-       e->start = __le32_to_cpu(dl->disk.total_blocks) - reservation;
+       e->start = total_blocks(&dl->disk) - reservation;
        e->size = 0;
        return rv;
 }
@@ -930,7 +1015,7 @@ static __u32 imsm_reserved_sectors(struct intel_super *super, struct dl *dl)
        for (i = 0; e[i].size; i++)
                continue;
 
-       rv = __le32_to_cpu(dl->disk.total_blocks) - e[i].start;
+       rv = total_blocks(&dl->disk) - e[i].start;
 
        free(e);
 
@@ -960,7 +1045,8 @@ static __u32 imsm_min_reserved_sectors(struct intel_super *super)
 {
        struct extent *e;
        int i;
-       __u32 min_active, remainder;
+       unsigned long long min_active;
+       __u32 remainder;
        __u32 rv = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
        struct dl *dl, *dl_min = NULL;
 
@@ -971,9 +1057,10 @@ static __u32 imsm_min_reserved_sectors(struct intel_super *super)
        for (dl = super->disks; dl; dl = dl->next) {
                if (dl->index < 0)
                        continue;
-               if (dl->disk.total_blocks < min_active || min_active == 0) {
+               unsigned long long blocks = total_blocks(&dl->disk);
+               if (blocks < min_active || min_active == 0) {
                        dl_min = dl;
-                       min_active = dl->disk.total_blocks;
+                       min_active = blocks;
                }
        }
        if (!dl_min)
@@ -1043,8 +1130,8 @@ static void print_imsm_dev(struct intel_super *super,
 {
        __u64 sz;
        int slot, i;
-       struct imsm_map *map = get_imsm_map(dev, 0);
-       struct imsm_map *map2 = get_imsm_map(dev, 1);
+       struct imsm_map *map = get_imsm_map(dev, MAP_0);
+       struct imsm_map *map2 = get_imsm_map(dev, MAP_1);
        __u32 ord;
 
        printf("\n");
@@ -1060,14 +1147,14 @@ static void print_imsm_dev(struct intel_super *super,
        printf("\n");
        printf("          Slots : [");
        for (i = 0; i < map->num_members; i++) {
-               ord = get_imsm_ord_tbl_ent(dev, i, 0);
+               ord = get_imsm_ord_tbl_ent(dev, i, MAP_0);
                printf("%s", ord & IMSM_ORD_REBUILD ? "_" : "U");
        }
        printf("]");
        if (map2) {
                printf(" <-- [");
                for (i = 0; i < map2->num_members; i++) {
-                       ord = get_imsm_ord_tbl_ent(dev, i, 1);
+                       ord = get_imsm_ord_tbl_ent(dev, i, MAP_1);
                        printf("%s", ord & IMSM_ORD_REBUILD ? "_" : "U");
                }
                printf("]");
@@ -1081,7 +1168,7 @@ static void print_imsm_dev(struct intel_super *super,
        printf("\n");
        slot = get_imsm_disk_slot(map, disk_idx);
        if (slot >= 0) {
-               ord = get_imsm_ord_tbl_ent(dev, slot, -1);
+               ord = get_imsm_ord_tbl_ent(dev, slot, MAP_X);
                printf("      This Slot : %d%s\n", slot,
                       ord & IMSM_ORD_REBUILD ? " (out-of-sync)" : "");
        } else
@@ -1091,13 +1178,13 @@ static void print_imsm_dev(struct intel_super *super,
        sz += __le32_to_cpu(dev->size_low);
        printf("     Array Size : %llu%s\n", (unsigned long long)sz,
               human_size(sz * 512));
-       sz = __le32_to_cpu(map->blocks_per_member);
+       sz = blocks_per_member(map);
        printf("   Per Dev Size : %llu%s\n", (unsigned long long)sz,
               human_size(sz * 512));
-       printf("  Sector Offset : %u\n",
-               __le32_to_cpu(map->pba_of_lba0));
-       printf("    Num Stripes : %u\n",
-               __le32_to_cpu(map->num_data_stripes));
+       printf("  Sector Offset : %llu\n",
+               pba_of_lba0(map));
+       printf("    Num Stripes : %llu\n",
+               num_data_stripes(map));
        printf("     Chunk Size : %u KiB",
                __le16_to_cpu(map->blocks_per_strip) / 2);
        if (map2)
@@ -1125,12 +1212,12 @@ static void print_imsm_dev(struct intel_super *super,
                printf("idle\n");
        printf("      Map State : %s", map_state_str[map->map_state]);
        if (dev->vol.migr_state) {
-               struct imsm_map *map = get_imsm_map(dev, 1);
+               struct imsm_map *map = get_imsm_map(dev, MAP_1);
 
                printf(" <-- %s", map_state_str[map->map_state]);
                printf("\n     Checkpoint : %u ",
                           __le32_to_cpu(dev->vol.curr_migr_unit));
-               if ((is_gen_migration(dev)) && (super->disks->index > 1))
+               if ((is_gen_migration(dev)) && ((slot > 1) || (slot < 0)))
                        printf("(N/A)");
                else
                        printf("(%llu)", (unsigned long long)
@@ -1158,7 +1245,7 @@ static void print_imsm_disk(struct imsm_disk *disk, int index, __u32 reserved)
                                            is_configured(disk) ? " active" : "",
                                            is_failed(disk) ? " failed" : "");
        printf("             Id : %08x\n", __le32_to_cpu(disk->scsi_id));
-       sz = __le32_to_cpu(disk->total_blocks) - reserved;
+       sz = total_blocks(disk) - reserved;
        printf("    Usable Size : %llu%s\n", (unsigned long long)sz,
               human_size(sz * 512));
 }
@@ -1171,11 +1258,19 @@ void examine_migr_rec_imsm(struct intel_super *super)
 
        for (i = 0; i < mpb->num_raid_devs; i++) {
                struct imsm_dev *dev = __get_imsm_dev(mpb, i);
+               struct imsm_map *map;
+               int slot = -1;
+
                if (is_gen_migration(dev) == 0)
                                continue;
 
                printf("\nMigration Record Information:");
-               if (super->disks->index > 1) {
+
+               /* first map under migration */
+               map = get_imsm_map(dev, MAP_0);
+               if (map)
+                       slot = get_imsm_disk_slot(map, super->disks->index);
+               if ((map == NULL) || (slot > 1) || (slot < 0)) {
                        printf(" Empty\n                              ");
                        printf("Examine one of first two disks in array\n");
                        break;
@@ -1215,12 +1310,12 @@ void examine_migr_rec_imsm(struct intel_super *super)
 /*******************************************************************************
  * function: imsm_check_attributes
  * Description: Function checks if features represented by attributes flags
- *             are supported by mdadm.
+ *             are supported by mdadm.
  * Parameters:
  *             attributes - Attributes read from metadata
  * Returns:
- *             0 - passed attributes contains unsupported features flags
- *             1 - all features are supported
+ *             0 - passed attributes contains unsupported features flags
+ *             1 - all features are supported
  ******************************************************************************/
 static int imsm_check_attributes(__u32 attributes)
 {
@@ -1231,7 +1326,7 @@ static int imsm_check_attributes(__u32 attributes)
 
        not_supported &= attributes;
        if (not_supported) {
-               fprintf(stderr, Name "(IMSM): Unsupported attributes : %x\n",
+               pr_err("(IMSM): Unsupported attributes : %x\n",
                        (unsigned)__le32_to_cpu(not_supported));
                if (not_supported & MPB_ATTRIB_CHECKSUM_VERIFY) {
                        dprintf("\t\tMPB_ATTRIB_CHECKSUM_VERIFY \n");
@@ -1291,7 +1386,7 @@ static int imsm_check_attributes(__u32 attributes)
                }
 
                if (not_supported)
-                       dprintf(Name "(IMSM): Unknown attributes : %x\n", not_supported);
+                       dprintf("(IMSM): Unknown attributes : %x\n", not_supported);
 
                ret_val = 0;
        }
@@ -1427,6 +1522,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;
@@ -1462,8 +1610,8 @@ 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)
-                       fprintf(stderr, Name ": port_count %d out of range\n", port_count);
+               if (verbose > 0)
+                       pr_err("port_count %d out of range\n", port_count);
                return 2;
        }
 
@@ -1495,15 +1643,15 @@ 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)
-                               fprintf(stderr, Name ": failed to allocate 'device'\n");
+                       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)
-                               fprintf(stderr, Name ": failed to read device type for %s\n",
+                       if (verbose > 0)
+                               pr_err("failed to read device type for %s\n",
                                        path);
                        err = 2;
                        free(device);
@@ -1555,18 +1703,19 @@ 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)
-                               fprintf(stderr, Name ": %s - invalid path name\n", path + hba_len);
+                       if (verbose > 0)
+                               pr_err("%s - invalid path name\n", path + hba_len);
                        err = 2;
                        break;
                }
                *c = '\0';
-               if (sscanf(&path[hba_len], "host%d", &port) == 1)
+               if ((sscanf(&path[hba_len], "ata%d", &port) == 1) ||
+                  ((sscanf(&path[hba_len], "host%d", &port) == 1)))
                        port -= host_base;
                else {
-                       if (verbose) {
+                       if (verbose > 0) {
                                *c = '/'; /* repair the full string */
-                               fprintf(stderr, Name ": failed to determine port number for %s\n",
+                               pr_err("failed to determine port number for %s\n",
                                        path);
                        }
                        err = 2;
@@ -1615,11 +1764,13 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
 static void print_found_intel_controllers(struct sys_dev *elem)
 {
        for (; elem; elem = elem->next) {
-               fprintf(stderr, Name ": found Intel(R) ");
+               pr_err("found Intel(R) ");
                if (elem->type == SYS_DEV_SATA)
                        fprintf(stderr, "SATA ");
                else if (elem->type == SYS_DEV_SAS)
                        fprintf(stderr, "SAS ");
+               else if (elem->type == SYS_DEV_NVME)
+                       fprintf(stderr, "NVMe ");
                fprintf(stderr, "RAID controller");
                if (elem->pci_id)
                        fprintf(stderr, " at %s", elem->pci_id);
@@ -1641,7 +1792,8 @@ static int ahci_get_port_count(const char *hba_path, int *port_count)
        for (ent = readdir(dir); ent; ent = readdir(dir)) {
                int host;
 
-               if (sscanf(ent->d_name, "host%d", &host) != 1)
+               if ((sscanf(ent->d_name, "ata%d", &host) != 1) &&
+                  ((sscanf(ent->d_name, "host%d", &host) != 1)))
                        continue;
                if (*port_count == 0)
                        host_base = host;
@@ -1657,9 +1809,15 @@ static int ahci_get_port_count(const char *hba_path, int *port_count)
 
 static void print_imsm_capability(const struct imsm_orom *orom)
 {
-       printf("       Platform : Intel(R) Matrix Storage Manager\n");
-       printf("        Version : %d.%d.%d.%d\n", orom->major_ver, orom->minor_ver,
-              orom->hotfix_ver, orom->build);
+       printf("       Platform : Intel(R) ");
+       if (orom->capabilities == 0 && orom->driver_features == 0)
+               printf("Matrix Storage Manager\n");
+       else
+               printf("Rapid Storage Technology%s\n",
+                       imsm_orom_is_enterprise(orom) ? " enterprise" : "");
+       if (orom->major_ver || orom->minor_ver || orom->hotfix_ver || orom->build)
+               printf("        Version : %d.%d.%d.%d\n", orom->major_ver,
+                               orom->minor_ver, orom->hotfix_ver, orom->build);
        printf("    RAID Levels :%s%s%s%s%s\n",
               imsm_orom_has_raid0(orom) ? " raid0" : "",
               imsm_orom_has_raid1(orom) ? " raid1" : "",
@@ -1683,12 +1841,54 @@ static void print_imsm_capability(const struct imsm_orom *orom)
               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("    2TB volumes :%s supported\n",
+              (orom->attr & IMSM_OROM_ATTR_2TB)?"":" not");
+       printf("      2TB disks :%s supported\n",
+              (orom->attr & IMSM_OROM_ATTR_2TB_DISK)?"":" not");
        printf("      Max Disks : %d\n", orom->tds);
-       printf("    Max Volumes : %d\n", orom->vpa);
+       printf("    Max Volumes : %d per array, %d per %s\n",
+              orom->vpa, orom->vphba,
+              imsm_orom_is_nvme(orom) ? "platform" : "controller");
        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");
+       if (orom->major_ver || orom->minor_ver || orom->hotfix_ver || orom->build)
+               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
@@ -1701,11 +1901,10 @@ static int detail_platform_imsm(int verbose, int enumerate_only)
         * platform capabilities.  If raid support is disabled in the BIOS the
         * option-rom capability structure will not be available.
         */
-       const struct imsm_orom *orom;
        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"))
@@ -1714,53 +1913,111 @@ static int detail_platform_imsm(int verbose, int enumerate_only)
                if (!list)
                        return 2;
                for (hba = list; hba; hba = hba->next) {
-                       orom = find_imsm_capability(hba->type);
-                       if (!orom) {
-                               result = 2;
+                       if (find_imsm_capability(hba)) {
+                               result = 0;
                                break;
                        }
+                       else
+                               result = 2;
                }
-               free_sys_dev(&list);
                return result;
        }
 
        list = find_intel_devices();
        if (!list) {
-               if (verbose)
-                       fprintf(stderr, Name ": no active Intel(R) RAID "
+               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) {
-               orom = find_imsm_capability(hba->type);
-               if (!orom)
-                       fprintf(stderr, Name ": imsm capabilities not found for controller: %s (type %s)\n",
+               if (controller_path && (compare_paths(hba->path, controller_path) != 0))
+                       continue;
+               if (!find_imsm_capability(hba)) {
+                       pr_err("imsm capabilities not found for controller: %s (type %s)\n",
                                hba->path, get_sys_dev_type(hba->type));
-               else
-                       print_imsm_capability(orom);
+                       continue;
+               }
+               result = 0;
        }
 
-       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)
-                                       fprintf(stderr, Name ": failed to enumerate "
-                                               "ports on SATA controller at %s.", 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;
+       }
+
+       const struct orom_entry *oroms = get_oroms();
+       int i;
+
+       for (i = 0; i < SYS_DEV_MAX && oroms[i].devid_list; i++) {
+               print_imsm_capability(&oroms[i].orom);
+
+               if (imsm_orom_is_nvme(&oroms[i].orom)) {
+                       for (hba = list; hba; hba = hba->next) {
+                               if (hba->type == SYS_DEV_NVME)
+                                       printf("    NVMe Device : %s\n", hba->path);
+                       }
+                       continue;
+               }
+
+               struct devid_list *devid;
+               for (devid = oroms[i].devid_list; devid; devid = devid->next) {
+                       hba = device_by_id(devid->devid);
+                       if (!hba)
+                               continue;
+
+                       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;
+                               }
                        }
                }
+               printf("\n");
+       }
+
+       return result;
+}
+
+static int export_detail_platform_imsm(int verbose, char *controller_path)
+{
+       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) {
+               if (controller_path && (compare_paths(hba->path,controller_path) != 0))
+                       continue;
+               if (!find_imsm_capability(hba) && verbose > 0)
+                       pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_IMSM_CAPABLE_DEVICE_UNDER_%s\n", hba->path);
+               else
+                       result = 0;
        }
 
-       free_sys_dev(&list);
+       const struct orom_entry *oroms = get_oroms();
+       int i;
+
+       for (i = 0; i < SYS_DEV_MAX && oroms[i].devid_list; i++)
+               print_imsm_capability_export(&oroms[i].orom);
+
        return result;
 }
+
 #endif
 
 static int match_home_imsm(struct supertype *st, char *homehost)
@@ -1787,7 +2044,7 @@ static void uuid_from_super_imsm(struct supertype *st, int uuid[4])
         *    not the device-set.
         *  uuid to recognise same set when adding a missing device back
         *    to an array.   This is a uuid for the device-set.
-        *  
+        *
         * For each of these we can make do with a truncated
         * or hashed uuid rather than the original, as long as
         * everyone agrees.
@@ -1860,7 +2117,7 @@ get_imsm_numerical_version(struct imsm_super *mpb, int *m, int *p)
 static __u32 migr_strip_blocks_resync(struct imsm_dev *dev)
 {
        /* migr_strip_size when repairing or initializing parity */
-       struct imsm_map *map = get_imsm_map(dev, 0);
+       struct imsm_map *map = get_imsm_map(dev, MAP_0);
        __u32 chunk = __le32_to_cpu(map->blocks_per_strip);
 
        switch (get_imsm_raid_level(map)) {
@@ -1878,7 +2135,7 @@ static __u32 migr_strip_blocks_rebuild(struct imsm_dev *dev)
         * this is different than migr_strip_size_resync(), but it's good
         * to be compatible
         */
-       struct imsm_map *map = get_imsm_map(dev, 1);
+       struct imsm_map *map = get_imsm_map(dev, MAP_1);
        __u32 chunk = __le32_to_cpu(map->blocks_per_strip);
 
        switch (get_imsm_raid_level(map)) {
@@ -1897,8 +2154,8 @@ static __u32 migr_strip_blocks_rebuild(struct imsm_dev *dev)
 
 static __u32 num_stripes_per_unit_resync(struct imsm_dev *dev)
 {
-       struct imsm_map *lo = get_imsm_map(dev, 0);
-       struct imsm_map *hi = get_imsm_map(dev, 1);
+       struct imsm_map *lo = get_imsm_map(dev, MAP_0);
+       struct imsm_map *hi = get_imsm_map(dev, MAP_1);
        __u32 lo_chunk = __le32_to_cpu(lo->blocks_per_strip);
        __u32 hi_chunk = __le32_to_cpu(hi->blocks_per_strip);
 
@@ -1907,11 +2164,11 @@ static __u32 num_stripes_per_unit_resync(struct imsm_dev *dev)
 
 static __u32 num_stripes_per_unit_rebuild(struct imsm_dev *dev)
 {
-       struct imsm_map *lo = get_imsm_map(dev, 0);
+       struct imsm_map *lo = get_imsm_map(dev, MAP_0);
        int level = get_imsm_raid_level(lo);
 
        if (level == 1 || level == 10) {
-               struct imsm_map *hi = get_imsm_map(dev, 1);
+               struct imsm_map *hi = get_imsm_map(dev, MAP_1);
 
                return hi->num_domains;
        } else
@@ -1927,20 +2184,22 @@ static __u8 imsm_num_data_members(struct imsm_dev *dev, int second_map)
 
        switch (get_imsm_raid_level(map)) {
        case 0:
+               return map->num_members;
+               break;
        case 1:
        case 10:
-               return map->num_members;
+               return map->num_members/2;
        case 5:
                return map->num_members - 1;
        default:
-               dprintf("%s: unsupported raid level\n", __func__);
+               dprintf("unsupported raid level\n");
                return 0;
        }
 }
 
 static __u32 parity_segment_depth(struct imsm_dev *dev)
 {
-       struct imsm_map *map = get_imsm_map(dev, 0);
+       struct imsm_map *map = get_imsm_map(dev, MAP_0);
        __u32 chunk =  __le32_to_cpu(map->blocks_per_strip);
 
        switch(get_imsm_raid_level(map)) {
@@ -1956,7 +2215,7 @@ static __u32 parity_segment_depth(struct imsm_dev *dev)
 
 static __u32 map_migr_block(struct imsm_dev *dev, __u32 block)
 {
-       struct imsm_map *map = get_imsm_map(dev, 1);
+       struct imsm_map *map = get_imsm_map(dev, MAP_1);
        __u32 chunk = __le32_to_cpu(map->blocks_per_strip);
        __u32 strip = block / chunk;
 
@@ -1995,7 +2254,7 @@ static __u64 blocks_per_migr_unit(struct intel_super *super,
        case MIGR_VERIFY:
        case MIGR_REPAIR:
        case MIGR_INIT: {
-               struct imsm_map *map = get_imsm_map(dev, 0);
+               struct imsm_map *map = get_imsm_map(dev, MAP_0);
                __u32 stripes_per_unit;
                __u32 blocks_per_unit;
                __u32 parity_depth;
@@ -2011,7 +2270,7 @@ static __u64 blocks_per_migr_unit(struct intel_super *super,
                 */
                stripes_per_unit = num_stripes_per_unit_resync(dev);
                migr_chunk = migr_strip_blocks_resync(dev);
-               disks = imsm_num_data_members(dev, 0);
+               disks = imsm_num_data_members(dev, MAP_0);
                blocks_per_unit = stripes_per_unit * migr_chunk * disks;
                stripe = __le16_to_cpu(map->blocks_per_strip) * disks;
                segment = blocks_per_unit / stripe;
@@ -2065,16 +2324,15 @@ static int read_imsm_migr_rec(int fd, struct intel_super *super)
        unsigned long long dsize;
 
        get_dev_size(fd, NULL, &dsize);
-       if (lseek64(fd, dsize - 512, SEEK_SET) < 0) {
-               fprintf(stderr,
-                       Name ": Cannot seek to anchor block: %s\n",
-                       strerror(errno));
+       if (lseek64(fd, dsize - MIGR_REC_POSITION, SEEK_SET) < 0) {
+               pr_err("Cannot seek to anchor block: %s\n",
+                      strerror(errno));
                goto out;
        }
-       if (read(fd, super->migr_rec_buf, 512) != 512) {
-               fprintf(stderr,
-                       Name ": Cannot read migr record block: %s\n",
-                       strerror(errno));
+       if (read(fd, super->migr_rec_buf, MIGR_REC_BUF_SIZE) !=
+                                                           MIGR_REC_BUF_SIZE) {
+               pr_err("Cannot read migr record block: %s\n",
+                      strerror(errno));
                goto out;
        }
        ret_val = 0;
@@ -2083,6 +2341,19 @@ out:
        return ret_val;
 }
 
+static struct imsm_dev *imsm_get_device_during_migration(
+       struct intel_super *super)
+{
+
+       struct intel_dev *dv;
+
+       for (dv = super->devlist; dv; dv = dv->next) {
+               if (is_gen_migration(dv->dev))
+                       return dv->dev;
+       }
+       return NULL;
+}
+
 /*******************************************************************************
  * Function:   load_imsm_migr_rec
  * Description:        Function reads imsm migration record (it is stored at the last
@@ -2093,6 +2364,7 @@ out:
  * Returns:
  *      0 : success
  *     -1 : fail
+ *     -2 : no migration in progress
  ******************************************************************************/
 static int load_imsm_migr_rec(struct intel_super *super, struct mdinfo *info)
 {
@@ -2101,13 +2373,31 @@ static int load_imsm_migr_rec(struct intel_super *super, struct mdinfo *info)
        char nm[30];
        int retval = -1;
        int fd = -1;
+       struct imsm_dev *dev;
+       struct imsm_map *map = NULL;
+       int slot = -1;
+
+       /* find map under migration */
+       dev = imsm_get_device_during_migration(super);
+       /* nothing to load,no migration in progress?
+       */
+       if (dev == NULL)
+               return -2;
+       map = get_imsm_map(dev, MAP_0);
 
        if (info) {
                for (sd = info->devs ; sd ; sd = sd->next) {
+                       /* skip spare and failed disks
+                        */
+                       if (sd->disk.raid_disk < 0)
+                               continue;
                        /* read only from one of the first two slots */
-                       if ((sd->disk.raid_disk > 1) ||
-                           (sd->disk.raid_disk < 0))
+                       if (map)
+                               slot = get_imsm_disk_slot(map,
+                                                         sd->disk.raid_disk);
+                       if ((map == NULL) || (slot > 1) || (slot < 0))
                                continue;
+
                        sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
                        fd = dev_open(nm, O_RDONLY);
                        if (fd >= 0)
@@ -2116,8 +2406,14 @@ static int load_imsm_migr_rec(struct intel_super *super, struct mdinfo *info)
        }
        if (fd < 0) {
                for (dl = super->disks; dl; dl = dl->next) {
+                       /* skip spare and failed disks
+                       */
+                       if (dl->index < 0)
+                               continue;
                        /* read only from one of the first two slots */
-                       if (dl->index > 1)
+                       if (map)
+                               slot = get_imsm_disk_slot(map, dl->index);
+                       if ((map == NULL) || (slot > 1) || (slot < 0))
                                continue;
                        sprintf(nm, "%d:%d", dl->major, dl->minor);
                        fd = dev_open(nm, O_RDONLY);
@@ -2153,7 +2449,7 @@ static int imsm_create_metadata_checkpoint_update(
 
        int update_memory_size = 0;
 
-       dprintf("imsm_create_metadata_checkpoint_update(enter)\n");
+       dprintf("(enter)\n");
 
        if (u == NULL)
                return 0;
@@ -2163,21 +2459,18 @@ 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");
+               dprintf("error: cannot get memory\n");
                return 0;
        }
        (*u)->type = update_general_migration_checkpoint;
        (*u)->curr_migr_unit = __le32_to_cpu(super->migr_rec->curr_migr_unit);
-       dprintf("imsm_create_metadata_checkpoint_update: prepared for %u\n",
-               (*u)->curr_migr_unit);
+       dprintf("prepared for %u\n", (*u)->curr_migr_unit);
 
        return update_memory_size;
 }
 
-
 static void imsm_update_metadata_locally(struct supertype *st,
                                         void *buf, int len);
 
@@ -2201,26 +2494,46 @@ static int write_imsm_migr_rec(struct supertype *st)
        struct dl *sd;
        int len;
        struct imsm_update_general_migration_checkpoint *u;
+       struct imsm_dev *dev;
+       struct imsm_map *map = NULL;
+
+       /* find map under migration */
+       dev = imsm_get_device_during_migration(super);
+       /* if no migration, write buffer anyway to clear migr_record
+        * on disk based on first available device
+       */
+       if (dev == NULL)
+               dev = get_imsm_dev(super, super->current_vol < 0 ? 0 :
+                                         super->current_vol);
+
+       map = get_imsm_map(dev, MAP_0);
 
        for (sd = super->disks ; sd ; sd = sd->next) {
+               int slot = -1;
+
+               /* skip failed and spare devices */
+               if (sd->index < 0)
+                       continue;
                /* write to 2 first slots only */
-               if ((sd->index < 0) || (sd->index > 1))
+               if (map)
+                       slot = get_imsm_disk_slot(map, sd->index);
+               if ((map == NULL) || (slot > 1) || (slot < 0))
                        continue;
+
                sprintf(nm, "%d:%d", sd->major, sd->minor);
                fd = dev_open(nm, O_RDWR);
                if (fd < 0)
                        continue;
                get_dev_size(fd, NULL, &dsize);
-               if (lseek64(fd, dsize - 512, SEEK_SET) < 0) {
-                       fprintf(stderr,
-                               Name ": Cannot seek to anchor block: %s\n",
-                               strerror(errno));
+               if (lseek64(fd, dsize - MIGR_REC_POSITION, SEEK_SET) < 0) {
+                       pr_err("Cannot seek to anchor block: %s\n",
+                              strerror(errno));
                        goto out;
                }
-               if (write(fd, super->migr_rec_buf, 512) != 512) {
-                       fprintf(stderr,
-                               Name ": Cannot write migr record block: %s\n",
-                               strerror(errno));
+               if (write(fd, super->migr_rec_buf, MIGR_REC_BUF_SIZE) !=
+                                                           MIGR_REC_BUF_SIZE) {
+                       pr_err("Cannot write migr record block: %s\n",
+                              strerror(errno));
                        goto out;
                }
                close(fd);
@@ -2278,18 +2591,40 @@ int imsm_reshape_blocks_arrays_changes(struct intel_super *super)
        }
        return rv;
 }
+static unsigned long long imsm_component_size_aligment_check(int level,
+                                             int chunk_size,
+                                             unsigned long long component_size)
+{
+       unsigned int component_size_alligment;
+
+       /* check component size aligment
+       */
+       component_size_alligment = component_size % (chunk_size/512);
+
+       dprintf("(Level: %i, chunk_size = %i, component_size = %llu), component_size_alligment = %u\n",
+               level, chunk_size, component_size,
+               component_size_alligment);
+
+       if (component_size_alligment && (level != 1) && (level != UnSet)) {
+               dprintf("imsm: reported component size alligned from %llu ",
+                       component_size);
+               component_size -= component_size_alligment;
+               dprintf_cont("to %llu (%i).\n",
+                       component_size, component_size_alligment);
+       }
+
+       return component_size;
+}
 
 static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, char *dmap)
 {
        struct intel_super *super = st->sb;
        struct migr_record *migr_rec = super->migr_rec;
        struct imsm_dev *dev = get_imsm_dev(super, super->current_vol);
-       struct imsm_map *map = get_imsm_map(dev, 0);
-       struct imsm_map *prev_map = get_imsm_map(dev, 1);
+       struct imsm_map *map = get_imsm_map(dev, MAP_0);
+       struct imsm_map *prev_map = get_imsm_map(dev, MAP_1);
        struct imsm_map *map_to_analyse = map;
        struct dl *dl;
-       char *devname;
-       unsigned int component_size_alligment;
        int map_disks = info->array.raid_disks;
 
        memset(info, 0, sizeof(*info));
@@ -2369,23 +2704,13 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
                                                          dl->index);
        }
 
-       info->data_offset         = __le32_to_cpu(map_to_analyse->pba_of_lba0);
-       info->component_size      =
-               __le32_to_cpu(map_to_analyse->blocks_per_member);
-
-       /* check component size aligment
-        */
-       component_size_alligment =
-               info->component_size % (info->array.chunk_size/512);
+       info->data_offset         = pba_of_lba0(map_to_analyse);
+       info->component_size      = blocks_per_member(map_to_analyse);
 
-       if (component_size_alligment &&
-           (info->array.level != 1) && (info->array.level != UnSet)) {
-               dprintf("imsm: reported component size alligned from %llu ",
-                       info->component_size);
-               info->component_size -= component_size_alligment;
-               dprintf("to %llu (%i).\n",
-                       info->component_size, component_size_alligment);
-       }
+       info->component_size = imsm_component_size_aligment_check(
+                                                       info->array.level,
+                                                       info->array.chunk_size,
+                                                       info->component_size);
 
        memset(info->uuid, 0, sizeof(info->uuid));
        info->recovery_start = MaxSector;
@@ -2430,9 +2755,9 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
                                (unsigned long long)blocks_per_unit,
                                info->reshape_progress);
 
-                       used_disks = imsm_num_data_members(dev, 1);
+                       used_disks = imsm_num_data_members(dev, MAP_1);
                        if (used_disks > 0) {
-                               array_blocks = map->blocks_per_member *
+                               array_blocks = blocks_per_member(map) *
                                        used_disks;
                                /* round array size down to closest MB
                                 */
@@ -2461,11 +2786,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);
 
@@ -2475,7 +2796,7 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
                        dmap[i] = 0;
                        if (i < info->array.raid_disks) {
                                struct imsm_disk *dsk;
-                               j = get_imsm_disk_idx(dev, i, -1);
+                               j = get_imsm_disk_idx(dev, i, MAP_X);
                                dsk = get_imsm_disk(super, j);
                                if (dsk && (dsk->status & CONFIGURED_DISK))
                                        dmap[i] = 1;
@@ -2490,6 +2811,7 @@ static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev,
 static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev,
                             int look_in_map);
 
+#ifndef MDASSEMBLE
 static void manage_second_map(struct intel_super *super, struct imsm_dev *dev)
 {
        if (is_gen_migration(dev)) {
@@ -2498,14 +2820,14 @@ static void manage_second_map(struct intel_super *super, struct imsm_dev *dev)
                struct imsm_map *map2 = get_imsm_map(dev, MAP_1);
 
                failed = imsm_count_failed(super, dev, MAP_1);
-               map_state = imsm_check_degraded(super, dev, failed,
-                                               MAP_1);
+               map_state = imsm_check_degraded(super, dev, failed, MAP_1);
                if (map2->map_state != map_state) {
                        map2->map_state = map_state;
                        super->updates_pending++;
                }
        }
 }
+#endif
 
 static struct imsm_disk *get_imsm_missing(struct intel_super *super, __u8 index)
 {
@@ -2539,7 +2861,7 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
        info->array.level         = LEVEL_CONTAINER;
        info->array.layout        = 0;
        info->array.md_minor      = -1;
-       info->array.ctime         = 0; /* N/A for imsm */ 
+       info->array.ctime         = 0; /* N/A for imsm */
        info->array.utime         = 0;
        info->array.chunk_size    = 0;
 
@@ -2568,13 +2890,13 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
 
                failed = imsm_count_failed(super, dev, MAP_0);
                state = imsm_check_degraded(super, dev, failed, MAP_0);
-               map = get_imsm_map(dev, 0);
+               map = get_imsm_map(dev, MAP_0);
 
                /* any newly missing disks?
                 * (catches single-degraded vs double-degraded)
                 */
                for (j = 0; j < map->num_members; j++) {
-                       __u32 ord = get_imsm_ord_tbl_ent(dev, j, 0);
+                       __u32 ord = get_imsm_ord_tbl_ent(dev, j, MAP_0);
                        __u32 idx = ord_to_idx(ord);
 
                        if (!(ord & IMSM_ORD_REBUILD) &&
@@ -2591,20 +2913,30 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
                        enough = 0;
                else /* we're normal, or already degraded */
                        enough = 1;
-
+               if (is_gen_migration(dev) && missing) {
+                       /* during general migration we need all disks
+                        * that process is running on.
+                        * No new missing disk is allowed.
+                        */
+                       max_enough = -1;
+                       enough = -1;
+                       /* no more checks necessary
+                        */
+                       break;
+               }
                /* in the missing/failed disk case check to see
                 * if at least one array is runnable
                 */
                max_enough = max(max_enough, enough);
        }
-       dprintf("%s: enough: %d\n", __func__, max_enough);
+       dprintf("enough: %d\n", max_enough);
        info->container_enough = max_enough;
 
        if (super->disks) {
                __u32 reserved = imsm_reserved_sectors(super, super->disks);
 
                disk = &super->disks->disk;
-               info->data_offset = __le32_to_cpu(disk->total_blocks) - reserved;
+               info->data_offset = total_blocks(&super->disks->disk) - reserved;
                info->component_size = reserved;
                info->disk.state  = is_configured(disk) ? (1 << MD_DISK_ACTIVE) : 0;
                /* we don't change info->disk.raid_disk here because
@@ -2644,23 +2976,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) {
-               fprintf(stderr, Name ": 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) {
-                       fprintf(stderr, Name ": 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;
@@ -2715,25 +3035,30 @@ static int update_super_imsm(struct supertype *st, struct mdinfo *info,
 
        mpb = super->anchor;
 
-       if (strcmp(update, "uuid") == 0 && uuid_set && !info->update_private)
-               rv = -1;
-       else if (strcmp(update, "uuid") == 0 && uuid_set && info->update_private) {
-               mpb->orig_family_num = *((__u32 *) info->update_private);
-               rv = 0;
-       } else if (strcmp(update, "uuid") == 0) {
-               __u32 *new_family = malloc(sizeof(*new_family));
-
-               /* update orig_family_number with the incoming random
-                * data, report the new effective uuid, and store the
-                * new orig_family_num for future updates.
+       if (strcmp(update, "uuid") == 0) {
+               /* We take this to mean that the family_num should be updated.
+                * However that is much smaller than the uuid so we cannot really
+                * allow an explicit uuid to be given.  And it is hard to reliably
+                * know if one was.
+                * So if !uuid_set we know the current uuid is random and just used
+                * the first 'int' and copy it to the other 3 positions.
+                * Otherwise we require the 4 'int's to be the same as would be the
+                * case if we are using a random uuid.  So an explicit uuid will be
+                * accepted as long as all for ints are the same... which shouldn't hurt
                 */
-               if (new_family) {
-                       memcpy(&mpb->orig_family_num, info->uuid, sizeof(__u32));
-                       uuid_from_super_imsm(st, info->uuid);
-                       *new_family = mpb->orig_family_num;
-                       info->update_private = new_family;
+               if (!uuid_set) {
+                       info->uuid[1] = info->uuid[2] = info->uuid[3] = info->uuid[0];
                        rv = 0;
+               } else {
+                       if (info->uuid[0] != info->uuid[1] ||
+                           info->uuid[1] != info->uuid[2] ||
+                           info->uuid[2] != info->uuid[3])
+                               rv = -1;
+                       else
+                               rv = 0;
                }
+               if (rv == 0)
+                       mpb->orig_family_num = info->uuid[0];
        } else if (strcmp(update, "assemble") == 0)
                rv = 0;
        else
@@ -2761,7 +3086,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;
@@ -2798,21 +3124,27 @@ 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 (!check_env("IMSM_NO_PLATFORM") && first->hba && sec->hba) {
+               if (first->hba->type != sec->hba->type) {
                        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);
+                               "HBAs of devices do not match %s != %s\n",
+                               get_sys_dev_type(first->hba->type),
+                               get_sys_dev_type(sec->hba->type));
+                       return 3;
+               }
+               if (first->orom != sec->orom) {
+                       fprintf(stderr,
+                               "HBAs of devices do not match %s != %s\n",
+                               first->hba->pci_id, sec->hba->pci_id);
                        return 3;
                }
        }
@@ -2843,7 +3175,6 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst)
 
        }
 
-
        /* if 'first' is a spare promote it to a populated mpb with sec's
         * family number
         */
@@ -2857,14 +3188,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;
@@ -2873,7 +3198,7 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst)
                if (i < sec->anchor->num_raid_devs) {
                        /* allocation failure */
                        free_devlist(first);
-                       fprintf(stderr, "imsm: failed to associate spare\n"); 
+                       pr_err("imsm: failed to associate spare\n");
                        return 3;
                }
                first->anchor->num_raid_devs = sec->anchor->num_raid_devs;
@@ -2904,7 +3229,7 @@ static void fd2devname(int fd, char *name)
        rv = readlink(path, dname, sizeof(dname)-1);
        if (rv <= 0)
                return;
-       
+
        dname[rv] = '\0';
        nm = strrchr(dname, '/');
        if (nm) {
@@ -2939,18 +3264,16 @@ static int imsm_read_serial(int fd, char *devname,
 
        if (rv != 0) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": Failed to retrieve serial for %s\n",
-                               devname);
+                       pr_err("Failed to retrieve serial for %s\n",
+                              devname);
                return rv;
        }
 
        rsp_len = scsi_serial[3];
        if (!rsp_len) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": Failed to retrieve serial for %s\n",
-                               devname);
+                       pr_err("Failed to retrieve serial for %s\n",
+                              devname);
                return 2;
        }
        rsp_buf = (char *) &scsi_serial[4];
@@ -3039,14 +3362,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)
-                       fprintf(stderr,
-                               Name ": 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);
@@ -3060,9 +3376,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);
@@ -3101,12 +3417,12 @@ static void migrate(struct imsm_dev *dev, struct intel_super *super,
                    __u8 to_state, int migr_type)
 {
        struct imsm_map *dest;
-       struct imsm_map *src = get_imsm_map(dev, 0);
+       struct imsm_map *src = get_imsm_map(dev, MAP_0);
 
        dev->vol.migr_state = 1;
        set_migr_type(dev, migr_type);
        dev->vol.curr_migr_unit = 0;
-       dest = get_imsm_map(dev, 1);
+       dest = get_imsm_map(dev, MAP_1);
 
        /* duplicate and then set the target end state in map[0] */
        memcpy(dest, src, sizeof_imsm_map(src));
@@ -3131,8 +3447,9 @@ static void migrate(struct imsm_dev *dev, struct intel_super *super,
 static void end_migration(struct imsm_dev *dev, struct intel_super *super,
                          __u8 map_state)
 {
-       struct imsm_map *map = get_imsm_map(dev, 0);
-       struct imsm_map *prev = get_imsm_map(dev, dev->vol.migr_state);
+       struct imsm_map *map = get_imsm_map(dev, MAP_0);
+       struct imsm_map *prev = get_imsm_map(dev, dev->vol.migr_state == 0 ?
+                                                   MAP_0 : MAP_1);
        int i, j;
 
        /* merge any IMSM_ORD_REBUILD bits that were not successfully
@@ -3187,19 +3504,13 @@ static int parse_raid_devices(struct intel_super *super)
                len_migr = sizeof_imsm_dev(dev_iter, 1);
                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;
@@ -3223,7 +3534,7 @@ static int parse_raid_devices(struct intel_super *super)
                super->buf = buf;
                super->len = len;
        }
-               
+
        return 0;
 }
 
@@ -3235,7 +3546,7 @@ struct bbm_log *__get_imsm_bbm_log(struct imsm_super *mpb)
        if (__le32_to_cpu(mpb->bbm_log_size)) {
                ptr = mpb;
                ptr += mpb->mpb_size - __le32_to_cpu(mpb->bbm_log_size);
-       } 
+       }
 
        return ptr;
 }
@@ -3264,9 +3575,9 @@ int check_mpb_migr_compatibility(struct intel_super *super)
                    dev_iter->vol.migr_state == 1 &&
                    dev_iter->vol.migr_type == MIGR_GEN_MIGR) {
                        /* This device is migrating */
-                       map0 = get_imsm_map(dev_iter, 0);
-                       map1 = get_imsm_map(dev_iter, 1);
-                       if (map0->pba_of_lba0 != map1->pba_of_lba0)
+                       map0 = get_imsm_map(dev_iter, MAP_0);
+                       map1 = get_imsm_map(dev_iter, MAP_1);
+                       if (pba_of_lba0(map0) != pba_of_lba0(map1))
                                /* migration optimization area was used */
                                return -1;
                        if (migr_rec->ascending_migr == 0
@@ -3294,40 +3605,35 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
        get_dev_size(fd, NULL, &dsize);
        if (dsize < 1024) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": %s: device to small for imsm\n",
-                               devname);
+                       pr_err("%s: device to small for imsm\n",
+                              devname);
                return 1;
        }
 
        if (lseek64(fd, dsize - (512 * 2), SEEK_SET) < 0) {
                if (devname)
-                       fprintf(stderr, Name
-                               ": Cannot seek to anchor block on %s: %s\n",
-                               devname, strerror(errno));
+                       pr_err("Cannot seek to anchor block on %s: %s\n",
+                              devname, strerror(errno));
                return 1;
        }
 
        if (posix_memalign((void**)&anchor, 512, 512) != 0) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": Failed to allocate imsm anchor buffer"
-                               " on %s\n", devname);
+                       pr_err("Failed to allocate imsm anchor buffer"
+                              " on %s\n", devname);
                return 1;
        }
        if (read(fd, anchor, 512) != 512) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": Cannot read anchor block on %s: %s\n",
-                               devname, strerror(errno));
+                       pr_err("Cannot read anchor block on %s: %s\n",
+                              devname, strerror(errno));
                free(anchor);
                return 1;
        }
 
        if (strncmp((char *) anchor->sig, MPB_SIGNATURE, MPB_SIG_LEN) != 0) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": no IMSM anchor on %s\n", devname);
+                       pr_err("no IMSM anchor on %s\n", devname);
                free(anchor);
                return 2;
        }
@@ -3340,9 +3646,8 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
        super->len = ROUND_UP(anchor->mpb_size, 512);
        if (posix_memalign(&super->buf, 512, super->len) != 0) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": unable to allocate %zu byte mpb buffer\n",
-                               super->len);
+                       pr_err("unable to allocate %zu byte mpb buffer\n",
+                              super->len);
                free(anchor);
                return 2;
        }
@@ -3351,22 +3656,21 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
        sectors = mpb_sectors(anchor) - 1;
        free(anchor);
 
-       if (posix_memalign(&super->migr_rec_buf, 512, 512) != 0) {
-               fprintf(stderr, Name
-                       ": %s could not allocate migr_rec buffer\n", __func__);
+       if (posix_memalign(&super->migr_rec_buf, 512, MIGR_REC_BUF_SIZE) != 0) {
+               pr_err("could not allocate migr_rec buffer\n");
                free(super->buf);
                return 2;
        }
+       super->clean_migration_record_by_mdmon = 0;
 
        if (!sectors) {
                check_sum = __gen_imsm_checksum(super->anchor);
                if (check_sum != __le32_to_cpu(super->anchor->check_sum)) {
                        if (devname)
-                               fprintf(stderr,
-                                       Name ": IMSM checksum %x != %x on %s\n",
-                                       check_sum,
-                                       __le32_to_cpu(super->anchor->check_sum),
-                                       devname);
+                               pr_err("IMSM checksum %x != %x on %s\n",
+                                      check_sum,
+                                      __le32_to_cpu(super->anchor->check_sum),
+                                      devname);
                        return 2;
                }
 
@@ -3376,27 +3680,24 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
        /* read the extended mpb */
        if (lseek64(fd, dsize - (512 * (2 + sectors)), SEEK_SET) < 0) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": Cannot seek to extended mpb on %s: %s\n",
-                               devname, strerror(errno));
+                       pr_err("Cannot seek to extended mpb on %s: %s\n",
+                              devname, strerror(errno));
                return 1;
        }
 
        if ((unsigned)read(fd, super->buf + 512, super->len - 512) != super->len - 512) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": Cannot read extended mpb on %s: %s\n",
-                               devname, strerror(errno));
+                       pr_err("Cannot read extended mpb on %s: %s\n",
+                              devname, strerror(errno));
                return 2;
        }
 
        check_sum = __gen_imsm_checksum(super->anchor);
        if (check_sum != __le32_to_cpu(super->anchor->check_sum)) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": IMSM checksum %x != %x on %s\n",
-                               check_sum, __le32_to_cpu(super->anchor->check_sum),
-                               devname);
+                       pr_err("IMSM checksum %x != %x on %s\n",
+                              check_sum, __le32_to_cpu(super->anchor->check_sum),
+                              devname);
                return 3;
        }
 
@@ -3411,19 +3712,45 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
 
 static int read_imsm_migr_rec(int fd, struct intel_super *super);
 
-static int
-load_and_parse_mpb(int fd, struct intel_super *super, char *devname, int keep_fd)
+/* clears hi bits in metadata if MPB_ATTRIB_2TB_DISK not set */
+static void clear_hi(struct intel_super *super)
 {
-       int err;
-
-       err = load_imsm_mpb(fd, super, devname);
-       if (err)
-               return err;
+       struct imsm_super *mpb = super->anchor;
+       int i, n;
+       if (mpb->attributes & MPB_ATTRIB_2TB_DISK)
+               return;
+       for (i = 0; i < mpb->num_disks; ++i) {
+               struct imsm_disk *disk = &mpb->disk[i];
+               disk->total_blocks_hi = 0;
+       }
+       for (i = 0; i < mpb->num_raid_devs; ++i) {
+               struct imsm_dev *dev = get_imsm_dev(super, i);
+               if (!dev)
+                       return;
+               for (n = 0; n < 2; ++n) {
+                       struct imsm_map *map = get_imsm_map(dev, n);
+                       if (!map)
+                               continue;
+                       map->pba_of_lba0_hi = 0;
+                       map->blocks_per_member_hi = 0;
+                       map->num_data_stripes_hi = 0;
+               }
+       }
+}
+
+static int
+load_and_parse_mpb(int fd, struct intel_super *super, char *devname, int keep_fd)
+{
+       int err;
+
+       err = load_imsm_mpb(fd, super, devname);
+       if (err)
+               return err;
        err = load_imsm_disk(fd, super, devname, keep_fd);
        if (err)
                return err;
        err = parse_raid_devices(super);
-
+       clear_hi(super);
        return err;
 }
 
@@ -3509,13 +3836,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 = ~((__u32 ) 0);
-       }
+       super->current_vol = -1;
+       super->create_offset = ~((unsigned long long) 0);
        return super;
 }
 
@@ -3535,9 +3859,8 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
        hba_name = find_disk_attached_hba(fd, NULL);
        if (!hba_name) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": %s is not attached to Intel(R) RAID controller.\n",
-                               devname);
+                       pr_err("%s is not attached to Intel(R) RAID controller.\n",
+                              devname);
                return 1;
        }
        rv = attach_hba_to_super(super, hba_name);
@@ -3545,14 +3868,14 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
                if (devname) {
                        struct intel_hba *hba = super->hba;
 
-                       fprintf(stderr, Name ": %s is attached to Intel(R) %s RAID "
+                       pr_err("%s is attached to Intel(R) %s RAID "
                                "controller (%s),\n"
                                "    but the container is assigned to Intel(R) "
                                "%s RAID controller (",
                                devname,
-                               hba_name->path,
+                               get_sys_dev_type(hba_name->type),
                                hba_name->pci_id ? : "Err!",
-                               get_sys_dev_type(hba_name->type));
+                               get_sys_dev_type(super->hba->type));
 
                        while (hba) {
                                fprintf(stderr, "%s", hba->pci_id ? : "Err!");
@@ -3560,18 +3883,16 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
                                        fprintf(stderr, ", ");
                                hba = hba->next;
                        }
-
                        fprintf(stderr, ").\n"
                                "    Mixing devices attached to different 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);
+       super->orom = find_imsm_capability(hba_name);
        if (!super->orom)
                return 3;
+
        return 0;
 }
 
@@ -3592,13 +3913,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;
@@ -3638,8 +3957,8 @@ static int __prep_thunderdome(struct intel_super **table, int tbl_size,
 
                if (tbl_mpb->family_num == mpb->family_num) {
                        if (tbl_mpb->check_sum == mpb->check_sum) {
-                               dprintf("%s: mpb from %d:%d matches %d:%d\n",
-                                       __func__, super->disks->major,
+                               dprintf("mpb from %d:%d matches %d:%d\n",
+                                       super->disks->major,
                                        super->disks->minor,
                                        table[i]->disks->major,
                                        table[i]->disks->minor);
@@ -3656,8 +3975,8 @@ static int __prep_thunderdome(struct intel_super **table, int tbl_size,
                                 */
                                struct intel_disk *idisk;
 
-                               dprintf("%s: mpb from %d:%d replaces %d:%d\n",
-                                       __func__, super->disks->major,
+                               dprintf("mpb from %d:%d replaces %d:%d\n",
+                                       super->disks->major,
                                        super->disks->minor,
                                        table[i]->disks->major,
                                        table[i]->disks->minor);
@@ -3685,8 +4004,8 @@ static int __prep_thunderdome(struct intel_super **table, int tbl_size,
                                                idisk->disk.status |= CONFIGURED_DISK;
                                }
 
-                               dprintf("%s: mpb from %d:%d prefer %d:%d\n",
-                                       __func__, super->disks->major,
+                               dprintf("mpb from %d:%d prefer %d:%d\n",
+                                       super->disks->major,
                                        super->disks->minor,
                                        table[i]->disks->major,
                                        table[i]->disks->minor);
@@ -3713,9 +4032,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;
@@ -3747,12 +4064,12 @@ validate_members(struct intel_super *super, struct intel_disk *disk_list,
                            idisk->owner == IMSM_UNKNOWN_OWNER)
                                ok_count++;
                        else
-                               dprintf("%s: '%.16s' owner %d != %d\n",
-                                       __func__, disk->serial, idisk->owner,
+                               dprintf("'%.16s' owner %d != %d\n",
+                                       disk->serial, idisk->owner,
                                        owner);
                } else {
-                       dprintf("%s: unknown disk %x [%d]: %.16s\n",
-                               __func__, __le32_to_cpu(mpb->family_num), i,
+                       dprintf("unknown disk %x [%d]: %.16s\n",
+                               __le32_to_cpu(mpb->family_num), i,
                                disk->serial);
                        break;
                }
@@ -3770,7 +4087,7 @@ static void show_conflicts(__u32 family_num, struct intel_super *super_list)
        for (s = super_list; s; s = s->next) {
                if (family_num != s->anchor->family_num)
                        continue;
-               fprintf(stderr, "Conflict, offlining family %#x on '%s'\n",
+               pr_err("Conflict, offlining family %#x on '%s'\n",
                        __le32_to_cpu(family_num), s->disks->devname);
        }
 }
@@ -3808,8 +4125,8 @@ imsm_thunderdome(struct intel_super **super_list, int len)
                        s = NULL;
 
                if (!s)
-                       dprintf("%s: marking family: %#x from %d:%d offline\n",
-                               __func__, mpb->family_num,
+                       dprintf("marking family: %#x from %d:%d offline\n",
+                               mpb->family_num,
                                super_table[i]->disks->major,
                                super_table[i]->disks->minor);
                super_table[i] = s;
@@ -3856,7 +4173,7 @@ imsm_thunderdome(struct intel_super **super_list, int len)
        champion = s;
 
        if (conflict)
-               fprintf(stderr, "Chose family %#x on '%s', "
+               pr_err("Chose family %#x on '%s', "
                        "assemble conflicts to new container with '--update=uuid'\n",
                        __le32_to_cpu(s->anchor->family_num), s->disks->devname);
 
@@ -3870,6 +4187,8 @@ imsm_thunderdome(struct intel_super **super_list, int len)
                if (s == champion)
                        continue;
 
+               mpb->attributes |= s->anchor->attributes & MPB_ATTRIB_2TB_DISK;
+
                for (i = 0; i < mpb->num_disks; i++) {
                        struct imsm_disk *disk;
 
@@ -3927,67 +4246,31 @@ imsm_thunderdome(struct intel_super **super_list, int len)
        return champion;
 }
 
+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, 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,
+                       int *max, int keep_fd);
+
 static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
-                              char *devname)
+                              char *devname, struct md_list *devlist,
+                              int keep_fd)
 {
-       struct mdinfo *sra;
        struct intel_super *super_list = NULL;
        struct intel_super *super = NULL;
-       int devnum = fd2devnum(fd);
-       struct mdinfo *sd;
-       int retry;
        int err = 0;
-       int i;
-
-       /* check if 'fd' an opened container */
-       sra = sysfs_read(fd, 0, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE);
-       if (!sra)
-               return 1;
+       int i = 0;
 
-       if (sra->array.major_version != -1 ||
-           sra->array.minor_version != -2 ||
-           strcmp(sra->text_version, "imsm") != 0) {
-               err = 1;
+       if (fd >= 0)
+               /* 'fd' is an opened container */
+               err = get_sra_super_block(fd, &super_list, devname, &i, keep_fd);
+       else
+               /* get super block from devlist devices */
+               err = get_devlist_super_block(devlist, &super_list, &i, keep_fd);
+       if (err)
                goto error;
-       }
-       /* load all mpbs */
-       for (sd = sra->devs, i = 0; sd; sd = sd->next, i++) {
-               struct intel_super *s = alloc_super();
-               char nm[32];
-               int dfd;
-               int rv;
-
-               err = 1;
-               if (!s)
-                       goto error;
-               s->next = super_list;
-               super_list = s;
-
-               err = 2;
-               sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
-               dfd = dev_open(nm, O_RDWR);
-               if (dfd < 0)
-                       goto error;
-
-               rv = find_intel_hba_capability(dfd, s, devname);
-               /* no orom/efi or non-intel hba of the disk */
-               if (rv != 0)
-                       goto error;
-
-               err = load_and_parse_mpb(dfd, s, NULL, 1);
-
-               /* retry the load if we might have raced against mdmon */
-               if (err == 3 && mdmon_running(devnum))
-                       for (retry = 0; retry < 3; retry++) {
-                               usleep(3000);
-                               err = load_and_parse_mpb(dfd, s, NULL, 1);
-                               if (err != 3)
-                                       break;
-                       }
-               if (err)
-                       goto error;
-       }
-
        /* all mpbs enter, maybe one leaves */
        super = imsm_thunderdome(&super_list, i);
        if (!super) {
@@ -4003,14 +4286,17 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
 
        /* load migration record */
        err = load_imsm_migr_rec(super, NULL);
-       if (err) {
+       if (err == -1) {
+               /* migration is in progress,
+                * but migr_rec cannot be loaded,
+                */
                err = 4;
                goto error;
        }
 
        /* Check migration compatibility */
-       if (check_mpb_migr_compatibility(super) != 0) {
-               fprintf(stderr, Name ": Unsupported migration detected");
+       if ((err == 0) && (check_mpb_migr_compatibility(super) != 0)) {
+               pr_err("Unsupported migration detected");
                if (devname)
                        fprintf(stderr, " on %s\n", devname);
                else
@@ -4029,13 +4315,15 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
                super_list = super_list->next;
                free_imsm(s);
        }
-       sysfs_free(sra);
 
        if (err)
                return err;
 
        *sbp = super;
-       st->container_dev = devnum;
+       if (fd >= 0)
+               strcpy(st->container_devnm, fd2devnm(fd));
+       else
+               st->container_devnm[0] = 0;
        if (err == 0 && st->ss == NULL) {
                st->ss = &super_imsm;
                st->minor_version = 0;
@@ -4044,9 +4332,140 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
        return 0;
 }
 
+static int
+get_devlist_super_block(struct md_list *devlist, struct intel_super **super_list,
+                       int *max, int keep_fd)
+{
+       struct md_list *tmpdev;
+       int err = 0;
+       int i = 0;
+
+       for (i = 0, tmpdev = devlist; tmpdev; tmpdev = tmpdev->next) {
+               if (tmpdev->used != 1)
+                       continue;
+               if (tmpdev->container == 1) {
+                       int lmax = 0;
+                       int fd = dev_open(tmpdev->devname, O_RDONLY|O_EXCL);
+                       if (fd < 0) {
+                               pr_err("cannot open device %s: %s\n",
+                                       tmpdev->devname, strerror(errno));
+                               err = 8;
+                               goto error;
+                       }
+                       err = get_sra_super_block(fd, super_list,
+                                                 tmpdev->devname, &lmax,
+                                                 keep_fd);
+                       i += lmax;
+                       close(fd);
+                       if (err) {
+                               err = 7;
+                               goto error;
+                       }
+               } else {
+                       int major = major(tmpdev->st_rdev);
+                       int minor = minor(tmpdev->st_rdev);
+                       err = get_super_block(super_list,
+                                             NULL,
+                                             tmpdev->devname,
+                                             major, minor,
+                                             keep_fd);
+                       i++;
+                       if (err) {
+                               err = 6;
+                               goto error;
+                       }
+               }
+       }
+ error:
+       *max = i;
+       return err;
+}
+
+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 err = 0;
+       int retry;
+
+       s = alloc_super();
+       if (!s) {
+               err = 1;
+               goto error;
+       }
+
+       sprintf(nm, "%d:%d", major, minor);
+       dfd = dev_open(nm, O_RDWR);
+       if (dfd < 0) {
+               err = 2;
+               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 && devnm && mdmon_running(devnm))
+               for (retry = 0; retry < 3; retry++) {
+                       usleep(3000);
+                       err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
+                       if (err != 3)
+                               break;
+               }
+ error:
+       if (!err) {
+               s->next = *super_list;
+               *super_list = s;
+       } else {
+               if (s)
+                       free(s);
+               if (dfd >= 0)
+                       close(dfd);
+       }
+       if ((dfd >= 0) && (!keep_fd))
+               close(dfd);
+       return err;
+
+}
+
+static int
+get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int *max, int keep_fd)
+{
+       struct mdinfo *sra;
+       char *devnm;
+       struct mdinfo *sd;
+       int err = 0;
+       int i = 0;
+       sra = sysfs_read(fd, NULL, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE);
+       if (!sra)
+               return 1;
+
+       if (sra->array.major_version != -1 ||
+           sra->array.minor_version != -2 ||
+           strcmp(sra->text_version, "imsm") != 0) {
+               err = 1;
+               goto error;
+       }
+       /* load all mpbs */
+       devnm = fd2devnm(fd);
+       for (sd = sra->devs, i = 0; sd; sd = sd->next, i++) {
+               if (get_super_block(super_list, devnm, devname,
+                                   sd->disk.major, sd->disk.minor, keep_fd) != 0) {
+                       err = 7;
+                       goto error;
+               }
+       }
+ error:
+       sysfs_free(sra);
+       *max = i;
+       return err;
+}
+
 static int load_container_imsm(struct supertype *st, int fd, char *devname)
 {
-       return load_super_imsm_all(st, fd, &st->sb, devname);
+       return load_super_imsm_all(st, fd, &st->sb, devname, NULL, 1);
 }
 #endif
 
@@ -4054,6 +4473,7 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
 {
        struct intel_super *super;
        int rv;
+       int retry;
 
        if (test_partition(fd))
                /* IMSM not allowed on partitions */
@@ -4062,12 +4482,6 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
        free_super_imsm(st);
 
        super = alloc_super();
-       if (!super) {
-               fprintf(stderr,
-                       Name ": 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.
@@ -4076,18 +4490,32 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
        /* no orom/efi or non-intel hba of the disk */
        if ((rv != 0) && (st->ignore_hw_compat == 0)) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": No OROM/EFI properties for %s\n", devname);
+                       pr_err("No OROM/EFI properties for %s\n", devname);
                free_imsm(super);
                return 2;
        }
        rv = load_and_parse_mpb(fd, super, devname, 0);
 
+       /* retry the load if we might have raced against mdmon */
+       if (rv == 3) {
+               struct mdstat_ent *mdstat = mdstat_by_component(fd2devnm(fd));
+
+               if (mdstat && mdmon_running(mdstat->devnm) && getpid() != mdmon_pid(mdstat->devnm)) {
+                       for (retry = 0; retry < 3; retry++) {
+                               usleep(3000);
+                               rv = load_and_parse_mpb(fd, super, devname, 0);
+                               if (rv != 3)
+                                       break;
+                       }
+               }
+
+               free_mdstat(mdstat);
+       }
+
        if (rv) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": Failed to load all information "
-                               "sections on %s\n", devname);
+                       pr_err("Failed to load all information "
+                              "sections on %s\n", devname);
                free_imsm(super);
                return rv;
        }
@@ -4103,8 +4531,7 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
        if (load_imsm_migr_rec(super, NULL) == 0) {
                /* Check for unsupported migration features */
                if (check_mpb_migr_compatibility(super) != 0) {
-                       fprintf(stderr,
-                               Name ": Unsupported migration detected");
+                       pr_err("Unsupported migration detected");
                        if (devname)
                                fprintf(stderr, " on %s\n", devname);
                        else
@@ -4123,22 +4550,13 @@ static __u16 info_to_blocks_per_strip(mdu_array_info_t *info)
        return info->chunk_size >> 9;
 }
 
-static __u32 info_to_num_data_stripes(mdu_array_info_t *info, int num_domains)
-{
-       __u32 num_stripes;
-
-       num_stripes = (info->size * 2) / info_to_blocks_per_strip(info);
-       num_stripes /= num_domains;
-
-       return num_stripes;
-}
-
-static __u32 info_to_blocks_per_member(mdu_array_info_t *info)
+static unsigned long long info_to_blocks_per_member(mdu_array_info_t *info,
+                                                   unsigned long long size)
 {
        if (info->level == 1)
-               return info->size * 2;
+               return size * 2;
        else
-               return (info->size * 2) & ~(info_to_blocks_per_strip(info) - 1);
+               return (size * 2) & ~(info_to_blocks_per_strip(info) - 1);
 }
 
 static void imsm_update_version_info(struct intel_super *super)
@@ -4152,7 +4570,7 @@ static void imsm_update_version_info(struct intel_super *super)
 
        for (i = 0; i < mpb->num_raid_devs; i++) {
                dev = get_imsm_dev(super, i);
-               map = get_imsm_map(dev, 0);
+               map = get_imsm_map(dev, MAP_0);
                if (__le32_to_cpu(dev->size_high) > 0)
                        mpb->attributes |= MPB_ATTRIB_2TB;
 
@@ -4207,14 +4625,15 @@ static int check_name(struct intel_super *super, char *name, int quiet)
        }
 
        if (reason && !quiet)
-               fprintf(stderr, Name ": imsm volume name %s\n", reason);
+               pr_err("imsm volume name %s\n", reason);
 
        return !reason;
 }
 
 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.
@@ -4229,10 +4648,10 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        int i;
        unsigned long long array_blocks;
        size_t size_old, size_new;
-       __u32 num_data_stripes;
+       unsigned long long num_data_stripes;
 
        if (super->orom && mpb->num_raid_devs >= super->orom->vpa) {
-               fprintf(stderr, Name": This imsm-container already has the "
+               pr_err("This imsm-container already has the "
                        "maximum of %d volumes\n", super->orom->vpa);
                return 0;
        }
@@ -4245,13 +4664,12 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                size_t size_round = ROUND_UP(size_new, 512);
 
                if (posix_memalign(&mpb_new, 512, size_round) != 0) {
-                       fprintf(stderr, Name": could not allocate new mpb\n");
+                       pr_err("could not allocate new mpb\n");
                        return 0;
                }
-               if (posix_memalign(&super->migr_rec_buf, 512, 512) != 0) {
-                       fprintf(stderr, Name
-                               ": %s could not allocate migr_rec buffer\n",
-                               __func__);
+               if (posix_memalign(&super->migr_rec_buf, 512,
+                                  MIGR_REC_BUF_SIZE) != 0) {
+                       pr_err("could not allocate migr_rec buffer\n");
                        free(super->buf);
                        free(super);
                        free(mpb_new);
@@ -4295,32 +4713,19 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                for (d = super->missing; d; d = d->next)
                        missing++;
                if (info->failed_disks > missing) {
-                       fprintf(stderr, Name": unable to add 'missing' disk to container\n");
+                       pr_err("unable to add 'missing' disk to container\n");
                        return 0;
                }
        }
 
        if (!check_name(super, name, 0))
                return 0;
-       dv = malloc(sizeof(*dv));
-       if (!dv) {
-               fprintf(stderr, Name ": failed to allocate device list entry\n");
-               return 0;
-       }
-       dev = calloc(1, sizeof(*dev) + sizeof(__u32) * (info->raid_disks - 1));
-       if (!dev) {
-               free(dv);
-               fprintf(stderr, Name": 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);
-       if (info->level == 1)
-               array_blocks = info_to_blocks_per_member(info);
-       else
-               array_blocks = calc_array_size(info->level, info->raid_disks,
+       array_blocks = calc_array_size(info->level, info->raid_disks,
                                               info->layout, info->chunk_size,
-                                              info->size*2);
+                                              size * 2);
        /* round array size down to closest MB */
        array_blocks = (array_blocks >> SECT_PER_MB_SHIFT) << SECT_PER_MB_SHIFT;
 
@@ -4332,13 +4737,14 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        set_migr_type(dev, MIGR_INIT);
        vol->dirty = !info->state;
        vol->curr_migr_unit = 0;
-       map = get_imsm_map(dev, 0);
-       map->pba_of_lba0 = __cpu_to_le32(super->create_offset);
-       map->blocks_per_member = __cpu_to_le32(info_to_blocks_per_member(info));
+       map = get_imsm_map(dev, MAP_0);
+       set_pba_of_lba0(map, super->create_offset);
+       set_blocks_per_member(map, info_to_blocks_per_member(info, size));
        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;
@@ -4347,7 +4753,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        if (info->level == 1 && info->raid_disks > 2) {
                free(dev);
                free(dv);
-               fprintf(stderr, Name": imsm does not support more than 2 disks"
+               pr_err("imsm does not support more than 2 disks"
                                "in a raid1 volume\n");
                return 0;
        }
@@ -4361,8 +4767,10 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        else
                map->num_domains = 1;
 
-       num_data_stripes = info_to_num_data_stripes(info, map->num_domains);
-       map->num_data_stripes = __cpu_to_le32(num_data_stripes);
+       /* info->size is only int so use the 'size' parameter instead */
+       num_data_stripes = (size * 2) / info_to_blocks_per_strip(info);
+       num_data_stripes /= map->num_domains;
+       set_num_data_stripes(map, num_data_stripes);
 
        map->num_members = info->raid_disks;
        for (i = 0; i < map->num_members; i++) {
@@ -4383,7 +4791,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
@@ -4398,8 +4807,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);
@@ -4412,13 +4827,11 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
                super = NULL;
        }
        if (!super) {
-               fprintf(stderr, Name
-                       ": %s could not allocate superblock\n", __func__);
+               pr_err("could not allocate superblock\n");
                return 0;
        }
-       if (posix_memalign(&super->migr_rec_buf, 512, 512) != 0) {
-               fprintf(stderr, Name
-                       ": %s could not allocate migr_rec buffer\n", __func__);
+       if (posix_memalign(&super->migr_rec_buf, 512, MIGR_REC_BUF_SIZE) != 0) {
+               pr_err("could not allocate migr_rec buffer\n");
                free(super->buf);
                free(super);
                return 0;
@@ -4456,10 +4869,10 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
        int slot;
 
        dev = get_imsm_dev(super, super->current_vol);
-       map = get_imsm_map(dev, 0);
+       map = get_imsm_map(dev, MAP_0);
 
        if (! (dk->state & (1<<MD_DISK_SYNC))) {
-               fprintf(stderr, Name ": %s: Cannot add spare devices to IMSM volume\n",
+               pr_err("%s: Cannot add spare devices to IMSM volume\n",
                        devname);
                return 1;
        }
@@ -4479,7 +4892,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
        }
 
        if (!dl) {
-               fprintf(stderr, Name ": %s is not a member of the same container\n", devname);
+               pr_err("%s is not a member of the same container\n", devname);
                return 1;
        }
 
@@ -4491,8 +4904,8 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
        /* Check the device has not already been added */
        slot = get_imsm_disk_slot(map, dl->index);
        if (slot >= 0 &&
-           (get_imsm_ord_tbl_ent(dev, slot, -1) & IMSM_ORD_REBUILD) == 0) {
-               fprintf(stderr, Name ": %s has been included in this array twice\n",
+           (get_imsm_ord_tbl_ent(dev, slot, MAP_X) & IMSM_ORD_REBUILD) == 0) {
+               pr_err("%s has been included in this array twice\n",
                        devname);
                return 1;
        }
@@ -4505,8 +4918,8 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
         */
        if (super->current_vol == 0) {
                for (df = super->missing; df; df = df->next) {
-                       if (dl->disk.total_blocks > df->disk.total_blocks)
-                               df->disk.total_blocks = dl->disk.total_blocks;
+                       if (total_blocks(&dl->disk) > total_blocks(&df->disk))
+                               set_total_blocks(&df->disk, total_blocks(&dl->disk));
                        _disk = __get_imsm_disk(mpb, df->index);
                        *_disk = df->disk;
                }
@@ -4515,21 +4928,24 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
        /* refresh unset/failed slots to point to valid 'missing' entries */
        for (df = super->missing; df; df = df->next)
                for (slot = 0; slot < mpb->num_disks; slot++) {
-                       __u32 ord = get_imsm_ord_tbl_ent(dev, slot, -1);
+                       __u32 ord = get_imsm_ord_tbl_ent(dev, slot, MAP_X);
 
                        if ((ord & IMSM_ORD_REBUILD) == 0)
                                continue;
                        set_imsm_ord_tbl_ent(map, slot, df->index | IMSM_ORD_REBUILD);
                        if (is_gen_migration(dev)) {
-                               struct imsm_map *map2 = get_imsm_map(dev, 1);
-                               if (slot < map2->num_members) {
+                               struct imsm_map *map2 = get_imsm_map(dev,
+                                                                    MAP_1);
+                               int slot2 = get_imsm_disk_slot(map2, df->index);
+                               if ((slot2 < map2->num_members) &&
+                                   (slot2 >= 0)) {
                                        __u32 ord2 = get_imsm_ord_tbl_ent(dev,
-                                                                         slot,
-                                                                         1);
+                                                                        slot2,
+                                                                        MAP_1);
                                        if ((unsigned)df->index ==
                                                               ord_to_idx(ord2))
                                                set_imsm_ord_tbl_ent(map2,
-                                                       slot,
+                                                       slot2,
                                                        df->index |
                                                        IMSM_ORD_REBUILD);
                                }
@@ -4545,7 +4961,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
 
                _disk = __get_imsm_disk(mpb, dl->index);
                if (!_dev || !_disk) {
-                       fprintf(stderr, Name ": BUG mpb setup error\n");
+                       pr_err("BUG mpb setup error\n");
                        return 1;
                }
                *_dev = *dev;
@@ -4592,7 +5008,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;
@@ -4618,31 +5035,36 @@ 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) {
-               fprintf(stderr,
-                       Name ": 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;
        rv = imsm_read_serial(fd, devname, dd->serial);
        if (rv) {
-               fprintf(stderr,
-                       Name ": failed to retrieve scsi serial, aborting\n");
+               pr_err("failed to retrieve scsi serial, aborting\n");
                free(dd);
                abort();
        }
 
        get_dev_size(fd, NULL, &size);
+       /* clear migr_rec when adding disk to container */
+       memset(super->migr_rec_buf, 0, MIGR_REC_BUF_SIZE);
+       if (lseek64(fd, size - MIGR_REC_POSITION, SEEK_SET) >= 0) {
+               if (write(fd, super->migr_rec_buf,
+                       MIGR_REC_BUF_SIZE) != MIGR_REC_BUF_SIZE)
+                       perror("Write migr_rec failed");
+       }
+
        size /= 512;
        serialcpy(dd->disk.serial, dd->serial);
-       dd->disk.total_blocks = __cpu_to_le32(size);
+       set_total_blocks(&dd->disk, size);
+       if (__le32_to_cpu(dd->disk.total_blocks_hi) > 0) {
+               struct imsm_super *mpb = super->anchor;
+               mpb->attributes |= MPB_ATTRIB_2TB_DISK;
+       }
        mark_spare(dd);
        if (sysfs_disk_to_scsi_id(fd, &id) == 0)
                dd->disk.scsi_id = __cpu_to_le32(id);
@@ -4661,7 +5083,6 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
        return 0;
 }
 
-
 static int remove_from_super_imsm(struct supertype *st, mdu_disk_info_t *dk)
 {
        struct intel_super *super = st->sb;
@@ -4672,18 +5093,10 @@ static int remove_from_super_imsm(struct supertype *st, mdu_disk_info_t *dk)
         * is prepared.
         */
        if (!st->update_tail) {
-               fprintf(stderr,
-                       Name ": %s shall be used in mdmon context only"
-                       "(line %d).\n", __func__, __LINE__);
+               pr_err("shall be used in mdmon context only\n");
                return 1;
        }
-       dd = malloc(sizeof(*dd));
-       if (!dd) {
-               fprintf(stderr,
-                       Name ": 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;
@@ -4693,7 +5106,6 @@ static int remove_from_super_imsm(struct supertype *st, mdu_disk_info_t *dk)
        dd->next = super->disk_mgmt_list;
        super->disk_mgmt_list = dd;
 
-
        return 0;
 }
 
@@ -4730,6 +5142,9 @@ static int write_super_imsm_spares(struct intel_super *super, int doclose)
                        continue;
 
                spare->disk[0] = d->disk;
+               if (__le32_to_cpu(d->disk.total_blocks_hi) > 0)
+                       spare->attributes |= MPB_ATTRIB_2TB_DISK;
+
                sum = __gen_imsm_checksum(spare);
                spare->family_num = __cpu_to_le32(sum);
                spare->orig_family_num = 0;
@@ -4737,8 +5152,8 @@ static int write_super_imsm_spares(struct intel_super *super, int doclose)
                spare->check_sum = __cpu_to_le32(sum);
 
                if (store_imsm_mpb(d->fd, spare)) {
-                       fprintf(stderr, "%s: failed for device %d:%d %s\n",
-                               __func__, d->major, d->minor, strerror(errno));
+                       pr_err("failed for device %d:%d %s\n",
+                               d->major, d->minor, strerror(errno));
                        return 1;
                }
                if (doclose) {
@@ -4806,25 +5221,35 @@ static int write_super_imsm(struct supertype *st, int doclose)
        sum = __gen_imsm_checksum(mpb);
        mpb->check_sum = __cpu_to_le32(sum);
 
+       if (super->clean_migration_record_by_mdmon) {
+               clear_migration_record = 1;
+               super->clean_migration_record_by_mdmon = 0;
+       }
        if (clear_migration_record)
-               memset(super->migr_rec_buf, 0, 512);
+               memset(super->migr_rec_buf, 0, MIGR_REC_BUF_SIZE);
 
        /* write the mpb for disks that compose raid devices */
        for (d = super->disks; d ; d = d->next) {
                if (d->index < 0 || is_failed(&d->disk))
                        continue;
-               if (store_imsm_mpb(d->fd, mpb))
-                       fprintf(stderr, "%s: failed for device %d:%d %s\n",
-                               __func__, d->major, d->minor, strerror(errno));
+
                if (clear_migration_record) {
                        unsigned long long dsize;
 
                        get_dev_size(d->fd, NULL, &dsize);
                        if (lseek64(d->fd, dsize - 512, SEEK_SET) >= 0) {
-                               if (write(d->fd, super->migr_rec_buf, 512) != 512)
+                               if (write(d->fd, super->migr_rec_buf,
+                                       MIGR_REC_BUF_SIZE) != MIGR_REC_BUF_SIZE)
                                        perror("Write migr_rec failed");
                        }
                }
+
+               if (store_imsm_mpb(d->fd, mpb))
+                       fprintf(stderr,
+                               "failed for device %d:%d (fd: %d)%s\n",
+                               d->major, d->minor,
+                               d->fd, strerror(errno));
+
                if (doclose) {
                        close(d->fd);
                        d->fd = -1;
@@ -4837,35 +5262,30 @@ static int write_super_imsm(struct supertype *st, int doclose)
        return 0;
 }
 
-
 static int create_array(struct supertype *st, int dev_idx)
 {
        size_t len;
        struct imsm_update_create_array *u;
        struct intel_super *super = st->sb;
        struct imsm_dev *dev = get_imsm_dev(super, dev_idx);
-       struct imsm_map *map = get_imsm_map(dev, 0);
+       struct imsm_map *map = get_imsm_map(dev, MAP_0);
        struct disk_info *inf;
        struct imsm_disk *disk;
        int i;
 
        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);
        inf = get_disk_info(u);
        for (i = 0; i < map->num_members; i++) {
-               int idx = get_imsm_disk_idx(dev, i, -1);
+               int idx = get_imsm_disk_idx(dev, i, MAP_X);
 
                disk = get_imsm_disk(super, idx);
+               if (!disk)
+                       disk = get_imsm_missing(super, idx);
                serialcpy(inf[i].serial, disk->serial);
        }
        append_metadata_update(st, u, len);
@@ -4883,13 +5303,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);
 
@@ -4922,7 +5336,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);
        }
 }
@@ -4951,7 +5365,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)
 {
@@ -4967,8 +5383,8 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
 
        fd = open(dev, O_RDONLY|O_EXCL, 0);
        if (fd < 0) {
-               if (verbose)
-                       fprintf(stderr, Name ": imsm: Cannot open %s: %s\n",
+               if (verbose > 0)
+                       pr_err("imsm: Cannot open %s: %s\n",
                                dev, strerror(errno));
                return 0;
        }
@@ -4981,20 +5397,12 @@ 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) {
-               fprintf(stderr,
-                       Name ": 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];
                fd2devname(fd, str);
-               dprintf("validate_geometry_imsm_container: fd: %d %s orom: %p rv: %d raiddisk: %d\n",
+               dprintf("fd: %d %s orom: %p rv: %d raiddisk: %d\n",
                        fd, str, super->orom, rv, raiddisks);
 #endif
                /* no orom/efi or non-intel hba of the disk */
@@ -5003,17 +5411,25 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
                return 0;
        }
        close(fd);
-       if (super->orom && raiddisks > super->orom->tds) {
-               if (verbose)
-                       fprintf(stderr, Name ": %d exceeds maximum number of"
-                               " platform supported disks: %d\n",
-                               raiddisks, super->orom->tds);
-
-               free_imsm(super);
-               return 0;
+       if (super->orom) {
+               if (raiddisks > super->orom->tds) {
+                       if (verbose)
+                               pr_err("%d exceeds maximum number of"
+                                       " platform supported disks: %d\n",
+                                       raiddisks, super->orom->tds);
+                       free_imsm(super);
+                       return 0;
+               }
+               if ((super->orom->attr & IMSM_OROM_ATTR_2TB_DISK) == 0 &&
+                   (ldsize >> 9) >> 32 > 0) {
+                       if (verbose)
+                               pr_err("%s exceeds maximum platform supported size\n", dev);
+                       free_imsm(super);
+                       return 0;
+               }
        }
 
-       *freesize = avail_size_imsm(st, ldsize >> 9);
+       *freesize = avail_size_imsm(st, ldsize >> 9, data_offset);
        free_imsm(super);
 
        return 1;
@@ -5052,7 +5468,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;
@@ -5061,9 +5477,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
         */
@@ -5119,7 +5532,7 @@ static unsigned long long merge_extents(struct intel_super *super, int sum_exten
        if (maxsize < reserve)
                return 0;
 
-       super->create_offset = ~((__u32) 0);
+       super->create_offset = ~((unsigned long long) 0);
        if (start + reserve > super->create_offset)
                return 0; /* start overflows create_offset */
        super->create_offset = start + reserve;
@@ -5149,6 +5562,346 @@ static int is_raid_level_supported(const struct imsm_orom *orom, int level, int
        return 0;
 }
 
+static int
+active_arrays_by_format(char *name, char* hba, struct md_list **devlist,
+                       int dpa, int verbose)
+{
+       struct mdstat_ent *mdstat = mdstat_read(0, 0);
+       struct mdstat_ent *memb = NULL;
+       int count = 0;
+       int num = 0;
+       struct md_list *dv = NULL;
+       int found;
+
+       for (memb = mdstat ; memb ; memb = memb->next) {
+               if (memb->metadata_version &&
+                   (strncmp(memb->metadata_version, "external:", 9) == 0)  &&
+                   (strcmp(&memb->metadata_version[9], name) == 0) &&
+                   !is_subarray(memb->metadata_version+9) &&
+                   memb->members) {
+                       struct dev_member *dev = memb->members;
+                       int fd = -1;
+                       while(dev && (fd < 0)) {
+                               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;
+                       if ((fd >= 0) && disk_attached_to_hba(fd, hba)) {
+                               struct mdstat_ent *vol;
+                               for (vol = mdstat ; vol ; vol = vol->next) {
+                                       if ((vol->active > 0) &&
+                                           vol->metadata_version &&
+                                           is_container_member(vol, memb->dev)) {
+                                               found++;
+                                               count++;
+                                       }
+                               }
+                               if (*devlist && (found < dpa)) {
+                                       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)
+                               close(fd);
+               }
+       }
+       free_mdstat(mdstat);
+       return count;
+}
+
+#ifdef DEBUG_LOOP
+static struct md_list*
+get_loop_devices(void)
+{
+       int i;
+       struct md_list *devlist = NULL;
+       struct md_list *dv = NULL;
+
+       for(i = 0; i < 12; i++) {
+               dv = xcalloc(1, sizeof(*dv));
+               dv->devname = xmalloc(40);
+               sprintf(dv->devname, "/dev/loop%d", i);
+               dv->next = devlist;
+               devlist = dv;
+       }
+       return devlist;
+}
+#endif
+
+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 examine\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.
@@ -5159,10 +5912,9 @@ static int imsm_default_chunk(const struct imsm_orom *orom)
        return min(512, (1 << fs));
 }
 
-#define pr_vrb(fmt, arg...) (void) (verbose && fprintf(stderr, Name fmt, ##arg))
 static int
 validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
-                           int raiddisks, int *chunk, int verbose)
+                           int raiddisks, int *chunk, unsigned long long size, int verbose)
 {
        /* check/set platform and metadata limits/defaults */
        if (super->orom && raiddisks > super->orom->dpa) {
@@ -5171,17 +5923,17 @@ 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" : "");
                return 0;
        }
 
-       if (chunk && (*chunk == 0 || *chunk == UnSet))
+       if (*chunk == 0 || *chunk == UnSet)
                *chunk = imsm_default_chunk(super->orom);
 
-       if (super->orom && chunk && !imsm_orom_has_chunk(super->orom, *chunk)) {
+       if (super->orom && !imsm_orom_has_chunk(super->orom, *chunk)) {
                pr_vrb(": platform does not support a chunk size of: "
                       "%d\n", *chunk);
                return 0;
@@ -5197,15 +5949,24 @@ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
                                layout, level);
                return 0;
        }
+
+       if (super->orom && (super->orom->attr & IMSM_OROM_ATTR_2TB) == 0 &&
+                       (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 
+/* 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,
+                                        unsigned long long size,
+                                        unsigned long long data_offset,
+                                        char *dev,
                                         unsigned long long *freesize,
                                         int verbose)
 {
@@ -5224,14 +5985,8 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
 
        mpb = super->anchor;
 
-       if (mpb->num_raid_devs > 0 && mpb->num_disks != raiddisks) {
-               fprintf(stderr, Name ": the option-rom requires all "
-                       "member disks to be a member of all volumes.\n");
-               return 0;
-       }
-
-       if (!validate_geometry_imsm_orom(super, level, layout, raiddisks, chunk, verbose)) {
-               fprintf(stderr, Name ": RAID gemetry validation failed. "
+       if (!validate_geometry_imsm_orom(super, level, layout, raiddisks, chunk, size, verbose)) {
+               pr_err("RAID gemetry validation failed. "
                        "Cannot proceed with the action(s).\n");
                return 0;
        }
@@ -5273,7 +6028,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
                }
                if (dcnt < raiddisks) {
                        if (verbose)
-                               fprintf(stderr, Name ": imsm: Not enough "
+                               pr_err("imsm: Not enough "
                                        "devices with space for this array "
                                        "(%d < %d)\n",
                                        dcnt, raiddisks);
@@ -5294,7 +6049,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
        }
        if (!dl) {
                if (verbose)
-                       fprintf(stderr, Name ": %s is not in the "
+                       pr_err("%s is not in the "
                                "same imsm set\n", dev);
                return 0;
        } else if (super->orom && dl->index < 0 && mpb->num_raid_devs) {
@@ -5303,9 +6058,14 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
                 * understand this configuration (all member disks must be
                 * members of each array in the container).
                 */
-               fprintf(stderr, Name ": %s is a spare and a volume"
+               pr_err("%s is a spare and a volume"
                        " is already defined for this container\n", dev);
-               fprintf(stderr, Name ": The option-rom requires all member"
+               pr_err("The option-rom requires all member"
+                       " disks to be a member of all volumes\n");
+               return 0;
+       } else if (super->orom && mpb->num_raid_devs > 0 &&
+                  mpb->num_disks != raiddisks) {
+               pr_err("The option-rom requires all member"
                        " disks to be a member of all volumes\n");
                return 0;
        }
@@ -5328,13 +6088,13 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
                dl->extent_cnt = i;
        } else {
                if (verbose)
-                       fprintf(stderr, Name ": unable to determine free space for: %s\n",
+                       pr_err("unable to determine free space for: %s\n",
                                dev);
                return 0;
        }
        if (maxsize < size) {
                if (verbose)
-                       fprintf(stderr, Name ": %s not enough space (%llu < %llu)\n",
+                       pr_err("%s not enough space (%llu < %llu)\n",
                                dev, maxsize, size);
                return 0;
        }
@@ -5349,25 +6109,41 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
 
        if (!check_env("IMSM_NO_PLATFORM") &&
            mpb->num_raid_devs > 0 && size && size != maxsize) {
-               fprintf(stderr, Name ": attempting to create a second "
+               pr_err("attempting to create a second "
                        "volume with size less then remaining space. "
                        "Aborting...\n");
                return 0;
        }
 
        if (maxsize < size || maxsize == 0) {
-               if (verbose)
-                       fprintf(stderr, Name ": not enough space after merge (%llu < %llu)\n",
-                               maxsize, size);
+               if (verbose) {
+                       if (maxsize == 0)
+                               pr_err("no free space"
+                                               " left on device. Aborting...\n");
+                       else
+                               pr_err("not enough space"
+                                               " to create volume of given size"
+                                               " (%llu < %llu). Aborting...\n",
+                                               maxsize, size);
+               }
                return 0;
        }
 
        *freesize = maxsize;
 
+       if (super->orom) {
+               int count = count_volumes(super->hba->path,
+                                     super->orom->dpa, verbose);
+               if (super->orom->vphba <= count) {
+                       pr_vrb(": platform does not support more than %d raid volumes.\n",
+                              super->orom->vphba);
+                       return 0;
+               }
+       }
        return 1;
 }
 
-static int reserve_space(struct supertype *st, int raiddisks,
+static int imsm_get_free_size(struct supertype *st, int raiddisks,
                         unsigned long long size, int chunk,
                         unsigned long long *freesize)
 {
@@ -5419,7 +6195,7 @@ static int reserve_space(struct supertype *st, int raiddisks,
            (super->orom && used && used != raiddisks) ||
            maxsize < minsize ||
            maxsize == 0) {
-               fprintf(stderr, Name ": not enough devices with space to create array.\n");
+               pr_err("not enough devices with space to create array.\n");
                return 0; /* No enough free spaces large enough */
        }
 
@@ -5429,8 +6205,15 @@ static int reserve_space(struct supertype *st, int raiddisks,
                        size /= 2 * chunk;
                        size *= 2 * chunk;
                }
+               maxsize = size;
+       }
+       if (!check_env("IMSM_NO_PLATFORM") &&
+           mpb->num_raid_devs > 0 && size && size != maxsize) {
+               pr_err("attempting to create a second "
+                       "volume with size less then remaining space. "
+                       "Aborting...\n");
+               return 0;
        }
-
        cnt = 0;
        for (dl = super->disks; dl; dl = dl->next)
                if (dl->e)
@@ -5438,11 +6221,35 @@ static int reserve_space(struct supertype *st, int raiddisks,
 
        *freesize = size;
 
+       dprintf("imsm: imsm_get_free_size() returns : %llu\n", size);
+
        return 1;
 }
 
+static int reserve_space(struct supertype *st, int raiddisks,
+                        unsigned long long size, int chunk,
+                        unsigned long long *freesize)
+{
+       struct intel_super *super = st->sb;
+       struct dl *dl;
+       int cnt;
+       int rv = 0;
+
+       rv = imsm_get_free_size(st, raiddisks, size, chunk, freesize);
+       if (rv) {
+               cnt = 0;
+               for (dl = super->disks; dl; dl = dl->next)
+                       if (dl->e)
+                               dl->raiddisk = cnt++;
+               rv = 1;
+       }
+
+       return rv;
+}
+
 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)
 {
@@ -5458,15 +6265,17 @@ 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,
+                                                       size, data_offset,
                                                        dev, freesize,
                                                        verbose);
        }
-       
+
        if (!dev) {
                if (st->sb) {
+                       struct intel_super *super = st->sb;
                        if (!validate_geometry_imsm_orom(st->sb, level, layout,
-                                                        raiddisks, chunk,
+                                                        raiddisks, chunk, size,
                                                         verbose))
                                return 0;
                        /* we are being asked to automatically layout a
@@ -5477,9 +6286,22 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                         * created.  add_to_super and getinfo_super
                         * detect when autolayout is in progress.
                         */
+                       /* assuming that freesize is always given when array is
+                          created */
+                       if (super->orom && freesize) {
+                               int count;
+                               count = count_volumes(super->hba->path,
+                                                     super->orom->dpa, verbose);
+                               if (super->orom->vphba <= count) {
+                                       pr_vrb(": platform does not support more"
+                                              " than %d raid volumes.\n",
+                                              super->orom->vphba);
+                                       return 0;
+                               }
+                       }
                        if (freesize)
                                return reserve_space(st, raiddisks, size,
-                                                    chunk?*chunk:0, freesize);
+                                                    *chunk, freesize);
                }
                return 1;
        }
@@ -5487,6 +6309,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);
        }
 
@@ -5494,15 +6317,14 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
        fd = open(dev, O_RDONLY|O_EXCL, 0);
        if (fd >= 0) {
                if (verbose)
-                       fprintf(stderr,
-                               Name ": Cannot create this array on device %s\n",
-                               dev);
+                       pr_err("Cannot create this array on device %s\n",
+                              dev);
                close(fd);
                return 0;
        }
        if (errno != EBUSY || (fd = open(dev, O_RDONLY, 0)) < 0) {
                if (verbose)
-                       fprintf(stderr, Name ": Cannot open %s: %s\n",
+                       pr_err("Cannot open %s: %s\n",
                                dev, strerror(errno));
                return 0;
        }
@@ -5511,11 +6333,11 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
        close(fd);
        if (cfd < 0) {
                if (verbose)
-                       fprintf(stderr, Name ": Cannot use %s: It is busy\n",
+                       pr_err("Cannot use %s: It is busy\n",
                                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;
@@ -5526,20 +6348,20 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                 */
                struct intel_super *super;
 
-               if (load_super_imsm_all(st, cfd, (void **) &super, NULL) == 0) {
+               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;
                }
        }
 
        if (verbose)
-               fprintf(stderr, Name ": failed container membership check\n");
+               pr_err("failed container membership check\n");
 
        close(cfd);
        return 0;
@@ -5586,20 +6408,17 @@ static int kill_subarray_imsm(struct supertype *st)
                if (i < current_vol)
                        continue;
                sprintf(subarray, "%u", i);
-               if (is_subarray_active(subarray, st->devname)) {
-                       fprintf(stderr,
-                               Name ": deleting subarray-%d would change the UUID of active subarray-%d, aborting\n",
-                               current_vol, i);
+               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);
 
                        return 2;
                }
        }
 
        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));
@@ -5645,9 +6464,8 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
                char *ep;
                int vol;
 
-               if (is_subarray_active(subarray, st->devname)) {
-                       fprintf(stderr,
-                               Name ": Unable to update name of active subarray\n");
+               if (is_subarray_active(subarray, st->devnm)) {
+                       pr_err("Unable to update name of active subarray\n");
                        return 2;
                }
 
@@ -5659,10 +6477,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);
@@ -5710,7 +6526,7 @@ static int is_rebuilding(struct imsm_dev *dev)
        if (migr_type(dev) != MIGR_REBUILD)
                return 0;
 
-       migr_map = get_imsm_map(dev, 1);
+       migr_map = get_imsm_map(dev, MAP_1);
 
        if (migr_map->map_state == IMSM_T_STATE_DEGRADED)
                return 1;
@@ -5718,6 +6534,26 @@ static int is_rebuilding(struct imsm_dev *dev)
                return 0;
 }
 
+#ifndef MDASSEMBLE
+static int is_initializing(struct imsm_dev *dev)
+{
+       struct imsm_map *migr_map;
+
+       if (!dev->vol.migr_state)
+               return 0;
+
+       if (migr_type(dev) != MIGR_INIT)
+               return 0;
+
+       migr_map = get_imsm_map(dev, MAP_1);
+
+       if (migr_map->map_state == IMSM_T_STATE_UNINITIALIZED)
+               return 1;
+
+       return 0;
+}
+#endif
+
 static void update_recovery_start(struct intel_super *super,
                                        struct imsm_dev *dev,
                                        struct mdinfo *array)
@@ -5742,7 +6578,7 @@ static void update_recovery_start(struct intel_super *super,
                 * IMSM_ORD_REBUILD, so assume they are missing and the
                 * disk_ord_tbl was not correctly updated
                 */
-               dprintf("%s: failed to locate out-of-sync disk\n", __func__);
+               dprintf("failed to locate out-of-sync disk\n");
                return;
        }
 
@@ -5776,18 +6612,17 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
        /* do not assemble arrays when not all attributes are supported */
        if (imsm_check_attributes(mpb->attributes) == 0) {
                sb_errors = 1;
-               fprintf(stderr, Name ": Unsupported attributes in IMSM metadata."
+               pr_err("Unsupported attributes in IMSM metadata."
                        "Arrays activation is blocked.\n");
        }
 
        /* check for bad blocks */
        if (imsm_bbm_log_size(super->anchor)) {
-               fprintf(stderr, Name ": BBM log found in IMSM metadata."
-                       "Arrays activation is blocked.\n");
+               pr_err("BBM log found in IMSM metadata."
+                      "Arrays activation is blocked.\n");
                sb_errors = 1;
        }
 
-
        /* count spare devices, not used in maps
         */
        for (d = super->disks; d; d = d->next)
@@ -5799,7 +6634,10 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                struct imsm_map *map;
                struct imsm_map *map2;
                struct mdinfo *this;
-               int slot, chunk;
+               int slot;
+#ifndef MDASSEMBLE
+               int chunk;
+#endif
                char *ep;
 
                if (subarray &&
@@ -5807,15 +6645,15 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                        continue;
 
                dev = get_imsm_dev(super, i);
-               map = get_imsm_map(dev, 0);
-               map2 = get_imsm_map(dev, 1);
+               map = get_imsm_map(dev, MAP_0);
+               map2 = get_imsm_map(dev, MAP_1);
 
                /* do not publish arrays that are in the middle of an
                 * unsupported migration
                 */
                if (dev->vol.migr_state &&
                    (migr_type(dev) == MIGR_STATE_CHANGE)) {
-                       fprintf(stderr, Name ": cannot assemble volume '%.16s':"
+                       pr_err("cannot assemble volume '%.16s':"
                                " unsupported migration in progress\n",
                                dev->volume);
                        continue;
@@ -5824,26 +6662,21 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                 * OROM/EFI
                 */
 
-               chunk = __le16_to_cpu(map->blocks_per_strip) >> 1;
-               this = malloc(sizeof(*this));
-               if (!this) {
-                       fprintf(stderr, Name ": failed to allocate %zu bytes\n",
-                               sizeof(*this));
-                       break;
-               }
+               this = xmalloc(sizeof(*this));
 
                super->current_vol = i;
                getinfo_super_imsm_volume(st, this, NULL);
                this->next = rest;
 #ifndef MDASSEMBLE
+               chunk = __le16_to_cpu(map->blocks_per_strip) >> 1;
                /* mdadm does not support all metadata features- set the bit in all arrays state */
                if (!validate_geometry_imsm_orom(super,
                                                 get_imsm_raid_level(map), /* RAID level */
                                                 imsm_level_to_layout(get_imsm_raid_level(map)),
                                                 map->num_members, /* raid disks */
-                                                &chunk,
+                                                &chunk, join_u32(dev->size_low, dev->size_high),
                                                 1 /* verbose */)) {
-                       fprintf(stderr, Name ": IMSM RAID geometry validation"
+                       pr_err("IMSM RAID geometry validation"
                                " failed.  Array %s activation is blocked.\n",
                                dev->volume);
                        this->array.state |=
@@ -5867,8 +6700,8 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                        __u32 ord;
 
                        skip = 0;
-                       idx = get_imsm_disk_idx(dev, slot, 0);
-                       ord = get_imsm_ord_tbl_ent(dev, slot, -1);
+                       idx = get_imsm_disk_idx(dev, slot, MAP_0);
+                       ord = get_imsm_ord_tbl_ent(dev, slot, MAP_X);
                        for (d = super->disks; d ; d = d->next)
                                if (d->index == idx)
                                        break;
@@ -5881,7 +6714,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                        if (ord & IMSM_ORD_REBUILD)
                                recovery_start = 0;
 
-                       /* 
+                       /*
                         * if we skip some disks the array will be assmebled degraded;
                         * reset resync start to avoid a dirty-degraded
                         * situation when performing the intial sync
@@ -5893,21 +6726,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) {
-                               fprintf(stderr, Name ": 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;
 
@@ -5931,8 +6750,8 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                                this->array.working_disks++;
 
                        info_d->events = __le32_to_cpu(mpb->generation_num);
-                       info_d->data_offset = __le32_to_cpu(map->pba_of_lba0);
-                       info_d->component_size = __le32_to_cpu(map->blocks_per_member);
+                       info_d->data_offset = pba_of_lba0(map);
+                       info_d->component_size = blocks_per_member(map);
                }
                /* now that the disk list is up-to-date fixup recovery_start */
                update_recovery_start(super, dev, this);
@@ -5949,7 +6768,6 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
        return rest;
 }
 
-
 static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev,
                                int failed, int look_in_map)
 {
@@ -5958,7 +6776,7 @@ static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev,
        map = get_imsm_map(dev, look_in_map);
 
        if (!failed)
-               return map->map_state == IMSM_T_STATE_UNINITIALIZED ? 
+               return map->map_state == IMSM_T_STATE_UNINITIALIZED ?
                        IMSM_T_STATE_UNINITIALIZED : IMSM_T_STATE_NORMAL;
 
        switch (get_imsm_raid_level(map)) {
@@ -5983,12 +6801,12 @@ static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev,
                int insync = insync;
 
                for (i = 0; i < map->num_members; i++) {
-                       __u32 ord = get_imsm_ord_tbl_ent(dev, i, -1);
+                       __u32 ord = get_imsm_ord_tbl_ent(dev, i, MAP_X);
                        int idx = ord_to_idx(ord);
                        struct imsm_disk *disk;
 
                        /* reset the potential in-sync count on even-numbered
-                        * slots.  num_copies is always 2 for imsm raid10 
+                        * slots.  num_copies is always 2 for imsm raid10
                         */
                        if ((i & 1) == 0)
                                insync = 2;
@@ -6044,8 +6862,11 @@ static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev,
 
        for (i = 0; i < map_for_loop->num_members; i++) {
                idx_1 = -255;
+               /* when MAP_X is passed both maps failures are counted
+                */
                if (prev &&
-                   (look_in_map & MAP_1) && (i < prev->num_members)) {
+                   ((look_in_map == MAP_1) || (look_in_map == MAP_X)) &&
+                   (i < prev->num_members)) {
                        ord = __le32_to_cpu(prev->disk_ord_tbl[i]);
                        idx_1 = ord_to_idx(ord);
 
@@ -6053,7 +6874,8 @@ static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev,
                        if (!disk || is_failed(disk) || ord & IMSM_ORD_REBUILD)
                                failed++;
                }
-               if ((look_in_map & MAP_0) && (i < map->num_members)) {
+               if (((look_in_map == MAP_0) || (look_in_map == MAP_X)) &&
+                   (i < map->num_members)) {
                        ord = __le32_to_cpu(map->disk_ord_tbl[i]);
                        idx = ord_to_idx(ord);
 
@@ -6075,10 +6897,9 @@ static int imsm_open_new(struct supertype *c, struct active_array *a,
 {
        struct intel_super *super = c->sb;
        struct imsm_super *mpb = super->anchor;
-       
+
        if (atoi(inst) >= mpb->num_raid_devs) {
-               fprintf(stderr, "%s: subarry index %d, out of range\n",
-                       __func__, atoi(inst));
+               pr_err("subarry index %d, out of range\n", atoi(inst));
                return -ENODEV;
        }
 
@@ -6101,7 +6922,7 @@ static int is_resyncing(struct imsm_dev *dev)
        if (migr_type(dev) == MIGR_GEN_MIGR)
                return 0;
 
-       migr_map = get_imsm_map(dev, 1);
+       migr_map = get_imsm_map(dev, MAP_1);
 
        if ((migr_map->map_state == IMSM_T_STATE_NORMAL) &&
            (dev->vol.migr_type != MIGR_GEN_MIGR))
@@ -6120,7 +6941,7 @@ static int mark_failure(struct imsm_dev *dev, struct imsm_disk *disk, int idx)
        unsigned int len, shift = 0;
 
        /* new failures are always set in map[0] */
-       map = get_imsm_map(dev, 0);
+       map = get_imsm_map(dev, MAP_0);
 
        slot = get_imsm_disk_slot(map, idx);
        if (slot < 0)
@@ -6139,10 +6960,17 @@ static int mark_failure(struct imsm_dev *dev, struct imsm_disk *disk, int idx)
 
        disk->status |= FAILED_DISK;
        set_imsm_ord_tbl_ent(map, slot, idx | IMSM_ORD_REBUILD);
-       if (is_gen_migration(dev)) {
-               struct imsm_map *map2 = get_imsm_map(dev, 1);
-               if (slot < map2->num_members)
-                       set_imsm_ord_tbl_ent(map2, slot,
+       /* mark failures in second map if second map exists and this disk
+        * in this slot.
+        * This is valid for migration, initialization and rebuild
+        */
+       if (dev->vol.migr_state) {
+               struct imsm_map *map2 = get_imsm_map(dev, MAP_1);
+               int slot2 = get_imsm_disk_slot(map2, idx);
+
+               if ((slot2 < map2->num_members) &&
+                   (slot2 >= 0))
+                       set_imsm_ord_tbl_ent(map2, slot2,
                                             idx | IMSM_ORD_REBUILD);
        }
        if (map->failed_disk_num == 0xff)
@@ -6168,15 +6996,34 @@ 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
+        */
+       if (is_gen_migration(dev) == 0) {
+               __u8 map_state;
+               int failed;
+
+               failed = imsm_count_failed(super, dev, MAP_0);
+               map_state = imsm_check_degraded(super, dev, failed, MAP_0);
+
+               if (failed)
+                       end_migration(dev, super, map_state);
+       }
        for (dl = super->missing; dl; dl = dl->next)
                mark_missing(dev, &dl->disk, dl->index);
        super->updates_pending++;
 }
 
-static unsigned long long imsm_set_array_size(struct imsm_dev *dev)
+static unsigned long long imsm_set_array_size(struct imsm_dev *dev,
+                                             long long new_size)
 {
-       int used_disks = imsm_num_data_members(dev, 0);
+       int used_disks = imsm_num_data_members(dev, MAP_0);
        unsigned long long array_blocks;
        struct imsm_map *map;
 
@@ -6193,8 +7040,17 @@ static unsigned long long imsm_set_array_size(struct imsm_dev *dev)
 
        /* set array size in metadata
         */
-       map = get_imsm_map(dev, 0);
-       array_blocks = map->blocks_per_member * used_disks;
+       if (new_size <= 0) {
+               /* OLCE size change is caused by added disks
+                */
+               map = get_imsm_map(dev, MAP_0);
+               array_blocks = blocks_per_member(map) * used_disks;
+       } else {
+               /* Online Volume Size Change
+                * Using  available free space
+                */
+               array_blocks = new_size;
+       }
 
        /* round array size down to closest MB
         */
@@ -6221,7 +7077,7 @@ static void imsm_progress_container_reshape(struct intel_super *super)
 
        for (i = 0; i < mpb->num_raid_devs; i++) {
                struct imsm_dev *dev = get_imsm_dev(super, i);
-               struct imsm_map *map = get_imsm_map(dev, 0);
+               struct imsm_map *map = get_imsm_map(dev, MAP_0);
                struct imsm_map *map2;
                int prev_num_members;
 
@@ -6246,12 +7102,13 @@ static void imsm_progress_container_reshape(struct intel_super *super)
                for (i = prev_num_members;
                     i < map->num_members; i++)
                        set_imsm_ord_tbl_ent(map, i, i);
-               map2 = get_imsm_map(dev, 1);
+               map2 = get_imsm_map(dev, MAP_1);
                /* Copy the current map */
                memcpy(map2, map, copy_map_size);
                map2->num_members = prev_num_members;
 
-               imsm_set_array_size(dev);
+               imsm_set_array_size(dev, -1);
+               super->clean_migration_record_by_mdmon = 1;
                super->updates_pending++;
        }
 }
@@ -6266,7 +7123,7 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
        int inst = a->info.container_member;
        struct intel_super *super = a->container->sb;
        struct imsm_dev *dev = get_imsm_dev(super, inst);
-       struct imsm_map *map = get_imsm_map(dev, 0);
+       struct imsm_map *map = get_imsm_map(dev, MAP_0);
        int failed = imsm_count_failed(super, dev, MAP_0);
        __u8 map_state = imsm_check_degraded(super, dev, failed, MAP_0);
        __u32 blocks_per_unit;
@@ -6290,12 +7147,14 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
                                 * user action is required to recover process
                                 */
                                if (0) {
-                               struct imsm_map *map2 = get_imsm_map(dev, 1);
-                               dev->vol.migr_state = 0;
-                               set_migr_type(dev, 0);
-                               dev->vol.curr_migr_unit = 0;
-                               memcpy(map, map2, sizeof_imsm_map(map2));
-                               super->updates_pending++;
+                                       struct imsm_map *map2 =
+                                               get_imsm_map(dev, MAP_1);
+                                       dev->vol.migr_state = 0;
+                                       set_migr_type(dev, 0);
+                                       dev->vol.curr_migr_unit = 0;
+                                       memcpy(map, map2,
+                                              sizeof_imsm_map(map2));
+                                       super->updates_pending++;
                                }
                        }
                        if (a->last_checkpoint >= a->info.component_size) {
@@ -6303,10 +7162,10 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
                                int used_disks;
                                struct mdinfo *mdi;
 
-                               used_disks = imsm_num_data_members(dev, 0);
+                               used_disks = imsm_num_data_members(dev, MAP_0);
                                if (used_disks > 0) {
                                        array_blocks =
-                                               map->blocks_per_member *
+                                               blocks_per_member(map) *
                                                used_disks;
                                        /* round array size down to closest MB
                                         */
@@ -6410,14 +7269,16 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
        int inst = a->info.container_member;
        struct intel_super *super = a->container->sb;
        struct imsm_dev *dev = get_imsm_dev(super, inst);
-       struct imsm_map *map = get_imsm_map(dev, 0);
+       struct imsm_map *map = get_imsm_map(dev, MAP_0);
        struct imsm_disk *disk;
+       struct mdinfo *mdi;
+       int recovery_not_finished = 0;
        int failed;
        __u32 ord;
        __u8 map_state;
 
        if (n > map->num_members)
-               fprintf(stderr, "imsm: set_disk %d out of range 0..%d\n",
+               pr_err("imsm: set_disk %d out of range 0..%d\n",
                        n, map->num_members - 1);
 
        if (n < 0)
@@ -6425,7 +7286,7 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
 
        dprintf("imsm: set_disk %d:%x\n", n, state);
 
-       ord = get_imsm_ord_tbl_ent(dev, n, 0);
+       ord = get_imsm_ord_tbl_ent(dev, n, MAP_0);
        disk = get_imsm_disk(super, ord_to_idx(ord));
 
        /* check for new failures */
@@ -6436,7 +7297,7 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
 
        /* check if in_sync */
        if (state & DS_INSYNC && ord & IMSM_ORD_REBUILD && is_rebuilding(dev)) {
-               struct imsm_map *migr_map = get_imsm_map(dev, 1);
+               struct imsm_map *migr_map = get_imsm_map(dev, MAP_1);
 
                set_imsm_ord_tbl_ent(migr_map, n, ord_to_idx(ord));
                super->updates_pending++;
@@ -6446,49 +7307,103 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
        map_state = imsm_check_degraded(super, dev, failed, MAP_0);
 
        /* check if recovery complete, newly degraded, or failed */
-       if (map_state == IMSM_T_STATE_NORMAL && is_rebuilding(dev)) {
-               end_migration(dev, super, map_state);
-               map = get_imsm_map(dev, 0);
-               map->failed_disk_num = ~0;
-               super->updates_pending++;
-               a->last_checkpoint = 0;
-       } else if (map_state == IMSM_T_STATE_DEGRADED &&
-                  map->map_state != map_state &&
-                  !dev->vol.migr_state) {
-               dprintf("imsm: mark degraded\n");
-               map->map_state = map_state;
-               super->updates_pending++;
-               a->last_checkpoint = 0;
-       } else if (map_state == IMSM_T_STATE_FAILED &&
-                  map->map_state != map_state) {
-               dprintf("imsm: mark failed\n");
-               end_migration(dev, super, map_state);
-               super->updates_pending++;
-               a->last_checkpoint = 0;
-       } else if (is_gen_migration(dev)) {
-               dprintf("imsm: Detected General Migration in state: ");
-
-               switch (map_state) {
-               case IMSM_T_STATE_NORMAL:
-                       dprintf("normal\n");
+       dprintf("imsm: Detected transition to state ");
+       switch (map_state) {
+       case IMSM_T_STATE_NORMAL: /* transition to normal state */
+               dprintf("normal: ");
+               if (is_rebuilding(dev)) {
+                       dprintf_cont("while rebuilding");
+                       /* check if recovery is really finished */
+                       for (mdi = a->info.devs; mdi ; mdi = mdi->next)
+                               if (mdi->recovery_start != MaxSector) {
+                                       recovery_not_finished = 1;
+                                       break;
+                               }
+                       if (recovery_not_finished) {
+                               dprintf_cont("\n");
+                               dprintf("Rebuild has not finished yet, state not changed");
+                               if (a->last_checkpoint < mdi->recovery_start) {
+                                       a->last_checkpoint = mdi->recovery_start;
+                                       super->updates_pending++;
+                               }
+                               break;
+                       }
+                       end_migration(dev, super, map_state);
+                       map = get_imsm_map(dev, MAP_0);
+                       map->failed_disk_num = ~0;
+                       super->updates_pending++;
+                       a->last_checkpoint = 0;
+                       break;
+               }
+               if (is_gen_migration(dev)) {
+                       dprintf_cont("while general migration");
                        if (a->last_checkpoint >= a->info.component_size)
                                end_migration(dev, super, map_state);
-                       map = get_imsm_map(dev, 0);
+                       else
+                               map->map_state = map_state;
+                       map = get_imsm_map(dev, MAP_0);
                        map->failed_disk_num = ~0;
+                       super->updates_pending++;
+                       break;
+               }
+       break;
+       case IMSM_T_STATE_DEGRADED: /* transition to degraded state */
+               dprintf_cont("degraded: ");
+               if ((map->map_state != map_state) &&
+                   !dev->vol.migr_state) {
+                       dprintf_cont("mark degraded");
+                       map->map_state = map_state;
+                       super->updates_pending++;
+                       a->last_checkpoint = 0;
                        break;
-               case IMSM_T_STATE_DEGRADED:
-                       dprintf("degraded\n");
+               }
+               if (is_rebuilding(dev)) {
+                       dprintf_cont("while rebuilding.");
+                       if (map->map_state != map_state)  {
+                               dprintf_cont(" Map state change");
+                               end_migration(dev, super, map_state);
+                               super->updates_pending++;
+                       }
+                       break;
+               }
+               if (is_gen_migration(dev)) {
+                       dprintf_cont("while general migration");
                        if (a->last_checkpoint >= a->info.component_size)
                                end_migration(dev, super, map_state);
-                       else
+                       else {
+                               map->map_state = map_state;
                                manage_second_map(super, dev);
+                       }
+                       super->updates_pending++;
                        break;
-               default:
-                       dprintf("failed\n");
                }
-               map->map_state = map_state;
-               super->updates_pending++;
+               if (is_initializing(dev)) {
+                       dprintf_cont("while initialization.");
+                       map->map_state = map_state;
+                       super->updates_pending++;
+                       break;
+               }
+       break;
+       case IMSM_T_STATE_FAILED: /* transition to failed state */
+               dprintf_cont("failed: ");
+               if (is_gen_migration(dev)) {
+                       dprintf_cont("while general migration");
+                       map->map_state = map_state;
+                       super->updates_pending++;
+                       break;
+               }
+               if (map->map_state != map_state) {
+                       dprintf_cont("mark failed");
+                       end_migration(dev, super, map_state);
+                       super->updates_pending++;
+                       a->last_checkpoint = 0;
+                       break;
+               }
+       break;
+       default:
+               dprintf_cont("state %i\n", map_state);
        }
+       dprintf_cont("\n");
 }
 
 static int store_imsm_mpb(int fd, struct imsm_super *mpb)
@@ -6539,7 +7454,7 @@ static void imsm_sync_metadata(struct supertype *container)
 static struct dl *imsm_readd(struct intel_super *super, int idx, struct active_array *a)
 {
        struct imsm_dev *dev = get_imsm_dev(super, a->info.container_member);
-       int i = get_imsm_disk_idx(dev, idx, -1);
+       int i = get_imsm_disk_idx(dev, idx, MAP_X);
        struct dl *dl;
 
        for (dl = super->disks; dl; dl = dl->next)
@@ -6550,7 +7465,7 @@ static struct dl *imsm_readd(struct intel_super *super, int idx, struct active_a
                dl = NULL;
 
        if (dl)
-               dprintf("%s: found %x:%x\n", __func__, dl->major, dl->minor);
+               dprintf("found %x:%x\n", dl->major, dl->minor);
 
        return dl;
 }
@@ -6560,7 +7475,7 @@ static struct dl *imsm_add_spare(struct intel_super *super, int slot,
                                 struct mdinfo *additional_test_list)
 {
        struct imsm_dev *dev = get_imsm_dev(super, a->info.container_member);
-       int idx = get_imsm_disk_idx(dev, slot, -1);
+       int idx = get_imsm_disk_idx(dev, slot, MAP_X);
        struct imsm_super *mpb = super->anchor;
        struct imsm_map *map;
        unsigned long long pos;
@@ -6622,7 +7537,7 @@ static struct dl *imsm_add_spare(struct intel_super *super, int slot,
                }
                for (i = 0; i < mpb->num_raid_devs; i++) {
                        dev = get_imsm_dev(super, i);
-                       map = get_imsm_map(dev, 0);
+                       map = get_imsm_map(dev, MAP_0);
 
                        /* check if this disk is already a member of
                         * this array
@@ -6633,9 +7548,9 @@ static struct dl *imsm_add_spare(struct intel_super *super, int slot,
                        found = 0;
                        j = 0;
                        pos = 0;
-                       array_start = __le32_to_cpu(map->pba_of_lba0);
+                       array_start = pba_of_lba0(map);
                        array_end = array_start +
-                                   __le32_to_cpu(map->blocks_per_member) - 1;
+                                   blocks_per_member(map) - 1;
 
                        do {
                                /* check that we can start at pba_of_lba0 with
@@ -6666,7 +7581,6 @@ static struct dl *imsm_add_spare(struct intel_super *super, int slot,
        return dl;
 }
 
-
 static int imsm_rebuild_allowed(struct supertype *cont, int dev_idx, int failed)
 {
        struct imsm_dev *dev2;
@@ -6678,10 +7592,9 @@ static int imsm_rebuild_allowed(struct supertype *cont, int dev_idx, int failed)
 
        dev2 = get_imsm_dev(cont->sb, dev_idx);
        if (dev2) {
-               state = imsm_check_degraded(cont->sb, dev2, failed,
-                                           MAP_0);
+               state = imsm_check_degraded(cont->sb, dev2, failed, MAP_0);
                if (state == IMSM_T_STATE_FAILED) {
-                       map = get_imsm_map(dev2, 0);
+                       map = get_imsm_map(dev2, MAP_0);
                        if (!map)
                                return 1;
                        for (slot = 0; slot < map->num_members; slot++) {
@@ -6689,7 +7602,7 @@ static int imsm_rebuild_allowed(struct supertype *cont, int dev_idx, int failed)
                                 * Check if failed disks are deleted from intel
                                 * disk list or are marked to be deleted
                                 */
-                               idx = get_imsm_disk_idx(dev2, slot, -1);
+                               idx = get_imsm_disk_idx(dev2, slot, MAP_X);
                                idisk = get_imsm_dl_disk(cont->sb, idx);
                                /*
                                 * Do not rebuild the array if failed disks
@@ -6723,7 +7636,7 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
        struct intel_super *super = a->container->sb;
        int inst = a->info.container_member;
        struct imsm_dev *dev = get_imsm_dev(super, inst);
-       struct imsm_map *map = get_imsm_map(dev, 0);
+       struct imsm_map *map = get_imsm_map(dev, MAP_0);
        int failed = a->info.array.raid_disks;
        struct mdinfo *rv = NULL;
        struct mdinfo *d;
@@ -6750,6 +7663,14 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
        if (imsm_reshape_blocks_arrays_changes(super))
                        return NULL;
 
+       /* Cannot activate another spare if rebuild is in progress already
+        */
+       if (is_rebuilding(dev)) {
+               dprintf("imsm: No spare activation allowed. "
+                       "Rebuild in progress already.\n");
+               return NULL;
+       }
+
        if (a->info.array.level == 4)
                /* No repair for takeovered array
                 * imsm doesn't support raid4
@@ -6803,12 +7724,9 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
                        dl = imsm_add_spare(super, i, a, 1, rv);
                if (!dl)
                        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
@@ -6828,7 +7746,7 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
                di->disk.minor = dl->minor;
                di->disk.state = 0;
                di->recovery_start = 0;
-               di->data_offset = __le32_to_cpu(map->pba_of_lba0);
+               di->data_offset = pba_of_lba0(map);
                di->component_size = a->info.component_size;
                di->container_member = inst;
                super->random = random32();
@@ -6846,24 +7764,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;
@@ -6888,15 +7791,15 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
 static int disks_overlap(struct intel_super *super, int idx, struct imsm_update_create_array *u)
 {
        struct imsm_dev *dev = get_imsm_dev(super, idx);
-       struct imsm_map *map = get_imsm_map(dev, 0);
-       struct imsm_map *new_map = get_imsm_map(&u->dev, 0);
+       struct imsm_map *map = get_imsm_map(dev, MAP_0);
+       struct imsm_map *new_map = get_imsm_map(&u->dev, MAP_0);
        struct disk_info *inf = get_disk_info(u);
        struct imsm_disk *disk;
        int i;
        int j;
 
        for (i = 0; i < map->num_members; i++) {
-               disk = get_imsm_disk(super, get_imsm_disk_idx(dev, i, -1));
+               disk = get_imsm_disk(super, get_imsm_disk_idx(dev, i, MAP_X));
                for (j = 0; j < new_map->num_members; j++)
                        if (serialcmp(disk->serial, inf[j].serial) == 0)
                                return 1;
@@ -6905,7 +7808,6 @@ static int disks_overlap(struct intel_super *super, int idx, struct imsm_update_
        return 0;
 }
 
-
 static struct dl *get_disk_super(struct intel_super *super, int major, int minor)
 {
        struct dl *dl = NULL;
@@ -6930,8 +7832,7 @@ static int remove_disk_super(struct intel_super *super, int major, int minor)
                                super->disks = dl->next;
                        dl->next = NULL;
                        __free_imsm_disk(dl);
-                       dprintf("%s: removed %x:%x\n",
-                               __func__, major, minor);
+                       dprintf("removed %x:%x\n", major, minor);
                        break;
                }
                prev = dl;
@@ -6957,9 +7858,8 @@ static int add_remove_disk_update(struct intel_super *super)
                        disk_cfg->next = super->disks;
                        super->disks = disk_cfg;
                        check_degraded = 1;
-                       dprintf("%s: added %x:%x\n",
-                               __func__, disk_cfg->major,
-                               disk_cfg->minor);
+                       dprintf("added %x:%x\n",
+                               disk_cfg->major, disk_cfg->minor);
                } else if (disk_cfg->action == DISK_REMOVE) {
                        dprintf("Disk remove action processed: %x.%x\n",
                                disk_cfg->major, disk_cfg->minor);
@@ -6983,7 +7883,6 @@ static int add_remove_disk_update(struct intel_super *super)
        return check_degraded;
 }
 
-
 static int apply_reshape_migration_update(struct imsm_update_reshape_migration *u,
                                                struct intel_super *super,
                                                void ***space_list)
@@ -6992,7 +7891,7 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration *
        void **tofree = NULL;
        int ret_val = 0;
 
-       dprintf("apply_reshape_migration_update()\n");
+       dprintf("(enter)\n");
        if ((u->subdev < 0) ||
            (u->subdev > 1)) {
                dprintf("imsm: Error: Wrong subdev: %i\n", u->subdev);
@@ -7009,7 +7908,7 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration *
                        struct imsm_map *map;
                        struct imsm_dev *new_dev =
                                (struct imsm_dev *)*space_list;
-                       struct imsm_map *migr_map = get_imsm_map(dev, 1);
+                       struct imsm_map *migr_map = get_imsm_map(dev, MAP_1);
                        int to_state;
                        struct dl *new_disk;
 
@@ -7017,7 +7916,7 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration *
                                return ret_val;
                        *space_list = **space_list;
                        memcpy(new_dev, dev, sizeof_imsm_dev(dev, 0));
-                       map = get_imsm_map(new_dev, 0);
+                       map = get_imsm_map(new_dev, MAP_0);
                        if (migr_map) {
                                dprintf("imsm: Error: migration in progress");
                                return ret_val;
@@ -7037,7 +7936,7 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration *
                        migrate(new_dev, super, to_state, MIGR_GEN_MIGR);
                        if (u->new_level > -1)
                                map->raid_level = u->new_level;
-                       migr_map = get_imsm_map(new_dev, 1);
+                       migr_map = get_imsm_map(new_dev, MAP_1);
                        if ((u->new_level == 5) &&
                            (migr_map->raid_level == 0)) {
                                int ord = map->num_members - 1;
@@ -7091,7 +7990,7 @@ skip_disk_add:
                        *tofree = *space_list;
                        /* calculate new size
                         */
-                       imsm_set_array_size(new_dev);
+                       imsm_set_array_size(new_dev, -1);
 
                        ret_val = 1;
                }
@@ -7106,13 +8005,49 @@ error_disk_add:
        return ret_val;
 }
 
+static int apply_size_change_update(struct imsm_update_size_change *u,
+               struct intel_super *super)
+{
+       struct intel_dev *id;
+       int ret_val = 0;
+
+       dprintf("(enter)\n");
+       if ((u->subdev < 0) ||
+           (u->subdev > 1)) {
+               dprintf("imsm: Error: Wrong subdev: %i\n", u->subdev);
+               return ret_val;
+       }
+
+       for (id = super->devlist ; id; id = id->next) {
+               if (id->index == (unsigned)u->subdev) {
+                       struct imsm_dev *dev = get_imsm_dev(super, u->subdev);
+                       struct imsm_map *map = get_imsm_map(dev, MAP_0);
+                       int used_disks = imsm_num_data_members(dev, MAP_0);
+                       unsigned long long blocks_per_member;
+
+                       /* calculate new size
+                        */
+                       blocks_per_member = u->new_size / used_disks;
+                       dprintf("(size: %llu, blocks per member: %llu)\n",
+                               u->new_size, blocks_per_member);
+                       set_blocks_per_member(map, blocks_per_member);
+                       imsm_set_array_size(dev, u->new_size);
+
+                       ret_val = 1;
+                       break;
+               }
+       }
+
+       return ret_val;
+}
+
 static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
-                                      struct intel_super *super,       
+                                      struct intel_super *super,
                                       struct active_array *active_array)
 {
        struct imsm_super *mpb = super->anchor;
        struct imsm_dev *dev = get_imsm_dev(super, u->array);
-       struct imsm_map *map = get_imsm_map(dev, 0);
+       struct imsm_map *map = get_imsm_map(dev, MAP_0);
        struct imsm_map *migr_map;
        struct active_array *a;
        struct imsm_disk *disk;
@@ -7125,7 +8060,7 @@ static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
        int second_map_created = 0;
 
        for (; u; u = u->next) {
-               victim = get_imsm_disk_idx(dev, u->slot, -1);
+               victim = get_imsm_disk_idx(dev, u->slot, MAP_X);
 
                if (victim < 0)
                        return 0;
@@ -7135,7 +8070,7 @@ static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
                                break;
 
                if (!dl) {
-                       fprintf(stderr, "error: imsm_activate_spare passed "
+                       pr_err("error: imsm_activate_spare passed "
                                "an unknown disk (index: %d)\n",
                                u->dl->index);
                        return 0;
@@ -7149,7 +8084,7 @@ static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
                        if (i == u->slot)
                                continue;
                        disk = get_imsm_disk(super,
-                                            get_imsm_disk_idx(dev, i, -1));
+                                            get_imsm_disk_idx(dev, i, MAP_X));
                        if (!disk || is_failed(disk))
                                failed++;
                }
@@ -7164,15 +8099,14 @@ static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
                disk->status &= ~SPARE_DISK;
 
                /* mark rebuild */
-               to_state = imsm_check_degraded(super, dev, failed,
-                                              MAP_0);
+               to_state = imsm_check_degraded(super, dev, failed, MAP_0);
                if (!second_map_created) {
                        second_map_created = 1;
                        map->map_state = IMSM_T_STATE_DEGRADED;
                        migrate(dev, super, to_state, MIGR_REBUILD);
                } else
                        map->map_state = to_state;
-               migr_map = get_imsm_map(dev, 1);
+               migr_map = get_imsm_map(dev, MAP_1);
                set_imsm_ord_tbl_ent(map, u->slot, dl->index);
                set_imsm_ord_tbl_ent(migr_map, u->slot,
                                     dl->index | IMSM_ORD_REBUILD);
@@ -7190,7 +8124,7 @@ static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
                found = 0;
                for (a = active_array; a ; a = a->next) {
                        dev = get_imsm_dev(super, a->info.container_member);
-                       map = get_imsm_map(dev, 0);
+                       map = get_imsm_map(dev, MAP_0);
 
                        if (get_imsm_disk_slot(map, victim) >= 0)
                                found++;
@@ -7237,7 +8171,7 @@ static int apply_reshape_container_disks_update(struct imsm_update_reshape *u,
        int ret_val = 0;
        unsigned int dev_id;
 
-       dprintf("imsm: apply_reshape_container_disks_update()\n");
+       dprintf("(enter)\n");
 
        /* enable spares to use in array */
        for (i = 0; i < delta_disks; i++) {
@@ -7282,8 +8216,8 @@ static int apply_reshape_container_disks_update(struct imsm_update_reshape *u,
                newdev = (void*)sp;
                /* Copy the dev, but not (all of) the map */
                memcpy(newdev, id->dev, sizeof(*newdev));
-               oldmap = get_imsm_map(id->dev, 0);
-               newmap = get_imsm_map(newdev, 0);
+               oldmap = get_imsm_map(id->dev, MAP_0);
+               newmap = get_imsm_map(newdev, MAP_0);
                /* Copy the current map */
                memcpy(newmap, oldmap, sizeof_imsm_map(oldmap));
                /* update one device only
@@ -7303,10 +8237,10 @@ static int apply_reshape_container_disks_update(struct imsm_update_reshape *u,
                        }
                        /* New map is correct, now need to save old map
                         */
-                       newmap = get_imsm_map(newdev, 1);
+                       newmap = get_imsm_map(newdev, MAP_1);
                        memcpy(newmap, oldmap, sizeof_imsm_map(oldmap));
 
-                       imsm_set_array_size(newdev);
+                       imsm_set_array_size(newdev, -1);
                }
 
                sp = (void **)id->dev;
@@ -7346,7 +8280,7 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
        if (dev == NULL)
                return 0;
 
-       map = get_imsm_map(dev, 0);
+       map = get_imsm_map(dev, MAP_0);
 
        if (u->direction == R10_TO_R0) {
                /* Number of failed disks must be half of initial disk number */
@@ -7410,7 +8344,7 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
                dev_new = (void *)space;
                memcpy(dev_new, dev, sizeof(*dev));
                /* update new map */
-               map = get_imsm_map(dev_new, 0);
+               map = get_imsm_map(dev_new, MAP_0);
                map->num_members = map->num_members * 2;
                map->map_state = IMSM_T_STATE_DEGRADED;
                map->num_domains = 2;
@@ -7442,9 +8376,9 @@ static void imsm_process_update(struct supertype *st,
         *      the arrays for general migration and convert selected spares
         *      into active devices.
         *    update_activate_spare - a spare device has replaced a failed
-        *      device in an array, update the disk_ord_tbl.  If this disk is
-        *      present in all member arrays then also clear the SPARE_DISK
-        *      flag
+        *      device in an array, update the disk_ord_tbl.  If this disk is
+        *      present in all member arrays then also clear the SPARE_DISK
+        *      flag
         *    update_create_array
         *    update_kill_array
         *    update_rename_array
@@ -7478,8 +8412,7 @@ static void imsm_process_update(struct supertype *st,
                struct imsm_update_general_migration_checkpoint *u =
                                                        (void *)update->buf;
 
-               dprintf("imsm: process_update() "
-                       "for update_general_migration_checkpoint called\n");
+               dprintf("called for update_general_migration_checkpoint\n");
 
                /* find device under general migration */
                for (id = super->devlist ; id; id = id->next) {
@@ -7514,8 +8447,14 @@ static void imsm_process_update(struct supertype *st,
                        super->updates_pending++;
                break;
        }
+       case update_size_change: {
+               struct imsm_update_size_change *u = (void *)update->buf;
+               if (apply_size_change_update(u, super))
+                       super->updates_pending++;
+               break;
+       }
        case update_activate_spare: {
-               struct imsm_update_activate_spare *u = (void *) update->buf; 
+               struct imsm_update_activate_spare *u = (void *) update->buf;
                if (apply_update_activate_spare(u, super, st->arrays))
                        super->updates_pending++;
                break;
@@ -7542,21 +8481,20 @@ static void imsm_process_update(struct supertype *st,
 
                /* handle racing creates: first come first serve */
                if (u->dev_idx < mpb->num_raid_devs) {
-                       dprintf("%s: subarray %d already defined\n",
-                               __func__, u->dev_idx);
+                       dprintf("subarray %d already defined\n", u->dev_idx);
                        goto create_error;
                }
 
                /* check update is next in sequence */
                if (u->dev_idx != mpb->num_raid_devs) {
-                       dprintf("%s: can not create array %d expected index %d\n",
-                               __func__, u->dev_idx, mpb->num_raid_devs);
+                       dprintf("can not create array %d expected index %d\n",
+                               u->dev_idx, mpb->num_raid_devs);
                        goto create_error;
                }
 
-               new_map = get_imsm_map(&u->dev, 0);
-               new_start = __le32_to_cpu(new_map->pba_of_lba0);
-               new_end = new_start + __le32_to_cpu(new_map->blocks_per_member);
+               new_map = get_imsm_map(&u->dev, MAP_0);
+               new_start = pba_of_lba0(new_map);
+               new_end = new_start + blocks_per_member(new_map);
                inf = get_disk_info(u);
 
                /* handle activate_spare versus create race:
@@ -7565,9 +8503,9 @@ static void imsm_process_update(struct supertype *st,
                 */
                for (i = 0; i < mpb->num_raid_devs; i++) {
                        dev = get_imsm_dev(super, i);
-                       map = get_imsm_map(dev, 0);
-                       start = __le32_to_cpu(map->pba_of_lba0);
-                       end = start + __le32_to_cpu(map->blocks_per_member);
+                       map = get_imsm_map(dev, MAP_0);
+                       start = pba_of_lba0(map);
+                       end = start + blocks_per_member(map);
                        if ((new_start >= start && new_start <= end) ||
                            (start >= new_start && start <= new_end))
                                /* overlap */;
@@ -7575,14 +8513,14 @@ static void imsm_process_update(struct supertype *st,
                                continue;
 
                        if (disks_overlap(super, i, u)) {
-                               dprintf("%s: arrays overlap\n", __func__);
+                               dprintf("arrays overlap\n");
                                goto create_error;
                        }
                }
 
                /* check that prepare update was successful */
                if (!update->space) {
-                       dprintf("%s: prepare update failed\n", __func__);
+                       dprintf("prepare update failed\n");
                        goto create_error;
                }
 
@@ -7594,7 +8532,7 @@ static void imsm_process_update(struct supertype *st,
                for (i = 0; i < new_map->num_members; i++) {
                        dl = serial_to_dl(inf[i].serial, super);
                        if (!dl) {
-                               dprintf("%s: disk disappeared\n", __func__);
+                               dprintf("disk disappeared\n");
                                goto create_error;
                        }
                }
@@ -7700,7 +8638,7 @@ static void imsm_process_update(struct supertype *st,
        }
        case update_add_remove_disk: {
                /* we may be able to repair some arrays if disks are
-                * being added, check teh status of add_remove_disk
+                * being added, check the status of add_remove_disk
                 * if discs has been added.
                 */
                if (add_remove_disk_update(super)) {
@@ -7713,15 +8651,15 @@ static void imsm_process_update(struct supertype *st,
                break;
        }
        default:
-               fprintf(stderr, "error: unsuported process update type:"
+               pr_err("error: unsuported process update type:"
                        "(type: %d)\n", type);
        }
 }
 
 static struct mdinfo *get_spares_for_grow(struct supertype *st);
 
-static void imsm_prepare_update(struct supertype *st,
-                               struct metadata_update *update)
+static int imsm_prepare_update(struct supertype *st,
+                              struct metadata_update *update)
 {
        /**
         * Allocate space to hold new disk entries, raid-device entries or a new
@@ -7730,35 +8668,38 @@ static void imsm_prepare_update(struct supertype *st,
         * integrated by the monitor thread without worrying about live pointers
         * in the manager thread.
         */
-       enum imsm_update_type type = *(enum imsm_update_type *) update->buf;
+       enum imsm_update_type type;
        struct intel_super *super = st->sb;
        struct imsm_super *mpb = super->anchor;
        size_t buf_len;
        size_t len = 0;
 
+       if (update->len < (int)sizeof(type))
+               return 0;
+
+       type = *(enum imsm_update_type *) update->buf;
+
        switch (type) {
        case update_general_migration_checkpoint:
-               dprintf("imsm: prepare_update() "
-                       "for update_general_migration_checkpoint called\n");
+               if (update->len < (int)sizeof(struct imsm_update_general_migration_checkpoint))
+                       return 0;
+               dprintf("called for update_general_migration_checkpoint\n");
                break;
        case update_takeover: {
                struct imsm_update_takeover *u = (void *)update->buf;
+               if (update->len < (int)sizeof(*u))
+                       return 0;
                if (u->direction == R0_TO_R10) {
                        void **tail = (void **)&update->space_list;
                        struct imsm_dev *dev = get_imsm_dev(super, u->subarray);
-                       struct imsm_map *map = get_imsm_map(dev, 0);
+                       struct imsm_map *map = get_imsm_map(dev, MAP_0);
                        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;
@@ -7766,24 +8707,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;
@@ -7801,7 +8729,10 @@ static void imsm_prepare_update(struct supertype *st,
                struct intel_dev *dl;
                void **space_tail = (void**)&update->space_list;
 
-               dprintf("imsm: imsm_prepare_update() for update_reshape\n");
+               if (update->len < (int)sizeof(*u))
+                       return 0;
+
+               dprintf("for update_reshape\n");
 
                for (dl = super->devlist; dl; dl = dl->next) {
                        int size = sizeof_imsm_dev(dl->dev, 1);
@@ -7809,9 +8740,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;
@@ -7835,7 +8764,10 @@ static void imsm_prepare_update(struct supertype *st,
                void *s;
                int current_level = -1;
 
-               dprintf("imsm: imsm_prepare_update() for update_reshape\n");
+               if (update->len < (int)sizeof(*u))
+                       return 0;
+
+               dprintf("for update_reshape\n");
 
                /* add space for bigger array in update
                 */
@@ -7845,9 +8777,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;
@@ -7860,12 +8790,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;
@@ -7878,7 +8803,7 @@ static void imsm_prepare_update(struct supertype *st,
                                struct imsm_map *map;
 
                                dev = get_imsm_dev(super, u->subdev);
-                               map = get_imsm_map(dev, 0);
+                               map = get_imsm_map(dev, MAP_0);
                                current_level = map->raid_level;
                                break;
                        }
@@ -7908,29 +8833,35 @@ static void imsm_prepare_update(struct supertype *st,
                dprintf("New anchor length is %llu\n", (unsigned long long)len);
                break;
        }
+       case update_size_change: {
+               if (update->len < (int)sizeof(struct imsm_update_size_change))
+                       return 0;
+               break;
+       }
+       case update_activate_spare: {
+               if (update->len < (int)sizeof(struct imsm_update_activate_spare))
+                       return 0;
+               break;
+       }
        case update_create_array: {
                struct imsm_update_create_array *u = (void *) update->buf;
                struct intel_dev *dv;
                struct imsm_dev *dev = &u->dev;
-               struct imsm_map *map = get_imsm_map(dev, 0);
+               struct imsm_map *map = get_imsm_map(dev, MAP_0);
                struct dl *dl;
                struct disk_info *inf;
                int i;
                int activate = 0;
 
+               if (update->len < (int)sizeof(*u))
+                       return 0;
+
                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++) {
@@ -7946,9 +8877,22 @@ static void imsm_prepare_update(struct supertype *st,
                }
                len += activate * sizeof(struct imsm_disk);
                break;
-       default:
+       }
+       case update_kill_array: {
+               if (update->len < (int)sizeof(struct imsm_update_kill_array))
+                       return 0;
+               break;
+       }
+       case update_rename_array: {
+               if (update->len < (int)sizeof(struct imsm_update_rename_array))
+                       return 0;
                break;
        }
+       case update_add_remove_disk:
+               /* no update->len needed */
+               break;
+       default:
+               return 0;
        }
 
        /* check if we need a larger metadata buffer */
@@ -7972,6 +8916,7 @@ static void imsm_prepare_update(struct supertype *st,
                else
                        super->next_buf = NULL;
        }
+       return 1;
 }
 
 /* must be called while manager is quiesced */
@@ -7984,8 +8929,7 @@ static void imsm_delete(struct intel_super *super, struct dl **dlp, unsigned ind
        int i, j, num_members;
        __u32 ord;
 
-       dprintf("%s: deleting device[%d] from imsm_super\n",
-               __func__, index);
+       dprintf("deleting device[%d] from imsm_super\n", index);
 
        /* shift all indexes down one */
        for (iter = super->disks; iter; iter = iter->next)
@@ -7997,20 +8941,20 @@ static void imsm_delete(struct intel_super *super, struct dl **dlp, unsigned ind
 
        for (i = 0; i < mpb->num_raid_devs; i++) {
                dev = get_imsm_dev(super, i);
-               map = get_imsm_map(dev, 0);
+               map = get_imsm_map(dev, MAP_0);
                num_members = map->num_members;
                for (j = 0; j < num_members; j++) {
                        /* update ord entries being careful not to propagate
                         * ord-flags to the first map
                         */
-                       ord = get_imsm_ord_tbl_ent(dev, j, -1);
+                       ord = get_imsm_ord_tbl_ent(dev, j, MAP_X);
 
                        if (ord_to_idx(ord) <= index)
                                continue;
 
-                       map = get_imsm_map(dev, 0);
+                       map = get_imsm_map(dev, MAP_0);
                        set_imsm_ord_tbl_ent(map, j, ord_to_idx(ord - 1));
-                       map = get_imsm_map(dev, 1);
+                       map = get_imsm_map(dev, MAP_1);
                        if (map)
                                set_imsm_ord_tbl_ent(map, j, ord - 1);
                }
@@ -8047,6 +8991,7 @@ static int imsm_get_allowed_degradation(int level, int raid_disks,
                                        struct imsm_dev *dev)
 {
        switch (level) {
+       case 1:
        case 10:{
                int ret_val = 0;
                struct imsm_map *map;
@@ -8056,7 +9001,7 @@ static int imsm_get_allowed_degradation(int level, int raid_disks,
                /* check map if all disks pairs not failed
                 * in both maps
                 */
-               map = get_imsm_map(dev, 0);
+               map = get_imsm_map(dev, MAP_0);
                for (i = 0; i < ret_val; i++) {
                        int degradation = 0;
                        if (get_imsm_disk(super, i) == NULL)
@@ -8066,7 +9011,7 @@ static int imsm_get_allowed_degradation(int level, int raid_disks,
                        if (degradation == 2)
                                return 0;
                }
-               map = get_imsm_map(dev, 1);
+               map = get_imsm_map(dev, MAP_1);
                /* if there is no second map
                 * result can be returned
                 */
@@ -8094,7 +9039,6 @@ static int imsm_get_allowed_degradation(int level, int raid_disks,
        }
 }
 
-
 /*******************************************************************************
  * Function:   open_backup_targets
  * Description:        Function opens file descriptors for all devices given in
@@ -8135,7 +9079,7 @@ int open_backup_targets(struct mdinfo *info, int raid_disks, int *raid_fds,
                             sd->disk.minor, 1);
                raid_fds[sd->disk.raid_disk] = dev_open(dn, O_RDWR);
                if (raid_fds[sd->disk.raid_disk] < 0) {
-                       fprintf(stderr, "cannot open component\n");
+                       pr_err("cannot open component\n");
                        continue;
                }
                opened++;
@@ -8146,13 +9090,90 @@ int open_backup_targets(struct mdinfo *info, int raid_disks, int *raid_fds,
                        imsm_get_allowed_degradation(info->new_level,
                                                     raid_disks,
                                                     super, dev)) {
-               fprintf(stderr, "Not enough disks can be opened.\n");
+               pr_err("Not enough disks can be opened.\n");
                close_targets(raid_fds, raid_disks);
                return -2;
        }
        return 0;
 }
 
+/*******************************************************************************
+ * Function:   validate_container_imsm
+ * Description: This routine validates container after assemble,
+ *             eg. if devices in container are under the same controller.
+ *
+ * Parameters:
+ *     info    : linked list with info about devices used in array
+ * Returns:
+ *     1 : HBA mismatch
+ *     0 : Success
+ ******************************************************************************/
+int validate_container_imsm(struct mdinfo *info)
+{
+       if (check_env("IMSM_NO_PLATFORM"))
+               return 0;
+
+       struct sys_dev *idev;
+       struct sys_dev *hba = NULL;
+       struct sys_dev *intel_devices = find_intel_devices();
+       char *dev_path = devt_to_devpath(makedev(info->disk.major,
+                                                                       info->disk.minor));
+
+       for (idev = intel_devices; idev; idev = idev->next) {
+               if (dev_path && strstr(dev_path, idev->path)) {
+                       hba = idev;
+                       break;
+               }
+       }
+       if (dev_path)
+               free(dev_path);
+
+       if (!hba) {
+               pr_err("WARNING - Cannot detect HBA for device %s!\n",
+                               devid2kname(makedev(info->disk.major, info->disk.minor)));
+               return 1;
+       }
+
+       const struct imsm_orom *orom = get_orom_by_device_id(hba->dev_id);
+       struct mdinfo *dev;
+
+       for (dev = info->next; dev; dev = dev->next) {
+               dev_path = devt_to_devpath(makedev(dev->disk.major, dev->disk.minor));
+
+               struct sys_dev *hba2 = NULL;
+               for (idev = intel_devices; idev; idev = idev->next) {
+                       if (dev_path && strstr(dev_path, idev->path)) {
+                               hba2 = idev;
+                               break;
+                       }
+               }
+               if (dev_path)
+                       free(dev_path);
+
+               const struct imsm_orom *orom2 = hba2 == NULL ? NULL :
+                               get_orom_by_device_id(hba2->dev_id);
+
+               if (hba2 && hba->type != hba2->type) {
+                       pr_err("WARNING - HBAs of devices do not match %s != %s\n",
+                               get_sys_dev_type(hba->type), get_sys_dev_type(hba2->type));
+                       return 1;
+               }
+
+               if (orom != orom2) {
+                       pr_err("WARNING - IMSM container assembled with disks under different HBAs!\n"
+                               "       This operation is not supported and can lead to data loss.\n");
+                       return 1;
+               }
+
+               if (!orom) {
+                       pr_err("WARNING - IMSM container assembled with disks under HBAs without IMSM platform support!\n"
+                               "       This operation is not supported and can lead to data loss.\n");
+                       return 1;
+               }
+       }
+
+       return 0;
+}
 #ifndef MDASSEMBLE
 /*******************************************************************************
  * Function:   init_migr_record_imsm
@@ -8175,8 +9196,8 @@ void init_migr_record_imsm(struct supertype *st, struct imsm_dev *dev,
        struct mdinfo *sd;
        char nm[30];
        int fd;
-       struct imsm_map *map_dest = get_imsm_map(dev, 0);
-       struct imsm_map *map_src = get_imsm_map(dev, 1);
+       struct imsm_map *map_dest = get_imsm_map(dev, MAP_0);
+       struct imsm_map *map_src = get_imsm_map(dev, MAP_1);
        unsigned long long num_migr_units;
        unsigned long long array_blocks;
 
@@ -8188,8 +9209,9 @@ void init_migr_record_imsm(struct supertype *st, struct imsm_dev *dev,
 
        migr_rec->dest_depth_per_unit = GEN_MIGR_AREA_SIZE /
                max(map_dest->blocks_per_strip, map_src->blocks_per_strip);
-       migr_rec->dest_depth_per_unit *= map_dest->blocks_per_strip;
-       new_data_disks = imsm_num_data_members(dev, 0);
+       migr_rec->dest_depth_per_unit *=
+               max(map_dest->blocks_per_strip, map_src->blocks_per_strip);
+       new_data_disks = imsm_num_data_members(dev, MAP_0);
        migr_rec->blocks_per_unit =
                __cpu_to_le32(migr_rec->dest_depth_per_unit * new_data_disks);
        migr_rec->dest_depth_per_unit =
@@ -8205,7 +9227,6 @@ void init_migr_record_imsm(struct supertype *st, struct imsm_dev *dev,
        migr_rec->post_migr_vol_cap =  dev->size_low;
        migr_rec->post_migr_vol_cap_hi = dev->size_high;
 
-
        /* Find the smallest dev */
        for (sd = info->devs ; sd ; sd = sd->next) {
                sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
@@ -8253,23 +9274,19 @@ int save_backup_imsm(struct supertype *st,
        unsigned long long *target_offsets = NULL;
        int *targets = NULL;
        int i;
-       struct imsm_map *map_dest = get_imsm_map(dev, 0);
+       struct imsm_map *map_dest = get_imsm_map(dev, MAP_0);
        int new_disks = map_dest->num_members;
        int dest_layout = 0;
        int dest_chunk;
        unsigned long long start;
-       int data_disks = imsm_num_data_members(dev, 0);
+       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++) {
@@ -8300,7 +9317,7 @@ int save_backup_imsm(struct supertype *st,
                            start,
                            length,
                            buf) != 0) {
-               fprintf(stderr, Name ": Error restoring stripes\n");
+               pr_err("Error restoring stripes\n");
                goto abort;
        }
 
@@ -8418,7 +9435,7 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
        if (id == NULL)
                return 1;
 
-       map_dest = get_imsm_map(id->dev, 0);
+       map_dest = get_imsm_map(id->dev, MAP_0);
        new_disks = map_dest->num_members;
 
        read_offset = (unsigned long long)
@@ -8426,18 +9443,15 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
 
        write_offset = ((unsigned long long)
                        __le32_to_cpu(migr_rec->dest_1st_member_lba) +
-                       __le32_to_cpu(map_dest->pba_of_lba0)) * 512;
+                       pba_of_lba0(map_dest)) * 512;
 
        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)) {
-               fprintf(stderr,
-                       Name ": Cannot open some devices belonging to array.\n");
+               pr_err("Cannot open some devices belonging to array.\n");
                goto abort;
        }
 
@@ -8447,30 +9461,26 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
                        continue;
                }
                if (lseek64(targets[i], read_offset, SEEK_SET) < 0) {
-                       fprintf(stderr,
-                               Name ": Cannot seek to block: %s\n",
-                               strerror(errno));
+                       pr_err("Cannot seek to block: %s\n",
+                              strerror(errno));
                        skipped_disks++;
                        continue;
                }
                if ((unsigned)read(targets[i], buf, unit_len) != unit_len) {
-                       fprintf(stderr,
-                               Name ": Cannot read copy area block: %s\n",
-                               strerror(errno));
+                       pr_err("Cannot read copy area block: %s\n",
+                              strerror(errno));
                        skipped_disks++;
                        continue;
                }
                if (lseek64(targets[i], write_offset, SEEK_SET) < 0) {
-                       fprintf(stderr,
-                               Name ": Cannot seek to block: %s\n",
-                               strerror(errno));
+                       pr_err("Cannot seek to block: %s\n",
+                              strerror(errno));
                        skipped_disks++;
                        continue;
                }
                if ((unsigned)write(targets[i], buf, unit_len) != unit_len) {
-                       fprintf(stderr,
-                               Name ": Cannot restore block: %s\n",
-                               strerror(errno));
+                       pr_err("Cannot restore block: %s\n",
+                              strerror(errno));
                        skipped_disks++;
                        continue;
                }
@@ -8480,9 +9490,8 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
                                                         new_disks,
                                                         super,
                                                         id->dev)) {
-               fprintf(stderr,
-                       Name ": Cannot restore data from backup."
-                       " Too many failed disks\n");
+               pr_err("Cannot restore data from backup."
+                      " Too many failed disks\n");
                goto abort;
        }
 
@@ -8513,7 +9522,7 @@ static const char *imsm_get_disk_controller_domain(const char *path)
        char *drv=NULL;
        struct stat st;
 
-       strncpy(disk_path, disk_by_path, PATH_MAX - 1);
+       strcpy(disk_path, disk_by_path);
        strncat(disk_path, path, PATH_MAX - strlen(disk_path) - 1);
        if (stat(disk_path, &st) == 0) {
                struct sys_dev* hba;
@@ -8527,35 +9536,35 @@ static const char *imsm_get_disk_controller_domain(const char *path)
                        drv = "isci";
                else if (hba && hba->type == SYS_DEV_SATA)
                        drv = "ahci";
-               else 
+               else
                        drv = "unknown";
                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,
                                                struct geo_params *geo,
-                                               int *old_raid_disks)
+                                               int *old_raid_disks,
+                                               int direction)
 {
        /* currently we only support increasing the number of devices
         * for a container.  This increases the number of device for each
@@ -8566,10 +9575,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 ||
@@ -8579,10 +9587,15 @@ static int imsm_reshape_is_allowed_on_container(struct supertype *st,
                return ret_val;
        }
 
+       if (direction == ROLLBACK_METADATA_CHANGES) {
+               dprintf("imsm: Metadata changes rollback is not supported for "
+                       "container operation.\n");
+               return ret_val;
+       }
+
        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);
@@ -8639,10 +9652,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;
                }
@@ -8653,19 +9665,19 @@ static int imsm_reshape_is_allowed_on_container(struct supertype *st,
                ret_val = 1;
 
        if (ret_val)
-               dprintf("\tContainer operation allowed\n");
+               dprintf("Container operation allowed\n");
        else
-               dprintf("\tError: %i\n", ret_val);
+               dprintf("Error: %i\n", ret_val);
 
        return ret_val;
 }
 
 /* Function: get_spares_for_grow
  * Description: Allocates memory and creates list of spare devices
- *             avaliable in container. Checks if spare drive size is acceptable.
+ *             avaliable in container. Checks if spare drive size is acceptable.
  * Parameters: Pointer to the supertype structure
  * Returns: Pointer to the list of spare devices (mdinfo structure) on success,
- *             NULL if fail
+ *             NULL if fail
  */
 static struct mdinfo *get_spares_for_grow(struct supertype *st)
 {
@@ -8693,8 +9705,7 @@ static int imsm_create_metadata_update_for_reshape(
        int delta_disks = 0;
        struct mdinfo *dev;
 
-       dprintf("imsm_update_metadata_for_reshape(enter) raid_disks = %i\n",
-               geo->raid_disks);
+       dprintf("(enter) raid_disks = %i\n", geo->raid_disks);
 
        delta_disks = geo->raid_disks - old_raid_disks;
 
@@ -8704,12 +9715,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;
@@ -8720,7 +9726,7 @@ static int imsm_create_metadata_update_for_reshape(
 
        if (spares == NULL
            || delta_disks > spares->array.spare_disks) {
-               fprintf(stderr, Name ": imsm: ERROR: Cannot get spare devices "
+               pr_err("imsm: ERROR: Cannot get spare devices "
                        "for %s.\n", geo->dev_name);
                i = -1;
                goto abort;
@@ -8753,16 +9759,46 @@ abort:
 
        dprintf("imsm: reshape update preparation :");
        if (i == delta_disks) {
-               dprintf(" OK\n");
+               dprintf_cont(" OK\n");
                *updatep = u;
                return update_memory_size;
        }
        free(u);
-       dprintf(" Error\n");
+       dprintf_cont(" Error\n");
 
        return 0;
 }
 
+/******************************************************************************
+ * function: imsm_create_metadata_update_for_size_change()
+ *           Creates update for IMSM array for array size change.
+ *
+ ******************************************************************************/
+static int imsm_create_metadata_update_for_size_change(
+                               struct supertype *st,
+                               struct geo_params *geo,
+                               struct imsm_update_size_change **updatep)
+{
+       struct intel_super *super = st->sb;
+       int update_memory_size = 0;
+       struct imsm_update_size_change *u = NULL;
+
+       dprintf("(enter) New size = %llu\n", geo->size);
+
+       /* size of all update data without anchor */
+       update_memory_size = sizeof(struct imsm_update_size_change);
+
+       u = xcalloc(1, update_memory_size);
+       u->type = update_size_change;
+       u->subdev = super->current_vol;
+       u->new_size = geo->size;
+
+       dprintf("imsm: reshape update preparation : OK\n");
+       *updatep = u;
+
+       return update_memory_size;
+}
+
 /******************************************************************************
  * function: imsm_create_metadata_update_for_migration()
  *           Creates update for IMSM array.
@@ -8779,18 +9815,12 @@ static int imsm_create_metadata_update_for_migration(
        struct imsm_dev *dev;
        int previous_level = -1;
 
-       dprintf("imsm_create_metadata_update_for_migration(enter)"
-               " New Level = %i\n", geo->level);
+       dprintf("(enter) New Level = %i\n", geo->level);
 
        /* 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;
@@ -8803,7 +9833,7 @@ static int imsm_create_metadata_update_for_migration(
        if (dev) {
                struct imsm_map *map;
 
-               map = get_imsm_map(dev, 0);
+               map = get_imsm_map(dev, MAP_0);
                if (map) {
                        int current_chunk_size =
                                __le16_to_cpu(map->blocks_per_strip) / 2;
@@ -8848,8 +9878,8 @@ static void imsm_update_metadata_locally(struct supertype *st,
        mu.space = NULL;
        mu.space_list = NULL;
        mu.next = NULL;
-       imsm_prepare_update(st, &mu);
-       imsm_process_update(st, &mu);
+       if (imsm_prepare_update(st, &mu))
+               imsm_process_update(st, &mu);
 
        while (mu.space_list) {
                void **space = mu.space_list;
@@ -8861,19 +9891,30 @@ static void imsm_update_metadata_locally(struct supertype *st,
 /***************************************************************************
 * Function:    imsm_analyze_change
 * Description: Function analyze change for single volume
-*              and validate if transition is supported
-* Parameters:  Geometry parameters, supertype structure
+*              and validate if transition is supported
+* Parameters:  Geometry parameters, supertype structure,
+*              metadata change direction (apply/rollback)
 * Returns:     Operation type code on success, -1 if fail
 ****************************************************************************/
 enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
-                                          struct geo_params *geo)
+                                          struct geo_params *geo,
+                                          int direction)
 {
        struct mdinfo info;
        int change = -1;
        int check_devs = 0;
        int chunk;
-       int devNumChange=0;
-       int layout = -1;
+       /* number of added/removed disks in operation result */
+       int devNumChange = 0;
+       /* imsm compatible layout value for array geometry verification */
+       int imsm_layout = -1;
+       int data_disks;
+       struct imsm_dev *dev;
+       struct intel_super *super;
+       unsigned long long current_size;
+       unsigned long long free_size;
+       unsigned long long max_size;
+       int rv;
 
        getinfo_super_imsm_volume(st, &info, NULL);
        if ((geo->level != info.array.level) &&
@@ -8884,21 +9925,20 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                        if (geo->level == 5) {
                                change = CH_MIGRATION;
                                if (geo->layout != ALGORITHM_LEFT_ASYMMETRIC) {
-                                       fprintf(stderr,
-                                       Name " Error. Requested Layout "
-                                       "not supported (left-asymmetric layout "
-                                       "is supported only)!\n");
+                                       pr_err("Error. Requested Layout "
+                                              "not supported (left-asymmetric layout "
+                                              "is supported only)!\n");
                                        change = -1;
                                        goto analyse_change_exit;
                                }
-                               layout =  geo->layout;
+                               imsm_layout =  geo->layout;
                                check_devs = 1;
                                devNumChange = 1; /* parity disk added */
                        } else if (geo->level == 10) {
                                change = CH_TAKEOVER;
                                check_devs = 1;
                                devNumChange = 2; /* two mirrors added */
-                               layout = 0x102; /* imsm supported layout */
+                               imsm_layout = 0x102; /* imsm supported layout */
                        }
                        break;
                case 1:
@@ -8907,15 +9947,14 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                                change = CH_TAKEOVER;
                                check_devs = 1;
                                devNumChange = -(geo->raid_disks/2);
-                               layout = 0; /* imsm raid0 layout */
+                               imsm_layout = 0; /* imsm raid0 layout */
                        }
                        break;
                }
                if (change == -1) {
-                       fprintf(stderr,
-                               Name " Error. Level Migration from %d to %d "
-                               "not supported!\n",
-                               info.array.level, geo->level);
+                       pr_err("Error. Level Migration from %d to %d "
+                              "not supported!\n",
+                              info.array.level, geo->level);
                        goto analyse_change_exit;
                }
        } else
@@ -8935,15 +9974,17 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                        geo->layout = 0;
                        geo->level = 5;
                } else {
-                       fprintf(stderr,
-                               Name " Error. Layout Migration from %d to %d "
-                               "not supported!\n",
-                               info.array.layout, geo->layout);
+                       pr_err("Error. Layout Migration from %d to %d "
+                              "not supported!\n",
+                              info.array.layout, geo->layout);
                        change = -1;
                        goto analyse_change_exit;
                }
-       } else
+       } else {
                geo->layout = info.array.layout;
+               if (imsm_layout == -1)
+                       imsm_layout = info.array.layout;
+       }
 
        if ((geo->chunksize > 0) && (geo->chunksize != UnSet)
            && (geo->chunksize != info.array.chunk_size))
@@ -8952,12 +9993,108 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                geo->chunksize = info.array.chunk_size;
 
        chunk = geo->chunksize / 1024;
+
+       super = st->sb;
+       dev = get_imsm_dev(super, super->current_vol);
+       data_disks = imsm_num_data_members(dev , MAP_0);
+       /* compute current size per disk member
+        */
+       current_size = info.custom_array_size / data_disks;
+
+       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 (change != -1) {
+                       pr_err("Error. Size change should be the only "
+                               "one at a time.\n");
+                       change = -1;
+                       goto analyse_change_exit;
+               }
+               if ((super->current_vol + 1) != super->anchor->num_raid_devs) {
+                       pr_err("Error. The last volume in container "
+                              "can be expanded only (%i/%s).\n",
+                              super->current_vol, st->devnm);
+                       goto analyse_change_exit;
+               }
+               /* check the maximum available size
+                */
+               rv =  imsm_get_free_size(st, dev->vol.map->num_members,
+                                        0, chunk, &free_size);
+               if (rv == 0)
+                       /* Cannot find maximum available space
+                        */
+                       max_size = 0;
+               else {
+                       max_size = free_size + current_size;
+                       /* align component size
+                        */
+                       max_size = imsm_component_size_aligment_check(
+                                       get_imsm_raid_level(dev->vol.map),
+                                       chunk * 1024,
+                                       max_size);
+               }
+               if (geo->size == MAX_SIZE) {
+                       /* requested size change to the maximum available size
+                        */
+                       if (max_size == 0) {
+                               pr_err("Error. Cannot find "
+                                       "maximum available space.\n");
+                               change = -1;
+                               goto analyse_change_exit;
+                       } else
+                               geo->size = max_size;
+               }
+
+               if ((direction == ROLLBACK_METADATA_CHANGES)) {
+                       /* accept size for rollback only
+                       */
+               } else {
+                       /* round size due to metadata compatibility
+                       */
+                       geo->size = (geo->size >> SECT_PER_MB_SHIFT)
+                                   << SECT_PER_MB_SHIFT;
+                       dprintf("Prepare update for size change to %llu\n",
+                               geo->size );
+                       if (current_size >= geo->size) {
+                               pr_err("Error. Size expansion is "
+                                      "supported only (current size is %llu, "
+                                      "requested size /rounded/ is %llu).\n",
+                                      current_size, geo->size);
+                               goto analyse_change_exit;
+                       }
+                       if (max_size && geo->size > max_size) {
+                               pr_err("Error. Requested size is larger "
+                                      "than maximum available size (maximum "
+                                      "available size is %llu, "
+                                      "requested size /rounded/ is %llu).\n",
+                                      max_size, geo->size);
+                               goto analyse_change_exit;
+                       }
+               }
+               geo->size *= data_disks;
+               geo->raid_disks = dev->vol.map->num_members;
+               change = CH_ARRAY_SIZE;
+       }
        if (!validate_geometry_imsm(st,
                                    geo->level,
-                                   layout,
+                                   imsm_layout,
                                    geo->raid_disks + devNumChange,
                                    &chunk,
-                                   geo->size,
+                                   geo->size, INVALID_SECTORS,
                                    0, 0, 1))
                change = -1;
 
@@ -8966,17 +10103,21 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                struct imsm_super *mpb = super->anchor;
 
                if (mpb->num_raid_devs > 1) {
-                       fprintf(stderr,
-                               Name " Error. Cannot perform operation on %s"
-                               "- for this operation it MUST be single "
-                               "array in container\n",
-                               geo->dev_name);
+                       pr_err("Error. Cannot perform operation on %s"
+                              "- for this operation it MUST be single "
+                              "array in container\n",
+                              geo->dev_name);
                        change = -1;
                }
        }
 
 analyse_change_exit:
-
+       if ((direction == ROLLBACK_METADATA_CHANGES) &&
+            ((change == CH_MIGRATION) || (change == CH_TAKEOVER))) {
+               dprintf("imsm: Metadata changes rollback is not supported for "
+                       "migration and takeover operations.\n");
+               change = -1;
+       }
        return change;
 }
 
@@ -8985,9 +10126,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;
@@ -9013,20 +10152,21 @@ 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 verbose)
+                             int direction, int verbose)
 {
        int ret_val = 1;
        struct geo_params geo;
 
-       dprintf("imsm: reshape_super called.\n");
+       dprintf("(enter)\n");
 
        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;
@@ -9035,19 +10175,19 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
        if (delta_disks != UnSet)
                geo.raid_disks += delta_disks;
 
-       dprintf("\tfor level      : %i\n", geo.level);
-       dprintf("\tfor raid_disks : %i\n", geo.raid_disks);
+       dprintf("for level      : %i\n", geo.level);
+       dprintf("for raid_disks : %i\n", geo.raid_disks);
 
        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;
 
                if (imsm_reshape_is_allowed_on_container(
-                           st, &geo, &old_raid_disks)) {
+                           st, &geo, &old_raid_disks, direction)) {
                        struct imsm_update_reshape *u = NULL;
                        int len;
 
@@ -9069,7 +10209,7 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
                                free(u);
 
                } else {
-                       fprintf(stderr, Name ": (imsm) Operation "
+                       pr_err("(imsm) Operation "
                                "is not allowed on this container\n");
                }
        } else {
@@ -9080,23 +10220,24 @@ 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) {
-                       fprintf(stderr, Name " 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;
-               change = imsm_analyze_change(st, &geo);
+               change = imsm_analyze_change(st, &geo, direction);
                switch (change) {
                case CH_TAKEOVER:
                        ret_val = imsm_takeover(st, &geo);
@@ -9121,6 +10262,26 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
                                free(u);
                }
                break;
+               case CH_ARRAY_SIZE: {
+                       struct imsm_update_size_change *u = NULL;
+                       int len =
+                               imsm_create_metadata_update_for_size_change(
+                                       st, &geo, &u);
+                       if (len < 1) {
+                               dprintf("imsm: "
+                                       "Cannot prepare update\n");
+                               break;
+                       }
+                       ret_val = 0;
+                       /* update metadata locally */
+                       imsm_update_metadata_locally(st, u, len);
+                       /* and possibly remotely */
+                       if (st->update_tail)
+                               append_metadata_update(st, u, len);
+                       else
+                               free(u);
+               }
+               break;
                default:
                        ret_val = 1;
                }
@@ -9145,37 +10306,33 @@ exit_imsm_reshape_super:
  ******************************************************************************/
 int wait_for_reshape_imsm(struct mdinfo *sra, int ndata)
 {
-       int fd = sysfs_get_fd(sra, NULL, "reshape_position");
+       int fd = sysfs_get_fd(sra, NULL, "sync_completed");
        unsigned long long completed;
        /* to_complete : new sync_max position */
        unsigned long long to_complete = sra->reshape_progress;
        unsigned long long position_to_set = to_complete / ndata;
 
        if (fd < 0) {
-               dprintf("imsm: wait_for_reshape_imsm() "
-                       "cannot open reshape_position\n");
+               dprintf("cannot open reshape_position\n");
                return 1;
        }
 
        if (sysfs_fd_get_ll(fd, &completed) < 0) {
-               dprintf("imsm: wait_for_reshape_imsm() "
-                       "cannot read reshape_position (no reshape in progres)\n");
+               dprintf("cannot read reshape_position (no reshape in progres)\n");
                close(fd);
                return 0;
        }
 
-       if (completed > to_complete) {
-               dprintf("imsm: wait_for_reshape_imsm() "
-                       "wrong next position to set %llu (%llu)\n",
-                       to_complete, completed);
+       if (completed > position_to_set) {
+               dprintf("wrong next position to set %llu (%llu)\n",
+                       to_complete, position_to_set);
                close(fd);
                return -1;
        }
        dprintf("Position set: %llu\n", position_to_set);
        if (sysfs_set_num(sra, NULL, "sync_max",
                          position_to_set) != 0) {
-               dprintf("imsm: wait_for_reshape_imsm() "
-                       "cannot set reshape position to %llu\n",
+               dprintf("cannot set reshape position to %llu\n",
                        position_to_set);
                close(fd);
                return -1;
@@ -9183,21 +10340,17 @@ int wait_for_reshape_imsm(struct mdinfo *sra, int ndata)
 
        do {
                char action[20];
-               fd_set rfds;
-               FD_ZERO(&rfds);
-               FD_SET(fd, &rfds);
-               select(fd+1, &rfds, NULL, NULL, NULL);
+               sysfs_wait(fd, NULL);
                if (sysfs_get_str(sra, NULL, "sync_action",
                                  action, 20) > 0 &&
                                strncmp(action, "reshape", 7) != 0)
                        break;
                if (sysfs_fd_get_ll(fd, &completed) < 0) {
-                       dprintf("imsm: wait_for_reshape_imsm() "
-                               "cannot read reshape_position (in loop)\n");
+                       dprintf("cannot read reshape_position (in loop)\n");
                        close(fd);
                        return 1;
                }
-       } while (completed < to_complete);
+       } while (completed < position_to_set);
        close(fd);
        return 0;
 
@@ -9218,8 +10371,10 @@ int check_degradation_change(struct mdinfo *info,
                             int degraded)
 {
        unsigned long long new_degraded;
-       sysfs_get_ll(info, NULL, "degraded", &new_degraded);
-       if (new_degraded != (unsigned long long)degraded) {
+       int rv;
+
+       rv = sysfs_get_ll(info, NULL, "degraded", &new_degraded);
+       if ((rv == -1) || (new_degraded != (unsigned long long)degraded)) {
                /* check each device to ensure it is still working */
                struct mdinfo *sd;
                new_degraded = 0;
@@ -9309,18 +10464,18 @@ static int imsm_manage_reshape(
        }
        /* Only one volume can migrate at the same time */
        if (migr_vol_qan != 1) {
-               fprintf(stderr, Name " : %s", migr_vol_qan ?
+               pr_err(": %s", migr_vol_qan ?
                        "Number of migrating volumes greater than 1\n" :
                        "There is no volume during migrationg\n");
                goto abort;
        }
 
-       map_src = get_imsm_map(dev, 1);
+       map_src = get_imsm_map(dev, MAP_1);
        if (map_src == NULL)
                goto abort;
 
-       ndata = imsm_num_data_members(dev, 0);
-       odata = imsm_num_data_members(dev, 1);
+       ndata = imsm_num_data_members(dev, MAP_0);
+       odata = imsm_num_data_members(dev, MAP_1);
 
        chunk = __le16_to_cpu(map_src->blocks_per_strip) * 512;
        old_data_stripe_length = odata * chunk;
@@ -9336,6 +10491,18 @@ static int imsm_manage_reshape(
                                "are present in copy area.\n");
                        goto abort;
                }
+               /* Save checkpoint to update migration record for current
+                * reshape position (in md). It can be farther than current
+                * reshape position in metadata.
+                */
+               if (save_checkpoint_imsm(st, sra, UNIT_SRC_NORMAL) == 1) {
+                       /* ignore error == 2, this can mean end of reshape here
+                        */
+                       dprintf("imsm: Cannot write checkpoint to "
+                               "migration record (UNIT_SRC_NORMAL, "
+                               "initial save)\n");
+                       goto abort;
+               }
        }
 
        /* size for data */
@@ -9453,6 +10620,8 @@ static int imsm_manage_reshape(
                        dprintf("wait_for_reshape_imsm returned error!\n");
                        goto abort;
                }
+               if (sigterm)
+                       goto abort;
 
                if (save_checkpoint_imsm(st, sra, UNIT_SRC_NORMAL) == 1) {
                        /* ignore error == 2, this can mean end of reshape here
@@ -9464,6 +10633,24 @@ static int imsm_manage_reshape(
 
        }
 
+       /* clear migr_rec on disks after successful migration */
+       struct dl *d;
+
+       memset(super->migr_rec_buf, 0, MIGR_REC_BUF_SIZE);
+       for (d = super->disks; d; d = d->next) {
+               if (d->index < 0 || is_failed(&d->disk))
+                       continue;
+               unsigned long long dsize;
+
+               get_dev_size(d->fd, NULL, &dsize);
+               if (lseek64(d->fd, dsize - MIGR_REC_POSITION,
+                           SEEK_SET) >= 0) {
+                       if (write(d->fd, super->migr_rec_buf,
+                               MIGR_REC_BUF_SIZE) != MIGR_REC_BUF_SIZE)
+                               perror("Write migr_rec failed");
+               }
+       }
+
        /* return '1' if done */
        ret_val = 1;
 abort:
@@ -9472,6 +10659,7 @@ abort:
 
        return ret_val;
 }
+
 #endif /* MDASSEMBLE */
 
 struct superswitch super_imsm = {
@@ -9487,6 +10675,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,
@@ -9495,6 +10684,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,
@@ -9513,7 +10703,7 @@ struct superswitch super_imsm = {
        .free_super     = free_super_imsm,
        .match_metadata_desc = match_metadata_desc_imsm,
        .container_content = container_content_imsm,
-
+       .validate_container = validate_container_imsm,
 
        .external       = 1,
        .name = "imsm",