1133808Spjd/*-
2156878Spjd * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3133808Spjd * All rights reserved.
4133808Spjd *
5133808Spjd * Redistribution and use in source and binary forms, with or without
6133808Spjd * modification, are permitted provided that the following conditions
7133808Spjd * are met:
8133808Spjd * 1. Redistributions of source code must retain the above copyright
9133808Spjd *    notice, this list of conditions and the following disclaimer.
10133808Spjd * 2. Redistributions in binary form must reproduce the above copyright
11133808Spjd *    notice, this list of conditions and the following disclaimer in the
12133808Spjd *    documentation and/or other materials provided with the distribution.
13155174Spjd *
14133808Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15133808Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16133808Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17133808Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18133808Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19133808Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20133808Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21133808Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22133808Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23133808Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24133808Spjd * SUCH DAMAGE.
25133808Spjd *
26133808Spjd * $FreeBSD$
27133808Spjd */
28133808Spjd
29133808Spjd#ifndef	_G_RAID3_H_
30133808Spjd#define	_G_RAID3_H_
31133808Spjd
32133808Spjd#include <sys/endian.h>
33133808Spjd#include <sys/md5.h>
34133808Spjd
35133808Spjd#define	G_RAID3_CLASS_NAME	"RAID3"
36133808Spjd
37133808Spjd#define	G_RAID3_MAGIC		"GEOM::RAID3"
38134136Spjd/*
39134136Spjd * Version history:
40134136Spjd * 0 - Initial version number.
41134136Spjd * 1 - Added 'round-robin reading' algorithm.
42134168Spjd * 2 - Added 'verify reading' algorithm.
43139295Spjd * 3 - Added md_genid field to metadata.
44142727Spjd * 4 - Added md_provsize field to metadata.
45163888Spjd * 5 - Added 'no failure synchronization' flag.
46134136Spjd */
47163888Spjd#define	G_RAID3_VERSION		5
48133808Spjd
49133808Spjd#define	G_RAID3_DISK_FLAG_DIRTY		0x0000000000000001ULL
50133808Spjd#define	G_RAID3_DISK_FLAG_SYNCHRONIZING	0x0000000000000002ULL
51133808Spjd#define	G_RAID3_DISK_FLAG_FORCE_SYNC	0x0000000000000004ULL
52133808Spjd#define	G_RAID3_DISK_FLAG_HARDCODED	0x0000000000000008ULL
53155546Spjd#define	G_RAID3_DISK_FLAG_BROKEN	0x0000000000000010ULL
54133808Spjd#define	G_RAID3_DISK_FLAG_MASK		(G_RAID3_DISK_FLAG_DIRTY |	\
55133808Spjd					 G_RAID3_DISK_FLAG_SYNCHRONIZING | \
56133808Spjd					 G_RAID3_DISK_FLAG_FORCE_SYNC)
57133808Spjd
58133808Spjd#define	G_RAID3_DEVICE_FLAG_NOAUTOSYNC	0x0000000000000001ULL
59134124Spjd#define	G_RAID3_DEVICE_FLAG_ROUND_ROBIN	0x0000000000000002ULL
60134168Spjd#define	G_RAID3_DEVICE_FLAG_VERIFY	0x0000000000000004ULL
61163888Spjd#define	G_RAID3_DEVICE_FLAG_NOFAILSYNC	0x0000000000000008ULL
62134124Spjd#define	G_RAID3_DEVICE_FLAG_MASK	(G_RAID3_DEVICE_FLAG_NOAUTOSYNC | \
63134168Spjd					 G_RAID3_DEVICE_FLAG_ROUND_ROBIN | \
64163888Spjd					 G_RAID3_DEVICE_FLAG_VERIFY | \
65163888Spjd					 G_RAID3_DEVICE_FLAG_NOFAILSYNC)
66133808Spjd
67133808Spjd#ifdef _KERNEL
68133808Spjdextern u_int g_raid3_debug;
69133808Spjd
70133808Spjd#define	G_RAID3_DEBUG(lvl, ...)	do {					\
71133808Spjd	if (g_raid3_debug >= (lvl)) {					\
72133808Spjd		printf("GEOM_RAID3");					\
73133808Spjd		if (g_raid3_debug > 0)					\
74133808Spjd			printf("[%u]", lvl);				\
75133808Spjd		printf(": ");						\
76133808Spjd		printf(__VA_ARGS__);					\
77133808Spjd		printf("\n");						\
78133808Spjd	}								\
79133808Spjd} while (0)
80133808Spjd#define	G_RAID3_LOGREQ(lvl, bp, ...)	do {				\
81133808Spjd	if (g_raid3_debug >= (lvl)) {					\
82133808Spjd		printf("GEOM_RAID3");					\
83133808Spjd		if (g_raid3_debug > 0)					\
84133808Spjd			printf("[%u]", lvl);				\
85133808Spjd		printf(": ");						\
86133808Spjd		printf(__VA_ARGS__);					\
87133808Spjd		printf(" ");						\
88133808Spjd		g_print_bio(bp);					\
89133808Spjd		printf("\n");						\
90133808Spjd	}								\
91133808Spjd} while (0)
92133808Spjd
93133808Spjd#define	G_RAID3_BIO_CFLAG_REGULAR	0x01
94133808Spjd#define	G_RAID3_BIO_CFLAG_SYNC		0x02
95133808Spjd#define	G_RAID3_BIO_CFLAG_PARITY	0x04
96133808Spjd#define	G_RAID3_BIO_CFLAG_NODISK	0x08
97133808Spjd#define	G_RAID3_BIO_CFLAG_REGSYNC	0x10
98134168Spjd#define	G_RAID3_BIO_CFLAG_MASK		(G_RAID3_BIO_CFLAG_REGULAR |	\
99134168Spjd					 G_RAID3_BIO_CFLAG_SYNC |	\
100134168Spjd					 G_RAID3_BIO_CFLAG_PARITY |	\
101134168Spjd					 G_RAID3_BIO_CFLAG_NODISK |	\
102134168Spjd					 G_RAID3_BIO_CFLAG_REGSYNC)
103133808Spjd
104133808Spjd#define	G_RAID3_BIO_PFLAG_DEGRADED	0x01
105133808Spjd#define	G_RAID3_BIO_PFLAG_NOPARITY	0x02
106134168Spjd#define	G_RAID3_BIO_PFLAG_VERIFY	0x04
107134168Spjd#define	G_RAID3_BIO_PFLAG_MASK		(G_RAID3_BIO_PFLAG_DEGRADED |	\
108134168Spjd					 G_RAID3_BIO_PFLAG_NOPARITY |	\
109134168Spjd					 G_RAID3_BIO_PFLAG_VERIFY)
110133808Spjd
111133808Spjd/*
112133808Spjd * Informations needed for synchronization.
113133808Spjd */
114133808Spjdstruct g_raid3_disk_sync {
115133808Spjd	struct g_consumer *ds_consumer;	/* Consumer connected to our device. */
116156612Spjd	off_t		  ds_offset;	/* Offset of next request to send. */
117156612Spjd	off_t		  ds_offset_done; /* Offset of already synchronized
118133808Spjd					   region. */
119156612Spjd	off_t		  ds_resync;	/* Resynchronize from this offset. */
120156612Spjd	u_int		  ds_syncid;	/* Disk's synchronization ID. */
121156612Spjd	u_int		  ds_inflight;	/* Number of in-flight sync requests. */
122156612Spjd	struct bio	**ds_bios;	/* BIOs for synchronization I/O. */
123133808Spjd};
124133808Spjd
125133808Spjd/*
126133808Spjd * Informations needed for synchronization.
127133808Spjd */
128133808Spjdstruct g_raid3_device_sync {
129133808Spjd	struct g_geom	*ds_geom;	/* Synchronization geom. */
130133808Spjd};
131133808Spjd
132133808Spjd#define	G_RAID3_DISK_STATE_NODISK		0
133133808Spjd#define	G_RAID3_DISK_STATE_NONE			1
134133808Spjd#define	G_RAID3_DISK_STATE_NEW			2
135133808Spjd#define	G_RAID3_DISK_STATE_ACTIVE		3
136133808Spjd#define	G_RAID3_DISK_STATE_STALE		4
137133808Spjd#define	G_RAID3_DISK_STATE_SYNCHRONIZING	5
138133808Spjd#define	G_RAID3_DISK_STATE_DISCONNECTED		6
139133808Spjd#define	G_RAID3_DISK_STATE_DESTROY		7
140133808Spjdstruct g_raid3_disk {
141133808Spjd	u_int		 d_no;		/* Disk number. */
142133808Spjd	struct g_consumer *d_consumer;	/* Consumer. */
143133808Spjd	struct g_raid3_softc *d_softc;	/* Back-pointer to softc. */
144133808Spjd	int		 d_state;	/* Disk state. */
145133808Spjd	uint64_t	 d_flags;	/* Additional flags. */
146139295Spjd	u_int		 d_genid;	/* Disk's generation ID. */
147133808Spjd	struct g_raid3_disk_sync d_sync; /* Sync information. */
148133808Spjd	LIST_ENTRY(g_raid3_disk) d_next;
149133808Spjd};
150133808Spjd#define	d_name	d_consumer->provider->name
151133808Spjd
152133808Spjd#define	G_RAID3_EVENT_DONTWAIT	0x1
153133808Spjd#define	G_RAID3_EVENT_WAIT	0x2
154133808Spjd#define	G_RAID3_EVENT_DEVICE	0x4
155133808Spjd#define	G_RAID3_EVENT_DONE	0x8
156133808Spjdstruct g_raid3_event {
157133808Spjd	struct g_raid3_disk	*e_disk;
158133808Spjd	int			 e_state;
159133808Spjd	int			 e_flags;
160133808Spjd	int			 e_error;
161133808Spjd	TAILQ_ENTRY(g_raid3_event) e_next;
162133808Spjd};
163133808Spjd
164133808Spjd#define	G_RAID3_DEVICE_FLAG_DESTROY	0x0100000000000000ULL
165133808Spjd#define	G_RAID3_DEVICE_FLAG_WAIT	0x0200000000000000ULL
166157630Spjd#define	G_RAID3_DEVICE_FLAG_DESTROYING	0x0400000000000000ULL
167133808Spjd
168133808Spjd#define	G_RAID3_DEVICE_STATE_STARTING		0
169133808Spjd#define	G_RAID3_DEVICE_STATE_DEGRADED		1
170133808Spjd#define	G_RAID3_DEVICE_STATE_COMPLETE		2
171133808Spjd
172139295Spjd/* Bump syncid on first write. */
173139671Spjd#define	G_RAID3_BUMP_SYNCID	0x1
174139295Spjd/* Bump genid immediately. */
175139671Spjd#define	G_RAID3_BUMP_GENID	0x2
176133808Spjd
177156612Spjdenum g_raid3_zones {
178156612Spjd	G_RAID3_ZONE_64K,
179156612Spjd	G_RAID3_ZONE_16K,
180156612Spjd	G_RAID3_ZONE_4K,
181156612Spjd	G_RAID3_NUM_ZONES
182156612Spjd};
183156612Spjd
184156612Spjdstatic __inline enum g_raid3_zones
185156612Spjdg_raid3_zone(size_t nbytes) {
186200821Smav	if (nbytes > 65536)
187200821Smav		return (G_RAID3_NUM_ZONES);
188200821Smav	else if (nbytes > 16384)
189156612Spjd		return (G_RAID3_ZONE_64K);
190156612Spjd	else if (nbytes > 4096)
191156612Spjd		return (G_RAID3_ZONE_16K);
192156612Spjd	else
193156612Spjd		return (G_RAID3_ZONE_4K);
194156612Spjd};
195156612Spjd
196133808Spjdstruct g_raid3_softc {
197133808Spjd	u_int		sc_state;	/* Device state. */
198133808Spjd	uint64_t	sc_mediasize;	/* Device size. */
199133808Spjd	uint32_t	sc_sectorsize;	/* Sector size. */
200133808Spjd	uint64_t	sc_flags;	/* Additional flags. */
201133808Spjd
202133808Spjd	struct g_geom	*sc_geom;
203133808Spjd	struct g_provider *sc_provider;
204133808Spjd
205133808Spjd	uint32_t	sc_id;		/* Device unique ID. */
206133808Spjd
207156612Spjd	struct sx	 sc_lock;
208133808Spjd	struct bio_queue_head sc_queue;
209133808Spjd	struct mtx	 sc_queue_mtx;
210133808Spjd	struct proc	*sc_worker;
211156612Spjd	struct bio_queue_head sc_regular_delayed; /* Delayed I/O requests due
212156612Spjd						     collision with sync
213156612Spjd						     requests. */
214156612Spjd	struct bio_queue_head sc_inflight; /* In-flight regular write
215156612Spjd					      requests. */
216156612Spjd	struct bio_queue_head sc_sync_delayed; /* Delayed sync requests due
217156612Spjd						  collision with regular
218156612Spjd						  requests. */
219133808Spjd
220133808Spjd	struct g_raid3_disk *sc_disks;
221133808Spjd	u_int		sc_ndisks;	/* Number of disks. */
222134124Spjd	u_int		sc_round_robin;
223133808Spjd	struct g_raid3_disk *sc_syncdisk;
224133808Spjd
225156612Spjd	struct g_raid3_zone {
226156612Spjd		uma_zone_t	sz_zone;
227156612Spjd		size_t		sz_inuse;
228156612Spjd		size_t		sz_max;
229156612Spjd		u_int		sz_requested;
230156612Spjd		u_int		sz_failed;
231156612Spjd	} sc_zones[G_RAID3_NUM_ZONES];
232133808Spjd
233139295Spjd	u_int		sc_genid;	/* Generation ID. */
234133808Spjd	u_int		sc_syncid;	/* Synchronization ID. */
235139295Spjd	int		sc_bump_id;
236133808Spjd	struct g_raid3_device_sync sc_sync;
237137258Spjd	int		sc_idle;	/* DIRTY flags removed. */
238155540Spjd	time_t		sc_last_write;
239155540Spjd	u_int		sc_writes;
240133808Spjd
241133808Spjd	TAILQ_HEAD(, g_raid3_event) sc_events;
242133808Spjd	struct mtx	sc_events_mtx;
243133808Spjd
244133808Spjd	struct callout	sc_callout;
245148440Spjd
246148440Spjd	struct root_hold_token *sc_rootmount;
247133808Spjd};
248133808Spjd#define	sc_name	sc_geom->name
249133808Spjd
250133808Spjdconst char *g_raid3_get_diskname(struct g_raid3_disk *disk);
251133808Spjdu_int g_raid3_ndisks(struct g_raid3_softc *sc, int state);
252157630Spjd#define	G_RAID3_DESTROY_SOFT	0
253157630Spjd#define	G_RAID3_DESTROY_DELAYED	1
254157630Spjd#define	G_RAID3_DESTROY_HARD	2
255157630Spjdint g_raid3_destroy(struct g_raid3_softc *sc, int how);
256133808Spjdint g_raid3_event_send(void *arg, int state, int flags);
257133808Spjdstruct g_raid3_metadata;
258139671Spjdint g_raid3_add_disk(struct g_raid3_softc *sc, struct g_provider *pp,
259139671Spjd    struct g_raid3_metadata *md);
260139671Spjdint g_raid3_read_metadata(struct g_consumer *cp, struct g_raid3_metadata *md);
261133808Spjdvoid g_raid3_fill_metadata(struct g_raid3_disk *disk,
262133808Spjd    struct g_raid3_metadata *md);
263133808Spjdint g_raid3_clear_metadata(struct g_raid3_disk *disk);
264133808Spjdvoid g_raid3_update_metadata(struct g_raid3_disk *disk);
265133808Spjd
266133808Spjdg_ctl_req_t g_raid3_config;
267133808Spjd#endif	/* _KERNEL */
268133808Spjd
269133808Spjdstruct g_raid3_metadata {
270133808Spjd	char		md_magic[16];	/* Magic value. */
271133808Spjd	uint32_t	md_version;	/* Version number. */
272133808Spjd	char		md_name[16];	/* Device name. */
273133808Spjd	uint32_t	md_id;		/* Device unique ID. */
274133808Spjd	uint16_t	md_no;		/* Component number. */
275133808Spjd	uint16_t	md_all;		/* Number of disks in device. */
276139295Spjd	uint32_t	md_genid;	/* Generation ID. */
277133808Spjd	uint32_t	md_syncid;	/* Synchronization ID. */
278133808Spjd	uint64_t	md_mediasize;	/* Size of whole device. */
279133808Spjd	uint32_t	md_sectorsize;	/* Sector size. */
280133808Spjd	uint64_t	md_sync_offset;	/* Synchronized offset. */
281133808Spjd	uint64_t	md_mflags;	/* Additional device flags. */
282133808Spjd	uint64_t	md_dflags;	/* Additional disk flags. */
283133808Spjd	char		md_provider[16]; /* Hardcoded provider. */
284142727Spjd	uint64_t	md_provsize;	/* Provider's size. */
285133808Spjd	u_char		md_hash[16];	/* MD5 hash. */
286133808Spjd};
287133808Spjdstatic __inline void
288133808Spjdraid3_metadata_encode(struct g_raid3_metadata *md, u_char *data)
289133808Spjd{
290133808Spjd	MD5_CTX ctx;
291133808Spjd
292133808Spjd	bcopy(md->md_magic, data, 16);
293133808Spjd	le32enc(data + 16, md->md_version);
294133808Spjd	bcopy(md->md_name, data + 20, 16);
295133808Spjd	le32enc(data + 36, md->md_id);
296133808Spjd	le16enc(data + 40, md->md_no);
297133808Spjd	le16enc(data + 42, md->md_all);
298139295Spjd	le32enc(data + 44, md->md_genid);
299139295Spjd	le32enc(data + 48, md->md_syncid);
300139295Spjd	le64enc(data + 52, md->md_mediasize);
301139295Spjd	le32enc(data + 60, md->md_sectorsize);
302139295Spjd	le64enc(data + 64, md->md_sync_offset);
303139295Spjd	le64enc(data + 72, md->md_mflags);
304139295Spjd	le64enc(data + 80, md->md_dflags);
305139295Spjd	bcopy(md->md_provider, data + 88, 16);
306142727Spjd	le64enc(data + 104, md->md_provsize);
307133808Spjd	MD5Init(&ctx);
308142727Spjd	MD5Update(&ctx, data, 112);
309133808Spjd	MD5Final(md->md_hash, &ctx);
310142727Spjd	bcopy(md->md_hash, data + 112, 16);
311133808Spjd}
312133808Spjdstatic __inline int
313139295Spjdraid3_metadata_decode_v0v1v2(const u_char *data, struct g_raid3_metadata *md)
314133808Spjd{
315133808Spjd	MD5_CTX ctx;
316133808Spjd
317133808Spjd	bcopy(data + 20, md->md_name, 16);
318133808Spjd	md->md_id = le32dec(data + 36);
319133808Spjd	md->md_no = le16dec(data + 40);
320133808Spjd	md->md_all = le16dec(data + 42);
321133808Spjd	md->md_syncid = le32dec(data + 44);
322133808Spjd	md->md_mediasize = le64dec(data + 48);
323133808Spjd	md->md_sectorsize = le32dec(data + 56);
324133808Spjd	md->md_sync_offset = le64dec(data + 60);
325133808Spjd	md->md_mflags = le64dec(data + 68);
326133808Spjd	md->md_dflags = le64dec(data + 76);
327133808Spjd	bcopy(data + 84, md->md_provider, 16);
328133808Spjd	bcopy(data + 100, md->md_hash, 16);
329133808Spjd	MD5Init(&ctx);
330133808Spjd	MD5Update(&ctx, data, 100);
331133808Spjd	MD5Final(md->md_hash, &ctx);
332133808Spjd	if (bcmp(md->md_hash, data + 100, 16) != 0)
333133808Spjd		return (EINVAL);
334142727Spjd
335142727Spjd	/* New fields. */
336142727Spjd	md->md_genid = 0;
337142727Spjd	md->md_provsize = 0;
338142727Spjd
339133808Spjd	return (0);
340133808Spjd}
341139295Spjdstatic __inline int
342139295Spjdraid3_metadata_decode_v3(const u_char *data, struct g_raid3_metadata *md)
343139295Spjd{
344139295Spjd	MD5_CTX ctx;
345133808Spjd
346139295Spjd	bcopy(data + 20, md->md_name, 16);
347139295Spjd	md->md_id = le32dec(data + 36);
348139295Spjd	md->md_no = le16dec(data + 40);
349139295Spjd	md->md_all = le16dec(data + 42);
350139295Spjd	md->md_genid = le32dec(data + 44);
351139295Spjd	md->md_syncid = le32dec(data + 48);
352139295Spjd	md->md_mediasize = le64dec(data + 52);
353139295Spjd	md->md_sectorsize = le32dec(data + 60);
354139295Spjd	md->md_sync_offset = le64dec(data + 64);
355139295Spjd	md->md_mflags = le64dec(data + 72);
356139295Spjd	md->md_dflags = le64dec(data + 80);
357139295Spjd	bcopy(data + 88, md->md_provider, 16);
358139295Spjd	bcopy(data + 104, md->md_hash, 16);
359139295Spjd	MD5Init(&ctx);
360139295Spjd	MD5Update(&ctx, data, 104);
361139295Spjd	MD5Final(md->md_hash, &ctx);
362139295Spjd	if (bcmp(md->md_hash, data + 104, 16) != 0)
363139295Spjd		return (EINVAL);
364142727Spjd
365142727Spjd	/* New fields. */
366142727Spjd	md->md_provsize = 0;
367142727Spjd
368139295Spjd	return (0);
369139295Spjd}
370139295Spjdstatic __inline int
371163888Spjdraid3_metadata_decode_v4v5(const u_char *data, struct g_raid3_metadata *md)
372142727Spjd{
373142727Spjd	MD5_CTX ctx;
374142727Spjd
375142727Spjd	bcopy(data + 20, md->md_name, 16);
376142727Spjd	md->md_id = le32dec(data + 36);
377142727Spjd	md->md_no = le16dec(data + 40);
378142727Spjd	md->md_all = le16dec(data + 42);
379142727Spjd	md->md_genid = le32dec(data + 44);
380142727Spjd	md->md_syncid = le32dec(data + 48);
381142727Spjd	md->md_mediasize = le64dec(data + 52);
382142727Spjd	md->md_sectorsize = le32dec(data + 60);
383142727Spjd	md->md_sync_offset = le64dec(data + 64);
384142727Spjd	md->md_mflags = le64dec(data + 72);
385142727Spjd	md->md_dflags = le64dec(data + 80);
386142727Spjd	bcopy(data + 88, md->md_provider, 16);
387142727Spjd	md->md_provsize = le64dec(data + 104);
388142727Spjd	bcopy(data + 112, md->md_hash, 16);
389142727Spjd	MD5Init(&ctx);
390142727Spjd	MD5Update(&ctx, data, 112);
391142727Spjd	MD5Final(md->md_hash, &ctx);
392142727Spjd	if (bcmp(md->md_hash, data + 112, 16) != 0)
393142727Spjd		return (EINVAL);
394142727Spjd	return (0);
395142727Spjd}
396142727Spjdstatic __inline int
397139295Spjdraid3_metadata_decode(const u_char *data, struct g_raid3_metadata *md)
398139295Spjd{
399139295Spjd	int error;
400155174Spjd
401139295Spjd	bcopy(data, md->md_magic, 16);
402139295Spjd	md->md_version = le32dec(data + 16);
403139295Spjd	switch (md->md_version) {
404139295Spjd	case 0:
405139295Spjd	case 1:
406139295Spjd	case 2:
407139295Spjd		error = raid3_metadata_decode_v0v1v2(data, md);
408139295Spjd		break;
409139295Spjd	case 3:
410139295Spjd		error = raid3_metadata_decode_v3(data, md);
411139295Spjd		break;
412142727Spjd	case 4:
413163888Spjd	case 5:
414163888Spjd		error = raid3_metadata_decode_v4v5(data, md);
415142727Spjd		break;
416139295Spjd	default:
417139295Spjd		error = EINVAL;
418139295Spjd		break;
419139295Spjd	}
420139295Spjd	return (error);
421139295Spjd}
422139295Spjd
423133808Spjdstatic __inline void
424133808Spjdraid3_metadata_dump(const struct g_raid3_metadata *md)
425133808Spjd{
426133808Spjd	static const char hex[] = "0123456789abcdef";
427133808Spjd	char hash[16 * 2 + 1];
428133808Spjd	u_int i;
429133808Spjd
430133808Spjd	printf("     magic: %s\n", md->md_magic);
431133808Spjd	printf("   version: %u\n", (u_int)md->md_version);
432133808Spjd	printf("      name: %s\n", md->md_name);
433133808Spjd	printf("        id: %u\n", (u_int)md->md_id);
434133808Spjd	printf("        no: %u\n", (u_int)md->md_no);
435133808Spjd	printf("       all: %u\n", (u_int)md->md_all);
436139295Spjd	printf("     genid: %u\n", (u_int)md->md_genid);
437133808Spjd	printf("    syncid: %u\n", (u_int)md->md_syncid);
438133808Spjd	printf(" mediasize: %jd\n", (intmax_t)md->md_mediasize);
439133808Spjd	printf("sectorsize: %u\n", (u_int)md->md_sectorsize);
440133808Spjd	printf("syncoffset: %jd\n", (intmax_t)md->md_sync_offset);
441133808Spjd	printf("    mflags:");
442133808Spjd	if (md->md_mflags == 0)
443133808Spjd		printf(" NONE");
444133808Spjd	else {
445133808Spjd		if ((md->md_mflags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0)
446133808Spjd			printf(" NOAUTOSYNC");
447134124Spjd		if ((md->md_mflags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0)
448134124Spjd			printf(" ROUND-ROBIN");
449134168Spjd		if ((md->md_mflags & G_RAID3_DEVICE_FLAG_VERIFY) != 0)
450134168Spjd			printf(" VERIFY");
451163888Spjd		if ((md->md_mflags & G_RAID3_DEVICE_FLAG_NOFAILSYNC) != 0)
452163888Spjd			printf(" NOFAILSYNC");
453133808Spjd	}
454133808Spjd	printf("\n");
455133808Spjd	printf("    dflags:");
456133808Spjd	if (md->md_dflags == 0)
457133808Spjd		printf(" NONE");
458133808Spjd	else {
459133808Spjd		if ((md->md_dflags & G_RAID3_DISK_FLAG_DIRTY) != 0)
460133808Spjd			printf(" DIRTY");
461133808Spjd		if ((md->md_dflags & G_RAID3_DISK_FLAG_SYNCHRONIZING) != 0)
462133808Spjd			printf(" SYNCHRONIZING");
463133808Spjd		if ((md->md_dflags & G_RAID3_DISK_FLAG_FORCE_SYNC) != 0)
464133808Spjd			printf(" FORCE_SYNC");
465133808Spjd	}
466133808Spjd	printf("\n");
467133808Spjd	printf("hcprovider: %s\n", md->md_provider);
468142727Spjd	printf("  provsize: %ju\n", (uintmax_t)md->md_provsize);
469133808Spjd	bzero(hash, sizeof(hash));
470133808Spjd	for (i = 0; i < 16; i++) {
471133808Spjd		hash[i * 2] = hex[md->md_hash[i] >> 4];
472133808Spjd		hash[i * 2 + 1] = hex[md->md_hash[i] & 0x0f];
473133808Spjd	}
474133808Spjd	printf("  MD5 hash: %s\n", hash);
475133808Spjd}
476133808Spjd#endif	/* !_G_RAID3_H_ */
477