~psusi/ubuntu/precise/dmraid/fix-gpt

« back to all changes in this revision

Viewing changes to 1.0.0.rc16/lib/format/ddf/ddf1.c

  • Committer: Bazaar Package Importer
  • Author(s): Artur Rona
  • Date: 2010-02-04 21:34:22 UTC
  • mfrom: (1.1.4 upstream) (2.4.3 sid)
  • Revision ID: james.westby@ubuntu.com-20100204213422-tdag8lcxpr7ahmg4
Tags: 1.0.0.rc16-3ubuntu1
* Merge from debian testing. (LP: #503136)  Remaining changes:
  - debian/dmraid-activate: Remove the special-casing of the root
    device which breaks in many situations and leaves the raw devices
    exposed. This was introduced in Debian to accommodate some broken
    configurations which wanted to access "partitions" on the raid
    raw devices. In Ubuntu, broken configurations has not been supported.
  - debian/dmraid.postinst: Comment out "udevadm trigger" call in postinst
    for now as it has severeconsequences when mountall is installed
    (clears /tmp).  If dmraid is installed, then presumably the important
    system devices are up and one canbe bothered with a reboot to take 
    the change into account. Let update-initramfs flag the system
    as needing a reboot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * SNIA DDF1 v1.0 metadata format handler.
 
3
 *
 
4
 * Copyright (C) 2005-2006 IBM, All rights reserved.
 
5
 * Written by Darrick Wong <djwong@us.ibm.com>
 
6
 *
 
7
 * Copyright (C) 2006-2008 Heinz Mauelshagen, Red Hat GmbH
 
8
 *                         All rights reserved.
 
9
 *
 
10
 * See file LICENSE at the top of this source tree for license information.
 
11
 */
 
12
 
 
13
#include "internal.h"
 
14
 
 
15
#define FORMAT_HANDLER
 
16
#include "ddf1.h"
 
17
#include "ddf1_lib.h"
 
18
#include "ddf1_crc.h"
 
19
#include "ddf1_cvt.h"
 
20
#include "ddf1_dump.h"
 
21
 
 
22
#define GRP_RD(rd) \
 
23
        (((struct ddf1_group_info *) (rd)->private.ptr)->rd_group)
 
24
 
 
25
/*
 
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.
 
29
 */
 
30
struct ddf1_group_info {
 
31
        struct raid_dev *rd_group;
 
32
};
 
33
 
 
34
static const char *handler = HANDLER;
 
35
 
 
36
#define DDF1_SPARES     ".ddf1_spares"
 
37
#define DDF1_DISKS      (char*) ".ddf1_disks"
 
38
 
 
39
/* PCI IDs for Adaptec */
 
40
// #define PCI_VENDOR_ID_ADAPTEC                0x9004
 
41
#define PCI_VENDOR_ID_ADAPTEC2          0x9005
 
42
 
 
43
/* Map DDF1 disk status to dmraid status */
 
44
static enum status
 
45
disk_status(struct ddf1_phys_drive *disk)
 
46
{
 
47
        struct states states[] = {
 
48
                {0x72, s_broken},
 
49
                {0x04, s_nosync},
 
50
                {0x08, s_setup},
 
51
                {0x01, s_ok},
 
52
                {0, s_undef},
 
53
        };
 
54
 
 
55
        return disk ? rd_status(states, disk->state, AND) : s_undef;
 
56
}
 
57
 
 
58
/*
 
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.
 
63
 */
 
64
/* Find this drive's physical data */
 
65
static struct ddf1_phys_drive *
 
66
get_phys_drive(struct ddf1 *ddf1)
 
67
{
 
68
        unsigned int i = ddf1->pd_header->max_drives;
 
69
 
 
70
        while (i--) {
 
71
                if (ddf1->pds[i].reference == ddf1->disk_data->reference)
 
72
                        return ddf1->pds + i;
 
73
        }
 
74
 
 
75
        return NULL;
 
76
}
 
77
 
 
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)
 
81
{
 
82
        int i = ddf1->vd_header->num_drives;
 
83
 
 
84
        while (i--) {
 
85
                if (!guidcmp(ddf1->vds[i].guid, cr->guid))
 
86
                        return ddf1->vds + i;
 
87
        }
 
88
 
 
89
        return NULL;
 
90
}
 
91
 
 
92
/*
 
93
 * Find the index of the VD config record given a physical drive and offset.
 
94
 */
 
95
static int
 
96
get_config_byoffset(struct ddf1 *ddf1, struct ddf1_phys_drive *pd,
 
97
                    uint64_t offset)
 
98
{
 
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;
 
103
 
 
104
        for (i = 0; i < cfgs; i++) {
 
105
                cfg = CR(ddf1, 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)
 
112
                                        return i;
 
113
                        }
 
114
                }
 
115
        }
 
116
 
 
117
        return -ENOENT;
 
118
}
 
119
 
 
120
/* Find the index of the nth VD config record for this physical drive. */
 
121
static int
 
122
get_config_index(struct ddf1 *ddf1, struct ddf1_phys_drive *pd, unsigned int *n)
 
123
{
 
124
        int cfgs = NUM_CONFIG_ENTRIES(ddf1), i, j, nn = *n;
 
125
        uint32_t *ids;
 
126
        struct ddf1_config_record *cr;
 
127
 
 
128
        for (i = 0; i < cfgs; i++) {
 
129
                cr = CR(ddf1, 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--)
 
134
                                        return i;
 
135
                        }
 
136
                }
 
137
        }
 
138
 
 
139
        *n -= nn;
 
140
        return nn < 0 ? -ENOENT : 0;
 
141
}
 
142
 
 
143
/*
 
144
 * Find the nth VD config record for this physical drive.
 
145
 */
 
146
static inline struct ddf1_config_record *
 
147
get_config(struct ddf1 *ddf1, struct ddf1_phys_drive *pd, unsigned int n)
 
148
{
 
149
        int i = get_config_index(ddf1, pd, &n);
 
150
 
 
151
        return i < 0 ? NULL : CR(ddf1, i);
 
152
}
 
153
 
 
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)
 
157
{
 
158
        struct ddf1_phys_drive *pd = get_phys_drive(ddf1);
 
159
        int i = get_config_byoffset(ddf1, pd, offset);
 
160
 
 
161
        return i < 0 ? NULL : get_config(ddf1, pd, i);
 
162
}
 
163
 
 
164
/* Find the config record disk/offset entry for this config/drive. */
 
165
static int
 
166
get_offset_entry(struct ddf1 *ddf1, struct ddf1_config_record *cr,
 
167
                 struct ddf1_phys_drive *pd)
 
168
{
 
169
        int i;
 
170
        uint32_t *ids;
 
171
 
 
172
        if (cr) {
 
173
                ids = CR_IDS(ddf1, cr);
 
174
                for (i = 0; i < ddf1->primary->max_phys_drives; i++) {
 
175
                        if (ids[i] == pd->reference)
 
176
                                return i;
 
177
                }
 
178
        }
 
179
 
 
180
        return -ENOENT;
 
181
}
 
182
 
 
183
/* Find the offset for this config/drive. */
 
184
static uint64_t
 
185
get_offset(struct ddf1 *ddf1, struct ddf1_config_record *cr,
 
186
           struct ddf1_phys_drive *pd)
 
187
{
 
188
        int i = get_offset_entry(ddf1, cr, pd);
 
189
 
 
190
        return i < 0 ? pd->size : CR_OFF(ddf1, cr)[i];
 
191
}
 
192
 
 
193
/* Calculate the stripe size, in sectors */
 
194
static inline unsigned int
 
195
stride(struct ddf1_config_record *cr)
 
196
{
 
197
        return to_bytes(1) >> 9 << cr->stripe_size;
 
198
}
 
199
 
 
200
/* Map the DDF1 raid type codes into dmraid type codes. */
 
201
static enum type
 
202
type(struct lib_context *lc, struct ddf1 *ddf1, struct ddf1_config_record *cr)
 
203
{
 
204
        unsigned int l;
 
205
        struct types *t;
 
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},
 
213
                {0, t_undef}
 
214
        };
 
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},
 
221
                {0, t_undef}
 
222
        };
 
223
 
 
224
        if (!cr)
 
225
                return t_undef;
 
226
 
 
227
        l = cr->raid_level;
 
228
        if (l == DDF1_RAID5) {
 
229
                /*
 
230
                 * FIXME: Do _all_ Adaptec controllers use left
 
231
                 * asymmetric parity and write zero to RLQ?
 
232
                 */
 
233
                if (ddf1->adaptec_mode)
 
234
                        return t_raid5_la;
 
235
 
 
236
                l = cr->raid_qualifier;
 
237
                t = qualifier_types;
 
238
        } else
 
239
                t = types;
 
240
 
 
241
        return rd_type(t, l);
 
242
}
 
243
 
 
244
/* Read the whole metadata chunk at once */
 
245
static uint8_t *
 
246
read_metadata_chunk(struct lib_context *lc, struct dev_info *di, uint64_t start)
 
247
{
 
248
        uint8_t *ret;
 
249
        size_t size = to_bytes(di->sectors - start);
 
250
 
 
251
        if (!(ret = alloc_private(lc, handler, size)))
 
252
                return NULL;
 
253
 
 
254
        if (!read_file(lc, handler, di->path, ret, size, to_bytes(start))) {
 
255
                dbg_free(ret);
 
256
                LOG_ERR(lc, NULL, "%s: unable to read metadata off %s",
 
257
                        handler, di->path);
 
258
        }
 
259
 
 
260
        return ret;
 
261
}
 
262
 
 
263
static inline void
 
264
cond_free(void *p)
 
265
{
 
266
        if (p)
 
267
                dbg_free(p);
 
268
}
 
269
 
 
270
/* Reused error message */
 
271
static inline void *
 
272
err_drive(struct lib_context *lc, struct dev_info *di, const char *what)
 
273
{
 
274
        LOG_ERR(lc, NULL, "%s: cannot find %s drive record on %s",
 
275
                handler, what, di->path);
 
276
}
 
277
 
 
278
static void *
 
279
err_phys_drive(struct lib_context *lc, struct dev_info *di)
 
280
{
 
281
        return err_drive(lc, di, "physical");
 
282
}
 
283
 
 
284
static void *
 
285
err_virt_drive(struct lib_context *lc, struct dev_info *di)
 
286
{
 
287
        return err_drive(lc, di, "virtual");
 
288
}
 
289
 
 
290
/*
 
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).
 
293
 */
 
294
static int
 
295
read_extended(struct lib_context *lc, struct dev_info *di, struct ddf1 *ddf1)
 
296
{
 
297
        int i;
 
298
        uint64_t where;
 
299
        size_t size;
 
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;
 
305
 
 
306
 
 
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),
 
311
                                     di->path, where)))
 
312
                goto bad;
 
313
 
 
314
        /* Read the secondary header. */
 
315
        ddf1_cvt_header(ddf1, pri);
 
316
        if (!(sec = ddf1->secondary = alloc_private(lc, handler, sizeof(*sec))))
 
317
                goto bad;
 
318
 
 
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))
 
322
                goto bad;
 
323
 
 
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;
 
330
        };
 
331
 
 
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",
 
336
                                 handler, di->path);
 
337
                        ddf1->primary = ddf1->secondary;
 
338
                        ddf1->secondary = NULL;
 
339
                }
 
340
        } else {
 
341
                if (sec->signature)
 
342
                        log_warn(lc, "%s: bad secondary header signature %x "
 
343
                                 "on %s", handler, sec->signature, di->path);
 
344
 
 
345
                dbg_free(sec);
 
346
                ddf1->secondary = NULL;
 
347
        }
 
348
 
 
349
        if (!ddf1->primary) {
 
350
                log_error(lc, "%s: both header signatures bad on %s",
 
351
                          handler, di->path);
 
352
                goto bad;
 
353
        }
 
354
 
 
355
        /* Read the adapter data */
 
356
        if (!(adap = ddf1->adapter = alloc_private(lc, handler, sizeof(*adap))))
 
357
                goto bad;
 
358
 
 
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))
 
362
                goto bad;
 
363
 
 
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 "
 
368
                                 "on %s",
 
369
                                 handler, ddf1->adapter->signature, di->path);
 
370
                dbg_free(ddf1->adapter);
 
371
                ddf1->adapter = NULL;
 
372
        }
 
373
 
 
374
        if (ddf1->adapter &&
 
375
            ddf1->adapter->pci_vendor == PCI_VENDOR_ID_ADAPTEC2) {
 
376
                log_notice(lc, "%s: Adaptec mode discovered on %s",
 
377
                           handler, di->path);
 
378
                ddf1->adaptec_mode = 1;
 
379
        }
 
380
 
 
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),
 
385
                                     di->path, where)))
 
386
                goto bad;
 
387
 
 
388
        /*
 
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.
 
391
         */
 
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);
 
396
                goto bad;
 
397
        }
 
398
 
 
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)))
 
404
                goto bad;
 
405
 
 
406
        ddf1_cvt_phys_drive_header(ddf1, pd);
 
407
        if (pd->signature != DDF1_PHYS_DRIVE_REC) {
 
408
                err_phys_drive(lc, di);
 
409
                goto bad;
 
410
        }
 
411
 
 
412
        /* Now read the physical drive data */
 
413
        ddf1->pds = (struct ddf1_phys_drive *) (((uint8_t *) ddf1->pd_header) +
 
414
                                                sizeof(*pd));
 
415
        for (i = 0; i < pd->num_drives; i++) {
 
416
                ddf1_cvt_phys_drive(ddf1, &ddf1->pds[i]);
 
417
                /*
 
418
                 * Adaptec controllers have a weird bug where this field is
 
419
                 * only four bytes ... and the next four are 0xFF.
 
420
                 */
 
421
                if (ddf1->pds[i].size >> 32 == 0xFFFFFFFF)
 
422
                        ddf1->pds[i].size &= 0xFFFFFFFF;
 
423
        }
 
424
 
 
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)))
 
430
                goto bad;
 
431
 
 
432
        ddf1_cvt_virt_drive_header(ddf1, vd);
 
433
        if (vd->signature != DDF1_VIRT_DRIVE_REC) {
 
434
                err_virt_drive(lc, di);
 
435
                goto bad;
 
436
        }
 
437
 
 
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]);
 
442
 
 
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,
 
447
                                                 di->path, where)))
 
448
                goto bad;
 
449
 
 
450
        /*
 
451
         * Ensure each record is: a config table for VDs; a config table for
 
452
         * spare disks; or vendor-specifc data of some sort.
 
453
         */
 
454
        ddf1_cvt_records(lc, di, ddf1, 1);
 
455
 
 
456
        /*
 
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
 
460
         * with them.
 
461
         */
 
462
        ddf1->in_cpu_format = 1;
 
463
 
 
464
        /* FIXME: We should verify the checksums for all modes */
 
465
        if (ddf1->adaptec_mode && !(ddf1_check_all_crcs(lc, di, ddf1)))
 
466
                goto bad;
 
467
 
 
468
        return 1;
 
469
 
 
470
bad:
 
471
        ddf1->vds = NULL;
 
472
        ddf1->pds = NULL;
 
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);
 
479
        return 0;
 
480
}
 
481
 
 
482
/* Count the number of raid_devs we need to create for this drive */
 
483
static unsigned int
 
484
num_devs(struct lib_context *lc, void *meta)
 
485
{
 
486
        struct ddf1 *ddf1 = meta;
 
487
        unsigned int num_drives = ~0;
 
488
 
 
489
        get_config_index(ddf1, get_phys_drive(ddf1), &num_drives);
 
490
        return num_drives;
 
491
}
 
492
 
 
493
/* Is this DDF1 metadata? */
 
494
static inline int
 
495
is_ddf1(struct lib_context *lc, struct dev_info *di, struct ddf1 *ddf1)
 
496
{
 
497
        /*
 
498
         * Check our magic numbers and that the version == v2.
 
499
         * We don't support anything other than that right now.
 
500
         */
 
501
 
 
502
        /* FIXME: We should examine the version headers... */
 
503
        return ddf1->anchor.signature == DDF1_HEADER ||
 
504
                ddf1->anchor.signature == DDF1_HEADER_BACKWARDS;
 
505
}
 
506
 
 
507
/* Try to find DDF1 metadata at a given offset (ddf1_sboffset) */
 
508
static struct ddf1 *
 
509
try_to_find_ddf1(struct lib_context *lc,
 
510
                 struct dev_info *di,
 
511
                 size_t * sz, uint64_t * offset,
 
512
                 union read_info *info, uint64_t ddf1_sboffset)
 
513
{
 
514
        struct ddf1 *ddf1;
 
515
 
 
516
        /*
 
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
 
520
         * offsets.
 
521
         */
 
522
        if (!(ddf1 = alloc_private(lc, handler, sizeof(*ddf1))))
 
523
                goto err;
 
524
 
 
525
        if (!read_file(lc, handler, di->path, &ddf1->anchor, to_bytes(1),
 
526
                       ddf1_sboffset) || !is_ddf1(lc, di, ddf1))
 
527
                goto bad;
 
528
 
 
529
        ddf1->anchor_offset = ddf1_sboffset;
 
530
 
 
531
        /* Convert endianness */
 
532
        ddf1->in_cpu_format = 0;
 
533
        if ((ddf1->disk_format = ddf1_endianness(lc, ddf1)) < 0)
 
534
                goto bad;
 
535
        ddf1_cvt_header(ddf1, &ddf1->anchor);
 
536
 
 
537
        /* Read extended metadata. */
 
538
        if (read_extended(lc, di, ddf1))
 
539
                return ddf1;
 
540
 
 
541
bad:
 
542
        dbg_free(ddf1);
 
543
err:
 
544
        return NULL;
 
545
}
 
546
 
 
547
/*
 
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.
 
552
 */
 
553
static void *
 
554
read_metadata_areas(struct lib_context *lc, struct dev_info *di,
 
555
                    size_t * sz, uint64_t * offset, union read_info *info)
 
556
{
 
557
        struct ddf1 *ddf1;
 
558
 
 
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;
 
564
        }
 
565
 
 
566
        return ddf1;
 
567
}
 
568
 
 
569
/* This is all hogwash since file_metadata can only be called once... */
 
570
static void
 
571
file_metadata_areas(struct lib_context *lc, struct dev_info *di, void *meta)
 
572
{
 
573
        uint8_t *buf;
 
574
        uint64_t start = ddf1_beginning(meta);
 
575
 
 
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));
 
580
                dbg_free(buf);
 
581
                file_dev_size(lc, handler, di); /* Record the device size. */
 
582
        }
 
583
}
 
584
 
 
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)
 
589
{
 
590
        /*
 
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.
 
594
         */
 
595
        return read_raid_dev(lc, di, read_metadata_areas, 0, 0, NULL, NULL,
 
596
                             file_metadata_areas, setup_rd, handler);
 
597
}
 
598
 
 
599
/* Compose an "identifier" for use as a sort key for raid sets. */
 
600
static inline int
 
601
compose_id(struct ddf1 *ddf1, struct raid_dev *rd)
 
602
{
 
603
        struct ddf1_phys_drive *pd = get_phys_drive(ddf1);
 
604
        int i = get_config_byoffset(ddf1, pd, rd->offset);
 
605
 
 
606
        return i < 0 ? -1 : get_offset_entry(ddf1, get_config(ddf1, pd, i), pd);
 
607
}
 
608
 
 
609
/* No sort. */
 
610
static int
 
611
no_sort(struct list_head *pos, struct list_head *new)
 
612
{
 
613
        return 0;
 
614
}
 
615
 
 
616
/* Sort DDF1 devices by offset entry within a RAID set. */
 
617
static int
 
618
dev_sort(struct list_head *pos, struct list_head *new)
 
619
{
 
620
        struct raid_dev *rd_pos = RD(pos), *rd_new = RD(new);
 
621
 
 
622
        return compose_id(META(GRP_RD(rd_new), ddf1), rd_new) <
 
623
                compose_id(META(GRP_RD(rd_pos), ddf1), rd_pos);
 
624
}
 
625
 
 
626
/*
 
627
 * IO error event handler.
 
628
 */
 
629
static int
 
630
event_io(struct lib_context *lc, struct event_io *e_io)
 
631
{
 
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);
 
634
 
 
635
        LOG_ERR(lc, 0, "%s: PANIC - don't know about event_io!", handler);
 
636
}
 
637
 
 
638
#if 0
 
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);
 
644
 
 
645
        /* Ignore if we've already marked this disk broken(?) */
 
646
if (rd->status & s_broken)
 
647
        return 0;
 
648
 
 
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? */
 
654
 
 
655
        /* Indicate that this is indeed a failure. */
 
656
return 1;
 
657
}
 
658
#endif
 
659
 
 
660
#define NAME_SIZE 64
 
661
/* Formulate a RAID set name for this disk. */
 
662
static char *
 
663
name(struct lib_context *lc, struct ddf1 *ddf1, struct raid_dev *rd)
 
664
{
 
665
        int i, prefix;
 
666
        char buf[NAME_SIZE];
 
667
        struct ddf1_phys_drive *pd;
 
668
        struct ddf1_virt_drive *vd;
 
669
        struct ddf1_config_record *cr;
 
670
 
 
671
        if (!(pd = get_phys_drive(ddf1)))
 
672
                return err_phys_drive(lc, rd->di);
 
673
 
 
674
        i = get_config_byoffset(ddf1, pd, rd->offset);
 
675
        cr = get_config(ddf1, pd, i);
 
676
        if (i < 0 || !cr) {
 
677
                sprintf(buf, DDF1_SPARES);
 
678
                goto out;
 
679
        }
 
680
 
 
681
        if (!(vd = get_virt_drive(ddf1, cr)))
 
682
                return err_virt_drive(lc, rd->di);
 
683
 
 
684
        sprintf(buf, "%s_", handler);
 
685
        prefix = strlen(buf);
 
686
 
 
687
        if (vd->name[0]) {
 
688
                memcpy(buf + prefix, vd->name, 16);
 
689
                i = prefix + 16;
 
690
                while (!isgraph(buf[--i]));
 
691
                buf[i + 1] = 0;
 
692
        } else {
 
693
                char *b;
 
694
 
 
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]);
 
699
        }
 
700
 
 
701
out:
 
702
        return dbg_strdup(buf); /* Only return the needed allocation */
 
703
}
 
704
 
 
705
/* Figure out the real size of a disk... */
 
706
static uint64_t
 
707
get_size(struct lib_context *lc, struct ddf1 *ddf1,
 
708
         struct ddf1_config_record *cr, struct ddf1_phys_drive *pd)
 
709
{
 
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;
 
714
 
 
715
        return pd->size;
 
716
}
 
717
 
 
718
/*
 
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.
 
723
 */
 
724
static struct raid_set *
 
725
group_rd(struct lib_context *lc,
 
726
         struct raid_set *rs_group, struct raid_dev *rd_group)
 
727
{
 
728
        struct ddf1 *ddf1 = META(rd_group, ddf1);
 
729
        struct raid_set *rs = NULL;
 
730
        struct raid_dev *rd;
 
731
        struct ddf1_config_record *cr;
 
732
        struct ddf1_phys_drive *pd;
 
733
        struct ddf1_group_info *gi;
 
734
        unsigned int devs, i;
 
735
 
 
736
        if (!(pd = get_phys_drive(ddf1)))
 
737
                return err_phys_drive(lc, rd_group->di);
 
738
 
 
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)))
 
743
                        return NULL;
 
744
 
 
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);
 
752
                        continue;
 
753
                }
 
754
 
 
755
                rd->offset = get_offset(ddf1, cr, pd);
 
756
 
 
757
                /*
 
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.
 
761
                 */
 
762
                if (!(rd->name = name(lc, ddf1, rd))) {
 
763
                        free_raid_dev(lc, &rd);
 
764
                        continue;
 
765
                }
 
766
 
 
767
                /* Stuff it into the appropriate raid set. */
 
768
                if (!(rs = find_or_alloc_raid_set(lc, rd->name, FIND_ALL,
 
769
                                                  rd, &rs_group->sets,
 
770
                                                  NO_CREATE, NO_CREATE_ARG))) {
 
771
                        free_raid_dev(lc, &rd);
 
772
                        return NULL;
 
773
                }
 
774
 
 
775
                if (!(gi = alloc_private(lc, handler, sizeof(*gi)))) {
 
776
                        free_raid_dev(lc, &rd);
 
777
                        return NULL;
 
778
                }
 
779
 
 
780
                /* Keep reference to the entire device for ddf1_check() */
 
781
                rd->private.ptr = gi;
 
782
                GRP_RD(rd) = rd_group;
 
783
 
 
784
                /* Add rest of subset state */
 
785
                rs->stride = stride(cr);
 
786
                rs->type = type(lc, ddf1, cr);
 
787
                rs->status = s_ok;
 
788
 
 
789
                /* Sort device into subset */
 
790
                list_add_sorted(lc, &rs->devs, &rd->devs, dev_sort);
 
791
        }
 
792
 
 
793
        return rs_group;
 
794
}
 
795
 
 
796
/* 
 
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).
 
800
 *
 
801
 * FIXME: We haven't been able to set up a RAID10 for testing...
 
802
 */
 
803
static struct raid_set *
 
804
ddf1_group(struct lib_context *lc, struct raid_dev *rd)
 
805
{
 
806
        struct ddf1 *ddf1 = META(rd, ddf1);
 
807
        struct ddf1_phys_drive *pd;
 
808
        struct raid_set *rs;
 
809
 
 
810
        if (!(pd = get_phys_drive(ddf1)))
 
811
                return err_phys_drive(lc, rd->di);
 
812
 
 
813
        if (!rd->name)
 
814
                LOG_ERR(lc, NULL, "%s: no RAID array name on %s",
 
815
                        handler, rd->di->path);
 
816
 
 
817
        /*
 
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.
 
821
         *
 
822
         * (Is this really necessary?)
 
823
         */
 
824
        if (!(rs = find_or_alloc_raid_set(lc, rd->name, FIND_TOP, rd,
 
825
                                          LC_RS(lc), NO_CREATE, NO_CREATE_ARG)))
 
826
                return NULL;
 
827
 
 
828
        rs->type = t_group;
 
829
        list_add_sorted(lc, &rs->devs, &rd->devs, no_sort);
 
830
 
 
831
        /* Go deal with the real arrays. */
 
832
        return group_rd(lc, rs, rd);
 
833
}
 
834
 
 
835
/* Write metadata. */
 
836
static int
 
837
ddf1_write(struct lib_context *lc, struct raid_dev *rd, int erase)
 
838
{
 
839
        int ret;
 
840
        struct ddf1 *ddf1 = META(rd, ddf1);
 
841
 
 
842
        if (ddf1->adaptec_mode)
 
843
                ddf1_update_all_crcs(lc, rd->di, ddf1);
 
844
 
 
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);
 
848
 
 
849
        return ret;
 
850
}
 
851
 
 
852
/*
 
853
 * Check integrity of a RAID set.
 
854
 */
 
855
 
 
856
/* Retrieve the number of devices that should be in this set. */
 
857
static unsigned int
 
858
device_count(struct raid_dev *rd, void *context)
 
859
{
 
860
        /* Get the logical drive */
 
861
        struct ddf1_config_record *cr =
 
862
                get_this_config(META(GRP_RD(rd), ddf1), rd->offset);
 
863
 
 
864
        return cr ? cr->primary_element_count : 0;
 
865
}
 
866
 
 
867
/* Check a RAID device */
 
868
static int
 
869
check_rd(struct lib_context *lc, struct raid_set *rs,
 
870
         struct raid_dev *rd, void *context)
 
871
{
 
872
        /*
 
873
         * FIXME: Should we do more checking for brokenness here?
 
874
         * We could check SMART data, etc.
 
875
         */
 
876
        return rd->type != s_broken;
 
877
}
 
878
 
 
879
/* Start the recursive RAID set check. */
 
880
static int
 
881
ddf1_check(struct lib_context *lc, struct raid_set *rs)
 
882
{
 
883
        return check_raid_set(lc, rs, device_count, NULL, check_rd,
 
884
                              NULL, handler);
 
885
}
 
886
 
 
887
static struct event_handlers ddf1_event_handlers = {
 
888
        .io = event_io,
 
889
        .rd = NULL,             /* FIXME: no device add/remove event handler yet. */
 
890
};
 
891
 
 
892
#ifdef DMRAID_NATIVE_LOG
 
893
/*
 
894
 * Log native information about the RAID device.
 
895
 */
 
896
static void
 
897
ddf1_log(struct lib_context *lc, struct raid_dev *rd)
 
898
{
 
899
        ddf1_dump_all(lc, rd->di, META(rd, ddf1), handler);
 
900
}
 
901
#endif /* #ifdef DMRAID_NATIVE_LOG  */
 
902
 
 
903
static struct dmraid_format ddf1_format = {
 
904
        .name = HANDLER,
 
905
        .descr = "SNIA DDF1",
 
906
        .caps = "0,1,4,5,linear",
 
907
        .format = FMT_RAID,
 
908
        .read = ddf1_read,
 
909
        .write = ddf1_write,
 
910
        .group = ddf1_group,
 
911
        .check = ddf1_check,
 
912
        .events = &ddf1_event_handlers,
 
913
#ifdef DMRAID_NATIVE_LOG
 
914
        .log = ddf1_log,
 
915
#endif
 
916
};
 
917
 
 
918
/* Register this format handler with the format core */
 
919
int
 
920
register_ddf1(struct lib_context *lc)
 
921
{
 
922
        return register_format_handler(lc, &ddf1_format);
 
923
}
 
924
 
 
925
/*
 
926
 * Set up a RAID device from what we've assembled out of the metadata.
 
927
 */
 
928
static int
 
929
setup_rd(struct lib_context *lc, struct raid_dev *rd,
 
930
         struct dev_info *di, void *meta, union read_info *info)
 
931
{
 
932
        unsigned int i, ma_count = 5;
 
933
        struct ddf1 *ddf1 = meta;
 
934
        struct meta_areas *ma;
 
935
        struct ddf1_phys_drive *pd;
 
936
 
 
937
        if (!(pd = get_phys_drive(ddf1)))
 
938
                LOG_ERR(lc, 0, "%s: Cannot find physical drive description "
 
939
                        "on %s!", handler, di->path);
 
940
 
 
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 */
 
946
 
 
947
        if (!(ma = rd->meta_areas = alloc_meta_areas(lc, rd, handler,
 
948
                                                     ma_count)))
 
949
                return 0;
 
950
 
 
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;
 
954
 
 
955
        ma->offset = ddf1->anchor_offset;
 
956
        (ma++)->area = &ddf1->anchor;
 
957
 
 
958
        (ma++)->area = ddf1->primary;
 
959
 
 
960
        if (ddf1->secondary)
 
961
                (ma++)->offset = ddf1->primary->secondary_table_lba;
 
962
 
 
963
        if (ddf1->adapter) {
 
964
                ma->offset += ddf1->primary->adapter_data_offset;
 
965
                ma->size = to_bytes(ddf1->primary->adapter_data_len);
 
966
                (ma++)->area = ddf1->adapter;
 
967
        }
 
968
 
 
969
        /* FIXME: set up workspace_lba */
 
970
 
 
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;
 
975
        }
 
976
 
 
977
        ma->offset += ddf1->primary->phys_drive_offset;
 
978
        ma->size = to_bytes(ddf1->primary->phys_drive_len);
 
979
        (ma++)->area = ddf1->pd_header;
 
980
 
 
981
        ma->offset += ddf1->primary->virt_drive_offset;
 
982
        ma->size = to_bytes(ddf1->primary->virt_drive_len);
 
983
        (ma++)->area = ddf1->vd_header;
 
984
 
 
985
        ma->offset += ddf1->primary->config_record_offset;
 
986
        ma->size = to_bytes(ddf1->primary->config_record_len);
 
987
        ma->area = ddf1->cfg;
 
988
 
 
989
        /* Now set up the rest of the metadata info */
 
990
        rd->di = di;
 
991
        rd->fmt = &ddf1_format;
 
992
        rd->status = disk_status(pd);
 
993
        rd->type = t_group;
 
994
        rd->offset = 0;
 
995
        if (!(rd->sectors = get_size(lc, ddf1, NULL, pd)))
 
996
                return log_zero_sectors(lc, di->path, handler);
 
997
 
 
998
        /* FIXME: better name */
 
999
        return (rd->name = dbg_strdup(DDF1_DISKS)) ? 1 : 0;
 
1000
}