0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 #undef PDCS_DEBUG
0038 #ifdef PDCS_DEBUG
0039 #define DPRINTK(fmt, args...) printk(KERN_DEBUG fmt, ## args)
0040 #else
0041 #define DPRINTK(fmt, args...)
0042 #endif
0043
0044 #include <linux/module.h>
0045 #include <linux/init.h>
0046 #include <linux/kernel.h>
0047 #include <linux/string.h>
0048 #include <linux/capability.h>
0049 #include <linux/ctype.h>
0050 #include <linux/sysfs.h>
0051 #include <linux/kobject.h>
0052 #include <linux/device.h>
0053 #include <linux/errno.h>
0054 #include <linux/spinlock.h>
0055
0056 #include <asm/pdc.h>
0057 #include <asm/page.h>
0058 #include <linux/uaccess.h>
0059 #include <asm/hardware.h>
0060
0061 #define PDCS_VERSION "0.30"
0062 #define PDCS_PREFIX "PDC Stable Storage"
0063
0064 #define PDCS_ADDR_PPRI 0x00
0065 #define PDCS_ADDR_OSID 0x40
0066 #define PDCS_ADDR_OSD1 0x48
0067 #define PDCS_ADDR_DIAG 0x58
0068 #define PDCS_ADDR_FSIZ 0x5C
0069 #define PDCS_ADDR_PCON 0x60
0070 #define PDCS_ADDR_PALT 0x80
0071 #define PDCS_ADDR_PKBD 0xA0
0072 #define PDCS_ADDR_OSD2 0xE0
0073
0074 MODULE_AUTHOR("Thibaut VARENE <varenet@parisc-linux.org>");
0075 MODULE_DESCRIPTION("sysfs interface to HP PDC Stable Storage data");
0076 MODULE_LICENSE("GPL");
0077 MODULE_VERSION(PDCS_VERSION);
0078
0079
0080 static unsigned long pdcs_size __read_mostly;
0081
0082
0083 static u16 pdcs_osid __read_mostly;
0084
0085
0086 struct pdcspath_entry {
0087 rwlock_t rw_lock;
0088 short ready;
0089 unsigned long addr;
0090 char *name;
0091 struct device_path devpath;
0092 struct device *dev;
0093 struct kobject kobj;
0094 };
0095
0096 struct pdcspath_attribute {
0097 struct attribute attr;
0098 ssize_t (*show)(struct pdcspath_entry *entry, char *buf);
0099 ssize_t (*store)(struct pdcspath_entry *entry, const char *buf, size_t count);
0100 };
0101
0102 #define PDCSPATH_ENTRY(_addr, _name) \
0103 struct pdcspath_entry pdcspath_entry_##_name = { \
0104 .ready = 0, \
0105 .addr = _addr, \
0106 .name = __stringify(_name), \
0107 };
0108
0109 #define PDCS_ATTR(_name, _mode, _show, _store) \
0110 struct kobj_attribute pdcs_attr_##_name = { \
0111 .attr = {.name = __stringify(_name), .mode = _mode}, \
0112 .show = _show, \
0113 .store = _store, \
0114 };
0115
0116 #define PATHS_ATTR(_name, _mode, _show, _store) \
0117 struct pdcspath_attribute paths_attr_##_name = { \
0118 .attr = {.name = __stringify(_name), .mode = _mode}, \
0119 .show = _show, \
0120 .store = _store, \
0121 };
0122
0123 #define to_pdcspath_attribute(_attr) container_of(_attr, struct pdcspath_attribute, attr)
0124 #define to_pdcspath_entry(obj) container_of(obj, struct pdcspath_entry, kobj)
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138 static int
0139 pdcspath_fetch(struct pdcspath_entry *entry)
0140 {
0141 struct device_path *devpath;
0142
0143 if (!entry)
0144 return -EINVAL;
0145
0146 devpath = &entry->devpath;
0147
0148 DPRINTK("%s: fetch: 0x%p, 0x%p, addr: 0x%lx\n", __func__,
0149 entry, devpath, entry->addr);
0150
0151
0152 if (pdc_stable_read(entry->addr, devpath, sizeof(*devpath)) != PDC_OK)
0153 return -EIO;
0154
0155
0156
0157
0158 entry->dev = hwpath_to_device((struct hardware_path *)devpath);
0159
0160 entry->ready = 1;
0161
0162 DPRINTK("%s: device: 0x%p\n", __func__, entry->dev);
0163
0164 return 0;
0165 }
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179 static void
0180 pdcspath_store(struct pdcspath_entry *entry)
0181 {
0182 struct device_path *devpath;
0183
0184 BUG_ON(!entry);
0185
0186 devpath = &entry->devpath;
0187
0188
0189
0190
0191 if (!entry->ready) {
0192
0193 BUG_ON(!entry->dev);
0194 device_to_hwpath(entry->dev, (struct hardware_path *)devpath);
0195 }
0196
0197
0198 DPRINTK("%s: store: 0x%p, 0x%p, addr: 0x%lx\n", __func__,
0199 entry, devpath, entry->addr);
0200
0201
0202 if (pdc_stable_write(entry->addr, devpath, sizeof(*devpath)) != PDC_OK)
0203 WARN(1, KERN_ERR "%s: an error occurred when writing to PDC.\n"
0204 "It is likely that the Stable Storage data has been corrupted.\n"
0205 "Please check it carefully upon next reboot.\n", __func__);
0206
0207
0208 entry->ready = 2;
0209
0210 DPRINTK("%s: device: 0x%p\n", __func__, entry->dev);
0211 }
0212
0213
0214
0215
0216
0217
0218
0219
0220 static ssize_t
0221 pdcspath_hwpath_read(struct pdcspath_entry *entry, char *buf)
0222 {
0223 char *out = buf;
0224 struct device_path *devpath;
0225 short i;
0226
0227 if (!entry || !buf)
0228 return -EINVAL;
0229
0230 read_lock(&entry->rw_lock);
0231 devpath = &entry->devpath;
0232 i = entry->ready;
0233 read_unlock(&entry->rw_lock);
0234
0235 if (!i)
0236 return -ENODATA;
0237
0238 for (i = 0; i < 6; i++) {
0239 if (devpath->bc[i] >= 128)
0240 continue;
0241 out += sprintf(out, "%u/", (unsigned char)devpath->bc[i]);
0242 }
0243 out += sprintf(out, "%u\n", (unsigned char)devpath->mod);
0244
0245 return out - buf;
0246 }
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263 static ssize_t
0264 pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t count)
0265 {
0266 struct hardware_path hwpath;
0267 unsigned short i;
0268 char in[64], *temp;
0269 struct device *dev;
0270 int ret;
0271
0272 if (!entry || !buf || !count)
0273 return -EINVAL;
0274
0275
0276 count = min_t(size_t, count, sizeof(in)-1);
0277 strncpy(in, buf, count);
0278 in[count] = '\0';
0279
0280
0281 memset(&hwpath, 0xff, sizeof(hwpath));
0282
0283
0284 if (!(temp = strrchr(in, '/')))
0285 return -EINVAL;
0286
0287 hwpath.mod = simple_strtoul(temp+1, NULL, 10);
0288 in[temp-in] = '\0';
0289 DPRINTK("%s: mod: %d\n", __func__, hwpath.mod);
0290
0291
0292
0293
0294
0295
0296 for (i=5; ((temp = strrchr(in, '/'))) && (temp-in > 0) && (likely(i)); i--) {
0297 hwpath.bc[i] = simple_strtoul(temp+1, NULL, 10);
0298 in[temp-in] = '\0';
0299 DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]);
0300 }
0301
0302
0303 hwpath.bc[i] = simple_strtoul(in, NULL, 10);
0304 DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]);
0305
0306
0307 if (!(dev = hwpath_to_device((struct hardware_path *)&hwpath))) {
0308 printk(KERN_WARNING "%s: attempt to set invalid \"%s\" "
0309 "hardware path: %s\n", __func__, entry->name, buf);
0310 return -EINVAL;
0311 }
0312
0313
0314 write_lock(&entry->rw_lock);
0315 entry->ready = 0;
0316 entry->dev = dev;
0317
0318
0319 pdcspath_store(entry);
0320
0321
0322 sysfs_remove_link(&entry->kobj, "device");
0323 write_unlock(&entry->rw_lock);
0324
0325 ret = sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
0326 WARN_ON(ret);
0327
0328 printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" path to \"%s\"\n",
0329 entry->name, buf);
0330
0331 return count;
0332 }
0333
0334
0335
0336
0337
0338
0339
0340
0341 static ssize_t
0342 pdcspath_layer_read(struct pdcspath_entry *entry, char *buf)
0343 {
0344 char *out = buf;
0345 struct device_path *devpath;
0346 short i;
0347
0348 if (!entry || !buf)
0349 return -EINVAL;
0350
0351 read_lock(&entry->rw_lock);
0352 devpath = &entry->devpath;
0353 i = entry->ready;
0354 read_unlock(&entry->rw_lock);
0355
0356 if (!i)
0357 return -ENODATA;
0358
0359 for (i = 0; i < 6 && devpath->layers[i]; i++)
0360 out += sprintf(out, "%u ", devpath->layers[i]);
0361
0362 out += sprintf(out, "\n");
0363
0364 return out - buf;
0365 }
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379 static ssize_t
0380 pdcspath_layer_write(struct pdcspath_entry *entry, const char *buf, size_t count)
0381 {
0382 unsigned int layers[6];
0383 unsigned short i;
0384 char in[64], *temp;
0385
0386 if (!entry || !buf || !count)
0387 return -EINVAL;
0388
0389
0390 count = min_t(size_t, count, sizeof(in)-1);
0391 strncpy(in, buf, count);
0392 in[count] = '\0';
0393
0394
0395 memset(&layers, 0, sizeof(layers));
0396
0397
0398 if (unlikely(!isdigit(*in)))
0399 return -EINVAL;
0400 layers[0] = simple_strtoul(in, NULL, 10);
0401 DPRINTK("%s: layer[0]: %d\n", __func__, layers[0]);
0402
0403 temp = in;
0404 for (i=1; ((temp = strchr(temp, '.'))) && (likely(i<6)); i++) {
0405 if (unlikely(!isdigit(*(++temp))))
0406 return -EINVAL;
0407 layers[i] = simple_strtoul(temp, NULL, 10);
0408 DPRINTK("%s: layer[%d]: %d\n", __func__, i, layers[i]);
0409 }
0410
0411
0412 write_lock(&entry->rw_lock);
0413
0414
0415
0416 memcpy(&entry->devpath.layers, &layers, sizeof(layers));
0417
0418
0419 pdcspath_store(entry);
0420 write_unlock(&entry->rw_lock);
0421
0422 printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" layers to \"%s\"\n",
0423 entry->name, buf);
0424
0425 return count;
0426 }
0427
0428
0429
0430
0431
0432
0433
0434 static ssize_t
0435 pdcspath_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
0436 {
0437 struct pdcspath_entry *entry = to_pdcspath_entry(kobj);
0438 struct pdcspath_attribute *pdcs_attr = to_pdcspath_attribute(attr);
0439 ssize_t ret = 0;
0440
0441 if (pdcs_attr->show)
0442 ret = pdcs_attr->show(entry, buf);
0443
0444 return ret;
0445 }
0446
0447
0448
0449
0450
0451
0452
0453
0454 static ssize_t
0455 pdcspath_attr_store(struct kobject *kobj, struct attribute *attr,
0456 const char *buf, size_t count)
0457 {
0458 struct pdcspath_entry *entry = to_pdcspath_entry(kobj);
0459 struct pdcspath_attribute *pdcs_attr = to_pdcspath_attribute(attr);
0460 ssize_t ret = 0;
0461
0462 if (!capable(CAP_SYS_ADMIN))
0463 return -EACCES;
0464
0465 if (pdcs_attr->store)
0466 ret = pdcs_attr->store(entry, buf, count);
0467
0468 return ret;
0469 }
0470
0471 static const struct sysfs_ops pdcspath_attr_ops = {
0472 .show = pdcspath_attr_show,
0473 .store = pdcspath_attr_store,
0474 };
0475
0476
0477 static PATHS_ATTR(hwpath, 0644, pdcspath_hwpath_read, pdcspath_hwpath_write);
0478 static PATHS_ATTR(layer, 0644, pdcspath_layer_read, pdcspath_layer_write);
0479
0480 static struct attribute *paths_subsys_attrs[] = {
0481 &paths_attr_hwpath.attr,
0482 &paths_attr_layer.attr,
0483 NULL,
0484 };
0485 ATTRIBUTE_GROUPS(paths_subsys);
0486
0487
0488 static struct kobj_type ktype_pdcspath = {
0489 .sysfs_ops = &pdcspath_attr_ops,
0490 .default_groups = paths_subsys_groups,
0491 };
0492
0493
0494 static PDCSPATH_ENTRY(PDCS_ADDR_PPRI, primary);
0495 static PDCSPATH_ENTRY(PDCS_ADDR_PCON, console);
0496 static PDCSPATH_ENTRY(PDCS_ADDR_PALT, alternative);
0497 static PDCSPATH_ENTRY(PDCS_ADDR_PKBD, keyboard);
0498
0499
0500 static struct pdcspath_entry *pdcspath_entries[] = {
0501 &pdcspath_entry_primary,
0502 &pdcspath_entry_alternative,
0503 &pdcspath_entry_console,
0504 &pdcspath_entry_keyboard,
0505 NULL,
0506 };
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516 static ssize_t pdcs_size_read(struct kobject *kobj,
0517 struct kobj_attribute *attr,
0518 char *buf)
0519 {
0520 char *out = buf;
0521
0522 if (!buf)
0523 return -EINVAL;
0524
0525
0526 out += sprintf(out, "%ld\n", pdcs_size);
0527
0528 return out - buf;
0529 }
0530
0531
0532
0533
0534
0535
0536 static ssize_t pdcs_auto_read(struct kobject *kobj,
0537 struct kobj_attribute *attr,
0538 char *buf, int knob)
0539 {
0540 char *out = buf;
0541 struct pdcspath_entry *pathentry;
0542
0543 if (!buf)
0544 return -EINVAL;
0545
0546
0547 pathentry = &pdcspath_entry_primary;
0548
0549 read_lock(&pathentry->rw_lock);
0550 out += sprintf(out, "%s\n", (pathentry->devpath.flags & knob) ?
0551 "On" : "Off");
0552 read_unlock(&pathentry->rw_lock);
0553
0554 return out - buf;
0555 }
0556
0557
0558
0559
0560
0561 static ssize_t pdcs_autoboot_read(struct kobject *kobj,
0562 struct kobj_attribute *attr, char *buf)
0563 {
0564 return pdcs_auto_read(kobj, attr, buf, PF_AUTOBOOT);
0565 }
0566
0567
0568
0569
0570
0571 static ssize_t pdcs_autosearch_read(struct kobject *kobj,
0572 struct kobj_attribute *attr, char *buf)
0573 {
0574 return pdcs_auto_read(kobj, attr, buf, PF_AUTOSEARCH);
0575 }
0576
0577
0578
0579
0580
0581
0582
0583 static ssize_t pdcs_timer_read(struct kobject *kobj,
0584 struct kobj_attribute *attr, char *buf)
0585 {
0586 char *out = buf;
0587 struct pdcspath_entry *pathentry;
0588
0589 if (!buf)
0590 return -EINVAL;
0591
0592
0593 pathentry = &pdcspath_entry_primary;
0594
0595
0596 read_lock(&pathentry->rw_lock);
0597 out += sprintf(out, "%u\n", (pathentry->devpath.flags & PF_TIMER) ?
0598 (1 << (pathentry->devpath.flags & PF_TIMER)) : 0);
0599 read_unlock(&pathentry->rw_lock);
0600
0601 return out - buf;
0602 }
0603
0604
0605
0606
0607
0608 static ssize_t pdcs_osid_read(struct kobject *kobj,
0609 struct kobj_attribute *attr, char *buf)
0610 {
0611 char *out = buf;
0612
0613 if (!buf)
0614 return -EINVAL;
0615
0616 out += sprintf(out, "%s dependent data (0x%.4x)\n",
0617 os_id_to_string(pdcs_osid), pdcs_osid);
0618
0619 return out - buf;
0620 }
0621
0622
0623
0624
0625
0626
0627
0628 static ssize_t pdcs_osdep1_read(struct kobject *kobj,
0629 struct kobj_attribute *attr, char *buf)
0630 {
0631 char *out = buf;
0632 u32 result[4];
0633
0634 if (!buf)
0635 return -EINVAL;
0636
0637 if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK)
0638 return -EIO;
0639
0640 out += sprintf(out, "0x%.8x\n", result[0]);
0641 out += sprintf(out, "0x%.8x\n", result[1]);
0642 out += sprintf(out, "0x%.8x\n", result[2]);
0643 out += sprintf(out, "0x%.8x\n", result[3]);
0644
0645 return out - buf;
0646 }
0647
0648
0649
0650
0651
0652
0653
0654 static ssize_t pdcs_diagnostic_read(struct kobject *kobj,
0655 struct kobj_attribute *attr, char *buf)
0656 {
0657 char *out = buf;
0658 u32 result;
0659
0660 if (!buf)
0661 return -EINVAL;
0662
0663
0664 if (pdc_stable_read(PDCS_ADDR_DIAG, &result, sizeof(result)) != PDC_OK)
0665 return -EIO;
0666
0667 out += sprintf(out, "0x%.4x\n", (result >> 16));
0668
0669 return out - buf;
0670 }
0671
0672
0673
0674
0675
0676
0677
0678 static ssize_t pdcs_fastsize_read(struct kobject *kobj,
0679 struct kobj_attribute *attr, char *buf)
0680 {
0681 char *out = buf;
0682 u32 result;
0683
0684 if (!buf)
0685 return -EINVAL;
0686
0687
0688 if (pdc_stable_read(PDCS_ADDR_FSIZ, &result, sizeof(result)) != PDC_OK)
0689 return -EIO;
0690
0691 if ((result & 0x0F) < 0x0E)
0692 out += sprintf(out, "%d kB", (1<<(result & 0x0F))*256);
0693 else
0694 out += sprintf(out, "All");
0695 out += sprintf(out, "\n");
0696
0697 return out - buf;
0698 }
0699
0700
0701
0702
0703
0704
0705
0706 static ssize_t pdcs_osdep2_read(struct kobject *kobj,
0707 struct kobj_attribute *attr, char *buf)
0708 {
0709 char *out = buf;
0710 unsigned long size;
0711 unsigned short i;
0712 u32 result;
0713
0714 if (unlikely(pdcs_size <= 224))
0715 return -ENODATA;
0716
0717 size = pdcs_size - 224;
0718
0719 if (!buf)
0720 return -EINVAL;
0721
0722 for (i=0; i<size; i+=4) {
0723 if (unlikely(pdc_stable_read(PDCS_ADDR_OSD2 + i, &result,
0724 sizeof(result)) != PDC_OK))
0725 return -EIO;
0726 out += sprintf(out, "0x%.8x\n", result);
0727 }
0728
0729 return out - buf;
0730 }
0731
0732
0733
0734
0735
0736
0737
0738
0739
0740
0741
0742 static ssize_t pdcs_auto_write(struct kobject *kobj,
0743 struct kobj_attribute *attr, const char *buf,
0744 size_t count, int knob)
0745 {
0746 struct pdcspath_entry *pathentry;
0747 unsigned char flags;
0748 char in[8], *temp;
0749 char c;
0750
0751 if (!capable(CAP_SYS_ADMIN))
0752 return -EACCES;
0753
0754 if (!buf || !count)
0755 return -EINVAL;
0756
0757
0758 count = min_t(size_t, count, sizeof(in)-1);
0759 strncpy(in, buf, count);
0760 in[count] = '\0';
0761
0762
0763 pathentry = &pdcspath_entry_primary;
0764
0765
0766 read_lock(&pathentry->rw_lock);
0767 flags = pathentry->devpath.flags;
0768 read_unlock(&pathentry->rw_lock);
0769
0770 DPRINTK("%s: flags before: 0x%X\n", __func__, flags);
0771
0772 temp = skip_spaces(in);
0773
0774 c = *temp++ - '0';
0775 if ((c != 0) && (c != 1))
0776 goto parse_error;
0777 if (c == 0)
0778 flags &= ~knob;
0779 else
0780 flags |= knob;
0781
0782 DPRINTK("%s: flags after: 0x%X\n", __func__, flags);
0783
0784
0785 write_lock(&pathentry->rw_lock);
0786
0787
0788 pathentry->devpath.flags = flags;
0789
0790
0791 pdcspath_store(pathentry);
0792 write_unlock(&pathentry->rw_lock);
0793
0794 printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" to \"%s\"\n",
0795 (knob & PF_AUTOBOOT) ? "autoboot" : "autosearch",
0796 (flags & knob) ? "On" : "Off");
0797
0798 return count;
0799
0800 parse_error:
0801 printk(KERN_WARNING "%s: Parse error: expect \"n\" (n == 0 or 1)\n", __func__);
0802 return -EINVAL;
0803 }
0804
0805
0806
0807
0808
0809
0810
0811
0812
0813
0814 static ssize_t pdcs_autoboot_write(struct kobject *kobj,
0815 struct kobj_attribute *attr,
0816 const char *buf, size_t count)
0817 {
0818 return pdcs_auto_write(kobj, attr, buf, count, PF_AUTOBOOT);
0819 }
0820
0821
0822
0823
0824
0825
0826
0827
0828
0829
0830 static ssize_t pdcs_autosearch_write(struct kobject *kobj,
0831 struct kobj_attribute *attr,
0832 const char *buf, size_t count)
0833 {
0834 return pdcs_auto_write(kobj, attr, buf, count, PF_AUTOSEARCH);
0835 }
0836
0837
0838
0839
0840
0841
0842
0843
0844
0845
0846 static ssize_t pdcs_osdep1_write(struct kobject *kobj,
0847 struct kobj_attribute *attr,
0848 const char *buf, size_t count)
0849 {
0850 u8 in[16];
0851
0852 if (!capable(CAP_SYS_ADMIN))
0853 return -EACCES;
0854
0855 if (!buf || !count)
0856 return -EINVAL;
0857
0858 if (unlikely(pdcs_osid != OS_ID_LINUX))
0859 return -EPERM;
0860
0861 if (count > 16)
0862 return -EMSGSIZE;
0863
0864
0865 memset(in, 0, 16);
0866 memcpy(in, buf, count);
0867
0868 if (pdc_stable_write(PDCS_ADDR_OSD1, &in, sizeof(in)) != PDC_OK)
0869 return -EIO;
0870
0871 return count;
0872 }
0873
0874
0875
0876
0877
0878
0879
0880
0881
0882
0883 static ssize_t pdcs_osdep2_write(struct kobject *kobj,
0884 struct kobj_attribute *attr,
0885 const char *buf, size_t count)
0886 {
0887 unsigned long size;
0888 unsigned short i;
0889 u8 in[4];
0890
0891 if (!capable(CAP_SYS_ADMIN))
0892 return -EACCES;
0893
0894 if (!buf || !count)
0895 return -EINVAL;
0896
0897 if (unlikely(pdcs_size <= 224))
0898 return -ENOSYS;
0899
0900 if (unlikely(pdcs_osid != OS_ID_LINUX))
0901 return -EPERM;
0902
0903 size = pdcs_size - 224;
0904
0905 if (count > size)
0906 return -EMSGSIZE;
0907
0908
0909
0910 for (i=0; i<count; i+=4) {
0911 memset(in, 0, 4);
0912 memcpy(in, buf+i, (count-i < 4) ? count-i : 4);
0913 if (unlikely(pdc_stable_write(PDCS_ADDR_OSD2 + i, &in,
0914 sizeof(in)) != PDC_OK))
0915 return -EIO;
0916 }
0917
0918 return count;
0919 }
0920
0921
0922 static PDCS_ATTR(size, 0444, pdcs_size_read, NULL);
0923 static PDCS_ATTR(autoboot, 0644, pdcs_autoboot_read, pdcs_autoboot_write);
0924 static PDCS_ATTR(autosearch, 0644, pdcs_autosearch_read, pdcs_autosearch_write);
0925 static PDCS_ATTR(timer, 0444, pdcs_timer_read, NULL);
0926 static PDCS_ATTR(osid, 0444, pdcs_osid_read, NULL);
0927 static PDCS_ATTR(osdep1, 0600, pdcs_osdep1_read, pdcs_osdep1_write);
0928 static PDCS_ATTR(diagnostic, 0400, pdcs_diagnostic_read, NULL);
0929 static PDCS_ATTR(fastsize, 0400, pdcs_fastsize_read, NULL);
0930 static PDCS_ATTR(osdep2, 0600, pdcs_osdep2_read, pdcs_osdep2_write);
0931
0932 static struct attribute *pdcs_subsys_attrs[] = {
0933 &pdcs_attr_size.attr,
0934 &pdcs_attr_autoboot.attr,
0935 &pdcs_attr_autosearch.attr,
0936 &pdcs_attr_timer.attr,
0937 &pdcs_attr_osid.attr,
0938 &pdcs_attr_osdep1.attr,
0939 &pdcs_attr_diagnostic.attr,
0940 &pdcs_attr_fastsize.attr,
0941 &pdcs_attr_osdep2.attr,
0942 NULL,
0943 };
0944
0945 static const struct attribute_group pdcs_attr_group = {
0946 .attrs = pdcs_subsys_attrs,
0947 };
0948
0949 static struct kobject *stable_kobj;
0950 static struct kset *paths_kset;
0951
0952
0953
0954
0955
0956
0957
0958
0959
0960
0961 static inline int __init
0962 pdcs_register_pathentries(void)
0963 {
0964 unsigned short i;
0965 struct pdcspath_entry *entry;
0966 int err;
0967
0968
0969 for (i = 0; (entry = pdcspath_entries[i]); i++)
0970 rwlock_init(&entry->rw_lock);
0971
0972 for (i = 0; (entry = pdcspath_entries[i]); i++) {
0973 write_lock(&entry->rw_lock);
0974 err = pdcspath_fetch(entry);
0975 write_unlock(&entry->rw_lock);
0976
0977 if (err < 0)
0978 continue;
0979
0980 entry->kobj.kset = paths_kset;
0981 err = kobject_init_and_add(&entry->kobj, &ktype_pdcspath, NULL,
0982 "%s", entry->name);
0983 if (err) {
0984 kobject_put(&entry->kobj);
0985 return err;
0986 }
0987
0988
0989 write_lock(&entry->rw_lock);
0990 entry->ready = 2;
0991 write_unlock(&entry->rw_lock);
0992
0993
0994 if (entry->dev) {
0995 err = sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
0996 WARN_ON(err);
0997 }
0998
0999 kobject_uevent(&entry->kobj, KOBJ_ADD);
1000 }
1001
1002 return 0;
1003 }
1004
1005
1006
1007
1008 static inline void
1009 pdcs_unregister_pathentries(void)
1010 {
1011 unsigned short i;
1012 struct pdcspath_entry *entry;
1013
1014 for (i = 0; (entry = pdcspath_entries[i]); i++) {
1015 read_lock(&entry->rw_lock);
1016 if (entry->ready >= 2)
1017 kobject_put(&entry->kobj);
1018 read_unlock(&entry->rw_lock);
1019 }
1020 }
1021
1022
1023
1024
1025
1026 static int __init
1027 pdc_stable_init(void)
1028 {
1029 int rc = 0, error = 0;
1030 u32 result;
1031
1032
1033 if (pdc_stable_get_size(&pdcs_size) != PDC_OK)
1034 return -ENODEV;
1035
1036
1037 if (pdcs_size < 96)
1038 return -ENODATA;
1039
1040 printk(KERN_INFO PDCS_PREFIX " facility v%s\n", PDCS_VERSION);
1041
1042
1043 if (pdc_stable_read(PDCS_ADDR_OSID, &result, sizeof(result)) != PDC_OK)
1044 return -EIO;
1045
1046
1047 pdcs_osid = (u16)(result >> 16);
1048
1049
1050 stable_kobj = kobject_create_and_add("stable", firmware_kobj);
1051 if (!stable_kobj) {
1052 rc = -ENOMEM;
1053 goto fail_firmreg;
1054 }
1055
1056
1057 error = sysfs_create_group(stable_kobj, &pdcs_attr_group);
1058
1059
1060 paths_kset = kset_create_and_add("paths", NULL, stable_kobj);
1061 if (!paths_kset) {
1062 rc = -ENOMEM;
1063 goto fail_ksetreg;
1064 }
1065
1066
1067 if ((rc = pdcs_register_pathentries()))
1068 goto fail_pdcsreg;
1069
1070 return rc;
1071
1072 fail_pdcsreg:
1073 pdcs_unregister_pathentries();
1074 kset_unregister(paths_kset);
1075
1076 fail_ksetreg:
1077 kobject_put(stable_kobj);
1078
1079 fail_firmreg:
1080 printk(KERN_INFO PDCS_PREFIX " bailing out\n");
1081 return rc;
1082 }
1083
1084 static void __exit
1085 pdc_stable_exit(void)
1086 {
1087 pdcs_unregister_pathentries();
1088 kset_unregister(paths_kset);
1089 kobject_put(stable_kobj);
1090 }
1091
1092
1093 module_init(pdc_stable_init);
1094 module_exit(pdc_stable_exit);