| /* |
| * Copyright (C) 2008 Karel Zak <kzak@redhat.com> |
| * |
| * Inspired by libvolume_id by |
| * Kay Sievers <kay.sievers@vrfy.org> |
| * |
| * This file may be redistributed under the terms of the |
| * GNU Lesser General Public License. |
| */ |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <stdint.h> |
| |
| #include "superblocks.h" |
| |
| /* http://www.snia.org/standards/home */ |
| #define DDF_GUID_LENGTH 24 |
| #define DDF_REV_LENGTH 8 |
| #define DDF_MAGIC 0xDE11DE11 |
| |
| |
| struct ddf_header { |
| uint32_t signature; |
| uint32_t crc; |
| uint8_t guid[DDF_GUID_LENGTH]; |
| char ddf_rev[8]; /* 01.02.00 */ |
| uint32_t seq; /* starts at '1' */ |
| uint32_t timestamp; |
| uint8_t openflag; |
| uint8_t foreignflag; |
| uint8_t enforcegroups; |
| uint8_t pad0; /* 0xff */ |
| uint8_t pad1[12]; /* 12 * 0xff */ |
| /* 64 bytes so far */ |
| uint8_t header_ext[32]; /* reserved: fill with 0xff */ |
| uint64_t primary_lba; |
| uint64_t secondary_lba; |
| uint8_t type; |
| uint8_t pad2[3]; /* 0xff */ |
| uint32_t workspace_len; /* sectors for vendor space - |
| * at least 32768(sectors) */ |
| uint64_t workspace_lba; |
| uint16_t max_pd_entries; /* one of 15, 63, 255, 1023, 4095 */ |
| uint16_t max_vd_entries; /* 2^(4,6,8,10,12)-1 : i.e. as above */ |
| uint16_t max_partitions; /* i.e. max num of configuration |
| record entries per disk */ |
| uint16_t config_record_len; /* 1 +ROUNDUP(max_primary_element_entries |
| *12/512) */ |
| uint16_t max_primary_element_entries; /* 16, 64, 256, 1024, or 4096 */ |
| uint8_t pad3[54]; /* 0xff */ |
| /* 192 bytes so far */ |
| uint32_t controller_section_offset; |
| uint32_t controller_section_length; |
| uint32_t phys_section_offset; |
| uint32_t phys_section_length; |
| uint32_t virt_section_offset; |
| uint32_t virt_section_length; |
| uint32_t config_section_offset; |
| uint32_t config_section_length; |
| uint32_t data_section_offset; |
| uint32_t data_section_length; |
| uint32_t bbm_section_offset; |
| uint32_t bbm_section_length; |
| uint32_t diag_space_offset; |
| uint32_t diag_space_length; |
| uint32_t vendor_offset; |
| uint32_t vendor_length; |
| /* 256 bytes so far */ |
| uint8_t pad4[256]; /* 0xff */ |
| } __attribute__((packed)); |
| |
| static int probe_ddf(blkid_probe pr, |
| const struct blkid_idmag *mag __attribute__((__unused__))) |
| { |
| int hdrs[] = { 1, 257 }; |
| size_t i; |
| struct ddf_header *ddf = NULL; |
| char version[DDF_REV_LENGTH + 1]; |
| uint64_t off, lba; |
| |
| if (pr->size < 0x30000) |
| return 1; |
| |
| for (i = 0; i < ARRAY_SIZE(hdrs); i++) { |
| off = ((pr->size / 0x200) - hdrs[i]) * 0x200; |
| |
| ddf = (struct ddf_header *) blkid_probe_get_buffer(pr, |
| off, |
| sizeof(struct ddf_header)); |
| if (!ddf) |
| return errno ? -errno : 1; |
| if (ddf->signature == cpu_to_be32(DDF_MAGIC) || |
| ddf->signature == cpu_to_le32(DDF_MAGIC)) |
| break; |
| ddf = NULL; |
| } |
| |
| if (!ddf) |
| return 1; |
| |
| lba = ddf->signature == cpu_to_be32(DDF_MAGIC) ? |
| be64_to_cpu(ddf->primary_lba) : |
| le64_to_cpu(ddf->primary_lba); |
| |
| if (lba > 0) { |
| /* check primary header */ |
| unsigned char *buf; |
| |
| buf = blkid_probe_get_buffer(pr, |
| lba << 9, sizeof(ddf->signature)); |
| if (!buf) |
| return errno ? -errno : 1; |
| |
| if (memcmp(buf, &ddf->signature, 4) != 0) |
| return 1; |
| } |
| |
| blkid_probe_strncpy_uuid(pr, ddf->guid, sizeof(ddf->guid)); |
| |
| memcpy(version, ddf->ddf_rev, sizeof(ddf->ddf_rev)); |
| *(version + sizeof(ddf->ddf_rev)) = '\0'; |
| |
| if (blkid_probe_set_version(pr, version) != 0) |
| return 1; |
| if (blkid_probe_set_magic(pr, off, |
| sizeof(ddf->signature), |
| (unsigned char *) &ddf->signature)) |
| return 1; |
| return 0; |
| } |
| |
| const struct blkid_idinfo ddfraid_idinfo = { |
| .name = "ddf_raid_member", |
| .usage = BLKID_USAGE_RAID, |
| .probefunc = probe_ddf, |
| .magics = BLKID_NONE_MAGIC |
| }; |
| |
| |