166aec647SPeter Oberparleiter // SPDX-License-Identifier: GPL-2.0 266aec647SPeter Oberparleiter /* 366aec647SPeter Oberparleiter * SCLP Store Data support and sysfs interface 466aec647SPeter Oberparleiter * 566aec647SPeter Oberparleiter * Copyright IBM Corp. 2017 666aec647SPeter Oberparleiter */ 766aec647SPeter Oberparleiter 866aec647SPeter Oberparleiter #define KMSG_COMPONENT "sclp_sd" 966aec647SPeter Oberparleiter #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 1066aec647SPeter Oberparleiter 1166aec647SPeter Oberparleiter #include <linux/completion.h> 1266aec647SPeter Oberparleiter #include <linux/kobject.h> 1366aec647SPeter Oberparleiter #include <linux/list.h> 1466aec647SPeter Oberparleiter #include <linux/printk.h> 1566aec647SPeter Oberparleiter #include <linux/slab.h> 1666aec647SPeter Oberparleiter #include <linux/vmalloc.h> 1766aec647SPeter Oberparleiter #include <linux/async.h> 1866aec647SPeter Oberparleiter #include <linux/export.h> 1966aec647SPeter Oberparleiter #include <linux/mutex.h> 2066aec647SPeter Oberparleiter 2166aec647SPeter Oberparleiter #include <asm/pgalloc.h> 2266aec647SPeter Oberparleiter 2366aec647SPeter Oberparleiter #include "sclp.h" 2466aec647SPeter Oberparleiter 2566aec647SPeter Oberparleiter #define SD_EQ_STORE_DATA 0 2666aec647SPeter Oberparleiter #define SD_EQ_HALT 1 2766aec647SPeter Oberparleiter #define SD_EQ_SIZE 2 2866aec647SPeter Oberparleiter 2966aec647SPeter Oberparleiter #define SD_DI_CONFIG 3 3066aec647SPeter Oberparleiter 3166aec647SPeter Oberparleiter struct sclp_sd_evbuf { 3266aec647SPeter Oberparleiter struct evbuf_header hdr; 3366aec647SPeter Oberparleiter u8 eq; 3466aec647SPeter Oberparleiter u8 di; 3566aec647SPeter Oberparleiter u8 rflags; 3666aec647SPeter Oberparleiter u64 :56; 3766aec647SPeter Oberparleiter u32 id; 3866aec647SPeter Oberparleiter u16 :16; 3966aec647SPeter Oberparleiter u8 fmt; 4066aec647SPeter Oberparleiter u8 status; 4166aec647SPeter Oberparleiter u64 sat; 4266aec647SPeter Oberparleiter u64 sa; 4366aec647SPeter Oberparleiter u32 esize; 4466aec647SPeter Oberparleiter u32 dsize; 4566aec647SPeter Oberparleiter } __packed; 4666aec647SPeter Oberparleiter 4766aec647SPeter Oberparleiter struct sclp_sd_sccb { 4866aec647SPeter Oberparleiter struct sccb_header hdr; 4966aec647SPeter Oberparleiter struct sclp_sd_evbuf evbuf; 5066aec647SPeter Oberparleiter } __packed __aligned(PAGE_SIZE); 5166aec647SPeter Oberparleiter 5266aec647SPeter Oberparleiter /** 5366aec647SPeter Oberparleiter * struct sclp_sd_data - Result of a Store Data request 5466aec647SPeter Oberparleiter * @esize_bytes: Resulting esize in bytes 5566aec647SPeter Oberparleiter * @dsize_bytes: Resulting dsize in bytes 5666aec647SPeter Oberparleiter * @data: Pointer to data - must be released using vfree() 5766aec647SPeter Oberparleiter */ 5866aec647SPeter Oberparleiter struct sclp_sd_data { 5966aec647SPeter Oberparleiter size_t esize_bytes; 6066aec647SPeter Oberparleiter size_t dsize_bytes; 6166aec647SPeter Oberparleiter void *data; 6266aec647SPeter Oberparleiter }; 6366aec647SPeter Oberparleiter 6466aec647SPeter Oberparleiter /** 6566aec647SPeter Oberparleiter * struct sclp_sd_listener - Listener for asynchronous Store Data response 6666aec647SPeter Oberparleiter * @list: For enqueueing this struct 6766aec647SPeter Oberparleiter * @id: Event ID of response to listen for 6866aec647SPeter Oberparleiter * @completion: Can be used to wait for response 6966aec647SPeter Oberparleiter * @evbuf: Contains the resulting Store Data response after completion 7066aec647SPeter Oberparleiter */ 7166aec647SPeter Oberparleiter struct sclp_sd_listener { 7266aec647SPeter Oberparleiter struct list_head list; 7366aec647SPeter Oberparleiter u32 id; 7466aec647SPeter Oberparleiter struct completion completion; 7566aec647SPeter Oberparleiter struct sclp_sd_evbuf evbuf; 7666aec647SPeter Oberparleiter }; 7766aec647SPeter Oberparleiter 7866aec647SPeter Oberparleiter /** 7966aec647SPeter Oberparleiter * struct sclp_sd_file - Sysfs representation of a Store Data entity 8066aec647SPeter Oberparleiter * @kobj: Kobject 8166aec647SPeter Oberparleiter * @data_attr: Attribute for accessing data contents 8266aec647SPeter Oberparleiter * @data_mutex: Mutex to serialize access and updates to @data 8366aec647SPeter Oberparleiter * @data: Data associated with this entity 8466aec647SPeter Oberparleiter * @di: DI value associated with this entity 8566aec647SPeter Oberparleiter */ 8666aec647SPeter Oberparleiter struct sclp_sd_file { 8766aec647SPeter Oberparleiter struct kobject kobj; 8866aec647SPeter Oberparleiter struct bin_attribute data_attr; 8966aec647SPeter Oberparleiter struct mutex data_mutex; 9066aec647SPeter Oberparleiter struct sclp_sd_data data; 9166aec647SPeter Oberparleiter u8 di; 9266aec647SPeter Oberparleiter }; 9366aec647SPeter Oberparleiter #define to_sd_file(x) container_of(x, struct sclp_sd_file, kobj) 9466aec647SPeter Oberparleiter 9566aec647SPeter Oberparleiter static struct kset *sclp_sd_kset; 9666aec647SPeter Oberparleiter static struct sclp_sd_file *config_file; 9766aec647SPeter Oberparleiter 9866aec647SPeter Oberparleiter static LIST_HEAD(sclp_sd_queue); 9966aec647SPeter Oberparleiter static DEFINE_SPINLOCK(sclp_sd_queue_lock); 10066aec647SPeter Oberparleiter 10166aec647SPeter Oberparleiter /** 10266aec647SPeter Oberparleiter * sclp_sd_listener_add() - Add listener for Store Data responses 10366aec647SPeter Oberparleiter * @listener: Listener to add 10466aec647SPeter Oberparleiter */ 10566aec647SPeter Oberparleiter static void sclp_sd_listener_add(struct sclp_sd_listener *listener) 10666aec647SPeter Oberparleiter { 10766aec647SPeter Oberparleiter spin_lock_irq(&sclp_sd_queue_lock); 10866aec647SPeter Oberparleiter list_add_tail(&listener->list, &sclp_sd_queue); 10966aec647SPeter Oberparleiter spin_unlock_irq(&sclp_sd_queue_lock); 11066aec647SPeter Oberparleiter } 11166aec647SPeter Oberparleiter 11266aec647SPeter Oberparleiter /** 11366aec647SPeter Oberparleiter * sclp_sd_listener_remove() - Remove listener for Store Data responses 11466aec647SPeter Oberparleiter * @listener: Listener to remove 11566aec647SPeter Oberparleiter */ 11666aec647SPeter Oberparleiter static void sclp_sd_listener_remove(struct sclp_sd_listener *listener) 11766aec647SPeter Oberparleiter { 11866aec647SPeter Oberparleiter spin_lock_irq(&sclp_sd_queue_lock); 11966aec647SPeter Oberparleiter list_del(&listener->list); 12066aec647SPeter Oberparleiter spin_unlock_irq(&sclp_sd_queue_lock); 12166aec647SPeter Oberparleiter } 12266aec647SPeter Oberparleiter 12366aec647SPeter Oberparleiter /** 12466aec647SPeter Oberparleiter * sclp_sd_listener_init() - Initialize a Store Data response listener 12566aec647SPeter Oberparleiter * @id: Event ID to listen for 12666aec647SPeter Oberparleiter * 12766aec647SPeter Oberparleiter * Initialize a listener for asynchronous Store Data responses. This listener 12866aec647SPeter Oberparleiter * can afterwards be used to wait for a specific response and to retrieve 12966aec647SPeter Oberparleiter * the associated response data. 13066aec647SPeter Oberparleiter */ 13166aec647SPeter Oberparleiter static void sclp_sd_listener_init(struct sclp_sd_listener *listener, u32 id) 13266aec647SPeter Oberparleiter { 13366aec647SPeter Oberparleiter memset(listener, 0, sizeof(*listener)); 13466aec647SPeter Oberparleiter listener->id = id; 13566aec647SPeter Oberparleiter init_completion(&listener->completion); 13666aec647SPeter Oberparleiter } 13766aec647SPeter Oberparleiter 13866aec647SPeter Oberparleiter /** 13966aec647SPeter Oberparleiter * sclp_sd_receiver() - Receiver for Store Data events 14066aec647SPeter Oberparleiter * @evbuf_hdr: Header of received events 14166aec647SPeter Oberparleiter * 14266aec647SPeter Oberparleiter * Process Store Data events and complete listeners with matching event IDs. 14366aec647SPeter Oberparleiter */ 14466aec647SPeter Oberparleiter static void sclp_sd_receiver(struct evbuf_header *evbuf_hdr) 14566aec647SPeter Oberparleiter { 14666aec647SPeter Oberparleiter struct sclp_sd_evbuf *evbuf = (struct sclp_sd_evbuf *) evbuf_hdr; 14766aec647SPeter Oberparleiter struct sclp_sd_listener *listener; 14866aec647SPeter Oberparleiter int found = 0; 14966aec647SPeter Oberparleiter 15066aec647SPeter Oberparleiter pr_debug("received event (id=0x%08x)\n", evbuf->id); 15166aec647SPeter Oberparleiter spin_lock(&sclp_sd_queue_lock); 15266aec647SPeter Oberparleiter list_for_each_entry(listener, &sclp_sd_queue, list) { 15366aec647SPeter Oberparleiter if (listener->id != evbuf->id) 15466aec647SPeter Oberparleiter continue; 15566aec647SPeter Oberparleiter 15666aec647SPeter Oberparleiter listener->evbuf = *evbuf; 15766aec647SPeter Oberparleiter complete(&listener->completion); 15866aec647SPeter Oberparleiter found = 1; 15966aec647SPeter Oberparleiter break; 16066aec647SPeter Oberparleiter } 16166aec647SPeter Oberparleiter spin_unlock(&sclp_sd_queue_lock); 16266aec647SPeter Oberparleiter 16366aec647SPeter Oberparleiter if (!found) 16466aec647SPeter Oberparleiter pr_debug("unsolicited event (id=0x%08x)\n", evbuf->id); 16566aec647SPeter Oberparleiter } 16666aec647SPeter Oberparleiter 16766aec647SPeter Oberparleiter static struct sclp_register sclp_sd_register = { 16866aec647SPeter Oberparleiter .send_mask = EVTYP_STORE_DATA_MASK, 16966aec647SPeter Oberparleiter .receive_mask = EVTYP_STORE_DATA_MASK, 17066aec647SPeter Oberparleiter .receiver_fn = sclp_sd_receiver, 17166aec647SPeter Oberparleiter }; 17266aec647SPeter Oberparleiter 17366aec647SPeter Oberparleiter /** 17466aec647SPeter Oberparleiter * sclp_sd_sync() - Perform Store Data request synchronously 17566aec647SPeter Oberparleiter * @page: Address of work page - must be below 2GB 17666aec647SPeter Oberparleiter * @eq: Input EQ value 17766aec647SPeter Oberparleiter * @di: Input DI value 17866aec647SPeter Oberparleiter * @sat: Input SAT value 17966aec647SPeter Oberparleiter * @sa: Input SA value used to specify the address of the target buffer 18066aec647SPeter Oberparleiter * @dsize_ptr: Optional pointer to input and output DSIZE value 18166aec647SPeter Oberparleiter * @esize_ptr: Optional pointer to output ESIZE value 18266aec647SPeter Oberparleiter * 18366aec647SPeter Oberparleiter * Perform Store Data request with specified parameters and wait for completion. 18466aec647SPeter Oberparleiter * 18566aec647SPeter Oberparleiter * Return %0 on success and store resulting DSIZE and ESIZE values in 18666aec647SPeter Oberparleiter * @dsize_ptr and @esize_ptr (if provided). Return non-zero on error. 18766aec647SPeter Oberparleiter */ 18866aec647SPeter Oberparleiter static int sclp_sd_sync(unsigned long page, u8 eq, u8 di, u64 sat, u64 sa, 18966aec647SPeter Oberparleiter u32 *dsize_ptr, u32 *esize_ptr) 19066aec647SPeter Oberparleiter { 19166aec647SPeter Oberparleiter struct sclp_sd_sccb *sccb = (void *) page; 19266aec647SPeter Oberparleiter struct sclp_sd_listener listener; 19366aec647SPeter Oberparleiter struct sclp_sd_evbuf *evbuf; 19466aec647SPeter Oberparleiter int rc; 19566aec647SPeter Oberparleiter 19666aec647SPeter Oberparleiter sclp_sd_listener_init(&listener, (u32) (addr_t) sccb); 19766aec647SPeter Oberparleiter sclp_sd_listener_add(&listener); 19866aec647SPeter Oberparleiter 19966aec647SPeter Oberparleiter /* Prepare SCCB */ 20066aec647SPeter Oberparleiter memset(sccb, 0, PAGE_SIZE); 20166aec647SPeter Oberparleiter sccb->hdr.length = sizeof(sccb->hdr) + sizeof(sccb->evbuf); 20266aec647SPeter Oberparleiter evbuf = &sccb->evbuf; 20366aec647SPeter Oberparleiter evbuf->hdr.length = sizeof(*evbuf); 20466aec647SPeter Oberparleiter evbuf->hdr.type = EVTYP_STORE_DATA; 20566aec647SPeter Oberparleiter evbuf->eq = eq; 20666aec647SPeter Oberparleiter evbuf->di = di; 20766aec647SPeter Oberparleiter evbuf->id = listener.id; 20866aec647SPeter Oberparleiter evbuf->fmt = 1; 20966aec647SPeter Oberparleiter evbuf->sat = sat; 21066aec647SPeter Oberparleiter evbuf->sa = sa; 21166aec647SPeter Oberparleiter if (dsize_ptr) 21266aec647SPeter Oberparleiter evbuf->dsize = *dsize_ptr; 21366aec647SPeter Oberparleiter 21466aec647SPeter Oberparleiter /* Perform command */ 21566aec647SPeter Oberparleiter pr_debug("request (eq=%d, di=%d, id=0x%08x)\n", eq, di, listener.id); 21666aec647SPeter Oberparleiter rc = sclp_sync_request(SCLP_CMDW_WRITE_EVENT_DATA, sccb); 21766aec647SPeter Oberparleiter pr_debug("request done (rc=%d)\n", rc); 21866aec647SPeter Oberparleiter if (rc) 21966aec647SPeter Oberparleiter goto out; 22066aec647SPeter Oberparleiter 22166aec647SPeter Oberparleiter /* Evaluate response */ 22266aec647SPeter Oberparleiter if (sccb->hdr.response_code == 0x73f0) { 22366aec647SPeter Oberparleiter pr_debug("event not supported\n"); 22466aec647SPeter Oberparleiter rc = -EIO; 22566aec647SPeter Oberparleiter goto out_remove; 22666aec647SPeter Oberparleiter } 22766aec647SPeter Oberparleiter if (sccb->hdr.response_code != 0x0020 || !(evbuf->hdr.flags & 0x80)) { 22866aec647SPeter Oberparleiter rc = -EIO; 22966aec647SPeter Oberparleiter goto out; 23066aec647SPeter Oberparleiter } 23166aec647SPeter Oberparleiter if (!(evbuf->rflags & 0x80)) { 23266aec647SPeter Oberparleiter rc = wait_for_completion_interruptible(&listener.completion); 23366aec647SPeter Oberparleiter if (rc) 23466aec647SPeter Oberparleiter goto out; 23566aec647SPeter Oberparleiter evbuf = &listener.evbuf; 23666aec647SPeter Oberparleiter } 23766aec647SPeter Oberparleiter switch (evbuf->status) { 23866aec647SPeter Oberparleiter case 0: 23966aec647SPeter Oberparleiter if (dsize_ptr) 24066aec647SPeter Oberparleiter *dsize_ptr = evbuf->dsize; 24166aec647SPeter Oberparleiter if (esize_ptr) 24266aec647SPeter Oberparleiter *esize_ptr = evbuf->esize; 24366aec647SPeter Oberparleiter pr_debug("success (dsize=%u, esize=%u)\n", evbuf->dsize, 24466aec647SPeter Oberparleiter evbuf->esize); 24566aec647SPeter Oberparleiter break; 24666aec647SPeter Oberparleiter case 3: 24766aec647SPeter Oberparleiter rc = -ENOENT; 24866aec647SPeter Oberparleiter break; 24966aec647SPeter Oberparleiter default: 25066aec647SPeter Oberparleiter rc = -EIO; 25166aec647SPeter Oberparleiter break; 25266aec647SPeter Oberparleiter 25366aec647SPeter Oberparleiter } 25466aec647SPeter Oberparleiter 25566aec647SPeter Oberparleiter out: 25666aec647SPeter Oberparleiter if (rc && rc != -ENOENT) { 25766aec647SPeter Oberparleiter /* Provide some information about what went wrong */ 25866aec647SPeter Oberparleiter pr_warn("Store Data request failed (eq=%d, di=%d, " 25966aec647SPeter Oberparleiter "response=0x%04x, flags=0x%02x, status=%d, rc=%d)\n", 26066aec647SPeter Oberparleiter eq, di, sccb->hdr.response_code, evbuf->hdr.flags, 26166aec647SPeter Oberparleiter evbuf->status, rc); 26266aec647SPeter Oberparleiter } 26366aec647SPeter Oberparleiter 26466aec647SPeter Oberparleiter out_remove: 26566aec647SPeter Oberparleiter sclp_sd_listener_remove(&listener); 26666aec647SPeter Oberparleiter 26766aec647SPeter Oberparleiter return rc; 26866aec647SPeter Oberparleiter } 26966aec647SPeter Oberparleiter 27066aec647SPeter Oberparleiter /** 27166aec647SPeter Oberparleiter * sclp_sd_store_data() - Obtain data for specified Store Data entity 27266aec647SPeter Oberparleiter * @result: Resulting data 27366aec647SPeter Oberparleiter * @di: DI value associated with this entity 27466aec647SPeter Oberparleiter * 27566aec647SPeter Oberparleiter * Perform a series of Store Data requests to obtain the size and contents of 27666aec647SPeter Oberparleiter * the specified Store Data entity. 27766aec647SPeter Oberparleiter * 27866aec647SPeter Oberparleiter * Return: 27966aec647SPeter Oberparleiter * %0: Success - result is stored in @result. @result->data must be 28066aec647SPeter Oberparleiter * released using vfree() after use. 28166aec647SPeter Oberparleiter * %-ENOENT: No data available for this entity 28266aec647SPeter Oberparleiter * %<0: Other error 28366aec647SPeter Oberparleiter */ 28466aec647SPeter Oberparleiter static int sclp_sd_store_data(struct sclp_sd_data *result, u8 di) 28566aec647SPeter Oberparleiter { 28666aec647SPeter Oberparleiter u32 dsize = 0, esize = 0; 28766aec647SPeter Oberparleiter unsigned long page, asce = 0; 28866aec647SPeter Oberparleiter void *data = NULL; 28966aec647SPeter Oberparleiter int rc; 29066aec647SPeter Oberparleiter 29166aec647SPeter Oberparleiter page = __get_free_page(GFP_KERNEL | GFP_DMA); 29266aec647SPeter Oberparleiter if (!page) 29366aec647SPeter Oberparleiter return -ENOMEM; 29466aec647SPeter Oberparleiter 29566aec647SPeter Oberparleiter /* Get size */ 29666aec647SPeter Oberparleiter rc = sclp_sd_sync(page, SD_EQ_SIZE, di, 0, 0, &dsize, &esize); 29766aec647SPeter Oberparleiter if (rc) 29866aec647SPeter Oberparleiter goto out; 29966aec647SPeter Oberparleiter if (dsize == 0) 30066aec647SPeter Oberparleiter goto out_result; 30166aec647SPeter Oberparleiter 30266aec647SPeter Oberparleiter /* Allocate memory */ 303*fad953ceSKees Cook data = vzalloc(array_size((size_t)dsize, PAGE_SIZE)); 30466aec647SPeter Oberparleiter if (!data) { 30566aec647SPeter Oberparleiter rc = -ENOMEM; 30666aec647SPeter Oberparleiter goto out; 30766aec647SPeter Oberparleiter } 30866aec647SPeter Oberparleiter 30966aec647SPeter Oberparleiter /* Get translation table for buffer */ 31066aec647SPeter Oberparleiter asce = base_asce_alloc((unsigned long) data, dsize); 31166aec647SPeter Oberparleiter if (!asce) { 31266aec647SPeter Oberparleiter vfree(data); 31366aec647SPeter Oberparleiter rc = -ENOMEM; 31466aec647SPeter Oberparleiter goto out; 31566aec647SPeter Oberparleiter } 31666aec647SPeter Oberparleiter 31766aec647SPeter Oberparleiter /* Get data */ 31866aec647SPeter Oberparleiter rc = sclp_sd_sync(page, SD_EQ_STORE_DATA, di, asce, (u64) data, &dsize, 31966aec647SPeter Oberparleiter &esize); 32066aec647SPeter Oberparleiter if (rc) { 32166aec647SPeter Oberparleiter /* Cancel running request if interrupted */ 32266aec647SPeter Oberparleiter if (rc == -ERESTARTSYS) 32366aec647SPeter Oberparleiter sclp_sd_sync(page, SD_EQ_HALT, di, 0, 0, NULL, NULL); 32466aec647SPeter Oberparleiter vfree(data); 32566aec647SPeter Oberparleiter goto out; 32666aec647SPeter Oberparleiter } 32766aec647SPeter Oberparleiter 32866aec647SPeter Oberparleiter out_result: 32966aec647SPeter Oberparleiter result->esize_bytes = (size_t) esize * PAGE_SIZE; 33066aec647SPeter Oberparleiter result->dsize_bytes = (size_t) dsize * PAGE_SIZE; 33166aec647SPeter Oberparleiter result->data = data; 33266aec647SPeter Oberparleiter 33366aec647SPeter Oberparleiter out: 33466aec647SPeter Oberparleiter base_asce_free(asce); 33566aec647SPeter Oberparleiter free_page(page); 33666aec647SPeter Oberparleiter 33766aec647SPeter Oberparleiter return rc; 33866aec647SPeter Oberparleiter } 33966aec647SPeter Oberparleiter 34066aec647SPeter Oberparleiter /** 34166aec647SPeter Oberparleiter * sclp_sd_data_reset() - Reset Store Data result buffer 34266aec647SPeter Oberparleiter * @data: Data buffer to reset 34366aec647SPeter Oberparleiter * 34466aec647SPeter Oberparleiter * Reset @data to initial state and release associated memory. 34566aec647SPeter Oberparleiter */ 34666aec647SPeter Oberparleiter static void sclp_sd_data_reset(struct sclp_sd_data *data) 34766aec647SPeter Oberparleiter { 34866aec647SPeter Oberparleiter vfree(data->data); 34966aec647SPeter Oberparleiter data->data = NULL; 35066aec647SPeter Oberparleiter data->dsize_bytes = 0; 35166aec647SPeter Oberparleiter data->esize_bytes = 0; 35266aec647SPeter Oberparleiter } 35366aec647SPeter Oberparleiter 35466aec647SPeter Oberparleiter /** 35566aec647SPeter Oberparleiter * sclp_sd_file_release() - Release function for sclp_sd_file object 35666aec647SPeter Oberparleiter * @kobj: Kobject embedded in sclp_sd_file object 35766aec647SPeter Oberparleiter */ 35866aec647SPeter Oberparleiter static void sclp_sd_file_release(struct kobject *kobj) 35966aec647SPeter Oberparleiter { 36066aec647SPeter Oberparleiter struct sclp_sd_file *sd_file = to_sd_file(kobj); 36166aec647SPeter Oberparleiter 36266aec647SPeter Oberparleiter sclp_sd_data_reset(&sd_file->data); 36366aec647SPeter Oberparleiter kfree(sd_file); 36466aec647SPeter Oberparleiter } 36566aec647SPeter Oberparleiter 36666aec647SPeter Oberparleiter /** 36766aec647SPeter Oberparleiter * sclp_sd_file_update() - Update contents of sclp_sd_file object 36866aec647SPeter Oberparleiter * @sd_file: Object to update 36966aec647SPeter Oberparleiter * 37066aec647SPeter Oberparleiter * Obtain the current version of data associated with the Store Data entity 37166aec647SPeter Oberparleiter * @sd_file. 37266aec647SPeter Oberparleiter * 37366aec647SPeter Oberparleiter * On success, return %0 and generate a KOBJ_CHANGE event to indicate that the 37466aec647SPeter Oberparleiter * data may have changed. Return non-zero otherwise. 37566aec647SPeter Oberparleiter */ 37666aec647SPeter Oberparleiter static int sclp_sd_file_update(struct sclp_sd_file *sd_file) 37766aec647SPeter Oberparleiter { 37866aec647SPeter Oberparleiter const char *name = kobject_name(&sd_file->kobj); 37966aec647SPeter Oberparleiter struct sclp_sd_data data; 38066aec647SPeter Oberparleiter int rc; 38166aec647SPeter Oberparleiter 38266aec647SPeter Oberparleiter rc = sclp_sd_store_data(&data, sd_file->di); 38366aec647SPeter Oberparleiter if (rc) { 38466aec647SPeter Oberparleiter if (rc == -ENOENT) { 38566aec647SPeter Oberparleiter pr_info("No data is available for the %s data entity\n", 38666aec647SPeter Oberparleiter name); 38766aec647SPeter Oberparleiter } 38866aec647SPeter Oberparleiter return rc; 38966aec647SPeter Oberparleiter } 39066aec647SPeter Oberparleiter 39166aec647SPeter Oberparleiter mutex_lock(&sd_file->data_mutex); 39266aec647SPeter Oberparleiter sclp_sd_data_reset(&sd_file->data); 39366aec647SPeter Oberparleiter sd_file->data = data; 39466aec647SPeter Oberparleiter mutex_unlock(&sd_file->data_mutex); 39566aec647SPeter Oberparleiter 39666aec647SPeter Oberparleiter pr_info("A %zu-byte %s data entity was retrieved\n", data.dsize_bytes, 39766aec647SPeter Oberparleiter name); 39866aec647SPeter Oberparleiter kobject_uevent(&sd_file->kobj, KOBJ_CHANGE); 39966aec647SPeter Oberparleiter 40066aec647SPeter Oberparleiter return 0; 40166aec647SPeter Oberparleiter } 40266aec647SPeter Oberparleiter 40366aec647SPeter Oberparleiter /** 40466aec647SPeter Oberparleiter * sclp_sd_file_update_async() - Wrapper for asynchronous update call 40566aec647SPeter Oberparleiter * @data: Object to update 40666aec647SPeter Oberparleiter */ 40766aec647SPeter Oberparleiter static void sclp_sd_file_update_async(void *data, async_cookie_t cookie) 40866aec647SPeter Oberparleiter { 40966aec647SPeter Oberparleiter struct sclp_sd_file *sd_file = data; 41066aec647SPeter Oberparleiter 41166aec647SPeter Oberparleiter sclp_sd_file_update(sd_file); 41266aec647SPeter Oberparleiter } 41366aec647SPeter Oberparleiter 41466aec647SPeter Oberparleiter /** 41566aec647SPeter Oberparleiter * reload_store() - Store function for "reload" sysfs attribute 41666aec647SPeter Oberparleiter * @kobj: Kobject of sclp_sd_file object 41766aec647SPeter Oberparleiter * 41866aec647SPeter Oberparleiter * Initiate a reload of the data associated with an sclp_sd_file object. 41966aec647SPeter Oberparleiter */ 42066aec647SPeter Oberparleiter static ssize_t reload_store(struct kobject *kobj, struct kobj_attribute *attr, 42166aec647SPeter Oberparleiter const char *buf, size_t count) 42266aec647SPeter Oberparleiter { 42366aec647SPeter Oberparleiter struct sclp_sd_file *sd_file = to_sd_file(kobj); 42466aec647SPeter Oberparleiter 42566aec647SPeter Oberparleiter sclp_sd_file_update(sd_file); 42666aec647SPeter Oberparleiter 42766aec647SPeter Oberparleiter return count; 42866aec647SPeter Oberparleiter } 42966aec647SPeter Oberparleiter 43066aec647SPeter Oberparleiter static struct kobj_attribute reload_attr = __ATTR_WO(reload); 43166aec647SPeter Oberparleiter 43266aec647SPeter Oberparleiter static struct attribute *sclp_sd_file_default_attrs[] = { 43366aec647SPeter Oberparleiter &reload_attr.attr, 43466aec647SPeter Oberparleiter NULL, 43566aec647SPeter Oberparleiter }; 43666aec647SPeter Oberparleiter 43766aec647SPeter Oberparleiter static struct kobj_type sclp_sd_file_ktype = { 43866aec647SPeter Oberparleiter .sysfs_ops = &kobj_sysfs_ops, 43966aec647SPeter Oberparleiter .release = sclp_sd_file_release, 44066aec647SPeter Oberparleiter .default_attrs = sclp_sd_file_default_attrs, 44166aec647SPeter Oberparleiter }; 44266aec647SPeter Oberparleiter 44366aec647SPeter Oberparleiter /** 44466aec647SPeter Oberparleiter * data_read() - Read function for "read" sysfs attribute 44566aec647SPeter Oberparleiter * @kobj: Kobject of sclp_sd_file object 44666aec647SPeter Oberparleiter * @buffer: Target buffer 44766aec647SPeter Oberparleiter * @off: Requested file offset 44866aec647SPeter Oberparleiter * @size: Requested number of bytes 44966aec647SPeter Oberparleiter * 45066aec647SPeter Oberparleiter * Store the requested portion of the Store Data entity contents into the 45166aec647SPeter Oberparleiter * specified buffer. Return the number of bytes stored on success, or %0 45266aec647SPeter Oberparleiter * on EOF. 45366aec647SPeter Oberparleiter */ 45466aec647SPeter Oberparleiter static ssize_t data_read(struct file *file, struct kobject *kobj, 45566aec647SPeter Oberparleiter struct bin_attribute *attr, char *buffer, 45666aec647SPeter Oberparleiter loff_t off, size_t size) 45766aec647SPeter Oberparleiter { 45866aec647SPeter Oberparleiter struct sclp_sd_file *sd_file = to_sd_file(kobj); 45966aec647SPeter Oberparleiter size_t data_size; 46066aec647SPeter Oberparleiter char *data; 46166aec647SPeter Oberparleiter 46266aec647SPeter Oberparleiter mutex_lock(&sd_file->data_mutex); 46366aec647SPeter Oberparleiter 46466aec647SPeter Oberparleiter data = sd_file->data.data; 46566aec647SPeter Oberparleiter data_size = sd_file->data.dsize_bytes; 46666aec647SPeter Oberparleiter if (!data || off >= data_size) { 46766aec647SPeter Oberparleiter size = 0; 46866aec647SPeter Oberparleiter } else { 46966aec647SPeter Oberparleiter if (off + size > data_size) 47066aec647SPeter Oberparleiter size = data_size - off; 47166aec647SPeter Oberparleiter memcpy(buffer, data + off, size); 47266aec647SPeter Oberparleiter } 47366aec647SPeter Oberparleiter 47466aec647SPeter Oberparleiter mutex_unlock(&sd_file->data_mutex); 47566aec647SPeter Oberparleiter 47666aec647SPeter Oberparleiter return size; 47766aec647SPeter Oberparleiter } 47866aec647SPeter Oberparleiter 47966aec647SPeter Oberparleiter /** 48066aec647SPeter Oberparleiter * sclp_sd_file_create() - Add a sysfs file representing a Store Data entity 48166aec647SPeter Oberparleiter * @name: Name of file 48266aec647SPeter Oberparleiter * @di: DI value associated with this entity 48366aec647SPeter Oberparleiter * 48466aec647SPeter Oberparleiter * Create a sysfs directory with the given @name located under 48566aec647SPeter Oberparleiter * 48666aec647SPeter Oberparleiter * /sys/firmware/sclp_sd/ 48766aec647SPeter Oberparleiter * 48866aec647SPeter Oberparleiter * The files in this directory can be used to access the contents of the Store 48966aec647SPeter Oberparleiter * Data entity associated with @DI. 49066aec647SPeter Oberparleiter * 49166aec647SPeter Oberparleiter * Return pointer to resulting sclp_sd_file object on success, %NULL otherwise. 49266aec647SPeter Oberparleiter * The object must be freed by calling kobject_put() on the embedded kobject 49366aec647SPeter Oberparleiter * pointer after use. 49466aec647SPeter Oberparleiter */ 49566aec647SPeter Oberparleiter static __init struct sclp_sd_file *sclp_sd_file_create(const char *name, u8 di) 49666aec647SPeter Oberparleiter { 49766aec647SPeter Oberparleiter struct sclp_sd_file *sd_file; 49866aec647SPeter Oberparleiter int rc; 49966aec647SPeter Oberparleiter 50066aec647SPeter Oberparleiter sd_file = kzalloc(sizeof(*sd_file), GFP_KERNEL); 50166aec647SPeter Oberparleiter if (!sd_file) 50266aec647SPeter Oberparleiter return NULL; 50366aec647SPeter Oberparleiter sd_file->di = di; 50466aec647SPeter Oberparleiter mutex_init(&sd_file->data_mutex); 50566aec647SPeter Oberparleiter 50666aec647SPeter Oberparleiter /* Create kobject located under /sys/firmware/sclp_sd/ */ 50766aec647SPeter Oberparleiter sd_file->kobj.kset = sclp_sd_kset; 50866aec647SPeter Oberparleiter rc = kobject_init_and_add(&sd_file->kobj, &sclp_sd_file_ktype, NULL, 50966aec647SPeter Oberparleiter "%s", name); 51066aec647SPeter Oberparleiter if (rc) { 51166aec647SPeter Oberparleiter kobject_put(&sd_file->kobj); 51266aec647SPeter Oberparleiter return NULL; 51366aec647SPeter Oberparleiter } 51466aec647SPeter Oberparleiter 51566aec647SPeter Oberparleiter sysfs_bin_attr_init(&sd_file->data_attr); 51666aec647SPeter Oberparleiter sd_file->data_attr.attr.name = "data"; 51766aec647SPeter Oberparleiter sd_file->data_attr.attr.mode = 0444; 51866aec647SPeter Oberparleiter sd_file->data_attr.read = data_read; 51966aec647SPeter Oberparleiter 52066aec647SPeter Oberparleiter rc = sysfs_create_bin_file(&sd_file->kobj, &sd_file->data_attr); 52166aec647SPeter Oberparleiter if (rc) { 52266aec647SPeter Oberparleiter kobject_put(&sd_file->kobj); 52366aec647SPeter Oberparleiter return NULL; 52466aec647SPeter Oberparleiter } 52566aec647SPeter Oberparleiter 52666aec647SPeter Oberparleiter /* 52766aec647SPeter Oberparleiter * For completeness only - users interested in entity data should listen 52866aec647SPeter Oberparleiter * for KOBJ_CHANGE instead. 52966aec647SPeter Oberparleiter */ 53066aec647SPeter Oberparleiter kobject_uevent(&sd_file->kobj, KOBJ_ADD); 53166aec647SPeter Oberparleiter 53266aec647SPeter Oberparleiter /* Don't let a slow Store Data request delay further initialization */ 53366aec647SPeter Oberparleiter async_schedule(sclp_sd_file_update_async, sd_file); 53466aec647SPeter Oberparleiter 53566aec647SPeter Oberparleiter return sd_file; 53666aec647SPeter Oberparleiter } 53766aec647SPeter Oberparleiter 53866aec647SPeter Oberparleiter /** 53966aec647SPeter Oberparleiter * sclp_sd_init() - Initialize sclp_sd support and register sysfs files 54066aec647SPeter Oberparleiter */ 54166aec647SPeter Oberparleiter static __init int sclp_sd_init(void) 54266aec647SPeter Oberparleiter { 54366aec647SPeter Oberparleiter int rc; 54466aec647SPeter Oberparleiter 54566aec647SPeter Oberparleiter rc = sclp_register(&sclp_sd_register); 54666aec647SPeter Oberparleiter if (rc) 54766aec647SPeter Oberparleiter return rc; 54866aec647SPeter Oberparleiter 54966aec647SPeter Oberparleiter /* Create kset named "sclp_sd" located under /sys/firmware/ */ 55066aec647SPeter Oberparleiter rc = -ENOMEM; 55166aec647SPeter Oberparleiter sclp_sd_kset = kset_create_and_add("sclp_sd", NULL, firmware_kobj); 55266aec647SPeter Oberparleiter if (!sclp_sd_kset) 55366aec647SPeter Oberparleiter goto err_kset; 55466aec647SPeter Oberparleiter 55566aec647SPeter Oberparleiter rc = -EINVAL; 55666aec647SPeter Oberparleiter config_file = sclp_sd_file_create("config", SD_DI_CONFIG); 55766aec647SPeter Oberparleiter if (!config_file) 55866aec647SPeter Oberparleiter goto err_config; 55966aec647SPeter Oberparleiter 56066aec647SPeter Oberparleiter return 0; 56166aec647SPeter Oberparleiter 56266aec647SPeter Oberparleiter err_config: 56366aec647SPeter Oberparleiter kset_unregister(sclp_sd_kset); 56466aec647SPeter Oberparleiter err_kset: 56566aec647SPeter Oberparleiter sclp_unregister(&sclp_sd_register); 56666aec647SPeter Oberparleiter 56766aec647SPeter Oberparleiter return rc; 56866aec647SPeter Oberparleiter } 56966aec647SPeter Oberparleiter device_initcall(sclp_sd_init); 570