Commit e3c652b5 authored by Michael Holzheu's avatar Michael Holzheu Committed by Martin Schwidefsky

[S390] zfcpdump: Implement async sdias event processing

There are two different ways to do the "store data in absolute
storage" SCLP event processing, synchronous and asynchrounous.
This patch adds the asynchronous variant.
Signed-off-by: default avatarMichael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent b43445ff
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#define KMSG_COMPONENT "sclp_sdias" #define KMSG_COMPONENT "sclp_sdias"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/completion.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <asm/sclp.h> #include <asm/sclp.h>
#include <asm/debug.h> #include <asm/debug.h>
...@@ -62,15 +63,29 @@ struct sdias_sccb { ...@@ -62,15 +63,29 @@ struct sdias_sccb {
} __attribute__((packed)); } __attribute__((packed));
static struct sdias_sccb sccb __attribute__((aligned(4096))); static struct sdias_sccb sccb __attribute__((aligned(4096)));
static struct sdias_evbuf sdias_evbuf;
static int sclp_req_done; static DECLARE_COMPLETION(evbuf_accepted);
static wait_queue_head_t sdias_wq; static DECLARE_COMPLETION(evbuf_done);
static DEFINE_MUTEX(sdias_mutex); static DEFINE_MUTEX(sdias_mutex);
/*
* Called by SCLP base when read event data has been completed (async mode only)
*/
static void sclp_sdias_receiver_fn(struct evbuf_header *evbuf)
{
memcpy(&sdias_evbuf, evbuf,
min_t(unsigned long, sizeof(sdias_evbuf), evbuf->length));
complete(&evbuf_done);
TRACE("sclp_sdias_receiver_fn done\n");
}
/*
* Called by SCLP base when sdias event has been accepted
*/
static void sdias_callback(struct sclp_req *request, void *data) static void sdias_callback(struct sclp_req *request, void *data)
{ {
sclp_req_done = 1; complete(&evbuf_accepted);
wake_up(&sdias_wq); /* Inform caller, that request is complete */
TRACE("callback done\n"); TRACE("callback done\n");
} }
...@@ -80,7 +95,6 @@ static int sdias_sclp_send(struct sclp_req *req) ...@@ -80,7 +95,6 @@ static int sdias_sclp_send(struct sclp_req *req)
int rc; int rc;
for (retries = SDIAS_RETRIES; retries; retries--) { for (retries = SDIAS_RETRIES; retries; retries--) {
sclp_req_done = 0;
TRACE("add request\n"); TRACE("add request\n");
rc = sclp_add_request(req); rc = sclp_add_request(req);
if (rc) { if (rc) {
...@@ -91,16 +105,31 @@ static int sdias_sclp_send(struct sclp_req *req) ...@@ -91,16 +105,31 @@ static int sdias_sclp_send(struct sclp_req *req)
continue; continue;
} }
/* initiated, wait for completion of service call */ /* initiated, wait for completion of service call */
wait_event(sdias_wq, (sclp_req_done == 1)); wait_for_completion(&evbuf_accepted);
if (req->status == SCLP_REQ_FAILED) { if (req->status == SCLP_REQ_FAILED) {
TRACE("sclp request failed\n"); TRACE("sclp request failed\n");
rc = -EIO;
continue; continue;
} }
/* if not accepted, retry */
if (!(sccb.evbuf.hdr.flags & 0x80)) {
TRACE("sclp request failed: flags=%x\n",
sccb.evbuf.hdr.flags);
continue;
}
/*
* for the sync interface the response is in the initial sccb
*/
if (!sclp_sdias_register.receiver_fn) {
memcpy(&sdias_evbuf, &sccb.evbuf, sizeof(sdias_evbuf));
TRACE("sync request done\n");
return 0;
}
/* otherwise we wait for completion */
wait_for_completion(&evbuf_done);
TRACE("request done\n"); TRACE("request done\n");
break; return 0;
} }
return rc; return -EIO;
} }
/* /*
...@@ -140,13 +169,12 @@ int sclp_sdias_blk_count(void) ...@@ -140,13 +169,12 @@ int sclp_sdias_blk_count(void)
goto out; goto out;
} }
switch (sccb.evbuf.event_status) { switch (sdias_evbuf.event_status) {
case 0: case 0:
rc = sccb.evbuf.blk_cnt; rc = sdias_evbuf.blk_cnt;
break; break;
default: default:
pr_err("SCLP error: %x\n", pr_err("SCLP error: %x\n", sdias_evbuf.event_status);
sccb.evbuf.event_status);
rc = -EIO; rc = -EIO;
goto out; goto out;
} }
...@@ -211,18 +239,18 @@ int sclp_sdias_copy(void *dest, int start_blk, int nr_blks) ...@@ -211,18 +239,18 @@ int sclp_sdias_copy(void *dest, int start_blk, int nr_blks)
goto out; goto out;
} }
switch (sccb.evbuf.event_status) { switch (sdias_evbuf.event_status) {
case EVSTATE_ALL_STORED: case EVSTATE_ALL_STORED:
TRACE("all stored\n"); TRACE("all stored\n");
case EVSTATE_PART_STORED: case EVSTATE_PART_STORED:
TRACE("part stored: %i\n", sccb.evbuf.blk_cnt); TRACE("part stored: %i\n", sdias_evbuf.blk_cnt);
break; break;
case EVSTATE_NO_DATA: case EVSTATE_NO_DATA:
TRACE("no data\n"); TRACE("no data\n");
default: default:
pr_err("Error from SCLP while copying hsa. " pr_err("Error from SCLP while copying hsa. "
"Event status = %x\n", "Event status = %x\n",
sccb.evbuf.event_status); sdias_evbuf.event_status);
rc = -EIO; rc = -EIO;
} }
out: out:
...@@ -230,19 +258,50 @@ int sclp_sdias_copy(void *dest, int start_blk, int nr_blks) ...@@ -230,19 +258,50 @@ int sclp_sdias_copy(void *dest, int start_blk, int nr_blks)
return rc; return rc;
} }
int __init sclp_sdias_init(void) static int __init sclp_sdias_register_check(void)
{ {
int rc; int rc;
rc = sclp_register(&sclp_sdias_register);
if (rc)
return rc;
if (sclp_sdias_blk_count() == 0) {
sclp_unregister(&sclp_sdias_register);
return -ENODEV;
}
return 0;
}
static int __init sclp_sdias_init_sync(void)
{
TRACE("Try synchronous mode\n");
sclp_sdias_register.receive_mask = 0;
sclp_sdias_register.receiver_fn = NULL;
return sclp_sdias_register_check();
}
static int __init sclp_sdias_init_async(void)
{
TRACE("Try asynchronous mode\n");
sclp_sdias_register.receive_mask = EVTYP_SDIAS_MASK;
sclp_sdias_register.receiver_fn = sclp_sdias_receiver_fn;
return sclp_sdias_register_check();
}
int __init sclp_sdias_init(void)
{
if (ipl_info.type != IPL_TYPE_FCP_DUMP) if (ipl_info.type != IPL_TYPE_FCP_DUMP)
return 0; return 0;
sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long)); sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long));
debug_register_view(sdias_dbf, &debug_sprintf_view); debug_register_view(sdias_dbf, &debug_sprintf_view);
debug_set_level(sdias_dbf, 6); debug_set_level(sdias_dbf, 6);
rc = sclp_register(&sclp_sdias_register); if (sclp_sdias_init_sync() == 0)
if (rc) goto out;
return rc; if (sclp_sdias_init_async() == 0)
init_waitqueue_head(&sdias_wq); goto out;
TRACE("init failed\n");
return -ENODEV;
out:
TRACE("init done\n"); TRACE("init done\n");
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment