brintos

brintos / linux-shallow public Read only

0
0
Text · 6.6 KiB · e915a34 Raw
278 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * SCLP "store data in absolute storage"4 *5 * Copyright IBM Corp. 2003, 20136 * Author(s): Michael Holzheu7 */8 9#define KMSG_COMPONENT "sclp_sdias"10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt11 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 30025 26static struct debug_info *sdias_dbf;27 28static struct sclp_register sclp_sdias_register = {29	.send_mask = EVTYP_SDIAS_MASK,30};31 32static struct sdias_sccb *sclp_sdias_sccb;33static struct sdias_evbuf sdias_evbuf;34 35static DECLARE_COMPLETION(evbuf_accepted);36static DECLARE_COMPLETION(evbuf_done);37static DEFINE_MUTEX(sdias_mutex);38 39/*40 * Called by SCLP base when read event data has been completed (async mode only)41 */42static 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 accepted52 */53static void sdias_callback(struct sclp_req *request, void *data)54{55	complete(&evbuf_accepted);56	TRACE("callback done\n");57}58 59static 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 sccb89		 */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 HSA105 */106int 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);151out: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 copied160 * @start_blk: Start Block (beginning with 1)161 * @nr_blks  : Number of 4K blocks to copy162 *163 * Return Value: 0 : Requested 'number' of blocks of data copied164 *		 <0: ERROR - negative event status165 */166int 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	}223out:224	mutex_unlock(&sdias_mutex);225	return rc;226}227 228static 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 242static 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 250static 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 258int __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;274out:275	TRACE("init done\n");276	return 0;277}278