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);
_______________________________________________
Ataraid-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/ataraid-list