From: heinzm@sourceware.org
To: dm-cvs@sourceware.org, dm-devel@redhat.com
Subject: dmraid ./CHANGELOG ./CREDITS ./KNOWN_BUGS ./RE ...
Date: 22 Feb 2008 17:04:43 -0000 [thread overview]
Message-ID: <20080222170443.29266.qmail@sourceware.org> (raw)
CVSROOT: /cvs/dm
Module name: dmraid
Changes by: heinzm@sourceware.org 2008-02-22 17:04:36
Modified files:
. : CHANGELOG CREDITS KNOWN_BUGS README TODO
include/dmraid : dmraid.h list.h metadata.h
lib : Makefile.in internal.h version.h
lib/activate : activate.c activate.h devmapper.c devmapper.h
lib/format : format.c ondisk.h register.h
lib/format/ataraid: asr.c asr.h hpt37x.c hpt37x.h hpt45x.c isw.c
jm.c lsi.c nv.c pdc.c sil.c sil.h via.c
lib/format/partition: dos.c
lib/locking : locking.c
lib/metadata : metadata.c
lib/misc : file.c
tools : Makefile.in VERSION
Added files:
include/dmraid : reconfig.h
lib/format/ataraid: .isw.c.swp .jm.c.swp
lib/format/ddf : README ddf1.c ddf1.c.orig ddf1.h ddf1_crc.c
ddf1_crc.h ddf1_cvt.c ddf1_cvt.h ddf1_dump.c
ddf1_dump.h ddf1_lib.c ddf1_lib.h
lib/metadata : log_ops.c reconfig.c
Log message:
1.0.0.rc12 checkin
Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/CHANGELOG.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/CREDITS.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/KNOWN_BUGS.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/README.diff?cvsroot=dm&r1=1.2&r2=1.3
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/TODO.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/include/dmraid/reconfig.h.diff?cvsroot=dm&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/include/dmraid/dmraid.h.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/include/dmraid/list.h.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/include/dmraid/metadata.h.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/Makefile.in.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/internal.h.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/version.h.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/activate/activate.c.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/activate/activate.h.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/activate/devmapper.c.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/activate/devmapper.h.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/format.c.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ondisk.h.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/register.h.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ataraid/.isw.c.swp.diff?cvsroot=dm&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ataraid/.jm.c.swp.diff?cvsroot=dm&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ataraid/asr.c.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ataraid/asr.h.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ataraid/hpt37x.c.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ataraid/hpt37x.h.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ataraid/hpt45x.c.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ataraid/isw.c.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ataraid/jm.c.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ataraid/lsi.c.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ataraid/nv.c.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ataraid/pdc.c.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ataraid/sil.c.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ataraid/sil.h.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ataraid/via.c.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ddf/README.diff?cvsroot=dm&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ddf/ddf1.c.diff?cvsroot=dm&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ddf/ddf1.c.orig.diff?cvsroot=dm&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ddf/ddf1.h.diff?cvsroot=dm&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ddf/ddf1_crc.c.diff?cvsroot=dm&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ddf/ddf1_crc.h.diff?cvsroot=dm&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ddf/ddf1_cvt.c.diff?cvsroot=dm&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ddf/ddf1_cvt.h.diff?cvsroot=dm&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ddf/ddf1_dump.c.diff?cvsroot=dm&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ddf/ddf1_dump.h.diff?cvsroot=dm&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ddf/ddf1_lib.c.diff?cvsroot=dm&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/ddf/ddf1_lib.h.diff?cvsroot=dm&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/format/partition/dos.c.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/locking/locking.c.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/metadata/log_ops.c.diff?cvsroot=dm&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/metadata/reconfig.c.diff?cvsroot=dm&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/metadata/metadata.c.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/lib/misc/file.c.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/tools/Makefile.in.diff?cvsroot=dm&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/dmraid/tools/VERSION.diff?cvsroot=dm&r1=1.1&r2=1.2
--- dmraid/CHANGELOG 2008/02/22 16:50:38 1.1
+++ dmraid/CHANGELOG 2008/02/22 17:04:35 1.2
@@ -1,4 +1,26 @@
+Changelog from dmraid 1.0.0.rc11 to 1.0.0.rc12 2006.09.22
+
+
+FIXES:
+------
+o sil.c: quorate() OBO fix
+o activate.c: handler() OBO fix
+o added log_zero_sectors() to various metadata format handlers
+
+FEATURES:
+---------
+o added SNIA DDF1 support (IBM)
+o added reload functionality to devmapper.c (IBM)
+o sil.[ch]: added JBOD support
+
+
+MISCELANIOUS:
+-------------
+o streamlined devmapper.c
+
+
+
Changelog from dmraid 1.0.0.rc10 to 1.0.0.rc11 2006.05.16
FIXES:
--- dmraid/CREDITS 2008/02/22 16:50:38 1.1
+++ dmraid/CREDITS 2008/02/22 17:04:35 1.2
@@ -5,6 +5,7 @@
o Jane Liu for the NVidia RAID metadata format handler
-o Darrick J. Wong for the Adpatec HostRAID ASR metadata format handler
+o Darrick J. Wong for the SNIA DDF1 and
+ Adaptec HostRAID ASR metadata format handlers
o various helpful people who provided metadata samples
--- dmraid/KNOWN_BUGS 2008/02/22 16:50:38 1.1
+++ dmraid/KNOWN_BUGS 2008/02/22 17:04:35 1.2
@@ -1,5 +1,5 @@
-KNOWN_BUGS in dmraid 1.0.0.rc11 2005.05.16
+KNOWN_BUGS in dmraid 1.0.0.rc12 2005.05.15
o "dmraid --sets[a/i]" doesn't work properly. Use the short option -s.
--- dmraid/README 2008/02/22 16:48:26 1.2
+++ dmraid/README 2008/02/22 17:04:35 1.3
@@ -1,6 +1,6 @@
********************************************************************************
* *
-* dmraid (Device-Mapper Software RAID support tool) 1.0.0.rc11 2006.05.15 *
+* dmraid (Device-Mapper Software RAID support tool) 1.0.0.rc12 2006.05.15 *
* *
* (C)opyright 2004-2006 Heinz Mauelshagen, Red Hat GmbH. *
* All rights reserved. *
@@ -26,6 +26,7 @@
NVidia NForce
Promise FastTrack
Silicon Image Medley
+SNIA DDF1
VIA Software RAID
Beside hints, enhancement proposals and patches, I want to know, if the mappings
--- dmraid/TODO 2008/02/22 16:50:38 1.1
+++ dmraid/TODO 2008/02/22 17:04:35 1.2
@@ -1,19 +1,15 @@
--- dmraid 1.0.0.rc11 TODO -- 2006.05.15
+-- dmraid 1.0.0.rc12 TODO -- 2006.09.19
+
+o use kpartx instead of my own metadata format handlers
o more enhancements for RAID set consistency checks
o neater -s output; something better than just paragraphs
for super- and subsets ?
-o higher RAID levels above 1; main restriction to support these is
- the need for device-mapper targets which map RAID4 and RAID5
- (Alpha patch for device-mapper RAID4/RAID5 target on my people page now)
-
o MD metadata format handler
-o SNIA DDF metadata format handler
-
o enhance metadata write feature in order to be able to store state changes
persistently; needs an event() method to inform the metadata handler about
state changes recognized eg, at the device-mapper interface layer
@@ -24,9 +20,6 @@
o more cleanup and enhance debug and verbose output
-o support other partitions than MSDOS on Software RAID devices or
- use kpartx instead ?
-
o regular expressions for metadata format, RAID device and RAID set selection
o does dmraid need a config file ?
/cvs/dm/dmraid/include/dmraid/reconfig.h,v --> standard output
revision 1.1
--- dmraid/include/dmraid/reconfig.h
+++ - 2008-02-22 17:04:37.144287000 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2006 Darrick Wong, IBM.
+ * All rights reserved.
+ *
+ * Copyright (C) 2006 Heinz Mauelshagen Red Hat GmbH.
+ * All rights reserved.
+ *
+ * See the file LICENSE at the top of this source tree for license information.
+ */
+
+#ifndef _RECONFIG_H_
+#define _RECONFIG_H_
+
+#include <dmraid/metadata.h>
+#include <dmraid/list.h>
+
+/* Type of change that a log entry describes */
+enum change_type {
+ ADD_TO_SET,
+ DELETE_FROM_SET,
+ WRITE_METADATA,
+ CREATE_CHILD_RD,
+ CREATE_RD,
+ DELETE_RD,
+ CREATE_RS,
+ DELETE_RS,
+ END_TRANSACTION
+};
+
+/* Change log entry */
+struct change {
+ struct list_head changes; /* Chain of log entries */
+ enum change_type type;
+
+ /* All of these items may be listed as parameters */
+ struct raid_set *rs;
+ struct raid_dev *rd;
+
+ uint64_t offset;
+ uint64_t length;
+
+ struct dev_info *di;
+
+ char *name;
+};
+
+extern int add_dev_to_set(struct lib_context *lc, struct raid_set *rs,
+ struct raid_dev *rd);
+extern int del_dev_in_set(struct lib_context *lc, struct raid_set *rs,
+ struct raid_dev *rd);
+extern void end_log(struct lib_context *lc, struct list_head *log);
+extern int revert_log(struct lib_context *lc, struct list_head *log);
+
+#endif
--- dmraid/include/dmraid/dmraid.h 2008/02/22 16:57:35 1.1
+++ dmraid/include/dmraid/dmraid.h 2008/02/22 17:04:35 1.2
@@ -17,6 +17,7 @@
#include <dmraid/display.h>
#include <dmraid/format.h>
#include <dmraid/metadata.h>
+#include <dmraid/reconfig.h>
/*
* Library init/exit
@@ -43,6 +44,7 @@
extern int discover_devices(struct lib_context *lc, char **devnodes);
extern void discover_raid_devices(struct lib_context *lc, char **devices);
extern void discover_partitions(struct lib_context *lc);
+extern int write_dev(struct lib_context *lc, struct raid_dev *rd, int erase);
/*
* Erase ondisk metadata.
--- dmraid/include/dmraid/list.h 2008/02/22 16:57:35 1.1
+++ dmraid/include/dmraid/list.h 2008/02/22 17:04:35 1.2
@@ -19,6 +19,8 @@
#define INIT_LIST_HEAD(a) do { (a)->next = (a)->prev = a; } while(0)
+#define LIST_HEAD(a) struct list_head a = { .next = &a, .prev = &a }
+
#define list_empty(pos) ((pos)->next == pos)
static inline void __list_add(struct list_head *new,
@@ -44,6 +46,11 @@
(pos)->next = (pos)->prev = 0; \
}
+#define list_del_init(pos) { \
+ list_del(pos); \
+ INIT_LIST_HEAD(pos); \
+}
+
/* Pointer to a struct 'type' derived from 'pos' and list_head* 'member'. */
#define list_entry(pos, type, member) \
((type*) ((char*)pos - (unsigned long)(&((type*)0)->member)))
--- dmraid/include/dmraid/metadata.h 2008/02/22 16:57:35 1.1
+++ dmraid/include/dmraid/metadata.h 2008/02/22 17:04:35 1.2
@@ -81,6 +81,18 @@
s_setup = 0x20, /* Only during RAID setup transition. */
};
+/*
+ * Mapping struct for RAID status unification.
+ *
+ * Format handler allocates an array and inserts mappings
+ * from format specific status to the unified ones above.
+ */
+enum compare { AND, EQUAL };
+struct states {
+ unsigned int status;
+ enum status unified_status;
+};
+
/* Check macros for states. */
#define S_UNDEF(status) ((status) & s_undef)
#define S_BROKEN(status) ((status) & s_broken)
@@ -195,6 +207,8 @@
enum status status; /* Status of set. */
};
+extern struct raid_set *get_raid_set(struct lib_context *lc,
+ struct raid_dev *rd);
extern struct dmraid_format *get_format(struct raid_set *rs);
extern const char *get_type(struct lib_context *lc, enum type type);
extern const char *get_dm_type(struct lib_context *lc, enum type type);
@@ -244,11 +258,14 @@
extern void discover_raid_devices(struct lib_context *lc, char **devices);
extern void discover_partitions(struct lib_context *lc);
extern unsigned int count_devices(struct lib_context *lc, enum dev_type type);
+extern enum status rd_status(struct states *states, unsigned int status,
+ enum compare cmp);
extern enum type rd_type(struct types *types, unsigned int type);
extern void file_metadata(struct lib_context *lc, const char *handler,
char *path, void *data, size_t size, uint64_t offset);
extern void file_dev_size(struct lib_context *lc, const char *handler,
struct dev_info *di);
+extern int write_dev(struct lib_context *lc, struct raid_dev *rd, int erase);
extern int erase_metadata(struct lib_context *lc);
#endif
--- dmraid/lib/Makefile.in 2008/02/22 16:57:35 1.1
+++ dmraid/lib/Makefile.in 2008/02/22 17:04:35 1.2
@@ -18,7 +18,9 @@
format/format.c \
locking/locking.c \
log/log.c \
+ metadata/log_ops.c \
metadata/metadata.c \
+ metadata/reconfig.c \
misc/file.c \
misc/init.c \
misc/lib_context.c \
@@ -35,7 +37,11 @@
format/ataraid/pdc.c \
format/ataraid/sil.c \
format/ataraid/via.c \
- format/ataraid/asr.c \
+ format/ddf/ddf1.c \
+ format/ddf/ddf1_lib.c \
+ format/ddf/ddf1_crc.c \
+ format/ddf/ddf1_cvt.c \
+ format/ddf/ddf1_dump.c \
format/partition/dos.c
OBJECTS=$(SOURCES:%.c=%.o)
--- dmraid/lib/internal.h 2008/02/22 16:57:35 1.1
+++ dmraid/lib/internal.h 2008/02/22 17:04:35 1.2
@@ -13,6 +13,7 @@
#endif
#include <ctype.h>
+#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
@@ -34,6 +35,7 @@
#include <dmraid/format.h>
#include <dmraid/metadata.h>
#include "activate/activate.h"
+#include <dmraid/reconfig.h>
#ifndef u_int16_t
#define u_int16_t uint16_t
--- dmraid/lib/version.h 2008/02/22 16:57:35 1.1
+++ dmraid/lib/version.h 2008/02/22 17:04:35 1.2
@@ -1,12 +1,12 @@
#ifndef DMRAID_LIB_VERSION
-#define DMRAID_LIB_VERSION "1.0.0.rc11"
+#define DMRAID_LIB_VERSION "1.0.0.rc12"
#define DMRAID_LIB_MAJOR_VERSION 1
#define DMRAID_LIB_MINOR_VERSION 0
#define DMRAID_LIB_SUBMINOR_VERSION 0
-#define DMRAID_LIB_VERSION_SUFFIX "rc11"
+#define DMRAID_LIB_VERSION_SUFFIX "rc12"
-#define DMRAID_LIB_DATE "(2006.05.15)"
+#define DMRAID_LIB_DATE "(2006.09.15)"
#endif
--- dmraid/lib/activate/activate.c 2008/02/22 16:57:35 1.1
+++ dmraid/lib/activate/activate.c 2008/02/22 17:04:35 1.2
@@ -506,7 +506,7 @@
do {
if (rs->type == th->type)
return th;
- } while (th++ < ARRAY_END(type_handler));
+ } while (++th < ARRAY_END(type_handler));
return type_handler;
}
@@ -572,6 +572,65 @@
return do_device(lc, rs, dm_unregister_for_event);
}
+/* Reload a single set. */
+static int reload_subset(struct lib_context *lc, struct raid_set *rs)
+{
+ int ret = 0;
+ char *table = NULL;
+
+ if (T_GROUP(rs))
+ return 1;
+
+ /* Suspend device */
+ if (!(ret = dm_suspend(lc, rs)))
+ LOG_ERR(lc, ret, "Device suspend failed.");
+
+ /* Call type handler */
+ if ((ret = (handler(rs))->f(lc, &table, rs))) {
+ if (OPT_TEST(lc))
+ display_table(lc, rs->name, table);
+ else
+ ret = dm_reload(lc, rs, table);
+ } else
+ log_err(lc, "no mapping possible for RAID set %s", rs->name);
+
+ free_string(lc, &table);
+
+ /* Try to resume */
+ if (ret)
+ dm_resume(lc, rs);
+ else
+ if (!(ret = dm_resume(lc, rs)))
+ LOG_ERR(lc, ret, "Device resume failed.");
+
+ return ret;
+}
+
+/* Reload a RAID set recursively (eg, RAID1 on top of RAID0). */
+static int reload_set(struct lib_context *lc, struct raid_set *rs)
+{
+ struct raid_set *r;
+
+ /* FIXME: Does it matter if the set is (in)active? */
+#if 0
+ if (!OPT_TEST(lc) &&
+ what == DM_ACTIVATE &&
+ dm_status(lc, rs)) {
+ log_print(lc, "RAID set \"%s\" already active", rs->name);
+ return 1;
+ }
+#endif
+
+ /* Recursively walk down the chain of stacked RAID sets */
+ list_for_each_entry(r, &rs->sets, list) {
+ /* Activate set below this one */
+ if (!reload_set(lc, r) && !T_GROUP(rs))
+ return 0;
+ }
+
+ return reload_subset(lc, rs);
+}
+
/* Activate a single set. */
static int activate_subset(struct lib_context *lc, struct raid_set *rs,
enum dm_what what)
@@ -683,6 +742,11 @@
case A_DEACTIVATE:
ret = deactivate_set(lc, rs, DM_REGISTER) &&
deactivate_set(lc, rs, DM_ACTIVATE);
+ break;
+
+ case A_RELOAD:
+ ret = reload_set(lc, rs);
+ break;
}
return ret;
--- dmraid/lib/activate/activate.h 2008/02/22 16:57:35 1.1
+++ dmraid/lib/activate/activate.h 2008/02/22 17:04:35 1.2
@@ -11,6 +11,7 @@
enum activate_type {
A_ACTIVATE,
A_DEACTIVATE,
+ A_RELOAD,
};
int change_set(struct lib_context *lc, enum activate_type what, void *rs);
--- dmraid/lib/activate/devmapper.c 2008/02/22 16:57:35 1.1
+++ dmraid/lib/activate/devmapper.c 2008/02/22 17:04:35 1.2
@@ -16,7 +16,6 @@
#include <string.h>
#include <ctype.h>
#include <dirent.h>
-#include <errno.h>
#include <unistd.h>
#include "internal.h"
@@ -148,19 +147,31 @@
return handle_table(lc, NULL, table, get_target_list());
}
-/* Create a mapped device. */
-int dm_create(struct lib_context *lc, struct raid_set *rs, char *table)
+/* Create a task, set its name and run it. */
+static int run_task(struct lib_context *lc, struct raid_set *rs,
+ char *table, int type)
{
- int ret = 0;
+ int ret;
struct dm_task *dmt;
_init_dm();
+ ret = (dmt = dm_task_create(type)) && dm_task_set_name(dmt, rs->name);
+ if (ret && table)
+ ret = parse_table(lc, dmt, table);
+
+ if (ret)
+ ret = dm_task_run(dmt);
+
+ _exit_dm(dmt);
+ return ret;
+}
+/* Create a mapped device. */
+int dm_create(struct lib_context *lc, struct raid_set *rs, char *table)
+{
+ int ret;
/* Create <dev_name> */
- ret = (dmt = dm_task_create(DM_DEVICE_CREATE)) &&
- dm_task_set_name(dmt, rs->name) &&
- parse_table(lc, dmt, table) &&
- dm_task_run(dmt);
+ ret = run_task(lc, rs, table, DM_DEVICE_CREATE);
/*
* In case device creation failed, check if target
@@ -169,29 +180,48 @@
if (!ret)
check_table(lc, table);
- _exit_dm(dmt);
-
return ret;
}
-/* Remove a mapped device. */
-int dm_remove(struct lib_context *lc, struct raid_set *rs)
+/* Suspend a mapped device. */
+int dm_suspend(struct lib_context *lc, struct raid_set *rs)
{
- int ret;
- struct dm_task *dmt;
+ /* Suspend <dev_name> */
+ return run_task(lc, rs, NULL, DM_DEVICE_SUSPEND);
+}
- _init_dm();
+/* Resume a mapped device. */
+int dm_resume(struct lib_context *lc, struct raid_set *rs)
+{
+ /* Resume <dev_name> */
+ return run_task(lc, rs, NULL, DM_DEVICE_RESUME);
+}
- /* remove <dev_name> */
- ret = (dmt = dm_task_create(DM_DEVICE_REMOVE)) &&
- dm_task_set_name(dmt, rs->name) &&
- dm_task_run(dmt);
+/* Reload a mapped device. */
+int dm_reload(struct lib_context *lc, struct raid_set *rs, char *table)
+{
+ int ret;
- _exit_dm(dmt);
+ /* Create <dev_name> */
+ ret = run_task(lc, rs, table, DM_DEVICE_RELOAD);
+
+ /*
+ * In case device creation failed, check if target
+ * isn't registered with the device-mapper core
+ */
+ if (!ret)
+ check_table(lc, table);
return ret;
}
+/* Remove a mapped device. */
+int dm_remove(struct lib_context *lc, struct raid_set *rs)
+{
+ /* Remove <dev_name> */
+ return run_task(lc, rs, NULL, DM_DEVICE_REMOVE);
+}
+
/* Retrieve status of a mapped device. */
/* FIXME: more status for device monitoring... */
int dm_status(struct lib_context *lc, struct raid_set *rs)
--- dmraid/lib/activate/devmapper.h 2008/02/22 16:57:35 1.1
+++ dmraid/lib/activate/devmapper.h 2008/02/22 17:04:35 1.2
@@ -13,5 +13,8 @@
int dm_remove(struct lib_context *lc, struct raid_set *rs);
int dm_status(struct lib_context *lc, struct raid_set *rs);
int dm_version(struct lib_context *lc, char *version, size_t size);
+int dm_suspend(struct lib_context *lc, struct raid_set *rs);
+int dm_resume(struct lib_context *lc, struct raid_set *rs);
+int dm_reload(struct lib_context *lc, struct raid_set *rs, char *table);
#endif
--- dmraid/lib/format/format.c 2008/02/22 16:57:36 1.1
+++ dmraid/lib/format/format.c 2008/02/22 17:04:35 1.2
@@ -35,22 +35,24 @@
struct format_member {
const unsigned short offset;
- const unsigned char all;
- const unsigned char method;
+ const unsigned char flags;
const char *msg;
} __attribute__ ((packed));
+enum { FMT_ALL = 0x01, FMT_METHOD = 0x02 } format_flags;
+#define IS_FMT_ALL(member) (member->flags & FMT_ALL)
+#define IS_FMT_METHOD(member) (member->flags & FMT_METHOD)
static struct format_member format_member[] = {
- { offset(name), 1, 0, "name" },
- { offset(descr), 1, 0, "description" },
- { offset(caps), 0, 0, "capabilities" },
- { offset(read), 1, 1, "read" },
- { offset(write), 0, 1, "write" },
- { offset(group), 1, 1, "group" },
- { offset(check), 1, 1, "check" },
- { offset(events), 0, 0, "events array" },
+ { offset(name), FMT_ALL, "name" },
+ { offset(descr), FMT_ALL, "description" },
+ { offset(caps), 0, "capabilities" },
+ { offset(read), FMT_ALL|FMT_METHOD, "read" },
+ { offset(write), FMT_METHOD, "write" },
+ { offset(group), FMT_ALL|FMT_METHOD, "group" },
+ { offset(check), FMT_ALL|FMT_METHOD, "check" },
+ { offset(events), 0, "events array" },
#ifdef NATIVE_LOG
- { offset(log), 0, 1, "log" },
+ { offset(log), FMT_METHOD, "log" },
#endif
};
#undef offset
@@ -58,12 +60,12 @@
static int check_member(struct lib_context *lc, struct dmraid_format *fmt,
struct format_member *member)
{
- if ((!member->all && fmt->format != FMT_RAID) ||
+ if ((!IS_FMT_ALL(member) && fmt->format != FMT_RAID) ||
*((unsigned long*) (((unsigned char*) fmt) + member->offset)))
return 0;
LOG_ERR(lc, 1, "%s: missing metadata format handler %s%s",
- fmt->name, member->msg, member->method ? " method" : "");
+ fmt->name, member->msg, IS_FMT_METHOD(member) ? " method" : "");
}
static int check_format_handler(struct lib_context *lc,
--- dmraid/lib/format/ondisk.h 2008/02/22 16:57:36 1.1
+++ dmraid/lib/format/ondisk.h 2008/02/22 17:04:35 1.2
@@ -18,7 +18,8 @@
#include "ataraid/pdc.h"
#include "ataraid/via.h"
#include "ataraid/sil.h"
-#include "ataraid/asr.h"
+
+#include "ddf/ddf1.h"
#include "partition/dos.h"
--- dmraid/lib/format/register.h 2008/02/22 16:57:36 1.1
+++ dmraid/lib/format/register.h 2008/02/22 17:04:35 1.2
@@ -16,6 +16,7 @@
/* Metadata format handlers. */
xx(asr)
+ xx(ddf1)
xx(hpt37x)
xx(hpt45x)
xx(isw)
/cvs/dm/dmraid/lib/format/ataraid/.isw.c.swp,v --> standard output
revision 1.1
Binary files /cvs/dm/dmraid/lib/format/ataraid/.isw.c.swp and - differ
co: output error: Broken pipe
co aborted
/cvs/dm/dmraid/lib/format/ataraid/.jm.c.swp,v --> standard output
revision 1.1
Binary files /cvs/dm/dmraid/lib/format/ataraid/.jm.c.swp and - differ
co: output error: Broken pipe
co aborted
--- dmraid/lib/format/ataraid/asr.c 2008/02/22 16:57:36 1.1
+++ dmraid/lib/format/ataraid/asr.c 2008/02/22 17:04:35 1.2
@@ -1,13 +1,19 @@
/*
- * Adaptec HostRAID ASR format interpreter for dmraid.
+ * Adaptec HostRAID ASR metadata format handler.
+ *
* Copyright (C) 2005-2006 IBM, All rights reserved.
- * Written by Darrick Wong <djwong@us.ibm.com>
+ * Written by Darrick Wong <djwong@us.ibm.com>,
+ * James Simshaw <simshawj@us.ibm.com>, and
+ * Adam DiCarlo <bikko@us.ibm.com>
+ *
+ * Copyright (C) 2006 Heinz Mauelshagen, Red Hat GmbH
+ * All rights reserved.
*
* See file LICENSE at the top of this source tree for license information.
*/
-#include <errno.h>
#include <netinet/in.h>
+#include <time.h>
#define HANDLER "asr"
@@ -21,44 +27,31 @@
#endif
static const char *handler = HANDLER;
-
-#define SPARE_ARRAY ".asr_spares"
-
-static int asr_write(struct lib_context *lc, struct raid_dev *rd, int erase);
+static const char *spare_array = ".asr_spares";
/* Map ASR disk status to dmraid status */
static enum status disk_status(struct asr_raid_configline *disk) {
- if (disk == NULL)
- return s_undef;
-
- switch (disk->raidstate) {
- case LSU_COMPONENT_STATE_OPTIMAL:
- return s_ok;
-
- case LSU_COMPONENT_STATE_DEGRADED:
- case LSU_COMPONENT_STATE_FAILED:
- return s_broken;
-
- case LSU_COMPONENT_STATE_UNINITIALIZED:
- case LSU_COMPONENT_STATE_UNCONFIGURED:
- return s_inconsistent;
-
- case LSU_COMPONENT_SUBSTATE_BUILDING:
- case LSU_COMPONENT_SUBSTATE_REBUILDING:
- case LSU_COMPONENT_STATE_REPLACED:
- return s_nosync;
+ static struct states states[] = {
+ { LSU_COMPONENT_STATE_OPTIMAL, s_ok },
+ { LSU_COMPONENT_STATE_DEGRADED, s_broken },
+ { LSU_COMPONENT_STATE_FAILED, s_broken },
+ { LSU_COMPONENT_STATE_UNINITIALIZED, s_inconsistent },
+ { LSU_COMPONENT_STATE_UNCONFIGURED, s_inconsistent },
+ { LSU_COMPONENT_SUBSTATE_BUILDING, s_nosync },
+ { LSU_COMPONENT_SUBSTATE_REBUILDING, s_nosync },
+ { LSU_COMPONENT_STATE_REPLACED, s_nosync },
+ { 0, s_undef },
+ };
- default:
- return s_undef;
- }
+ return rd_status(states, disk->raidstate, EQUAL);
}
/* Extract config line from metadata */
static struct asr_raid_configline *get_config(struct asr *asr, uint32_t magic)
{
- unsigned int i;
+ unsigned int i = asr->rt->elmcnt;
- for (i = 0; i < asr->rt->elmcnt; i++) {
+ while (i--) {
if (asr->rt->ent[i].raidmagic == magic)
return asr->rt->ent + i;
}
@@ -90,12 +83,9 @@
size_t len;
char *ret;
- if ((ret = dbg_malloc((len = _name(lc, asr, NULL, 0) + 1)))) {
+ if ((ret = dbg_malloc((len = _name(lc, asr, NULL, 0) + 1))))
_name(lc, asr, ret, len);
- /* Why do we call mk_alpha? This makes labels like
- * "OS-u320-15k" become "OS-udca-bek", which is confusing.
- * mk_alpha(lc, ret + HANDLER_LEN, len - HANDLER_LEN); */
- } else
+ else
log_alloc_err(lc, handler);
return ret;
@@ -107,23 +97,23 @@
return cl ? cl->strpsize: 0;
}
-/* Mapping of template types to generic types */
/*
* FIXME: This needs more examination. Does HostRAID do linear
* combination? The BIOS implies that it only does RAID 0, 1 and 10.
* The emd driver implied support for RAID3/4/5, but dm doesn't
* do any of those right now (RAID4 and RAID5 are in the works).
*/
-static struct types types[] = {
- { ASR_RAID0, t_raid0 },
- { ASR_RAID1, t_raid1 },
- { ASR_RAIDSPR, t_spare },
- { 0, t_undef}
-};
-
/* Map the ASR raid type codes into dmraid type codes. */
static enum type type(struct asr_raid_configline *cl)
{
+ /* Mapping of template types to generic types */
+ static struct types types[] = {
+ { ASR_RAID0, t_raid0 },
+ { ASR_RAID1, t_raid1 },
+ { ASR_RAIDSPR, t_spare },
+ { 0, t_undef},
+ };
+
return cl ? rd_type(types, (unsigned int) cl->raidtype) : t_undef;
}
@@ -131,9 +121,7 @@
* Read an ASR RAID device. Fields are big endian, so
* need to convert them if we're on a LE machine (i386, etc).
*/
-#define ASR_BLOCK 0x01
-#define ASR_TABLE 0x02
-#define ASR_EXTTABLE 0x04
+enum { ASR_BLOCK = 0x01, ASR_TABLE = 0x02, ASR_EXTTABLE = 0x04 };
#if BYTE_ORDER == LITTLE_ENDIAN
static void cvt_configline(struct asr_raid_configline *cl)
@@ -154,11 +142,9 @@
static void to_cpu(void *meta, unsigned int cvt)
{
- int i;
struct asr *asr = meta;
- int elmcnt = asr->rt->elmcnt;
-
- int use_old_elmcnt = (asr->rt->ridcode == RVALID2);
+ unsigned int i, elmcnt = asr->rt->elmcnt,
+ use_old_elmcnt = (asr->rt->ridcode == RVALID2);
if (cvt & ASR_BLOCK) {
CVT32(asr->rb.b0idcode);
@@ -190,15 +176,13 @@
CVT32(asr->rt->recreateDate);
/* Convert the first seven config lines */
- for (i = 0; i < (elmcnt < 7 ? elmcnt : 7); i++)
+ for (i = 0; i < (min(elmcnt, ASR_TBLELMCNT)); i++)
cvt_configline(asr->rt->ent + i);
-
}
if (cvt & ASR_EXTTABLE) {
- for (i = 7; i < elmcnt; i++) {
+ for (i = ASR_TBLELMCNT; i < elmcnt; i++)
cvt_configline(asr->rt->ent + i);
- }
}
}
@@ -209,31 +193,41 @@
/* Compute the checksum of RAID metadata */
static unsigned int compute_checksum(struct asr *asr)
{
- uint8_t *ptr;
- unsigned int i, checksum;
+ uint8_t *ptr = (uint8_t*) asr->rt->ent;
+ unsigned int checksum = 0,
+ end = sizeof(*asr->rt->ent) * asr->rt->elmcnt;
/* Compute checksum. */
- ptr = (uint8_t*) asr->rt->ent;
- checksum = 0;
- for (i = 0; i < sizeof(*asr->rt->ent) * asr->rt->elmcnt; i++)
- checksum += ptr[i];
+ while (end--)
+ checksum += *(ptr++);
return checksum & 0xFFFF;
}
+/* (Un)truncate white space at the end of a name */
+enum truncate { TRUNCATE, UNTRUNCATE };
+static void handle_white_space(uint8_t *p, enum truncate truncate)
+{
+ unsigned int j = ASR_NAMELEN;
+ uint8_t c = truncate == TRUNCATE ? 0 : ' ';
+
+ while (j-- && (truncate == TRUNCATE ? isspace(p[j]) : !p[j]))
+ p[j] = c;
+}
+
/* Read extended metadata areas */
static int read_extended(struct lib_context *lc, struct dev_info *di,
struct asr *asr)
{
unsigned int remaining, i, chk;
- int j;
- log_info(lc, "%s: reading extended data", di->path);
+ log_notice(lc, "%s: reading extended data on %s", handler, di->path);
/* Read the RAID table. */
if (!read_file(lc, handler, di->path, asr->rt, ASR_DISK_BLOCK_SIZE,
(uint64_t) asr->rb.raidtbl * ASR_DISK_BLOCK_SIZE))
- LOG_ERR(lc, 0, "%s: Could not read metadata.", handler);
+ LOG_ERR(lc, 0, "%s: Could not read metadata off %s",
+ handler, di->path);
/* Convert it */
to_cpu(asr, ASR_TABLE);
@@ -241,21 +235,21 @@
/* Is this ok? */
if (asr->rt->ridcode != RVALID2)
LOG_ERR(lc, 0, "%s: Invalid magic number in RAID table; "
- "saw 0x%X, expected 0x%X.", handler, asr->rt->ridcode,
- RVALID2);
+ "saw 0x%X, expected 0x%X on %s",
+ handler, asr->rt->ridcode, RVALID2, di->path);
/* Have we a valid element count? */
- if (asr->rt->elmcnt >= asr->rt->maxelm)
- LOG_ERR(lc, 0, "%s: Invalid RAID config table count.\n",
- handler);
+ if (asr->rt->elmcnt >= asr->rt->maxelm || asr->rt->elmcnt == 0)
+ LOG_ERR(lc, 0, "%s: Invalid RAID config table count on %s",
+ handler, di->path);
/* Is each element the right size? */
- if (asr->rt->elmsize != sizeof(struct asr_raid_configline))
- LOG_ERR(lc, 0, "%s: RAID config line is the wrong size.\n",
- handler);
+ if (asr->rt->elmsize != sizeof(*asr->rt->ent))
+ LOG_ERR(lc, 0, "%s: Wrong RAID config line size on %s",
+ handler, di->path);
/* Figure out how much else we need to read. */
- if (asr->rt->elmcnt > 7) {
+ if (asr->rt->elmcnt > ASR_TBLELMCNT) {
remaining = asr->rt->elmsize * (asr->rt->elmcnt - 7);
if (!read_file(lc, handler, di->path, asr->rt->ent + 7,
remaining, (uint64_t)(asr->rb.raidtbl + 1) *
@@ -268,8 +262,8 @@
chk = compute_checksum(asr);
if (chk != asr->rt->rchksum)
LOG_ERR(lc, 0,"%s: Invalid RAID config table checksum "
- "(0x%X vs. 0x%X).",
- handler, chk, asr->rt->rchksum);
+ "(0x%X vs. 0x%X) on %s",
+ handler, chk, asr->rt->rchksum, di->path);
/* Process the name of each line of the config line. */
for (i = 0; i < asr->rt->elmcnt; i++) {
@@ -299,11 +293,7 @@
memcpy(asr->rt->ent[i].name, asr->rt->ent[0].name, 16);
/* Now truncate trailing whitespace in the name. */
- for (j = 15; j >= 0; j--) {
- if (asr->rt->ent[i].name[j] != ' ')
- break;
- }
- asr->rt->ent[i].name[j + 1] = 0;
+ handle_white_space(asr->rt->ent[i].name, TRUNCATE);
}
return 1;
@@ -322,8 +312,7 @@
if (asr->rb.resver == RBLOCK_VER)
return 1;
- LOG_ERR(lc, 0,
- "%s: ASR v%d detected, but we only support v8.\n",
+ log_err(lc, "%s: ASR v%d detected, but we only support v8",
handler, asr->rb.resver);
}
@@ -358,10 +347,10 @@
* the two magic numbers, the version, and the pointer to the
* RAID table. Everything else appears to be unused in v8.
*/
- if (!(asr = alloc_private(lc, handler, sizeof(struct asr))))
+ if (!(asr = alloc_private(lc, handler, sizeof(*asr))))
goto bad0;
- if (!(asr->rt = alloc_private(lc, handler, sizeof(struct asr_raidtable))))
+ if (!(asr->rt = alloc_private(lc, handler, sizeof(*asr->rt))))
goto bad1;
if (!read_file(lc, handler, di->path, &asr->rb, size, asr_sboffset))
@@ -395,7 +384,28 @@
asr = NULL;
out:
- return (void*) asr;
+ return asr;
+}
+
+/* Read the whole metadata chunk at once */
+static uint8_t *read_metadata_chunk(struct lib_context *lc, struct dev_info *di,
+ uint64_t start)
+{
+ uint8_t *ret;
+ size_t size = (di->sectors - start) * ASR_DISK_BLOCK_SIZE;
+
+ if (!(ret = dbg_malloc(size)))
+ LOG_ERR(lc, ret, "%s: unable to allocate memory for %s",
+ handler, di->path);
+
+ if (!read_file(lc, handler, di->path, ret, size,
+ start * ASR_DISK_BLOCK_SIZE)) {
+ dbg_free(ret);
+ LOG_ERR(lc, NULL, "%s: unable to read metadata on %s",
+ handler, di->path);
+ }
+
+ return ret;
}
/*
@@ -405,20 +415,26 @@
static void file_metadata_areas(struct lib_context *lc, struct dev_info *di,
void *meta)
{
+ uint8_t *buf;
struct asr *asr = meta;
+ uint64_t start = asr->rb.raidtbl;
+
+ if (!(buf = read_metadata_chunk(lc, di, start)))
+ return;
/* Register the raid tables. */
- file_metadata(lc, handler, di->path, asr->rt,
+ file_metadata(lc, handler, di->path, buf,
ASR_DISK_BLOCK_SIZE * 17,
- (uint64_t)asr->rb.raidtbl * ASR_DISK_BLOCK_SIZE);
-
+ start * ASR_DISK_BLOCK_SIZE);
+
+ dbg_free(buf);
+
/* Record the device size if -D was specified. */
file_dev_size(lc, handler, di);
}
static int setup_rd(struct lib_context *lc, struct raid_dev *rd,
struct dev_info *di, void *meta, union read_info *info);
-
static struct raid_dev *asr_read(struct lib_context *lc,
struct dev_info *di)
{
@@ -438,8 +454,8 @@
/*
* Compose a 64-bit ID for device sorting.
- * Is hba:ch:lun:id ok? It seems to be the way the binary driver
- * does it...
+ * Is hba:ch:lun:id ok?
+ * It seems to be the way the binary driver does it...
*/
static inline uint64_t compose_id(struct asr_raid_configline *cl)
{
@@ -465,11 +481,8 @@
for (i = 0; i < asr->rt->elmcnt; i++) {
if (asr->rt->ent[i].raidlevel == FWL)
- {
toplevel = i;
- }
- else if (asr->rt->ent[i].raidlevel == FWL_2)
- {
+ else if (asr->rt->ent[i].raidlevel == FWL_2) {
toplevel = i;
break;
}
@@ -488,13 +501,10 @@
/* This MUST be done backwards! */
for (i = asr->rt->elmcnt - 1; i > -1; i--) {
- if (asr->rt->ent[i].raidmagic == asr->rb.drivemagic)
- {
+ if (asr->rt->ent[i].raidmagic == asr->rb.drivemagic) {
for (j = i - 1; j > -1; j--) {
if (asr->rt->ent[j].raidlevel == FWL)
- {
- return &asr->rt->ent[j];
- }
+ return asr->rt->ent + j;
}
}
}
@@ -502,9 +512,20 @@
return NULL;
}
+static struct raid_dev *find_spare(struct lib_context *lc) {
+ struct raid_dev *spare;
+
+ list_for_each_entry(spare, LC_RD(lc), list) {
+ if (spare->type == t_spare)
+ return spare;
+ }
+
+ return NULL;
+}
+
/* Wrapper for name() */
static char *js_name(struct lib_context *lc, struct raid_dev *rd,
- unsigned int subset)
+ unsigned int subset)
{
return name(lc, META(rd, asr));
}
@@ -523,8 +544,8 @@
if (rd->status & s_broken)
return 0;
- log_err(lc, "I/O error on device %s at sector %lu.",
- e_io->rd->di->path, e_io->sector);
+ log_err(lc, "%s: I/O error on device %s at sector %lu",
+ handler, e_io->rd->di->path, e_io->sector);
/* Mark the array as degraded and the disk as failed. */
rd->status = s_broken;
@@ -532,8 +553,90 @@
fwl->raidstate = LSU_COMPONENT_STATE_DEGRADED;
/* FIXME: Do we have to mark a parent too? */
- /* Indicate that this is indeed a failure. */
- return 1;
+ return 1; /* Indicate that this is indeed a failure. */
+}
+
+/*
+ * Helper routines for asr_group()
+ */
+static struct raid_set *do_spare(struct lib_context *lc, struct raid_dev *rd)
+{
+ struct raid_set *rs;
+
+ /*
+ * If this drive really _is_ attached to a specific
+ * RAID set, then just attach it. Really old HostRAID cards
+ * do this... but I don't have any hardware to test this.
+ */
+ /*
+ * FIXME: dmraid ignores spares attached to RAID arrays.
+ * For now, we'll let it get sucked into the ASR spare pool.
+ * If we need it, we'll reconfigure it; if not, nobody touches
+ * it.
+ *
+ * rs = find_set(lc, name(lc, asr), FIND_TOP, rd, LC_RS(lc),
+ * NO_CREATE, NO_CREATE_ARG);
+ */
+
+ /* Otherwise, make a global spare pool. */
+ rs = find_or_alloc_raid_set(lc, (char*)spare_array, FIND_TOP, rd,
+ LC_RS(lc), NO_CREATE, NO_CREATE_ARG);
+
+ /*
+ * Setting the type to t_spare guarantees that dmraid won't
+ * try to set up a real device-mapper mapping.
+ */
+ rs->type = t_spare;
+
+ /* Add the disk to the set. */
+ list_add_sorted(lc, &rs->devs, &rd->devs, dev_sort);
+ return rs;
+}
+
+#define BUFSIZE 128
+static struct raid_set *do_stacked(struct lib_context *lc, struct raid_dev *rd,
+ struct asr_raid_configline *cl)
+{
+ char buf[BUFSIZE], *path = rd->di->path;
+ struct raid_set *rs, *ss;
+ struct asr_raid_configline *fwl;
+ struct asr *asr = META(rd, asr);
+
+ /* First compute the name of the disk's direct parent. */
+ fwl = find_logical(asr);
+ if (!fwl)
+ LOG_ERR(lc, NULL, "%s: Failed to find RAID configuration "
+ "line on %s",
+ handler, path);
+
+ snprintf(buf, BUFSIZE, ".asr_%s_%x_donotuse",
+ fwl->name, fwl->raidmagic);
+
+ /* Now find said parent. */
+ rs = find_or_alloc_raid_set(lc, buf, FIND_ALL, rd, NO_LIST,
+ NO_CREATE, NO_CREATE_ARG);
+ if (!rs)
+ LOG_ERR(lc, NULL, "%s: Error creating RAID set for %s",
+ handler, path);
+
+ rs->stride = stride(cl);
+ rs->status = s_ok;
+ rs->type = type(fwl);
+
+ /* Add the disk to the set. */
+ list_add_sorted(lc, &rs->devs, &rd->devs, dev_sort);
+
+ /* Find the top level set. */
+ ss = join_superset(lc, js_name, NO_CREATE, set_sort, rs, rd);
+ if (!ss)
+ LOG_ERR(lc, NULL, "%s: Error creating top RAID set for %s",
+ handler, path);
+
+ ss->stride = stride(cl);
+ ss->status = s_ok;
+ /* FIXME: correct type (this crashed in stacked set code) */
+ ss->type = t_raid1; // type(&asr->rt->ent[top_idx]);
+ return ss;
}
/*
@@ -541,69 +644,35 @@
* which this disk belongs, and then attaching it. Note that there are other
* complications, such as two-layer arrays (RAID10).
*/
-#define BUFSIZE 128
static struct raid_set *asr_group(struct lib_context *lc, struct raid_dev *rd)
{
int top_idx;
struct asr *asr = META(rd, asr);
struct asr_raid_configline *cl = this_disk(asr);
- struct asr_raid_configline *fwl;
- struct raid_set *set, *sset;
- char buf[BUFSIZE];
+ struct raid_set *rs;
- if (T_SPARE(rd)) {
- /*
- * If this drive really _is_ attached to a specific
- * RAID set, then just attach it. Really old HostRAID cards
- * do this... but I don't have any hardware to test this.
- */
- /*
- * FIXME: dmraid ignores spares attached to RAID arrays.
- * For now, we'll let it get sucked into the ASR spare pool.
- * If we need it, we'll reconfigure it; if not, nobody touches
- * it.
- *
- set = find_set(lc, name(lc, asr), FIND_TOP, rd, LC_RS(lc),
- NO_CREATE, NO_CREATE_ARG);
- */
-
- /* Otherwise, make a global spare pool. */
- set = find_or_alloc_raid_set(lc, (char*)SPARE_ARRAY,
- FIND_TOP, rd, LC_RS(lc), NO_CREATE, NO_CREATE_ARG);
-
- /*
- * Setting the type to t_spare guarantees that dmraid won't
- * try to set up a real device-mapper mapping.
- */
- set->type = t_spare;
-
- /* Add the disk to the set. */
- list_add_sorted(lc, &set->devs, &rd->devs, dev_sort);
- return set;
- }
+ if (T_SPARE(rd))
+ return do_spare(lc, rd);
/* Find the top level FWL/FWL2 for this device. */
top_idx = find_toplevel(lc, asr);
- if (top_idx < 0) {
- LOG_ERR(lc, NULL, "Can't find a logical array config "
- "for disk %x\n",
- asr->rb.drivemagic);
- }
+ if (top_idx < 0)
+ LOG_ERR(lc, NULL, "%s: Can't find a logical array config "
+ "for disk %x",
+ handler, asr->rb.drivemagic);
/* This is a simple RAID0/1 array. Find the set. */
- if (asr->rt->ent[top_idx].raidlevel == FWL)
- {
- set = find_or_alloc_raid_set(lc, name(lc, asr),
- FIND_TOP, rd, LC_RS(lc), NO_CREATE, NO_CREATE_ARG);
-
- set->stride = stride(cl);
- set->status = s_ok;
- set->type = type(find_logical(asr));
+ if (asr->rt->ent[top_idx].raidlevel == FWL) {
+ rs = find_or_alloc_raid_set(lc, name(lc, asr), FIND_TOP,
+ rd, LC_RS(lc), NO_CREATE,
+ NO_CREATE_ARG);
+ rs->stride = stride(cl);
+ rs->status = s_ok;
+ rs->type = type(find_logical(asr));
/* Add the disk to the set. */
- list_add_sorted(lc, &set->devs, &rd->devs, dev_sort);
-
- return set;
+ list_add_sorted(lc, &rs->devs, &rd->devs, dev_sort);
+ return rs;
}
/*
@@ -612,59 +681,276 @@
* and use join_superset to attach the parent set to the top set.
*/
if (asr->rt->ent[top_idx].raidlevel == FWL_2)
- {
- /* First compute the name of the disk's direct parent. */
- fwl = find_logical(asr);
- snprintf(buf, BUFSIZE, ".asr_%s_%x_donotuse",
- fwl->name, fwl->raidmagic);
-
- /* Now find said parent. */
- set = find_or_alloc_raid_set(lc, buf,
- FIND_ALL, rd, NO_LIST, NO_CREATE, NO_CREATE_ARG);
-
- if (!set)
- LOG_ERR(lc, NULL, "Error creating RAID set.\n");
-
- set->stride = stride(cl);
- set->status = s_ok;
- set->type = type(fwl);
+ return do_stacked(lc, rd, cl);
- /* Add the disk to the set. */
- list_add_sorted(lc, &set->devs, &rd->devs, dev_sort);
-
- /* Find the top level set. */
- sset = join_superset(lc, js_name, NO_CREATE,
- set_sort, set, rd);
-
- if (!sset)
- LOG_ERR(lc, NULL, "Error creating top RAID set.\n");
-
- sset->stride = stride(cl);
- sset->status = s_ok;
- sset->type = type(&asr->rt->ent[top_idx]);
- return sset;
+ /* If we land here, something's seriously wrong. */
+ LOG_ERR(lc, NULL, "%s: Top level array config is not FWL/FWL2?",
+ handler);
+}
+
+/* deletes configline from metadata of given asr, by index. */
+static void delete_configline(struct asr *asr, int index)
+{
+ struct asr_raid_configline *cl, *end;
+
+ asr->rt->elmcnt--;
+ cl = asr->rt->ent + index;
+ end = asr->rt->ent + asr->rt->elmcnt;
+ while (cl < end) {
+ memcpy(cl, cl + 1, sizeof(*cl));
+ ++cl;
}
+}
- /* If we land here, something's seriously wrong. */
- LOG_ERR(lc, NULL, "Top level array config is not FWL/FWL2?\n");
+/* Find the newest configline entry in raid set and return a pointer to it. */
+static struct raid_dev *find_newest_drive(struct raid_set *rs)
+{
+ struct asr *asr;
+ struct raid_dev *device, *newest = NULL;
+ uint16_t newest_raidseq = 0;
+ int i;
+
+ list_for_each_entry(device, &rs->devs, devs) {
+ asr = META(device, asr);
+ // FIXME: We should be able to assume each configline
+ // in a single drive has the same raidseq as the rest
+ // in that drive. We're doing too much work here.
+ for (i = 0; i < asr->rt->elmcnt; ++i) {
+ if (asr->rt->ent[i].raidseq >= newest_raidseq) {
+ newest_raidseq = asr->rt->ent[i].raidseq;
+ newest = device;
+ }
+ }
+ }
+
+ return newest;
+}
+
+/* Creates a random integer for a drive magic section */
+static uint32_t create_drivemagic() {
+
+ srand(time(NULL));
+ return rand() + rand();
+}
+
+static int spare(struct lib_context *lc, struct raid_dev *rd,
+ struct asr *asr)
+{
+ struct asr_raid_configline *cl;
+
+ /* If the magic is already 0xFFFFFFFF, exit */
+ if (asr->rt->raidmagic == 0xFFFFFFFF)
+ return 1;
+
+ /* Otherwise, set the magic */
+ asr->rt->raidmagic = 0xFFFFFFFF;
+
+ /* Erase all the CLs, create the two defaults and exit */
+ /* FIXME: How to set blockstoragetid? */
+ asr->rt->elmcnt = 2;
+
+ /* Note the presence of an array of spares in first config
+ * line entry. */
+ cl = asr->rt->ent;
+ cl->raidmagic = 0xFFFFFFFF;
+ cl->raidseq = 0;
+ cl->name[0] = 0;
+ cl->raidcnt = 1;
+ cl->raidtype = ASR_RAIDSPR;
+ cl->lcapcty = rd->di->sectors;
+ cl->raidlevel = FWL;
+ cl++;
+
+ /* Actually describe the disk: it's a spare. */
+ cl->raidmagic = asr->rb.drivemagic;
+ cl->raidseq = 0;
+ cl->name[0] = 0;
+ cl->raidcnt = 0;
+ cl->raidtype = ASR_RAIDSPR;
+ cl->lcapcty = rd->di->sectors;
+ cl->raidlevel = FWP;
+
+ return 1;
+}
+
+/* Returns (boolean) whether or not the drive described by the given configline
+ * is in the given raid_set. */
+static int in_raid_set(struct asr_raid_configline *cl, struct raid_set *rs)
+{
+ struct asr *asr;
+ struct raid_dev *d;
+
+ list_for_each_entry(d, &rs->devs, devs) {
+ asr = META(d, asr);
+ if (cl->raidmagic == asr->rb.drivemagic)
+ return 1;
+ }
+ return 0;
+}
+
+/* Delete extra configlines which would otherwise trip us up. */
+static int cleanup_configlines(struct raid_dev *rd, struct raid_set *rs)
+{
+ struct asr *a;
+ struct raid_dev *d;
+ struct asr_raid_configline *cl;
+ int clcnt;
+
+ list_for_each_entry(d, &rs->devs, devs) {
+ a = META(d, asr);
+
+ cl = a->rt->ent;
+ for (clcnt = 0; clcnt < a->rt->elmcnt; /* done in loop */ ) {
+ /* If it's in the seen list, or is a logical drive,
+ * end iteration. The idea: get rid of configlines
+ * which describe devices which are no longer in the
+ * array.
+ * FIXME: If our topmost level is FWL2, we could have
+ * FWL entries which need to be removed, right? We need
+ * to check for this condition, too. */
+ if (cl->raidlevel != FWP || in_raid_set(cl, rs)) {
+ cl++;
+ clcnt++;
+ } else {
+ /* Delete entry. After deleting, a new entry is
+ * found at *cl (a->rt->ent[clcnt]), so don't
+ * increment counter/pointer; otherwise we'd
+ * skip an entry.
+ */
+ delete_configline(a, clcnt);
+ }
+ }
+ }
+ return 1;
+}
+
+/* Add a CL entry */
+static int create_configline(struct raid_set *rs, struct asr *asr,
+ struct asr *a, struct raid_dev* newest)
+{
+ if (asr->rt->elmcnt >= RCTBL_MAX_ENTRIES) {
+ return 0;
+ }
+
+ struct asr *newest_asr;
+ struct asr_raid_configline *cl;
+
+ newest_asr = META(newest, asr);
+
+ cl = asr->rt->ent + asr->rt->elmcnt;
+ asr->rt->elmcnt++;
+
+ /* Use first raidseq, below: FIXME - don't assume all CLS are
+ * consistent */
+ cl->raidmagic = a->rb.drivemagic;
+ cl->raidseq = newest_asr->rt->ent[0].raidseq;
+ cl->strpsize = newest_asr->rt->ent[0].strpsize;
+ strcpy((char*) cl->name, &rs->name[4]); /* starts after "asr_" */
+ cl->raidcnt = 0;
+
+ /* Convert rs->type to an ASR_RAID type for the CL */
+ switch (rs->type) {
+ case t_raid0:
+ cl->raidtype = ASR_RAID0;
+ break;
+ case t_raid1:
+ cl->raidtype = ASR_RAID1;
+ break;
+ default:
+ return 0;
+ }
+ cl->lcapcty = newest_asr->rt->ent[0].lcapcty;
+ cl->raidlevel = FWP;
+ return 1;
+}
+
+/* Update metadata to reflect the current raid set configuration.
+ * Returns boolean success. */
+static int update_metadata(struct lib_context *lc, struct raid_dev *rd,
+ struct asr *asr)
+{
+ struct raid_set *rs;
+ struct asr_raid_configline *cl;
+ struct raid_dev *d, *newest;
+ struct asr *a;
+
+ /* Find the raid set */
+ rs = get_raid_set(lc, rd);
+ if (!rs) {
+ /* Array-less disks ... have no CLs ? */
+ asr->rt->elmcnt = 0;
+ return 1;
+ }
+
+ /* If this is the spare array... */
+ if (!strcmp(spare_array, rs->name))
+ return spare(lc, rd, asr);
+
+ /* Find newest drive for use below */
+ if (!(newest = find_newest_drive(rs)))
+ return 0;
+
+ /* If the drive magic is 0xFFFFFFFF, assign a random one. */
+ if (asr->rb.drivemagic == 0xFFFFFFFF)
+ asr->rb.drivemagic = create_drivemagic();
+
+ /* Make sure the raid type agrees with the metadata */
+ if (type(this_disk(asr)) == t_spare) {
+ struct asr *newest_asr = META(newest, asr);
+
+ /* copy entire table from newest drive */
+ asr->rt->elmcnt = newest_asr->rt->elmcnt;
+ memcpy(asr->rt->ent, newest_asr->rt->ent,
+ asr->rt->elmcnt * sizeof(*asr->rt->ent));
+ }
+
+ /* Increment the top level CL's raid count */
+ /* Fixme: What about the the FWLs in a FWL2 setting? */
+ cl = asr->rt->ent + find_toplevel(lc, asr);
+ cl->raidseq++;
+
+ /* For each disk in the rs */
+ list_for_each_entry(d, &rs->devs, devs) {
+ a = META(d, asr);
+
+ /* If it's in the CL already... */
+ if ((cl = get_config(asr, a->rb.drivemagic))) {
+ /* Increment seq number */
+ cl->raidseq++;
+ continue;
+ }
+
+ /* If the magic is 0xFFFFFFFF, assign a random one */
+ if (a->rb.drivemagic == 0xFFFFFFFF) {
+ a->rb.drivemagic = create_drivemagic();
+ }
+
+ if (!(newest = find_newest_drive(rs)))
+ return 0;
+
+ create_configline(rs, asr, a, newest);
+ }
+
+ cleanup_configlines(rd, rs);
+
+ return 1;
}
+
/* Write metadata. */
static int asr_write(struct lib_context *lc, struct raid_dev *rd, int erase)
{
- int ret, i, j;
struct asr *asr = META(rd, asr);
- int elmcnt = asr->rt->elmcnt;
+ int elmcnt = asr->rt->elmcnt, i, ret;
+
+ /* Update the metadata if we're not erasing it. */
+ if (!erase)
+ update_metadata(lc, rd, asr);
/* Untruncate trailing whitespace in the name. */
- for (i = 0; i < elmcnt; i++) {
- for (j = 15; j >= 0; j--) {
- if (asr->rt->ent[i].name[j] == 0)
- break;
- }
- asr->rt->ent[i].name[j] = ' ';
- }
+ for (i = 0; i < elmcnt; i++)
+ handle_white_space(asr->rt->ent[i].name, UNTRUNCATE);
/* Compute checksum */
asr->rt->rchksum = compute_checksum(asr);
@@ -679,13 +965,8 @@
to_cpu(asr, ASR_BLOCK | ASR_TABLE | ASR_EXTTABLE);
/* Truncate trailing whitespace in the name. */
- for (i = 0; i < elmcnt; i++) {
- for (j = 15; j >= 0; j--) {
- if (asr->rt->ent[i].name[j] != ' ')
- break;
- }
- asr->rt->ent[i].name[j + 1] = 0;
- }
+ for (i = 0; i < elmcnt; i++)
+ handle_white_space(asr->rt->ent[i].name, TRUNCATE);
return ret;
}
@@ -699,7 +980,8 @@
{
/* Get the logical drive */
struct asr_raid_configline *cl = find_logical(META(rd, asr));
- return (cl ? cl->raidcnt : 0);
+
+ return cl ? cl->raidcnt : 0;
}
/* Check a RAID device */
@@ -707,7 +989,7 @@
struct raid_dev *rd, void *context)
{
/* FIXME: Assume non-broken means ok. */
- return (rd->type != s_broken);
+ return rd->type != s_broken;
}
/* Start the recursive RAID set check. */
@@ -840,34 +1122,30 @@
struct asr_raid_configline *cl = this_disk(asr);
if (!cl)
- LOG_ERR(lc, 0, "%s: Could not find current disk!\n",
- handler);
+ LOG_ERR(lc, 0, "%s: Could not find current disk!", handler);
/* We need two metadata areas */
- if (!(rd->meta_areas = alloc_meta_areas(lc, rd, handler, 2)))
+ if (!(ma = rd->meta_areas = alloc_meta_areas(lc, rd, handler, 2)))
return 0;
/* First area: raid reserved block. */
- ma = rd->meta_areas;
ma->offset = ASR_CONFIGOFFSET >> 9;
ma->size = ASR_DISK_BLOCK_SIZE;
- ma->area = (void*) asr;
+ (ma++)->area = asr;
/* Second area: raid table. */
- ma++;
ma->offset = asr->rb.raidtbl;
ma->size = ASR_DISK_BLOCK_SIZE * 16;
- ma->area = (void*) asr->rt;
+ ma->area = asr->rt;
/* Now set up the rest of the metadata info */
rd->di = di;
rd->fmt = &asr_format;
-
rd->status = disk_status(cl);
rd->type = type(cl);
-
rd->offset = ASR_DATAOFFSET;
- rd->sectors = cl->lcapcty;
+ if (!(rd->sectors = cl->lcapcty))
+ return log_zero_sectors(lc, di->path, handler);
return (rd->name = name(lc, asr)) ? 1 : 0;
}
--- dmraid/lib/format/ataraid/asr.h 2008/02/22 16:57:36 1.1
+++ dmraid/lib/format/ataraid/asr.h 2008/02/22 17:04:35 1.2
@@ -137,7 +137,8 @@
uint16_t blockStorageTid;
uint32_t curAppBlock;
uint32_t appBurstCount;
- uint8_t name[16]; /* Full name of the array. */
+#define ASR_NAMELEN 16
+ uint8_t name[ASR_NAMELEN]; /* Full name of the array. */
} __attribute__ ((packed));
struct asr_raidtable
@@ -148,6 +149,7 @@
uint32_t rversion; /* Version of the RAID config table */
uint16_t maxelm; /* Maximum number of elements */
uint16_t elmcnt; /* Element Count (number used) */
+#define ASR_TBLELMCNT 7
uint16_t elmsize; /* Size of an individual raidCLine */
uint16_t rchksum; /* RAID table check sum
(no rconfTblV2)*/
--- dmraid/lib/format/ataraid/hpt37x.c 2008/02/22 16:57:36 1.1
+++ dmraid/lib/format/ataraid/hpt37x.c 2008/02/22 17:04:35 1.2
@@ -1,4 +1,6 @@
/*
+ * Highpoint 37X ATARAID series metadata format handler.
+ *
* Copyright (C) 2004,2005 Heinz Mauelshagen, Red Hat GmbH.
* All rights reserved.
*
@@ -6,8 +8,6 @@
*/
/*
- * Highpoint 37X ATARAID metadata format handler.
- *
* hpt37x_read(), hpt37x_group() and group_rd() profited from
* Carl-Daniel Hailfinger's raiddetect code.
*/
@@ -70,21 +70,21 @@
return hpt->magic == HPT37X_MAGIC_BAD ? s_broken : s_ok;
}
-/* Mapping of HPT 37X types to generic types. */
-static struct types types[] = {
- { HPT37X_T_SINGLEDISK, t_linear},
- { HPT37X_T_SPAN, t_linear},
- { HPT37X_T_RAID0, t_raid0},
- { HPT37X_T_RAID1, t_raid1},
- { HPT37X_T_RAID01_RAID0, t_raid0},
- { HPT37X_T_RAID01_RAID1, t_raid1},
- /* FIXME: support RAID 3+5 */
- { 0, t_undef}
-};
-
/* Neutralize disk type. */
static enum type type(struct hpt37x *hpt)
{
+ /* Mapping of HPT 37X types to generic types. */
+ static struct types types[] = {
+ { HPT37X_T_SINGLEDISK, t_linear},
+ { HPT37X_T_SPAN, t_linear},
+ { HPT37X_T_RAID0, t_raid0},
+ { HPT37X_T_RAID1, t_raid1},
+ { HPT37X_T_RAID01_RAID0, t_raid0},
+ { HPT37X_T_RAID01_RAID1, t_raid1},
+ /* FIXME: support RAID 3+5 */
+ { 0, t_undef},
+ };
+
return hpt->magic_0 ?
rd_type(types, (unsigned int) hpt->type) : t_spare;
}
@@ -103,6 +103,16 @@
(META(RD_RS(RS(pos)), hpt37x))->order;
}
+/* Magic check. */
+static int check_magic(void *meta)
+{
+ struct hpt37x *hpt = meta;
+
+ return (hpt->magic == HPT37X_MAGIC_OK ||
+ hpt->magic == HPT37X_MAGIC_BAD) &&
+ hpt->disk_number < 8;
+}
+
/*
* Read a Highpoint 37X RAID device.
*/
@@ -113,7 +123,6 @@
static void to_cpu(void *meta)
{
struct hpt37x *hpt = meta;
- struct hpt37x_errorlog *l;
CVT32(hpt->magic);
CVT32(hpt->magic_0);
@@ -123,23 +132,25 @@
CVT32(hpt->disk_mode);
CVT32(hpt->boot_mode);
- for (l = hpt->errorlog;
- l < hpt->errorlog + hpt->error_log_entries;
- l++) {
- CVT32(l->timestamp);
- CVT32(l->lba);
+ /* Only convert error log entries in case we discover proper magic */
+ if (check_magic(meta)) {
+ struct hpt37x_errorlog *l;
+
+ for (l = hpt->errorlog;
+ l < hpt->errorlog +
+ min(hpt->error_log_entries, HPT37X_MAX_ERRORLOG);
+ l++) {
+ CVT32(l->timestamp);
+ CVT32(l->lba);
+ }
}
}
#endif
-/* Magic check. */
+/* Use magic check to tell, if this is Highpoint 37x */
static int is_hpt37x(struct lib_context *lc, struct dev_info *di, void *meta)
{
- struct hpt37x *hpt = meta;
-
- return (hpt->magic == HPT37X_MAGIC_OK ||
- hpt->magic == HPT37X_MAGIC_BAD) &&
- hpt->disk_number < 8;
+ return check_magic(meta);
}
static int setup_rd(struct lib_context *lc, struct raid_dev *rd,
--- dmraid/lib/format/ataraid/hpt37x.h 2008/02/22 16:57:36 1.1
+++ dmraid/lib/format/ataraid/hpt37x.h 2008/02/22 17:04:35 1.2
@@ -79,6 +79,7 @@
uint8_t boot_protect;
uint8_t error_log_entries;
uint8_t error_log_index;
+#define HPT37X_MAX_ERRORLOG 32
struct hpt37x_errorlog
{
uint32_t timestamp;
@@ -90,7 +91,7 @@
uint8_t status;
uint8_t sectors;
uint32_t lba;
- } errorlog[32];
+ } errorlog[HPT37X_MAX_ERRORLOG];
uint8_t filler[60];
} __attribute__ ((packed));
#endif
--- dmraid/lib/format/ataraid/hpt45x.c 2008/02/22 16:57:36 1.1
+++ dmraid/lib/format/ataraid/hpt45x.c 2008/02/22 17:04:35 1.2
@@ -1,4 +1,6 @@
/*
+ * Highpoint 45X ATARAID series metadata format handler.
+ *
* Copyright (C) 2004,2005 Heinz Mauelshagen, Red Hat GmbH.
* All rights reserved.
*
@@ -6,8 +8,6 @@
*/
/*
- * Highpoint 45X ATARAID metadata format handler.
- *
* hpt45x_read(), hpt45x_group() and group_rd() profited from
* Carl-Daniel Hailfinger's raiddetect code.
*/
@@ -65,18 +65,18 @@
return hpt->magic == HPT45X_MAGIC_BAD ? s_broken : s_ok;
}
-/* Mapping of HPT 45X types to generic types */
-static struct types types[] = {
- { HPT45X_T_SPAN, t_linear},
- { HPT45X_T_RAID0, t_raid0},
- { HPT45X_T_RAID1, t_raid1},
-/* FIXME: handle RAID 3+5 */
- { 0, t_undef}
-};
-
/* Neutralize disk type */
static enum type type(struct hpt45x *hpt)
{
+ /* Mapping of HPT 45X types to generic types */
+ static struct types types[] = {
+ { HPT45X_T_SPAN, t_linear},
+ { HPT45X_T_RAID0, t_raid0},
+ { HPT45X_T_RAID1, t_raid1},
+ /* FIXME: handle RAID 4+5 */
+ { 0, t_undef},
+ };
+
return hpt->magic_0 ? rd_type(types, (unsigned int) hpt->type) :
t_spare;
}
--- dmraid/lib/format/ataraid/isw.c 2008/02/22 16:57:36 1.1
+++ dmraid/lib/format/ataraid/isw.c 2008/02/22 17:04:35 1.2
@@ -1,4 +1,6 @@
/*
+ * Intel Software RAID metadata format handler.
+ *
* Copyright (C) 2004,2005 Heinz Mauelshagen, Red Hat GmbH.
* All rights reserved.
*
@@ -6,8 +8,6 @@
*/
/*
- * Intel Software RAID metadata format handler.
- *
* isw_read() etc. profited from Carl-Daniel Hailfinger's raiddetect code.
*
* Profited from the Linux 2.4 iswraid driver by
@@ -101,19 +101,16 @@
return s_undef;
}
-/*
- * Mapping of Intel types to generic types.
- */
-static struct types types[] = {
- { ISW_T_RAID0, t_raid0},
- { ISW_T_RAID1, t_raid1},
- { ISW_T_RAID5, t_raid5_la},
- { 0, t_undef},
-};
-
/* Neutralize disk type. */
static enum type type(struct raid_dev *rd)
{
+ /* Mapping of Intel types to generic types. */
+ static struct types types[] = {
+ { ISW_T_RAID0, t_raid0},
+ { ISW_T_RAID1, t_raid1},
+ { ISW_T_RAID5, t_raid5_la},
+ { 0, t_undef},
+ };
struct isw_dev *dev = rd->private.ptr;
return dev ? rd_type(types, (unsigned int) dev->vol.map.raid_level) :
@@ -229,7 +226,8 @@
static int is_isw(struct lib_context *lc, struct dev_info *di, struct isw *isw)
{
- if (strncmp((const char *) isw->sig, MPB_SIGNATURE, sizeof(MPB_SIGNATURE) - 1))
+ if (strncmp((const char *) isw->sig, MPB_SIGNATURE,
+ sizeof(MPB_SIGNATURE) - 1))
return 0;
/* Check version info, older versions supported */
@@ -437,9 +435,10 @@
r->fmt = rd->fmt;
r->offset = dev->vol.map.pba_of_lba0;
- r->sectors = dev->vol.map.blocks_per_member;
+ if ((r->sectors = dev->vol.map.blocks_per_member))
+ goto out;
- goto out;
+ log_zero_sectors(lc, rd->di->path, handler);
free:
free_raid_dev(lc, &r);
@@ -792,7 +791,8 @@
rd->fmt = &isw_format;
rd->offset = ISW_DATAOFFSET;
- rd->sectors = info->u64 >> 9;
+ if (!(rd->sectors = info->u64 >> 9))
+ return log_zero_sectors(lc, di->path, handler);
rd->status = status(lc, rd);
rd->type = t_group;
--- dmraid/lib/format/ataraid/jm.c 2008/02/22 16:57:36 1.1
+++ dmraid/lib/format/ataraid/jm.c 2008/02/22 17:04:35 1.2
@@ -1,13 +1,12 @@
/*
+ * JMicron metadata format handler.
+ *
* Copyright (C) 2006 Heinz Mauelshagen, Red Hat GmbH.
* All rights reserved.
*
* See file LICENSE at the top of this source tree for license information.
*/
-/*
- * JMicron ATARAID metadata format handler.
- */
#define HANDLER "jmicron"
#include "internal.h"
@@ -59,18 +58,18 @@
return jm->attribute & ~(JM_MOUNT|JM_BOOTABLE|JM_BADSEC|JM_ACTIVE|JM_UNSYNC|JM_NEWEST) ? s_broken : s_ok;
}
-/* Mapping of JM types to generic types */
-static struct types types[] = {
- { JM_T_JBOD, t_linear},
- { JM_T_RAID0, t_raid0},
- { JM_T_RAID01, t_raid1},
- { JM_T_RAID1, t_raid1},
- { 0, t_undef}
-};
-
/* Neutralize disk type */
static enum type type(struct jm *jm)
{
+ /* Mapping of JM types to generic types */
+ static struct types types[] = {
+ { JM_T_JBOD, t_linear},
+ { JM_T_RAID0, t_raid0},
+ { JM_T_RAID01, t_raid1},
+ { JM_T_RAID1, t_raid1},
+ { 0, t_undef},
+ };
+
return rd_type(types, (unsigned int) jm->mode);
}
@@ -83,7 +82,8 @@
while (count--)
sum += *p++;
- return sum;
+ /* FIXME: shouldn't this be one value only ? */
+ return sum == 0 || sum == 1;
}
static inline unsigned int segment(uint32_t m)
@@ -219,7 +219,7 @@
return !strncmp((const char*) jm->signature,
JM_SIGNATURE, JM_SIGNATURE_LEN)
- && !checksum(jm);
+ && checksum(jm);
}
static int setup_rd(struct lib_context *lc, struct raid_dev *rd,
--- dmraid/lib/format/ataraid/lsi.c 2008/02/22 16:57:36 1.1
+++ dmraid/lib/format/ataraid/lsi.c 2008/02/22 17:04:35 1.2
@@ -1,4 +1,6 @@
/*
+ * LSI Logic MegaRAID (and MegaIDE ?) ATARAID metadata format handler.
+ *
* Copyright (C) 2004,2005 Heinz Mauelshagen, Red Hat GmbH.
* All rights reserved.
*
@@ -6,10 +8,7 @@
*/
/*
- * LSI Logic MegaRAID (and MegaIDE ?) ATARAID metadata format handler.
- *
- * Needs more metadata reengineering and grouping logic coding.
- *
+ * FIXME: needs more metadata reengineering and grouping logic coding.
*/
#define HANDLER "lsi"
@@ -63,17 +62,17 @@
return ret;
}
-/* Mapping of LSI Logic types to generic types */
-static struct types types[] = {
- { LSI_T_RAID0, t_raid0 },
- { LSI_T_RAID1, t_raid1 },
- { LSI_T_RAID10, t_raid0 },
- { 0, t_undef}
-};
-
/* Neutralize disk type */
static enum type type(struct lsi *lsi)
{
+ /* Mapping of LSI Logic types to generic types */
+ static struct types types[] = {
+ { LSI_T_RAID0, t_raid0 },
+ { LSI_T_RAID1, t_raid1 },
+ { LSI_T_RAID10, t_raid0 },
+ { 0, t_undef}
+ };
+
return rd_type(types, (unsigned int) lsi->type);
}
@@ -353,7 +352,8 @@
rd->offset = LSI_DATAOFFSET;
/* FIXME: propper size ? */
- rd->sectors = rd->meta_areas->offset;
+ if (!(rd->sectors = rd->meta_areas->offset))
+ return log_zero_sectors(lc, di->path, handler);
return (rd->name = name(lc, rd, 1)) ? 1 : 0;
}
--- dmraid/lib/format/ataraid/nv.c 2008/02/22 16:57:36 1.1
+++ dmraid/lib/format/ataraid/nv.c 2008/02/22 17:04:35 1.2
@@ -1,4 +1,6 @@
/*
+ * NVidia NVRAID metadata format handler.
+ *
* Copyright (C) 2004 NVidia Corporation. All rights reserved.
* Copyright (C) 2004,2005 Heinz Mauelshagen, Red Hat GmbH.
* All rights reserved.
@@ -6,9 +8,6 @@
* See file LICENSE at the top of this source tree for license information.
*/
-/*
- * NVidia NVRAID metadata format handler.
- */
#define HANDLER "nvidia"
#include "internal.h"
@@ -62,45 +61,39 @@
return ret;
}
-/* Mapping of nv types to generic types */
-static struct types types[] = {
- { NV_LEVEL_JBOD, t_linear },
- { NV_LEVEL_0, t_raid0 },
- { NV_LEVEL_1, t_raid1 },
- { NV_LEVEL_1_0, t_raid0 }, /* Treat as 0 here, add mirror later */
- { NV_LEVEL_3, t_raid4 },
- { NV_LEVEL_5_SYM, t_raid5_ls },
- { NV_LEVEL_UNKNOWN, t_spare}, /* FIXME: UNKNOWN = spare ? */
- /* FIXME: The ones below don't really map to anything ?? */
- { NV_LEVEL_10, t_undef },
- { NV_LEVEL_5, t_undef }, /* Asymmetric RAID 5 is not used */
-};
-
static enum status status(struct nv *nv)
{
- if (NV_BROKEN(nv))
- return s_broken;
-
- switch(nv->array.raidJobCode) {
- case NV_IDLE:
- return s_ok;
-
- case NV_SCDB_INIT_RAID:
- case NV_SCDB_SYNC_RAID:
- return s_nosync;
-
- case NV_SCDB_REBUILD_RAID:
- case NV_SCDB_UPGRADE_RAID:
- return s_inconsistent;
- }
+ static struct states states[] = {
+ { NV_IDLE, s_ok },
+ { NV_SCDB_INIT_RAID, s_nosync },
+ { NV_SCDB_SYNC_RAID, s_nosync },
+ { NV_SCDB_REBUILD_RAID, s_inconsistent },
+ { NV_SCDB_UPGRADE_RAID, s_inconsistent },
+ { 0, s_undef },
+ };
- return s_broken;
+ return NV_BROKEN(nv) ?
+ s_broken : rd_status(states, nv->array.raidJobCode, EQUAL);
}
/* Neutralize disk type using generic metadata type mapping function. */
static enum type type(struct nv *nv)
{
uint8_t stripeWidth = nv->array.stripeWidth;
+ /* Mapping of nv types to generic types */
+ static struct types types[] = {
+ { NV_LEVEL_JBOD, t_linear },
+ { NV_LEVEL_0, t_raid0 },
+ { NV_LEVEL_1, t_raid1 },
+ /* Treat as 0 here, add mirror later */
+ { NV_LEVEL_1_0, t_raid0 },
+ { NV_LEVEL_3, t_raid4 },
+ { NV_LEVEL_5_SYM, t_raid5_ls },
+ { NV_LEVEL_UNKNOWN, t_spare}, /* FIXME: UNKNOWN = spare ? */
+ /* FIXME: The ones below don't really map to anything ?? */
+ { NV_LEVEL_10, t_undef },
+ { NV_LEVEL_5, t_undef }, /* Asymmetric RAID 5 is not used */
+ };
/*
* FIXME: is there a direct way to decide what
@@ -426,7 +419,8 @@
rd->type = type(nv);
rd->offset = NV_DATAOFFSET;
- rd->sectors = rd->meta_areas->offset;
+ if (!(rd->sectors = rd->meta_areas->offset))
+ return log_zero_sectors(lc, di->path, handler);
return (rd->name = name(lc, rd, 1)) ? 1 : 0;
}
--- dmraid/lib/format/ataraid/pdc.c 2008/02/22 16:57:36 1.1
+++ dmraid/lib/format/ataraid/pdc.c 2008/02/22 17:04:35 1.2
@@ -1,4 +1,6 @@
/*
+ * Promise FastTrak ATARAID metadata format handler.
+ *
* Copyright (C) 2004,2005 Heinz Mauelshagen, Red Hat GmbH.
* All rights reserved.
*
@@ -6,8 +8,6 @@
*/
/*
- * Promise FastTrak ATARAID metadata format handler.
- *
* pdc_read() and pdc_group() profited from
* Carl-Daniel Hailfinger's raiddetect code.
*/
@@ -65,18 +65,7 @@
return PDC_BROKEN(pdc) ? s_broken : s_ok;
}
-/*
- * Mapping of Promise types to generic types.
- */
#define PDC_T_RAID10 0x2 /* Not defind by Promise (yet). */
-static struct types types[] = {
- { PDC_T_SPAN, t_linear},
- { PDC_T_RAID0, t_raid0},
- { PDC_T_RAID1, t_raid1},
- { PDC_T_RAID10, t_raid0},
- { 0, t_undef}
-};
-
static int is_raid10(struct pdc *pdc)
{
return pdc->raid.type == PDC_T_RAID10 ||
@@ -86,6 +75,15 @@
/* Neutralize disk type */
static enum type type(struct pdc *pdc)
{
+ /* Mapping of Promise types to generic types. */
+ static struct types types[] = {
+ { PDC_T_SPAN, t_linear},
+ { PDC_T_RAID0, t_raid0},
+ { PDC_T_RAID1, t_raid1},
+ { PDC_T_RAID10, t_raid0},
+ { 0, t_undef}
+ };
+
if (is_raid10(pdc))
pdc->raid.type = PDC_T_RAID10;
--- dmraid/lib/format/ataraid/sil.c 2008/02/22 16:57:36 1.1
+++ dmraid/lib/format/ataraid/sil.c 2008/02/22 17:04:35 1.2
@@ -1,13 +1,12 @@
/*
+ * Silicon Image Medley ATARAID metadata format handler.
+ *
* Copyright (C) 2004,2005 Heinz Mauelshagen, Red Hat GmbH.
* All rights reserved.
*
* See file LICENSE at the top of this source tree for license information.
*/
-/*
- * Silicon Image Medley ATARAID metadata format handler.
- */
#define HANDLER "sil"
#include "internal.h"
@@ -58,31 +57,30 @@
*/
static enum status status(struct sil *sil)
{
- switch (sil->mirrored_set_state) {
- case SIL_OK:
- case SIL_MIRROR_SYNC:
- return s_ok;
-
- case SIL_MIRROR_NOSYNC:
- return s_nosync;
- }
+ struct states states[] = {
+ { SIL_OK, s_ok },
+ { SIL_MIRROR_SYNC, s_ok },
+ { SIL_MIRROR_NOSYNC, s_nosync },
+ { 0, s_broken },
+ };
- return s_broken;
+ return rd_status(states, sil->mirrored_set_state, EQUAL);
}
-/* Mapping of SIL 680 types to generic types */
-static struct types types[] = {
- { SIL_T_SPARE, t_spare},
- { SIL_T_RAID0, t_raid0},
- { SIL_T_RAID5, t_raid5_ls},
- { SIL_T_RAID1, t_raid1},
- { SIL_T_RAID10, t_raid0},
- { 0, t_undef}
-};
-
/* Neutralize disk type */
static enum type type(struct sil *sil)
{
+ /* Mapping of SIL 680 types to generic types */
+ static struct types types[] = {
+ { SIL_T_SPARE, t_spare},
+ { SIL_T_JBOD, t_linear},
+ { SIL_T_RAID0, t_raid0},
+ { SIL_T_RAID5, t_raid5_ls},
+ { SIL_T_RAID1, t_raid1},
+ { SIL_T_RAID10, t_raid0},
+ { 0, t_undef}
+ };
+
return rd_type(types, (unsigned int) sil->type);
}
@@ -179,8 +177,6 @@
if (!(sils = dbg_malloc(AREAS * sizeof(*sils))))
goto out;
- memset(sils, 0, AREAS * sizeof(*sils));
-
/* Read the 4 metadata areas. */
for (i = valid = 0; i < AREAS; i++) {
if (!(sil = alloc_private_and_read(lc, handler, sizeof(*sil),
@@ -316,6 +312,7 @@
list_add_sorted(lc, &rs->devs, &rd->devs, dev_sort);
switch (sil->type) {
+ case SIL_T_JBOD:
case SIL_T_RAID0:
case SIL_T_RAID1:
case SIL_T_RAID5:
@@ -533,35 +530,37 @@
static struct sil *quorate(struct lib_context *lc, struct dev_info *di,
struct sil *sils[])
{
- unsigned int areas = 0, i, j;
- struct sil *sil;
+ unsigned int areas = 0, i, ident = 0, j;
+ struct sil *sil = NULL, *tmp;
/* Count valid metadata areas. */
- while (areas < AREAS && sils[areas++]);
-
- if (areas == AREAS)
- goto out;
+ while (areas < AREAS && sils[areas])
+ areas++;
- log_err(lc, "%s: only %u/%u metadata areas found on %s, %sing...",
- handler, areas, AREAS, di->path, areas > 1 ? "elect" : "pick");
+ if (areas != AREAS)
+ log_err(lc, "%s: only %u/%u metadata areas found on "
+ "%s, %sing...",
+ handler, areas, AREAS, di->path,
+ areas > 1 ? "elect" : "pick");
/* Identify maximum identical copies. */
for (i = 0; i < areas; i++) {
- for (j = i + 1, sil = sils[i]; j < areas; j++) {
+ for (ident = 0, j = i + 1, sil = sils[i]; j < areas; j++) {
if (!memcmp(sil, sils[j], sizeof(*sil)))
- goto end;
+ ident++;
}
+
+ if (ident > areas / 2);
+ break;
}
- end:
- if (i) {
- sil = sils[0];
- sils[0] = sils[i];
- sils[i] = sil;
+ if (ident) {
+ tmp = sils[0];
+ sils[0] = sil;
+ sils[i] = tmp;
}
- out:
- return sils[0];
+ return sil;
}
static int setup_rd(struct lib_context *lc, struct raid_dev *rd,
--- dmraid/lib/format/ataraid/sil.h 2008/02/22 16:57:36 1.1
+++ dmraid/lib/format/ataraid/sil.h 2008/02/22 17:04:35 1.2
@@ -50,6 +50,7 @@
#define SIL_T_RAID10 2
#define SIL_T_RAID5 16
#define SIL_T_SPARE 3
+#define SIL_T_JBOD 255
int8_t drives_per_striped_set; /* 0x118 */
int8_t striped_set_number; /* 0x119 */
int8_t drives_per_mirrored_set;/* 0x11A */
--- dmraid/lib/format/ataraid/via.c 2008/02/22 16:57:36 1.1
+++ dmraid/lib/format/ataraid/via.c 2008/02/22 17:04:35 1.2
@@ -1,13 +1,12 @@
/*
+ * VIA metadata format handler.
+ *
* Copyright (C) 2004,2005 Heinz Mauelshagen, Red Hat GmbH.
* All rights reserved.
*
* See file DISCLAIMER at the top of this source tree for license information.
*/
-/*
- * VIA metadata format handler.
- */
#define HANDLER "via"
#include "internal.h"
@@ -95,18 +94,18 @@
return via->array.disk.in_disk_array ? s_ok : s_undef;
}
-/* Mapping of via types to generic types */
-static struct types types[] = {
- { VIA_T_SPAN, t_linear },
- { VIA_T_RAID0, t_raid0 },
- { VIA_T_RAID1, t_raid1 },
- { VIA_T_RAID01, t_raid0 },
- { 0, t_undef}
-};
-
/* Neutralize disk type using generic metadata type mapping function */
static enum type type(struct via *via)
{
+ /* Mapping of via types to generic types */
+ static struct types types[] = {
+ { VIA_T_SPAN, t_linear },
+ { VIA_T_RAID0, t_raid0 },
+ { VIA_T_RAID1, t_raid1 },
+ { VIA_T_RAID01, t_raid0 },
+ { 0, t_undef}
+ };
+
return rd_type(types, (unsigned int) VIA_RAID_TYPE(via));
}
@@ -142,7 +141,6 @@
while (i--)
sum += ((uint8_t*) via)[i];
-printf("sum=%u via->checksum=%u\n", sum, via->checksum);
return sum == via->checksum;
}
@@ -407,7 +405,8 @@
rd->type = type(via);
rd->offset = VIA_DATAOFFSET;
- rd->sectors = rd->meta_areas->offset;
+ if (!(rd->sectors = rd->meta_areas->offset))
+ return log_zero_sectors(lc, di->path, handler);
return (rd->name = name(lc, rd, 1)) ? 1 : 0;
}
/cvs/dm/dmraid/lib/format/ddf/README,v --> standard output
revision 1.1
--- dmraid/lib/format/ddf/README
+++ - 2008-02-22 17:04:40.236923000 +0000
@@ -0,0 +1,3 @@
+
+This directory contains the SNIA DDF1 metadata format handler
+
/cvs/dm/dmraid/lib/format/ddf/ddf1.c,v --> standard output
revision 1.1
--- dmraid/lib/format/ddf/ddf1.c
+++ - 2008-02-22 17:04:41.194337000 +0000
@@ -0,0 +1,966 @@
+/*
+ * SNIA DDF1 v1.0 metadata format handler.
+ *
+ * Copyright (C) 2005-2006 IBM, All rights reserved.
+ * Written by Darrick Wong <djwong@us.ibm.com>
+ *
+ * Copyright (C) 2006 Heinz Mauelshagen, Red Hat GmbH
+ * All rights reserved.
+ *
+ * See file LICENSE at the top of this source tree for license information.
+ */
+
+#include "internal.h"
+
+#define FORMAT_HANDLER
+#include "ddf1.h"
+#include "ddf1_lib.h"
+#include "ddf1_crc.h"
+#include "ddf1_cvt.h"
+#include "ddf1_dump.h"
+
+static const char *handler = HANDLER;
+
+#define DDF1_SPARES ".ddf1_spares"
+#define DDF1_DISKS (char*) ".ddf1_disks"
+
+/* PCI IDs for Adaptec */
+// #define PCI_VENDOR_ID_ADAPTEC 0x9004
+#define PCI_VENDOR_ID_ADAPTEC2 0x9005
+
+/* Map DDF1 disk status to dmraid status */
+static enum status disk_status(struct ddf1_phys_drive *disk) {
+ struct states states[] = {
+ { 0x72, s_broken },
+ { 0x04, s_nosync },
+ { 0x08, s_setup },
+ { 0x01, s_ok },
+ { 0, s_undef },
+ };
+
+ return disk ? rd_status(states, disk->state, AND) : s_undef;
+}
+
+/*
+ * Compare two GUIDs. For some reason, Adaptec sometimes writes 0xFFFFFFFF
+ * as the last four bytes (ala DDF2) and sometimes writes real data.
+ * For now we'll compare the first twenty and only the last four if
+ * both GUIDs don't have 0xFFFFFFFF in bytes 20-23. Gross.
+ */
+/* Find this drive's physical data */
+static struct ddf1_phys_drive *get_phys_drive(struct ddf1 *ddf1)
+{
+ unsigned int i = ddf1->pd_header->max_drives;
+
+ while (i--) {
+ if (ddf1->pds[i].reference == ddf1->disk_data->reference)
+ return ddf1->pds + i;
+ }
+
+ return NULL;
+}
+
+/* Find the virtual drive that goes with this config record */
+static struct ddf1_virt_drive *get_virt_drive(struct ddf1 *ddf1,
+ struct ddf1_config_record *cr)
+{
+ int i = ddf1->vd_header->num_drives;
+
+ while (i--) {
+ if (!guidcmp(ddf1->vds[i].guid, cr->guid))
+ return ddf1->vds + i;
+ }
+
+ return NULL;
+}
+
+/*
+ * Find the index of the VD config record given a physical drive and offset.
+ */
+static int get_config_byoffset(struct ddf1 *ddf1, struct ddf1_phys_drive *pd,
+ uint64_t offset)
+{
+ int cfgs = NUM_CONFIG_ENTRIES(ddf1), i;
+ uint32_t *cfg_drive_ids, j;
+ uint64_t *cfg_drive_offsets;
+ struct ddf1_config_record *cfg;
+
+ for (i = 0; i < cfgs; i++) {
+ cfg = CR(ddf1, i);
+ if (cfg->signature == DDF1_VD_CONFIG_REC) {
+ cfg_drive_ids = CR_IDS(ddf1, cfg);
+ cfg_drive_offsets = CR_OFF(ddf1, cfg);
+ for (j = 0; j < cfg->primary_element_count; j++) {
+ if (cfg_drive_ids[j] == pd->reference &&
+ cfg_drive_offsets[j] == offset)
+ return i;
+ }
+ }
+ }
+
+ return -ENOENT;
+}
+
+/* Find the index of the nth VD config record for this physical drive. */
+static int get_config_index(struct ddf1 *ddf1, struct ddf1_phys_drive *pd,
+ unsigned int *n)
+{
+ int cfgs = NUM_CONFIG_ENTRIES(ddf1), i, j, nn = *n;
+ uint32_t *ids;
+ struct ddf1_config_record *cr;
+
+ for (i = 0; i < cfgs; i++) {
+ cr = CR(ddf1, i);
+ if (cr->signature == DDF1_VD_CONFIG_REC) {
+ ids = CR_IDS(ddf1, cr);
+ for (j = 0; j < cr->primary_element_count; j++) {
+ if (ids[j] == pd->reference && !nn--)
+ return i;
+ }
+ }
+ }
+
+ *n -= nn;
+ return nn < 0 ? -ENOENT : 0;
+}
+
+/*
+ * Find the nth VD config record for this physical drive.
+ */
+static inline struct ddf1_config_record *get_config(struct ddf1 *ddf1,
+ struct ddf1_phys_drive *pd,
+ unsigned int n)
+{
+ int i = get_config_index(ddf1, pd, &n);
+
+ return i < 0 ? NULL : CR(ddf1, i);
+}
+
+/* Find a config record for this drive, given the offset of the array. */
+static inline struct ddf1_config_record *get_this_config(struct ddf1 *ddf1,
+ uint64_t offset)
+{
+ struct ddf1_phys_drive *pd = get_phys_drive(ddf1);
+ int i = get_config_byoffset(ddf1, pd, offset);
+
+ return i < 0 ? NULL : get_config(ddf1, pd, i);
+}
+
+/* Find the config record disk/offset entry for this config/drive. */
+static int get_offset_entry(struct ddf1 *ddf1, struct ddf1_config_record *cr,
+ struct ddf1_phys_drive *pd)
+{
+ int i;
+ uint32_t *ids;
+
+ if (cr) {
+ ids = CR_IDS(ddf1, cr);
+ for (i = 0; i < ddf1->primary->max_phys_drives; i++) {
+ if (ids[i] == pd->reference)
+ return i;
+ }
+ }
+
+ return -ENOENT;
+}
+
+/* Find the offset for this config/drive. */
+static uint64_t get_offset(struct ddf1 *ddf1, struct ddf1_config_record *cr,
+ struct ddf1_phys_drive *pd)
+{
+ int i = get_offset_entry(ddf1, cr, pd);
+
+ return i < 0 ? pd->size : CR_OFF(ddf1, cr)[i];
+}
+
+/* Calculate the stripe size, in sectors */
+static inline unsigned int stride(struct ddf1_config_record *cr)
+{
+ return to_bytes(1) >> 9 << cr->stripe_size;
+}
+
+/* Map the DDF1 raid type codes into dmraid type codes. */
+static enum type type(struct lib_context *lc, struct ddf1 *ddf1,
+ struct ddf1_config_record *cr)
+{
+ unsigned int l;
+ struct types *t;
+ /* Mapping of template types to generic types */
+ static struct types types[] = {
+ { DDF1_RAID0, t_raid0 },
+ { DDF1_RAID1, t_raid1 },
+ { DDF1_RAID4, t_raid4 },
+ { DDF1_CONCAT, t_linear },
+ { DDF1_JBOD, t_linear },
+ { 0, t_undef}
+ };
+ /* Seperate array for RAID5 qualifiers */
+ static struct types qualifier_types[] = {
+ /* FIXME: Is RLQ=0 really right symmetric? */
+ { DDF1_RAID5_RS, t_raid5_rs },
+ { DDF1_RAID5_LA, t_raid5_la },
+ { DDF1_RAID5_LS, t_raid5_ls },
+ { 0, t_undef}
+ };
+
+ if (!cr)
+ return t_undef;
+
+ l = cr->raid_level;
+ if (l == DDF1_RAID5) {
+ /*
+ * FIXME: Do _all_ Adaptec controllers use left
+ * asymmetric parity and write zero to RLQ?
+ */
+ if (ddf1->adaptec_mode)
+ return t_raid5_la;
+
+ l = cr->raid_qualifier;
+ t = qualifier_types;
+ } else
+ t = types;
+
+ return rd_type(t, l);
+}
+
+/* Read the whole metadata chunk at once */
+static uint8_t *read_metadata_chunk(struct lib_context *lc, struct dev_info *di,
+ uint64_t start)
+{
+ uint8_t *ret;
+ size_t size = to_bytes(di->sectors - start);
+
+ if (!(ret = alloc_private(lc, handler, size)))
+ return NULL;
+
+ if (!read_file(lc, handler, di->path, ret, size, to_bytes(start))) {
+ dbg_free(ret);
+ LOG_ERR(lc, NULL, "%s: unable to read metadata off %s",
+ handler, di->path);
+ }
+
+ return ret;
+}
+
+static inline void cond_free(void *p)
+{
+ if (p)
+ dbg_free(p);
+}
+
+/* Reused error message */
+static inline void *err_drive(struct lib_context *lc, struct dev_info *di,
+ const char *what)
+{
+ LOG_ERR(lc, NULL, "%s: cannot find %s drive record on %s",
+ handler, what, di->path);
+}
+
+static void *err_phys_drive(struct lib_context *lc, struct dev_info *di)
+{
+ return err_drive(lc, di, "physical");
+}
+
+static void *err_virt_drive(struct lib_context *lc, struct dev_info *di)
+{
+ return err_drive(lc, di, "virtual");
+}
+
+/*
+ * Read a DDF1 RAID device. Fields are little endian, so
+ * need to convert them if we're on a BE machine (ppc, etc).
+ */
+static int read_extended(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1)
+{
+ int i;
+ uint64_t where;
+ size_t size;
+ struct ddf1_header *pri, *sec;
+ struct ddf1_adapter *adap;
+ struct ddf1_disk_data *ddata;
+ struct ddf1_phys_drives *pd;
+ struct ddf1_virt_drives *vd;
+
+
+ /* Read the primary DDF header */
+ where = to_bytes(ddf1->anchor.primary_table_lba);
+ if (!(pri = ddf1->primary =
+ alloc_private_and_read(lc, handler, sizeof(*pri),
+ di->path, where)))
+ goto bad;
+
+ /* Read the secondary header. */
+ ddf1_cvt_header(ddf1, pri);
+ if (!(sec = ddf1->secondary = alloc_private(lc, handler, sizeof(*sec))))
+ goto bad;
+
+ where = to_bytes(ddf1->anchor.secondary_table_lba);
+ if (ddf1->anchor.secondary_table_lba != 0xFFFFFFFFFFFFFFFFULL &&
+ !read_file(lc, handler, di->path, sec, sizeof(*sec), where))
+ goto bad;
+
+ ddf1_cvt_header(ddf1, sec);
+ if (pri->signature != DDF1_HEADER) {
+ log_warn(lc, "%s: incorrect primary header signature %x on",
+ handler, pri->signature, di->path);
+ cond_free(ddf1->primary);
+ ddf1->primary = NULL;
+ };
+
+ if (sec->signature == DDF1_HEADER) {
+ /* If we encounter an error, we use the secondary table */
+ if (!ddf1->primary) {
+ log_warn(lc, "%s: using secondary header on %s",
+ handler, di->path);
+ ddf1->primary = ddf1->secondary;
+ ddf1->secondary = NULL;
+ }
+ } else {
+ if (sec->signature)
+ log_warn(lc, "%s: bad secondary header signature %x "
+ "on %s",
+ handler, sec->signature, di->path);
+
+ dbg_free(sec);
+ ddf1->secondary = NULL;
+ }
+
+ if (!ddf1->primary) {
+ log_error(lc, "%s: both header signatures bad on %s",
+ handler, di->path);
+ goto bad;
+ }
+
+ /* Read the adapter data */
+ if (!(adap = ddf1->adapter = alloc_private(lc, handler, sizeof(*adap))))
+ goto bad;
+
+ where = to_bytes(pri->primary_table_lba + pri->adapter_data_offset);
+ if (pri->adapter_data_offset != 0xFFFFFFFF &&
+ !read_file(lc, handler, di->path, adap, sizeof(*adap), where))
+ goto bad;
+
+ ddf1_cvt_adapter(ddf1, ddf1->adapter);
+ if (ddf1->adapter->signature != DDF1_ADAPTER_DATA) {
+ if (ddf1->adapter->signature)
+ log_warn(lc, "%s: incorrect adapter data signature %x "
+ "on %s",
+ handler, ddf1->adapter->signature, di->path);
+ dbg_free(ddf1->adapter);
+ ddf1->adapter = NULL;
+ }
+
+ if (ddf1->adapter &&
+ ddf1->adapter->pci_vendor == PCI_VENDOR_ID_ADAPTEC2) {
+ log_notice(lc, "%s: Adaptec mode discvered on %s",
+ handler, di->path);
+ ddf1->adaptec_mode = 1;
+ }
+
+ /* Read physical drive characteristic data */
+ where = to_bytes(pri->primary_table_lba + pri->disk_data_offset);
+ if (!(ddata = ddf1->disk_data =
+ alloc_private_and_read(lc, handler, sizeof(*ddata),
+ di->path, where)))
+ goto bad;
+
+ /*
+ * This table isn't technically required, but for now we rely
+ * on it to give us a key into the physical drive table.
+ */
+ ddf1_cvt_disk_data(ddf1, ddata);
+ if (ddata->signature != DDF1_FORCED_PD_GUID) {
+ log_warn(lc, "%s: incorrect disk data signature %x on %s",
+ handler, ddata->signature, di->path);
+ goto bad;
+ }
+
+ /* Read physical drive data header */
+ where = to_bytes(pri->primary_table_lba + pri->phys_drive_offset);
+ size = to_bytes(pri->phys_drive_len);
+ if (!(pd = ddf1->pd_header =
+ alloc_private_and_read(lc, handler, size, di->path, where)))
+ goto bad;
+
+ ddf1_cvt_phys_drive_header(ddf1, pd);
+ if (pd->signature != DDF1_PHYS_DRIVE_REC) {
+ err_phys_drive(lc, di);
+ goto bad;
+ }
+
+ /* Now read the physical drive data */
+ ddf1->pds = (struct ddf1_phys_drive *)(((uint8_t *)ddf1->pd_header) +
+ sizeof (*pd));
+ for (i = 0; i < pd->num_drives; i++) {
+ ddf1_cvt_phys_drive(ddf1, &ddf1->pds[i]);
+ /*
+ * Adaptec controllers have a weird bug where this field is
+ * only four bytes ... and the next four are 0xFF.
+ */
+ if (ddf1->pds[i].size >> 32 == 0xFFFFFFFF)
+ ddf1->pds[i].size &= 0xFFFFFFFF;
+ }
+
+ /* Read virtual drive data header */
+ where = to_bytes(pri->primary_table_lba + pri->virt_drive_offset);
+ size = to_bytes(pri->phys_drive_len);
+ if (!(vd = ddf1->vd_header =
+ alloc_private_and_read(lc, handler, size, di->path, where)))
+ goto bad;
+
+ ddf1_cvt_virt_drive_header(ddf1, vd);
+ if (vd->signature != DDF1_VIRT_DRIVE_REC) {
+ err_virt_drive(lc, di);
+ goto bad;
+ }
+
+ /* Now read the virtual drive data */
+ ddf1->vds = (struct ddf1_virt_drive*)(((uint8_t*) vd) + sizeof (*pd));
+ for (i = 0; i < vd->num_drives; i++)
+ ddf1_cvt_virt_drive(ddf1, &ddf1->vds[i]);
+
+ /* Read config data */
+ where = to_bytes(pri->primary_table_lba + pri->config_record_offset);
+ size = to_bytes(pri->config_record_len);
+ if (!(ddf1->cfg = alloc_private_and_read(lc, handler, size,
+ di->path, where)))
+ goto bad;
+
+ /*
+ * Ensure each record is: a config table for VDs; a config table for
+ * spare disks; or vendor-specifc data of some sort.
+ */
+ ddf1_cvt_records(lc, di, ddf1, 1);
+
+ /*
+ * FIXME: We don't pick up diagnostic logs, vendor specific logs,
+ * bad block data, etc. That shouldn't cause a problem with reading
+ * or writing metadata, but at some point we might want to do something
+ * with them.
+ */
+ ddf1->in_cpu_format = 1;
+
+ /* FIXME: We should verify the checksums for all modes */
+ if (ddf1->adaptec_mode &&
+ !(ddf1_check_all_crcs(lc, di, ddf1)))
+ goto bad;
+
+ return 1;
+
+bad:
+ ddf1->vds = NULL;
+ ddf1->pds = NULL;
+ cond_free(ddf1->cfg);
+ cond_free(ddf1->pd_header);
+ cond_free(ddf1->disk_data);
+ cond_free(ddf1->adapter);
+ cond_free(ddf1->secondary);
+ cond_free(ddf1->primary);
+ return 0;
+}
+
+/* Count the number of raid_devs we need to create for this drive */
+static unsigned int num_devs(struct lib_context *lc, void *meta)
+{
+ struct ddf1 *ddf1 = meta;
+ unsigned int num_drives = ~0;
+
+ get_config_index(ddf1, get_phys_drive(ddf1), &num_drives);
+ return num_drives;
+}
+
+/* Is this DDF1 metadata? */
+static inline int is_ddf1(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1)
+{
+ /*
+ * Check our magic numbers and that the version == v2.
+ * We don't support anything other than that right now.
+ */
+
+ /* FIXME: We should examine the version headers... */
+ return ddf1->anchor.signature == DDF1_HEADER ||
+ ddf1->anchor.signature == DDF1_HEADER_BACKWARDS;
+}
+
+/* Try to find DDF1 metadata at a given offset (ddf1_sboffset) */
+static struct ddf1 *try_to_find_ddf1(struct lib_context *lc,
+ struct dev_info *di,
+ size_t *sz, uint64_t *offset,
+ union read_info *info,
+ uint64_t ddf1_sboffset)
+{
+ struct ddf1 *ddf1;
+
+ /*
+ * Try to find a DDF1 anchor block at ddf1_sboffset. In theory this
+ * should be the very last block, but some Adaptec controllers have
+ * issues with standards compliance. So we have to try with various
+ * offsets.
+ */
+ if (!(ddf1 = alloc_private(lc, handler, sizeof(*ddf1))))
+ goto err;
+
+ if (!read_file(lc, handler, di->path, &ddf1->anchor, to_bytes(1),
+ ddf1_sboffset) ||
+ !is_ddf1(lc, di, ddf1))
+ goto bad;
+
+ ddf1->anchor_offset = ddf1_sboffset;
+
+ /* Convert endianness */
+ ddf1->in_cpu_format = 0;
+ if ((ddf1->disk_format = ddf1_endianness(lc, ddf1)) < 0)
+ goto bad;
+ ddf1_cvt_header(ddf1, &ddf1->anchor);
+
+ /* Read extended metadata. */
+ if (read_extended(lc, di, ddf1))
+ return ddf1;
+
+ bad:
+ dbg_free(ddf1);
+ err:
+ return NULL;
+}
+
+/*
+ * Attempt to interpret DDF1 metadata from a block device. This function
+ * returns either NULL or a pointer to a descriptor struct.
+ * Note that the struct should be fully converted to the correct endianness
+ * by the time this function returns.
+ */
+static void *read_metadata_areas(struct lib_context *lc, struct dev_info *di,
+ size_t *sz, uint64_t *offset,
+ union read_info *info)
+{
+ struct ddf1 *ddf1;
+
+ if (!(ddf1 = try_to_find_ddf1(lc, di, sz, offset,
+ info, DDF1_CONFIGOFFSET))) {
+ if ((ddf1 = try_to_find_ddf1(lc, di, sz, offset,
+ info, DDF1_CONFIGOFFSET_ADAPTEC)))
+ ddf1->adaptec_mode = 1;
+ }
+
+ return ddf1;
+}
+
+/* This is all hogwash since file_metadata can only be called once... */
+static void file_metadata_areas(struct lib_context *lc, struct dev_info *di,
+ void *meta)
+{
+ uint8_t *buf;
+ uint64_t start = ddf1_beginning(meta);
+
+ if ((buf = read_metadata_chunk(lc, di, start))) {
+ /* Record metadata. */
+ file_metadata(lc, handler, di->path, buf,
+ to_bytes(di->sectors - start), to_bytes(start));
+ dbg_free(buf);
+ file_dev_size(lc, handler, di); /* Record the device size. */
+ }
+}
+
+static int setup_rd(struct lib_context *lc, struct raid_dev *rd,
+ struct dev_info *di, void *meta, union read_info *info);
+static struct raid_dev *ddf1_read(struct lib_context *lc,
+ struct dev_info *di)
+{
+ /*
+ * NOTE: Everything called after read_metadata_areas assumes that
+ * the reserved block, raid table and config table have been
+ * converted to the appropriate endianness.
+ */
+ return read_raid_dev(lc, di, read_metadata_areas, 0, 0, NULL, NULL,
+ file_metadata_areas, setup_rd, handler);
+}
+
+/* Compose an "identifier" for use as a sort key for raid sets. */
+static inline int compose_id(struct ddf1 *ddf1, struct raid_dev *rd)
+{
+ struct ddf1_phys_drive *pd = get_phys_drive(ddf1);
+ int i = get_config_byoffset(ddf1, pd, rd->offset);
+
+ return i < 0 ? -1 : get_offset_entry(ddf1, get_config(ddf1, pd, i), pd);
+}
+
+/* No sort. */
+static int no_sort(struct list_head *pos, struct list_head *new)
+{
+ return 0;
+}
+
+/* Sort DDF1 devices by offset entry within a RAID set. */
+static int dev_sort(struct list_head *pos, struct list_head *new)
+{
+ return compose_id(META(RD(new)->private.ptr, ddf1), RD(new)) <
+ compose_id(META(RD(pos)->private.ptr, ddf1), RD(pos));
+}
+
+/*
+ * IO error event handler.
+ */
+static int event_io(struct lib_context *lc, struct event_io *e_io)
+{
+ log_err(lc, "%s: I/O error on device %s at sector %lu.\n",
+ handler, e_io->rd->di->path, e_io->sector);
+
+ LOG_ERR(lc, 0, "%s: PANIC - don't know about event_io!", handler);
+}
+
+#if 0
+ /* FIXME: This should not use META() directly? */
+ struct raid_dev *rd = e_io->rd;
+ struct ddf1 *ddf1 = META(rd, ddf1);
+ struct ddf1_raid_configline *cl = this_disk(ddf1);
+ struct ddf1_raid_configline *fwl = find_logical(ddf1);
+
+ /* Ignore if we've already marked this disk broken(?) */
+ if (rd->status & s_broken)
+ return 0;
+
+ /* Mark the array as degraded and the disk as failed. */
+ rd->status = s_broken;
+ cl->raidstate = LSU_COMPONENT_STATE_FAILED;
+ fwl->raidstate = LSU_COMPONENT_STATE_DEGRADED;
+ /* FIXME: Do we have to mark a parent too? */
+
+ /* Indicate that this is indeed a failure. */
+ return 1;
+}
+#endif
+
+#define NAME_SIZE 64
+/* Formulate a RAID set name for this disk. */
+static char *name(struct lib_context *lc, struct ddf1 *ddf1,
+ struct raid_dev *rd)
+{
+ int i, prefix;
+ char buf[NAME_SIZE];
+ struct ddf1_phys_drive *pd;
+ struct ddf1_virt_drive *vd;
+ struct ddf1_config_record *cr;
+
+ if (!(pd = get_phys_drive(ddf1)))
+ return err_phys_drive(lc, rd->di);
+
+ i = get_config_byoffset(ddf1, pd, rd->offset);
+ cr = get_config(ddf1, pd, i);
+ if (i < 0 || !cr) {
+ sprintf(buf, DDF1_SPARES);
+ goto out;
+ }
+
+ if (!(vd = get_virt_drive(ddf1, cr)))
+ return err_virt_drive(lc, rd->di);
+
+ sprintf(buf, "%s_", handler);
+ prefix = strlen(buf);
+
+ if (vd->name[0]) {
+ memcpy(buf + prefix, vd->name, 16);
+ i = prefix + 16;
+ while (!isgraph(buf[--i]));
+ buf[i+1] = 0;
+ } else {
+ char *b;
+
+ for (b = buf + prefix, i = 0; i < 24; b += 8, i += 4)
+ sprintf(b, "%02x%02x%02x%02x",
+ vd->guid[i], vd->guid[i+1],
+ vd->guid[i+2], vd->guid[i+3]);
+ }
+
+ out:
+ return dbg_strdup(buf); /* Only return the needed allocation */
+}
+
+/* Figure out the real size of a disk... */
+static uint64_t get_size(struct lib_context *lc, struct ddf1 *ddf1,
+ struct ddf1_config_record *cr,
+ struct ddf1_phys_drive *pd)
+{
+ if (cr)
+ /* Some Adaptec controllers need this clamping. */
+ return type(lc, ddf1, cr) == t_raid0 ?
+ cr->sectors - cr->sectors % stride(cr) : cr->sectors;
+
+ return pd->size;
+}
+
+/*
+ * Create all the volumes of a DDF1 disk as subsets of the top level DDF1
+ * disk group. rs_group points to that raid subset and is returned if the
+ * function is successful, NULL if not. rd_group is the raid device that
+ * represents the entire disk drive.
+ */
+static struct raid_set *group_rd(struct lib_context *lc,
+ struct raid_set *rs_group,
+ struct raid_dev *rd_group)
+{
+ struct ddf1 *ddf1 = META(rd_group, ddf1);
+ struct raid_set *rs = NULL;
+ struct raid_dev *rd;
+ struct ddf1_config_record *cr;
+ struct ddf1_phys_drive *pd;
+ unsigned int devs, i;
+
+ if (!(pd = get_phys_drive(ddf1)))
+ return err_phys_drive(lc, rd_group->di);
+
+ devs = num_devs(lc, ddf1);
+ for (i = 0; i < devs; i++) {
+ /* Allocate a raid_dev for this volume */
+ if (!(rd = alloc_raid_dev(lc, handler)))
+ return NULL;
+
+ cr = get_config(ddf1, pd, i);
+ rd->di = rd_group->di;
+ rd->fmt = rd_group->fmt;
+ rd->type = type(lc, ddf1, cr);
+ if (!(rd->sectors = get_size(lc, ddf1, cr, pd))) {
+ log_zero_sectors(lc, rd->di->path, handler);
+ free_raid_dev(lc, &rd);
+ continue;
+ }
+
+ rd->offset = get_offset(ddf1, cr, pd);
+
+ /*
+ * If we have a virtual drive config without an entry in the
+ * list of virtual drives, we ignore it. Weird bug seen on
+ * Adaptec 2410SA controller.
+ */
+ if (!(rd->name = name(lc, ddf1, rd))) {
+ free_raid_dev(lc, &rd);
+ continue;
+ }
+
+ /* Stuff it into the appropriate raid set. */
+ if (!(rs = find_or_alloc_raid_set(lc, rd->name, FIND_ALL,
+ rd, &rs_group->sets,
+ NO_CREATE, NO_CREATE_ARG))) {
+ free_raid_dev(lc, &rd);
+ return NULL;
+ }
+
+ /* Keep reference to the entire device for ddf1_check() */
+ rd->private.ptr = rd_group;
+
+ /* Add rest of subset state */
+ rs->stride = stride(cr);
+ rs->type = type(lc, ddf1, cr);
+ rs->status = s_ok;
+
+ /* Sort device into subset */
+ list_add_sorted(lc, &rs->devs, &rd->devs, dev_sort);
+ }
+
+ return rs_group;
+}
+
+/*
+ * Add a DDF1 device to a RAID set. This involves finding the raid set to
+ * which this disk belongs, and then attaching it. Note that there are other
+ * complications, such as two-layer arrays (RAID10).
+ *
+ * FIXME: We haven't been able to set up a RAID10 for testing...
+ */
+static struct raid_set *ddf1_group(struct lib_context *lc, struct raid_dev *rd)
+{
+ struct ddf1 *ddf1 = META(rd, ddf1);
+ struct ddf1_phys_drive *pd;
+ struct raid_set *rs;
+
+ if (!(pd = get_phys_drive(ddf1)))
+ return err_phys_drive(lc, rd->di);
+
+ if (!rd->name)
+ LOG_ERR(lc, NULL, "%s: no RAID array name on %s",
+ handler, rd->di->path);
+
+ /*
+ * Find/create a raid set for all DDF drives and put this disk
+ * into that set. The raid_sets for the real arrays will be created
+ * as children of the disk's raid_set.
+ *
+ * (Is this really necessary?)
+ */
+ if (!(rs = find_or_alloc_raid_set(lc, rd->name, FIND_TOP, rd,
+ LC_RS(lc), NO_CREATE,
+ NO_CREATE_ARG)))
+ return NULL;
+
+ rs->type = t_group;
+ list_add_sorted(lc, &rs->devs, &rd->devs, no_sort);
+
+ /* Go deal with the real arrays. */
+ return group_rd(lc, rs, rd);
+}
+
+/* Write metadata. */
+static int ddf1_write(struct lib_context *lc, struct raid_dev *rd, int erase)
+{
+ int ret;
+ struct ddf1 *ddf1 = META(rd, ddf1);
+
+ if (ddf1->adaptec_mode)
+ ddf1_update_all_crcs(lc, rd->di, ddf1);
+
+ ddf1_cvt_all(lc, ddf1, rd->di);
+ ret = write_metadata(lc, handler, rd, -1, erase);
+ ddf1_cvt_all(lc, ddf1, rd->di);
+
+ return ret;
+}
+
+/*
+ * Check integrity of a RAID set.
+ */
+
+/* Retrieve the number of devices that should be in this set. */
+static unsigned int device_count(struct raid_dev *rd, void *context)
+{
+ /* Get the logical drive */
+ struct ddf1_config_record *cr =
+ get_this_config(META(rd->private.ptr, ddf1), rd->offset);
+
+ /*
+ * Release reference after check, so that core
+ * doesn't try to free it multiple times.
+ */
+ rd->private.ptr = NULL;
+ return cr ? cr->primary_element_count : 0;
+}
+
+/* Check a RAID device */
+static int check_rd(struct lib_context *lc, struct raid_set *rs,
+ struct raid_dev *rd, void *context)
+{
+ /*
+ * FIXME: Should we do more checking for brokenness here?
+ * We could check SMART data, etc.
+ */
+ return rd->type != s_broken;
+}
+
+/* Start the recursive RAID set check. */
+static int ddf1_check(struct lib_context *lc, struct raid_set *rs)
+{
+ return check_raid_set(lc, rs, device_count, NULL, check_rd,
+ NULL, handler);
+}
+
+static struct event_handlers ddf1_event_handlers = {
+ .io = event_io,
+ .rd = NULL, /* FIXME: no device add/remove event handler yet. */
+};
+
+#ifdef DMRAID_NATIVE_LOG
+/*
+ * Log native information about the RAID device.
+ */
+static void ddf1_log(struct lib_context *lc, struct raid_dev *rd)
+{
+ ddf1_dump_all(lc, rd->di, META(rd, ddf1), handler);
+}
+#endif /* #ifdef DMRAID_NATIVE_LOG */
+
+static struct dmraid_format ddf1_format = {
+ .name = HANDLER,
+ .descr = "SNIA DDF1",
+ .caps = "0,1,4,5,linear",
+ .format = FMT_RAID,
+ .read = ddf1_read,
+ .write = ddf1_write,
+ .group = ddf1_group,
+ .check = ddf1_check,
+ .events = &ddf1_event_handlers,
+#ifdef DMRAID_NATIVE_LOG
+ .log = ddf1_log,
+#endif
+};
+
+/* Register this format handler with the format core */
+int register_ddf1(struct lib_context *lc)
+{
+ return register_format_handler(lc, &ddf1_format);
+}
+
+/*
+ * Set up a RAID device from what we've assembled out of the metadata.
+ */
+static int setup_rd(struct lib_context *lc, struct raid_dev *rd,
+ struct dev_info *di, void *meta, union read_info *info)
+{
+ unsigned int i, ma_count = 5;
+ struct ddf1 *ddf1 = meta;
+ struct meta_areas *ma;
+ struct ddf1_phys_drive *pd;
+
+ if (!(pd = get_phys_drive(ddf1)))
+ LOG_ERR(lc, 0, "%s: Cannot find physical drive description "
+ "on %s!", handler, di->path);
+
+ /* We need multiple metadata areas */
+ ma_count += ddf1->adapter ? 1 : 0;
+ ma_count += ddf1->secondary ? 1 : 0;
+ ma_count += ddf1->disk_data ? 1 : 0;
+ /* FIXME: metadata area for workspace_lba */
+
+ if (!(ma = rd->meta_areas = alloc_meta_areas(lc, rd, handler,
+ ma_count)))
+ return 0;
+
+ /* Preset metadata area offset and size and adjust below */
+ for (i = 0; i < ma_count; i++)
+ ma[i].offset = ddf1->primary->primary_table_lba;
+
+ ma->offset = ddf1->anchor_offset;
+ (ma++)->area = &ddf1->anchor;
+
+ (ma++)->area = ddf1->primary;
+
+ if (ddf1->secondary)
+ (ma++)->offset = ddf1->primary->secondary_table_lba;
+
+ if (ddf1->adapter) {
+ ma->offset += ddf1->primary->adapter_data_offset;
+ ma->size = to_bytes(ddf1->primary->adapter_data_len);
+ (ma++)->area = ddf1->adapter;
+ }
+
+ /* FIXME: set up workspace_lba */
+
+ if (ddf1->disk_data) {
+ ma->offset += ddf1->primary->disk_data_offset;
+ ma->size = to_bytes(ddf1->primary->disk_data_len);
+ (ma++)->area = ddf1->disk_data;
+ }
+
+ ma->offset += ddf1->primary->phys_drive_offset;
+ ma->size = to_bytes(ddf1->primary->phys_drive_len);
+ (ma++)->area = ddf1->pd_header;
+
+ ma->offset += ddf1->primary->virt_drive_offset;
+ ma->size = to_bytes(ddf1->primary->virt_drive_len);
+ (ma++)->area = ddf1->vd_header;
+
+ ma->offset += ddf1->primary->config_record_offset;
+ ma->size = to_bytes(ddf1->primary->config_record_len);
+ ma->area = ddf1->cfg;
+
+ /* Now set up the rest of the metadata info */
+ rd->di = di;
+ rd->fmt = &ddf1_format;
+ rd->status = disk_status(pd);
+ rd->type = t_group;
+ rd->offset = 0;
+ if (!(rd->sectors = get_size(lc, ddf1, NULL, pd)))
+ return log_zero_sectors(lc, di->path, handler);
+
+ /* FIXME: better name */
+ return (rd->name = dbg_strdup(DDF1_DISKS)) ? 1 : 0;
+}
/cvs/dm/dmraid/lib/format/ddf/ddf1.c.orig,v --> standard output
revision 1.1
--- dmraid/lib/format/ddf/ddf1.c.orig
+++ - 2008-02-22 17:04:41.464564000 +0000
@@ -0,0 +1,1047 @@
+/*
+ * SNIA DDF1 v1.0 metadata format handler.
+ *
+ * Copyright (C) 2005-2006 IBM, All rights reserved.
+ * Written by Darrick Wong <djwong@us.ibm.com>
+ *
+ * Copyright (C) 2006 Heinz Mauelshage, Red Hat GmbH
+ * All rights reserved.
+ *
+ * See file LICENSE at the top of this source tree for license information.
+ */
+
+#include <errno.h>
+
+#define HANDLER "ddf1"
+
+#include "internal.h"
+
+#define FORMAT_HANDLER
+#include "ddf1.h"
+
+// #include "ddf1_crc.h"
+#include "ddf1_cvt.h"
+#include "ddf1_dump.h"
+
+static const char *handler = HANDLER;
+
+/* PCI IDs for Adaptec */
+#define PCI_VENDOR_ID_ADAPTEC 0x9004
+#define PCI_VENDOR_ID_ADAPTEC2 0x9005
+
+/* Find the beginning of all DDF metadata */
+static uint64_t find_ddf_beginning(struct ddf1 *ddf1)
+{
+ uint64_t start;
+ struct ddf1_header *h = &ddf1->anchor;
+
+ start = ddf1->anchor_offset;
+ if (h->primary_table_lba < start)
+ start = h->primary_table_lba;
+ if (h->secondary_table_lba < start)
+ start = h->secondary_table_lba;
+#ifdef WORKSPACE_IS_PART_OF_DDF
+ if (ddf1->primary->workspace_lba < start)
+ start = ddf1->primary->workspace_lba;
+#endif
+
+ return start;
+}
+
+/* Figure out what endian conversions we need */
+static void find_endian(struct lib_context *lc, struct ddf1 *ddf1)
+{
+ uint8_t *ptr = (uint8_t*) &ddf1->anchor.signature;
+
+ if (ptr[0] == 0xDE && ptr[1] == 0x11)
+ ddf1->disk_format = BIG_ENDIAN;
+ else if (ptr[0] == 0x11 && ptr[1] == 0xDE)
+ ddf1->disk_format = LITTLE_ENDIAN;
+ else {
+ log_error(lc, "Can't figure out endianness!");
+ ddf1->disk_format = 0;
+ }
+}
+
+/* Map DDF1 disk status to dmraid status */
+static enum status disk_status(struct ddf1_phys_drive *disk) {
+ struct {
+ uint8_t flag;
+ enum status status;
+ } states[] = {
+ { 0x72, s_broken },
+ { 0x04, s_nosync },
+ { 0x08, s_setup },
+ { 0x01, s_ok },
+ }, *s = states;
+
+ if (disk) {
+ do {
+ if (disk->state & s->flag)
+ return s->status;
+ } while ((s++)->status != s_ok);
+ }
+
+ return s_undef;
+}
+
+/*
+ * Compare two GUIDs. For some reason, Adaptec sometimes writes 0xFFFFFFFF
+ * as the last four bytes (ala DDF2) and sometimes writes real data.
+ * For now we'll compare the first twenty and only the last four if
+ * both GUIDs don't have 0xFFFFFFFF in bytes 20-23. Gross.
+ */
+static inline uint8_t _and(uint8_t *p)
+{
+ return p[20] & p[21] & p[22] & p[23];
+}
+
+static int guidcmp(uint8_t *one, uint8_t *two)
+{
+ int x = memcmp(one, two, DDF1_GUID_LENGTH - 4);
+
+ if (x)
+ return x;
+
+ return (_and(one) || _and(two)) ? 0 : memcmp(one + 20, two + 20, 4);
+}
+
+/* Find the physical drive data for a drive */
+static struct ddf1_phys_drive *get_phys_drive(struct ddf1 *ddf1, uint32_t ref)
+{
+ unsigned int i = ddf1->pd_header->max_drives;
+ struct ddf1_phys_drive *pd;
+
+ while (i--) {
+ pd = ddf1->pds + i;
+ if (pd->reference == ref)
+ return pd;
+ }
+
+ return NULL;
+}
+
+/* Find this drive's physical data */
+static inline struct ddf1_phys_drive *get_this_phys_drive(struct ddf1 *ddf1)
+{
+ return get_phys_drive(ddf1, ddf1->disk_data->reference);
+}
+
+/* Find the virtual drive that goes with this config record */
+static struct ddf1_virt_drive *get_virt_drive(struct ddf1 *ddf1,
+ struct ddf1_config_record *cr)
+{
+ int i = ddf1->vd_header->num_drives;
+ struct ddf1_virt_drive *vd;
+
+ while (i--) {
+ vd = ddf1->vds + i;
+ if (!guidcmp(vd->guid, cr->guid))
+ return vd;
+ }
+
+ return NULL;
+}
+
+/*
+ * Find the index of the VD config record given a physical drive and offset.
+ */
+static int get_config_byoffset(struct ddf1 *ddf1, struct ddf1_phys_drive *pd,
+ uint64_t offset)
+{
+ int cfgs = NUM_CONFIG_ENTRIES(ddf1), i;
+ uint32_t *cfg_drive_ids, j;
+ uint64_t *cfg_drive_offsets;
+ struct ddf1_config_record *cfg;
+
+ for (i = 0; i < cfgs; i++) {
+ cfg = CR(ddf1, i);
+ if (cfg->signature == DDF1_VD_CONFIG_REC) {
+ cfg_drive_ids = CR_IDS(ddf1, cfg);
+ cfg_drive_offsets = CR_OFF(ddf1, cfg);
+ for (j = 0; j < cfg->primary_element_count; j++) {
+ if (cfg_drive_ids[j] == pd->reference &&
+ cfg_drive_offsets[j] == offset)
+ return i;
+ }
+ }
+ }
+
+ return -ENOENT;
+}
+
+/* Find the index of the nth VD config record for this physical drive. */
+static int get_config_index(struct ddf1 *ddf1, struct ddf1_phys_drive *pd,
+ unsigned int *n)
+{
+ int cfgs = NUM_CONFIG_ENTRIES(ddf1), i, j, nn = *n;
+ uint32_t *ids;
+ struct ddf1_config_record *cr;
+
+ for (i = 0; i < cfgs; i++) {
+ cr = CR(ddf1, i);
+ if (cr->signature == DDF1_VD_CONFIG_REC) {
+ ids = CR_IDS(ddf1, cr);
+ for (j = 0; j < cr->primary_element_count; j++) {
+ if (ids[j] == pd->reference && !nn--)
+ return i;
+ }
+ }
+ }
+
+ *n -= nn;
+ return nn < 0 ? -ENOENT : 0;
+}
+
+/*
+ * Find the nth VD config record for this physical drive.
+ */
+static inline struct ddf1_config_record *get_config(struct ddf1 *ddf1,
+ struct ddf1_phys_drive *pd,
+ unsigned int n)
+{
+ int i = get_config_index(ddf1, pd, &n);
+
+ return i < 0 ? NULL : CR(ddf1, i);
+}
+
+/* Find a config record for this drive, given the offset of the array. */
+static inline struct ddf1_config_record *get_this_config(struct ddf1 *ddf1,
+ uint64_t offset)
+{
+ struct ddf1_phys_drive *pd = get_this_phys_drive(ddf1);
+ int i = get_config_byoffset(ddf1, pd, offset);
+
+ return i < 0 ? NULL : get_config(ddf1, pd, i);
+}
+
+/* Find the config record disk/offset entry for this config/drive. */
+static int get_offset_entry(struct ddf1 *ddf1, struct ddf1_config_record *cr,
+ struct ddf1_phys_drive *pd)
+{
+ int i;
+ uint32_t *ids;
+
+ if (cr) {
+ ids = CR_IDS(ddf1, cr);
+ for (i = 0; i < ddf1->primary->max_phys_drives; i++) {
+ if (ids[i] == pd->reference)
+ return i;
+ }
+ }
+
+ return -ENOENT;
+}
+
+/* Find the offset for this config/drive. */
+static uint64_t get_offset(struct ddf1 *ddf1, struct ddf1_config_record *cr,
+ struct ddf1_phys_drive *pd)
+{
+ int i = get_offset_entry(ddf1, cr, pd);
+
+ return i < 0 ? pd->size : CR_OFF(ddf1, cr)[i];
+}
+
+/* Calculate the stripe size, in sectors */
+static inline unsigned int stride(struct ddf1_config_record *cr)
+{
+ return 1 << cr->stripe_size; // * 512 * 2;
+}
+
+/* Mapping of template types to generic types */
+static struct types types[] = {
+ { DDF1_RAID0, t_raid0 },
+ { DDF1_RAID1, t_raid1 },
+ { DDF1_RAID4, t_raid4 },
+ { DDF1_CONCAT, t_linear },
+ { DDF1_JBOD, t_linear },
+ { 0, t_undef}
+};
+
+/* Seperate array for RAID5 qualifiers */
+static struct types qualifier_types[] = {
+ /* FIXME: Is RLQ=0 really right symmetric? */
+ { DDF1_RAID5_RS, t_raid5_rs },
+ { DDF1_RAID5_LA, t_raid5_la },
+ { DDF1_RAID5_LS, t_raid5_ls },
+ { 0, t_undef}
+};
+
+/* Map the DDF1 raid type codes into dmraid type codes. */
+static enum type type(struct lib_context *lc, struct ddf1 *ddf1,
+ struct ddf1_config_record *cr)
+{
+ unsigned int l;
+ struct types *t;
+
+ if (!cr)
+ return t_undef;
+
+ l = cr->raid_level;
+ if (l == DDF1_RAID5) {
+ /*
+ * FIXME: Do _all_ Adaptec controllers use left
+ * asymmetric parity and write zero to RLQ?
+ */
+ if (ddf1->adaptec_mode)
+ return t_raid5_la;
+
+ l = cr->raid_qualifier;
+ t = qualifier_types;
+ } else
+ t = types;
+
+ return rd_type(t, l);
+}
+
+/* Read the whole metadata chunk at once */
+static uint8_t *read_metadata_chunk(struct lib_context *lc, struct dev_info *di,
+ uint64_t start)
+{
+ uint8_t *ret;
+ size_t size = (di->sectors - start) * DDF1_BLKSIZE;
+
+ if (!(ret = dbg_malloc(size)))
+ LOG_ERR(lc, ret, "%s: unable to allocate memory.", di->path);
+
+ if (!read_file(lc, handler, di->path, ret, size,
+ start * DDF1_BLKSIZE)) {
+ dbg_free(ret);
+ LOG_ERR(lc, NULL, "%s: unable to read metadata.", di->path);
+ }
+
+ return ret;
+}
+
+static inline void cond_free(void *p)
+{
+ if (p)
+ dbg_free(p);
+}
+
+/*
+ * Read an DDF1 RAID device. Fields are little endian, so
+ * need to convert them if we're on a BE machine (ppc, etc).
+ */
+static int read_extended(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1)
+{
+ int i;
+ uint64_t where;
+ size_t size;
+ struct ddf1_header *pri, *sec;
+ struct ddf1_adapter *adap;
+ struct ddf1_disk_data *ddata;
+ struct ddf1_phys_drives *pd;
+ struct ddf1_virt_drives *vd;
+
+ /* FIXME: We should verify the checksums... */
+
+ /* Read the primary DDF header */
+ where = ddf1->anchor.primary_table_lba * DDF1_BLKSIZE;
+ if (!(pri = ddf1->primary =
+ alloc_private_and_read(lc, handler, sizeof(*pri),
+ di->path, where)))
+ goto bad;
+
+ /* Read the secondary header. */
+ ddf1_cvt_header(ddf1, pri);
+ if (!(sec = ddf1->secondary = alloc_private(lc, handler, sizeof(*sec))))
+ goto bad;
+
+ where = ddf1->anchor.secondary_table_lba * DDF1_BLKSIZE;
+ if (ddf1->anchor.secondary_table_lba != 0xFFFFFFFFFFFFFFFFULL &&
+ !read_file(lc, handler, di->path, sec, sizeof(*sec), where))
+ goto bad;
+
+ ddf1_cvt_header(ddf1, sec);
+ if (pri->signature != DDF1_HEADER) {
+ log_warn(lc, "%s: incorrect primary header signature %x",
+ di->path, pri->signature);
+ cond_free(ddf1->primary);
+ ddf1->primary = NULL;
+ };
+
+ if (sec->signature == DDF1_HEADER) {
+ /* If we encounter an error, we use the secondary table */
+ if (!ddf1->primary) {
+ log_warn(lc, "%s: using secondary header", di->path);
+ ddf1->primary = ddf1->secondary;
+ ddf1->secondary = NULL;
+ }
+ } else {
+ if (sec->signature)
+ log_warn(lc, "%s: bad secondary header signature %x",
+ di->path, sec->signature);
+
+ dbg_free(sec);
+ ddf1->secondary = NULL;
+ }
+
+ if (!ddf1->primary) {
+ log_error(lc, "%s: both header signatures bad", di->path);
+ goto bad;
+ }
+
+ /* Read the adapter data */
+ if (!(adap = ddf1->adapter = alloc_private(lc, handler, sizeof(*adap))))
+ goto bad;
+
+ where = (pri->primary_table_lba + pri->adapter_data_offset)
+ * DDF1_BLKSIZE;
+ if (pri->adapter_data_offset != 0xFFFFFFFF &&
+ !read_file(lc, handler, di->path, adap, sizeof(*adap), where))
+ goto bad;
+
+ ddf1_cvt_adapter(ddf1, ddf1->adapter);
+ if (ddf1->adapter->signature != DDF1_ADAPTER_DATA) {
+ if (ddf1->adapter->signature)
+ log_warn(lc, "%s: incorrect adapter data signature %x",
+ di->path, ddf1->adapter->signature);
+ free (ddf1->adapter);
+ ddf1->adapter = NULL;
+ }
+
+ if (ddf1->adapter &&
+ ddf1->adapter->pci_vendor == PCI_VENDOR_ID_ADAPTEC2)
+ ddf1->adaptec_mode = 1;
+
+ /* Read physical drive characteristic data */
+ where = (pri->primary_table_lba + pri->disk_data_offset) * DDF1_BLKSIZE;
+ if (!(ddata = ddf1->disk_data =
+ alloc_private_and_read(lc, handler, sizeof(*ddata),
+ di->path, where)))
+ goto bad;
+
+ /*
+ * This table isn't technically required, but for now we rely
+ * on it to give us a key into the physical drive table.
+ */
+ ddf1_cvt_disk_data(ddf1, ddata);
+ if (ddata->signature != DDF1_FORCED_PD_GUID) {
+ log_warn(lc, "%s: incorrect disk data signature %x",
+ di->path, ddata->signature);
+ goto bad;
+ }
+
+ /* Read physical drive data header */
+ where = (pri->primary_table_lba + pri->phys_drive_offset) *
+ DDF1_BLKSIZE;
+ size = pri->phys_drive_len * DDF1_BLKSIZE;
+ if (!(pd = ddf1->pd_header =
+ alloc_private_and_read(lc, handler, size, di->path, where)))
+ goto bad;
+
+ ddf1_cvt_phys_drive_header(ddf1, pd);
+ if (pd->signature != DDF1_PHYS_DRIVE_REC) {
+ log_warn(lc, "%s: cannot find physical drive records",
+ di->path);
+ goto bad;
+ }
+
+ /* Now read the physical drive data */
+ ddf1->pds = (struct ddf1_phys_drive *)(((uint8_t *)ddf1->pd_header) +
+ sizeof (*pd));
+ for (i = 0; i < pd->num_drives; i++) {
+ ddf1_cvt_phys_drive(ddf1, &ddf1->pds[i]);
+ /*
+ * Adaptec controllers have a weird bug where this field is
+ * only four bytes ... and the next four are 0xFF.
+ */
+ if (ddf1->pds[i].size >> 32 == 0xFFFFFFFF)
+ ddf1->pds[i].size &= 0xFFFFFFFF;
+ }
+
+ /* Read virtual drive data header */
+ where = (pri->primary_table_lba + pri->virt_drive_offset) *
+ DDF1_BLKSIZE;
+ size = pri->phys_drive_len * DDF1_BLKSIZE;
+ if (!(vd = ddf1->vd_header =
+ alloc_private_and_read(lc, handler, size, di->path, where)))
+ goto bad;
+
+ ddf1_cvt_virt_drive_header(ddf1, vd);
+ if (vd->signature != DDF1_VIRT_DRIVE_REC) {
+ log_warn(lc, "%s: cannot find virtual drive records",
+ di->path);
+ goto bad;
+ }
+
+ /* Now read the virtual drive data */
+ ddf1->vds = (struct ddf1_virt_drive*)(((uint8_t*) vd) + sizeof (*pd));
+ for (i = 0; i < vd->num_drives; i++)
+ ddf1_cvt_virt_drive(ddf1, &ddf1->vds[i]);
+
+ /* Read config data */
+ where = (pri->primary_table_lba + pri->config_record_offset) *
+ DDF1_BLKSIZE;
+ size = pri->config_record_len * DDF1_BLKSIZE;
+ if (!(ddf1->cfg = alloc_private_and_read(lc, handler, size,
+ di->path, where)))
+ goto bad;
+
+ /*
+ * Ensure each record is: a config table for VDs; a config table for
+ * spare disks; or vendor-specifc data of some sort.
+ */
+ ddf1_cvt_records(lc, di, ddf1, 1);
+
+ /*
+ * FIXME: We don't pick up diagnostic logs, vendor specific logs,
+ * bad block data, etc. That shouldn't cause a problem with reading
+ * or writing metadata, but at some point we might want to do something
+ * with them.
+ */
+ ddf1->in_cpu_format = 1;
+ return 1;
+
+bad:
+ ddf1->vds = NULL;
+ ddf1->pds = NULL;
+ cond_free(ddf1->cfg);
+ cond_free(ddf1->pd_header);
+ cond_free(ddf1->disk_data);
+ cond_free(ddf1->adapter);
+ cond_free(ddf1->secondary);
+ cond_free(ddf1->primary);
+ return 0;
+}
+
+
+/* Count the number of raid_devs we need to create for this drive */
+static unsigned int num_devs(struct lib_context *lc, void *meta)
+{
+ struct ddf1 *ddf1 = meta;
+ unsigned int num_drives = ~0;
+
+ get_config_index(ddf1, get_this_phys_drive(ddf1), &num_drives);
+ return num_drives;
+}
+
+/* Check CRC on a given struct */
+/*
+enum struct_type { ANCHOR, HEADER_PRIM, HEADER_SEC,
+ ADAPTER, DISK_DATA, PHYS_DRIVES,
+ VIRT_DRIVES, CONFIG_RECORD };
+static uint32_t checksum(struct ddf1 *ddf1, enum struct_type type)
+{
+ struct {
+ enum struct_type type;
+ void *ptr;
+ size_t len;
+ } types[] = {
+ { ANCHOR, &ddf1->anchor, sizeof(ddf1->anchor) },
+ { HEADER_PRIM, ddf1->primary, sizeof(*ddf1->primary) },
+ { HEADER_SEC, ddf1->secondary, sizeof(*ddf1->secondary) },
+ { ADAPTER, ddf1->adapter, sizeof(*ddf1->adapter) },
+ { DISK_DATA, ddf1->disk_data, sizeof(*ddf1->disk_data) },
+ { PHYS_DRIVES, ddf1->pd_header, sizeof(*ddf1->pd_header) },
+ { VIRT_DRIVES, ddf1->vd_header, sizeof(*ddf1->vd_header) },
+ { CONFIG_RECORD, ddf1->cfg, sizeof(*ddf1->cfg) },
+ }, *t = ARRAY_END(types);
+
+ while (t-- > types) {
+ if (type == t->type)
+ return crc(t->ptr, t->len);
+ }
+
+ return 0;
+}
+*/
+
+/* Is this DDF1 metadata? */
+static inline int is_ddf1(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1)
+{
+ /*
+ * Check our magic numbers and that the version == v2.
+ * We don't support anything other than that right now.
+ */
+
+ /* FIXME: We should examine the version headers... */
+ return ddf1->anchor.signature == DDF1_HEADER ||
+ ddf1->anchor.signature == DDF1_HEADER_BACKWARDS;
+}
+
+/* Try to find DDF1 metadata at a given offset (ddf1_sboffset) */
+static struct ddf1 *try_to_find_ddf1(struct lib_context *lc,
+ struct dev_info *di,
+ size_t *sz, uint64_t *offset,
+ union read_info *info,
+ uint64_t ddf1_sboffset)
+{
+ struct ddf1 *ddf1;
+ // uint32_t crc;
+
+ /*
+ * Try to find a DDF1 anchor block at ddf1_sboffset. In theory this
+ * should be the very last block, but some Adaptec controllers have
+ * issues with standards compliance. So we have to try with various
+ * offsets.
+ */
+ if (!(ddf1 = alloc_private(lc, handler, sizeof(*ddf1))))
+ goto err;
+
+ if (!read_file(lc, handler, di->path, &ddf1->anchor, DDF1_BLKSIZE,
+ ddf1_sboffset) ||
+ !is_ddf1(lc, di, ddf1))
+ goto bad;
+
+ ddf1->anchor_offset = ddf1_sboffset;
+
+ /* Convert endianness */
+ ddf1->in_cpu_format = 0;
+ find_endian(lc, ddf1);
+ ddf1_cvt_header(ddf1, &ddf1->anchor);
+
+ /* FIXME: crc */
+/*
+ crc = checksum(ddf1, ANCHOR);
+ printf("crc=%08x ", crc);
+ printf("ddf1=%08x\n", ddf1->anchor.crc);
+*/
+
+ /* Read extended metadata. */
+ if (read_extended(lc, di, ddf1))
+ return ddf1;
+
+ bad:
+ dbg_free(ddf1);
+ err:
+ return NULL;
+}
+
+/*
+ * Attempt to interpret DDF1 metadata from a block device. This function
+ * returns either NULL or a pointer to a descriptor struct.
+ * Note that the struct should be fully converted to the correct endianness
+ * by the time this function returns.
+ */
+static void *read_metadata_areas(struct lib_context *lc, struct dev_info *di,
+ size_t *sz, uint64_t *offset,
+ union read_info *info)
+{
+ struct ddf1 *ddf1;
+
+ if ((ddf1 = try_to_find_ddf1(lc, di, sz, offset,
+ info, DDF1_CONFIGOFFSET)))
+ goto out;
+
+ if ((ddf1 = try_to_find_ddf1(lc, di, sz, offset,
+ info, DDF1_CONFIGOFFSET_ADAPTEC)))
+ ddf1->adaptec_mode = 1;
+
+ out:
+ return ddf1;
+}
+
+/* This is all hogwash since file_metadata can only be called once... */
+static void file_metadata_areas(struct lib_context *lc, struct dev_info *di,
+ void *meta)
+{
+ uint8_t *buf;
+ uint64_t start = find_ddf_beginning(meta);
+
+ if (!(buf = read_metadata_chunk(lc, di, start)))
+ return;
+
+ /* Record metadata. */
+ file_metadata(lc, handler, di->path, buf,
+ (di->sectors - start) * DDF1_BLKSIZE,
+ start * DDF1_BLKSIZE);
+
+ dbg_free(buf);
+
+ /* Record the device size. */
+ file_dev_size(lc, handler, di);
+}
+
+static int setup_rd(struct lib_context *lc, struct raid_dev *rd,
+ struct dev_info *di, void *meta, union read_info *info);
+static struct raid_dev *ddf1_read(struct lib_context *lc,
+ struct dev_info *di)
+{
+ /*
+ * NOTE: Everything called after read_metadata_areas assumes that
+ * the reserved block, raid table and config table have been
+ * converted to the appropriate endianness.
+ */
+ return read_raid_dev(lc, di, read_metadata_areas, 0, 0, NULL, NULL,
+ file_metadata_areas, setup_rd, handler);
+}
+
+/* Compose an "identifier" for use as a sort key for raid sets. */
+static inline int compose_id(struct ddf1 *ddf1, struct raid_dev *rd)
+{
+ struct ddf1_phys_drive *pd = get_this_phys_drive(ddf1);
+ int i = get_config_byoffset(ddf1, pd, rd->offset);
+
+ return i < 0 ? -1 : get_offset_entry(ddf1, get_config(ddf1, pd, i), pd);
+}
+
+/* No sort. */
+static int no_sort(struct list_head *pos, struct list_head *new)
+{
+ return 0;
+}
+
+/* Sort DDF1 devices by for a RAID set. */
+static int dev_sort(struct list_head *pos, struct list_head *new)
+{
+ return compose_id(META(RD(new)->private.ptr, ddf1), RD(new)) <
+ compose_id(META(RD(pos)->private.ptr, ddf1), RD(pos));
+}
+
+/*
+ * IO error event handler.
+ */
+static int event_io(struct lib_context *lc, struct event_io *e_io)
+{
+ log_err(lc, "I/O error on device %s at sector %lu.\n",
+ e_io->rd->di->path, e_io->sector);
+
+ LOG_ERR(lc, 0, "PANIC: ddf1 doesn't know about event_io!\n");
+}
+
+#if 0
+ /* FIXME: This should not use META() directly? */
+ struct raid_dev *rd = e_io->rd;
+ struct ddf1 *ddf1 = META(rd, ddf1);
+ struct ddf1_raid_configline *cl = this_disk(ddf1);
+ struct ddf1_raid_configline *fwl = find_logical(ddf1);
+
+ /* Ignore if we've already marked this disk broken(?) */
+ if (rd->status & s_broken)
+ return 0;
+
+ /* Mark the array as degraded and the disk as failed. */
+ rd->status = s_broken;
+ cl->raidstate = LSU_COMPONENT_STATE_FAILED;
+ fwl->raidstate = LSU_COMPONENT_STATE_DEGRADED;
+ /* FIXME: Do we have to mark a parent too? */
+
+ /* Indicate that this is indeed a failure. */
+ return 1;
+}
+#endif
+
+#define NAME_SIZE 64
+/* Formulate a RAID set name for this disk. */
+static char *name(struct lib_context *lc, struct ddf1 *ddf1,
+ struct raid_dev *rd)
+{
+ int i, prefix;
+ char *buf, *r;
+ struct ddf1_phys_drive *pd;
+ struct ddf1_virt_drive *vd;
+ struct ddf1_config_record *cr;
+
+ if (!(pd = get_this_phys_drive(ddf1)))
+ LOG_ERR(lc, NULL, "Cannot find physical drive description!");
+
+ if (!(buf = dbg_malloc(NAME_SIZE)))
+ LOG_ERR(lc, NULL, "Cannot allocate memory for name.");
+
+ i = get_config_byoffset(ddf1, pd, rd->offset);
+ cr = get_config(ddf1, pd, i);
+ if (i < 0 || !cr) {
+ sprintf(buf, ".ddf1_spares");
+ goto out;
+ }
+
+ if (!(vd = get_virt_drive(ddf1, cr))) {
+ dbg_free(buf);
+ LOG_ERR(lc, NULL, "Cannot find virtual drive description!");
+ }
+
+ sprintf(buf, "%s_", handler);
+ prefix = strlen(buf);
+
+ if (vd->name[0]) {
+ memcpy(buf + prefix, vd->name, 16);
+ i = prefix + 16;
+ while (!isgraph(buf[--i]));
+ buf[i+1] = 0;
+ } else {
+ char *b;
+
+ for (b = buf + prefix, i = 0; i < 24; b += 8, i += 4)
+ sprintf(b, "%02x%02x%02x%02x",
+ vd->guid[i], vd->guid[i+1],
+ vd->guid[i+2], vd->guid[i+3]);
+ }
+
+ out:
+ /* Just return the needed allocation */
+ r = dbg_strdup(buf);
+ dbg_free(buf);
+
+ return r;
+}
+
+/* Figure out the real size of a disk... */
+static uint64_t get_size(struct lib_context *lc, struct ddf1 *ddf1,
+ struct ddf1_config_record *cr,
+ struct ddf1_phys_drive *pd)
+{
+ if (cr)
+ /* Some Adaptec controllers need this clamping. */
+ return type(lc, ddf1, cr) == t_raid0 ?
+ cr->sectors - cr->sectors % stride(cr) : cr->sectors;
+
+ return pd->size;
+}
+
+/*
+ * Create all the volumes of a DDF disk as subsets of the top level DDF
+ * disk group. rs_group points to that raid set and is returned if the
+ * function is successful, NULL if not. rd_group is the raid_dev that
+ * represents the entire disk drive.
+ */
+static struct raid_set *group_rd(struct lib_context *lc,
+ struct raid_set *rs_group,
+ struct raid_dev *rd_group)
+{
+ struct ddf1 *ddf1 = META(rd_group, ddf1);
+ struct raid_set *rs = NULL;
+ struct raid_dev *rd;
+ struct ddf1_config_record *cr;
+ struct ddf1_phys_drive *pd;
+ unsigned int devs, i;
+
+ if (!(pd = get_this_phys_drive(ddf1)))
+ return NULL;
+
+ devs = num_devs(lc, ddf1);
+ for (i = 0; i < devs; i++) {
+ /* Allocate a raid_dev for this volume */
+ if (!(rd = alloc_raid_dev(lc, handler)))
+ return NULL;
+
+ cr = get_config(ddf1, pd, i);
+ rd->di = rd_group->di;
+ rd->fmt = rd_group->fmt;
+ rd->type = type(lc, ddf1, cr);
+ rd->offset = get_offset(ddf1, cr, pd);
+ rd->sectors = get_size(lc, ddf1, cr, pd);
+ rd->name = name(lc, ddf1, rd);
+
+ /* Stuff it into the appropriate raid set. */
+ if (!(rs = find_or_alloc_raid_set(lc, rd->name, FIND_ALL,
+ rd, &rs_group->sets,
+ NO_CREATE, NO_CREATE_ARG))) {
+ free_raid_dev(lc, &rd);
+ return NULL;
+ }
+
+ rs->stride = stride(cr);
+ rs->type = type(lc, ddf1, cr);
+ rs->status = s_ok;
+
+ if (!(rd->private.ptr = alloc_private(lc, handler,
+ sizeof(*rd_group))))
+ return NULL;
+
+ memcpy(rd->private.ptr, rd_group, sizeof (*rd_group));
+ list_add_sorted(lc, &rs->devs, &rd->devs, dev_sort);
+ }
+
+ return rs_group;
+}
+
+/*
+ * Add an DDF1 device to a RAID set. This involves finding the raid set to
+ * which this disk belongs, and then attaching it. Note that there are other
+ * complications, such as two-layer arrays (RAID10).
+ *
+ * FIXME: We haven't been able to set up a RAID10 for testing...
+ */
+static struct raid_set *ddf1_group(struct lib_context *lc, struct raid_dev *rd)
+{
+ struct ddf1 *ddf1 = META(rd, ddf1);
+ struct ddf1_phys_drive *pd;
+ struct raid_set *rs;
+ char *set_name;
+
+ if (!(pd = get_this_phys_drive(ddf1)))
+ LOG_ERR(lc, NULL, "Cannot find physical drive description!\n");
+
+ if (!(set_name = rd->name))
+ LOG_ERR(lc, NULL, "%s: Could not find RAID array name.\n",
+ rd->di->path);
+
+ /*
+ * Find/create a raid set for all DDF drives and put this disk
+ * into that set. The raid_sets for the real arrays will be created
+ * as children of the disk's raid_set.
+ *
+ * (Is this really necessary?)
+ */
+ if (!(rs = find_or_alloc_raid_set(lc, set_name, FIND_TOP, rd,
+ LC_RS(lc), NO_CREATE,
+ NO_CREATE_ARG)))
+ return NULL;
+
+ rs->type = t_group;
+ list_add_sorted(lc, &rs->devs, &rd->devs, no_sort);
+
+ /* Go deal with the real arrays. */
+ return group_rd(lc, rs, rd);
+}
+
+/* Write metadata. */
+static int ddf1_write(struct lib_context *lc, struct raid_dev *rd, int erase)
+{
+ int ret;
+ struct ddf1 *ddf1 = META(rd, ddf1);
+
+ ddf1_cvt_all(lc, ddf1, rd->di);
+ ret = write_metadata(lc, handler, rd, -1, erase);
+ ddf1_cvt_all(lc, ddf1, rd->di);
+
+ return ret;
+}
+
+/*
+ * Check integrity of a RAID set.
+ */
+
+/* Retrieve the number of devices that should be in this set. */
+static unsigned int device_count(struct raid_dev *rd, void *context)
+{
+ /* Get the logical drive */
+ struct ddf1_config_record *cr =
+ get_this_config(META(rd->private.ptr, ddf1), rd->offset);
+
+ return cr ? cr->primary_element_count : 0;
+}
+
+/* Check a RAID device */
+static int check_rd(struct lib_context *lc, struct raid_set *rs,
+ struct raid_dev *rd, void *context)
+{
+ /*
+ * FIXME: Should we do more checking for brokenness here?
+ * We could check SMART data, verify that nobody else is
+ * putting non-ddf disks in our raid set, etc.
+ */
+ return rd->type != s_broken;
+}
+
+/* Start the recursive RAID set check. */
+static int ddf1_check(struct lib_context *lc, struct raid_set *rs)
+{
+ return check_raid_set(lc, rs, device_count, NULL, check_rd,
+ NULL, handler);
+}
+
+static struct event_handlers ddf1_event_handlers = {
+ .io = event_io,
+ .rd = NULL, /* FIXME: no device add/remove event handler yet. */
+};
+
+#ifdef DMRAID_NATIVE_LOG
+/*
+ * Log native information about the RAID device.
+ */
+static void ddf1_log(struct lib_context *lc, struct raid_dev *rd)
+{
+ ddf1_dump_all(lc, handler, META(rd, ddf1), rd->di);
+}
+#endif /* #ifdef DMRAID_NATIVE_LOG */
+
+static struct dmraid_format ddf1_format = {
+ .name = HANDLER,
+ .descr = "SNIA DDF1",
+ .caps = "0,1,4,5,linear",
+ .format = FMT_RAID,
+ .read = ddf1_read,
+ .write = ddf1_write,
+ .group = ddf1_group,
+ .check = ddf1_check,
+ .events = &ddf1_event_handlers,
+#ifdef DMRAID_NATIVE_LOG
+ .log = ddf1_log,
+#endif
+};
+
+/* Register this format handler with the format core */
+int register_ddf1(struct lib_context *lc)
+{
+ return register_format_handler(lc, &ddf1_format);
+}
+
+/*
+ * Set up a RAID device from what we've assembled out of the metadata.
+ */
+static int setup_rd(struct lib_context *lc, struct raid_dev *rd,
+ struct dev_info *di, void *meta, union read_info *info)
+{
+ unsigned int i, ma_count = 5;
+ struct ddf1 *ddf1 = meta;
+ struct meta_areas *ma;
+ struct ddf1_phys_drive *pd;
+
+ if (!(pd = get_this_phys_drive(ddf1)))
+ LOG_ERR(lc, 0, "Cannot find physical drive description!\n");
+
+ /* We need multiple metadata areas */
+ ma_count += ddf1->adapter ? 1 : 0;
+ ma_count += ddf1->secondary ? 1 : 0;
+ ma_count += ddf1->disk_data ? 1 : 0;
+ /* FIXME: metadata area for workspace_lba */
+
+ if (!(ma = rd->meta_areas = alloc_meta_areas(lc, rd, handler,
+ ma_count)))
+ return 0;
+
+ /* Preset metadata area offset and size and adjust below */
+ for (i = 0; i < ma_count; i++) {
+ ma[i].offset = ddf1->primary->primary_table_lba;
+ ma[i].size = DDF1_BLKSIZE;
+ }
+
+ ma->offset = ddf1->anchor_offset;
+ (ma++)->area = &ddf1->anchor;
+
+ (ma++)->area = ddf1->primary;
+
+ if (ddf1->secondary)
+ (ma++)->offset = ddf1->primary->secondary_table_lba;
+
+ if (ddf1->adapter) {
+ ma->offset += ddf1->primary->adapter_data_offset;
+ ma->size *= ddf1->primary->adapter_data_len;
+ (ma++)->area = ddf1->adapter;
+ }
+
+ /* FIXME: set up workspace_lba */
+
+ if (ddf1->disk_data) {
+ ma->offset += ddf1->primary->disk_data_offset;
+ ma->size *= ddf1->primary->disk_data_len;
+ (ma++)->area = ddf1->disk_data;
+ }
+
+ ma->offset += ddf1->primary->phys_drive_offset;
+ ma->size *= ddf1->primary->phys_drive_len;
+ (ma++)->area = ddf1->pd_header;
+
+ ma->offset += ddf1->primary->virt_drive_offset;
+ ma->size *= ddf1->primary->virt_drive_len;
+ (ma++)->area = ddf1->vd_header;
+
+ ma->offset += ddf1->primary->config_record_offset;
+ ma->size *= ddf1->primary->config_record_len;
+ ma->area = ddf1->cfg;
+
+ /* Now set up the rest of the metadata info */
+ rd->di = di;
+ rd->fmt = &ddf1_format;
+ rd->status = disk_status(pd);
+ rd->type = t_group;
+ rd->offset = 0;
+ rd->sectors = get_size(lc, ddf1, NULL, pd);
+ rd->name = dbg_strdup((char*) ".ddf_disks"); /* FIXME: better name */
+ return rd->name ? 1 : 0;
+}
/cvs/dm/dmraid/lib/format/ddf/ddf1.h,v --> standard output
revision 1.1
--- dmraid/lib/format/ddf/ddf1.h
+++ - 2008-02-22 17:04:41.633908000 +0000
@@ -0,0 +1,273 @@
+/*
+ * SNIA DDF1 v1.0 metadata format handler.
+ *
+ * Copyright (C) 2005-2006 IBM, All rights reserved.
+ * Written by Darrick Wong <djwong@us.ibm.com>
+ *
+ * Copyright (C) 2006 Heinz Mauelshagen, Red Hat GmbH
+ * All rights reserved.
+ *
+ * See file LICENSE at the top of this source tree for license information.
+ */
+
+#ifndef _DDF1_H
+#define _DDF1_H
+
+/* Beginning of stuff that Darrick Wong added */
+#ifdef FORMAT_HANDLER
+#undef FORMAT_HANDLER
+
+#define HANDLER "ddf1"
+
+/* Number of config records */
+#define NUM_CONFIG_ENTRIES(ddf1) ((ddf1)->primary->config_record_len / \
+ (ddf1)->primary->vd_config_record_len)
+
+/* Macros to access config records */
+#define SR(ddf, idx) ((struct ddf1_spare_header*)(((uint8_t*)(ddf)->cfg) + \
+ ((idx) * (ddf)->primary->vd_config_record_len * 512)))
+
+#define CR(ddf, idx) ((struct ddf1_config_record*)(((uint8_t*)(ddf)->cfg) + \
+ ((idx) * (ddf)->primary->vd_config_record_len * 512)))
+
+#define CR_IDS(ddf, cr) ((uint32_t*)(((uint8_t*)(cr)) + \
+ sizeof(struct ddf1_config_record)))
+
+#define CR_OFF(ddf, cr) ((uint64_t*)(((uint8_t*)(cr)) + \
+ sizeof(struct ddf1_config_record) + \
+ (ddf1_cr_off_maxpds_helper(ddf) * sizeof(uint32_t))))
+
+
+/* DDF1 metadata offset in bytes */
+#define DDF1_CONFIGOFFSET ((di->sectors - 1) << 9)
+/* DDF1 metadata offset on weird adaptec controllers */
+#define DDF1_CONFIGOFFSET_ADAPTEC ((di->sectors - 257) << 9)
+
+/* Data offset in sectors */
+#define DDF1_DATAOFFSET 0
+
+/* Assume block size is 512... */
+#define DDF1_BLKSIZE 512
+
+/* Length of GUIDs in DDF */
+#define DDF1_GUID_LENGTH 24
+
+/* Length of DDF revision strings */
+#define DDF1_REV_LENGTH 8
+
+/* RAID types */
+#define DDF1_RAID0 0x00
+#define DDF1_RAID1 0x01
+#define DDF1_RAID3 0x03
+#define DDF1_RAID4 0x04
+#define DDF1_RAID5 0x05
+#define DDF1_RAID1E 0x11
+#define DDF1_JBOD 0x0F
+#define DDF1_CONCAT 0x1F
+#define DDF1_RAID5E 0x15
+#define DDF1_RAID5EE 0x25
+#define DDF1_RAID6 0x16
+
+#define DDF1_RAID5_RS 0
+#define DDF1_RAID5_LA 2
+#define DDF1_RAID5_LS 3
+
+/* Table signatures */
+#define DDF1_HEADER 0xDE11DE11
+#define DDF1_HEADER_BACKWARDS 0x11DE11DE
+#define DDF1_ADAPTER_DATA 0XAD111111
+#define DDF1_PHYS_DRIVE_REC 0X22222222
+#define DDF1_FORCED_PD_GUID 0x33333333
+#define DDF1_VIRT_DRIVE_REC 0xDDDDDDDD
+#define DDF1_VD_CONFIG_REC 0xEEEEEEEE
+#define DDF1_SPARE_REC 0x55555555
+#define DDF1_VU_CONFIG_REC 0x88888888
+#define DDF1_VENDOR_DATA 0x01DBEEF0
+#define DDF1_BAD_BLOCKS 0xABADB10C
+#define DDF1_INVALID 0xFFFFFFFF
+
+/* DDF1 version string */
+#define DDF1_VER_STRING "01.00.00"
+
+/* The DDF1 header table */
+struct ddf1_header {
+ uint32_t signature;
+ uint32_t crc;
+ uint8_t guid[DDF1_GUID_LENGTH];
+ uint8_t ddf_rev[DDF1_REV_LENGTH];
+ uint32_t seqnum;
+ uint32_t timestamp;
+ uint8_t open_flag;
+ uint8_t foreign_flag;
+ uint8_t grouping_enforced;
+ uint8_t reserved2[45];
+ uint64_t primary_table_lba;
+ uint64_t secondary_table_lba;
+ uint8_t header_type;
+ uint8_t reserved3[3];
+ uint32_t workspace_length;
+ uint64_t workspace_lba;
+ uint16_t max_phys_drives;
+ uint16_t max_virt_drives;
+ uint16_t max_partitions;
+ uint16_t vd_config_record_len;
+ uint16_t max_primary_elements;
+ uint8_t reserved4[54];
+ uint32_t adapter_data_offset;
+ uint32_t adapter_data_len;
+ uint32_t phys_drive_offset;
+ uint32_t phys_drive_len;
+ uint32_t virt_drive_offset;
+ uint32_t virt_drive_len;
+ uint32_t config_record_offset;
+ uint32_t config_record_len;
+ uint32_t disk_data_offset;
+ uint32_t disk_data_len;
+ uint32_t badblock_offset;
+ uint32_t badblock_len;
+ uint32_t diag_offset;
+ uint32_t diag_len;
+ uint32_t vendor_offset;
+ uint32_t vendor_len;
+ uint8_t reserved5[256];
+} __attribute__ ((packed));
+
+/* The adapter data header */
+struct ddf1_adapter {
+ uint32_t signature;
+ uint32_t crc;
+ uint8_t guid[DDF1_GUID_LENGTH];
+ uint16_t pci_vendor;
+ uint16_t pci_device;
+ uint16_t pci_subvendor;
+ uint16_t pci_subdevice;
+ uint8_t reserved2[24];
+ uint8_t adapter_data[448];
+} __attribute__ ((packed));
+
+/* Physical drive info */
+struct ddf1_disk_data {
+ uint32_t signature;
+ uint32_t crc;
+ uint8_t guid[DDF1_GUID_LENGTH];
+ uint32_t reference;
+ uint8_t forced_ref_flag;
+ uint8_t forced_guid_flag;
+ uint8_t scratch[32];
+ uint8_t reserved[442];
+} __attribute__ ((packed));
+
+/* Physical drive record header */
+struct ddf1_phys_drives {
+ uint32_t signature;
+ uint32_t crc;
+ uint16_t num_drives;
+ uint16_t max_drives;
+ uint8_t reserved2[52];
+ /* 64 bytes */
+ /* Drive records follow */
+} __attribute__ ((packed));
+
+/* Physical drive record */
+struct ddf1_phys_drive {
+ uint8_t guid[DDF1_GUID_LENGTH];
+ uint32_t reference;
+ uint16_t type;
+ uint16_t state;
+ uint64_t size;
+ uint8_t path_info[18];
+ uint8_t reserved3[6];
+} __attribute__ ((packed));
+
+/* Virtual drive record header */
+struct ddf1_virt_drives {
+ uint32_t signature;
+ uint32_t crc;
+ uint16_t num_drives;
+ uint16_t max_drives;
+ uint8_t reserved2[52];
+ /* Drive records follow */
+} __attribute__ ((packed));
+
+/* Virtual drive record */
+struct ddf1_virt_drive {
+ uint8_t guid[DDF1_GUID_LENGTH];
+ uint16_t vd_num;
+ uint16_t reserved2;
+ uint32_t type;
+ uint8_t state;
+ uint8_t init_state;
+ uint8_t reserved3[14];
+ uint8_t name[16];
+} __attribute__ ((packed));
+
+/* Virtual disk configuration record. */
+struct ddf1_config_record {
+ uint32_t signature;
+ uint32_t crc;
+ uint8_t guid[DDF1_GUID_LENGTH];
+ uint32_t timestamp;
+ uint32_t seqnum;
+ uint8_t reserved[24];
+ uint16_t primary_element_count;
+ uint8_t stripe_size;
+ uint8_t raid_level;
+ uint8_t raid_qualifier;
+ uint8_t secondary_element_count;
+ uint8_t secondary_element_number;
+ uint8_t secondary_element_raid_level;
+ uint64_t sectors;
+ uint64_t size;
+ uint64_t reserved2;
+ uint32_t spares[8];
+ uint64_t cache_policy;
+ uint8_t bg_task_rate;
+ /* 137 bytes */
+ uint8_t reserved3[3+52+192+32+32+16+16+32];
+ /* 512 bytes */
+} __attribute__ ((packed));
+
+/* Spare disk record */
+struct ddf1_spare {
+ uint8_t guid[DDF1_GUID_LENGTH];
+ uint16_t secondary_element;
+ uint8_t reserved[6];
+} __attribute__ ((packed));
+
+/* Spare disk assignment record */
+struct ddf1_spare_header {
+ uint32_t signature;
+ uint32_t crc;
+ uint32_t timestamp;
+ uint8_t reserved[7];
+ uint8_t type;
+ uint16_t num_spares;
+ uint16_t max_spares;
+ uint8_t reserved2[8];
+ struct ddf1_spare spares[0];
+} __attribute__ ((packed));
+
+/* Metadata owner */
+struct ddf1 {
+ struct ddf1_header anchor;
+ uint64_t anchor_offset;
+
+ struct ddf1_header *primary, *secondary;
+ struct ddf1_adapter *adapter;
+ struct ddf1_disk_data *disk_data;
+ struct ddf1_phys_drives *pd_header;
+ struct ddf1_phys_drive *pds;
+ struct ddf1_virt_drives *vd_header;
+ struct ddf1_virt_drive *vds;
+ struct ddf1_config_record *cfg;
+
+ int disk_format;
+ int in_cpu_format;
+ int adaptec_mode;
+};
+
+#endif /* FORMAT_HANDLER */
+
+int register_ddf1(struct lib_context *lc);
+
+#endif /* _DDF1_H */
/cvs/dm/dmraid/lib/format/ddf/ddf1_crc.c,v --> standard output
revision 1.1
--- dmraid/lib/format/ddf/ddf1_crc.c
+++ - 2008-02-22 17:04:41.774069000 +0000
@@ -0,0 +1,178 @@
+/*
+ * SNIA DDF1 v1.0 metadata format handler.
+ *
+ * Copyright (C) 2005-2006 IBM, All rights reserved.
+ * Written by James Simshaw <simshawj@us.ibm.com>
+ *
+ * Copyright (C) 2006 Heinz Mauelshagen, Red Hat GmbH
+ * All rights reserved.
+ *
+ * See file LICENSE at the top of this source tree for license information.
+ */
+
+#include "internal.h"
+
+#define FORMAT_HANDLER
+#include "ddf1.h"
+#include "ddf1_crc.h"
+#include "ddf1_lib.h"
+#include "zlib.h"
+
+#define DM_BYTEORDER_SWAB
+#include <datastruct/byteorder.h>
+
+/* CRC info for various functions below */
+struct crc_info {
+ void *p;
+ uint32_t *crc;
+ size_t size;
+ const char *text;
+};
+
+/* Compute the checksum of a table */
+static uint32_t do_crc32(struct lib_context *lc, struct crc_info *ci)
+{
+ uint32_t old_csum = *ci->crc, ret = crc32(0, NULL, 0); /* Init CRC */
+
+ *ci->crc = 0xFFFFFFFF;
+ ret = crc32(ret, ci->p, ci->size); /* zlib */
+ *ci->crc = old_csum;
+ return ret;
+}
+
+static inline size_t record_size(struct ddf1 *ddf1)
+{
+ return ddf1->primary->vd_config_record_len * DDF1_BLKSIZE;
+}
+
+#define CRC32(postfix, record_type, macro) \
+static int crc32_ ## postfix(struct lib_context *lc, struct dev_info *di, \
+ struct ddf1 *ddf1, int idx) \
+{ \
+ struct record_type *r = macro(ddf1, idx); \
+ struct crc_info ci = { \
+ .p = r, \
+ .crc = &r->crc, \
+ .size = record_size(ddf1), \
+ }; \
+\
+ r->crc = do_crc32(lc, &ci); \
+ return 1; \
+}
+
+CRC32(vd, ddf1_config_record, CR);
+CRC32(spare, ddf1_spare_header, SR);
+#undef CRC32
+
+
+/* Process the configuration records to have their CRCs updated */
+static int update_cfg_crc(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1)
+{
+ static struct ddf1_record_handler handlers = {
+ .vd = crc32_vd,
+ .spare = crc32_spare,
+ };
+
+ ddf1_process_records(lc, di, &handlers, ddf1, 0);
+ return 1;
+}
+
+/* Checks the CRC for a particular table */
+static int check_crc(struct lib_context *lc, struct dev_info *di,
+ struct crc_info *ci)
+{
+ uint32_t crc32;
+
+ crc32 = do_crc32(lc, ci);
+ if (*ci->crc != crc32)
+ log_warn(lc, "%s: %s with CRC %X, expected %X on %s",
+ HANDLER, ci->text, crc32, *ci->crc, di->path);
+
+ return 1;
+
+}
+
+#define CHECK_CRC(prefix, record_type, macro, txt) \
+static int prefix ## _check_crc(struct lib_context *lc, struct dev_info *di, \
+ struct ddf1 *ddf1, int idx) \
+{ \
+ struct record_type *r = macro(ddf1, idx); \
+ struct crc_info ci = { \
+ .p = r, \
+ .crc = &r->crc, \
+ .size = record_size(ddf1), \
+ .text = txt, \
+ }; \
+\
+ return check_crc(lc, di, &ci); \
+}
+CHECK_CRC(vd, ddf1_config_record, CR, "VD CFG");
+CHECK_CRC(spare, ddf1_spare_header, SR, "Spare CFG");
+#undef CHECK_CRC
+
+/* Process the configuration records to have their CRCs checked */
+static int check_cfg_crc(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1)
+{
+ struct ddf1_record_handler handlers = {
+ .vd = vd_check_crc,
+ .spare = spare_check_crc,
+ };
+
+ return ddf1_process_records(lc, di, &handlers, ddf1, 0);
+}
+
+
+/* Processes all of the DDF1 information for having their CRCs updated*/
+enum all_type { CHECK, UPDATE };
+static int all_crcs(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1, enum all_type type)
+{
+ int ret = 1;
+ uint32_t crc;
+ struct crc_info crcs[] = {
+ { ddf1->primary, &ddf1->primary->crc,
+ sizeof(*ddf1->primary), "primary header" },
+ { ddf1->secondary, &ddf1->secondary->crc,
+ sizeof(*ddf1->secondary), "secondary header" },
+ { ddf1->adapter, &ddf1->adapter->crc,
+ ddf1->primary->adapter_data_len * DDF1_BLKSIZE, "adapter" },
+ { ddf1->disk_data, &ddf1->disk_data->crc,
+ ddf1->primary->disk_data_len * DDF1_BLKSIZE, "disk data" },
+ { ddf1->pd_header, &ddf1->pd_header->crc,
+ ddf1->primary->phys_drive_len * DDF1_BLKSIZE,
+ "physical drives" },
+ { ddf1->vd_header, &ddf1->vd_header->crc,
+ ddf1->primary->virt_drive_len * DDF1_BLKSIZE,
+ "virtual drives" },
+ }, *c = ARRAY_END(crcs);
+
+ while (c-- > crcs) {
+ if (c->p) {
+ if (type == CHECK)
+ ret &= check_crc(lc, di, c);
+ else {
+ crc = do_crc32(lc, c);
+ *c->crc = crc;
+ }
+ }
+ }
+
+ return type == CHECK ? ret & check_cfg_crc(lc, di, ddf1) :
+ update_cfg_crc(lc, di, ddf1);
+}
+
+/* Processes the tables to check their CRCs */
+int ddf1_check_all_crcs(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1)
+{
+ return all_crcs(lc, di, ddf1, CHECK);
+}
+
+/* Processes all of the DDF1 information for having their CRCs updated */
+void ddf1_update_all_crcs(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1)
+{
+ all_crcs(lc, di, ddf1, UPDATE);
+}
/cvs/dm/dmraid/lib/format/ddf/ddf1_crc.h,v --> standard output
revision 1.1
--- dmraid/lib/format/ddf/ddf1_crc.h
+++ - 2008-02-22 17:04:41.890347000 +0000
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2006 Heinz Mauelshage, Red Hat GmbH
+ * All rights reserved.
+ *
+ * See file LICENSE at the top of this source tree for license information.
+ */
+
+/*
+ * Copyright (C) 2006 Heinz Mauelshagen, Red Hat GmbH.
+ * All rights reserved.
+ *
+ * See file LICENSE at the top of this source tree for license information.
+ */
+
+#ifndef _DDF1_CRC_H_
+#define _DDF1_CRC_H_
+
+int ddf1_check_all_crcs(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1);
+void ddf1_update_all_crcs(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1);
+
+#endif
/cvs/dm/dmraid/lib/format/ddf/ddf1_cvt.c,v --> standard output
revision 1.1
--- dmraid/lib/format/ddf/ddf1_cvt.c
+++ - 2008-02-22 17:04:41.991594000 +0000
@@ -0,0 +1,254 @@
+/*
+ * SNIA DDF1 v1.0 metadata format handler.
+ *
+ * Copyright (C) 2005-2006 IBM, All rights reserved.
+ * Written by Darrick Wong <djwong@us.ibm.com>
+ *
+ * Copyright (C) 2006 Heinz Mauelshagen, Red Hat GmbH
+ * All rights reserved.
+ *
+ * See file LICENSE at the top of this source tree for license information.
+ */
+
+#include "internal.h"
+#define FORMAT_HANDLER
+#include "ddf1.h"
+#include "ddf1_lib.h"
+#include "ddf1_cvt.h"
+
+#define DM_BYTEORDER_SWAB
+#include <datastruct/byteorder.h>
+
+/* Convert a DDF header */
+void ddf1_cvt_header(struct ddf1 *ddf1, struct ddf1_header *hdr)
+{
+ if (BYTE_ORDER == ddf1->disk_format)
+ return;
+
+ CVT32(hdr->signature);
+ CVT32(hdr->crc);
+ CVT32(hdr->seqnum);
+ CVT32(hdr->timestamp);
+ CVT64(hdr->primary_table_lba);
+ CVT64(hdr->secondary_table_lba);
+ CVT32(hdr->workspace_length);
+ CVT64(hdr->workspace_lba);
+ CVT16(hdr->max_phys_drives);
+ CVT16(hdr->max_virt_drives);
+ CVT16(hdr->max_partitions);
+ CVT16(hdr->vd_config_record_len);
+ CVT16(hdr->max_primary_elements);
+ CVT32(hdr->adapter_data_offset);
+ CVT32(hdr->adapter_data_len);
+ CVT32(hdr->phys_drive_offset);
+ CVT32(hdr->phys_drive_len);
+ CVT32(hdr->virt_drive_offset);
+ CVT32(hdr->virt_drive_len);
+ CVT32(hdr->config_record_offset);
+ CVT32(hdr->config_record_len);
+ CVT32(hdr->disk_data_offset);
+ CVT32(hdr->disk_data_len);
+ CVT32(hdr->badblock_offset);
+ CVT32(hdr->badblock_len);
+ CVT32(hdr->diag_offset);
+ CVT32(hdr->diag_len);
+ CVT32(hdr->vendor_offset);
+ CVT32(hdr->vendor_len);
+}
+
+/* Convert DDF adapter data */
+void ddf1_cvt_adapter(struct ddf1 *ddf1, struct ddf1_adapter *hdr)
+{
+ if (BYTE_ORDER == ddf1->disk_format)
+ return;
+
+ CVT32(hdr->signature);
+ CVT32(hdr->crc);
+ CVT16(hdr->pci_vendor);
+ CVT16(hdr->pci_device);
+ CVT16(hdr->pci_subvendor);
+ CVT16(hdr->pci_subdevice);
+}
+
+/* Convert physical disk data */
+void ddf1_cvt_disk_data(struct ddf1 *ddf1, struct ddf1_disk_data *hdr)
+{
+ if (BYTE_ORDER == ddf1->disk_format)
+ return;
+
+ CVT32(hdr->signature);
+ CVT32(hdr->crc);
+ CVT32(hdr->reference);
+}
+
+/* Convert physical drive header data */
+void ddf1_cvt_phys_drive_header(struct ddf1 *ddf1, struct ddf1_phys_drives *hdr)
+{
+ if (BYTE_ORDER == ddf1->disk_format)
+ return;
+
+ CVT32(hdr->signature);
+ CVT32(hdr->crc);
+ CVT16(hdr->num_drives);
+ CVT16(hdr->max_drives);
+}
+
+/* Convert physical drive data */
+void ddf1_cvt_phys_drive(struct ddf1 *ddf1, struct ddf1_phys_drive *hdr)
+{
+ if (BYTE_ORDER == ddf1->disk_format)
+ return;
+
+ CVT32(hdr->reference);
+ CVT16(hdr->type);
+ CVT16(hdr->state);
+ CVT64(hdr->size);
+}
+
+/* Convert virtual drive header data */
+void ddf1_cvt_virt_drive_header(struct ddf1 *ddf1, struct ddf1_virt_drives *hdr)
+{
+ if (BYTE_ORDER == ddf1->disk_format)
+ return;
+
+ CVT32(hdr->signature);
+ CVT32(hdr->crc);
+ CVT16(hdr->num_drives);
+ CVT16(hdr->max_drives);
+}
+
+/* Convert virtual drive data */
+void ddf1_cvt_virt_drive(struct ddf1 *ddf1, struct ddf1_virt_drive *hdr)
+{
+ if (BYTE_ORDER == ddf1->disk_format)
+ return;
+
+ CVT32(hdr->vd_num);
+ CVT32(hdr->type);
+}
+
+/* Convert config record data */
+int ddf1_cvt_config_record(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1, int idx)
+{
+ unsigned int i;
+ uint16_t max_pds;
+ uint32_t *ids, x;
+ uint64_t *off;
+ struct ddf1_config_record *hdr = CR(ddf1, idx);
+
+ if (BYTE_ORDER == ddf1->disk_format)
+ return 1;
+
+ max_pds = hdr->primary_element_count;
+ ids = CR_IDS(ddf1, hdr);
+
+ /* This chunk is derived from CR_OFF */
+ x = ddf1_cr_off_maxpds_helper(ddf1);
+ if (ddf1->primary->signature == DDF1_HEADER_BACKWARDS)
+ CVT32(x);
+
+ off = ((uint64_t*) (((uint8_t*) hdr) + sizeof(*hdr) + (x * sizeof(x))));
+
+ CVT32(hdr->signature);
+ CVT32(hdr->crc);
+ CVT32(hdr->timestamp);
+ CVT32(hdr->seqnum);
+ CVT16(hdr->primary_element_count);
+ if (!ddf1->in_cpu_format)
+ max_pds = hdr->primary_element_count;
+
+ CVT64(hdr->sectors);
+ CVT64(hdr->size);
+ for (i = 0; i < 8; i++)
+ CVT32(hdr->spares[i]);
+
+ CVT64(hdr->cache_policy);
+ for (i = 0; i < max_pds; i++) {
+ CVT32(ids[i]);
+ CVT64(off[i]);
+ }
+ return 1;
+}
+
+/* Convert spare records */
+int ddf1_cvt_spare_record(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1, int idx)
+{
+ uint16_t x, i;
+ struct ddf1_spare_header *sh = SR(ddf1, idx);
+
+ if (BYTE_ORDER == ddf1->disk_format)
+ return 1;
+
+ CVT32(sh->signature);
+ CVT32(sh->crc);
+ CVT32(sh->timestamp);
+ CVT16(sh->max_spares);
+ x = sh->num_spares;
+ CVT16(sh->num_spares);
+ if (!ddf1->in_cpu_format)
+ x = sh->num_spares;
+
+ for (i = 0; i < x; i++)
+ CVT16(sh->spares[i].secondary_element);
+
+ return 1;
+}
+
+void ddf1_cvt_records(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1, int in_cpu_format)
+{
+ static struct ddf1_record_handler handlers = {
+ .vd = ddf1_cvt_config_record,
+ .spare = ddf1_cvt_spare_record,
+ };
+
+ ddf1_process_records(lc, di, &handlers, ddf1, in_cpu_format);
+}
+
+/* Convert endianness of all metadata */
+void ddf1_cvt_all(struct lib_context *lc, struct ddf1 *ddf1,
+ struct dev_info *di)
+{
+ int i;
+ uint16_t pds = 0, vds = 0;
+
+ ddf1_cvt_header(ddf1, &ddf1->anchor);
+ if (ddf1->in_cpu_format)
+ ddf1_cvt_records(lc, di, ddf1, ddf1->in_cpu_format);
+
+ ddf1_cvt_header(ddf1, ddf1->primary);
+ if (!ddf1->in_cpu_format)
+ ddf1_cvt_records(lc, di, ddf1, ddf1->in_cpu_format);
+
+ if (ddf1->secondary)
+ ddf1_cvt_header(ddf1, ddf1->secondary);
+
+ if (ddf1->adapter)
+ ddf1_cvt_adapter(ddf1, ddf1->adapter);
+
+ ddf1_cvt_disk_data(ddf1, ddf1->disk_data);
+
+ if (ddf1->in_cpu_format)
+ pds = ddf1->pd_header->num_drives;
+
+ ddf1_cvt_phys_drive_header(ddf1, ddf1->pd_header);
+ if (!ddf1->in_cpu_format)
+ pds = ddf1->pd_header->num_drives;
+
+ for (i = 0; i < pds; i++)
+ ddf1_cvt_phys_drive(ddf1, &ddf1->pds[i]);
+
+ if (ddf1->in_cpu_format)
+ vds = ddf1->vd_header->num_drives;
+
+ ddf1_cvt_virt_drive_header(ddf1, ddf1->vd_header);
+ if (!ddf1->in_cpu_format)
+ vds = ddf1->vd_header->num_drives;
+
+ for (i = 0; i < vds; i++)
+ ddf1_cvt_virt_drive(ddf1, &ddf1->vds[i]);
+
+ ddf1->in_cpu_format = !ddf1->in_cpu_format;
+}
/cvs/dm/dmraid/lib/format/ddf/ddf1_cvt.h,v --> standard output
revision 1.1
--- dmraid/lib/format/ddf/ddf1_cvt.h
+++ - 2008-02-22 17:04:42.116921000 +0000
@@ -0,0 +1,36 @@
+/*
+ * SNIA DDF1 v1.0 metadata format handler.
+ *
+ * Copyright (C) 2005-2006 IBM, All rights reserved.
+ * Written by Darrick Wong <djwong@us.ibm.com>
+ *
+ * Copyright (C) 2006 Heinz Mauelshagen, Red Hat GmbH
+ * All rights reserved.
+ *
+ * See file LICENSE at the top of this source tree for license information.
+ */
+
+#ifndef _DDF1_CVT_H_
+#define _DDF1_CVT_H_
+
+#include "internal.h"
+
+void ddf1_cvt_header(struct ddf1 *ddf1, struct ddf1_header *hdr);
+void ddf1_cvt_adapter(struct ddf1 *ddf1, struct ddf1_adapter *hdr);
+void ddf1_cvt_disk_data(struct ddf1 *ddf1, struct ddf1_disk_data *hdr);
+void ddf1_cvt_phys_drive_header(struct ddf1 *ddf1,
+ struct ddf1_phys_drives *hdr);
+void ddf1_cvt_phys_drive(struct ddf1 *ddf1, struct ddf1_phys_drive *hdr);
+void ddf1_cvt_virt_drive_header(struct ddf1 *ddf1,
+ struct ddf1_virt_drives *hdr);
+void ddf1_cvt_virt_drive(struct ddf1 *ddf1, struct ddf1_virt_drive *hdr);
+int ddf1_cvt_config_record(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1, int idx);
+int ddf1_cvt_spare_record(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1, int idx);
+void ddf1_cvt_records(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1, int in_cpu_format);
+void ddf1_cvt_all(struct lib_context *lc, struct ddf1 *ddf1,
+ struct dev_info *di);
+
+#endif
/cvs/dm/dmraid/lib/format/ddf/ddf1_dump.c,v --> standard output
revision 1.1
--- dmraid/lib/format/ddf/ddf1_dump.c
+++ - 2008-02-22 17:04:42.195186000 +0000
@@ -0,0 +1,281 @@
+/*
+ * SNIA DDF1 v1.0 metadata format handler.
+ *
+ * Copyright (C) 2005-2006 IBM, All rights reserved.
+ * Written by Darrick Wong <djwong@us.ibm.com>
+ *
+ * Copyright (C) 2006 Heinz Mauelshagen, Red Hat GmbH
+ * All rights reserved.
+ *
+ * See file LICENSE at the top of this source tree for license information.
+ */
+
+#ifdef DMRAID_NATIVE_LOG
+
+#include "internal.h"
+#define FORMAT_HANDLER
+#include "ddf1.h"
+#include "ddf1_lib.h"
+
+/* Print DDF GUIDs. */
+#ifdef NATIVE_LOG_OFFSET
+
+#define DP_BUF(name, basevar, x, len) do { \
+ _dp_guid(lc, name, P_OFF(x, basevar, x), len);\
+} while (0)
+
+#define DP_GUID(name, basevar, x) do {\
+_dp_guid(lc, name, P_OFF(x, basevar, x), DDF1_GUID_LENGTH);\
+} while (0)
+
+static void _dp_guid(struct lib_context *lc, const char *name,
+ unsigned int offset, void *data, unsigned int len)
+{
+ char *p;
+ int i;
+
+ p = data;
+ log_print_nnl(lc, "0x%03x %s\"", offset, name);
+ for (i = 0; i < len; i++)
+ log_print_nnl(lc, "%c",
+ (isgraph(p[i]) || p[i] == ' ' ? p[i] : '.'));
+
+ log_print_nnl(lc, "\" [");
+ for (i = 0; i < len; i++)
+ log_print_nnl(lc, "%s%02x", (i != 0 ? " " : ""), p[i] & 0xFF);
+
+ log_print_nnl(lc, "]\n");
+}
+#else
+#define DP_BUF(name, basevar, x, len)
+#define DP_GUID(name, basevar, x)
+#endif
+
+/* Dump top */
+static void dump_top(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1, const char *handler)
+{
+ log_print(lc, "%s (%s):", di->path, handler);
+ log_print(lc, "DDF1 anchor at %llu with tables in %s-endian format.",
+ ddf1->anchor_offset / DDF1_BLKSIZE,
+ (ddf1->disk_format == LITTLE_ENDIAN ? "little" : "big"));
+}
+
+/* Dump DDF tables. */
+static void dump_header(struct lib_context *lc, struct ddf1_header *dh)
+{
+ if (!dh)
+ return;
+
+ log_print(lc, "DDF1 Header at %p", dh);
+ DP("signature:\t0x%X", dh, dh->signature);
+ DP("crc:\t\t0x%X", dh, dh->crc);
+ DP_GUID("guid:\t\t", dh, dh->guid);
+ DP_BUF("rev:\t\t", dh, dh->ddf_rev, DDF1_REV_LENGTH);
+ DP("seqnum:\t\t%d", dh, dh->seqnum);
+ DP("timestamp:\t0x%X", dh, dh->timestamp);
+ DP("open:\t\t0x%X", dh, dh->open_flag);
+ DP("foreign:\t\t0x%X", dh, dh->foreign_flag);
+ DP("grouping:\t\t0x%X", dh, dh->grouping_enforced);
+ DP("primary header:\t%lu", dh, dh->primary_table_lba);
+ DP("secondary header:\t%lu", dh, dh->secondary_table_lba);
+ DP("header type:\t0x%X", dh, dh->header_type);
+ DP("workspace len:\t%d", dh, dh->workspace_length);
+ DP("workspace lba:\t%lu", dh, dh->workspace_lba);
+ DP("max pd:\t\t%d", dh, dh->max_phys_drives);
+ DP("max vd:\t\t%d", dh, dh->max_virt_drives);
+ DP("max part:\t\t%d", dh, dh->max_partitions);
+ DP("vd_config len:\t%d", dh, dh->vd_config_record_len);
+ DP("max_primary_elts:\t%d", dh, dh->max_primary_elements);
+ DP("adapter_offset:\t%d", dh, dh->adapter_data_offset);
+ DP("adapter_len:\t%d", dh, dh->adapter_data_len);
+ DP("pd_offset:\t%d", dh, dh->phys_drive_offset);
+ DP("pd_len:\t\t%d", dh, dh->phys_drive_len);
+ DP("vd_offset:\t%d", dh, dh->virt_drive_offset);
+ DP("vd_len:\t\t%d", dh, dh->virt_drive_len);
+ DP("config_offset:\t%d", dh, dh->config_record_offset);
+ DP("config_len:\t%d", dh, dh->config_record_len);
+ DP("disk_data_offset:\t%d", dh, dh->disk_data_offset);
+ DP("disk_data_len:\t%d", dh, dh->disk_data_len);
+ DP("badblock_offset:\t%d", dh, dh->badblock_offset);
+ DP("badblock_len:\t%d", dh, dh->badblock_len);
+ DP("diag_offset:\t%d", dh, dh->diag_offset);
+ DP("diag_len:\t\t%d", dh, dh->diag_len);
+ DP("vendor_offset:\t%d", dh, dh->vendor_offset);
+ DP("vendor_len:\t%d", dh, dh->vendor_len);
+}
+
+static void dump_adapter(struct lib_context *lc, struct ddf1_adapter *da)
+{
+ if (!da)
+ return;
+
+ log_print(lc, "Adapter Data at %p", da);
+ DP("signature:\t0x%X", da, da->signature);
+ DP("crc:\t\t0x%X", da, da->crc);
+ DP_GUID("guid:\t\t", da, da->guid);
+ DP("pci vendor:\t0x%X", da, da->pci_vendor);
+ DP("pci device:\t0x%X", da, da->pci_device);
+ DP("pci subvendor:\t0x%X", da, da->pci_subvendor);
+ DP("pci subdevice:\t0x%X", da, da->pci_subdevice);
+}
+
+static void dump_disk_data(struct lib_context *lc, struct ddf1_disk_data *fg)
+{
+ log_print(lc, "Disk Data at %p", fg);
+ DP("signature:\t0x%X", fg, fg->signature);
+ DP("crc:\t\t0x%X", fg, fg->crc);
+ DP_GUID("guid:\t\t", fg, fg->guid);
+ DP("reference:\t\t0x%X", fg, fg->reference);
+ DP("forced_ref_flag:\t%d", fg, fg->forced_ref_flag);
+ DP("forced_guid_flag:\t%d", fg, fg->forced_guid_flag);
+}
+
+static void dump_phys_drive_header(struct lib_context *lc,
+ struct ddf1_phys_drives *pd)
+{
+ log_print(lc, "Physical Drive Header at %p", pd);
+ DP("signature:\t0x%X", pd, pd->signature);
+ DP("crc:\t\t0x%X", pd, pd->crc);
+ DP("num drives:\t%d", pd, pd->num_drives);
+ DP("max drives:\t%d", pd, pd->max_drives);
+}
+
+static void dump_phys_drive(struct lib_context *lc, struct ddf1_phys_drive *pd)
+{
+ log_print(lc, "Physical Drive at %p", pd);
+ DP_GUID("guid:\t\t", pd, pd->guid);
+ DP("reference #:\t0x%X", pd, pd->reference);
+ DP("type:\t\t0x%X", pd, pd->type);
+ DP("state:\t\t0x%X", pd, pd->state);
+ DP("size:\t\t%llu", pd, pd->size);
+ DP_BUF("path info:\t", pd, pd->path_info, 18);
+}
+
+static void dump_virt_drive_header(struct lib_context *lc,
+ struct ddf1_virt_drives *vd)
+{
+ log_print(lc, "Virtual Drive Header at %p", vd);
+ DP("signature:\t0x%X", vd, vd->signature);
+ DP("crc:\t\t0x%X", vd, vd->crc);
+ DP("num drives:\t%d", vd, vd->num_drives);
+ DP("max drives:\t%d", vd, vd->max_drives);
+}
+
+static void dump_virt_drive(struct lib_context *lc, struct ddf1_virt_drive *vd)
+{
+ log_print(lc, "Virtual Drive at %p", vd);
+ DP_GUID("guid:\t\t", vd, vd->guid);
+ DP("vd #:\t\t0x%X", vd, vd->vd_num);
+ DP("type:\t\t0x%X", vd, vd->type);
+ DP("state:\t\t0x%X", vd, vd->state);
+ DP("init state:\t0x%X", vd, vd->init_state);
+ DP_BUF("name:\t\t", vd, vd->name, 16);
+}
+
+static int dump_config_record(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf, int idx)
+{
+ int i;
+ uint16_t x;
+ uint32_t *cfg_drive_ids;
+ uint64_t *cfg_drive_offsets;
+ struct ddf1_config_record *cfg = CR(ddf, idx);
+
+ if (cfg->signature != DDF1_VD_CONFIG_REC)
+ return 1;
+
+ log_print(lc, "Virtual Drive Config Record at %p", cfg);
+ DP("signature:\t0x%X", cfg, cfg->signature);
+ DP("crc:\t\t0x%X", cfg, cfg->crc);
+ DP_GUID("guid:\t\t", cfg, cfg->guid);
+ DP("timestamp:\t0x%X", cfg, cfg->timestamp);
+ DP("seqnum:\t\t%d", cfg, cfg->seqnum);
+ DP("primary count:\t%d", cfg, cfg->primary_element_count);
+ DP("stripe size:\t%dKiB", cfg, cfg->stripe_size);
+ DP("raid level:\t%d", cfg, cfg->raid_level);
+ DP("raid qualifier:\t%d", cfg, cfg->raid_qualifier);
+ DP("secondary count:\t%d", cfg, cfg->secondary_element_count);
+ DP("secondary number:\t%d", cfg, cfg->secondary_element_number);
+ DP("secondary level:\t%d", cfg, cfg->secondary_element_raid_level);
+ DP("spare 0:\t\t0x%X", cfg, cfg->spares[0]);
+ DP("spare 1:\t\t0x%X", cfg, cfg->spares[1]);
+ DP("spare 2:\t\t0x%X", cfg, cfg->spares[2]);
+ DP("spare 3:\t\t0x%X", cfg, cfg->spares[3]);
+ DP("spare 4:\t\t0x%X", cfg, cfg->spares[4]);
+ DP("spare 5:\t\t0x%X", cfg, cfg->spares[5]);
+ DP("spare 6:\t\t0x%X", cfg, cfg->spares[6]);
+ DP("spare 7:\t\t0x%X", cfg, cfg->spares[7]);
+ DP("cache policy:\t0x%X", cfg, cfg->cache_policy);
+ DP("bg task rate:\t%d", cfg, cfg->bg_task_rate);
+ DP("sector count:\t%llu", cfg, cfg->sectors);
+ DP("size:\t\t%llu", cfg, cfg->size);
+ cfg_drive_ids = CR_IDS(ddf, cfg);
+ cfg_drive_offsets = CR_OFF(ddf, cfg);
+
+ x = cfg->primary_element_count;
+ log_print(lc, "Drive map:");
+ for (i = 0; i < x; i++) {
+ log_print(lc, "%d: %X @ %lu", i, cfg_drive_ids[i],
+ cfg_drive_offsets[i]);
+ }
+ return 1;
+}
+
+static int dump_spares(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1, int idx)
+{
+ int i;
+ struct ddf1_spare_header *sh = SR(ddf1, idx);
+
+ log_print(lc, "Spare Config Record at %p", sh);
+ DP("signature:\t0x%X", sh, sh->signature);
+ DP("crc:\t\t0x%X", sh, sh->crc);
+ DP("timestamp:\t0x%X", sh, sh->timestamp);
+ DP("type:\t\t0x%X", sh, sh->type);
+ DP("num drives:\t%d", sh, sh->num_spares);
+ DP("max drives:\t%d", sh, sh->max_spares);
+
+ for (i = 0; i < sh->num_spares; i++) {
+ log_print(lc, "Spare %d:", i);
+ DP_GUID("guid:\t\t", sh, sh->spares[i].guid);
+ DP("secondary:\t%d", sh, sh->spares[i].secondary_element);
+ }
+ return 1;
+}
+
+static void dump_config_records(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1)
+{
+ static struct ddf1_record_handler handlers = {
+ .vd = dump_config_record,
+ .spare = dump_spares,
+ };
+
+ ddf1_process_records(lc, di, &handlers, ddf1, 1);
+}
+
+/* Dump the entire table */
+void ddf1_dump_all(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1, const char *handler)
+{
+ int i;
+
+ dump_top(lc, di, ddf1, handler);
+ dump_header(lc, &ddf1->anchor);
+ dump_header(lc, ddf1->primary);
+ dump_header(lc, ddf1->secondary);
+ dump_adapter(lc, ddf1->adapter);
+ dump_disk_data(lc, ddf1->disk_data);
+ dump_phys_drive_header(lc, ddf1->pd_header);
+ for (i = 0; i < ddf1->pd_header->num_drives; i++)
+ dump_phys_drive(lc, ddf1->pds + i);
+
+ dump_virt_drive_header(lc, ddf1->vd_header);
+ for (i = 0; i < ddf1->vd_header->num_drives; i++)
+ dump_virt_drive(lc, ddf1->vds + i);
+
+ dump_config_records(lc, di, ddf1);
+}
+
+#endif /* DMRAID_NATIVE_LOG */
/cvs/dm/dmraid/lib/format/ddf/ddf1_dump.h,v --> standard output
revision 1.1
--- dmraid/lib/format/ddf/ddf1_dump.h
+++ - 2008-02-22 17:04:42.273199000 +0000
@@ -0,0 +1,24 @@
+/*
+ * SNIA DDF1 v1.0 metadata format handler.
+ *
+ * Copyright (C) 2005-2006 IBM, All rights reserved.
+ * Written by Darrick Wong <djwong@us.ibm.com>
+ *
+ * Copyright (C) 2006 Heinz Mauelshagen, Red Hat GmbH
+ * All rights reserved.
+ *
+ * See file LICENSE at the top of this source tree for license information.
+ */
+
+#ifdef DMRAID_NATIVE_LOG
+
+#include "internal.h"
+
+#ifndef _DDF1_DUMP_H_
+#define _DDF1_DUMP_H_
+
+void ddf1_dump_all(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1, const char *handler);
+
+#endif /* _DDF1_DUMP_H */
+#endif /* DMRAID_NATIVE_LOG */
/cvs/dm/dmraid/lib/format/ddf/ddf1_lib.c,v --> standard output
revision 1.1
--- dmraid/lib/format/ddf/ddf1_lib.c
+++ - 2008-02-22 17:04:42.350222000 +0000
@@ -0,0 +1,102 @@
+/*
+ * SNIA DDF1 v1.0 metadata format handler.
+ *
+ * Copyright (C) 2005-2006 IBM, All rights reserved.
+ * Written by Darrick Wong <djwong@us.ibm.com>
+ *
+ * Copyright (C) 2006 Heinz Mauelshagen, Red Hat GmbH
+ * All rights reserved.
+ *
+ * See file LICENSE at the top of this source tree for license information.
+ */
+
+#include "internal.h"
+
+#define FORMAT_HANDLER
+#include "ddf1.h"
+#include "ddf1_lib.h"
+
+#define DM_BYTEORDER_SWAB
+#include <datastruct/byteorder.h>
+
+/* Figure out what endian conversions we need */
+int ddf1_endianness(struct lib_context *lc, struct ddf1 *ddf1)
+{
+ uint8_t *ptr = (uint8_t*) &ddf1->anchor.signature;
+
+ if (ptr[0] == 0xDE && ptr[1] == 0x11)
+ return BIG_ENDIAN;
+ else if (ptr[0] == 0x11 && ptr[1] == 0xDE)
+ return LITTLE_ENDIAN;
+ else
+ LOG_ERR(lc, -EINVAL, "Can't figure out endianness!");
+}
+
+/* Find the beginning of all DDF metadata */
+uint64_t ddf1_beginning(struct ddf1 *ddf1)
+{
+ uint64_t start;
+ struct ddf1_header *h = &ddf1->anchor;
+
+ start = ddf1->anchor_offset;
+ if (h->primary_table_lba < start)
+ start = h->primary_table_lba;
+ if (h->secondary_table_lba < start)
+ start = h->secondary_table_lba;
+#ifdef WORKSPACE_IS_PART_OF_DDF
+ if (ddf1->primary->workspace_lba < start)
+ start = ddf1->primary->workspace_lba;
+#endif
+
+ return start;
+}
+
+/* Helper for CR_OFF */
+uint16_t ddf1_cr_off_maxpds_helper(struct ddf1 *ddf1)
+{
+ struct ddf1_header *h = ddf1->primary;
+
+ /* The 0xFFFF nonsense is a weird Adaptec quirk */
+ return (h->max_primary_elements == 0xFFFF && ddf1->adaptec_mode) ?
+ h->max_phys_drives : h->max_primary_elements;
+}
+
+/* Process DDF1 records depending on type */
+int ddf1_process_records(struct lib_context *lc, struct dev_info *di,
+ struct ddf1_record_handler *handler,
+ struct ddf1 *ddf1, int in_cpu_format)
+{
+ unsigned int i, cfgs = NUM_CONFIG_ENTRIES(ddf1);
+ uint32_t x;
+
+ for (i = 0; i < cfgs; i++) {
+ x = *((uint32_t*) CR(ddf1, i));
+ if (!in_cpu_format &&
+ BYTE_ORDER != ddf1->disk_format)
+ CVT32(x);
+
+ switch (x) {
+ case DDF1_VD_CONFIG_REC:
+ if (!handler->vd(lc, di, ddf1, i))
+ return 0;
+
+ break;
+
+ case DDF1_SPARE_REC:
+ if (!handler->spare(lc, di, ddf1, i))
+ return 0;
+
+ break;
+
+ case 0: /* Adaptec puts zero in this field??? */
+ case DDF1_INVALID:
+ break;
+
+ default:
+ log_warn(lc, "%s: Unknown config record %d.",
+ di->path, x);
+ }
+ }
+
+ return 1;
+}
/cvs/dm/dmraid/lib/format/ddf/ddf1_lib.h,v --> standard output
revision 1.1
--- dmraid/lib/format/ddf/ddf1_lib.h
+++ - 2008-02-22 17:04:42.433453000 +0000
@@ -0,0 +1,53 @@
+/*
+ * SNIA DDF1 v1.0 metadata format handler.
+ *
+ * Copyright (C) 2005-2006 IBM, All rights reserved.
+ * Written by Darrick Wong <djwong@us.ibm.com>
+ *
+ * Copyright (C) 2006 Heinz Mauelshagen, Red Hat GmbH
+ * All rights reserved.
+ *
+ * See file LICENSE at the top of this source tree for license information.
+ */
+
+#ifndef _DDF1_LIB_H
+#define _DDF1_LIB_H
+
+/* Cpmpare two GUIDs */
+static inline uint8_t _and(uint8_t *p)
+{
+ return p[20] & p[21] & p[22] & p[23];
+}
+
+static inline int guidcmp(uint8_t *one, uint8_t *two)
+{
+ int x = memcmp(one, two, DDF1_GUID_LENGTH - 4);
+
+ if (x)
+ return x;
+
+ return (_and(one) || _and(two)) ? 0 : memcmp(one + 20, two + 20, 4);
+}
+
+/* Byte offset for sector */
+static inline uint64_t to_bytes(uint64_t sector)
+{
+ return sector * DDF1_BLKSIZE;
+}
+
+uint64_t ddf1_beginning(struct ddf1 *ddf1);
+uint16_t ddf1_cr_off_maxpds_helper(struct ddf1 *ddf1);
+int ddf1_endianness(struct lib_context *lc, struct ddf1 *ddf1);
+
+struct ddf1_record_handler {
+ int (*vd)(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1, int idx);
+ int (*spare)(struct lib_context *lc, struct dev_info *di,
+ struct ddf1 *ddf1, int idx);
+};
+
+int ddf1_process_records(struct lib_context *lc, struct dev_info *di,
+ struct ddf1_record_handler *handler,
+ struct ddf1 *ddf1, int in_cpu_format);
+
+#endif
--- dmraid/lib/format/partition/dos.c 2008/02/22 16:57:36 1.1
+++ dmraid/lib/format/partition/dos.c 2008/02/22 17:04:36 1.2
@@ -143,6 +143,17 @@
return rs;
}
+/* Check sector vs. RAID device end */
+static int rd_check_end(struct lib_context *lc,
+ struct raid_dev *rd, uint64_t sector)
+{
+ if (sector > rd->di->sectors)
+ LOG_ERR(lc, 1, "%s: partition address past end of RAID device",
+ handler);
+
+ return 0;
+}
+
/*
* Allocate a DOS RAID device and a set.
* Set the device up and add it to the set.
@@ -173,7 +184,9 @@
r->offset = get_part_start(raw_part, sector);
r->sectors = (uint64_t) raw_part->length;
- if (!(rs = _alloc_raid_set(lc, r)))
+ if (rd_check_end(lc, rd, r->offset) ||
+ rd_check_end(lc, rd, r->offset + r->sectors) ||
+ !(rs = _alloc_raid_set(lc, r)))
goto free_di;
list_add_tail(&r->devs, &rs->devs);
@@ -238,13 +251,13 @@
* An entry pointing to the present logical partition.
* It is an offset from the present partition table location.
*/
- p1 = &dos->partitions[0];
+ p1 = dos->partitions;
/*
* An entry pointing to the next logical partition table.
* It is an offset from the main extended partition start.
*/
- p2 = &dos->partitions[1];
+ p2 = dos->partitions + 1;
/* If it is a partition, add it to the set */
if (is_partition(p1, start_sector) &&
@@ -301,8 +314,12 @@
part_end = part_start + raw_table_entry->length;
/* Avoid infinite recursion (mostly). */
- if (part_start == start_sector ||
- part_end > rd->sectors)
+ if (part_start == start_sector)
+ continue;
+
+ /* Check bogus partition starts + ends */
+ if (rd_check_end(lc, rd, part_start) ||
+ rd_check_end(lc, rd, part_end))
continue;
/*
@@ -365,7 +382,7 @@
.check = dos_check,
.events = NULL, /* Not supported */
#ifdef DMRAID_NATIVE_LOG
- .log = NULL, /* Not supported */
+ .log = NULL, /* Not supported; use fdisk and friends */
#endif
};
--- dmraid/lib/locking/locking.c 2008/02/22 16:57:36 1.1
+++ dmraid/lib/locking/locking.c 2008/02/22 17:04:36 1.2
@@ -5,8 +5,6 @@
* See file LICENSE at the top of this source tree for license information.
*/
-#include <errno.h>
-
#ifndef __KLIBC__
# include <sys/file.h>
#endif
/cvs/dm/dmraid/lib/metadata/log_ops.c,v --> standard output
revision 1.1
--- dmraid/lib/metadata/log_ops.c
+++ - 2008-02-22 17:04:42.683358000 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2006 Darrick Wong, IBM
+ * All rights reserved.
+ *
+ * Copyright (C) 2006 Heinz Mauelshagen, Red Hat GmbH
+ * All rights reserved.
+ *
+ * See file LICENSE at the top of this source tree for license information.
+ */
+#include "internal.h"
+
+void end_log(struct lib_context *lc, struct list_head *log)
+{
+ struct list_head *pos, *tmp;
+
+ list_for_each_safe(pos, tmp, log) {
+ list_del(pos);
+ dbg_free(list_entry(pos, struct change, changes));
+ }
+}
+
+int revert_log(struct lib_context *lc, struct list_head *log)
+{
+ int writes_started = 0, ret = 0;
+ struct change *entry;
+ struct raid_dev *rd;
+
+ list_for_each_entry(entry, log, changes) {
+ if (writes_started && entry->type != WRITE_METADATA) {
+ log_err(lc, "%s: State change after metadata write?",
+ __func__);
+ ret = -EINVAL;
+ break;
+ }
+
+ if (entry->type == ADD_TO_SET) {
+ rd = entry->rd;
+ rd->type = t_spare;
+ list_del_init(&entry->rd->devs);
+ } else if (entry->type == WRITE_METADATA) {
+ writes_started = 1;
+ rd = entry->rd;
+ ret = write_dev(lc, rd, 0);
+ if (ret) {
+ log_err(lc, "%s: Error while reverting "
+ "metadata.", __func__);
+ break;
+ }
+ }
+ }
+
+ end_log(lc, log);
+ return ret;
+}
/cvs/dm/dmraid/lib/metadata/reconfig.c,v --> standard output
revision 1.1
--- dmraid/lib/metadata/reconfig.c
+++ - 2008-02-22 17:04:42.761505000 +0000
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2006 IBM, all rights reserved.
+ * Written by Darrick Wong <djwong@us.ibm.com>,
+ * James Simshaw <simshawj@us.ibm.com>, and
+ * Adam DiCarlo <bikko@us.ibm.com>
+ *
+ * Copyright (C) 2006 Heinz Mauelshagen, Red Hat GmbH
+ * All rights reserved
+ *
+ * See file LICENSE at the top of this source tree for license information.
+ */
+#include "internal.h"
+
+#define add_to_log(entry, log) \
+ list_add_tail(&(entry)->changes, &(log));
+
+static inline int alloc_entry(struct change **entry)
+{
+ return (*entry = dbg_malloc(sizeof (*entry))) ? 0 : -ENOMEM;
+}
+
+static int nuke_spare(struct lib_context *lc, struct raid_dev *rd)
+{
+ printf("Nuking Spare\n");
+ list_del_init(&rd->devs);
+ return 0;
+}
+
+/* Add a device to a RAID1 set and start the resync */
+static int add_dev_to_raid1(struct lib_context *lc, struct raid_set *rs,
+ struct raid_dev *rd)
+{
+ int ret;
+ struct raid_dev *tmp;
+ struct change *entry;
+ LIST_HEAD(log); /* playback log */
+
+ /* Add device to the raid set */
+ ret = alloc_entry(&entry);
+ if (ret)
+ goto err;
+
+ entry->type = ADD_TO_SET;
+ entry->rs = rs;
+ entry->rd = rd;
+ add_to_log(entry, log);
+ list_add_tail(&rd->devs, &rs->devs);
+ rd->type = t_raid1;
+
+ /* Check that this is a sane configuration */
+ list_for_each_entry(tmp, &rs->devs, devs) {
+ ret = tmp->fmt->check(lc, rs);
+ if (ret)
+ goto err;
+ }
+
+ /* Write the metadata of the drive we're adding _first_ */
+ ret = alloc_entry(&entry);
+ if (ret)
+ goto err;
+
+ entry->type = WRITE_METADATA;
+ entry->rd = rd;
+ add_to_log(entry, log);
+ ret = write_dev(lc, rd, 0);
+ if (!ret)
+ goto err;
+
+ /* Write metadatas of every device in the set */
+ list_for_each_entry(tmp, &rs->devs, devs) {
+ if (tmp != rd) {
+ ret = alloc_entry(&entry);
+ if (ret)
+ goto err;
+
+ entry->type = WRITE_METADATA;
+ entry->rd = tmp;
+ add_to_log(entry, log);
+ ret = write_dev(lc, tmp, 0);
+ if (!ret)
+ goto err;
+ }
+ }
+
+ /* Reconfigure device mapper */
+ // FIXME: is nosync enough? rs->status |= s_inconsistent;
+ rs->status |= s_nosync;
+ change_set(lc, A_ACTIVATE, rs);
+ ret = change_set(lc, A_RELOAD, rs);
+ // FIXME: might need this later: change_set(lc, A_DEACTIVATE,rs);
+ if (!ret)
+ goto err;
+
+ /* End transaction */
+ end_log(lc, &log);
+ return 0;
+
+err:
+ revert_log(lc, &log);
+ return ret;
+}
+
+/* Remove a disk from a raid1 */
+static int del_dev_in_raid1(struct lib_context *lc, struct raid_set *rs,
+ struct raid_dev *rd)
+{
+ int ret;
+ struct raid_dev *tmp;
+ struct change *entry;
+ LIST_HEAD(log); /* Playback log */
+
+ /* Remove device from the raid set */
+ ret = alloc_entry(&entry);
+ if (ret)
+ goto err;
+
+ entry->type = DELETE_FROM_SET;
+ entry->rs = rs;
+ entry->rd = rd;
+ add_to_log(entry, log);
+ list_del_init(&rd->devs);
+ rd->type = t_spare;
+
+ /* Check that this is a sane configuration */
+ list_for_each_entry(tmp, &rs->devs, devs) {
+ ret = tmp->fmt->check(lc, rs);
+ if (ret)
+ goto err;
+ }
+
+ /* Write the metadata of the drive we're removing _first_ */
+ ret = alloc_entry(&entry);
+ if (ret)
+ goto err;
+
+ entry->type = WRITE_METADATA;
+ entry->rd = rd;
+ add_to_log(entry, log);
+ ret = write_dev(lc, rd, 0);
+ if (!ret)
+ goto err;
+
+ /* Write metadatas of every device in the set */
+ list_for_each_entry(tmp, &rs->devs, devs) {
+ if (tmp == rd)
+ continue;
+
+ ret = alloc_entry(&entry);
+ if (ret)
+ goto err;
+
+ entry->type = WRITE_METADATA;
+ entry->rd = tmp;
+ add_to_log(entry, log);
+ ret = write_dev(lc, tmp, 0);
+ if (!ret)
+ goto err;
+ }
+
+ /* Reconfigure device mapper */
+ rs->status |= s_inconsistent;
+ rs->status |= s_nosync;
+ ret = change_set(lc, A_RELOAD, rs);
+ if (!ret)
+ goto err;
+
+ /* End transaction */
+ end_log(lc, &log);
+ return 0;
+
+err:
+ revert_log(lc, &log);
+ return ret;
+}
+
+/* Corelate type and function to handle addition/removel of RAID device */
+struct handler {
+ enum change_type type;
+ int (*func) (struct lib_context *lc, struct raid_set *rs,
+ struct raid_dev *rd);
+};
+
+/* Call the function to handle addition/removal of a RAID device */
+static int handle_dev(struct lib_context *lc, struct handler *h,
+ struct raid_set *rs, struct raid_dev *rd)
+{
+ do {
+ if (h->type == rs->type)
+ return h->func(lc, rs, rd);
+ } while ((++h)->type != t_undef);
+
+ LOG_ERR(lc, -ENOENT, "%s: no handler for %x", __func__, rs->type);
+}
+
+/* Add a disk to an array. */
+int add_dev_to_set(struct lib_context *lc, struct raid_set *rs,
+ struct raid_dev *rd)
+{
+ struct handler handlers[] = {
+ {t_raid1, add_dev_to_raid1},
+ {t_undef, NULL},
+ };
+
+ if (T_SPARE(rd))
+ nuke_spare(lc, rd);
+ else if (!list_empty(&rd->devs))
+ LOG_ERR(lc, -EBUSY, "%s: disk already in another set!",
+ __func__);
+
+ if (T_GROUP(rd))
+ LOG_ERR(lc, -EISDIR,
+ "%s: can't add a group raid_dev to a raid_set.",
+ __func__);
+
+ return handle_dev(lc, handlers, rs, rd);
+}
+
+/* Remove a disk from an array */
+int del_dev_in_set(struct lib_context *lc, struct raid_set *rs,
+ struct raid_dev *rd)
+{
+ struct handler handlers[] = {
+ {t_raid1, del_dev_in_raid1},
+ {t_undef, NULL},
+ };
+
+ if (list_empty(&rd->devs))
+ LOG_ERR(lc, -EBUSY, "%s: disk is not in a set!", __func__);
+
+ /* FIXME: Not sure if this is true. */
+ if (T_GROUP(rd))
+ LOG_ERR(lc, -EISDIR,
+ "%s: can't remove a group raid_dev from a raid_set.",
+ __func__);
+
+ return handle_dev(lc, handlers, rs, rd);
+}
--- dmraid/lib/metadata/metadata.c 2008/02/22 16:57:36 1.1
+++ dmraid/lib/metadata/metadata.c 2008/02/22 17:04:36 1.2
@@ -60,9 +60,12 @@
{
unsigned int ret = ARRAY_SIZE(ascii_type);
- while (ret-- && !(type & ascii_type[ret].type));
+ while (ret--) {
+ if (type & ascii_type[ret].type)
+ return ret;
+ }
- return ret;
+ return 0;
}
const char *get_type(struct lib_context *lc, enum type type)
@@ -83,7 +86,8 @@
get_type_index(rs->type))
- get_type_index(t_raid1);
- return stacked_ascii_type[T_RAID0(rs) ? 1 : 0][t];
+ return stacked_ascii_type[T_RAID0(rs) ? 1 : 0]
+ [t > t_raid0 ? t_undef : t];
}
/* Check, if a RAID set is stacked (ie, hierachical). */
@@ -120,7 +124,7 @@
static uint64_t add_sectors(struct raid_set *rs, uint64_t sectors,
uint64_t add)
{
- add = round_down(add, rs->stride);
+ add = rs->stride ? round_down(add, rs->stride) : add;
if (T_RAID1(rs)) {
if (!sectors || sectors > add)
@@ -626,8 +630,7 @@
/*
* Write RAID metadata to a device.
*/
-static int dmraid_write(struct lib_context *lc,
- struct raid_dev *rd, int erase)
+int write_dev(struct lib_context *lc, struct raid_dev *rd, int erase)
{
int ret = 0;
struct dmraid_format *fmt = rd->fmt;
@@ -813,6 +816,20 @@
return DEVS(rs) ? (RD_RS(rs))->fmt : NULL;
}
+/* Find the set associated with a device */
+struct raid_set *get_raid_set(struct lib_context *lc, struct raid_dev *dev)
+{
+ struct raid_set *rs;
+ struct raid_dev *rd;
+
+ list_for_each_entry(rs, LC_RS(lc), list)
+ list_for_each_entry(rd, &rs->devs, devs)
+ if (dev == rd)
+ return rs;
+
+ return NULL;
+}
+
/* Check metadata consistency of raid sets. */
static void check_raid_sets(struct lib_context *lc)
{
@@ -933,7 +950,7 @@
* FIXME: does it make sense to try the rest of the
* devices in case we fail writing one ?
*/
- if (!dmraid_write(lc, rd, 0)) {
+ if (!write_dev(lc, rd, 0)) {
log_err(lc, "writing RAID device \"%s\", continuing",
rd->di->path);
ret = 0;
@@ -953,7 +970,7 @@
if (yes_no_prompt(lc, "Do you really want to erase \"%s\" "
"ondisk metadata on %s",
rd->fmt->name, rd->di->path) &&
- !dmraid_write(lc, rd, 1)) {
+ !write_dev(lc, rd, 1)) {
log_err(lc, "erasing ondisk metadata on %s",
rd->di->path);
ret = 0;
@@ -970,15 +987,27 @@
*/
enum type rd_type(struct types *t, unsigned int type)
{
- for (; t->type != type && t->unified_type != t_undef; t++);
+ for (; t->type && t->type != type; t++);
return t->unified_type;
}
/*
+ * Support function for metadata format handlers:
+ *
+ * Return neutralized RAID status for given metadata status
+ */
+enum status rd_status(struct states *s, unsigned int status, enum compare cmp)
+{
+ for (; s->status && (cmp == AND ? !(s->status & status) : (s->status != status)); s++);
+
+ return s->unified_status;
+}
+
+/*
* Support function for metadata format handlers.
*
- * Sort a an element into a list by optionally
+ * Sort an element into a list by optionally
* using a metadata format handler helper function.
*/
void list_add_sorted(struct lib_context *lc,
--- dmraid/lib/misc/file.c 2008/02/22 16:57:36 1.1
+++ dmraid/lib/misc/file.c 2008/02/22 17:04:36 1.2
@@ -5,7 +5,6 @@
* See file LICENSE at the top of this source tree for license information.
*/
-#include <errno.h>
#include "internal.h"
/* Create directory recusively. */
--- dmraid/tools/Makefile.in 2008/02/22 16:57:37 1.1
+++ dmraid/tools/Makefile.in 2008/02/22 17:04:36 1.2
@@ -20,7 +20,7 @@
TARGETS=\
dmraid
-DMRAIDLIBS=-ldmraid
+DMRAIDLIBS=-ldmraid -lz
include $(top_srcdir)/make.tmpl
--- dmraid/tools/VERSION 2008/02/22 16:57:37 1.1
+++ dmraid/tools/VERSION 2008/02/22 17:04:36 1.2
@@ -1 +1 @@
-1.0.0.rc11 (2006.05.15)
+1.0.0.rc12 (2006.09.15)
reply other threads:[~2008-02-22 17:04 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20080222170443.29266.qmail@sourceware.org \
--to=heinzm@sourceware.org \
--cc=dm-cvs@sourceware.org \
--cc=dm-devel@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.