[dm-devel] dmraid ./CHANGELOG ./CREDITS ./KNOWN_BUGS ./RE ...
heinzm at sourceware.org
heinzm at sourceware.org
Fri Feb 22 17:04:43 UTC 2008
CVSROOT: /cvs/dm
Module name: dmraid
Changes by: heinzm at 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 at us.ibm.com>
+ * Written by Darrick Wong <djwong at us.ibm.com>,
+ * James Simshaw <simshawj at us.ibm.com>, and
+ * Adam DiCarlo <bikko at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at us.ibm.com>,
+ * James Simshaw <simshawj at us.ibm.com>, and
+ * Adam DiCarlo <bikko at 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)
More information about the dm-devel
mailing list