Skip to content

Commit

Permalink
[S390] zfcpdump: Implement async sdias event processing
Browse files Browse the repository at this point in the history
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: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
  • Loading branch information
Michael Holzheu authored and Martin Schwidefsky committed Mar 11, 2012
1 parent b43445f commit e3c652b
Showing 1 changed file with 80 additions and 21 deletions.
101 changes: 80 additions & 21 deletions drivers/s390/char/sclp_sdias.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define KMSG_COMPONENT "sclp_sdias"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt

#include <linux/completion.h>
#include <linux/sched.h>
#include <asm/sclp.h>
#include <asm/debug.h>
Expand Down Expand Up @@ -62,15 +63,29 @@ struct sdias_sccb {
} __attribute__((packed));

static struct sdias_sccb sccb __attribute__((aligned(4096)));
static struct sdias_evbuf sdias_evbuf;

static int sclp_req_done;
static wait_queue_head_t sdias_wq;
static DECLARE_COMPLETION(evbuf_accepted);
static DECLARE_COMPLETION(evbuf_done);
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)
{
sclp_req_done = 1;
wake_up(&sdias_wq); /* Inform caller, that request is complete */
complete(&evbuf_accepted);
TRACE("callback done\n");
}

Expand All @@ -80,7 +95,6 @@ static int sdias_sclp_send(struct sclp_req *req)
int rc;

for (retries = SDIAS_RETRIES; retries; retries--) {
sclp_req_done = 0;
TRACE("add request\n");
rc = sclp_add_request(req);
if (rc) {
Expand All @@ -91,16 +105,31 @@ static int sdias_sclp_send(struct sclp_req *req)
continue;
}
/* 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) {
TRACE("sclp request failed\n");
rc = -EIO;
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");
break;
return 0;
}
return rc;
return -EIO;
}

/*
Expand Down Expand Up @@ -140,13 +169,12 @@ int sclp_sdias_blk_count(void)
goto out;
}

switch (sccb.evbuf.event_status) {
switch (sdias_evbuf.event_status) {
case 0:
rc = sccb.evbuf.blk_cnt;
rc = sdias_evbuf.blk_cnt;
break;
default:
pr_err("SCLP error: %x\n",
sccb.evbuf.event_status);
pr_err("SCLP error: %x\n", sdias_evbuf.event_status);
rc = -EIO;
goto out;
}
Expand Down Expand Up @@ -211,38 +239,69 @@ int sclp_sdias_copy(void *dest, int start_blk, int nr_blks)
goto out;
}

switch (sccb.evbuf.event_status) {
switch (sdias_evbuf.event_status) {
case EVSTATE_ALL_STORED:
TRACE("all stored\n");
case EVSTATE_PART_STORED:
TRACE("part stored: %i\n", sccb.evbuf.blk_cnt);
TRACE("part stored: %i\n", sdias_evbuf.blk_cnt);
break;
case EVSTATE_NO_DATA:
TRACE("no data\n");
default:
pr_err("Error from SCLP while copying hsa. "
"Event status = %x\n",
sccb.evbuf.event_status);
sdias_evbuf.event_status);
rc = -EIO;
}
out:
mutex_unlock(&sdias_mutex);
return rc;
}

int __init sclp_sdias_init(void)
static int __init sclp_sdias_register_check(void)
{
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)
return 0;
sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long));
debug_register_view(sdias_dbf, &debug_sprintf_view);
debug_set_level(sdias_dbf, 6);
rc = sclp_register(&sclp_sdias_register);
if (rc)
return rc;
init_waitqueue_head(&sdias_wq);
if (sclp_sdias_init_sync() == 0)
goto out;
if (sclp_sdias_init_async() == 0)
goto out;
TRACE("init failed\n");
return -ENODEV;
out:
TRACE("init done\n");
return 0;
}
Expand Down

0 comments on commit e3c652b

Please sign in to comment.