1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * SCLP Store Data support and sysfs interface
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright IBM Corp. 2017
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #define KMSG_COMPONENT "sclp_sd"
9*4882a593Smuzhiyun #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/completion.h>
12*4882a593Smuzhiyun #include <linux/kobject.h>
13*4882a593Smuzhiyun #include <linux/list.h>
14*4882a593Smuzhiyun #include <linux/printk.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun #include <linux/vmalloc.h>
17*4882a593Smuzhiyun #include <linux/async.h>
18*4882a593Smuzhiyun #include <linux/export.h>
19*4882a593Smuzhiyun #include <linux/mutex.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include <asm/pgalloc.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include "sclp.h"
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #define SD_EQ_STORE_DATA 0
26*4882a593Smuzhiyun #define SD_EQ_HALT 1
27*4882a593Smuzhiyun #define SD_EQ_SIZE 2
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define SD_DI_CONFIG 3
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun struct sclp_sd_evbuf {
32*4882a593Smuzhiyun struct evbuf_header hdr;
33*4882a593Smuzhiyun u8 eq;
34*4882a593Smuzhiyun u8 di;
35*4882a593Smuzhiyun u8 rflags;
36*4882a593Smuzhiyun u64 :56;
37*4882a593Smuzhiyun u32 id;
38*4882a593Smuzhiyun u16 :16;
39*4882a593Smuzhiyun u8 fmt;
40*4882a593Smuzhiyun u8 status;
41*4882a593Smuzhiyun u64 sat;
42*4882a593Smuzhiyun u64 sa;
43*4882a593Smuzhiyun u32 esize;
44*4882a593Smuzhiyun u32 dsize;
45*4882a593Smuzhiyun } __packed;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun struct sclp_sd_sccb {
48*4882a593Smuzhiyun struct sccb_header hdr;
49*4882a593Smuzhiyun struct sclp_sd_evbuf evbuf;
50*4882a593Smuzhiyun } __packed __aligned(PAGE_SIZE);
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /**
53*4882a593Smuzhiyun * struct sclp_sd_data - Result of a Store Data request
54*4882a593Smuzhiyun * @esize_bytes: Resulting esize in bytes
55*4882a593Smuzhiyun * @dsize_bytes: Resulting dsize in bytes
56*4882a593Smuzhiyun * @data: Pointer to data - must be released using vfree()
57*4882a593Smuzhiyun */
58*4882a593Smuzhiyun struct sclp_sd_data {
59*4882a593Smuzhiyun size_t esize_bytes;
60*4882a593Smuzhiyun size_t dsize_bytes;
61*4882a593Smuzhiyun void *data;
62*4882a593Smuzhiyun };
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun /**
65*4882a593Smuzhiyun * struct sclp_sd_listener - Listener for asynchronous Store Data response
66*4882a593Smuzhiyun * @list: For enqueueing this struct
67*4882a593Smuzhiyun * @id: Event ID of response to listen for
68*4882a593Smuzhiyun * @completion: Can be used to wait for response
69*4882a593Smuzhiyun * @evbuf: Contains the resulting Store Data response after completion
70*4882a593Smuzhiyun */
71*4882a593Smuzhiyun struct sclp_sd_listener {
72*4882a593Smuzhiyun struct list_head list;
73*4882a593Smuzhiyun u32 id;
74*4882a593Smuzhiyun struct completion completion;
75*4882a593Smuzhiyun struct sclp_sd_evbuf evbuf;
76*4882a593Smuzhiyun };
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun /**
79*4882a593Smuzhiyun * struct sclp_sd_file - Sysfs representation of a Store Data entity
80*4882a593Smuzhiyun * @kobj: Kobject
81*4882a593Smuzhiyun * @data_attr: Attribute for accessing data contents
82*4882a593Smuzhiyun * @data_mutex: Mutex to serialize access and updates to @data
83*4882a593Smuzhiyun * @data: Data associated with this entity
84*4882a593Smuzhiyun * @di: DI value associated with this entity
85*4882a593Smuzhiyun */
86*4882a593Smuzhiyun struct sclp_sd_file {
87*4882a593Smuzhiyun struct kobject kobj;
88*4882a593Smuzhiyun struct bin_attribute data_attr;
89*4882a593Smuzhiyun struct mutex data_mutex;
90*4882a593Smuzhiyun struct sclp_sd_data data;
91*4882a593Smuzhiyun u8 di;
92*4882a593Smuzhiyun };
93*4882a593Smuzhiyun #define to_sd_file(x) container_of(x, struct sclp_sd_file, kobj)
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun static struct kset *sclp_sd_kset;
96*4882a593Smuzhiyun static struct sclp_sd_file *config_file;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun static LIST_HEAD(sclp_sd_queue);
99*4882a593Smuzhiyun static DEFINE_SPINLOCK(sclp_sd_queue_lock);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun /**
102*4882a593Smuzhiyun * sclp_sd_listener_add() - Add listener for Store Data responses
103*4882a593Smuzhiyun * @listener: Listener to add
104*4882a593Smuzhiyun */
sclp_sd_listener_add(struct sclp_sd_listener * listener)105*4882a593Smuzhiyun static void sclp_sd_listener_add(struct sclp_sd_listener *listener)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun spin_lock_irq(&sclp_sd_queue_lock);
108*4882a593Smuzhiyun list_add_tail(&listener->list, &sclp_sd_queue);
109*4882a593Smuzhiyun spin_unlock_irq(&sclp_sd_queue_lock);
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /**
113*4882a593Smuzhiyun * sclp_sd_listener_remove() - Remove listener for Store Data responses
114*4882a593Smuzhiyun * @listener: Listener to remove
115*4882a593Smuzhiyun */
sclp_sd_listener_remove(struct sclp_sd_listener * listener)116*4882a593Smuzhiyun static void sclp_sd_listener_remove(struct sclp_sd_listener *listener)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun spin_lock_irq(&sclp_sd_queue_lock);
119*4882a593Smuzhiyun list_del(&listener->list);
120*4882a593Smuzhiyun spin_unlock_irq(&sclp_sd_queue_lock);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun /**
124*4882a593Smuzhiyun * sclp_sd_listener_init() - Initialize a Store Data response listener
125*4882a593Smuzhiyun * @id: Event ID to listen for
126*4882a593Smuzhiyun *
127*4882a593Smuzhiyun * Initialize a listener for asynchronous Store Data responses. This listener
128*4882a593Smuzhiyun * can afterwards be used to wait for a specific response and to retrieve
129*4882a593Smuzhiyun * the associated response data.
130*4882a593Smuzhiyun */
sclp_sd_listener_init(struct sclp_sd_listener * listener,u32 id)131*4882a593Smuzhiyun static void sclp_sd_listener_init(struct sclp_sd_listener *listener, u32 id)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun memset(listener, 0, sizeof(*listener));
134*4882a593Smuzhiyun listener->id = id;
135*4882a593Smuzhiyun init_completion(&listener->completion);
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /**
139*4882a593Smuzhiyun * sclp_sd_receiver() - Receiver for Store Data events
140*4882a593Smuzhiyun * @evbuf_hdr: Header of received events
141*4882a593Smuzhiyun *
142*4882a593Smuzhiyun * Process Store Data events and complete listeners with matching event IDs.
143*4882a593Smuzhiyun */
sclp_sd_receiver(struct evbuf_header * evbuf_hdr)144*4882a593Smuzhiyun static void sclp_sd_receiver(struct evbuf_header *evbuf_hdr)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun struct sclp_sd_evbuf *evbuf = (struct sclp_sd_evbuf *) evbuf_hdr;
147*4882a593Smuzhiyun struct sclp_sd_listener *listener;
148*4882a593Smuzhiyun int found = 0;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun pr_debug("received event (id=0x%08x)\n", evbuf->id);
151*4882a593Smuzhiyun spin_lock(&sclp_sd_queue_lock);
152*4882a593Smuzhiyun list_for_each_entry(listener, &sclp_sd_queue, list) {
153*4882a593Smuzhiyun if (listener->id != evbuf->id)
154*4882a593Smuzhiyun continue;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun listener->evbuf = *evbuf;
157*4882a593Smuzhiyun complete(&listener->completion);
158*4882a593Smuzhiyun found = 1;
159*4882a593Smuzhiyun break;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun spin_unlock(&sclp_sd_queue_lock);
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun if (!found)
164*4882a593Smuzhiyun pr_debug("unsolicited event (id=0x%08x)\n", evbuf->id);
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun static struct sclp_register sclp_sd_register = {
168*4882a593Smuzhiyun .send_mask = EVTYP_STORE_DATA_MASK,
169*4882a593Smuzhiyun .receive_mask = EVTYP_STORE_DATA_MASK,
170*4882a593Smuzhiyun .receiver_fn = sclp_sd_receiver,
171*4882a593Smuzhiyun };
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun /**
174*4882a593Smuzhiyun * sclp_sd_sync() - Perform Store Data request synchronously
175*4882a593Smuzhiyun * @page: Address of work page - must be below 2GB
176*4882a593Smuzhiyun * @eq: Input EQ value
177*4882a593Smuzhiyun * @di: Input DI value
178*4882a593Smuzhiyun * @sat: Input SAT value
179*4882a593Smuzhiyun * @sa: Input SA value used to specify the address of the target buffer
180*4882a593Smuzhiyun * @dsize_ptr: Optional pointer to input and output DSIZE value
181*4882a593Smuzhiyun * @esize_ptr: Optional pointer to output ESIZE value
182*4882a593Smuzhiyun *
183*4882a593Smuzhiyun * Perform Store Data request with specified parameters and wait for completion.
184*4882a593Smuzhiyun *
185*4882a593Smuzhiyun * Return %0 on success and store resulting DSIZE and ESIZE values in
186*4882a593Smuzhiyun * @dsize_ptr and @esize_ptr (if provided). Return non-zero on error.
187*4882a593Smuzhiyun */
sclp_sd_sync(unsigned long page,u8 eq,u8 di,u64 sat,u64 sa,u32 * dsize_ptr,u32 * esize_ptr)188*4882a593Smuzhiyun static int sclp_sd_sync(unsigned long page, u8 eq, u8 di, u64 sat, u64 sa,
189*4882a593Smuzhiyun u32 *dsize_ptr, u32 *esize_ptr)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun struct sclp_sd_sccb *sccb = (void *) page;
192*4882a593Smuzhiyun struct sclp_sd_listener listener;
193*4882a593Smuzhiyun struct sclp_sd_evbuf *evbuf;
194*4882a593Smuzhiyun int rc;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun sclp_sd_listener_init(&listener, (u32) (addr_t) sccb);
197*4882a593Smuzhiyun sclp_sd_listener_add(&listener);
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun /* Prepare SCCB */
200*4882a593Smuzhiyun memset(sccb, 0, PAGE_SIZE);
201*4882a593Smuzhiyun sccb->hdr.length = sizeof(sccb->hdr) + sizeof(sccb->evbuf);
202*4882a593Smuzhiyun evbuf = &sccb->evbuf;
203*4882a593Smuzhiyun evbuf->hdr.length = sizeof(*evbuf);
204*4882a593Smuzhiyun evbuf->hdr.type = EVTYP_STORE_DATA;
205*4882a593Smuzhiyun evbuf->eq = eq;
206*4882a593Smuzhiyun evbuf->di = di;
207*4882a593Smuzhiyun evbuf->id = listener.id;
208*4882a593Smuzhiyun evbuf->fmt = 1;
209*4882a593Smuzhiyun evbuf->sat = sat;
210*4882a593Smuzhiyun evbuf->sa = sa;
211*4882a593Smuzhiyun if (dsize_ptr)
212*4882a593Smuzhiyun evbuf->dsize = *dsize_ptr;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun /* Perform command */
215*4882a593Smuzhiyun pr_debug("request (eq=%d, di=%d, id=0x%08x)\n", eq, di, listener.id);
216*4882a593Smuzhiyun rc = sclp_sync_request(SCLP_CMDW_WRITE_EVENT_DATA, sccb);
217*4882a593Smuzhiyun pr_debug("request done (rc=%d)\n", rc);
218*4882a593Smuzhiyun if (rc)
219*4882a593Smuzhiyun goto out;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun /* Evaluate response */
222*4882a593Smuzhiyun if (sccb->hdr.response_code == 0x73f0) {
223*4882a593Smuzhiyun pr_debug("event not supported\n");
224*4882a593Smuzhiyun rc = -EIO;
225*4882a593Smuzhiyun goto out_remove;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun if (sccb->hdr.response_code != 0x0020 || !(evbuf->hdr.flags & 0x80)) {
228*4882a593Smuzhiyun rc = -EIO;
229*4882a593Smuzhiyun goto out;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun if (!(evbuf->rflags & 0x80)) {
232*4882a593Smuzhiyun rc = wait_for_completion_interruptible(&listener.completion);
233*4882a593Smuzhiyun if (rc)
234*4882a593Smuzhiyun goto out;
235*4882a593Smuzhiyun evbuf = &listener.evbuf;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun switch (evbuf->status) {
238*4882a593Smuzhiyun case 0:
239*4882a593Smuzhiyun if (dsize_ptr)
240*4882a593Smuzhiyun *dsize_ptr = evbuf->dsize;
241*4882a593Smuzhiyun if (esize_ptr)
242*4882a593Smuzhiyun *esize_ptr = evbuf->esize;
243*4882a593Smuzhiyun pr_debug("success (dsize=%u, esize=%u)\n", evbuf->dsize,
244*4882a593Smuzhiyun evbuf->esize);
245*4882a593Smuzhiyun break;
246*4882a593Smuzhiyun case 3:
247*4882a593Smuzhiyun rc = -ENOENT;
248*4882a593Smuzhiyun break;
249*4882a593Smuzhiyun default:
250*4882a593Smuzhiyun rc = -EIO;
251*4882a593Smuzhiyun break;
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun out:
256*4882a593Smuzhiyun if (rc && rc != -ENOENT) {
257*4882a593Smuzhiyun /* Provide some information about what went wrong */
258*4882a593Smuzhiyun pr_warn("Store Data request failed (eq=%d, di=%d, "
259*4882a593Smuzhiyun "response=0x%04x, flags=0x%02x, status=%d, rc=%d)\n",
260*4882a593Smuzhiyun eq, di, sccb->hdr.response_code, evbuf->hdr.flags,
261*4882a593Smuzhiyun evbuf->status, rc);
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun out_remove:
265*4882a593Smuzhiyun sclp_sd_listener_remove(&listener);
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun return rc;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun /**
271*4882a593Smuzhiyun * sclp_sd_store_data() - Obtain data for specified Store Data entity
272*4882a593Smuzhiyun * @result: Resulting data
273*4882a593Smuzhiyun * @di: DI value associated with this entity
274*4882a593Smuzhiyun *
275*4882a593Smuzhiyun * Perform a series of Store Data requests to obtain the size and contents of
276*4882a593Smuzhiyun * the specified Store Data entity.
277*4882a593Smuzhiyun *
278*4882a593Smuzhiyun * Return:
279*4882a593Smuzhiyun * %0: Success - result is stored in @result. @result->data must be
280*4882a593Smuzhiyun * released using vfree() after use.
281*4882a593Smuzhiyun * %-ENOENT: No data available for this entity
282*4882a593Smuzhiyun * %<0: Other error
283*4882a593Smuzhiyun */
sclp_sd_store_data(struct sclp_sd_data * result,u8 di)284*4882a593Smuzhiyun static int sclp_sd_store_data(struct sclp_sd_data *result, u8 di)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun u32 dsize = 0, esize = 0;
287*4882a593Smuzhiyun unsigned long page, asce = 0;
288*4882a593Smuzhiyun void *data = NULL;
289*4882a593Smuzhiyun int rc;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun page = __get_free_page(GFP_KERNEL | GFP_DMA);
292*4882a593Smuzhiyun if (!page)
293*4882a593Smuzhiyun return -ENOMEM;
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun /* Get size */
296*4882a593Smuzhiyun rc = sclp_sd_sync(page, SD_EQ_SIZE, di, 0, 0, &dsize, &esize);
297*4882a593Smuzhiyun if (rc)
298*4882a593Smuzhiyun goto out;
299*4882a593Smuzhiyun if (dsize == 0)
300*4882a593Smuzhiyun goto out_result;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /* Allocate memory */
303*4882a593Smuzhiyun data = vzalloc(array_size((size_t)dsize, PAGE_SIZE));
304*4882a593Smuzhiyun if (!data) {
305*4882a593Smuzhiyun rc = -ENOMEM;
306*4882a593Smuzhiyun goto out;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun /* Get translation table for buffer */
310*4882a593Smuzhiyun asce = base_asce_alloc((unsigned long) data, dsize);
311*4882a593Smuzhiyun if (!asce) {
312*4882a593Smuzhiyun vfree(data);
313*4882a593Smuzhiyun rc = -ENOMEM;
314*4882a593Smuzhiyun goto out;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun /* Get data */
318*4882a593Smuzhiyun rc = sclp_sd_sync(page, SD_EQ_STORE_DATA, di, asce, (u64) data, &dsize,
319*4882a593Smuzhiyun &esize);
320*4882a593Smuzhiyun if (rc) {
321*4882a593Smuzhiyun /* Cancel running request if interrupted */
322*4882a593Smuzhiyun if (rc == -ERESTARTSYS)
323*4882a593Smuzhiyun sclp_sd_sync(page, SD_EQ_HALT, di, 0, 0, NULL, NULL);
324*4882a593Smuzhiyun vfree(data);
325*4882a593Smuzhiyun goto out;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun out_result:
329*4882a593Smuzhiyun result->esize_bytes = (size_t) esize * PAGE_SIZE;
330*4882a593Smuzhiyun result->dsize_bytes = (size_t) dsize * PAGE_SIZE;
331*4882a593Smuzhiyun result->data = data;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun out:
334*4882a593Smuzhiyun base_asce_free(asce);
335*4882a593Smuzhiyun free_page(page);
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun return rc;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun /**
341*4882a593Smuzhiyun * sclp_sd_data_reset() - Reset Store Data result buffer
342*4882a593Smuzhiyun * @data: Data buffer to reset
343*4882a593Smuzhiyun *
344*4882a593Smuzhiyun * Reset @data to initial state and release associated memory.
345*4882a593Smuzhiyun */
sclp_sd_data_reset(struct sclp_sd_data * data)346*4882a593Smuzhiyun static void sclp_sd_data_reset(struct sclp_sd_data *data)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun vfree(data->data);
349*4882a593Smuzhiyun data->data = NULL;
350*4882a593Smuzhiyun data->dsize_bytes = 0;
351*4882a593Smuzhiyun data->esize_bytes = 0;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun /**
355*4882a593Smuzhiyun * sclp_sd_file_release() - Release function for sclp_sd_file object
356*4882a593Smuzhiyun * @kobj: Kobject embedded in sclp_sd_file object
357*4882a593Smuzhiyun */
sclp_sd_file_release(struct kobject * kobj)358*4882a593Smuzhiyun static void sclp_sd_file_release(struct kobject *kobj)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun struct sclp_sd_file *sd_file = to_sd_file(kobj);
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun sclp_sd_data_reset(&sd_file->data);
363*4882a593Smuzhiyun kfree(sd_file);
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun /**
367*4882a593Smuzhiyun * sclp_sd_file_update() - Update contents of sclp_sd_file object
368*4882a593Smuzhiyun * @sd_file: Object to update
369*4882a593Smuzhiyun *
370*4882a593Smuzhiyun * Obtain the current version of data associated with the Store Data entity
371*4882a593Smuzhiyun * @sd_file.
372*4882a593Smuzhiyun *
373*4882a593Smuzhiyun * On success, return %0 and generate a KOBJ_CHANGE event to indicate that the
374*4882a593Smuzhiyun * data may have changed. Return non-zero otherwise.
375*4882a593Smuzhiyun */
sclp_sd_file_update(struct sclp_sd_file * sd_file)376*4882a593Smuzhiyun static int sclp_sd_file_update(struct sclp_sd_file *sd_file)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun const char *name = kobject_name(&sd_file->kobj);
379*4882a593Smuzhiyun struct sclp_sd_data data;
380*4882a593Smuzhiyun int rc;
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun rc = sclp_sd_store_data(&data, sd_file->di);
383*4882a593Smuzhiyun if (rc) {
384*4882a593Smuzhiyun if (rc == -ENOENT) {
385*4882a593Smuzhiyun pr_info("No data is available for the %s data entity\n",
386*4882a593Smuzhiyun name);
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun return rc;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun mutex_lock(&sd_file->data_mutex);
392*4882a593Smuzhiyun sclp_sd_data_reset(&sd_file->data);
393*4882a593Smuzhiyun sd_file->data = data;
394*4882a593Smuzhiyun mutex_unlock(&sd_file->data_mutex);
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun pr_info("A %zu-byte %s data entity was retrieved\n", data.dsize_bytes,
397*4882a593Smuzhiyun name);
398*4882a593Smuzhiyun kobject_uevent(&sd_file->kobj, KOBJ_CHANGE);
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun return 0;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun /**
404*4882a593Smuzhiyun * sclp_sd_file_update_async() - Wrapper for asynchronous update call
405*4882a593Smuzhiyun * @data: Object to update
406*4882a593Smuzhiyun */
sclp_sd_file_update_async(void * data,async_cookie_t cookie)407*4882a593Smuzhiyun static void sclp_sd_file_update_async(void *data, async_cookie_t cookie)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun struct sclp_sd_file *sd_file = data;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun sclp_sd_file_update(sd_file);
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun /**
415*4882a593Smuzhiyun * reload_store() - Store function for "reload" sysfs attribute
416*4882a593Smuzhiyun * @kobj: Kobject of sclp_sd_file object
417*4882a593Smuzhiyun *
418*4882a593Smuzhiyun * Initiate a reload of the data associated with an sclp_sd_file object.
419*4882a593Smuzhiyun */
reload_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)420*4882a593Smuzhiyun static ssize_t reload_store(struct kobject *kobj, struct kobj_attribute *attr,
421*4882a593Smuzhiyun const char *buf, size_t count)
422*4882a593Smuzhiyun {
423*4882a593Smuzhiyun struct sclp_sd_file *sd_file = to_sd_file(kobj);
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun sclp_sd_file_update(sd_file);
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun return count;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun static struct kobj_attribute reload_attr = __ATTR_WO(reload);
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun static struct attribute *sclp_sd_file_default_attrs[] = {
433*4882a593Smuzhiyun &reload_attr.attr,
434*4882a593Smuzhiyun NULL,
435*4882a593Smuzhiyun };
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun static struct kobj_type sclp_sd_file_ktype = {
438*4882a593Smuzhiyun .sysfs_ops = &kobj_sysfs_ops,
439*4882a593Smuzhiyun .release = sclp_sd_file_release,
440*4882a593Smuzhiyun .default_attrs = sclp_sd_file_default_attrs,
441*4882a593Smuzhiyun };
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun /**
444*4882a593Smuzhiyun * data_read() - Read function for "read" sysfs attribute
445*4882a593Smuzhiyun * @kobj: Kobject of sclp_sd_file object
446*4882a593Smuzhiyun * @buffer: Target buffer
447*4882a593Smuzhiyun * @off: Requested file offset
448*4882a593Smuzhiyun * @size: Requested number of bytes
449*4882a593Smuzhiyun *
450*4882a593Smuzhiyun * Store the requested portion of the Store Data entity contents into the
451*4882a593Smuzhiyun * specified buffer. Return the number of bytes stored on success, or %0
452*4882a593Smuzhiyun * on EOF.
453*4882a593Smuzhiyun */
data_read(struct file * file,struct kobject * kobj,struct bin_attribute * attr,char * buffer,loff_t off,size_t size)454*4882a593Smuzhiyun static ssize_t data_read(struct file *file, struct kobject *kobj,
455*4882a593Smuzhiyun struct bin_attribute *attr, char *buffer,
456*4882a593Smuzhiyun loff_t off, size_t size)
457*4882a593Smuzhiyun {
458*4882a593Smuzhiyun struct sclp_sd_file *sd_file = to_sd_file(kobj);
459*4882a593Smuzhiyun size_t data_size;
460*4882a593Smuzhiyun char *data;
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun mutex_lock(&sd_file->data_mutex);
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun data = sd_file->data.data;
465*4882a593Smuzhiyun data_size = sd_file->data.dsize_bytes;
466*4882a593Smuzhiyun if (!data || off >= data_size) {
467*4882a593Smuzhiyun size = 0;
468*4882a593Smuzhiyun } else {
469*4882a593Smuzhiyun if (off + size > data_size)
470*4882a593Smuzhiyun size = data_size - off;
471*4882a593Smuzhiyun memcpy(buffer, data + off, size);
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun mutex_unlock(&sd_file->data_mutex);
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun return size;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun /**
480*4882a593Smuzhiyun * sclp_sd_file_create() - Add a sysfs file representing a Store Data entity
481*4882a593Smuzhiyun * @name: Name of file
482*4882a593Smuzhiyun * @di: DI value associated with this entity
483*4882a593Smuzhiyun *
484*4882a593Smuzhiyun * Create a sysfs directory with the given @name located under
485*4882a593Smuzhiyun *
486*4882a593Smuzhiyun * /sys/firmware/sclp_sd/
487*4882a593Smuzhiyun *
488*4882a593Smuzhiyun * The files in this directory can be used to access the contents of the Store
489*4882a593Smuzhiyun * Data entity associated with @DI.
490*4882a593Smuzhiyun *
491*4882a593Smuzhiyun * Return pointer to resulting sclp_sd_file object on success, %NULL otherwise.
492*4882a593Smuzhiyun * The object must be freed by calling kobject_put() on the embedded kobject
493*4882a593Smuzhiyun * pointer after use.
494*4882a593Smuzhiyun */
sclp_sd_file_create(const char * name,u8 di)495*4882a593Smuzhiyun static __init struct sclp_sd_file *sclp_sd_file_create(const char *name, u8 di)
496*4882a593Smuzhiyun {
497*4882a593Smuzhiyun struct sclp_sd_file *sd_file;
498*4882a593Smuzhiyun int rc;
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun sd_file = kzalloc(sizeof(*sd_file), GFP_KERNEL);
501*4882a593Smuzhiyun if (!sd_file)
502*4882a593Smuzhiyun return NULL;
503*4882a593Smuzhiyun sd_file->di = di;
504*4882a593Smuzhiyun mutex_init(&sd_file->data_mutex);
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun /* Create kobject located under /sys/firmware/sclp_sd/ */
507*4882a593Smuzhiyun sd_file->kobj.kset = sclp_sd_kset;
508*4882a593Smuzhiyun rc = kobject_init_and_add(&sd_file->kobj, &sclp_sd_file_ktype, NULL,
509*4882a593Smuzhiyun "%s", name);
510*4882a593Smuzhiyun if (rc) {
511*4882a593Smuzhiyun kobject_put(&sd_file->kobj);
512*4882a593Smuzhiyun return NULL;
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun sysfs_bin_attr_init(&sd_file->data_attr);
516*4882a593Smuzhiyun sd_file->data_attr.attr.name = "data";
517*4882a593Smuzhiyun sd_file->data_attr.attr.mode = 0444;
518*4882a593Smuzhiyun sd_file->data_attr.read = data_read;
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun rc = sysfs_create_bin_file(&sd_file->kobj, &sd_file->data_attr);
521*4882a593Smuzhiyun if (rc) {
522*4882a593Smuzhiyun kobject_put(&sd_file->kobj);
523*4882a593Smuzhiyun return NULL;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun /*
527*4882a593Smuzhiyun * For completeness only - users interested in entity data should listen
528*4882a593Smuzhiyun * for KOBJ_CHANGE instead.
529*4882a593Smuzhiyun */
530*4882a593Smuzhiyun kobject_uevent(&sd_file->kobj, KOBJ_ADD);
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun /* Don't let a slow Store Data request delay further initialization */
533*4882a593Smuzhiyun async_schedule(sclp_sd_file_update_async, sd_file);
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun return sd_file;
536*4882a593Smuzhiyun }
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun /**
539*4882a593Smuzhiyun * sclp_sd_init() - Initialize sclp_sd support and register sysfs files
540*4882a593Smuzhiyun */
sclp_sd_init(void)541*4882a593Smuzhiyun static __init int sclp_sd_init(void)
542*4882a593Smuzhiyun {
543*4882a593Smuzhiyun int rc;
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun rc = sclp_register(&sclp_sd_register);
546*4882a593Smuzhiyun if (rc)
547*4882a593Smuzhiyun return rc;
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun /* Create kset named "sclp_sd" located under /sys/firmware/ */
550*4882a593Smuzhiyun rc = -ENOMEM;
551*4882a593Smuzhiyun sclp_sd_kset = kset_create_and_add("sclp_sd", NULL, firmware_kobj);
552*4882a593Smuzhiyun if (!sclp_sd_kset)
553*4882a593Smuzhiyun goto err_kset;
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun rc = -EINVAL;
556*4882a593Smuzhiyun config_file = sclp_sd_file_create("config", SD_DI_CONFIG);
557*4882a593Smuzhiyun if (!config_file)
558*4882a593Smuzhiyun goto err_config;
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun return 0;
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun err_config:
563*4882a593Smuzhiyun kset_unregister(sclp_sd_kset);
564*4882a593Smuzhiyun err_kset:
565*4882a593Smuzhiyun sclp_unregister(&sclp_sd_register);
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun return rc;
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun device_initcall(sclp_sd_init);
570