[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Part 2 of 2: Patch to add crc32 support to the ddf1 metadata handler



Hello,

This patch adds crc32 checks for Adaptec cards following the ddf1 specifications.

James Simshaw
--- ../ORIGINAL/lib/format/ataraid/ddf1.c	2006-07-10 09:22:09.000000000 -0700
+++ lib/format/ataraid/ddf1.c	2006-07-24 12:35:34.000000000 -0700
@@ -6,6 +6,7 @@
  * See file LICENSE at the top of this source tree for license information.
  */
 
+#include <zlib.h>
 #include <errno.h>
 #include <netinet/in.h>
 
@@ -123,6 +124,185 @@ static enum status disk_status(struct dd
 	return s_undef;
 }
 
+/* Compute the checksum of a table */
+static uint32_t compute_crc32(void *buf, uint32_t *csum_field, uint32_t len)
+{
+	uint32_t x;
+	uint32_t old_csum;
+
+	old_csum = *csum_field;
+	*csum_field = 0xFFFFFFFF;
+	x = crc32(0, NULL, 0);
+	x = crc32(x, buf, len);
+	*csum_field = old_csum;
+
+	return x;
+}
+
+/* Process the configuration records to have their CRCs updated */
+static int update_cfg_crc(struct ddf1 *ddf1)
+{
+	uint32_t x, crc;
+	int i;
+
+	for (i = 0; i < NUM_CONFIG_ENTRIES(ddf1); i++) {
+		x = *((uint32_t *)CR(ddf1, i));
+		if (BYTE_ORDER != ddf1->disk_format)
+			CVT32(x);
+
+		switch (x) {
+			case DDF1_VD_CONFIG_REC:
+				crc=compute_crc32(CR(ddf1, i), &(CR(ddf1,i)->crc), 
+					      ddf1->primary->vd_config_record_len * 
+					      DDF1_BLKSIZE);
+				CR(ddf1,i)->crc = crc;
+				break;
+
+			case DDF1_SPARE_REC:
+				crc=compute_crc32(SR(ddf1, i), &(SR(ddf1,i)->crc), 
+					      ddf1->primary->vd_config_record_len * 
+					      DDF1_BLKSIZE);
+				SR(ddf1,i)->crc = crc;
+				break;
+
+			case 0: /* Adaptec puts zero in this field??? */
+			case DDF1_INVALID:
+				break;
+
+			default:
+				printf("Unknown config record %d.", x);
+		}
+	}
+}
+
+/* Processes all of the DDF1 information for having their CRCs updated*/
+static void update_crcs(struct ddf1 *ddf1)
+{
+	uint32_t crc32;
+ 
+	crc32 = compute_crc32(ddf1->primary, &ddf1->primary->crc, 
+			      sizeof(struct ddf1_header));
+	ddf1->primary->crc = crc32;
+
+	if (ddf1->secondary != NULL) {
+		crc32 = compute_crc32(ddf1->secondary, &ddf1->secondary->crc, 
+				      sizeof(struct ddf1_header));
+		ddf1->secondary->crc = crc32;
+	}
+
+	crc32 = compute_crc32(ddf1->adapter, &ddf1->adapter->crc, 
+			      ddf1->primary->adapter_data_len *
+			      DDF1_BLKSIZE);
+	ddf1->adapter->crc = crc32;
+
+	crc32 = compute_crc32(ddf1->disk_data, &ddf1->disk_data->crc, 
+			      ddf1->primary->disk_data_len *
+			      DDF1_BLKSIZE);
+	ddf1->disk_data->crc = crc32;
+
+	crc32 = compute_crc32(ddf1->pd_header, &ddf1->pd_header->crc, 
+			      ddf1->primary->phys_drive_len * 
+			      DDF1_BLKSIZE);
+	ddf1->pd_header->crc = crc32;
+
+	crc32 = compute_crc32(ddf1->vd_header, &ddf1->vd_header->crc, 
+			      ddf1->primary->virt_drive_len * 
+			      DDF1_BLKSIZE);
+	ddf1->vd_header->crc = crc32;
+
+	update_cfg_crc(ddf1);
+
+}
+
+/* Checks the CRC for a particular table */
+static int check_crc(void *buf, uint32_t *crc, int length, char *check)
+{
+	uint32_t crc32;
+
+	crc32 = compute_crc32(buf, crc, length);
+	if (*crc != crc32) {
+		LOG_ERR(NULL, "Check failed for %s with a crc of %X instead of %X\n",
+			check, crc32, *crc);
+		return 0;
+	} 
+	
+	return 1;
+
+}
+
+/* Process the configuration records to have their CRCs checked */
+static int check_cfg_crc(struct ddf1 *ddf1)
+{
+	uint32_t x;
+	int i;
+
+	for (i = 0; i < NUM_CONFIG_ENTRIES(ddf1); i++) {
+		x = *((uint32_t *)CR(ddf1, i));
+		if (BYTE_ORDER != ddf1->disk_format)
+			CVT32(x);
+
+		switch (x) {
+			case DDF1_VD_CONFIG_REC:
+				if (!(check_crc(CR(ddf1, i), &(CR(ddf1,i)->crc), 
+					        ddf1->primary->vd_config_record_len * 
+						DDF1_BLKSIZE, "VD CFG")))
+					return 0;
+				break;
+
+			case DDF1_SPARE_REC:
+				if (!(check_crc(SR(ddf1, i), &(SR(ddf1,i)->crc), 
+					        ddf1->primary->vd_config_record_len * 
+					        DDF1_BLKSIZE, "Spare CFG")))
+					return 0;
+				break;
+
+			case 0: /* Adaptec puts zero in this field??? */
+			case DDF1_INVALID:
+				break;
+
+			default:
+				printf("Unknown config record %d.", x);
+		}
+	}	
+	return 1;
+}
+
+/* Processes the tables to check their CRCs */
+static int check_all_crcs(struct ddf1 *ddf1)
+{
+	int chk_p, chk_s, chk_a, chk_d, chk_pd, chk_vd, chk_cfg;
+
+	chk_p = check_crc(ddf1->primary, &ddf1->primary->crc, 
+			  sizeof(struct ddf1_header), "Primary Header");
+
+	if (ddf1->secondary != NULL)
+		chk_s = check_crc(ddf1->secondary, &ddf1->secondary->crc, 
+			    	  sizeof(struct ddf1_header), 
+				  "Secondary Header");
+	else
+		chk_s = 1;
+
+	chk_a = check_crc(ddf1->adapter, &ddf1->adapter->crc, 
+			  ddf1->primary->adapter_data_len *
+			  DDF1_BLKSIZE, "Adapter");
+	
+	chk_d = check_crc(ddf1->disk_data, &ddf1->disk_data->crc, 
+			  ddf1->primary->disk_data_len *
+			  DDF1_BLKSIZE, "Disk Data");
+
+	chk_pd = check_crc(ddf1->pd_header, &ddf1->pd_header->crc, 
+			   ddf1->primary->phys_drive_len * 
+			   DDF1_BLKSIZE, "Phys Drives");
+
+	chk_vd = check_crc(ddf1->vd_header, &ddf1->vd_header->crc, 
+			   ddf1->primary->virt_drive_len * 
+			   DDF1_BLKSIZE, "Virt Drives");
+
+	chk_cfg = check_cfg_crc(ddf1);
+
+	return chk_p && chk_s && chk_a && chk_d && chk_pd && chk_vd && chk_cfg;
+}
+
 /* Find the physical drive data for a drive */
 static struct ddf1_phys_drive *get_phys_drive(struct ddf1 *ddf1, uint32_t ref)
 {
@@ -858,6 +1038,13 @@ static int read_extended(struct lib_cont
 	 */
 	ddf1->in_cpu_format = 1;
 
+	if (ddf1->adaptec_mode) {
+		if (!(check_all_crcs(ddf1))) {
+			printf("CRC Check Failed\n");
+			goto bad;
+		}
+	}
+
 	return 1;
 
 bad:
@@ -1264,6 +1451,9 @@ static int ddf1_write(struct lib_context
 	int ret;
         struct ddf1 *ddf1 = META(rd, ddf1);
 
+	if (ddf1->adaptec_mode)
+		update_crcs(ddf1);
+
         cvt_all(ddf1);
         ret = write_metadata(lc, handler, rd, -1, erase);
         cvt_all(ddf1);

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]