| 1 | |
| 2 | |
| 3 | * raid_class.c - implementation of a simple raid visualisation class
|
| 4 | *
|
| 5 | * Copyright (c) 2005 - James Bottomley <[email protected]>
|
| 6 | *
|
| 7 | * This class is designed to allow raid attributes to be visualised and
|
| 8 | * manipulated in a form independent of the underlying raid. Ultimately this
|
| 9 | * should work for both hardware and software raids.
|
| 10 |
|
| 11 | #include <linux/init.h>
|
| 12 | #include <linux/module.h>
|
| 13 | #include <linux/list.h>
|
| 14 | #include <linux/slab.h>
|
| 15 | #include <linux/string.h>
|
| 16 | #include <linux/raid_class.h>
|
| 17 | #include <scsi/scsi_device.h>
|
| 18 | #include <scsi/scsi_host.h>
|
| 19 |
|
| 20 | #define RAID_NUM_ATTRS 3
|
| 21 |
|
| 22 | struct raid_internal {
|
| 23 | struct raid_template r;
|
| 24 | struct raid_function_template *f;
|
| 25 |
|
| 26 | struct device_attribute private_attrs[RAID_NUM_ATTRS];
|
| 27 | |
| 28 | * needed by scsi_sysfs.c
|
| 29 | struct device_attribute *attrs[RAID_NUM_ATTRS + 1];
|
| 30 | };
|
| 31 |
|
| 32 | struct raid_component {
|
| 33 | struct list_head node;
|
| 34 | struct device dev;
|
| 35 | int num;
|
| 36 | };
|
| 37 |
|
| 38 | #define to_raid_internal(tmpl) container_of(tmpl, struct raid_internal, r)
|
| 39 |
|
| 40 | #define tc_to_raid_internal(tcont) ({ \
|
| 41 | struct raid_template *r = \
|
| 42 | container_of(tcont, struct raid_template, raid_attrs); \
|
| 43 | to_raid_internal(r); \
|
| 44 | })
|
| 45 |
|
| 46 | #define ac_to_raid_internal(acont) ({ \
|
| 47 | struct transport_container *tc = \
|
| 48 | container_of(acont, struct transport_container, ac); \
|
| 49 | tc_to_raid_internal(tc); \
|
| 50 | })
|
| 51 |
|
| 52 | #define device_to_raid_internal(dev) ({ \
|
| 53 | struct attribute_container *ac = \
|
| 54 | attribute_container_classdev_to_container(dev); \
|
| 55 | ac_to_raid_internal(ac); \
|
| 56 | })
|
| 57 |
|
| 58 |
|
| 59 | static int raid_match(struct attribute_container *cont, struct device *dev)
|
| 60 | {
|
| 61 | |
| 62 | * emulated RAID devices, so start with SCSI
|
| 63 | struct raid_internal *i = ac_to_raid_internal(cont);
|
| 64 |
|
| 65 | if (IS_ENABLED(CONFIG_SCSI) && scsi_is_sdev_device(dev)) {
|
| 66 | struct scsi_device *sdev = to_scsi_device(dev);
|
| 67 |
|
| 68 | if (i->f->cookie != sdev->host->hostt)
|
| 69 | return 0;
|
| 70 |
|
| 71 | return i->f->is_raid(dev);
|
| 72 | }
|
| 73 |
|
| 74 | return 0;
|
| 75 | }
|
| 76 |
|
| 77 | static int raid_setup(struct transport_container *tc, struct device *dev,
|
| 78 | struct device *cdev)
|
| 79 | {
|
| 80 | struct raid_data *rd;
|
| 81 |
|
| 82 | BUG_ON(dev_get_drvdata(cdev));
|
| 83 |
|
| 84 | rd = kzalloc_obj(*rd);
|
| 85 | if (!rd)
|
| 86 | return -ENOMEM;
|
| 87 |
|
| 88 | INIT_LIST_HEAD(&rd->component_list);
|
| 89 | dev_set_drvdata(cdev, rd);
|
| 90 |
|
| 91 | return 0;
|
| 92 | }
|
| 93 |
|
| 94 | static int raid_remove(struct transport_container *tc, struct device *dev,
|
| 95 | struct device *cdev)
|
| 96 | {
|
| 97 | struct raid_data *rd = dev_get_drvdata(cdev);
|
| 98 | struct raid_component *rc, *next;
|
| 99 | dev_printk(KERN_ERR, dev, "RAID REMOVE\n");
|
| 100 | dev_set_drvdata(cdev, NULL);
|
| 101 | list_for_each_entry_safe(rc, next, &rd->component_list, node) {
|
| 102 | list_del(&rc->node);
|
| 103 | dev_printk(KERN_ERR, rc->dev.parent, "RAID COMPONENT REMOVE\n");
|
| 104 | device_unregister(&rc->dev);
|
| 105 | }
|
| 106 | dev_printk(KERN_ERR, dev, "RAID REMOVE DONE\n");
|
| 107 | kfree(rd);
|
| 108 | return 0;
|
| 109 | }
|
| 110 |
|
| 111 | static DECLARE_TRANSPORT_CLASS(raid_class,
|
| 112 | "raid_devices",
|
| 113 | raid_setup,
|
| 114 | raid_remove,
|
| 115 | NULL);
|
| 116 |
|
| 117 | static const struct {
|
| 118 | enum raid_state value;
|
| 119 | char *name;
|
| 120 | } raid_states[] = {
|
| 121 | { RAID_STATE_UNKNOWN, "unknown" },
|
| 122 | { RAID_STATE_ACTIVE, "active" },
|
| 123 | { RAID_STATE_DEGRADED, "degraded" },
|
| 124 | { RAID_STATE_RESYNCING, "resyncing" },
|
| 125 | { RAID_STATE_OFFLINE, "offline" },
|
| 126 | };
|
| 127 |
|
| 128 | static const char *raid_state_name(enum raid_state state)
|
| 129 | {
|
| 130 | int i;
|
| 131 | char *name = NULL;
|
| 132 |
|
| 133 | for (i = 0; i < ARRAY_SIZE(raid_states); i++) {
|
| 134 | if (raid_states[i].value == state) {
|
| 135 | name = raid_states[i].name;
|
| 136 | break;
|
| 137 | }
|
| 138 | }
|
| 139 | return name;
|
| 140 | }
|
| 141 |
|
| 142 | static struct {
|
| 143 | enum raid_level value;
|
| 144 | char *name;
|
| 145 | } raid_levels[] = {
|
| 146 | { RAID_LEVEL_UNKNOWN, "unknown" },
|
| 147 | { RAID_LEVEL_LINEAR, "linear" },
|
| 148 | { RAID_LEVEL_0, "raid0" },
|
| 149 | { RAID_LEVEL_1, "raid1" },
|
| 150 | { RAID_LEVEL_10, "raid10" },
|
| 151 | { RAID_LEVEL_1E, "raid1e" },
|
| 152 | { RAID_LEVEL_3, "raid3" },
|
| 153 | { RAID_LEVEL_4, "raid4" },
|
| 154 | { RAID_LEVEL_5, "raid5" },
|
| 155 | { RAID_LEVEL_50, "raid50" },
|
| 156 | { RAID_LEVEL_6, "raid6" },
|
| 157 | { RAID_LEVEL_JBOD, "jbod" },
|
| 158 | };
|
| 159 |
|
| 160 | static const char *raid_level_name(enum raid_level level)
|
| 161 | {
|
| 162 | int i;
|
| 163 | char *name = NULL;
|
| 164 |
|
| 165 | for (i = 0; i < ARRAY_SIZE(raid_levels); i++) {
|
| 166 | if (raid_levels[i].value == level) {
|
| 167 | name = raid_levels[i].name;
|
| 168 | break;
|
| 169 | }
|
| 170 | }
|
| 171 | return name;
|
| 172 | }
|
| 173 |
|
| 174 | #define raid_attr_show_internal(attr, fmt, var, code) \
|
| 175 | static ssize_t raid_show_##attr(struct device *dev, \
|
| 176 | struct device_attribute *attr, \
|
| 177 | char *buf) \
|
| 178 | { \
|
| 179 | struct raid_data *rd = dev_get_drvdata(dev); \
|
| 180 | code \
|
| 181 | return snprintf(buf, 20, #fmt "\n", var); \
|
| 182 | }
|
| 183 |
|
| 184 | #define raid_attr_ro_states(attr, states, code) \
|
| 185 | raid_attr_show_internal(attr, %s, name, \
|
| 186 | const char *name; \
|
| 187 | code \
|
| 188 | name = raid_##states##_name(rd->attr); \
|
| 189 | ) \
|
| 190 | static DEVICE_ATTR(attr, S_IRUGO, raid_show_##attr, NULL)
|
| 191 |
|
| 192 |
|
| 193 | #define raid_attr_ro_internal(attr, code) \
|
| 194 | raid_attr_show_internal(attr, %d, rd->attr, code) \
|
| 195 | static DEVICE_ATTR(attr, S_IRUGO, raid_show_##attr, NULL)
|
| 196 |
|
| 197 | #define ATTR_CODE(attr) \
|
| 198 | struct raid_internal *i = device_to_raid_internal(dev); \
|
| 199 | if (i->f->get_##attr) \
|
| 200 | i->f->get_##attr(dev->parent);
|
| 201 |
|
| 202 | #define raid_attr_ro(attr) raid_attr_ro_internal(attr, )
|
| 203 | #define raid_attr_ro_fn(attr) raid_attr_ro_internal(attr, ATTR_CODE(attr))
|
| 204 | #define raid_attr_ro_state(attr) raid_attr_ro_states(attr, attr, )
|
| 205 | #define raid_attr_ro_state_fn(attr) raid_attr_ro_states(attr, attr, ATTR_CODE(attr))
|
| 206 |
|
| 207 |
|
| 208 | raid_attr_ro_state(level);
|
| 209 | raid_attr_ro_fn(resync);
|
| 210 | raid_attr_ro_state_fn(state);
|
| 211 |
|
| 212 | struct raid_template *
|
| 213 | raid_class_attach(struct raid_function_template *ft)
|
| 214 | {
|
| 215 | struct raid_internal *i = kzalloc_obj(struct raid_internal);
|
| 216 | int count = 0;
|
| 217 |
|
| 218 | if (unlikely(!i))
|
| 219 | return NULL;
|
| 220 |
|
| 221 | i->f = ft;
|
| 222 |
|
| 223 | i->r.raid_attrs.ac.class = &raid_class.class;
|
| 224 | i->r.raid_attrs.ac.match = raid_match;
|
| 225 | i->r.raid_attrs.ac.attrs = &i->attrs[0];
|
| 226 |
|
| 227 | attribute_container_register(&i->r.raid_attrs.ac);
|
| 228 |
|
| 229 | i->attrs[count++] = &dev_attr_level;
|
| 230 | i->attrs[count++] = &dev_attr_resync;
|
| 231 | i->attrs[count++] = &dev_attr_state;
|
| 232 |
|
| 233 | i->attrs[count] = NULL;
|
| 234 | BUG_ON(count > RAID_NUM_ATTRS);
|
| 235 |
|
| 236 | return &i->r;
|
| 237 | }
|
| 238 | EXPORT_SYMBOL(raid_class_attach);
|
| 239 |
|
| 240 | void
|
| 241 | raid_class_release(struct raid_template *r)
|
| 242 | {
|
| 243 | struct raid_internal *i = to_raid_internal(r);
|
| 244 |
|
| 245 | BUG_ON(attribute_container_unregister(&i->r.raid_attrs.ac));
|
| 246 |
|
| 247 | kfree(i);
|
| 248 | }
|
| 249 | EXPORT_SYMBOL(raid_class_release);
|
| 250 |
|
| 251 | static __init int raid_init(void)
|
| 252 | {
|
| 253 | return transport_class_register(&raid_class);
|
| 254 | }
|
| 255 |
|
| 256 | static __exit void raid_exit(void)
|
| 257 | {
|
| 258 | transport_class_unregister(&raid_class);
|
| 259 | }
|
| 260 |
|
| 261 | MODULE_AUTHOR("James Bottomley");
|
| 262 | MODULE_DESCRIPTION("RAID device class");
|
| 263 | MODULE_LICENSE("GPL");
|
| 264 |
|
| 265 | module_init(raid_init);
|
| 266 | module_exit(raid_exit);
|
| 267 |
|