File Index
Files and directories
Sign in
FILE

sclp_sdias.c

File preview with syntax highlighting.

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