summaryrefslogtreecommitdiff
path: root/drivers/s390
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/dasd.c8
-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
-rw-r--r--drivers/s390/cio/Makefile5
-rw-r--r--drivers/s390/cio/airq.c1
-rw-r--r--drivers/s390/cio/chsc_sch.c5
-rw-r--r--drivers/s390/cio/cio.c37
-rw-r--r--drivers/s390/cio/cio.h12
-rw-r--r--drivers/s390/cio/crw.c1
-rw-r--r--drivers/s390/cio/css.c2
-rw-r--r--drivers/s390/cio/device_fsm.c2
-rw-r--r--drivers/s390/cio/io_sch.h45
-rw-r--r--drivers/s390/cio/ioasm.c224
-rw-r--r--drivers/s390/cio/ioasm.h169
-rw-r--r--drivers/s390/cio/qdio_debug.c6
-rw-r--r--drivers/s390/cio/trace.c24
-rw-r--r--drivers/s390/cio/trace.h363
-rw-r--r--drivers/s390/crypto/zcrypt_api.c6
-rw-r--r--drivers/s390/net/ctcm_main.c7
-rw-r--r--drivers/s390/net/qeth_core.h4
-rw-r--r--drivers/s390/net/qeth_core_main.c11
-rw-r--r--drivers/s390/net/qeth_l2_main.c1
-rw-r--r--drivers/s390/net/qeth_l3_main.c40
33 files changed, 883 insertions, 776 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index a263c10359e1..41605dac8309 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -2556,8 +2556,12 @@ static void __dasd_process_request_queue(struct dasd_block *block)
return;
}
- /* if device ist stopped do not fetch new requests */
- if (basedev->stopped)
+ /*
+ * if device is stopped do not fetch new requests
+ * except failfast is active which will let requests fail
+ * immediately in __dasd_block_start_head()
+ */
+ if (basedev->stopped && !(basedev->features & DASD_FEATURE_FAILFAST))
return;
/* Now we try to fetch requests from the request queue */
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
index eaca3e006301..b3f1c458905f 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 6fa9364d1c07..dd2f7c832e5e 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 0fc3fe5fd5b8..7d82bbcb12df 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 7c511add5aa7..4d7a9badfede 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 d4b61d9088fb..8cb7d8fbadd6 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 f58bf4c6c3ee..272898225dbb 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 944156207477..2ced50ccca63 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 d70d8c20229c..000000000000
--- 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 7bc6df3100ef..6804354c42bd 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 0fdedadff7bc..2a67b496a9e2 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 0efb27f6f199..6c30e93ab8fa 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 823f41fc4bbd..5043ecfa1fbc 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);
}
diff --git a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile
index 8c4a386e97f6..3ab9aedeb84a 100644
--- a/drivers/s390/cio/Makefile
+++ b/drivers/s390/cio/Makefile
@@ -2,8 +2,11 @@
# Makefile for the S/390 common i/o drivers
#
+# The following is required for define_trace.h to find ./trace.h
+CFLAGS_trace.o := -I$(src)
+
obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o \
- fcx.o itcw.o crw.o ccwreq.o
+ fcx.o itcw.o crw.o ccwreq.o trace.o ioasm.o
ccw_device-objs += device.o device_fsm.o device_ops.o
ccw_device-objs += device_id.o device_pgid.o device_status.o
obj-y += ccw_device.o cmf.o
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
index 56eb4ee4deba..99b5db469097 100644
--- a/drivers/s390/cio/airq.c
+++ b/drivers/s390/cio/airq.c
@@ -89,6 +89,7 @@ static irqreturn_t do_airq_interrupt(int irq, void *dummy)
set_cpu_flag(CIF_NOHZ_DELAY);
tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
+ trace_s390_cio_adapter_int(tpi_info);
head = &airq_lists[tpi_info->isc];
rcu_read_lock();
hlist_for_each_entry_rcu(airq, head, list)
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
index 213159dec89e..b6f12c2bb114 100644
--- a/drivers/s390/cio/chsc_sch.c
+++ b/drivers/s390/cio/chsc_sch.c
@@ -133,7 +133,7 @@ static int chsc_subchannel_prepare(struct subchannel *sch)
* since we don't have a way to clear the subchannel and
* cannot disable it with a request running.
*/
- cc = stsch_err(sch->schid, &schib);
+ cc = stsch(sch->schid, &schib);
if (!cc && scsw_stctl(&schib.scsw))
return -EAGAIN;
return 0;
@@ -185,8 +185,7 @@ static int __init chsc_init_dbfs(void)
debug_set_level(chsc_debug_log_id, 2);
return 0;
out:
- if (chsc_debug_msg_id)
- debug_unregister(chsc_debug_msg_id);
+ debug_unregister(chsc_debug_msg_id);
return -ENOMEM;
}
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 690b8547e828..39a8ae54e9c1 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -41,6 +41,7 @@
#include "blacklist.h"
#include "cio_debug.h"
#include "chp.h"
+#include "trace.h"
debug_info_t *cio_debug_msg_id;
debug_info_t *cio_debug_trace_id;
@@ -76,12 +77,9 @@ static int __init cio_debug_init(void)
return 0;
out_unregister:
- if (cio_debug_msg_id)
- debug_unregister(cio_debug_msg_id);
- if (cio_debug_trace_id)
- debug_unregister(cio_debug_trace_id);
- if (cio_debug_crw_id)
- debug_unregister(cio_debug_crw_id);
+ debug_unregister(cio_debug_msg_id);
+ debug_unregister(cio_debug_trace_id);
+ debug_unregister(cio_debug_crw_id);
return -1;
}
@@ -348,18 +346,18 @@ int cio_commit_config(struct subchannel *sch)
struct schib schib;
struct irb irb;
- if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib))
+ if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib))
return -ENODEV;
for (retry = 0; retry < 5; retry++) {
/* copy desired changes to local schib */
cio_apply_config(sch, &schib);
- ccode = msch_err(sch->schid, &schib);
+ ccode = msch(sch->schid, &schib);
if (ccode < 0) /* -EIO if msch gets a program check. */
return ccode;
switch (ccode) {
case 0: /* successful */
- if (stsch_err(sch->schid, &schib) ||
+ if (stsch(sch->schid, &schib) ||
!css_sch_is_valid(&schib))
return -ENODEV;
if (cio_check_config(sch, &schib)) {
@@ -394,7 +392,7 @@ int cio_update_schib(struct subchannel *sch)
{
struct schib schib;
- if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib))
+ if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib))
return -ENODEV;
memcpy(&sch->schib, &schib, sizeof(schib));
@@ -503,7 +501,7 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
* If stsch gets an exception, it means the current subchannel set
* is not valid.
*/
- ccode = stsch_err(schid, &sch->schib);
+ ccode = stsch(schid, &sch->schib);
if (ccode) {
err = (ccode == 3) ? -ENXIO : ccode;
goto out;
@@ -542,6 +540,7 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy)
set_cpu_flag(CIF_NOHZ_DELAY);
tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
+ trace_s390_cio_interrupt(tpi_info);
irb = this_cpu_ptr(&cio_irb);
sch = (struct subchannel *)(unsigned long) tpi_info->intparm;
if (!sch) {
@@ -619,7 +618,7 @@ static int cio_test_for_console(struct subchannel_id schid, void *data)
{
struct schib schib;
- if (stsch_err(schid, &schib) != 0)
+ if (stsch(schid, &schib) != 0)
return -ENXIO;
if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
(schib.pmcw.dev == console_devno)) {
@@ -638,7 +637,7 @@ static int cio_get_console_sch_no(void)
if (console_irq != -1) {
/* VM provided us with the irq number of the console. */
schid.sch_no = console_irq;
- if (stsch_err(schid, &schib) != 0 ||
+ if (stsch(schid, &schib) != 0 ||
(schib.pmcw.st != SUBCHANNEL_TYPE_IO) || !schib.pmcw.dnv)
return -1;
console_devno = schib.pmcw.dev;
@@ -708,10 +707,10 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
cc = 0;
for (retry=0;retry<3;retry++) {
schib->pmcw.ena = 0;
- cc = msch_err(schid, schib);
+ cc = msch(schid, schib);
if (cc)
return (cc==3?-ENODEV:-EBUSY);
- if (stsch_err(schid, schib) || !css_sch_is_valid(schib))
+ if (stsch(schid, schib) || !css_sch_is_valid(schib))
return -ENODEV;
if (!schib->pmcw.ena)
return 0;
@@ -758,7 +757,7 @@ static int stsch_reset(struct subchannel_id schid, struct schib *addr)
pgm_check_occured = 0;
s390_base_pgm_handler_fn = cio_reset_pgm_check_handler;
- rc = stsch_err(schid, addr);
+ rc = stsch(schid, addr);
s390_base_pgm_handler_fn = NULL;
/* The program check handler could have changed pgm_check_occured. */
@@ -795,7 +794,7 @@ static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data)
/* No default clear strategy */
break;
}
- stsch_err(schid, &schib);
+ stsch(schid, &schib);
__disable_subchannel_easy(schid, &schib);
}
out:
@@ -917,7 +916,7 @@ void reipl_ccw_dev(struct ccw_dev_id *devid)
{
struct subchannel_id uninitialized_var(schid);
- s390_reset_system(NULL, NULL, NULL);
+ s390_reset_system();
if (reipl_find_schid(devid, &schid) != 0)
panic("IPL Device not found\n");
do_reipl_asm(*((__u32*)&schid));
@@ -943,7 +942,7 @@ int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
if (__chsc_enable_facility(&sda_area, CHSC_SDA_OC_MSS))
return -ENODEV;
}
- if (stsch_err(schid, &schib))
+ if (stsch(schid, &schib))
return -ENODEV;
if (schib.pmcw.st != SUBCHANNEL_TYPE_IO)
return -ENODEV;
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index a01376ae1749..93de0b46b489 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -45,6 +45,18 @@ struct pmcw {
/* ... in an operand exception. */
} __attribute__ ((packed));
+/* I/O-Interruption Code as stored by TEST PENDING INTERRUPTION (TPI). */
+struct tpi_info {
+ struct subchannel_id schid;
+ u32 intparm;
+ u32 adapter_IO:1;
+ u32 :1;
+ u32 isc:3;
+ u32 :27;
+ u32 type:3;
+ u32 :12;
+} __packed __aligned(4);
+
/* Target SCHIB configuration. */
struct schib_config {
u64 mba;
diff --git a/drivers/s390/cio/crw.c b/drivers/s390/cio/crw.c
index 0f8a25f98b10..3d3cd402b376 100644
--- a/drivers/s390/cio/crw.c
+++ b/drivers/s390/cio/crw.c
@@ -14,6 +14,7 @@
#include <linux/wait.h>
#include <asm/crw.h>
#include <asm/ctl_reg.h>
+#include "ioasm.h"
static DEFINE_MUTEX(crw_handler_mutex);
static crw_handler_t crw_handlers[NR_RSCS];
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 489e703dc82d..3d2b20ee613f 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -390,7 +390,7 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
/* Will be done on the slow path. */
return -EAGAIN;
}
- if (stsch_err(schid, &schib)) {
+ if (stsch(schid, &schib)) {
/* Subchannel is not provided. */
return -ENXIO;
}
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 92e03b42e661..8327d47e08b6 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -44,7 +44,7 @@ static void ccw_timeout_log(struct ccw_device *cdev)
sch = to_subchannel(cdev->dev.parent);
private = to_io_private(sch);
orb = &private->orb;
- cc = stsch_err(sch->schid, &schib);
+ cc = stsch(sch->schid, &schib);
printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, "
"device information:\n", get_tod_clock());
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
index b108f4a5c7dd..8975060af96c 100644
--- a/drivers/s390/cio/io_sch.h
+++ b/drivers/s390/cio/io_sch.h
@@ -169,49 +169,4 @@ struct ccw_device_private {
enum interruption_class int_class;
};
-static inline int rsch(struct subchannel_id schid)
-{
- register struct subchannel_id reg1 asm("1") = schid;
- int ccode;
-
- asm volatile(
- " rsch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1)
- : "cc", "memory");
- return ccode;
-}
-
-static inline int hsch(struct subchannel_id schid)
-{
- register struct subchannel_id reg1 asm("1") = schid;
- int ccode;
-
- asm volatile(
- " hsch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1)
- : "cc");
- return ccode;
-}
-
-static inline int xsch(struct subchannel_id schid)
-{
- register struct subchannel_id reg1 asm("1") = schid;
- int ccode;
-
- asm volatile(
- " .insn rre,0xb2760000,%1,0\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1)
- : "cc");
- return ccode;
-}
-
#endif
diff --git a/drivers/s390/cio/ioasm.c b/drivers/s390/cio/ioasm.c
new file mode 100644
index 000000000000..98984818618f
--- /dev/null
+++ b/drivers/s390/cio/ioasm.c
@@ -0,0 +1,224 @@
+/*
+ * Channel subsystem I/O instructions.
+ */
+
+#include <linux/export.h>
+
+#include <asm/chpid.h>
+#include <asm/schid.h>
+#include <asm/crw.h>
+
+#include "ioasm.h"
+#include "orb.h"
+#include "cio.h"
+
+int stsch(struct subchannel_id schid, struct schib *addr)
+{
+ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode = -EIO;
+
+ asm volatile(
+ " stsch 0(%3)\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ "1:\n"
+ EX_TABLE(0b, 1b)
+ : "+d" (ccode), "=m" (*addr)
+ : "d" (reg1), "a" (addr)
+ : "cc");
+ trace_s390_cio_stsch(schid, addr, ccode);
+
+ return ccode;
+}
+EXPORT_SYMBOL(stsch);
+
+int msch(struct subchannel_id schid, struct schib *addr)
+{
+ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode = -EIO;
+
+ asm volatile(
+ " msch 0(%2)\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ "1:\n"
+ EX_TABLE(0b, 1b)
+ : "+d" (ccode)
+ : "d" (reg1), "a" (addr), "m" (*addr)
+ : "cc");
+ trace_s390_cio_msch(schid, addr, ccode);
+
+ return ccode;
+}
+
+int tsch(struct subchannel_id schid, struct irb *addr)
+{
+ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode;
+
+ asm volatile(
+ " tsch 0(%3)\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode), "=m" (*addr)
+ : "d" (reg1), "a" (addr)
+ : "cc");
+ trace_s390_cio_tsch(schid, addr, ccode);
+
+ return ccode;
+}
+
+int ssch(struct subchannel_id schid, union orb *addr)
+{
+ register struct subchannel_id reg1 asm("1") = schid;
+ int ccode = -EIO;
+
+ asm volatile(
+ " ssch 0(%2)\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ "1:\n"
+ EX_TABLE(0b, 1b)
+ : "+d" (ccode)
+ : "d" (reg1), "a" (addr), "m" (*addr)
+ : "cc", "memory");
+ trace_s390_cio_ssch(schid, addr, ccode);
+
+ return ccode;
+}
+EXPORT_SYMBOL(ssch);
+
+int csch(struct subchannel_id schid)
+{
+ register struct subchannel_id reg1 asm("1") = schid;
+ int ccode;
+
+ asm volatile(
+ " csch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode)
+ : "d" (reg1)
+ : "cc");
+ trace_s390_cio_csch(schid, ccode);
+
+ return ccode;
+}
+EXPORT_SYMBOL(csch);
+
+int tpi(struct tpi_info *addr)
+{
+ int ccode;
+
+ asm volatile(
+ " tpi 0(%2)\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode), "=m" (*addr)
+ : "a" (addr)
+ : "cc");
+ trace_s390_cio_tpi(addr, ccode);
+
+ return ccode;
+}
+
+int chsc(void *chsc_area)
+{
+ typedef struct { char _[4096]; } addr_type;
+ int cc;
+
+ asm volatile(
+ " .insn rre,0xb25f0000,%2,0\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (cc), "=m" (*(addr_type *) chsc_area)
+ : "d" (chsc_area), "m" (*(addr_type *) chsc_area)
+ : "cc");
+ trace_s390_cio_chsc(chsc_area, cc);
+
+ return cc;
+}
+EXPORT_SYMBOL(chsc);
+
+int rchp(struct chp_id chpid)
+{
+ register struct chp_id reg1 asm ("1") = chpid;
+ int ccode;
+
+ asm volatile(
+ " lr 1,%1\n"
+ " rchp\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1) : "cc");
+ trace_s390_cio_rchp(chpid, ccode);
+
+ return ccode;
+}
+
+int rsch(struct subchannel_id schid)
+{
+ register struct subchannel_id reg1 asm("1") = schid;
+ int ccode;
+
+ asm volatile(
+ " rsch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode)
+ : "d" (reg1)
+ : "cc", "memory");
+ trace_s390_cio_rsch(schid, ccode);
+
+ return ccode;
+}
+
+int hsch(struct subchannel_id schid)
+{
+ register struct subchannel_id reg1 asm("1") = schid;
+ int ccode;
+
+ asm volatile(
+ " hsch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode)
+ : "d" (reg1)
+ : "cc");
+ trace_s390_cio_hsch(schid, ccode);
+
+ return ccode;
+}
+
+int xsch(struct subchannel_id schid)
+{
+ register struct subchannel_id reg1 asm("1") = schid;
+ int ccode;
+
+ asm volatile(
+ " xsch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode)
+ : "d" (reg1)
+ : "cc");
+ trace_s390_cio_xsch(schid, ccode);
+
+ return ccode;
+}
+
+int stcrw(struct crw *crw)
+{
+ int ccode;
+
+ asm volatile(
+ " stcrw 0(%2)\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (ccode), "=m" (*crw)
+ : "a" (crw)
+ : "cc");
+ trace_s390_cio_stcrw(crw, ccode);
+
+ return ccode;
+}
diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h
index 4d80fc67a06b..b31ee6bff1e4 100644
--- a/drivers/s390/cio/ioasm.h
+++ b/drivers/s390/cio/ioasm.h
@@ -3,165 +3,26 @@
#include <asm/chpid.h>
#include <asm/schid.h>
+#include <asm/crw.h>
#include "orb.h"
#include "cio.h"
+#include "trace.h"
/*
- * TPI info structure
+ * Some S390 specific IO instructions
*/
-struct tpi_info {
- struct subchannel_id schid;
- __u32 intparm; /* interruption parameter */
- __u32 adapter_IO : 1;
- __u32 reserved2 : 1;
- __u32 isc : 3;
- __u32 reserved3 : 12;
- __u32 int_type : 3;
- __u32 reserved4 : 12;
-} __attribute__ ((packed));
-
-/*
- * Some S390 specific IO instructions as inline
- */
-
-static inline int stsch_err(struct subchannel_id schid, struct schib *addr)
-{
- register struct subchannel_id reg1 asm ("1") = schid;
- int ccode = -EIO;
-
- asm volatile(
- " stsch 0(%3)\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- "1:\n"
- EX_TABLE(0b,1b)
- : "+d" (ccode), "=m" (*addr)
- : "d" (reg1), "a" (addr)
- : "cc");
- return ccode;
-}
-
-static inline int msch(struct subchannel_id schid, struct schib *addr)
-{
- register struct subchannel_id reg1 asm ("1") = schid;
- int ccode;
-
- asm volatile(
- " msch 0(%2)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1), "a" (addr), "m" (*addr)
- : "cc");
- return ccode;
-}
-
-static inline int msch_err(struct subchannel_id schid, struct schib *addr)
-{
- register struct subchannel_id reg1 asm ("1") = schid;
- int ccode = -EIO;
-
- asm volatile(
- " msch 0(%2)\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- "1:\n"
- EX_TABLE(0b,1b)
- : "+d" (ccode)
- : "d" (reg1), "a" (addr), "m" (*addr)
- : "cc");
- return ccode;
-}
-
-static inline int tsch(struct subchannel_id schid, struct irb *addr)
-{
- register struct subchannel_id reg1 asm ("1") = schid;
- int ccode;
-
- asm volatile(
- " tsch 0(%3)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode), "=m" (*addr)
- : "d" (reg1), "a" (addr)
- : "cc");
- return ccode;
-}
-
-static inline int ssch(struct subchannel_id schid, union orb *addr)
-{
- register struct subchannel_id reg1 asm("1") = schid;
- int ccode = -EIO;
-
- asm volatile(
- " ssch 0(%2)\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- "1:\n"
- EX_TABLE(0b, 1b)
- : "+d" (ccode)
- : "d" (reg1), "a" (addr), "m" (*addr)
- : "cc", "memory");
- return ccode;
-}
-
-static inline int csch(struct subchannel_id schid)
-{
- register struct subchannel_id reg1 asm("1") = schid;
- int ccode;
-
- asm volatile(
- " csch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1)
- : "cc");
- return ccode;
-}
-
-static inline int tpi(struct tpi_info *addr)
-{
- int ccode;
-
- asm volatile(
- " tpi 0(%2)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode), "=m" (*addr)
- : "a" (addr)
- : "cc");
- return ccode;
-}
-
-static inline int chsc(void *chsc_area)
-{
- typedef struct { char _[4096]; } addr_type;
- int cc;
-
- asm volatile(
- " .insn rre,0xb25f0000,%2,0\n"
- " ipm %0\n"
- " srl %0,28\n"
- : "=d" (cc), "=m" (*(addr_type *) chsc_area)
- : "d" (chsc_area), "m" (*(addr_type *) chsc_area)
- : "cc");
- return cc;
-}
-
-static inline int rchp(struct chp_id chpid)
-{
- register struct chp_id reg1 asm ("1") = chpid;
- int ccode;
-
- asm volatile(
- " lr 1,%1\n"
- " rchp\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode) : "d" (reg1) : "cc");
- return ccode;
-}
+int stsch(struct subchannel_id schid, struct schib *addr);
+int msch(struct subchannel_id schid, struct schib *addr);
+int tsch(struct subchannel_id schid, struct irb *addr);
+int ssch(struct subchannel_id schid, union orb *addr);
+int csch(struct subchannel_id schid);
+int tpi(struct tpi_info *addr);
+int chsc(void *chsc_area);
+int rchp(struct chp_id chpid);
+int rsch(struct subchannel_id schid);
+int hsch(struct subchannel_id schid);
+int xsch(struct subchannel_id schid);
+int stcrw(struct crw *crw);
#endif
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c
index f1f3baa8e6e4..b6fc147f83d8 100644
--- a/drivers/s390/cio/qdio_debug.c
+++ b/drivers/s390/cio/qdio_debug.c
@@ -366,8 +366,6 @@ void qdio_debug_exit(void)
{
qdio_clear_dbf_list();
debugfs_remove(debugfs_root);
- if (qdio_dbf_setup)
- debug_unregister(qdio_dbf_setup);
- if (qdio_dbf_error)
- debug_unregister(qdio_dbf_error);
+ debug_unregister(qdio_dbf_setup);
+ debug_unregister(qdio_dbf_error);
}
diff --git a/drivers/s390/cio/trace.c b/drivers/s390/cio/trace.c
new file mode 100644
index 000000000000..8e706669ac8b
--- /dev/null
+++ b/drivers/s390/cio/trace.c
@@ -0,0 +1,24 @@
+/*
+ * Tracepoint definitions for s390_cio
+ *
+ * Copyright IBM Corp. 2015
+ * Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+ */
+
+#include <asm/crw.h>
+#include "cio.h"
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_stsch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_msch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_tsch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_tpi);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_ssch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_csch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_hsch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_xsch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_rsch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_rchp);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_chsc);
diff --git a/drivers/s390/cio/trace.h b/drivers/s390/cio/trace.h
new file mode 100644
index 000000000000..5b807a09f21b
--- /dev/null
+++ b/drivers/s390/cio/trace.h
@@ -0,0 +1,363 @@
+/*
+ * Tracepoint header for the s390 Common I/O layer (CIO)
+ *
+ * Copyright IBM Corp. 2015
+ * Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+ */
+
+#include <linux/kernel.h>
+#include <asm/crw.h>
+#include <uapi/asm/chpid.h>
+#include <uapi/asm/schid.h>
+#include "cio.h"
+#include "orb.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM s390
+
+#if !defined(_TRACE_S390_CIO_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_S390_CIO_H
+
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(s390_class_schib,
+ TP_PROTO(struct subchannel_id schid, struct schib *schib, int cc),
+ TP_ARGS(schid, schib, cc),
+ TP_STRUCT__entry(
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ __field(u16, devno)
+ __field_struct(struct schib, schib)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->cssid = schid.cssid;
+ __entry->ssid = schid.ssid;
+ __entry->schno = schid.sch_no;
+ __entry->devno = schib->pmcw.dev;
+ __entry->schib = *schib;
+ __entry->cc = cc;
+ ),
+ TP_printk("schid=%x.%x.%04x cc=%d ena=%d st=%d dnv=%d dev=%04x "
+ "lpm=0x%02x pnom=0x%02x lpum=0x%02x pim=0x%02x pam=0x%02x "
+ "pom=0x%02x chpids=%016llx",
+ __entry->cssid, __entry->ssid, __entry->schno, __entry->cc,
+ __entry->schib.pmcw.ena, __entry->schib.pmcw.st,
+ __entry->schib.pmcw.dnv, __entry->schib.pmcw.dev,
+ __entry->schib.pmcw.lpm, __entry->schib.pmcw.pnom,
+ __entry->schib.pmcw.lpum, __entry->schib.pmcw.pim,
+ __entry->schib.pmcw.pam, __entry->schib.pmcw.pom,
+ *((u64 *) __entry->schib.pmcw.chpid)
+ )
+);
+
+/**
+ * s390_cio_stsch - Store Subchannel instruction (STSCH) was performed
+ * @schid: Subchannel ID
+ * @schib: Subchannel-Information block
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schib, s390_cio_stsch,
+ TP_PROTO(struct subchannel_id schid, struct schib *schib, int cc),
+ TP_ARGS(schid, schib, cc)
+);
+
+/**
+ * s390_cio_msch - Modify Subchannel instruction (MSCH) was performed
+ * @schid: Subchannel ID
+ * @schib: Subchannel-Information block
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schib, s390_cio_msch,
+ TP_PROTO(struct subchannel_id schid, struct schib *schib, int cc),
+ TP_ARGS(schid, schib, cc)
+);
+
+/**
+ * s390_cio_tsch - Test Subchannel instruction (TSCH) was performed
+ * @schid: Subchannel ID
+ * @irb: Interruption-Response Block
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_tsch,
+ TP_PROTO(struct subchannel_id schid, struct irb *irb, int cc),
+ TP_ARGS(schid, irb, cc),
+ TP_STRUCT__entry(
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ __field_struct(struct irb, irb)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->cssid = schid.cssid;
+ __entry->ssid = schid.ssid;
+ __entry->schno = schid.sch_no;
+ __entry->irb = *irb;
+ __entry->cc = cc;
+ ),
+ TP_printk("schid=%x.%x.%04x cc=%d dcc=%d pno=%d fctl=0x%x actl=0x%x "
+ "stctl=0x%x dstat=0x%x cstat=0x%x",
+ __entry->cssid, __entry->ssid, __entry->schno, __entry->cc,
+ scsw_cc(&__entry->irb.scsw), scsw_pno(&__entry->irb.scsw),
+ scsw_fctl(&__entry->irb.scsw), scsw_actl(&__entry->irb.scsw),
+ scsw_stctl(&__entry->irb.scsw),
+ scsw_dstat(&__entry->irb.scsw), scsw_cstat(&__entry->irb.scsw)
+ )
+);
+
+/**
+ * s390_cio_tpi - Test Pending Interruption instruction (TPI) was performed
+ * @addr: Address of the I/O interruption code or %NULL
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_tpi,
+ TP_PROTO(struct tpi_info *addr, int cc),
+ TP_ARGS(addr, cc),
+ TP_STRUCT__entry(
+ __field(int, cc)
+ __field_struct(struct tpi_info, tpi_info)
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ ),
+ TP_fast_assign(
+ __entry->cc = cc;
+ if (cc != 0)
+ memset(&__entry->tpi_info, 0, sizeof(struct tpi_info));
+ else if (addr)
+ __entry->tpi_info = *addr;
+ else {
+ memcpy(&__entry->tpi_info, &S390_lowcore.subchannel_id,
+ sizeof(struct tpi_info));
+ }
+ __entry->cssid = __entry->tpi_info.schid.cssid;
+ __entry->ssid = __entry->tpi_info.schid.ssid;
+ __entry->schno = __entry->tpi_info.schid.sch_no;
+ ),
+ TP_printk("schid=%x.%x.%04x cc=%d a=%d isc=%d type=%d",
+ __entry->cssid, __entry->ssid, __entry->schno, __entry->cc,
+ __entry->tpi_info.adapter_IO, __entry->tpi_info.isc,
+ __entry->tpi_info.type
+ )
+);
+
+/**
+ * s390_cio_ssch - Start Subchannel instruction (SSCH) was performed
+ * @schid: Subchannel ID
+ * @orb: Operation-Request Block
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_ssch,
+ TP_PROTO(struct subchannel_id schid, union orb *orb, int cc),
+ TP_ARGS(schid, orb, cc),
+ TP_STRUCT__entry(
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ __field_struct(union orb, orb)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->cssid = schid.cssid;
+ __entry->ssid = schid.ssid;
+ __entry->schno = schid.sch_no;
+ __entry->orb = *orb;
+ __entry->cc = cc;
+ ),
+ TP_printk("schid=%x.%x.%04x cc=%d", __entry->cssid, __entry->ssid,
+ __entry->schno, __entry->cc
+ )
+);
+
+DECLARE_EVENT_CLASS(s390_class_schid,
+ TP_PROTO(struct subchannel_id schid, int cc),
+ TP_ARGS(schid, cc),
+ TP_STRUCT__entry(
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->cssid = schid.cssid;
+ __entry->ssid = schid.ssid;
+ __entry->schno = schid.sch_no;
+ __entry->cc = cc;
+ ),
+ TP_printk("schid=%x.%x.%04x cc=%d", __entry->cssid, __entry->ssid,
+ __entry->schno, __entry->cc
+ )
+);
+
+/**
+ * s390_cio_csch - Clear Subchannel instruction (CSCH) was performed
+ * @schid: Subchannel ID
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schid, s390_cio_csch,
+ TP_PROTO(struct subchannel_id schid, int cc),
+ TP_ARGS(schid, cc)
+);
+
+/**
+ * s390_cio_hsch - Halt Subchannel instruction (HSCH) was performed
+ * @schid: Subchannel ID
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schid, s390_cio_hsch,
+ TP_PROTO(struct subchannel_id schid, int cc),
+ TP_ARGS(schid, cc)
+);
+
+/**
+ * s390_cio_xsch - Cancel Subchannel instruction (XSCH) was performed
+ * @schid: Subchannel ID
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schid, s390_cio_xsch,
+ TP_PROTO(struct subchannel_id schid, int cc),
+ TP_ARGS(schid, cc)
+);
+
+/**
+ * s390_cio_rsch - Resume Subchannel instruction (RSCH) was performed
+ * @schid: Subchannel ID
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schid, s390_cio_rsch,
+ TP_PROTO(struct subchannel_id schid, int cc),
+ TP_ARGS(schid, cc)
+);
+
+/**
+ * s390_cio_rchp - Reset Channel Path (RCHP) instruction was performed
+ * @chpid: Channel-Path Identifier
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_rchp,
+ TP_PROTO(struct chp_id chpid, int cc),
+ TP_ARGS(chpid, cc),
+ TP_STRUCT__entry(
+ __field(u8, cssid)
+ __field(u8, id)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->cssid = chpid.cssid;
+ __entry->id = chpid.id;
+ __entry->cc = cc;
+ ),
+ TP_printk("chpid=%x.%02x cc=%d", __entry->cssid, __entry->id,
+ __entry->cc
+ )
+);
+
+#define CHSC_MAX_REQUEST_LEN 64
+#define CHSC_MAX_RESPONSE_LEN 64
+
+/**
+ * s390_cio_chsc - Channel Subsystem Call (CHSC) instruction was performed
+ * @chsc: CHSC block
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_chsc,
+ TP_PROTO(struct chsc_header *chsc, int cc),
+ TP_ARGS(chsc, cc),
+ TP_STRUCT__entry(
+ __field(int, cc)
+ __field(u16, code)
+ __field(u16, rcode)
+ __array(u8, request, CHSC_MAX_REQUEST_LEN)
+ __array(u8, response, CHSC_MAX_RESPONSE_LEN)
+ ),
+ TP_fast_assign(
+ __entry->cc = cc;
+ __entry->code = chsc->code;
+ memcpy(&entry->request, chsc,
+ min_t(u16, chsc->length, CHSC_MAX_REQUEST_LEN));
+ chsc = (struct chsc_header *) ((char *) chsc + chsc->length);
+ __entry->rcode = chsc->code;
+ memcpy(&entry->response, chsc,
+ min_t(u16, chsc->length, CHSC_MAX_RESPONSE_LEN));
+ ),
+ TP_printk("code=0x%04x cc=%d rcode=0x%04x", __entry->code,
+ __entry->cc, __entry->rcode)
+);
+
+/**
+ * s390_cio_interrupt - An I/O interrupt occurred
+ * @tpi_info: Address of the I/O interruption code
+ */
+TRACE_EVENT(s390_cio_interrupt,
+ TP_PROTO(struct tpi_info *tpi_info),
+ TP_ARGS(tpi_info),
+ TP_STRUCT__entry(
+ __field_struct(struct tpi_info, tpi_info)
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ ),
+ TP_fast_assign(
+ __entry->tpi_info = *tpi_info;
+ __entry->cssid = __entry->tpi_info.schid.cssid;
+ __entry->ssid = __entry->tpi_info.schid.ssid;
+ __entry->schno = __entry->tpi_info.schid.sch_no;
+ ),
+ TP_printk("schid=%x.%x.%04x isc=%d type=%d",
+ __entry->cssid, __entry->ssid, __entry->schno,
+ __entry->tpi_info.isc, __entry->tpi_info.type
+ )
+);
+
+/**
+ * s390_cio_adapter_int - An adapter interrupt occurred
+ * @tpi_info: Address of the I/O interruption code
+ */
+TRACE_EVENT(s390_cio_adapter_int,
+ TP_PROTO(struct tpi_info *tpi_info),
+ TP_ARGS(tpi_info),
+ TP_STRUCT__entry(
+ __field_struct(struct tpi_info, tpi_info)
+ ),
+ TP_fast_assign(
+ __entry->tpi_info = *tpi_info;
+ ),
+ TP_printk("isc=%d", __entry->tpi_info.isc)
+);
+
+/**
+ * s390_cio_stcrw - Store Channel Report Word (STCRW) was performed
+ * @crw: Channel Report Word
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_stcrw,
+ TP_PROTO(struct crw *crw, int cc),
+ TP_ARGS(crw, cc),
+ TP_STRUCT__entry(
+ __field_struct(struct crw, crw)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->crw = *crw;
+ __entry->cc = cc;
+ ),
+ TP_printk("cc=%d slct=%d oflw=%d chn=%d rsc=%d anc=%d erc=0x%x "
+ "rsid=0x%x",
+ __entry->cc, __entry->crw.slct, __entry->crw.oflw,
+ __entry->crw.chn, __entry->crw.rsc, __entry->crw.anc,
+ __entry->crw.erc, __entry->crw.rsid
+ )
+);
+
+#endif /* _TRACE_S390_CIO_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+#include <trace/define_trace.h>
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 9f8fa42c062c..5d3d04c040c2 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -1428,10 +1428,8 @@ int __init zcrypt_debug_init(void)
void zcrypt_debug_exit(void)
{
debugfs_remove(debugfs_root);
- if (zcrypt_dbf_common)
- debug_unregister(zcrypt_dbf_common);
- if (zcrypt_dbf_devices)
- debug_unregister(zcrypt_dbf_devices);
+ debug_unregister(zcrypt_dbf_common);
+ debug_unregister(zcrypt_dbf_devices);
}
/**
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c
index 05c37d6d4afe..c3e22523faf3 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -1677,11 +1677,8 @@ static int ctcm_shutdown_device(struct ccwgroup_device *cgdev)
ccw_device_set_offline(cgdev->cdev[1]);
ccw_device_set_offline(cgdev->cdev[0]);
-
- if (priv->channel[CTCM_READ])
- channel_remove(priv->channel[CTCM_READ]);
- if (priv->channel[CTCM_WRITE])
- channel_remove(priv->channel[CTCM_WRITE]);
+ channel_remove(priv->channel[CTCM_READ]);
+ channel_remove(priv->channel[CTCM_WRITE]);
priv->channel[CTCM_READ] = priv->channel[CTCM_WRITE] = NULL;
return 0;
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 1766a20ebcb1..ec2e014e885c 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -981,6 +981,10 @@ int qeth_send_setassparms(struct qeth_card *, struct qeth_cmd_buffer *, __u16,
int (*reply_cb)(struct qeth_card *,
struct qeth_reply *, unsigned long),
void *);
+struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *,
+ enum qeth_ipa_funcs,
+ __u16, __u16,
+ enum qeth_prot_versions);
int qeth_start_ipa_tx_checksum(struct qeth_card *);
int qeth_set_rx_csum(struct qeth_card *, int);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 31ac53fa5cee..787153764120 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -2684,8 +2684,6 @@ void qeth_print_status_message(struct qeth_card *card)
sprintf(card->info.mcl_level, "%02x%02x",
card->info.mcl_level[2],
card->info.mcl_level[3]);
-
- card->info.mcl_level[QETH_MCL_LENGTH] = 0;
break;
}
/* fallthrough */
@@ -5297,10 +5295,10 @@ static int qeth_setassparms_cb(struct qeth_card *card,
return 0;
}
-static struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *card,
- enum qeth_ipa_funcs ipa_func,
- __u16 cmd_code, __u16 len,
- enum qeth_prot_versions prot)
+struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *card,
+ enum qeth_ipa_funcs ipa_func,
+ __u16 cmd_code, __u16 len,
+ enum qeth_prot_versions prot)
{
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
@@ -5319,6 +5317,7 @@ static struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *card,
return iob;
}
+EXPORT_SYMBOL_GPL(qeth_get_setassparms_cmd);
int qeth_send_setassparms(struct qeth_card *card,
struct qeth_cmd_buffer *iob, __u16 len, long data,
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 8f1b091e1732..80b1979e8d95 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -1126,6 +1126,7 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
qeth_l2_request_initial_mac(card);
SET_NETDEV_DEV(card->dev, &card->gdev->dev);
netif_napi_add(card->dev, &card->napi, qeth_l2_poll, QETH_NAPI_WEIGHT);
+ netif_carrier_off(card->dev);
return register_netdev(card->dev);
}
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 543960e96b42..7c8c68c26540 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -1043,28 +1043,6 @@ static int qeth_l3_default_setassparms_cb(struct qeth_card *card,
return 0;
}
-static struct qeth_cmd_buffer *qeth_l3_get_setassparms_cmd(
- struct qeth_card *card, enum qeth_ipa_funcs ipa_func, __u16 cmd_code,
- __u16 len, enum qeth_prot_versions prot)
-{
- struct qeth_cmd_buffer *iob;
- struct qeth_ipa_cmd *cmd;
-
- QETH_CARD_TEXT(card, 4, "getasscm");
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETASSPARMS, prot);
-
- if (iob) {
- cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
- cmd->data.setassparms.hdr.assist_no = ipa_func;
- cmd->data.setassparms.hdr.length = 8 + len;
- cmd->data.setassparms.hdr.command_code = cmd_code;
- cmd->data.setassparms.hdr.return_code = 0;
- cmd->data.setassparms.hdr.seq_no = 0;
- }
-
- return iob;
-}
-
#ifdef CONFIG_QETH_IPV6
static int qeth_l3_send_simple_setassparms_ipv6(struct qeth_card *card,
enum qeth_ipa_funcs ipa_func, __u16 cmd_code)
@@ -1073,7 +1051,7 @@ static int qeth_l3_send_simple_setassparms_ipv6(struct qeth_card *card,
struct qeth_cmd_buffer *iob;
QETH_CARD_TEXT(card, 4, "simassp6");
- iob = qeth_l3_get_setassparms_cmd(card, ipa_func, cmd_code,
+ iob = qeth_get_setassparms_cmd(card, ipa_func, cmd_code,
0, QETH_PROT_IPV6);
if (!iob)
return -ENOMEM;
@@ -2344,10 +2322,11 @@ static int qeth_l3_query_arp_cache_info(struct qeth_card *card,
QETH_CARD_TEXT_(card, 3, "qarpipv%i", prot);
- iob = qeth_l3_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
- IPA_CMD_ASS_ARP_QUERY_INFO,
- sizeof(struct qeth_arp_query_data) - sizeof(char),
- prot);
+ iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
+ IPA_CMD_ASS_ARP_QUERY_INFO,
+ sizeof(struct qeth_arp_query_data)
+ - sizeof(char),
+ prot);
if (!iob)
return -ENOMEM;
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
@@ -2439,7 +2418,7 @@ static int qeth_l3_arp_add_entry(struct qeth_card *card,
return -EOPNOTSUPP;
}
- iob = qeth_l3_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
+ iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
IPA_CMD_ASS_ARP_ADD_ENTRY,
sizeof(struct qeth_arp_cache_entry),
QETH_PROT_IPV4);
@@ -2480,7 +2459,7 @@ static int qeth_l3_arp_remove_entry(struct qeth_card *card,
return -EOPNOTSUPP;
}
memcpy(buf, entry, 12);
- iob = qeth_l3_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
+ iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
IPA_CMD_ASS_ARP_REMOVE_ENTRY,
12,
QETH_PROT_IPV4);
@@ -2818,7 +2797,7 @@ static inline int qeth_l3_tso_elements(struct sk_buff *skb)
{
unsigned long tcpd = (unsigned long)tcp_hdr(skb) +
tcp_hdr(skb)->doff * 4;
- int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data);
+ int tcpd_len = skb_headlen(skb) - (tcpd - (unsigned long)skb->data);
int elements = PFN_UP(tcpd + tcpd_len - 1) - PFN_DOWN(tcpd);
elements += qeth_get_elements_for_frags(skb);
@@ -3220,6 +3199,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
SET_NETDEV_DEV(card->dev, &card->gdev->dev);
netif_napi_add(card->dev, &card->napi, qeth_l3_poll, QETH_NAPI_WEIGHT);
+ netif_carrier_off(card->dev);
return register_netdev(card->dev);
}