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
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include <stdint.h>
16
17 #include "superblocks.h"
18
19 #define JM_SIGNATURE "JM"
20 #define JM_MINOR_VERSION(_x) ((_x)->version & 0xFF)
21 #define JM_MAJOR_VERSION(_x) ((_x)->version >> 8)
22 #define JM_SPARES 2
23 #define JM_MEMBERS 8
24
25 struct jm_metadata {
26 int8_t signature[2]; /* 0x0 - 0x01 */
27
28 uint16_t version; /* 0x03 - 0x04 JMicron version */
29
30 uint16_t checksum; /* 0x04 - 0x05 */
31 uint8_t filler[10];
32
33 uint32_t identity; /* 0x10 - 0x13 */
34
35 struct {
36 uint32_t base; /* 0x14 - 0x17 */
37 uint32_t range; /* 0x18 - 0x1B range */
38 uint16_t range2; /* 0x1C - 0x1D range2 */
39 } segment;
40
41 int8_t name[16]; /* 0x20 - 0x2F */
42
43 uint8_t mode; /* 0x30 RAID level */
44 uint8_t block; /* 0x31 stride size (2=4K, 3=8K, ...) */
45 uint16_t attribute; /* 0x32 - 0x33 */
46 uint8_t filler1[4];
47
48 uint32_t spare[JM_SPARES]; /* 0x38 - 0x3F */
49 uint32_t member[JM_MEMBERS]; /* 0x40 - 0x5F */
50
51 uint8_t filler2[0x20];
52 } __attribute__ ((packed));
53
54 static void jm_to_cpu(struct jm_metadata *jm)
55 {
56 unsigned int i;
57
58 jm->version = le16_to_cpu(jm->version);
59 jm->checksum = le16_to_cpu(jm->checksum);
60 jm->identity = le32_to_cpu(jm->identity);
61 jm->segment.base = le32_to_cpu(jm->segment.base);
62 jm->segment.range = le32_to_cpu(jm->segment.range);
63 jm->segment.range2 = le16_to_cpu(jm->segment.range2);
64
65 jm->attribute = le16_to_cpu(jm->attribute);
66
67 for (i = 0; i < JM_SPARES; i++)
68 jm->spare[i] = le32_to_cpu(jm->spare[i]);
69
70 for (i = 0; i < JM_MEMBERS; i++)
71 jm->member[i] = le32_to_cpu(jm->member[i]);
72 }
73
74 static int jm_checksum(const struct jm_metadata *jm)
75 {
76 size_t count = sizeof(*jm) / sizeof(uint16_t);
77 uint16_t sum = 0;
78 unsigned char *ptr = (unsigned char *) jm;
79
80 while (count--) {
81 uint16_t val;
82
83 memcpy(&val, ptr, sizeof(uint16_t));
84 sum += le16_to_cpu(val);
85
86 ptr += sizeof(uint16_t);
87 }
88
89 return sum == 0 || sum == 1;
90 }
91
92 static int probe_jmraid(blkid_probe pr,
93 const struct blkid_idmag *mag __attribute__((__unused__)))
94 {
95 uint64_t off;
96 struct jm_metadata *jm;
97
98 if (pr->size < 0x10000)
99 return 1;
100 if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
101 return 1;
102
103 off = ((pr->size / 0x200) - 1) * 0x200;
104 jm = (struct jm_metadata *)
105 blkid_probe_get_buffer(pr,
106 off,
107 sizeof(struct jm_metadata));
108 if (!jm)
109 return errno ? -errno : 1;
110
111 if (memcmp(jm->signature, JM_SIGNATURE, sizeof(JM_SIGNATURE) - 1) != 0)
112 return 1;
113
114 if (!jm_checksum(jm))
115 return 1;
116
117 jm_to_cpu(jm);
118
119 if (jm->mode > 5)
120 return 1;
121
122 if (blkid_probe_sprintf_version(pr, "%u.%u",
123 JM_MAJOR_VERSION(jm), JM_MINOR_VERSION(jm)) != 0)
124 return 1;
125 if (blkid_probe_set_magic(pr, off, sizeof(jm->signature),
126 (unsigned char *) jm->signature))
127 return 1;
128 return 0;
129 }
130
131 const struct blkid_idinfo jmraid_idinfo = {
132 .name = "jmicron_raid_member",
133 .usage = BLKID_USAGE_RAID,
134 .probefunc = probe_jmraid,
135 .magics = BLKID_NONE_MAGIC
136 };