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

James Simshaw <[email protected]>
Newsgroups gmane.linux.ataraid
Message-ID <[email protected]>
Hello,

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

James Simshaw

_______________________________________________
Ataraid-list mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/ataraid-list
crc32.patch (text/x-patch, 5.6 KB)
--- ../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);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.