diff options
-rw-r--r-- | sys/geom/raid/md_ddf.c | 202 |
1 files changed, 134 insertions, 68 deletions
diff --git a/sys/geom/raid/md_ddf.c b/sys/geom/raid/md_ddf.c index dd80172..08d6f4b 100644 --- a/sys/geom/raid/md_ddf.c +++ b/sys/geom/raid/md_ddf.c @@ -179,6 +179,10 @@ static struct g_raid_md_class g_raid_md_ddf_class = { (n) * GET16((m), hdr->Configuration_Record_Length) * \ (m)->sectorsize)) +#define GETSAPTR(m, n) ((struct ddf_sa_record *)((uint8_t *)(m)->cr + \ + (n) * GET16((m), hdr->Configuration_Record_Length) * \ + (m)->sectorsize)) + static int isff(uint8_t *buf, int size) { @@ -294,8 +298,8 @@ g_raid_md_ddf_print(struct ddf_meta *meta) printf("\n"); printf("VD_Number 0x%04x\n", GET16(meta, vdr->entry[j].VD_Number)); - printf("VD_Type 0x%02x\n", - GET8(meta, vdr->entry[j].VD_Type)); + printf("VD_Type 0x%04x\n", + GET16(meta, vdr->entry[j].VD_Type)); printf("VD_State 0x%02x\n", GET8(meta, vdr->entry[j].VD_State)); printf("Init_State 0x%02x\n", @@ -396,6 +400,7 @@ g_raid_md_ddf_print(struct ddf_meta *meta) GET16D(meta, sa->entry[i].Secondary_Element)); } break; + case 0x00000000: case 0xFFFFFFFF: break; default: @@ -476,7 +481,8 @@ ddf_meta_find_vdc(struct ddf_meta *meta, uint8_t *GUID) memcmp(vdc->VD_GUID, GUID, 24) == 0) return (vdc); } else - if (GET32D(meta, vdc->Signature) == 0xffffffff) + if (GET32D(meta, vdc->Signature) == 0xffffffff || + GET32D(meta, vdc->Signature) == 0) return (vdc); } return (NULL); @@ -527,6 +533,29 @@ ddf_meta_find_disk(struct ddf_vol_meta *vmeta, uint32_t PD_Reference, return (-1); } +static struct ddf_sa_record * +ddf_meta_find_sa(struct ddf_meta *meta, int create) +{ + struct ddf_sa_record *sa; + int i, num; + + num = GETCRNUM(meta); + for (i = 0; i < num; i++) { + sa = GETSAPTR(meta, i); + if (GET32D(meta, sa->Signature) == DDF_SA_SIGNATURE) + return (sa); + } + if (create) { + for (i = 0; i < num; i++) { + sa = GETSAPTR(meta, i); + if (GET32D(meta, sa->Signature) == 0xffffffff || + GET32D(meta, sa->Signature) == 0) + return (sa); + } + } + return (NULL); +} + static void ddf_meta_create(struct g_raid_disk *disk, struct ddf_meta *sample) { @@ -643,9 +672,9 @@ ddf_meta_create(struct g_raid_disk *disk, struct ddf_meta *sample) pos += GET32(meta, hdr->Diagnostic_Space_Length); SET32(meta, hdr->Vendor_Specific_Logs, GET32(meta, hdr->Vendor_Specific_Logs_Length) != 0 ? pos : 0xffffffff); - pos += GET32(meta, hdr->Vendor_Specific_Logs_Length); + pos += min(GET32(meta, hdr->Vendor_Specific_Logs_Length), 1); SET64(meta, hdr->Primary_Header_LBA, - anchorlba - pos - 16); + anchorlba - pos); SET64(meta, hdr->Secondary_Header_LBA, 0xffffffffffffffffULL); SET64(meta, hdr->WorkSpace_LBA, @@ -1318,29 +1347,6 @@ ddf_meta_erase(struct g_consumer *cp) return (error); } -#if 0 -static int -ddf_meta_write_spare(struct g_consumer *cp) -{ - struct ddf_header *meta; - int error; - - meta = malloc(sizeof(*meta), M_MD_DDF, M_WAITOK | M_ZERO); - memcpy(&meta->ddf_id[0], DDF_MAGIC, sizeof(DDF_MAGIC) - 1); - meta->dummy_0 = 0x00020000; - meta->integrity = DDF_I_VALID; - meta->disk.flags = DDF_F_SPARE | DDF_F_ONLINE | DDF_F_VALID; - meta->disk.number = 0xff; - arc4rand(&meta->disk.id, sizeof(meta->disk.id), 0); - meta->disk_sectors = cp->provider->mediasize / cp->provider->sectorsize; - meta->disk_sectors -= 131072; - meta->rebuild_lba = UINT32_MAX; - error = ddf_meta_write(cp, &meta, 1); - free(meta, M_MD_DDF); - return (error); -} -#endif - static struct g_raid_volume * g_raid_md_ddf_get_volume(struct g_raid_softc *sc, uint8_t *GUID) { @@ -1574,6 +1580,7 @@ g_raid_md_ddf_start_disk(struct g_raid_disk *disk, struct g_raid_volume *vol) struct ddf_vol_meta *vmeta; struct ddf_meta *pdmeta, *gmeta; struct ddf_vdc_record *vdc1; + struct ddf_sa_record *sa; off_t size, eoff = 0, esize = 0; uint64_t *val2; int disk_pos, md_disk_bvd = -1, md_disk_pos = -1, md_pde_pos; @@ -1596,7 +1603,8 @@ g_raid_md_ddf_start_disk(struct g_raid_disk *disk, struct g_raid_volume *vol) md_pde_pos = ddf_meta_find_pd(gmeta, NULL, reference); if (disk_pos < 0) { - G_RAID_DEBUG1(1, sc, "Disk %s is not part of the volume %s", + G_RAID_DEBUG1(1, sc, + "Disk %s is not a present part of the volume %s", g_raid_get_diskname(disk), vol->v_name); /* Failed stale disk is useless for us. */ @@ -1606,10 +1614,8 @@ g_raid_md_ddf_start_disk(struct g_raid_disk *disk, struct g_raid_volume *vol) } /* If disk has some metadata for this volume - erase. */ - if (pdmeta->cr != NULL && - (vdc1 = ddf_meta_find_vdc(pdmeta, vmeta->vdc->VD_GUID)) != NULL) { + if ((vdc1 = ddf_meta_find_vdc(pdmeta, vmeta->vdc->VD_GUID)) != NULL) SET32D(pdmeta, vdc1->Signature, 0xffffffff); - } /* If we are in the start process, that's all for now. */ if (!pv->pv_started) @@ -1656,12 +1662,28 @@ g_raid_md_ddf_start_disk(struct g_raid_disk *disk, struct g_raid_volume *vol) md_disk_pos = disk_pos % GET16(vmeta, vdc->Primary_Element_Count); // XXX } else { nofit: - if (ddf_meta_count_vdc(&pd->pd_meta, NULL) == 0) { + if (disk->d_state == G_RAID_DISK_S_NONE) g_raid_change_disk_state(disk, - G_RAID_DISK_S_SPARE); - } + G_RAID_DISK_S_STALE); return (0); } + + /* + * If spare is committable, delete spare record. + * Othersize, mark it active and leave there. + */ + sa = ddf_meta_find_sa(&pd->pd_meta, 0); + if (sa != NULL) { + if ((GET8D(&pd->pd_meta, sa->Spare_Type) & + DDF_SAR_TYPE_REVERTIBLE) == 0) { + SET32D(&pd->pd_meta, sa->Signature, 0xffffffff); + } else { + SET8D(&pd->pd_meta, sa->Spare_Type, + GET8D(&pd->pd_meta, sa->Spare_Type) | + DDF_SAR_TYPE_ACTIVE); + } + } + G_RAID_DEBUG1(1, sc, "Disk %s takes pos %d in the volume %s", g_raid_get_diskname(disk), disk_pos, vol->v_name); resurrection = 1; @@ -1798,6 +1820,7 @@ g_raid_md_ddf_start(struct g_raid_volume *vol) struct g_raid_subdisk *sd; struct g_raid_disk *disk; struct g_raid_md_object *md; + struct g_raid_md_ddf_perdisk *pd; struct g_raid_md_ddf_pervolume *pv; struct g_raid_md_ddf_object *mdi; struct ddf_vol_meta *vmeta; @@ -1846,16 +1869,9 @@ g_raid_md_ddf_start(struct g_raid_volume *vol) g_raid_start_volume(vol); /* Make all disks found till the moment take their places. */ - for (i = 0, j = 0, bvd = 0; i < vol->v_disks_count; i++, j++) { - if (j == GET16(vmeta, vdc->Primary_Element_Count)) { - j = 0; - bvd++; - } - if (vmeta->bvdc[bvd] == NULL) - continue; - disk = g_raid_md_ddf_get_disk(sc, NULL, - GET32(vmeta, bvdc[bvd]->Physical_Disk_Sequence[j])); - if (disk != NULL) + TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { + pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data; + if (ddf_meta_find_vdc(&pd->pd_meta, vmeta->vdc->VD_GUID) != NULL) g_raid_md_ddf_start_disk(disk, vol); } @@ -1901,7 +1917,7 @@ g_raid_md_ddf_new_disk(struct g_raid_disk *disk) struct ddf_vol_meta *vmeta; struct ddf_vdc_record *vdc; struct ddf_vd_entry *vde; - int i, j, k, num, have, need, needthis, cnt, spare; + int i, j, k, num, have, need, cnt, spare; uint32_t val; char buf[17]; @@ -1963,9 +1979,17 @@ g_raid_md_ddf_new_disk(struct g_raid_disk *disk) pv = vol->v_md_data; vmeta = &pv->pv_meta; + if (ddf_meta_find_vdc(pdmeta, vmeta->vdc->VD_GUID) == NULL) + continue; + + if (pv->pv_started) { + if (g_raid_md_ddf_start_disk(disk, vol)) + g_raid_md_write_ddf(md, vol, NULL, NULL); + continue; + } + /* If we collected all needed disks - start array. */ need = 0; - needthis = 0; have = 0; for (k = 0; k < GET8(vmeta, vdc->Secondary_Element_Count); k++) { if (vmeta->bvdc[k] == NULL) { @@ -1976,23 +2000,14 @@ g_raid_md_ddf_new_disk(struct g_raid_disk *disk) need += cnt; for (i = 0; i < cnt; i++) { val = GET32(vmeta, bvdc[k]->Physical_Disk_Sequence[i]); - if (GET32(pdmeta, pdd->PD_Reference) == val) - needthis++; - else if (g_raid_md_ddf_get_disk(sc, NULL, val) != NULL) + if (g_raid_md_ddf_get_disk(sc, NULL, val) != NULL) have++; } } - if (!needthis) - continue; - if (pv->pv_started) { - if (g_raid_md_ddf_start_disk(disk, vol)) - g_raid_md_write_ddf(md, vol, NULL, NULL); - } else { - G_RAID_DEBUG1(1, sc, "Volume %s now has %d of %d disks", - vol->v_name, have + needthis, need); - if (have + needthis == need) - g_raid_md_ddf_start(vol); - } + G_RAID_DEBUG1(1, sc, "Volume %s now has %d of %d disks", + vol->v_name, have, need); + if (have == need) + g_raid_md_ddf_start(vol); } } @@ -2173,6 +2188,7 @@ g_raid_md_ctl_ddf(struct g_raid_md_object *md, struct g_raid_md_ddf_perdisk *pd; struct g_raid_md_ddf_pervolume *pv; struct g_raid_md_ddf_object *mdi; + struct ddf_sa_record *sa; struct g_consumer *cp; struct g_provider *pp; char arg[16]; @@ -2610,11 +2626,23 @@ g_raid_md_ctl_ddf(struct g_raid_md_object *md, /* Welcome the "new" disk. */ g_raid_change_disk_state(disk, G_RAID_DISK_S_SPARE); ddf_meta_create(disk, &mdi->mdio_meta); + sa = ddf_meta_find_sa(&pd->pd_meta, 1); + if (sa != NULL) { + SET32D(&pd->pd_meta, sa->Signature, + DDF_SA_SIGNATURE); + SET8D(&pd->pd_meta, sa->Spare_Type, 0); + SET16D(&pd->pd_meta, sa->Populated_SAEs, 0); + SET16D(&pd->pd_meta, sa->MAX_SAE_Supported, + (GET16(&pd->pd_meta, hdr->Configuration_Record_Length) * + pd->pd_meta.sectorsize - + sizeof(struct ddf_sa_record)) / + sizeof(struct ddf_sa_entry)); + } if (mdi->mdio_meta.hdr == NULL) ddf_meta_copy(&mdi->mdio_meta, &pd->pd_meta); else ddf_meta_update(&mdi->mdio_meta, &pd->pd_meta); -// ddf_meta_write_spare(cp); + g_raid_md_write_ddf(md, NULL, NULL, NULL); g_raid_md_ddf_refill(sc); } return (error); @@ -2636,6 +2664,7 @@ g_raid_md_write_ddf(struct g_raid_md_object *md, struct g_raid_volume *tvol, struct ddf_meta *gmeta; struct ddf_vol_meta *vmeta; struct ddf_vdc_record *vdc; + struct ddf_sa_record *sa; uint64_t *val2; int i, j, pos, bvd, size; @@ -2657,7 +2686,8 @@ g_raid_md_write_ddf(struct g_raid_md_object *md, struct g_raid_volume *tvol, continue; SET16(gmeta, pdr->entry[i].PD_Type, GET16(gmeta, pdr->entry[i].PD_Type) & - ~DDF_PDE_PARTICIPATING); + ~(DDF_PDE_PARTICIPATING | + DDF_PDE_GLOBAL_SPARE | DDF_PDE_CONFIG_SPARE)); if ((GET16(gmeta, pdr->entry[i].PD_State) & DDF_PDE_PFA) == 0) SET16(gmeta, pdr->entry[i].PD_State, 0); @@ -2759,15 +2789,15 @@ g_raid_md_write_ddf(struct g_raid_md_object *md, struct g_raid_volume *tvol, if (sd->sd_state == G_RAID_SUBDISK_S_NONE) SET32(gmeta, pdr->entry[j].PD_State, GET32(gmeta, pdr->entry[j].PD_State) | - DDF_PDE_FAILED | DDF_PDE_MISSING); + (DDF_PDE_FAILED | DDF_PDE_MISSING)); else if (sd->sd_state == G_RAID_SUBDISK_S_FAILED) SET32(gmeta, pdr->entry[j].PD_State, GET32(gmeta, pdr->entry[j].PD_State) | - DDF_PDE_FAILED | DDF_PDE_PFA); + (DDF_PDE_FAILED | DDF_PDE_PFA)); else if (sd->sd_state <= G_RAID_SUBDISK_S_REBUILD) SET32(gmeta, pdr->entry[j].PD_State, GET32(gmeta, pdr->entry[j].PD_State) | - DDF_PDE_FAILED); + DDF_PDE_REBUILD); else SET32(gmeta, pdr->entry[j].PD_State, GET32(gmeta, pdr->entry[j].PD_State) | @@ -2775,11 +2805,46 @@ g_raid_md_write_ddf(struct g_raid_md_object *md, struct g_raid_volume *tvol, } } + /* Mark spare and failed disks as such. */ + TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { + pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data; + i = ddf_meta_find_pd(gmeta, NULL, + GET32(&pd->pd_meta, pdd->PD_Reference)); + if (i < 0) + continue; + if (disk->d_state == G_RAID_DISK_S_FAILED) { + SET32(gmeta, pdr->entry[i].PD_State, + GET32(gmeta, pdr->entry[i].PD_State) | + (DDF_PDE_FAILED | DDF_PDE_PFA)); + } + if (disk->d_state != G_RAID_DISK_S_SPARE) + continue; + sa = ddf_meta_find_sa(&pd->pd_meta, 0); + if (sa == NULL || + (GET8D(&pd->pd_meta, sa->Spare_Type) & + DDF_SAR_TYPE_DEDICATED) == 0) { + SET16(gmeta, pdr->entry[i].PD_Type, + GET16(gmeta, pdr->entry[i].PD_Type) | + DDF_PDE_GLOBAL_SPARE); + } else { + SET16(gmeta, pdr->entry[i].PD_Type, + GET16(gmeta, pdr->entry[i].PD_Type) | + DDF_PDE_CONFIG_SPARE); + } + SET32(gmeta, pdr->entry[i].PD_State, + GET32(gmeta, pdr->entry[i].PD_State) | + DDF_PDE_ONLINE); + } + /* Remove disks without "participating" flag (unused). */ for (i = 0, j = -1; i < GET16(gmeta, pdr->Populated_PDEs); i++) { if (isff(gmeta->pdr->entry[i].PD_GUID, 24)) continue; - if (GET16(gmeta, pdr->entry[i].PD_Type) & DDF_PDE_PARTICIPATING) + if ((GET16(gmeta, pdr->entry[i].PD_Type) & + (DDF_PDE_PARTICIPATING | + DDF_PDE_GLOBAL_SPARE | DDF_PDE_CONFIG_SPARE)) != 0 || + g_raid_md_ddf_get_disk(sc, + NULL, GET32(gmeta, pdr->entry[i].PD_Reference)) != NULL) j = i; else memset(&gmeta->pdr->entry[i], 0xff, @@ -2790,7 +2855,8 @@ g_raid_md_write_ddf(struct g_raid_md_object *md, struct g_raid_volume *tvol, /* Update per-disk metadata and write them. */ TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data; - if (disk->d_state != G_RAID_DISK_S_ACTIVE) + if (disk->d_state != G_RAID_DISK_S_ACTIVE && + disk->d_state != G_RAID_DISK_S_SPARE) continue; /* Update PDR. */ memcpy(pd->pd_meta.pdr, gmeta->pdr, |