2
* SNIA DDF1 v1.0 metadata format handler.
4
* Copyright (C) 2005-2006 IBM, All rights reserved.
5
* Written by Darrick Wong <djwong@us.ibm.com>
7
* Copyright (C) 2006-2008 Heinz Mauelshagen, Red Hat GmbH
10
* See file LICENSE at the top of this source tree for license information.
15
#define FORMAT_HANDLER
20
#include "ddf1_dump.h"
23
(((struct ddf1_group_info *) (rd)->private.ptr)->rd_group)
26
* Helper struct to squirrel a group set reference to the check method
27
* in order to avoid, that premature deallocation in metadata.c
28
* removes the group set.
30
struct ddf1_group_info {
31
struct raid_dev *rd_group;
34
static const char *handler = HANDLER;
36
#define DDF1_SPARES ".ddf1_spares"
37
#define DDF1_DISKS (char*) ".ddf1_disks"
39
/* PCI IDs for Adaptec */
40
// #define PCI_VENDOR_ID_ADAPTEC 0x9004
41
#define PCI_VENDOR_ID_ADAPTEC2 0x9005
43
/* Map DDF1 disk status to dmraid status */
45
disk_status(struct ddf1_phys_drive *disk)
47
struct states states[] = {
55
return disk ? rd_status(states, disk->state, AND) : s_undef;
59
* Compare two GUIDs. For some reason, Adaptec sometimes writes 0xFFFFFFFF
60
* as the last four bytes (ala DDF2) and sometimes writes real data.
61
* For now we'll compare the first twenty and only the last four if
62
* both GUIDs don't have 0xFFFFFFFF in bytes 20-23. Gross.
64
/* Find this drive's physical data */
65
static struct ddf1_phys_drive *
66
get_phys_drive(struct ddf1 *ddf1)
68
unsigned int i = ddf1->pd_header->max_drives;
71
if (ddf1->pds[i].reference == ddf1->disk_data->reference)
78
/* Find the virtual drive that goes with this config record */
79
static struct ddf1_virt_drive *
80
get_virt_drive(struct ddf1 *ddf1, struct ddf1_config_record *cr)
82
int i = ddf1->vd_header->num_drives;
85
if (!guidcmp(ddf1->vds[i].guid, cr->guid))
93
* Find the index of the VD config record given a physical drive and offset.
96
get_config_byoffset(struct ddf1 *ddf1, struct ddf1_phys_drive *pd,
99
int cfgs = NUM_CONFIG_ENTRIES(ddf1), i;
100
uint32_t *cfg_drive_ids, j;
101
uint64_t *cfg_drive_offsets;
102
struct ddf1_config_record *cfg;
104
for (i = 0; i < cfgs; i++) {
106
if (cfg->signature == DDF1_VD_CONFIG_REC) {
107
cfg_drive_ids = CR_IDS(ddf1, cfg);
108
cfg_drive_offsets = CR_OFF(ddf1, cfg);
109
for (j = 0; j < cfg->primary_element_count; j++) {
110
if (cfg_drive_ids[j] == pd->reference &&
111
cfg_drive_offsets[j] == offset)
120
/* Find the index of the nth VD config record for this physical drive. */
122
get_config_index(struct ddf1 *ddf1, struct ddf1_phys_drive *pd, unsigned int *n)
124
int cfgs = NUM_CONFIG_ENTRIES(ddf1), i, j, nn = *n;
126
struct ddf1_config_record *cr;
128
for (i = 0; i < cfgs; i++) {
130
if (cr->signature == DDF1_VD_CONFIG_REC) {
131
ids = CR_IDS(ddf1, cr);
132
for (j = 0; j < cr->primary_element_count; j++) {
133
if (ids[j] == pd->reference && !nn--)
140
return nn < 0 ? -ENOENT : 0;
144
* Find the nth VD config record for this physical drive.
146
static inline struct ddf1_config_record *
147
get_config(struct ddf1 *ddf1, struct ddf1_phys_drive *pd, unsigned int n)
149
int i = get_config_index(ddf1, pd, &n);
151
return i < 0 ? NULL : CR(ddf1, i);
154
/* Find a config record for this drive, given the offset of the array. */
155
static inline struct ddf1_config_record *
156
get_this_config(struct ddf1 *ddf1, uint64_t offset)
158
struct ddf1_phys_drive *pd = get_phys_drive(ddf1);
159
int i = get_config_byoffset(ddf1, pd, offset);
161
return i < 0 ? NULL : get_config(ddf1, pd, i);
164
/* Find the config record disk/offset entry for this config/drive. */
166
get_offset_entry(struct ddf1 *ddf1, struct ddf1_config_record *cr,
167
struct ddf1_phys_drive *pd)
173
ids = CR_IDS(ddf1, cr);
174
for (i = 0; i < ddf1->primary->max_phys_drives; i++) {
175
if (ids[i] == pd->reference)
183
/* Find the offset for this config/drive. */
185
get_offset(struct ddf1 *ddf1, struct ddf1_config_record *cr,
186
struct ddf1_phys_drive *pd)
188
int i = get_offset_entry(ddf1, cr, pd);
190
return i < 0 ? pd->size : CR_OFF(ddf1, cr)[i];
193
/* Calculate the stripe size, in sectors */
194
static inline unsigned int
195
stride(struct ddf1_config_record *cr)
197
return to_bytes(1) >> 9 << cr->stripe_size;
200
/* Map the DDF1 raid type codes into dmraid type codes. */
202
type(struct lib_context *lc, struct ddf1 *ddf1, struct ddf1_config_record *cr)
206
/* Mapping of template types to generic types */
207
static struct types types[] = {
208
{DDF1_RAID0, t_raid0},
209
{DDF1_RAID1, t_raid1},
210
{DDF1_RAID4, t_raid4},
211
{DDF1_CONCAT, t_linear},
212
{DDF1_JBOD, t_linear},
215
/* Seperate array for RAID5 qualifiers */
216
static struct types qualifier_types[] = {
217
/* FIXME: Is RLQ=0 really right symmetric? */
218
{DDF1_RAID5_RS, t_raid5_rs},
219
{DDF1_RAID5_LA, t_raid5_la},
220
{DDF1_RAID5_LS, t_raid5_ls},
228
if (l == DDF1_RAID5) {
230
* FIXME: Do _all_ Adaptec controllers use left
231
* asymmetric parity and write zero to RLQ?
233
if (ddf1->adaptec_mode)
236
l = cr->raid_qualifier;
241
return rd_type(t, l);
244
/* Read the whole metadata chunk at once */
246
read_metadata_chunk(struct lib_context *lc, struct dev_info *di, uint64_t start)
249
size_t size = to_bytes(di->sectors - start);
251
if (!(ret = alloc_private(lc, handler, size)))
254
if (!read_file(lc, handler, di->path, ret, size, to_bytes(start))) {
256
LOG_ERR(lc, NULL, "%s: unable to read metadata off %s",
270
/* Reused error message */
272
err_drive(struct lib_context *lc, struct dev_info *di, const char *what)
274
LOG_ERR(lc, NULL, "%s: cannot find %s drive record on %s",
275
handler, what, di->path);
279
err_phys_drive(struct lib_context *lc, struct dev_info *di)
281
return err_drive(lc, di, "physical");
285
err_virt_drive(struct lib_context *lc, struct dev_info *di)
287
return err_drive(lc, di, "virtual");
291
* Read a DDF1 RAID device. Fields are little endian, so
292
* need to convert them if we're on a BE machine (ppc, etc).
295
read_extended(struct lib_context *lc, struct dev_info *di, struct ddf1 *ddf1)
300
struct ddf1_header *pri, *sec;
301
struct ddf1_adapter *adap;
302
struct ddf1_disk_data *ddata;
303
struct ddf1_phys_drives *pd;
304
struct ddf1_virt_drives *vd;
307
/* Read the primary DDF header */
308
where = to_bytes(ddf1->anchor.primary_table_lba);
309
if (!(pri = ddf1->primary =
310
alloc_private_and_read(lc, handler, sizeof(*pri),
314
/* Read the secondary header. */
315
ddf1_cvt_header(ddf1, pri);
316
if (!(sec = ddf1->secondary = alloc_private(lc, handler, sizeof(*sec))))
319
where = to_bytes(ddf1->anchor.secondary_table_lba);
320
if (ddf1->anchor.secondary_table_lba != 0xFFFFFFFFFFFFFFFFULL &&
321
!read_file(lc, handler, di->path, sec, sizeof(*sec), where))
324
ddf1_cvt_header(ddf1, sec);
325
if (pri->signature != DDF1_HEADER) {
326
log_warn(lc, "%s: incorrect primary header signature %x on",
327
handler, pri->signature, di->path);
328
cond_free(ddf1->primary);
329
ddf1->primary = NULL;
332
if (sec->signature == DDF1_HEADER) {
333
/* If we encounter an error, we use the secondary table */
334
if (!ddf1->primary) {
335
log_warn(lc, "%s: using secondary header on %s",
337
ddf1->primary = ddf1->secondary;
338
ddf1->secondary = NULL;
342
log_warn(lc, "%s: bad secondary header signature %x "
343
"on %s", handler, sec->signature, di->path);
346
ddf1->secondary = NULL;
349
if (!ddf1->primary) {
350
log_error(lc, "%s: both header signatures bad on %s",
355
/* Read the adapter data */
356
if (!(adap = ddf1->adapter = alloc_private(lc, handler, sizeof(*adap))))
359
where = to_bytes(pri->primary_table_lba + pri->adapter_data_offset);
360
if (pri->adapter_data_offset != 0xFFFFFFFF &&
361
!read_file(lc, handler, di->path, adap, sizeof(*adap), where))
364
ddf1_cvt_adapter(ddf1, ddf1->adapter);
365
if (ddf1->adapter->signature != DDF1_ADAPTER_DATA) {
366
if (ddf1->adapter->signature)
367
log_warn(lc, "%s: incorrect adapter data signature %x "
369
handler, ddf1->adapter->signature, di->path);
370
dbg_free(ddf1->adapter);
371
ddf1->adapter = NULL;
375
ddf1->adapter->pci_vendor == PCI_VENDOR_ID_ADAPTEC2) {
376
log_notice(lc, "%s: Adaptec mode discovered on %s",
378
ddf1->adaptec_mode = 1;
381
/* Read physical drive characteristic data */
382
where = to_bytes(pri->primary_table_lba + pri->disk_data_offset);
383
if (!(ddata = ddf1->disk_data =
384
alloc_private_and_read(lc, handler, sizeof(*ddata),
389
* This table isn't technically required, but for now we rely
390
* on it to give us a key into the physical drive table.
392
ddf1_cvt_disk_data(ddf1, ddata);
393
if (ddata->signature != DDF1_FORCED_PD_GUID) {
394
log_warn(lc, "%s: incorrect disk data signature %x on %s",
395
handler, ddata->signature, di->path);
399
/* Read physical drive data header */
400
where = to_bytes(pri->primary_table_lba + pri->phys_drive_offset);
401
size = to_bytes(pri->phys_drive_len);
402
if (!(pd = ddf1->pd_header =
403
alloc_private_and_read(lc, handler, size, di->path, where)))
406
ddf1_cvt_phys_drive_header(ddf1, pd);
407
if (pd->signature != DDF1_PHYS_DRIVE_REC) {
408
err_phys_drive(lc, di);
412
/* Now read the physical drive data */
413
ddf1->pds = (struct ddf1_phys_drive *) (((uint8_t *) ddf1->pd_header) +
415
for (i = 0; i < pd->num_drives; i++) {
416
ddf1_cvt_phys_drive(ddf1, &ddf1->pds[i]);
418
* Adaptec controllers have a weird bug where this field is
419
* only four bytes ... and the next four are 0xFF.
421
if (ddf1->pds[i].size >> 32 == 0xFFFFFFFF)
422
ddf1->pds[i].size &= 0xFFFFFFFF;
425
/* Read virtual drive data header */
426
where = to_bytes(pri->primary_table_lba + pri->virt_drive_offset);
427
size = to_bytes(pri->phys_drive_len);
428
if (!(vd = ddf1->vd_header =
429
alloc_private_and_read(lc, handler, size, di->path, where)))
432
ddf1_cvt_virt_drive_header(ddf1, vd);
433
if (vd->signature != DDF1_VIRT_DRIVE_REC) {
434
err_virt_drive(lc, di);
438
/* Now read the virtual drive data */
439
ddf1->vds = (struct ddf1_virt_drive *) (((uint8_t *) vd) + sizeof(*pd));
440
for (i = 0; i < vd->num_drives; i++)
441
ddf1_cvt_virt_drive(ddf1, &ddf1->vds[i]);
443
/* Read config data */
444
where = to_bytes(pri->primary_table_lba + pri->config_record_offset);
445
size = to_bytes(pri->config_record_len);
446
if (!(ddf1->cfg = alloc_private_and_read(lc, handler, size,
451
* Ensure each record is: a config table for VDs; a config table for
452
* spare disks; or vendor-specifc data of some sort.
454
ddf1_cvt_records(lc, di, ddf1, 1);
457
* FIXME: We don't pick up diagnostic logs, vendor specific logs,
458
* bad block data, etc. That shouldn't cause a problem with reading
459
* or writing metadata, but at some point we might want to do something
462
ddf1->in_cpu_format = 1;
464
/* FIXME: We should verify the checksums for all modes */
465
if (ddf1->adaptec_mode && !(ddf1_check_all_crcs(lc, di, ddf1)))
473
cond_free(ddf1->cfg);
474
cond_free(ddf1->pd_header);
475
cond_free(ddf1->disk_data);
476
cond_free(ddf1->adapter);
477
cond_free(ddf1->secondary);
478
cond_free(ddf1->primary);
482
/* Count the number of raid_devs we need to create for this drive */
484
num_devs(struct lib_context *lc, void *meta)
486
struct ddf1 *ddf1 = meta;
487
unsigned int num_drives = ~0;
489
get_config_index(ddf1, get_phys_drive(ddf1), &num_drives);
493
/* Is this DDF1 metadata? */
495
is_ddf1(struct lib_context *lc, struct dev_info *di, struct ddf1 *ddf1)
498
* Check our magic numbers and that the version == v2.
499
* We don't support anything other than that right now.
502
/* FIXME: We should examine the version headers... */
503
return ddf1->anchor.signature == DDF1_HEADER ||
504
ddf1->anchor.signature == DDF1_HEADER_BACKWARDS;
507
/* Try to find DDF1 metadata at a given offset (ddf1_sboffset) */
509
try_to_find_ddf1(struct lib_context *lc,
511
size_t * sz, uint64_t * offset,
512
union read_info *info, uint64_t ddf1_sboffset)
517
* Try to find a DDF1 anchor block at ddf1_sboffset. In theory this
518
* should be the very last block, but some Adaptec controllers have
519
* issues with standards compliance. So we have to try with various
522
if (!(ddf1 = alloc_private(lc, handler, sizeof(*ddf1))))
525
if (!read_file(lc, handler, di->path, &ddf1->anchor, to_bytes(1),
526
ddf1_sboffset) || !is_ddf1(lc, di, ddf1))
529
ddf1->anchor_offset = ddf1_sboffset;
531
/* Convert endianness */
532
ddf1->in_cpu_format = 0;
533
if ((ddf1->disk_format = ddf1_endianness(lc, ddf1)) < 0)
535
ddf1_cvt_header(ddf1, &ddf1->anchor);
537
/* Read extended metadata. */
538
if (read_extended(lc, di, ddf1))
548
* Attempt to interpret DDF1 metadata from a block device. This function
549
* returns either NULL or a pointer to a descriptor struct.
550
* Note that the struct should be fully converted to the correct endianness
551
* by the time this function returns.
554
read_metadata_areas(struct lib_context *lc, struct dev_info *di,
555
size_t * sz, uint64_t * offset, union read_info *info)
559
if (!(ddf1 = try_to_find_ddf1(lc, di, sz, offset,
560
info, DDF1_CONFIGOFFSET))) {
561
if ((ddf1 = try_to_find_ddf1(lc, di, sz, offset,
562
info, DDF1_CONFIGOFFSET_ADAPTEC)))
563
ddf1->adaptec_mode = 1;
569
/* This is all hogwash since file_metadata can only be called once... */
571
file_metadata_areas(struct lib_context *lc, struct dev_info *di, void *meta)
574
uint64_t start = ddf1_beginning(meta);
576
if ((buf = read_metadata_chunk(lc, di, start))) {
577
/* Record metadata. */
578
file_metadata(lc, handler, di->path, buf,
579
to_bytes(di->sectors - start), to_bytes(start));
581
file_dev_size(lc, handler, di); /* Record the device size. */
585
static int setup_rd(struct lib_context *lc, struct raid_dev *rd,
586
struct dev_info *di, void *meta, union read_info *info);
587
static struct raid_dev *
588
ddf1_read(struct lib_context *lc, struct dev_info *di)
591
* NOTE: Everything called after read_metadata_areas assumes that
592
* the reserved block, raid table and config table have been
593
* converted to the appropriate endianness.
595
return read_raid_dev(lc, di, read_metadata_areas, 0, 0, NULL, NULL,
596
file_metadata_areas, setup_rd, handler);
599
/* Compose an "identifier" for use as a sort key for raid sets. */
601
compose_id(struct ddf1 *ddf1, struct raid_dev *rd)
603
struct ddf1_phys_drive *pd = get_phys_drive(ddf1);
604
int i = get_config_byoffset(ddf1, pd, rd->offset);
606
return i < 0 ? -1 : get_offset_entry(ddf1, get_config(ddf1, pd, i), pd);
611
no_sort(struct list_head *pos, struct list_head *new)
616
/* Sort DDF1 devices by offset entry within a RAID set. */
618
dev_sort(struct list_head *pos, struct list_head *new)
620
struct raid_dev *rd_pos = RD(pos), *rd_new = RD(new);
622
return compose_id(META(GRP_RD(rd_new), ddf1), rd_new) <
623
compose_id(META(GRP_RD(rd_pos), ddf1), rd_pos);
627
* IO error event handler.
630
event_io(struct lib_context *lc, struct event_io *e_io)
632
log_err(lc, "%s: I/O error on device %s at sector %lu.\n",
633
handler, e_io->rd->di->path, e_io->sector);
635
LOG_ERR(lc, 0, "%s: PANIC - don't know about event_io!", handler);
639
/* FIXME: This should not use META() directly? */
640
struct raid_dev *rd = e_io->rd;
641
struct ddf1 *ddf1 = META(rd, ddf1);
642
struct ddf1_raid_configline *cl = this_disk(ddf1);
643
struct ddf1_raid_configline *fwl = find_logical(ddf1);
645
/* Ignore if we've already marked this disk broken(?) */
646
if (rd->status & s_broken)
649
/* Mark the array as degraded and the disk as failed. */
650
rd->status = s_broken;
651
cl->raidstate = LSU_COMPONENT_STATE_FAILED;
652
fwl->raidstate = LSU_COMPONENT_STATE_DEGRADED;
653
/* FIXME: Do we have to mark a parent too? */
655
/* Indicate that this is indeed a failure. */
661
/* Formulate a RAID set name for this disk. */
663
name(struct lib_context *lc, struct ddf1 *ddf1, struct raid_dev *rd)
667
struct ddf1_phys_drive *pd;
668
struct ddf1_virt_drive *vd;
669
struct ddf1_config_record *cr;
671
if (!(pd = get_phys_drive(ddf1)))
672
return err_phys_drive(lc, rd->di);
674
i = get_config_byoffset(ddf1, pd, rd->offset);
675
cr = get_config(ddf1, pd, i);
677
sprintf(buf, DDF1_SPARES);
681
if (!(vd = get_virt_drive(ddf1, cr)))
682
return err_virt_drive(lc, rd->di);
684
sprintf(buf, "%s_", handler);
685
prefix = strlen(buf);
688
memcpy(buf + prefix, vd->name, 16);
690
while (!isgraph(buf[--i]));
695
for (b = buf + prefix, i = 0; i < 24; b += 8, i += 4)
696
sprintf(b, "%02x%02x%02x%02x",
697
vd->guid[i], vd->guid[i + 1],
698
vd->guid[i + 2], vd->guid[i + 3]);
702
return dbg_strdup(buf); /* Only return the needed allocation */
705
/* Figure out the real size of a disk... */
707
get_size(struct lib_context *lc, struct ddf1 *ddf1,
708
struct ddf1_config_record *cr, struct ddf1_phys_drive *pd)
710
if (cr && cr->sectors)
711
/* Some Adaptec controllers need this clamping. */
712
return type(lc, ddf1, cr) == t_raid0 ?
713
cr->sectors - cr->sectors % stride(cr) : cr->sectors;
719
* Create all the volumes of a DDF1 disk as subsets of the top level DDF1
720
* disk group. rs_group points to that raid subset and is returned if the
721
* function is successful, NULL if not. rd_group is the raid device that
722
* represents the entire disk drive.
724
static struct raid_set *
725
group_rd(struct lib_context *lc,
726
struct raid_set *rs_group, struct raid_dev *rd_group)
728
struct ddf1 *ddf1 = META(rd_group, ddf1);
729
struct raid_set *rs = NULL;
731
struct ddf1_config_record *cr;
732
struct ddf1_phys_drive *pd;
733
struct ddf1_group_info *gi;
734
unsigned int devs, i;
736
if (!(pd = get_phys_drive(ddf1)))
737
return err_phys_drive(lc, rd_group->di);
739
devs = num_devs(lc, ddf1);
740
for (i = 0; i < devs; i++) {
741
/* Allocate a raid_dev for this volume */
742
if (!(rd = alloc_raid_dev(lc, handler)))
745
cr = get_config(ddf1, pd, i);
746
rd->di = rd_group->di;
747
rd->fmt = rd_group->fmt;
748
rd->type = type(lc, ddf1, cr);
749
if (!(rd->sectors = get_size(lc, ddf1, cr, pd))) {
750
log_zero_sectors(lc, rd->di->path, handler);
751
free_raid_dev(lc, &rd);
755
rd->offset = get_offset(ddf1, cr, pd);
758
* If we have a virtual drive config without an entry in the
759
* list of virtual drives, we ignore it. Weird bug seen on
760
* Adaptec 2410SA controller.
762
if (!(rd->name = name(lc, ddf1, rd))) {
763
free_raid_dev(lc, &rd);
767
/* Stuff it into the appropriate raid set. */
768
if (!(rs = find_or_alloc_raid_set(lc, rd->name, FIND_ALL,
770
NO_CREATE, NO_CREATE_ARG))) {
771
free_raid_dev(lc, &rd);
775
if (!(gi = alloc_private(lc, handler, sizeof(*gi)))) {
776
free_raid_dev(lc, &rd);
780
/* Keep reference to the entire device for ddf1_check() */
781
rd->private.ptr = gi;
782
GRP_RD(rd) = rd_group;
784
/* Add rest of subset state */
785
rs->stride = stride(cr);
786
rs->type = type(lc, ddf1, cr);
789
/* Sort device into subset */
790
list_add_sorted(lc, &rs->devs, &rd->devs, dev_sort);
797
* Add a DDF1 device to a RAID set. This involves finding the raid set to
798
* which this disk belongs, and then attaching it. Note that there are other
799
* complications, such as two-layer arrays (RAID10).
801
* FIXME: We haven't been able to set up a RAID10 for testing...
803
static struct raid_set *
804
ddf1_group(struct lib_context *lc, struct raid_dev *rd)
806
struct ddf1 *ddf1 = META(rd, ddf1);
807
struct ddf1_phys_drive *pd;
810
if (!(pd = get_phys_drive(ddf1)))
811
return err_phys_drive(lc, rd->di);
814
LOG_ERR(lc, NULL, "%s: no RAID array name on %s",
815
handler, rd->di->path);
818
* Find/create a raid set for all DDF drives and put this disk
819
* into that set. The raid_sets for the real arrays will be created
820
* as children of the disk's raid_set.
822
* (Is this really necessary?)
824
if (!(rs = find_or_alloc_raid_set(lc, rd->name, FIND_TOP, rd,
825
LC_RS(lc), NO_CREATE, NO_CREATE_ARG)))
829
list_add_sorted(lc, &rs->devs, &rd->devs, no_sort);
831
/* Go deal with the real arrays. */
832
return group_rd(lc, rs, rd);
835
/* Write metadata. */
837
ddf1_write(struct lib_context *lc, struct raid_dev *rd, int erase)
840
struct ddf1 *ddf1 = META(rd, ddf1);
842
if (ddf1->adaptec_mode)
843
ddf1_update_all_crcs(lc, rd->di, ddf1);
845
ddf1_cvt_all(lc, ddf1, rd->di);
846
ret = write_metadata(lc, handler, rd, -1, erase);
847
ddf1_cvt_all(lc, ddf1, rd->di);
853
* Check integrity of a RAID set.
856
/* Retrieve the number of devices that should be in this set. */
858
device_count(struct raid_dev *rd, void *context)
860
/* Get the logical drive */
861
struct ddf1_config_record *cr =
862
get_this_config(META(GRP_RD(rd), ddf1), rd->offset);
864
return cr ? cr->primary_element_count : 0;
867
/* Check a RAID device */
869
check_rd(struct lib_context *lc, struct raid_set *rs,
870
struct raid_dev *rd, void *context)
873
* FIXME: Should we do more checking for brokenness here?
874
* We could check SMART data, etc.
876
return rd->type != s_broken;
879
/* Start the recursive RAID set check. */
881
ddf1_check(struct lib_context *lc, struct raid_set *rs)
883
return check_raid_set(lc, rs, device_count, NULL, check_rd,
887
static struct event_handlers ddf1_event_handlers = {
889
.rd = NULL, /* FIXME: no device add/remove event handler yet. */
892
#ifdef DMRAID_NATIVE_LOG
894
* Log native information about the RAID device.
897
ddf1_log(struct lib_context *lc, struct raid_dev *rd)
899
ddf1_dump_all(lc, rd->di, META(rd, ddf1), handler);
901
#endif /* #ifdef DMRAID_NATIVE_LOG */
903
static struct dmraid_format ddf1_format = {
905
.descr = "SNIA DDF1",
906
.caps = "0,1,4,5,linear",
912
.events = &ddf1_event_handlers,
913
#ifdef DMRAID_NATIVE_LOG
918
/* Register this format handler with the format core */
920
register_ddf1(struct lib_context *lc)
922
return register_format_handler(lc, &ddf1_format);
926
* Set up a RAID device from what we've assembled out of the metadata.
929
setup_rd(struct lib_context *lc, struct raid_dev *rd,
930
struct dev_info *di, void *meta, union read_info *info)
932
unsigned int i, ma_count = 5;
933
struct ddf1 *ddf1 = meta;
934
struct meta_areas *ma;
935
struct ddf1_phys_drive *pd;
937
if (!(pd = get_phys_drive(ddf1)))
938
LOG_ERR(lc, 0, "%s: Cannot find physical drive description "
939
"on %s!", handler, di->path);
941
/* We need multiple metadata areas */
942
ma_count += ddf1->adapter ? 1 : 0;
943
ma_count += ddf1->secondary ? 1 : 0;
944
ma_count += ddf1->disk_data ? 1 : 0;
945
/* FIXME: metadata area for workspace_lba */
947
if (!(ma = rd->meta_areas = alloc_meta_areas(lc, rd, handler,
951
/* Preset metadata area offset and size and adjust below */
952
for (i = 0; i < ma_count; i++)
953
ma[i].offset = ddf1->primary->primary_table_lba;
955
ma->offset = ddf1->anchor_offset;
956
(ma++)->area = &ddf1->anchor;
958
(ma++)->area = ddf1->primary;
961
(ma++)->offset = ddf1->primary->secondary_table_lba;
964
ma->offset += ddf1->primary->adapter_data_offset;
965
ma->size = to_bytes(ddf1->primary->adapter_data_len);
966
(ma++)->area = ddf1->adapter;
969
/* FIXME: set up workspace_lba */
971
if (ddf1->disk_data) {
972
ma->offset += ddf1->primary->disk_data_offset;
973
ma->size = to_bytes(ddf1->primary->disk_data_len);
974
(ma++)->area = ddf1->disk_data;
977
ma->offset += ddf1->primary->phys_drive_offset;
978
ma->size = to_bytes(ddf1->primary->phys_drive_len);
979
(ma++)->area = ddf1->pd_header;
981
ma->offset += ddf1->primary->virt_drive_offset;
982
ma->size = to_bytes(ddf1->primary->virt_drive_len);
983
(ma++)->area = ddf1->vd_header;
985
ma->offset += ddf1->primary->config_record_offset;
986
ma->size = to_bytes(ddf1->primary->config_record_len);
987
ma->area = ddf1->cfg;
989
/* Now set up the rest of the metadata info */
991
rd->fmt = &ddf1_format;
992
rd->status = disk_status(pd);
995
if (!(rd->sectors = get_size(lc, ddf1, NULL, pd)))
996
return log_zero_sectors(lc, di->path, handler);
998
/* FIXME: better name */
999
return (rd->name = dbg_strdup(DDF1_DISKS)) ? 1 : 0;