^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Interfaces to retrieve and set PDC Stable options (firmware)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2005-2006 Thibaut VARENE <varenet@parisc-linux.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * DEV NOTE: the PDC Procedures reference states that:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * "A minimum of 96 bytes of Stable Storage is required. Providing more than
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * 96 bytes of Stable Storage is optional [...]. Failure to provide the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * optional locations from 96 to 192 results in the loss of certain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * functionality during boot."
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Since locations between 96 and 192 are the various paths, most (if not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * all) PA-RISC machines should have them. Anyway, for safety reasons, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * following code can deal with just 96 bytes of Stable Storage, and all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * sizes between 96 and 192 bytes (provided they are multiple of struct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * device_path size, eg: 128, 160 and 192) to provide full information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * One last word: there's one path we can always count on: the primary path.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * Anything above 224 bytes is used for 'osdep2' OS-dependent storage area.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * The first OS-dependent area should always be available. Obviously, this is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * not true for the other one. Also bear in mind that reading/writing from/to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * osdep2 is much more expensive than from/to osdep1.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * NOTE: We do not handle the 2 bytes OS-dep area at 0x5D, nor the first
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * 2 bytes of storage available right after OSID. That's a total of 4 bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * sacrificed: -ETOOLAZY :P
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * The current policy wrt file permissions is:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * - write: root only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * - read: (reading triggers PDC calls) ? root only : everyone
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * The rationale is that PDC calls could hog (DoS) the machine.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * TODO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * - timer/fastsize write calls
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #undef PDCS_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #ifdef PDCS_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define DPRINTK(fmt, args...) printk(KERN_DEBUG fmt, ## args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define DPRINTK(fmt, args...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #include <linux/capability.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #include <linux/ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #include <linux/sysfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #include <linux/kobject.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #include <asm/pdc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #include <asm/page.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #include <asm/hardware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define PDCS_VERSION "0.30"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define PDCS_PREFIX "PDC Stable Storage"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define PDCS_ADDR_PPRI 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define PDCS_ADDR_OSID 0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define PDCS_ADDR_OSD1 0x48
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define PDCS_ADDR_DIAG 0x58
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define PDCS_ADDR_FSIZ 0x5C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define PDCS_ADDR_PCON 0x60
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define PDCS_ADDR_PALT 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define PDCS_ADDR_PKBD 0xA0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define PDCS_ADDR_OSD2 0xE0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) MODULE_AUTHOR("Thibaut VARENE <varenet@parisc-linux.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) MODULE_DESCRIPTION("sysfs interface to HP PDC Stable Storage data");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) MODULE_VERSION(PDCS_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /* holds Stable Storage size. Initialized once and for all, no lock needed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static unsigned long pdcs_size __read_mostly;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) /* holds OS ID. Initialized once and for all, hopefully to 0x0006 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static u16 pdcs_osid __read_mostly;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /* This struct defines what we need to deal with a parisc pdc path entry */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct pdcspath_entry {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) rwlock_t rw_lock; /* to protect path entry access */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) short ready; /* entry record is valid if != 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) unsigned long addr; /* entry address in stable storage */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) char *name; /* entry name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct device_path devpath; /* device path in parisc representation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct device *dev; /* corresponding device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct kobject kobj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) struct pdcspath_attribute {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) struct attribute attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) ssize_t (*show)(struct pdcspath_entry *entry, char *buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) ssize_t (*store)(struct pdcspath_entry *entry, const char *buf, size_t count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define PDCSPATH_ENTRY(_addr, _name) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct pdcspath_entry pdcspath_entry_##_name = { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) .ready = 0, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) .addr = _addr, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .name = __stringify(_name), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define PDCS_ATTR(_name, _mode, _show, _store) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct kobj_attribute pdcs_attr_##_name = { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) .attr = {.name = __stringify(_name), .mode = _mode}, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) .show = _show, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) .store = _store, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) #define PATHS_ATTR(_name, _mode, _show, _store) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct pdcspath_attribute paths_attr_##_name = { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) .attr = {.name = __stringify(_name), .mode = _mode}, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) .show = _show, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) .store = _store, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #define to_pdcspath_attribute(_attr) container_of(_attr, struct pdcspath_attribute, attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) #define to_pdcspath_entry(obj) container_of(obj, struct pdcspath_entry, kobj)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * pdcspath_fetch - This function populates the path entry structs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * @entry: A pointer to an allocated pdcspath_entry.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * The general idea is that you don't read from the Stable Storage every time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * you access the files provided by the facilities. We store a copy of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * content of the stable storage WRT various paths in these structs. We read
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * these structs when reading the files, and we will write to these structs when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * writing to the files, and only then write them back to the Stable Storage.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * This function expects to be called with @entry->rw_lock write-hold.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) pdcspath_fetch(struct pdcspath_entry *entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) struct device_path *devpath;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (!entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) devpath = &entry->devpath;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) DPRINTK("%s: fetch: 0x%p, 0x%p, addr: 0x%lx\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) entry, devpath, entry->addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /* addr, devpath and count must be word aligned */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (pdc_stable_read(entry->addr, devpath, sizeof(*devpath)) != PDC_OK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /* Find the matching device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) NOTE: hardware_path overlays with device_path, so the nice cast can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) be used */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) entry->dev = hwpath_to_device((struct hardware_path *)devpath);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) entry->ready = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) DPRINTK("%s: device: 0x%p\n", __func__, entry->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) * pdcspath_store - This function writes a path to stable storage.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * @entry: A pointer to an allocated pdcspath_entry.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) * It can be used in two ways: either by passing it a preset devpath struct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) * containing an already computed hardware path, or by passing it a device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) * pointer, from which it'll find out the corresponding hardware path.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) * For now we do not handle the case where there's an error in writing to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) * Stable Storage area, so you'd better not mess up the data :P
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) * This function expects to be called with @entry->rw_lock write-hold.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) pdcspath_store(struct pdcspath_entry *entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) struct device_path *devpath;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) BUG_ON(!entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) devpath = &entry->devpath;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) /* We expect the caller to set the ready flag to 0 if the hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) path struct provided is invalid, so that we know we have to fill it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) First case, we don't have a preset hwpath... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (!entry->ready) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) /* ...but we have a device, map it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) BUG_ON(!entry->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) device_to_hwpath(entry->dev, (struct hardware_path *)devpath);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) /* else, we expect the provided hwpath to be valid. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) DPRINTK("%s: store: 0x%p, 0x%p, addr: 0x%lx\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) entry, devpath, entry->addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) /* addr, devpath and count must be word aligned */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) if (pdc_stable_write(entry->addr, devpath, sizeof(*devpath)) != PDC_OK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) WARN(1, KERN_ERR "%s: an error occurred when writing to PDC.\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) "It is likely that the Stable Storage data has been corrupted.\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) "Please check it carefully upon next reboot.\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) /* kobject is already registered */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) entry->ready = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) DPRINTK("%s: device: 0x%p\n", __func__, entry->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) * pdcspath_hwpath_read - This function handles hardware path pretty printing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * @entry: An allocated and populated pdscpath_entry struct.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * @buf: The output buffer to write to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * We will call this function to format the output of the hwpath attribute file.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) pdcspath_hwpath_read(struct pdcspath_entry *entry, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) char *out = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) struct device_path *devpath;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) short i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (!entry || !buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) read_lock(&entry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) devpath = &entry->devpath;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) i = entry->ready;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) read_unlock(&entry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (!i) /* entry is not ready */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) return -ENODATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) for (i = 0; i < 6; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) if (devpath->bc[i] >= 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) out += sprintf(out, "%u/", (unsigned char)devpath->bc[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) out += sprintf(out, "%u\n", (unsigned char)devpath->mod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) return out - buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) * pdcspath_hwpath_write - This function handles hardware path modifying.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) * @entry: An allocated and populated pdscpath_entry struct.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) * @buf: The input buffer to read from.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) * @count: The number of bytes to be read.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * We will call this function to change the current hardware path.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) * Hardware paths are to be given '/'-delimited, without brackets.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) * We make sure that the provided path actually maps to an existing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) * device, BUT nothing would prevent some foolish user to set the path to some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) * PCI bridge or even a CPU...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) * A better work around would be to make sure we are at the end of a device tree
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) * for instance, but it would be IMHO beyond the simple scope of that driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) * The aim is to provide a facility. Data correctness is left to userland.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) struct hardware_path hwpath;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) unsigned short i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) char in[64], *temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (!entry || !buf || !count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) /* We'll use a local copy of buf */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) count = min_t(size_t, count, sizeof(in)-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) strncpy(in, buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) in[count] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) /* Let's clean up the target. 0xff is a blank pattern */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) memset(&hwpath, 0xff, sizeof(hwpath));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) /* First, pick the mod field (the last one of the input string) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) if (!(temp = strrchr(in, '/')))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) hwpath.mod = simple_strtoul(temp+1, NULL, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) in[temp-in] = '\0'; /* truncate the remaining string. just precaution */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) DPRINTK("%s: mod: %d\n", __func__, hwpath.mod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) /* Then, loop for each delimiter, making sure we don't have too many.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) we write the bc fields in a down-top way. No matter what, we stop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) before writing the last field. If there are too many fields anyway,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) then the user is a moron and it'll be caught up later when we'll
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) check the consistency of the given hwpath. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) for (i=5; ((temp = strrchr(in, '/'))) && (temp-in > 0) && (likely(i)); i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) hwpath.bc[i] = simple_strtoul(temp+1, NULL, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) in[temp-in] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) /* Store the final field */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) hwpath.bc[i] = simple_strtoul(in, NULL, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) /* Now we check that the user isn't trying to lure us */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) if (!(dev = hwpath_to_device((struct hardware_path *)&hwpath))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) printk(KERN_WARNING "%s: attempt to set invalid \"%s\" "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) "hardware path: %s\n", __func__, entry->name, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) /* So far so good, let's get in deep */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) write_lock(&entry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) entry->ready = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) entry->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) /* Now, dive in. Write back to the hardware */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) pdcspath_store(entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) /* Update the symlink to the real device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) sysfs_remove_link(&entry->kobj, "device");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) write_unlock(&entry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) ret = sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) WARN_ON(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" path to \"%s\"\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) entry->name, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) * pdcspath_layer_read - Extended layer (eg. SCSI ids) pretty printing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) * @entry: An allocated and populated pdscpath_entry struct.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) * @buf: The output buffer to write to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) * We will call this function to format the output of the layer attribute file.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) pdcspath_layer_read(struct pdcspath_entry *entry, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) char *out = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) struct device_path *devpath;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) short i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) if (!entry || !buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) read_lock(&entry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) devpath = &entry->devpath;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) i = entry->ready;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) read_unlock(&entry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) if (!i) /* entry is not ready */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) return -ENODATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) for (i = 0; i < 6 && devpath->layers[i]; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) out += sprintf(out, "%u ", devpath->layers[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) out += sprintf(out, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) return out - buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) * pdcspath_layer_write - This function handles extended layer modifying.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) * @entry: An allocated and populated pdscpath_entry struct.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) * @buf: The input buffer to read from.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) * @count: The number of bytes to be read.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) * We will call this function to change the current layer value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) * Layers are to be given '.'-delimited, without brackets.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) * XXX beware we are far less checky WRT input data provided than for hwpath.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) * Potential harm can be done, since there's no way to check the validity of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) * the layer fields.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) pdcspath_layer_write(struct pdcspath_entry *entry, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) unsigned int layers[6]; /* device-specific info (ctlr#, unit#, ...) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) unsigned short i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) char in[64], *temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) if (!entry || !buf || !count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) /* We'll use a local copy of buf */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) count = min_t(size_t, count, sizeof(in)-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) strncpy(in, buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) in[count] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) /* Let's clean up the target. 0 is a blank pattern */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) memset(&layers, 0, sizeof(layers));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) /* First, pick the first layer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) if (unlikely(!isdigit(*in)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) layers[0] = simple_strtoul(in, NULL, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) DPRINTK("%s: layer[0]: %d\n", __func__, layers[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) temp = in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) for (i=1; ((temp = strchr(temp, '.'))) && (likely(i<6)); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (unlikely(!isdigit(*(++temp))))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) layers[i] = simple_strtoul(temp, NULL, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) DPRINTK("%s: layer[%d]: %d\n", __func__, i, layers[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) /* So far so good, let's get in deep */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) write_lock(&entry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) /* First, overwrite the current layers with the new ones, not touching
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) the hardware path. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) memcpy(&entry->devpath.layers, &layers, sizeof(layers));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) /* Now, dive in. Write back to the hardware */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) pdcspath_store(entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) write_unlock(&entry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" layers to \"%s\"\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) entry->name, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) * pdcspath_attr_show - Generic read function call wrapper.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) * @kobj: The kobject to get info from.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) * @attr: The attribute looked upon.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) * @buf: The output buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) pdcspath_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) struct pdcspath_entry *entry = to_pdcspath_entry(kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) struct pdcspath_attribute *pdcs_attr = to_pdcspath_attribute(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) ssize_t ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) if (pdcs_attr->show)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) ret = pdcs_attr->show(entry, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) * pdcspath_attr_store - Generic write function call wrapper.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) * @kobj: The kobject to write info to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) * @attr: The attribute to be modified.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) * @buf: The input buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) * @count: The size of the buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) pdcspath_attr_store(struct kobject *kobj, struct attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) struct pdcspath_entry *entry = to_pdcspath_entry(kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) struct pdcspath_attribute *pdcs_attr = to_pdcspath_attribute(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) ssize_t ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) if (!capable(CAP_SYS_ADMIN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) return -EACCES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) if (pdcs_attr->store)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) ret = pdcs_attr->store(entry, buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) static const struct sysfs_ops pdcspath_attr_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) .show = pdcspath_attr_show,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) .store = pdcspath_attr_store,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) /* These are the two attributes of any PDC path. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) static PATHS_ATTR(hwpath, 0644, pdcspath_hwpath_read, pdcspath_hwpath_write);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) static PATHS_ATTR(layer, 0644, pdcspath_layer_read, pdcspath_layer_write);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) static struct attribute *paths_subsys_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) &paths_attr_hwpath.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) &paths_attr_layer.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) /* Specific kobject type for our PDC paths */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) static struct kobj_type ktype_pdcspath = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) .sysfs_ops = &pdcspath_attr_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) .default_attrs = paths_subsys_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) /* We hard define the 4 types of path we expect to find */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) static PDCSPATH_ENTRY(PDCS_ADDR_PPRI, primary);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) static PDCSPATH_ENTRY(PDCS_ADDR_PCON, console);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) static PDCSPATH_ENTRY(PDCS_ADDR_PALT, alternative);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) static PDCSPATH_ENTRY(PDCS_ADDR_PKBD, keyboard);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) /* An array containing all PDC paths we will deal with */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) static struct pdcspath_entry *pdcspath_entries[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) &pdcspath_entry_primary,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) &pdcspath_entry_alternative,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) &pdcspath_entry_console,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) &pdcspath_entry_keyboard,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) /* For more insight of what's going on here, refer to PDC Procedures doc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) * Section PDC_STABLE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) * pdcs_size_read - Stable Storage size output.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) * @buf: The output buffer to write to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) static ssize_t pdcs_size_read(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) char *out = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) /* show the size of the stable storage */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) out += sprintf(out, "%ld\n", pdcs_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) return out - buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) * pdcs_auto_read - Stable Storage autoboot/search flag output.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) * @buf: The output buffer to write to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) static ssize_t pdcs_auto_read(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) char *buf, int knob)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) char *out = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) struct pdcspath_entry *pathentry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) /* Current flags are stored in primary boot path entry */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) pathentry = &pdcspath_entry_primary;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) read_lock(&pathentry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) out += sprintf(out, "%s\n", (pathentry->devpath.flags & knob) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) "On" : "Off");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) read_unlock(&pathentry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) return out - buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) * pdcs_autoboot_read - Stable Storage autoboot flag output.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) * @buf: The output buffer to write to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) static ssize_t pdcs_autoboot_read(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) struct kobj_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) return pdcs_auto_read(kobj, attr, buf, PF_AUTOBOOT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) * pdcs_autosearch_read - Stable Storage autoboot flag output.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) * @buf: The output buffer to write to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) static ssize_t pdcs_autosearch_read(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) struct kobj_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) return pdcs_auto_read(kobj, attr, buf, PF_AUTOSEARCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) * pdcs_timer_read - Stable Storage timer count output (in seconds).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) * @buf: The output buffer to write to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) * The value of the timer field correponds to a number of seconds in powers of 2.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) static ssize_t pdcs_timer_read(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) struct kobj_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) char *out = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) struct pdcspath_entry *pathentry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) /* Current flags are stored in primary boot path entry */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) pathentry = &pdcspath_entry_primary;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) /* print the timer value in seconds */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) read_lock(&pathentry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) out += sprintf(out, "%u\n", (pathentry->devpath.flags & PF_TIMER) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) (1 << (pathentry->devpath.flags & PF_TIMER)) : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) read_unlock(&pathentry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) return out - buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) * pdcs_osid_read - Stable Storage OS ID register output.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) * @buf: The output buffer to write to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) static ssize_t pdcs_osid_read(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) struct kobj_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) char *out = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) out += sprintf(out, "%s dependent data (0x%.4x)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) os_id_to_string(pdcs_osid), pdcs_osid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) return out - buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) * pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) * @buf: The output buffer to write to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) * This can hold 16 bytes of OS-Dependent data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) static ssize_t pdcs_osdep1_read(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) struct kobj_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) char *out = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) u32 result[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) out += sprintf(out, "0x%.8x\n", result[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) out += sprintf(out, "0x%.8x\n", result[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) out += sprintf(out, "0x%.8x\n", result[2]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) out += sprintf(out, "0x%.8x\n", result[3]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) return out - buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) * pdcs_diagnostic_read - Stable Storage Diagnostic register output.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) * @buf: The output buffer to write to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) * I have NFC how to interpret the content of that register ;-).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) static ssize_t pdcs_diagnostic_read(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) struct kobj_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) char *out = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) u32 result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) /* get diagnostic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) if (pdc_stable_read(PDCS_ADDR_DIAG, &result, sizeof(result)) != PDC_OK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) out += sprintf(out, "0x%.4x\n", (result >> 16));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) return out - buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) * pdcs_fastsize_read - Stable Storage FastSize register output.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) * @buf: The output buffer to write to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) * This register holds the amount of system RAM to be tested during boot sequence.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) static ssize_t pdcs_fastsize_read(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) struct kobj_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) char *out = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) u32 result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) /* get fast-size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) if (pdc_stable_read(PDCS_ADDR_FSIZ, &result, sizeof(result)) != PDC_OK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) if ((result & 0x0F) < 0x0E)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) out += sprintf(out, "%d kB", (1<<(result & 0x0F))*256);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) out += sprintf(out, "All");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) out += sprintf(out, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) return out - buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) * pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) * @buf: The output buffer to write to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) * This can hold pdcs_size - 224 bytes of OS-Dependent data, when available.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) static ssize_t pdcs_osdep2_read(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) struct kobj_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) char *out = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) unsigned long size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) unsigned short i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) u32 result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) if (unlikely(pdcs_size <= 224))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) return -ENODATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) size = pdcs_size - 224;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) for (i=0; i<size; i+=4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) if (unlikely(pdc_stable_read(PDCS_ADDR_OSD2 + i, &result,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) sizeof(result)) != PDC_OK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) out += sprintf(out, "0x%.8x\n", result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) return out - buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) * pdcs_auto_write - This function handles autoboot/search flag modifying.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) * @buf: The input buffer to read from.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) * @count: The number of bytes to be read.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) * We will call this function to change the current autoboot flag.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) * We expect a precise syntax:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) * \"n\" (n == 0 or 1) to toggle AutoBoot Off or On
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) static ssize_t pdcs_auto_write(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) struct kobj_attribute *attr, const char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) size_t count, int knob)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) struct pdcspath_entry *pathentry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) unsigned char flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) char in[8], *temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) char c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) if (!capable(CAP_SYS_ADMIN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) return -EACCES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) if (!buf || !count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) /* We'll use a local copy of buf */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) count = min_t(size_t, count, sizeof(in)-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) strncpy(in, buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) in[count] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) /* Current flags are stored in primary boot path entry */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) pathentry = &pdcspath_entry_primary;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) /* Be nice to the existing flag record */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) read_lock(&pathentry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) flags = pathentry->devpath.flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) read_unlock(&pathentry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) DPRINTK("%s: flags before: 0x%X\n", __func__, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) temp = skip_spaces(in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) c = *temp++ - '0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) if ((c != 0) && (c != 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) goto parse_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) if (c == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) flags &= ~knob;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) flags |= knob;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) DPRINTK("%s: flags after: 0x%X\n", __func__, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) /* So far so good, let's get in deep */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) write_lock(&pathentry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) /* Change the path entry flags first */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) pathentry->devpath.flags = flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) /* Now, dive in. Write back to the hardware */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) pdcspath_store(pathentry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) write_unlock(&pathentry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" to \"%s\"\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) (knob & PF_AUTOBOOT) ? "autoboot" : "autosearch",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) (flags & knob) ? "On" : "Off");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) parse_error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) printk(KERN_WARNING "%s: Parse error: expect \"n\" (n == 0 or 1)\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) * pdcs_autoboot_write - This function handles autoboot flag modifying.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) * @buf: The input buffer to read from.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) * @count: The number of bytes to be read.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) * We will call this function to change the current boot flags.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) * We expect a precise syntax:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) * \"n\" (n == 0 or 1) to toggle AutoSearch Off or On
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) static ssize_t pdcs_autoboot_write(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) return pdcs_auto_write(kobj, attr, buf, count, PF_AUTOBOOT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) * pdcs_autosearch_write - This function handles autosearch flag modifying.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) * @buf: The input buffer to read from.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) * @count: The number of bytes to be read.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) * We will call this function to change the current boot flags.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) * We expect a precise syntax:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) * \"n\" (n == 0 or 1) to toggle AutoSearch Off or On
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) static ssize_t pdcs_autosearch_write(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) return pdcs_auto_write(kobj, attr, buf, count, PF_AUTOSEARCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) * pdcs_osdep1_write - Stable Storage OS-Dependent data area 1 input.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) * @buf: The input buffer to read from.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) * @count: The number of bytes to be read.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) * This can store 16 bytes of OS-Dependent data. We use a byte-by-byte
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) * write approach. It's up to userspace to deal with it when constructing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) * its input buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) static ssize_t pdcs_osdep1_write(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) u8 in[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) if (!capable(CAP_SYS_ADMIN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) return -EACCES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) if (!buf || !count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) if (unlikely(pdcs_osid != OS_ID_LINUX))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) if (count > 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) /* We'll use a local copy of buf */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) memset(in, 0, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) memcpy(in, buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) if (pdc_stable_write(PDCS_ADDR_OSD1, &in, sizeof(in)) != PDC_OK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) * pdcs_osdep2_write - Stable Storage OS-Dependent data area 2 input.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) * @buf: The input buffer to read from.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) * @count: The number of bytes to be read.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) * This can store pdcs_size - 224 bytes of OS-Dependent data. We use a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) * byte-by-byte write approach. It's up to userspace to deal with it when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) * constructing its input buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) static ssize_t pdcs_osdep2_write(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) unsigned long size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) unsigned short i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) u8 in[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) if (!capable(CAP_SYS_ADMIN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) return -EACCES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) if (!buf || !count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) if (unlikely(pdcs_size <= 224))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) return -ENOSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) if (unlikely(pdcs_osid != OS_ID_LINUX))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) size = pdcs_size - 224;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) if (count > size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) /* We'll use a local copy of buf */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) for (i=0; i<count; i+=4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) memset(in, 0, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) memcpy(in, buf+i, (count-i < 4) ? count-i : 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) if (unlikely(pdc_stable_write(PDCS_ADDR_OSD2 + i, &in,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) sizeof(in)) != PDC_OK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) /* The remaining attributes. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) static PDCS_ATTR(size, 0444, pdcs_size_read, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) static PDCS_ATTR(autoboot, 0644, pdcs_autoboot_read, pdcs_autoboot_write);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) static PDCS_ATTR(autosearch, 0644, pdcs_autosearch_read, pdcs_autosearch_write);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) static PDCS_ATTR(timer, 0444, pdcs_timer_read, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) static PDCS_ATTR(osid, 0444, pdcs_osid_read, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) static PDCS_ATTR(osdep1, 0600, pdcs_osdep1_read, pdcs_osdep1_write);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) static PDCS_ATTR(diagnostic, 0400, pdcs_diagnostic_read, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) static PDCS_ATTR(fastsize, 0400, pdcs_fastsize_read, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) static PDCS_ATTR(osdep2, 0600, pdcs_osdep2_read, pdcs_osdep2_write);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) static struct attribute *pdcs_subsys_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) &pdcs_attr_size.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) &pdcs_attr_autoboot.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) &pdcs_attr_autosearch.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) &pdcs_attr_timer.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) &pdcs_attr_osid.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) &pdcs_attr_osdep1.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) &pdcs_attr_diagnostic.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) &pdcs_attr_fastsize.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) &pdcs_attr_osdep2.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) static const struct attribute_group pdcs_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) .attrs = pdcs_subsys_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) static struct kobject *stable_kobj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) static struct kset *paths_kset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) * pdcs_register_pathentries - Prepares path entries kobjects for sysfs usage.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) * It creates kobjects corresponding to each path entry with nice sysfs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) * links to the real device. This is where the magic takes place: when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) * registering the subsystem attributes during module init, each kobject hereby
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) * created will show in the sysfs tree as a folder containing files as defined
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) * by path_subsys_attr[].
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) static inline int __init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) pdcs_register_pathentries(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) unsigned short i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) struct pdcspath_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) /* Initialize the entries rw_lock before anything else */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) for (i = 0; (entry = pdcspath_entries[i]); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) rwlock_init(&entry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) for (i = 0; (entry = pdcspath_entries[i]); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) write_lock(&entry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) err = pdcspath_fetch(entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) write_unlock(&entry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) entry->kobj.kset = paths_kset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) err = kobject_init_and_add(&entry->kobj, &ktype_pdcspath, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) "%s", entry->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) kobject_put(&entry->kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) /* kobject is now registered */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) write_lock(&entry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) entry->ready = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) write_unlock(&entry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) /* Add a nice symlink to the real device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) if (entry->dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) err = sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) WARN_ON(err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) kobject_uevent(&entry->kobj, KOBJ_ADD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) * pdcs_unregister_pathentries - Routine called when unregistering the module.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) pdcs_unregister_pathentries(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) unsigned short i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) struct pdcspath_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) for (i = 0; (entry = pdcspath_entries[i]); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) read_lock(&entry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) if (entry->ready >= 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) kobject_put(&entry->kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) read_unlock(&entry->rw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) * For now we register the stable subsystem with the firmware subsystem
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) * and the paths subsystem with the stable subsystem
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) static int __init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) pdc_stable_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) int rc = 0, error = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) u32 result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) /* find the size of the stable storage */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) if (pdc_stable_get_size(&pdcs_size) != PDC_OK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) /* make sure we have enough data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) if (pdcs_size < 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) return -ENODATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) printk(KERN_INFO PDCS_PREFIX " facility v%s\n", PDCS_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) /* get OSID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) if (pdc_stable_read(PDCS_ADDR_OSID, &result, sizeof(result)) != PDC_OK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) /* the actual result is 16 bits away */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) pdcs_osid = (u16)(result >> 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) /* For now we'll register the directory at /sys/firmware/stable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) stable_kobj = kobject_create_and_add("stable", firmware_kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) if (!stable_kobj) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) goto fail_firmreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) /* Don't forget the root entries */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) error = sysfs_create_group(stable_kobj, &pdcs_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) /* register the paths kset as a child of the stable kset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) paths_kset = kset_create_and_add("paths", NULL, stable_kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) if (!paths_kset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) goto fail_ksetreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) /* now we create all "files" for the paths kset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) if ((rc = pdcs_register_pathentries()))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) goto fail_pdcsreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) fail_pdcsreg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) pdcs_unregister_pathentries();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) kset_unregister(paths_kset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) fail_ksetreg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) kobject_put(stable_kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) fail_firmreg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) printk(KERN_INFO PDCS_PREFIX " bailing out\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) static void __exit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) pdc_stable_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) pdcs_unregister_pathentries();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) kset_unregister(paths_kset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) kobject_put(stable_kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) module_init(pdc_stable_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) module_exit(pdc_stable_exit);