* [PATCH 1/3] DDF: cleanly save the secondary DDF structure
2012-12-07 22:38 Fixes for DDF with LSI BIOS RAID mwilck
@ 2012-12-07 22:38 ` mwilck
2012-12-07 22:39 ` [PATCH 2/3] DDF: use existing locations for primary and " mwilck
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: mwilck @ 2012-12-07 22:38 UTC (permalink / raw)
To: linux-raid; +Cc: mwilck
From: Martin Wilck <mwilck@arcor.de>
So far, mdadm only saved the header of the secondary structure.
With this patch, the full secondary DDF structure is saved
consistently
---
super-ddf.c | 136 +++++++++++++++++++++++++++++++++-------------------------
1 files changed, 77 insertions(+), 59 deletions(-)
diff --git a/super-ddf.c b/super-ddf.c
index 3b3c1f0..c336db4 100644
--- a/super-ddf.c
+++ b/super-ddf.c
@@ -2317,17 +2317,86 @@ static int remove_from_super_ddf(struct supertype *st, mdu_disk_info_t *dk)
*/
#define NULL_CONF_SZ 4096
-static int __write_init_super_ddf(struct supertype *st)
+static int __write_ddf_structure(struct dl *d, struct ddf_super *ddf, __u8 type, char *null_aligned)
{
+ unsigned long long sector;
+ struct ddf_header *header;
+ int fd, i, n_config, conf_size;
+
+ fd = d->fd;
+
+ switch (type) {
+ case DDF_HEADER_PRIMARY:
+ header = &ddf->primary;
+ sector = __be64_to_cpu(header->primary_lba);
+ break;
+ case DDF_HEADER_SECONDARY:
+ header = &ddf->secondary;
+ sector = __be64_to_cpu(header->secondary_lba);
+ break;
+ default:
+ return 0;
+ }
+
+ header->type = type;
+ header->openflag = 0;
+ header->crc = calc_crc(header, 512);
+
+ lseek64(fd, sector<<9, 0);
+ if (write(fd, header, 512) < 0)
+ return 0;
+
+ ddf->controller.crc = calc_crc(&ddf->controller, 512);
+ if (write(fd, &ddf->controller, 512) < 0)
+ return 0;
+
+ ddf->phys->crc = calc_crc(ddf->phys, ddf->pdsize);
+ if (write(fd, ddf->phys, ddf->pdsize) < 0)
+ return 0;
+ ddf->virt->crc = calc_crc(ddf->virt, ddf->vdsize);
+ if (write(fd, ddf->virt, ddf->vdsize) < 0)
+ return 0;
+
+ /* Now write lots of config records. */
+ n_config = ddf->max_part;
+ conf_size = ddf->conf_rec_len * 512;
+ for (i = 0 ; i <= n_config ; i++) {
+ struct vcl *c = d->vlist[i];
+ if (i == n_config)
+ c = (struct vcl*)d->spare;
+
+ if (c) {
+ c->conf.crc = calc_crc(&c->conf, conf_size);
+ if (write(fd, &c->conf, conf_size) < 0)
+ break;
+ } else {
+ unsigned int togo = conf_size;
+ while (togo > NULL_CONF_SZ) {
+ if (write(fd, null_aligned, NULL_CONF_SZ) < 0)
+ break;
+ togo -= NULL_CONF_SZ;
+ }
+ if (write(fd, null_aligned, togo) < 0)
+ break;
+ }
+ }
+ if (i <= n_config)
+ return 0;
+
+ d->disk.crc = calc_crc(&d->disk, 512);
+ if (write(fd, &d->disk, 512) < 0)
+ return 0;
+ return 1;
+}
+
+static int __write_init_super_ddf(struct supertype *st)
+{
struct ddf_super *ddf = st->sb;
- int i;
struct dl *d;
- int n_config;
- int conf_size;
int attempts = 0;
int successes = 0;
- unsigned long long size, sector;
+ unsigned long long size;
char *null_aligned;
if (posix_memalign((void**)&null_aligned, 4096, NULL_CONF_SZ) != 0) {
@@ -2355,6 +2424,7 @@ static int __write_init_super_ddf(struct supertype *st)
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);
ddf->anchor.seq = __cpu_to_be32(1);
memcpy(&ddf->primary, &ddf->anchor, 512);
memcpy(&ddf->secondary, &ddf->anchor, 512);
@@ -2363,64 +2433,12 @@ static int __write_init_super_ddf(struct supertype *st)
ddf->anchor.seq = 0xFFFFFFFF; /* no sequencing in anchor */
ddf->anchor.crc = calc_crc(&ddf->anchor, 512);
- ddf->primary.openflag = 0;
- ddf->primary.type = DDF_HEADER_PRIMARY;
-
- ddf->secondary.openflag = 0;
- ddf->secondary.type = DDF_HEADER_SECONDARY;
-
- ddf->primary.crc = calc_crc(&ddf->primary, 512);
- ddf->secondary.crc = calc_crc(&ddf->secondary, 512);
-
- sector = size - 16*1024*2;
- lseek64(fd, sector<<9, 0);
- if (write(fd, &ddf->primary, 512) < 0)
+ if (!__write_ddf_structure(d, ddf, DDF_HEADER_PRIMARY, null_aligned))
continue;
- ddf->controller.crc = calc_crc(&ddf->controller, 512);
- if (write(fd, &ddf->controller, 512) < 0)
- continue;
-
- ddf->phys->crc = calc_crc(ddf->phys, ddf->pdsize);
-
- if (write(fd, ddf->phys, ddf->pdsize) < 0)
+ if (!__write_ddf_structure(d, ddf, DDF_HEADER_SECONDARY, null_aligned))
continue;
- ddf->virt->crc = calc_crc(ddf->virt, ddf->vdsize);
- if (write(fd, ddf->virt, ddf->vdsize) < 0)
- continue;
-
- /* Now write lots of config records. */
- n_config = ddf->max_part;
- conf_size = ddf->conf_rec_len * 512;
- for (i = 0 ; i <= n_config ; i++) {
- struct vcl *c = d->vlist[i];
- if (i == n_config)
- c = (struct vcl*)d->spare;
-
- if (c) {
- c->conf.crc = calc_crc(&c->conf, conf_size);
- if (write(fd, &c->conf, conf_size) < 0)
- break;
- } else {
- unsigned int togo = conf_size;
- while (togo > NULL_CONF_SZ) {
- if (write(fd, null_aligned, NULL_CONF_SZ) < 0)
- break;
- togo -= NULL_CONF_SZ;
- }
- if (write(fd, null_aligned, togo) < 0)
- break;
- }
- }
- if (i <= n_config)
- continue;
- d->disk.crc = calc_crc(&d->disk, 512);
- if (write(fd, &d->disk, 512) < 0)
- continue;
-
- /* Maybe do the same for secondary */
-
lseek64(fd, (size-1)*512, SEEK_SET);
if (write(fd, &ddf->anchor, 512) < 0)
continue;
--
1.7.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/3] DDF: use existing locations for primary and secondary DDF structure
2012-12-07 22:38 Fixes for DDF with LSI BIOS RAID mwilck
2012-12-07 22:38 ` [PATCH 1/3] DDF: cleanly save the secondary DDF structure mwilck
@ 2012-12-07 22:39 ` mwilck
2012-12-07 22:39 ` [PATCH 3/3] DDF: increase seq number when writing meta data mwilck
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: mwilck @ 2012-12-07 22:39 UTC (permalink / raw)
To: linux-raid; +Cc: mwilck
From: Martin Wilck <mwilck@arcor.de>
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.
---
super-ddf.c | 28 ++++++++++++++++++++++++----
1 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/super-ddf.c b/super-ddf.c
index c336db4..7fe038e 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 */
@@ -666,8 +669,16 @@ static int load_ddf_local(int fd, struct ddf_super *super,
dl->fd = keep ? fd : -1;
dl->size = 0;
- if (get_dev_size(fd, devname, &dsize))
+ 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 +2433,18 @@ 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);
--
1.7.1
^ permalink raw reply related [flat|nested] 6+ messages in thread