From 097bcf005780ddf0bb9169b8b7c4330a8c603799 Mon Sep 17 00:00:00 2001 From: "mwilck@arcor.de" Date: Fri, 1 Mar 2013 23:28:23 +0100 Subject: [PATCH] DDF: use existing locations for primary and secondary DDF structure Some RAID BIOSes apparently use hard-coded LBA offsets (presumably from the end of the disk) for the primary and secondary DDF structure, ignoring the values given in the DDF anchor. This is broken BIOS behavior, but it will cause any changes made by MD (e.g. setting the init_state flag after a full initialization) to be "forgotten" after the next reboot. This patch fixes this by using the exiting LBA locations if available. Verified that this fixes MD+LSI Mega Software RAID BIOS. Signed-off-by: Martin Wilck Signed-off-by: NeilBrown --- super-ddf.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/super-ddf.c b/super-ddf.c index 38af913..dfbd551 100644 --- a/super-ddf.c +++ b/super-ddf.c @@ -421,6 +421,9 @@ struct ddf_super { char *devname; int fd; unsigned long long size; /* sectors */ + unsigned long long primary_lba; /* sectors */ + unsigned long long secondary_lba; /* sectors */ + unsigned long long workspace_lba; /* sectors */ int pdnum; /* index in ->phys */ struct spare_assign *spare; void *mdupdate; /* hold metadata update */ @@ -668,6 +671,13 @@ static int load_ddf_local(int fd, struct ddf_super *super, dl->size = 0; if (get_dev_size(fd, devname, &dsize)) dl->size = dsize >> 9; + /* If the disks have different sizes, the LBAs will differ + * between phys disks. + * At this point here, the values in super->active must be valid + * for this phys disk. */ + dl->primary_lba = super->active->primary_lba; + dl->secondary_lba = super->active->secondary_lba; + dl->workspace_lba = super->active->workspace_lba; dl->spare = NULL; for (i = 0 ; i < super->max_part ; i++) dl->vlist[i] = NULL; @@ -2422,9 +2432,21 @@ static int __write_init_super_ddf(struct supertype *st) */ get_dev_size(fd, NULL, &size); size /= 512; - ddf->anchor.workspace_lba = __cpu_to_be64(size - 32*1024*2); - ddf->anchor.primary_lba = __cpu_to_be64(size - 16*1024*2); - ddf->anchor.secondary_lba = __cpu_to_be64(size - 31*1024*2); + if (d->workspace_lba != 0) + ddf->anchor.workspace_lba = d->workspace_lba; + else + ddf->anchor.workspace_lba = + __cpu_to_be64(size - 32*1024*2); + if (d->primary_lba != 0) + ddf->anchor.primary_lba = d->primary_lba; + else + ddf->anchor.primary_lba = + __cpu_to_be64(size - 16*1024*2); + if (d->secondary_lba != 0) + ddf->anchor.secondary_lba = d->secondary_lba; + else + ddf->anchor.secondary_lba = + __cpu_to_be64(size - 32*1024*2); ddf->anchor.seq = __cpu_to_be32(1); memcpy(&ddf->primary, &ddf->anchor, 512); memcpy(&ddf->secondary, &ddf->anchor, 512);