]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
mdmon: bad block support for external metadata - store bad blocks
[thirdparty/mdadm.git] / super-intel.c
index 95a72b6ad81f99cb9b110aacbe518c709ea91f71..3d21f312b86d9f5f0b51b2804ba7134ccaeb4752 100644 (file)
@@ -90,6 +90,7 @@
 #define IMSM_RESERVED_SECTORS 4096
 #define NUM_BLOCKS_DIRTY_STRIPE_REGION 2056
 #define SECT_PER_MB_SHIFT 11
+#define MAX_SECTOR_SIZE 4096
 
 /* Disk configuration info. */
 #define IMSM_MAX_DEVICES 255
@@ -243,9 +244,9 @@ 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 MIGR_REC_BUF_SECTORS 1 /* size of migr_record i/o buffer in sectors */
+#define MIGR_REC_SECTOR_POSITION 1 /* migr_record position offset on disk,
+                              * MIGR_REC_BUF_SECTORS <= MIGR_REC_SECTOR_POS
                               */
 
 #define UNIT_SRC_NORMAL     0   /* Source data for curr_migr_unit must
@@ -318,14 +319,15 @@ static void set_migr_type(struct imsm_dev *dev, __u8 migr_type)
        }
 }
 
-static unsigned int sector_count(__u32 bytes)
+static unsigned int sector_count(__u32 bytes, unsigned int sector_size)
 {
-       return ROUND_UP(bytes, 512) / 512;
+       return ROUND_UP(bytes, sector_size) / sector_size;
 }
 
-static unsigned int mpb_sectors(struct imsm_super *mpb)
+static unsigned int mpb_sectors(struct imsm_super *mpb,
+                                       unsigned int sector_size)
 {
-       return sector_count(__le32_to_cpu(mpb->mpb_size));
+       return sector_count(__le32_to_cpu(mpb->mpb_size), sector_size);
 }
 
 struct intel_dev {
@@ -366,6 +368,7 @@ struct intel_super {
        unsigned long long create_offset; /* common start for 'current_vol' */
        __u32 random; /* random data for seeding new family numbers */
        struct intel_dev *devlist;
+       unsigned int sector_size; /* sector size of used member drives */
        struct dl {
                struct dl *next;
                int index;
@@ -510,7 +513,8 @@ static const char *_sys_dev_type[] = {
        [SYS_DEV_UNKNOWN] = "Unknown",
        [SYS_DEV_SAS] = "SAS",
        [SYS_DEV_SATA] = "SATA",
-       [SYS_DEV_NVME] = "NVMe"
+       [SYS_DEV_NVME] = "NVMe",
+       [SYS_DEV_VMD] = "VMD"
 };
 
 const char *get_sys_dev_type(enum sys_dev_type type)
@@ -536,7 +540,8 @@ static struct intel_hba * alloc_intel_hba(struct sys_dev *device)
 
 static struct intel_hba * find_intel_hba(struct intel_hba *hba, struct sys_dev *device)
 {
-       struct intel_hba *result=NULL;
+       struct intel_hba *result;
+
        for (result = hba; result; result = result->next) {
                if (result->type == device->type && strcmp(result->path, device->path) == 0)
                        break;
@@ -905,7 +910,6 @@ static unsigned long long blocks_per_member(struct imsm_map *map)
        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)
@@ -917,7 +921,6 @@ 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)
 {
@@ -1119,6 +1122,8 @@ static unsigned long long min_acceptable_spare_size_imsm(struct supertype *st)
 
 static int is_gen_migration(struct imsm_dev *dev);
 
+#define IMSM_4K_DIV 8
+
 #ifndef MDASSEMBLE
 static __u64 blocks_per_migr_unit(struct intel_super *super,
                                  struct imsm_dev *dev);
@@ -1217,7 +1222,7 @@ static void print_imsm_dev(struct intel_super *super,
                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)) && ((slot > 1) || (slot < 0)))
+               if (is_gen_migration(dev) && (slot > 1 || slot < 0))
                        printf("(N/A)");
                else
                        printf("(%llu)", (unsigned long long)
@@ -1250,6 +1255,61 @@ static void print_imsm_disk(struct imsm_disk *disk, int index, __u32 reserved)
               human_size(sz * 512));
 }
 
+void convert_to_4k_imsm_migr_rec(struct intel_super *super)
+{
+       struct migr_record *migr_rec = super->migr_rec;
+
+       migr_rec->blocks_per_unit /= IMSM_4K_DIV;
+       migr_rec->ckpt_area_pba /= IMSM_4K_DIV;
+       migr_rec->dest_1st_member_lba /= IMSM_4K_DIV;
+       migr_rec->dest_depth_per_unit /= IMSM_4K_DIV;
+       split_ull((join_u32(migr_rec->post_migr_vol_cap,
+                migr_rec->post_migr_vol_cap_hi) / IMSM_4K_DIV),
+                &migr_rec->post_migr_vol_cap, &migr_rec->post_migr_vol_cap_hi);
+}
+
+void convert_to_4k_imsm_disk(struct imsm_disk *disk)
+{
+       set_total_blocks(disk, (total_blocks(disk)/IMSM_4K_DIV));
+}
+
+void convert_to_4k(struct intel_super *super)
+{
+       struct imsm_super *mpb = super->anchor;
+       struct imsm_disk *disk;
+       int i;
+
+       for (i = 0; i < mpb->num_disks ; i++) {
+               disk = __get_imsm_disk(mpb, i);
+               /* disk */
+               convert_to_4k_imsm_disk(disk);
+       }
+       for (i = 0; i < mpb->num_raid_devs; i++) {
+               struct imsm_dev *dev = __get_imsm_dev(mpb, i);
+               struct imsm_map *map = get_imsm_map(dev, MAP_0);
+               /* dev */
+               split_ull((join_u32(dev->size_low, dev->size_high)/IMSM_4K_DIV),
+                                &dev->size_low, &dev->size_high);
+               dev->vol.curr_migr_unit /= IMSM_4K_DIV;
+
+               /* map0 */
+               set_blocks_per_member(map, blocks_per_member(map)/IMSM_4K_DIV);
+               map->blocks_per_strip /= IMSM_4K_DIV;
+               set_pba_of_lba0(map, pba_of_lba0(map)/IMSM_4K_DIV);
+
+               if (dev->vol.migr_state) {
+                       /* map1 */
+                       map = get_imsm_map(dev, MAP_1);
+                       set_blocks_per_member(map,
+                           blocks_per_member(map)/IMSM_4K_DIV);
+                       map->blocks_per_strip /= IMSM_4K_DIV;
+                       set_pba_of_lba0(map, pba_of_lba0(map)/IMSM_4K_DIV);
+               }
+       }
+
+       mpb->check_sum = __gen_imsm_checksum(mpb);
+}
+
 void examine_migr_rec_imsm(struct intel_super *super)
 {
        struct migr_record *migr_rec = super->migr_rec;
@@ -1270,7 +1330,7 @@ void examine_migr_rec_imsm(struct intel_super *super)
                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)) {
+               if (map == NULL || slot > 1 || slot < 0) {
                        printf(" Empty\n                              ");
                        printf("Examine one of first two disks in array\n");
                        break;
@@ -1307,6 +1367,59 @@ void examine_migr_rec_imsm(struct intel_super *super)
        }
 }
 #endif /* MDASSEMBLE */
+
+void convert_from_4k_imsm_migr_rec(struct intel_super *super)
+{
+       struct migr_record *migr_rec = super->migr_rec;
+
+       migr_rec->blocks_per_unit *= IMSM_4K_DIV;
+       migr_rec->ckpt_area_pba *= IMSM_4K_DIV;
+       migr_rec->dest_1st_member_lba *= IMSM_4K_DIV;
+       migr_rec->dest_depth_per_unit *= IMSM_4K_DIV;
+       split_ull((join_u32(migr_rec->post_migr_vol_cap,
+                migr_rec->post_migr_vol_cap_hi) * IMSM_4K_DIV),
+                &migr_rec->post_migr_vol_cap,
+                &migr_rec->post_migr_vol_cap_hi);
+}
+
+void convert_from_4k(struct intel_super *super)
+{
+       struct imsm_super *mpb = super->anchor;
+       struct imsm_disk *disk;
+       int i;
+
+       for (i = 0; i < mpb->num_disks ; i++) {
+               disk = __get_imsm_disk(mpb, i);
+               /* disk */
+               set_total_blocks(disk, (total_blocks(disk)*IMSM_4K_DIV));
+       }
+
+       for (i = 0; i < mpb->num_raid_devs; i++) {
+               struct imsm_dev *dev = __get_imsm_dev(mpb, i);
+               struct imsm_map *map = get_imsm_map(dev, MAP_0);
+               /* dev */
+               split_ull((join_u32(dev->size_low, dev->size_high)*IMSM_4K_DIV),
+                                &dev->size_low, &dev->size_high);
+               dev->vol.curr_migr_unit *= IMSM_4K_DIV;
+
+               /* map0 */
+               set_blocks_per_member(map, blocks_per_member(map)*IMSM_4K_DIV);
+               map->blocks_per_strip *= IMSM_4K_DIV;
+               set_pba_of_lba0(map, pba_of_lba0(map)*IMSM_4K_DIV);
+
+               if (dev->vol.migr_state) {
+                       /* map1 */
+                       map = get_imsm_map(dev, MAP_1);
+                       set_blocks_per_member(map,
+                           blocks_per_member(map)*IMSM_4K_DIV);
+                       map->blocks_per_strip *= IMSM_4K_DIV;
+                       set_pba_of_lba0(map, pba_of_lba0(map)*IMSM_4K_DIV);
+               }
+       }
+
+       mpb->check_sum = __gen_imsm_checksum(mpb);
+}
+
 /*******************************************************************************
  * function: imsm_check_attributes
  * Description: Function checks if features represented by attributes flags
@@ -1427,7 +1540,7 @@ static void examine_super_imsm(struct supertype *st, char *homehost)
        sum = __le32_to_cpu(mpb->check_sum);
        printf("       Checksum : %08x %s\n", sum,
                __gen_imsm_checksum(mpb) == sum ? "correct" : "incorrect");
-       printf("    MPB Sectors : %d\n", mpb_sectors(mpb));
+       printf("    MPB Sectors : %d\n", mpb_sectors(mpb, super->sector_size));
        printf("          Disks : %d\n", mpb->num_disks);
        printf("   RAID Devices : %d\n", mpb->num_raid_devs);
        print_imsm_disk(__get_imsm_disk(mpb, super->disks->index), super->disks->index, reserved);
@@ -1524,7 +1637,7 @@ static void export_examine_super_imsm(struct supertype *st)
 
 static int copy_metadata_imsm(struct supertype *st, int from, int to)
 {
-       /* The second last 512byte sector of the device contains
+       /* The second last 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
@@ -1537,29 +1650,31 @@ static int copy_metadata_imsm(struct supertype *st, int from, int to)
        unsigned long long dsize, offset;
        int sectors;
        struct imsm_super *sb;
-       int written = 0;
+       struct intel_super *super = st->sb;
+       unsigned int sector_size = super->sector_size;
+       unsigned int written = 0;
 
-       if (posix_memalign(&buf, 4096, 4096) != 0)
+       if (posix_memalign(&buf, MAX_SECTOR_SIZE, MAX_SECTOR_SIZE) != 0)
                return 1;
 
        if (!get_dev_size(from, NULL, &dsize))
                goto err;
 
-       if (lseek64(from, dsize-1024, 0) < 0)
+       if (lseek64(from, dsize-(2*sector_size), 0) < 0)
                goto err;
-       if (read(from, buf, 512) != 512)
+       if (read(from, buf, sector_size) != sector_size)
                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;
+       sectors = mpb_sectors(sb, sector_size) + 2;
+       offset = dsize - sectors * sector_size;
        if (lseek64(from, offset, 0) < 0 ||
            lseek64(to, offset, 0) < 0)
                goto err;
-       while (written < sectors * 512) {
-               int n = sectors*512 - written;
+       while (written < sectors * sector_size) {
+               int n = sectors*sector_size - written;
                if (n > 4096)
                        n = 4096;
                if (read(from, buf, n) != n)
@@ -1619,7 +1734,10 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
         * this hba
         */
        dir = opendir("/sys/dev/block");
-       for (ent = dir ? readdir(dir) : NULL; ent; ent = readdir(dir)) {
+       if (!dir)
+               return 1;
+
+       for (ent = readdir(dir); ent; ent = readdir(dir)) {
                int fd;
                char model[64];
                char vendor[64];
@@ -1649,7 +1767,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
                        break;
                }
                sprintf(device, "/sys/dev/block/%d:%d/device/type", major, minor);
-               if (load_sys(device, buf) != 0) {
+               if (load_sys(device, buf, sizeof(buf)) != 0) {
                        if (verbose > 0)
                                pr_err("failed to read device type for %s\n",
                                        path);
@@ -1664,7 +1782,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
                        vendor[0] = '\0';
                        model[0] = '\0';
                        sprintf(device, "/sys/dev/block/%d:%d/device/vendor", major, minor);
-                       if (load_sys(device, buf) == 0) {
+                       if (load_sys(device, buf, sizeof(buf)) == 0) {
                                strncpy(vendor, buf, sizeof(vendor));
                                vendor[sizeof(vendor) - 1] = '\0';
                                c = (char *) &vendor[sizeof(vendor) - 1];
@@ -1673,7 +1791,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
 
                        }
                        sprintf(device, "/sys/dev/block/%d:%d/device/model", major, minor);
-                       if (load_sys(device, buf) == 0) {
+                       if (load_sys(device, buf, sizeof(buf)) == 0) {
                                strncpy(model, buf, sizeof(model));
                                model[sizeof(model) - 1] = '\0';
                                c = (char *) &model[sizeof(model) - 1];
@@ -1761,6 +1879,61 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
        return err;
 }
 
+static int print_vmd_attached_devs(struct sys_dev *hba)
+{
+       struct dirent *ent;
+       DIR *dir;
+       char path[292];
+       char link[256];
+       char *c, *rp;
+
+       if (hba->type != SYS_DEV_VMD)
+               return 1;
+
+       /* scroll through /sys/dev/block looking for devices attached to
+        * this hba
+        */
+       dir = opendir("/sys/bus/pci/drivers/nvme");
+       if (!dir)
+               return 1;
+
+       for (ent = readdir(dir); ent; ent = readdir(dir)) {
+               int n;
+
+               /* is 'ent' a device? check that the 'subsystem' link exists and
+                * that its target matches 'bus'
+                */
+               sprintf(path, "/sys/bus/pci/drivers/nvme/%s/subsystem",
+                       ent->d_name);
+               n = readlink(path, link, sizeof(link));
+               if (n < 0 || n >= (int)sizeof(link))
+                       continue;
+               link[n] = '\0';
+               c = strrchr(link, '/');
+               if (!c)
+                       continue;
+               if (strncmp("pci", c+1, strlen("pci")) != 0)
+                       continue;
+
+               sprintf(path, "/sys/bus/pci/drivers/nvme/%s", ent->d_name);
+               /* if not a intel NVMe - skip it*/
+               if (devpath_to_vendor(path) != 0x8086)
+                       continue;
+
+               rp = realpath(path, NULL);
+               if (!rp)
+                       continue;
+
+               if (path_attached_to_hba(rp, hba->path)) {
+                       printf(" NVMe under VMD : %s\n", rp);
+               }
+               free(rp);
+       }
+
+       closedir(dir);
+       return 0;
+}
+
 static void print_found_intel_controllers(struct sys_dev *elem)
 {
        for (; elem; elem = elem->next) {
@@ -1771,7 +1944,12 @@ static void print_found_intel_controllers(struct sys_dev *elem)
                        fprintf(stderr, "SAS ");
                else if (elem->type == SYS_DEV_NVME)
                        fprintf(stderr, "NVMe ");
-               fprintf(stderr, "RAID controller");
+
+               if (elem->type == SYS_DEV_VMD)
+                       fprintf(stderr, "VMD domain");
+               else
+                       fprintf(stderr, "RAID controller");
+
                if (elem->pci_id)
                        fprintf(stderr, " at %s", elem->pci_id);
                fprintf(stderr, ".\n");
@@ -1935,8 +2113,10 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle
                if (controller_path && (compare_paths(hba->path, controller_path) != 0))
                        continue;
                if (!find_imsm_capability(hba)) {
+                       char buf[PATH_MAX];
                        pr_err("imsm capabilities not found for controller: %s (type %s)\n",
-                               hba->path, get_sys_dev_type(hba->type));
+                                 hba->type == SYS_DEV_VMD ? vmd_domain_to_controller(hba, buf) : hba->path,
+                                 get_sys_dev_type(hba->type));
                        continue;
                }
                result = 0;
@@ -1951,13 +2131,31 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle
        const struct orom_entry *entry;
 
        for (entry = orom_entries; entry; entry = entry->next) {
-               print_imsm_capability(&entry->orom);
+               if (entry->type == SYS_DEV_VMD) {
+                       print_imsm_capability(&entry->orom);
+                       for (hba = list; hba; hba = hba->next) {
+                               if (hba->type == SYS_DEV_VMD) {
+                                       char buf[PATH_MAX];
+                                       printf(" I/O Controller : %s (%s)\n",
+                                               vmd_domain_to_controller(hba, buf), get_sys_dev_type(hba->type));
+                                       if (print_vmd_attached_devs(hba)) {
+                                               if (verbose > 0)
+                                                       pr_err("failed to get devices attached to VMD domain.\n");
+                                               result |= 2;
+                                       }
+                               }
+                       }
+                       printf("\n");
+                       continue;
+               }
 
-               if (imsm_orom_is_nvme(&entry->orom)) {
+               print_imsm_capability(&entry->orom);
+               if (entry->type == SYS_DEV_NVME) {
                        for (hba = list; hba; hba = hba->next) {
                                if (hba->type == SYS_DEV_NVME)
                                        printf("    NVMe Device : %s\n", hba->path);
                        }
+                       printf("\n");
                        continue;
                }
 
@@ -2000,16 +2198,25 @@ static int export_detail_platform_imsm(int verbose, char *controller_path)
        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);
+               if (!find_imsm_capability(hba) && verbose > 0) {
+                       char buf[PATH_MAX];
+                       pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_IMSM_CAPABLE_DEVICE_UNDER_%s\n",
+                       hba->type == SYS_DEV_VMD ? vmd_domain_to_controller(hba, buf) : hba->path);
+               }
                else
                        result = 0;
        }
 
        const struct orom_entry *entry;
 
-       for (entry = orom_entries; entry; entry = entry->next)
+       for (entry = orom_entries; entry; entry = entry->next) {
+               if (entry->type == SYS_DEV_VMD) {
+                       for (hba = list; hba; hba = hba->next)
+                               print_imsm_capability_export(&entry->orom);
+                       continue;
+               }
                print_imsm_capability_export(&entry->orom);
+       }
 
        return result;
 }
@@ -2317,21 +2524,26 @@ static int imsm_level_to_layout(int level)
 static int read_imsm_migr_rec(int fd, struct intel_super *super)
 {
        int ret_val = -1;
+       unsigned int sector_size = super->sector_size;
        unsigned long long dsize;
 
        get_dev_size(fd, NULL, &dsize);
-       if (lseek64(fd, dsize - MIGR_REC_POSITION, SEEK_SET) < 0) {
+       if (lseek64(fd, dsize - (sector_size*MIGR_REC_SECTOR_POSITION),
+                  SEEK_SET) < 0) {
                pr_err("Cannot seek to anchor block: %s\n",
                       strerror(errno));
                goto out;
        }
-       if (read(fd, super->migr_rec_buf, MIGR_REC_BUF_SIZE) !=
-                                                           MIGR_REC_BUF_SIZE) {
+       if (read(fd, super->migr_rec_buf,
+           MIGR_REC_BUF_SECTORS*sector_size) !=
+           MIGR_REC_BUF_SECTORS*sector_size) {
                pr_err("Cannot read migr record block: %s\n",
                       strerror(errno));
                goto out;
        }
        ret_val = 0;
+       if (sector_size == 4096)
+               convert_from_4k_imsm_migr_rec(super);
 
 out:
        return ret_val;
@@ -2365,12 +2577,12 @@ static struct imsm_dev *imsm_get_device_during_migration(
 static int load_imsm_migr_rec(struct intel_super *super, struct mdinfo *info)
 {
        struct mdinfo *sd;
-       struct dl *dl = NULL;
+       struct dl *dl;
        char nm[30];
        int retval = -1;
        int fd = -1;
        struct imsm_dev *dev;
-       struct imsm_map *map = NULL;
+       struct imsm_map *map;
        int slot = -1;
 
        /* find map under migration */
@@ -2379,19 +2591,12 @@ static int load_imsm_migr_rec(struct intel_super *super, struct mdinfo *info)
        */
        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 (map)
-                               slot = get_imsm_disk_slot(map,
-                                                         sd->disk.raid_disk);
-                       if ((map == NULL) || (slot > 1) || (slot < 0))
+                       if ((sd->disk.raid_disk < 0) ||
+                           (sd->disk.raid_disk > 1))
                                continue;
 
                        sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
@@ -2401,6 +2606,7 @@ static int load_imsm_migr_rec(struct intel_super *super, struct mdinfo *info)
                }
        }
        if (fd < 0) {
+               map = get_imsm_map(dev, MAP_0);
                for (dl = super->disks; dl; dl = dl->next) {
                        /* skip spare and failed disks
                        */
@@ -2409,7 +2615,7 @@ static int load_imsm_migr_rec(struct intel_super *super, struct mdinfo *info)
                        /* read only from one of the first two slots */
                        if (map)
                                slot = get_imsm_disk_slot(map, dl->index);
-                       if ((map == NULL) || (slot > 1) || (slot < 0))
+                       if (map == NULL || slot > 1 || slot < 0)
                                continue;
                        sprintf(nm, "%d:%d", dl->major, dl->minor);
                        fd = dev_open(nm, O_RDONLY);
@@ -2483,6 +2689,7 @@ static void imsm_update_metadata_locally(struct supertype *st,
 static int write_imsm_migr_rec(struct supertype *st)
 {
        struct intel_super *super = st->sb;
+       unsigned int sector_size = super->sector_size;
        unsigned long long dsize;
        char nm[30];
        int fd = -1;
@@ -2491,7 +2698,7 @@ static int write_imsm_migr_rec(struct supertype *st)
        int len;
        struct imsm_update_general_migration_checkpoint *u;
        struct imsm_dev *dev;
-       struct imsm_map *map = NULL;
+       struct imsm_map *map;
 
        /* find map under migration */
        dev = imsm_get_device_during_migration(super);
@@ -2504,6 +2711,8 @@ static int write_imsm_migr_rec(struct supertype *st)
 
        map = get_imsm_map(dev, MAP_0);
 
+       if (sector_size == 4096)
+               convert_to_4k_imsm_migr_rec(super);
        for (sd = super->disks ; sd ; sd = sd->next) {
                int slot = -1;
 
@@ -2513,7 +2722,7 @@ static int write_imsm_migr_rec(struct supertype *st)
                /* write to 2 first slots only */
                if (map)
                        slot = get_imsm_disk_slot(map, sd->index);
-               if ((map == NULL) || (slot > 1) || (slot < 0))
+               if (map == NULL || slot > 1 || slot < 0)
                        continue;
 
                sprintf(nm, "%d:%d", sd->major, sd->minor);
@@ -2521,13 +2730,15 @@ static int write_imsm_migr_rec(struct supertype *st)
                if (fd < 0)
                        continue;
                get_dev_size(fd, NULL, &dsize);
-               if (lseek64(fd, dsize - MIGR_REC_POSITION, SEEK_SET) < 0) {
+               if (lseek64(fd, dsize - (MIGR_REC_SECTOR_POSITION*sector_size),
+                   SEEK_SET) < 0) {
                        pr_err("Cannot seek to anchor block: %s\n",
                               strerror(errno));
                        goto out;
                }
-               if (write(fd, super->migr_rec_buf, MIGR_REC_BUF_SIZE) !=
-                                                           MIGR_REC_BUF_SIZE) {
+               if (write(fd, super->migr_rec_buf,
+                   MIGR_REC_BUF_SECTORS*sector_size) !=
+                   MIGR_REC_BUF_SECTORS*sector_size) {
                        pr_err("Cannot write migr record block: %s\n",
                               strerror(errno));
                        goto out;
@@ -2535,9 +2746,10 @@ static int write_imsm_migr_rec(struct supertype *st)
                close(fd);
                fd = -1;
        }
+       if (sector_size == 4096)
+               convert_from_4k_imsm_migr_rec(super);
        /* update checkpoint information in metadata */
        len = imsm_create_metadata_checkpoint_update(super, &u);
-
        if (len <= 0) {
                dprintf("imsm: Cannot prepare update\n");
                goto out;
@@ -2589,13 +2801,14 @@ int imsm_reshape_blocks_arrays_changes(struct intel_super *super)
 }
 static unsigned long long imsm_component_size_aligment_check(int level,
                                              int chunk_size,
+                                             unsigned int sector_size,
                                              unsigned long long component_size)
 {
        unsigned int component_size_alligment;
 
        /* check component size aligment
        */
-       component_size_alligment = component_size % (chunk_size/512);
+       component_size_alligment = component_size % (chunk_size/sector_size);
 
        dprintf("(Level: %i, chunk_size = %i, component_size = %llu), component_size_alligment = %u\n",
                level, chunk_size, component_size,
@@ -2701,11 +2914,18 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
        }
 
        info->data_offset         = pba_of_lba0(map_to_analyse);
-       info->component_size      = blocks_per_member(map_to_analyse);
+
+       if (info->array.level == 5) {
+               info->component_size = num_data_stripes(map_to_analyse) *
+                                      map_to_analyse->blocks_per_strip;
+       } else {
+               info->component_size = blocks_per_member(map_to_analyse);
+       }
 
        info->component_size = imsm_component_size_aligment_check(
                                                        info->array.level,
                                                        info->array.chunk_size,
+                                                       super->sector_size,
                                                        info->component_size);
 
        memset(info->uuid, 0, sizeof(info->uuid));
@@ -2963,7 +3183,7 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
  * for each disk in array */
 struct mdinfo *getinfo_super_disks_imsm(struct supertype *st)
 {
-       struct mdinfo *mddev = NULL;
+       struct mdinfo *mddev;
        struct intel_super *super = st->sb;
        struct imsm_disk *disk;
        int count = 0;
@@ -3233,23 +3453,40 @@ static void fd2devname(int fd, char *name)
        }
 }
 
+static int nvme_get_serial(int fd, void *buf, size_t buf_len)
+{
+       char path[60];
+       char *name = fd2kname(fd);
+
+       if (!name)
+               return 1;
+
+       if (strncmp(name, "nvme", 4) != 0)
+               return 1;
+
+       snprintf(path, sizeof(path) - 1, "/sys/block/%s/device/serial", name);
+
+       return load_sys(path, buf, buf_len);
+}
+
 extern int scsi_get_serial(int fd, void *buf, size_t buf_len);
 
 static int imsm_read_serial(int fd, char *devname,
                            __u8 serial[MAX_RAID_SERIAL_LEN])
 {
-       unsigned char scsi_serial[255];
+       char buf[50];
        int rv;
-       int rsp_len;
        int len;
        char *dest;
        char *src;
-       char *rsp_buf;
-       int i;
+       unsigned int i;
 
-       memset(scsi_serial, 0, sizeof(scsi_serial));
+       memset(buf, 0, sizeof(buf));
 
-       rv = scsi_get_serial(fd, scsi_serial, sizeof(scsi_serial));
+       rv = nvme_get_serial(fd, buf, sizeof(buf));
+
+       if (rv)
+               rv = scsi_get_serial(fd, buf, sizeof(buf));
 
        if (rv && check_env("IMSM_DEVNAME_AS_SERIAL")) {
                memset(serial, 0, MAX_RAID_SERIAL_LEN);
@@ -3264,20 +3501,11 @@ static int imsm_read_serial(int fd, char *devname,
                return rv;
        }
 
-       rsp_len = scsi_serial[3];
-       if (!rsp_len) {
-               if (devname)
-                       pr_err("Failed to retrieve serial for %s\n",
-                              devname);
-               return 2;
-       }
-       rsp_buf = (char *) &scsi_serial[4];
-
        /* trim all whitespace and non-printable characters and convert
         * ':' to ';'
         */
-       for (i = 0, dest = rsp_buf; i < rsp_len; i++) {
-               src = &rsp_buf[i];
+       for (i = 0, dest = buf; i < sizeof(buf) && buf[i]; i++) {
+               src = &buf[i];
                if (*src > 0x20) {
                        /* ':' is reserved for use in placeholder serial
                         * numbers for missing disks
@@ -3288,8 +3516,8 @@ static int imsm_read_serial(int fd, char *devname,
                                *dest++ = *src;
                }
        }
-       len = dest - rsp_buf;
-       dest = rsp_buf;
+       len = dest - buf;
+       dest = buf;
 
        /* truncate leading characters */
        if (len > MAX_RAID_SERIAL_LEN) {
@@ -3421,8 +3649,7 @@ static void migrate(struct imsm_dev *dev, struct intel_super *super,
 
        /* duplicate and then set the target end state in map[0] */
        memcpy(dest, src, sizeof_imsm_map(src));
-       if ((migr_type == MIGR_REBUILD) ||
-           (migr_type ==  MIGR_GEN_MIGR)) {
+       if (migr_type == MIGR_REBUILD || migr_type ==  MIGR_GEN_MIGR) {
                __u32 ord;
                int i;
 
@@ -3452,8 +3679,8 @@ static void end_migration(struct imsm_dev *dev, struct intel_super *super,
         *
         * FIXME add support for raid-level-migration
         */
-       if ((map_state != map->map_state) && (is_gen_migration(dev) == 0) &&
-               (prev->map_state != IMSM_T_STATE_UNINITIALIZED)) {
+       if (map_state != map->map_state && (is_gen_migration(dev) == 0) &&
+           prev->map_state != IMSM_T_STATE_UNINITIALIZED) {
                /* when final map state is other than expected
                 * merge maps (not for migration)
                 */
@@ -3519,8 +3746,9 @@ static int parse_raid_devices(struct intel_super *super)
        if (__le32_to_cpu(mpb->mpb_size) + space_needed > super->len) {
                void *buf;
 
-               len = ROUND_UP(__le32_to_cpu(mpb->mpb_size) + space_needed, 512);
-               if (posix_memalign(&buf, 512, len) != 0)
+               len = ROUND_UP(__le32_to_cpu(mpb->mpb_size) + space_needed,
+                             super->sector_size);
+               if (posix_memalign(&buf, MAX_SECTOR_SIZE, len) != 0)
                        return 1;
 
                memcpy(buf, super->buf, super->len);
@@ -3593,31 +3821,32 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
 {
        unsigned long long dsize;
        unsigned long long sectors;
+       unsigned int sector_size = super->sector_size;
        struct stat;
        struct imsm_super *anchor;
        __u32 check_sum;
 
        get_dev_size(fd, NULL, &dsize);
-       if (dsize < 1024) {
+       if (dsize < 2*sector_size) {
                if (devname)
                        pr_err("%s: device to small for imsm\n",
                               devname);
                return 1;
        }
 
-       if (lseek64(fd, dsize - (512 * 2), SEEK_SET) < 0) {
+       if (lseek64(fd, dsize - (sector_size * 2), SEEK_SET) < 0) {
                if (devname)
                        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 (posix_memalign((void **)&anchor, sector_size, sector_size) != 0) {
                if (devname)
                        pr_err("Failed to allocate imsm anchor buffer on %s\n", devname);
                return 1;
        }
-       if (read(fd, anchor, 512) != 512) {
+       if (read(fd, anchor, sector_size) != sector_size) {
                if (devname)
                        pr_err("Cannot read anchor block on %s: %s\n",
                               devname, strerror(errno));
@@ -3637,20 +3866,21 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
 
        /* capability and hba must be updated with new super allocation */
        find_intel_hba_capability(fd, super, devname);
-       super->len = ROUND_UP(anchor->mpb_size, 512);
-       if (posix_memalign(&super->buf, 512, super->len) != 0) {
+       super->len = ROUND_UP(anchor->mpb_size, sector_size);
+       if (posix_memalign(&super->buf, MAX_SECTOR_SIZE, super->len) != 0) {
                if (devname)
                        pr_err("unable to allocate %zu byte mpb buffer\n",
                               super->len);
                free(anchor);
                return 2;
        }
-       memcpy(super->buf, anchor, 512);
+       memcpy(super->buf, anchor, sector_size);
 
-       sectors = mpb_sectors(anchor) - 1;
+       sectors = mpb_sectors(anchor, sector_size) - 1;
        free(anchor);
 
-       if (posix_memalign(&super->migr_rec_buf, 512, MIGR_REC_BUF_SIZE) != 0) {
+       if (posix_memalign(&super->migr_rec_buf, sector_size,
+           MIGR_REC_BUF_SECTORS*sector_size) != 0) {
                pr_err("could not allocate migr_rec buffer\n");
                free(super->buf);
                return 2;
@@ -3672,14 +3902,15 @@ 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 (lseek64(fd, dsize - (sector_size * (2 + sectors)), SEEK_SET) < 0) {
                if (devname)
                        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 ((unsigned int)read(fd, super->buf + sector_size,
+                   super->len - sector_size) != super->len - sector_size) {
                if (devname)
                        pr_err("Cannot read extended mpb on %s: %s\n",
                               devname, strerror(errno));
@@ -3740,6 +3971,8 @@ load_and_parse_mpb(int fd, struct intel_super *super, char *devname, int keep_fd
        err = load_imsm_mpb(fd, super, devname);
        if (err)
                return err;
+       if (super->sector_size == 4096)
+               convert_from_4k(super);
        err = load_imsm_disk(fd, super, devname, keep_fd);
        if (err)
                return err;
@@ -3845,7 +4078,7 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
        struct sys_dev *hba_name;
        int rv = 0;
 
-       if ((fd < 0) || check_env("IMSM_NO_PLATFORM")) {
+       if (fd < 0 || check_env("IMSM_NO_PLATFORM")) {
                super->orom = NULL;
                super->hba = NULL;
                return 0;
@@ -3862,12 +4095,14 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
                if (devname) {
                        struct intel_hba *hba = super->hba;
 
-                       pr_err("%s is attached to Intel(R) %s RAID controller (%s),\n"
-                               "    but the container is assigned to Intel(R) %s RAID controller (",
+                       pr_err("%s is attached to Intel(R) %s %s (%s),\n"
+                               "    but the container is assigned to Intel(R) %s %s (",
                                devname,
                                get_sys_dev_type(hba_name->type),
+                               hba_name->type == SYS_DEV_VMD ? "domain" : "RAID controller",
                                hba_name->pci_id ? : "Err!",
-                               get_sys_dev_type(super->hba->type));
+                               get_sys_dev_type(super->hba->type),
+                               hba->type == SYS_DEV_VMD ? "domain" : "RAID controller");
 
                        while (hba) {
                                fprintf(stderr, "%s", hba->pci_id ? : "Err!");
@@ -3876,7 +4111,8 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
                                hba = hba->next;
                        }
                        fprintf(stderr, ").\n"
-                               "    Mixing devices attached to different controllers is not allowed.\n");
+                               "    Mixing devices attached to different %s is not allowed.\n",
+                               hba_name->type == SYS_DEV_VMD ? "VMD domains" : "controllers");
                }
                return 2;
        }
@@ -4285,7 +4521,7 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
        }
 
        /* Check migration compatibility */
-       if ((err == 0) && (check_mpb_migr_compatibility(super) != 0)) {
+       if (err == 0 && check_mpb_migr_compatibility(super) != 0) {
                pr_err("Unsupported migration detected");
                if (devname)
                        fprintf(stderr, " on %s\n", devname);
@@ -4374,7 +4610,7 @@ get_devlist_super_block(struct md_list *devlist, struct intel_super **super_list
 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;
+       struct intel_super *s;
        char nm[32];
        int dfd = -1;
        int err = 0;
@@ -4393,6 +4629,7 @@ static int get_super_block(struct intel_super **super_list, char *devnm, char *d
                goto error;
        }
 
+       get_dev_sector_size(dfd, NULL, &s->sector_size);
        find_intel_hba_capability(dfd, s, devname);
        err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
 
@@ -4414,7 +4651,7 @@ static int get_super_block(struct intel_super **super_list, char *devnm, char *d
                if (dfd >= 0)
                        close(dfd);
        }
-       if ((dfd >= 0) && (!keep_fd))
+       if (dfd >= 0 && !keep_fd)
                close(dfd);
        return err;
 
@@ -4472,13 +4709,14 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
        free_super_imsm(st);
 
        super = alloc_super();
+       get_dev_sector_size(fd, NULL, &super->sector_size);
        /* 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.
         */
        rv = find_intel_hba_capability(fd, super, devname);
        /* no orom/efi or non-intel hba of the disk */
-       if ((rv != 0) && (st->ignore_hw_compat == 0)) {
+       if (rv != 0 && st->ignore_hw_compat == 0) {
                if (devname)
                        pr_err("No OROM/EFI properties for %s\n", devname);
                free_imsm(super);
@@ -4488,7 +4726,11 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
 
        /* retry the load if we might have raced against mdmon */
        if (rv == 3) {
-               struct mdstat_ent *mdstat = mdstat_by_component(fd2devnm(fd));
+               struct mdstat_ent *mdstat = NULL;
+               char *name = fd2kname(fd);
+
+               if (name)
+                       mdstat = mdstat_by_component(name);
 
                if (mdstat && mdmon_running(mdstat->devnm) && getpid() != mdmon_pid(mdstat->devnm)) {
                        for (retry = 0; retry < 3; retry++) {
@@ -4628,6 +4870,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
         * so st->sb is already set.
         */
        struct intel_super *super = st->sb;
+       unsigned int sector_size = super->sector_size;
        struct imsm_super *mpb = super->anchor;
        struct intel_dev *dv;
        struct imsm_dev *dev;
@@ -4649,14 +4892,14 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        size_new = disks_to_mpb_size(info->nr_disks);
        if (size_new > size_old) {
                void *mpb_new;
-               size_t size_round = ROUND_UP(size_new, 512);
+               size_t size_round = ROUND_UP(size_new, sector_size);
 
-               if (posix_memalign(&mpb_new, 512, size_round) != 0) {
+               if (posix_memalign(&mpb_new, sector_size, size_round) != 0) {
                        pr_err("could not allocate new mpb\n");
                        return 0;
                }
-               if (posix_memalign(&super->migr_rec_buf, 512,
-                                  MIGR_REC_BUF_SIZE) != 0) {
+               if (posix_memalign(&super->migr_rec_buf, sector_size,
+                                  MIGR_REC_BUF_SECTORS*sector_size) != 0) {
                        pr_err("could not allocate migr_rec buffer\n");
                        free(super->buf);
                        free(super);
@@ -4806,10 +5049,11 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
        if (info)
                mpb_size = disks_to_mpb_size(info->nr_disks);
        else
-               mpb_size = 512;
+               mpb_size = MAX_SECTOR_SIZE;
 
        super = alloc_super();
-       if (super && posix_memalign(&super->buf, 512, mpb_size) != 0) {
+       if (super &&
+           posix_memalign(&super->buf, MAX_SECTOR_SIZE, mpb_size) != 0) {
                free(super);
                super = NULL;
        }
@@ -4817,7 +5061,8 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
                pr_err("could not allocate superblock\n");
                return 0;
        }
-       if (posix_memalign(&super->migr_rec_buf, 512, MIGR_REC_BUF_SIZE) != 0) {
+       if (posix_memalign(&super->migr_rec_buf, MAX_SECTOR_SIZE,
+           MIGR_REC_BUF_SECTORS*MAX_SECTOR_SIZE) != 0) {
                pr_err("could not allocate migr_rec buffer\n");
                free(super->buf);
                free(super);
@@ -4924,8 +5169,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
                                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)) {
+                               if (slot2 < map2->num_members && slot2 >= 0) {
                                        __u32 ord2 = get_imsm_ord_tbl_ent(dev,
                                                                         slot2,
                                                                         MAP_1);
@@ -5001,6 +5245,7 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
        struct intel_super *super = st->sb;
        struct dl *dd;
        unsigned long long size;
+       unsigned int member_sector_size;
        __u32 id;
        int rv;
        struct stat stb;
@@ -5032,16 +5277,75 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
        rv = imsm_read_serial(fd, devname, dd->serial);
        if (rv) {
                pr_err("failed to retrieve scsi serial, aborting\n");
+               if (dd->devname)
+                       free(dd->devname);
                free(dd);
                abort();
        }
+       if (super->hba && ((super->hba->type == SYS_DEV_NVME) ||
+          (super->hba->type == SYS_DEV_VMD))) {
+               int i;
+               char *devpath = diskfd_to_devpath(fd);
+               char controller_path[PATH_MAX];
+
+               if (!devpath) {
+                       pr_err("failed to get devpath, aborting\n");
+                       if (dd->devname)
+                               free(dd->devname);
+                       free(dd);
+                       return 1;
+               }
+
+               snprintf(controller_path, PATH_MAX-1, "%s/device", devpath);
+               free(devpath);
+
+               if (devpath_to_vendor(controller_path) == 0x8086) {
+                       /*
+                        * If Intel's NVMe drive has serial ended with
+                        * "-A","-B","-1" or "-2" it means that this is "x8"
+                        * device (double drive on single PCIe card).
+                        * User should be warned about potential data loss.
+                        */
+                       for (i = MAX_RAID_SERIAL_LEN-1; i > 0; i--) {
+                               /* Skip empty character at the end */
+                               if (dd->serial[i] == 0)
+                                       continue;
+
+                               if (((dd->serial[i] == 'A') ||
+                                  (dd->serial[i] == 'B') ||
+                                  (dd->serial[i] == '1') ||
+                                  (dd->serial[i] == '2')) &&
+                                  (dd->serial[i-1] == '-'))
+                                       pr_err("\tThe action you are about to take may put your data at risk.\n"
+                                               "\tPlease note that x8 devices may consist of two separate x4 devices "
+                                               "located on a single PCIe port.\n"
+                                               "\tRAID 0 is the only supported configuration for this type of x8 device.\n");
+                               break;
+                       }
+               }
+       }
 
        get_dev_size(fd, NULL, &size);
+       get_dev_sector_size(fd, NULL, &member_sector_size);
+
+       if (super->sector_size == 0) {
+               /* this a first device, so sector_size is not set yet */
+               super->sector_size = member_sector_size;
+       } else if (member_sector_size != super->sector_size) {
+               pr_err("Mixing between different sector size is forbidden, aborting...\n");
+               if (dd->devname)
+                       free(dd->devname);
+               free(dd);
+               return 1;
+       }
+
        /* 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) {
+       memset(super->migr_rec_buf, 0, MIGR_REC_BUF_SECTORS*super->sector_size);
+       if (lseek64(fd, size - MIGR_REC_SECTOR_POSITION*super->sector_size,
+           SEEK_SET) >= 0) {
                if (write(fd, super->migr_rec_buf,
-                       MIGR_REC_BUF_SIZE) != MIGR_REC_BUF_SIZE)
+                   MIGR_REC_BUF_SECTORS*super->sector_size) !=
+                   MIGR_REC_BUF_SECTORS*super->sector_size)
                        perror("Write migr_rec failed");
        }
 
@@ -5099,9 +5403,9 @@ static int remove_from_super_imsm(struct supertype *st, mdu_disk_info_t *dk)
 static int store_imsm_mpb(int fd, struct imsm_super *mpb);
 
 static union {
-       char buf[512];
+       char buf[MAX_SECTOR_SIZE];
        struct imsm_super anchor;
-} spare_record __attribute__ ((aligned(512)));
+} spare_record __attribute__ ((aligned(MAX_SECTOR_SIZE)));
 
 /* spare records have their own family number and do not have any defined raid
  * devices
@@ -5132,6 +5436,9 @@ static int write_super_imsm_spares(struct intel_super *super, int doclose)
                if (__le32_to_cpu(d->disk.total_blocks_hi) > 0)
                        spare->attributes |= MPB_ATTRIB_2TB_DISK;
 
+               if (super->sector_size == 4096)
+                       convert_to_4k_imsm_disk(&spare->disk[0]);
+
                sum = __gen_imsm_checksum(spare);
                spare->family_num = __cpu_to_le32(sum);
                spare->orig_family_num = 0;
@@ -5155,6 +5462,7 @@ static int write_super_imsm_spares(struct intel_super *super, int doclose)
 static int write_super_imsm(struct supertype *st, int doclose)
 {
        struct intel_super *super = st->sb;
+       unsigned int sector_size = super->sector_size;
        struct imsm_super *mpb = super->anchor;
        struct dl *d;
        __u32 generation;
@@ -5213,7 +5521,11 @@ static int write_super_imsm(struct supertype *st, int doclose)
                super->clean_migration_record_by_mdmon = 0;
        }
        if (clear_migration_record)
-               memset(super->migr_rec_buf, 0, MIGR_REC_BUF_SIZE);
+               memset(super->migr_rec_buf, 0,
+                   MIGR_REC_BUF_SECTORS*sector_size);
+
+       if (sector_size == 4096)
+               convert_to_4k(super);
 
        /* write the mpb for disks that compose raid devices */
        for (d = super->disks; d ; d = d->next) {
@@ -5224,9 +5536,11 @@ static int write_super_imsm(struct supertype *st, int doclose)
                        unsigned long long dsize;
 
                        get_dev_size(d->fd, NULL, &dsize);
-                       if (lseek64(d->fd, dsize - 512, SEEK_SET) >= 0) {
+                       if (lseek64(d->fd, dsize - sector_size,
+                           SEEK_SET) >= 0) {
                                if (write(d->fd, super->migr_rec_buf,
-                                       MIGR_REC_BUF_SIZE) != MIGR_REC_BUF_SIZE)
+                                   MIGR_REC_BUF_SECTORS*sector_size) !=
+                                   MIGR_REC_BUF_SECTORS*sector_size)
                                        perror("Write migr_rec failed");
                        }
                }
@@ -5338,6 +5652,8 @@ static int store_super_imsm(struct supertype *st, int fd)
                return 1;
 
 #ifndef MDASSEMBLE
+       if (super->sector_size == 4096)
+               convert_to_4k(super);
        return store_imsm_mpb(fd, mpb);
 #else
        return 1;
@@ -5360,7 +5676,7 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
 {
        int fd;
        unsigned long long ldsize;
-       struct intel_super *super=NULL;
+       struct intel_super *super;
        int rv = 0;
 
        if (level != LEVEL_CONTAINER)
@@ -5384,6 +5700,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 (!get_dev_sector_size(fd, NULL, &super->sector_size)) {
+               close(fd);
+               free_imsm(super);
+               return 0;
+       }
+
        rv = find_intel_hba_capability(fd, super, verbose > 0 ? dev : NULL);
        if (rv != 0) {
 #if DEBUG
@@ -5553,10 +5875,10 @@ 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;
+       struct mdstat_ent *memb;
        int count = 0;
        int num = 0;
-       struct md_list *dv = NULL;
+       struct md_list *dv;
        int found;
 
        for (memb = mdstat ; memb ; memb = memb->next) {
@@ -5572,18 +5894,18 @@ active_arrays_by_format(char *name, char* hba, struct md_list **devlist,
                                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",
+                               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)) {
+                       if (fd >= 0 && disk_attached_to_hba(fd, hba)) {
                                struct mdstat_ent *vol;
                                for (vol = mdstat ; vol ; vol = vol->next) {
-                                       if ((vol->active > 0) &&
+                                       if (vol->active > 0 &&
                                            vol->metadata_version &&
                                            is_container_member(vol, memb->devnm)) {
                                                found++;
@@ -5614,7 +5936,7 @@ get_loop_devices(void)
 {
        int i;
        struct md_list *devlist = NULL;
-       struct md_list *dv = NULL;
+       struct md_list *dv;
 
        for(i = 0; i < 12; i++) {
                dv = xcalloc(1, sizeof(*dv));
@@ -5631,7 +5953,7 @@ static struct md_list*
 get_devices(const char *hba_path)
 {
        struct md_list *devlist = NULL;
-       struct md_list *dv = NULL;
+       struct md_list *dv;
        struct dirent *ent;
        DIR *dir;
        int err = 0;
@@ -5694,7 +6016,7 @@ count_volumes_list(struct md_list *devlist, char *homehost,
 {
        struct md_list *tmpdev;
        int count = 0;
-       struct supertype *st = NULL;
+       struct supertype *st;
 
        /* first walk the list of devices to find a consistent set
         * that match the criterea, if that is possible.
@@ -5703,7 +6025,7 @@ count_volumes_list(struct md_list *devlist, char *homehost,
        *found = 0;
        st = match_metadata_desc_imsm("imsm");
        if (st == NULL) {
-               pr_vrb("cannot allocate memory for imsm supertype\n");
+               pr_vrb("cannot allocate memory for imsm supertype\n");
                return 0;
        }
 
@@ -5716,7 +6038,7 @@ count_volumes_list(struct md_list *devlist, char *homehost,
                        continue;
                tst = dup_super(st);
                if (tst == NULL) {
-                       pr_vrb("cannot allocate memory for imsm supertype\n");
+                       pr_vrb("cannot allocate memory for imsm supertype\n");
                        goto err_1;
                }
                tmpdev->container = 0;
@@ -5835,7 +6157,7 @@ count_volumes_list(struct md_list *devlist, char *homehost,
        }
 
        for (tmpdev = devlist; tmpdev; tmpdev = tmpdev->next) {
-               if ((tmpdev->used == 1) && (tmpdev->found)) {
+               if (tmpdev->used == 1 && tmpdev->found) {
                        if (count) {
                                if (count < tmpdev->found)
                                        count = 0;
@@ -5878,8 +6200,7 @@ count_volumes(struct intel_hba *hba, int dpa, int verbose)
 
        devid_list = entry->devid_list;
        for (dv = devid_list; dv; dv = dv->next) {
-
-               struct md_list *devlist = NULL;
+               struct md_list *devlist;
                struct sys_dev *device = device_by_id(dv->devid);
                char *hba_path;
                int found = 0;
@@ -5935,14 +6256,14 @@ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
 {
        /* check/set platform and metadata limits/defaults */
        if (super->orom && raiddisks > super->orom->dpa) {
-               pr_vrb("platform supports a maximum of %d disks per array\n",
+               pr_vrb("platform supports a maximum of %d disks per array\n",
                       super->orom->dpa);
                return 0;
        }
 
        /* capabilities of OROM tested - copied from validate_geometry_imsm_volume */
        if (!is_raid_level_supported(super->orom, level, raiddisks)) {
-               pr_vrb("platform does not support raid%d with %d disk%s\n",
+               pr_vrb("platform does not support raid%d with %d disk%s\n",
                        level, raiddisks, raiddisks > 1 ? "s" : "");
                return 0;
        }
@@ -5951,24 +6272,24 @@ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
                *chunk = imsm_default_chunk(super->orom);
 
        if (super->orom && !imsm_orom_has_chunk(super->orom, *chunk)) {
-               pr_vrb("platform does not support a chunk size of: %d\n", *chunk);
+               pr_vrb("platform does not support a chunk size of: %d\n", *chunk);
                return 0;
        }
 
        if (layout != imsm_level_to_layout(level)) {
                if (level == 5)
-                       pr_vrb("imsm raid 5 only supports the left-asymmetric layout\n");
+                       pr_vrb("imsm raid 5 only supports the left-asymmetric layout\n");
                else if (level == 10)
-                       pr_vrb("imsm raid 10 only supports the n2 layout\n");
+                       pr_vrb("imsm raid 10 only supports the n2 layout\n");
                else
-                       pr_vrb("imsm unknown layout %#x for this raid level %d\n",
+                       pr_vrb("imsm unknown layout %#x for this raid level %d\n",
                                layout, level);
                return 0;
        }
 
        if (super->orom && (super->orom->attr & IMSM_OROM_ATTR_2TB) == 0 &&
                        (calc_array_size(level, raiddisks, layout, *chunk, size) >> 32) > 0) {
-               pr_vrb("platform does not support a volume size over 2TB\n");
+               pr_vrb("platform does not support a volume size over 2TB\n");
                return 0;
        }
 
@@ -6139,7 +6460,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
                int count = count_volumes(super->hba,
                                      super->orom->dpa, verbose);
                if (super->orom->vphba <= count) {
-                       pr_vrb("platform does not support more than %d raid volumes.\n",
+                       pr_vrb("platform does not support more than %d raid volumes.\n",
                               super->orom->vphba);
                        return 0;
                }
@@ -6295,7 +6616,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                                count = count_volumes(super->hba,
                                                      super->orom->dpa, verbose);
                                if (super->orom->vphba <= count) {
-                                       pr_vrb("platform does not support more than %d raid volumes.\n",
+                                       pr_vrb("platform does not support more than %d raid volumes.\n",
                                               super->orom->vphba);
                                        return 0;
                                }
@@ -6748,7 +7069,14 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
 
                        info_d->events = __le32_to_cpu(mpb->generation_num);
                        info_d->data_offset = pba_of_lba0(map);
-                       info_d->component_size = blocks_per_member(map);
+
+                       if (map->raid_level == 5) {
+                               info_d->component_size =
+                                               num_data_stripes(map) *
+                                               map->blocks_per_strip;
+                       } else {
+                               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);
@@ -6862,8 +7190,8 @@ static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev,
                /* when MAP_X is passed both maps failures are counted
                 */
                if (prev &&
-                   ((look_in_map == MAP_1) || (look_in_map == MAP_X)) &&
-                   (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);
 
@@ -6871,8 +7199,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) || (look_in_map == MAP_X)) &&
-                   (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);
 
@@ -6921,8 +7249,8 @@ static int is_resyncing(struct imsm_dev *dev)
 
        migr_map = get_imsm_map(dev, MAP_1);
 
-       if ((migr_map->map_state == IMSM_T_STATE_NORMAL) &&
-           (dev->vol.migr_type != MIGR_GEN_MIGR))
+       if (migr_map->map_state == IMSM_T_STATE_NORMAL &&
+           dev->vol.migr_type != MIGR_GEN_MIGR)
                return 1;
        else
                return 0;
@@ -6965,8 +7293,7 @@ static int mark_failure(struct imsm_dev *dev, struct imsm_disk *disk, int idx)
                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))
+               if (slot2 < map2->num_members && slot2 >= 0)
                        set_imsm_ord_tbl_ent(map2, slot2,
                                             idx | IMSM_ORD_REBUILD);
        }
@@ -7346,8 +7673,7 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
        break;
        case IMSM_T_STATE_DEGRADED: /* transition to degraded state */
                dprintf_cont("degraded: ");
-               if ((map->map_state != map_state) &&
-                   !dev->vol.migr_state) {
+               if (map->map_state != map_state && !dev->vol.migr_state) {
                        dprintf_cont("mark degraded");
                        map->map_state = map_state;
                        super->updates_pending++;
@@ -7409,27 +7735,30 @@ static int store_imsm_mpb(int fd, struct imsm_super *mpb)
        __u32 mpb_size = __le32_to_cpu(mpb->mpb_size);
        unsigned long long dsize;
        unsigned long long sectors;
+       unsigned int sector_size;
 
+       get_dev_sector_size(fd, NULL, &sector_size);
        get_dev_size(fd, NULL, &dsize);
 
-       if (mpb_size > 512) {
+       if (mpb_size > sector_size) {
                /* -1 to account for anchor */
-               sectors = mpb_sectors(mpb) - 1;
+               sectors = mpb_sectors(mpb, sector_size) - 1;
 
                /* write the extended mpb to the sectors preceeding the anchor */
-               if (lseek64(fd, dsize - (512 * (2 + sectors)), SEEK_SET) < 0)
+               if (lseek64(fd, dsize - (sector_size * (2 + sectors)),
+                  SEEK_SET) < 0)
                        return 1;
 
-               if ((unsigned long long)write(fd, buf + 512, 512 * sectors)
-                   != 512 * sectors)
+               if ((unsigned long long)write(fd, buf + sector_size,
+                  sector_size * sectors) != sector_size * sectors)
                        return 1;
        }
 
        /* first block is stored on second to last sector of the disk */
-       if (lseek64(fd, dsize - (512 * 2), SEEK_SET) < 0)
+       if (lseek64(fd, dsize - (sector_size * 2), SEEK_SET) < 0)
                return 1;
 
-       if (write(fd, buf, 512) != 512)
+       if (write(fd, buf, sector_size) != sector_size)
                return 1;
 
        return 0;
@@ -7677,6 +8006,11 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
                        IMSM_T_STATE_DEGRADED)
                return NULL;
 
+       if (get_imsm_map(dev, MAP_0)->map_state == IMSM_T_STATE_UNINITIALIZED) {
+               dprintf("imsm: No spare activation allowed. Volume is not initialized.\n");
+               return NULL;
+       }
+
        /*
         * If there are any failed disks check state of the other volume.
         * Block rebuild if the another one is failed until failed disks
@@ -7805,21 +8139,22 @@ static int disks_overlap(struct intel_super *super, int idx, struct imsm_update_
 
 static struct dl *get_disk_super(struct intel_super *super, int major, int minor)
 {
-       struct dl *dl = NULL;
+       struct dl *dl;
+
        for (dl = super->disks; dl; dl = dl->next)
-               if ((dl->major == major) &&  (dl->minor == minor))
+               if (dl->major == major &&  dl->minor == minor)
                        return dl;
        return NULL;
 }
 
 static int remove_disk_super(struct intel_super *super, int major, int minor)
 {
-       struct dl *prev = NULL;
+       struct dl *prev;
        struct dl *dl;
 
        prev = NULL;
        for (dl = super->disks; dl; dl = dl->next) {
-               if ((dl->major == major) && (dl->minor == minor)) {
+               if (dl->major == major && dl->minor == minor) {
                        /* remove */
                        if (prev)
                                prev->next = dl->next;
@@ -7840,7 +8175,8 @@ static void imsm_delete(struct intel_super *super, struct dl **dlp, unsigned ind
 static int add_remove_disk_update(struct intel_super *super)
 {
        int check_degraded = 0;
-       struct dl *disk = NULL;
+       struct dl *disk;
+
        /* add/remove some spares to/from the metadata/contrainer */
        while (super->disk_mgmt_list) {
                struct dl *disk_cfg;
@@ -7887,12 +8223,11 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration *
        int ret_val = 0;
 
        dprintf("(enter)\n");
-       if ((u->subdev < 0) ||
-           (u->subdev > 1)) {
+       if (u->subdev < 0 || u->subdev > 1) {
                dprintf("imsm: Error: Wrong subdev: %i\n", u->subdev);
                return ret_val;
        }
-       if ((space_list == NULL) || (*space_list == NULL)) {
+       if (space_list == NULL || *space_list == NULL) {
                dprintf("imsm: Error: Memory is not allocated\n");
                return ret_val;
        }
@@ -7947,15 +8282,28 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration *
 
                        /* update chunk size
                         */
-                       if (u->new_chunksize > 0)
+                       if (u->new_chunksize > 0) {
+                               unsigned long long num_data_stripes;
+                               int used_disks =
+                                       imsm_num_data_members(dev, MAP_0);
+
+                               if (used_disks == 0)
+                                       return ret_val;
+
                                map->blocks_per_strip =
                                        __cpu_to_le16(u->new_chunksize * 2);
+                               num_data_stripes =
+                                       (join_u32(dev->size_low, dev->size_high)
+                                       / used_disks);
+                               num_data_stripes /= map->blocks_per_strip;
+                               num_data_stripes /= map->num_domains;
+                               set_num_data_stripes(map, num_data_stripes);
+                       }
 
                        /* add disk
                         */
-                       if ((u->new_level != 5) ||
-                           (migr_map->raid_level != 0) ||
-                           (migr_map->raid_level == map->raid_level))
+                       if (u->new_level != 5 || migr_map->raid_level != 0 ||
+                           migr_map->raid_level == map->raid_level)
                                goto skip_disk_add;
 
                        if (u->new_disks[0] >= 0) {
@@ -8006,8 +8354,7 @@ static int apply_size_change_update(struct imsm_update_size_change *u,
        int ret_val = 0;
 
        dprintf("(enter)\n");
-       if ((u->subdev < 0) ||
-           (u->subdev > 1)) {
+       if (u->subdev < 0 || u->subdev > 1) {
                dprintf("imsm: Error: Wrong subdev: %i\n", u->subdev);
                return ret_val;
        }
@@ -8018,13 +8365,19 @@ static int apply_size_change_update(struct imsm_update_size_change *u,
                        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;
+                       unsigned long long num_data_stripes;
 
                        /* 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);
+                       num_data_stripes = blocks_per_member /
+                                          map->blocks_per_strip;
+                       num_data_stripes /= map->num_domains;
+                       dprintf("(size: %llu, blocks per member: %llu, num_data_stipes: %llu)\n",
+                               u->new_size, blocks_per_member,
+                               num_data_stripes);
                        set_blocks_per_member(map, blocks_per_member);
+                       set_num_data_stripes(map, num_data_stripes);
                        imsm_set_array_size(dev, u->new_size);
 
                        ret_val = 1;
@@ -8174,9 +8527,9 @@ static int apply_reshape_container_disks_update(struct imsm_update_reshape *u,
                dprintf("imsm: new disk for reshape is: %i:%i (%p, index = %i)\n",
                        major(u->new_disks[i]), minor(u->new_disks[i]),
                        new_disk, new_disk->index);
-               if ((new_disk == NULL) ||
-                   ((new_disk->index >= 0) &&
-                    (new_disk->index < u->old_raid_disks)))
+               if (new_disk == NULL ||
+                   (new_disk->index >= 0 &&
+                    new_disk->index < u->old_raid_disks))
                        goto update_reshape_exit;
                new_disk->index = disk_count++;
                /* slot to fill in autolayout
@@ -8275,6 +8628,14 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
        map = get_imsm_map(dev, MAP_0);
 
        if (u->direction == R10_TO_R0) {
+               unsigned long long num_data_stripes;
+
+               map->num_domains = 1;
+               num_data_stripes = blocks_per_member(map);
+               num_data_stripes /= map->blocks_per_strip;
+               num_data_stripes /= map->num_domains;
+               set_num_data_stripes(map, num_data_stripes);
+
                /* Number of failed disks must be half of initial disk number */
                if (imsm_count_failed(super, dev, MAP_0) !=
                                (map->num_members / 2))
@@ -8661,6 +9022,7 @@ static int imsm_prepare_update(struct supertype *st,
         */
        enum imsm_update_type type;
        struct intel_super *super = st->sb;
+       unsigned int sector_size = super->sector_size;
        struct imsm_super *mpb = super->anchor;
        size_t buf_len;
        size_t len = 0;
@@ -8798,7 +9160,7 @@ static int imsm_prepare_update(struct supertype *st,
                                current_level = map->raid_level;
                                break;
                        }
-               if ((u->new_level == 5) && (u->new_level != current_level)) {
+               if (u->new_level == 5 && u->new_level != current_level) {
                        struct mdinfo *spares;
 
                        spares = get_spares_for_grow(st);
@@ -8897,12 +9259,13 @@ static int imsm_prepare_update(struct supertype *st,
                 * if this allocation fails process_update will notice that
                 * ->next_len is set and ->next_buf is NULL
                 */
-               buf_len = ROUND_UP(__le32_to_cpu(mpb->mpb_size) + len, 512);
+               buf_len = ROUND_UP(__le32_to_cpu(mpb->mpb_size) + len,
+                                 sector_size);
                if (super->next_buf)
                        free(super->next_buf);
 
                super->next_len = buf_len;
-               if (posix_memalign(&super->next_buf, 512, buf_len) == 0)
+               if (posix_memalign(&super->next_buf, sector_size, buf_len) == 0)
                        memset(super->next_buf, 0, buf_len);
                else
                        super->next_buf = NULL;
@@ -9062,8 +9425,7 @@ int open_backup_targets(struct mdinfo *info, int raid_disks, int *raid_fds,
                        continue;
                }
 
-               if ((sd->disk.raid_disk >= raid_disks) ||
-                   (sd->disk.raid_disk < 0))
+               if (sd->disk.raid_disk >= raid_disks || sd->disk.raid_disk < 0)
                        continue;
 
                dn = map_dev(sd->disk.major,
@@ -9078,9 +9440,8 @@ int open_backup_targets(struct mdinfo *info, int raid_disks, int *raid_fds,
        /* check if maximum array degradation level is not exceeded
        */
        if ((raid_disks - opened) >
-                       imsm_get_allowed_degradation(info->new_level,
-                                                    raid_disks,
-                                                    super, dev)) {
+           imsm_get_allowed_degradation(info->new_level, raid_disks,
+                                        super, dev)) {
                pr_err("Not enough disks can be opened.\n");
                close_targets(raid_fds, raid_disks);
                return -2;
@@ -9262,8 +9623,8 @@ int save_backup_imsm(struct supertype *st,
 {
        int rv = -1;
        struct intel_super *super = st->sb;
-       unsigned long long *target_offsets = NULL;
-       int *targets = NULL;
+       unsigned long long *target_offsets;
+       int *targets;
        int i;
        struct imsm_map *map_dest = get_imsm_map(dev, MAP_0);
        int new_disks = map_dest->num_members;
@@ -9390,7 +9751,7 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
 {
        struct intel_super *super = st->sb;
        struct migr_record *migr_rec = super->migr_rec;
-       struct imsm_map *map_dest = NULL;
+       struct imsm_map *map_dest;
        struct intel_dev *id = NULL;
        unsigned long long read_offset;
        unsigned long long write_offset;
@@ -9399,6 +9760,7 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
        int new_disks, i, err;
        char *buf = NULL;
        int retval = 1;
+       unsigned int sector_size = super->sector_size;
        unsigned long curr_migr_unit = __le32_to_cpu(migr_rec->curr_migr_unit);
        unsigned long num_migr_units = __le32_to_cpu(migr_rec->num_migr_units);
        char buffer[20];
@@ -9435,7 +9797,7 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
                        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)
+       if (posix_memalign((void **)&buf, sector_size, unit_len) != 0)
                goto abort;
        targets = xcalloc(new_disks, sizeof(int));
 
@@ -9513,7 +9875,7 @@ static const char *imsm_get_disk_controller_domain(const char *path)
        strncat(disk_path, path, PATH_MAX - strlen(disk_path) - 1);
        if (stat(disk_path, &st) == 0) {
                struct sys_dev* hba;
-               char *path=NULL;
+               char *path;
 
                path = devt_to_devpath(st.st_rdev);
                if (path == NULL)
@@ -9592,8 +9954,7 @@ static int imsm_reshape_is_allowed_on_container(struct supertype *st,
                        break;
                }
 
-               if ((info->array.level != 0) &&
-                   (info->array.level != 5)) {
+               if (info->array.level != 0 && info->array.level != 5) {
                        /* we cannot use this container with other raid level
                         */
                        dprintf("imsm: for container operation wrong raid level (%i) detected\n",
@@ -9678,11 +10039,11 @@ static int imsm_create_metadata_update_for_reshape(
 {
        struct intel_super *super = st->sb;
        struct imsm_super *mpb = super->anchor;
-       int update_memory_size = 0;
-       struct imsm_update_reshape *u = NULL;
-       struct mdinfo *spares = NULL;
+       int update_memory_size;
+       struct imsm_update_reshape *u;
+       struct mdinfo *spares;
        int i;
-       int delta_disks = 0;
+       int delta_disks;
        struct mdinfo *dev;
 
        dprintf("(enter) raid_disks = %i\n", geo->raid_disks);
@@ -9759,8 +10120,8 @@ static int imsm_create_metadata_update_for_size_change(
                                struct imsm_update_size_change **updatep)
 {
        struct intel_super *super = st->sb;
-       int update_memory_size = 0;
-       struct imsm_update_size_change *u = NULL;
+       int update_memory_size;
+       struct imsm_update_size_change *u;
 
        dprintf("(enter) New size = %llu\n", geo->size);
 
@@ -9789,8 +10150,8 @@ static int imsm_create_metadata_update_for_migration(
                                        struct imsm_update_reshape_migration **updatep)
 {
        struct intel_super *super = st->sb;
-       int update_memory_size = 0;
-       struct imsm_update_reshape_migration *u = NULL;
+       int update_memory_size;
+       struct imsm_update_reshape_migration *u;
        struct imsm_dev *dev;
        int previous_level = -1;
 
@@ -9825,12 +10186,12 @@ static int imsm_create_metadata_update_for_migration(
                        previous_level = map->raid_level;
                }
        }
-       if ((geo->level == 5) && (previous_level == 0)) {
+       if (geo->level == 5 && previous_level == 0) {
                struct mdinfo *spares = NULL;
 
                u->new_raid_disks++;
                spares = get_spares_for_grow(st);
-               if ((spares == NULL) || (spares->array.spare_disks < 1)) {
+               if (spares == NULL || spares->array.spare_disks < 1) {
                        free(u);
                        sysfs_free(spares);
                        update_memory_size = 0;
@@ -9894,9 +10255,8 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
        int rv;
 
        getinfo_super_imsm_volume(st, &info, NULL);
-       if ((geo->level != info.array.level) &&
-           (geo->level >= 0) &&
-           (geo->level != UnSet)) {
+       if (geo->level != info.array.level && geo->level >= 0 &&
+           geo->level != UnSet) {
                switch (info.array.level) {
                case 0:
                        if (geo->level == 5) {
@@ -9934,16 +10294,14 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
        } else
                geo->level = info.array.level;
 
-       if ((geo->layout != info.array.layout)
-           && ((geo->layout != UnSet) && (geo->layout != -1))) {
+       if (geo->layout != info.array.layout &&
+           (geo->layout != UnSet && geo->layout != -1)) {
                change = CH_MIGRATION;
-               if ((info.array.layout == 0)
-                   && (info.array.level == 5)
-                   && (geo->layout == 5)) {
+               if (info.array.layout == 0 && info.array.level == 5 &&
+                   geo->layout == 5) {
                        /* reshape 5 -> 4 */
-               } else if ((info.array.layout == 5)
-                          && (info.array.level == 5)
-                          && (geo->layout == 0)) {
+               } else if (info.array.layout == 5 && info.array.level == 5 &&
+                          geo->layout == 0) {
                        /* reshape 4 -> 5 */
                        geo->layout = 0;
                        geo->level = 5;
@@ -9959,11 +10317,17 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                        imsm_layout = info.array.layout;
        }
 
-       if ((geo->chunksize > 0) && (geo->chunksize != UnSet)
-           && (geo->chunksize != info.array.chunk_size))
+       if (geo->chunksize > 0 && geo->chunksize != UnSet &&
+           geo->chunksize != info.array.chunk_size) {
+               if (info.array.level == 10) {
+                       pr_err("Error. Chunk size change for RAID 10 is not supported.\n");
+                       change = -1;
+                       goto analyse_change_exit;
+               }
                change = CH_MIGRATION;
-       else
+       } else {
                geo->chunksize = info.array.chunk_size;
+       }
 
        chunk = geo->chunksize / 1024;
 
@@ -9974,12 +10338,12 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
         */
        current_size = info.custom_array_size / data_disks;
 
-       if ((geo->size > 0) && (geo->size != MAX_SIZE)) {
+       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,
+                                   chunk * 1024, super->sector_size,
                                    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",
@@ -9988,7 +10352,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                }
        }
 
-       if ((current_size != geo->size) && (geo->size > 0)) {
+       if (current_size != geo->size && geo->size > 0) {
                if (change != -1) {
                        pr_err("Error. Size change should be the only one at a time.\n");
                        change = -1;
@@ -10013,7 +10377,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                         */
                        max_size = imsm_component_size_aligment_check(
                                        get_imsm_raid_level(dev->vol.map),
-                                       chunk * 1024,
+                                       chunk * 1024, super->sector_size,
                                        max_size);
                }
                if (geo->size == MAX_SIZE) {
@@ -10027,7 +10391,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                                geo->size = max_size;
                }
 
-               if ((direction == ROLLBACK_METADATA_CHANGES)) {
+               if (direction == ROLLBACK_METADATA_CHANGES) {
                        /* accept size for rollback only
                        */
                } else {
@@ -10073,8 +10437,8 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
        }
 
 analyse_change_exit:
-       if ((direction == ROLLBACK_METADATA_CHANGES) &&
-            ((change == CH_MIGRATION) || (change == CH_TAKEOVER))) {
+       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;
        }
@@ -10249,6 +10613,33 @@ exit_imsm_reshape_super:
        return ret_val;
 }
 
+#define COMPLETED_OK           0
+#define COMPLETED_NONE         1
+#define COMPLETED_DELAYED      2
+
+static int read_completed(int fd, unsigned long long *val)
+{
+       int ret;
+       char buf[50];
+
+       ret = sysfs_fd_get_str(fd, buf, 50);
+       if (ret < 0)
+               return ret;
+
+       ret = COMPLETED_OK;
+       if (strncmp(buf, "none", 4) == 0) {
+               ret = COMPLETED_NONE;
+       } else if (strncmp(buf, "delayed", 7) == 0) {
+               ret = COMPLETED_DELAYED;
+       } else {
+               char *ep;
+               *val = strtoull(buf, &ep, 0);
+               if (ep == buf || (*ep != 0 && *ep != '\n' && *ep != ' '))
+                       ret = -1;
+       }
+       return ret;
+}
+
 /*******************************************************************************
  * Function:   wait_for_reshape_imsm
  * Description:        Function writes new sync_max value and waits until
@@ -10264,6 +10655,7 @@ exit_imsm_reshape_super:
 int wait_for_reshape_imsm(struct mdinfo *sra, int ndata)
 {
        int fd = sysfs_get_fd(sra, NULL, "sync_completed");
+       int retry = 3;
        unsigned long long completed;
        /* to_complete : new sync_max position */
        unsigned long long to_complete = sra->reshape_progress;
@@ -10274,11 +10666,17 @@ int wait_for_reshape_imsm(struct mdinfo *sra, int ndata)
                return 1;
        }
 
-       if (sysfs_fd_get_ll(fd, &completed) < 0) {
-               dprintf("cannot read reshape_position (no reshape in progres)\n");
-               close(fd);
-               return 0;
-       }
+       do {
+               if (sysfs_fd_get_ll(fd, &completed) < 0) {
+                       if (!retry) {
+                               dprintf("cannot read reshape_position (no reshape in progres)\n");
+                               close(fd);
+                               return 1;
+                       }
+                       usleep(30000);
+               } else
+                       break;
+       } while (retry--);
 
        if (completed > position_to_set) {
                dprintf("wrong next position to set %llu (%llu)\n",
@@ -10296,21 +10694,31 @@ int wait_for_reshape_imsm(struct mdinfo *sra, int ndata)
        }
 
        do {
+               int rc;
                char action[20];
-               sysfs_wait(fd, NULL);
+               int timeout = 3000;
+
+               sysfs_wait(fd, &timeout);
                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) {
+                               strncmp(action, "reshape", 7) != 0) {
+                       if (strncmp(action, "idle", 4) == 0)
+                               break;
+                       close(fd);
+                       return -1;
+               }
+
+               rc = read_completed(fd, &completed);
+               if (rc < 0) {
                        dprintf("cannot read reshape_position (in loop)\n");
                        close(fd);
                        return 1;
-               }
+               } else if (rc == COMPLETED_NONE)
+                       break;
        } while (completed < position_to_set);
+
        close(fd);
        return 0;
-
 }
 
 /*******************************************************************************
@@ -10331,7 +10739,7 @@ int check_degradation_change(struct mdinfo *info,
        int rv;
 
        rv = sysfs_get_ll(info, NULL, "degraded", &new_degraded);
-       if ((rv == -1) || (new_degraded != (unsigned long long)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;
@@ -10339,9 +10747,10 @@ int check_degradation_change(struct mdinfo *info,
                        if (sd->disk.state & (1<<MD_DISK_FAULTY))
                                continue;
                        if (sd->disk.state & (1<<MD_DISK_SYNC)) {
-                               char sbuf[20];
+                               char sbuf[100];
+
                                if (sysfs_get_str(info,
-                                       sd, "state", sbuf, 20) < 0 ||
+                                       sd, "state", sbuf, sizeof(sbuf)) < 0 ||
                                        strstr(sbuf, "faulty") ||
                                        strstr(sbuf, "in_sync") == NULL) {
                                        /* this device is dead */
@@ -10366,7 +10775,7 @@ int check_degradation_change(struct mdinfo *info,
  * Function:   imsm_manage_reshape
  * Description:        Function finds array under reshape and it manages reshape
  *             process. It creates stripes backups (if required) and sets
- *             checheckpoits.
+ *             checkpoints.
  * Parameters:
  *     afd             : Backup handle (nattive) - not used
  *     sra             : general array info
@@ -10390,7 +10799,8 @@ static int imsm_manage_reshape(
 {
        int ret_val = 0;
        struct intel_super *super = st->sb;
-       struct intel_dev *dv = NULL;
+       struct intel_dev *dv;
+       unsigned int sector_size = super->sector_size;
        struct imsm_dev *dev = NULL;
        struct imsm_map *map_src;
        int migr_vol_qan = 0;
@@ -10408,7 +10818,10 @@ static int imsm_manage_reshape(
        int degraded = 0;
        int source_layout = 0;
 
-       if (!fds || !offsets || !sra)
+       if (!sra)
+               return ret_val;
+
+       if (!fds || !offsets)
                goto abort;
 
        /* Find volume during the reshape */
@@ -10421,7 +10834,7 @@ static int imsm_manage_reshape(
        }
        /* Only one volume can migrate at the same time */
        if (migr_vol_qan != 1) {
-               pr_err("%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;
@@ -10465,8 +10878,8 @@ static int imsm_manage_reshape(
        buf_size += __le32_to_cpu(migr_rec->dest_depth_per_unit) * 512;
        /* add space for stripe aligment */
        buf_size += old_data_stripe_length;
-       if (posix_memalign((void **)&buf, 4096, buf_size)) {
-               dprintf("imsm: Cannot allocate checpoint buffer\n");
+       if (posix_memalign((void **)&buf, MAX_SECTOR_SIZE, buf_size)) {
+               dprintf("imsm: Cannot allocate checkpoint buffer\n");
                goto abort;
        }
 
@@ -10496,7 +10909,7 @@ static int imsm_manage_reshape(
 
                start = current_position * 512;
 
-               /* allign reading start to old geometry */
+               /* align reading start to old geometry */
                start_buf_shift = start % old_data_stripe_length;
                start_src = start - start_buf_shift;
 
@@ -10510,7 +10923,7 @@ static int imsm_manage_reshape(
                         *             to backup alligned to source array
                         *             [bytes]
                         */
-                       unsigned long long next_step_filler = 0;
+                       unsigned long long next_step_filler;
                        unsigned long long copy_length = next_step * 512;
 
                        /* allign copy area length to stripe in old geometry */
@@ -10563,7 +10976,7 @@ static int imsm_manage_reshape(
                sra->reshape_progress = next_step;
 
                /* wait until reshape finish */
-               if (wait_for_reshape_imsm(sra, ndata) < 0) {
+               if (wait_for_reshape_imsm(sra, ndata)) {
                        dprintf("wait_for_reshape_imsm returned error!\n");
                        goto abort;
                }
@@ -10582,17 +10995,18 @@ 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);
+       memset(super->migr_rec_buf, 0, MIGR_REC_BUF_SECTORS*sector_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,
+               if (lseek64(d->fd, dsize - MIGR_REC_SECTOR_POSITION*sector_size,
                            SEEK_SET) >= 0) {
                        if (write(d->fd, super->migr_rec_buf,
-                               MIGR_REC_BUF_SIZE) != MIGR_REC_BUF_SIZE)
+                           MIGR_REC_BUF_SECTORS*sector_size) !=
+                           MIGR_REC_BUF_SECTORS*sector_size)
                                perror("Write migr_rec failed");
                }
        }
@@ -10601,7 +11015,10 @@ static int imsm_manage_reshape(
        ret_val = 1;
 abort:
        free(buf);
-       abort_reshape(sra);
+       /* See Grow.c: abort_reshape() for further explanation */
+       sysfs_set_num(sra, NULL, "suspend_lo", 0x7FFFFFFFFFFFFFFFULL);
+       sysfs_set_num(sra, NULL, "suspend_hi", 0);
+       sysfs_set_num(sra, NULL, "suspend_lo", 0);
 
        return ret_val;
 }