summaryrefslogtreecommitdiff
path: root/drivers/s390/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/char')
-rw-r--r--drivers/s390/char/Kconfig21
-rw-r--r--drivers/s390/char/Makefile5
-rw-r--r--drivers/s390/char/con3215.c2
-rw-r--r--drivers/s390/char/con3270.c2
-rw-r--r--drivers/s390/char/hmcdrv_ftp.c6
-rw-r--r--drivers/s390/char/sclp.c5
-rw-r--r--drivers/s390/char/sclp_config.c102
-rw-r--r--drivers/s390/char/sclp_cpi.c40
-rw-r--r--drivers/s390/char/sclp_early.c16
-rw-r--r--drivers/s390/char/vmcp.c11
-rw-r--r--drivers/s390/char/vmur.c15
-rw-r--r--drivers/s390/char/zcore.c461
12 files changed, 185 insertions, 501 deletions
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
index eaca3e006..b3f1c4589 100644
--- a/drivers/s390/char/Kconfig
+++ b/drivers/s390/char/Kconfig
@@ -78,19 +78,6 @@ config SCLP_VT220_CONSOLE
Include support for using an IBM SCLP VT220-compatible terminal as a
Linux system console.
-config SCLP_CPI
- def_tristate m
- prompt "Control-Program Identification"
- depends on S390
- help
- This option enables the hardware console interface for system
- identification. This is commonly used for workload management and
- gives you a nice name for the system on the service element.
- Please select this option as a module since built-in operation is
- completely untested.
- You should only select this option if you know what you are doing,
- need this feature and intend to run your kernel in LPAR.
-
config SCLP_ASYNC
def_tristate m
prompt "Support for Call Home via Asynchronous SCLP Records"
@@ -125,6 +112,14 @@ config HMC_DRV
transfer cache size from it's default value 0.5MB to N bytes. If N
is zero, then no caching is performed.
+config SCLP_OFB
+ def_bool n
+ prompt "Support for Open-for-Business SCLP Event"
+ depends on S390
+ help
+ This option enables the Open-for-Business interface to the s390
+ Service Element.
+
config S390_TAPE
def_tristate m
prompt "S/390 tape device support"
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index 6fa9364d1..dd2f7c832 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -16,7 +16,6 @@ obj-$(CONFIG_TN3215) += con3215.o
obj-$(CONFIG_SCLP_TTY) += sclp_tty.o
obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o
obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o
-obj-$(CONFIG_SCLP_CPI) += sclp_cpi.o
obj-$(CONFIG_SCLP_ASYNC) += sclp_async.o
obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o
@@ -30,9 +29,7 @@ obj-$(CONFIG_S390_TAPE_3590) += tape_3590.o
obj-$(CONFIG_MONREADER) += monreader.o
obj-$(CONFIG_MONWRITER) += monwriter.o
obj-$(CONFIG_S390_VMUR) += vmur.o
-
-zcore_mod-objs := sclp_sdias.o zcore.o
-obj-$(CONFIG_CRASH_DUMP) += zcore_mod.o
+obj-$(CONFIG_CRASH_DUMP) += sclp_sdias.o zcore.o
hmcdrv-objs := hmcdrv_mod.o hmcdrv_dev.o hmcdrv_ftp.o hmcdrv_cache.o diag_ftp.o sclp_ftp.o
obj-$(CONFIG_HMC_DRV) += hmcdrv.o
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 0fc3fe5fd..7d82bbcb1 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -922,6 +922,8 @@ static int __init con3215_init(void)
spin_lock_init(&raw3215_freelist_lock);
for (i = 0; i < NR_3215_REQ; i++) {
req = kzalloc(sizeof(struct raw3215_req), GFP_KERNEL | GFP_DMA);
+ if (!req)
+ return -ENOMEM;
req->next = raw3215_freelist;
raw3215_freelist = req;
}
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index 7c511add5..4d7a9badf 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -606,6 +606,8 @@ con3270_init(void)
return PTR_ERR(rp);
condev = kzalloc(sizeof(struct con3270), GFP_KERNEL | GFP_DMA);
+ if (!condev)
+ return -ENOMEM;
condev->view.dev = rp;
condev->read = raw3270_request_alloc(0);
diff --git a/drivers/s390/char/hmcdrv_ftp.c b/drivers/s390/char/hmcdrv_ftp.c
index d4b61d908..8cb7d8fba 100644
--- a/drivers/s390/char/hmcdrv_ftp.c
+++ b/drivers/s390/char/hmcdrv_ftp.c
@@ -37,7 +37,7 @@ struct hmcdrv_ftp_ops {
static enum hmcdrv_ftp_cmdid hmcdrv_ftp_cmd_getid(const char *cmd, int len);
static int hmcdrv_ftp_parse(char *cmd, struct hmcdrv_ftp_cmdspec *ftp);
-static struct hmcdrv_ftp_ops *hmcdrv_ftp_funcs; /* current operations */
+static const struct hmcdrv_ftp_ops *hmcdrv_ftp_funcs; /* current operations */
static DEFINE_MUTEX(hmcdrv_ftp_mutex); /* mutex for hmcdrv_ftp_funcs */
static unsigned hmcdrv_ftp_refcnt; /* start/shutdown reference counter */
@@ -290,13 +290,13 @@ ssize_t hmcdrv_ftp_cmd(char __kernel *cmd, loff_t offset,
*/
int hmcdrv_ftp_startup(void)
{
- static struct hmcdrv_ftp_ops hmcdrv_ftp_zvm = {
+ static const struct hmcdrv_ftp_ops hmcdrv_ftp_zvm = {
.startup = diag_ftp_startup,
.shutdown = diag_ftp_shutdown,
.transfer = diag_ftp_cmd
};
- static struct hmcdrv_ftp_ops hmcdrv_ftp_lpar = {
+ static const struct hmcdrv_ftp_ops hmcdrv_ftp_lpar = {
.startup = sclp_ftp_startup,
.shutdown = sclp_ftp_shutdown,
.transfer = sclp_ftp_cmd
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index f58bf4c6c..272898225 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -579,9 +579,8 @@ sclp_sync_wait(void)
old_tick = local_tick_disable();
trace_hardirqs_on();
__ctl_store(cr0, 0, 0);
- cr0_sync = cr0;
- cr0_sync &= 0xffff00a0;
- cr0_sync |= 0x00000200;
+ cr0_sync = cr0 & ~CR0_IRQ_SUBCLASS_MASK;
+ cr0_sync |= 1UL << (63 - 54);
__ctl_load(cr0_sync, 0, 0);
__arch_local_irq_stosm(0x01);
/* Loop until driver state indicates finished request */
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
index 944156207..2ced50ccc 100644
--- a/drivers/s390/char/sclp_config.c
+++ b/drivers/s390/char/sclp_config.c
@@ -11,6 +11,8 @@
#include <linux/cpu.h>
#include <linux/device.h>
#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
#include <asm/smp.h>
#include "sclp.h"
@@ -20,8 +22,22 @@ struct conf_mgm_data {
u8 ev_qualifier;
} __attribute__((packed));
+#define OFB_DATA_MAX 64
+
+struct sclp_ofb_evbuf {
+ struct evbuf_header header;
+ struct conf_mgm_data cm_data;
+ char ev_data[OFB_DATA_MAX];
+} __packed;
+
+struct sclp_ofb_sccb {
+ struct sccb_header header;
+ struct sclp_ofb_evbuf ofb_evbuf;
+} __packed;
+
#define EV_QUAL_CPU_CHANGE 1
#define EV_QUAL_CAP_CHANGE 3
+#define EV_QUAL_OPEN4BUSINESS 5
static struct work_struct sclp_cpu_capability_work;
static struct work_struct sclp_cpu_change_work;
@@ -63,15 +79,99 @@ static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
static struct sclp_register sclp_conf_register =
{
+#ifdef CONFIG_SCLP_OFB
+ .send_mask = EVTYP_CONFMGMDATA_MASK,
+#endif
.receive_mask = EVTYP_CONFMGMDATA_MASK,
.receiver_fn = sclp_conf_receiver_fn,
};
+#ifdef CONFIG_SCLP_OFB
+static int sclp_ofb_send_req(char *ev_data, size_t len)
+{
+ static DEFINE_MUTEX(send_mutex);
+ struct sclp_ofb_sccb *sccb;
+ int rc, response;
+
+ if (len > OFB_DATA_MAX)
+ return -EINVAL;
+ sccb = (struct sclp_ofb_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ if (!sccb)
+ return -ENOMEM;
+ /* Setup SCCB for Control-Program Identification */
+ sccb->header.length = sizeof(struct sclp_ofb_sccb);
+ sccb->ofb_evbuf.header.length = sizeof(struct sclp_ofb_evbuf);
+ sccb->ofb_evbuf.header.type = EVTYP_CONFMGMDATA;
+ sccb->ofb_evbuf.cm_data.ev_qualifier = EV_QUAL_OPEN4BUSINESS;
+ memcpy(sccb->ofb_evbuf.ev_data, ev_data, len);
+
+ if (!(sclp_conf_register.sclp_receive_mask & EVTYP_CONFMGMDATA_MASK))
+ pr_warn("SCLP receiver did not register to receive "
+ "Configuration Management Data Events.\n");
+
+ mutex_lock(&send_mutex);
+ rc = sclp_sync_request(SCLP_CMDW_WRITE_EVENT_DATA, sccb);
+ mutex_unlock(&send_mutex);
+ if (rc)
+ goto out;
+ response = sccb->header.response_code;
+ if (response != 0x0020) {
+ pr_err("Open for Business request failed with response code "
+ "0x%04x\n", response);
+ rc = -EIO;
+ }
+out:
+ free_page((unsigned long)sccb);
+ return rc;
+}
+
+static ssize_t sysfs_ofb_data_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ int rc;
+
+ rc = sclp_ofb_send_req(buf, count);
+ return rc ?: count;
+}
+
+static struct bin_attribute ofb_bin_attr = {
+ .attr = {
+ .name = "event_data",
+ .mode = S_IWUSR,
+ },
+ .write = sysfs_ofb_data_write,
+};
+#endif
+
+static int __init sclp_ofb_setup(void)
+{
+#ifdef CONFIG_SCLP_OFB
+ struct kset *ofb_kset;
+ int rc;
+
+ ofb_kset = kset_create_and_add("ofb", NULL, firmware_kobj);
+ if (!ofb_kset)
+ return -ENOMEM;
+ rc = sysfs_create_bin_file(&ofb_kset->kobj, &ofb_bin_attr);
+ if (rc) {
+ kset_unregister(ofb_kset);
+ return rc;
+ }
+#endif
+ return 0;
+}
+
static int __init sclp_conf_init(void)
{
+ int rc;
+
INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify);
INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify);
- return sclp_register(&sclp_conf_register);
+ rc = sclp_register(&sclp_conf_register);
+ if (rc)
+ return rc;
+ return sclp_ofb_setup();
}
__initcall(sclp_conf_init);
diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c
deleted file mode 100644
index d70d8c202..000000000
--- a/drivers/s390/char/sclp_cpi.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SCLP control programm identification
- *
- * Copyright IBM Corp. 2001, 2007
- * Author(s): Martin Peschke <mpeschke@de.ibm.com>
- * Michael Ernst <mernst@de.ibm.com>
- */
-
-#include <linux/kmod.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/version.h>
-#include "sclp_cpi_sys.h"
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Identify this operating system instance "
- "to the System z hardware");
-MODULE_AUTHOR("Martin Peschke <mpeschke@de.ibm.com>, "
- "Michael Ernst <mernst@de.ibm.com>");
-
-static char *system_name = "";
-static char *sysplex_name = "";
-
-module_param(system_name, charp, 0);
-MODULE_PARM_DESC(system_name, "e.g. hostname - max. 8 characters");
-module_param(sysplex_name, charp, 0);
-MODULE_PARM_DESC(sysplex_name, "if applicable - max. 8 characters");
-
-static int __init cpi_module_init(void)
-{
- return sclp_cpi_set_data(system_name, sysplex_name, "LINUX",
- LINUX_VERSION_CODE);
-}
-
-static void __exit cpi_module_exit(void)
-{
-}
-
-module_init(cpi_module_init);
-module_exit(cpi_module_exit);
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index 7bc6df310..6804354c4 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -40,10 +40,14 @@ struct read_info_sccb {
u8 fac85; /* 85 */
u8 _pad_86[91 - 86]; /* 86-90 */
u8 flags; /* 91 */
- u8 _pad_92[100 - 92]; /* 92-99 */
+ u8 _pad_92[99 - 92]; /* 92-98 */
+ u8 hamaxpow; /* 99 */
u32 rnsize2; /* 100-103 */
u64 rnmax2; /* 104-111 */
- u8 _pad_112[120 - 112]; /* 112-119 */
+ u8 _pad_112[116 - 112]; /* 112-115 */
+ u8 fac116; /* 116 */
+ u8 _pad_117[119 - 117]; /* 117-118 */
+ u8 fac119; /* 119 */
u16 hcpua; /* 120-121 */
u8 _pad_122[4096 - 122]; /* 122-4095 */
} __packed __aligned(PAGE_SIZE);
@@ -108,6 +112,8 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
sclp.facilities = sccb->facilities;
sclp.has_sprp = !!(sccb->fac84 & 0x02);
sclp.has_core_type = !!(sccb->fac84 & 0x01);
+ sclp.has_esca = !!(sccb->fac116 & 0x08);
+ sclp.has_hvs = !!(sccb->fac119 & 0x80);
if (sccb->fac85 & 0x02)
S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP;
sclp.rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
@@ -115,6 +121,11 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
sclp.rzm <<= 20;
sclp.ibc = sccb->ibc;
+ if (sccb->hamaxpow && sccb->hamaxpow < 64)
+ sclp.hamax = (1UL << sccb->hamaxpow) - 1;
+ else
+ sclp.hamax = U64_MAX;
+
if (!sccb->hcpua) {
if (MACHINE_IS_VM)
sclp.max_cores = 64;
@@ -131,6 +142,7 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
continue;
sclp.has_siif = cpue->siif;
sclp.has_sigpif = cpue->sigpif;
+ sclp.has_sief2 = cpue->sief2;
break;
}
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
index 0fdedadff..2a67b496a 100644
--- a/drivers/s390/char/vmcp.c
+++ b/drivers/s390/char/vmcp.c
@@ -88,14 +88,9 @@ vmcp_write(struct file *file, const char __user *buff, size_t count,
if (count > 240)
return -EINVAL;
- cmd = kmalloc(count + 1, GFP_KERNEL);
- if (!cmd)
- return -ENOMEM;
- if (copy_from_user(cmd, buff, count)) {
- kfree(cmd);
- return -EFAULT;
- }
- cmd[count] = '\0';
+ cmd = memdup_user_nul(buff, count);
+ if (IS_ERR(cmd))
+ return PTR_ERR(cmd);
session = file->private_data;
if (mutex_lock_interruptible(&session->mutex)) {
kfree(cmd);
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
index 0efb27f6f..6c30e93ab 100644
--- a/drivers/s390/char/vmur.c
+++ b/drivers/s390/char/vmur.c
@@ -782,24 +782,11 @@ static int ur_release(struct inode *inode, struct file *file)
static loff_t ur_llseek(struct file *file, loff_t offset, int whence)
{
- loff_t newpos;
-
if ((file->f_flags & O_ACCMODE) != O_RDONLY)
return -ESPIPE; /* seek allowed only for reader */
if (offset % PAGE_SIZE)
return -ESPIPE; /* only multiples of 4K allowed */
- switch (whence) {
- case 0: /* SEEK_SET */
- newpos = offset;
- break;
- case 1: /* SEEK_CUR */
- newpos = file->f_pos + offset;
- break;
- default:
- return -EINVAL;
- }
- file->f_pos = newpos;
- return newpos;
+ return no_seek_end_llseek(file, offset, whence);
}
static const struct file_operations ur_fops = {
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 823f41fc4..5043ecfa1 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -28,13 +28,12 @@
#include <asm/processor.h>
#include <asm/irqflags.h>
#include <asm/checksum.h>
+#include <asm/os_info.h>
#include <asm/switch_to.h>
#include "sclp.h"
#define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x)
-#define TO_USER 1
-#define TO_KERNEL 0
#define CHUNK_INFO_SIZE 34 /* 2 16-byte char, each followed by blank */
enum arch_id {
@@ -42,241 +41,93 @@ enum arch_id {
ARCH_S390X = 1,
};
-/* dump system info */
-
-struct sys_info {
- enum arch_id arch;
- unsigned long sa_base;
- u32 sa_size;
- int cpu_map[NR_CPUS];
- unsigned long mem_size;
- struct save_area lc_mask;
-};
-
struct ipib_info {
unsigned long ipib;
u32 checksum;
} __attribute__((packed));
-static struct sys_info sys_info;
static struct debug_info *zcore_dbf;
static int hsa_available;
static struct dentry *zcore_dir;
-static struct dentry *zcore_file;
static struct dentry *zcore_memmap_file;
static struct dentry *zcore_reipl_file;
static struct dentry *zcore_hsa_file;
static struct ipl_parameter_block *ipl_block;
+static char hsa_buf[PAGE_SIZE] __aligned(PAGE_SIZE);
+
/*
- * Copy memory from HSA to kernel or user memory (not reentrant):
+ * Copy memory from HSA to user memory (not reentrant):
*
- * @dest: Kernel or user buffer where memory should be copied to
+ * @dest: User buffer where memory should be copied to
* @src: Start address within HSA where data should be copied
* @count: Size of buffer, which should be copied
- * @mode: Either TO_KERNEL or TO_USER
*/
-int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode)
+int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count)
{
- int offs, blk_num;
- static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+ unsigned long offset, bytes;
if (!hsa_available)
return -ENODATA;
- if (count == 0)
- return 0;
- /* copy first block */
- offs = 0;
- if ((src % PAGE_SIZE) != 0) {
- blk_num = src / PAGE_SIZE + 2;
- if (sclp_sdias_copy(buf, blk_num, 1)) {
+ while (count) {
+ if (sclp_sdias_copy(hsa_buf, src / PAGE_SIZE + 2, 1)) {
TRACE("sclp_sdias_copy() failed\n");
return -EIO;
}
- offs = min((PAGE_SIZE - (src % PAGE_SIZE)), count);
- if (mode == TO_USER) {
- if (copy_to_user((__force __user void*) dest,
- buf + (src % PAGE_SIZE), offs))
- return -EFAULT;
- } else
- memcpy(dest, buf + (src % PAGE_SIZE), offs);
- }
- if (offs == count)
- goto out;
-
- /* copy middle */
- for (; (offs + PAGE_SIZE) <= count; offs += PAGE_SIZE) {
- blk_num = (src + offs) / PAGE_SIZE + 2;
- if (sclp_sdias_copy(buf, blk_num, 1)) {
- TRACE("sclp_sdias_copy() failed\n");
- return -EIO;
- }
- if (mode == TO_USER) {
- if (copy_to_user((__force __user void*) dest + offs,
- buf, PAGE_SIZE))
- return -EFAULT;
- } else
- memcpy(dest + offs, buf, PAGE_SIZE);
- }
- if (offs == count)
- goto out;
-
- /* copy last block */
- blk_num = (src + offs) / PAGE_SIZE + 2;
- if (sclp_sdias_copy(buf, blk_num, 1)) {
- TRACE("sclp_sdias_copy() failed\n");
- return -EIO;
- }
- if (mode == TO_USER) {
- if (copy_to_user((__force __user void*) dest + offs, buf,
- count - offs))
+ offset = src % PAGE_SIZE;
+ bytes = min(PAGE_SIZE - offset, count);
+ if (copy_to_user(dest, hsa_buf + offset, bytes))
return -EFAULT;
- } else
- memcpy(dest + offs, buf, count - offs);
-out:
- return 0;
-}
-
-static int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count)
-{
- return memcpy_hsa((void __force *) dest, src, count, TO_USER);
-}
-
-static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
-{
- return memcpy_hsa(dest, src, count, TO_KERNEL);
-}
-
-static int __init init_cpu_info(enum arch_id arch)
-{
- struct save_area_ext *sa_ext;
-
- /* get info for boot cpu from lowcore, stored in the HSA */
-
- sa_ext = dump_save_areas.areas[0];
- if (!sa_ext)
- return -ENOMEM;
- if (memcpy_hsa_kernel(&sa_ext->sa, sys_info.sa_base,
- sys_info.sa_size) < 0) {
- TRACE("could not copy from HSA\n");
- kfree(sa_ext);
- return -EIO;
+ src += bytes;
+ dest += bytes;
+ count -= bytes;
}
- if (MACHINE_HAS_VX)
- save_vx_regs_safe(sa_ext->vx_regs);
return 0;
}
-static DEFINE_MUTEX(zcore_mutex);
-
-#define DUMP_VERSION 0x5
-#define DUMP_MAGIC 0xa8190173618f23fdULL
-#define DUMP_ARCH_S390X 2
-#define DUMP_ARCH_S390 1
-#define HEADER_SIZE 4096
-
-/* dump header dumped according to s390 crash dump format */
-
-struct zcore_header {
- u64 magic;
- u32 version;
- u32 header_size;
- u32 dump_level;
- u32 page_size;
- u64 mem_size;
- u64 mem_start;
- u64 mem_end;
- u32 num_pages;
- u32 pad1;
- u64 tod;
- struct cpuid cpu_id;
- u32 arch_id;
- u32 volnr;
- u32 build_arch;
- u64 rmem_size;
- u8 mvdump;
- u16 cpu_cnt;
- u16 real_cpu_cnt;
- u8 end_pad1[0x200-0x061];
- u64 mvdump_sign;
- u64 mvdump_zipl_time;
- u8 end_pad2[0x800-0x210];
- u32 lc_vec[512];
-} __attribute__((packed,__aligned__(16)));
-
-static struct zcore_header zcore_header = {
- .magic = DUMP_MAGIC,
- .version = DUMP_VERSION,
- .header_size = 4096,
- .dump_level = 0,
- .page_size = PAGE_SIZE,
- .mem_start = 0,
- .build_arch = DUMP_ARCH_S390X,
-};
-
/*
- * Copy lowcore info to buffer. Use map in order to copy only register parts.
+ * Copy memory from HSA to kernel memory (not reentrant):
*
- * @buf: User buffer
- * @sa: Pointer to save area
- * @sa_off: Offset in save area to copy
- * @len: Number of bytes to copy
+ * @dest: Kernel or user buffer where memory should be copied to
+ * @src: Start address within HSA where data should be copied
+ * @count: Size of buffer, which should be copied
*/
-static int copy_lc(void __user *buf, void *sa, int sa_off, int len)
+int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
{
- int i;
- char *lc_mask = (char*)&sys_info.lc_mask;
+ unsigned long offset, bytes;
- for (i = 0; i < len; i++) {
- if (!lc_mask[i + sa_off])
- continue;
- if (copy_to_user(buf + i, sa + sa_off + i, 1))
- return -EFAULT;
+ if (!hsa_available)
+ return -ENODATA;
+
+ while (count) {
+ if (sclp_sdias_copy(hsa_buf, src / PAGE_SIZE + 2, 1)) {
+ TRACE("sclp_sdias_copy() failed\n");
+ return -EIO;
+ }
+ offset = src % PAGE_SIZE;
+ bytes = min(PAGE_SIZE - offset, count);
+ memcpy(dest, hsa_buf + offset, bytes);
+ src += bytes;
+ dest += bytes;
+ count -= bytes;
}
return 0;
}
-/*
- * Copy lowcores info to memory, if necessary
- *
- * @buf: User buffer
- * @addr: Start address of buffer in dump memory
- * @count: Size of buffer
- */
-static int zcore_add_lc(char __user *buf, unsigned long start, size_t count)
+static int __init init_cpu_info(void)
{
- unsigned long end;
- int i;
-
- if (count == 0)
- return 0;
+ struct save_area *sa;
- end = start + count;
- for (i = 0; i < dump_save_areas.count; i++) {
- unsigned long cp_start, cp_end; /* copy range */
- unsigned long sa_start, sa_end; /* save area range */
- unsigned long prefix;
- unsigned long sa_off, len, buf_off;
- struct save_area *save_area = &dump_save_areas.areas[i]->sa;
-
- prefix = save_area->pref_reg;
- sa_start = prefix + sys_info.sa_base;
- sa_end = prefix + sys_info.sa_base + sys_info.sa_size;
-
- if ((end < sa_start) || (start > sa_end))
- continue;
- cp_start = max(start, sa_start);
- cp_end = min(end, sa_end);
-
- buf_off = cp_start - start;
- sa_off = cp_start - sa_start;
- len = cp_end - cp_start;
-
- TRACE("copy_lc for: %lx\n", start);
- if (copy_lc(buf + buf_off, save_area, sa_off, len))
- return -EFAULT;
+ /* get info for boot cpu from lowcore, stored in the HSA */
+ sa = save_area_boot_cpu();
+ if (!sa)
+ return -ENOMEM;
+ if (memcpy_hsa_kernel(hsa_buf, __LC_FPREGS_SAVE_AREA, 512) < 0) {
+ TRACE("could not copy from HSA\n");
+ return -EIO;
}
+ save_area_add_regs(sa, hsa_buf); /* vx registers are saved in smp.c */
return 0;
}
@@ -289,126 +140,6 @@ static void release_hsa(void)
hsa_available = 0;
}
-/*
- * Read routine for zcore character device
- * First 4K are dump header
- * Next 32MB are HSA Memory
- * Rest is read from absolute Memory
- */
-static ssize_t zcore_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
-{
- unsigned long mem_start; /* Start address in memory */
- size_t mem_offs; /* Offset in dump memory */
- size_t hdr_count; /* Size of header part of output buffer */
- size_t size;
- int rc;
-
- mutex_lock(&zcore_mutex);
-
- if (*ppos > (sys_info.mem_size + HEADER_SIZE)) {
- rc = -EINVAL;
- goto fail;
- }
-
- count = min(count, (size_t) (sys_info.mem_size + HEADER_SIZE - *ppos));
-
- /* Copy dump header */
- if (*ppos < HEADER_SIZE) {
- size = min(count, (size_t) (HEADER_SIZE - *ppos));
- if (copy_to_user(buf, &zcore_header + *ppos, size)) {
- rc = -EFAULT;
- goto fail;
- }
- hdr_count = size;
- mem_start = 0;
- } else {
- hdr_count = 0;
- mem_start = *ppos - HEADER_SIZE;
- }
-
- mem_offs = 0;
-
- /* Copy from HSA data */
- if (*ppos < sclp.hsa_size + HEADER_SIZE) {
- size = min((count - hdr_count),
- (size_t) (sclp.hsa_size - mem_start));
- rc = memcpy_hsa_user(buf + hdr_count, mem_start, size);
- if (rc)
- goto fail;
-
- mem_offs += size;
- }
-
- /* Copy from real mem */
- size = count - mem_offs - hdr_count;
- rc = copy_to_user_real(buf + hdr_count + mem_offs,
- (void *) mem_start + mem_offs, size);
- if (rc)
- goto fail;
-
- /*
- * Since s390 dump analysis tools like lcrash or crash
- * expect register sets in the prefix pages of the cpus,
- * we copy them into the read buffer, if necessary.
- * buf + hdr_count: Start of memory part of output buffer
- * mem_start: Start memory address to copy from
- * count - hdr_count: Size of memory area to copy
- */
- if (zcore_add_lc(buf + hdr_count, mem_start, count - hdr_count)) {
- rc = -EFAULT;
- goto fail;
- }
- *ppos += count;
-fail:
- mutex_unlock(&zcore_mutex);
- return (rc < 0) ? rc : count;
-}
-
-static int zcore_open(struct inode *inode, struct file *filp)
-{
- if (!hsa_available)
- return -ENODATA;
- else
- return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
-}
-
-static int zcore_release(struct inode *inode, struct file *filep)
-{
- if (hsa_available)
- release_hsa();
- return 0;
-}
-
-static loff_t zcore_lseek(struct file *file, loff_t offset, int orig)
-{
- loff_t rc;
-
- mutex_lock(&zcore_mutex);
- switch (orig) {
- case 0:
- file->f_pos = offset;
- rc = file->f_pos;
- break;
- case 1:
- file->f_pos += offset;
- rc = file->f_pos;
- break;
- default:
- rc = -EINVAL;
- }
- mutex_unlock(&zcore_mutex);
- return rc;
-}
-
-static const struct file_operations zcore_fops = {
- .owner = THIS_MODULE,
- .llseek = zcore_lseek,
- .read = zcore_read,
- .open = zcore_open,
- .release = zcore_release,
-};
-
static ssize_t zcore_memmap_read(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -512,50 +243,6 @@ static const struct file_operations zcore_hsa_fops = {
.llseek = no_llseek,
};
-static void __init set_lc_mask(struct save_area *map)
-{
- memset(&map->fp_regs, 0xff, sizeof(map->fp_regs));
- memset(&map->gp_regs, 0xff, sizeof(map->gp_regs));
- memset(&map->psw, 0xff, sizeof(map->psw));
- memset(&map->pref_reg, 0xff, sizeof(map->pref_reg));
- memset(&map->fp_ctrl_reg, 0xff, sizeof(map->fp_ctrl_reg));
- memset(&map->tod_reg, 0xff, sizeof(map->tod_reg));
- memset(&map->timer, 0xff, sizeof(map->timer));
- memset(&map->clk_cmp, 0xff, sizeof(map->clk_cmp));
- memset(&map->acc_regs, 0xff, sizeof(map->acc_regs));
- memset(&map->ctrl_regs, 0xff, sizeof(map->ctrl_regs));
-}
-
-/*
- * Initialize dump globals for a given architecture
- */
-static int __init sys_info_init(enum arch_id arch, unsigned long mem_end)
-{
- int rc;
-
- switch (arch) {
- case ARCH_S390X:
- pr_alert("DETECTED 'S390X (64 bit) OS'\n");
- break;
- case ARCH_S390:
- pr_alert("DETECTED 'S390 (32 bit) OS'\n");
- break;
- default:
- pr_alert("0x%x is an unknown architecture.\n",arch);
- return -EINVAL;
- }
- sys_info.sa_base = SAVE_AREA_BASE;
- sys_info.sa_size = sizeof(struct save_area);
- sys_info.arch = arch;
- set_lc_mask(&sys_info.lc_mask);
- rc = init_cpu_info(arch);
- if (rc)
- return rc;
- sys_info.mem_size = mem_end;
-
- return 0;
-}
-
static int __init check_sdias(void)
{
if (!sclp.hsa_size) {
@@ -565,43 +252,6 @@ static int __init check_sdias(void)
return 0;
}
-static int __init get_mem_info(unsigned long *mem, unsigned long *end)
-{
- struct memblock_region *reg;
-
- for_each_memblock(memory, reg) {
- *mem += reg->size;
- *end = max_t(unsigned long, *end, reg->base + reg->size);
- }
- return 0;
-}
-
-static void __init zcore_header_init(int arch, struct zcore_header *hdr,
- unsigned long mem_size)
-{
- u32 prefix;
- int i;
-
- if (arch == ARCH_S390X)
- hdr->arch_id = DUMP_ARCH_S390X;
- else
- hdr->arch_id = DUMP_ARCH_S390;
- hdr->mem_size = mem_size;
- hdr->rmem_size = mem_size;
- hdr->mem_end = sys_info.mem_size;
- hdr->num_pages = mem_size / PAGE_SIZE;
- hdr->tod = get_tod_clock();
- get_cpu_id(&hdr->cpu_id);
- for (i = 0; i < dump_save_areas.count; i++) {
- prefix = dump_save_areas.areas[i]->sa.pref_reg;
- hdr->real_cpu_cnt++;
- if (!prefix)
- continue;
- hdr->lc_vec[hdr->cpu_cnt] = prefix;
- hdr->cpu_cnt++;
- }
-}
-
/*
* Provide IPL parameter information block from either HSA or memory
* for future reipl
@@ -634,11 +284,9 @@ static int __init zcore_reipl_init(void)
static int __init zcore_init(void)
{
- unsigned long mem_size, mem_end;
unsigned char arch;
int rc;
- mem_size = mem_end = 0;
if (ipl_info.type != IPL_TYPE_FCP_DUMP)
return -ENODATA;
if (OLDMEM_BASE)
@@ -672,14 +320,10 @@ static int __init zcore_init(void)
goto fail;
}
- rc = get_mem_info(&mem_size, &mem_end);
- if (rc)
- goto fail;
-
- rc = sys_info_init(arch, mem_end);
+ pr_alert("DETECTED 'S390X (64 bit) OS'\n");
+ rc = init_cpu_info();
if (rc)
goto fail;
- zcore_header_init(arch, &zcore_header, mem_size);
rc = zcore_reipl_init();
if (rc)
@@ -690,17 +334,11 @@ static int __init zcore_init(void)
rc = -ENOMEM;
goto fail;
}
- zcore_file = debugfs_create_file("mem", S_IRUSR, zcore_dir, NULL,
- &zcore_fops);
- if (!zcore_file) {
- rc = -ENOMEM;
- goto fail_dir;
- }
zcore_memmap_file = debugfs_create_file("memmap", S_IRUSR, zcore_dir,
NULL, &zcore_memmap_fops);
if (!zcore_memmap_file) {
rc = -ENOMEM;
- goto fail_file;
+ goto fail_dir;
}
zcore_reipl_file = debugfs_create_file("reipl", S_IRUSR, zcore_dir,
NULL, &zcore_reipl_fops);
@@ -720,8 +358,6 @@ fail_reipl_file:
debugfs_remove(zcore_reipl_file);
fail_memmap_file:
debugfs_remove(zcore_memmap_file);
-fail_file:
- debugfs_remove(zcore_file);
fail_dir:
debugfs_remove(zcore_dir);
fail:
@@ -737,7 +373,6 @@ static void __exit zcore_exit(void)
debugfs_remove(zcore_hsa_file);
debugfs_remove(zcore_reipl_file);
debugfs_remove(zcore_memmap_file);
- debugfs_remove(zcore_file);
debugfs_remove(zcore_dir);
diag308(DIAG308_REL_HSA, NULL);
}