]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
Retire mdassemble
[thirdparty/mdadm.git] / super-intel.c
index 3d21f312b86d9f5f0b51b2804ba7134ccaeb4752..0aed57c8e2c5b431d5b7fb873e2da4ecb6f6bc97 100644 (file)
@@ -81,7 +81,8 @@
                                        MPB_ATTRIB_RAID1           | \
                                        MPB_ATTRIB_RAID10          | \
                                        MPB_ATTRIB_RAID5           | \
-                                       MPB_ATTRIB_EXP_STRIPE_SIZE)
+                                       MPB_ATTRIB_EXP_STRIPE_SIZE | \
+                                       MPB_ATTRIB_BBM)
 
 /* Define attributes that are unused but not harmful */
 #define MPB_ATTRIB_IGNORED             (MPB_ATTRIB_NEVER_USE)
@@ -101,6 +102,7 @@ struct imsm_disk {
 #define SPARE_DISK      __cpu_to_le32(0x01)  /* Spare */
 #define CONFIGURED_DISK __cpu_to_le32(0x02)  /* Member of some RaidDev */
 #define FAILED_DISK     __cpu_to_le32(0x04)  /* Permanent failure */
+#define JOURNAL_DISK    __cpu_to_le32(0x2000000) /* Device marked as Journaling Drive */
        __u32 status;                    /* 0xF0 - 0xF3 */
        __u32 owner_cfg_num; /* which config 0,1,2... owns this disk */
        __u32 total_blocks_hi;           /* 0xF4 - 0xF5 total blocks hi */
@@ -154,6 +156,9 @@ struct imsm_vol {
 #define MIGR_STATE_CHANGE 4
 #define MIGR_REPAIR 5
        __u8  migr_type;        /* Initializing, Rebuilding, ... */
+#define RAIDVOL_CLEAN          0
+#define RAIDVOL_DIRTY          1
+#define RAIDVOL_DSRECORD_VALID 2
        __u8  dirty;
        __u8  fs_state;         /* fast-sync state for CnG (0xff == disabled) */
        __u16 verify_errors;    /* number of mismatches */
@@ -189,7 +194,24 @@ struct imsm_dev {
        __u16 cache_policy;
        __u8  cng_state;
        __u8  cng_sub_state;
-#define IMSM_DEV_FILLERS 10
+       __u16 my_vol_raid_dev_num; /* Used in Unique volume Id for this RaidDev */
+
+       /* NVM_EN */
+       __u8 nv_cache_mode;
+       __u8 nv_cache_flags;
+
+       /* Unique Volume Id of the NvCache Volume associated with this volume */
+       __u32 nvc_vol_orig_family_num;
+       __u16 nvc_vol_raid_dev_num;
+
+#define RWH_OFF 0
+#define RWH_DISTRIBUTED 1
+#define RWH_JOURNALING_DRIVE 2
+       __u8  rwh_policy; /* Raid Write Hole Policy */
+       __u8  jd_serial[MAX_RAID_SERIAL_LEN]; /* Journal Drive serial number */
+       __u8  filler1;
+
+#define IMSM_DEV_FILLERS 3
        __u32 filler[IMSM_DEV_FILLERS];
        struct imsm_vol vol;
 } __attribute__ ((packed));
@@ -218,27 +240,29 @@ struct imsm_super {
 } __attribute__ ((packed));
 
 #define BBM_LOG_MAX_ENTRIES 254
+#define BBM_LOG_MAX_LBA_ENTRY_VAL 256          /* Represents 256 LBAs */
+#define BBM_LOG_SIGNATURE 0xabadb10c
+
+struct bbm_log_block_addr {
+       __u16 w1;
+       __u32 dw1;
+} __attribute__ ((__packed__));
 
 struct bbm_log_entry {
-       __u64 defective_block_start;
-#define UNREADABLE 0xFFFFFFFF
-       __u32 spare_block_offset;
-       __u16 remapped_marked_count;
-       __u16 disk_ordinal;
+       __u8 marked_count;              /* Number of blocks marked - 1 */
+       __u8 disk_ordinal;              /* Disk entry within the imsm_super */
+       struct bbm_log_block_addr defective_block_start;
 } __attribute__ ((__packed__));
 
 struct bbm_log {
        __u32 signature; /* 0xABADB10C */
        __u32 entry_count;
-       __u32 reserved_spare_block_count; /* 0 */
-       __u32 reserved; /* 0xFFFF */
-       __u64 first_spare_lba;
-       struct bbm_log_entry mapped_block_entries[BBM_LOG_MAX_ENTRIES];
+       struct bbm_log_entry marked_block_entries[BBM_LOG_MAX_ENTRIES];
 } __attribute__ ((__packed__));
 
-#ifndef MDASSEMBLE
 static char *map_state_str[] = { "normal", "uninitialized", "degraded", "failed" };
-#endif
+
+#define BLOCKS_PER_KB  (1024/512)
 
 #define RAID_DISK_RESERVED_BLOCKS_IMSM_HI 2209
 
@@ -254,6 +278,9 @@ static char *map_state_str[] = { "normal", "uninitialized", "degraded", "failed"
 #define UNIT_SRC_IN_CP_AREA 1   /* Source data for curr_migr_unit has
                                 *  already been migrated and must
                                 *  be recovered from checkpoint area */
+
+#define PPL_ENTRY_SPACE (128 * 1024) /* Size of the PPL, without the header */
+
 struct migr_record {
        __u32 rec_status;           /* Status used to determine how to restart
                                     * migration in case it aborts
@@ -361,6 +388,7 @@ struct intel_super {
                array, it indicates that mdmon is allowed to clean migration
                record */
        size_t len; /* size of the 'buf' allocation */
+       size_t extra_space; /* extra space in 'buf' that is not used yet */
        void *next_buf; /* for realloc'ing buf from the manager */
        size_t next_len;
        int updates_pending; /* count of pending updates for mdmon */
@@ -389,6 +417,7 @@ struct intel_super {
        struct intel_hba *hba; /* device path of the raid controller for this metadata */
        const struct imsm_orom *orom; /* platform firmware support */
        struct intel_super *next; /* (temp) list for disambiguating family_num */
+       struct md_bb bb;        /* memory for get_bad_blocks call */
 };
 
 struct intel_disk {
@@ -421,6 +450,8 @@ enum imsm_update_type {
        update_takeover,
        update_general_migration_checkpoint,
        update_size_change,
+       update_prealloc_badblocks_mem,
+       update_rwh_policy,
 };
 
 struct imsm_update_activate_spare {
@@ -509,6 +540,16 @@ struct imsm_update_add_remove_disk {
        enum imsm_update_type type;
 };
 
+struct imsm_update_prealloc_bb_mem {
+       enum imsm_update_type type;
+};
+
+struct imsm_update_rwh_policy {
+       enum imsm_update_type type;
+       int new_policy;
+       int dev_idx;
+};
+
 static const char *_sys_dev_type[] = {
        [SYS_DEV_UNKNOWN] = "Unknown",
        [SYS_DEV_SAS] = "SAS",
@@ -629,12 +670,10 @@ static struct supertype *match_metadata_desc_imsm(char *arg)
        return st;
 }
 
-#ifndef MDASSEMBLE
 static __u8 *get_imsm_version(struct imsm_super *mpb)
 {
        return &mpb->sig[MPB_SIG_LEN];
 }
-#endif
 
 /* retrieve a disk directly from the anchor when the anchor is known to be
  * up-to-date, currently only at load time
@@ -741,7 +780,6 @@ static size_t sizeof_imsm_dev(struct imsm_dev *dev, int migr_state)
        return size;
 }
 
-#ifndef MDASSEMBLE
 /* retrieve disk serial number list from a metadata update */
 static struct disk_info *get_disk_info(struct imsm_update_create_array *update)
 {
@@ -753,7 +791,6 @@ static struct disk_info *get_disk_info(struct imsm_update_create_array *update)
 
        return inf;
 }
-#endif
 
 static struct imsm_dev *__get_imsm_dev(struct imsm_super *mpb, __u8 index)
 {
@@ -788,6 +825,242 @@ static struct imsm_dev *get_imsm_dev(struct intel_super *super, __u8 index)
        return NULL;
 }
 
+static inline unsigned long long __le48_to_cpu(const struct bbm_log_block_addr
+                                              *addr)
+{
+       return ((((__u64)__le32_to_cpu(addr->dw1)) << 16) |
+               __le16_to_cpu(addr->w1));
+}
+
+static inline struct bbm_log_block_addr __cpu_to_le48(unsigned long long sec)
+{
+       struct bbm_log_block_addr addr;
+
+       addr.w1 =  __cpu_to_le16((__u16)(sec & 0xffff));
+       addr.dw1 = __cpu_to_le32((__u32)(sec >> 16) & 0xffffffff);
+       return addr;
+}
+
+/* get size of the bbm log */
+static __u32 get_imsm_bbm_log_size(struct bbm_log *log)
+{
+       if (!log || log->entry_count == 0)
+               return 0;
+
+       return sizeof(log->signature) +
+               sizeof(log->entry_count) +
+               log->entry_count * sizeof(struct bbm_log_entry);
+}
+
+/* check if bad block is not partially stored in bbm log */
+static int is_stored_in_bbm(struct bbm_log *log, const __u8 idx, const unsigned
+                           long long sector, const int length, __u32 *pos)
+{
+       __u32 i;
+
+       for (i = *pos; i < log->entry_count; i++) {
+               struct bbm_log_entry *entry = &log->marked_block_entries[i];
+               unsigned long long bb_start;
+               unsigned long long bb_end;
+
+               bb_start = __le48_to_cpu(&entry->defective_block_start);
+               bb_end = bb_start + (entry->marked_count + 1);
+
+               if ((entry->disk_ordinal == idx) && (bb_start >= sector) &&
+                   (bb_end <= sector + length)) {
+                       *pos = i;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/* record new bad block in bbm log */
+static int record_new_badblock(struct bbm_log *log, const __u8 idx, unsigned
+                              long long sector, int length)
+{
+       int new_bb = 0;
+       __u32 pos = 0;
+       struct bbm_log_entry *entry = NULL;
+
+       while (is_stored_in_bbm(log, idx, sector, length, &pos)) {
+               struct bbm_log_entry *e = &log->marked_block_entries[pos];
+
+               if ((e->marked_count + 1 == BBM_LOG_MAX_LBA_ENTRY_VAL) &&
+                   (__le48_to_cpu(&e->defective_block_start) == sector)) {
+                       sector += BBM_LOG_MAX_LBA_ENTRY_VAL;
+                       length -= BBM_LOG_MAX_LBA_ENTRY_VAL;
+                       pos = pos + 1;
+                       continue;
+               }
+               entry = e;
+               break;
+       }
+
+       if (entry) {
+               int cnt = (length <= BBM_LOG_MAX_LBA_ENTRY_VAL) ? length :
+                       BBM_LOG_MAX_LBA_ENTRY_VAL;
+               entry->defective_block_start = __cpu_to_le48(sector);
+               entry->marked_count = cnt - 1;
+               if (cnt == length)
+                       return 1;
+               sector += cnt;
+               length -= cnt;
+       }
+
+       new_bb = ROUND_UP(length, BBM_LOG_MAX_LBA_ENTRY_VAL) /
+               BBM_LOG_MAX_LBA_ENTRY_VAL;
+       if (log->entry_count + new_bb > BBM_LOG_MAX_ENTRIES)
+               return 0;
+
+       while (length > 0) {
+               int cnt = (length <= BBM_LOG_MAX_LBA_ENTRY_VAL) ? length :
+                       BBM_LOG_MAX_LBA_ENTRY_VAL;
+               struct bbm_log_entry *entry =
+                       &log->marked_block_entries[log->entry_count];
+
+               entry->defective_block_start = __cpu_to_le48(sector);
+               entry->marked_count = cnt - 1;
+               entry->disk_ordinal = idx;
+
+               sector += cnt;
+               length -= cnt;
+
+               log->entry_count++;
+       }
+
+       return new_bb;
+}
+
+/* clear all bad blocks for given disk */
+static void clear_disk_badblocks(struct bbm_log *log, const __u8 idx)
+{
+       __u32 i = 0;
+
+       while (i < log->entry_count) {
+               struct bbm_log_entry *entries = log->marked_block_entries;
+
+               if (entries[i].disk_ordinal == idx) {
+                       if (i < log->entry_count - 1)
+                               entries[i] = entries[log->entry_count - 1];
+                       log->entry_count--;
+               } else {
+                       i++;
+               }
+       }
+}
+
+/* clear given bad block */
+static int clear_badblock(struct bbm_log *log, const __u8 idx, const unsigned
+                         long long sector, const int length) {
+       __u32 i = 0;
+
+       while (i < log->entry_count) {
+               struct bbm_log_entry *entries = log->marked_block_entries;
+
+               if ((entries[i].disk_ordinal == idx) &&
+                   (__le48_to_cpu(&entries[i].defective_block_start) ==
+                    sector) && (entries[i].marked_count + 1 == length)) {
+                       if (i < log->entry_count - 1)
+                               entries[i] = entries[log->entry_count - 1];
+                       log->entry_count--;
+                       break;
+               }
+               i++;
+       }
+
+       return 1;
+}
+
+/* allocate and load BBM log from metadata */
+static int load_bbm_log(struct intel_super *super)
+{
+       struct imsm_super *mpb = super->anchor;
+       __u32 bbm_log_size =  __le32_to_cpu(mpb->bbm_log_size);
+
+       super->bbm_log = xcalloc(1, sizeof(struct bbm_log));
+       if (!super->bbm_log)
+               return 1;
+
+       if (bbm_log_size) {
+               struct bbm_log *log = (void *)mpb +
+                       __le32_to_cpu(mpb->mpb_size) - bbm_log_size;
+
+               __u32 entry_count;
+
+               if (bbm_log_size < sizeof(log->signature) +
+                   sizeof(log->entry_count))
+                       return 2;
+
+               entry_count = __le32_to_cpu(log->entry_count);
+               if ((__le32_to_cpu(log->signature) != BBM_LOG_SIGNATURE) ||
+                   (entry_count > BBM_LOG_MAX_ENTRIES))
+                       return 3;
+
+               if (bbm_log_size !=
+                   sizeof(log->signature) + sizeof(log->entry_count) +
+                   entry_count * sizeof(struct bbm_log_entry))
+                       return 4;
+
+               memcpy(super->bbm_log, log, bbm_log_size);
+       } else {
+               super->bbm_log->signature = __cpu_to_le32(BBM_LOG_SIGNATURE);
+               super->bbm_log->entry_count = 0;
+       }
+
+       return 0;
+}
+
+/* checks if bad block is within volume boundaries */
+static int is_bad_block_in_volume(const struct bbm_log_entry *entry,
+                       const unsigned long long start_sector,
+                       const unsigned long long size)
+{
+       unsigned long long bb_start;
+       unsigned long long bb_end;
+
+       bb_start = __le48_to_cpu(&entry->defective_block_start);
+       bb_end = bb_start + (entry->marked_count + 1);
+
+       if (((bb_start >= start_sector) && (bb_start < start_sector + size)) ||
+           ((bb_end >= start_sector) && (bb_end <= start_sector + size)))
+               return 1;
+
+       return 0;
+}
+
+/* get list of bad blocks on a drive for a volume */
+static void get_volume_badblocks(const struct bbm_log *log, const __u8 idx,
+                       const unsigned long long start_sector,
+                       const unsigned long long size,
+                       struct md_bb *bbs)
+{
+       __u32 count = 0;
+       __u32 i;
+
+       for (i = 0; i < log->entry_count; i++) {
+               const struct bbm_log_entry *ent =
+                       &log->marked_block_entries[i];
+               struct md_bb_entry *bb;
+
+               if ((ent->disk_ordinal == idx) &&
+                   is_bad_block_in_volume(ent, start_sector, size)) {
+
+                       if (!bbs->entries) {
+                               bbs->entries = xmalloc(BBM_LOG_MAX_ENTRIES *
+                                                    sizeof(*bb));
+                               if (!bbs->entries)
+                                       break;
+                       }
+
+                       bb = &bbs->entries[count++];
+                       bb->sector = __le48_to_cpu(&ent->defective_block_start);
+                       bb->length = ent->marked_count + 1;
+               }
+       }
+       bbs->count = count;
+}
+
 /*
  * for second_map:
  *  == MAP_0 get first map
@@ -1040,6 +1313,24 @@ static int is_failed(struct imsm_disk *disk)
        return (disk->status & FAILED_DISK) == FAILED_DISK;
 }
 
+static int is_journal(struct imsm_disk *disk)
+{
+       return (disk->status & JOURNAL_DISK) == JOURNAL_DISK;
+}
+
+/* round array size down to closest MB and ensure it splits evenly
+ * between members
+ */
+static unsigned long long round_size_to_mb(unsigned long long size, unsigned int
+                                          disk_count)
+{
+       size /= disk_count;
+       size = (size >> SECT_PER_MB_SHIFT) << SECT_PER_MB_SHIFT;
+       size *= disk_count;
+
+       return size;
+}
+
 /* try to determine how much space is reserved for metadata from
  * the last get_extents() entry on the smallest active disk,
  * otherwise fallback to the default
@@ -1124,7 +1415,6 @@ 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);
 
@@ -1229,11 +1519,23 @@ static void print_imsm_dev(struct intel_super *super,
                                   blocks_per_migr_unit(super, dev));
        }
        printf("\n");
-       printf("    Dirty State : %s\n", dev->vol.dirty ? "dirty" : "clean");
+       printf("    Dirty State : %s\n", (dev->vol.dirty & RAIDVOL_DIRTY) ?
+                                        "dirty" : "clean");
+       printf("     RWH Policy : ");
+       if (dev->rwh_policy == RWH_OFF)
+               printf("off\n");
+       else if (dev->rwh_policy == RWH_DISTRIBUTED)
+               printf("PPL distributed\n");
+       else if (dev->rwh_policy == RWH_JOURNALING_DRIVE)
+               printf("PPL journaling drive\n");
+       else
+               printf("<unknown:%d>\n", dev->rwh_policy);
 }
 
-static void print_imsm_disk(struct imsm_disk *disk, int index, __u32 reserved)
-{
+static void print_imsm_disk(struct imsm_disk *disk,
+                           int index,
+                           __u32 reserved,
+                           unsigned int sector_size) {
        char str[MAX_RAID_SERIAL_LEN + 1];
        __u64 sz;
 
@@ -1246,12 +1548,14 @@ static void print_imsm_disk(struct imsm_disk *disk, int index, __u32 reserved)
                printf("  Disk%02d Serial : %s\n", index, str);
        else
                printf("    Disk Serial : %s\n", str);
-       printf("          State :%s%s%s\n", is_spare(disk) ? " spare" : "",
-                                           is_configured(disk) ? " active" : "",
-                                           is_failed(disk) ? " failed" : "");
+       printf("          State :%s%s%s%s\n", is_spare(disk) ? " spare" : "",
+                                             is_configured(disk) ? " active" : "",
+                                             is_failed(disk) ? " failed" : "",
+                                             is_journal(disk) ? " journal" : "");
        printf("             Id : %08x\n", __le32_to_cpu(disk->scsi_id));
        sz = total_blocks(disk) - reserved;
-       printf("    Usable Size : %llu%s\n", (unsigned long long)sz,
+       printf("    Usable Size : %llu%s\n",
+              (unsigned long long)sz * 512 / sector_size,
               human_size(sz * 512));
 }
 
@@ -1278,6 +1582,7 @@ void convert_to_4k(struct intel_super *super)
        struct imsm_super *mpb = super->anchor;
        struct imsm_disk *disk;
        int i;
+       __u32 bbm_log_size = __le32_to_cpu(mpb->bbm_log_size);
 
        for (i = 0; i < mpb->num_disks ; i++) {
                disk = __get_imsm_disk(mpb, i);
@@ -1306,6 +1611,24 @@ void convert_to_4k(struct intel_super *super)
                        set_pba_of_lba0(map, pba_of_lba0(map)/IMSM_4K_DIV);
                }
        }
+       if (bbm_log_size) {
+               struct bbm_log *log = (void *)mpb +
+                       __le32_to_cpu(mpb->mpb_size) - bbm_log_size;
+               __u32 i;
+
+               for (i = 0; i < log->entry_count; i++) {
+                       struct bbm_log_entry *entry =
+                               &log->marked_block_entries[i];
+
+                       __u8 count = entry->marked_count + 1;
+                       unsigned long long sector =
+                               __le48_to_cpu(&entry->defective_block_start);
+
+                       entry->defective_block_start =
+                               __cpu_to_le48(sector/IMSM_4K_DIV);
+                       entry->marked_count = max(count/IMSM_4K_DIV, 1) - 1;
+               }
+       }
 
        mpb->check_sum = __gen_imsm_checksum(mpb);
 }
@@ -1366,7 +1689,6 @@ void examine_migr_rec_imsm(struct intel_super *super)
                break;
        }
 }
-#endif /* MDASSEMBLE */
 
 void convert_from_4k_imsm_migr_rec(struct intel_super *super)
 {
@@ -1387,6 +1709,7 @@ void convert_from_4k(struct intel_super *super)
        struct imsm_super *mpb = super->anchor;
        struct imsm_disk *disk;
        int i;
+       __u32 bbm_log_size = __le32_to_cpu(mpb->bbm_log_size);
 
        for (i = 0; i < mpb->num_disks ; i++) {
                disk = __get_imsm_disk(mpb, i);
@@ -1416,6 +1739,24 @@ void convert_from_4k(struct intel_super *super)
                        set_pba_of_lba0(map, pba_of_lba0(map)*IMSM_4K_DIV);
                }
        }
+       if (bbm_log_size) {
+               struct bbm_log *log = (void *)mpb +
+                       __le32_to_cpu(mpb->mpb_size) - bbm_log_size;
+               __u32 i;
+
+               for (i = 0; i < log->entry_count; i++) {
+                       struct bbm_log_entry *entry =
+                               &log->marked_block_entries[i];
+
+                       __u8 count = entry->marked_count + 1;
+                       unsigned long long sector =
+                               __le48_to_cpu(&entry->defective_block_start);
+
+                       entry->defective_block_start =
+                               __cpu_to_le48(sector*IMSM_4K_DIV);
+                       entry->marked_count = count*IMSM_4K_DIV - 1;
+               }
+       }
 
        mpb->check_sum = __gen_imsm_checksum(mpb);
 }
@@ -1507,7 +1848,6 @@ static int imsm_check_attributes(__u32 attributes)
        return ret_val;
 }
 
-#ifndef MDASSEMBLE
 static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *map);
 
 static void examine_super_imsm(struct supertype *st, char *homehost)
@@ -1522,7 +1862,8 @@ static void examine_super_imsm(struct supertype *st, char *homehost)
        __u32 reserved = imsm_reserved_sectors(super, super->disks);
        struct dl *dl;
 
-       snprintf(str, MPB_SIG_LEN, "%s", mpb->sig);
+       strncpy(str, (char *)mpb->sig, MPB_SIG_LEN);
+       str[MPB_SIG_LEN-1] = '\0';
        printf("          Magic : %s\n", str);
        snprintf(str, strlen(MPB_VERSION_RAID0), "%s", get_imsm_version(mpb));
        printf("        Version : %s\n", get_imsm_version(mpb));
@@ -1543,8 +1884,9 @@ static void examine_super_imsm(struct supertype *st, char *homehost)
        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);
-       if (super->bbm_log) {
+       print_imsm_disk(__get_imsm_disk(mpb, super->disks->index),
+                       super->disks->index, reserved, super->sector_size);
+       if (get_imsm_bbm_log_size(super->bbm_log)) {
                struct bbm_log *log = super->bbm_log;
 
                printf("\n");
@@ -1552,9 +1894,6 @@ static void examine_super_imsm(struct supertype *st, char *homehost)
                printf("       Log Size : %d\n", __le32_to_cpu(mpb->bbm_log_size));
                printf("      Signature : %x\n", __le32_to_cpu(log->signature));
                printf("    Entry Count : %d\n", __le32_to_cpu(log->entry_count));
-               printf("   Spare Blocks : %d\n",  __le32_to_cpu(log->reserved_spare_block_count));
-               printf("    First Spare : %llx\n",
-                      (unsigned long long) __le64_to_cpu(log->first_spare_lba));
        }
        for (i = 0; i < mpb->num_raid_devs; i++) {
                struct mdinfo info;
@@ -1568,12 +1907,14 @@ static void examine_super_imsm(struct supertype *st, char *homehost)
        for (i = 0; i < mpb->num_disks; i++) {
                if (i == super->disks->index)
                        continue;
-               print_imsm_disk(__get_imsm_disk(mpb, i), i, reserved);
+               print_imsm_disk(__get_imsm_disk(mpb, i), i, reserved,
+                               super->sector_size);
        }
 
        for (dl = super->disks; dl; dl = dl->next)
                if (dl->index == -1)
-                       print_imsm_disk(&dl->disk, -1, reserved);
+                       print_imsm_disk(&dl->disk, -1, reserved,
+                                       super->sector_size);
 
        examine_migr_rec_imsm(super);
 }
@@ -1662,7 +2003,7 @@ static int copy_metadata_imsm(struct supertype *st, int from, int to)
 
        if (lseek64(from, dsize-(2*sector_size), 0) < 0)
                goto err;
-       if (read(from, buf, sector_size) != sector_size)
+       if ((unsigned int)read(from, buf, sector_size) != sector_size)
                goto err;
        sb = buf;
        if (strncmp((char*)sb->sig, MPB_SIGNATURE, MPB_SIG_LEN) != 0)
@@ -1697,7 +2038,7 @@ static void detail_super_imsm(struct supertype *st, char *homehost)
 
        getinfo_super_imsm(st, &info, NULL);
        fname_from_uuid(st, &info, nbuf, ':');
-       printf("\n           UUID : %s\n", nbuf + 5);
+       printf("\n              UUID : %s\n", nbuf + 5);
 }
 
 static void brief_detail_super_imsm(struct supertype *st)
@@ -1916,9 +2257,6 @@ static int print_vmd_attached_devs(struct sys_dev *hba)
                        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)
@@ -2133,6 +2471,8 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle
        for (entry = orom_entries; entry; entry = entry->next) {
                if (entry->type == SYS_DEV_VMD) {
                        print_imsm_capability(&entry->orom);
+                       printf(" 3rd party NVMe :%s supported\n",
+                           imsm_orom_has_tpv_support(&entry->orom)?"":" not");
                        for (hba = list; hba; hba = hba->next) {
                                if (hba->type == SYS_DEV_VMD) {
                                        char buf[PATH_MAX];
@@ -2221,8 +2561,6 @@ static int export_detail_platform_imsm(int verbose, char *controller_path)
        return result;
 }
 
-#endif
-
 static int match_home_imsm(struct supertype *st, char *homehost)
 {
        /* the imsm metadata format does not specify any host
@@ -2534,7 +2872,7 @@ static int read_imsm_migr_rec(int fd, struct intel_super *super)
                       strerror(errno));
                goto out;
        }
-       if (read(fd, super->migr_rec_buf,
+       if ((unsigned int)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",
@@ -2633,7 +2971,6 @@ out:
        return retval;
 }
 
-#ifndef MDASSEMBLE
 /*******************************************************************************
  * function: imsm_create_metadata_checkpoint_update
  * Description: It creates update for checkpoint change.
@@ -2736,7 +3073,7 @@ static int write_imsm_migr_rec(struct supertype *st)
                               strerror(errno));
                        goto out;
                }
-               if (write(fd, super->migr_rec_buf,
+               if ((unsigned int)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",
@@ -2774,7 +3111,6 @@ static int write_imsm_migr_rec(struct supertype *st)
                close(fd);
        return retval;
 }
-#endif /* MDASSEMBLE */
 
 /* spare/missing disks activations are not allowe when
  * array/container performs reshape operation, because
@@ -2825,6 +3161,15 @@ static unsigned long long imsm_component_size_aligment_check(int level,
        return component_size;
 }
 
+static unsigned long long get_ppl_sector(struct intel_super *super, int dev_idx)
+{
+       struct imsm_dev *dev = get_imsm_dev(super, dev_idx);
+       struct imsm_map *map = get_imsm_map(dev, MAP_0);
+
+       return pba_of_lba0(map) +
+              (num_data_stripes(map) * map->blocks_per_strip);
+}
+
 static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, char *dmap)
 {
        struct intel_super *super = st->sb;
@@ -2851,7 +3196,7 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
        info->array.utime         = 0;
        info->array.chunk_size    =
                __le16_to_cpu(map_to_analyse->blocks_per_strip) << 9;
-       info->array.state         = !dev->vol.dirty;
+       info->array.state         = !(dev->vol.dirty & RAIDVOL_DIRTY);
        info->custom_array_size   = __le32_to_cpu(dev->size_high);
        info->custom_array_size   <<= 32;
        info->custom_array_size   |= __le32_to_cpu(dev->size_low);
@@ -2927,14 +3272,25 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
                                                        info->array.chunk_size,
                                                        super->sector_size,
                                                        info->component_size);
+       info->bb.supported = 1;
 
        memset(info->uuid, 0, sizeof(info->uuid));
        info->recovery_start = MaxSector;
 
+       if (info->array.level == 5 && dev->rwh_policy == RWH_DISTRIBUTED) {
+               info->consistency_policy = CONSISTENCY_POLICY_PPL;
+               info->ppl_sector = get_ppl_sector(super, super->current_vol);
+               info->ppl_size = (PPL_HEADER_SIZE + PPL_ENTRY_SPACE) >> 9;
+       } else if (info->array.level <= 0) {
+               info->consistency_policy = CONSISTENCY_POLICY_NONE;
+       } else {
+               info->consistency_policy = CONSISTENCY_POLICY_RESYNC;
+       }
+
        info->reshape_progress = 0;
        info->resync_start = MaxSector;
        if ((map_to_analyse->map_state == IMSM_T_STATE_UNINITIALIZED ||
-           dev->vol.dirty) &&
+           !(info->array.state & 1)) &&
            imsm_reshape_blocks_arrays_changes(super) == 0) {
                info->resync_start = 0;
        }
@@ -2974,11 +3330,10 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
                        if (used_disks > 0) {
                                array_blocks = blocks_per_member(map) *
                                        used_disks;
-                               /* round array size down to closest MB
-                                */
-                               info->custom_array_size = (array_blocks
-                                               >> SECT_PER_MB_SHIFT)
-                                               << SECT_PER_MB_SHIFT;
+                               info->custom_array_size =
+                                       round_size_to_mb(array_blocks,
+                                                        used_disks);
+
                        }
                }
                case MIGR_VERIFY:
@@ -3026,7 +3381,6 @@ static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev,
 static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev,
                             int look_in_map);
 
-#ifndef MDASSEMBLE
 static void manage_second_map(struct intel_super *super, struct imsm_dev *dev)
 {
        if (is_gen_migration(dev)) {
@@ -3042,7 +3396,6 @@ static void manage_second_map(struct intel_super *super, struct imsm_dev *dev)
                }
        }
 }
-#endif
 
 static struct imsm_disk *get_imsm_missing(struct intel_super *super, __u8 index)
 {
@@ -3093,9 +3446,11 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
        info->name[0] = 0;
        info->recovery_start = MaxSector;
        info->recovery_blocked = imsm_reshape_blocks_arrays_changes(st->sb);
+       info->bb.supported = 1;
 
        /* do we have the all the insync disks that we expect? */
        mpb = super->anchor;
+       info->events = __le32_to_cpu(mpb->generation_num);
 
        for (i = 0; i < mpb->num_raid_devs; i++) {
                struct imsm_dev *dev = get_imsm_dev(super, i);
@@ -3159,7 +3514,8 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
                 * found the 'most fresh' version of the metadata
                 */
                info->disk.state |= is_failed(disk) ? (1 << MD_DISK_FAULTY) : 0;
-               info->disk.state |= is_spare(disk) ? 0 : (1 << MD_DISK_SYNC);
+               info->disk.state |= (is_spare(disk) || is_journal(disk)) ?
+                                   0 : (1 << MD_DISK_SYNC);
        }
 
        /* only call uuid_from_super_imsm when this disk is part of a populated container,
@@ -3297,6 +3653,8 @@ static size_t disks_to_mpb_size(int disks)
        size += (4 - 2) * sizeof(struct imsm_map);
        /* 4 possible disk_ord_tbl's */
        size += 4 * (disks - 1) * sizeof(__u32);
+       /* maximum bbm log */
+       size += sizeof(struct bbm_log);
 
        return size;
 }
@@ -3612,14 +3970,13 @@ load_imsm_disk(int fd, struct intel_super *super, char *devname, int keep_fd)
                 */
                if (is_failed(&dl->disk))
                        dl->index = -2;
-               else if (is_spare(&dl->disk))
+               else if (is_spare(&dl->disk) || is_journal(&dl->disk))
                        dl->index = -1;
        }
 
        return 0;
 }
 
-#ifndef MDASSEMBLE
 /* When migrating map0 contains the 'destination' state while map1
  * contains the current state.  When not migrating map0 contains the
  * current state.  This routine assumes that map[0].map_state is set to
@@ -3707,7 +4064,6 @@ static void end_migration(struct imsm_dev *dev, struct intel_super *super,
        dev->vol.curr_migr_unit = 0;
        map->map_state = map_state;
 }
-#endif
 
 static int parse_raid_devices(struct intel_super *super)
 {
@@ -3758,20 +4114,9 @@ static int parse_raid_devices(struct intel_super *super)
                super->len = len;
        }
 
-       return 0;
-}
-
-/* retrieve a pointer to the bbm log which starts after all raid devices */
-struct bbm_log *__get_imsm_bbm_log(struct imsm_super *mpb)
-{
-       void *ptr = NULL;
-
-       if (__le32_to_cpu(mpb->bbm_log_size)) {
-               ptr = mpb;
-               ptr += mpb->mpb_size - __le32_to_cpu(mpb->bbm_log_size);
-       }
+       super->extra_space += space_needed;
 
-       return ptr;
+       return 0;
 }
 
 /*******************************************************************************
@@ -3846,7 +4191,7 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
                        pr_err("Failed to allocate imsm anchor buffer on %s\n", devname);
                return 1;
        }
-       if (read(fd, anchor, sector_size) != sector_size) {
+       if ((unsigned int)read(fd, anchor, sector_size) != sector_size) {
                if (devname)
                        pr_err("Cannot read anchor block on %s: %s\n",
                               devname, strerror(errno));
@@ -3926,12 +4271,6 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
                return 3;
        }
 
-       /* FIXME the BBM log is disk specific so we cannot use this global
-        * buffer for all disks.  Ok for now since we only look at the global
-        * bbm_log_size parameter to gate assembly
-        */
-       super->bbm_log = __get_imsm_bbm_log(super->anchor);
-
        return 0;
 }
 
@@ -3977,6 +4316,9 @@ load_and_parse_mpb(int fd, struct intel_super *super, char *devname, int keep_fd
        if (err)
                return err;
        err = parse_raid_devices(super);
+       if (err)
+               return err;
+       err = load_bbm_log(super);
        clear_hi(super);
        return err;
 }
@@ -4041,12 +4383,15 @@ static void __free_imsm(struct intel_super *super, int free_disks)
                free(elem);
                elem = next;
        }
+       if (super->bbm_log)
+               free(super->bbm_log);
        super->hba = NULL;
 }
 
 static void free_imsm(struct intel_super *super)
 {
        __free_imsm(super, 1);
+       free(super->bb.entries);
        free(super);
 }
 
@@ -4067,6 +4412,14 @@ static struct intel_super *alloc_super(void)
 
        super->current_vol = -1;
        super->create_offset = ~((unsigned long long) 0);
+
+       super->bb.entries = xmalloc(BBM_LOG_MAX_ENTRIES *
+                                  sizeof(struct md_bb_entry));
+       if (!super->bb.entries) {
+               free(super);
+               return NULL;
+       }
+
        return super;
 }
 
@@ -4156,7 +4509,6 @@ static int find_missing(struct intel_super *super)
        return 0;
 }
 
-#ifndef MDASSEMBLE
 static struct intel_disk *disk_list_get(__u8 *serial, struct intel_disk *disk_list)
 {
        struct intel_disk *idisk = disk_list;
@@ -4647,7 +4999,7 @@ static int get_super_block(struct intel_super **super_list, char *devnm, char *d
                *super_list = s;
        } else {
                if (s)
-                       free(s);
+                       free_imsm(s);
                if (dfd >= 0)
                        close(dfd);
        }
@@ -4694,7 +5046,6 @@ static int load_container_imsm(struct supertype *st, int fd, char *devname)
 {
        return load_super_imsm_all(st, fd, &st->sb, devname, NULL, 1);
 }
-#endif
 
 static int load_super_imsm(struct supertype *st, int fd, char *devname)
 {
@@ -4710,6 +5061,8 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
 
        super = alloc_super();
        get_dev_sector_size(fd, NULL, &super->sector_size);
+       if (!super)
+               return 1;
        /* Load hba and capabilities if they exist.
         * But do not preclude loading metadata in case capabilities or hba are
         * non-compliant and ignore_hw_compat is set.
@@ -4862,7 +5215,7 @@ static int check_name(struct intel_super *super, char *name, int quiet)
 }
 
 static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
-                                 unsigned long long size, char *name,
+                                 struct shape *s, char *name,
                                  char *homehost, int *uuid,
                                  long long data_offset)
 {
@@ -4881,6 +5234,8 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        unsigned long long array_blocks;
        size_t size_old, size_new;
        unsigned long long num_data_stripes;
+       unsigned int data_disks;
+       unsigned long long size_per_member;
 
        if (super->orom && mpb->num_raid_devs >= super->orom->vpa) {
                pr_err("This imsm-container already has the maximum of %d volumes\n", super->orom->vpa);
@@ -4912,6 +5267,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                super->anchor = mpb_new;
                mpb->mpb_size = __cpu_to_le32(size_new);
                memset(mpb_new + size_old, 0, size_round - size_old);
+               super->len = size_round;
        }
        super->current_vol = idx;
 
@@ -4934,7 +5290,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                        disk->status = CONFIGURED_DISK | FAILED_DISK;
                        disk->scsi_id = __cpu_to_le32(~(__u32)0);
                        snprintf((char *) disk->serial, MAX_RAID_SERIAL_LEN,
-                                "missing:%d", i);
+                                "missing:%d", (__u8)i);
                }
                find_missing(super);
        } else {
@@ -4956,9 +5312,11 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        strncpy((char *) dev->volume, name, MAX_RAID_SERIAL_LEN);
        array_blocks = calc_array_size(info->level, info->raid_disks,
                                               info->layout, info->chunk_size,
-                                              size * 2);
-       /* round array size down to closest MB */
-       array_blocks = (array_blocks >> SECT_PER_MB_SHIFT) << SECT_PER_MB_SHIFT;
+                                              s->size * BLOCKS_PER_KB);
+       data_disks = get_data_disks(info->level, info->layout,
+                                   info->raid_disks);
+       array_blocks = round_size_to_mb(array_blocks, data_disks);
+       size_per_member = array_blocks / data_disks;
 
        dev->size_low = __cpu_to_le32((__u32) array_blocks);
        dev->size_high = __cpu_to_le32((__u32) (array_blocks >> 32));
@@ -4970,7 +5328,9 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        vol->curr_migr_unit = 0;
        map = get_imsm_map(dev, MAP_0);
        set_pba_of_lba0(map, super->create_offset);
-       set_blocks_per_member(map, info_to_blocks_per_member(info, size));
+       set_blocks_per_member(map, info_to_blocks_per_member(info,
+                                                            size_per_member /
+                                                            BLOCKS_PER_KB));
        map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info));
        map->failed_disk_num = ~0;
        if (info->level > 0)
@@ -4998,7 +5358,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                map->num_domains = 1;
 
        /* info->size is only int so use the 'size' parameter instead */
-       num_data_stripes = (size * 2) / info_to_blocks_per_strip(info);
+       num_data_stripes = size_per_member / info_to_blocks_per_strip(info);
        num_data_stripes /= map->num_domains;
        set_num_data_stripes(map, num_data_stripes);
 
@@ -5009,6 +5369,20 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        }
        mpb->num_raid_devs++;
 
+       if (s->consistency_policy == UnSet ||
+           s->consistency_policy == CONSISTENCY_POLICY_RESYNC ||
+           s->consistency_policy == CONSISTENCY_POLICY_NONE) {
+               dev->rwh_policy = RWH_OFF;
+       } else if (s->consistency_policy == CONSISTENCY_POLICY_PPL) {
+               dev->rwh_policy = RWH_DISTRIBUTED;
+       } else {
+               free(dev);
+               free(dv);
+               pr_err("imsm does not support consistency policy %s\n",
+                      map_num(consistency_policies, s->consistency_policy));
+               return 0;
+       }
+
        dv->dev = dev;
        dv->index = super->current_vol;
        dv->next = super->devlist;
@@ -5020,7 +5394,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
 }
 
 static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
-                          unsigned long long size, char *name,
+                          struct shape *s, char *name,
                           char *homehost, int *uuid,
                           unsigned long long data_offset)
 {
@@ -5043,7 +5417,7 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
        }
 
        if (st->sb)
-               return init_super_imsm_volume(st, info, size, name, homehost, uuid,
+               return init_super_imsm_volume(st, info, s, name, homehost, uuid,
                                              data_offset);
 
        if (info)
@@ -5054,7 +5428,7 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
        super = alloc_super();
        if (super &&
            posix_memalign(&super->buf, MAX_SECTOR_SIZE, mpb_size) != 0) {
-               free(super);
+               free_imsm(super);
                super = NULL;
        }
        if (!super) {
@@ -5065,7 +5439,7 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
            MIGR_REC_BUF_SECTORS*MAX_SECTOR_SIZE) != 0) {
                pr_err("could not allocate migr_rec buffer\n");
                free(super->buf);
-               free(super);
+               free_imsm(super);
                return 0;
        }
        memset(super->buf, 0, mpb_size);
@@ -5088,7 +5462,6 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
        return 1;
 }
 
-#ifndef MDASSEMBLE
 static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
                                     int fd, char *devname)
 {
@@ -5322,6 +5695,13 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
                                                "\tRAID 0 is the only supported configuration for this type of x8 device.\n");
                                break;
                        }
+               } else if (super->hba->type == SYS_DEV_VMD && super->orom &&
+                   !imsm_orom_has_tpv_support(super->orom)) {
+                       pr_err("\tPlatform configuration does not support non-Intel NVMe drives.\n"
+                              "\tPlease refer to Intel(R) RSTe user guide.\n");
+                       free(dd->devname);
+                       free(dd);
+                       return 1;
                }
        }
 
@@ -5343,7 +5723,7 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
        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,
+               if ((unsigned int)write(fd, super->migr_rec_buf,
                    MIGR_REC_BUF_SECTORS*super->sector_size) !=
                    MIGR_REC_BUF_SECTORS*super->sector_size)
                        perror("Write migr_rec failed");
@@ -5472,6 +5852,7 @@ static int write_super_imsm(struct supertype *st, int doclose)
        __u32 mpb_size = sizeof(struct imsm_super) - sizeof(struct imsm_disk);
        int num_disks = 0;
        int clear_migration_record = 1;
+       __u32 bbm_log_size;
 
        /* 'generation' is incremented everytime the metadata is written */
        generation = __le32_to_cpu(mpb->generation_num);
@@ -5509,9 +5890,23 @@ static int write_super_imsm(struct supertype *st, int doclose)
                if (is_gen_migration(dev2))
                        clear_migration_record = 0;
        }
-       mpb_size += __le32_to_cpu(mpb->bbm_log_size);
+
+       bbm_log_size = get_imsm_bbm_log_size(super->bbm_log);
+
+       if (bbm_log_size) {
+               memcpy((void *)mpb + mpb_size, super->bbm_log, bbm_log_size);
+               mpb->attributes |= MPB_ATTRIB_BBM;
+       } else
+               mpb->attributes &= ~MPB_ATTRIB_BBM;
+
+       super->anchor->bbm_log_size = __cpu_to_le32(bbm_log_size);
+       mpb_size += bbm_log_size;
        mpb->mpb_size = __cpu_to_le32(mpb_size);
 
+#ifdef DEBUG
+       assert(super->len == 0 || mpb_size <= super->len);
+#endif
+
        /* recalculate checksum */
        sum = __gen_imsm_checksum(mpb);
        mpb->check_sum = __cpu_to_le32(sum);
@@ -5538,7 +5933,8 @@ static int write_super_imsm(struct supertype *st, int doclose)
                        get_dev_size(d->fd, NULL, &dsize);
                        if (lseek64(d->fd, dsize - sector_size,
                            SEEK_SET) >= 0) {
-                               if (write(d->fd, super->migr_rec_buf,
+                               if ((unsigned int)write(d->fd,
+                                   super->migr_rec_buf,
                                    MIGR_REC_BUF_SECTORS*sector_size) !=
                                    MIGR_REC_BUF_SECTORS*sector_size)
                                        perror("Write migr_rec failed");
@@ -5611,10 +6007,142 @@ static int mgmt_disk(struct supertype *st)
        return 0;
 }
 
+__u32 crc32c_le(__u32 crc, unsigned char const *p, size_t len);
+
+static int write_init_ppl_imsm(struct supertype *st, struct mdinfo *info, int fd)
+{
+       struct intel_super *super = st->sb;
+       void *buf;
+       struct ppl_header *ppl_hdr;
+       int ret;
+
+       ret = posix_memalign(&buf, 4096, PPL_HEADER_SIZE);
+       if (ret) {
+               pr_err("Failed to allocate PPL header buffer\n");
+               return ret;
+       }
+
+       memset(buf, 0, PPL_HEADER_SIZE);
+       ppl_hdr = buf;
+       memset(ppl_hdr->reserved, 0xff, PPL_HDR_RESERVED);
+       ppl_hdr->signature = __cpu_to_le32(super->anchor->orig_family_num);
+       ppl_hdr->checksum = __cpu_to_le32(~crc32c_le(~0, buf, PPL_HEADER_SIZE));
+
+       if (lseek64(fd, info->ppl_sector * 512, SEEK_SET) < 0) {
+               ret = errno;
+               perror("Failed to seek to PPL header location");
+       }
+
+       if (!ret && write(fd, buf, PPL_HEADER_SIZE) != PPL_HEADER_SIZE) {
+               ret = errno;
+               perror("Write PPL header failed");
+       }
+
+       if (!ret)
+               fsync(fd);
+
+       free(buf);
+       return ret;
+}
+
+static int validate_ppl_imsm(struct supertype *st, struct mdinfo *info,
+                            struct mdinfo *disk)
+{
+       struct intel_super *super = st->sb;
+       struct dl *d;
+       void *buf;
+       int ret = 0;
+       struct ppl_header *ppl_hdr;
+       __u32 crc;
+       struct imsm_dev *dev;
+       struct imsm_map *map;
+       __u32 idx;
+
+       if (disk->disk.raid_disk < 0)
+               return 0;
+
+       if (posix_memalign(&buf, 4096, PPL_HEADER_SIZE)) {
+               pr_err("Failed to allocate PPL header buffer\n");
+               return -1;
+       }
+
+       dev = get_imsm_dev(super, info->container_member);
+       map = get_imsm_map(dev, MAP_X);
+       idx = get_imsm_disk_idx(dev, disk->disk.raid_disk, MAP_X);
+       d = get_imsm_dl_disk(super, idx);
+
+       if (!d || d->index < 0 || is_failed(&d->disk))
+               goto out;
+
+       if (lseek64(d->fd, info->ppl_sector * 512, SEEK_SET) < 0) {
+               perror("Failed to seek to PPL header location");
+               ret = -1;
+               goto out;
+       }
+
+       if (read(d->fd, buf, PPL_HEADER_SIZE) != PPL_HEADER_SIZE) {
+               perror("Read PPL header failed");
+               ret = -1;
+               goto out;
+       }
+
+       ppl_hdr = buf;
+
+       crc = __le32_to_cpu(ppl_hdr->checksum);
+       ppl_hdr->checksum = 0;
+
+       if (crc != ~crc32c_le(~0, buf, PPL_HEADER_SIZE)) {
+               dprintf("Wrong PPL header checksum on %s\n",
+                       d->devname);
+               ret = 1;
+       }
+
+       if (!ret && (__le32_to_cpu(ppl_hdr->signature) !=
+                     super->anchor->orig_family_num)) {
+               dprintf("Wrong PPL header signature on %s\n",
+                       d->devname);
+               ret = 1;
+       }
+
+out:
+       free(buf);
+
+       if (ret == 1 && map->map_state == IMSM_T_STATE_UNINITIALIZED)
+               return st->ss->write_init_ppl(st, info, d->fd);
+
+       return ret;
+}
+
+static int write_init_ppl_imsm_all(struct supertype *st, struct mdinfo *info)
+{
+       struct intel_super *super = st->sb;
+       struct dl *d;
+       int ret = 0;
+
+       if (info->consistency_policy != CONSISTENCY_POLICY_PPL ||
+           info->array.level != 5)
+               return 0;
+
+       for (d = super->disks; d ; d = d->next) {
+               if (d->index < 0 || is_failed(&d->disk))
+                       continue;
+
+               ret = st->ss->write_init_ppl(st, info, d->fd);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
 static int write_init_super_imsm(struct supertype *st)
 {
        struct intel_super *super = st->sb;
        int current_vol = super->current_vol;
+       int rv = 0;
+       struct mdinfo info;
+
+       getinfo_super_imsm(st, &info, NULL);
 
        /* we are done with current_vol reset it to point st at the container */
        super->current_vol = -1;
@@ -5622,26 +6150,30 @@ static int write_init_super_imsm(struct supertype *st)
        if (st->update_tail) {
                /* queue the recently created array / added disk
                 * as a metadata update */
-               int rv;
 
                /* determine if we are creating a volume or adding a disk */
                if (current_vol < 0) {
                        /* in the mgmt (add/remove) disk case we are running
                         * in mdmon context, so don't close fd's
                         */
-                       return mgmt_disk(st);
-               } else
-                       rv = create_array(st, current_vol);
-
-               return rv;
+                       rv = mgmt_disk(st);
+               } else {
+                       rv = write_init_ppl_imsm_all(st, &info);
+                       if (!rv)
+                               rv = create_array(st, current_vol);
+               }
        } else {
                struct dl *d;
                for (d = super->disks; d; d = d->next)
                        Kill(d->devname, NULL, 0, -1, 1);
-               return write_super_imsm(st, 1);
+               if (current_vol >= 0)
+                       rv = write_init_ppl_imsm_all(st, &info);
+               if (!rv)
+                       rv = write_super_imsm(st, 1);
        }
+
+       return rv;
 }
-#endif
 
 static int store_super_imsm(struct supertype *st, int fd)
 {
@@ -5651,21 +6183,11 @@ static int store_super_imsm(struct supertype *st, int fd)
        if (!mpb)
                return 1;
 
-#ifndef MDASSEMBLE
        if (super->sector_size == 4096)
                convert_to_4k(super);
        return store_imsm_mpb(fd, mpb);
-#else
-       return 1;
-#endif
-}
-
-static int imsm_bbm_log_size(struct imsm_super *mpb)
-{
-       return __le32_to_cpu(mpb->bbm_log_size);
 }
 
-#ifndef MDASSEMBLE
 static int validate_geometry_imsm_container(struct supertype *st, int level,
                                            int layout, int raiddisks, int chunk,
                                            unsigned long long size,
@@ -5700,6 +6222,10 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
         * note that there is no fd for the disks in array.
         */
        super = alloc_super();
+       if (!super) {
+               close(fd);
+               return 0;
+       }
        if (!get_dev_sector_size(fd, NULL, &super->sector_size)) {
                close(fd);
                free_imsm(super);
@@ -6174,20 +6700,20 @@ count_volumes_list(struct md_list *devlist, char *homehost,
        return count;
 }
 
-static int
-count_volumes(struct intel_hba *hba, int dpa, int verbose)
+static int __count_volumes(char *hba_path, int dpa, int verbose,
+                          int cmp_hba_path)
 {
        struct sys_dev *idev, *intel_devices = find_intel_devices();
        int count = 0;
        const struct orom_entry *entry;
        struct devid_list *dv, *devid_list;
 
-       if (!hba || !hba->path)
+       if (!hba_path)
                return 0;
 
        for (idev = intel_devices; idev; idev = idev->next) {
-               if (strstr(idev->path, hba->path))
-                               break;
+               if (strstr(idev->path, hba_path))
+                       break;
        }
 
        if (!idev || !idev->dev_id)
@@ -6201,22 +6727,28 @@ 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;
-               struct sys_dev *device = device_by_id(dv->devid);
-               char *hba_path;
+               struct sys_dev *device = NULL;
+               char *hpath;
                int found = 0;
 
+               if (cmp_hba_path)
+                       device = device_by_id_and_path(dv->devid, hba_path);
+               else
+                       device = device_by_id(dv->devid);
+
                if (device)
-                       hba_path = device->path;
+                       hpath = device->path;
                else
                        return 0;
 
-               devlist = get_devices(hba_path);
+               devlist = get_devices(hpath);
                /* if no intel devices return zero volumes */
                if (devlist == NULL)
                        return 0;
 
-               count += active_arrays_by_format("imsm", hba_path, &devlist, dpa, verbose);
-               dprintf("path: %s active arrays: %d\n", hba_path, count);
+               count += active_arrays_by_format("imsm", hpath, &devlist, dpa,
+                                                verbose);
+               dprintf("path: %s active arrays: %d\n", hpath, count);
                if (devlist == NULL)
                        return 0;
                do  {
@@ -6228,7 +6760,7 @@ count_volumes(struct intel_hba *hba, int dpa, int verbose)
                        dprintf("found %d count: %d\n", found, count);
                } while (found);
 
-               dprintf("path: %s total number of volumes: %d\n", hba_path, count);
+               dprintf("path: %s total number of volumes: %d\n", hpath, count);
 
                while (devlist) {
                        struct md_list *dv = devlist;
@@ -6240,6 +6772,24 @@ count_volumes(struct intel_hba *hba, int dpa, int verbose)
        return count;
 }
 
+static int count_volumes(struct intel_hba *hba, int dpa, int verbose)
+{
+       if (!hba)
+               return 0;
+       if (hba->type == SYS_DEV_VMD) {
+               struct sys_dev *dev;
+               int count = 0;
+
+               for (dev = find_intel_devices(); dev; dev = dev->next) {
+                       if (dev->type == SYS_DEV_VMD)
+                               count += __count_volumes(dev->path, dpa,
+                                                        verbose, 1);
+               }
+               return count;
+       }
+       return __count_volumes(hba->path, dpa, verbose, 0);
+}
+
 static int imsm_default_chunk(const struct imsm_orom *orom)
 {
        /* up to 512 if the plaform supports it, otherwise the platform max.
@@ -6574,7 +7124,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                                  int raiddisks, int *chunk, unsigned long long size,
                                  unsigned long long data_offset,
                                  char *dev, unsigned long long *freesize,
-                                 int verbose)
+                                 int consistency_policy, int verbose)
 {
        int fd, cfd;
        struct mdinfo *sra;
@@ -6803,26 +7353,55 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
 
                        u->type = update_rename_array;
                        u->dev_idx = vol;
-                       snprintf((char *) u->name, MAX_RAID_SERIAL_LEN, "%s", name);
+                       strncpy((char *) u->name, name, MAX_RAID_SERIAL_LEN);
+                       u->name[MAX_RAID_SERIAL_LEN-1] = '\0';
                        append_metadata_update(st, u, sizeof(*u));
                } else {
                        struct imsm_dev *dev;
                        int i;
 
                        dev = get_imsm_dev(super, vol);
-                       snprintf((char *) dev->volume, MAX_RAID_SERIAL_LEN, "%s", name);
+                       strncpy((char *) dev->volume, name, MAX_RAID_SERIAL_LEN);
+                       dev->volume[MAX_RAID_SERIAL_LEN-1] = '\0';
                        for (i = 0; i < mpb->num_raid_devs; i++) {
                                dev = get_imsm_dev(super, i);
                                handle_missing(super, dev);
                        }
                        super->updates_pending++;
                }
+       } else if (strcmp(update, "ppl") == 0 ||
+                  strcmp(update, "no-ppl") == 0) {
+               int new_policy;
+               char *ep;
+               int vol = strtoul(subarray, &ep, 10);
+
+               if (*ep != '\0' || vol >= super->anchor->num_raid_devs)
+                       return 2;
+
+               if (strcmp(update, "ppl") == 0)
+                       new_policy = RWH_DISTRIBUTED;
+               else
+                       new_policy = RWH_OFF;
+
+               if (st->update_tail) {
+                       struct imsm_update_rwh_policy *u = xmalloc(sizeof(*u));
+
+                       u->type = update_rwh_policy;
+                       u->dev_idx = vol;
+                       u->new_policy = new_policy;
+                       append_metadata_update(st, u, sizeof(*u));
+               } else {
+                       struct imsm_dev *dev;
+
+                       dev = get_imsm_dev(super, vol);
+                       dev->rwh_policy = new_policy;
+                       super->updates_pending++;
+               }
        } else
                return 2;
 
        return 0;
 }
-#endif /* MDASSEMBLE */
 
 static int is_gen_migration(struct imsm_dev *dev)
 {
@@ -6856,7 +7435,6 @@ static int is_rebuilding(struct imsm_dev *dev)
                return 0;
 }
 
-#ifndef MDASSEMBLE
 static int is_initializing(struct imsm_dev *dev)
 {
        struct imsm_map *migr_map;
@@ -6874,7 +7452,6 @@ static int is_initializing(struct imsm_dev *dev)
 
        return 0;
 }
-#endif
 
 static void update_recovery_start(struct intel_super *super,
                                        struct imsm_dev *dev,
@@ -6908,9 +7485,7 @@ static void update_recovery_start(struct intel_super *super,
        rebuild->recovery_start = units * blocks_per_migr_unit(super, dev);
 }
 
-#ifndef MDASSEMBLE
 static int recover_backup_imsm(struct supertype *st, struct mdinfo *info);
-#endif
 
 static struct mdinfo *container_content_imsm(struct supertype *st, char *subarray)
 {
@@ -6937,12 +7512,6 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                pr_err("Unsupported attributes in IMSM metadata.Arrays activation is blocked.\n");
        }
 
-       /* check for bad blocks */
-       if (imsm_bbm_log_size(super->anchor)) {
-               pr_err("BBM log found in IMSM metadata.Arrays activation is blocked.\n");
-               sb_errors = 1;
-       }
-
        /* count spare devices, not used in maps
         */
        for (d = super->disks; d; d = d->next)
@@ -6955,9 +7524,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                struct imsm_map *map2;
                struct mdinfo *this;
                int slot;
-#ifndef MDASSEMBLE
                int chunk;
-#endif
                char *ep;
 
                if (subarray &&
@@ -6986,7 +7553,6 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                super->current_vol = i;
                getinfo_super_imsm_volume(st, this, NULL);
                this->next = rest;
-#ifndef MDASSEMBLE
                chunk = __le16_to_cpu(map->blocks_per_strip) >> 1;
                /* mdadm does not support all metadata features- set the bit in all arrays state */
                if (!validate_geometry_imsm_orom(super,
@@ -7001,7 +7567,6 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                          (1<<MD_SB_BLOCK_CONTAINER_RESHAPE) |
                          (1<<MD_SB_BLOCK_VOLUME);
                }
-#endif
 
                /* if array has bad blocks, set suitable bit in all arrays state */
                if (sb_errors)
@@ -7039,7 +7604,8 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                         *
                         * FIXME handle dirty degraded
                         */
-                       if ((skip || recovery_start == 0) && !dev->vol.dirty)
+                       if ((skip || recovery_start == 0) &&
+                           !(dev->vol.dirty & RAIDVOL_DIRTY))
                                this->resync_start = MaxSector;
                        if (skip)
                                continue;
@@ -7074,19 +7640,26 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                                info_d->component_size =
                                                num_data_stripes(map) *
                                                map->blocks_per_strip;
+                               info_d->ppl_sector = this->ppl_sector;
+                               info_d->ppl_size = this->ppl_size;
                        } else {
                                info_d->component_size = blocks_per_member(map);
                        }
+                       info_d->consistency_policy = this->consistency_policy;
+
+                       info_d->bb.supported = 1;
+                       get_volume_badblocks(super->bbm_log, ord_to_idx(ord),
+                                            info_d->data_offset,
+                                            info_d->component_size,
+                                            &info_d->bb);
                }
                /* now that the disk list is up-to-date fixup recovery_start */
                update_recovery_start(super, dev, this);
                this->array.spare_disks += spare_disks;
 
-#ifndef MDASSEMBLE
                /* check for reshape */
                if (this->reshape_active == 1)
                        recover_backup_imsm(st, this);
-#endif
                rest = this;
        }
 
@@ -7216,12 +7789,12 @@ static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev,
        return failed;
 }
 
-#ifndef MDASSEMBLE
 static int imsm_open_new(struct supertype *c, struct active_array *a,
                         char *inst)
 {
        struct intel_super *super = c->sb;
        struct imsm_super *mpb = super->anchor;
+       struct imsm_update_prealloc_bb_mem u;
 
        if (atoi(inst) >= mpb->num_raid_devs) {
                pr_err("subarry index %d, out of range\n", atoi(inst));
@@ -7230,6 +7803,10 @@ static int imsm_open_new(struct supertype *c, struct active_array *a,
 
        dprintf("imsm: open_new %s\n", inst);
        a->info.container_member = atoi(inst);
+
+       u.type = update_prealloc_badblocks_mem;
+       imsm_update_metadata_locally(c, &u, sizeof(u));
+
        return 0;
 }
 
@@ -7257,7 +7834,8 @@ static int is_resyncing(struct imsm_dev *dev)
 }
 
 /* return true if we recorded new information */
-static int mark_failure(struct imsm_dev *dev, struct imsm_disk *disk, int idx)
+static int mark_failure(struct intel_super *super,
+                       struct imsm_dev *dev, struct imsm_disk *disk, int idx)
 {
        __u32 ord;
        int slot;
@@ -7299,12 +7877,16 @@ static int mark_failure(struct imsm_dev *dev, struct imsm_disk *disk, int idx)
        }
        if (map->failed_disk_num == 0xff)
                map->failed_disk_num = slot;
+
+       clear_disk_badblocks(super->bbm_log, ord_to_idx(ord));
+
        return 1;
 }
 
-static void mark_missing(struct imsm_dev *dev, struct imsm_disk *disk, int idx)
+static void mark_missing(struct intel_super *super,
+                        struct imsm_dev *dev, struct imsm_disk *disk, int idx)
 {
-       mark_failure(dev, disk, idx);
+       mark_failure(super, dev, disk, idx);
 
        if (disk->scsi_id == __cpu_to_le32(~(__u32)0))
                return;
@@ -7340,7 +7922,7 @@ static void handle_missing(struct intel_super *super, struct imsm_dev *dev)
                        end_migration(dev, super, map_state);
        }
        for (dl = super->missing; dl; dl = dl->next)
-               mark_missing(dev, &dl->disk, dl->index);
+               mark_missing(super, dev, &dl->disk, dl->index);
        super->updates_pending++;
 }
 
@@ -7376,9 +7958,7 @@ static unsigned long long imsm_set_array_size(struct imsm_dev *dev,
                array_blocks = new_size;
        }
 
-       /* round array size down to closest MB
-        */
-       array_blocks = (array_blocks >> SECT_PER_MB_SHIFT) << SECT_PER_MB_SHIFT;
+       array_blocks = round_size_to_mb(array_blocks, used_disks);
        dev->size_low = __cpu_to_le32((__u32)array_blocks);
        dev->size_high = __cpu_to_le32((__u32)(array_blocks >> 32));
 
@@ -7491,11 +8071,9 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
                                        array_blocks =
                                                blocks_per_member(map) *
                                                used_disks;
-                                       /* round array size down to closest MB
-                                        */
-                                       array_blocks = (array_blocks
-                                                       >> SECT_PER_MB_SHIFT)
-                                               << SECT_PER_MB_SHIFT;
+                                       array_blocks =
+                                               round_size_to_mb(array_blocks,
+                                                                used_disks);
                                        a->info.custom_array_size = array_blocks;
                                        /* encourage manager to update array
                                         * size
@@ -7576,18 +8154,41 @@ mark_checkpoint:
 
 skip_mark_checkpoint:
        /* mark dirty / clean */
-       if (dev->vol.dirty != !consistent) {
+       if (((dev->vol.dirty & RAIDVOL_DIRTY) && consistent) ||
+           (!(dev->vol.dirty & RAIDVOL_DIRTY) && !consistent)) {
                dprintf("imsm: mark '%s'\n", consistent ? "clean" : "dirty");
-               if (consistent)
-                       dev->vol.dirty = 0;
-               else
-                       dev->vol.dirty = 1;
+               if (consistent) {
+                       dev->vol.dirty = RAIDVOL_CLEAN;
+               } else {
+                       dev->vol.dirty = RAIDVOL_DIRTY;
+                       if (dev->rwh_policy == RWH_DISTRIBUTED)
+                               dev->vol.dirty |= RAIDVOL_DSRECORD_VALID;
+               }
                super->updates_pending++;
        }
 
        return consistent;
 }
 
+static int imsm_disk_slot_to_ord(struct active_array *a, int slot)
+{
+       int inst = a->info.container_member;
+       struct intel_super *super = a->container->sb;
+       struct imsm_dev *dev = get_imsm_dev(super, inst);
+       struct imsm_map *map = get_imsm_map(dev, MAP_0);
+
+       if (slot > map->num_members) {
+               pr_err("imsm: imsm_disk_slot_to_ord %d out of range 0..%d\n",
+                      slot, map->num_members - 1);
+               return -1;
+       }
+
+       if (slot < 0)
+               return -1;
+
+       return get_imsm_ord_tbl_ent(dev, slot, MAP_0);
+}
+
 static void imsm_set_disk(struct active_array *a, int n, int state)
 {
        int inst = a->info.container_member;
@@ -7598,24 +8199,19 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
        struct mdinfo *mdi;
        int recovery_not_finished = 0;
        int failed;
-       __u32 ord;
+       int ord;
        __u8 map_state;
 
-       if (n > map->num_members)
-               pr_err("imsm: set_disk %d out of range 0..%d\n",
-                       n, map->num_members - 1);
-
-       if (n < 0)
+       ord = imsm_disk_slot_to_ord(a, n);
+       if (ord < 0)
                return;
 
        dprintf("imsm: set_disk %d:%x\n", n, state);
-
-       ord = get_imsm_ord_tbl_ent(dev, n, MAP_0);
        disk = get_imsm_disk(super, ord_to_idx(ord));
 
        /* check for new failures */
        if (state & DS_FAULTY) {
-               if (mark_failure(dev, disk, ord_to_idx(ord)))
+               if (mark_failure(super, dev, disk, ord_to_idx(ord)))
                        super->updates_pending++;
        }
 
@@ -7758,7 +8354,7 @@ static int store_imsm_mpb(int fd, struct imsm_super *mpb)
        if (lseek64(fd, dsize - (sector_size * 2), SEEK_SET) < 0)
                return 1;
 
-       if (write(fd, buf, sector_size) != sector_size)
+       if ((unsigned int)write(fd, buf, sector_size) != sector_size)
                return 1;
 
        return 0;
@@ -8078,6 +8674,12 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
                di->data_offset = pba_of_lba0(map);
                di->component_size = a->info.component_size;
                di->container_member = inst;
+               di->bb.supported = 1;
+               if (dev->rwh_policy == RWH_DISTRIBUTED) {
+                       di->consistency_policy = CONSISTENCY_POLICY_PPL;
+                       di->ppl_sector = get_ppl_sector(super, inst);
+                       di->ppl_size = (PPL_HEADER_SIZE + PPL_ENTRY_SPACE) >> 9;
+               }
                super->random = random32();
                di->next = rv;
                rv = di;
@@ -8712,7 +9314,7 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
        for (du = super->missing; du; du = du->next)
                if (du->index >= 0) {
                        set_imsm_ord_tbl_ent(map, du->index, du->index);
-                       mark_missing(dv->dev, &du->disk, du->index);
+                       mark_missing(super, dv->dev, &du->disk, du->index);
                }
 
        return 1;
@@ -9003,6 +9605,23 @@ static void imsm_process_update(struct supertype *st,
                }
                break;
        }
+       case update_prealloc_badblocks_mem:
+               break;
+       case update_rwh_policy: {
+               struct imsm_update_rwh_policy *u = (void *)update->buf;
+               int target = u->dev_idx;
+               struct imsm_dev *dev = get_imsm_dev(super, target);
+               if (!dev) {
+                       dprintf("could not find subarray-%d\n", target);
+                       break;
+               }
+
+               if (dev->rwh_policy != u->new_policy) {
+                       dev->rwh_policy = u->new_policy;
+                       super->updates_pending++;
+               }
+               break;
+       }
        default:
                pr_err("error: unsuported process update type:(type: %d)\n",    type);
        }
@@ -9244,6 +9863,15 @@ static int imsm_prepare_update(struct supertype *st,
        case update_add_remove_disk:
                /* no update->len needed */
                break;
+       case update_prealloc_badblocks_mem:
+               super->extra_space += sizeof(struct bbm_log) -
+                       get_imsm_bbm_log_size(super->bbm_log);
+               break;
+       case update_rwh_policy: {
+               if (update->len < (int)sizeof(struct imsm_update_rwh_policy))
+                       return 0;
+               break;
+       }
        default:
                return 0;
        }
@@ -9254,13 +9882,13 @@ static int imsm_prepare_update(struct supertype *st,
        else
                buf_len = super->len;
 
-       if (__le32_to_cpu(mpb->mpb_size) + len > buf_len) {
+       if (__le32_to_cpu(mpb->mpb_size) + super->extra_space + len > buf_len) {
                /* ok we need a larger buf than what is currently allocated
                 * 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,
-                                 sector_size);
+               buf_len = ROUND_UP(__le32_to_cpu(mpb->mpb_size) +
+                                  super->extra_space + len, sector_size);
                if (super->next_buf)
                        free(super->next_buf);
 
@@ -9280,8 +9908,9 @@ static void imsm_delete(struct intel_super *super, struct dl **dlp, unsigned ind
        struct dl *iter;
        struct imsm_dev *dev;
        struct imsm_map *map;
-       int i, j, num_members;
+       unsigned int i, j, num_members;
        __u32 ord;
+       struct bbm_log *log = super->bbm_log;
 
        dprintf("deleting device[%d] from imsm_super\n", index);
 
@@ -9314,6 +9943,14 @@ static void imsm_delete(struct intel_super *super, struct dl **dlp, unsigned ind
                }
        }
 
+       for (i = 0; i < log->entry_count; i++) {
+               struct bbm_log_entry *entry = &log->marked_block_entries[i];
+
+               if (entry->disk_ordinal <= index)
+                       continue;
+               entry->disk_ordinal--;
+       }
+
        mpb->num_disks--;
        super->updates_pending++;
        if (*dlp) {
@@ -9323,7 +9960,6 @@ static void imsm_delete(struct intel_super *super, struct dl **dlp, unsigned ind
                __free_imsm_disk(dl);
        }
 }
-#endif /* MDASSEMBLE */
 
 static void close_targets(int *targets, int new_disks)
 {
@@ -9526,7 +10162,151 @@ int validate_container_imsm(struct mdinfo *info)
 
        return 0;
 }
-#ifndef MDASSEMBLE
+
+/*******************************************************************************
+* Function:   imsm_record_badblock
+* Description: This routine stores new bad block record in BBM log
+*
+* Parameters:
+*     a                : array containing a bad block
+*     slot     : disk number containing a bad block
+*     sector   : bad block sector
+*     length   : bad block sectors range
+* Returns:
+*     1 : Success
+*     0 : Error
+******************************************************************************/
+static int imsm_record_badblock(struct active_array *a, int slot,
+                         unsigned long long sector, int length)
+{
+       struct intel_super *super = a->container->sb;
+       int ord;
+       int ret;
+
+       ord = imsm_disk_slot_to_ord(a, slot);
+       if (ord < 0)
+               return 0;
+
+       ret = record_new_badblock(super->bbm_log, ord_to_idx(ord), sector,
+                                  length);
+       if (ret)
+               super->updates_pending++;
+
+       return ret;
+}
+/*******************************************************************************
+* Function:   imsm_clear_badblock
+* Description: This routine clears bad block record from BBM log
+*
+* Parameters:
+*     a                : array containing a bad block
+*     slot     : disk number containing a bad block
+*     sector   : bad block sector
+*     length   : bad block sectors range
+* Returns:
+*     1 : Success
+*     0 : Error
+******************************************************************************/
+static int imsm_clear_badblock(struct active_array *a, int slot,
+                       unsigned long long sector, int length)
+{
+       struct intel_super *super = a->container->sb;
+       int ord;
+       int ret;
+
+       ord = imsm_disk_slot_to_ord(a, slot);
+       if (ord < 0)
+               return 0;
+
+       ret = clear_badblock(super->bbm_log, ord_to_idx(ord), sector, length);
+       if (ret)
+               super->updates_pending++;
+
+       return ret;
+}
+/*******************************************************************************
+* Function:   imsm_get_badblocks
+* Description: This routine get list of bad blocks for an array
+*
+* Parameters:
+*     a                : array
+*     slot     : disk number
+* Returns:
+*     bb       : structure containing bad blocks
+*     NULL     : error
+******************************************************************************/
+static struct md_bb *imsm_get_badblocks(struct active_array *a, int slot)
+{
+       int inst = a->info.container_member;
+       struct intel_super *super = a->container->sb;
+       struct imsm_dev *dev = get_imsm_dev(super, inst);
+       struct imsm_map *map = get_imsm_map(dev, MAP_0);
+       int ord;
+
+       ord = imsm_disk_slot_to_ord(a, slot);
+       if (ord < 0)
+               return NULL;
+
+       get_volume_badblocks(super->bbm_log, ord_to_idx(ord), pba_of_lba0(map),
+                            blocks_per_member(map), &super->bb);
+
+       return &super->bb;
+}
+/*******************************************************************************
+* Function:   examine_badblocks_imsm
+* Description: Prints list of bad blocks on a disk to the standard output
+*
+* Parameters:
+*     st       : metadata handler
+*     fd       : open file descriptor for device
+*     devname  : device name
+* Returns:
+*     0 : Success
+*     1 : Error
+******************************************************************************/
+static int examine_badblocks_imsm(struct supertype *st, int fd, char *devname)
+{
+       struct intel_super *super = st->sb;
+       struct bbm_log *log = super->bbm_log;
+       struct dl *d = NULL;
+       int any = 0;
+
+       for (d = super->disks; d ; d = d->next) {
+               if (strcmp(d->devname, devname) == 0)
+                       break;
+       }
+
+       if ((d == NULL) || (d->index < 0)) { /* serial mismatch probably */
+               pr_err("%s doesn't appear to be part of a raid array\n",
+                      devname);
+               return 1;
+       }
+
+       if (log != NULL) {
+               unsigned int i;
+               struct bbm_log_entry *entry = &log->marked_block_entries[0];
+
+               for (i = 0; i < log->entry_count; i++) {
+                       if (entry[i].disk_ordinal == d->index) {
+                               unsigned long long sector = __le48_to_cpu(
+                                       &entry[i].defective_block_start);
+                               int cnt = entry[i].marked_count + 1;
+
+                               if (!any) {
+                                       printf("Bad-blocks on %s:\n", devname);
+                                       any = 1;
+                               }
+
+                               printf("%20llu for %d sectors\n", sector, cnt);
+                       }
+               }
+       }
+
+       if (!any)
+               printf("No bad-blocks list configured on %s\n", devname);
+
+       return 0;
+}
 /*******************************************************************************
  * Function:   init_migr_record_imsm
  * Description:        Function inits imsm migration record
@@ -10195,7 +10975,7 @@ static int imsm_create_metadata_update_for_migration(
                        free(u);
                        sysfs_free(spares);
                        update_memory_size = 0;
-                       dprintf("error: cannot get spare device for requested migration");
+                       pr_err("cannot get spare device for requested migration\n");
                        return 0;
                }
                sysfs_free(spares);
@@ -10323,6 +11103,11 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                        pr_err("Error. Chunk size change for RAID 10 is not supported.\n");
                        change = -1;
                        goto analyse_change_exit;
+               } else if (info.component_size % (geo->chunksize/512)) {
+                       pr_err("New chunk size (%dK) does not evenly divide device size (%lluk). Aborting...\n",
+                              geo->chunksize/1024, info.component_size/2);
+                       change = -1;
+                       goto analyse_change_exit;
                }
                change = CH_MIGRATION;
        } else {
@@ -10422,7 +11207,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                                    geo->raid_disks + devNumChange,
                                    &chunk,
                                    geo->size, INVALID_SECTORS,
-                                   0, 0, 1))
+                                   0, 0, info.consistency_policy, 1))
                change = -1;
 
        if (check_devs) {
@@ -11004,7 +11789,7 @@ static int imsm_manage_reshape(
                get_dev_size(d->fd, NULL, &dsize);
                if (lseek64(d->fd, dsize - MIGR_REC_SECTOR_POSITION*sector_size,
                            SEEK_SET) >= 0) {
-                       if (write(d->fd, super->migr_rec_buf,
+                       if ((unsigned int)write(d->fd, super->migr_rec_buf,
                            MIGR_REC_BUF_SECTORS*sector_size) !=
                            MIGR_REC_BUF_SECTORS*sector_size)
                                perror("Write migr_rec failed");
@@ -11023,10 +11808,7 @@ abort:
        return ret_val;
 }
 
-#endif /* MDASSEMBLE */
-
 struct superswitch super_imsm = {
-#ifndef        MDASSEMBLE
        .examine_super  = examine_super_imsm,
        .brief_examine_super = brief_examine_super_imsm,
        .brief_examine_subarrays = brief_examine_subarrays_imsm,
@@ -11048,7 +11830,7 @@ struct superswitch super_imsm = {
        .manage_reshape = imsm_manage_reshape,
        .recover_backup = recover_backup_imsm,
        .copy_metadata = copy_metadata_imsm,
-#endif
+       .examine_badblocks = examine_badblocks_imsm,
        .match_home     = match_home_imsm,
        .uuid_from_super= uuid_from_super_imsm,
        .getinfo_super  = getinfo_super_imsm,
@@ -11068,10 +11850,12 @@ struct superswitch super_imsm = {
        .container_content = container_content_imsm,
        .validate_container = validate_container_imsm,
 
+       .write_init_ppl = write_init_ppl_imsm,
+       .validate_ppl   = validate_ppl_imsm,
+
        .external       = 1,
        .name = "imsm",
 
-#ifndef MDASSEMBLE
 /* for mdmon */
        .open_new       = imsm_open_new,
        .set_array_state= imsm_set_array_state,
@@ -11080,5 +11864,7 @@ struct superswitch super_imsm = {
        .activate_spare = imsm_activate_spare,
        .process_update = imsm_process_update,
        .prepare_update = imsm_prepare_update,
-#endif /* MDASSEMBLE */
+       .record_bad_block = imsm_record_badblock,
+       .clear_bad_block  = imsm_clear_badblock,
+       .get_bad_blocks   = imsm_get_badblocks,
 };