summaryrefslogtreecommitdiffstats
path: root/libblkid/src/superblocks/ddf_raid.c
blob: fc2c39d3e597f4302f22c968f274b4e4c4dec1ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 * 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
};