]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
Change way of printing name of a process
[thirdparty/mdadm.git] / super-intel.c
index 64f181e36087fd2c132ba72bf79e4d77644459de..d90033932a17462aaabd8b43a8c50ca309a4e4d2 100644 (file)
@@ -101,7 +101,7 @@ struct imsm_disk {
 #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 */ 
+       __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 */
@@ -235,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
@@ -249,7 +248,6 @@ static char *map_state_str[] = { "normal", "uninitialized", "degraded", "failed"
                               * 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
@@ -431,7 +429,7 @@ struct imsm_update_activate_spare {
 };
 
 struct geo_params {
-       int dev_id;
+       char devnm[32];
        char *dev_name;
        unsigned long long size;
        int level;
@@ -508,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)
@@ -562,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;
 
@@ -576,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)
@@ -587,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);
 
@@ -626,7 +617,6 @@ static struct supertype *match_metadata_desc_imsm(char *arg)
                return NULL;
 
        st = xcalloc(1, sizeof(*st));
-       st->container_dev = NoMdDev;
        st->ss = &super_imsm;
        st->max_devs = IMSM_MAX_DEVICES;
        st->minor_version = 0;
@@ -685,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)
@@ -976,7 +966,7 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl)
        }
        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
@@ -1320,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)
 {
@@ -1396,7 +1386,7 @@ static int imsm_check_attributes(__u32 attributes)
                }
 
                if (not_supported)
-                       dprintf(Name "(IMSM): Unknown attributes : %x\n", not_supported);
+                       dprintf("%s (IMSM): Unknown attributes : %x\n", Name, not_supported);
 
                ret_val = 0;
        }
@@ -1532,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;
@@ -1666,7 +1709,8 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
                        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 > 0) {
@@ -1725,6 +1769,8 @@ static void print_found_intel_controllers(struct sys_dev *elem)
                        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);
@@ -1746,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;
@@ -1762,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" : "",
@@ -1793,16 +1846,18 @@ static void print_imsm_capability(const struct imsm_orom *orom)
        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 per array, %d per controller\n",
-              orom->vpa, orom->vphba);
+       printf("    Max Volumes : %d per array, %d per %s\n",
+              orom->vpa, orom->vphba,
+              imsm_orom_is_nvme(orom) ? "platform" : "controller");
        return;
 }
 
 static void print_imsm_capability_export(const struct imsm_orom *orom)
 {
        printf("MD_FIRMWARE_TYPE=imsm\n");
-       printf("IMSM_VERSION=%d.%d.%d.%d\n",orom->major_ver, orom->minor_ver,
-                       orom->hotfix_ver, orom->build);
+       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 " : "",
@@ -1846,7 +1901,6 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle
         * 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;
@@ -1859,15 +1913,13 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle
                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 = 0;
+                               result = 2;
                }
-               free_sys_dev(&list);
                return result;
        }
 
@@ -1876,21 +1928,47 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle
                if (verbose > 0)
                        pr_err("no active Intel(R) RAID "
                                "controller found.\n");
-               free_sys_dev(&list);
                return 2;
        } else if (verbose > 0)
                print_found_intel_controllers(list);
 
        for (hba = list; hba; hba = hba->next) {
-               if (controller_path && (compare_paths(hba->path,controller_path) != 0))
+               if (controller_path && (compare_paths(hba->path, controller_path) != 0))
                        continue;
-               orom = find_imsm_capability(hba->type);
-               if (!orom)
+               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 {
-                       result = 0;
-                       print_imsm_capability(orom);
+                       continue;
+               }
+               result = 0;
+       }
+
+       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) {
@@ -1903,19 +1981,14 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle
                                }
                        }
                }
+               printf("\n");
        }
 
-       if (controller_path && result == 1)
-               pr_err("no active Intel(R) RAID "
-                               "controller found under %s\n",controller_path);
-
-       free_sys_dev(&list);
        return result;
 }
 
 static int export_detail_platform_imsm(int verbose, char *controller_path)
 {
-       const struct imsm_orom *orom;
        struct sys_dev *list, *hba;
        int result=1;
 
@@ -1924,24 +1997,24 @@ static int export_detail_platform_imsm(int verbose, char *controller_path)
                if (verbose > 0)
                        pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_INTEL_DEVICES\n");
                result = 2;
-               free_sys_dev(&list);
                return result;
        }
 
        for (hba = list; hba; hba = hba->next) {
                if (controller_path && (compare_paths(hba->path,controller_path) != 0))
                        continue;
-               orom = find_imsm_capability(hba->type);
-               if (!orom) {
-                       if (verbose > 0)
-                               pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_IMSM_CAPABLE_DEVICE_UNDER_%s\n",hba->path);
-               }
-               else {
-                       print_imsm_capability_export(orom);
+               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;
-               }
        }
 
+       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;
 }
 
@@ -1971,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.
@@ -2400,7 +2473,6 @@ static int imsm_create_metadata_checkpoint_update(
        return update_memory_size;
 }
 
-
 static void imsm_update_metadata_locally(struct supertype *st,
                                         void *buf, int len);
 
@@ -2557,7 +2629,6 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
        struct imsm_map *prev_map = get_imsm_map(dev, MAP_1);
        struct imsm_map *map_to_analyse = map;
        struct dl *dl;
-       char *devname;
        int map_disks = info->array.raid_disks;
 
        memset(info, 0, sizeof(*info));
@@ -2719,11 +2790,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);
 
@@ -2748,7 +2815,6 @@ 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)
 {
@@ -2799,7 +2865,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;
 
@@ -3024,7 +3090,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;
@@ -3061,21 +3128,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 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 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",
+                               first->hba->pci_id, sec->hba->pci_id);
                        return 3;
                }
        }
@@ -3106,7 +3179,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
         */
@@ -3130,7 +3202,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;
@@ -3478,7 +3550,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;
 }
@@ -3805,9 +3877,9 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
                                "    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!");
@@ -3815,18 +3887,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;
 }
 
@@ -4021,7 +4091,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);
        }
 }
@@ -4107,7 +4177,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);
 
@@ -4180,16 +4250,14 @@ 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, int devnum, char *devname,
+static int get_super_block(struct intel_super **super_list, char *devnm, char *devname,
                           int major, int minor, int keep_fd);
 static int
 get_devlist_super_block(struct md_list *devlist, struct intel_super **super_list,
                        int *max, int keep_fd);
 
-
 static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
                               char *devname, struct md_list *devlist,
                               int keep_fd)
@@ -4252,15 +4320,14 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
                free_imsm(s);
        }
 
-
        if (err)
                return err;
 
        *sbp = super;
        if (fd >= 0)
-               st->container_dev = fd2devnum(fd);
+               strcpy(st->container_devnm, fd2devnm(fd));
        else
-               st->container_dev = NoMdDev;
+               st->container_devnm[0] = 0;
        if (err == 0 && st->ss == NULL) {
                st->ss = &super_imsm;
                st->minor_version = 0;
@@ -4269,7 +4336,6 @@ 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)
@@ -4303,7 +4369,7 @@ get_devlist_super_block(struct md_list *devlist, struct intel_super **super_list
                        int major = major(tmpdev->st_rdev);
                        int minor = minor(tmpdev->st_rdev);
                        err = get_super_block(super_list,
-                                             -1,
+                                             NULL,
                                              tmpdev->devname,
                                              major, minor,
                                              keep_fd);
@@ -4319,13 +4385,12 @@ get_devlist_super_block(struct md_list *devlist, struct intel_super **super_list
        return err;
 }
 
-static int get_super_block(struct intel_super **super_list, int devnum, char *devname,
+static int get_super_block(struct intel_super **super_list, char *devnm, char *devname,
                           int major, int minor, int keep_fd)
 {
        struct intel_super*s = NULL;
        char nm[32];
        int dfd = -1;
-       int rv;
        int err = 0;
        int retry;
 
@@ -4342,17 +4407,11 @@ static int get_super_block(struct intel_super **super_list, int devnum, char *de
                goto error;
        }
 
-       rv = find_intel_hba_capability(dfd, s, devname);
-       /* no orom/efi or non-intel hba of the disk */
-       if (rv != 0) {
-               err = 4;
-               goto error;
-       }
-
+       find_intel_hba_capability(dfd, s, devname);
        err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
 
        /* retry the load if we might have raced against mdmon */
-       if (err == 3 && (devnum != -1) && mdmon_running(devnum))
+       if (err == 3 && devnm && mdmon_running(devnm))
                for (retry = 0; retry < 3; retry++) {
                        usleep(3000);
                        err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
@@ -4379,11 +4438,11 @@ static int
 get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int *max, int keep_fd)
 {
        struct mdinfo *sra;
-       int devnum;
+       char *devnm;
        struct mdinfo *sd;
        int err = 0;
        int i = 0;
-       sra = sysfs_read(fd, 0, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE);
+       sra = sysfs_read(fd, NULL, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE);
        if (!sra)
                return 1;
 
@@ -4394,9 +4453,9 @@ get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int
                goto error;
        }
        /* load all mpbs */
-       devnum = fd2devnum(fd);
+       devnm = fd2devnm(fd);
        for (sd = sra->devs, i = 0; sd; sd = sd->next, i++) {
-               if (get_super_block(super_list, devnum, devname,
+               if (get_super_block(super_list, devnm, devname,
                                    sd->disk.major, sd->disk.minor, keep_fd) != 0) {
                        err = 7;
                        goto error;
@@ -4418,6 +4477,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 */
@@ -4440,6 +4500,22 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
        }
        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)
                        pr_err("Failed to load all information "
@@ -4560,7 +4636,8 @@ static int check_name(struct intel_super *super, char *name, int quiet)
 
 static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                                  unsigned long long size, char *name,
-                                 char *homehost, int *uuid)
+                                 char *homehost, int *uuid,
+                                 long long data_offset)
 {
        /* We are creating a volume inside a pre-existing container.
         * so st->sb is already set.
@@ -4671,7 +4748,8 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info));
        map->failed_disk_num = ~0;
        if (info->level > 0)
-               map->map_state = IMSM_T_STATE_UNINITIALIZED;
+               map->map_state = (info->state ? IMSM_T_STATE_NORMAL
+                                 : IMSM_T_STATE_UNINITIALIZED);
        else
                map->map_state = info->failed_disks ? IMSM_T_STATE_FAILED :
                                                      IMSM_T_STATE_NORMAL;
@@ -4718,7 +4796,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
@@ -4733,8 +4812,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);
@@ -4928,7 +5013,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;
@@ -4969,6 +5055,14 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
        }
 
        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);
        set_total_blocks(&dd->disk, size);
@@ -4994,7 +5088,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;
@@ -5019,7 +5112,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;
 }
 
@@ -5066,7 +5158,7 @@ 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",
+                       pr_err("%s: failed for device %d:%d %s\n",
                                __func__, d->major, d->minor, strerror(errno));
                        return 1;
                }
@@ -5176,7 +5268,6 @@ 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;
@@ -5199,6 +5290,8 @@ static int create_array(struct supertype *st, int dev_idx)
                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);
@@ -5278,7 +5371,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)
 {
@@ -5340,7 +5435,7 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
                }
        }
 
-       *freesize = avail_size_imsm(st, ldsize >> 9);
+       *freesize = avail_size_imsm(st, ldsize >> 9, data_offset);
        free_imsm(super);
 
        return 1;
@@ -5473,7 +5568,6 @@ 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)
@@ -5597,7 +5691,6 @@ get_devices(const char *hba_path)
                        continue;
                }
 
-
                dv = xcalloc(1, sizeof(*dv));
                dv->devname = xstrdup(buf);
                dv->next = devlist;
@@ -5779,7 +5872,6 @@ count_volumes_list(struct md_list *devlist, char *homehost,
        return count;
 }
 
-
 static int
 count_volumes(char *hba, int dpa, int verbose)
 {
@@ -5837,17 +5929,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;
@@ -5864,20 +5956,23 @@ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
                return 0;
        }
 
-       if (super->orom && (super->orom->attr & IMSM_OROM_ATTR_2TB) == 0 && chunk &&
+       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)
 {
@@ -6160,6 +6255,7 @@ static int reserve_space(struct supertype *st, int raiddisks,
 
 static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                                  int raiddisks, int *chunk, unsigned long long size,
+                                 unsigned long long data_offset,
                                  char *dev, unsigned long long *freesize,
                                  int verbose)
 {
@@ -6175,7 +6271,8 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                /* Must be a fresh device to add to a container */
                return validate_geometry_imsm_container(st, level, layout,
                                                        raiddisks,
-                                                       chunk?*chunk:0, size,
+                                                       *chunk,
+                                                       size, data_offset,
                                                        dev, freesize,
                                                        verbose);
        }
@@ -6210,7 +6307,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                        }
                        if (freesize)
                                return reserve_space(st, raiddisks, size,
-                                                    chunk?*chunk:0, freesize);
+                                                    *chunk, freesize);
                }
                return 1;
        }
@@ -6218,6 +6315,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);
        }
 
@@ -6245,7 +6343,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                                dev);
                return 0;
        }
-       sra = sysfs_read(cfd, 0, GET_VERSION);
+       sra = sysfs_read(cfd, NULL, GET_VERSION);
        if (sra && sra->array.major_version == -1 &&
            strcmp(sra->text_version, "imsm") == 0)
                is_member = 1;
@@ -6258,11 +6356,11 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
 
                if (load_super_imsm_all(st, cfd, (void **) &super, NULL, NULL, 1) == 0) {
                        st->sb = super;
-                       st->container_dev = fd2devnum(cfd);
+                       strcpy(st->container_devnm, fd2devnm(cfd));
                        close(cfd);
                        return validate_geometry_imsm_volume(st, level, layout,
                                                             raiddisks, chunk,
-                                                            size, dev,
+                                                            size, data_offset, dev,
                                                             freesize, 1)
                                ? 1 : -1;
                }
@@ -6316,7 +6414,7 @@ static int kill_subarray_imsm(struct supertype *st)
                if (i < current_vol)
                        continue;
                sprintf(subarray, "%u", i);
-               if (is_subarray_active(subarray, st->devname)) {
+               if (is_subarray_active(subarray, st->devnm)) {
                        pr_err("deleting subarray-%d would change the UUID of active subarray-%d, aborting\n",
                               current_vol, i);
 
@@ -6372,7 +6470,7 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
                char *ep;
                int vol;
 
-               if (is_subarray_active(subarray, st->devname)) {
+               if (is_subarray_active(subarray, st->devnm)) {
                        pr_err("Unable to update name of active subarray\n");
                        return 2;
                }
@@ -6531,7 +6629,6 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                sb_errors = 1;
        }
 
-
        /* count spare devices, not used in maps
         */
        for (d = super->disks; d; d = d->next)
@@ -6623,7 +6720,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
@@ -6677,7 +6774,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)
 {
@@ -6686,7 +6782,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)) {
@@ -6716,7 +6812,7 @@ static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev,
                        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;
@@ -6809,7 +6905,7 @@ static int imsm_open_new(struct supertype *c, struct active_array *a,
        struct imsm_super *mpb = super->anchor;
 
        if (atoi(inst) >= mpb->num_raid_devs) {
-               fprintf(stderr, "%s: subarry index %d, out of range\n",
+               pr_err("%s: subarry index %d, out of range\n",
                        __func__, atoi(inst));
                return -ENODEV;
        }
@@ -6907,6 +7003,12 @@ static void handle_missing(struct intel_super *super, struct imsm_dev *dev)
        if (!super->missing)
                return;
 
+       /* When orom adds replacement for missing disk it does
+        * not remove entry of missing disk, but just updates map with
+        * new added disk. So it is not enough just to test if there is
+        * any missing disk, we have to look if there are any failed disks
+        * in map to stop migration */
+
        dprintf("imsm: mark missing\n");
        /* end process for initialization and rebuild only
         */
@@ -6917,7 +7019,8 @@ static void handle_missing(struct intel_super *super, struct imsm_dev *dev)
                failed = imsm_count_failed(super, dev, MAP_0);
                map_state = imsm_check_degraded(super, dev, failed, MAP_0);
 
-               end_migration(dev, super, map_state);
+               if (failed)
+                       end_migration(dev, super, map_state);
        }
        for (dl = super->missing; dl; dl = dl->next)
                mark_missing(dev, &dl->disk, dl->index);
@@ -7182,7 +7285,7 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
        __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)
@@ -7486,7 +7589,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;
@@ -7630,7 +7732,7 @@ 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 = xcalloc(1, sizeof(*di));
 
@@ -7671,7 +7773,7 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
         * disk_ord_tbl for the array
         */
        mu = xmalloc(sizeof(*mu));
-       mu->buf = xcalloc(num_spares, 
+       mu->buf = xcalloc(num_spares,
                          sizeof(struct imsm_update_activate_spare));
        mu->space = NULL;
        mu->space_list = NULL;
@@ -7714,7 +7816,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;
@@ -7792,7 +7893,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)
@@ -7952,7 +8052,6 @@ static int apply_size_change_update(struct imsm_update_size_change *u,
        return ret_val;
 }
 
-
 static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
                                       struct intel_super *super,
                                       struct active_array *active_array)
@@ -7982,7 +8081,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;
@@ -8288,9 +8387,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
@@ -8367,7 +8466,7 @@ static void imsm_process_update(struct supertype *st,
                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;
@@ -8552,7 +8651,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)) {
@@ -8565,15 +8664,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
@@ -8582,19 +8681,28 @@ 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:
+               if (update->len < (int)sizeof(struct imsm_update_general_migration_checkpoint))
+                       return 0;
                dprintf("imsm: prepare_update() "
                        "for update_general_migration_checkpoint called\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);
@@ -8635,6 +8743,9 @@ static void imsm_prepare_update(struct supertype *st,
                struct intel_dev *dl;
                void **space_tail = (void**)&update->space_list;
 
+               if (update->len < (int)sizeof(*u))
+                       return 0;
+
                dprintf("imsm: imsm_prepare_update() for update_reshape\n");
 
                for (dl = super->devlist; dl; dl = dl->next) {
@@ -8667,6 +8778,9 @@ static void imsm_prepare_update(struct supertype *st,
                void *s;
                int current_level = -1;
 
+               if (update->len < (int)sizeof(*u))
+                       return 0;
+
                dprintf("imsm: imsm_prepare_update() for update_reshape\n");
 
                /* add space for bigger array in update
@@ -8734,6 +8848,13 @@ static void imsm_prepare_update(struct supertype *st,
                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: {
@@ -8746,6 +8867,9 @@ static void imsm_prepare_update(struct supertype *st,
                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 */
@@ -8767,9 +8891,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 */
@@ -8793,6 +8930,7 @@ static void imsm_prepare_update(struct supertype *st,
                else
                        super->next_buf = NULL;
        }
+       return 1;
 }
 
 /* must be called while manager is quiesced */
@@ -8916,7 +9054,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
@@ -8957,7 +9094,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++;
@@ -8968,13 +9105,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
@@ -9028,7 +9242,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);
@@ -9324,7 +9537,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;
@@ -9338,30 +9551,29 @@ 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,
@@ -9378,8 +9590,7 @@ 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 > 0 ||
            geo->level != UnSet ||
@@ -9399,8 +9610,7 @@ static int imsm_reshape_is_allowed_on_container(struct supertype *st,
 
        info = container_content_imsm(st, NULL);
        for (member = info; member; member = member->next) {
-               int result;
-               int minor;
+               char *result;
 
                dprintf("imsm: checking device_num: %i\n",
                        member->container_member);
@@ -9457,10 +9667,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;
                }
@@ -9480,10 +9689,10 @@ static int imsm_reshape_is_allowed_on_container(struct supertype *st,
 
 /* 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)
 {
@@ -9576,7 +9785,6 @@ abort:
        return 0;
 }
 
-
 /******************************************************************************
  * function: imsm_create_metadata_update_for_size_change()
  *           Creates update for IMSM array for array size change.
@@ -9688,8 +9896,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;
@@ -9701,7 +9909,7 @@ 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
+*              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
@@ -9836,8 +10044,8 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                }
                if ((super->current_vol + 1) != super->anchor->num_raid_devs) {
                        pr_err("Error. The last volume in container "
-                              "can be expanded only (%i/%i).\n",
-                              super->current_vol, st->devnum);
+                              "can be expanded only (%i/%s).\n",
+                              super->current_vol, st->devnm);
                        goto analyse_change_exit;
                }
                /* check the maximum available size
@@ -9904,7 +10112,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                                    imsm_layout,
                                    geo->raid_disks + devNumChange,
                                    &chunk,
-                                   geo->size,
+                                   geo->size, INVALID_SECTORS,
                                    0, 0, 1))
                change = -1;
 
@@ -9976,7 +10184,7 @@ static int imsm_reshape_super(struct supertype *st, unsigned long long size,
        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;
@@ -9991,7 +10199,7 @@ static int imsm_reshape_super(struct supertype *st, unsigned long long size,
        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;
@@ -10030,19 +10238,20 @@ static int imsm_reshape_super(struct supertype *st, unsigned long long size,
                 */
                struct intel_super *super = st->sb;
                struct intel_dev *dev = super->devlist;
-               int change, devnum;
+               int change;
                dprintf("imsm: info: Volume operation\n");
                /* find requested device */
                while (dev) {
-                       if (imsm_find_array_minor_by_subdev(
-                                   dev->index, st->container_dev, &devnum) == 0
-                           && devnum == geo.dev_id)
+                       char *devnm =
+                               imsm_find_array_devnm_by_subdev(
+                                       dev->index, st->container_devnm);
+                       if (devnm && strcmp(devnm, geo.devnm) == 0)
                                break;
                        dev = dev->next;
                }
                if (dev == NULL) {
-                       pr_err("Cannot find %s (%i) subarray\n",
-                               geo.dev_name, geo.dev_id);
+                       pr_err("Cannot find %s (%s) subarray\n",
+                               geo.dev_name, geo.devnm);
                        goto exit_imsm_reshape_super;
                }
                super->current_vol = dev->index;
@@ -10115,7 +10324,7 @@ 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;
@@ -10134,10 +10343,10 @@ int wait_for_reshape_imsm(struct mdinfo *sra, int ndata)
                return 0;
        }
 
-       if (completed > to_complete) {
+       if (completed > position_to_set) {
                dprintf("imsm: wait_for_reshape_imsm() "
                        "wrong next position to set %llu (%llu)\n",
-                       to_complete, completed);
+                       to_complete, position_to_set);
                close(fd);
                return -1;
        }
@@ -10153,10 +10362,7 @@ 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)
@@ -10167,7 +10373,7 @@ int wait_for_reshape_imsm(struct mdinfo *sra, int ndata)
                        close(fd);
                        return 1;
                }
-       } while (completed < to_complete);
+       } while (completed < position_to_set);
        close(fd);
        return 0;
 
@@ -10437,6 +10643,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
@@ -10448,6 +10656,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:
@@ -10456,6 +10682,7 @@ abort:
 
        return ret_val;
 }
+
 #endif /* MDASSEMBLE */
 
 struct superswitch super_imsm = {
@@ -10480,6 +10707,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,
@@ -10498,7 +10726,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",