summaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/dasd.c6
-rw-r--r--drivers/s390/block/dasd_alias.c64
-rw-r--r--drivers/s390/block/dasd_eckd.c65
-rw-r--r--drivers/s390/block/dasd_int.h2
-rw-r--r--drivers/s390/block/dasd_ioctl.c1
-rw-r--r--drivers/s390/char/con3215.c31
-rw-r--r--drivers/s390/char/fs3270.c1
-rw-r--r--drivers/s390/char/raw3270.c2
-rw-r--r--drivers/s390/char/sclp_tty.c1
-rw-r--r--drivers/s390/char/sclp_vt220.c1
-rw-r--r--drivers/s390/char/tty3270.c1
-rw-r--r--drivers/s390/char/vmcp.c1
-rw-r--r--drivers/s390/char/vmwatchdog.c4
-rw-r--r--drivers/s390/cio/ccwgroup.c2
-rw-r--r--drivers/s390/cio/chsc_sch.c1
-rw-r--r--drivers/s390/cio/cmf.c2
-rw-r--r--drivers/s390/cio/device.c8
-rw-r--r--drivers/s390/cio/qdio_main.c4
-rw-r--r--drivers/s390/kvm/kvm_virtio.c2
-rw-r--r--drivers/s390/net/ctcm_fsms.c11
-rw-r--r--drivers/s390/net/ctcm_main.c3
-rw-r--r--drivers/s390/net/ctcm_mpc.c12
-rw-r--r--drivers/s390/net/lcs.c12
-rw-r--r--drivers/s390/net/qeth_core.h1
-rw-r--r--drivers/s390/net/qeth_core_main.c110
-rw-r--r--drivers/s390/net/qeth_core_mpc.c1
-rw-r--r--drivers/s390/net/qeth_core_mpc.h14
-rw-r--r--drivers/s390/net/qeth_l2_main.c7
-rw-r--r--drivers/s390/net/qeth_l3_main.c40
-rw-r--r--drivers/s390/net/smsgiucv_app.c9
-rw-r--r--drivers/s390/scsi/zfcp_cfdc.c1
31 files changed, 255 insertions, 165 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index eef27a197c0..110137e7ec8 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -3261,6 +3261,12 @@ void dasd_generic_path_event(struct ccw_device *cdev, int *path_event)
device->path_data.tbvpm |= eventlpm;
dasd_schedule_device_bh(device);
}
+ if (path_event[chp] & PE_PATHGROUP_ESTABLISHED) {
+ DBF_DEV_EVENT(DBF_WARNING, device, "%s",
+ "Pathgroup re-established\n");
+ if (device->discipline->kick_validate)
+ device->discipline->kick_validate(device);
+ }
}
dasd_put_device(device);
}
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
index 553b3c5abb0..b3beed5434e 100644
--- a/drivers/s390/block/dasd_alias.c
+++ b/drivers/s390/block/dasd_alias.c
@@ -189,14 +189,12 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
unsigned long flags;
struct alias_server *server, *newserver;
struct alias_lcu *lcu, *newlcu;
- int is_lcu_known;
struct dasd_uid uid;
private = (struct dasd_eckd_private *) device->private;
device->discipline->get_uid(device, &uid);
spin_lock_irqsave(&aliastree.lock, flags);
- is_lcu_known = 1;
server = _find_server(&uid);
if (!server) {
spin_unlock_irqrestore(&aliastree.lock, flags);
@@ -208,7 +206,6 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
if (!server) {
list_add(&newserver->server, &aliastree.serverlist);
server = newserver;
- is_lcu_known = 0;
} else {
/* someone was faster */
_free_server(newserver);
@@ -226,12 +223,10 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
if (!lcu) {
list_add(&newlcu->lcu, &server->lculist);
lcu = newlcu;
- is_lcu_known = 0;
} else {
/* someone was faster */
_free_lcu(newlcu);
}
- is_lcu_known = 0;
}
spin_lock(&lcu->lock);
list_add(&device->alias_list, &lcu->inactive_devices);
@@ -239,64 +234,7 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
spin_unlock(&lcu->lock);
spin_unlock_irqrestore(&aliastree.lock, flags);
- return is_lcu_known;
-}
-
-/*
- * The first device to be registered on an LCU will have to do
- * some additional setup steps to configure that LCU on the
- * storage server. All further devices should wait with their
- * initialization until the first device is done.
- * To synchronize this work, the first device will call
- * dasd_alias_lcu_setup_complete when it is done, and all
- * other devices will wait for it with dasd_alias_wait_for_lcu_setup.
- */
-void dasd_alias_lcu_setup_complete(struct dasd_device *device)
-{
- unsigned long flags;
- struct alias_server *server;
- struct alias_lcu *lcu;
- struct dasd_uid uid;
-
- device->discipline->get_uid(device, &uid);
- lcu = NULL;
- spin_lock_irqsave(&aliastree.lock, flags);
- server = _find_server(&uid);
- if (server)
- lcu = _find_lcu(server, &uid);
- spin_unlock_irqrestore(&aliastree.lock, flags);
- if (!lcu) {
- DBF_EVENT_DEVID(DBF_ERR, device->cdev,
- "could not find lcu for %04x %02x",
- uid.ssid, uid.real_unit_addr);
- WARN_ON(1);
- return;
- }
- complete_all(&lcu->lcu_setup);
-}
-
-void dasd_alias_wait_for_lcu_setup(struct dasd_device *device)
-{
- unsigned long flags;
- struct alias_server *server;
- struct alias_lcu *lcu;
- struct dasd_uid uid;
-
- device->discipline->get_uid(device, &uid);
- lcu = NULL;
- spin_lock_irqsave(&aliastree.lock, flags);
- server = _find_server(&uid);
- if (server)
- lcu = _find_lcu(server, &uid);
- spin_unlock_irqrestore(&aliastree.lock, flags);
- if (!lcu) {
- DBF_EVENT_DEVID(DBF_ERR, device->cdev,
- "could not find lcu for %04x %02x",
- uid.ssid, uid.real_unit_addr);
- WARN_ON(1);
- return;
- }
- wait_for_completion(&lcu->lcu_setup);
+ return 0;
}
/*
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index bbcd5e9206e..2617b1ed470 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -18,12 +18,12 @@
#include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/bio.h>
#include <linux/module.h>
+#include <linux/compat.h>
#include <linux/init.h>
#include <asm/debug.h>
#include <asm/idals.h>
#include <asm/ebcdic.h>
-#include <asm/compat.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/cio.h>
@@ -1534,6 +1534,10 @@ static void dasd_eckd_validate_server(struct dasd_device *device)
struct dasd_eckd_private *private;
int enable_pav;
+ private = (struct dasd_eckd_private *) device->private;
+ if (private->uid.type == UA_BASE_PAV_ALIAS ||
+ private->uid.type == UA_HYPER_PAV_ALIAS)
+ return;
if (dasd_nopav || MACHINE_IS_VM)
enable_pav = 0;
else
@@ -1542,11 +1546,28 @@ static void dasd_eckd_validate_server(struct dasd_device *device)
/* may be requested feature is not available on server,
* therefore just report error and go ahead */
- private = (struct dasd_eckd_private *) device->private;
DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "PSF-SSC for SSID %04x "
"returned rc=%d", private->uid.ssid, rc);
}
+/*
+ * worker to do a validate server in case of a lost pathgroup
+ */
+static void dasd_eckd_do_validate_server(struct work_struct *work)
+{
+ struct dasd_device *device = container_of(work, struct dasd_device,
+ kick_validate);
+ dasd_eckd_validate_server(device);
+ dasd_put_device(device);
+}
+
+static void dasd_eckd_kick_validate_server(struct dasd_device *device)
+{
+ dasd_get_device(device);
+ /* queue call to do_validate_server to the kernel event daemon. */
+ schedule_work(&device->kick_validate);
+}
+
static u32 get_fcx_max_data(struct dasd_device *device)
{
#if defined(CONFIG_64BIT)
@@ -1588,10 +1609,13 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
struct dasd_eckd_private *private;
struct dasd_block *block;
struct dasd_uid temp_uid;
- int is_known, rc, i;
+ int rc, i;
int readonly;
unsigned long value;
+ /* setup work queue for validate server*/
+ INIT_WORK(&device->kick_validate, dasd_eckd_do_validate_server);
+
if (!ccw_device_is_pathgroup(device->cdev)) {
dev_warn(&device->cdev->dev,
"A channel path group could not be established\n");
@@ -1651,22 +1675,12 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
block->base = device;
}
- /* register lcu with alias handling, enable PAV if this is a new lcu */
- is_known = dasd_alias_make_device_known_to_lcu(device);
- if (is_known < 0) {
- rc = is_known;
+ /* register lcu with alias handling, enable PAV */
+ rc = dasd_alias_make_device_known_to_lcu(device);
+ if (rc)
goto out_err2;
- }
- /*
- * dasd_eckd_validate_server is done on the first device that
- * is found for an LCU. All later other devices have to wait
- * for it, so they will read the correct feature codes.
- */
- if (!is_known) {
- dasd_eckd_validate_server(device);
- dasd_alias_lcu_setup_complete(device);
- } else
- dasd_alias_wait_for_lcu_setup(device);
+
+ dasd_eckd_validate_server(device);
/* device may report different configuration data after LCU setup */
rc = dasd_eckd_read_conf(device);
@@ -4098,7 +4112,7 @@ static int dasd_eckd_restore_device(struct dasd_device *device)
{
struct dasd_eckd_private *private;
struct dasd_eckd_characteristics temp_rdc_data;
- int is_known, rc;
+ int rc;
struct dasd_uid temp_uid;
unsigned long flags;
@@ -4121,14 +4135,10 @@ static int dasd_eckd_restore_device(struct dasd_device *device)
goto out_err;
/* register lcu with alias handling, enable PAV if this is a new lcu */
- is_known = dasd_alias_make_device_known_to_lcu(device);
- if (is_known < 0)
- return is_known;
- if (!is_known) {
- dasd_eckd_validate_server(device);
- dasd_alias_lcu_setup_complete(device);
- } else
- dasd_alias_wait_for_lcu_setup(device);
+ rc = dasd_alias_make_device_known_to_lcu(device);
+ if (rc)
+ return rc;
+ dasd_eckd_validate_server(device);
/* RE-Read Configuration Data */
rc = dasd_eckd_read_conf(device);
@@ -4270,6 +4280,7 @@ static struct dasd_discipline dasd_eckd_discipline = {
.restore = dasd_eckd_restore_device,
.reload = dasd_eckd_reload_device,
.get_uid = dasd_eckd_get_uid,
+ .kick_validate = dasd_eckd_kick_validate_server,
};
static int __init
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index afe8c33422e..33a6743ddc5 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -355,6 +355,7 @@ struct dasd_discipline {
int (*reload) (struct dasd_device *);
int (*get_uid) (struct dasd_device *, struct dasd_uid *);
+ void (*kick_validate) (struct dasd_device *);
};
extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -455,6 +456,7 @@ struct dasd_device {
struct work_struct kick_work;
struct work_struct restore_device;
struct work_struct reload_device;
+ struct work_struct kick_validate;
struct timer_list timer;
debug_info_t *debug_area;
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index f1a2016829f..792c69e78fe 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -13,6 +13,7 @@
#define KMSG_COMPONENT "dasd"
#include <linux/interrupt.h>
+#include <linux/compat.h>
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/blkpg.h>
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 934458ad55e..4f9f1dcc155 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -87,6 +87,7 @@ struct raw3215_info {
struct tty_struct *tty; /* pointer to tty structure if present */
struct raw3215_req *queued_read; /* pointer to queued read requests */
struct raw3215_req *queued_write;/* pointer to queued write requests */
+ struct tasklet_struct tlet; /* tasklet to invoke tty_wakeup */
wait_queue_head_t empty_wait; /* wait queue for flushing */
struct timer_list timer; /* timer for delayed output */
int line_pos; /* position on the line (for tabs) */
@@ -334,19 +335,23 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
}
/*
+ * Call tty_wakeup from tasklet context
+ */
+static void raw3215_wakeup(unsigned long data)
+{
+ struct raw3215_info *raw = (struct raw3215_info *) data;
+ tty_wakeup(raw->tty);
+}
+
+/*
* Try to start the next IO and wake up processes waiting on the tty.
*/
static void raw3215_next_io(struct raw3215_info *raw)
{
- struct tty_struct *tty;
-
raw3215_mk_write_req(raw);
raw3215_try_io(raw);
- tty = raw->tty;
- if (tty != NULL &&
- RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) {
- tty_wakeup(tty);
- }
+ if (raw->tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE)
+ tasklet_schedule(&raw->tlet);
}
/*
@@ -682,6 +687,7 @@ static int raw3215_probe (struct ccw_device *cdev)
return -ENOMEM;
}
init_waitqueue_head(&raw->empty_wait);
+ tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
dev_set_drvdata(&cdev->dev, raw);
cdev->handler = raw3215_irq;
@@ -901,6 +907,7 @@ static int __init con3215_init(void)
raw->flags |= RAW3215_FIXED;
init_waitqueue_head(&raw->empty_wait);
+ tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
/* Request the console irq */
if (raw3215_startup(raw) != 0) {
@@ -926,13 +933,9 @@ console_initcall(con3215_init);
static int tty3215_open(struct tty_struct *tty, struct file * filp)
{
struct raw3215_info *raw;
- int retval, line;
-
- line = tty->index;
- if ((line < 0) || (line >= NR_3215))
- return -ENODEV;
+ int retval;
- raw = raw3215[line];
+ raw = raw3215[tty->index];
if (raw == NULL)
return -ENODEV;
@@ -966,6 +969,7 @@ static void tty3215_close(struct tty_struct *tty, struct file * filp)
tty->closing = 1;
/* Shutdown the terminal */
raw3215_shutdown(raw);
+ tasklet_kill(&raw->tlet);
tty->closing = 0;
raw->tty = NULL;
}
@@ -1137,7 +1141,6 @@ static int __init tty3215_init(void)
* proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
*/
- driver->owner = THIS_MODULE;
driver->driver_name = "tty3215";
driver->name = "ttyS";
driver->major = TTY_MAJOR;
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index e71298158f9..911704571b9 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -11,6 +11,7 @@
#include <linux/console.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/compat.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/slab.h>
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index e5cb9248a44..f3b8bb84faf 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -75,7 +75,7 @@ static LIST_HEAD(raw3270_devices);
static int raw3270_registered;
/* Module parameters */
-static int tubxcorrect = 0;
+static bool tubxcorrect = 0;
module_param(tubxcorrect, bool, 0);
/*
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index a879c139926..40a9d69c898 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -551,7 +551,6 @@ sclp_tty_init(void)
return rc;
}
- driver->owner = THIS_MODULE;
driver->driver_name = "sclp_line";
driver->name = "sclp_line";
driver->major = TTY_MAJOR;
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index 5d706e6c946..b635472ae66 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -685,7 +685,6 @@ static int __init sclp_vt220_tty_init(void)
if (rc)
goto out_driver;
- driver->owner = THIS_MODULE;
driver->driver_name = SCLP_VT220_DRIVER_NAME;
driver->name = SCLP_VT220_DEVICE_NAME;
driver->major = SCLP_VT220_MAJOR;
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 2db1482b406..b43445a55cb 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -1784,7 +1784,6 @@ static int __init tty3270_init(void)
* Entries in tty3270_driver that are NOT initialized:
* proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
*/
- driver->owner = THIS_MODULE;
driver->driver_name = "ttyTUB";
driver->name = "ttyTUB";
driver->major = IBM_TTY3270_MAJOR;
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
index 75bde6a8b7d..89c03e6b1c0 100644
--- a/drivers/s390/char/vmcp.c
+++ b/drivers/s390/char/vmcp.c
@@ -13,6 +13,7 @@
#include <linux/fs.h>
#include <linux/init.h>
+#include <linux/compat.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c
index 11312f401c7..2211277a107 100644
--- a/drivers/s390/char/vmwatchdog.c
+++ b/drivers/s390/char/vmwatchdog.c
@@ -28,9 +28,9 @@
#define MAX_CMDLEN 240
#define MIN_INTERVAL 15
static char vmwdt_cmd[MAX_CMDLEN] = "IPL";
-static int vmwdt_conceal;
+static bool vmwdt_conceal;
-static int vmwdt_nowayout = WATCHDOG_NOWAYOUT;
+static bool vmwdt_nowayout = WATCHDOG_NOWAYOUT;
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 4f1989d27b1..5f1dc6fb570 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -580,7 +580,6 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
struct device *dev;
/* We don't want ccwgroup devices to live longer than their driver. */
- get_driver(&cdriver->driver);
while ((dev = driver_find_device(&cdriver->driver, NULL, NULL,
__ccwgroup_match_all))) {
struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
@@ -592,7 +591,6 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
mutex_unlock(&gdev->reg_mutex);
put_device(dev);
}
- put_driver(&cdriver->driver);
driver_unregister(&cdriver->driver);
}
EXPORT_SYMBOL(ccwgroup_driver_unregister);
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
index 0c87b0fc771..8f9a1a38449 100644
--- a/drivers/s390/cio/chsc_sch.c
+++ b/drivers/s390/cio/chsc_sch.c
@@ -8,6 +8,7 @@
*/
#include <linux/slab.h>
+#include <linux/compat.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/uaccess.h>
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 2985eb43948..204ca728e7f 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -98,7 +98,7 @@ enum cmb_format {
* enum cmb_format.
*/
static int format = CMF_AUTODETECT;
-module_param(format, bool, 0444);
+module_param(format, bint, 0444);
/**
* struct cmb_operations - functions to use depending on cmb_format
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 47269858ecb..02d01525946 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1676,15 +1676,9 @@ struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv,
const char *bus_id)
{
struct device *dev;
- struct device_driver *drv;
- drv = get_driver(&cdrv->driver);
- if (!drv)
- return NULL;
-
- dev = driver_find_device(drv, NULL, (void *)bus_id,
+ dev = driver_find_device(&cdrv->driver, NULL, (void *)bus_id,
__ccwdev_check_busid);
- put_driver(drv);
return dev ? to_ccwdev(dev) : NULL;
}
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 3ef8d071c64..770a740a393 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -167,7 +167,7 @@ again:
DBF_ERROR("%4x EQBS ERROR", SCH_NO(q));
DBF_ERROR("%3d%3d%2d", count, tmp_count, nr);
q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION,
- 0, -1, -1, q->irq_ptr->int_parm);
+ q->nr, q->first_to_kick, count, q->irq_ptr->int_parm);
return 0;
}
@@ -215,7 +215,7 @@ again:
DBF_ERROR("%4x SQBS ERROR", SCH_NO(q));
DBF_ERROR("%3d%3d%2d", count, tmp_count, nr);
q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION,
- 0, -1, -1, q->irq_ptr->int_parm);
+ q->nr, q->first_to_kick, count, q->irq_ptr->int_parm);
return 0;
}
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
index 8af868bab20..7bc1955337e 100644
--- a/drivers/s390/kvm/kvm_virtio.c
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -198,7 +198,7 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
goto out;
vq = vring_new_virtqueue(config->num, KVM_S390_VIRTIO_RING_ALIGN,
- vdev, (void *) config->address,
+ vdev, true, (void *) config->address,
kvm_notify, callback, name);
if (!vq) {
err = -ENOMEM;
diff --git a/drivers/s390/net/ctcm_fsms.c b/drivers/s390/net/ctcm_fsms.c
index 2d602207541..a69766900a1 100644
--- a/drivers/s390/net/ctcm_fsms.c
+++ b/drivers/s390/net/ctcm_fsms.c
@@ -1341,6 +1341,12 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg)
spin_unlock(&ch->collect_lock);
clear_normalized_cda(&ch->ccw[1]);
+
+ CTCM_PR_DBGDATA("ccwcda=0x%p data=0x%p\n",
+ (void *)(unsigned long)ch->ccw[1].cda,
+ ch->trans_skb->data);
+ ch->ccw[1].count = ch->max_bufsize;
+
if (set_normalized_cda(&ch->ccw[1], ch->trans_skb->data)) {
dev_kfree_skb_any(ch->trans_skb);
ch->trans_skb = NULL;
@@ -1350,6 +1356,11 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg)
fsm_event(priv->mpcg->fsm, MPCG_EVENT_INOP, dev);
return;
}
+
+ CTCM_PR_DBGDATA("ccwcda=0x%p data=0x%p\n",
+ (void *)(unsigned long)ch->ccw[1].cda,
+ ch->trans_skb->data);
+
ch->ccw[1].count = ch->trans_skb->len;
fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch);
ch->prof.send_stamp = current_kernel_time(); /* xtime */
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c
index 5cb93a8e340..11f3b071f30 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -562,6 +562,9 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
skb_queue_tail(&ch->io_queue, skb);
ccw_idx = 3;
}
+ if (do_debug_ccw)
+ ctcmpc_dumpit((char *)&ch->ccw[ccw_idx],
+ sizeof(struct ccw1) * 3);
ch->retry = 0;
fsm_newstate(ch->fsm, CTC_STATE_TX);
fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch);
diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c
index da4c747335e..ac7975b7a83 100644
--- a/drivers/s390/net/ctcm_mpc.c
+++ b/drivers/s390/net/ctcm_mpc.c
@@ -53,8 +53,8 @@
#include <linux/moduleparam.h>
#include <asm/idals.h>
-#include "ctcm_mpc.h"
#include "ctcm_main.h"
+#include "ctcm_mpc.h"
#include "ctcm_fsms.h"
static const struct xid2 init_xid = {
@@ -132,7 +132,7 @@ void ctcmpc_dumpit(char *buf, int len)
__u32 ct, sw, rm, dup;
char *ptr, *rptr;
char tbuf[82], tdup[82];
- #if (UTS_MACHINE == s390x)
+ #ifdef CONFIG_64BIT
char addr[22];
#else
char addr[12];
@@ -149,8 +149,8 @@ void ctcmpc_dumpit(char *buf, int len)
for (ct = 0; ct < len; ct++, ptr++, rptr++) {
if (sw == 0) {
- #if (UTS_MACHINE == s390x)
- sprintf(addr, "%16.16lx", (__u64)rptr);
+ #ifdef CONFIG_64BIT
+ sprintf(addr, "%16.16llx", (__u64)rptr);
#else
sprintf(addr, "%8.8X", (__u32)rptr);
#endif
@@ -164,8 +164,8 @@ void ctcmpc_dumpit(char *buf, int len)
if (sw == 8)
strcat(bhex, " ");
- #if (UTS_MACHINE == s390x)
- sprintf(tbuf, "%2.2lX", (__u64)*ptr);
+ #if CONFIG_64BIT
+ sprintf(tbuf, "%2.2llX", (__u64)*ptr);
#else
sprintf(tbuf, "%2.2X", (__u32)*ptr);
#endif
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 863fc219715..687efe4d589 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -2240,7 +2240,7 @@ __lcs_shutdown_device(struct ccwgroup_device *ccwgdev, int recovery_mode)
{
struct lcs_card *card;
enum lcs_dev_states recover_state;
- int ret;
+ int ret = 0, ret2 = 0, ret3 = 0;
LCS_DBF_TEXT(3, setup, "shtdndev");
card = dev_get_drvdata(&ccwgdev->dev);
@@ -2255,13 +2255,15 @@ __lcs_shutdown_device(struct ccwgroup_device *ccwgdev, int recovery_mode)
recover_state = card->state;
ret = lcs_stop_device(card->dev);
- ret = ccw_device_set_offline(card->read.ccwdev);
- ret = ccw_device_set_offline(card->write.ccwdev);
+ ret2 = ccw_device_set_offline(card->read.ccwdev);
+ ret3 = ccw_device_set_offline(card->write.ccwdev);
+ if (!ret)
+ ret = (ret2) ? ret2 : ret3;
+ if (ret)
+ LCS_DBF_TEXT_(3, setup, "1err:%d", ret);
if (recover_state == DEV_STATE_UP) {
card->state = DEV_STATE_RECOVER;
}
- if (ret)
- return ret;
return 0;
}
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 4abc79d3963..ec7921b5138 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -906,6 +906,7 @@ void qeth_prepare_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *, char);
struct qeth_cmd_buffer *qeth_wait_for_buffer(struct qeth_channel *);
int qeth_mdio_read(struct net_device *, int, int);
int qeth_snmp_command(struct qeth_card *, char __user *);
+int qeth_query_oat_command(struct qeth_card *, char __user *);
struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *, __u32, __u32);
int qeth_default_setadapterparms_cb(struct qeth_card *, struct qeth_reply *,
unsigned long);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 9c3f38da4c0..120955c6641 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -26,6 +26,7 @@
#include <asm/ebcdic.h>
#include <asm/io.h>
#include <asm/sysinfo.h>
+#include <asm/compat.h>
#include "qeth_core.h"
@@ -50,6 +51,7 @@ static struct kmem_cache *qeth_qdio_outbuf_cache;
static struct device *qeth_core_root_dev;
static unsigned int known_devices[][6] = QETH_MODELLIST_ARRAY;
static struct lock_class_key qdio_out_skb_queue_key;
+static struct mutex qeth_mod_mutex;
static void qeth_send_control_data_cb(struct qeth_channel *,
struct qeth_cmd_buffer *);
@@ -677,6 +679,7 @@ void qeth_release_buffer(struct qeth_channel *channel,
iob->callback = qeth_send_control_data_cb;
iob->rc = 0;
spin_unlock_irqrestore(&channel->iob_lock, flags);
+ wake_up(&channel->wait_q);
}
EXPORT_SYMBOL_GPL(qeth_release_buffer);
@@ -2942,8 +2945,8 @@ static int qeth_query_ipassists_cb(struct qeth_card *card,
card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled;
}
QETH_DBF_TEXT(SETUP, 2, "suppenbl");
- QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_supported);
- QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_enabled);
+ QETH_DBF_TEXT_(SETUP, 2, "%08x", (__u32)cmd->hdr.ipa_supported);
+ QETH_DBF_TEXT_(SETUP, 2, "%08x", (__u32)cmd->hdr.ipa_enabled);
return 0;
}
@@ -4319,7 +4322,7 @@ static int qeth_snmp_command_cb(struct qeth_card *card,
/* check if there is enough room in userspace */
if ((qinfo->udata_len - qinfo->udata_offset) < data_len) {
QETH_CARD_TEXT_(card, 4, "scer3%i", -ENOMEM);
- cmd->hdr.return_code = -ENOMEM;
+ cmd->hdr.return_code = IPA_RC_ENOMEM;
return 0;
}
QETH_CARD_TEXT_(card, 4, "snore%i",
@@ -4402,6 +4405,104 @@ int qeth_snmp_command(struct qeth_card *card, char __user *udata)
}
EXPORT_SYMBOL_GPL(qeth_snmp_command);
+static int qeth_setadpparms_query_oat_cb(struct qeth_card *card,
+ struct qeth_reply *reply, unsigned long data)
+{
+ struct qeth_ipa_cmd *cmd;
+ struct qeth_qoat_priv *priv;
+ char *resdata;
+ int resdatalen;
+
+ QETH_CARD_TEXT(card, 3, "qoatcb");
+
+ cmd = (struct qeth_ipa_cmd *)data;
+ priv = (struct qeth_qoat_priv *)reply->param;
+ resdatalen = cmd->data.setadapterparms.hdr.cmdlength;
+ resdata = (char *)data + 28;
+
+ if (resdatalen > (priv->buffer_len - priv->response_len)) {
+ cmd->hdr.return_code = IPA_RC_FFFF;
+ return 0;
+ }
+
+ memcpy((priv->buffer + priv->response_len), resdata,
+ resdatalen);
+ priv->response_len += resdatalen;
+
+ if (cmd->data.setadapterparms.hdr.seq_no <
+ cmd->data.setadapterparms.hdr.used_total)
+ return 1;
+ return 0;
+}
+
+int qeth_query_oat_command(struct qeth_card *card, char __user *udata)
+{
+ int rc = 0;
+ struct qeth_cmd_buffer *iob;
+ struct qeth_ipa_cmd *cmd;
+ struct qeth_query_oat *oat_req;
+ struct qeth_query_oat_data oat_data;
+ struct qeth_qoat_priv priv;
+ void __user *tmp;
+
+ QETH_CARD_TEXT(card, 3, "qoatcmd");
+
+ if (!qeth_adp_supported(card, IPA_SETADP_QUERY_OAT)) {
+ rc = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (copy_from_user(&oat_data, udata,
+ sizeof(struct qeth_query_oat_data))) {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ priv.buffer_len = oat_data.buffer_len;
+ priv.response_len = 0;
+ priv.buffer = kzalloc(oat_data.buffer_len, GFP_KERNEL);
+ if (!priv.buffer) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_OAT,
+ sizeof(struct qeth_ipacmd_setadpparms_hdr) +
+ sizeof(struct qeth_query_oat));
+ cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+ oat_req = &cmd->data.setadapterparms.data.query_oat;
+ oat_req->subcmd_code = oat_data.command;
+
+ rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_query_oat_cb,
+ &priv);
+ if (!rc) {
+ if (is_compat_task())
+ tmp = compat_ptr(oat_data.ptr);
+ else
+ tmp = (void __user *)(unsigned long)oat_data.ptr;
+
+ if (copy_to_user(tmp, priv.buffer,
+ priv.response_len)) {
+ rc = -EFAULT;
+ goto out_free;
+ }
+
+ oat_data.response_len = priv.response_len;
+
+ if (copy_to_user(udata, &oat_data,
+ sizeof(struct qeth_query_oat_data)))
+ rc = -EFAULT;
+ } else
+ if (rc == IPA_RC_FFFF)
+ rc = -EFAULT;
+
+out_free:
+ kfree(priv.buffer);
+out:
+ return rc;
+}
+EXPORT_SYMBOL_GPL(qeth_query_oat_command);
+
static inline int qeth_get_qdio_q_format(struct qeth_card *card)
{
switch (card->info.type) {
@@ -4940,6 +5041,7 @@ int qeth_core_load_discipline(struct qeth_card *card,
enum qeth_discipline_id discipline)
{
int rc = 0;
+ mutex_lock(&qeth_mod_mutex);
switch (discipline) {
case QETH_DISCIPLINE_LAYER3:
card->discipline.ccwgdriver = try_then_request_module(
@@ -4957,6 +5059,7 @@ int qeth_core_load_discipline(struct qeth_card *card,
"support discipline %d\n", discipline);
rc = -EINVAL;
}
+ mutex_unlock(&qeth_mod_mutex);
return rc;
}
@@ -5440,6 +5543,7 @@ static int __init qeth_core_init(void)
pr_info("loading core functions\n");
INIT_LIST_HEAD(&qeth_core_card_list.list);
rwlock_init(&qeth_core_card_list.rwlock);
+ mutex_init(&qeth_mod_mutex);
rc = qeth_register_dbf_views();
if (rc)
diff --git a/drivers/s390/net/qeth_core_mpc.c b/drivers/s390/net/qeth_core_mpc.c
index ec24901c802..7fab6544def 100644
--- a/drivers/s390/net/qeth_core_mpc.c
+++ b/drivers/s390/net/qeth_core_mpc.c
@@ -207,6 +207,7 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = {
{IPA_RC_MC_ADDR_ALREADY_DEFINED, "Multicast address already defined"},
{IPA_RC_LAN_OFFLINE, "STRTLAN_LAN_DISABLED - LAN offline"},
{IPA_RC_INVALID_IP_VERSION2, "Invalid IP version"},
+ {IPA_RC_ENOMEM, "Memory problem"},
{IPA_RC_FFFF, "Unknown Error"}
};
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index e5a9d1c0383..ff41e42004a 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -190,6 +190,7 @@ enum qeth_ipa_return_codes {
IPA_RC_MC_ADDR_ALREADY_DEFINED = 0xe013,
IPA_RC_LAN_OFFLINE = 0xe080,
IPA_RC_INVALID_IP_VERSION2 = 0xf001,
+ IPA_RC_ENOMEM = 0xfffe,
IPA_RC_FFFF = 0xffff
};
/* for DELIP */
@@ -249,6 +250,7 @@ enum qeth_ipa_setadp_cmd {
IPA_SETADP_SET_PROMISC_MODE = 0x00000800L,
IPA_SETADP_SET_DIAG_ASSIST = 0x00002000L,
IPA_SETADP_SET_ACCESS_CONTROL = 0x00010000L,
+ IPA_SETADP_QUERY_OAT = 0x00080000L,
};
enum qeth_ipa_mac_ops {
CHANGE_ADDR_READ_MAC = 0,
@@ -398,6 +400,17 @@ struct qeth_set_access_ctrl {
__u32 subcmd_code;
} __attribute__((packed));
+struct qeth_query_oat {
+ __u32 subcmd_code;
+ __u8 reserved[12];
+} __packed;
+
+struct qeth_qoat_priv {
+ __u32 buffer_len;
+ __u32 response_len;
+ char *buffer;
+};
+
struct qeth_ipacmd_setadpparms_hdr {
__u32 supp_hw_cmds;
__u32 reserved1;
@@ -417,6 +430,7 @@ struct qeth_ipacmd_setadpparms {
struct qeth_change_addr change_addr;
struct qeth_snmp_cmd snmp;
struct qeth_set_access_ctrl set_access_ctrl;
+ struct qeth_query_oat query_oat;
__u32 mode;
} data;
} __attribute__ ((packed));
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index c1296713311..0e7c29d1d7e 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -75,6 +75,9 @@ static int qeth_l2_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
mii_data->val_out = qeth_mdio_read(dev,
mii_data->phy_id, mii_data->reg_num);
break;
+ case SIOC_QETH_QUERY_OAT:
+ rc = qeth_query_oat_command(card, rq->ifr_ifru.ifru_data);
+ break;
default:
rc = -EOPNOTSUPP;
}
@@ -573,7 +576,6 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card,
default:
break;
}
- cmd->hdr.return_code = -EIO;
} else {
card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
memcpy(card->dev->dev_addr, cmd->data.setdelmac.mac,
@@ -602,7 +604,6 @@ static int qeth_l2_send_delmac_cb(struct qeth_card *card,
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code) {
QETH_CARD_TEXT_(card, 2, "err%d", cmd->hdr.return_code);
- cmd->hdr.return_code = -EIO;
return 0;
}
card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
@@ -679,7 +680,7 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
rc = qeth_l2_send_delmac(card, &card->dev->dev_addr[0]);
if (!rc)
rc = qeth_l2_send_setmac(card, addr->sa_data);
- return rc;
+ return rc ? -EINVAL : 0;
}
static void qeth_l2_set_multicast_list(struct net_device *dev)
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 9648e4e6833..f8592160768 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -28,6 +28,8 @@
#include <net/ip.h>
#include <net/arp.h>
+#include <net/route.h>
+#include <net/ip6_fib.h>
#include <net/ip6_checksum.h>
#include <net/iucv/af_iucv.h>
@@ -2428,7 +2430,7 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
if ((qinfo->udata_len - qinfo->udata_offset) < esize) {
QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOMEM);
- cmd->hdr.return_code = -ENOMEM;
+ cmd->hdr.return_code = IPA_RC_ENOMEM;
goto out_error;
}
@@ -2743,6 +2745,9 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
mii_data->phy_id,
mii_data->reg_num);
break;
+ case SIOC_QETH_QUERY_OAT:
+ rc = qeth_query_oat_command(card, rq->ifr_ifru.ifru_data);
+ break;
default:
rc = -EOPNOTSUPP;
}
@@ -2832,7 +2837,6 @@ static void qeth_l3_fill_af_iucv_hdr(struct qeth_card *card,
static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb, int ipv, int cast_type)
{
- struct neighbour *n = NULL;
struct dst_entry *dst;
memset(hdr, 0, sizeof(struct qeth_hdr));
@@ -2855,33 +2859,29 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
rcu_read_lock();
dst = skb_dst(skb);
- if (dst)
- n = dst_get_neighbour_noref(dst);
if (ipv == 4) {
+ struct rtable *rt = (struct rtable *) dst;
+ __be32 *pkey = &ip_hdr(skb)->daddr;
+
+ if (rt->rt_gateway)
+ pkey = &rt->rt_gateway;
+
/* IPv4 */
hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type);
memset(hdr->hdr.l3.dest_addr, 0, 12);
- if (n) {
- *((u32 *) (&hdr->hdr.l3.dest_addr[12])) =
- *((u32 *) n->primary_key);
- } else {
- /* fill in destination address used in ip header */
- *((u32 *) (&hdr->hdr.l3.dest_addr[12])) =
- ip_hdr(skb)->daddr;
- }
+ *((__be32 *) (&hdr->hdr.l3.dest_addr[12])) = *pkey;
} else if (ipv == 6) {
+ struct rt6_info *rt = (struct rt6_info *) dst;
+ struct in6_addr *pkey = &ipv6_hdr(skb)->daddr;
+
+ if (!ipv6_addr_any(&rt->rt6i_gateway))
+ pkey = &rt->rt6i_gateway;
+
/* IPv6 */
hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type);
if (card->info.type == QETH_CARD_TYPE_IQD)
hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU;
- if (n) {
- memcpy(hdr->hdr.l3.dest_addr,
- n->primary_key, 16);
- } else {
- /* fill in destination address used in ip header */
- memcpy(hdr->hdr.l3.dest_addr,
- &ipv6_hdr(skb)->daddr, 16);
- }
+ memcpy(hdr->hdr.l3.dest_addr, pkey, 16);
} else {
/* passthrough */
if ((skb->dev->type == ARPHRD_IEEE802_TR) &&
diff --git a/drivers/s390/net/smsgiucv_app.c b/drivers/s390/net/smsgiucv_app.c
index 4d2ea400042..32515a201bb 100644
--- a/drivers/s390/net/smsgiucv_app.c
+++ b/drivers/s390/net/smsgiucv_app.c
@@ -168,7 +168,7 @@ static int __init smsgiucv_app_init(void)
rc = dev_set_name(smsg_app_dev, KMSG_COMPONENT);
if (rc) {
kfree(smsg_app_dev);
- goto fail_put_driver;
+ goto fail;
}
smsg_app_dev->bus = &iucv_bus;
smsg_app_dev->parent = iucv_root;
@@ -177,7 +177,7 @@ static int __init smsgiucv_app_init(void)
rc = device_register(smsg_app_dev);
if (rc) {
put_device(smsg_app_dev);
- goto fail_put_driver;
+ goto fail;
}
/* convert sender to uppercase characters */
@@ -191,12 +191,11 @@ static int __init smsgiucv_app_init(void)
rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback);
if (rc) {
device_unregister(smsg_app_dev);
- goto fail_put_driver;
+ goto fail;
}
rc = 0;
-fail_put_driver:
- put_driver(smsgiucv_drv);
+fail:
return rc;
}
module_init(smsgiucv_app_init);
diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c
index 303dde09d29..fab2c2592a9 100644
--- a/drivers/s390/scsi/zfcp_cfdc.c
+++ b/drivers/s390/scsi/zfcp_cfdc.c
@@ -11,6 +11,7 @@
#define KMSG_COMPONENT "zfcp"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+#include <linux/compat.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/miscdevice.h>