Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 293932
b: refs/heads/master
c: e3c652b
h: refs/heads/master
v: v3
  • Loading branch information
Michael Holzheu authored and Martin Schwidefsky committed Mar 11, 2012
1 parent 09212ab commit b2f07de
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 22 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b43445ff6c514822979cc9ae02c76f98bf68721c
refs/heads/master: e3c652b533aab733bf3ffb50654fb82f079c5329
101 changes: 80 additions & 21 deletions trunk/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 b2f07de

Please sign in to comment.