summaryrefslogtreecommitdiff
path: root/drivers/s390
diff options
context:
space:
mode:
authorPeter Oberparleiter <oberpar@linux.ibm.com>2024-06-20 15:20:28 +0300
committerAlexander Gordeev <agordeev@linux.ibm.com>2024-07-01 18:47:01 +0300
commitbb748badfdfb4c6e5c5cb40ded1721f99d32072f (patch)
tree8c147df3bc68ef18e4aa1d5819b47940fab70770 /drivers/s390
parentbf365071ea92b9579d5a272679b74052a5643e35 (diff)
downloadlinux-bb748badfdfb4c6e5c5cb40ded1721f99d32072f.tar.xz
s390/sclp: Add timeout to Store Data requests
Due to a bug in some firmware versions, Store Data requests might not get an event response in certain situations. As a result, the boot process will be blocked indefinitely. Fix this by introducing timeout handling for Store Data requests. In case a timeout occurs, the Store Data operation is halted and no data is retrieved from the SCLP facility. Note: A minority of installed systems rely on Store Data result for device auto-configuration. These systems will fail to boot in case of a Store Data timeout and will need to be switched to manual device configuration as workaround. Reviewed-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com> Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/char/sclp_sd.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/drivers/s390/char/sclp_sd.c b/drivers/s390/char/sclp_sd.c
index 322700b96207..c2dc9aadb7d2 100644
--- a/drivers/s390/char/sclp_sd.c
+++ b/drivers/s390/char/sclp_sd.c
@@ -9,6 +9,7 @@
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/completion.h>
+#include <linux/jiffies.h>
#include <linux/kobject.h>
#include <linux/list.h>
#include <linux/printk.h>
@@ -28,6 +29,8 @@
#define SD_DI_CONFIG 3
+#define SD_TIMEOUT msecs_to_jiffies(30000)
+
struct sclp_sd_evbuf {
struct evbuf_header hdr;
u8 eq;
@@ -234,9 +237,12 @@ static int sclp_sd_sync(unsigned long page, u8 eq, u8 di, u64 sat, u64 sa,
goto out;
}
if (!(evbuf->rflags & 0x80)) {
- rc = wait_for_completion_interruptible(&listener.completion);
- if (rc)
+ rc = wait_for_completion_interruptible_timeout(&listener.completion, SD_TIMEOUT);
+ if (rc == 0)
+ rc = -ETIME;
+ if (rc < 0)
goto out;
+ rc = 0;
evbuf = &listener.evbuf;
}
switch (evbuf->status) {
@@ -323,8 +329,8 @@ static int sclp_sd_store_data(struct sclp_sd_data *result, u8 di)
rc = sclp_sd_sync(page, SD_EQ_STORE_DATA, di, asce, (u64) data, &dsize,
&esize);
if (rc) {
- /* Cancel running request if interrupted */
- if (rc == -ERESTARTSYS) {
+ /* Cancel running request if interrupted or timed out */
+ if (rc == -ERESTARTSYS || rc == -ETIME) {
if (sclp_sd_sync(page, SD_EQ_HALT, di, 0, 0, NULL, NULL)) {
pr_warn("Could not stop Store Data request - leaking at least %zu bytes\n",
(size_t)dsize * PAGE_SIZE);