aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/char/sclp_sdias.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-22 18:15:32 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-22 18:15:32 -0700
commitdb1417967959569599da2a4bd0ffb93b17ad795f (patch)
tree08751414d5f4a9e264af924154ed3543a8e573a9 /drivers/s390/char/sclp_sdias.c
parentsecurity: optimize avc_audit() common path (diff)
parent[S390] kernel: Pass correct stack for smp_call_ipl_cpu() (diff)
downloadlinux-dev-db1417967959569599da2a4bd0ffb93b17ad795f.tar.xz
linux-dev-db1417967959569599da2a4bd0ffb93b17ad795f.zip
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 patches from Martin Schwidefsky: "The biggest patch is the rework of the smp code, something I wanted to do for some time. There are some patches for our various dump methods and one new thing: z/VM LGR detection. LGR stands for linux-guest- relocation and is the guest migration feature of z/VM. For debugging purposes we keep a log of the systems where a specific guest has lived." Fix up trivial conflict in arch/s390/kernel/smp.c due to the scheduler cleanup having removed some code next to removed s390 code. * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: [S390] kernel: Pass correct stack for smp_call_ipl_cpu() [S390] Ensure that vmcore_info pointer is never accessed directly [S390] dasd: prevent validate server for offline devices [S390] Remove monolithic build option for zcrypt driver. [S390] stack dump: fix indentation in output [S390] kernel: Add OS info memory interface [S390] Use block_sigmask() [S390] kernel: Add z/VM LGR detection [S390] irq: external interrupt code passing [S390] irq: set __ARCH_IRQ_EXIT_IRQS_DISABLED [S390] zfcpdump: Implement async sdias event processing [S390] Use copy_to_absolute_zero() instead of "stura/sturg" [S390] rework idle code [S390] rework smp code [S390] rename lowcore field [S390] Fix gcc 4.6.0 compile warning
Diffstat (limited to 'drivers/s390/char/sclp_sdias.c')
-rw-r--r--drivers/s390/char/sclp_sdias.c101
1 files changed, 80 insertions, 21 deletions
diff --git a/drivers/s390/char/sclp_sdias.c b/drivers/s390/char/sclp_sdias.c
index fa733ecd3d70..69e6c50d4cfb 100644
--- a/drivers/s390/char/sclp_sdias.c
+++ b/drivers/s390/char/sclp_sdias.c
@@ -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>
@@ -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");
}
@@ -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) {
@@ -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;
}
/*
@@ -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;
}
@@ -211,18 +239,18 @@ 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:
@@ -230,19 +258,50 @@ out:
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;
}