svn commit: r234899 - head/sys/geom/raid

Alexander Motin mav at FreeBSD.org
Tue May 1 18:00:32 UTC 2012


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,


More information about the svn-src-all mailing list