2
* Highpoint 45X ATARAID series metadata format handler.
4
* Copyright (C) 2004,2005 Heinz Mauelshagen, Red Hat GmbH.
7
* See file LICENSE at the top of this source tree for license information.
11
* hpt45x_read(), hpt45x_group() and group_rd() profited from
12
* Carl-Daniel Hailfinger's raiddetect code.
14
#define HANDLER "hpt45x"
17
#define FORMAT_HANDLER
20
#if BYTE_ORDER != LITTLE_ENDIAN
21
# define DM_BYTEORDER_SWAB
22
# include <datastruct/byteorder.h>
25
static const char *handler = HANDLER;
27
/* Make up RAID set name from magic_0 number */
28
/* FIXME: better name ? */
29
static size_t _name(struct hpt45x *hpt, char *str, size_t len,
35
fmt = subset ? "hpt45x_%u-%u" : "hpt45x_%u";
39
return snprintf(str, len, fmt, hpt->magic_0, hpt->raid1_disk_number);
42
static char *name(struct lib_context *lc, struct raid_dev *rd,
47
struct hpt45x *hpt = META(rd, hpt45x);
49
if ((ret = dbg_malloc((len = _name(hpt, NULL, 0, subset) + 1)))) {
50
_name(hpt, ret, len, subset);
51
mk_alpha(lc, ret + HANDLER_LEN, len - HANDLER_LEN -
52
(strrchr(ret, '-') ? 3 : 1));
54
log_alloc_err(lc, handler);
60
* Retrieve status of device.
61
* FIXME: is this sufficient to cover all state ?
63
static enum status status(struct hpt45x *hpt)
65
return hpt->magic == HPT45X_MAGIC_BAD ? s_broken : s_ok;
68
/* Neutralize disk type */
69
static enum type type(struct hpt45x *hpt)
71
/* Mapping of HPT 45X types to generic types */
72
static struct types types[] = {
73
{ HPT45X_T_SPAN, t_linear},
74
{ HPT45X_T_RAID0, t_raid0},
75
{ HPT45X_T_RAID1, t_raid1},
76
/* FIXME: handle RAID 4+5 */
80
return hpt->magic_0 ? rd_type(types, (unsigned int) hpt->type) :
84
/* Decide about ordering sequence of RAID device. */
85
static int dev_sort(struct list_head *pos, struct list_head *new)
87
return (META(RD(new), hpt45x))->disk_number <
88
(META(RD(pos), hpt45x))->disk_number;
91
/* Decide about ordering sequence of RAID subset. */
92
static int set_sort(struct list_head *pos, struct list_head *new)
94
return (META(RD_RS(RS(new)), hpt45x))->raid1_disk_number <
95
(META(RD_RS(RS(pos)), hpt45x))->raid1_disk_number;
99
* Group the RAID disk into a HPT45X set.
101
* Check device hierarchy and create super set appropriately.
103
static unsigned int stride(unsigned int shift)
105
return shift ? 1 << shift : 0;
108
static void super_created(struct raid_set *super, void *private)
110
super->type = t_raid1;
111
super->stride = stride(META((private), hpt45x)->raid1_shift);
114
static int group_rd(struct lib_context *lc, struct raid_set *rs,
115
struct raid_set **ss, struct raid_dev *rd)
117
struct hpt45x *hpt = META(rd, hpt45x);
119
if (!init_raid_set(lc, rs, rd, stride(hpt->raid0_shift),
123
list_add_sorted(lc, &rs->devs, &rd->devs, dev_sort);
129
if (!find_set(lc, NULL, rs->name, FIND_TOP))
130
list_add_tail(&rs->list, LC_RS(lc));
135
if (hpt->raid1_type != HPT45X_T_RAID1)
140
* We've got a striped raid set with a mirror on top
142
* Let's find and optionally allocate the mirror set on top.
144
if (!(*ss = join_superset(lc, name, super_created,
153
* Add a Highpoint RAID device to a set.
155
static struct raid_set *hpt45x_group(struct lib_context *lc,
158
struct raid_set *rs, *ss = NULL;
163
if ((rs = find_or_alloc_raid_set(lc, rd->name, FIND_ALL, rd,
164
NO_LIST, NO_CREATE, NO_CREATE_ARG)))
165
return group_rd(lc, rs, &ss, rd) ? (ss ? ss : rs) : NULL;
171
* Read a Highpoint 45X RAID device.
173
/* Endianess conversion. */
174
#if BYTE_ORDER == LITTLE_ENDIAN
177
static void to_cpu(void *meta)
179
struct hpt45x *hpt = meta;
184
CVT32(hpt->total_secs);
189
static int is_hpt45x(struct lib_context *lc, struct dev_info *di, void *meta)
191
struct hpt45x *hpt = meta;
193
return (hpt->magic == HPT45X_MAGIC_OK ||
194
hpt->magic == HPT45X_MAGIC_BAD) &&
195
hpt->disk_number < 8;
198
static int setup_rd(struct lib_context *lc, struct raid_dev *rd,
199
struct dev_info *di, void *meta, union read_info *info);
200
static struct raid_dev *hpt45x_read(struct lib_context *lc,
203
return read_raid_dev(lc, di, NULL,
204
sizeof(struct hpt45x), HPT45X_CONFIGOFFSET,
205
to_cpu, is_hpt45x, NULL, setup_rd, handler);
209
* Write a Highpoint 45X RAID device.
211
static int hpt45x_write(struct lib_context *lc,
212
struct raid_dev *rd, int erase)
215
#if BYTE_ORDER != LITTLE_ENDIAN
216
struct hpt45x *hpt = META(rd, hpt45x);
220
ret = write_metadata(lc, handler, rd, -1, erase);
221
#if BYTE_ORDER != LITTLE_ENDIAN
228
* Check a Highpoint 45X RAID set.
230
* FIXME: more sanity checks.
232
static unsigned int devices(struct raid_dev *rd, void *context)
234
return (META(rd, hpt45x))->raid_disks;
237
static int hpt45x_check(struct lib_context *lc, struct raid_set *rs)
239
return check_raid_set(lc, rs, devices, NULL,
240
NO_CHECK_RD, NULL, handler);
244
* IO error event handler.
246
static int event_io(struct lib_context *lc, struct event_io *e_io)
248
struct raid_dev *rd = e_io->rd;
249
struct hpt45x *hpt = META(rd, hpt45x);
251
/* Avoid write trashing. */
252
if (S_BROKEN(status(hpt)))
255
hpt->magic = HPT45X_MAGIC_BAD;
260
static struct event_handlers hpt45x_event_handlers = {
262
.rd = NULL, /* FIXME: no device add/remove event handler yet. */
265
#ifdef DMRAID_NATIVE_LOG
267
* Log native information about an HPT45X RAID device.
269
static void hpt45x_log(struct lib_context *lc, struct raid_dev *rd)
272
struct hpt45x *hpt = META(rd, hpt45x);
274
log_print(lc, "%s (%s):", rd->di->path, handler);
275
DP("magic: 0x%x", hpt, hpt->magic);
276
DP("magic_0: 0x%x", hpt, hpt->magic_0);
277
DP("magic_1: 0x%x", hpt, hpt->magic_1);
278
DP("total_secs: %u", hpt, hpt->total_secs);
279
DP("type: %u", hpt, hpt->type);
280
DP("raid_disks: %u", hpt, hpt->raid_disks);
281
DP("disk_number: %u", hpt, hpt->disk_number);
282
DP("raid0_shift: %u", hpt, hpt->raid0_shift);
283
for (i = 0; i < 3; i++)
284
P2("dummy[%u]: 0x%x", hpt, i, hpt->dummy[i]);
285
DP("raid1_type: %u", hpt, hpt->raid1_type);
286
DP("raid1_raid_disks: %u", hpt, hpt->raid1_raid_disks);
287
DP("raid1_disk_number: %u", hpt, hpt->raid1_disk_number);
288
DP("raid1_shift: %u", hpt, hpt->raid1_shift);
290
for (i = 0; i < 3; i++)
291
P2("dummy1[%u]: 0x%x", hpt, i, hpt->dummy1[i]);
295
static struct dmraid_format hpt45x_format = {
297
.descr = "Highpoint HPT45X",
301
.write = hpt45x_write,
302
.group = hpt45x_group,
303
.check = hpt45x_check,
304
.events = &hpt45x_event_handlers,
305
#ifdef DMRAID_NATIVE_LOG
310
/* Register this format handler with the format core. */
311
int register_hpt45x(struct lib_context *lc)
313
return register_format_handler(lc, &hpt45x_format);
316
/* Calculate RAID device size in sectors depending on RAID type. */
317
static uint64_t sectors(struct raid_dev *rd, void *meta)
319
struct hpt45x *hpt = meta;
323
return hpt->total_secs /
324
(hpt->raid_disks ? hpt->raid_disks : 1);
327
return hpt->total_secs;
330
return rd->meta_areas->offset;
334
/* Set the RAID device contents up derived from the Highpoint ones */
335
static int setup_rd(struct lib_context *lc, struct raid_dev *rd,
336
struct dev_info *di, void *meta, union read_info *info)
338
struct hpt45x *hpt = meta;
340
if (!(rd->meta_areas = alloc_meta_areas(lc, rd, handler, 1)))
343
rd->meta_areas->offset = HPT45X_CONFIGOFFSET >> 9;
344
rd->meta_areas->size = sizeof(*hpt);
345
rd->meta_areas->area = (void*) hpt;
348
rd->fmt = &hpt45x_format;
350
rd->status = status(hpt);
351
rd->type = type(hpt);
353
rd->offset = HPT45X_DATAOFFSET;
354
if (!(rd->sectors = sectors(rd, hpt)))
355
return log_zero_sectors(lc, di->path, handler);
357
return (rd->name = name(lc, rd, hpt->raid1_type == HPT45X_T_RAID1)) ?