18394d51pjd/*-
2a82e3a8pfg * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3a82e3a8pfg *
4ba34146pjd * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
58394d51pjd * All rights reserved.
68394d51pjd *
78394d51pjd * Redistribution and use in source and binary forms, with or without
88394d51pjd * modification, are permitted provided that the following conditions
98394d51pjd * are met:
108394d51pjd * 1. Redistributions of source code must retain the above copyright
118394d51pjd *    notice, this list of conditions and the following disclaimer.
128394d51pjd * 2. Redistributions in binary form must reproduce the above copyright
138394d51pjd *    notice, this list of conditions and the following disclaimer in the
148394d51pjd *    documentation and/or other materials provided with the distribution.
156f074b6pjd *
168394d51pjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
178394d51pjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
188394d51pjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
198394d51pjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
208394d51pjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
218394d51pjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
228394d51pjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
238394d51pjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
248394d51pjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
258394d51pjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
268394d51pjd * SUCH DAMAGE.
278394d51pjd *
288394d51pjd * $FreeBSD$
298394d51pjd */
308394d51pjd
318394d51pjd#ifndef	_G_RAID3_H_
328394d51pjd#define	_G_RAID3_H_
338394d51pjd
348394d51pjd#include <sys/endian.h>
358394d51pjd#include <sys/md5.h>
368394d51pjd
378394d51pjd#define	G_RAID3_CLASS_NAME	"RAID3"
388394d51pjd
398394d51pjd#define	G_RAID3_MAGIC		"GEOM::RAID3"
402acdd88pjd/*
412acdd88pjd * Version history:
422acdd88pjd * 0 - Initial version number.
432acdd88pjd * 1 - Added 'round-robin reading' algorithm.
447e2ef21pjd * 2 - Added 'verify reading' algorithm.
450bb72c3pjd * 3 - Added md_genid field to metadata.
46668a028pjd * 4 - Added md_provsize field to metadata.
47b34fb80pjd * 5 - Added 'no failure synchronization' flag.
482acdd88pjd */
49b34fb80pjd#define	G_RAID3_VERSION		5
508394d51pjd
518394d51pjd#define	G_RAID3_DISK_FLAG_DIRTY		0x0000000000000001ULL
528394d51pjd#define	G_RAID3_DISK_FLAG_SYNCHRONIZING	0x0000000000000002ULL
538394d51pjd#define	G_RAID3_DISK_FLAG_FORCE_SYNC	0x0000000000000004ULL
548394d51pjd#define	G_RAID3_DISK_FLAG_HARDCODED	0x0000000000000008ULL
55beaa5fcpjd#define	G_RAID3_DISK_FLAG_BROKEN	0x0000000000000010ULL
568394d51pjd#define	G_RAID3_DISK_FLAG_MASK		(G_RAID3_DISK_FLAG_DIRTY |	\
578394d51pjd					 G_RAID3_DISK_FLAG_SYNCHRONIZING | \
588394d51pjd					 G_RAID3_DISK_FLAG_FORCE_SYNC)
598394d51pjd
608394d51pjd#define	G_RAID3_DEVICE_FLAG_NOAUTOSYNC	0x0000000000000001ULL
61c3c6740pjd#define	G_RAID3_DEVICE_FLAG_ROUND_ROBIN	0x0000000000000002ULL
627e2ef21pjd#define	G_RAID3_DEVICE_FLAG_VERIFY	0x0000000000000004ULL
63b34fb80pjd#define	G_RAID3_DEVICE_FLAG_NOFAILSYNC	0x0000000000000008ULL
64c3c6740pjd#define	G_RAID3_DEVICE_FLAG_MASK	(G_RAID3_DEVICE_FLAG_NOAUTOSYNC | \
657e2ef21pjd					 G_RAID3_DEVICE_FLAG_ROUND_ROBIN | \
66b34fb80pjd					 G_RAID3_DEVICE_FLAG_VERIFY | \
67b34fb80pjd					 G_RAID3_DEVICE_FLAG_NOFAILSYNC)
688394d51pjd
698394d51pjd#ifdef _KERNEL
708394d51pjdextern u_int g_raid3_debug;
718394d51pjd
7210d53fccem#define	G_RAID3_DEBUG(lvl, ...) \
7310d53fccem    _GEOM_DEBUG("GEOM_RAID3", g_raid3_debug, (lvl), NULL, __VA_ARGS__)
7410d53fccem#define	G_RAID3_LOGREQ(lvl, bp, ...) \
7510d53fccem    _GEOM_DEBUG("GEOM_RAID3", g_raid3_debug, (lvl), (bp), __VA_ARGS__)
768394d51pjd
778394d51pjd#define	G_RAID3_BIO_CFLAG_REGULAR	0x01
788394d51pjd#define	G_RAID3_BIO_CFLAG_SYNC		0x02
798394d51pjd#define	G_RAID3_BIO_CFLAG_PARITY	0x04
808394d51pjd#define	G_RAID3_BIO_CFLAG_NODISK	0x08
818394d51pjd#define	G_RAID3_BIO_CFLAG_REGSYNC	0x10
827e2ef21pjd#define	G_RAID3_BIO_CFLAG_MASK		(G_RAID3_BIO_CFLAG_REGULAR |	\
837e2ef21pjd					 G_RAID3_BIO_CFLAG_SYNC |	\
847e2ef21pjd					 G_RAID3_BIO_CFLAG_PARITY |	\
857e2ef21pjd					 G_RAID3_BIO_CFLAG_NODISK |	\
867e2ef21pjd					 G_RAID3_BIO_CFLAG_REGSYNC)
878394d51pjd
888394d51pjd#define	G_RAID3_BIO_PFLAG_DEGRADED	0x01
898394d51pjd#define	G_RAID3_BIO_PFLAG_NOPARITY	0x02
907e2ef21pjd#define	G_RAID3_BIO_PFLAG_VERIFY	0x04
917e2ef21pjd#define	G_RAID3_BIO_PFLAG_MASK		(G_RAID3_BIO_PFLAG_DEGRADED |	\
927e2ef21pjd					 G_RAID3_BIO_PFLAG_NOPARITY |	\
937e2ef21pjd					 G_RAID3_BIO_PFLAG_VERIFY)
948394d51pjd
958394d51pjd/*
968394d51pjd * Informations needed for synchronization.
978394d51pjd */
988394d51pjdstruct g_raid3_disk_sync {
998394d51pjd	struct g_consumer *ds_consumer;	/* Consumer connected to our device. */
100349adc9pjd	off_t		  ds_offset;	/* Offset of next request to send. */
101349adc9pjd	off_t		  ds_offset_done; /* Offset of already synchronized
1028394d51pjd					   region. */
103349adc9pjd	off_t		  ds_resync;	/* Resynchronize from this offset. */
104349adc9pjd	u_int		  ds_syncid;	/* Disk's synchronization ID. */
105349adc9pjd	u_int		  ds_inflight;	/* Number of in-flight sync requests. */
106349adc9pjd	struct bio	**ds_bios;	/* BIOs for synchronization I/O. */
1078394d51pjd};
1088394d51pjd
1098394d51pjd/*
1108394d51pjd * Informations needed for synchronization.
1118394d51pjd */
1128394d51pjdstruct g_raid3_device_sync {
1138394d51pjd	struct g_geom	*ds_geom;	/* Synchronization geom. */
1148394d51pjd};
1158394d51pjd
1168394d51pjd#define	G_RAID3_DISK_STATE_NODISK		0
1178394d51pjd#define	G_RAID3_DISK_STATE_NONE			1
1188394d51pjd#define	G_RAID3_DISK_STATE_NEW			2
1198394d51pjd#define	G_RAID3_DISK_STATE_ACTIVE		3
1208394d51pjd#define	G_RAID3_DISK_STATE_STALE		4
1218394d51pjd#define	G_RAID3_DISK_STATE_SYNCHRONIZING	5
1228394d51pjd#define	G_RAID3_DISK_STATE_DISCONNECTED		6
1238394d51pjd#define	G_RAID3_DISK_STATE_DESTROY		7
1248394d51pjdstruct g_raid3_disk {
1258394d51pjd	u_int		 d_no;		/* Disk number. */
1268394d51pjd	struct g_consumer *d_consumer;	/* Consumer. */
1278394d51pjd	struct g_raid3_softc *d_softc;	/* Back-pointer to softc. */
1288394d51pjd	int		 d_state;	/* Disk state. */
1298394d51pjd	uint64_t	 d_flags;	/* Additional flags. */
1300bb72c3pjd	u_int		 d_genid;	/* Disk's generation ID. */
1318394d51pjd	struct g_raid3_disk_sync d_sync; /* Sync information. */
1328394d51pjd	LIST_ENTRY(g_raid3_disk) d_next;
1338394d51pjd};
1348394d51pjd#define	d_name	d_consumer->provider->name
1358394d51pjd
1368394d51pjd#define	G_RAID3_EVENT_DONTWAIT	0x1
1378394d51pjd#define	G_RAID3_EVENT_WAIT	0x2
1388394d51pjd#define	G_RAID3_EVENT_DEVICE	0x4
1398394d51pjd#define	G_RAID3_EVENT_DONE	0x8
1408394d51pjdstruct g_raid3_event {
1418394d51pjd	struct g_raid3_disk	*e_disk;
1428394d51pjd	int			 e_state;
1438394d51pjd	int			 e_flags;
1448394d51pjd	int			 e_error;
1458394d51pjd	TAILQ_ENTRY(g_raid3_event) e_next;
1468394d51pjd};
1478394d51pjd
1488394d51pjd#define	G_RAID3_DEVICE_FLAG_DESTROY	0x0100000000000000ULL
1498394d51pjd#define	G_RAID3_DEVICE_FLAG_WAIT	0x0200000000000000ULL
150d7eb5b2pjd#define	G_RAID3_DEVICE_FLAG_DESTROYING	0x0400000000000000ULL
1518394d51pjd
1528394d51pjd#define	G_RAID3_DEVICE_STATE_STARTING		0
1538394d51pjd#define	G_RAID3_DEVICE_STATE_DEGRADED		1
1548394d51pjd#define	G_RAID3_DEVICE_STATE_COMPLETE		2
1558394d51pjd
1560bb72c3pjd/* Bump syncid on first write. */
157589a968pjd#define	G_RAID3_BUMP_SYNCID	0x1
1580bb72c3pjd/* Bump genid immediately. */
159589a968pjd#define	G_RAID3_BUMP_GENID	0x2
1608394d51pjd
161349adc9pjdenum g_raid3_zones {
162349adc9pjd	G_RAID3_ZONE_64K,
163349adc9pjd	G_RAID3_ZONE_16K,
164349adc9pjd	G_RAID3_ZONE_4K,
165349adc9pjd	G_RAID3_NUM_ZONES
166349adc9pjd};
167349adc9pjd
168349adc9pjdstatic __inline enum g_raid3_zones
169349adc9pjdg_raid3_zone(size_t nbytes) {
1703edd147mav	if (nbytes > 65536)
1713edd147mav		return (G_RAID3_NUM_ZONES);
1723edd147mav	else if (nbytes > 16384)
173349adc9pjd		return (G_RAID3_ZONE_64K);
174349adc9pjd	else if (nbytes > 4096)
175349adc9pjd		return (G_RAID3_ZONE_16K);
176349adc9pjd	else
177349adc9pjd		return (G_RAID3_ZONE_4K);
178349adc9pjd};
179349adc9pjd
1808394d51pjdstruct g_raid3_softc {
1818394d51pjd	u_int		sc_state;	/* Device state. */
1828394d51pjd	uint64_t	sc_mediasize;	/* Device size. */
1838394d51pjd	uint32_t	sc_sectorsize;	/* Sector size. */
1848394d51pjd	uint64_t	sc_flags;	/* Additional flags. */
1858394d51pjd
1868394d51pjd	struct g_geom	*sc_geom;
1878394d51pjd	struct g_provider *sc_provider;
1888394d51pjd
1898394d51pjd	uint32_t	sc_id;		/* Device unique ID. */
1908394d51pjd
191349adc9pjd	struct sx	 sc_lock;
1928394d51pjd	struct bio_queue_head sc_queue;
1938394d51pjd	struct mtx	 sc_queue_mtx;
1948394d51pjd	struct proc	*sc_worker;
195349adc9pjd	struct bio_queue_head sc_regular_delayed; /* Delayed I/O requests due
196349adc9pjd						     collision with sync
197349adc9pjd						     requests. */
198349adc9pjd	struct bio_queue_head sc_inflight; /* In-flight regular write
199349adc9pjd					      requests. */
200349adc9pjd	struct bio_queue_head sc_sync_delayed; /* Delayed sync requests due
201349adc9pjd						  collision with regular
202349adc9pjd						  requests. */
2038394d51pjd
2048394d51pjd	struct g_raid3_disk *sc_disks;
2058394d51pjd	u_int		sc_ndisks;	/* Number of disks. */
206c3c6740pjd	u_int		sc_round_robin;
2078394d51pjd	struct g_raid3_disk *sc_syncdisk;
2088394d51pjd
209349adc9pjd	struct g_raid3_zone {
210349adc9pjd		uma_zone_t	sz_zone;
211349adc9pjd		size_t		sz_inuse;
212349adc9pjd		size_t		sz_max;
213349adc9pjd		u_int		sz_requested;
214349adc9pjd		u_int		sz_failed;
215349adc9pjd	} sc_zones[G_RAID3_NUM_ZONES];
2168394d51pjd
2170bb72c3pjd	u_int		sc_genid;	/* Generation ID. */
2188394d51pjd	u_int		sc_syncid;	/* Synchronization ID. */
2190bb72c3pjd	int		sc_bump_id;
2208394d51pjd	struct g_raid3_device_sync sc_sync;
221b004592pjd	int		sc_idle;	/* DIRTY flags removed. */
22226f9aebpjd	time_t		sc_last_write;
22326f9aebpjd	u_int		sc_writes;
2248394d51pjd
2258394d51pjd	TAILQ_HEAD(, g_raid3_event) sc_events;
2268394d51pjd	struct mtx	sc_events_mtx;
2278394d51pjd
2288394d51pjd	struct callout	sc_callout;
229eb46744pjd
230eb46744pjd	struct root_hold_token *sc_rootmount;
2318394d51pjd};
2328394d51pjd#define	sc_name	sc_geom->name
2338394d51pjd
2348394d51pjdconst char *g_raid3_get_diskname(struct g_raid3_disk *disk);
2358394d51pjdu_int g_raid3_ndisks(struct g_raid3_softc *sc, int state);
236d7eb5b2pjd#define	G_RAID3_DESTROY_SOFT	0
237d7eb5b2pjd#define	G_RAID3_DESTROY_DELAYED	1
238d7eb5b2pjd#define	G_RAID3_DESTROY_HARD	2
239d7eb5b2pjdint g_raid3_destroy(struct g_raid3_softc *sc, int how);
2408394d51pjdint g_raid3_event_send(void *arg, int state, int flags);
2418394d51pjdstruct g_raid3_metadata;
242589a968pjdint g_raid3_add_disk(struct g_raid3_softc *sc, struct g_provider *pp,
243589a968pjd    struct g_raid3_metadata *md);
244589a968pjdint g_raid3_read_metadata(struct g_consumer *cp, struct g_raid3_metadata *md);
2458394d51pjdvoid g_raid3_fill_metadata(struct g_raid3_disk *disk,
2468394d51pjd    struct g_raid3_metadata *md);
2478394d51pjdint g_raid3_clear_metadata(struct g_raid3_disk *disk);
2488394d51pjdvoid g_raid3_update_metadata(struct g_raid3_disk *disk);
2498394d51pjd
2508394d51pjdg_ctl_req_t g_raid3_config;
2518394d51pjd#endif	/* _KERNEL */
2528394d51pjd
2538394d51pjdstruct g_raid3_metadata {
2548394d51pjd	char		md_magic[16];	/* Magic value. */
2558394d51pjd	uint32_t	md_version;	/* Version number. */
2568394d51pjd	char		md_name[16];	/* Device name. */
2578394d51pjd	uint32_t	md_id;		/* Device unique ID. */
2588394d51pjd	uint16_t	md_no;		/* Component number. */
2598394d51pjd	uint16_t	md_all;		/* Number of disks in device. */
2600bb72c3pjd	uint32_t	md_genid;	/* Generation ID. */
2618394d51pjd	uint32_t	md_syncid;	/* Synchronization ID. */
2628394d51pjd	uint64_t	md_mediasize;	/* Size of whole device. */
2638394d51pjd	uint32_t	md_sectorsize;	/* Sector size. */
2648394d51pjd	uint64_t	md_sync_offset;	/* Synchronized offset. */
2658394d51pjd	uint64_t	md_mflags;	/* Additional device flags. */
2668394d51pjd	uint64_t	md_dflags;	/* Additional disk flags. */
2678394d51pjd	char		md_provider[16]; /* Hardcoded provider. */
268668a028pjd	uint64_t	md_provsize;	/* Provider's size. */
2698394d51pjd	u_char		md_hash[16];	/* MD5 hash. */
2708394d51pjd};
2718394d51pjdstatic __inline void
2728394d51pjdraid3_metadata_encode(struct g_raid3_metadata *md, u_char *data)
2738394d51pjd{
2748394d51pjd	MD5_CTX ctx;
2758394d51pjd
2768394d51pjd	bcopy(md->md_magic, data, 16);
2778394d51pjd	le32enc(data + 16, md->md_version);
2788394d51pjd	bcopy(md->md_name, data + 20, 16);
2798394d51pjd	le32enc(data + 36, md->md_id);
2808394d51pjd	le16enc(data + 40, md->md_no);
2818394d51pjd	le16enc(data + 42, md->md_all);
2820bb72c3pjd	le32enc(data + 44, md->md_genid);
2830bb72c3pjd	le32enc(data + 48, md->md_syncid);
2840bb72c3pjd	le64enc(data + 52, md->md_mediasize);
2850bb72c3pjd	le32enc(data + 60, md->md_sectorsize);
2860bb72c3pjd	le64enc(data + 64, md->md_sync_offset);
2870bb72c3pjd	le64enc(data + 72, md->md_mflags);
2880bb72c3pjd	le64enc(data + 80, md->md_dflags);
2890bb72c3pjd	bcopy(md->md_provider, data + 88, 16);
290668a028pjd	le64enc(data + 104, md->md_provsize);
2918394d51pjd	MD5Init(&ctx);
292668a028pjd	MD5Update(&ctx, data, 112);
2938394d51pjd	MD5Final(md->md_hash, &ctx);
294668a028pjd	bcopy(md->md_hash, data + 112, 16);
2958394d51pjd}
2968394d51pjdstatic __inline int
2970bb72c3pjdraid3_metadata_decode_v0v1v2(const u_char *data, struct g_raid3_metadata *md)
2988394d51pjd{
2998394d51pjd	MD5_CTX ctx;
3008394d51pjd
3018394d51pjd	bcopy(data + 20, md->md_name, 16);
3028394d51pjd	md->md_id = le32dec(data + 36);
3038394d51pjd	md->md_no = le16dec(data + 40);
3048394d51pjd	md->md_all = le16dec(data + 42);
3058394d51pjd	md->md_syncid = le32dec(data + 44);
3068394d51pjd	md->md_mediasize = le64dec(data + 48);
3078394d51pjd	md->md_sectorsize = le32dec(data + 56);
3088394d51pjd	md->md_sync_offset = le64dec(data + 60);
3098394d51pjd	md->md_mflags = le64dec(data + 68);
3108394d51pjd	md->md_dflags = le64dec(data + 76);
3118394d51pjd	bcopy(data + 84, md->md_provider, 16);
3128394d51pjd	bcopy(data + 100, md->md_hash, 16);
3138394d51pjd	MD5Init(&ctx);
3148394d51pjd	MD5Update(&ctx, data, 100);
3158394d51pjd	MD5Final(md->md_hash, &ctx);
3168394d51pjd	if (bcmp(md->md_hash, data + 100, 16) != 0)
3178394d51pjd		return (EINVAL);
318668a028pjd
319668a028pjd	/* New fields. */
320668a028pjd	md->md_genid = 0;
321668a028pjd	md->md_provsize = 0;
322668a028pjd
3238394d51pjd	return (0);
3248394d51pjd}
3250bb72c3pjdstatic __inline int
3260bb72c3pjdraid3_metadata_decode_v3(const u_char *data, struct g_raid3_metadata *md)
3270bb72c3pjd{
3280bb72c3pjd	MD5_CTX ctx;
3290bb72c3pjd
3300bb72c3pjd	bcopy(data + 20, md->md_name, 16);
3310bb72c3pjd	md->md_id = le32dec(data + 36);
3320bb72c3pjd	md->md_no = le16dec(data + 40);
3330bb72c3pjd	md->md_all = le16dec(data + 42);
3340bb72c3pjd	md->md_genid = le32dec(data + 44);
3350bb72c3pjd	md->md_syncid = le32dec(data + 48);
3360bb72c3pjd	md->md_mediasize = le64dec(data + 52);
3370bb72c3pjd	md->md_sectorsize = le32dec(data + 60);
3380bb72c3pjd	md->md_sync_offset = le64dec(data + 64);
3390bb72c3pjd	md->md_mflags = le64dec(data + 72);
3400bb72c3pjd	md->md_dflags = le64dec(data + 80);
3410bb72c3pjd	bcopy(data + 88, md->md_provider, 16);
3420bb72c3pjd	bcopy(data + 104, md->md_hash, 16);
3430bb72c3pjd	MD5Init(&ctx);
3440bb72c3pjd	MD5Update(&ctx, data, 104);
3450bb72c3pjd	MD5Final(md->md_hash, &ctx);
3460bb72c3pjd	if (bcmp(md->md_hash, data + 104, 16) != 0)
3470bb72c3pjd		return (EINVAL);
348668a028pjd
349668a028pjd	/* New fields. */
350668a028pjd	md->md_provsize = 0;
351668a028pjd
352668a028pjd	return (0);
353668a028pjd}
354668a028pjdstatic __inline int
355b34fb80pjdraid3_metadata_decode_v4v5(const u_char *data, struct g_raid3_metadata *md)
356668a028pjd{
357668a028pjd	MD5_CTX ctx;
358668a028pjd
359668a028pjd	bcopy(data + 20, md->md_name, 16);
360668a028pjd	md->md_id = le32dec(data + 36);
361668a028pjd	md->md_no = le16dec(data + 40);
362668a028pjd	md->md_all = le16dec(data + 42);
363668a028pjd	md->md_genid = le32dec(data + 44);
364668a028pjd	md->md_syncid = le32dec(data + 48);
365668a028pjd	md->md_mediasize = le64dec(data + 52);
366668a028pjd	md->md_sectorsize = le32dec(data + 60);
367668a028pjd	md->md_sync_offset = le64dec(data + 64);
368668a028pjd	md->md_mflags = le64dec(data + 72);
369668a028pjd	md->md_dflags = le64dec(data + 80);
370668a028pjd	bcopy(data + 88, md->md_provider, 16);
371668a028pjd	md->md_provsize = le64dec(data + 104);
372668a028pjd	bcopy(data + 112, md->md_hash, 16);
373668a028pjd	MD5Init(&ctx);
374668a028pjd	MD5Update(&ctx, data, 112);
375668a028pjd	MD5Final(md->md_hash, &ctx);
376668a028pjd	if (bcmp(md->md_hash, data + 112, 16) != 0)
377668a028pjd		return (EINVAL);
3780bb72c3pjd	return (0);
3790bb72c3pjd}
3800bb72c3pjdstatic __inline int
3810bb72c3pjdraid3_metadata_decode(const u_char *data, struct g_raid3_metadata *md)
3820bb72c3pjd{
3830bb72c3pjd	int error;
3846f074b6pjd
3850bb72c3pjd	bcopy(data, md->md_magic, 16);
3860bb72c3pjd	md->md_version = le32dec(data + 16);
3870bb72c3pjd	switch (md->md_version) {
3880bb72c3pjd	case 0:
3890bb72c3pjd	case 1:
3900bb72c3pjd	case 2:
3910bb72c3pjd		error = raid3_metadata_decode_v0v1v2(data, md);
3920bb72c3pjd		break;
3930bb72c3pjd	case 3:
3940bb72c3pjd		error = raid3_metadata_decode_v3(data, md);
3950bb72c3pjd		break;
396668a028pjd	case 4:
397b34fb80pjd	case 5:
398b34fb80pjd		error = raid3_metadata_decode_v4v5(data, md);
399668a028pjd		break;
4000bb72c3pjd	default:
4010bb72c3pjd		error = EINVAL;
4020bb72c3pjd		break;
4030bb72c3pjd	}
4040bb72c3pjd	return (error);
4050bb72c3pjd}
4068394d51pjd
4078394d51pjdstatic __inline void
4088394d51pjdraid3_metadata_dump(const struct g_raid3_metadata *md)
4098394d51pjd{
4108394d51pjd	static const char hex[] = "0123456789abcdef";
4118394d51pjd	char hash[16 * 2 + 1];
4128394d51pjd	u_int i;
4138394d51pjd
4148394d51pjd	printf("     magic: %s\n", md->md_magic);
4158394d51pjd	printf("   version: %u\n", (u_int)md->md_version);
4168394d51pjd	printf("      name: %s\n", md->md_name);
4178394d51pjd	printf("        id: %u\n", (u_int)md->md_id);
4188394d51pjd	printf("        no: %u\n", (u_int)md->md_no);
4198394d51pjd	printf("       all: %u\n", (u_int)md->md_all);
4200bb72c3pjd	printf("     genid: %u\n", (u_int)md->md_genid);
4218394d51pjd	printf("    syncid: %u\n", (u_int)md->md_syncid);
4228394d51pjd	printf(" mediasize: %jd\n", (intmax_t)md->md_mediasize);
4238394d51pjd	printf("sectorsize: %u\n", (u_int)md->md_sectorsize);
4248394d51pjd	printf("syncoffset: %jd\n", (intmax_t)md->md_sync_offset);
4258394d51pjd	printf("    mflags:");
4268394d51pjd	if (md->md_mflags == 0)
4278394d51pjd		printf(" NONE");
4288394d51pjd	else {
4298394d51pjd		if ((md->md_mflags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0)
4308394d51pjd			printf(" NOAUTOSYNC");
431c3c6740pjd		if ((md->md_mflags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0)
432c3c6740pjd			printf(" ROUND-ROBIN");
4337e2ef21pjd		if ((md->md_mflags & G_RAID3_DEVICE_FLAG_VERIFY) != 0)
4347e2ef21pjd			printf(" VERIFY");
435b34fb80pjd		if ((md->md_mflags & G_RAID3_DEVICE_FLAG_NOFAILSYNC) != 0)
436b34fb80pjd			printf(" NOFAILSYNC");
4378394d51pjd	}
4388394d51pjd	printf("\n");
4398394d51pjd	printf("    dflags:");
4408394d51pjd	if (md->md_dflags == 0)
4418394d51pjd		printf(" NONE");
4428394d51pjd	else {
4438394d51pjd		if ((md->md_dflags & G_RAID3_DISK_FLAG_DIRTY) != 0)
4448394d51pjd			printf(" DIRTY");
4458394d51pjd		if ((md->md_dflags & G_RAID3_DISK_FLAG_SYNCHRONIZING) != 0)
4468394d51pjd			printf(" SYNCHRONIZING");
4478394d51pjd		if ((md->md_dflags & G_RAID3_DISK_FLAG_FORCE_SYNC) != 0)
4488394d51pjd			printf(" FORCE_SYNC");
4498394d51pjd	}
4508394d51pjd	printf("\n");
4518394d51pjd	printf("hcprovider: %s\n", md->md_provider);
452668a028pjd	printf("  provsize: %ju\n", (uintmax_t)md->md_provsize);
4538394d51pjd	bzero(hash, sizeof(hash));
4548394d51pjd	for (i = 0; i < 16; i++) {
4558394d51pjd		hash[i * 2] = hex[md->md_hash[i] >> 4];
4568394d51pjd		hash[i * 2 + 1] = hex[md->md_hash[i] & 0x0f];
4578394d51pjd	}
4588394d51pjd	printf("  MD5 hash: %s\n", hash);
4598394d51pjd}
4608394d51pjd#endif	/* !_G_RAID3_H_ */
461