summaryrefslogtreecommitdiff
path: root/drivers/s390/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/char')
-rw-r--r--drivers/s390/char/Makefile1
-rw-r--r--drivers/s390/char/monwriter.c33
-rw-r--r--drivers/s390/char/sclp.h52
-rw-r--r--drivers/s390/char/sclp_cmd.c11
-rw-r--r--drivers/s390/char/sclp_early.c123
-rw-r--r--drivers/s390/char/sclp_early_core.c127
-rw-r--r--drivers/s390/char/sclp_pci.c10
-rw-r--r--drivers/s390/char/tape_3590.c2
-rw-r--r--drivers/s390/char/vmlogrdr.c2
9 files changed, 212 insertions, 149 deletions
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index c6ab34f94b1b..3072b89785dd 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -11,6 +11,7 @@ endif
GCOV_PROFILE_sclp_early_core.o := n
KCOV_INSTRUMENT_sclp_early_core.o := n
UBSAN_SANITIZE_sclp_early_core.o := n
+KASAN_SANITIZE_sclp_early_core.o := n
CFLAGS_sclp_early_core.o += -D__NO_FORTIFY
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
index 4f1a69c9d81d..fdc0c0b7a6f5 100644
--- a/drivers/s390/char/monwriter.c
+++ b/drivers/s390/char/monwriter.c
@@ -58,22 +58,31 @@ struct mon_private {
static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
{
- struct appldata_product_id id;
+ struct appldata_parameter_list *parm_list;
+ struct appldata_product_id *id;
int rc;
- memcpy(id.prod_nr, "LNXAPPL", 7);
- id.prod_fn = myhdr->applid;
- id.record_nr = myhdr->record_num;
- id.version_nr = myhdr->version;
- id.release_nr = myhdr->release;
- id.mod_lvl = myhdr->mod_level;
- rc = appldata_asm(&id, fcn, (void *) buffer, myhdr->datalen);
+ id = kmalloc(sizeof(*id), GFP_KERNEL);
+ parm_list = kmalloc(sizeof(*parm_list), GFP_KERNEL);
+ rc = -ENOMEM;
+ if (!id || !parm_list)
+ goto out;
+ memcpy(id->prod_nr, "LNXAPPL", 7);
+ id->prod_fn = myhdr->applid;
+ id->record_nr = myhdr->record_num;
+ id->version_nr = myhdr->version;
+ id->release_nr = myhdr->release;
+ id->mod_lvl = myhdr->mod_level;
+ rc = appldata_asm(parm_list, id, fcn,
+ (void *) buffer, myhdr->datalen);
if (rc <= 0)
- return rc;
+ goto out;
pr_err("Writing monitor data failed with rc=%i\n", rc);
- if (rc == 5)
- return -EPERM;
- return -EINVAL;
+ rc = (rc == 5) ? -EPERM : -EINVAL;
+out:
+ kfree(id);
+ kfree(parm_list);
+ return rc;
}
static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index 1fe4918088e7..b3fcc24b1182 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -63,6 +63,9 @@
typedef unsigned int sclp_cmdw_t;
#define SCLP_CMDW_READ_CPU_INFO 0x00010001
+#define SCLP_CMDW_READ_SCP_INFO 0x00020001
+#define SCLP_CMDW_READ_STORAGE_INFO 0x00040001
+#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
#define SCLP_CMDW_READ_EVENT_DATA 0x00770005
#define SCLP_CMDW_WRITE_EVENT_DATA 0x00760005
#define SCLP_CMDW_WRITE_EVENT_MASK 0x00780005
@@ -156,6 +159,54 @@ struct read_cpu_info_sccb {
u8 reserved[4096 - 16];
} __attribute__((packed, aligned(PAGE_SIZE)));
+struct read_info_sccb {
+ struct sccb_header header; /* 0-7 */
+ u16 rnmax; /* 8-9 */
+ u8 rnsize; /* 10 */
+ u8 _pad_11[16 - 11]; /* 11-15 */
+ u16 ncpurl; /* 16-17 */
+ u16 cpuoff; /* 18-19 */
+ u8 _pad_20[24 - 20]; /* 20-23 */
+ u8 loadparm[8]; /* 24-31 */
+ u8 _pad_32[42 - 32]; /* 32-41 */
+ u8 fac42; /* 42 */
+ u8 fac43; /* 43 */
+ u8 _pad_44[48 - 44]; /* 44-47 */
+ u64 facilities; /* 48-55 */
+ u8 _pad_56[66 - 56]; /* 56-65 */
+ u8 fac66; /* 66 */
+ u8 _pad_67[76 - 67]; /* 67-83 */
+ u32 ibc; /* 76-79 */
+ u8 _pad80[84 - 80]; /* 80-83 */
+ u8 fac84; /* 84 */
+ u8 fac85; /* 85 */
+ u8 _pad_86[91 - 86]; /* 86-90 */
+ u8 fac91; /* 91 */
+ u8 _pad_92[98 - 92]; /* 92-97 */
+ u8 fac98; /* 98 */
+ u8 hamaxpow; /* 99 */
+ u32 rnsize2; /* 100-103 */
+ u64 rnmax2; /* 104-111 */
+ u32 hsa_size; /* 112-115 */
+ u8 fac116; /* 116 */
+ u8 fac117; /* 117 */
+ u8 fac118; /* 118 */
+ u8 fac119; /* 119 */
+ u16 hcpua; /* 120-121 */
+ u8 _pad_122[124 - 122]; /* 122-123 */
+ u32 hmfai; /* 124-127 */
+ u8 _pad_128[4096 - 128]; /* 128-4095 */
+} __packed __aligned(PAGE_SIZE);
+
+struct read_storage_sccb {
+ struct sccb_header header;
+ u16 max_id;
+ u16 assigned;
+ u16 standby;
+ u16 :16;
+ u32 entries[0];
+} __packed;
+
static inline void sclp_fill_core_info(struct sclp_core_info *info,
struct read_cpu_info_sccb *sccb)
{
@@ -275,6 +326,7 @@ unsigned int sclp_early_con_check_vt220(struct init_sccb *sccb);
int sclp_early_set_event_mask(struct init_sccb *sccb,
sccb_mask_t receive_mask,
sccb_mask_t send_mask);
+int sclp_early_get_info(struct read_info_sccb *info);
/* useful inlines */
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index d7686a68c093..37d42de06079 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -460,15 +460,6 @@ static int sclp_mem_freeze(struct device *dev)
return -EPERM;
}
-struct read_storage_sccb {
- struct sccb_header header;
- u16 max_id;
- u16 assigned;
- u16 standby;
- u16 :16;
- u32 entries[0];
-} __packed;
-
static const struct dev_pm_ops sclp_mem_pm_ops = {
.freeze = sclp_mem_freeze,
};
@@ -498,7 +489,7 @@ static int __init sclp_detect_standby_memory(void)
for (id = 0; id <= sclp_max_storage_id; id++) {
memset(sccb, 0, PAGE_SIZE);
sccb->header.length = PAGE_SIZE;
- rc = sclp_sync_request(0x00040001 | id << 8, sccb);
+ rc = sclp_sync_request(SCLP_CMDW_READ_STORAGE_INFO | id << 8, sccb);
if (rc)
goto out;
switch (sccb->header.response_code) {
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index 9a74abb9224d..e792cee3b51c 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -15,80 +15,17 @@
#include "sclp_sdias.h"
#include "sclp.h"
-#define SCLP_CMDW_READ_SCP_INFO 0x00020001
-#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
-
-struct read_info_sccb {
- struct sccb_header header; /* 0-7 */
- u16 rnmax; /* 8-9 */
- u8 rnsize; /* 10 */
- u8 _pad_11[16 - 11]; /* 11-15 */
- u16 ncpurl; /* 16-17 */
- u16 cpuoff; /* 18-19 */
- u8 _pad_20[24 - 20]; /* 20-23 */
- u8 loadparm[8]; /* 24-31 */
- u8 _pad_32[42 - 32]; /* 32-41 */
- u8 fac42; /* 42 */
- u8 fac43; /* 43 */
- u8 _pad_44[48 - 44]; /* 44-47 */
- u64 facilities; /* 48-55 */
- u8 _pad_56[66 - 56]; /* 56-65 */
- u8 fac66; /* 66 */
- u8 _pad_67[76 - 67]; /* 67-83 */
- u32 ibc; /* 76-79 */
- u8 _pad80[84 - 80]; /* 80-83 */
- u8 fac84; /* 84 */
- u8 fac85; /* 85 */
- u8 _pad_86[91 - 86]; /* 86-90 */
- u8 fac91; /* 91 */
- u8 _pad_92[98 - 92]; /* 92-97 */
- u8 fac98; /* 98 */
- u8 hamaxpow; /* 99 */
- u32 rnsize2; /* 100-103 */
- u64 rnmax2; /* 104-111 */
- u8 _pad_112[116 - 112]; /* 112-115 */
- u8 fac116; /* 116 */
- u8 fac117; /* 117 */
- u8 fac118; /* 118 */
- u8 fac119; /* 119 */
- u16 hcpua; /* 120-121 */
- u8 _pad_122[124 - 122]; /* 122-123 */
- u32 hmfai; /* 124-127 */
- u8 _pad_128[4096 - 128]; /* 128-4095 */
-} __packed __aligned(PAGE_SIZE);
-
static struct sclp_ipl_info sclp_ipl_info;
struct sclp_info sclp;
EXPORT_SYMBOL(sclp);
-static int __init sclp_early_read_info(struct read_info_sccb *sccb)
-{
- int i;
- sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
- SCLP_CMDW_READ_SCP_INFO};
-
- for (i = 0; i < ARRAY_SIZE(commands); i++) {
- memset(sccb, 0, sizeof(*sccb));
- sccb->header.length = sizeof(*sccb);
- sccb->header.function_code = 0x80;
- sccb->header.control_mask[2] = 0x80;
- if (sclp_early_cmd(commands[i], sccb))
- break;
- if (sccb->header.response_code == 0x10)
- return 0;
- if (sccb->header.response_code != 0x1f0)
- break;
- }
- return -EIO;
-}
-
static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
{
struct sclp_core_entry *cpue;
u16 boot_cpu_address, cpu;
- if (sclp_early_read_info(sccb))
+ if (sclp_early_get_info(sccb))
return;
sclp.facilities = sccb->facilities;
@@ -147,6 +84,8 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
sclp_ipl_info.has_dump = 1;
memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN);
+ if (sccb->hsa_size)
+ sclp.hsa_size = (sccb->hsa_size - 1) * PAGE_SIZE;
sclp.mtid = (sccb->fac42 & 0x80) ? (sccb->fac42 & 31) : 0;
sclp.mtid_cp = (sccb->fac42 & 0x80) ? (sccb->fac43 & 31) : 0;
sclp.mtid_prev = (sccb->fac42 & 0x80) ? (sccb->fac66 & 31) : 0;
@@ -189,61 +128,6 @@ int __init sclp_early_get_core_info(struct sclp_core_info *info)
return 0;
}
-static long __init sclp_early_hsa_size_init(struct sdias_sccb *sccb)
-{
- memset(sccb, 0, sizeof(*sccb));
- sccb->hdr.length = sizeof(*sccb);
- sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
- sccb->evbuf.hdr.type = EVTYP_SDIAS;
- sccb->evbuf.event_qual = SDIAS_EQ_SIZE;
- sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
- sccb->evbuf.event_id = 4712;
- sccb->evbuf.dbs = 1;
- if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb))
- return -EIO;
- if (sccb->hdr.response_code != 0x20)
- return -EIO;
- if (sccb->evbuf.blk_cnt == 0)
- return 0;
- return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
-}
-
-static long __init sclp_early_hsa_copy_wait(struct sdias_sccb *sccb)
-{
- memset(sccb, 0, PAGE_SIZE);
- sccb->hdr.length = PAGE_SIZE;
- if (sclp_early_cmd(SCLP_CMDW_READ_EVENT_DATA, sccb))
- return -EIO;
- if ((sccb->hdr.response_code != 0x20) && (sccb->hdr.response_code != 0x220))
- return -EIO;
- if (sccb->evbuf.blk_cnt == 0)
- return 0;
- return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
-}
-
-static void __init sclp_early_hsa_size_detect(void *sccb)
-{
- unsigned long flags;
- long size = -EIO;
-
- raw_local_irq_save(flags);
- if (sclp_early_set_event_mask(sccb, EVTYP_SDIAS_MASK, EVTYP_SDIAS_MASK))
- goto out;
- size = sclp_early_hsa_size_init(sccb);
- /* First check for synchronous response (LPAR) */
- if (size)
- goto out_mask;
- if (!(S390_lowcore.ext_params & 1))
- sclp_early_wait_irq();
- size = sclp_early_hsa_copy_wait(sccb);
-out_mask:
- sclp_early_set_event_mask(sccb, 0, 0);
-out:
- raw_local_irq_restore(flags);
- if (size > 0)
- sclp.hsa_size = size;
-}
-
static void __init sclp_early_console_detect(struct init_sccb *sccb)
{
if (sccb->header.response_code != 0x20)
@@ -262,7 +146,6 @@ void __init sclp_early_detect(void)
sclp_early_facilities_detect(sccb);
sclp_early_init_core_info(sccb);
- sclp_early_hsa_size_detect(sccb);
/*
* Turn off SCLP event notifications. Also save remote masks in the
diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c
index eceba3858cef..387c114ded3f 100644
--- a/drivers/s390/char/sclp_early_core.c
+++ b/drivers/s390/char/sclp_early_core.c
@@ -9,9 +9,13 @@
#include <asm/lowcore.h>
#include <asm/ebcdic.h>
#include <asm/irq.h>
+#include <asm/sections.h>
+#include <asm/mem_detect.h>
#include "sclp.h"
#include "sclp_rw.h"
+static struct read_info_sccb __bootdata(sclp_info_sccb);
+static int __bootdata(sclp_info_sccb_valid);
char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(.data);
int sclp_init_state __section(.data) = sclp_init_state_uninitialized;
/*
@@ -210,11 +214,11 @@ static int sclp_early_setup(int disable, int *have_linemode, int *have_vt220)
* Output one or more lines of text on the SCLP console (VT220 and /
* or line-mode).
*/
-void __sclp_early_printk(const char *str, unsigned int len)
+void __sclp_early_printk(const char *str, unsigned int len, unsigned int force)
{
int have_linemode, have_vt220;
- if (sclp_init_state != sclp_init_state_uninitialized)
+ if (!force && sclp_init_state != sclp_init_state_uninitialized)
return;
if (sclp_early_setup(0, &have_linemode, &have_vt220) != 0)
return;
@@ -227,5 +231,122 @@ void __sclp_early_printk(const char *str, unsigned int len)
void sclp_early_printk(const char *str)
{
- __sclp_early_printk(str, strlen(str));
+ __sclp_early_printk(str, strlen(str), 0);
+}
+
+void sclp_early_printk_force(const char *str)
+{
+ __sclp_early_printk(str, strlen(str), 1);
+}
+
+int __init sclp_early_read_info(void)
+{
+ int i;
+ struct read_info_sccb *sccb = &sclp_info_sccb;
+ sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
+ SCLP_CMDW_READ_SCP_INFO};
+
+ for (i = 0; i < ARRAY_SIZE(commands); i++) {
+ memset(sccb, 0, sizeof(*sccb));
+ sccb->header.length = sizeof(*sccb);
+ sccb->header.function_code = 0x80;
+ sccb->header.control_mask[2] = 0x80;
+ if (sclp_early_cmd(commands[i], sccb))
+ break;
+ if (sccb->header.response_code == 0x10) {
+ sclp_info_sccb_valid = 1;
+ return 0;
+ }
+ if (sccb->header.response_code != 0x1f0)
+ break;
+ }
+ return -EIO;
+}
+
+int __init sclp_early_get_info(struct read_info_sccb *info)
+{
+ if (!sclp_info_sccb_valid)
+ return -EIO;
+
+ *info = sclp_info_sccb;
+ return 0;
+}
+
+int __init sclp_early_get_memsize(unsigned long *mem)
+{
+ unsigned long rnmax;
+ unsigned long rnsize;
+ struct read_info_sccb *sccb = &sclp_info_sccb;
+
+ if (!sclp_info_sccb_valid)
+ return -EIO;
+
+ rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
+ rnsize = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
+ rnsize <<= 20;
+ *mem = rnsize * rnmax;
+ return 0;
+}
+
+int __init sclp_early_get_hsa_size(unsigned long *hsa_size)
+{
+ if (!sclp_info_sccb_valid)
+ return -EIO;
+
+ *hsa_size = 0;
+ if (sclp_info_sccb.hsa_size)
+ *hsa_size = (sclp_info_sccb.hsa_size - 1) * PAGE_SIZE;
+ return 0;
+}
+
+#define SCLP_STORAGE_INFO_FACILITY 0x0000400000000000UL
+
+void __weak __init add_mem_detect_block(u64 start, u64 end) {}
+int __init sclp_early_read_storage_info(void)
+{
+ struct read_storage_sccb *sccb = (struct read_storage_sccb *)&sclp_early_sccb;
+ int rc, id, max_id = 0;
+ unsigned long rn, rzm;
+ sclp_cmdw_t command;
+ u16 sn;
+
+ if (!sclp_info_sccb_valid)
+ return -EIO;
+
+ if (!(sclp_info_sccb.facilities & SCLP_STORAGE_INFO_FACILITY))
+ return -EOPNOTSUPP;
+
+ rzm = sclp_info_sccb.rnsize ?: sclp_info_sccb.rnsize2;
+ rzm <<= 20;
+
+ for (id = 0; id <= max_id; id++) {
+ memset(sclp_early_sccb, 0, sizeof(sclp_early_sccb));
+ sccb->header.length = sizeof(sclp_early_sccb);
+ command = SCLP_CMDW_READ_STORAGE_INFO | (id << 8);
+ rc = sclp_early_cmd(command, sccb);
+ if (rc)
+ goto fail;
+
+ max_id = sccb->max_id;
+ switch (sccb->header.response_code) {
+ case 0x0010:
+ for (sn = 0; sn < sccb->assigned; sn++) {
+ if (!sccb->entries[sn])
+ continue;
+ rn = sccb->entries[sn] >> 16;
+ add_mem_detect_block((rn - 1) * rzm, rn * rzm);
+ }
+ break;
+ case 0x0310:
+ case 0x0410:
+ break;
+ default:
+ goto fail;
+ }
+ }
+
+ return 0;
+fail:
+ mem_detect.count = 0;
+ return -EIO;
}
diff --git a/drivers/s390/char/sclp_pci.c b/drivers/s390/char/sclp_pci.c
index e7c84a4e5eb5..995e9196852e 100644
--- a/drivers/s390/char/sclp_pci.c
+++ b/drivers/s390/char/sclp_pci.c
@@ -24,6 +24,7 @@
#define SCLP_ATYPE_PCI 2
+#define SCLP_ERRNOTIFY_AQ_RESET 0
#define SCLP_ERRNOTIFY_AQ_REPAIR 1
#define SCLP_ERRNOTIFY_AQ_INFO_LOG 2
@@ -111,9 +112,14 @@ static int sclp_pci_check_report(struct zpci_report_error_header *report)
if (report->version != 1)
return -EINVAL;
- if (report->action != SCLP_ERRNOTIFY_AQ_REPAIR &&
- report->action != SCLP_ERRNOTIFY_AQ_INFO_LOG)
+ switch (report->action) {
+ case SCLP_ERRNOTIFY_AQ_RESET:
+ case SCLP_ERRNOTIFY_AQ_REPAIR:
+ case SCLP_ERRNOTIFY_AQ_INFO_LOG:
+ break;
+ default:
return -EINVAL;
+ }
if (report->length > (PAGE_SIZE - sizeof(struct err_notify_sccb)))
return -EINVAL;
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index cdcde18e7220..4554cdf4d6bd 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -971,7 +971,7 @@ tape_3590_print_mim_msg_f0(struct tape_device *device, struct irb *irb)
snprintf(exception, BUFSIZE, "Data degraded");
break;
case 0x03:
- snprintf(exception, BUFSIZE, "Data degraded in partion %i",
+ snprintf(exception, BUFSIZE, "Data degraded in partition %i",
sense->fmt.f70.mp);
break;
case 0x04:
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index 069b9ef08206..58333cb4503f 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -153,7 +153,7 @@ static struct vmlogrdr_priv_t sys_ser[] = {
}
};
-#define MAXMINOR (sizeof(sys_ser)/sizeof(struct vmlogrdr_priv_t))
+#define MAXMINOR ARRAY_SIZE(sys_ser)
static char FENCE[] = {"EOR"};
static int vmlogrdr_major = 0;