Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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);