diff options
Diffstat (limited to 'drivers/s390')
71 files changed, 455 insertions, 138 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 4951aa82e9f5..bbea90baf98f 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -26,6 +26,7 @@ #include <asm/ebcdic.h> #include <asm/idals.h> #include <asm/itcw.h> +#include <asm/diag.h> /* This is ugly... */ #define PRINTK_HEADER "dasd:" @@ -2212,6 +2213,13 @@ static int dasd_open(struct block_device *bdev, fmode_t mode) goto out; } + if ((mode & FMODE_WRITE) && + (test_bit(DASD_FLAG_DEVICE_RO, &base->flags) || + (base->features & DASD_FEATURE_READONLY))) { + rc = -EROFS; + goto out; + } + return 0; out: @@ -2289,6 +2297,34 @@ dasd_exit(void) * SECTION: common functions for ccw_driver use */ +/* + * Is the device read-only? + * Note that this function does not report the setting of the + * readonly device attribute, but how it is configured in z/VM. + */ +int dasd_device_is_ro(struct dasd_device *device) +{ + struct ccw_dev_id dev_id; + struct diag210 diag_data; + int rc; + + if (!MACHINE_IS_VM) + return 0; + ccw_device_get_id(device->cdev, &dev_id); + memset(&diag_data, 0, sizeof(diag_data)); + diag_data.vrdcdvno = dev_id.devno; + diag_data.vrdclen = sizeof(diag_data); + rc = diag210(&diag_data); + if (rc == 0 || rc == 2) { + return diag_data.vrdcvfla & 0x80; + } else { + DBF_EVENT(DBF_WARNING, "diag210 failed for dev=%04x with rc=%d", + dev_id.devno, rc); + return 0; + } +} +EXPORT_SYMBOL_GPL(dasd_device_is_ro); + static void dasd_generic_auto_online(void *data, async_cookie_t cookie) { struct ccw_device *cdev = data; diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 44796ba4eb9b..6927e751ce3e 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -10,7 +10,6 @@ #define KMSG_COMPONENT "dasd-eckd" #include <linux/timer.h> -#include <linux/slab.h> #include <asm/idals.h> #define PRINTK_HEADER "dasd_erp(3990): " @@ -1045,6 +1044,10 @@ dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense) erp->retries = 5; + } else if (sense[1] & SNS1_WRITE_INHIBITED) { + dev_err(&device->cdev->dev, "An I/O request was rejected" + " because writing is inhibited\n"); + erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); } else { /* fatal error - set status to FAILED internal error 09 - Command Reject */ @@ -2283,7 +2286,8 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr) if (cqr->cpmode == 1) { cplength = 0; - datasize = sizeof(struct tcw) + sizeof(struct tsb); + /* TCW needs to be 64 byte aligned, so leave enough room */ + datasize = 64 + sizeof(struct tcw) + sizeof(struct tsb); } else { cplength = 2; datasize = 0; @@ -2312,8 +2316,8 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr) if (cqr->cpmode == 1) { /* make a shallow copy of the original tcw but set new tsb */ erp->cpmode = 1; - erp->cpaddr = erp->data; - tcw = erp->data; + erp->cpaddr = PTR_ALIGN(erp->data, 64); + tcw = erp->cpaddr; tsb = (struct tsb *) &tcw[1]; *tcw = *((struct tcw *)cqr->cpaddr); tcw->tsb = (long)tsb; diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 148b1dd24070..8c4814258e93 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -8,6 +8,7 @@ #define KMSG_COMPONENT "dasd-eckd" #include <linux/list.h> +#include <linux/slab.h> #include <asm/ebcdic.h> #include "dasd_int.h" #include "dasd_eckd.h" diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index d49766f3b940..eff9c812c5c2 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -18,6 +18,7 @@ #include <linux/ctype.h> #include <linux/init.h> #include <linux/module.h> +#include <linux/slab.h> #include <asm/debug.h> #include <asm/uaccess.h> @@ -742,6 +743,7 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct dasd_devmap *devmap; + struct dasd_device *device; int val; char *endp; @@ -758,12 +760,14 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr, devmap->features |= DASD_FEATURE_READONLY; else devmap->features &= ~DASD_FEATURE_READONLY; - if (devmap->device) - devmap->device->features = devmap->features; - if (devmap->device && devmap->device->block - && devmap->device->block->gdp) - set_disk_ro(devmap->device->block->gdp, val); + device = devmap->device; + if (device) { + device->features = devmap->features; + val = val || test_bit(DASD_FLAG_DEVICE_RO, &device->flags); + } spin_unlock(&dasd_devmap_lock); + if (device && device->block && device->block->gdp) + set_disk_ro(device->block->gdp, val); return count; } diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 6e14863f5c70..687f323cdc38 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -145,12 +145,10 @@ dasd_diag_erp(struct dasd_device *device) mdsk_term_io(device); rc = mdsk_init_io(device, device->block->bp_block, 0, NULL); if (rc == 4) { - if (!(device->features & DASD_FEATURE_READONLY)) { + if (!(test_and_set_bit(DASD_FLAG_DEVICE_RO, &device->flags))) pr_warning("%s: The access mode of a DIAG device " "changed to read-only\n", dev_name(&device->cdev->dev)); - device->features |= DASD_FEATURE_READONLY; - } rc = 0; } if (rc) @@ -449,7 +447,7 @@ dasd_diag_check_device(struct dasd_device *device) rc = -EIO; } else { if (rc == 4) - device->features |= DASD_FEATURE_READONLY; + set_bit(DASD_FLAG_DEVICE_RO, &device->flags); pr_info("%s: New DASD with %ld byte/block, total size %ld " "KB%s\n", dev_name(&device->cdev->dev), (unsigned long) block->bp_block, diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 1cca21aafaba..0cb233116855 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1089,6 +1089,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) struct dasd_eckd_private *private; struct dasd_block *block; int is_known, rc; + int readonly; if (!ccw_device_is_pathgroup(device->cdev)) { dev_warn(&device->cdev->dev, @@ -1182,15 +1183,20 @@ dasd_eckd_check_characteristics(struct dasd_device *device) else private->real_cyl = private->rdc_data.no_cyl; + readonly = dasd_device_is_ro(device); + if (readonly) + set_bit(DASD_FLAG_DEVICE_RO, &device->flags); + dev_info(&device->cdev->dev, "New DASD %04X/%02X (CU %04X/%02X) " - "with %d cylinders, %d heads, %d sectors\n", + "with %d cylinders, %d heads, %d sectors%s\n", private->rdc_data.dev_type, private->rdc_data.dev_model, private->rdc_data.cu_type, private->rdc_data.cu_model.model, private->real_cyl, private->rdc_data.trk_per_cyl, - private->rdc_data.sec_per_trk); + private->rdc_data.sec_per_trk, + readonly ? ", read-only device" : ""); return 0; out_err3: @@ -2839,8 +2845,13 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp) char *psf_data, *rssd_result; struct dasd_ccw_req *cqr; struct ccw1 *ccw; + char psf0, psf1; int rc; + if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) + return -EACCES; + psf0 = psf1 = 0; + /* Copy parms from caller */ rc = -EFAULT; if (copy_from_user(&usrparm, argp, sizeof(usrparm))) @@ -2869,12 +2880,8 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp) (void __user *)(unsigned long) usrparm.psf_data, usrparm.psf_data_len)) goto out_free; - - /* sanity check on syscall header */ - if (psf_data[0] != 0x17 && psf_data[1] != 0xce) { - rc = -EINVAL; - goto out_free; - } + psf0 = psf_data[0]; + psf1 = psf_data[1]; /* setup CCWs for PSF + RSSD */ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2 , 0, device); @@ -2925,7 +2932,9 @@ out_free: kfree(rssd_result); kfree(psf_data); out: - DBF_DEV_EVENT(DBF_WARNING, device, "Symmetrix ioctl: rc=%d", rc); + DBF_DEV_EVENT(DBF_WARNING, device, + "Symmetrix ioctl (0x%02x 0x%02x): rc=%d", + (int) psf0, (int) psf1, rc); return rc; } @@ -3146,11 +3155,11 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, tsb = NULL; sense = NULL; - if (irb->scsw.tm.tcw) + if (irb->scsw.tm.tcw && (irb->scsw.tm.fcxs == 0x01)) tsb = tcw_get_tsb( (struct tcw *)(unsigned long)irb->scsw.tm.tcw); - if (tsb && (irb->scsw.tm.fcxs == 0x01)) { + if (tsb) { len += sprintf(page + len, KERN_ERR PRINTK_HEADER " tsb->length %d\n", tsb->length); len += sprintf(page + len, KERN_ERR PRINTK_HEADER diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index 1f3e967aaba8..dd88803e4899 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -19,6 +19,7 @@ #include <linux/mutex.h> #include <linux/smp_lock.h> #include <linux/err.h> +#include <linux/slab.h> #include <asm/uaccess.h> #include <asm/atomic.h> diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 0f152444ac77..37282b90eecc 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -124,6 +124,7 @@ dasd_fba_check_characteristics(struct dasd_device *device) struct dasd_fba_private *private; struct ccw_device *cdev = device->cdev; int rc; + int readonly; private = (struct dasd_fba_private *) device->private; if (!private) { @@ -162,16 +163,21 @@ dasd_fba_check_characteristics(struct dasd_device *device) return rc; } + readonly = dasd_device_is_ro(device); + if (readonly) + set_bit(DASD_FLAG_DEVICE_RO, &device->flags); + dev_info(&device->cdev->dev, "New FBA DASD %04X/%02X (CU %04X/%02X) with %d MB " - "and %d B/blk\n", + "and %d B/blk%s\n", cdev->id.dev_type, cdev->id.dev_model, cdev->id.cu_type, cdev->id.cu_model, ((private->rdc_data.blk_bdsa * (private->rdc_data.blk_size >> 9)) >> 11), - private->rdc_data.blk_size); + private->rdc_data.blk_size, + readonly ? ", read-only device" : ""); return 0; } diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index 94f92a1247f2..30a1ca3d08b7 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -70,7 +70,8 @@ int dasd_gendisk_alloc(struct dasd_block *block) } len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26)); - if (block->base->features & DASD_FEATURE_READONLY) + if (base->features & DASD_FEATURE_READONLY || + test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) set_disk_ro(gdp, 1); gdp->private_data = block; gdp->queue = block->request_queue; diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index ed73ce550822..a91d4a97d4f2 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -436,6 +436,10 @@ struct dasd_block { #define DASD_FLAG_OFFLINE 3 /* device is in offline processing */ #define DASD_FLAG_EER_SNSS 4 /* A SNSS is required */ #define DASD_FLAG_EER_IN_USE 5 /* A SNSS request is running */ +#define DASD_FLAG_DEVICE_RO 6 /* The device itself is read-only. Don't + * confuse this with the user specified + * read-only feature. + */ void dasd_put_device_wake(struct dasd_device *); @@ -609,6 +613,9 @@ char *dasd_get_sense(struct irb *); void dasd_device_set_stop_bits(struct dasd_device *, int); void dasd_device_remove_stop_bits(struct dasd_device *, int); +int dasd_device_is_ro(struct dasd_device *); + + /* externals in dasd_devmap.c */ extern int dasd_max_devindex; extern int dasd_probeonly; diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 7039d9cf0fb4..1557214944f7 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -17,6 +17,7 @@ #include <linux/fs.h> #include <linux/blkpg.h> #include <linux/smp_lock.h> +#include <linux/slab.h> #include <asm/compat.h> #include <asm/ccwdev.h> #include <asm/cmb.h> @@ -199,7 +200,8 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp) if (!argp) return -EINVAL; - if (block->base->features & DASD_FEATURE_READONLY) + if (block->base->features & DASD_FEATURE_READONLY || + test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags)) return -EROFS; if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) return -EFAULT; @@ -349,7 +351,8 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) return -EINVAL; if (get_user(intval, (int __user *)argp)) return -EFAULT; - + if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags)) + return -EROFS; set_disk_ro(bdev->bd_disk, intval); return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval); } diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index f13a0bdd148c..2eb025592809 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -14,6 +14,7 @@ #define KMSG_COMPONENT "dasd" #include <linux/ctype.h> +#include <linux/slab.h> #include <linux/string.h> #include <linux/seq_file.h> #include <linux/vmalloc.h> diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 118de392af63..c881a14fa5dd 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -33,7 +33,6 @@ #include <linux/ctype.h> /* isdigit, isxdigit */ #include <linux/errno.h> #include <linux/init.h> -#include <linux/slab.h> #include <linux/blkdev.h> #include <linux/blkpg.h> #include <linux/hdreg.h> /* HDIO_GETGEO */ @@ -41,6 +40,7 @@ #include <linux/bio.h> #include <linux/suspend.h> #include <linux/platform_device.h> +#include <linux/gfp.h> #include <asm/uaccess.h> #define XPRAM_NAME "xpram" diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index 6bca81aea396..bb07577e8fd4 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -12,6 +12,7 @@ #include <linux/interrupt.h> #include <linux/list.h> #include <linux/types.h> +#include <linux/slab.h> #include <linux/err.h> #include <linux/reboot.h> diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index 31c59b0d6df0..0eabcca3c92d 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c @@ -12,6 +12,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/list.h> +#include <linux/slab.h> #include <linux/types.h> #include <linux/smp_lock.h> diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c index cee4d4e42429..cb6bffe7141a 100644 --- a/drivers/s390/char/keyboard.c +++ b/drivers/s390/char/keyboard.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <linux/sched.h> +#include <linux/slab.h> #include <linux/sysrq.h> #include <linux/consolemap.h> diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 33e96484d54f..2ed3f82e5c30 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -21,6 +21,7 @@ #include <linux/interrupt.h> #include <linux/poll.h> #include <linux/device.h> +#include <linux/slab.h> #include <net/iucv/iucv.h> #include <asm/uaccess.h> #include <asm/ebcdic.h> diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index 668a0579b26b..98a49dfda1de 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -20,6 +20,7 @@ #include <linux/poll.h> #include <linux/mutex.h> #include <linux/platform_device.h> +#include <linux/slab.h> #include <asm/uaccess.h> #include <asm/ebcdic.h> #include <asm/io.h> diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 62ddf5202b79..2a4c566456e7 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -373,7 +373,7 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) rq->rc = ccw_device_start(rp->cdev, &rq->ccw, (unsigned long) rq, 0, 0); if (rq->rc == 0) - return; /* Sucessfully restarted. */ + return; /* Successfully restarted. */ break; case RAW3270_IO_STOP: if (!rq) diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index ec88c59842e3..f6d72e1f2a38 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -196,7 +196,7 @@ __sclp_start_request(struct sclp_req *req) req->start_count++; if (rc == 0) { - /* Sucessfully started request */ + /* Successfully started request */ req->status = SCLP_REQ_RUNNING; sclp_running_state = sclp_running_state_running; __sclp_set_request_timer(SCLP_RETRY_INTERVAL * HZ, diff --git a/drivers/s390/char/sclp_async.c b/drivers/s390/char/sclp_async.c index 740fe405c395..7ad30e72f868 100644 --- a/drivers/s390/char/sclp_async.c +++ b/drivers/s390/char/sclp_async.c @@ -11,6 +11,7 @@ #include <linux/device.h> #include <linux/stat.h> #include <linux/string.h> +#include <linux/slab.h> #include <linux/ctype.h> #include <linux/kmod.h> #include <linux/err.h> @@ -84,6 +85,7 @@ static int proc_handler_callhome(struct ctl_table *ctl, int write, rc = copy_from_user(buf, buffer, sizeof(buf)); if (rc != 0) return -EFAULT; + buf[sizeof(buf) - 1] = '\0'; if (strict_strtoul(buf, 0, &val) != 0) return -EINVAL; if (val != 0 && val != 1) diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index b3beab610da4..4b60ede07f0e 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -308,6 +308,13 @@ struct assign_storage_sccb { u16 rn; } __packed; +int arch_get_memory_phys_device(unsigned long start_pfn) +{ + if (!rzm) + return 0; + return PFN_PHYS(start_pfn) >> ilog2(rzm); +} + static unsigned long long rn2addr(u16 rn) { return (unsigned long long) (rn - 1) * rzm; diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c index ad698d30cb3b..ecf45c54f8c4 100644 --- a/drivers/s390/char/sclp_con.c +++ b/drivers/s390/char/sclp_con.c @@ -14,6 +14,7 @@ #include <linux/termios.h> #include <linux/err.h> #include <linux/reboot.h> +#include <linux/gfp.h> #include "sclp.h" #include "sclp_rw.h" diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 434ba04b1309..8258d590505f 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -13,10 +13,10 @@ #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> -#include <linux/slab.h> #include <linux/err.h> #include <linux/init.h> #include <linux/interrupt.h> +#include <linux/gfp.h> #include <asm/uaccess.h> #include "ctrlchar.h" diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 3796ffdb8479..5d706e6c946f 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -23,6 +23,7 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/reboot.h> +#include <linux/slab.h> #include <asm/uaccess.h> #include "sclp.h" diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index cb70fa1cf539..c17f35b6136a 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/bio.h> #include <linux/workqueue.h> +#include <linux/slab.h> #define TAPE_DBF_AREA tape_34xx_dbf diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 9821c5886613..fc993acf99b6 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -12,6 +12,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include <linux/module.h> +#include <linux/slab.h> #include <linux/init.h> #include <linux/bio.h> #include <asm/ebcdic.h> diff --git a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c index b2864e3edb6d..55343df61edd 100644 --- a/drivers/s390/char/tape_class.c +++ b/drivers/s390/char/tape_class.c @@ -11,6 +11,8 @@ #define KMSG_COMPONENT "tape" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/slab.h> + #include "tape_class.h" MODULE_AUTHOR("Stefan Bader <shbader@de.ibm.com>"); diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 81b094e480e6..29c2d73d719d 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -20,6 +20,7 @@ #include <linux/spinlock.h> // for locks #include <linux/vmalloc.h> #include <linux/list.h> +#include <linux/slab.h> #include <asm/types.h> // for variable types diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 921dcda77676..5bb59d36a6d4 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -19,6 +19,7 @@ #include <linux/kernel.h> #include <linux/miscdevice.h> #include <linux/module.h> +#include <linux/slab.h> #include <asm/compat.h> #include <asm/cpcmd.h> #include <asm/debug.h> diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 7dfa5412d5a8..e40a1b892866 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -16,6 +16,7 @@ #include <linux/module.h> #include <linux/init.h> +#include <linux/slab.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/interrupt.h> diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index cc56fc708bae..1de672f21037 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -12,6 +12,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include <linux/cdev.h> +#include <linux/slab.h> #include <linux/smp_lock.h> #include <asm/uaccess.h> diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index c974058e48d2..e13508c98b1a 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c @@ -17,6 +17,7 @@ #include <linux/miscdevice.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/slab.h> #include <linux/suspend.h> #include <linux/watchdog.h> diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 3438658b66b7..18daf16aa357 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -13,6 +13,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include <linux/init.h> +#include <linux/slab.h> #include <linux/miscdevice.h> #include <linux/debugfs.h> #include <asm/asm-offsets.h> @@ -141,33 +142,6 @@ static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count) return memcpy_hsa(dest, src, count, TO_KERNEL); } -static int memcpy_real(void *dest, unsigned long src, size_t count) -{ - unsigned long flags; - int rc = -EFAULT; - register unsigned long _dest asm("2") = (unsigned long) dest; - register unsigned long _len1 asm("3") = (unsigned long) count; - register unsigned long _src asm("4") = src; - register unsigned long _len2 asm("5") = (unsigned long) count; - - if (count == 0) - return 0; - flags = __raw_local_irq_stnsm(0xf8UL); /* switch to real mode */ - asm volatile ( - "0: mvcle %1,%2,0x0\n" - "1: jo 0b\n" - " lhi %0,0x0\n" - "2:\n" - EX_TABLE(1b,2b) - : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1), - "+d" (_len2), "=m" (*((long*)dest)) - : "m" (*((long*)src)) - : "cc", "memory"); - __raw_local_irq_ssm(flags); - - return rc; -} - static int memcpy_real_user(void __user *dest, unsigned long src, size_t count) { static char buf[4096]; @@ -175,7 +149,7 @@ static int memcpy_real_user(void __user *dest, unsigned long src, size_t count) while (offs < count) { size = min(sizeof(buf), count - offs); - if (memcpy_real(buf, src + offs, size)) + if (memcpy_real(buf, (void *) src + offs, size)) return -EFAULT; if (copy_to_user(dest + offs, buf, size)) return -EFAULT; @@ -663,7 +637,7 @@ static int __init zcore_reipl_init(void) if (ipib_info.ipib < ZFCPDUMP_HSA_SIZE) rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE); else - rc = memcpy_real(ipl_block, ipib_info.ipib, PAGE_SIZE); + rc = memcpy_real(ipl_block, (void *) ipib_info.ipib, PAGE_SIZE); if (rc) { free_page((unsigned long) ipl_block); return rc; diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 7eab9ab9f406..13cb60162e42 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -14,7 +14,6 @@ #include <linux/init.h> #include <linux/vmalloc.h> -#include <linux/slab.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/ctype.h> diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index c268a2e5b7c3..1d16189f2f2d 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -15,6 +15,7 @@ #include <linux/wait.h> #include <linux/mutex.h> #include <linux/errno.h> +#include <linux/slab.h> #include <asm/chpid.h> #include <asm/sclp.h> #include <asm/crw.h> diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 852612f5dba0..404f630c27ca 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -7,6 +7,7 @@ * */ +#include <linux/slab.h> #include <linux/device.h> #include <linux/module.h> #include <linux/uaccess.h> diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index c6abb75c4615..6d229f3523a0 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -764,7 +764,7 @@ static void sch_create_and_recog_new_device(struct subchannel *sch) static void io_subchannel_register(struct ccw_device *cdev) { struct subchannel *sch; - int ret; + int ret, adjust_init_count = 1; unsigned long flags; sch = to_subchannel(cdev->dev.parent); @@ -793,6 +793,7 @@ static void io_subchannel_register(struct ccw_device *cdev) cdev->private->dev_id.ssid, cdev->private->dev_id.devno); } + adjust_init_count = 0; goto out; } /* @@ -818,7 +819,7 @@ out: cdev->private->flags.recog_done = 1; wake_up(&cdev->private->wait_q); out_err: - if (atomic_dec_and_test(&ccw_device_init_count)) + if (adjust_init_count && atomic_dec_and_test(&ccw_device_init_count)) wake_up(&ccw_device_init_wq); } diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index c94eb2a0fa2e..6ce83f56d537 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -33,7 +33,6 @@ void qdio_allocate_dbf(struct qdio_initialize *init_data, DBF_HEX(&init_data->input_handler, sizeof(void *)); DBF_HEX(&init_data->output_handler, sizeof(void *)); DBF_HEX(&init_data->int_parm, sizeof(long)); - DBF_HEX(&init_data->flags, sizeof(long)); DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *)); DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *)); DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 232ef047ba34..88be7b9ea6e1 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -13,6 +13,7 @@ #include <linux/kernel.h> #include <linux/timer.h> #include <linux/delay.h> +#include <linux/gfp.h> #include <asm/atomic.h> #include <asm/debug.h> #include <asm/qdio.h> @@ -588,10 +589,11 @@ static void qdio_kick_handler(struct qdio_q *q) if (q->is_input_q) { qperf_inc(q, inbound_handler); DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%02x c:%02x", start, count); - } else + } else { qperf_inc(q, outbound_handler); DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x", start, count); + } q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count, q->irq_ptr->int_parm); diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 9942c1031b25..ce5f8910ff83 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -7,6 +7,7 @@ * Jan Glauber <jang@linux.vnet.ibm.com> */ #include <linux/io.h> +#include <linux/slab.h> #include <asm/atomic.h> #include <asm/debug.h> #include <asm/qdio.h> diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 20836eff88c5..91c6028d7b74 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -33,6 +33,7 @@ #include <linux/err.h> #include <linux/interrupt.h> #include <linux/workqueue.h> +#include <linux/slab.h> #include <linux/notifier.h> #include <linux/kthread.h> #include <linux/mutex.h> diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index ba50fe02e572..304caf549973 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -36,6 +36,7 @@ #include <linux/seq_file.h> #include <linux/compat.h> #include <linux/smp_lock.h> +#include <linux/slab.h> #include <asm/atomic.h> #include <asm/uaccess.h> #include <linux/hw_random.h> diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index c6fb0aa89507..9c409efa1ecf 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -27,6 +27,7 @@ */ #include <linux/module.h> +#include <linux/slab.h> #include <linux/init.h> #include <linux/err.h> #include <asm/atomic.h> diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c index e78df3671caf..09e934b295a0 100644 --- a/drivers/s390/crypto/zcrypt_pcica.c +++ b/drivers/s390/crypto/zcrypt_pcica.c @@ -27,6 +27,7 @@ */ #include <linux/module.h> +#include <linux/slab.h> #include <linux/init.h> #include <linux/err.h> #include <asm/atomic.h> diff --git a/drivers/s390/crypto/zcrypt_pcicc.c b/drivers/s390/crypto/zcrypt_pcicc.c index 142f72a2ca5a..9dec5c77cff4 100644 --- a/drivers/s390/crypto/zcrypt_pcicc.c +++ b/drivers/s390/crypto/zcrypt_pcicc.c @@ -28,6 +28,7 @@ #include <linux/module.h> #include <linux/init.h> +#include <linux/gfp.h> #include <linux/err.h> #include <asm/atomic.h> #include <asm/uaccess.h> diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index 68f3e6204db8..510fab4577d4 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -30,6 +30,7 @@ #include <linux/init.h> #include <linux/err.h> #include <linux/delay.h> +#include <linux/slab.h> #include <asm/atomic.h> #include <asm/uaccess.h> diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index b2fc4fd63f7f..4e298bc8949d 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -15,6 +15,7 @@ #include <linux/err.h> #include <linux/virtio.h> #include <linux/virtio_config.h> +#include <linux/slab.h> #include <linux/virtio_console.h> #include <linux/interrupt.h> #include <linux/virtio_ring.h> diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index cb909a5b5047..977bb4d4ed15 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig @@ -43,6 +43,16 @@ config SMSGIUCV Select this option if you want to be able to receive SMSG messages from other VM guest systems. +config SMSGIUCV_EVENT + tristate "Deliver IUCV special messages as uevents (VM only)" + depends on SMSGIUCV + help + Select this option to deliver CP special messages (SMSGs) as + uevents. The driver handles only those special messages that + start with "APP". + + To compile as a module, choose M. The module name is "smsgiucv_app". + config CLAW tristate "CLAW device support" depends on CCW && NETDEVICES diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile index 6cab5a62f99e..4dfe8c1092da 100644 --- a/drivers/s390/net/Makefile +++ b/drivers/s390/net/Makefile @@ -6,6 +6,7 @@ ctcm-y += ctcm_main.o ctcm_fsms.o ctcm_mpc.o ctcm_sysfs.o ctcm_dbug.o obj-$(CONFIG_CTCM) += ctcm.o fsm.o obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o obj-$(CONFIG_SMSGIUCV) += smsgiucv.o +obj-$(CONFIG_SMSGIUCV_EVENT) += smsgiucv_app.o obj-$(CONFIG_LCS) += lcs.o obj-$(CONFIG_CLAW) += claw.o qeth-y += qeth_core_sys.o qeth_core_main.o qeth_core_mpc.o diff --git a/drivers/s390/net/ctcm_dbug.c b/drivers/s390/net/ctcm_dbug.c index 1ca58f153470..d962fd741a23 100644 --- a/drivers/s390/net/ctcm_dbug.c +++ b/drivers/s390/net/ctcm_dbug.c @@ -10,7 +10,6 @@ #include <linux/string.h> #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/slab.h> #include <linux/ctype.h> #include <linux/sysctl.h> #include <linux/module.h> diff --git a/drivers/s390/net/ctcm_sysfs.c b/drivers/s390/net/ctcm_sysfs.c index 738ad26c74a7..2b24550e865e 100644 --- a/drivers/s390/net/ctcm_sysfs.c +++ b/drivers/s390/net/ctcm_sysfs.c @@ -14,6 +14,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include <linux/sysfs.h> +#include <linux/slab.h> #include "ctcm_main.h" /* diff --git a/drivers/s390/net/fsm.c b/drivers/s390/net/fsm.c index cae48cbc5e96..e5dea67f902e 100644 --- a/drivers/s390/net/fsm.c +++ b/drivers/s390/net/fsm.c @@ -5,6 +5,7 @@ #include "fsm.h" #include <linux/module.h> +#include <linux/slab.h> #include <linux/timer.h> MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)"); diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index f6cc46dc0501..9b19ea13b4d8 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -37,6 +37,7 @@ #include <linux/igmp.h> #include <linux/delay.h> #include <linux/kthread.h> +#include <linux/slab.h> #include <net/arp.h> #include <net/ip.h> diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index a3ac4456e0b1..fcd005aad989 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -763,7 +763,8 @@ static inline int qeth_get_micros(void) static inline int qeth_get_ip_version(struct sk_buff *skb) { - switch (skb->protocol) { + struct ethhdr *ehdr = (struct ethhdr *)skb->data; + switch (ehdr->h_proto) { case ETH_P_IPV6: return 6; case ETH_P_IP: diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index fa8a519218ac..3ba738b2e271 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -20,6 +20,7 @@ #include <linux/tcp.h> #include <linux/mii.h> #include <linux/kthread.h> +#include <linux/slab.h> #include <asm/ebcdic.h> #include <asm/io.h> @@ -537,7 +538,8 @@ static void qeth_send_control_data_cb(struct qeth_channel *channel, dev_err(&card->gdev->dev, "The qeth device is not configured " "for the OSI layer required by z/VM\n"); - qeth_schedule_recovery(card); + else + qeth_schedule_recovery(card); goto out; } @@ -1113,8 +1115,6 @@ static int qeth_setup_card(struct qeth_card *card) card->ipato.enabled = 0; card->ipato.invert4 = 0; card->ipato.invert6 = 0; - if (card->info.type == QETH_CARD_TYPE_IQD) - card->options.checksum_type = NO_CHECKSUMMING; /* init QDIO stuff */ qeth_init_qdio_info(card); return 0; @@ -3805,9 +3805,6 @@ static int qeth_qdio_establish(struct qeth_card *card) init_data.input_handler = card->discipline.input_handler; init_data.output_handler = card->discipline.output_handler; init_data.int_parm = (unsigned long) card; - init_data.flags = QDIO_INBOUND_0COPY_SBALS | - QDIO_OUTBOUND_0COPY_SBALS | - QDIO_USE_OUTBOUND_PCIS; init_data.input_sbal_addr_array = (void **) in_sbal_ptrs; init_data.output_sbal_addr_array = (void **) out_sbal_ptrs; diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 88ae4357136a..25dfd5abd19b 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -8,6 +8,9 @@ * Frank Blaschka <frank.blaschka@de.ibm.com> */ +#define KMSG_COMPONENT "qeth" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/list.h> #include <linux/rwsem.h> #include <asm/ebcdic.h> diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 51fde6f2e0b8..6a801dc3bf8e 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -16,6 +16,7 @@ #include <linux/string.h> #include <linux/errno.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/etherdevice.h> #include <linux/mii.h> #include <linux/ip.h> @@ -1071,11 +1072,9 @@ static int qeth_l2_recover(void *ptr) dev_info(&card->gdev->dev, "Device successfully recovered!\n"); else { - if (card->dev) { - rtnl_lock(); - dev_close(card->dev); - rtnl_unlock(); - } + rtnl_lock(); + dev_close(card->dev); + rtnl_unlock(); dev_warn(&card->gdev->dev, "The qeth device driver " "failed to recover an error on the device\n"); } @@ -1129,11 +1128,9 @@ static int qeth_l2_pm_resume(struct ccwgroup_device *gdev) if (card->state == CARD_STATE_RECOVER) { rc = __qeth_l2_set_online(card->gdev, 1); if (rc) { - if (card->dev) { - rtnl_lock(); - dev_close(card->dev); - rtnl_unlock(); - } + rtnl_lock(); + dev_close(card->dev); + rtnl_unlock(); } } else rc = __qeth_l2_set_online(card->gdev, 0); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 5475834ab916..fc6ca1da8b98 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -22,6 +22,7 @@ #include <linux/ipv6.h> #include <linux/inetdevice.h> #include <linux/igmp.h> +#include <linux/slab.h> #include <net/ip.h> #include <net/arp.h> @@ -1691,39 +1692,43 @@ qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply, cmd = (struct qeth_ipa_cmd *)data; rc = cmd->hdr.return_code; - if (rc) { + if (rc) QETH_DBF_TEXT_(TRACE, 2, "dxter%x", rc); - if (cmd->data.diagass.action == QETH_DIAGS_CMD_TRACE_ENABLE) { - switch (rc) { - case IPA_RC_HARDWARE_AUTH_ERROR: - dev_warn(&card->gdev->dev, "The device is not " - "authorized to run as a HiperSockets " - "network traffic analyzer\n"); - break; - case IPA_RC_TRACE_ALREADY_ACTIVE: - dev_warn(&card->gdev->dev, "A HiperSockets " - "network traffic analyzer is already " - "active in the HiperSockets LAN\n"); - break; - default: - break; - } - } - return 0; - } - switch (cmd->data.diagass.action) { case QETH_DIAGS_CMD_TRACE_QUERY: break; case QETH_DIAGS_CMD_TRACE_DISABLE: - card->info.promisc_mode = SET_PROMISC_MODE_OFF; - dev_info(&card->gdev->dev, "The HiperSockets network traffic " - "analyzer is deactivated\n"); + switch (rc) { + case 0: + case IPA_RC_INVALID_SUBCMD: + card->info.promisc_mode = SET_PROMISC_MODE_OFF; + dev_info(&card->gdev->dev, "The HiperSockets network " + "traffic analyzer is deactivated\n"); + break; + default: + break; + } break; case QETH_DIAGS_CMD_TRACE_ENABLE: - card->info.promisc_mode = SET_PROMISC_MODE_ON; - dev_info(&card->gdev->dev, "The HiperSockets network traffic " - "analyzer is activated\n"); + switch (rc) { + case 0: + card->info.promisc_mode = SET_PROMISC_MODE_ON; + dev_info(&card->gdev->dev, "The HiperSockets network " + "traffic analyzer is activated\n"); + break; + case IPA_RC_HARDWARE_AUTH_ERROR: + dev_warn(&card->gdev->dev, "The device is not " + "authorized to run as a HiperSockets network " + "traffic analyzer\n"); + break; + case IPA_RC_TRACE_ALREADY_ACTIVE: + dev_warn(&card->gdev->dev, "A HiperSockets " + "network traffic analyzer is already " + "active in the HiperSockets LAN\n"); + break; + default: + break; + } break; default: QETH_DBF_MESSAGE(2, "Unknown sniffer action (0x%04x) on %s\n", @@ -2215,11 +2220,9 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) if (recovery_mode) qeth_l3_stop(card->dev); else { - if (card->dev) { - rtnl_lock(); - dev_close(card->dev); - rtnl_unlock(); - } + rtnl_lock(); + dev_close(card->dev); + rtnl_unlock(); } if (!card->use_hard_stop) { rc = qeth_send_stoplan(card); @@ -2900,10 +2903,8 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) int data_offset = -1; int nr_frags; - if ((card->info.type == QETH_CARD_TYPE_IQD) && - (((skb->protocol != htons(ETH_P_IPV6)) && - (skb->protocol != htons(ETH_P_IP))) || - card->options.sniffer)) + if (((card->info.type == QETH_CARD_TYPE_IQD) && (!ipv)) || + card->options.sniffer) goto tx_drop; if ((card->state != CARD_STATE_UP) || !card->lan_online) { @@ -2949,14 +2950,14 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (data_offset < 0) skb_pull(new_skb, ETH_HLEN); } else { - if (new_skb->protocol == htons(ETH_P_IP)) { + if (ipv == 4) { if (card->dev->type == ARPHRD_IEEE802_TR) skb_pull(new_skb, TR_HLEN); else skb_pull(new_skb, ETH_HLEN); } - if (new_skb->protocol == ETH_P_IPV6 && card->vlangrp && + if (ipv == 6 && card->vlangrp && vlan_tx_tag_present(new_skb)) { skb_push(new_skb, VLAN_HLEN); skb_copy_to_linear_data(new_skb, new_skb->data + 4, 4); @@ -3534,11 +3535,9 @@ static int qeth_l3_pm_resume(struct ccwgroup_device *gdev) if (card->state == CARD_STATE_RECOVER) { rc = __qeth_l3_set_online(card->gdev, 1); if (rc) { - if (card->dev) { - rtnl_lock(); - dev_close(card->dev); - rtnl_unlock(); - } + rtnl_lock(); + dev_close(card->dev); + rtnl_unlock(); } } else rc = __qeth_l3_set_online(card->gdev, 0); diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index 3f08b11274ae..25b3e7aae44f 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -8,6 +8,8 @@ * Frank Blaschka <frank.blaschka@de.ibm.com> */ +#include <linux/slab.h> + #include "qeth_l3.h" #define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \ diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index 67f2485d2372..70491274da16 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c @@ -24,6 +24,7 @@ #include <linux/init.h> #include <linux/errno.h> #include <linux/device.h> +#include <linux/slab.h> #include <net/iucv/iucv.h> #include <asm/cpcmd.h> #include <asm/ebcdic.h> @@ -31,9 +32,9 @@ struct smsg_callback { struct list_head list; - char *prefix; + const char *prefix; int len; - void (*callback)(char *from, char *str); + void (*callback)(const char *from, char *str); }; MODULE_AUTHOR @@ -100,8 +101,8 @@ static void smsg_message_pending(struct iucv_path *path, kfree(buffer); } -int smsg_register_callback(char *prefix, - void (*callback)(char *from, char *str)) +int smsg_register_callback(const char *prefix, + void (*callback)(const char *from, char *str)) { struct smsg_callback *cb; @@ -117,8 +118,9 @@ int smsg_register_callback(char *prefix, return 0; } -void smsg_unregister_callback(char *prefix, - void (*callback)(char *from, char *str)) +void smsg_unregister_callback(const char *prefix, + void (*callback)(const char *from, + char *str)) { struct smsg_callback *cb, *tmp; @@ -176,7 +178,7 @@ static const struct dev_pm_ops smsg_pm_ops = { static struct device_driver smsg_driver = { .owner = THIS_MODULE, - .name = "SMSGIUCV", + .name = SMSGIUCV_DRV_NAME, .bus = &iucv_bus, .pm = &smsg_pm_ops, }; diff --git a/drivers/s390/net/smsgiucv.h b/drivers/s390/net/smsgiucv.h index 67f5d4f8378d..149a1151608d 100644 --- a/drivers/s390/net/smsgiucv.h +++ b/drivers/s390/net/smsgiucv.h @@ -5,6 +5,10 @@ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) */ -int smsg_register_callback(char *, void (*)(char *, char *)); -void smsg_unregister_callback(char *, void (*)(char *, char *)); +#define SMSGIUCV_DRV_NAME "SMSGIUCV" + +int smsg_register_callback(const char *, + void (*)(const char *, char *)); +void smsg_unregister_callback(const char *, + void (*)(const char *, char *)); diff --git a/drivers/s390/net/smsgiucv_app.c b/drivers/s390/net/smsgiucv_app.c new file mode 100644 index 000000000000..137688790207 --- /dev/null +++ b/drivers/s390/net/smsgiucv_app.c @@ -0,0 +1,212 @@ +/* + * Deliver z/VM CP special messages (SMSG) as uevents. + * + * The driver registers for z/VM CP special messages with the + * "APP" prefix. Incoming messages are delivered to user space + * as uevents. + * + * Copyright IBM Corp. 2010 + * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com> + * + */ +#define KMSG_COMPONENT "smsgiucv_app" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include <linux/ctype.h> +#include <linux/err.h> +#include <linux/device.h> +#include <linux/list.h> +#include <linux/kobject.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> +#include <net/iucv/iucv.h> +#include "smsgiucv.h" + +/* prefix used for SMSG registration */ +#define SMSG_PREFIX "APP" + +/* SMSG related uevent environment variables */ +#define ENV_SENDER_STR "SMSG_SENDER=" +#define ENV_SENDER_LEN (strlen(ENV_SENDER_STR) + 8 + 1) +#define ENV_PREFIX_STR "SMSG_ID=" +#define ENV_PREFIX_LEN (strlen(ENV_PREFIX_STR) + \ + strlen(SMSG_PREFIX) + 1) +#define ENV_TEXT_STR "SMSG_TEXT=" +#define ENV_TEXT_LEN(msg) (strlen(ENV_TEXT_STR) + strlen((msg)) + 1) + +/* z/VM user ID which is permitted to send SMSGs + * If the value is undefined or empty (""), special messages are + * accepted from any z/VM user ID. */ +static char *sender; +module_param(sender, charp, 0400); +MODULE_PARM_DESC(sender, "z/VM user ID from which CP SMSGs are accepted"); + +/* SMSG device representation */ +static struct device *smsg_app_dev; + +/* list element for queuing received messages for delivery */ +struct smsg_app_event { + struct list_head list; + char *buf; + char *envp[4]; +}; + +/* queue for outgoing uevents */ +static LIST_HEAD(smsg_event_queue); +static DEFINE_SPINLOCK(smsg_event_queue_lock); + +static void smsg_app_event_free(struct smsg_app_event *ev) +{ + kfree(ev->buf); + kfree(ev); +} + +static struct smsg_app_event *smsg_app_event_alloc(const char *from, + const char *msg) +{ + struct smsg_app_event *ev; + + ev = kzalloc(sizeof(*ev), GFP_ATOMIC); + if (!ev) + return NULL; + + ev->buf = kzalloc(ENV_SENDER_LEN + ENV_PREFIX_LEN + + ENV_TEXT_LEN(msg), GFP_ATOMIC); + if (!ev->buf) { + kfree(ev); + return NULL; + } + + /* setting up environment pointers into buf */ + ev->envp[0] = ev->buf; + ev->envp[1] = ev->envp[0] + ENV_SENDER_LEN; + ev->envp[2] = ev->envp[1] + ENV_PREFIX_LEN; + ev->envp[3] = NULL; + + /* setting up environment: sender, prefix name, and message text */ + snprintf(ev->envp[0], ENV_SENDER_LEN, ENV_SENDER_STR "%s", from); + snprintf(ev->envp[1], ENV_PREFIX_LEN, ENV_PREFIX_STR "%s", SMSG_PREFIX); + snprintf(ev->envp[2], ENV_TEXT_LEN(msg), ENV_TEXT_STR "%s", msg); + + return ev; +} + +static void smsg_event_work_fn(struct work_struct *work) +{ + LIST_HEAD(event_queue); + struct smsg_app_event *p, *n; + struct device *dev; + + dev = get_device(smsg_app_dev); + if (!dev) + return; + + spin_lock_bh(&smsg_event_queue_lock); + list_splice_init(&smsg_event_queue, &event_queue); + spin_unlock_bh(&smsg_event_queue_lock); + + list_for_each_entry_safe(p, n, &event_queue, list) { + list_del(&p->list); + kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, p->envp); + smsg_app_event_free(p); + } + + put_device(dev); +} +static DECLARE_WORK(smsg_event_work, smsg_event_work_fn); + +static void smsg_app_callback(const char *from, char *msg) +{ + struct smsg_app_event *se; + + /* check if the originating z/VM user ID matches + * the configured sender. */ + if (sender && strlen(sender) > 0 && strcmp(from, sender) != 0) + return; + + /* get start of message text (skip prefix and leading blanks) */ + msg += strlen(SMSG_PREFIX); + while (*msg && isspace(*msg)) + msg++; + if (*msg == '\0') + return; + + /* allocate event list element and its environment */ + se = smsg_app_event_alloc(from, msg); + if (!se) + return; + + /* queue event and schedule work function */ + spin_lock(&smsg_event_queue_lock); + list_add_tail(&se->list, &smsg_event_queue); + spin_unlock(&smsg_event_queue_lock); + + schedule_work(&smsg_event_work); + return; +} + +static int __init smsgiucv_app_init(void) +{ + struct device_driver *smsgiucv_drv; + int rc; + + if (!MACHINE_IS_VM) + return -ENODEV; + + smsg_app_dev = kzalloc(sizeof(*smsg_app_dev), GFP_KERNEL); + if (!smsg_app_dev) + return -ENOMEM; + + smsgiucv_drv = driver_find(SMSGIUCV_DRV_NAME, &iucv_bus); + if (!smsgiucv_drv) { + kfree(smsg_app_dev); + return -ENODEV; + } + + rc = dev_set_name(smsg_app_dev, KMSG_COMPONENT); + if (rc) { + kfree(smsg_app_dev); + goto fail_put_driver; + } + smsg_app_dev->bus = &iucv_bus; + smsg_app_dev->parent = iucv_root; + smsg_app_dev->release = (void (*)(struct device *)) kfree; + smsg_app_dev->driver = smsgiucv_drv; + rc = device_register(smsg_app_dev); + if (rc) { + put_device(smsg_app_dev); + goto fail_put_driver; + } + + /* register with the smsgiucv device driver */ + rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback); + if (rc) { + device_unregister(smsg_app_dev); + goto fail_put_driver; + } + + rc = 0; +fail_put_driver: + put_driver(smsgiucv_drv); + return rc; +} +module_init(smsgiucv_app_init); + +static void __exit smsgiucv_app_exit(void) +{ + /* unregister callback */ + smsg_unregister_callback(SMSG_PREFIX, smsg_app_callback); + + /* cancel pending work and flush any queued event work */ + cancel_work_sync(&smsg_event_work); + smsg_event_work_fn(&smsg_event_work); + + device_unregister(smsg_app_dev); +} +module_exit(smsgiucv_app_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Deliver z/VM CP SMSG as uevents"); +MODULE_AUTHOR("Hendrik Brueckner <brueckner@linux.vnet.ibm.com>"); diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 66d6c01fcf3e..1e6183a86ce5 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -30,6 +30,7 @@ #include <linux/miscdevice.h> #include <linux/seq_file.h> +#include <linux/slab.h> #include "zfcp_ext.h" #include "zfcp_fc.h" #include "zfcp_reqlist.h" diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index 0eb6eefd2c1a..25d9e0ae9c57 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -10,6 +10,7 @@ #define KMSG_COMPONENT "zfcp" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/slab.h> #include <linux/types.h> #include <linux/miscdevice.h> #include <asm/compat.h> diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 7a149fd85f6d..075852f6968c 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -10,6 +10,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include <linux/ctype.h> +#include <linux/slab.h> #include <asm/debug.h> #include "zfcp_dbf.h" #include "zfcp_ext.h" diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 5219670f0c99..2a1cbb74b99b 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -10,6 +10,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include <linux/types.h> +#include <linux/slab.h> #include <scsi/fc/fc_els.h> #include <scsi/libfc.h> #include "zfcp_ext.h" diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 6538742b421a..18564891ea61 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -10,6 +10,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include <linux/blktrace_api.h> +#include <linux/slab.h> #include <scsi/fc/fc_els.h> #include "zfcp_ext.h" #include "zfcp_fc.h" diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 71b97ff77cf0..dbfa312a7f50 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -9,6 +9,7 @@ #define KMSG_COMPONENT "zfcp" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/slab.h> #include "zfcp_ext.h" #include "zfcp_qdio.h" @@ -319,8 +320,6 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id, id->input_handler = zfcp_qdio_int_resp; id->output_handler = zfcp_qdio_int_req; id->int_parm = (unsigned long) qdio; - id->flags = QDIO_INBOUND_0COPY_SBALS | - QDIO_OUTBOUND_0COPY_SBALS | QDIO_USE_OUTBOUND_PCIS; id->input_sbal_addr_array = (void **) (qdio->resp_q.sbal); id->output_sbal_addr_array = (void **) (qdio->req_q.sbal); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index c3c4178888af..174b6d57d576 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -10,6 +10,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include <linux/types.h> +#include <linux/slab.h> #include <scsi/fc/fc_fcp.h> #include <asm/atomic.h> #include "zfcp_ext.h" diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index a43035d4bd70..f5f60698dc4c 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -9,6 +9,7 @@ #define KMSG_COMPONENT "zfcp" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/slab.h> #include "zfcp_ext.h" #define ZFCP_DEV_ATTR(_feat, _name, _mode, _show, _store) \ |