/src/util-linux/libblkid/src/superblocks/ddf_raid.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2008 Karel Zak <kzak@redhat.com> |
3 | | * |
4 | | * Inspired by libvolume_id by |
5 | | * Kay Sievers <kay.sievers@vrfy.org> |
6 | | * |
7 | | * This file may be redistributed under the terms of the |
8 | | * GNU Lesser General Public License. |
9 | | */ |
10 | | #include <stdio.h> |
11 | | #include <stdlib.h> |
12 | | #include <unistd.h> |
13 | | #include <string.h> |
14 | | #include <stdint.h> |
15 | | |
16 | | #include "crc32.h" |
17 | | #include "superblocks.h" |
18 | | |
19 | | /* http://www.snia.org/standards/home */ |
20 | | #define DDF_GUID_LENGTH 24 |
21 | | #define DDF_REV_LENGTH 8 |
22 | | #define DDF_MAGIC 0xDE11DE11 |
23 | | |
24 | | |
25 | | struct ddf_header { |
26 | | uint32_t signature; |
27 | | uint32_t crc; |
28 | | uint8_t guid[DDF_GUID_LENGTH]; |
29 | | char ddf_rev[8]; /* 01.02.00 */ |
30 | | uint32_t seq; /* starts at '1' */ |
31 | | uint32_t timestamp; |
32 | | uint8_t openflag; |
33 | | uint8_t foreignflag; |
34 | | uint8_t enforcegroups; |
35 | | uint8_t pad0; /* 0xff */ |
36 | | uint8_t pad1[12]; /* 12 * 0xff */ |
37 | | /* 64 bytes so far */ |
38 | | uint8_t header_ext[32]; /* reserved: fill with 0xff */ |
39 | | uint64_t primary_lba; |
40 | | uint64_t secondary_lba; |
41 | | uint8_t type; |
42 | | uint8_t pad2[3]; /* 0xff */ |
43 | | uint32_t workspace_len; /* sectors for vendor space - |
44 | | * at least 32768(sectors) */ |
45 | | uint64_t workspace_lba; |
46 | | uint16_t max_pd_entries; /* one of 15, 63, 255, 1023, 4095 */ |
47 | | uint16_t max_vd_entries; /* 2^(4,6,8,10,12)-1 : i.e. as above */ |
48 | | uint16_t max_partitions; /* i.e. max num of configuration |
49 | | record entries per disk */ |
50 | | uint16_t config_record_len; /* 1 +ROUNDUP(max_primary_element_entries |
51 | | *12/512) */ |
52 | | uint16_t max_primary_element_entries; /* 16, 64, 256, 1024, or 4096 */ |
53 | | uint8_t pad3[54]; /* 0xff */ |
54 | | /* 192 bytes so far */ |
55 | | uint32_t controller_section_offset; |
56 | | uint32_t controller_section_length; |
57 | | uint32_t phys_section_offset; |
58 | | uint32_t phys_section_length; |
59 | | uint32_t virt_section_offset; |
60 | | uint32_t virt_section_length; |
61 | | uint32_t config_section_offset; |
62 | | uint32_t config_section_length; |
63 | | uint32_t data_section_offset; |
64 | | uint32_t data_section_length; |
65 | | uint32_t bbm_section_offset; |
66 | | uint32_t bbm_section_length; |
67 | | uint32_t diag_space_offset; |
68 | | uint32_t diag_space_length; |
69 | | uint32_t vendor_offset; |
70 | | uint32_t vendor_length; |
71 | | /* 256 bytes so far */ |
72 | | uint8_t pad4[256]; /* 0xff */ |
73 | | } __attribute__((packed)); |
74 | | |
75 | | static int ddf_verify_csum(blkid_probe pr, const struct ddf_header *ddf) |
76 | 0 | { |
77 | 0 | uint32_t expected, crc; |
78 | |
|
79 | 0 | expected = be32_to_cpu(ddf->crc); |
80 | |
|
81 | 0 | crc = ul_crc32_exclude_offset(0, |
82 | 0 | (const unsigned char *)ddf, sizeof(*ddf), |
83 | 0 | offsetof(__typeof__(*ddf), crc), |
84 | 0 | sizeof_member(__typeof__(*ddf), crc), |
85 | 0 | 0xff); |
86 | |
|
87 | 0 | return blkid_probe_verify_csum(pr, crc, expected); |
88 | 0 | } |
89 | | |
90 | | static int probe_ddf(blkid_probe pr, |
91 | | const struct blkid_idmag *mag __attribute__((__unused__))) |
92 | 6.12k | { |
93 | 6.12k | int hdrs[] = { 1, 257 }; |
94 | 6.12k | size_t i; |
95 | 6.12k | const struct ddf_header *ddf = NULL; |
96 | 6.12k | char version[DDF_REV_LENGTH + 1]; |
97 | 6.12k | uint64_t off = 0, lba; |
98 | | |
99 | 18.3k | for (i = 0; i < ARRAY_SIZE(hdrs); i++) { |
100 | 12.2k | off = ((pr->size / 0x200) - hdrs[i]) * 0x200; |
101 | | |
102 | 12.2k | ddf = (const struct ddf_header *) blkid_probe_get_buffer(pr, |
103 | 12.2k | off, |
104 | 12.2k | sizeof(struct ddf_header)); |
105 | 12.2k | if (!ddf) |
106 | 0 | return errno ? -errno : 1; |
107 | 12.2k | if (ddf->signature == cpu_to_be32(DDF_MAGIC) && ddf_verify_csum(pr, ddf)) |
108 | 0 | break; |
109 | 12.2k | ddf = NULL; |
110 | 12.2k | } |
111 | | |
112 | 6.12k | if (!ddf) |
113 | 6.12k | return 1; |
114 | | |
115 | 0 | lba = be64_to_cpu(ddf->primary_lba); |
116 | |
|
117 | 0 | if (lba > 0) { |
118 | | /* check primary header */ |
119 | 0 | const unsigned char *buf; |
120 | |
|
121 | 0 | buf = blkid_probe_get_buffer(pr, |
122 | 0 | lba << 9, sizeof(ddf->signature)); |
123 | 0 | if (!buf) |
124 | 0 | return errno ? -errno : 1; |
125 | | |
126 | 0 | if (memcmp(buf, &ddf->signature, 4) != 0) |
127 | 0 | return 1; |
128 | 0 | } |
129 | | |
130 | 0 | blkid_probe_strncpy_uuid(pr, ddf->guid, sizeof(ddf->guid)); |
131 | |
|
132 | 0 | memcpy(version, ddf->ddf_rev, sizeof(ddf->ddf_rev)); |
133 | 0 | *(version + sizeof(ddf->ddf_rev)) = '\0'; |
134 | |
|
135 | 0 | if (blkid_probe_set_version(pr, version) != 0) |
136 | 0 | return 1; |
137 | 0 | if (blkid_probe_set_magic(pr, off, |
138 | 0 | sizeof(ddf->signature), |
139 | 0 | (const unsigned char *) &ddf->signature)) |
140 | 0 | return 1; |
141 | 0 | return 0; |
142 | 0 | } |
143 | | |
144 | | const struct blkid_idinfo ddfraid_idinfo = { |
145 | | .name = "ddf_raid_member", |
146 | | .usage = BLKID_USAGE_RAID, |
147 | | .minsz = 0x30000, |
148 | | .probefunc = probe_ddf, |
149 | | .magics = BLKID_NONE_MAGIC |
150 | | }; |
151 | | |
152 | | |