+static int all_ff(char *guid)
+{
+ int i;
+ for (i = 0; i < DDF_GUID_LEN; i++)
+ if (guid[i] != (char)0xff)
+ return 0;
+ return 1;
+}
+static int chunk_to_shift(int chunksize)
+{
+ return ffs(chunksize/512)-1;
+}
+
+static int level_to_prl(int level)
+{
+ switch (level) {
+ case LEVEL_LINEAR: return DDF_CONCAT;
+ case 0: return DDF_RAID0;
+ case 1: return DDF_RAID1;
+ case 4: return DDF_RAID4;
+ case 5: return DDF_RAID5;
+ case 6: return DDF_RAID6;
+ default: return -1;
+ }
+}
+static int layout_to_rlq(int level, int layout, int raiddisks)
+{
+ switch(level) {
+ case 0:
+ return DDF_RAID0_SIMPLE;
+ case 1:
+ switch(raiddisks) {
+ case 2: return DDF_RAID1_SIMPLE;
+ case 3: return DDF_RAID1_MULTI;
+ default: return -1;
+ }
+ case 4:
+ switch(layout) {
+ case 0: return DDF_RAID4_N;
+ }
+ break;
+ case 5:
+ case 6:
+ switch(layout) {
+ case ALGORITHM_LEFT_ASYMMETRIC:
+ return DDF_RAID5_N_RESTART;
+ case ALGORITHM_RIGHT_ASYMMETRIC:
+ return DDF_RAID5_0_RESTART;
+ case ALGORITHM_LEFT_SYMMETRIC:
+ return DDF_RAID5_N_CONTINUE;
+ case ALGORITHM_RIGHT_SYMMETRIC:
+ return -1; /* not mentioned in standard */
+ }
+ }
+ return -1;
+}
+
+static int init_super_ddf_bvd(struct supertype *st,
+ mdu_array_info_t *info,
+ unsigned long long size,
+ char *name, char *homehost,
+ int *uuid)
+{
+ /* We are creating a BVD inside a pre-existing container.
+ * so st->sb is already set.
+ * We need to create a new vd_config and a new virtual_entry
+ */
+ struct ddf_super *ddf = st->sb;
+ int venum;
+ struct virtual_entry *ve;
+ struct vcl *vcl;
+ struct vd_config *vc;
+ int mppe;
+ int conflen;
+
+ if (__be16_to_cpu(ddf->virt->populated_vdes)
+ >= __be16_to_cpu(ddf->virt->max_vdes)) {
+ fprintf(stderr, Name": This ddf already has the "
+ "maximum of %d virtual devices\n",
+ __be16_to_cpu(ddf->virt->max_vdes));
+ return 0;
+ }
+
+ for (venum = 0; venum < __be16_to_cpu(ddf->virt->max_vdes); venum++)
+ if (all_ff(ddf->virt->entries[venum].guid))
+ break;
+ if (venum == __be16_to_cpu(ddf->virt->max_vdes)) {
+ fprintf(stderr, Name ": Cannot find spare slot for "
+ "virtual disk - DDF is corrupt\n");
+ return 0;
+ }
+ ve = &ddf->virt->entries[venum];
+
+ /* A Virtual Disk GUID contains the T10 Vendor ID, controller type,
+ * timestamp, random number
+ */
+ make_header_guid(ve->guid);
+ ve->unit = __cpu_to_be16(info->md_minor);
+ ve->pad0 = 0xFFFF;
+ ve->guid_crc = crc32(0, (unsigned char*)ddf->anchor.guid, DDF_GUID_LEN);
+ ve->type = 0;
+ ve->state = 0;
+ ve->init_state = 0;
+ if (!(info->state & 1))
+ ve->init_state = DDF_state_inconsistent;
+ memset(ve->pad1, 0xff, 14);
+ memset(ve->name, ' ', 16);
+ if (name)
+ strncpy(ve->name, name, 16);
+ ddf->virt->populated_vdes =
+ __cpu_to_be16(__be16_to_cpu(ddf->virt->populated_vdes)+1);
+
+ /* Now create a new vd_config */
+ conflen = __be16_to_cpu(ddf->active->config_record_len);
+ vcl = malloc(offsetof(struct vcl, conf) + conflen * 512);
+ vcl->lba_offset = (__u64*) &vcl->conf.phys_refnum[ddf->max_part+1];
+
+ vc = &vcl->conf;
+
+ vc->magic = DDF_VD_CONF_MAGIC;
+ memcpy(vc->guid, ve->guid, DDF_GUID_LEN);
+ vc->timestamp = __cpu_to_be32(time(0)-DECADE);
+ vc->seqnum = __cpu_to_be32(1);
+ memset(vc->pad0, 0xff, 24);
+ vc->prim_elmnt_count = __cpu_to_be16(info->raid_disks);
+ vc->chunk_shift = chunk_to_shift(info->chunk_size);
+ vc->prl = level_to_prl(info->level);
+ vc->rlq = layout_to_rlq(info->level, info->layout, info->raid_disks);
+ vc->sec_elmnt_count = 1;
+ vc->sec_elmnt_seq = 0;
+ vc->srl = 0;
+ vc->blocks = __cpu_to_be64(info->size * 2);
+ vc->array_blocks = __cpu_to_be64(
+ calc_array_size(info->level, info->raid_disks, info->layout,
+ info->chunk_size, info->size*2));
+ memset(vc->pad1, 0xff, 8);
+ vc->spare_refs[0] = 0xffffffff;
+ vc->spare_refs[1] = 0xffffffff;
+ vc->spare_refs[2] = 0xffffffff;
+ vc->spare_refs[3] = 0xffffffff;
+ vc->spare_refs[4] = 0xffffffff;
+ vc->spare_refs[5] = 0xffffffff;
+ vc->spare_refs[6] = 0xffffffff;
+ vc->spare_refs[7] = 0xffffffff;
+ memset(vc->cache_pol, 0, 8);
+ vc->bg_rate = 0x80;
+ memset(vc->pad2, 0xff, 3);
+ memset(vc->pad3, 0xff, 52);
+ memset(vc->pad4, 0xff, 192);
+ memset(vc->v0, 0xff, 32);
+ memset(vc->v1, 0xff, 32);
+ memset(vc->v2, 0xff, 16);
+ memset(vc->v3, 0xff, 16);
+ memset(vc->vendor, 0xff, 32);
+ mppe = __be16_to_cpu(ddf->anchor.max_primary_element_entries);
+ memset(vc->phys_refnum, 0xff, 4*mppe);
+ memset(vc->phys_refnum+mppe, 0x00, 8*mppe);
+
+ vcl->next = ddf->conflist;
+ ddf->conflist = vcl;
+ ddf->newconf = vcl;
+ return 1;
+}
+
+static void add_to_super_ddf_bvd(struct supertype *st,
+ mdu_disk_info_t *dk, int fd, char *devname)
+{
+ /* fd and devname identify a device with-in the ddf container (st).
+ * dk identifies a location in the new BVD.
+ * We need to find suitable free space in that device and update
+ * the phys_refnum and lba_offset for the newly created vd_config.
+ * We might also want to update the type in the phys_disk
+ * section. FIXME
+ */
+ struct dl *dl;
+ struct ddf_super *ddf = st->sb;
+ struct vd_config *vc;
+ __u64 *lba_offset;
+ int mppe;
+
+ for (dl = ddf->dlist; dl ; dl = dl->next)
+ if (dl->major == dk->major &&
+ dl->minor == dk->minor)
+ break;
+ if (!dl || ! (dk->state & (1<<MD_DISK_SYNC)))
+ return;
+
+ vc = &ddf->newconf->conf;
+ vc->phys_refnum[dk->raid_disk] = dl->disk.refnum;
+ mppe = __be16_to_cpu(ddf->anchor.max_primary_element_entries);
+ lba_offset = (__u64*)(vc->phys_refnum + mppe);
+ lba_offset[dk->raid_disk] = 0; /* FIXME */
+
+ dl->vlist[0] =ddf->newconf; /* FIXME */
+
+ dl->fd = fd;
+ dl->devname = devname;
+}
+