1 /* 2 * Enclosure Services 3 * 4 * Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com> 5 * 6 **----------------------------------------------------------------------------- 7 ** 8 ** This program is free software; you can redistribute it and/or 9 ** modify it under the terms of the GNU General Public License 10 ** version 2 as published by the Free Software Foundation. 11 ** 12 ** This program is distributed in the hope that it will be useful, 13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 ** GNU General Public License for more details. 16 ** 17 ** You should have received a copy of the GNU General Public License 18 ** along with this program; if not, write to the Free Software 19 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 ** 21 **----------------------------------------------------------------------------- 22 */ 23 #include <linux/device.h> 24 #include <linux/enclosure.h> 25 #include <linux/err.h> 26 #include <linux/list.h> 27 #include <linux/kernel.h> 28 #include <linux/module.h> 29 #include <linux/mutex.h> 30 31 static LIST_HEAD(container_list); 32 static DEFINE_MUTEX(container_list_lock); 33 static struct class enclosure_class; 34 static struct class enclosure_component_class; 35 36 /** 37 * enclosure_find - find an enclosure given a device 38 * @dev: the device to find for 39 * 40 * Looks through the list of registered enclosures to see 41 * if it can find a match for a device. Returns NULL if no 42 * enclosure is found. Obtains a reference to the enclosure class 43 * device which must be released with class_device_put(). 44 */ 45 struct enclosure_device *enclosure_find(struct device *dev) 46 { 47 struct enclosure_device *edev = NULL; 48 49 mutex_lock(&container_list_lock); 50 list_for_each_entry(edev, &container_list, node) { 51 if (edev->cdev.dev == dev) { 52 class_device_get(&edev->cdev); 53 mutex_unlock(&container_list_lock); 54 return edev; 55 } 56 } 57 mutex_unlock(&container_list_lock); 58 59 return NULL; 60 } 61 EXPORT_SYMBOL_GPL(enclosure_find); 62 63 /** 64 * enclosure_for_each_device - calls a function for each enclosure 65 * @fn: the function to call 66 * @data: the data to pass to each call 67 * 68 * Loops over all the enclosures calling the function. 69 * 70 * Note, this function uses a mutex which will be held across calls to 71 * @fn, so it must have non atomic context, and @fn may (although it 72 * should not) sleep or otherwise cause the mutex to be held for 73 * indefinite periods 74 */ 75 int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *), 76 void *data) 77 { 78 int error = 0; 79 struct enclosure_device *edev; 80 81 mutex_lock(&container_list_lock); 82 list_for_each_entry(edev, &container_list, node) { 83 error = fn(edev, data); 84 if (error) 85 break; 86 } 87 mutex_unlock(&container_list_lock); 88 89 return error; 90 } 91 EXPORT_SYMBOL_GPL(enclosure_for_each_device); 92 93 /** 94 * enclosure_register - register device as an enclosure 95 * 96 * @dev: device containing the enclosure 97 * @components: number of components in the enclosure 98 * 99 * This sets up the device for being an enclosure. Note that @dev does 100 * not have to be a dedicated enclosure device. It may be some other type 101 * of device that additionally responds to enclosure services 102 */ 103 struct enclosure_device * 104 enclosure_register(struct device *dev, const char *name, int components, 105 struct enclosure_component_callbacks *cb) 106 { 107 struct enclosure_device *edev = 108 kzalloc(sizeof(struct enclosure_device) + 109 sizeof(struct enclosure_component)*components, 110 GFP_KERNEL); 111 int err, i; 112 113 BUG_ON(!cb); 114 115 if (!edev) 116 return ERR_PTR(-ENOMEM); 117 118 edev->components = components; 119 120 edev->cdev.class = &enclosure_class; 121 edev->cdev.dev = get_device(dev); 122 edev->cb = cb; 123 snprintf(edev->cdev.class_id, BUS_ID_SIZE, "%s", name); 124 err = class_device_register(&edev->cdev); 125 if (err) 126 goto err; 127 128 for (i = 0; i < components; i++) 129 edev->component[i].number = -1; 130 131 mutex_lock(&container_list_lock); 132 list_add_tail(&edev->node, &container_list); 133 mutex_unlock(&container_list_lock); 134 135 return edev; 136 137 err: 138 put_device(edev->cdev.dev); 139 kfree(edev); 140 return ERR_PTR(err); 141 } 142 EXPORT_SYMBOL_GPL(enclosure_register); 143 144 static struct enclosure_component_callbacks enclosure_null_callbacks; 145 146 /** 147 * enclosure_unregister - remove an enclosure 148 * 149 * @edev: the registered enclosure to remove; 150 */ 151 void enclosure_unregister(struct enclosure_device *edev) 152 { 153 int i; 154 155 mutex_lock(&container_list_lock); 156 list_del(&edev->node); 157 mutex_unlock(&container_list_lock); 158 159 for (i = 0; i < edev->components; i++) 160 if (edev->component[i].number != -1) 161 class_device_unregister(&edev->component[i].cdev); 162 163 /* prevent any callbacks into service user */ 164 edev->cb = &enclosure_null_callbacks; 165 class_device_unregister(&edev->cdev); 166 } 167 EXPORT_SYMBOL_GPL(enclosure_unregister); 168 169 static void enclosure_release(struct class_device *cdev) 170 { 171 struct enclosure_device *edev = to_enclosure_device(cdev); 172 173 put_device(cdev->dev); 174 kfree(edev); 175 } 176 177 static void enclosure_component_release(struct class_device *cdev) 178 { 179 if (cdev->dev) 180 put_device(cdev->dev); 181 class_device_put(cdev->parent); 182 } 183 184 /** 185 * enclosure_component_register - add a particular component to an enclosure 186 * @edev: the enclosure to add the component 187 * @num: the device number 188 * @type: the type of component being added 189 * @name: an optional name to appear in sysfs (leave NULL if none) 190 * 191 * Registers the component. The name is optional for enclosures that 192 * give their components a unique name. If not, leave the field NULL 193 * and a name will be assigned. 194 * 195 * Returns a pointer to the enclosure component or an error. 196 */ 197 struct enclosure_component * 198 enclosure_component_register(struct enclosure_device *edev, 199 unsigned int number, 200 enum enclosure_component_type type, 201 const char *name) 202 { 203 struct enclosure_component *ecomp; 204 struct class_device *cdev; 205 int err; 206 207 if (number >= edev->components) 208 return ERR_PTR(-EINVAL); 209 210 ecomp = &edev->component[number]; 211 212 if (ecomp->number != -1) 213 return ERR_PTR(-EINVAL); 214 215 ecomp->type = type; 216 ecomp->number = number; 217 cdev = &ecomp->cdev; 218 cdev->parent = class_device_get(&edev->cdev); 219 cdev->class = &enclosure_component_class; 220 if (name) 221 snprintf(cdev->class_id, BUS_ID_SIZE, "%s", name); 222 else 223 snprintf(cdev->class_id, BUS_ID_SIZE, "%u", number); 224 225 err = class_device_register(cdev); 226 if (err) 227 ERR_PTR(err); 228 229 return ecomp; 230 } 231 EXPORT_SYMBOL_GPL(enclosure_component_register); 232 233 /** 234 * enclosure_add_device - add a device as being part of an enclosure 235 * @edev: the enclosure device being added to. 236 * @num: the number of the component 237 * @dev: the device being added 238 * 239 * Declares a real device to reside in slot (or identifier) @num of an 240 * enclosure. This will cause the relevant sysfs links to appear. 241 * This function may also be used to change a device associated with 242 * an enclosure without having to call enclosure_remove_device() in 243 * between. 244 * 245 * Returns zero on success or an error. 246 */ 247 int enclosure_add_device(struct enclosure_device *edev, int component, 248 struct device *dev) 249 { 250 struct class_device *cdev; 251 252 if (!edev || component >= edev->components) 253 return -EINVAL; 254 255 cdev = &edev->component[component].cdev; 256 257 class_device_del(cdev); 258 if (cdev->dev) 259 put_device(cdev->dev); 260 cdev->dev = get_device(dev); 261 return class_device_add(cdev); 262 } 263 EXPORT_SYMBOL_GPL(enclosure_add_device); 264 265 /** 266 * enclosure_remove_device - remove a device from an enclosure 267 * @edev: the enclosure device 268 * @num: the number of the component to remove 269 * 270 * Returns zero on success or an error. 271 * 272 */ 273 int enclosure_remove_device(struct enclosure_device *edev, int component) 274 { 275 struct class_device *cdev; 276 277 if (!edev || component >= edev->components) 278 return -EINVAL; 279 280 cdev = &edev->component[component].cdev; 281 282 class_device_del(cdev); 283 if (cdev->dev) 284 put_device(cdev->dev); 285 cdev->dev = NULL; 286 return class_device_add(cdev); 287 } 288 EXPORT_SYMBOL_GPL(enclosure_remove_device); 289 290 /* 291 * sysfs pieces below 292 */ 293 294 static ssize_t enclosure_show_components(struct class_device *cdev, char *buf) 295 { 296 struct enclosure_device *edev = to_enclosure_device(cdev); 297 298 return snprintf(buf, 40, "%d\n", edev->components); 299 } 300 301 static struct class_device_attribute enclosure_attrs[] = { 302 __ATTR(components, S_IRUGO, enclosure_show_components, NULL), 303 __ATTR_NULL 304 }; 305 306 static struct class enclosure_class = { 307 .name = "enclosure", 308 .owner = THIS_MODULE, 309 .release = enclosure_release, 310 .class_dev_attrs = enclosure_attrs, 311 }; 312 313 static const char *const enclosure_status [] = { 314 [ENCLOSURE_STATUS_UNSUPPORTED] = "unsupported", 315 [ENCLOSURE_STATUS_OK] = "OK", 316 [ENCLOSURE_STATUS_CRITICAL] = "critical", 317 [ENCLOSURE_STATUS_NON_CRITICAL] = "non-critical", 318 [ENCLOSURE_STATUS_UNRECOVERABLE] = "unrecoverable", 319 [ENCLOSURE_STATUS_NOT_INSTALLED] = "not installed", 320 [ENCLOSURE_STATUS_UNKNOWN] = "unknown", 321 [ENCLOSURE_STATUS_UNAVAILABLE] = "unavailable", 322 }; 323 324 static const char *const enclosure_type [] = { 325 [ENCLOSURE_COMPONENT_DEVICE] = "device", 326 [ENCLOSURE_COMPONENT_ARRAY_DEVICE] = "array device", 327 }; 328 329 static ssize_t get_component_fault(struct class_device *cdev, char *buf) 330 { 331 struct enclosure_device *edev = to_enclosure_device(cdev->parent); 332 struct enclosure_component *ecomp = to_enclosure_component(cdev); 333 334 if (edev->cb->get_fault) 335 edev->cb->get_fault(edev, ecomp); 336 return snprintf(buf, 40, "%d\n", ecomp->fault); 337 } 338 339 static ssize_t set_component_fault(struct class_device *cdev, const char *buf, 340 size_t count) 341 { 342 struct enclosure_device *edev = to_enclosure_device(cdev->parent); 343 struct enclosure_component *ecomp = to_enclosure_component(cdev); 344 int val = simple_strtoul(buf, NULL, 0); 345 346 if (edev->cb->set_fault) 347 edev->cb->set_fault(edev, ecomp, val); 348 return count; 349 } 350 351 static ssize_t get_component_status(struct class_device *cdev, char *buf) 352 { 353 struct enclosure_device *edev = to_enclosure_device(cdev->parent); 354 struct enclosure_component *ecomp = to_enclosure_component(cdev); 355 356 if (edev->cb->get_status) 357 edev->cb->get_status(edev, ecomp); 358 return snprintf(buf, 40, "%s\n", enclosure_status[ecomp->status]); 359 } 360 361 static ssize_t set_component_status(struct class_device *cdev, const char *buf, 362 size_t count) 363 { 364 struct enclosure_device *edev = to_enclosure_device(cdev->parent); 365 struct enclosure_component *ecomp = to_enclosure_component(cdev); 366 int i; 367 368 for (i = 0; enclosure_status[i]; i++) { 369 if (strncmp(buf, enclosure_status[i], 370 strlen(enclosure_status[i])) == 0 && 371 (buf[strlen(enclosure_status[i])] == '\n' || 372 buf[strlen(enclosure_status[i])] == '\0')) 373 break; 374 } 375 376 if (enclosure_status[i] && edev->cb->set_status) { 377 edev->cb->set_status(edev, ecomp, i); 378 return count; 379 } else 380 return -EINVAL; 381 } 382 383 static ssize_t get_component_active(struct class_device *cdev, char *buf) 384 { 385 struct enclosure_device *edev = to_enclosure_device(cdev->parent); 386 struct enclosure_component *ecomp = to_enclosure_component(cdev); 387 388 if (edev->cb->get_active) 389 edev->cb->get_active(edev, ecomp); 390 return snprintf(buf, 40, "%d\n", ecomp->active); 391 } 392 393 static ssize_t set_component_active(struct class_device *cdev, const char *buf, 394 size_t count) 395 { 396 struct enclosure_device *edev = to_enclosure_device(cdev->parent); 397 struct enclosure_component *ecomp = to_enclosure_component(cdev); 398 int val = simple_strtoul(buf, NULL, 0); 399 400 if (edev->cb->set_active) 401 edev->cb->set_active(edev, ecomp, val); 402 return count; 403 } 404 405 static ssize_t get_component_locate(struct class_device *cdev, char *buf) 406 { 407 struct enclosure_device *edev = to_enclosure_device(cdev->parent); 408 struct enclosure_component *ecomp = to_enclosure_component(cdev); 409 410 if (edev->cb->get_locate) 411 edev->cb->get_locate(edev, ecomp); 412 return snprintf(buf, 40, "%d\n", ecomp->locate); 413 } 414 415 static ssize_t set_component_locate(struct class_device *cdev, const char *buf, 416 size_t count) 417 { 418 struct enclosure_device *edev = to_enclosure_device(cdev->parent); 419 struct enclosure_component *ecomp = to_enclosure_component(cdev); 420 int val = simple_strtoul(buf, NULL, 0); 421 422 if (edev->cb->set_locate) 423 edev->cb->set_locate(edev, ecomp, val); 424 return count; 425 } 426 427 static ssize_t get_component_type(struct class_device *cdev, char *buf) 428 { 429 struct enclosure_component *ecomp = to_enclosure_component(cdev); 430 431 return snprintf(buf, 40, "%s\n", enclosure_type[ecomp->type]); 432 } 433 434 435 static struct class_device_attribute enclosure_component_attrs[] = { 436 __ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault, 437 set_component_fault), 438 __ATTR(status, S_IRUGO | S_IWUSR, get_component_status, 439 set_component_status), 440 __ATTR(active, S_IRUGO | S_IWUSR, get_component_active, 441 set_component_active), 442 __ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate, 443 set_component_locate), 444 __ATTR(type, S_IRUGO, get_component_type, NULL), 445 __ATTR_NULL 446 }; 447 448 static struct class enclosure_component_class = { 449 .name = "enclosure_component", 450 .owner = THIS_MODULE, 451 .class_dev_attrs = enclosure_component_attrs, 452 .release = enclosure_component_release, 453 }; 454 455 static int __init enclosure_init(void) 456 { 457 int err; 458 459 err = class_register(&enclosure_class); 460 if (err) 461 return err; 462 err = class_register(&enclosure_component_class); 463 if (err) 464 goto err_out; 465 466 return 0; 467 err_out: 468 class_unregister(&enclosure_class); 469 470 return err; 471 } 472 473 static void __exit enclosure_exit(void) 474 { 475 class_unregister(&enclosure_component_class); 476 class_unregister(&enclosure_class); 477 } 478 479 module_init(enclosure_init); 480 module_exit(enclosure_exit); 481 482 MODULE_AUTHOR("James Bottomley"); 483 MODULE_DESCRIPTION("Enclosure Services"); 484 MODULE_LICENSE("GPL v2"); 485