Date: Tue, 1 May 2012 18:00:31 +0000 (UTC) From: Alexander Motin <mav@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r234899 - head/sys/geom/raid Message-ID: <201205011800.q41I0VKA038185@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: mav Date: Tue May 1 18:00:31 2012 New Revision: 234899 URL: http://svn.freebsd.org/changeset/base/234899 Log: Improve spare disks support. Unluckily, for some reason Adaptec 1430SA RAID BIOS doesn't want to understand spare disks created by graid. But at least spares created by BIOS are working fine now. Modified: head/sys/geom/raid/md_ddf.c Modified: head/sys/geom/raid/md_ddf.c ============================================================================== --- head/sys/geom/raid/md_ddf.c Tue May 1 17:16:01 2012 (r234898) +++ head/sys/geom/raid/md_ddf.c Tue May 1 18:00:31 2012 (r234899) @@ -179,6 +179,10 @@ static struct g_raid_md_class g_raid_md_ (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 *met 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 *met 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, 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 * 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 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_d 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_d 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_d } /* 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_d 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 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 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_dis 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_dis 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_dis 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_objec 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_objec /* 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_obj 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_obj 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_obj 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_obj } } + /* 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_obj /* 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,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201205011800.q41I0VKA038185>