1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   * SCLP "store data in absolute storage"
4   *
5   * Copyright IBM Corp. 2003, 2013
6   * Author(s): Michael Holzheu
7   */
8  
9  #define KMSG_COMPONENT "sclp_sdias"
10  #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11  
12  #include <linux/completion.h>
13  #include <linux/sched.h>
14  #include <asm/sclp.h>
15  #include <asm/debug.h>
16  #include <asm/ipl.h>
17  
18  #include "sclp_sdias.h"
19  #include "sclp.h"
20  #include "sclp_rw.h"
21  
22  #define TRACE(x...) debug_sprintf_event(sdias_dbf, 1, x)
23  
24  #define SDIAS_RETRIES 300
25  
26  static struct debug_info *sdias_dbf;
27  
28  static struct sclp_register sclp_sdias_register = {
29  	.send_mask = EVTYP_SDIAS_MASK,
30  };
31  
32  static struct sdias_sccb *sclp_sdias_sccb;
33  static struct sdias_evbuf sdias_evbuf;
34  
35  static DECLARE_COMPLETION(evbuf_accepted);
36  static DECLARE_COMPLETION(evbuf_done);
37  static DEFINE_MUTEX(sdias_mutex);
38  
39  /*
40   * Called by SCLP base when read event data has been completed (async mode only)
41   */
sclp_sdias_receiver_fn(struct evbuf_header * evbuf)42  static void sclp_sdias_receiver_fn(struct evbuf_header *evbuf)
43  {
44  	memcpy(&sdias_evbuf, evbuf,
45  	       min_t(unsigned long, sizeof(sdias_evbuf), evbuf->length));
46  	complete(&evbuf_done);
47  	TRACE("sclp_sdias_receiver_fn done\n");
48  }
49  
50  /*
51   * Called by SCLP base when sdias event has been accepted
52   */
sdias_callback(struct sclp_req * request,void * data)53  static void sdias_callback(struct sclp_req *request, void *data)
54  {
55  	complete(&evbuf_accepted);
56  	TRACE("callback done\n");
57  }
58  
sdias_sclp_send(struct sclp_req * req)59  static int sdias_sclp_send(struct sclp_req *req)
60  {
61  	struct sdias_sccb *sccb = sclp_sdias_sccb;
62  	int retries;
63  	int rc;
64  
65  	for (retries = SDIAS_RETRIES; retries; retries--) {
66  		TRACE("add request\n");
67  		rc = sclp_add_request(req);
68  		if (rc) {
69  			/* not initiated, wait some time and retry */
70  			set_current_state(TASK_INTERRUPTIBLE);
71  			TRACE("add request failed: rc = %i\n",rc);
72  			schedule_timeout(msecs_to_jiffies(500));
73  			continue;
74  		}
75  		/* initiated, wait for completion of service call */
76  		wait_for_completion(&evbuf_accepted);
77  		if (req->status == SCLP_REQ_FAILED) {
78  			TRACE("sclp request failed\n");
79  			continue;
80  		}
81  		/* if not accepted, retry */
82  		if (!(sccb->evbuf.hdr.flags & 0x80)) {
83  			TRACE("sclp request failed: flags=%x\n",
84  			      sccb->evbuf.hdr.flags);
85  			continue;
86  		}
87  		/*
88  		 * for the sync interface the response is in the initial sccb
89  		 */
90  		if (!sclp_sdias_register.receiver_fn) {
91  			memcpy(&sdias_evbuf, &sccb->evbuf, sizeof(sdias_evbuf));
92  			TRACE("sync request done\n");
93  			return 0;
94  		}
95  		/* otherwise we wait for completion */
96  		wait_for_completion(&evbuf_done);
97  		TRACE("request done\n");
98  		return 0;
99  	}
100  	return -EIO;
101  }
102  
103  /*
104   * Get number of blocks (4K) available in the HSA
105   */
sclp_sdias_blk_count(void)106  int sclp_sdias_blk_count(void)
107  {
108  	struct sdias_sccb *sccb = sclp_sdias_sccb;
109  	struct sclp_req request;
110  	int rc;
111  
112  	mutex_lock(&sdias_mutex);
113  
114  	memset(sccb, 0, sizeof(*sccb));
115  	memset(&request, 0, sizeof(request));
116  
117  	sccb->hdr.length = sizeof(*sccb);
118  	sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
119  	sccb->evbuf.hdr.type = EVTYP_SDIAS;
120  	sccb->evbuf.event_qual = SDIAS_EQ_SIZE;
121  	sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
122  	sccb->evbuf.event_id = 4712;
123  	sccb->evbuf.dbs = 1;
124  
125  	request.sccb = sccb;
126  	request.command = SCLP_CMDW_WRITE_EVENT_DATA;
127  	request.status = SCLP_REQ_FILLED;
128  	request.callback = sdias_callback;
129  
130  	rc = sdias_sclp_send(&request);
131  	if (rc) {
132  		pr_err("sclp_send failed for get_nr_blocks\n");
133  		goto out;
134  	}
135  	if (sccb->hdr.response_code != 0x0020) {
136  		TRACE("send failed: %x\n", sccb->hdr.response_code);
137  		rc = -EIO;
138  		goto out;
139  	}
140  
141  	switch (sdias_evbuf.event_status) {
142  		case 0:
143  			rc = sdias_evbuf.blk_cnt;
144  			break;
145  		default:
146  			pr_err("SCLP error: %x\n", sdias_evbuf.event_status);
147  			rc = -EIO;
148  			goto out;
149  	}
150  	TRACE("%i blocks\n", rc);
151  out:
152  	mutex_unlock(&sdias_mutex);
153  	return rc;
154  }
155  
156  /*
157   * Copy from HSA to absolute storage (not reentrant):
158   *
159   * @dest     : Address of buffer where data should be copied
160   * @start_blk: Start Block (beginning with 1)
161   * @nr_blks  : Number of 4K blocks to copy
162   *
163   * Return Value: 0 : Requested 'number' of blocks of data copied
164   *		 <0: ERROR - negative event status
165   */
sclp_sdias_copy(void * dest,int start_blk,int nr_blks)166  int sclp_sdias_copy(void *dest, int start_blk, int nr_blks)
167  {
168  	struct sdias_sccb *sccb = sclp_sdias_sccb;
169  	struct sclp_req request;
170  	int rc;
171  
172  	mutex_lock(&sdias_mutex);
173  
174  	memset(sccb, 0, sizeof(*sccb));
175  	memset(&request, 0, sizeof(request));
176  
177  	sccb->hdr.length = sizeof(*sccb);
178  	sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
179  	sccb->evbuf.hdr.type = EVTYP_SDIAS;
180  	sccb->evbuf.hdr.flags = 0;
181  	sccb->evbuf.event_qual = SDIAS_EQ_STORE_DATA;
182  	sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
183  	sccb->evbuf.event_id = 4712;
184  	sccb->evbuf.asa_size = SDIAS_ASA_SIZE_64;
185  	sccb->evbuf.event_status = 0;
186  	sccb->evbuf.blk_cnt = nr_blks;
187  	sccb->evbuf.asa = __pa(dest);
188  	sccb->evbuf.fbn = start_blk;
189  	sccb->evbuf.lbn = 0;
190  	sccb->evbuf.dbs = 1;
191  
192  	request.sccb	 = sccb;
193  	request.command  = SCLP_CMDW_WRITE_EVENT_DATA;
194  	request.status	 = SCLP_REQ_FILLED;
195  	request.callback = sdias_callback;
196  
197  	rc = sdias_sclp_send(&request);
198  	if (rc) {
199  		pr_err("sclp_send failed: %x\n", rc);
200  		goto out;
201  	}
202  	if (sccb->hdr.response_code != 0x0020) {
203  		TRACE("copy failed: %x\n", sccb->hdr.response_code);
204  		rc = -EIO;
205  		goto out;
206  	}
207  
208  	switch (sdias_evbuf.event_status) {
209  	case SDIAS_EVSTATE_ALL_STORED:
210  		TRACE("all stored\n");
211  		break;
212  	case SDIAS_EVSTATE_PART_STORED:
213  		TRACE("part stored: %i\n", sdias_evbuf.blk_cnt);
214  		break;
215  	case SDIAS_EVSTATE_NO_DATA:
216  		TRACE("no data\n");
217  		fallthrough;
218  	default:
219  		pr_err("Error from SCLP while copying hsa. Event status = %x\n",
220  		       sdias_evbuf.event_status);
221  		rc = -EIO;
222  	}
223  out:
224  	mutex_unlock(&sdias_mutex);
225  	return rc;
226  }
227  
sclp_sdias_register_check(void)228  static int __init sclp_sdias_register_check(void)
229  {
230  	int rc;
231  
232  	rc = sclp_register(&sclp_sdias_register);
233  	if (rc)
234  		return rc;
235  	if (sclp_sdias_blk_count() == 0) {
236  		sclp_unregister(&sclp_sdias_register);
237  		return -ENODEV;
238  	}
239  	return 0;
240  }
241  
sclp_sdias_init_sync(void)242  static int __init sclp_sdias_init_sync(void)
243  {
244  	TRACE("Try synchronous mode\n");
245  	sclp_sdias_register.receive_mask = 0;
246  	sclp_sdias_register.receiver_fn = NULL;
247  	return sclp_sdias_register_check();
248  }
249  
sclp_sdias_init_async(void)250  static int __init sclp_sdias_init_async(void)
251  {
252  	TRACE("Try asynchronous mode\n");
253  	sclp_sdias_register.receive_mask = EVTYP_SDIAS_MASK;
254  	sclp_sdias_register.receiver_fn = sclp_sdias_receiver_fn;
255  	return sclp_sdias_register_check();
256  }
257  
sclp_sdias_init(void)258  int __init sclp_sdias_init(void)
259  {
260  	if (!is_ipl_type_dump())
261  		return 0;
262  	sclp_sdias_sccb = (void *) __get_free_page(GFP_KERNEL | GFP_DMA);
263  	BUG_ON(!sclp_sdias_sccb);
264  	sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long));
265  	debug_register_view(sdias_dbf, &debug_sprintf_view);
266  	debug_set_level(sdias_dbf, 6);
267  	if (sclp_sdias_init_sync() == 0)
268  		goto out;
269  	if (sclp_sdias_init_async() == 0)
270  		goto out;
271  	TRACE("init failed\n");
272  	free_page((unsigned long) sclp_sdias_sccb);
273  	return -ENODEV;
274  out:
275  	TRACE("init done\n");
276  	return 0;
277  }
278