diff options
Diffstat (limited to 'drivers/s390/char')
| -rw-r--r-- | drivers/s390/char/Kconfig | 10 | ||||
| -rw-r--r-- | drivers/s390/char/Makefile | 1 | ||||
| -rw-r--r-- | drivers/s390/char/monreader.c | 2 | ||||
| -rw-r--r-- | drivers/s390/char/sclp.h | 4 | ||||
| -rw-r--r-- | drivers/s390/char/sclp_async.c | 224 | ||||
| -rw-r--r-- | drivers/s390/char/tape_34xx.c | 2 | ||||
| -rw-r--r-- | drivers/s390/char/tape_3590.c | 4 | ||||
| -rw-r--r-- | drivers/s390/char/tape_block.c | 12 | ||||
| -rw-r--r-- | drivers/s390/char/tape_core.c | 18 | ||||
| -rw-r--r-- | drivers/s390/char/tape_std.c | 2 | ||||
| -rw-r--r-- | drivers/s390/char/vmlogrdr.c | 4 | ||||
| -rw-r--r-- | drivers/s390/char/vmur.c | 19 | ||||
| -rw-r--r-- | drivers/s390/char/zcore.c | 2 | 
13 files changed, 272 insertions, 32 deletions
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig index 0769ced52db..4e34d3686c2 100644 --- a/drivers/s390/char/Kconfig +++ b/drivers/s390/char/Kconfig @@ -82,6 +82,16 @@ config SCLP_CPI  	  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 +	tristate "Support for Call Home via Asynchronous SCLP Records" +	depends on S390 +	help +	  This option enables the call home function, which is able to inform +	  the service element and connected organisations about a kernel panic. +	  You should only select this option if you know what you are doing, +	  want for inform other people about your kernel panics, +	  need this feature and intend to run your kernel in LPAR. +  config S390_TAPE  	tristate "S/390 tape device support"  	depends on CCW diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index 7e73e39a174..efb500ab66c 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -16,6 +16,7 @@ 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_ZVM_WATCHDOG) += vmwatchdog.o  obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 3234e90bd7f..89ece1c235a 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -581,7 +581,7 @@ static int __init mon_init(void)  	monreader_device->release = (void (*)(struct device *))kfree;  	rc = device_register(monreader_device);  	if (rc) { -		kfree(monreader_device); +		put_device(monreader_device);  		goto out_driver;  	} diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 60e7cb07095..6bb5a6bdfab 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -27,6 +27,7 @@  #define EVTYP_VT220MSG		0x1A  #define EVTYP_CONFMGMDATA	0x04  #define EVTYP_SDIAS		0x1C +#define EVTYP_ASYNC		0x0A  #define EVTYP_OPCMD_MASK	0x80000000  #define EVTYP_MSG_MASK		0x40000000 @@ -38,6 +39,7 @@  #define EVTYP_VT220MSG_MASK	0x00000040  #define EVTYP_CONFMGMDATA_MASK	0x10000000  #define EVTYP_SDIAS_MASK	0x00000010 +#define EVTYP_ASYNC_MASK	0x00400000  #define GNRLMSGFLGS_DOM		0x8000  #define GNRLMSGFLGS_SNDALRM	0x4000 @@ -85,12 +87,12 @@ struct sccb_header {  } __attribute__((packed));  extern u64 sclp_facilities; -  #define SCLP_HAS_CHP_INFO	(sclp_facilities & 0x8000000000000000ULL)  #define SCLP_HAS_CHP_RECONFIG	(sclp_facilities & 0x2000000000000000ULL)  #define SCLP_HAS_CPU_INFO	(sclp_facilities & 0x0800000000000000ULL)  #define SCLP_HAS_CPU_RECONFIG	(sclp_facilities & 0x0400000000000000ULL) +  struct gds_subvector {  	u8	length;  	u8	key; diff --git a/drivers/s390/char/sclp_async.c b/drivers/s390/char/sclp_async.c new file mode 100644 index 00000000000..daaec185ed3 --- /dev/null +++ b/drivers/s390/char/sclp_async.c @@ -0,0 +1,224 @@ +/* + * Enable Asynchronous Notification via SCLP. + * + * Copyright IBM Corp. 2009 + * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com> + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/stat.h> +#include <linux/string.h> +#include <linux/ctype.h> +#include <linux/kmod.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/proc_fs.h> +#include <linux/sysctl.h> +#include <linux/utsname.h> +#include "sclp.h" + +static int callhome_enabled; +static struct sclp_req *request; +static struct sclp_async_sccb *sccb; +static int sclp_async_send_wait(char *message); +static struct ctl_table_header *callhome_sysctl_header; +static DEFINE_SPINLOCK(sclp_async_lock); +static char nodename[64]; +#define SCLP_NORMAL_WRITE	0x00 + +struct async_evbuf { +	struct evbuf_header header; +	u64 reserved; +	u8 rflags; +	u8 empty; +	u8 rtype; +	u8 otype; +	char comp_id[12]; +	char data[3000]; /* there is still some space left */ +} __attribute__((packed)); + +struct sclp_async_sccb { +	struct sccb_header header; +	struct async_evbuf evbuf; +} __attribute__((packed)); + +static struct sclp_register sclp_async_register = { +	.send_mask = EVTYP_ASYNC_MASK, +}; + +static int call_home_on_panic(struct notifier_block *self, +			      unsigned long event, void *data) +{ +		strncat(data, nodename, strlen(nodename)); +		sclp_async_send_wait(data); +		return NOTIFY_DONE; +} + +static struct notifier_block call_home_panic_nb = { +	.notifier_call = call_home_on_panic, +	.priority = INT_MAX, +}; + +static int proc_handler_callhome(ctl_table *ctl, int write, struct file *filp, +				 void __user *buffer, size_t *count, +				 loff_t *ppos) +{ +	unsigned long val; +	int len, rc; +	char buf[2]; + +	if (!*count | (*ppos && !write)) { +		*count = 0; +		return 0; +	} +	if (!write) { +		len =  sprintf(buf, "%d\n", callhome_enabled); +		buf[len] = '\0'; +		rc = copy_to_user(buffer, buf, sizeof(buf)); +		if (rc != 0) +			return -EFAULT; +	} else { +		len = *count; +		rc = copy_from_user(buf, buffer, sizeof(buf)); +		if (rc != 0) +			return -EFAULT; +		if (strict_strtoul(buf, 0, &val) != 0) +			return -EINVAL; +		if (val != 0 && val != 1) +			return -EINVAL; +		callhome_enabled = val; +	} +	*count = len; +	*ppos += len; +	return 0; +} + +static struct ctl_table callhome_table[] = { +	{ +		.procname	= "callhome", +		.mode		= 0644, +		.proc_handler	= &proc_handler_callhome, +	}, +	{ .ctl_name = 0 } +}; + +static struct ctl_table kern_dir_table[] = { +	{ +		.ctl_name	= CTL_KERN, +		.procname	= "kernel", +		.maxlen		= 0, +		.mode		= 0555, +		.child		= callhome_table, +	}, +	{ .ctl_name = 0 } +}; + +/* + * Function used to transfer asynchronous notification + * records which waits for send completion + */ +static int sclp_async_send_wait(char *message) +{ +	struct async_evbuf *evb; +	int rc; +	unsigned long flags; + +	if (!callhome_enabled) +		return 0; +	sccb->evbuf.header.type = EVTYP_ASYNC; +	sccb->evbuf.rtype = 0xA5; +	sccb->evbuf.otype = 0x00; +	evb = &sccb->evbuf; +	request->command = SCLP_CMDW_WRITE_EVENT_DATA; +	request->sccb = sccb; +	request->status = SCLP_REQ_FILLED; +	strncpy(sccb->evbuf.data, message, sizeof(sccb->evbuf.data)); +	/* +	 * Retain Queue +	 * e.g. 5639CC140 500 Red Hat RHEL5 Linux for zSeries (RHEL AS) +	 */ +	strncpy(sccb->evbuf.comp_id, "000000000", sizeof(sccb->evbuf.comp_id)); +	sccb->evbuf.header.length = sizeof(sccb->evbuf); +	sccb->header.length = sizeof(sccb->evbuf) + sizeof(sccb->header); +	sccb->header.function_code = SCLP_NORMAL_WRITE; +	rc = sclp_add_request(request); +	if (rc) +		return rc; +	spin_lock_irqsave(&sclp_async_lock, flags); +	while (request->status != SCLP_REQ_DONE && +		request->status != SCLP_REQ_FAILED) { +		 sclp_sync_wait(); +	} +	spin_unlock_irqrestore(&sclp_async_lock, flags); +	if (request->status != SCLP_REQ_DONE) +		return -EIO; +	rc = ((struct sclp_async_sccb *) +	       request->sccb)->header.response_code; +	if (rc != 0x0020) +		return -EIO; +	if (evb->header.flags != 0x80) +		return -EIO; +	return rc; +} + +static int __init sclp_async_init(void) +{ +	int rc; + +	rc = sclp_register(&sclp_async_register); +	if (rc) +		return rc; +	callhome_sysctl_header = register_sysctl_table(kern_dir_table); +	if (!callhome_sysctl_header) { +		rc = -ENOMEM; +		goto out_sclp; +	} +	if (!(sclp_async_register.sclp_receive_mask & EVTYP_ASYNC_MASK)) { +		rc = -EOPNOTSUPP; +		goto out_sclp; +	} +	rc = -ENOMEM; +	request = kzalloc(sizeof(struct sclp_req), GFP_KERNEL); +	if (!request) +		goto out_sys; +	sccb = (struct sclp_async_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA); +	if (!sccb) +		goto out_mem; +	rc =  atomic_notifier_chain_register(&panic_notifier_list, +					     &call_home_panic_nb); +	if (rc) +		goto out_mem; + +	strncpy(nodename, init_utsname()->nodename, 64); +	return 0; + +out_mem: +	kfree(request); +	free_page((unsigned long) sccb); +out_sys: +	unregister_sysctl_table(callhome_sysctl_header); +out_sclp: +	sclp_unregister(&sclp_async_register); +	return rc; + +} +module_init(sclp_async_init); + +static void __exit sclp_async_exit(void) +{ +	atomic_notifier_chain_unregister(&panic_notifier_list, +					 &call_home_panic_nb); +	unregister_sysctl_table(callhome_sysctl_header); +	sclp_unregister(&sclp_async_register); +	free_page((unsigned long) sccb); +	kfree(request); +} +module_exit(sclp_async_exit); + +MODULE_AUTHOR("Copyright IBM Corp. 2009"); +MODULE_AUTHOR("Hans-Joachim Picht <hans@linux.vnet.ibm.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SCLP Asynchronous Notification Records"); diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 5a519fac37b..2fe45ff77b7 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -8,7 +8,7 @@   *		 Martin Schwidefsky <schwidefsky@de.ibm.com>   */ -#define KMSG_COMPONENT "tape" +#define KMSG_COMPONENT "tape_34xx"  #include <linux/module.h>  #include <linux/init.h> diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 418f72dd39b..e4cc3aae916 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -8,7 +8,7 @@   *		 Martin Schwidefsky <schwidefsky@de.ibm.com>   */ -#define KMSG_COMPONENT "tape" +#define KMSG_COMPONENT "tape_3590"  #include <linux/module.h>  #include <linux/init.h> @@ -39,8 +39,6 @@ EXPORT_SYMBOL(TAPE_DBF_AREA);   * - Read Alternate:		 implemented   *******************************************************************/ -#define KMSG_COMPONENT "tape" -  static const char *tape_3590_msg[TAPE_3590_MAX_MSG] = {  	[0x00] = "",  	[0x10] = "Lost Sense", diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 47ff695255e..4cb9e70507a 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -302,8 +302,6 @@ tapeblock_revalidate_disk(struct gendisk *disk)  	if (!device->blk_data.medium_changed)  		return 0; -	dev_info(&device->cdev->dev, "Determining the size of the recorded " -		"area...\n");  	rc = tape_mtop(device, MTFSFM, 1);  	if (rc)  		return rc; @@ -312,6 +310,8 @@ tapeblock_revalidate_disk(struct gendisk *disk)  	if (rc < 0)  		return rc; +	pr_info("%s: Determining the size of the recorded area...\n", +		dev_name(&device->cdev->dev));  	DBF_LH(3, "Image file ends at %d\n", rc);  	nr_of_blks = rc; @@ -330,8 +330,8 @@ tapeblock_revalidate_disk(struct gendisk *disk)  	device->bof = rc;  	nr_of_blks -= rc; -	dev_info(&device->cdev->dev, "The size of the recorded area is %i " -		"blocks\n", nr_of_blks); +	pr_info("%s: The size of the recorded area is %i blocks\n", +		dev_name(&device->cdev->dev), nr_of_blks);  	set_capacity(device->blk_data.disk,  		nr_of_blks*(TAPEBLOCK_HSEC_SIZE/512)); @@ -366,8 +366,8 @@ tapeblock_open(struct block_device *bdev, fmode_t mode)  	if (device->required_tapemarks) {  		DBF_EVENT(2, "TBLOCK: missing tapemarks\n"); -		dev_warn(&device->cdev->dev, "Opening the tape failed because" -			" of missing end-of-file marks\n"); +		pr_warning("%s: Opening the tape failed because of missing " +			   "end-of-file marks\n", dev_name(&device->cdev->dev));  		rc = -EPERM;  		goto put_device;  	} diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 1d420d94759..5cd31e07164 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -214,13 +214,15 @@ tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate)  	switch(newstate){  	case MS_UNLOADED:  		device->tape_generic_status |= GMT_DR_OPEN(~0); -		dev_info(&device->cdev->dev, "The tape cartridge has been " -			"successfully unloaded\n"); +		if (device->medium_state == MS_LOADED) +			pr_info("%s: The tape cartridge has been successfully " +				"unloaded\n", dev_name(&device->cdev->dev));  		break;  	case MS_LOADED:  		device->tape_generic_status &= ~GMT_DR_OPEN(~0); -		dev_info(&device->cdev->dev, "A tape cartridge has been " -			"mounted\n"); +		if (device->medium_state == MS_UNLOADED) +			pr_info("%s: A tape cartridge has been mounted\n", +				dev_name(&device->cdev->dev));  		break;  	default:  		// print nothing @@ -358,11 +360,11 @@ tape_generic_online(struct tape_device *device,  out_char:  	tapechar_cleanup_device(device); +out_minor: +	tape_remove_minor(device);  out_discipline:  	device->discipline->cleanup_device(device);  	device->discipline = NULL; -out_minor: -	tape_remove_minor(device);  out:  	module_put(discipline->owner);  	return rc; @@ -654,8 +656,8 @@ tape_generic_remove(struct ccw_device *cdev)  			 */  			DBF_EVENT(3, "(%08x): Drive in use vanished!\n",  				device->cdev_id); -			dev_warn(&device->cdev->dev, "A tape unit was detached" -				" while in use\n"); +			pr_warning("%s: A tape unit was detached while in " +				   "use\n", dev_name(&device->cdev->dev));  			tape_state_set(device, TS_NOT_OPER);  			__tape_discard_requests(device);  			spin_unlock_irq(get_ccwdev_lock(device->cdev)); diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index 1a9420ba518..750354ad16e 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c @@ -68,7 +68,7 @@ tape_std_assign(struct tape_device *device)  	 * to another host (actually this shouldn't happen but it does).  	 * So we set up a timeout for this call.  	 */ -	init_timer(&timeout); +	init_timer_on_stack(&timeout);  	timeout.function = tape_std_assign_timeout;  	timeout.data     = (unsigned long) request;  	timeout.expires  = jiffies + 2 * HZ; diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index c20a4fe6da5..d1a142fa3eb 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -765,8 +765,10 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)  	} else  		return -ENOMEM;  	ret = device_register(dev); -	if (ret) +	if (ret) { +		put_device(dev);  		return ret; +	}  	ret = sysfs_create_group(&dev->kobj, &vmlogrdr_attr_group);  	if (ret) { diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 31b902e94f7..77571b68539 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -1026,9 +1026,15 @@ static int __init ur_init(void)  	debug_set_level(vmur_dbf, 6); +	vmur_class = class_create(THIS_MODULE, "vmur"); +	if (IS_ERR(vmur_class)) { +		rc = PTR_ERR(vmur_class); +		goto fail_free_dbf; +	} +  	rc = ccw_driver_register(&ur_driver);  	if (rc) -		goto fail_free_dbf; +		goto fail_class_destroy;  	rc = alloc_chrdev_region(&dev, 0, NUM_MINORS, "vmur");  	if (rc) { @@ -1038,18 +1044,13 @@ static int __init ur_init(void)  	}  	ur_first_dev_maj_min = MKDEV(MAJOR(dev), 0); -	vmur_class = class_create(THIS_MODULE, "vmur"); -	if (IS_ERR(vmur_class)) { -		rc = PTR_ERR(vmur_class); -		goto fail_unregister_region; -	}  	pr_info("%s loaded.\n", ur_banner);  	return 0; -fail_unregister_region: -	unregister_chrdev_region(ur_first_dev_maj_min, NUM_MINORS);  fail_unregister_driver:  	ccw_driver_unregister(&ur_driver); +fail_class_destroy: +	class_destroy(vmur_class);  fail_free_dbf:  	debug_unregister(vmur_dbf);  	return rc; @@ -1057,9 +1058,9 @@ fail_free_dbf:  static void __exit ur_exit(void)  { -	class_destroy(vmur_class);  	unregister_chrdev_region(ur_first_dev_maj_min, NUM_MINORS);  	ccw_driver_unregister(&ur_driver); +	class_destroy(vmur_class);  	debug_unregister(vmur_dbf);  	pr_info("%s unloaded.\n", ur_banner);  } diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 1bbae433fbd..c431198bdbc 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -275,7 +275,7 @@ struct zcore_header {  	u32 num_pages;  	u32 pad1;  	u64 tod; -	cpuid_t cpu_id; +	struct cpuid cpu_id;  	u32 arch_id;  	u32 volnr;  	u32 build_arch;  |