diff options
99 files changed, 4059 insertions, 2917 deletions
| diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 1a29ff3df3c5..954b23cecfd1 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -830,6 +830,9 @@ and is between 256 and 4096 characters. It is defined in the file  	hvc_iucv=	[S390] Number of z/VM IUCV hypervisor console (HVC)  			       terminal devices. Valid values: 0..8 +	hvc_iucv_allow=	[S390] Comma-separated list of z/VM user IDs. +			       If specified, z/VM IUCV HVC accepts connections +			       from listed z/VM user IDs only.  	i8042.debug	[HW] Toggle i8042 debug mode  	i8042.direct	[HW] Put keyboard port into non-translated mode diff --git a/MAINTAINERS b/MAINTAINERS index bc919b645f37..4dacdfcdbe6e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3745,6 +3745,15 @@ L:	linux-s390@vger.kernel.org  W:	http://www.ibm.com/developerworks/linux/linux390/  S:	Supported +S390 ZCRYPT DRIVER +P:	Felix Beck +M:	felix.beck@de.ibm.com +P:	Ralph Wuerthner +M:	ralph.wuerthner@de.ibm.com +M:	linux390@de.ibm.com +L:	linux-s390@vger.kernel.org +S:	Supported +  S390 ZFCP DRIVER  P:	Christof Schmitt  M:	christof.schmitt@de.ibm.com diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 6b0a3538dc63..2a8af5e16345 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -343,13 +343,6 @@ source "mm/Kconfig"  comment "I/O subsystem configuration" -config MACHCHK_WARNING -	bool "Process warning machine checks" -	help -	  Select this option if you want the machine check handler on IBM S/390 or -	  zSeries to process warning machine checks (e.g. on power failures). -	  If unsure, say "Y". -  config QDIO  	tristate "QDIO support"  	---help--- @@ -521,7 +514,7 @@ config APPLDATA_OS  config APPLDATA_NET_SUM  	tristate "Monitor overall network statistics" -	depends on APPLDATA_BASE +	depends on APPLDATA_BASE && NET  	help  	  This provides network related data to the Linux - VM Monitor Stream,  	  currently there is only a total sum of network I/O statistics, no @@ -552,7 +545,7 @@ config KEXEC  	  but is independent of hardware/microcode support.  config ZFCPDUMP -	tristate "zfcpdump support" +	bool "zfcpdump support"  	select SMP  	default n  	help diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c index eca724d229ec..b49c00ce65e9 100644 --- a/arch/s390/crypto/prng.c +++ b/arch/s390/crypto/prng.c @@ -201,8 +201,7 @@ out_free:  static void __exit prng_exit(void)  {  	/* wipe me */ -	memset(p->buf, 0, prng_chunk_size); -	kfree(p->buf); +	kzfree(p->buf);  	kfree(p);  	misc_deregister(&prng_dev); diff --git a/arch/s390/include/asm/bitops.h b/arch/s390/include/asm/bitops.h index 8e9243ae0c19..b30606f6d523 100644 --- a/arch/s390/include/asm/bitops.h +++ b/arch/s390/include/asm/bitops.h @@ -57,7 +57,7 @@   * with operation of the form "set_bit(bitnr, flags)".   */ -/* bitmap tables from arch/S390/kernel/bitmap.S */ +/* bitmap tables from arch/s390/kernel/bitmap.c */  extern const char _oi_bitmap[];  extern const char _ni_bitmap[];  extern const char _zb_findmap[]; @@ -525,16 +525,16 @@ static inline unsigned long __ffs_word_loop(const unsigned long *addr,  static inline unsigned long __ffz_word(unsigned long nr, unsigned long word)  {  #ifdef __s390x__ -	if (likely((word & 0xffffffff) == 0xffffffff)) { +	if ((word & 0xffffffff) == 0xffffffff) {  		word >>= 32;  		nr += 32;  	}  #endif -	if (likely((word & 0xffff) == 0xffff)) { +	if ((word & 0xffff) == 0xffff) {  		word >>= 16;  		nr += 16;  	} -	if (likely((word & 0xff) == 0xff)) { +	if ((word & 0xff) == 0xff) {  		word >>= 8;  		nr += 8;  	} @@ -549,16 +549,16 @@ static inline unsigned long __ffz_word(unsigned long nr, unsigned long word)  static inline unsigned long __ffs_word(unsigned long nr, unsigned long word)  {  #ifdef __s390x__ -	if (likely((word & 0xffffffff) == 0)) { +	if ((word & 0xffffffff) == 0) {  		word >>= 32;  		nr += 32;  	}  #endif -	if (likely((word & 0xffff) == 0)) { +	if ((word & 0xffff) == 0) {  		word >>= 16;  		nr += 16;  	} -	if (likely((word & 0xff) == 0)) { +	if ((word & 0xff) == 0) {  		word >>= 8;  		nr += 8;  	} diff --git a/arch/s390/include/asm/crw.h b/arch/s390/include/asm/crw.h new file mode 100644 index 000000000000..2185a6d619d3 --- /dev/null +++ b/arch/s390/include/asm/crw.h @@ -0,0 +1,68 @@ +/* + *   Data definitions for channel report processing + *    Copyright IBM Corp. 2000,2009 + *    Author(s): Ingo Adlung <adlung@de.ibm.com>, + *		 Martin Schwidefsky <schwidefsky@de.ibm.com>, + *		 Cornelia Huck <cornelia.huck@de.ibm.com>, + *		 Heiko Carstens <heiko.carstens@de.ibm.com>, + */ + +#ifndef _ASM_S390_CRW_H +#define _ASM_S390_CRW_H + +#include <linux/types.h> + +/* + * Channel Report Word + */ +struct crw { +	__u32 res1 :  1;   /* reserved zero */ +	__u32 slct :  1;   /* solicited */ +	__u32 oflw :  1;   /* overflow */ +	__u32 chn  :  1;   /* chained */ +	__u32 rsc  :  4;   /* reporting source code */ +	__u32 anc  :  1;   /* ancillary report */ +	__u32 res2 :  1;   /* reserved zero */ +	__u32 erc  :  6;   /* error-recovery code */ +	__u32 rsid : 16;   /* reporting-source ID */ +} __attribute__ ((packed)); + +typedef void (*crw_handler_t)(struct crw *, struct crw *, int); + +extern int crw_register_handler(int rsc, crw_handler_t handler); +extern void crw_unregister_handler(int rsc); +extern void crw_handle_channel_report(void); + +#define NR_RSCS 16 + +#define CRW_RSC_MONITOR  0x2  /* monitoring facility */ +#define CRW_RSC_SCH	 0x3  /* subchannel */ +#define CRW_RSC_CPATH	 0x4  /* channel path */ +#define CRW_RSC_CONFIG	 0x9  /* configuration-alert facility */ +#define CRW_RSC_CSS	 0xB  /* channel subsystem */ + +#define CRW_ERC_EVENT	 0x00 /* event information pending */ +#define CRW_ERC_AVAIL	 0x01 /* available */ +#define CRW_ERC_INIT	 0x02 /* initialized */ +#define CRW_ERC_TERROR	 0x03 /* temporary error */ +#define CRW_ERC_IPARM	 0x04 /* installed parm initialized */ +#define CRW_ERC_TERM	 0x05 /* terminal */ +#define CRW_ERC_PERRN	 0x06 /* perm. error, fac. not init */ +#define CRW_ERC_PERRI	 0x07 /* perm. error, facility init */ +#define CRW_ERC_PMOD	 0x08 /* installed parameters modified */ + +static inline int stcrw(struct crw *pcrw) +{ +	int ccode; + +	asm volatile( +		"	stcrw	0(%2)\n" +		"	ipm	%0\n" +		"	srl	%0,28\n" +		: "=d" (ccode), "=m" (*pcrw) +		: "a" (pcrw) +		: "cc" ); +	return ccode; +} + +#endif /* _ASM_S390_CRW_H */ diff --git a/arch/s390/include/asm/dasd.h b/arch/s390/include/asm/dasd.h index e2db6f16d9c8..218bce81ec70 100644 --- a/arch/s390/include/asm/dasd.h +++ b/arch/s390/include/asm/dasd.h @@ -162,15 +162,15 @@ typedef struct dasd_profile_info_t {          unsigned int dasd_io_nr_req[32]; /* histogram of # of requests in chanq */  } dasd_profile_info_t; -/*  +/*   * struct format_data_t   * represents all data necessary to format a dasd   */  typedef struct format_data_t { -	int start_unit; /* from track */ -	int stop_unit;  /* to track */ -	int blksize;    /* sectorsize */ -        int intensity;   +	unsigned int start_unit; /* from track */ +	unsigned int stop_unit;  /* to track */ +	unsigned int blksize;	 /* sectorsize */ +	unsigned int intensity;  } format_data_t;  /* diff --git a/arch/s390/include/asm/idals.h b/arch/s390/include/asm/idals.h index e82c10efe65a..aae276d00383 100644 --- a/arch/s390/include/asm/idals.h +++ b/arch/s390/include/asm/idals.h @@ -44,24 +44,18 @@ idal_is_needed(void *vaddr, unsigned int length)  /*   * Return the number of idal words needed for an address/length pair.   */ -static inline unsigned int -idal_nr_words(void *vaddr, unsigned int length) +static inline unsigned int idal_nr_words(void *vaddr, unsigned int length)  { -#ifdef __s390x__ -	if (idal_is_needed(vaddr, length)) -		return ((__pa(vaddr) & (IDA_BLOCK_SIZE-1)) + length +  -			(IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG; -#endif -	return 0; +	return ((__pa(vaddr) & (IDA_BLOCK_SIZE-1)) + length + +		(IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;  }  /*   * Create the list of idal words for an address/length pair.   */ -static inline unsigned long * -idal_create_words(unsigned long *idaws, void *vaddr, unsigned int length) +static inline unsigned long *idal_create_words(unsigned long *idaws, +					       void *vaddr, unsigned int length)  { -#ifdef __s390x__  	unsigned long paddr;  	unsigned int cidaw; @@ -74,7 +68,6 @@ idal_create_words(unsigned long *idaws, void *vaddr, unsigned int length)  		paddr += IDA_BLOCK_SIZE;  		*idaws++ = paddr;  	} -#endif  	return idaws;  } diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index f3720defdd16..b349f1c7fdfa 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -11,129 +11,118 @@  #ifndef _ASM_S390_LOWCORE_H  #define _ASM_S390_LOWCORE_H -#ifndef __s390x__ -#define __LC_EXT_OLD_PSW                0x018 -#define __LC_SVC_OLD_PSW                0x020 -#define __LC_PGM_OLD_PSW                0x028 -#define __LC_MCK_OLD_PSW                0x030 -#define __LC_IO_OLD_PSW                 0x038 -#define __LC_EXT_NEW_PSW                0x058 -#define __LC_SVC_NEW_PSW                0x060 -#define __LC_PGM_NEW_PSW                0x068 -#define __LC_MCK_NEW_PSW                0x070 -#define __LC_IO_NEW_PSW                 0x078 -#else /* !__s390x__ */ -#define __LC_EXT_OLD_PSW                0x0130 -#define __LC_SVC_OLD_PSW                0x0140 -#define __LC_PGM_OLD_PSW                0x0150 -#define __LC_MCK_OLD_PSW                0x0160 -#define __LC_IO_OLD_PSW                 0x0170 -#define __LC_EXT_NEW_PSW                0x01b0 -#define __LC_SVC_NEW_PSW                0x01c0 -#define __LC_PGM_NEW_PSW                0x01d0 -#define __LC_MCK_NEW_PSW                0x01e0 -#define __LC_IO_NEW_PSW                 0x01f0 -#endif /* !__s390x__ */ - -#define __LC_IPL_PARMBLOCK_PTR		0x014 -#define __LC_EXT_PARAMS                 0x080 -#define __LC_CPU_ADDRESS                0x084 -#define __LC_EXT_INT_CODE               0x086 - -#define __LC_SVC_ILC                    0x088 -#define __LC_SVC_INT_CODE               0x08A -#define __LC_PGM_ILC                    0x08C -#define __LC_PGM_INT_CODE               0x08E +#define __LC_IPL_PARMBLOCK_PTR		0x0014 +#define __LC_EXT_PARAMS			0x0080 +#define __LC_CPU_ADDRESS		0x0084 +#define __LC_EXT_INT_CODE		0x0086 -#define __LC_PER_ATMID			0x096 -#define __LC_PER_ADDRESS		0x098 -#define __LC_PER_ACCESS_ID		0x0A1 -#define __LC_AR_MODE_ID			0x0A3 +#define __LC_SVC_ILC			0x0088 +#define __LC_SVC_INT_CODE		0x008a +#define __LC_PGM_ILC			0x008c +#define __LC_PGM_INT_CODE		0x008e -#define __LC_SUBCHANNEL_ID              0x0B8 -#define __LC_SUBCHANNEL_NR              0x0BA -#define __LC_IO_INT_PARM                0x0BC -#define __LC_IO_INT_WORD                0x0C0 -#define __LC_MCCK_CODE                  0x0E8 +#define __LC_PER_ATMID			0x0096 +#define __LC_PER_ADDRESS		0x0098 +#define __LC_PER_ACCESS_ID		0x00a1 +#define __LC_AR_MODE_ID			0x00a3 -#define __LC_LAST_BREAK 		0x110 - -#define __LC_RETURN_PSW                 0x200 - -#define __LC_SAVE_AREA                  0xC00 - -#ifndef __s390x__ -#define __LC_IRB			0x208 -#define __LC_SYNC_ENTER_TIMER		0x248 -#define __LC_ASYNC_ENTER_TIMER		0x250 -#define __LC_EXIT_TIMER			0x258 -#define __LC_USER_TIMER			0x260 -#define __LC_SYSTEM_TIMER		0x268 -#define __LC_STEAL_TIMER		0x270 -#define __LC_LAST_UPDATE_TIMER		0x278 -#define __LC_LAST_UPDATE_CLOCK		0x280 -#define __LC_RETURN_MCCK_PSW            0x288 -#define __LC_KERNEL_STACK               0xC40 -#define __LC_THREAD_INFO		0xC44 -#define __LC_ASYNC_STACK                0xC48 -#define __LC_KERNEL_ASCE		0xC4C -#define __LC_USER_ASCE			0xC50 -#define __LC_PANIC_STACK                0xC54 -#define __LC_CPUID                      0xC60 -#define __LC_CPUADDR                    0xC68 -#define __LC_IPLDEV                     0xC7C -#define __LC_CURRENT			0xC90 -#define __LC_INT_CLOCK			0xC98 -#else /* __s390x__ */ -#define __LC_IRB			0x210 -#define __LC_SYNC_ENTER_TIMER		0x250 -#define __LC_ASYNC_ENTER_TIMER		0x258 -#define __LC_EXIT_TIMER			0x260 -#define __LC_USER_TIMER			0x268 -#define __LC_SYSTEM_TIMER		0x270 -#define __LC_STEAL_TIMER		0x278 -#define __LC_LAST_UPDATE_TIMER		0x280 -#define __LC_LAST_UPDATE_CLOCK		0x288 -#define __LC_RETURN_MCCK_PSW            0x290 -#define __LC_KERNEL_STACK               0xD40 -#define __LC_THREAD_INFO		0xD48 -#define __LC_ASYNC_STACK                0xD50 -#define __LC_KERNEL_ASCE		0xD58 -#define __LC_USER_ASCE			0xD60 -#define __LC_PANIC_STACK                0xD68 -#define __LC_CPUID			0xD80 -#define __LC_CPUADDR			0xD88 -#define __LC_IPLDEV                     0xDB8 -#define __LC_CURRENT			0xDD8 -#define __LC_INT_CLOCK			0xDE8 -#define __LC_VDSO_PER_CPU		0xE38 -#endif /* __s390x__ */ +#define __LC_SUBCHANNEL_ID		0x00b8 +#define __LC_SUBCHANNEL_NR		0x00ba +#define __LC_IO_INT_PARM		0x00bc +#define __LC_IO_INT_WORD		0x00c0 +#define __LC_MCCK_CODE			0x00e8 -#define __LC_PASTE			0xE40 +#define __LC_DUMP_REIPL			0x0e00 -#define __LC_PANIC_MAGIC		0xE00  #ifndef __s390x__ -#define __LC_PFAULT_INTPARM             0x080 -#define __LC_CPU_TIMER_SAVE_AREA        0x0D8 -#define __LC_CLOCK_COMP_SAVE_AREA	0x0E0 -#define __LC_PSW_SAVE_AREA		0x100 -#define __LC_PREFIX_SAVE_AREA		0x108 -#define __LC_AREGS_SAVE_AREA            0x120 -#define __LC_FPREGS_SAVE_AREA		0x160 -#define __LC_GPREGS_SAVE_AREA           0x180 -#define __LC_CREGS_SAVE_AREA            0x1C0 +#define __LC_EXT_OLD_PSW		0x0018 +#define __LC_SVC_OLD_PSW		0x0020 +#define __LC_PGM_OLD_PSW		0x0028 +#define __LC_MCK_OLD_PSW		0x0030 +#define __LC_IO_OLD_PSW			0x0038 +#define __LC_EXT_NEW_PSW		0x0058 +#define __LC_SVC_NEW_PSW		0x0060 +#define __LC_PGM_NEW_PSW		0x0068 +#define __LC_MCK_NEW_PSW		0x0070 +#define __LC_IO_NEW_PSW			0x0078 +#define __LC_SAVE_AREA			0x0200 +#define __LC_RETURN_PSW			0x0240 +#define __LC_RETURN_MCCK_PSW		0x0248 +#define __LC_SYNC_ENTER_TIMER		0x0250 +#define __LC_ASYNC_ENTER_TIMER		0x0258 +#define __LC_EXIT_TIMER			0x0260 +#define __LC_USER_TIMER			0x0268 +#define __LC_SYSTEM_TIMER		0x0270 +#define __LC_STEAL_TIMER		0x0278 +#define __LC_LAST_UPDATE_TIMER		0x0280 +#define __LC_LAST_UPDATE_CLOCK		0x0288 +#define __LC_CURRENT			0x0290 +#define __LC_THREAD_INFO		0x0294 +#define __LC_KERNEL_STACK		0x0298 +#define __LC_ASYNC_STACK		0x029c +#define __LC_PANIC_STACK		0x02a0 +#define __LC_KERNEL_ASCE		0x02a4 +#define __LC_USER_ASCE			0x02a8 +#define __LC_USER_EXEC_ASCE		0x02ac +#define __LC_CPUID			0x02b0 +#define __LC_INT_CLOCK			0x02c8 +#define __LC_IRB			0x0300 +#define __LC_PFAULT_INTPARM		0x0080 +#define __LC_CPU_TIMER_SAVE_AREA	0x00d8 +#define __LC_CLOCK_COMP_SAVE_AREA	0x00e0 +#define __LC_PSW_SAVE_AREA		0x0100 +#define __LC_PREFIX_SAVE_AREA		0x0108 +#define __LC_AREGS_SAVE_AREA		0x0120 +#define __LC_FPREGS_SAVE_AREA		0x0160 +#define __LC_GPREGS_SAVE_AREA		0x0180 +#define __LC_CREGS_SAVE_AREA		0x01c0  #else /* __s390x__ */ -#define __LC_PFAULT_INTPARM             0x11B8 +#define __LC_LAST_BREAK			0x0110 +#define __LC_EXT_OLD_PSW		0x0130 +#define __LC_SVC_OLD_PSW		0x0140 +#define __LC_PGM_OLD_PSW		0x0150 +#define __LC_MCK_OLD_PSW		0x0160 +#define __LC_IO_OLD_PSW			0x0170 +#define __LC_EXT_NEW_PSW		0x01b0 +#define __LC_SVC_NEW_PSW		0x01c0 +#define __LC_PGM_NEW_PSW		0x01d0 +#define __LC_MCK_NEW_PSW		0x01e0 +#define __LC_IO_NEW_PSW			0x01f0 +#define __LC_SAVE_AREA			0x0200 +#define __LC_RETURN_PSW			0x0280 +#define __LC_RETURN_MCCK_PSW		0x0290 +#define __LC_SYNC_ENTER_TIMER		0x02a0 +#define __LC_ASYNC_ENTER_TIMER		0x02a8 +#define __LC_EXIT_TIMER			0x02b0 +#define __LC_USER_TIMER			0x02b8 +#define __LC_SYSTEM_TIMER		0x02c0 +#define __LC_STEAL_TIMER		0x02c8 +#define __LC_LAST_UPDATE_TIMER		0x02d0 +#define __LC_LAST_UPDATE_CLOCK		0x02d8 +#define __LC_CURRENT			0x02e0 +#define __LC_THREAD_INFO		0x02e8 +#define __LC_KERNEL_STACK		0x02f0 +#define __LC_ASYNC_STACK		0x02f8 +#define __LC_PANIC_STACK		0x0300 +#define __LC_KERNEL_ASCE		0x0308 +#define __LC_USER_ASCE			0x0310 +#define __LC_USER_EXEC_ASCE		0x0318 +#define __LC_CPUID			0x0320 +#define __LC_INT_CLOCK			0x0340 +#define __LC_VDSO_PER_CPU		0x0350 +#define __LC_IRB			0x0380 +#define __LC_PASTE			0x03c0 +#define __LC_PFAULT_INTPARM		0x11b8  #define __LC_FPREGS_SAVE_AREA		0x1200 -#define __LC_GPREGS_SAVE_AREA           0x1280 +#define __LC_GPREGS_SAVE_AREA		0x1280  #define __LC_PSW_SAVE_AREA		0x1300  #define __LC_PREFIX_SAVE_AREA		0x1318 -#define __LC_FP_CREG_SAVE_AREA		0x131C +#define __LC_FP_CREG_SAVE_AREA		0x131c  #define __LC_TODREG_SAVE_AREA		0x1324 -#define __LC_CPU_TIMER_SAVE_AREA        0x1328 +#define __LC_CPU_TIMER_SAVE_AREA	0x1328  #define __LC_CLOCK_COMP_SAVE_AREA	0x1331 -#define __LC_AREGS_SAVE_AREA            0x1340 -#define __LC_CREGS_SAVE_AREA            0x1380 +#define __LC_AREGS_SAVE_AREA		0x1340 +#define __LC_CREGS_SAVE_AREA		0x1380  #endif /* __s390x__ */  #ifndef __ASSEMBLY__ @@ -198,222 +187,240 @@ union save_area {  struct _lowcore  {  #ifndef __s390x__ -        /* prefix area: defined by architecture */ -	psw_t        restart_psw;              /* 0x000 */ -	__u32        ccw2[4];                  /* 0x008 */ -	psw_t        external_old_psw;         /* 0x018 */ -	psw_t        svc_old_psw;              /* 0x020 */ -	psw_t        program_old_psw;          /* 0x028 */ -	psw_t        mcck_old_psw;             /* 0x030 */ -	psw_t        io_old_psw;               /* 0x038 */ -	__u8         pad1[0x58-0x40];          /* 0x040 */ -	psw_t        external_new_psw;         /* 0x058 */ -	psw_t        svc_new_psw;              /* 0x060 */ -	psw_t        program_new_psw;          /* 0x068 */ -	psw_t        mcck_new_psw;             /* 0x070 */ -	psw_t        io_new_psw;               /* 0x078 */ -	__u32        ext_params;               /* 0x080 */ -	__u16        cpu_addr;                 /* 0x084 */ -	__u16        ext_int_code;             /* 0x086 */ -        __u16        svc_ilc;                  /* 0x088 */ -        __u16        svc_code;                 /* 0x08a */ -        __u16        pgm_ilc;                  /* 0x08c */ -        __u16        pgm_code;                 /* 0x08e */ -	__u32        trans_exc_code;           /* 0x090 */ -	__u16        mon_class_num;            /* 0x094 */ -	__u16        per_perc_atmid;           /* 0x096 */ -	__u32        per_address;              /* 0x098 */ -	__u32        monitor_code;             /* 0x09c */ -	__u8         exc_access_id;            /* 0x0a0 */ -	__u8         per_access_id;            /* 0x0a1 */ -	__u8         pad2[0xB8-0xA2];          /* 0x0a2 */ -	__u16        subchannel_id;            /* 0x0b8 */ -	__u16        subchannel_nr;            /* 0x0ba */ -	__u32        io_int_parm;              /* 0x0bc */ -	__u32        io_int_word;              /* 0x0c0 */ -	__u8	     pad3[0xc8-0xc4];	       /* 0x0c4 */ -	__u32	     stfl_fac_list;	       /* 0x0c8 */ -	__u8	     pad4[0xd4-0xcc];	       /* 0x0cc */ -	__u32        extended_save_area_addr;  /* 0x0d4 */ -	__u32        cpu_timer_save_area[2];   /* 0x0d8 */ -	__u32        clock_comp_save_area[2];  /* 0x0e0 */ -	__u32        mcck_interruption_code[2]; /* 0x0e8 */ -	__u8	     pad5[0xf4-0xf0];	       /* 0x0f0 */ -	__u32        external_damage_code;     /* 0x0f4 */ -	__u32        failing_storage_address;  /* 0x0f8 */ -	__u8	     pad6[0x100-0xfc];	       /* 0x0fc */ -	__u32        st_status_fixed_logout[4];/* 0x100 */ -	__u8	     pad7[0x120-0x110];        /* 0x110 */ -	__u32        access_regs_save_area[16];/* 0x120 */ -	__u32        floating_pt_save_area[8]; /* 0x160 */ -	__u32        gpregs_save_area[16];     /* 0x180 */ -	__u32        cregs_save_area[16];      /* 0x1c0 */	 - -        psw_t        return_psw;               /* 0x200 */ -	__u8	     irb[64];		       /* 0x208 */ -	__u64        sync_enter_timer;         /* 0x248 */ -	__u64        async_enter_timer;        /* 0x250 */ -	__u64        exit_timer;               /* 0x258 */ -	__u64	     user_timer;	       /* 0x260 */ -	__u64	     system_timer;	       /* 0x268 */ -	__u64	     steal_timer;	       /* 0x270 */ -	__u64	     last_update_timer;        /* 0x278 */ -	__u64	     last_update_clock;        /* 0x280 */ -        psw_t        return_mcck_psw;          /* 0x288 */ -	__u8         pad8[0xc00-0x290];        /* 0x290 */ - -        /* System info area */ -	__u32        save_area[16];            /* 0xc00 */ -	__u32        kernel_stack;             /* 0xc40 */ -	__u32        thread_info;              /* 0xc44 */ -	__u32        async_stack;              /* 0xc48 */ -	__u32        kernel_asce;              /* 0xc4c */ -	__u32        user_asce;                /* 0xc50 */ -	__u32        panic_stack;              /* 0xc54 */ -	__u32	     user_exec_asce;	       /* 0xc58 */ -	__u8	     pad10[0xc60-0xc5c];       /* 0xc5c */ -	/* entry.S sensitive area start */ -	struct       cpuinfo_S390 cpu_data;    /* 0xc60 */ -	__u32        ipl_device;               /* 0xc7c */ -	/* entry.S sensitive area end */ - -        /* SMP info area: defined by DJB */ -	__u64	     clock_comparator;	       /* 0xc80 */ -	__u32        ext_call_fast;            /* 0xc88 */ -	__u32        percpu_offset;            /* 0xc8c */ -	__u32        current_task;	       /* 0xc90 */ -	__u32        softirq_pending;	       /* 0xc94 */ -	__u64        int_clock;                /* 0xc98 */ -        __u8         pad11[0xe00-0xca0];       /* 0xca0 */ - -        /* 0xe00 is used as indicator for dump tools */ -        /* whether the kernel died with panic() or not */ -        __u32        panic_magic;              /* 0xe00 */ - -        /* Align to the top 1k of prefix area */ -	__u8         pad12[0x1000-0xe04];      /* 0xe04 */ +	/* 0x0000 - 0x01ff: defined by architecture */ +	psw_t	restart_psw;			/* 0x0000 */ +	__u32	ccw2[4];			/* 0x0008 */ +	psw_t	external_old_psw;		/* 0x0018 */ +	psw_t	svc_old_psw;			/* 0x0020 */ +	psw_t	program_old_psw;		/* 0x0028 */ +	psw_t	mcck_old_psw;			/* 0x0030 */ +	psw_t	io_old_psw;			/* 0x0038 */ +	__u8	pad_0x0040[0x0058-0x0040];	/* 0x0040 */ +	psw_t	external_new_psw;		/* 0x0058 */ +	psw_t	svc_new_psw;			/* 0x0060 */ +	psw_t	program_new_psw;		/* 0x0068 */ +	psw_t	mcck_new_psw;			/* 0x0070 */ +	psw_t	io_new_psw;			/* 0x0078 */ +	__u32	ext_params;			/* 0x0080 */ +	__u16	cpu_addr;			/* 0x0084 */ +	__u16	ext_int_code;			/* 0x0086 */ +	__u16	svc_ilc;			/* 0x0088 */ +	__u16	svc_code;			/* 0x008a */ +	__u16	pgm_ilc;			/* 0x008c */ +	__u16	pgm_code;			/* 0x008e */ +	__u32	trans_exc_code;			/* 0x0090 */ +	__u16	mon_class_num;			/* 0x0094 */ +	__u16	per_perc_atmid;			/* 0x0096 */ +	__u32	per_address;			/* 0x0098 */ +	__u32	monitor_code;			/* 0x009c */ +	__u8	exc_access_id;			/* 0x00a0 */ +	__u8	per_access_id;			/* 0x00a1 */ +	__u8	pad_0x00a2[0x00b8-0x00a2];	/* 0x00a2 */ +	__u16	subchannel_id;			/* 0x00b8 */ +	__u16	subchannel_nr;			/* 0x00ba */ +	__u32	io_int_parm;			/* 0x00bc */ +	__u32	io_int_word;			/* 0x00c0 */ +	__u8	pad_0x00c4[0x00c8-0x00c4];	/* 0x00c4 */ +	__u32	stfl_fac_list;			/* 0x00c8 */ +	__u8	pad_0x00cc[0x00d4-0x00cc];	/* 0x00cc */ +	__u32	extended_save_area_addr;	/* 0x00d4 */ +	__u32	cpu_timer_save_area[2];		/* 0x00d8 */ +	__u32	clock_comp_save_area[2];	/* 0x00e0 */ +	__u32	mcck_interruption_code[2];	/* 0x00e8 */ +	__u8	pad_0x00f0[0x00f4-0x00f0];	/* 0x00f0 */ +	__u32	external_damage_code;		/* 0x00f4 */ +	__u32	failing_storage_address;	/* 0x00f8 */ +	__u8	pad_0x00fc[0x0100-0x00fc];	/* 0x00fc */ +	__u32	st_status_fixed_logout[4];	/* 0x0100 */ +	__u8	pad_0x0110[0x0120-0x0110];	/* 0x0110 */ + +	/* CPU register save area: defined by architecture */ +	__u32	access_regs_save_area[16];	/* 0x0120 */ +	__u32	floating_pt_save_area[8];	/* 0x0160 */ +	__u32	gpregs_save_area[16];		/* 0x0180 */ +	__u32	cregs_save_area[16];		/* 0x01c0 */ + +	/* Return psws. */ +	__u32	save_area[16];			/* 0x0200 */ +	psw_t	return_psw;			/* 0x0240 */ +	psw_t	return_mcck_psw;		/* 0x0248 */ + +	/* CPU time accounting values */ +	__u64	sync_enter_timer;		/* 0x0250 */ +	__u64	async_enter_timer;		/* 0x0258 */ +	__u64	exit_timer;			/* 0x0260 */ +	__u64	user_timer;			/* 0x0268 */ +	__u64	system_timer;			/* 0x0270 */ +	__u64	steal_timer;			/* 0x0278 */ +	__u64	last_update_timer;		/* 0x0280 */ +	__u64	last_update_clock;		/* 0x0288 */ + +	/* Current process. */ +	__u32	current_task;			/* 0x0290 */ +	__u32	thread_info;			/* 0x0294 */ +	__u32	kernel_stack;			/* 0x0298 */ + +	/* Interrupt and panic stack. */ +	__u32	async_stack;			/* 0x029c */ +	__u32	panic_stack;			/* 0x02a0 */ + +	/* Address space pointer. */ +	__u32	kernel_asce;			/* 0x02a4 */ +	__u32	user_asce;			/* 0x02a8 */ +	__u32	user_exec_asce;			/* 0x02ac */ + +	/* SMP info area */ +	cpuid_t	cpu_id;				/* 0x02b0 */ +	__u32	cpu_nr;				/* 0x02b8 */ +	__u32	softirq_pending;		/* 0x02bc */ +	__u32	percpu_offset;			/* 0x02c0 */ +	__u32	ext_call_fast;			/* 0x02c4 */ +	__u64	int_clock;			/* 0x02c8 */ +	__u64	clock_comparator;		/* 0x02d0 */ +	__u8	pad_0x02d8[0x0300-0x02d8];	/* 0x02d8 */ + +	/* Interrupt response block */ +	__u8	irb[64];			/* 0x0300 */ + +	__u8	pad_0x0400[0x0e00-0x0400];	/* 0x0400 */ + +	/* +	 * 0xe00 contains the address of the IPL Parameter Information +	 * block. Dump tools need IPIB for IPL after dump. +	 * Note: do not change the position of any fields in 0x0e00-0x0f00 +	 */ +	__u32	ipib;				/* 0x0e00 */ +	__u32	ipib_checksum;			/* 0x0e04 */ + +	/* Align to the top 1k of prefix area */ +	__u8	pad_0x0e08[0x1000-0x0e08];	/* 0x0e08 */  #else /* !__s390x__ */ -        /* prefix area: defined by architecture */ -	__u32        ccw1[2];                  /* 0x000 */ -	__u32        ccw2[4];                  /* 0x008 */ -	__u8         pad1[0x80-0x18];          /* 0x018 */ -	__u32        ext_params;               /* 0x080 */ -	__u16        cpu_addr;                 /* 0x084 */ -	__u16        ext_int_code;             /* 0x086 */ -        __u16        svc_ilc;                  /* 0x088 */ -        __u16        svc_code;                 /* 0x08a */ -        __u16        pgm_ilc;                  /* 0x08c */ -        __u16        pgm_code;                 /* 0x08e */ -	__u32        data_exc_code;            /* 0x090 */ -	__u16        mon_class_num;            /* 0x094 */ -	__u16        per_perc_atmid;           /* 0x096 */ -	addr_t       per_address;              /* 0x098 */ -	__u8         exc_access_id;            /* 0x0a0 */ -	__u8         per_access_id;            /* 0x0a1 */ -	__u8         op_access_id;             /* 0x0a2 */ -	__u8         ar_access_id;             /* 0x0a3 */ -	__u8         pad2[0xA8-0xA4];          /* 0x0a4 */ -	addr_t       trans_exc_code;           /* 0x0A0 */ -	addr_t       monitor_code;             /* 0x09c */ -	__u16        subchannel_id;            /* 0x0b8 */ -	__u16        subchannel_nr;            /* 0x0ba */ -	__u32        io_int_parm;              /* 0x0bc */ -	__u32        io_int_word;              /* 0x0c0 */ -	__u8         pad3[0xc8-0xc4];          /* 0x0c4 */ -	__u32        stfl_fac_list;            /* 0x0c8 */ -	__u8         pad4[0xe8-0xcc];          /* 0x0cc */ -	__u32        mcck_interruption_code[2]; /* 0x0e8 */ -	__u8         pad5[0xf4-0xf0];          /* 0x0f0 */ -	__u32        external_damage_code;     /* 0x0f4 */ -	addr_t       failing_storage_address;  /* 0x0f8 */ -	__u8         pad6[0x120-0x100];        /* 0x100 */ -	psw_t        restart_old_psw;          /* 0x120 */ -	psw_t        external_old_psw;         /* 0x130 */ -	psw_t        svc_old_psw;              /* 0x140 */ -	psw_t        program_old_psw;          /* 0x150 */ -	psw_t        mcck_old_psw;             /* 0x160 */ -	psw_t        io_old_psw;               /* 0x170 */ -	__u8         pad7[0x1a0-0x180];        /* 0x180 */ -	psw_t        restart_psw;              /* 0x1a0 */ -	psw_t        external_new_psw;         /* 0x1b0 */ -	psw_t        svc_new_psw;              /* 0x1c0 */ -	psw_t        program_new_psw;          /* 0x1d0 */ -	psw_t        mcck_new_psw;             /* 0x1e0 */ -	psw_t        io_new_psw;               /* 0x1f0 */ -        psw_t        return_psw;               /* 0x200 */ -	__u8	     irb[64];		       /* 0x210 */ -	__u64        sync_enter_timer;         /* 0x250 */ -	__u64        async_enter_timer;        /* 0x258 */ -	__u64        exit_timer;               /* 0x260 */ -	__u64	     user_timer;	       /* 0x268 */ -	__u64	     system_timer;	       /* 0x270 */ -	__u64	     steal_timer;	       /* 0x278 */ -	__u64	     last_update_timer;        /* 0x280 */ -	__u64	     last_update_clock;        /* 0x288 */ -        psw_t        return_mcck_psw;          /* 0x290 */ -        __u8         pad8[0xc00-0x2a0];        /* 0x2a0 */ -        /* System info area */ -	__u64        save_area[16];            /* 0xc00 */ -        __u8         pad9[0xd40-0xc80];        /* 0xc80 */ - 	__u64        kernel_stack;             /* 0xd40 */ -	__u64        thread_info;              /* 0xd48 */ -	__u64        async_stack;              /* 0xd50 */ -	__u64        kernel_asce;              /* 0xd58 */ -	__u64        user_asce;                /* 0xd60 */ -	__u64        panic_stack;              /* 0xd68 */ -	__u64	     user_exec_asce;	       /* 0xd70 */ -	__u8	     pad10[0xd80-0xd78];       /* 0xd78 */ -	/* entry.S sensitive area start */ -	struct       cpuinfo_S390 cpu_data;    /* 0xd80 */ -	__u32        ipl_device;               /* 0xdb8 */ -	__u32        pad11;                    /* 0xdbc */ -	/* entry.S sensitive area end */ - -        /* SMP info area: defined by DJB */ -	__u64	     clock_comparator;	       /* 0xdc0 */ -	__u64        ext_call_fast;            /* 0xdc8 */ -	__u64        percpu_offset;            /* 0xdd0 */ -	__u64        current_task;	       /* 0xdd8 */ -	__u32	     softirq_pending;	       /* 0xde0 */ -	__u32	     pad_0x0de4;	       /* 0xde4 */ -	__u64        int_clock;                /* 0xde8 */ -        __u8         pad12[0xe00-0xdf0];       /* 0xdf0 */ - -        /* 0xe00 is used as indicator for dump tools */ -        /* whether the kernel died with panic() or not */ -        __u32        panic_magic;              /* 0xe00 */ +	/* 0x0000 - 0x01ff: defined by architecture */ +	__u32	ccw1[2];			/* 0x0000 */ +	__u32	ccw2[4];			/* 0x0008 */ +	__u8	pad_0x0018[0x0080-0x0018];	/* 0x0018 */ +	__u32	ext_params;			/* 0x0080 */ +	__u16	cpu_addr;			/* 0x0084 */ +	__u16	ext_int_code;			/* 0x0086 */ +	__u16	svc_ilc;			/* 0x0088 */ +	__u16	svc_code;			/* 0x008a */ +	__u16	pgm_ilc;			/* 0x008c */ +	__u16	pgm_code;			/* 0x008e */ +	__u32	data_exc_code;			/* 0x0090 */ +	__u16	mon_class_num;			/* 0x0094 */ +	__u16	per_perc_atmid;			/* 0x0096 */ +	addr_t	per_address;			/* 0x0098 */ +	__u8	exc_access_id;			/* 0x00a0 */ +	__u8	per_access_id;			/* 0x00a1 */ +	__u8	op_access_id;			/* 0x00a2 */ +	__u8	ar_access_id;			/* 0x00a3 */ +	__u8	pad_0x00a4[0x00a8-0x00a4];	/* 0x00a4 */ +	addr_t	trans_exc_code;			/* 0x00a8 */ +	addr_t	monitor_code;			/* 0x00b0 */ +	__u16	subchannel_id;			/* 0x00b8 */ +	__u16	subchannel_nr;			/* 0x00ba */ +	__u32	io_int_parm;			/* 0x00bc */ +	__u32	io_int_word;			/* 0x00c0 */ +	__u8	pad_0x00c4[0x00c8-0x00c4];	/* 0x00c4 */ +	__u32	stfl_fac_list;			/* 0x00c8 */ +	__u8	pad_0x00cc[0x00e8-0x00cc];	/* 0x00cc */ +	__u32	mcck_interruption_code[2];	/* 0x00e8 */ +	__u8	pad_0x00f0[0x00f4-0x00f0];	/* 0x00f0 */ +	__u32	external_damage_code;		/* 0x00f4 */ +	addr_t	failing_storage_address;	/* 0x00f8 */ +	__u8	pad_0x0100[0x0120-0x0100];	/* 0x0100 */ +	psw_t	restart_old_psw;		/* 0x0120 */ +	psw_t	external_old_psw;		/* 0x0130 */ +	psw_t	svc_old_psw;			/* 0x0140 */ +	psw_t	program_old_psw;		/* 0x0150 */ +	psw_t	mcck_old_psw;			/* 0x0160 */ +	psw_t	io_old_psw;			/* 0x0170 */ +	__u8	pad_0x0180[0x01a0-0x0180];	/* 0x0180 */ +	psw_t	restart_psw;			/* 0x01a0 */ +	psw_t	external_new_psw;		/* 0x01b0 */ +	psw_t	svc_new_psw;			/* 0x01c0 */ +	psw_t	program_new_psw;		/* 0x01d0 */ +	psw_t	mcck_new_psw;			/* 0x01e0 */ +	psw_t	io_new_psw;			/* 0x01f0 */ + +	/* Entry/exit save area & return psws. */ +	__u64	save_area[16];			/* 0x0200 */ +	psw_t	return_psw;			/* 0x0280 */ +	psw_t	return_mcck_psw;		/* 0x0290 */ + +	/* CPU accounting and timing values. */ +	__u64	sync_enter_timer;		/* 0x02a0 */ +	__u64	async_enter_timer;		/* 0x02a8 */ +	__u64	exit_timer;			/* 0x02b0 */ +	__u64	user_timer;			/* 0x02b8 */ +	__u64	system_timer;			/* 0x02c0 */ +	__u64	steal_timer;			/* 0x02c8 */ +	__u64	last_update_timer;		/* 0x02d0 */ +	__u64	last_update_clock;		/* 0x02d8 */ + +	/* Current process. */ +	__u64	current_task;			/* 0x02e0 */ +	__u64	thread_info;			/* 0x02e8 */ +	__u64	kernel_stack;			/* 0x02f0 */ + +	/* Interrupt and panic stack. */ +	__u64	async_stack;			/* 0x02f8 */ +	__u64	panic_stack;			/* 0x0300 */ + +	/* Address space pointer. */ +	__u64	kernel_asce;			/* 0x0308 */ +	__u64	user_asce;			/* 0x0310 */ +	__u64	user_exec_asce;			/* 0x0318 */ + +	/* SMP info area */ +	cpuid_t	cpu_id;				/* 0x0320 */ +	__u32	cpu_nr;				/* 0x0328 */ +	__u32	softirq_pending;		/* 0x032c */ +	__u64	percpu_offset;			/* 0x0330 */ +	__u64	ext_call_fast;			/* 0x0338 */ +	__u64	int_clock;			/* 0x0340 */ +	__u64	clock_comparator;		/* 0x0348 */ +	__u64	vdso_per_cpu_data;		/* 0x0350 */ +	__u8	pad_0x0358[0x0380-0x0358];	/* 0x0358 */ + +	/* Interrupt response block. */ +	__u8	irb[64];			/* 0x0380 */  	/* Per cpu primary space access list */ -	__u8	     pad_0xe04[0xe38-0xe04];   /* 0xe04 */ -	__u64	     vdso_per_cpu_data;	       /* 0xe38 */ -	__u32	     paste[16];		       /* 0xe40 */ - -	__u8	     pad13[0x11b8-0xe80];      /* 0xe80 */ - -	/* 64 bit extparam used for pfault, diag 250 etc  */ -	__u64        ext_params2;               /* 0x11B8 */ - -	__u8         pad14[0x1200-0x11C0];      /* 0x11C0 */ - -        /* System info area */  - -	__u64        floating_pt_save_area[16]; /* 0x1200 */ -	__u64        gpregs_save_area[16];      /* 0x1280 */ -	__u32        st_status_fixed_logout[4]; /* 0x1300 */ -	__u8         pad15[0x1318-0x1310];      /* 0x1310 */ -	__u32        prefixreg_save_area;       /* 0x1318 */ -	__u32        fpt_creg_save_area;        /* 0x131c */ -	__u8         pad16[0x1324-0x1320];      /* 0x1320 */ -	__u32        tod_progreg_save_area;     /* 0x1324 */ -	__u32        cpu_timer_save_area[2];    /* 0x1328 */ -	__u32        clock_comp_save_area[2];   /* 0x1330 */ -	__u8         pad17[0x1340-0x1338];      /* 0x1338 */ -	__u32        access_regs_save_area[16]; /* 0x1340 */  -	__u64        cregs_save_area[16];       /* 0x1380 */ +	__u32	paste[16];			/* 0x03c0 */ + +	__u8	pad_0x0400[0x0e00-0x0400];	/* 0x0400 */ + +	/* +	 * 0xe00 contains the address of the IPL Parameter Information +	 * block. Dump tools need IPIB for IPL after dump. +	 * Note: do not change the position of any fields in 0x0e00-0x0f00 +	 */ +	__u64	ipib;				/* 0x0e00 */ +	__u32	ipib_checksum;			/* 0x0e08 */ +	__u8	pad_0x0e0c[0x11b8-0x0e0c];	/* 0x0e0c */ + +	/* 64 bit extparam used for pfault/diag 250: defined by architecture */ +	__u64	ext_params2;			/* 0x11B8 */ +	__u8	pad_0x11c0[0x1200-0x11C0];	/* 0x11C0 */ + +	/* CPU register save area: defined by architecture */ +	__u64	floating_pt_save_area[16];	/* 0x1200 */ +	__u64	gpregs_save_area[16];		/* 0x1280 */ +	__u32	st_status_fixed_logout[4];	/* 0x1300 */ +	__u8	pad_0x1310[0x1318-0x1310];	/* 0x1310 */ +	__u32	prefixreg_save_area;		/* 0x1318 */ +	__u32	fpt_creg_save_area;		/* 0x131c */ +	__u8	pad_0x1320[0x1324-0x1320];	/* 0x1320 */ +	__u32	tod_progreg_save_area;		/* 0x1324 */ +	__u32	cpu_timer_save_area[2];		/* 0x1328 */ +	__u32	clock_comp_save_area[2];	/* 0x1330 */ +	__u8	pad_0x1338[0x1340-0x1338];	/* 0x1338 */ +	__u32	access_regs_save_area[16];	/* 0x1340 */ +	__u64	cregs_save_area[16];		/* 0x1380 */  	/* align to the top of the prefix area */ - -	__u8         pad18[0x2000-0x1400];      /* 0x1400 */ +	__u8	pad_0x1400[0x2000-0x1400];	/* 0x1400 */  #endif /* !__s390x__ */  } __attribute__((packed)); /* End structure*/ @@ -433,8 +440,6 @@ static inline __u32 store_prefix(void)  	return address;  } -#define __PANIC_MAGIC           0xDEADC0DE -  #endif  #endif diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index 28ec870655af..fc7edd6f41b6 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h @@ -74,7 +74,7 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)  static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,  			     struct task_struct *tsk)  { -	cpu_set(smp_processor_id(), next->cpu_vm_mask); +	cpumask_set_cpu(smp_processor_id(), mm_cpumask(next));  	update_mm(next, tsk);  } diff --git a/arch/s390/include/asm/nmi.h b/arch/s390/include/asm/nmi.h new file mode 100644 index 000000000000..f4b60441adca --- /dev/null +++ b/arch/s390/include/asm/nmi.h @@ -0,0 +1,66 @@ +/* + *   Machine check handler definitions + * + *    Copyright IBM Corp. 2000,2009 + *    Author(s): Ingo Adlung <adlung@de.ibm.com>, + *		 Martin Schwidefsky <schwidefsky@de.ibm.com>, + *		 Cornelia Huck <cornelia.huck@de.ibm.com>, + *		 Heiko Carstens <heiko.carstens@de.ibm.com>, + */ + +#ifndef _ASM_S390_NMI_H +#define _ASM_S390_NMI_H + +#include <linux/types.h> + +struct mci { +	__u32 sd :  1; /* 00 system damage */ +	__u32 pd :  1; /* 01 instruction-processing damage */ +	__u32 sr :  1; /* 02 system recovery */ +	__u32	 :  1; /* 03 */ +	__u32 cd :  1; /* 04 timing-facility damage */ +	__u32 ed :  1; /* 05 external damage */ +	__u32	 :  1; /* 06 */ +	__u32 dg :  1; /* 07 degradation */ +	__u32 w  :  1; /* 08 warning pending */ +	__u32 cp :  1; /* 09 channel-report pending */ +	__u32 sp :  1; /* 10 service-processor damage */ +	__u32 ck :  1; /* 11 channel-subsystem damage */ +	__u32	 :  2; /* 12-13 */ +	__u32 b  :  1; /* 14 backed up */ +	__u32	 :  1; /* 15 */ +	__u32 se :  1; /* 16 storage error uncorrected */ +	__u32 sc :  1; /* 17 storage error corrected */ +	__u32 ke :  1; /* 18 storage-key error uncorrected */ +	__u32 ds :  1; /* 19 storage degradation */ +	__u32 wp :  1; /* 20 psw mwp validity */ +	__u32 ms :  1; /* 21 psw mask and key validity */ +	__u32 pm :  1; /* 22 psw program mask and cc validity */ +	__u32 ia :  1; /* 23 psw instruction address validity */ +	__u32 fa :  1; /* 24 failing storage address validity */ +	__u32	 :  1; /* 25 */ +	__u32 ec :  1; /* 26 external damage code validity */ +	__u32 fp :  1; /* 27 floating point register validity */ +	__u32 gr :  1; /* 28 general register validity */ +	__u32 cr :  1; /* 29 control register validity */ +	__u32	 :  1; /* 30 */ +	__u32 st :  1; /* 31 storage logical validity */ +	__u32 ie :  1; /* 32 indirect storage error */ +	__u32 ar :  1; /* 33 access register validity */ +	__u32 da :  1; /* 34 delayed access exception */ +	__u32	 :  7; /* 35-41 */ +	__u32 pr :  1; /* 42 tod programmable register validity */ +	__u32 fc :  1; /* 43 fp control register validity */ +	__u32 ap :  1; /* 44 ancillary report */ +	__u32	 :  1; /* 45 */ +	__u32 ct :  1; /* 46 cpu timer validity */ +	__u32 cc :  1; /* 47 clock comparator validity */ +	__u32	 : 16; /* 47-63 */ +}; + +struct pt_regs; + +extern void s390_handle_mcck(void); +extern void s390_do_machine_check(struct pt_regs *regs); + +#endif /* _ASM_S390_NMI_H */ diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index db4523fe38ac..61862b3ac794 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -42,22 +42,8 @@ static inline void get_cpu_id(cpuid_t *ptr)  	asm volatile("stidp 0(%1)" : "=m" (*ptr) : "a" (ptr));  } -struct cpuinfo_S390 -{ -        cpuid_t  cpu_id; -        __u16    cpu_addr; -        __u16    cpu_nr; -        unsigned long loops_per_jiffy; -        unsigned long *pgd_quick; -#ifdef __s390x__ -        unsigned long *pmd_quick; -#endif /* __s390x__ */ -        unsigned long *pte_quick; -        unsigned long pgtable_cache_sz; -}; -  extern void s390_adjust_jiffies(void); -extern void print_cpu_info(struct cpuinfo_S390 *); +extern void print_cpu_info(void);  extern int get_cpu_capability(unsigned int *);  /* diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index 8920025c3c02..f1b051630c50 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h @@ -172,6 +172,8 @@  #define NUM_CRS		16  #define NUM_ACRS	16 +#define NUM_CR_WORDS	3 +  #define FPR_SIZE	8  #define FPC_SIZE	4  #define FPC_PAD_SIZE	4 /* gcc insists on aligning the fpregs */ @@ -334,7 +336,7 @@ struct pt_regs   */  typedef struct  { -	unsigned long cr[3]; +	unsigned long cr[NUM_CR_WORDS];  } per_cr_words;  #define PER_EM_MASK 0xE8000000UL diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index 27fc1746de15..402d6dcf0d26 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h @@ -314,6 +314,7 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int,  			    int, int, unsigned long);  /* qdio errors reported to the upper-layer program */ +#define QDIO_ERROR_SIGA_TARGET			0x02  #define QDIO_ERROR_SIGA_ACCESS_EXCEPTION	0x10  #define QDIO_ERROR_SIGA_BUSY			0x20  #define QDIO_ERROR_ACTIVATE_CHECK_CONDITION	0x40 diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h index 024b91e06239..2009158a4502 100644 --- a/arch/s390/include/asm/smp.h +++ b/arch/s390/include/asm/smp.h @@ -50,12 +50,7 @@ extern void machine_power_off_smp(void);  #define PROC_CHANGE_PENALTY	20		/* Schedule penalty */ -#define raw_smp_processor_id()	(S390_lowcore.cpu_data.cpu_nr) - -static inline __u16 hard_smp_processor_id(void) -{ -	return stap(); -} +#define raw_smp_processor_id()	(S390_lowcore.cpu_nr)  /*   * returns 1 if cpu is in stopped/check stopped state or not operational diff --git a/arch/s390/include/asm/string.h b/arch/s390/include/asm/string.h index d074673a6d9b..cd0241db5a46 100644 --- a/arch/s390/include/asm/string.h +++ b/arch/s390/include/asm/string.h @@ -100,6 +100,7 @@ static inline char *strcat(char *dst, const char *src)  static inline char *strcpy(char *dst, const char *src)  { +#if __GNUC__ < 4  	register int r0 asm("0") = 0;  	char *ret = dst; @@ -109,10 +110,14 @@ static inline char *strcpy(char *dst, const char *src)  		: "+&a" (dst), "+&a" (src) : "d" (r0)  		: "cc", "memory");  	return ret; +#else +	return __builtin_strcpy(dst, src); +#endif  }  static inline size_t strlen(const char *s)  { +#if __GNUC__ < 4  	register unsigned long r0 asm("0") = 0;  	const char *tmp = s; @@ -121,6 +126,9 @@ static inline size_t strlen(const char *s)  		"	jo	0b"  		: "+d" (r0), "+a" (tmp) :  : "cc");  	return r0 - (unsigned long) s; +#else +	return __builtin_strlen(s); +#endif  }  static inline size_t strnlen(const char * s, size_t n) @@ -135,7 +143,13 @@ static inline size_t strnlen(const char * s, size_t n)  		: "+a" (end), "+a" (tmp) : "d" (r0)  : "cc");  	return end - s;  } - +#else /* IN_ARCH_STRING_C */ +void *memchr(const void * s, int c, size_t n); +void *memscan(void *s, int c, size_t n); +char *strcat(char *dst, const char *src); +char *strcpy(char *dst, const char *src); +size_t strlen(const char *s); +size_t strnlen(const char * s, size_t n);  #endif /* !IN_ARCH_STRING_C */  #endif /* __KERNEL__ */ diff --git a/arch/s390/include/asm/sysinfo.h b/arch/s390/include/asm/sysinfo.h index ad93212d9e16..9d70057d828c 100644 --- a/arch/s390/include/asm/sysinfo.h +++ b/arch/s390/include/asm/sysinfo.h @@ -100,6 +100,7 @@ struct sysinfo_3_2_2 {  		char reserved_1[24];  	} vm[8]; +	char reserved_544[3552];  };  static inline int stsi(void *sysinfo, int fc, int sel1, int sel2) diff --git a/arch/s390/include/asm/tlbflush.h b/arch/s390/include/asm/tlbflush.h index d60394b9745e..304cffa623e1 100644 --- a/arch/s390/include/asm/tlbflush.h +++ b/arch/s390/include/asm/tlbflush.h @@ -51,7 +51,7 @@ static inline void __tlb_flush_full(struct mm_struct *mm)  	 * If the process only ran on the local cpu, do a local flush.  	 */  	local_cpumask = cpumask_of_cpu(smp_processor_id()); -	if (cpus_equal(mm->cpu_vm_mask, local_cpumask)) +	if (cpumask_equal(mm_cpumask(mm), &local_cpumask))  		__tlb_flush_local();  	else  		__tlb_flush_global(); @@ -73,7 +73,7 @@ static inline void __tlb_flush_idte(unsigned long asce)  static inline void __tlb_flush_mm(struct mm_struct * mm)  { -	if (unlikely(cpus_empty(mm->cpu_vm_mask))) +	if (unlikely(cpumask_empty(mm_cpumask(mm))))  		return;  	/*  	 * If the machine has IDTE we prefer to do a per mm flush diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h index c979c3b56ab0..5e0ad618dc45 100644 --- a/arch/s390/include/asm/topology.h +++ b/arch/s390/include/asm/topology.h @@ -5,7 +5,6 @@  #define mc_capable()	(1) -cpumask_t cpu_coregroup_map(unsigned int cpu);  const struct cpumask *cpu_coregroup_mask(unsigned int cpu);  extern cpumask_t cpu_core_map[NR_CPUS]; diff --git a/arch/s390/include/asm/vtoc.h b/arch/s390/include/asm/vtoc.h index 3a5267d90d29..8406a2b3157a 100644 --- a/arch/s390/include/asm/vtoc.h +++ b/arch/s390/include/asm/vtoc.h @@ -39,7 +39,7 @@ struct vtoc_labeldate  	__u16 day;  } __attribute__ ((packed)); -struct vtoc_volume_label +struct vtoc_volume_label_cdl  {  	char volkey[4];		/* volume key = volume label */  	char vollbl[4];		/* volume label */ @@ -56,6 +56,14 @@ struct vtoc_volume_label  	char res3[29];		/* reserved */  } __attribute__ ((packed)); +struct vtoc_volume_label_ldl { +	char vollbl[4];		/* volume label */ +	char volid[6];		/* volume identifier */ +	char res3[69];		/* reserved */ +	char ldl_version;	/* version number, valid for ldl format */ +	__u64 formatted_blocks; /* valid when ldl_version >= f2  */ +} __attribute__ ((packed)); +  struct vtoc_extent  {  	__u8 typeind;			/* extent type indicator */ @@ -140,7 +148,11 @@ struct vtoc_format4_label  	char res2[10];		/* reserved */  	__u8 DS4EFLVL;		/* extended free-space management level */  	struct vtoc_cchhb DS4EFPTR; /* pointer to extended free-space info */ -	char res3[9];		/* reserved */ +	char res3;		/* reserved */ +	__u32 DS4DCYL;		/* number of logical cyls */ +	char res4[2];		/* reserved */ +	__u8 DS4DEVF2;		/* device flags */ +	char res5;		/* reserved */  } __attribute__ ((packed));  struct vtoc_ds5ext diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 3edc6c6f258b..228e3105ded7 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -17,10 +17,12 @@ CFLAGS_smp.o	:= -Wno-nonnull  #  CFLAGS_ptrace.o		+= -DUTS_MACHINE='"$(UTS_MACHINE)"' +CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w +  obj-y	:=  bitmap.o traps.o time.o process.o base.o early.o setup.o \  	    processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \  	    s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o \ -	    vdso.o vtime.o +	    vdso.o vtime.o sysinfo.o nmi.o  obj-y	+= $(if $(CONFIG_64BIT),entry64.o,entry.o)  obj-y	+= $(if $(CONFIG_64BIT),reipl64.o,reipl.o) diff --git a/arch/s390/kernel/bitmap.S b/arch/s390/kernel/bitmap.S deleted file mode 100644 index dfb41f946e23..000000000000 --- a/arch/s390/kernel/bitmap.S +++ /dev/null @@ -1,56 +0,0 @@ -/* - *  arch/s390/kernel/bitmap.S - *    Bitmaps for set_bit, clear_bit, test_and_set_bit, ... - *    See include/asm-s390/{bitops.h|posix_types.h} for details - * - *  S390 version - *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), - */ - -         .globl _oi_bitmap -_oi_bitmap: -         .byte  0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 - -         .globl _ni_bitmap -_ni_bitmap: -         .byte  0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F - -         .globl _zb_findmap -_zb_findmap: -         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 -         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5 -         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4  -         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6 -         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 -         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5 -         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 -         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7 -         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 -         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5 -         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 -         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6 -         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 -         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5 -         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 -         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8 - -         .globl _sb_findmap -_sb_findmap: -         .byte  8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 -         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 -         .byte  5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 -         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 -         .byte  6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 -         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 -         .byte  5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 -         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 -         .byte  7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 -         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 -         .byte  5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 -         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 -         .byte  6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 -         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 -         .byte  5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 -         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 - diff --git a/arch/s390/kernel/bitmap.c b/arch/s390/kernel/bitmap.c new file mode 100644 index 000000000000..3ae4757b006a --- /dev/null +++ b/arch/s390/kernel/bitmap.c @@ -0,0 +1,54 @@ +/* + *    Bitmaps for set_bit, clear_bit, test_and_set_bit, ... + *    See include/asm/{bitops.h|posix_types.h} for details + * + *    Copyright IBM Corp. 1999,2009 + *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>, + */ + +#include <linux/bitops.h> +#include <linux/module.h> + +const char _oi_bitmap[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; +EXPORT_SYMBOL(_oi_bitmap); + +const char _ni_bitmap[] = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f }; +EXPORT_SYMBOL(_ni_bitmap); + +const char _zb_findmap[] = { +	0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, +	0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, +	0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, +	0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6, +	0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, +	0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, +	0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, +	0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7, +	0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, +	0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, +	0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, +	0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6, +	0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, +	0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, +	0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, +	0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8 }; +EXPORT_SYMBOL(_zb_findmap); + +const char _sb_findmap[] = { +	8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, +	4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, +	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, +	4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, +	6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, +	4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, +	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, +	4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, +	7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, +	4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, +	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, +	4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, +	6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, +	4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, +	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, +	4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 }; +EXPORT_SYMBOL(_sb_findmap); diff --git a/arch/s390/kernel/compat_ptrace.h b/arch/s390/kernel/compat_ptrace.h index a2be3a978d5c..123dd660d7fb 100644 --- a/arch/s390/kernel/compat_ptrace.h +++ b/arch/s390/kernel/compat_ptrace.h @@ -1,10 +1,11 @@  #ifndef _PTRACE32_H  #define _PTRACE32_H +#include <asm/ptrace.h>    /* needed for NUM_CR_WORDS */  #include "compat_linux.h"  /* needed for psw_compat_t */  typedef struct { -	__u32 cr[3]; +	__u32 cr[NUM_CR_WORDS];  } per_cr_words32;  typedef struct { diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index ba03fc0a3a56..be8bceaf37d9 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -603,7 +603,7 @@ debug_input(struct file *file, const char __user *user_buf, size_t length,  static int  debug_open(struct inode *inode, struct file *file)  { -	int i = 0, rc = 0; +	int i, rc = 0;  	file_private_info_t *p_info;  	debug_info_t *debug_info, *debug_info_snapshot; @@ -642,8 +642,7 @@ found:  	p_info = kmalloc(sizeof(file_private_info_t),  						GFP_KERNEL);  	if(!p_info){ -		if(debug_info_snapshot) -			debug_info_free(debug_info_snapshot); +		debug_info_free(debug_info_snapshot);  		rc = -ENOMEM;  		goto out;  	} @@ -698,8 +697,7 @@ debug_info_t *debug_register_mode(const char *name, int pages_per_area,  	if ((uid != 0) || (gid != 0))  		pr_warning("Root becomes the owner of all s390dbf files "  			   "in sysfs\n"); -	if (!initialized) -		BUG(); +	BUG_ON(!initialized);  	mutex_lock(&debug_mutex);          /* create new debug_info */ @@ -1156,7 +1154,6 @@ debug_unregister_view(debug_info_t * id, struct debug_view *view)  	else {  		debugfs_remove(id->debugfs_entries[i]);  		id->views[i] = NULL; -		rc = 0;  	}  	spin_unlock_irqrestore(&id->lock, flags);  out: diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 2a2ca268b1dd..4d221c81c849 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -6,6 +6,7 @@   *		 Heiko Carstens <heiko.carstens@de.ibm.com>   */ +#include <linux/compiler.h>  #include <linux/init.h>  #include <linux/errno.h>  #include <linux/string.h> @@ -20,6 +21,7 @@  #include <asm/processor.h>  #include <asm/sections.h>  #include <asm/setup.h> +#include <asm/sysinfo.h>  #include <asm/cpcmd.h>  #include <asm/sclp.h>  #include "entry.h" @@ -173,19 +175,21 @@ static noinline __init void init_kernel_storage_key(void)  		page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);  } +static __initdata struct sysinfo_3_2_2 vmms __aligned(PAGE_SIZE); +  static noinline __init void detect_machine_type(void)  { -	struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data; - -	get_cpu_id(&S390_lowcore.cpu_data.cpu_id); - -	/* Running under z/VM ? */ -	if (cpuinfo->cpu_id.version == 0xff) -		machine_flags |= MACHINE_FLAG_VM; +	/* No VM information? Looks like LPAR */ +	if (stsi(&vmms, 3, 2, 2) == -ENOSYS) +		return; +	if (!vmms.count) +		return; -	/* Running under KVM ? */ -	if (cpuinfo->cpu_id.version == 0xfe) +	/* Running under KVM? If not we assume z/VM */ +	if (!memcmp(vmms.vm[0].cpi, "\xd2\xe5\xd4", 3))  		machine_flags |= MACHINE_FLAG_KVM; +	else +		machine_flags |= MACHINE_FLAG_VM;  }  static __init void early_pgm_check_handler(void) @@ -348,7 +352,6 @@ static void __init setup_boot_command_line(void)  	/* copy arch command line */  	strlcpy(boot_command_line, COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); -	boot_command_line[ARCH_COMMAND_LINE_SIZE - 1] = 0;  	/* append IPL PARM data to the boot command line */  	if (MACHINE_IS_VM) { diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index ec7e35f6055b..1046c2c9f8d1 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -469,6 +469,8 @@ start:  	.org	0x10000  startup:basr	%r13,0			# get base  .LPG0: +	xc	0x200(256),0x200	# partially clear lowcore +	xc	0x300(256),0x300  #ifndef CONFIG_MARCH_G5  	# check processor version against MARCH_{G5,Z900,Z990,Z9_109,Z10} diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S index db476d114caa..2ced846065b7 100644 --- a/arch/s390/kernel/head31.S +++ b/arch/s390/kernel/head31.S @@ -20,7 +20,6 @@ startup_continue:  	lctl	%c0,%c15,.Lctl-.LPG1(%r13) # load control registers  	l	%r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area  					# move IPL device to lowcore -	mvc	__LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12)  #  # Setup stack  # diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index f9f70aa15244..65667b2e65ce 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -86,7 +86,6 @@ startup_continue:  	lctlg	%c0,%c15,.Lctl-.LPG1(%r13)	# load control registers  	lg	%r12,.Lparmaddr-.LPG1(%r13)	# pointer to parameter area  					# move IPL device to lowcore -	mvc	__LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12)  	lghi	%r0,__LC_PASTE  	stg	%r0,__LC_VDSO_PER_CPU  # diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 2dcf590faba6..6f3711a0eaaa 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -23,7 +23,7 @@  #include <asm/ebcdic.h>  #include <asm/reset.h>  #include <asm/sclp.h> -#include <asm/setup.h> +#include <asm/checksum.h>  #define IPL_PARM_BLOCK_VERSION 0 @@ -56,13 +56,14 @@ struct shutdown_trigger {  };  /* - * Five shutdown action types are supported: + * The following shutdown action types are supported:   */  #define SHUTDOWN_ACTION_IPL_STR		"ipl"  #define SHUTDOWN_ACTION_REIPL_STR	"reipl"  #define SHUTDOWN_ACTION_DUMP_STR	"dump"  #define SHUTDOWN_ACTION_VMCMD_STR	"vmcmd"  #define SHUTDOWN_ACTION_STOP_STR	"stop" +#define SHUTDOWN_ACTION_DUMP_REIPL_STR	"dump_reipl"  struct shutdown_action {  	char *name; @@ -146,6 +147,7 @@ static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT;  static struct ipl_parameter_block *reipl_block_fcp;  static struct ipl_parameter_block *reipl_block_ccw;  static struct ipl_parameter_block *reipl_block_nss; +static struct ipl_parameter_block *reipl_block_actual;  static int dump_capabilities = DUMP_TYPE_NONE;  static enum dump_type dump_type = DUMP_TYPE_NONE; @@ -835,6 +837,7 @@ static int reipl_set_type(enum ipl_type type)  			reipl_method = REIPL_METHOD_CCW_VM;  		else  			reipl_method = REIPL_METHOD_CCW_CIO; +		reipl_block_actual = reipl_block_ccw;  		break;  	case IPL_TYPE_FCP:  		if (diag308_set_works) @@ -843,6 +846,7 @@ static int reipl_set_type(enum ipl_type type)  			reipl_method = REIPL_METHOD_FCP_RO_VM;  		else  			reipl_method = REIPL_METHOD_FCP_RO_DIAG; +		reipl_block_actual = reipl_block_fcp;  		break;  	case IPL_TYPE_FCP_DUMP:  		reipl_method = REIPL_METHOD_FCP_DUMP; @@ -852,6 +856,7 @@ static int reipl_set_type(enum ipl_type type)  			reipl_method = REIPL_METHOD_NSS_DIAG;  		else  			reipl_method = REIPL_METHOD_NSS; +		reipl_block_actual = reipl_block_nss;  		break;  	case IPL_TYPE_UNKNOWN:  		reipl_method = REIPL_METHOD_DEFAULT; @@ -960,7 +965,6 @@ static void reipl_run(struct shutdown_trigger *trigger)  		diag308(DIAG308_IPL, NULL);  		break;  	case REIPL_METHOD_FCP_DUMP: -	default:  		break;  	}  	disabled_wait((unsigned long) __builtin_return_address(0)); @@ -1069,10 +1073,12 @@ static int __init reipl_fcp_init(void)  {  	int rc; -	if ((!diag308_set_works) && (ipl_info.type != IPL_TYPE_FCP)) -		return 0; -	if ((!diag308_set_works) && (ipl_info.type == IPL_TYPE_FCP)) -		make_attrs_ro(reipl_fcp_attrs); +	if (!diag308_set_works) { +		if (ipl_info.type == IPL_TYPE_FCP) +			make_attrs_ro(reipl_fcp_attrs); +		else +			return 0; +	}  	reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);  	if (!reipl_block_fcp) @@ -1253,7 +1259,6 @@ static void dump_run(struct shutdown_trigger *trigger)  		diag308(DIAG308_DUMP, NULL);  		break;  	case DUMP_METHOD_NONE: -	default:  		return;  	}  	printk(KERN_EMERG "Dump failed!\n"); @@ -1332,6 +1337,49 @@ static struct shutdown_action __refdata dump_action = {  	.init	= dump_init,  }; +static void dump_reipl_run(struct shutdown_trigger *trigger) +{ +	preempt_disable(); +	/* +	 * Bypass dynamic address translation (DAT) when storing IPL parameter +	 * information block address and checksum into the prefix area +	 * (corresponding to absolute addresses 0-8191). +	 * When enhanced DAT applies and the STE format control in one, +	 * the absolute address is formed without prefixing. In this case a +	 * normal store (stg/st) into the prefix area would no more match to +	 * absolute addresses 0-8191. +	 */ +#ifdef CONFIG_64BIT +	asm volatile("sturg %0,%1" +		:: "a" ((unsigned long) reipl_block_actual), +		"a" (&lowcore_ptr[smp_processor_id()]->ipib)); +#else +	asm volatile("stura %0,%1" +		:: "a" ((unsigned long) reipl_block_actual), +		"a" (&lowcore_ptr[smp_processor_id()]->ipib)); +#endif +	asm volatile("stura %0,%1" +		:: "a" (csum_partial(reipl_block_actual, +				     reipl_block_actual->hdr.len, 0)), +		"a" (&lowcore_ptr[smp_processor_id()]->ipib_checksum)); +	preempt_enable(); +	dump_run(trigger); +} + +static int __init dump_reipl_init(void) +{ +	if (!diag308_set_works) +		return -EOPNOTSUPP; +	else +		return 0; +} + +static struct shutdown_action __refdata dump_reipl_action = { +	.name	= SHUTDOWN_ACTION_DUMP_REIPL_STR, +	.fn	= dump_reipl_run, +	.init	= dump_reipl_init, +}; +  /*   * vmcmd shutdown action: Trigger vm command on shutdown.   */ @@ -1421,7 +1469,8 @@ static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR,  /* action list */  static struct shutdown_action *shutdown_actions_list[] = { -	&ipl_action, &reipl_action, &dump_action, &vmcmd_action, &stop_action}; +	&ipl_action, &reipl_action, &dump_reipl_action, &dump_action, +	&vmcmd_action, &stop_action};  #define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *))  /* @@ -1434,11 +1483,11 @@ static int set_trigger(const char *buf, struct shutdown_trigger *trigger,  		       size_t len)  {  	int i; +  	for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {  		if (!shutdown_actions_list[i])  			continue; -		if (strncmp(buf, shutdown_actions_list[i]->name, -			    strlen(shutdown_actions_list[i]->name)) == 0) { +		if (sysfs_streq(buf, shutdown_actions_list[i]->name)) {  			trigger->action = shutdown_actions_list[i];  			return len;  		} @@ -1672,7 +1721,7 @@ static int on_panic_notify(struct notifier_block *self,  static struct notifier_block on_panic_nb = {  	.notifier_call = on_panic_notify, -	.priority = 0, +	.priority = INT_MIN,  };  void __init setup_ipl(void) @@ -1696,7 +1745,6 @@ void __init setup_ipl(void)  			sizeof(ipl_info.data.nss.name));  		break;  	case IPL_TYPE_UNKNOWN: -	default:  		/* We have no info to copy */  		break;  	} diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 59b4e796680a..eed4a00cb676 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -310,15 +310,20 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,  			info->plt_initialized = 1;  		}  		if (r_type == R_390_PLTOFF16 || -		    r_type == R_390_PLTOFF32 -		    || r_type == R_390_PLTOFF64 -			) +		    r_type == R_390_PLTOFF32 || +		    r_type == R_390_PLTOFF64)  			val = me->arch.plt_offset - me->arch.got_offset +  				info->plt_offset + rela->r_addend; -		else -			val =  (Elf_Addr) me->module_core + -				me->arch.plt_offset + info->plt_offset +  -				rela->r_addend - loc; +		else { +			if (!((r_type == R_390_PLT16DBL && +			       val - loc + 0xffffUL < 0x1ffffeUL) || +			      (r_type == R_390_PLT32DBL && +			       val - loc + 0xffffffffULL < 0x1fffffffeULL))) +				val = (Elf_Addr) me->module_core + +					me->arch.plt_offset + +					info->plt_offset; +			val += rela->r_addend - loc; +		}  		if (r_type == R_390_PLT16DBL)  			*(unsigned short *) loc = val >> 1;  		else if (r_type == R_390_PLTOFF16) diff --git a/drivers/s390/s390mach.c b/arch/s390/kernel/nmi.c index 92b0417f8e12..4bfdc421d7e9 100644 --- a/drivers/s390/s390mach.c +++ b/arch/s390/kernel/nmi.c @@ -1,137 +1,23 @@  /* - *  drivers/s390/s390mach.c - *   S/390 machine check handler + *   Machine check handler   * - *    Copyright IBM Corp. 2000,2008 - *    Author(s): Ingo Adlung (adlung@de.ibm.com) - *		 Martin Schwidefsky (schwidefsky@de.ibm.com) - *		 Cornelia Huck <cornelia.huck@de.ibm.com> + *    Copyright IBM Corp. 2000,2009 + *    Author(s): Ingo Adlung <adlung@de.ibm.com>, + *		 Martin Schwidefsky <schwidefsky@de.ibm.com>, + *		 Cornelia Huck <cornelia.huck@de.ibm.com>, + *		 Heiko Carstens <heiko.carstens@de.ibm.com>,   */  #include <linux/init.h> -#include <linux/sched.h>  #include <linux/errno.h> -#include <linux/workqueue.h>  #include <linux/time.h> -#include <linux/device.h> -#include <linux/kthread.h> -#include <asm/etr.h> +#include <linux/module.h>  #include <asm/lowcore.h> -#include <asm/cio.h> +#include <asm/smp.h> +#include <asm/etr.h>  #include <asm/cpu.h> -#include "s390mach.h" - -static struct semaphore m_sem; - -static NORET_TYPE void -s390_handle_damage(char *msg) -{ -#ifdef CONFIG_SMP -	smp_send_stop(); -#endif -	disabled_wait((unsigned long) __builtin_return_address(0)); -	for(;;); -} - -static crw_handler_t crw_handlers[NR_RSCS]; - -/** - * s390_register_crw_handler() - register a channel report word handler - * @rsc: reporting source code to handle - * @handler: handler to be registered - * - * Returns %0 on success and a negative error value otherwise. - */ -int s390_register_crw_handler(int rsc, crw_handler_t handler) -{ -	if ((rsc < 0) || (rsc >= NR_RSCS)) -		return -EINVAL; -	if (!cmpxchg(&crw_handlers[rsc], NULL, handler)) -		return 0; -	return -EBUSY; -} - -/** - * s390_unregister_crw_handler() - unregister a channel report word handler - * @rsc: reporting source code to handle - */ -void s390_unregister_crw_handler(int rsc) -{ -	if ((rsc < 0) || (rsc >= NR_RSCS)) -		return; -	xchg(&crw_handlers[rsc], NULL); -	synchronize_sched(); -} - -/* - * Retrieve CRWs and call function to handle event. - */ -static int s390_collect_crw_info(void *param) -{ -	struct crw crw[2]; -	int ccode; -	struct semaphore *sem; -	unsigned int chain; -	int ignore; - -	sem = (struct semaphore *)param; -repeat: -	ignore = down_interruptible(sem); -	chain = 0; -	while (1) { -		if (unlikely(chain > 1)) { -			struct crw tmp_crw; - -			printk(KERN_WARNING"%s: Code does not support more " -			       "than two chained crws; please report to " -			       "linux390@de.ibm.com!\n", __func__); -			ccode = stcrw(&tmp_crw); -			printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, " -			       "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", -			       __func__, tmp_crw.slct, tmp_crw.oflw, -			       tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc, -			       tmp_crw.erc, tmp_crw.rsid); -			printk(KERN_WARNING"%s: This was crw number %x in the " -			       "chain\n", __func__, chain); -			if (ccode != 0) -				break; -			chain = tmp_crw.chn ? chain + 1 : 0; -			continue; -		} -		ccode = stcrw(&crw[chain]); -		if (ccode != 0) -			break; -		printk(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, " -		       "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", -		       crw[chain].slct, crw[chain].oflw, crw[chain].chn, -		       crw[chain].rsc, crw[chain].anc, crw[chain].erc, -		       crw[chain].rsid); -		/* Check for overflows. */ -		if (crw[chain].oflw) { -			int i; - -			pr_debug("%s: crw overflow detected!\n", __func__); -			for (i = 0; i < NR_RSCS; i++) { -				if (crw_handlers[i]) -					crw_handlers[i](NULL, NULL, 1); -			} -			chain = 0; -			continue; -		} -		if (crw[0].chn && !chain) { -			chain++; -			continue; -		} -		if (crw_handlers[crw[chain].rsc]) -			crw_handlers[crw[chain].rsc](&crw[0], -						     chain ? &crw[1] : NULL, -						     0); -		/* chain is always 0 or 1 here. */ -		chain = crw[chain].chn ? chain + 1 : 0; -	} -	goto repeat; -	return 0; -} +#include <asm/nmi.h> +#include <asm/crw.h>  struct mcck_struct {  	int kill_task; @@ -142,12 +28,18 @@ struct mcck_struct {  static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck); +static NORET_TYPE void s390_handle_damage(char *msg) +{ +	smp_send_stop(); +	disabled_wait((unsigned long) __builtin_return_address(0)); +	while (1); +} +  /*   * Main machine check handler function. Will be called with interrupts enabled   * or disabled and machine checks enabled or disabled.   */ -void -s390_handle_mcck(void) +void s390_handle_mcck(void)  {  	unsigned long flags;  	struct mcck_struct mcck; @@ -166,29 +58,24 @@ s390_handle_mcck(void)  	local_irq_restore(flags);  	if (mcck.channel_report) -		up(&m_sem); - -#ifdef CONFIG_MACHCHK_WARNING -/* - * The warning may remain for a prolonged period on the bare iron. - * (actually till the machine is powered off, or until the problem is gone) - * So we just stop listening for the WARNING MCH and prevent continuously - * being interrupted.  One caveat is however, that we must do this per - * processor and cannot use the smp version of ctl_clear_bit(). - * On VM we only get one interrupt per virtally presented machinecheck. - * Though one suffices, we may get one interrupt per (virtual) processor. - */ +		crw_handle_channel_report(); +	/* +	 * A warning may remain for a prolonged period on the bare iron. +	 * (actually until the machine is powered off, or the problem is gone) +	 * So we just stop listening for the WARNING MCH and avoid continuously +	 * being interrupted.  One caveat is however, that we must do this per +	 * processor and cannot use the smp version of ctl_clear_bit(). +	 * On VM we only get one interrupt per virtally presented machinecheck. +	 * Though one suffices, we may get one interrupt per (virtual) cpu. +	 */  	if (mcck.warning) {	/* WARNING pending ? */  		static int mchchk_wng_posted = 0; -		/* -		 * Use single machine clear, as we cannot handle smp right now -		 */ + +		/* Use single cpu clear, as we cannot handle smp here. */  		__ctl_clear_bit(14, 24);	/* Disable WARNING MCH */  		if (xchg(&mchchk_wng_posted, 1) == 0)  			kill_cad_pid(SIGPWR, 1);  	} -#endif -  	if (mcck.kill_task) {  		local_irq_enable();  		printk(KERN_EMERG "mcck: Terminating task because of machine " @@ -204,8 +91,7 @@ EXPORT_SYMBOL_GPL(s390_handle_mcck);   * returns 0 if all registers could be validated   * returns 1 otherwise   */ -static int -s390_revalidate_registers(struct mci *mci) +static int notrace s390_revalidate_registers(struct mci *mci)  {  	int kill_task;  	u64 tmpclock; @@ -214,22 +100,21 @@ s390_revalidate_registers(struct mci *mci)  	kill_task = 0;  	zero = 0; -	/* General purpose registers */ -	if (!mci->gr) + +	if (!mci->gr) {  		/*  		 * General purpose registers couldn't be restored and have  		 * unknown contents. Process needs to be terminated.  		 */  		kill_task = 1; - -	/* Revalidate floating point registers */ -	if (!mci->fp) +	} +	if (!mci->fp) {  		/*  		 * Floating point registers can't be restored and  		 * therefore the process needs to be terminated.  		 */  		kill_task = 1; - +	}  #ifndef CONFIG_64BIT  	asm volatile(  		"	ld	0,0(%0)\n" @@ -245,9 +130,8 @@ s390_revalidate_registers(struct mci *mci)  		fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area;  #else  		fpt_save_area = (void *) S390_lowcore.extended_save_area_addr; -		fpt_creg_save_area = fpt_save_area+128; +		fpt_creg_save_area = fpt_save_area + 128;  #endif -		/* Floating point control register */  		if (!mci->fc) {  			/*  			 * Floating point control register can't be restored. @@ -278,26 +162,25 @@ s390_revalidate_registers(struct mci *mci)  			"	ld	15,120(%0)\n"  			: : "a" (fpt_save_area));  	} -  	/* Revalidate access registers */  	asm volatile(  		"	lam	0,15,0(%0)"  		: : "a" (&S390_lowcore.access_regs_save_area)); -	if (!mci->ar) +	if (!mci->ar) {  		/*  		 * Access registers have unknown contents.  		 * Terminating task.  		 */  		kill_task = 1; - +	}  	/* Revalidate control registers */ -	if (!mci->cr) +	if (!mci->cr) {  		/*  		 * Control registers have unknown contents.  		 * Can't recover and therefore stopping machine.  		 */  		s390_handle_damage("invalid control registers."); -	else +	} else {  #ifdef CONFIG_64BIT  		asm volatile(  			"	lctlg	0,15,0(%0)" @@ -307,12 +190,11 @@ s390_revalidate_registers(struct mci *mci)  			"	lctl	0,15,0(%0)"  			: : "a" (&S390_lowcore.cregs_save_area));  #endif - +	}  	/*  	 * We don't even try to revalidate the TOD register, since we simply  	 * can't write something sensible into that register.  	 */ -  #ifdef CONFIG_64BIT  	/*  	 * See if we can revalidate the TOD programmable register with its @@ -330,7 +212,6 @@ s390_revalidate_registers(struct mci *mci)  			: : "a" (&S390_lowcore.tod_progreg_save_area)  			: "0", "cc");  #endif -  	/* Revalidate clock comparator register */  	asm volatile(  		"	stck	0(%1)\n" @@ -354,32 +235,35 @@ s390_revalidate_registers(struct mci *mci)  #define MAX_IPD_COUNT	29  #define MAX_IPD_TIME	(5 * 60 * USEC_PER_SEC) /* 5 minutes */ +#define ED_STP_ISLAND	6	/* External damage STP island check */ +#define ED_STP_SYNC	7	/* External damage STP sync check */ +#define ED_ETR_SYNC	12	/* External damage ETR sync check */ +#define ED_ETR_SWITCH	13	/* External damage ETR switch to local */ +  /*   * machine check handler.   */ -void -s390_do_machine_check(struct pt_regs *regs) +void notrace s390_do_machine_check(struct pt_regs *regs)  { +	static int ipd_count;  	static DEFINE_SPINLOCK(ipd_lock);  	static unsigned long long last_ipd; -	static int ipd_count; +	struct mcck_struct *mcck;  	unsigned long long tmp;  	struct mci *mci; -	struct mcck_struct *mcck;  	int umode;  	lockdep_off(); -  	s390_idle_check();  	mci = (struct mci *) &S390_lowcore.mcck_interruption_code;  	mcck = &__get_cpu_var(cpu_mcck);  	umode = user_mode(regs); -	if (mci->sd) +	if (mci->sd) {  		/* System damage -> stopping machine */  		s390_handle_damage("received system damage machine check."); - +	}  	if (mci->pd) {  		if (mci->b) {  			/* Processing backup -> verify if we can survive this */ @@ -409,24 +293,17 @@ s390_do_machine_check(struct pt_regs *regs)  			 * Nullifying exigent condition, therefore we might  			 * retry this instruction.  			 */ -  			spin_lock(&ipd_lock); -  			tmp = get_clock(); -  			if (((tmp - last_ipd) >> 12) < MAX_IPD_TIME)  				ipd_count++;  			else  				ipd_count = 1; -  			last_ipd = tmp; -  			if (ipd_count == MAX_IPD_COUNT)  				s390_handle_damage("too many ipd retries."); -  			spin_unlock(&ipd_lock); -		} -		else { +		} else {  			/* Processing damage -> stopping machine */  			s390_handle_damage("received instruction processing "  					   "damage machine check."); @@ -441,20 +318,18 @@ s390_do_machine_check(struct pt_regs *regs)  			mcck->kill_task = 1;  			mcck->mcck_code = *(unsigned long long *) mci;  			set_thread_flag(TIF_MCCK_PENDING); -		} -		else +		} else {  			/*  			 * Couldn't restore all register contents while in  			 * kernel mode -> stopping machine.  			 */  			s390_handle_damage("unable to revalidate registers."); +		}  	} -  	if (mci->cd) {  		/* Timing facility damage */  		s390_handle_damage("TOD clock damaged");  	} -  	if (mci->ed && mci->ec) {  		/* External damage */  		if (S390_lowcore.external_damage_code & (1U << ED_ETR_SYNC)) @@ -466,28 +341,23 @@ s390_do_machine_check(struct pt_regs *regs)  		if (S390_lowcore.external_damage_code & (1U << ED_STP_ISLAND))  			stp_island_check();  	} -  	if (mci->se)  		/* Storage error uncorrected */  		s390_handle_damage("received storage error uncorrected "  				   "machine check."); -  	if (mci->ke)  		/* Storage key-error uncorrected */  		s390_handle_damage("received storage key-error uncorrected "  				   "machine check."); -  	if (mci->ds && mci->fa)  		/* Storage degradation */  		s390_handle_damage("received storage degradation machine "  				   "check."); -  	if (mci->cp) {  		/* Channel report word pending */  		mcck->channel_report = 1;  		set_thread_flag(TIF_MCCK_PENDING);  	} -  	if (mci->w) {  		/* Warning pending */  		mcck->warning = 1; @@ -496,43 +366,11 @@ s390_do_machine_check(struct pt_regs *regs)  	lockdep_on();  } -/* - * s390_init_machine_check - * - * initialize machine check handling - */ -static int -machine_check_init(void) +static int __init machine_check_init(void)  { -	init_MUTEX_LOCKED(&m_sem);  	ctl_set_bit(14, 25);	/* enable external damage MCH */ -	ctl_set_bit(14, 27);    /* enable system recovery MCH */ -#ifdef CONFIG_MACHCHK_WARNING +	ctl_set_bit(14, 27);	/* enable system recovery MCH */  	ctl_set_bit(14, 24);	/* enable warning MCH */ -#endif  	return 0;  } - -/* - * Initialize the machine check handler really early to be able to - * catch all machine checks that happen during boot - */  arch_initcall(machine_check_init); - -/* - * Machine checks for the channel subsystem must be enabled - * after the channel subsystem is initialized - */ -static int __init -machine_check_crw_init (void) -{ -	struct task_struct *task; - -	task = kthread_run(s390_collect_crw_info, &m_sem, "kmcheck"); -	if (IS_ERR(task)) -		return PTR_ERR(task); -	ctl_set_bit(14, 28);	/* enable channel report MCH */ -	return 0; -} - -device_initcall (machine_check_crw_init); diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 5cd38a90e64d..b48e961a38f6 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -1,18 +1,10 @@  /* - *  arch/s390/kernel/process.c + * This file handles the architecture dependent parts of process handling.   * - *  S390 version - *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), - *               Hartmut Penner (hp@de.ibm.com), - *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), - * - *  Derived from "arch/i386/kernel/process.c" - *    Copyright (C) 1995, Linus Torvalds - */ - -/* - * This file handles the architecture-dependent parts of process handling.. + *    Copyright IBM Corp. 1999,2009 + *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>, + *		 Hartmut Penner <hp@de.ibm.com>, + *		 Denis Joseph Barrow,   */  #include <linux/compiler.h> @@ -47,6 +39,7 @@  #include <asm/processor.h>  #include <asm/irq.h>  #include <asm/timer.h> +#include <asm/nmi.h>  #include "entry.h"  asmlinkage void ret_from_fork(void) asm ("ret_from_fork"); @@ -76,7 +69,6 @@ unsigned long thread_saved_pc(struct task_struct *tsk)  	return sf->gprs[8];  } -extern void s390_handle_mcck(void);  /*   * The idle loop on a S390...   */ @@ -149,6 +141,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)  	return do_fork(flags | CLONE_VM | CLONE_UNTRACED,  		       0, ®s, 0, NULL, NULL);  } +EXPORT_SYMBOL(kernel_thread);  /*   * Free current thread data structures etc.. @@ -168,34 +161,35 @@ void release_thread(struct task_struct *dead_task)  }  int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, -	unsigned long unused, -        struct task_struct * p, struct pt_regs * regs) +		unsigned long unused, +		struct task_struct *p, struct pt_regs *regs)  { -        struct fake_frame -          { -	    struct stack_frame sf; -            struct pt_regs childregs; -          } *frame; - -        frame = container_of(task_pt_regs(p), struct fake_frame, childregs); -        p->thread.ksp = (unsigned long) frame; +	struct thread_info *ti; +	struct fake_frame +	{ +		struct stack_frame sf; +		struct pt_regs childregs; +	} *frame; + +	frame = container_of(task_pt_regs(p), struct fake_frame, childregs); +	p->thread.ksp = (unsigned long) frame;  	/* Store access registers to kernel stack of new process. */ -        frame->childregs = *regs; +	frame->childregs = *regs;  	frame->childregs.gprs[2] = 0;	/* child returns 0 on fork. */ -        frame->childregs.gprs[15] = new_stackp; -        frame->sf.back_chain = 0; +	frame->childregs.gprs[15] = new_stackp; +	frame->sf.back_chain = 0; -        /* new return point is ret_from_fork */ -        frame->sf.gprs[8] = (unsigned long) ret_from_fork; +	/* new return point is ret_from_fork */ +	frame->sf.gprs[8] = (unsigned long) ret_from_fork; -        /* fake return stack for resume(), don't go back to schedule */ -        frame->sf.gprs[9] = (unsigned long) frame; +	/* fake return stack for resume(), don't go back to schedule */ +	frame->sf.gprs[9] = (unsigned long) frame;  	/* Save access registers to new thread structure. */  	save_access_regs(&p->thread.acrs[0]);  #ifndef CONFIG_64BIT -        /* +	/*  	 * save fprs to current->thread.fp_regs to merge them with  	 * the emulated registers and then copy the result to the child.  	 */ @@ -220,10 +214,13 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,  #endif /* CONFIG_64BIT */  	/* start new process with ar4 pointing to the correct address space */  	p->thread.mm_segment = get_fs(); -        /* Don't copy debug registers */ -        memset(&p->thread.per_info,0,sizeof(p->thread.per_info)); - -        return 0; +	/* Don't copy debug registers */ +	memset(&p->thread.per_info, 0, sizeof(p->thread.per_info)); +	/* Initialize per thread user and system timer values */ +	ti = task_thread_info(p); +	ti->user_timer = 0; +	ti->system_timer = 0; +	return 0;  }  SYSCALL_DEFINE0(fork) @@ -311,7 +308,7 @@ out:  int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs)  {  #ifndef CONFIG_64BIT -        /* +	/*  	 * save fprs to current->thread.fp_regs to merge them with  	 * the emulated registers and then copy the result to the dump.  	 */ @@ -322,6 +319,7 @@ int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs)  #endif /* CONFIG_64BIT */  	return 1;  } +EXPORT_SYMBOL(dump_fpu);  unsigned long get_wchan(struct task_struct *p)  { @@ -346,4 +344,3 @@ unsigned long get_wchan(struct task_struct *p)  	}  	return 0;  } - diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 82c1872cfe80..802c8ab247f3 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -18,10 +18,11 @@  #include <asm/lowcore.h>  #include <asm/param.h> -void __cpuinit print_cpu_info(struct cpuinfo_S390 *cpuinfo) +void __cpuinit print_cpu_info(void)  {  	pr_info("Processor %d started, address %d, identification %06X\n", -		cpuinfo->cpu_nr, cpuinfo->cpu_addr, cpuinfo->cpu_id.ident); +		S390_lowcore.cpu_nr, S390_lowcore.cpu_addr, +		S390_lowcore.cpu_id.ident);  }  /* @@ -30,48 +31,46 @@ void __cpuinit print_cpu_info(struct cpuinfo_S390 *cpuinfo)  static int show_cpuinfo(struct seq_file *m, void *v)  { -	static const char *hwcap_str[8] = { +	static const char *hwcap_str[9] = {  		"esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", -		"edat" +		"edat", "etf3eh"  	}; -       struct cpuinfo_S390 *cpuinfo; -       unsigned long n = (unsigned long) v - 1; -       int i; +	struct _lowcore *lc; +	unsigned long n = (unsigned long) v - 1; +	int i; -       s390_adjust_jiffies(); -       preempt_disable(); -       if (!n) { -	       seq_printf(m, "vendor_id       : IBM/S390\n" -			  "# processors    : %i\n" -			  "bogomips per cpu: %lu.%02lu\n", -			  num_online_cpus(), loops_per_jiffy/(500000/HZ), -			  (loops_per_jiffy/(5000/HZ))%100); -	       seq_puts(m, "features\t: "); -	       for (i = 0; i < 8; i++) -		       if (hwcap_str[i] && (elf_hwcap & (1UL << i))) -			       seq_printf(m, "%s ", hwcap_str[i]); -	       seq_puts(m, "\n"); -       } +	s390_adjust_jiffies(); +	preempt_disable(); +	if (!n) { +		seq_printf(m, "vendor_id       : IBM/S390\n" +			   "# processors    : %i\n" +			   "bogomips per cpu: %lu.%02lu\n", +			   num_online_cpus(), loops_per_jiffy/(500000/HZ), +			   (loops_per_jiffy/(5000/HZ))%100); +		seq_puts(m, "features\t: "); +		for (i = 0; i < 9; i++) +			if (hwcap_str[i] && (elf_hwcap & (1UL << i))) +				seq_printf(m, "%s ", hwcap_str[i]); +		seq_puts(m, "\n"); +	} -       if (cpu_online(n)) { +	if (cpu_online(n)) {  #ifdef CONFIG_SMP -	       if (smp_processor_id() == n) -		       cpuinfo = &S390_lowcore.cpu_data; -	       else -		       cpuinfo = &lowcore_ptr[n]->cpu_data; +		lc = (smp_processor_id() == n) ? +			&S390_lowcore : lowcore_ptr[n];  #else -	       cpuinfo = &S390_lowcore.cpu_data; +		lc = &S390_lowcore;  #endif -	       seq_printf(m, "processor %li: " -			  "version = %02X,  " -			  "identification = %06X,  " -			  "machine = %04X\n", -			  n, cpuinfo->cpu_id.version, -			  cpuinfo->cpu_id.ident, -			  cpuinfo->cpu_id.machine); -       } -       preempt_enable(); -       return 0; +		seq_printf(m, "processor %li: " +			   "version = %02X,  " +			   "identification = %06X,  " +			   "machine = %04X\n", +			   n, lc->cpu_id.version, +			   lc->cpu_id.ident, +			   lc->cpu_id.machine); +	} +	preempt_enable(); +	return 0;  }  static void *c_start(struct seq_file *m, loff_t *pos) diff --git a/arch/s390/kernel/reipl64.S b/arch/s390/kernel/reipl64.S index c41930499a5f..774147824c3d 100644 --- a/arch/s390/kernel/reipl64.S +++ b/arch/s390/kernel/reipl64.S @@ -1,10 +1,7 @@  /* - *  arch/s390/kernel/reipl.S - * - *  S390 version - *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation - *    Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com) -		 Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + *    Copyright IBM Corp 2000,2009 + *    Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>, + *		 Denis Joseph Barrow,   */  #include <asm/lowcore.h> @@ -30,7 +27,7 @@ do_reipl_asm:	basr	%r13,0  		mvc	__LC_PREFIX_SAVE_AREA-0x1000(4,%r1),0(%r10)  		stfpc	__LC_FP_CREG_SAVE_AREA-0x1000(%r1)  		stckc	.Lclkcmp-.Lpg0(%r13) -		mvc	__LC_CLOCK_COMP_SAVE_AREA-0x1000(8,%r1),.Lclkcmp-.Lpg0(%r13) +		mvc	__LC_CLOCK_COMP_SAVE_AREA-0x1000(7,%r1),.Lclkcmp-.Lpg0(%r13)  		stpt	__LC_CPU_TIMER_SAVE_AREA-0x1000(%r1)  		stg	%r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1) diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c index 46b90cb03707..656fcbb9bd83 100644 --- a/arch/s390/kernel/s390_ksyms.c +++ b/arch/s390/kernel/s390_ksyms.c @@ -1,49 +1,5 @@ -/* - *  arch/s390/kernel/s390_ksyms.c - * - *  S390 version - */ -#include <linux/highuid.h>  #include <linux/module.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/syscalls.h> -#include <linux/interrupt.h> -#include <asm/checksum.h> -#include <asm/cpcmd.h> -#include <asm/delay.h> -#include <asm/pgalloc.h> -#include <asm/setup.h>  #include <asm/ftrace.h> -#ifdef CONFIG_IP_MULTICAST -#include <net/arp.h> -#endif - -/* - * memory management - */ -EXPORT_SYMBOL(_oi_bitmap); -EXPORT_SYMBOL(_ni_bitmap); -EXPORT_SYMBOL(_zb_findmap); -EXPORT_SYMBOL(_sb_findmap); - -/* - * binfmt_elf loader  - */ -extern int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs); -EXPORT_SYMBOL(dump_fpu); -EXPORT_SYMBOL(empty_zero_page); - -/* - * misc. - */ -EXPORT_SYMBOL(machine_flags); -EXPORT_SYMBOL(__udelay); -EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(csum_fold); -EXPORT_SYMBOL(console_mode); -EXPORT_SYMBOL(console_devno); -EXPORT_SYMBOL(console_irq);  #ifdef CONFIG_FUNCTION_TRACER  EXPORT_SYMBOL(_mcount); diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index c5cfb6185eac..06201b93cbbf 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -74,9 +74,17 @@ EXPORT_SYMBOL(uaccess);   * Machine setup..   */  unsigned int console_mode = 0; +EXPORT_SYMBOL(console_mode); +  unsigned int console_devno = -1; +EXPORT_SYMBOL(console_devno); +  unsigned int console_irq = -1; +EXPORT_SYMBOL(console_irq); +  unsigned long machine_flags; +EXPORT_SYMBOL(machine_flags); +  unsigned long elf_hwcap = 0;  char elf_platform[ELF_PLATFORM_SIZE]; @@ -86,6 +94,10 @@ volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */  int __initdata memory_end_set;  unsigned long __initdata memory_end; +/* An array with a pointer to the lowcore of every CPU. */ +struct _lowcore *lowcore_ptr[NR_CPUS]; +EXPORT_SYMBOL(lowcore_ptr); +  /*   * This is set up by the setup-routine at boot-time   * for S390 need to find out, what we have to setup @@ -109,13 +121,10 @@ static struct resource data_resource = {   */  void __cpuinit cpu_init(void)  { -        int addr = hard_smp_processor_id(); -          /*           * Store processor id in lowcore (used e.g. in timer_interrupt)           */ -	get_cpu_id(&S390_lowcore.cpu_data.cpu_id); -        S390_lowcore.cpu_data.cpu_addr = addr; +	get_cpu_id(&S390_lowcore.cpu_id);          /*           * Force FPU initialization: @@ -125,8 +134,7 @@ void __cpuinit cpu_init(void)  	atomic_inc(&init_mm.mm_count);  	current->active_mm = &init_mm; -        if (current->mm) -                BUG(); +	BUG_ON(current->mm);          enter_lazy_tlb(&init_mm, current);  } @@ -217,7 +225,7 @@ static void __init conmode_default(void)  	}  } -#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE) +#ifdef CONFIG_ZFCPDUMP  static void __init setup_zfcpdump(unsigned int console_devno)  {  	static char str[41]; @@ -289,11 +297,7 @@ static int __init early_parse_mem(char *p)  early_param("mem", early_parse_mem);  #ifdef CONFIG_S390_SWITCH_AMODE -#ifdef CONFIG_PGSTE -unsigned int switch_amode = 1; -#else  unsigned int switch_amode = 0; -#endif  EXPORT_SYMBOL_GPL(switch_amode);  static int set_amode_and_uaccess(unsigned long user_amode, @@ -414,7 +418,6 @@ setup_lowcore(void)  		PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;  	lc->io_new_psw.mask = psw_kernel_bits;  	lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; -	lc->ipl_device = S390_lowcore.ipl_device;  	lc->clock_comparator = -1ULL;  	lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;  	lc->async_stack = (unsigned long) @@ -434,6 +437,7 @@ setup_lowcore(void)  	lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0];  #endif  	set_prefix((u32)(unsigned long) lc); +	lowcore_ptr[0] = lc;  }  static void __init @@ -510,7 +514,7 @@ static void __init setup_memory_end(void)  	unsigned long max_mem;  	int i; -#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE) +#ifdef CONFIG_ZFCPDUMP  	if (ipl_info.type == IPL_TYPE_FCP_DUMP) {  		memory_end = ZFCPDUMP_HSA_SIZE;  		memory_end_set = 1; @@ -677,7 +681,6 @@ setup_memory(void)  static void __init setup_hwcaps(void)  {  	static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 }; -	struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data;  	unsigned long long facility_list_extended;  	unsigned int facility_list;  	int i; @@ -693,15 +696,22 @@ static void __init setup_hwcaps(void)  	 *   Bit 17: the message-security assist is installed  	 *   Bit 19: the long-displacement facility is installed  	 *   Bit 21: the extended-immediate facility is installed +	 *   Bit 22: extended-translation facility 3 is installed +	 *   Bit 30: extended-translation facility 3 enhancement facility  	 * These get translated to:  	 *   HWCAP_S390_ESAN3 bit 0, HWCAP_S390_ZARCH bit 1,  	 *   HWCAP_S390_STFLE bit 2, HWCAP_S390_MSA bit 3, -	 *   HWCAP_S390_LDISP bit 4, and HWCAP_S390_EIMM bit 5. +	 *   HWCAP_S390_LDISP bit 4, HWCAP_S390_EIMM bit 5 and +	 *   HWCAP_S390_ETF3EH bit 8 (22 && 30).  	 */  	for (i = 0; i < 6; i++)  		if (facility_list & (1UL << (31 - stfl_bits[i])))  			elf_hwcap |= 1UL << i; +	if ((facility_list & (1UL << (31 - 22))) +	    && (facility_list & (1UL << (31 - 30)))) +		elf_hwcap |= 1UL << 8; +  	/*  	 * Check for additional facilities with store-facility-list-extended.  	 * stfle stores doublewords (8 byte) with bit 1ULL<<63 as bit 0 @@ -710,20 +720,22 @@ static void __init setup_hwcaps(void)  	 * How many facility words are stored depends on the number of  	 * doublewords passed to the instruction. The additional facilites  	 * are: -	 *   Bit 43: decimal floating point facility is installed +	 *   Bit 42: decimal floating point facility is installed +	 *   Bit 44: perform floating point operation facility is installed  	 * translated to: -	 *   HWCAP_S390_DFP bit 6. +	 *   HWCAP_S390_DFP bit 6 (42 && 44).  	 */  	if ((elf_hwcap & (1UL << 2)) &&  	    __stfle(&facility_list_extended, 1) > 0) { -		if (facility_list_extended & (1ULL << (64 - 43))) +		if ((facility_list_extended & (1ULL << (63 - 42))) +		    && (facility_list_extended & (1ULL << (63 - 44))))  			elf_hwcap |= 1UL << 6;  	}  	if (MACHINE_HAS_HPAGE)  		elf_hwcap |= 1UL << 7; -	switch (cpuinfo->cpu_id.machine) { +	switch (S390_lowcore.cpu_id.machine) {  	case 0x9672:  #if !defined(CONFIG_64BIT)  	default:	/* Use "g5" as default for 31 bit kernels. */ @@ -816,7 +828,7 @@ setup_arch(char **cmdline_p)  	setup_lowcore();          cpu_init(); -        __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr; +	__cpu_logical_map[0] = stap();  	s390_init_cpu_topology();  	/* diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 2d337cbb9329..006ed5016eb4 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -32,6 +32,7 @@  #include <linux/delay.h>  #include <linux/cache.h>  #include <linux/interrupt.h> +#include <linux/irqflags.h>  #include <linux/cpu.h>  #include <linux/timex.h>  #include <linux/bootmem.h> @@ -50,12 +51,6 @@  #include <asm/vdso.h>  #include "entry.h" -/* - * An array with a pointer the lowcore of every CPU. - */ -struct _lowcore *lowcore_ptr[NR_CPUS]; -EXPORT_SYMBOL(lowcore_ptr); -  static struct task_struct *current_set[NR_CPUS];  static u8 smp_cpu_type; @@ -81,9 +76,7 @@ void smp_send_stop(void)  	/* Disable all interrupts/machine checks */  	__load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK); - -	/* write magic number to zero page (absolute 0) */ -	lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC; +	trace_hardirqs_off();  	/* stop all processors */  	for_each_online_cpu(cpu) { @@ -233,7 +226,7 @@ EXPORT_SYMBOL(smp_ctl_clear_bit);   */  #define CPU_INIT_NO	1 -#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE) +#ifdef CONFIG_ZFCPDUMP  /*   * zfcpdump_prefix_array holds prefix registers for the following scenario: @@ -274,7 +267,7 @@ EXPORT_SYMBOL_GPL(zfcpdump_save_areas);  static inline void smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) { } -#endif /* CONFIG_ZFCPDUMP || CONFIG_ZFCPDUMP_MODULE */ +#endif /* CONFIG_ZFCPDUMP */  static int cpu_stopped(int cpu)  { @@ -304,8 +297,8 @@ static int smp_rescan_cpus_sigp(cpumask_t avail)  {  	int cpu_id, logical_cpu; -	logical_cpu = first_cpu(avail); -	if (logical_cpu == NR_CPUS) +	logical_cpu = cpumask_first(&avail); +	if (logical_cpu >= nr_cpu_ids)  		return 0;  	for (cpu_id = 0; cpu_id <= 65535; cpu_id++) {  		if (cpu_known(cpu_id)) @@ -316,8 +309,8 @@ static int smp_rescan_cpus_sigp(cpumask_t avail)  			continue;  		cpu_set(logical_cpu, cpu_present_map);  		smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED; -		logical_cpu = next_cpu(logical_cpu, avail); -		if (logical_cpu == NR_CPUS) +		logical_cpu = cpumask_next(logical_cpu, &avail); +		if (logical_cpu >= nr_cpu_ids)  			break;  	}  	return 0; @@ -329,8 +322,8 @@ static int smp_rescan_cpus_sclp(cpumask_t avail)  	int cpu_id, logical_cpu, cpu;  	int rc; -	logical_cpu = first_cpu(avail); -	if (logical_cpu == NR_CPUS) +	logical_cpu = cpumask_first(&avail); +	if (logical_cpu >= nr_cpu_ids)  		return 0;  	info = kmalloc(sizeof(*info), GFP_KERNEL);  	if (!info) @@ -351,8 +344,8 @@ static int smp_rescan_cpus_sclp(cpumask_t avail)  			smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY;  		else  			smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED; -		logical_cpu = next_cpu(logical_cpu, avail); -		if (logical_cpu == NR_CPUS) +		logical_cpu = cpumask_next(logical_cpu, &avail); +		if (logical_cpu >= nr_cpu_ids)  			break;  	}  out: @@ -379,7 +372,7 @@ static void __init smp_detect_cpus(void)  	c_cpus = 1;  	s_cpus = 0; -	boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr; +	boot_cpu_addr = __cpu_logical_map[0];  	info = kmalloc(sizeof(*info), GFP_KERNEL);  	if (!info)  		panic("smp_detect_cpus failed to allocate memory\n"); @@ -453,7 +446,7 @@ int __cpuinit start_secondary(void *cpuvoid)  	/* Switch on interrupts */  	local_irq_enable();  	/* Print info about this processor */ -	print_cpu_info(&S390_lowcore.cpu_data); +	print_cpu_info();  	/* cpu_idle will call schedule for us */  	cpu_idle();  	return 0; @@ -515,7 +508,6 @@ out:  	return -ENOMEM;  } -#ifdef CONFIG_HOTPLUG_CPU  static void smp_free_lowcore(int cpu)  {  	struct _lowcore *lowcore; @@ -534,7 +526,6 @@ static void smp_free_lowcore(int cpu)  	free_pages((unsigned long) lowcore, lc_order);  	lowcore_ptr[cpu] = NULL;  } -#endif /* CONFIG_HOTPLUG_CPU */  /* Upping and downing of CPUs */  int __cpuinit __cpu_up(unsigned int cpu) @@ -543,16 +534,23 @@ int __cpuinit __cpu_up(unsigned int cpu)  	struct _lowcore *cpu_lowcore;  	struct stack_frame *sf;  	sigp_ccode ccode; +	u32 lowcore;  	if (smp_cpu_state[cpu] != CPU_STATE_CONFIGURED)  		return -EIO;  	if (smp_alloc_lowcore(cpu))  		return -ENOMEM; - -	ccode = signal_processor_p((__u32)(unsigned long)(lowcore_ptr[cpu]), -				   cpu, sigp_set_prefix); -	if (ccode) -		return -EIO; +	do { +		ccode = signal_processor(cpu, sigp_initial_cpu_reset); +		if (ccode == sigp_busy) +			udelay(10); +		if (ccode == sigp_not_operational) +			goto err_out; +	} while (ccode == sigp_busy); + +	lowcore = (u32)(unsigned long)lowcore_ptr[cpu]; +	while (signal_processor_p(lowcore, cpu, sigp_set_prefix) == sigp_busy) +		udelay(10);  	idle = current_set[cpu];  	cpu_lowcore = lowcore_ptr[cpu]; @@ -571,9 +569,8 @@ int __cpuinit __cpu_up(unsigned int cpu)  		: : "a" (&cpu_lowcore->access_regs_save_area) : "memory");  	cpu_lowcore->percpu_offset = __per_cpu_offset[cpu];  	cpu_lowcore->current_task = (unsigned long) idle; -	cpu_lowcore->cpu_data.cpu_nr = cpu; +	cpu_lowcore->cpu_nr = cpu;  	cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce; -	cpu_lowcore->ipl_device = S390_lowcore.ipl_device;  	eieio();  	while (signal_processor(cpu, sigp_restart) == sigp_busy) @@ -582,6 +579,10 @@ int __cpuinit __cpu_up(unsigned int cpu)  	while (!cpu_online(cpu))  		cpu_relax();  	return 0; + +err_out: +	smp_free_lowcore(cpu); +	return -EIO;  }  static int __init setup_possible_cpus(char *s) @@ -589,9 +590,8 @@ static int __init setup_possible_cpus(char *s)  	int pcpus, cpu;  	pcpus = simple_strtoul(s, NULL, 0); -	cpu_possible_map = cpumask_of_cpu(0); -	for (cpu = 1; cpu < pcpus && cpu < NR_CPUS; cpu++) -		cpu_set(cpu, cpu_possible_map); +	for (cpu = 0; cpu < pcpus && cpu < nr_cpu_ids; cpu++) +		set_cpu_possible(cpu, true);  	return 0;  }  early_param("possible_cpus", setup_possible_cpus); @@ -663,7 +663,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)  	/* request the 0x1201 emergency signal external interrupt */  	if (register_external_interrupt(0x1201, do_ext_call_interrupt) != 0)  		panic("Couldn't request external interrupt 0x1201"); -	print_cpu_info(&S390_lowcore.cpu_data); +	print_cpu_info();  	/* Reallocate current lowcore, but keep its contents. */  	lc_order = sizeof(long) == 8 ? 1 : 0; diff --git a/drivers/s390/sysinfo.c b/arch/s390/kernel/sysinfo.c index 0eea90781385..b5e75e1061c8 100644 --- a/drivers/s390/sysinfo.c +++ b/arch/s390/kernel/sysinfo.c @@ -1,9 +1,7 @@  /* - *  drivers/s390/sysinfo.c - * - *  Copyright IBM Corp. 2001, 2008 - *  Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com) - *	       Martin Schwidefsky <schwidefsky@de.ibm.com> + *  Copyright IBM Corp. 2001, 2009 + *  Author(s): Ulrich Weigand <Ulrich.Weigand@de.ibm.com>, + *	       Martin Schwidefsky <schwidefsky@de.ibm.com>,   */  #include <linux/kernel.h> @@ -24,7 +22,7 @@  static inline int stsi_0(void)  { -	int rc = stsi (NULL, 0, 0, 0); +	int rc = stsi(NULL, 0, 0, 0);  	return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28);  } @@ -78,23 +76,6 @@ static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len)  	return len;  } -#if 0 /* Currently unused */ -static int stsi_1_2_1(struct sysinfo_1_2_1 *info, char *page, int len) -{ -	if (stsi(info, 1, 2, 1) == -ENOSYS) -		return len; - -	len += sprintf(page + len, "\n"); -	EBCASC(info->sequence, sizeof(info->sequence)); -	EBCASC(info->plant, sizeof(info->plant)); -	len += sprintf(page + len, "Sequence Code of CPU: %-16.16s\n", -		       info->sequence); -	len += sprintf(page + len, "Plant of CPU:         %-16.16s\n", -		       info->plant); -	return len; -} -#endif -  static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len)  {  	struct sysinfo_1_2_2_extension *ext; @@ -145,33 +126,15 @@ static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len)  	if (info->secondary_capability != 0)  		len += sprintf(page + len, "Secondary Capability: %d\n",  			       info->secondary_capability); -  	return len;  } -#if 0 /* Currently unused */ -static int stsi_2_2_1(struct sysinfo_2_2_1 *info, char *page, int len) -{ -	if (stsi(info, 2, 2, 1) == -ENOSYS) -		return len; - -	len += sprintf(page + len, "\n"); -	EBCASC (info->sequence, sizeof(info->sequence)); -	EBCASC (info->plant, sizeof(info->plant)); -	len += sprintf(page + len, "Sequence Code of logical CPU: %-16.16s\n", -		       info->sequence); -	len += sprintf(page + len, "Plant of logical CPU: %-16.16s\n", -		       info->plant); -	return len; -} -#endif -  static int stsi_2_2_2(struct sysinfo_2_2_2 *info, char *page, int len)  {  	if (stsi(info, 2, 2, 2) == -ENOSYS)  		return len; -	EBCASC (info->name, sizeof(info->name)); +	EBCASC(info->name, sizeof(info->name));  	len += sprintf(page + len, "\n");  	len += sprintf(page + len, "LPAR Number:          %d\n", @@ -214,8 +177,8 @@ static int stsi_3_2_2(struct sysinfo_3_2_2 *info, char *page, int len)  	if (stsi(info, 3, 2, 2) == -ENOSYS)  		return len;  	for (i = 0; i < info->count; i++) { -		EBCASC (info->vm[i].name, sizeof(info->vm[i].name)); -		EBCASC (info->vm[i].cpi, sizeof(info->vm[i].cpi)); +		EBCASC(info->vm[i].name, sizeof(info->vm[i].name)); +		EBCASC(info->vm[i].cpi, sizeof(info->vm[i].cpi));  		len += sprintf(page + len, "\n");  		len += sprintf(page + len, "VM%02d Name:            %-8.8s\n",  			       i, info->vm[i].name); @@ -237,14 +200,13 @@ static int stsi_3_2_2(struct sysinfo_3_2_2 *info, char *page, int len)  	return len;  } -  static int proc_read_sysinfo(char *page, char **start, -                             off_t off, int count, -                             int *eof, void *data) +			     off_t off, int count, +			     int *eof, void *data)  { -	unsigned long info = get_zeroed_page (GFP_KERNEL); +	unsigned long info = get_zeroed_page(GFP_KERNEL);  	int level, len; -	 +  	if (!info)  		return 0; @@ -262,8 +224,8 @@ static int proc_read_sysinfo(char *page, char **start,  	if (level >= 3)  		len = stsi_3_2_2((struct sysinfo_3_2_2 *) info, page, len); -	free_page (info); -        return len; +	free_page(info); +	return len;  }  static __init int create_proc_sysinfo(void) @@ -272,8 +234,7 @@ static __init int create_proc_sysinfo(void)  			       proc_read_sysinfo, NULL);  	return 0;  } - -__initcall(create_proc_sysinfo); +device_initcall(create_proc_sysinfo);  /*   * Service levels interface. @@ -387,13 +348,11 @@ static __init int create_proc_service_level(void)  		register_service_level(&service_level_vm);  	return 0;  } -  subsys_initcall(create_proc_service_level);  /*   * Bogomips calculation based on cpu capability.   */ -  int get_cpu_capability(unsigned int *capability)  {  	struct sysinfo_1_2_2 *info; diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index fc468cae4460..f72d41068dc2 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -331,6 +331,7 @@ static unsigned long long adjust_time(unsigned long long old,  }  static DEFINE_PER_CPU(atomic_t, clock_sync_word); +static DEFINE_MUTEX(clock_sync_mutex);  static unsigned long clock_sync_flags;  #define CLOCK_SYNC_HAS_ETR	0 @@ -394,6 +395,20 @@ static void enable_sync_clock(void)  	atomic_set_mask(0x80000000, sw_ptr);  } +/* + * Function to check if the clock is in sync. + */ +static inline int check_sync_clock(void) +{ +	atomic_t *sw_ptr; +	int rc; + +	sw_ptr = &get_cpu_var(clock_sync_word); +	rc = (atomic_read(sw_ptr) & 0x80000000U) != 0; +	put_cpu_var(clock_sync_sync); +	return rc; +} +  /* Single threaded workqueue used for etr and stp sync events */  static struct workqueue_struct *time_sync_wq; @@ -485,6 +500,8 @@ static void etr_reset(void)  	if (etr_setr(&etr_eacr) == 0) {  		etr_tolec = get_clock();  		set_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags); +		if (etr_port0_online && etr_port1_online) +			set_bit(CLOCK_SYNC_ETR, &clock_sync_flags);  	} else if (etr_port0_online || etr_port1_online) {  		pr_warning("The real or virtual hardware system does "  			   "not provide an ETR interface\n"); @@ -533,8 +550,7 @@ void etr_switch_to_local(void)  {  	if (!etr_eacr.sl)  		return; -	if (test_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) -		disable_sync_clock(NULL); +	disable_sync_clock(NULL);  	set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events);  	queue_work(time_sync_wq, &etr_work);  } @@ -549,8 +565,7 @@ void etr_sync_check(void)  {  	if (!etr_eacr.es)  		return; -	if (test_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) -		disable_sync_clock(NULL); +	disable_sync_clock(NULL);  	set_bit(ETR_EVENT_SYNC_CHECK, &etr_events);  	queue_work(time_sync_wq, &etr_work);  } @@ -914,7 +929,7 @@ static struct etr_eacr etr_handle_update(struct etr_aib *aib,  	 * Do not try to get the alternate port aib if the clock  	 * is not in sync yet.  	 */ -	if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags) && !eacr.es) +	if (!check_sync_clock())  		return eacr;  	/* @@ -997,7 +1012,6 @@ static void etr_work_fn(struct work_struct *work)  		on_each_cpu(disable_sync_clock, NULL, 1);  		del_timer_sync(&etr_timer);  		etr_update_eacr(eacr); -		clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags);  		goto out_unlock;  	} @@ -1071,18 +1085,13 @@ static void etr_work_fn(struct work_struct *work)  		/* Both ports not usable. */  		eacr.es = eacr.sl = 0;  		sync_port = -1; -		clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags);  	} -	if (!test_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) -		eacr.es = 0; -  	/*  	 * If the clock is in sync just update the eacr and return.  	 * If there is no valid sync port wait for a port update.  	 */ -	if (test_bit(CLOCK_SYNC_STP, &clock_sync_flags) || -	    eacr.es || sync_port < 0) { +	if (check_sync_clock() || sync_port < 0) {  		etr_update_eacr(eacr);  		etr_set_tolec_timeout(now);  		goto out_unlock; @@ -1103,13 +1112,11 @@ static void etr_work_fn(struct work_struct *work)  	 * and set up a timer to try again after 0.5 seconds  	 */  	etr_update_eacr(eacr); -	set_bit(CLOCK_SYNC_ETR, &clock_sync_flags);  	if (now < etr_tolec + (1600000 << 12) ||  	    etr_sync_clock_stop(&aib, sync_port) != 0) {  		/* Sync failed. Try again in 1/2 second. */  		eacr.es = 0;  		etr_update_eacr(eacr); -		clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags);  		etr_set_sync_timeout();  	} else  		etr_set_tolec_timeout(now); @@ -1191,19 +1198,30 @@ static ssize_t etr_online_store(struct sys_device *dev,  		return -EINVAL;  	if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags))  		return -EOPNOTSUPP; +	mutex_lock(&clock_sync_mutex);  	if (dev == &etr_port0_dev) {  		if (etr_port0_online == value) -			return count;	/* Nothing to do. */ +			goto out;	/* Nothing to do. */  		etr_port0_online = value; +		if (etr_port0_online && etr_port1_online) +			set_bit(CLOCK_SYNC_ETR, &clock_sync_flags); +		else +			clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags);  		set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);  		queue_work(time_sync_wq, &etr_work);  	} else {  		if (etr_port1_online == value) -			return count;	/* Nothing to do. */ +			goto out;	/* Nothing to do. */  		etr_port1_online = value; +		if (etr_port0_online && etr_port1_online) +			set_bit(CLOCK_SYNC_ETR, &clock_sync_flags); +		else +			clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags);  		set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);  		queue_work(time_sync_wq, &etr_work);  	} +out: +	mutex_unlock(&clock_sync_mutex);  	return count;  } @@ -1471,8 +1489,6 @@ static void stp_timing_alert(struct stp_irq_parm *intparm)   */  void stp_sync_check(void)  { -	if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags)) -		return;  	disable_sync_clock(NULL);  	queue_work(time_sync_wq, &stp_work);  } @@ -1485,8 +1501,6 @@ void stp_sync_check(void)   */  void stp_island_check(void)  { -	if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags)) -		return;  	disable_sync_clock(NULL);  	queue_work(time_sync_wq, &stp_work);  } @@ -1513,10 +1527,6 @@ static int stp_sync_clock(void *data)  	enable_sync_clock(); -	set_bit(CLOCK_SYNC_STP, &clock_sync_flags); -	if (test_and_clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) -		queue_work(time_sync_wq, &etr_work); -  	rc = 0;  	if (stp_info.todoff[0] || stp_info.todoff[1] ||  	    stp_info.todoff[2] || stp_info.todoff[3] || @@ -1535,9 +1545,6 @@ static int stp_sync_clock(void *data)  	if (rc) {  		disable_sync_clock(NULL);  		stp_sync->in_sync = -EAGAIN; -		clear_bit(CLOCK_SYNC_STP, &clock_sync_flags); -		if (etr_port0_online || etr_port1_online) -			queue_work(time_sync_wq, &etr_work);  	} else  		stp_sync->in_sync = 1;  	xchg(&first, 0); @@ -1569,6 +1576,10 @@ static void stp_work_fn(struct work_struct *work)  	if (rc || stp_info.c == 0)  		goto out_unlock; +	/* Skip synchronization if the clock is already in sync. */ +	if (check_sync_clock()) +		goto out_unlock; +  	memset(&stp_sync, 0, sizeof(stp_sync));  	get_online_cpus();  	atomic_set(&stp_sync.cpus, num_online_cpus() - 1); @@ -1684,8 +1695,14 @@ static ssize_t stp_online_store(struct sysdev_class *class,  		return -EINVAL;  	if (!test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags))  		return -EOPNOTSUPP; +	mutex_lock(&clock_sync_mutex);  	stp_online = value; +	if (stp_online) +		set_bit(CLOCK_SYNC_STP, &clock_sync_flags); +	else +		clear_bit(CLOCK_SYNC_STP, &clock_sync_flags);  	queue_work(time_sync_wq, &stp_work); +	mutex_unlock(&clock_sync_mutex);  	return count;  } diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index cc362c9ea8f1..3c72c9cf22b6 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -74,7 +74,7 @@ static DEFINE_SPINLOCK(topology_lock);  cpumask_t cpu_core_map[NR_CPUS]; -cpumask_t cpu_coregroup_map(unsigned int cpu) +static cpumask_t cpu_coregroup_map(unsigned int cpu)  {  	struct core_info *core = &core_info;  	unsigned long flags; diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 4584d81984c0..c2e42cc65ce7 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -61,9 +61,11 @@ extern pgm_check_handler_t do_asce_exception;  #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; })  #ifndef CONFIG_64BIT +#define LONG "%08lx "  #define FOURLONG "%08lx %08lx %08lx %08lx\n"  static int kstack_depth_to_print = 12;  #else /* CONFIG_64BIT */ +#define LONG "%016lx "  #define FOURLONG "%016lx %016lx %016lx %016lx\n"  static int kstack_depth_to_print = 20;  #endif /* CONFIG_64BIT */ @@ -155,7 +157,7 @@ void show_stack(struct task_struct *task, unsigned long *sp)  			break;  		if (i && ((i * sizeof (long) % 32) == 0))  			printk("\n       "); -		printk("%p ", (void *)*stack++); +		printk(LONG, *stack++);  	}  	printk("\n");  	show_trace(task, sp); diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c index 690e17819686..89b2e7f1b7a9 100644 --- a/arch/s390/kernel/vdso.c +++ b/arch/s390/kernel/vdso.c @@ -144,7 +144,6 @@ out:  	return -ENOMEM;  } -#ifdef CONFIG_HOTPLUG_CPU  void vdso_free_per_cpu(int cpu, struct _lowcore *lowcore)  {  	unsigned long segment_table, page_table, page_frame; @@ -163,7 +162,6 @@ void vdso_free_per_cpu(int cpu, struct _lowcore *lowcore)  	free_page(page_table);  	free_pages(segment_table, SEGMENT_ORDER);  } -#endif /* CONFIG_HOTPLUG_CPU */  static void __vdso_init_cr5(void *dummy)  { diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index d796d05c9c01..7a2063eb88f0 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -108,6 +108,8 @@ SECTIONS  		EXIT_TEXT  	} +	/* early.c uses stsi, which requires page aligned data. */ +	. = ALIGN(PAGE_SIZE);  	.init.data : {  		INIT_DATA  	} diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index cbfe91e10120..f4d56e9939c9 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -23,7 +23,7 @@  #include <linux/timer.h>  #include <asm/lowcore.h>  #include <asm/pgtable.h> - +#include <asm/nmi.h>  #include "kvm-s390.h"  #include "gaccess.h" @@ -286,7 +286,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)  	setup_timer(&vcpu->arch.ckc_timer, kvm_s390_idle_wakeup,  		 (unsigned long) vcpu);  	get_cpu_id(&vcpu->arch.cpu_id); -	vcpu->arch.cpu_id.version = 0xfe; +	vcpu->arch.cpu_id.version = 0xff;  	return 0;  } @@ -440,8 +440,6 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,  	return -EINVAL; /* not implemented yet */  } -extern void s390_handle_mcck(void); -  static void __vcpu_run(struct kvm_vcpu *vcpu)  {  	memcpy(&vcpu->arch.sie_block->gg14, &vcpu->arch.guest_gprs[14], 16); diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index 6ccb9fab055a..3f5f680726ed 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c @@ -9,6 +9,7 @@  #include <linux/sched.h>  #include <linux/delay.h>  #include <linux/timex.h> +#include <linux/module.h>  #include <linux/irqflags.h>  #include <linux/interrupt.h> @@ -92,6 +93,7 @@ out:  	local_irq_restore(flags);  	preempt_enable();  } +EXPORT_SYMBOL(__udelay);  /*   * Simple udelay variant. To be used on startup and reboot diff --git a/arch/s390/lib/string.c b/arch/s390/lib/string.c index ae5cf5d03d41..4143b7c19096 100644 --- a/arch/s390/lib/string.c +++ b/arch/s390/lib/string.c @@ -44,7 +44,11 @@ static inline char *__strnend(const char *s, size_t n)   */  size_t strlen(const char *s)  { +#if __GNUC__ < 4  	return __strend(s) - s; +#else +	return __builtin_strlen(s); +#endif  }  EXPORT_SYMBOL(strlen); @@ -70,6 +74,7 @@ EXPORT_SYMBOL(strnlen);   */  char *strcpy(char *dest, const char *src)  { +#if __GNUC__ < 4  	register int r0 asm("0") = 0;  	char *ret = dest; @@ -78,6 +83,9 @@ char *strcpy(char *dest, const char *src)  		      : "+&a" (dest), "+&a" (src) : "d" (r0)  		      : "cc", "memory" );  	return ret; +#else +	return __builtin_strcpy(dest, src); +#endif  }  EXPORT_SYMBOL(strcpy); diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 4d537205e83c..833e8366c351 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -200,29 +200,6 @@ static void do_low_address(struct pt_regs *regs, unsigned long error_code)  	do_no_context(regs, error_code, 0);  } -/* - * We ran out of memory, or some other thing happened to us that made - * us unable to handle the page fault gracefully. - */ -static int do_out_of_memory(struct pt_regs *regs, unsigned long error_code, -			    unsigned long address) -{ -	struct task_struct *tsk = current; -	struct mm_struct *mm = tsk->mm; - -	up_read(&mm->mmap_sem); -	if (is_global_init(tsk)) { -		yield(); -		down_read(&mm->mmap_sem); -		return 1; -	} -	printk("VM: killing process %s\n", tsk->comm); -	if (regs->psw.mask & PSW_MASK_PSTATE) -		do_group_exit(SIGKILL); -	do_no_context(regs, error_code, address); -	return 0; -} -  static void do_sigbus(struct pt_regs *regs, unsigned long error_code,  		      unsigned long address)  { @@ -367,7 +344,6 @@ good_area:  			goto bad_area;  	} -survive:  	if (is_vm_hugetlb_page(vma))  		address &= HPAGE_MASK;  	/* @@ -378,8 +354,8 @@ survive:  	fault = handle_mm_fault(mm, vma, address, write);  	if (unlikely(fault & VM_FAULT_ERROR)) {  		if (fault & VM_FAULT_OOM) { -			if (do_out_of_memory(regs, error_code, address)) -				goto survive; +			up_read(&mm->mmap_sem); +			pagefault_out_of_memory();  			return;  		} else if (fault & VM_FAULT_SIGBUS) {  			do_sigbus(regs, error_code, address); diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index f0258ca3b17e..c634dfbe92e9 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -40,7 +40,9 @@  DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);  pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE))); +  char  empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); +EXPORT_SYMBOL(empty_zero_page);  /*   * paging_init() sets up the page tables diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 6b6ddc4ea02b..be6c1cf4ad5a 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -258,6 +258,10 @@ int s390_enable_sie(void)  	struct task_struct *tsk = current;  	struct mm_struct *mm, *old_mm; +	/* Do we have switched amode? If no, we cannot do sie */ +	if (!switch_amode) +		return -EINVAL; +  	/* Do we have pgstes? if yes, we are done */  	if (tsk->mm->context.has_pgste)  		return 0; @@ -292,7 +296,7 @@ int s390_enable_sie(void)  	tsk->mm = tsk->active_mm = mm;  	preempt_disable();  	update_mm(mm, tsk); -	cpu_set(smp_processor_id(), mm->cpu_vm_mask); +	cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));  	preempt_enable();  	task_unlock(tsk);  	mmput(old_mm); diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c index a53496828b76..54481a887769 100644 --- a/drivers/char/hvc_iucv.c +++ b/drivers/char/hvc_iucv.c @@ -13,10 +13,11 @@  #include <linux/types.h>  #include <asm/ebcdic.h> +#include <linux/ctype.h>  #include <linux/delay.h>  #include <linux/init.h>  #include <linux/mempool.h> -#include <linux/module.h> +#include <linux/moduleparam.h>  #include <linux/tty.h>  #include <linux/wait.h>  #include <net/iucv/iucv.h> @@ -95,6 +96,12 @@ static unsigned long hvc_iucv_devices = 1;  /* Array of allocated hvc iucv tty lines... */  static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES];  #define IUCV_HVC_CON_IDX	(0) +/* List of z/VM user ID filter entries (struct iucv_vmid_filter) */ +#define MAX_VMID_FILTER		(500) +static size_t hvc_iucv_filter_size; +static void *hvc_iucv_filter; +static const char *hvc_iucv_filter_string; +static DEFINE_RWLOCK(hvc_iucv_filter_lock);  /* Kmem cache and mempool for iucv_tty_buffer elements */  static struct kmem_cache *hvc_iucv_buffer_cache; @@ -618,6 +625,27 @@ static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id)  }  /** + * hvc_iucv_filter_connreq() - Filter connection request based on z/VM user ID + * @ipvmid:	Originating z/VM user ID (right padded with blanks) + * + * Returns 0 if the z/VM user ID @ipvmid is allowed to connection, otherwise + * non-zero. + */ +static int hvc_iucv_filter_connreq(u8 ipvmid[8]) +{ +	size_t i; + +	/* Note: default policy is ACCEPT if no filter is set */ +	if (!hvc_iucv_filter_size) +		return 0; + +	for (i = 0; i < hvc_iucv_filter_size; i++) +		if (0 == memcmp(ipvmid, hvc_iucv_filter + (8 * i), 8)) +			return 0; +	return 1; +} + +/**   * hvc_iucv_path_pending() - IUCV handler to process a connection request.   * @path:	Pending path (struct iucv_path)   * @ipvmid:	z/VM system identifier of originator @@ -641,6 +669,7 @@ static	int hvc_iucv_path_pending(struct iucv_path *path,  {  	struct hvc_iucv_private *priv;  	u8 nuser_data[16]; +	u8 vm_user_id[9];  	int i, rc;  	priv = NULL; @@ -653,6 +682,20 @@ static	int hvc_iucv_path_pending(struct iucv_path *path,  	if (!priv)  		return -ENODEV; +	/* Enforce that ipvmid is allowed to connect to us */ +	read_lock(&hvc_iucv_filter_lock); +	rc = hvc_iucv_filter_connreq(ipvmid); +	read_unlock(&hvc_iucv_filter_lock); +	if (rc) { +		iucv_path_sever(path, ipuser); +		iucv_path_free(path); +		memcpy(vm_user_id, ipvmid, 8); +		vm_user_id[8] = 0; +		pr_info("A connection request from z/VM user ID %s " +			"was refused\n", vm_user_id); +		return 0; +	} +  	spin_lock(&priv->lock);  	/* If the terminal is already connected or being severed, then sever @@ -877,6 +920,171 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console)  }  /** + * hvc_iucv_parse_filter() - Parse filter for a single z/VM user ID + * @filter:	String containing a comma-separated list of z/VM user IDs + */ +static const char *hvc_iucv_parse_filter(const char *filter, char *dest) +{ +	const char *nextdelim, *residual; +	size_t len; + +	nextdelim = strchr(filter, ','); +	if (nextdelim) { +		len = nextdelim - filter; +		residual = nextdelim + 1; +	} else { +		len = strlen(filter); +		residual = filter + len; +	} + +	if (len == 0) +		return ERR_PTR(-EINVAL); + +	/* check for '\n' (if called from sysfs) */ +	if (filter[len - 1] == '\n') +		len--; + +	if (len > 8) +		return ERR_PTR(-EINVAL); + +	/* pad with blanks and save upper case version of user ID */ +	memset(dest, ' ', 8); +	while (len--) +		dest[len] = toupper(filter[len]); +	return residual; +} + +/** + * hvc_iucv_setup_filter() - Set up z/VM user ID filter + * @filter:	String consisting of a comma-separated list of z/VM user IDs + * + * The function parses the @filter string and creates an array containing + * the list of z/VM user ID filter entries. + * Return code 0 means success, -EINVAL if the filter is syntactically + * incorrect, -ENOMEM if there was not enough memory to allocate the + * filter list array, or -ENOSPC if too many z/VM user IDs have been specified. + */ +static int hvc_iucv_setup_filter(const char *val) +{ +	const char *residual; +	int err; +	size_t size, count; +	void *array, *old_filter; + +	count = strlen(val); +	if (count == 0 || (count == 1 && val[0] == '\n')) { +		size  = 0; +		array = NULL; +		goto out_replace_filter;	/* clear filter */ +	} + +	/* count user IDs in order to allocate sufficient memory */ +	size = 1; +	residual = val; +	while ((residual = strchr(residual, ',')) != NULL) { +		residual++; +		size++; +	} + +	/* check if the specified list exceeds the filter limit */ +	if (size > MAX_VMID_FILTER) +		return -ENOSPC; + +	array = kzalloc(size * 8, GFP_KERNEL); +	if (!array) +		return -ENOMEM; + +	count = size; +	residual = val; +	while (*residual && count) { +		residual = hvc_iucv_parse_filter(residual, +						 array + ((size - count) * 8)); +		if (IS_ERR(residual)) { +			err = PTR_ERR(residual); +			kfree(array); +			goto out_err; +		} +		count--; +	} + +out_replace_filter: +	write_lock_bh(&hvc_iucv_filter_lock); +	old_filter = hvc_iucv_filter; +	hvc_iucv_filter_size = size; +	hvc_iucv_filter = array; +	write_unlock_bh(&hvc_iucv_filter_lock); +	kfree(old_filter); + +	err = 0; +out_err: +	return err; +} + +/** + * param_set_vmidfilter() - Set z/VM user ID filter parameter + * @val:	String consisting of a comma-separated list of z/VM user IDs + * @kp:		Kernel parameter pointing to hvc_iucv_filter array + * + * The function sets up the z/VM user ID filter specified as comma-separated + * list of user IDs in @val. + * Note: If it is called early in the boot process, @val is stored and + *	 parsed later in hvc_iucv_init(). + */ +static int param_set_vmidfilter(const char *val, struct kernel_param *kp) +{ +	int rc; + +	if (!MACHINE_IS_VM || !hvc_iucv_devices) +		return -ENODEV; + +	if (!val) +		return -EINVAL; + +	rc = 0; +	if (slab_is_available()) +		rc = hvc_iucv_setup_filter(val); +	else +		hvc_iucv_filter_string = val;	/* defer... */ +	return rc; +} + +/** + * param_get_vmidfilter() - Get z/VM user ID filter + * @buffer:	Buffer to store z/VM user ID filter, + *		(buffer size assumption PAGE_SIZE) + * @kp:		Kernel parameter pointing to the hvc_iucv_filter array + * + * The function stores the filter as a comma-separated list of z/VM user IDs + * in @buffer. Typically, sysfs routines call this function for attr show. + */ +static int param_get_vmidfilter(char *buffer, struct kernel_param *kp) +{ +	int rc; +	size_t index, len; +	void *start, *end; + +	if (!MACHINE_IS_VM || !hvc_iucv_devices) +		return -ENODEV; + +	rc = 0; +	read_lock_bh(&hvc_iucv_filter_lock); +	for (index = 0; index < hvc_iucv_filter_size; index++) { +		start = hvc_iucv_filter + (8 * index); +		end   = memchr(start, ' ', 8); +		len   = (end) ? end - start : 8; +		memcpy(buffer + rc, start, len); +		rc += len; +		buffer[rc++] = ','; +	} +	read_unlock_bh(&hvc_iucv_filter_lock); +	if (rc) +		buffer[--rc] = '\0';	/* replace last comma and update rc */ +	return rc; +} + +#define param_check_vmidfilter(name, p) __param_check(name, p, void) + +/**   * hvc_iucv_init() - z/VM IUCV HVC device driver initialization   */  static int __init hvc_iucv_init(void) @@ -884,24 +1092,53 @@ static int __init hvc_iucv_init(void)  	int rc;  	unsigned int i; +	if (!hvc_iucv_devices) +		return -ENODEV; +  	if (!MACHINE_IS_VM) { -		pr_info("The z/VM IUCV HVC device driver cannot " +		pr_notice("The z/VM IUCV HVC device driver cannot "  			   "be used without z/VM\n"); -		return -ENODEV; +		rc = -ENODEV; +		goto out_error;  	} -	if (!hvc_iucv_devices) -		return -ENODEV; +	if (hvc_iucv_devices > MAX_HVC_IUCV_LINES) { +		pr_err("%lu is not a valid value for the hvc_iucv= " +			"kernel parameter\n", hvc_iucv_devices); +		rc = -EINVAL; +		goto out_error; +	} -	if (hvc_iucv_devices > MAX_HVC_IUCV_LINES) -		return -EINVAL; +	/* parse hvc_iucv_allow string and create z/VM user ID filter list */ +	if (hvc_iucv_filter_string) { +		rc = hvc_iucv_setup_filter(hvc_iucv_filter_string); +		switch (rc) { +		case 0: +			break; +		case -ENOMEM: +			pr_err("Allocating memory failed with " +				"reason code=%d\n", 3); +			goto out_error; +		case -EINVAL: +			pr_err("hvc_iucv_allow= does not specify a valid " +				"z/VM user ID list\n"); +			goto out_error; +		case -ENOSPC: +			pr_err("hvc_iucv_allow= specifies too many " +				"z/VM user IDs\n"); +			goto out_error; +		default: +			goto out_error; +		} +	}  	hvc_iucv_buffer_cache = kmem_cache_create(KMSG_COMPONENT,  					   sizeof(struct iucv_tty_buffer),  					   0, 0, NULL);  	if (!hvc_iucv_buffer_cache) {  		pr_err("Allocating memory failed with reason code=%d\n", 1); -		return -ENOMEM; +		rc = -ENOMEM; +		goto out_error;  	}  	hvc_iucv_mempool = mempool_create_slab_pool(MEMPOOL_MIN_NR, @@ -909,7 +1146,8 @@ static int __init hvc_iucv_init(void)  	if (!hvc_iucv_mempool) {  		pr_err("Allocating memory failed with reason code=%d\n", 2);  		kmem_cache_destroy(hvc_iucv_buffer_cache); -		return -ENOMEM; +		rc = -ENOMEM; +		goto out_error;  	}  	/* register the first terminal device as console @@ -953,6 +1191,8 @@ out_error_hvc:  out_error_memory:  	mempool_destroy(hvc_iucv_mempool);  	kmem_cache_destroy(hvc_iucv_buffer_cache); +out_error: +	hvc_iucv_devices = 0; /* ensure that we do not provide any device */  	return rc;  } @@ -968,3 +1208,4 @@ static	int __init hvc_iucv_config(char *val)  device_initcall(hvc_iucv_init);  __setup("hvc_iucv=", hvc_iucv_config); +core_param(hvc_iucv_allow, hvc_iucv_filter, vmidfilter, 0640); diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile index d0eae59bc366..95bccfd3f169 100644 --- a/drivers/s390/Makefile +++ b/drivers/s390/Makefile @@ -2,9 +2,6 @@  # Makefile for the S/390 specific device drivers  # -CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w - -obj-y += s390mach.o sysinfo.o  obj-y += cio/ block/ char/ crypto/ net/ scsi/ kvm/  drivers-y += drivers/s390/built-in.o diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 08c23a921012..2fd64e5a9ab2 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -9,6 +9,9 @@   *   */ +#define KMSG_COMPONENT "dasd" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +  #include <linux/kmod.h>  #include <linux/init.h>  #include <linux/interrupt.h> @@ -22,6 +25,7 @@  #include <asm/ebcdic.h>  #include <asm/idals.h>  #include <asm/todclk.h> +#include <asm/itcw.h>  /* This is ugly... */  #define PRINTK_HEADER "dasd:" @@ -221,7 +225,7 @@ static int dasd_state_known_to_basic(struct dasd_device *device)  			return rc;  	}  	/* register 'device' debug area, used for all DBF_DEV_XXX calls */ -	device->debug_area = debug_register(dev_name(&device->cdev->dev), 1, 1, +	device->debug_area = debug_register(dev_name(&device->cdev->dev), 4, 1,  					    8 * sizeof(long));  	debug_register_view(device->debug_area, &debug_sprintf_view);  	debug_set_level(device->debug_area, DBF_WARNING); @@ -762,7 +766,7 @@ static inline int dasd_check_cqr(struct dasd_ccw_req *cqr)  		return -EINVAL;  	device = cqr->startdev;  	if (strncmp((char *) &cqr->magic, device->discipline->ebcname, 4)) { -		DEV_MESSAGE(KERN_WARNING, device, +		DBF_DEV_EVENT(DBF_WARNING, device,  			    " dasd_ccw_req 0x%08x magic doesn't match"  			    " discipline 0x%08x",  			    cqr->magic, @@ -782,6 +786,7 @@ int dasd_term_IO(struct dasd_ccw_req *cqr)  {  	struct dasd_device *device;  	int retries, rc; +	char errorstring[ERRORLENGTH];  	/* Check the cqr */  	rc = dasd_check_cqr(cqr); @@ -815,10 +820,10 @@ int dasd_term_IO(struct dasd_ccw_req *cqr)  				      "device busy, retry later");  			break;  		default: -			DEV_MESSAGE(KERN_ERR, device, -				    "line %d unknown RC=%d, please " -				    "report to linux390@de.ibm.com", -				    __LINE__, rc); +			/* internal error 10 - unknown rc*/ +			snprintf(errorstring, ERRORLENGTH, "10 %d", rc); +			dev_err(&device->cdev->dev, "An error occurred in the " +				"DASD device driver, reason=%s\n", errorstring);  			BUG();  			break;  		} @@ -836,6 +841,7 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)  {  	struct dasd_device *device;  	int rc; +	char errorstring[ERRORLENGTH];  	/* Check the cqr */  	rc = dasd_check_cqr(cqr); @@ -843,17 +849,23 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)  		return rc;  	device = (struct dasd_device *) cqr->startdev;  	if (cqr->retries < 0) { -		DEV_MESSAGE(KERN_DEBUG, device, -			    "start_IO: request %p (%02x/%i) - no retry left.", -			    cqr, cqr->status, cqr->retries); +		/* internal error 14 - start_IO run out of retries */ +		sprintf(errorstring, "14 %p", cqr); +		dev_err(&device->cdev->dev, "An error occurred in the DASD " +			"device driver, reason=%s\n", errorstring);  		cqr->status = DASD_CQR_ERROR;  		return -EIO;  	}  	cqr->startclk = get_clock();  	cqr->starttime = jiffies;  	cqr->retries--; -	rc = ccw_device_start(device->cdev, cqr->cpaddr, (long) cqr, -			      cqr->lpm, 0); +	if (cqr->cpmode == 1) { +		rc = ccw_device_tm_start(device->cdev, cqr->cpaddr, +					 (long) cqr, cqr->lpm); +	} else { +		rc = ccw_device_start(device->cdev, cqr->cpaddr, +				      (long) cqr, cqr->lpm, 0); +	}  	switch (rc) {  	case 0:  		cqr->status = DASD_CQR_IN_IO; @@ -862,11 +874,11 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)  			      cqr);  		break;  	case -EBUSY: -		DBF_DEV_EVENT(DBF_ERR, device, "%s", +		DBF_DEV_EVENT(DBF_DEBUG, device, "%s",  			      "start_IO: device busy, retry later");  		break;  	case -ETIMEDOUT: -		DBF_DEV_EVENT(DBF_ERR, device, "%s", +		DBF_DEV_EVENT(DBF_DEBUG, device, "%s",  			      "start_IO: request timeout, retry later");  		break;  	case -EACCES: @@ -876,19 +888,24 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)  		 * Do a retry with all available pathes.  		 */  		cqr->lpm = LPM_ANYPATH; -		DBF_DEV_EVENT(DBF_ERR, device, "%s", +		DBF_DEV_EVENT(DBF_DEBUG, device, "%s",  			      "start_IO: selected pathes gone,"  			      " retry on all pathes");  		break;  	case -ENODEV: +		DBF_DEV_EVENT(DBF_DEBUG, device, "%s", +			      "start_IO: -ENODEV device gone, retry"); +		break;  	case -EIO: -		DBF_DEV_EVENT(DBF_ERR, device, "%s", -			      "start_IO: device gone, retry"); +		DBF_DEV_EVENT(DBF_DEBUG, device, "%s", +			      "start_IO: -EIO device gone, retry");  		break;  	default: -		DEV_MESSAGE(KERN_ERR, device, -			    "line %d unknown RC=%d, please report" -			    " to linux390@de.ibm.com", __LINE__, rc); +		/* internal error 11 - unknown rc */ +		snprintf(errorstring, ERRORLENGTH, "11 %d", rc); +		dev_err(&device->cdev->dev, +			"An error occurred in the DASD device driver, " +			"reason=%s\n", errorstring);  		BUG();  		break;  	} @@ -945,7 +962,7 @@ static void dasd_handle_killed_request(struct ccw_device *cdev,  		return;  	cqr = (struct dasd_ccw_req *) intparm;  	if (cqr->status != DASD_CQR_IN_IO) { -		MESSAGE(KERN_DEBUG, +		DBF_EVENT(DBF_DEBUG,  			"invalid status in handle_killed_request: "  			"bus_id %s, status %02x",  			dev_name(&cdev->dev), cqr->status); @@ -956,8 +973,8 @@ static void dasd_handle_killed_request(struct ccw_device *cdev,  	if (device == NULL ||  	    device != dasd_device_from_cdev_locked(cdev) ||  	    strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { -		MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s", -			dev_name(&cdev->dev)); +		DBF_DEV_EVENT(DBF_DEBUG, device, "invalid device in request: " +			      "bus_id %s", dev_name(&cdev->dev));  		return;  	} @@ -996,11 +1013,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,  		case -EIO:  			break;  		case -ETIMEDOUT: -			printk(KERN_WARNING"%s(%s): request timed out\n", +			DBF_EVENT(DBF_WARNING, "%s(%s): request timed out\n",  			       __func__, dev_name(&cdev->dev));  			break;  		default: -			printk(KERN_WARNING"%s(%s): unknown error %ld\n", +			DBF_EVENT(DBF_WARNING, "%s(%s): unknown error %ld\n",  			       __func__, dev_name(&cdev->dev), PTR_ERR(irb));  		}  		dasd_handle_killed_request(cdev, intparm); @@ -1009,15 +1026,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,  	now = get_clock(); -	DBF_EVENT(DBF_ERR, "Interrupt: bus_id %s CS/DS %04x ip %08x", -		  dev_name(&cdev->dev), ((irb->scsw.cmd.cstat << 8) | -		  irb->scsw.cmd.dstat), (unsigned int) intparm); -  	/* check for unsolicited interrupts */  	cqr = (struct dasd_ccw_req *) intparm; -	if (!cqr || ((irb->scsw.cmd.cc == 1) && -		     (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) && -		     (irb->scsw.cmd.stctl & SCSW_STCTL_STATUS_PEND))) { +	if (!cqr || ((scsw_cc(&irb->scsw) == 1) && +		     (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) && +		     (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND))) {  		if (cqr && cqr->status == DASD_CQR_IN_IO)  			cqr->status = DASD_CQR_QUEUED;  		device = dasd_device_from_cdev_locked(cdev); @@ -1033,14 +1046,14 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,  	device = (struct dasd_device *) cqr->startdev;  	if (!device ||  	    strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { -		MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s", -			dev_name(&cdev->dev)); +		DBF_DEV_EVENT(DBF_DEBUG, device, "invalid device in request: " +			      "bus_id %s", dev_name(&cdev->dev));  		return;  	}  	/* Check for clear pending */  	if (cqr->status == DASD_CQR_CLEAR_PENDING && -	    irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC) { +	    scsw_fctl(&irb->scsw) & SCSW_FCTL_CLEAR_FUNC) {  		cqr->status = DASD_CQR_CLEARED;  		dasd_device_clear_timer(device);  		wake_up(&dasd_flush_wq); @@ -1048,19 +1061,17 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,  		return;  	} - 	/* check status - the request might have been killed by dyn detach */ +	/* check status - the request might have been killed by dyn detach */  	if (cqr->status != DASD_CQR_IN_IO) { -		MESSAGE(KERN_DEBUG, -			"invalid status: bus_id %s, status %02x", -			dev_name(&cdev->dev), cqr->status); +		DBF_DEV_EVENT(DBF_DEBUG, device, "invalid status: bus_id %s, " +			      "status %02x", dev_name(&cdev->dev), cqr->status);  		return;  	} -	DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p", -		      ((irb->scsw.cmd.cstat << 8) | irb->scsw.cmd.dstat), cqr); +  	next = NULL;  	expires = 0; -	if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && -	    irb->scsw.cmd.cstat == 0 && !irb->esw.esw0.erw.cons) { +	if (scsw_dstat(&irb->scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && +	    scsw_cstat(&irb->scsw) == 0) {  		/* request was completed successfully */  		cqr->status = DASD_CQR_SUCCESS;  		cqr->stopclk = now; @@ -1071,18 +1082,23 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,  		}  	} else {  /* error */  		memcpy(&cqr->irb, irb, sizeof(struct irb)); +		/* log sense for every failed I/O to s390 debugfeature */ +		dasd_log_sense_dbf(cqr, irb);  		if (device->features & DASD_FEATURE_ERPLOG) {  			dasd_log_sense(cqr, irb);  		} +  		/*  		 * If we don't want complex ERP for this request, then just  		 * reset this and retry it in the fastpath  		 */  		if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) &&  		    cqr->retries > 0) { -			DEV_MESSAGE(KERN_DEBUG, device, -				    "default ERP in fastpath (%i retries left)", -				    cqr->retries); +			if (cqr->lpm == LPM_ANYPATH) +				DBF_DEV_EVENT(DBF_DEBUG, device, +					      "default ERP in fastpath " +					      "(%i retries left)", +					      cqr->retries);  			cqr->lpm    = LPM_ANYPATH;  			cqr->status = DASD_CQR_QUEUED;  			next = cqr; @@ -1093,10 +1109,6 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,  	    (!device->stopped)) {  		if (device->discipline->start_IO(next) == 0)  			expires = next->expires; -		else -			DEV_MESSAGE(KERN_DEBUG, device, "%s", -				    "Interrupt fastpath " -				    "failed!");  	}  	if (expires != 0)  		dasd_device_set_timer(device, expires); @@ -1169,6 +1181,7 @@ static void __dasd_device_process_final_queue(struct dasd_device *device,  	struct dasd_block *block;  	void (*callback)(struct dasd_ccw_req *, void *data);  	void *callback_data; +	char errorstring[ERRORLENGTH];  	list_for_each_safe(l, n, final_queue) {  		cqr = list_entry(l, struct dasd_ccw_req, devlist); @@ -1189,10 +1202,11 @@ static void __dasd_device_process_final_queue(struct dasd_device *device,  			cqr->status = DASD_CQR_TERMINATED;  			break;  		default: -			DEV_MESSAGE(KERN_ERR, device, -				    "wrong cqr status in __dasd_process_final_queue " -				    "for cqr %p, status %x", -				    cqr, cqr->status); +			/* internal error 12 - wrong cqr status*/ +			snprintf(errorstring, ERRORLENGTH, "12 %p %x02", cqr, cqr->status); +			dev_err(&device->cdev->dev, +				"An error occurred in the DASD device driver, " +				"reason=%s\n", errorstring);  			BUG();  		}  		if (cqr->callback != NULL) @@ -1217,18 +1231,17 @@ static void __dasd_device_check_expire(struct dasd_device *device)  	    (time_after_eq(jiffies, cqr->expires + cqr->starttime))) {  		if (device->discipline->term_IO(cqr) != 0) {  			/* Hmpf, try again in 5 sec */ -			DEV_MESSAGE(KERN_ERR, device, -				    "internal error - timeout (%is) expired " -				    "for cqr %p, termination failed, " -				    "retrying in 5s", -				    (cqr->expires/HZ), cqr); +			dev_err(&device->cdev->dev, +				"cqr %p timed out (%is) but cannot be " +				"ended, retrying in 5 s\n", +				cqr, (cqr->expires/HZ));  			cqr->expires += 5*HZ;  			dasd_device_set_timer(device, 5*HZ);  		} else { -			DEV_MESSAGE(KERN_ERR, device, -				    "internal error - timeout (%is) expired " -				    "for cqr %p (%i retries left)", -				    (cqr->expires/HZ), cqr, cqr->retries); +			dev_err(&device->cdev->dev, +				"cqr %p timed out (%is), %i retries " +				"remaining\n", cqr, (cqr->expires/HZ), +				cqr->retries);  		}  	}  } @@ -1290,10 +1303,9 @@ int dasd_flush_device_queue(struct dasd_device *device)  			rc = device->discipline->term_IO(cqr);  			if (rc) {  				/* unable to terminate requeust */ -				DEV_MESSAGE(KERN_ERR, device, -					    "dasd flush ccw_queue is unable " -					    " to terminate request %p", -					    cqr); +				dev_err(&device->cdev->dev, +					"Flushing the DASD request queue " +					"failed for request %p\n", cqr);  				/* stop flush processing */  				goto finished;  			} @@ -1537,10 +1549,9 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr)  		/* request in IO - terminate IO and release again */  		rc = device->discipline->term_IO(cqr);  		if (rc) { -			DEV_MESSAGE(KERN_ERR, device, -				    "dasd_cancel_req is unable " -				    " to terminate request %p, rc = %d", -				    cqr, rc); +			dev_err(&device->cdev->dev, +				"Cancelling request %p failed with rc=%d\n", +				cqr, rc);  		} else {  			cqr->stopclk = get_clock();  			rc = 1; @@ -1617,7 +1628,7 @@ static inline void __dasd_block_process_erp(struct dasd_block *block,  	if (cqr->status == DASD_CQR_DONE)  		DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful");  	else -		DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful"); +		dev_err(&device->cdev->dev, "ERP failed for the DASD\n");  	erp_fn = device->discipline->erp_postaction(cqr);  	erp_fn(cqr);  } @@ -1991,8 +2002,11 @@ static void dasd_setup_queue(struct dasd_block *block)  	blk_queue_max_sectors(block->request_queue, max);  	blk_queue_max_phys_segments(block->request_queue, -1L);  	blk_queue_max_hw_segments(block->request_queue, -1L); -	blk_queue_max_segment_size(block->request_queue, -1L); -	blk_queue_segment_boundary(block->request_queue, -1L); +	/* with page sized segments we can translate each segement into +	 * one idaw/tidaw +	 */ +	blk_queue_max_segment_size(block->request_queue, PAGE_SIZE); +	blk_queue_segment_boundary(block->request_queue, PAGE_SIZE - 1);  	blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN, NULL);  } @@ -2043,8 +2057,9 @@ static int dasd_open(struct block_device *bdev, fmode_t mode)  	}  	if (dasd_probeonly) { -		DEV_MESSAGE(KERN_INFO, base, "%s", -			    "No access to device due to probeonly mode"); +		dev_info(&base->cdev->dev, +			 "Accessing the DASD failed because it is in " +			 "probeonly mode\n");  		rc = -EPERM;  		goto out;  	} @@ -2101,7 +2116,8 @@ dasd_device_operations = {  	.owner		= THIS_MODULE,  	.open		= dasd_open,  	.release	= dasd_release, -	.locked_ioctl	= dasd_ioctl, +	.ioctl		= dasd_ioctl, +	.compat_ioctl	= dasd_ioctl,  	.getgeo		= dasd_getgeo,  }; @@ -2143,14 +2159,14 @@ int dasd_generic_probe(struct ccw_device *cdev,  	ret = ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);  	if (ret) { -		printk(KERN_WARNING +		DBF_EVENT(DBF_WARNING,  		       "dasd_generic_probe: could not set ccw-device options "  		       "for %s\n", dev_name(&cdev->dev));  		return ret;  	}  	ret = dasd_add_sysfs_files(cdev);  	if (ret) { -		printk(KERN_WARNING +		DBF_EVENT(DBF_WARNING,  		       "dasd_generic_probe: could not add sysfs entries "  		       "for %s\n", dev_name(&cdev->dev));  		return ret; @@ -2166,9 +2182,7 @@ int dasd_generic_probe(struct ccw_device *cdev,  	    (dasd_autodetect && dasd_busid_known(dev_name(&cdev->dev)) != 0))  		ret = ccw_device_set_online(cdev);  	if (ret) -		printk(KERN_WARNING -		       "dasd_generic_probe: could not initially " -		       "online ccw-device %s; return code: %d\n", +		pr_warning("%s: Setting the DASD online failed with rc=%d\n",  		       dev_name(&cdev->dev), ret);  	return 0;  } @@ -2232,10 +2246,9 @@ int dasd_generic_set_online(struct ccw_device *cdev,  	discipline = base_discipline;  	if (device->features & DASD_FEATURE_USEDIAG) {  	  	if (!dasd_diag_discipline_pointer) { -		        printk (KERN_WARNING -				"dasd_generic couldn't online device %s " -				"- discipline DIAG not available\n", -				dev_name(&cdev->dev)); +			pr_warning("%s Setting the DASD online failed because " +				   "of missing DIAG discipline\n", +				   dev_name(&cdev->dev));  			dasd_delete_device(device);  			return -ENODEV;  		} @@ -2256,10 +2269,9 @@ int dasd_generic_set_online(struct ccw_device *cdev,  	/* check_device will allocate block device if necessary */  	rc = discipline->check_device(device);  	if (rc) { -		printk (KERN_WARNING -			"dasd_generic couldn't online device %s " -			"with discipline %s rc=%i\n", -			dev_name(&cdev->dev), discipline->name, rc); +		pr_warning("%s Setting the DASD online with discipline %s " +			   "failed with rc=%i\n", +			   dev_name(&cdev->dev), discipline->name, rc);  		module_put(discipline->owner);  		module_put(base_discipline->owner);  		dasd_delete_device(device); @@ -2268,9 +2280,8 @@ int dasd_generic_set_online(struct ccw_device *cdev,  	dasd_set_target_state(device, DASD_STATE_ONLINE);  	if (device->state <= DASD_STATE_KNOWN) { -		printk (KERN_WARNING -			"dasd_generic discipline not found for %s\n", -			dev_name(&cdev->dev)); +		pr_warning("%s Setting the DASD online failed because of a " +			   "missing discipline\n", dev_name(&cdev->dev));  		rc = -ENODEV;  		dasd_set_target_state(device, DASD_STATE_NEW);  		if (device->block) @@ -2314,13 +2325,13 @@ int dasd_generic_set_offline(struct ccw_device *cdev)  		open_count = atomic_read(&device->block->open_count);  		if (open_count > max_count) {  			if (open_count > 0) -				printk(KERN_WARNING "Can't offline dasd " -				       "device with open count = %i.\n", -				       open_count); +				pr_warning("%s: The DASD cannot be set offline " +					   "with open count %i\n", +					   dev_name(&cdev->dev), open_count);  			else -				printk(KERN_WARNING "%s", -				       "Can't offline dasd device due " -				       "to internal use\n"); +				pr_warning("%s: The DASD cannot be set offline " +					   "while it is in use\n", +					   dev_name(&cdev->dev));  			clear_bit(DASD_FLAG_OFFLINE, &device->flags);  			dasd_put_device(device);  			return -EBUSY; @@ -2393,8 +2404,10 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,  	cqr = dasd_smalloc_request(magic, 1 /* RDC */, rdc_buffer_size, device);  	if (IS_ERR(cqr)) { -		DEV_MESSAGE(KERN_WARNING, device, "%s", -			    "Could not allocate RDC request"); +		/* internal error 13 - Allocating the RDC request failed*/ +		dev_err(&device->cdev->dev, +			 "An error occurred in the DASD device driver, " +			 "reason=%s\n", "13");  		return cqr;  	} @@ -2431,6 +2444,40 @@ int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic,  }  EXPORT_SYMBOL_GPL(dasd_generic_read_dev_chars); +/* + *   In command mode and transport mode we need to look for sense + *   data in different places. The sense data itself is allways + *   an array of 32 bytes, so we can unify the sense data access + *   for both modes. + */ +char *dasd_get_sense(struct irb *irb) +{ +	struct tsb *tsb = NULL; +	char *sense = NULL; + +	if (scsw_is_tm(&irb->scsw) && (irb->scsw.tm.fcxs == 0x01)) { +		if (irb->scsw.tm.tcw) +			tsb = tcw_get_tsb((struct tcw *)(unsigned long) +					  irb->scsw.tm.tcw); +		if (tsb && tsb->length == 64 && tsb->flags) +			switch (tsb->flags & 0x07) { +			case 1:	/* tsa_iostat */ +				sense = tsb->tsa.iostat.sense; +				break; +			case 2: /* tsa_ddpc */ +				sense = tsb->tsa.ddpc.sense; +				break; +			default: +				/* currently we don't use interrogate data */ +				break; +			} +	} else if (irb->esw.esw0.erw.cons) { +		sense = irb->ecw; +	} +	return sense; +} +EXPORT_SYMBOL_GPL(dasd_get_sense); +  static int __init dasd_init(void)  {  	int rc; @@ -2472,7 +2519,7 @@ static int __init dasd_init(void)  	return 0;  failed: -	MESSAGE(KERN_INFO, "%s", "initialization not performed due to errors"); +	pr_info("The DASD device driver could not be initialized\n");  	dasd_exit();  	return rc;  } diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index d82aad5224f0..27991b692056 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -7,6 +7,8 @@   *   */ +#define KMSG_COMPONENT "dasd" +  #include <linux/timer.h>  #include <linux/slab.h>  #include <asm/idals.h> @@ -75,7 +77,7 @@ dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)  	struct dasd_device *device = erp->startdev;  	unsigned long flags; -	DEV_MESSAGE(KERN_INFO, device, +	DBF_DEV_EVENT(DBF_INFO, device,  		    "blocking request queue for %is", expires/HZ);  	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); @@ -114,9 +116,9 @@ dasd_3990_erp_int_req(struct dasd_ccw_req * erp)  	} else {  		/* issue a message and wait for 'device ready' interrupt */ -		DEV_MESSAGE(KERN_ERR, device, "%s", +		dev_err(&device->cdev->dev,  			    "is offline or not installed - " -			    "INTERVENTION REQUIRED!!"); +			    "INTERVENTION REQUIRED!!\n");  		dasd_3990_erp_block_queue(erp, 60*HZ);  	} @@ -158,7 +160,7 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)  	if ((erp->lpm & opm) != 0x00) { -		DEV_MESSAGE(KERN_DEBUG, device, +		DBF_DEV_EVENT(DBF_WARNING, device,  			    "try alternate lpm=%x (lpum=%x / opm=%x)",  			    erp->lpm, erp->irb.esw.esw0.sublog.lpum, opm); @@ -166,10 +168,9 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)  		erp->status = DASD_CQR_FILLED;  		erp->retries = 10;  	} else { -		DEV_MESSAGE(KERN_ERR, device, -			    "No alternate channel path left (lpum=%x / " -			    "opm=%x) -> permanent error", -			    erp->irb.esw.esw0.sublog.lpum, opm); +		dev_err(&device->cdev->dev, +			"The DASD cannot be reached on any path (lpum=%x" +			"/opm=%x)\n", erp->irb.esw.esw0.sublog.lpum, opm);  		/* post request with permanent error */  		erp->status = DASD_CQR_FAILED; @@ -204,8 +205,8 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)  					  sizeof(struct DCTL_data),  					  device);  	if (IS_ERR(dctl_cqr)) { -		DEV_MESSAGE(KERN_ERR, device, "%s", -			    "Unable to allocate DCTL-CQR"); +		dev_err(&device->cdev->dev, +			    "Unable to allocate DCTL-CQR\n");  		erp->status = DASD_CQR_FAILED;  		return erp;  	} @@ -294,7 +295,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)  	/* interrupt (this enables easier enqueing of the cqr)	    */  	if (erp->function != dasd_3990_erp_action_4) { -		DEV_MESSAGE(KERN_INFO, device, "%s", +		DBF_DEV_EVENT(DBF_INFO, device, "%s",  			    "dasd_3990_erp_action_4: first time retry");  		erp->retries = 256; @@ -303,7 +304,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)  	} else {  		if (sense && (sense[25] == 0x1D)) { /* state change pending */ -			DEV_MESSAGE(KERN_INFO, device, +			DBF_DEV_EVENT(DBF_INFO, device,  				    "waiting for state change pending "  				    "interrupt, %d retries left",  				    erp->retries); @@ -311,15 +312,14 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)  			dasd_3990_erp_block_queue(erp, 30*HZ);  		} else if (sense && (sense[25] == 0x1E)) {	/* busy */ -			DEV_MESSAGE(KERN_INFO, device, +			DBF_DEV_EVENT(DBF_INFO, device,  				    "busy - redriving request later, "  				    "%d retries left",  				    erp->retries);                          dasd_3990_erp_block_queue(erp, HZ);  		} else { -  			/* no state change pending - retry */ -			DEV_MESSAGE (KERN_INFO, device, +			DBF_DEV_EVENT(DBF_INFO, device,  				     "redriving request immediately, "  				     "%d retries left",  				     erp->retries); @@ -384,6 +384,7 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)  	struct dasd_device *device = erp->startdev;  	char msg_format = (sense[7] & 0xF0);  	char msg_no = (sense[7] & 0x0F); +	char errorstring[ERRORLENGTH];  	switch (msg_format) {  	case 0x00:		/* Format 0 - Program or System Checks */ @@ -394,95 +395,97 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)  			case 0x00:	/* No Message */  				break;  			case 0x01: -				DEV_MESSAGE(KERN_WARNING, device, "%s", -					    "FORMAT 0 - Invalid Command"); +				dev_warn(&device->cdev->dev, +					    "FORMAT 0 - Invalid Command\n");  				break;  			case 0x02: -				DEV_MESSAGE(KERN_WARNING, device, "%s", +				dev_warn(&device->cdev->dev,  					    "FORMAT 0 - Invalid Command " -					    "Sequence"); +					    "Sequence\n");  				break;  			case 0x03: -				DEV_MESSAGE(KERN_WARNING, device, "%s", +				dev_warn(&device->cdev->dev,  					    "FORMAT 0 - CCW Count less than " -					    "required"); +					    "required\n");  				break;  			case 0x04: -				DEV_MESSAGE(KERN_WARNING, device, "%s", -					    "FORMAT 0 - Invalid Parameter"); +				dev_warn(&device->cdev->dev, +					    "FORMAT 0 - Invalid Parameter\n");  				break;  			case 0x05: -				DEV_MESSAGE(KERN_WARNING, device, "%s", -					    "FORMAT 0 - Diagnostic of Sepecial" -					    " Command Violates File Mask"); +				dev_warn(&device->cdev->dev, +					    "FORMAT 0 - Diagnostic of Special" +					    " Command Violates File Mask\n");  				break;  			case 0x07: -				DEV_MESSAGE(KERN_WARNING, device, "%s", +				dev_warn(&device->cdev->dev,  					    "FORMAT 0 - Channel Returned with " -					    "Incorrect retry CCW"); +					    "Incorrect retry CCW\n");  				break;  			case 0x08: -				DEV_MESSAGE(KERN_WARNING, device, "%s", -					    "FORMAT 0 - Reset Notification"); +				dev_warn(&device->cdev->dev, +					    "FORMAT 0 - Reset Notification\n");  				break;  			case 0x09: -				DEV_MESSAGE(KERN_WARNING, device, "%s", -					    "FORMAT 0 - Storage Path Restart"); +				dev_warn(&device->cdev->dev, +					 "FORMAT 0 - Storage Path Restart\n");  				break;  			case 0x0A: -				DEV_MESSAGE(KERN_WARNING, device, +				dev_warn(&device->cdev->dev,  					    "FORMAT 0 - Channel requested " -					    "... %02x", sense[8]); +					    "... %02x\n", sense[8]);  				break;  			case 0x0B: -				DEV_MESSAGE(KERN_WARNING, device, "%s", +				dev_warn(&device->cdev->dev,  					    "FORMAT 0 - Invalid Defective/" -					    "Alternate Track Pointer"); +					    "Alternate Track Pointer\n");  				break;  			case 0x0C: -				DEV_MESSAGE(KERN_WARNING, device, "%s", +				dev_warn(&device->cdev->dev,  					    "FORMAT 0 - DPS Installation " -					    "Check"); +					    "Check\n");  				break;  			case 0x0E: -				DEV_MESSAGE(KERN_WARNING, device, "%s", +				dev_warn(&device->cdev->dev,  					    "FORMAT 0 - Command Invalid on " -					    "Secondary Address"); +					    "Secondary Address\n");  				break;  			case 0x0F: -				DEV_MESSAGE(KERN_WARNING, device, +				dev_warn(&device->cdev->dev,  					    "FORMAT 0 - Status Not As " -					    "Required: reason %02x", sense[8]); +					    "Required: reason %02x\n", +					 sense[8]);  				break;  			default: -				DEV_MESSAGE(KERN_WARNING, device, "%s", -					    "FORMAT 0 - Reseved"); +				dev_warn(&device->cdev->dev, +					    "FORMAT 0 - Reserved\n");  			}  		} else {  			switch (msg_no) {  			case 0x00:	/* No Message */  				break;  			case 0x01: -				DEV_MESSAGE(KERN_WARNING, device, "%s", -					    "FORMAT 0 - Device Error Source"); +				dev_warn(&device->cdev->dev, +					 "FORMAT 0 - Device Error " +					 "Source\n");  				break;  			case 0x02: -				DEV_MESSAGE(KERN_WARNING, device, "%s", -					    "FORMAT 0 - Reserved"); +				dev_warn(&device->cdev->dev, +					    "FORMAT 0 - Reserved\n");  				break;  			case 0x03: -				DEV_MESSAGE(KERN_WARNING, device, +				dev_warn(&device->cdev->dev,  					    "FORMAT 0 - Device Fenced - " -					    "device = %02x", sense[4]); +					    "device = %02x\n", sense[4]);  				break;  			case 0x04: -				DEV_MESSAGE(KERN_WARNING, device, "%s", +				dev_warn(&device->cdev->dev,  					    "FORMAT 0 - Data Pinned for " -					    "Device"); +					    "Device\n");  				break;  			default: -				DEV_MESSAGE(KERN_WARNING, device, "%s", -					    "FORMAT 0 - Reserved"); +				dev_warn(&device->cdev->dev, +					    "FORMAT 0 - Reserved\n");  			}  		}  		break; @@ -492,348 +495,352 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)  		case 0x00:	/* No Message */  			break;  		case 0x01: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 1 - Device Status 1 not as " -				    "expected"); +				    "expected\n");  			break;  		case 0x03: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 1 - Index missing"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 1 - Index missing\n");  			break;  		case 0x04: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 1 - Interruption cannot be reset"); +			dev_warn(&device->cdev->dev, +				 "FORMAT 1 - Interruption cannot be " +				 "reset\n");  			break;  		case 0x05: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 1 - Device did not respond to " -				    "selection"); +				    "selection\n");  			break;  		case 0x06: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 1 - Device check-2 error or Set " -				    "Sector is not complete"); +				    "Sector is not complete\n");  			break;  		case 0x07: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 1 - Head address does not " -				    "compare"); +				    "compare\n");  			break;  		case 0x08: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 1 - Device status 1 not valid"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 1 - Device status 1 not valid\n");  			break;  		case 0x09: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 1 - Device not ready"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 1 - Device not ready\n");  			break;  		case 0x0A: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 1 - Track physical address did " -				    "not compare"); +				    "not compare\n");  			break;  		case 0x0B: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 1 - Missing device address bit"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 1 - Missing device address bit\n");  			break;  		case 0x0C: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 1 - Drive motor switch is off"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 1 - Drive motor switch is off\n");  			break;  		case 0x0D: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 1 - Seek incomplete"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 1 - Seek incomplete\n");  			break;  		case 0x0E: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 1 - Cylinder address did not " -				    "compare"); +				    "compare\n");  			break;  		case 0x0F: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 1 - Offset active cannot be " -				    "reset"); +				    "reset\n");  			break;  		default: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 1 - Reserved"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 1 - Reserved\n");  		}  		break;  	case 0x20:		/* Format 2 - 3990 Equipment Checks */  		switch (msg_no) {  		case 0x08: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 2 - 3990 check-2 error"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 2 - 3990 check-2 error\n");  			break;  		case 0x0E: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 2 - Support facility errors"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 2 - Support facility errors\n");  			break;  		case 0x0F: -			DEV_MESSAGE(KERN_WARNING, device, -				    "FORMAT 2 - Microcode detected error %02x", -				    sense[8]); +			dev_warn(&device->cdev->dev, +				 "FORMAT 2 - Microcode detected error " +				 "%02x\n", +				 sense[8]);  			break;  		default: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 2 - Reserved"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 2 - Reserved\n");  		}  		break;  	case 0x30:		/* Format 3 - 3990 Control Checks */  		switch (msg_no) {  		case 0x0F: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 3 - Allegiance terminated"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 3 - Allegiance terminated\n");  			break;  		default: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 3 - Reserved"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 3 - Reserved\n");  		}  		break;  	case 0x40:		/* Format 4 - Data Checks */  		switch (msg_no) {  		case 0x00: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 4 - Home address area error"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 4 - Home address area error\n");  			break;  		case 0x01: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 4 - Count area error"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 4 - Count area error\n");  			break;  		case 0x02: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 4 - Key area error"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 4 - Key area error\n");  			break;  		case 0x03: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 4 - Data area error"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 4 - Data area error\n");  			break;  		case 0x04: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 4 - No sync byte in home address " -				    "area"); +				    "area\n");  			break;  		case 0x05: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 4 - No sync byte in count address " -				    "area"); +				    "area\n");  			break;  		case 0x06: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 4 - No sync byte in key area"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 4 - No sync byte in key area\n");  			break;  		case 0x07: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 4 - No sync byte in data area"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 4 - No sync byte in data area\n");  			break;  		case 0x08: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 4 - Home address area error; " -				    "offset active"); +				    "offset active\n");  			break;  		case 0x09: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 4 - Count area error; offset " -				    "active"); +				    "active\n");  			break;  		case 0x0A: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 4 - Key area error; offset " -				    "active"); +				    "active\n");  			break;  		case 0x0B: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 4 - Data area error; " -				    "offset active"); +				    "offset active\n");  			break;  		case 0x0C: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 4 - No sync byte in home " -				    "address area; offset active"); +				    "address area; offset active\n");  			break;  		case 0x0D: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 4 - No syn byte in count " -				    "address area; offset active"); +				    "address area; offset active\n");  			break;  		case 0x0E: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 4 - No sync byte in key area; " -				    "offset active"); +				    "offset active\n");  			break;  		case 0x0F: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 4 - No syn byte in data area; " -				    "offset active"); +				    "offset active\n");  			break;  		default: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 4 - Reserved"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 4 - Reserved\n");  		}  		break;  	case 0x50:  /* Format 5 - Data Check with displacement information */  		switch (msg_no) {  		case 0x00: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 5 - Data Check in the " -				    "home address area"); +				    "home address area\n");  			break;  		case 0x01: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 5 - Data Check in the count area"); +			dev_warn(&device->cdev->dev, +				 "FORMAT 5 - Data Check in the count " +				 "area\n");  			break;  		case 0x02: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 5 - Data Check in the key area"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 5 - Data Check in the key area\n");  			break;  		case 0x03: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 5 - Data Check in the data area"); +			dev_warn(&device->cdev->dev, +				 "FORMAT 5 - Data Check in the data " +				 "area\n");  			break;  		case 0x08: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 5 - Data Check in the " -				    "home address area; offset active"); +				    "home address area; offset active\n");  			break;  		case 0x09: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 5 - Data Check in the count area; " -				    "offset active"); +				    "offset active\n");  			break;  		case 0x0A: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 5 - Data Check in the key area; " -				    "offset active"); +				    "offset active\n");  			break;  		case 0x0B: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 5 - Data Check in the data area; " -				    "offset active"); +				    "offset active\n");  			break;  		default: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 5 - Reserved"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 5 - Reserved\n");  		}  		break;  	case 0x60:  /* Format 6 - Usage Statistics/Overrun Errors */  		switch (msg_no) {  		case 0x00: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 6 - Overrun on channel A"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 6 - Overrun on channel A\n");  			break;  		case 0x01: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 6 - Overrun on channel B"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 6 - Overrun on channel B\n");  			break;  		case 0x02: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 6 - Overrun on channel C"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 6 - Overrun on channel C\n");  			break;  		case 0x03: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 6 - Overrun on channel D"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 6 - Overrun on channel D\n");  			break;  		case 0x04: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 6 - Overrun on channel E"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 6 - Overrun on channel E\n");  			break;  		case 0x05: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 6 - Overrun on channel F"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 6 - Overrun on channel F\n");  			break;  		case 0x06: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 6 - Overrun on channel G"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 6 - Overrun on channel G\n");  			break;  		case 0x07: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 6 - Overrun on channel H"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 6 - Overrun on channel H\n");  			break;  		default: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 6 - Reserved"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 6 - Reserved\n");  		}  		break;  	case 0x70:  /* Format 7 - Device Connection Control Checks */  		switch (msg_no) {  		case 0x00: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 7 - RCC initiated by a connection " -				    "check alert"); +				    "check alert\n");  			break;  		case 0x01: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 7 - RCC 1 sequence not " -				    "successful"); +				    "successful\n");  			break;  		case 0x02: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 7 - RCC 1 and RCC 2 sequences not " -				    "successful"); +				    "successful\n");  			break;  		case 0x03: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 7 - Invalid tag-in during " -				    "selection sequence"); +				    "selection sequence\n");  			break;  		case 0x04: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 7 - extra RCC required"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 7 - extra RCC required\n");  			break;  		case 0x05: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 7 - Invalid DCC selection " -				    "response or timeout"); +				    "response or timeout\n");  			break;  		case 0x06: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 7 - Missing end operation; device " -				    "transfer complete"); +				    "transfer complete\n");  			break;  		case 0x07: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 7 - Missing end operation; device " -				    "transfer incomplete"); +				    "transfer incomplete\n");  			break;  		case 0x08: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 7 - Invalid tag-in for an " -				    "immediate command sequence"); +				    "immediate command sequence\n");  			break;  		case 0x09: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 7 - Invalid tag-in for an " -				    "extended command sequence"); +				    "extended command sequence\n");  			break;  		case 0x0A: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 7 - 3990 microcode time out when " -				    "stopping selection"); +				    "stopping selection\n");  			break;  		case 0x0B: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 7 - No response to selection " -				    "after a poll interruption"); +				    "after a poll interruption\n");  			break;  		case 0x0C: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 7 - Permanent path error (DASD " -				    "controller not available)"); +				    "controller not available)\n");  			break;  		case 0x0D: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 7 - DASD controller not available" -				    " on disconnected command chain"); +				    " on disconnected command chain\n");  			break;  		default: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 7 - Reserved"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 7 - Reserved\n");  		}  		break; @@ -841,52 +848,52 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)  		switch (msg_no) {  		case 0x00:	/* No Message */  		case 0x01: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 8 - Error correction code " -				    "hardware fault"); +				    "hardware fault\n");  			break;  		case 0x03: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 8 - Unexpected end operation " -				    "response code"); +				    "response code\n");  			break;  		case 0x04: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 8 - End operation with transfer " -				    "count not zero"); +				    "count not zero\n");  			break;  		case 0x05: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 8 - End operation with transfer " -				    "count zero"); +				    "count zero\n");  			break;  		case 0x06: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 8 - DPS checks after a system " -				    "reset or selective reset"); +				    "reset or selective reset\n");  			break;  		case 0x07: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 8 - DPS cannot be filled"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 8 - DPS cannot be filled\n");  			break;  		case 0x08: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 8 - Short busy time-out during " -				    "device selection"); +				    "device selection\n");  			break;  		case 0x09: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 8 - DASD controller failed to " -				    "set or reset the long busy latch"); +				    "set or reset the long busy latch\n");  			break;  		case 0x0A: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 8 - No interruption from device " -				    "during a command chain"); +				    "during a command chain\n");  			break;  		default: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 8 - Reserved"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 8 - Reserved\n");  		}  		break; @@ -895,97 +902,100 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)  		case 0x00:  			break;	/* No Message */  		case 0x06: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 9 - Device check-2 error"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 9 - Device check-2 error\n");  			break;  		case 0x07: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 9 - Head address did not compare"); +			dev_warn(&device->cdev->dev, +				 "FORMAT 9 - Head address did not " +				 "compare\n");  			break;  		case 0x0A: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 9 - Track physical address did " -				    "not compare while oriented"); +				    "not compare while oriented\n");  			break;  		case 0x0E: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT 9 - Cylinder address did not " -				    "compare"); +				    "compare\n");  			break;  		default: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT 9 - Reserved"); +			dev_warn(&device->cdev->dev, +				    "FORMAT 9 - Reserved\n");  		}  		break;  	case 0xF0:		/* Format F - Cache Storage Checks */  		switch (msg_no) {  		case 0x00: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT F - Operation Terminated"); +			dev_warn(&device->cdev->dev, +				    "FORMAT F - Operation Terminated\n");  			break;  		case 0x01: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT F - Subsystem Processing Error"); +			dev_warn(&device->cdev->dev, +				    "FORMAT F - Subsystem Processing Error\n");  			break;  		case 0x02: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT F - Cache or nonvolatile storage " -				    "equipment failure"); +				    "equipment failure\n");  			break;  		case 0x04: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT F - Caching terminated"); +			dev_warn(&device->cdev->dev, +				    "FORMAT F - Caching terminated\n");  			break;  		case 0x06: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT F - Cache fast write access not " -				    "authorized"); +				    "authorized\n");  			break;  		case 0x07: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT F - Track format incorrect"); +			dev_warn(&device->cdev->dev, +				    "FORMAT F - Track format incorrect\n");  			break;  		case 0x09: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT F - Caching reinitiated"); +			dev_warn(&device->cdev->dev, +				    "FORMAT F - Caching reinitiated\n");  			break;  		case 0x0A: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT F - Nonvolatile storage " -				    "terminated"); +				    "terminated\n");  			break;  		case 0x0B: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT F - Volume is suspended duplex"); +			dev_warn(&device->cdev->dev, +				    "FORMAT F - Volume is suspended duplex\n");  			/* call extended error reporting (EER) */  			dasd_eer_write(device, erp->refers,  				       DASD_EER_PPRCSUSPEND);  			break;  		case 0x0C: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT F - Subsystem status connot be " -				    "determined"); +			dev_warn(&device->cdev->dev, +				    "FORMAT F - Subsystem status cannot be " +				    "determined\n");  			break;  		case 0x0D: -			DEV_MESSAGE(KERN_WARNING, device, "%s", +			dev_warn(&device->cdev->dev,  				    "FORMAT F - Caching status reset to " -				    "default"); +				    "default\n");  			break;  		case 0x0E: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT F - DASD Fast Write inhibited"); +			dev_warn(&device->cdev->dev, +				    "FORMAT F - DASD Fast Write inhibited\n");  			break;  		default: -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "FORMAT D - Reserved"); +			dev_warn(&device->cdev->dev, +				    "FORMAT D - Reserved\n");  		}  		break; -	default:	/* unknown message format - should not happen */ -	        DEV_MESSAGE (KERN_WARNING, device, -                             "unknown message format %02x", -                             msg_format); +	default:	/* unknown message format - should not happen +			   internal error 03 - unknown message format */ +		snprintf(errorstring, ERRORLENGTH, "03 %x02", msg_format); +		dev_err(&device->cdev->dev, +			 "An error occurred in the DASD device driver, " +			 "reason=%s\n", errorstring);  		break;  	}			/* end switch message format */ @@ -1015,7 +1025,7 @@ dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)  	/* env data present (ACTION 10 - retry should work) */  	if (sense[2] & SNS2_ENV_DATA_PRESENT) { -		DEV_MESSAGE(KERN_DEBUG, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "Command Reject - environmental data present");  		dasd_3990_handle_env_data(erp, sense); @@ -1023,9 +1033,10 @@ dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)  		erp->retries = 5;  	} else { -		/* fatal error -  set status to FAILED */ -		DEV_MESSAGE(KERN_ERR, device, "%s", -			    "Command Reject - Fatal error"); +		/* fatal error -  set status to FAILED +		   internal error 09 - Command Reject */ +		dev_err(&device->cdev->dev, "An error occurred in the DASD " +			"device driver, reason=%s\n", "09");  		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);  	} @@ -1061,7 +1072,7 @@ dasd_3990_erp_bus_out(struct dasd_ccw_req * erp)  	} else {  		/* issue a message and wait for 'device ready' interrupt */ -		DEV_MESSAGE(KERN_DEBUG, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "bus out parity error or BOPC requested by "  			    "channel"); @@ -1093,21 +1104,19 @@ dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense)  	erp->function = dasd_3990_erp_equip_check;  	if (sense[1] & SNS1_WRITE_INHIBITED) { +		dev_info(&device->cdev->dev, +			    "Write inhibited path encountered\n"); -		DEV_MESSAGE(KERN_DEBUG, device, "%s", -			    "Write inhibited path encountered"); - -		/* vary path offline */ -		DEV_MESSAGE(KERN_ERR, device, "%s", -			    "Path should be varied off-line. " -			    "This is not implemented yet \n - please report " -			    "to linux390@de.ibm.com"); +		/* vary path offline +		   internal error 04 - Path should be varied off-line.*/ +		dev_err(&device->cdev->dev, "An error occurred in the DASD " +			"device driver, reason=%s\n", "04");  		erp = dasd_3990_erp_action_1(erp);  	} else if (sense[2] & SNS2_ENV_DATA_PRESENT) { -		DEV_MESSAGE(KERN_DEBUG, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "Equipment Check - " "environmental data present");  		dasd_3990_handle_env_data(erp, sense); @@ -1116,7 +1125,7 @@ dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense)  	} else if (sense[1] & SNS1_PERM_ERR) { -		DEV_MESSAGE(KERN_DEBUG, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "Equipment Check - retry exhausted or "  			    "undesirable"); @@ -1125,7 +1134,7 @@ dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense)  	} else {  		/* all other equipment checks - Action 5 */  		/* rest is done when retries == 0 */ -		DEV_MESSAGE(KERN_DEBUG, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "Equipment check or processing error");  		erp = dasd_3990_erp_action_5(erp); @@ -1156,9 +1165,9 @@ dasd_3990_erp_data_check(struct dasd_ccw_req * erp, char *sense)  	if (sense[2] & SNS2_CORRECTABLE) {	/* correctable data check */  		/* issue message that the data has been corrected */ -		DEV_MESSAGE(KERN_EMERG, device, "%s", +		dev_emerg(&device->cdev->dev,  			    "Data recovered during retry with PCI " -			    "fetch mode active"); +			    "fetch mode active\n");  		/* not possible to handle this situation in Linux */  		panic("No way to inform application about the possibly " @@ -1166,7 +1175,7 @@ dasd_3990_erp_data_check(struct dasd_ccw_req * erp, char *sense)  	} else if (sense[2] & SNS2_ENV_DATA_PRESENT) { -		DEV_MESSAGE(KERN_DEBUG, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "Uncorrectable data check recovered secondary "  			    "addr of duplex pair"); @@ -1174,7 +1183,7 @@ dasd_3990_erp_data_check(struct dasd_ccw_req * erp, char *sense)  	} else if (sense[1] & SNS1_PERM_ERR) { -		DEV_MESSAGE(KERN_DEBUG, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "Uncorrectable data check with internal "  			    "retry exhausted"); @@ -1182,7 +1191,7 @@ dasd_3990_erp_data_check(struct dasd_ccw_req * erp, char *sense)  	} else {  		/* all other data checks */ -		DEV_MESSAGE(KERN_DEBUG, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "Uncorrectable data check with retry count "  			    "exhausted..."); @@ -1212,7 +1221,7 @@ dasd_3990_erp_overrun(struct dasd_ccw_req * erp, char *sense)  	erp->function = dasd_3990_erp_overrun; -	DEV_MESSAGE(KERN_DEBUG, device, "%s", +	DBF_DEV_EVENT(DBF_WARNING, device, "%s",  		    "Overrun - service overrun or overrun"  		    " error requested by channel"); @@ -1243,7 +1252,7 @@ dasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense)  	if (sense[2] & SNS2_ENV_DATA_PRESENT) { -		DEV_MESSAGE(KERN_DEBUG, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "Track format error when destaging or "  			    "staging data"); @@ -1252,8 +1261,10 @@ dasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense)  		erp = dasd_3990_erp_action_4(erp, sense);  	} else { -		DEV_MESSAGE(KERN_ERR, device, "%s", -			    "Invalid Track Format - Fatal error"); +		/* internal error 06 - The track format is not valid*/ +		dev_err(&device->cdev->dev, +			"An error occurred in the DASD device driver, " +			"reason=%s\n", "06");  		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);  	} @@ -1279,8 +1290,8 @@ dasd_3990_erp_EOC(struct dasd_ccw_req * default_erp, char *sense)  	struct dasd_device *device = default_erp->startdev; -	DEV_MESSAGE(KERN_ERR, device, "%s", -		    "End-of-Cylinder - must never happen"); +	dev_err(&device->cdev->dev, +		"The cylinder data for accessing the DASD is inconsistent\n");  	/* implement action 7 - BUG */  	return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED); @@ -1306,7 +1317,7 @@ dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense)  	erp->function = dasd_3990_erp_env_data; -	DEV_MESSAGE(KERN_DEBUG, device, "%s", "Environmental data present"); +	DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Environmental data present");  	dasd_3990_handle_env_data(erp, sense); @@ -1339,8 +1350,8 @@ dasd_3990_erp_no_rec(struct dasd_ccw_req * default_erp, char *sense)  	struct dasd_device *device = default_erp->startdev; -	DEV_MESSAGE(KERN_ERR, device, "%s", -		    "No Record Found - Fatal error "); +	dev_err(&device->cdev->dev, +		    "The specified record was not found\n");  	return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED); @@ -1365,7 +1376,8 @@ dasd_3990_erp_file_prot(struct dasd_ccw_req * erp)  	struct dasd_device *device = erp->startdev; -	DEV_MESSAGE(KERN_ERR, device, "%s", "File Protected"); +	dev_err(&device->cdev->dev, "Accessing the DASD failed because of " +		"a hardware error\n");  	return dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); @@ -1394,7 +1406,7 @@ static struct dasd_ccw_req *dasd_3990_erp_inspect_alias(  	if (cqr->block &&  	    (cqr->block->base != cqr->startdev)) {  		if (cqr->startdev->features & DASD_FEATURE_ERPLOG) { -			DEV_MESSAGE(KERN_ERR, cqr->startdev, +			DBF_DEV_EVENT(DBF_ERR, cqr->startdev,  				    "ERP on alias device for request %p,"  				    " recover on base device %s", cqr,  				    dev_name(&cqr->block->base->cdev->dev)); @@ -1511,7 +1523,7 @@ dasd_3990_erp_action_10_32(struct dasd_ccw_req * erp, char *sense)  	erp->retries = 256;  	erp->function = dasd_3990_erp_action_10_32; -	DEV_MESSAGE(KERN_DEBUG, device, "%s", "Perform logging requested"); +	DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Perform logging requested");  	return erp; @@ -1549,7 +1561,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)  	char *LO_data;		/* LO_eckd_data_t */  	struct ccw1 *ccw, *oldccw; -	DEV_MESSAGE(KERN_DEBUG, device, "%s", +	DBF_DEV_EVENT(DBF_WARNING, device, "%s",  		    "Write not finished because of unexpected condition");  	default_erp->function = dasd_3990_erp_action_1B_32; @@ -1561,10 +1573,16 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)  		cqr = cqr->refers;  	} +	if (scsw_is_tm(&cqr->irb.scsw)) { +		DBF_DEV_EVENT(DBF_WARNING, device, "%s", +			      "32 bit sense, action 1B is not defined" +			      " in transport mode - just retry"); +		return default_erp; +	} +  	/* for imprecise ending just do default erp */  	if (sense[1] & 0x01) { - -		DEV_MESSAGE(KERN_DEBUG, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "Imprecise ending is set - just retry");  		return default_erp; @@ -1575,8 +1593,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)  	cpa = default_erp->refers->irb.scsw.cmd.cpa;  	if (cpa == 0) { - -		DEV_MESSAGE(KERN_DEBUG, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "Unable to determine address of the CCW "  			    "to be restarted"); @@ -1590,7 +1607,9 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)  				     sizeof(struct LO_eckd_data), device);  	if (IS_ERR(erp)) { -		DEV_MESSAGE(KERN_ERR, device, "%s", "Unable to allocate ERP"); +		/* internal error 01 - Unable to allocate ERP */ +		dev_err(&device->cdev->dev, "An error occurred in the DASD " +			"device driver, reason=%s\n", "01");  		return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);  	} @@ -1599,7 +1618,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)  	oldccw = cqr->cpaddr;  	if (oldccw->cmd_code == DASD_ECKD_CCW_PFX) {  		PFX_data = cqr->data; -		memcpy(DE_data, &PFX_data->define_extend, +		memcpy(DE_data, &PFX_data->define_extent,  		       sizeof(struct DE_eckd_data));  	} else  		memcpy(DE_data, cqr->data, sizeof(struct DE_eckd_data)); @@ -1608,10 +1627,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)  	LO_data = erp->data + sizeof(struct DE_eckd_data);  	if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) { - -		DEV_MESSAGE(KERN_ERR, device, "%s", -			    "BUG - this should not happen"); - +		/* should not */  		return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);  	} @@ -1701,7 +1717,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)  	char *LO_data;		/* struct LO_eckd_data */  	struct ccw1 *ccw; -	DEV_MESSAGE(KERN_DEBUG, device, "%s", +	DBF_DEV_EVENT(DBF_WARNING, device, "%s",  		    "Write not finished because of unexpected condition"  		    " - follow on"); @@ -1712,10 +1728,16 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)  		cqr = cqr->refers;  	} +	if (scsw_is_tm(&cqr->irb.scsw)) { +		DBF_DEV_EVENT(DBF_WARNING, device, "%s", +			      "32 bit sense, action 1B, update," +			      " in transport mode - just retry"); +		return previous_erp; +	} +  	/* for imprecise ending just do default erp */  	if (sense[1] & 0x01) { - -		DEV_MESSAGE(KERN_DEBUG, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "Imprecise ending is set - just retry");  		previous_erp->status = DASD_CQR_FILLED; @@ -1728,10 +1750,10 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)  	cpa = previous_erp->irb.scsw.cmd.cpa;  	if (cpa == 0) { - -		DEV_MESSAGE(KERN_DEBUG, device, "%s", -			    "Unable to determine address of the CCW " -			    "to be restarted"); +		/* internal error 02 - +		   Unable to determine address of the CCW to be restarted */ +		dev_err(&device->cdev->dev, "An error occurred in the DASD " +			"device driver, reason=%s\n", "02");  		previous_erp->status = DASD_CQR_FAILED; @@ -1744,10 +1766,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)  	LO_data = erp->data + sizeof(struct DE_eckd_data);  	if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) { - -		DEV_MESSAGE(KERN_ERR, device, "%s", -			    "BUG - this should not happen"); - +		/* should not happen */  		previous_erp->status = DASD_CQR_FAILED;  		return previous_erp; @@ -1935,14 +1954,13 @@ dasd_3990_erp_compound_config(struct dasd_ccw_req * erp, char *sense)  	if ((sense[25] & DASD_SENSE_BIT_1) && (sense[26] & DASD_SENSE_BIT_2)) { -		/* set to suspended duplex state then restart */ +		/* set to suspended duplex state then restart +		   internal error 05 - Set device to suspended duplex state +		   should be done */  		struct dasd_device *device = erp->startdev; - -		DEV_MESSAGE(KERN_ERR, device, "%s", -			    "Set device to suspended duplex state should be " -			    "done!\n" -			    "This is not implemented yet (for compound ERP)" -			    " - please report to linux390@de.ibm.com"); +		dev_err(&device->cdev->dev, +			"An error occurred in the DASD device driver, " +			"reason=%s\n", "05");  	} @@ -2012,15 +2030,14 @@ dasd_3990_erp_handle_sim(struct dasd_device *device, char *sense)  {  	/* print message according to log or message to operator mode */  	if ((sense[24] & DASD_SIM_MSG_TO_OP) || (sense[1] & 0x10)) { -  		/* print SIM SRC from RefCode */ -		DEV_MESSAGE(KERN_ERR, device, "SIM - SRC: " -			    "%02x%02x%02x%02x", sense[22], +		dev_err(&device->cdev->dev, "SIM - SRC: " +			    "%02x%02x%02x%02x\n", sense[22],  			    sense[23], sense[11], sense[12]);  	} else if (sense[24] & DASD_SIM_LOG) {  		/* print SIM SRC Refcode */ -		DEV_MESSAGE(KERN_WARNING, device, "SIM - SRC: " -			    "%02x%02x%02x%02x", sense[22], +		dev_warn(&device->cdev->dev, "log SIM - SRC: " +			    "%02x%02x%02x%02x\n", sense[22],  			    sense[23], sense[11], sense[12]);  	}  } @@ -2063,14 +2080,14 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)  		switch (sense[25]) {  		case 0x00:	/* success - use default ERP for retries */ -		        DEV_MESSAGE(KERN_DEBUG, device, "%s", +			DBF_DEV_EVENT(DBF_DEBUG, device, "%s",  				    "ERP called for successful request"  				    " - just retry");  			break;  		case 0x01:	/* fatal error */ -			DEV_MESSAGE(KERN_ERR, device, "%s", -				    "Retry not recommended - Fatal error"); +			dev_err(&device->cdev->dev, +				    "ERP failed for the DASD\n");  			erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);  			break; @@ -2080,13 +2097,10 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)  			erp = dasd_3990_erp_int_req(erp);  			break; -		case 0x0F:  /* length mismatch during update write command */ -			DEV_MESSAGE(KERN_ERR, device, "%s", -				    "update write command error - should not " -				    "happen;\n" -				    "Please send this message together with " -				    "the above sense data to linux390@de." -				    "ibm.com"); +		case 0x0F:  /* length mismatch during update write command +			       internal error 08 - update write command error*/ +			dev_err(&device->cdev->dev, "An error occurred in the " +				"DASD device driver, reason=%s\n", "08");  			erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);  			break; @@ -2095,13 +2109,12 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)  			erp = dasd_3990_erp_action_10_32(erp, sense);  			break; -		case 0x15:	/* next track outside defined extend */ -			DEV_MESSAGE(KERN_ERR, device, "%s", -				    "next track outside defined extend - " -				    "should not happen;\n" -				    "Please send this message together with " -				    "the above sense data to linux390@de." -				    "ibm.com"); +		case 0x15:	/* next track outside defined extend +				   internal error 07 - The next track is not +				   within the defined storage extent */ +			dev_err(&device->cdev->dev, +				"An error occurred in the DASD device driver, " +				"reason=%s\n", "07");  			erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);  			break; @@ -2112,9 +2125,9 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)  			break;  		case 0x1C:	/* invalid data */ -			DEV_MESSAGE(KERN_EMERG, device, "%s", +			dev_emerg(&device->cdev->dev,  				    "Data recovered during retry with PCI " -				    "fetch mode active"); +				    "fetch mode active\n");  			/* not possible to handle this situation in Linux */  			panic @@ -2123,7 +2136,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)  			break;  		case 0x1D:	/* state-change pending */ -			DEV_MESSAGE(KERN_DEBUG, device, "%s", +			DBF_DEV_EVENT(DBF_WARNING, device, "%s",  				    "A State change pending condition exists "  				    "for the subsystem or device"); @@ -2131,7 +2144,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)  			break;  		case 0x1E:	/* busy */ -                        DEV_MESSAGE(KERN_DEBUG, device, "%s", +			DBF_DEV_EVENT(DBF_WARNING, device, "%s",  				    "Busy condition exists "  				    "for the subsystem or device");                          erp = dasd_3990_erp_action_4(erp, sense); @@ -2171,9 +2184,9 @@ dasd_3990_erp_control_check(struct dasd_ccw_req *erp)  {  	struct dasd_device *device = erp->startdev; -	if (erp->refers->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK +	if (scsw_cstat(&erp->refers->irb.scsw) & (SCHN_STAT_INTF_CTRL_CHK  					   | SCHN_STAT_CHN_CTRL_CHK)) { -		DEV_MESSAGE(KERN_DEBUG, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "channel or interface control check");  		erp = dasd_3990_erp_action_4(erp, NULL);  	} @@ -2193,21 +2206,23 @@ dasd_3990_erp_control_check(struct dasd_ccw_req *erp)   *   erp_new		contens was possibly modified   */  static struct dasd_ccw_req * -dasd_3990_erp_inspect(struct dasd_ccw_req * erp) +dasd_3990_erp_inspect(struct dasd_ccw_req *erp)  {  	struct dasd_ccw_req *erp_new = NULL; -	/* sense data are located in the refers record of the */ -	/* already set up new ERP !			      */ -	char *sense = erp->refers->irb.ecw; +	char *sense;  	/* if this problem occured on an alias retry on base */  	erp_new = dasd_3990_erp_inspect_alias(erp);  	if (erp_new)  		return erp_new; -	/* check if no concurrent sens is available */ -	if (!erp->refers->irb.esw.esw0.erw.cons) +	/* sense data are located in the refers record of the +	 * already set up new ERP ! +	 * check if concurrent sens is available +	 */ +	sense = dasd_get_sense(&erp->refers->irb); +	if (!sense)  		erp_new = dasd_3990_erp_control_check(erp);  	/* distinguish between 24 and 32 byte sense data */  	else if (sense[27] & DASD_SENSE_BIT_0) { @@ -2231,7 +2246,11 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp)   * DESCRIPTION   *   This funtion adds an additional request block (ERP) to the head of   *   the given cqr (or erp). - *   This erp is initialized as an default erp (retry TIC) + *   For a command mode cqr the erp is initialized as an default erp + *   (retry TIC). + *   For transport mode we make a copy of the original TCW (points to + *   the original TCCB, TIDALs, etc.) but give it a fresh + *   TSB so the original sense data will not be changed.   *   * PARAMETER   *   cqr		head of the current ERP-chain (or single cqr if @@ -2239,25 +2258,35 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp)   * RETURN VALUES   *   erp		pointer to new ERP-chain head   */ -static struct dasd_ccw_req * -dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr) +static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr)  {  	struct dasd_device *device = cqr->startdev;  	struct ccw1 *ccw; - -	/* allocate additional request block */  	struct dasd_ccw_req *erp; +	int cplength, datasize; +	struct tcw *tcw; +	struct tsb *tsb; + +	if (cqr->cpmode == 1) { +		cplength = 0; +		datasize = sizeof(struct tcw) + sizeof(struct tsb); +	} else { +		cplength = 2; +		datasize = 0; +	} -	erp = dasd_alloc_erp_request((char *) &cqr->magic, 2, 0, device); +	/* allocate additional request block */ +	erp = dasd_alloc_erp_request((char *) &cqr->magic, +				     cplength, datasize, device);  	if (IS_ERR(erp)) {                  if (cqr->retries <= 0) { -		        DEV_MESSAGE(KERN_ERR, device, "%s", +			DBF_DEV_EVENT(DBF_ERR, device, "%s",  				    "Unable to allocate ERP request");  			cqr->status = DASD_CQR_FAILED;                          cqr->stopclk = get_clock ();  		} else { -                        DEV_MESSAGE (KERN_ERR, device, +			DBF_DEV_EVENT(DBF_ERR, device,                                       "Unable to allocate ERP request "  				     "(%i retries left)",                                       cqr->retries); @@ -2266,13 +2295,24 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)  		return cqr;  	} -	/* initialize request with default TIC to current ERP/CQR */ -	ccw = erp->cpaddr; -	ccw->cmd_code = CCW_CMD_NOOP; -	ccw->flags = CCW_FLAG_CC; -	ccw++; -	ccw->cmd_code = CCW_CMD_TIC; -	ccw->cda      = (long)(cqr->cpaddr); +	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; +		tsb = (struct tsb *) &tcw[1]; +		*tcw = *((struct tcw *)cqr->cpaddr); +		tcw->tsb = (long)tsb; +	} else { +		/* initialize request with default TIC to current ERP/CQR */ +		ccw = erp->cpaddr; +		ccw->cmd_code = CCW_CMD_NOOP; +		ccw->flags = CCW_FLAG_CC; +		ccw++; +		ccw->cmd_code = CCW_CMD_TIC; +		ccw->cda      = (long)(cqr->cpaddr); +	} +  	erp->function = dasd_3990_erp_add_erp;  	erp->refers   = cqr;  	erp->startdev = device; @@ -2282,7 +2322,6 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)  	erp->expires  = 0;  	erp->retries  = 256;  	erp->buildclk = get_clock(); -  	erp->status = DASD_CQR_FILLED;  	return erp; @@ -2340,28 +2379,33 @@ dasd_3990_erp_additional_erp(struct dasd_ccw_req * cqr)   *   match		'boolean' for match found   *			returns 1 if match found, otherwise 0.   */ -static int -dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2) +static int dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, +				     struct dasd_ccw_req *cqr2)  { +	char *sense1, *sense2;  	if (cqr1->startdev != cqr2->startdev)  		return 0; -	if (cqr1->irb.esw.esw0.erw.cons != cqr2->irb.esw.esw0.erw.cons) -		return 0; +	sense1 = dasd_get_sense(&cqr1->irb); +	sense2 = dasd_get_sense(&cqr2->irb); -	if ((cqr1->irb.esw.esw0.erw.cons == 0) && -	    (cqr2->irb.esw.esw0.erw.cons == 0))	{ -		if ((cqr1->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK | -					     SCHN_STAT_CHN_CTRL_CHK)) == -		    (cqr2->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK | -					     SCHN_STAT_CHN_CTRL_CHK))) +	/* one request has sense data, the other not -> no match, return 0 */ +	if (!sense1 != !sense2) +		return 0; +	/* no sense data in both cases -> check cstat for IFCC */ +	if (!sense1 && !sense2)	{ +		if ((scsw_cstat(&cqr1->irb.scsw) & (SCHN_STAT_INTF_CTRL_CHK | +						    SCHN_STAT_CHN_CTRL_CHK)) == +		    (scsw_cstat(&cqr2->irb.scsw) & (SCHN_STAT_INTF_CTRL_CHK | +						    SCHN_STAT_CHN_CTRL_CHK)))  			return 1; /* match with ifcc*/  	}  	/* check sense data; byte 0-2,25,27 */ -	if (!((memcmp (cqr1->irb.ecw, cqr2->irb.ecw, 3) == 0) && -	      (cqr1->irb.ecw[27] == cqr2->irb.ecw[27]) && -	      (cqr1->irb.ecw[25] == cqr2->irb.ecw[25]))) { +	if (!(sense1 && sense2 && +	      (memcmp(sense1, sense2, 3) == 0) && +	      (sense1[27] == sense2[27]) && +	      (sense1[25] == sense2[25]))) {  		return 0;	/* sense doesn't match */  	} @@ -2434,7 +2478,7 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)  {  	struct dasd_device *device = erp->startdev; -	char *sense = erp->irb.ecw; +	char *sense = dasd_get_sense(&erp->irb);  	/* check for 24 byte sense ERP */  	if ((erp->function == dasd_3990_erp_bus_out) || @@ -2449,7 +2493,7 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)  		/* prepare erp for retry on different channel path */  		erp = dasd_3990_erp_action_1(erp); -		if (!(sense[2] & DASD_SENSE_BIT_0)) { +		if (sense && !(sense[2] & DASD_SENSE_BIT_0)) {  			/* issue a Diagnostic Control command with an  			 * Inhibit Write subcommand */ @@ -2471,7 +2515,7 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)  					break;  				}  			default: -				DEV_MESSAGE(KERN_DEBUG, device, +				DBF_DEV_EVENT(DBF_WARNING, device,  					    "invalid subcommand modifier 0x%x "  					    "for Diagnostic Control Command",  					    sense[25]); @@ -2479,19 +2523,21 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)  		}  		/* check for 32 byte sense ERP */ -	} else if ((erp->function == dasd_3990_erp_compound_retry) || -		   (erp->function == dasd_3990_erp_compound_path) || -		   (erp->function == dasd_3990_erp_compound_code) || -		   (erp->function == dasd_3990_erp_compound_config)) { +	} else if (sense && +		   ((erp->function == dasd_3990_erp_compound_retry) || +		    (erp->function == dasd_3990_erp_compound_path) || +		    (erp->function == dasd_3990_erp_compound_code) || +		    (erp->function == dasd_3990_erp_compound_config))) {  		erp = dasd_3990_erp_compound(erp, sense);  	} else { -		/* No retry left and no additional special handling */ -		/*necessary */ -		DEV_MESSAGE(KERN_ERR, device, -			    "no retries left for erp %p - " -			    "set status to FAILED", erp); +		/* +		 * No retry left and no additional special handling +		 * necessary +		 */ +		dev_err(&device->cdev->dev, +			"ERP %p has run out of retries and failed\n", erp);  		erp->status = DASD_CQR_FAILED;  	} @@ -2548,24 +2594,25 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,  	if (erp->retries > 0) { -		char *sense = erp->refers->irb.ecw; +		char *sense = dasd_get_sense(&erp->refers->irb);  		/* check for special retries */ -		if (erp->function == dasd_3990_erp_action_4) { +		if (sense && erp->function == dasd_3990_erp_action_4) {  			erp = dasd_3990_erp_action_4(erp, sense); -		} else if (erp->function == dasd_3990_erp_action_1B_32) { +		} else if (sense && +			   erp->function == dasd_3990_erp_action_1B_32) {  			erp = dasd_3990_update_1B(erp, sense); -		} else if (erp->function == dasd_3990_erp_int_req) { +		} else if (sense && erp->function == dasd_3990_erp_int_req) {  			erp = dasd_3990_erp_int_req(erp);  		} else {  			/* simple retry	  */ -			DEV_MESSAGE(KERN_DEBUG, device, +			DBF_DEV_EVENT(DBF_DEBUG, device,  				    "%i retries left for erp %p",  				    erp->retries, erp); @@ -2609,24 +2656,24 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)  	if (device->features & DASD_FEATURE_ERPLOG) {  		/* print current erp_chain */ -		DEV_MESSAGE(KERN_ERR, device, "%s", -			    "ERP chain at BEGINNING of ERP-ACTION"); +		dev_err(&device->cdev->dev, +			    "ERP chain at BEGINNING of ERP-ACTION\n");  		for (temp_erp = cqr;  		     temp_erp != NULL; temp_erp = temp_erp->refers) { -			DEV_MESSAGE(KERN_ERR, device, -				    "   erp %p (%02x) refers to %p", +			dev_err(&device->cdev->dev, +				    "ERP %p (%02x) refers to %p\n",  				    temp_erp, temp_erp->status,  				    temp_erp->refers);  		}  	}  	/* double-check if current erp/cqr was successful */ -	if ((cqr->irb.scsw.cmd.cstat == 0x00) && -	    (cqr->irb.scsw.cmd.dstat == +	if ((scsw_cstat(&cqr->irb.scsw) == 0x00) && +	    (scsw_dstat(&cqr->irb.scsw) ==  	     (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { -		DEV_MESSAGE(KERN_DEBUG, device, +		DBF_DEV_EVENT(DBF_DEBUG, device,  			    "ERP called for successful request %p"  			    " - NO ERP necessary", cqr); @@ -2648,13 +2695,13 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)  	if (device->features & DASD_FEATURE_ERPLOG) {  		/* print current erp_chain */ -		DEV_MESSAGE(KERN_ERR, device, "%s", -			    "ERP chain at END of ERP-ACTION"); +		dev_err(&device->cdev->dev, +			    "ERP chain at END of ERP-ACTION\n");  		for (temp_erp = erp;  		     temp_erp != NULL; temp_erp = temp_erp->refers) { -			DEV_MESSAGE(KERN_ERR, device, -				    "   erp %p (%02x) refers to %p", +			dev_err(&device->cdev->dev, +				    "ERP %p (%02x) refers to %p\n",  				    temp_erp, temp_erp->status,  				    temp_erp->refers);  		} @@ -2667,6 +2714,8 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)  		list_add_tail(&erp->blocklist, &cqr->blocklist);  	} + +  	return erp;  }				/* end dasd_3990_erp_action */ diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 20676cdef4a5..5b7bbc87593b 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -5,6 +5,8 @@   * Author(s): Stefan Weinhuber <wein@de.ibm.com>   */ +#define KMSG_COMPONENT "dasd" +  #include <linux/list.h>  #include <asm/ebcdic.h>  #include "dasd_int.h" @@ -503,7 +505,7 @@ static void lcu_update_work(struct work_struct *work)  	 */  	spin_lock_irqsave(&lcu->lock, flags);  	if (rc || (lcu->flags & NEED_UAC_UPDATE)) { -		DEV_MESSAGE(KERN_WARNING, device, "could not update" +		DBF_DEV_EVENT(DBF_WARNING, device, "could not update"  			    " alias data in lcu (rc = %d), retry later", rc);  		schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ);  	} else { @@ -646,14 +648,16 @@ static int reset_summary_unit_check(struct alias_lcu *lcu,  {  	struct dasd_ccw_req *cqr;  	int rc = 0; +	struct ccw1 *ccw;  	cqr = lcu->rsu_cqr;  	strncpy((char *) &cqr->magic, "ECKD", 4);  	ASCEBC((char *) &cqr->magic, 4); -	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RSCK; -	cqr->cpaddr->flags = 0 ; -	cqr->cpaddr->count = 16; -	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; +	ccw = cqr->cpaddr; +	ccw->cmd_code = DASD_ECKD_CCW_RSCK; +	ccw->flags = 0 ; +	ccw->count = 16; +	ccw->cda = (__u32)(addr_t) cqr->data;  	((char *)cqr->data)[0] = reason;  	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); @@ -855,16 +859,25 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device,  	struct alias_lcu *lcu;  	char reason;  	struct dasd_eckd_private *private; +	char *sense;  	private = (struct dasd_eckd_private *) device->private; -	reason = irb->ecw[8]; -	DEV_MESSAGE(KERN_WARNING, device, "%s %x", -		    "eckd handle summary unit check: reason", reason); +	sense = dasd_get_sense(irb); +	if (sense) { +		reason = sense[8]; +		DBF_DEV_EVENT(DBF_NOTICE, device, "%s %x", +			    "eckd handle summary unit check: reason", reason); +	} else { +		DBF_DEV_EVENT(DBF_WARNING, device, "%s", +			    "eckd handle summary unit check:" +			    " no reason code available"); +		return; +	}  	lcu = private->lcu;  	if (!lcu) { -		DEV_MESSAGE(KERN_WARNING, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "device not ready to handle summary"  			    " unit check (no lcu structure)");  		return; @@ -877,7 +890,7 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device,  	 * the next interrupt on a different device  	 */  	if (list_empty(&device->alias_list)) { -		DEV_MESSAGE(KERN_WARNING, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "device is in offline processing,"  			    " don't do summary unit check handling");  		spin_unlock(&lcu->lock); @@ -885,7 +898,7 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device,  	}  	if (lcu->suc_data.device) {  		/* already scheduled or running */ -		DEV_MESSAGE(KERN_WARNING, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "previous instance of summary unit check worker"  			    " still pending");  		spin_unlock(&lcu->lock); diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 34339902efb9..e77666c8e6c0 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -13,6 +13,8 @@   *   */ +#define KMSG_COMPONENT "dasd" +  #include <linux/ctype.h>  #include <linux/init.h>  #include <linux/module.h> @@ -67,6 +69,8 @@ int dasd_probeonly =  0;	/* is true, when probeonly mode is active */  int dasd_autodetect = 0;	/* is true, when autodetection is active */  int dasd_nopav = 0;		/* is true, when PAV is disabled */  EXPORT_SYMBOL_GPL(dasd_nopav); +int dasd_nofcx;			/* disable High Performance Ficon */ +EXPORT_SYMBOL_GPL(dasd_nofcx);  /*   * char *dasd[] is intended to hold the ranges supplied by the dasd= statement @@ -125,6 +129,7 @@ __setup ("dasd=", dasd_call_setup);   * Read a device busid/devno from a string.   */  static int +  dasd_busid(char **str, int *id0, int *id1, int *devno)  {  	int val, old_style; @@ -132,8 +137,7 @@ dasd_busid(char **str, int *id0, int *id1, int *devno)  	/* Interpret ipldev busid */  	if (strncmp(DASD_IPLDEV, *str, strlen(DASD_IPLDEV)) == 0) {  		if (ipl_info.type != IPL_TYPE_CCW) { -			MESSAGE(KERN_ERR, "%s", "ipl device is not a ccw " -				"device"); +			pr_err("The IPL device is not a CCW device\n");  			return -EINVAL;  		}  		*id0 = 0; @@ -209,9 +213,8 @@ dasd_feature_list(char *str, char **endp)  		else if (len == 8 && !strncmp(str, "failfast", 8))  			features |= DASD_FEATURE_FAILFAST;  		else { -			MESSAGE(KERN_WARNING, -				"unsupported feature: %*s, " -				"ignoring setting", len, str); +			pr_warning("%*s is not a supported device option\n", +				   len, str);  			rc = -EINVAL;  		}  		str += len; @@ -220,8 +223,8 @@ dasd_feature_list(char *str, char **endp)  		str++;  	}  	if (*str != ')') { -		MESSAGE(KERN_WARNING, "%s", -			"missing ')' in dasd parameter string\n"); +		pr_warning("A closing parenthesis ')' is missing in the " +			   "dasd= parameter\n");  		rc = -EINVAL;  	} else  		str++; @@ -253,25 +256,29 @@ dasd_parse_keyword( char *parsestring ) {          }  	if (strncmp("autodetect", parsestring, length) == 0) {  		dasd_autodetect = 1; -		MESSAGE (KERN_INFO, "%s", -			 "turning to autodetection mode"); +		pr_info("The autodetection mode has been activated\n");                  return residual_str;          }  	if (strncmp("probeonly", parsestring, length) == 0) {  		dasd_probeonly = 1; -		MESSAGE(KERN_INFO, "%s", -			"turning to probeonly mode"); +		pr_info("The probeonly mode has been activated\n");                  return residual_str;          }  	if (strncmp("nopav", parsestring, length) == 0) {  		if (MACHINE_IS_VM) -			MESSAGE(KERN_INFO, "%s", "'nopav' not supported on VM"); +			pr_info("'nopav' is not supported on z/VM\n");  		else {  			dasd_nopav = 1; -			MESSAGE(KERN_INFO, "%s", "disable PAV mode"); +			pr_info("PAV support has be deactivated\n");  		}  		return residual_str;  	} +	if (strncmp("nofcx", parsestring, length) == 0) { +		dasd_nofcx = 1; +		pr_info("High Performance FICON support has been " +			"deactivated\n"); +		return residual_str; +	}  	if (strncmp("fixedbuffers", parsestring, length) == 0) {  		if (dasd_page_cache)  			return residual_str; @@ -280,10 +287,10 @@ dasd_parse_keyword( char *parsestring ) {  					  PAGE_SIZE, SLAB_CACHE_DMA,  					  NULL);  		if (!dasd_page_cache) -			MESSAGE(KERN_WARNING, "%s", "Failed to create slab, " +			DBF_EVENT(DBF_WARNING, "%s", "Failed to create slab, "  				"fixed buffer mode disabled.");  		else -			MESSAGE (KERN_INFO, "%s", +			DBF_EVENT(DBF_INFO, "%s",  				 "turning on fixed buffer mode");                  return residual_str;          } @@ -321,7 +328,7 @@ dasd_parse_range( char *parsestring ) {  	    (from_id0 != to_id0 || from_id1 != to_id1 || from > to))  		rc = -EINVAL;  	if (rc) { -		MESSAGE(KERN_ERR, "Invalid device range %s", parsestring); +		pr_err("%s is not a valid device range\n", parsestring);  		return ERR_PTR(rc);  	}  	features = dasd_feature_list(str, &str); @@ -340,8 +347,8 @@ dasd_parse_range( char *parsestring ) {  		return str + 1;  	if (*str == '\0')  		return str; -	MESSAGE(KERN_WARNING, -		"junk at end of dasd parameter string: %s\n", str); +	pr_warning("The dasd= parameter value %s has an invalid ending\n", +		   str);  	return ERR_PTR(-EINVAL);  } diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index ef2a56952054..b9a7f7733446 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -8,6 +8,8 @@   *   */ +#define KMSG_COMPONENT "dasd" +  #include <linux/stddef.h>  #include <linux/kernel.h>  #include <linux/slab.h> @@ -144,8 +146,8 @@ dasd_diag_erp(struct dasd_device *device)  	mdsk_term_io(device);  	rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);  	if (rc) -		DEV_MESSAGE(KERN_WARNING, device, "DIAG ERP unsuccessful, " -			    "rc=%d", rc); +		dev_warn(&device->cdev->dev, "DIAG ERP failed with " +			    "rc=%d\n", rc);  }  /* Start a given request at the device. Return zero on success, non-zero @@ -160,7 +162,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr)  	device = cqr->startdev;  	if (cqr->retries < 0) { -		DEV_MESSAGE(KERN_WARNING, device, "DIAG start_IO: request %p " +		DBF_DEV_EVENT(DBF_ERR, device, "DIAG start_IO: request %p "  			    "- no retry left)", cqr);  		cqr->status = DASD_CQR_ERROR;  		return -EIO; @@ -195,7 +197,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr)  		break;  	default: /* Error condition */  		cqr->status = DASD_CQR_QUEUED; -		DEV_MESSAGE(KERN_WARNING, device, "dia250 returned rc=%d", rc); +		DBF_DEV_EVENT(DBF_WARNING, device, "dia250 returned rc=%d", rc);  		dasd_diag_erp(device);  		rc = -EIO;  		break; @@ -243,13 +245,14 @@ dasd_ext_handler(__u16 code)  		return;  	}  	if (!ip) {		/* no intparm: unsolicited interrupt */ -		MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt"); +		DBF_EVENT(DBF_NOTICE, "%s", "caught unsolicited " +			      "interrupt");  		return;  	}  	cqr = (struct dasd_ccw_req *) ip;  	device = (struct dasd_device *) cqr->startdev;  	if (strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { -		DEV_MESSAGE(KERN_WARNING, device, +		DBF_DEV_EVENT(DBF_WARNING, device,  			    " magic number of dasd_ccw_req 0x%08X doesn't"  			    " match discipline 0x%08X",  			    cqr->magic, *(int *) (&device->discipline->name)); @@ -281,15 +284,11 @@ dasd_ext_handler(__u16 code)  				rc = dasd_start_diag(next);  				if (rc == 0)  					expires = next->expires; -				else if (rc != -EACCES) -					DEV_MESSAGE(KERN_WARNING, device, "%s", -						    "Interrupt fastpath " -						    "failed!");  			}  		}  	} else {  		cqr->status = DASD_CQR_QUEUED; -		DEV_MESSAGE(KERN_WARNING, device, "interrupt status for " +		DBF_DEV_EVENT(DBF_DEBUG, device, "interrupt status for "  			    "request %p was %d (%d retries left)", cqr, status,  			    cqr->retries);  		dasd_diag_erp(device); @@ -322,8 +321,9 @@ dasd_diag_check_device(struct dasd_device *device)  	if (private == NULL) {  		private = kzalloc(sizeof(struct dasd_diag_private),GFP_KERNEL);  		if (private == NULL) { -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				"memory allocation failed for private data"); +			DBF_DEV_EVENT(DBF_WARNING, device, "%s", +				"Allocating memory for private DASD data " +				      "failed\n");  			return -ENOMEM;  		}  		ccw_device_get_id(device->cdev, &private->dev_id); @@ -331,7 +331,7 @@ dasd_diag_check_device(struct dasd_device *device)  	}  	block = dasd_alloc_block();  	if (IS_ERR(block)) { -		DEV_MESSAGE(KERN_WARNING, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "could not allocate dasd block structure");  		device->private = NULL;  		kfree(private); @@ -347,7 +347,7 @@ dasd_diag_check_device(struct dasd_device *device)  	rc = diag210((struct diag210 *) rdc_data);  	if (rc) { -		DEV_MESSAGE(KERN_WARNING, device, "failed to retrieve device " +		DBF_DEV_EVENT(DBF_WARNING, device, "failed to retrieve device "  			    "information (rc=%d)", rc);  		rc = -EOPNOTSUPP;  		goto out; @@ -362,8 +362,8 @@ dasd_diag_check_device(struct dasd_device *device)  		private->pt_block = 2;  		break;  	default: -		DEV_MESSAGE(KERN_WARNING, device, "unsupported device class " -			    "(class=%d)", private->rdc_data.vdev_class); +		dev_warn(&device->cdev->dev, "Device type %d is not supported " +			    "in DIAG mode\n", private->rdc_data.vdev_class);  		rc = -EOPNOTSUPP;  		goto out;  	} @@ -380,7 +380,7 @@ dasd_diag_check_device(struct dasd_device *device)  	/* figure out blocksize of device */  	label = (struct vtoc_cms_label *) get_zeroed_page(GFP_KERNEL);  	if (label == NULL)  { -		DEV_MESSAGE(KERN_WARNING, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "No memory to allocate initialization request");  		rc = -ENOMEM;  		goto out; @@ -404,8 +404,8 @@ dasd_diag_check_device(struct dasd_device *device)  		private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;  		rc = dia250(&private->iob, RW_BIO);  		if (rc == 3) { -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				"DIAG call failed"); +			dev_warn(&device->cdev->dev, +				"A 64-bit DIAG call failed\n");  			rc = -EOPNOTSUPP;  			goto out_label;  		} @@ -414,8 +414,8 @@ dasd_diag_check_device(struct dasd_device *device)  			break;  	}  	if (bsize > PAGE_SIZE) { -		DEV_MESSAGE(KERN_WARNING, device, "device access failed " -			    "(rc=%d)", rc); +		dev_warn(&device->cdev->dev, "Accessing the DASD failed because" +			 " of an incorrect format (rc=%d)\n", rc);  		rc = -EIO;  		goto out_label;  	} @@ -433,15 +433,15 @@ dasd_diag_check_device(struct dasd_device *device)  		block->s2b_shift++;  	rc = mdsk_init_io(device, block->bp_block, 0, NULL);  	if (rc) { -		DEV_MESSAGE(KERN_WARNING, device, "DIAG initialization " -			"failed (rc=%d)", rc); +		dev_warn(&device->cdev->dev, "DIAG initialization " +			"failed with rc=%d\n", rc);  		rc = -EIO;  	} else { -		DEV_MESSAGE(KERN_INFO, device, -			    "(%ld B/blk): %ldkB", -			    (unsigned long) block->bp_block, -			    (unsigned long) (block->blocks << -				block->s2b_shift) >> 1); +		dev_info(&device->cdev->dev, +			 "New DASD with %ld byte/block, total size %ld KB\n", +			 (unsigned long) block->bp_block, +			 (unsigned long) (block->blocks << +					  block->s2b_shift) >> 1);  	}  out_label:  	free_page((long) label); @@ -595,7 +595,7 @@ static void  dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,  		     struct irb *stat)  { -	DEV_MESSAGE(KERN_ERR, device, "%s", +	DBF_DEV_EVENT(DBF_WARNING, device, "%s",  		    "dump sense not available for DIAG data");  } @@ -621,10 +621,8 @@ static int __init  dasd_diag_init(void)  {  	if (!MACHINE_IS_VM) { -		MESSAGE_LOG(KERN_INFO, -			    "Machine is not VM: %s " -			    "discipline not initializing", -			    dasd_diag_discipline.name); +		pr_info("Discipline %s cannot be used without z/VM\n", +			dasd_diag_discipline.name);  		return -ENODEV;  	}  	ASCEBC(dasd_diag_discipline.ebcname, 4); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index bdb87998f364..21254793c604 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -11,6 +11,8 @@   *   */ +#define KMSG_COMPONENT "dasd" +  #include <linux/stddef.h>  #include <linux/kernel.h>  #include <linux/slab.h> @@ -27,9 +29,12 @@  #include <asm/uaccess.h>  #include <asm/cio.h>  #include <asm/ccwdev.h> +#include <asm/itcw.h>  #include "dasd_int.h"  #include "dasd_eckd.h" +#include "../cio/chsc.h" +  #ifdef PRINTK_HEADER  #undef PRINTK_HEADER @@ -84,7 +89,7 @@ dasd_eckd_probe (struct ccw_device *cdev)  	/* set ECKD specific ccw-device options */  	ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE);  	if (ret) { -		printk(KERN_WARNING +		DBF_EVENT(DBF_WARNING,  		       "dasd_eckd_probe: could not set ccw-device options "  		       "for %s\n", dev_name(&cdev->dev));  		return ret; @@ -159,6 +164,14 @@ recs_per_track(struct dasd_eckd_characteristics * rdc,  	return 0;  } +static void set_ch_t(struct ch_t *geo, __u32 cyl, __u8 head) +{ +	geo->cyl = (__u16) cyl; +	geo->head = cyl >> 16; +	geo->head <<= 4; +	geo->head |= head; +} +  static int  check_XRC (struct ccw1         *de_ccw,             struct DE_eckd_data *data, @@ -186,11 +199,12 @@ check_XRC (struct ccw1         *de_ccw,  }  static int -define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, -	      int totrk, int cmd, struct dasd_device * device) +define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk, +	      unsigned int totrk, int cmd, struct dasd_device *device)  {  	struct dasd_eckd_private *private; -	struct ch_t geo, beg, end; +	u32 begcyl, endcyl; +	u16 heads, beghead, endhead;  	int rc = 0;  	private = (struct dasd_eckd_private *) device->private; @@ -236,7 +250,8 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,  		rc = check_XRC (ccw, data, device);  		break;  	default: -		DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd); +		dev_err(&device->cdev->dev, +			"0x%x is not a known command\n", cmd);  		break;  	} @@ -248,27 +263,24 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,  	    && !(private->uses_cdl && trk < 2))  		data->ga_extended |= 0x40; /* Regular Data Format Mode */ -	geo.cyl = private->rdc_data.no_cyl; -	geo.head = private->rdc_data.trk_per_cyl; -	beg.cyl = trk / geo.head; -	beg.head = trk % geo.head; -	end.cyl = totrk / geo.head; -	end.head = totrk % geo.head; +	heads = private->rdc_data.trk_per_cyl; +	begcyl = trk / heads; +	beghead = trk % heads; +	endcyl = totrk / heads; +	endhead = totrk % heads;  	/* check for sequential prestage - enhance cylinder range */  	if (data->attributes.operation == DASD_SEQ_PRESTAGE ||  	    data->attributes.operation == DASD_SEQ_ACCESS) { -		if (end.cyl + private->attrib.nr_cyl < geo.cyl) -			end.cyl += private->attrib.nr_cyl; +		if (endcyl + private->attrib.nr_cyl < private->real_cyl) +			endcyl += private->attrib.nr_cyl;  		else -			end.cyl = (geo.cyl - 1); +			endcyl = (private->real_cyl - 1);  	} -	data->beg_ext.cyl = beg.cyl; -	data->beg_ext.head = beg.head; -	data->end_ext.cyl = end.cyl; -	data->end_ext.head = end.head; +	set_ch_t(&data->beg_ext, begcyl, beghead); +	set_ch_t(&data->end_ext, endcyl, endhead);  	return rc;  } @@ -283,29 +295,145 @@ static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata,  		return 0;  	/* switch on System Time Stamp - needed for XRC Support */ -	pfxdata->define_extend.ga_extended |= 0x08; /* 'Time Stamp Valid'   */ -	pfxdata->define_extend.ga_extended |= 0x02; /* 'Extended Parameter' */ +	pfxdata->define_extent.ga_extended |= 0x08; /* 'Time Stamp Valid'   */ +	pfxdata->define_extent.ga_extended |= 0x02; /* 'Extended Parameter' */  	pfxdata->validity.time_stamp = 1;	    /* 'Time Stamp Valid'   */ -	rc = get_sync_clock(&pfxdata->define_extend.ep_sys_time); +	rc = get_sync_clock(&pfxdata->define_extent.ep_sys_time);  	/* Ignore return code if sync clock is switched off. */  	if (rc == -ENOSYS || rc == -EACCES)  		rc = 0;  	return rc;  } -static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk, -		  int totrk, int cmd, struct dasd_device *basedev, -		  struct dasd_device *startdev) +static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk, +			  unsigned int rec_on_trk, int count, int cmd, +			  struct dasd_device *device, unsigned int reclen, +			  unsigned int tlf) +{ +	struct dasd_eckd_private *private; +	int sector; +	int dn, d; + +	private = (struct dasd_eckd_private *) device->private; + +	memset(data, 0, sizeof(*data)); +	sector = 0; +	if (rec_on_trk) { +		switch (private->rdc_data.dev_type) { +		case 0x3390: +			dn = ceil_quot(reclen + 6, 232); +			d = 9 + ceil_quot(reclen + 6 * (dn + 1), 34); +			sector = (49 + (rec_on_trk - 1) * (10 + d)) / 8; +			break; +		case 0x3380: +			d = 7 + ceil_quot(reclen + 12, 32); +			sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7; +			break; +		} +	} +	data->sector = sector; +	/* note: meaning of count depends on the operation +	 *	 for record based I/O it's the number of records, but for +	 *	 track based I/O it's the number of tracks +	 */ +	data->count = count; +	switch (cmd) { +	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: +		data->operation.orientation = 0x3; +		data->operation.operation = 0x03; +		break; +	case DASD_ECKD_CCW_READ_HOME_ADDRESS: +		data->operation.orientation = 0x3; +		data->operation.operation = 0x16; +		break; +	case DASD_ECKD_CCW_WRITE_RECORD_ZERO: +		data->operation.orientation = 0x1; +		data->operation.operation = 0x03; +		data->count++; +		break; +	case DASD_ECKD_CCW_READ_RECORD_ZERO: +		data->operation.orientation = 0x3; +		data->operation.operation = 0x16; +		data->count++; +		break; +	case DASD_ECKD_CCW_WRITE: +	case DASD_ECKD_CCW_WRITE_MT: +	case DASD_ECKD_CCW_WRITE_KD: +	case DASD_ECKD_CCW_WRITE_KD_MT: +		data->auxiliary.length_valid = 0x1; +		data->length = reclen; +		data->operation.operation = 0x01; +		break; +	case DASD_ECKD_CCW_WRITE_CKD: +	case DASD_ECKD_CCW_WRITE_CKD_MT: +		data->auxiliary.length_valid = 0x1; +		data->length = reclen; +		data->operation.operation = 0x03; +		break; +	case DASD_ECKD_CCW_WRITE_TRACK_DATA: +		data->auxiliary.length_valid = 0x1; +		data->length = reclen;	/* not tlf, as one might think */ +		data->operation.operation = 0x3F; +		data->extended_operation = 0x23; +		break; +	case DASD_ECKD_CCW_READ: +	case DASD_ECKD_CCW_READ_MT: +	case DASD_ECKD_CCW_READ_KD: +	case DASD_ECKD_CCW_READ_KD_MT: +		data->auxiliary.length_valid = 0x1; +		data->length = reclen; +		data->operation.operation = 0x06; +		break; +	case DASD_ECKD_CCW_READ_CKD: +	case DASD_ECKD_CCW_READ_CKD_MT: +		data->auxiliary.length_valid = 0x1; +		data->length = reclen; +		data->operation.operation = 0x16; +		break; +	case DASD_ECKD_CCW_READ_COUNT: +		data->operation.operation = 0x06; +		break; +	case DASD_ECKD_CCW_READ_TRACK_DATA: +		data->auxiliary.length_valid = 0x1; +		data->length = tlf; +		data->operation.operation = 0x0C; +		break; +	case DASD_ECKD_CCW_ERASE: +		data->length = reclen; +		data->auxiliary.length_valid = 0x1; +		data->operation.operation = 0x0b; +		break; +	default: +		DBF_DEV_EVENT(DBF_ERR, device, +			    "fill LRE unknown opcode 0x%x", cmd); +		BUG(); +	} +	set_ch_t(&data->seek_addr, +		 trk / private->rdc_data.trk_per_cyl, +		 trk % private->rdc_data.trk_per_cyl); +	data->search_arg.cyl = data->seek_addr.cyl; +	data->search_arg.head = data->seek_addr.head; +	data->search_arg.record = rec_on_trk; +} + +static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, +		      unsigned int trk, unsigned int totrk, int cmd, +		      struct dasd_device *basedev, struct dasd_device *startdev, +		      unsigned char format, unsigned int rec_on_trk, int count, +		      unsigned int blksize, unsigned int tlf)  {  	struct dasd_eckd_private *basepriv, *startpriv; -	struct DE_eckd_data *data; -	struct ch_t geo, beg, end; +	struct DE_eckd_data *dedata; +	struct LRE_eckd_data *lredata; +	u32 begcyl, endcyl; +	u16 heads, beghead, endhead;  	int rc = 0;  	basepriv = (struct dasd_eckd_private *) basedev->private;  	startpriv = (struct dasd_eckd_private *) startdev->private; -	data = &pfxdata->define_extend; +	dedata = &pfxdata->define_extent; +	lredata = &pfxdata->locate_record;  	ccw->cmd_code = DASD_ECKD_CCW_PFX;  	ccw->flags = 0; @@ -314,10 +442,16 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk,  	memset(pfxdata, 0, sizeof(*pfxdata));  	/* prefix data */ -	pfxdata->format = 0; +	if (format > 1) { +		DBF_DEV_EVENT(DBF_ERR, basedev, +			      "PFX LRE unknown format 0x%x", format); +		BUG(); +		return -EINVAL; +	} +	pfxdata->format = format;  	pfxdata->base_address = basepriv->ned->unit_addr;  	pfxdata->base_lss = basepriv->ned->ID; -	pfxdata->validity.define_extend = 1; +	pfxdata->validity.define_extent = 1;  	/* private uid is kept up to date, conf_data may be outdated */  	if (startpriv->uid.type != UA_BASE_DEVICE) { @@ -337,70 +471,94 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk,  	case DASD_ECKD_CCW_READ_KD:  	case DASD_ECKD_CCW_READ_KD_MT:  	case DASD_ECKD_CCW_READ_COUNT: -		data->mask.perm = 0x1; -		data->attributes.operation = basepriv->attrib.operation; +		dedata->mask.perm = 0x1; +		dedata->attributes.operation = basepriv->attrib.operation; +		break; +	case DASD_ECKD_CCW_READ_TRACK_DATA: +		dedata->mask.perm = 0x1; +		dedata->attributes.operation = basepriv->attrib.operation; +		dedata->blk_size = 0;  		break;  	case DASD_ECKD_CCW_WRITE:  	case DASD_ECKD_CCW_WRITE_MT:  	case DASD_ECKD_CCW_WRITE_KD:  	case DASD_ECKD_CCW_WRITE_KD_MT: -		data->mask.perm = 0x02; -		data->attributes.operation = basepriv->attrib.operation; +		dedata->mask.perm = 0x02; +		dedata->attributes.operation = basepriv->attrib.operation;  		rc = check_XRC_on_prefix(pfxdata, basedev);  		break;  	case DASD_ECKD_CCW_WRITE_CKD:  	case DASD_ECKD_CCW_WRITE_CKD_MT: -		data->attributes.operation = DASD_BYPASS_CACHE; +		dedata->attributes.operation = DASD_BYPASS_CACHE;  		rc = check_XRC_on_prefix(pfxdata, basedev);  		break;  	case DASD_ECKD_CCW_ERASE:  	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:  	case DASD_ECKD_CCW_WRITE_RECORD_ZERO: -		data->mask.perm = 0x3; -		data->mask.auth = 0x1; -		data->attributes.operation = DASD_BYPASS_CACHE; +		dedata->mask.perm = 0x3; +		dedata->mask.auth = 0x1; +		dedata->attributes.operation = DASD_BYPASS_CACHE;  		rc = check_XRC_on_prefix(pfxdata, basedev);  		break; -	default: -		DEV_MESSAGE(KERN_ERR, basedev, "unknown opcode 0x%x", cmd); +	case DASD_ECKD_CCW_WRITE_TRACK_DATA: +		dedata->mask.perm = 0x02; +		dedata->attributes.operation = basepriv->attrib.operation; +		dedata->blk_size = blksize; +		rc = check_XRC_on_prefix(pfxdata, basedev);  		break; +	default: +		DBF_DEV_EVENT(DBF_ERR, basedev, +			    "PFX LRE unknown opcode 0x%x", cmd); +		BUG(); +		return -EINVAL;  	} -	data->attributes.mode = 0x3;	/* ECKD */ +	dedata->attributes.mode = 0x3;	/* ECKD */  	if ((basepriv->rdc_data.cu_type == 0x2105 ||  	     basepriv->rdc_data.cu_type == 0x2107 ||  	     basepriv->rdc_data.cu_type == 0x1750)  	    && !(basepriv->uses_cdl && trk < 2)) -		data->ga_extended |= 0x40; /* Regular Data Format Mode */ +		dedata->ga_extended |= 0x40; /* Regular Data Format Mode */ -	geo.cyl = basepriv->rdc_data.no_cyl; -	geo.head = basepriv->rdc_data.trk_per_cyl; -	beg.cyl = trk / geo.head; -	beg.head = trk % geo.head; -	end.cyl = totrk / geo.head; -	end.head = totrk % geo.head; +	heads = basepriv->rdc_data.trk_per_cyl; +	begcyl = trk / heads; +	beghead = trk % heads; +	endcyl = totrk / heads; +	endhead = totrk % heads;  	/* check for sequential prestage - enhance cylinder range */ -	if (data->attributes.operation == DASD_SEQ_PRESTAGE || -	    data->attributes.operation == DASD_SEQ_ACCESS) { +	if (dedata->attributes.operation == DASD_SEQ_PRESTAGE || +	    dedata->attributes.operation == DASD_SEQ_ACCESS) { -		if (end.cyl + basepriv->attrib.nr_cyl < geo.cyl) -			end.cyl += basepriv->attrib.nr_cyl; +		if (endcyl + basepriv->attrib.nr_cyl < basepriv->real_cyl) +			endcyl += basepriv->attrib.nr_cyl;  		else -			end.cyl = (geo.cyl - 1); +			endcyl = (basepriv->real_cyl - 1); +	} + +	set_ch_t(&dedata->beg_ext, begcyl, beghead); +	set_ch_t(&dedata->end_ext, endcyl, endhead); + +	if (format == 1) { +		fill_LRE_data(lredata, trk, rec_on_trk, count, cmd, +			      basedev, blksize, tlf);  	} -	data->beg_ext.cyl = beg.cyl; -	data->beg_ext.head = beg.head; -	data->end_ext.cyl = end.cyl; -	data->end_ext.head = end.head;  	return rc;  } +static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, +		  unsigned int trk, unsigned int totrk, int cmd, +		  struct dasd_device *basedev, struct dasd_device *startdev) +{ +	return prefix_LRE(ccw, pfxdata, trk, totrk, cmd, basedev, startdev, +			  0, 0, 0, 0, 0); +} +  static void -locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk, -	      int rec_on_trk, int no_rec, int cmd, +locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, unsigned int trk, +	      unsigned int rec_on_trk, int no_rec, int cmd,  	      struct dasd_device * device, int reclen)  {  	struct dasd_eckd_private *private; @@ -491,12 +649,14 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,  		data->operation.operation = 0x0b;  		break;  	default: -		DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd); -	} -	data->seek_addr.cyl = data->search_arg.cyl = -		trk / private->rdc_data.trk_per_cyl; -	data->seek_addr.head = data->search_arg.head = -		trk % private->rdc_data.trk_per_cyl; +		DBF_DEV_EVENT(DBF_ERR, device, "unknown locate record " +			      "opcode 0x%x", cmd); +	} +	set_ch_t(&data->seek_addr, +		 trk / private->rdc_data.trk_per_cyl, +		 trk % private->rdc_data.trk_per_cyl); +	data->search_arg.cyl = data->seek_addr.cyl; +	data->search_arg.head = data->seek_addr.head;  	data->search_arg.record = rec_on_trk;  } @@ -585,8 +745,8 @@ static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device,  	cqr = dasd_smalloc_request("ECKD", 1 /* RCD */, ciw->count, device);  	if (IS_ERR(cqr)) { -		DEV_MESSAGE(KERN_WARNING, device, "%s", -			    "Could not allocate RCD request"); +		DBF_DEV_EVENT(DBF_WARNING, device, "%s", +			      "Could not allocate RCD request");  		return cqr;  	} @@ -736,14 +896,16 @@ static int dasd_eckd_read_conf(struct dasd_device *device)  			rc = dasd_eckd_read_conf_lpm(device, &conf_data,  						     &conf_len, lpm);  			if (rc && rc != -EOPNOTSUPP) {	/* -EOPNOTSUPP is ok */ -				MESSAGE(KERN_WARNING, -					"Read configuration data returned " -					"error %d", rc); +				DBF_EVENT(DBF_WARNING, +					  "Read configuration data returned " +					  "error %d for device: %s", rc, +					  dev_name(&device->cdev->dev));  				return rc;  			}  			if (conf_data == NULL) { -				MESSAGE(KERN_WARNING, "%s", "No configuration " -					"data retrieved"); +				DBF_EVENT(DBF_WARNING, "No configuration " +					  "data retrieved for device: %s", +					  dev_name(&device->cdev->dev));  				continue;	/* no error */  			}  			/* save first valid configuration data */ @@ -790,8 +952,9 @@ static int dasd_eckd_read_features(struct dasd_device *device)  				    sizeof(struct dasd_rssd_features)),  				   device);  	if (IS_ERR(cqr)) { -		DEV_MESSAGE(KERN_WARNING, device, "%s", -			    "Could not allocate initialization request"); +		DBF_EVENT(DBF_WARNING, "Could not allocate initialization " +			  "request for device: %s", +			  dev_name(&device->cdev->dev));  		return PTR_ERR(cqr);  	}  	cqr->startdev = device; @@ -840,7 +1003,8 @@ static int dasd_eckd_read_features(struct dasd_device *device)  /*   * Build CP for Perform Subsystem Function - SSC.   */ -static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device) +static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device, +						    int enable_pav)  {  	struct dasd_ccw_req *cqr;  	struct dasd_psf_ssc_data *psf_ssc_data; @@ -851,15 +1015,17 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device)  				  device);  	if (IS_ERR(cqr)) { -		DEV_MESSAGE(KERN_WARNING, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			   "Could not allocate PSF-SSC request");  		return cqr;  	}  	psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;  	psf_ssc_data->order = PSF_ORDER_SSC; -	psf_ssc_data->suborder = 0x88; -	psf_ssc_data->reserved[0] = 0x88; - +	psf_ssc_data->suborder = 0x40; +	if (enable_pav) { +		psf_ssc_data->suborder |= 0x88; +		psf_ssc_data->reserved[0] = 0x88; +	}  	ccw = cqr->cpaddr;  	ccw->cmd_code = DASD_ECKD_CCW_PSF;  	ccw->cda = (__u32)(addr_t)psf_ssc_data; @@ -880,12 +1046,12 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device)   * call might change behaviour of DASD devices.   */  static int -dasd_eckd_psf_ssc(struct dasd_device *device) +dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav)  {  	struct dasd_ccw_req *cqr;  	int rc; -	cqr = dasd_eckd_build_psf_ssc(device); +	cqr = dasd_eckd_build_psf_ssc(device, enable_pav);  	if (IS_ERR(cqr))  		return PTR_ERR(cqr); @@ -904,19 +1070,20 @@ static int dasd_eckd_validate_server(struct dasd_device *device)  {  	int rc;  	struct dasd_eckd_private *private; +	int enable_pav; -	/* Currently PAV is the only reason to 'validate' server on LPAR */  	if (dasd_nopav || MACHINE_IS_VM) -		return 0; - -	rc = dasd_eckd_psf_ssc(device); +		enable_pav = 0; +	else +		enable_pav = 1; +	rc = dasd_eckd_psf_ssc(device, enable_pav);  	/* may be requested feature is not available on server,  	 * therefore just report error and go ahead */  	private = (struct dasd_eckd_private *) device->private; -	DEV_MESSAGE(KERN_INFO, device, -		    "PSF-SSC on storage subsystem %s.%s.%04x returned rc=%d", -		    private->uid.vendor, private->uid.serial, -		    private->uid.ssid, rc); +	DBF_EVENT(DBF_WARNING, "PSF-SSC on storage subsystem %s.%s.%04x " +		  "returned rc=%d for device: %s", +		  private->uid.vendor, private->uid.serial, +		  private->uid.ssid, rc, dev_name(&device->cdev->dev));  	/* RE-Read Configuration Data */  	return dasd_eckd_read_conf(device);  } @@ -938,9 +1105,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device)  		private = kzalloc(sizeof(struct dasd_eckd_private),  				  GFP_KERNEL | GFP_DMA);  		if (private == NULL) { -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "memory allocation failed for private " -				    "data"); +			dev_warn(&device->cdev->dev, +				 "Allocating memory for private DASD data " +				 "failed\n");  			return -ENOMEM;  		}  		device->private = (void *) private; @@ -965,8 +1132,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device)  	if (private->uid.type == UA_BASE_DEVICE) {  		block = dasd_alloc_block();  		if (IS_ERR(block)) { -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "could not allocate dasd block structure"); +			DBF_EVENT(DBF_WARNING, "could not allocate dasd " +				  "block structure for device: %s", +				  dev_name(&device->cdev->dev));  			rc = PTR_ERR(block);  			goto out_err1;  		} @@ -997,20 +1165,27 @@ dasd_eckd_check_characteristics(struct dasd_device *device)  	memset(rdc_data, 0, sizeof(rdc_data));  	rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64);  	if (rc) { -		DEV_MESSAGE(KERN_WARNING, device, -			    "Read device characteristics returned " -			    "rc=%d", rc); +		DBF_EVENT(DBF_WARNING, +			  "Read device characteristics failed, rc=%d for " +			  "device: %s", rc, dev_name(&device->cdev->dev));  		goto out_err3;  	} -	DEV_MESSAGE(KERN_INFO, device, -		    "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d", -		    private->rdc_data.dev_type, -		    private->rdc_data.dev_model, -		    private->rdc_data.cu_type, -		    private->rdc_data.cu_model.model, -		    private->rdc_data.no_cyl, -		    private->rdc_data.trk_per_cyl, -		    private->rdc_data.sec_per_trk); +	/* find the vaild cylinder size */ +	if (private->rdc_data.no_cyl == LV_COMPAT_CYL && +	    private->rdc_data.long_no_cyl) +		private->real_cyl = private->rdc_data.long_no_cyl; +	else +		private->real_cyl = private->rdc_data.no_cyl; + +	dev_info(&device->cdev->dev, "New DASD %04X/%02X (CU %04X/%02X) " +		 "with %d cylinders, %d heads, %d sectors\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);  	return 0;  out_err3: @@ -1151,14 +1326,12 @@ dasd_eckd_end_analysis(struct dasd_block *block)  	status = private->init_cqr_status;  	private->init_cqr_status = -1;  	if (status != DASD_CQR_DONE) { -		DEV_MESSAGE(KERN_WARNING, device, "%s", -			    "volume analysis returned unformatted disk"); +		dev_warn(&device->cdev->dev, +			    "The DASD is not formatted\n");  		return -EMEDIUMTYPE;  	}  	private->uses_cdl = 1; -	/* Calculate number of blocks/records per track. */ -	blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block);  	/* Check Track 0 for Compatible Disk Layout */  	count_area = NULL;  	for (i = 0; i < 3; i++) { @@ -1182,8 +1355,8 @@ dasd_eckd_end_analysis(struct dasd_block *block)  			count_area = &private->count_area[0];  	} else {  		if (private->count_area[3].record == 1) -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "Trk 0: no records after VTOC!"); +			dev_warn(&device->cdev->dev, +				 "Track 0 has no records following the VTOC\n");  	}  	if (count_area != NULL && count_area->kl == 0) {  		/* we found notthing violating our disk layout */ @@ -1191,8 +1364,8 @@ dasd_eckd_end_analysis(struct dasd_block *block)  			block->bp_block = count_area->dl;  	}  	if (block->bp_block == 0) { -		DEV_MESSAGE(KERN_WARNING, device, "%s", -			    "Volume has incompatible disk layout"); +		dev_warn(&device->cdev->dev, +			 "The disk layout of the DASD is not supported\n");  		return -EMEDIUMTYPE;  	}  	block->s2b_shift = 0;	/* bits to shift 512 to get a block */ @@ -1200,19 +1373,19 @@ dasd_eckd_end_analysis(struct dasd_block *block)  		block->s2b_shift++;  	blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block); -	block->blocks = (private->rdc_data.no_cyl * +	block->blocks = (private->real_cyl *  			  private->rdc_data.trk_per_cyl *  			  blk_per_trk); -	DEV_MESSAGE(KERN_INFO, device, -		    "(%dkB blks): %dkB at %dkB/trk %s", -		    (block->bp_block >> 10), -		    ((private->rdc_data.no_cyl * -		      private->rdc_data.trk_per_cyl * -		      blk_per_trk * (block->bp_block >> 9)) >> 1), -		    ((blk_per_trk * block->bp_block) >> 10), -		    private->uses_cdl ? -		    "compatible disk layout" : "linux disk layout"); +	dev_info(&device->cdev->dev, +		 "DASD with %d KB/block, %d KB total size, %d KB/track, " +		 "%s\n", (block->bp_block >> 10), +		 ((private->real_cyl * +		   private->rdc_data.trk_per_cyl * +		   blk_per_trk * (block->bp_block >> 9)) >> 1), +		 ((blk_per_trk * block->bp_block) >> 10), +		 private->uses_cdl ? +		 "compatible disk layout" : "linux disk layout");  	return 0;  } @@ -1262,31 +1435,35 @@ dasd_eckd_format_device(struct dasd_device * device,  	struct eckd_count *ect;  	struct ccw1 *ccw;  	void *data; -	int rpt, cyl, head; +	int rpt; +	struct ch_t address;  	int cplength, datasize;  	int i; +	int intensity = 0; +	int r0_perm;  	private = (struct dasd_eckd_private *) device->private;  	rpt = recs_per_track(&private->rdc_data, 0, fdata->blksize); -	cyl = fdata->start_unit / private->rdc_data.trk_per_cyl; -	head = fdata->start_unit % private->rdc_data.trk_per_cyl; +	set_ch_t(&address, +		 fdata->start_unit / private->rdc_data.trk_per_cyl, +		 fdata->start_unit % private->rdc_data.trk_per_cyl);  	/* Sanity checks. */  	if (fdata->start_unit >= -	    (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)) { -		DEV_MESSAGE(KERN_INFO, device, "Track no %d too big!", -			    fdata->start_unit); +	    (private->real_cyl * private->rdc_data.trk_per_cyl)) { +		dev_warn(&device->cdev->dev, "Start track number %d used in " +			 "formatting is too big\n", fdata->start_unit);  		return ERR_PTR(-EINVAL);  	}  	if (fdata->start_unit > fdata->stop_unit) { -		DEV_MESSAGE(KERN_INFO, device, "Track %d reached! ending.", -			    fdata->start_unit); +		dev_warn(&device->cdev->dev, "Start track %d used in " +			 "formatting exceeds end track\n", fdata->start_unit);  		return ERR_PTR(-EINVAL);  	}  	if (dasd_check_blocksize(fdata->blksize) != 0) { -		DEV_MESSAGE(KERN_WARNING, device, -			    "Invalid blocksize %d...terminating!", -			    fdata->blksize); +		dev_warn(&device->cdev->dev, +			 "The DASD cannot be formatted with block size %d\n", +			 fdata->blksize);  		return ERR_PTR(-EINVAL);  	} @@ -1296,9 +1473,17 @@ dasd_eckd_format_device(struct dasd_device * device,  	 *   Bit 1: write home address, currently not supported  	 *   Bit 2: invalidate tracks  	 *   Bit 3: use OS/390 compatible disk layout (cdl) +	 *   Bit 4: do not allow storage subsystem to modify record zero  	 * Only some bit combinations do make sense.  	 */ -	switch (fdata->intensity) { +	if (fdata->intensity & 0x10) { +		r0_perm = 0; +		intensity = fdata->intensity & ~0x10; +	} else { +		r0_perm = 1; +		intensity = fdata->intensity; +	} +	switch (intensity) {  	case 0x00:	/* Normal format */  	case 0x08:	/* Normal format, use cdl. */  		cplength = 2 + rpt; @@ -1322,8 +1507,8 @@ dasd_eckd_format_device(struct dasd_device * device,  			sizeof(struct eckd_count);  		break;  	default: -		DEV_MESSAGE(KERN_WARNING, device, "Invalid flags 0x%x.", -			    fdata->intensity); +		dev_warn(&device->cdev->dev, "An I/O control call used " +			 "incorrect flags 0x%x\n", fdata->intensity);  		return ERR_PTR(-EINVAL);  	}  	/* Allocate the format ccw request. */ @@ -1335,11 +1520,14 @@ dasd_eckd_format_device(struct dasd_device * device,  	data = fcp->data;  	ccw = fcp->cpaddr; -	switch (fdata->intensity & ~0x08) { +	switch (intensity & ~0x08) {  	case 0x00: /* Normal format. */  		define_extent(ccw++, (struct DE_eckd_data *) data,  			      fdata->start_unit, fdata->start_unit,  			      DASD_ECKD_CCW_WRITE_CKD, device); +		/* grant subsystem permission to format R0 */ +		if (r0_perm) +			((struct DE_eckd_data *)data)->ga_extended |= 0x04;  		data += sizeof(struct DE_eckd_data);  		ccw[-1].flags |= CCW_FLAG_CC;  		locate_record(ccw++, (struct LO_eckd_data *) data, @@ -1373,11 +1561,11 @@ dasd_eckd_format_device(struct dasd_device * device,  		data += sizeof(struct LO_eckd_data);  		break;  	} -	if (fdata->intensity & 0x01) {	/* write record zero */ +	if (intensity & 0x01) {	/* write record zero */  		ect = (struct eckd_count *) data;  		data += sizeof(struct eckd_count); -		ect->cyl = cyl; -		ect->head = head; +		ect->cyl = address.cyl; +		ect->head = address.head;  		ect->record = 0;  		ect->kl = 0;  		ect->dl = 8; @@ -1388,11 +1576,11 @@ dasd_eckd_format_device(struct dasd_device * device,  		ccw->cda = (__u32)(addr_t) ect;  		ccw++;  	} -	if ((fdata->intensity & ~0x08) & 0x04) {	/* erase track */ +	if ((intensity & ~0x08) & 0x04) {	/* erase track */  		ect = (struct eckd_count *) data;  		data += sizeof(struct eckd_count); -		ect->cyl = cyl; -		ect->head = head; +		ect->cyl = address.cyl; +		ect->head = address.head;  		ect->record = 1;  		ect->kl = 0;  		ect->dl = 0; @@ -1405,20 +1593,20 @@ dasd_eckd_format_device(struct dasd_device * device,  		for (i = 0; i < rpt; i++) {  			ect = (struct eckd_count *) data;  			data += sizeof(struct eckd_count); -			ect->cyl = cyl; -			ect->head = head; +			ect->cyl = address.cyl; +			ect->head = address.head;  			ect->record = i + 1;  			ect->kl = 0;  			ect->dl = fdata->blksize;  			/* Check for special tracks 0-1 when formatting CDL */ -			if ((fdata->intensity & 0x08) && +			if ((intensity & 0x08) &&  			    fdata->start_unit == 0) {  				if (i < 3) {  					ect->kl = 4;  					ect->dl = sizes_trk0[i] - 4;  				}  			} -			if ((fdata->intensity & 0x08) && +			if ((intensity & 0x08) &&  			    fdata->start_unit == 1) {  				ect->kl = 44;  				ect->dl = LABEL_SIZE - 44; @@ -1479,57 +1667,69 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,  						   struct irb *irb)  {  	char mask; +	char *sense = NULL;  	/* first of all check for state change pending interrupt */  	mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; -	if ((irb->scsw.cmd.dstat & mask) == mask) { +	if ((scsw_dstat(&irb->scsw) & mask) == mask) {  		dasd_generic_handle_state_change(device);  		return;  	}  	/* summary unit check */ -	if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) && +	if ((scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) &&  	    (irb->ecw[7] == 0x0D)) {  		dasd_alias_handle_summary_unit_check(device, irb);  		return;  	} - +	sense = dasd_get_sense(irb);  	/* service information message SIM */ -	if (irb->esw.esw0.erw.cons && !(irb->ecw[27] & DASD_SENSE_BIT_0) && -	    ((irb->ecw[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) { -		dasd_3990_erp_handle_sim(device, irb->ecw); +	if (sense && !(sense[27] & DASD_SENSE_BIT_0) && +	    ((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) { +		dasd_3990_erp_handle_sim(device, sense);  		dasd_schedule_device_bh(device);  		return;  	} -	if ((irb->scsw.cmd.cc == 1) && -	    (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) && -	    (irb->scsw.cmd.actl & SCSW_ACTL_START_PEND) && -	    (irb->scsw.cmd.stctl & SCSW_STCTL_STATUS_PEND)) { +	if ((scsw_cc(&irb->scsw) == 1) && +	    (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) && +	    (scsw_actl(&irb->scsw) & SCSW_ACTL_START_PEND) && +	    (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND)) {  		/* fake irb do nothing, they are handled elsewhere */  		dasd_schedule_device_bh(device);  		return;  	} -	if (!(irb->esw.esw0.erw.cons)) { +	if (!sense) {  		/* just report other unsolicited interrupts */ -		DEV_MESSAGE(KERN_ERR, device, "%s", +		DBF_DEV_EVENT(DBF_ERR, device, "%s",  			    "unsolicited interrupt received");  	} else { -		DEV_MESSAGE(KERN_ERR, device, "%s", +		DBF_DEV_EVENT(DBF_ERR, device, "%s",  			    "unsolicited interrupt received "  			    "(sense available)"); -		device->discipline->dump_sense(device, NULL, irb); +		device->discipline->dump_sense_dbf(device, NULL, irb, +						   "unsolicited");  	}  	dasd_schedule_device_bh(device);  	return;  }; -static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, + +static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( +					       struct dasd_device *startdev,  					       struct dasd_block *block, -					       struct request *req) +					       struct request *req, +					       sector_t first_rec, +					       sector_t last_rec, +					       sector_t first_trk, +					       sector_t last_trk, +					       unsigned int first_offs, +					       unsigned int last_offs, +					       unsigned int blk_per_trk, +					       unsigned int blksize)  {  	struct dasd_eckd_private *private;  	unsigned long *idaws; @@ -1539,11 +1739,9 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,  	struct req_iterator iter;  	struct bio_vec *bv;  	char *dst; -	unsigned int blksize, blk_per_trk, off; +	unsigned int off;  	int count, cidaw, cplength, datasize; -	sector_t recid, first_rec, last_rec; -	sector_t first_trk, last_trk; -	unsigned int first_offs, last_offs; +	sector_t recid;  	unsigned char cmd, rcmd;  	int use_prefix;  	struct dasd_device *basedev; @@ -1556,15 +1754,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,  		cmd = DASD_ECKD_CCW_WRITE_MT;  	else  		return ERR_PTR(-EINVAL); -	/* Calculate number of blocks/records per track. */ -	blksize = block->bp_block; -	blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); -	/* Calculate record id of first and last block. */ -	first_rec = first_trk = req->sector >> block->s2b_shift; -	first_offs = sector_div(first_trk, blk_per_trk); -	last_rec = last_trk = -		(req->sector + req->nr_sectors - 1) >> block->s2b_shift; -	last_offs = sector_div(last_trk, blk_per_trk); +  	/* Check struct bio and count the number of blocks for the request. */  	count = 0;  	cidaw = 0; @@ -1714,6 +1904,497 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,  	return cqr;  } +static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( +					       struct dasd_device *startdev, +					       struct dasd_block *block, +					       struct request *req, +					       sector_t first_rec, +					       sector_t last_rec, +					       sector_t first_trk, +					       sector_t last_trk, +					       unsigned int first_offs, +					       unsigned int last_offs, +					       unsigned int blk_per_trk, +					       unsigned int blksize) +{ +	struct dasd_eckd_private *private; +	unsigned long *idaws; +	struct dasd_ccw_req *cqr; +	struct ccw1 *ccw; +	struct req_iterator iter; +	struct bio_vec *bv; +	char *dst, *idaw_dst; +	unsigned int cidaw, cplength, datasize; +	unsigned int tlf; +	sector_t recid; +	unsigned char cmd; +	struct dasd_device *basedev; +	unsigned int trkcount, count, count_to_trk_end; +	unsigned int idaw_len, seg_len, part_len, len_to_track_end; +	unsigned char new_track, end_idaw; +	sector_t trkid; +	unsigned int recoffs; + +	basedev = block->base; +	private = (struct dasd_eckd_private *) basedev->private; +	if (rq_data_dir(req) == READ) +		cmd = DASD_ECKD_CCW_READ_TRACK_DATA; +	else if (rq_data_dir(req) == WRITE) +		cmd = DASD_ECKD_CCW_WRITE_TRACK_DATA; +	else +		return ERR_PTR(-EINVAL); + +	/* Track based I/O needs IDAWs for each page, and not just for +	 * 64 bit addresses. We need additional idals for pages +	 * that get filled from two tracks, so we use the number +	 * of records as upper limit. +	 */ +	cidaw = last_rec - first_rec + 1; +	trkcount = last_trk - first_trk + 1; + +	/* 1x prefix + one read/write ccw per track */ +	cplength = 1 + trkcount; + +	/* on 31-bit we need space for two 32 bit addresses per page +	 * on 64-bit one 64 bit address +	 */ +	datasize = sizeof(struct PFX_eckd_data) + +		cidaw * sizeof(unsigned long long); + +	/* Allocate the ccw request. */ +	cqr = dasd_smalloc_request(dasd_eckd_discipline.name, +				   cplength, datasize, startdev); +	if (IS_ERR(cqr)) +		return cqr; +	ccw = cqr->cpaddr; +	/* transfer length factor: how many bytes to read from the last track */ +	if (first_trk == last_trk) +		tlf = last_offs - first_offs + 1; +	else +		tlf = last_offs + 1; +	tlf *= blksize; + +	if (prefix_LRE(ccw++, cqr->data, first_trk, +		       last_trk, cmd, basedev, startdev, +		       1 /* format */, first_offs + 1, +		       trkcount, blksize, +		       tlf) == -EAGAIN) { +		/* Clock not in sync and XRC is enabled. +		 * Try again later. +		 */ +		dasd_sfree_request(cqr, startdev); +		return ERR_PTR(-EAGAIN); +	} + +	/* +	 * The translation of request into ccw programs must meet the +	 * following conditions: +	 * - all idaws but the first and the last must address full pages +	 *   (or 2K blocks on 31-bit) +	 * - the scope of a ccw and it's idal ends with the track boundaries +	 */ +	idaws = (unsigned long *) (cqr->data + sizeof(struct PFX_eckd_data)); +	recid = first_rec; +	new_track = 1; +	end_idaw = 0; +	len_to_track_end = 0; +	idaw_dst = 0; +	idaw_len = 0; +	rq_for_each_segment(bv, req, iter) { +		dst = page_address(bv->bv_page) + bv->bv_offset; +		seg_len = bv->bv_len; +		while (seg_len) { +			if (new_track) { +				trkid = recid; +				recoffs = sector_div(trkid, blk_per_trk); +				count_to_trk_end = blk_per_trk - recoffs; +				count = min((last_rec - recid + 1), +					    (sector_t)count_to_trk_end); +				len_to_track_end = count * blksize; +				ccw[-1].flags |= CCW_FLAG_CC; +				ccw->cmd_code = cmd; +				ccw->count = len_to_track_end; +				ccw->cda = (__u32)(addr_t)idaws; +				ccw->flags = CCW_FLAG_IDA; +				ccw++; +				recid += count; +				new_track = 0; +			} +			/* If we start a new idaw, everything is fine and the +			 * start of the new idaw is the start of this segment. +			 * If we continue an idaw, we must make sure that the +			 * current segment begins where the so far accumulated +			 * idaw ends +			 */ +			if (!idaw_dst) +				idaw_dst = dst; +			if ((idaw_dst + idaw_len) != dst) { +				dasd_sfree_request(cqr, startdev); +				return ERR_PTR(-ERANGE); +			} +			part_len = min(seg_len, len_to_track_end); +			seg_len -= part_len; +			dst += part_len; +			idaw_len += part_len; +			len_to_track_end -= part_len; +			/* collected memory area ends on an IDA_BLOCK border, +			 * -> create an idaw +			 * idal_create_words will handle cases where idaw_len +			 * is larger then IDA_BLOCK_SIZE +			 */ +			if (!(__pa(idaw_dst + idaw_len) & (IDA_BLOCK_SIZE-1))) +				end_idaw = 1; +			/* We also need to end the idaw at track end */ +			if (!len_to_track_end) { +				new_track = 1; +				end_idaw = 1; +			} +			if (end_idaw) { +				idaws = idal_create_words(idaws, idaw_dst, +							  idaw_len); +				idaw_dst = 0; +				idaw_len = 0; +				end_idaw = 0; +			} +		} +	} + +	if (blk_noretry_request(req) || +	    block->base->features & DASD_FEATURE_FAILFAST) +		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); +	cqr->startdev = startdev; +	cqr->memdev = startdev; +	cqr->block = block; +	cqr->expires = 5 * 60 * HZ;	/* 5 minutes */ +	cqr->lpm = private->path_data.ppm; +	cqr->retries = 256; +	cqr->buildclk = get_clock(); +	cqr->status = DASD_CQR_FILLED; +	return cqr; +} + +static int prepare_itcw(struct itcw *itcw, +			unsigned int trk, unsigned int totrk, int cmd, +			struct dasd_device *basedev, +			struct dasd_device *startdev, +			unsigned int rec_on_trk, int count, +			unsigned int blksize, +			unsigned int total_data_size, +			unsigned int tlf, +			unsigned int blk_per_trk) +{ +	struct PFX_eckd_data pfxdata; +	struct dasd_eckd_private *basepriv, *startpriv; +	struct DE_eckd_data *dedata; +	struct LRE_eckd_data *lredata; +	struct dcw *dcw; + +	u32 begcyl, endcyl; +	u16 heads, beghead, endhead; +	u8 pfx_cmd; + +	int rc = 0; +	int sector = 0; +	int dn, d; + + +	/* setup prefix data */ +	basepriv = (struct dasd_eckd_private *) basedev->private; +	startpriv = (struct dasd_eckd_private *) startdev->private; +	dedata = &pfxdata.define_extent; +	lredata = &pfxdata.locate_record; + +	memset(&pfxdata, 0, sizeof(pfxdata)); +	pfxdata.format = 1; /* PFX with LRE */ +	pfxdata.base_address = basepriv->ned->unit_addr; +	pfxdata.base_lss = basepriv->ned->ID; +	pfxdata.validity.define_extent = 1; + +	/* private uid is kept up to date, conf_data may be outdated */ +	if (startpriv->uid.type != UA_BASE_DEVICE) { +		pfxdata.validity.verify_base = 1; +		if (startpriv->uid.type == UA_HYPER_PAV_ALIAS) +			pfxdata.validity.hyper_pav = 1; +	} + +	switch (cmd) { +	case DASD_ECKD_CCW_READ_TRACK_DATA: +		dedata->mask.perm = 0x1; +		dedata->attributes.operation = basepriv->attrib.operation; +		dedata->blk_size = blksize; +		dedata->ga_extended |= 0x42; +		lredata->operation.orientation = 0x0; +		lredata->operation.operation = 0x0C; +		lredata->auxiliary.check_bytes = 0x01; +		pfx_cmd = DASD_ECKD_CCW_PFX_READ; +		break; +	case DASD_ECKD_CCW_WRITE_TRACK_DATA: +		dedata->mask.perm = 0x02; +		dedata->attributes.operation = basepriv->attrib.operation; +		dedata->blk_size = blksize; +		rc = check_XRC_on_prefix(&pfxdata, basedev); +		dedata->ga_extended |= 0x42; +		lredata->operation.orientation = 0x0; +		lredata->operation.operation = 0x3F; +		lredata->extended_operation = 0x23; +		lredata->auxiliary.check_bytes = 0x2; +		pfx_cmd = DASD_ECKD_CCW_PFX; +		break; +	default: +		DBF_DEV_EVENT(DBF_ERR, basedev, +			      "prepare itcw, unknown opcode 0x%x", cmd); +		BUG(); +		break; +	} +	if (rc) +		return rc; + +	dedata->attributes.mode = 0x3;	/* ECKD */ + +	heads = basepriv->rdc_data.trk_per_cyl; +	begcyl = trk / heads; +	beghead = trk % heads; +	endcyl = totrk / heads; +	endhead = totrk % heads; + +	/* check for sequential prestage - enhance cylinder range */ +	if (dedata->attributes.operation == DASD_SEQ_PRESTAGE || +	    dedata->attributes.operation == DASD_SEQ_ACCESS) { + +		if (endcyl + basepriv->attrib.nr_cyl < basepriv->real_cyl) +			endcyl += basepriv->attrib.nr_cyl; +		else +			endcyl = (basepriv->real_cyl - 1); +	} + +	set_ch_t(&dedata->beg_ext, begcyl, beghead); +	set_ch_t(&dedata->end_ext, endcyl, endhead); + +	dedata->ep_format = 0x20; /* records per track is valid */ +	dedata->ep_rec_per_track = blk_per_trk; + +	if (rec_on_trk) { +		switch (basepriv->rdc_data.dev_type) { +		case 0x3390: +			dn = ceil_quot(blksize + 6, 232); +			d = 9 + ceil_quot(blksize + 6 * (dn + 1), 34); +			sector = (49 + (rec_on_trk - 1) * (10 + d)) / 8; +			break; +		case 0x3380: +			d = 7 + ceil_quot(blksize + 12, 32); +			sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7; +			break; +		} +	} + +	lredata->auxiliary.length_valid = 1; +	lredata->auxiliary.length_scope = 1; +	lredata->auxiliary.imbedded_ccw_valid = 1; +	lredata->length = tlf; +	lredata->imbedded_ccw = cmd; +	lredata->count = count; +	lredata->sector = sector; +	set_ch_t(&lredata->seek_addr, begcyl, beghead); +	lredata->search_arg.cyl = lredata->seek_addr.cyl; +	lredata->search_arg.head = lredata->seek_addr.head; +	lredata->search_arg.record = rec_on_trk; + +	dcw = itcw_add_dcw(itcw, pfx_cmd, 0, +		     &pfxdata, sizeof(pfxdata), total_data_size); + +	return rc; +} + +static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( +					       struct dasd_device *startdev, +					       struct dasd_block *block, +					       struct request *req, +					       sector_t first_rec, +					       sector_t last_rec, +					       sector_t first_trk, +					       sector_t last_trk, +					       unsigned int first_offs, +					       unsigned int last_offs, +					       unsigned int blk_per_trk, +					       unsigned int blksize) +{ +	struct dasd_eckd_private *private; +	struct dasd_ccw_req *cqr; +	struct req_iterator iter; +	struct bio_vec *bv; +	char *dst; +	unsigned int trkcount, ctidaw; +	unsigned char cmd; +	struct dasd_device *basedev; +	unsigned int tlf; +	struct itcw *itcw; +	struct tidaw *last_tidaw = NULL; +	int itcw_op; +	size_t itcw_size; + +	basedev = block->base; +	private = (struct dasd_eckd_private *) basedev->private; +	if (rq_data_dir(req) == READ) { +		cmd = DASD_ECKD_CCW_READ_TRACK_DATA; +		itcw_op = ITCW_OP_READ; +	} else if (rq_data_dir(req) == WRITE) { +		cmd = DASD_ECKD_CCW_WRITE_TRACK_DATA; +		itcw_op = ITCW_OP_WRITE; +	} else +		return ERR_PTR(-EINVAL); + +	/* trackbased I/O needs address all memory via TIDAWs, +	 * not just for 64 bit addresses. This allows us to map +	 * each segment directly to one tidaw. +	 */ +	trkcount = last_trk - first_trk + 1; +	ctidaw = 0; +	rq_for_each_segment(bv, req, iter) { +		++ctidaw; +	} + +	/* Allocate the ccw request. */ +	itcw_size = itcw_calc_size(0, ctidaw, 0); +	cqr = dasd_smalloc_request(dasd_eckd_discipline.name, +				   0, itcw_size, startdev); +	if (IS_ERR(cqr)) +		return cqr; + +	cqr->cpmode = 1; +	cqr->startdev = startdev; +	cqr->memdev = startdev; +	cqr->block = block; +	cqr->expires = 100*HZ; +	cqr->buildclk = get_clock(); +	cqr->status = DASD_CQR_FILLED; +	cqr->retries = 10; + +	/* transfer length factor: how many bytes to read from the last track */ +	if (first_trk == last_trk) +		tlf = last_offs - first_offs + 1; +	else +		tlf = last_offs + 1; +	tlf *= blksize; + +	itcw = itcw_init(cqr->data, itcw_size, itcw_op, 0, ctidaw, 0); +	cqr->cpaddr = itcw_get_tcw(itcw); + +	if (prepare_itcw(itcw, first_trk, last_trk, +			 cmd, basedev, startdev, +			 first_offs + 1, +			 trkcount, blksize, +			 (last_rec - first_rec + 1) * blksize, +			 tlf, blk_per_trk) == -EAGAIN) { +		/* Clock not in sync and XRC is enabled. +		 * Try again later. +		 */ +		dasd_sfree_request(cqr, startdev); +		return ERR_PTR(-EAGAIN); +	} + +	/* +	 * A tidaw can address 4k of memory, but must not cross page boundaries +	 * We can let the block layer handle this by setting +	 * blk_queue_segment_boundary to page boundaries and +	 * blk_max_segment_size to page size when setting up the request queue. +	 */ +	rq_for_each_segment(bv, req, iter) { +		dst = page_address(bv->bv_page) + bv->bv_offset; +		last_tidaw = itcw_add_tidaw(itcw, 0x00, dst, bv->bv_len); +		if (IS_ERR(last_tidaw)) +			return (struct dasd_ccw_req *)last_tidaw; +	} + +	last_tidaw->flags |= 0x80; +	itcw_finalize(itcw); + +	if (blk_noretry_request(req) || +	    block->base->features & DASD_FEATURE_FAILFAST) +		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); +	cqr->startdev = startdev; +	cqr->memdev = startdev; +	cqr->block = block; +	cqr->expires = 5 * 60 * HZ;	/* 5 minutes */ +	cqr->lpm = private->path_data.ppm; +	cqr->retries = 256; +	cqr->buildclk = get_clock(); +	cqr->status = DASD_CQR_FILLED; +	return cqr; +} + +static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, +					       struct dasd_block *block, +					       struct request *req) +{ +	int tpm, cmdrtd, cmdwtd; +	int use_prefix; + +	struct dasd_eckd_private *private; +	int fcx_in_css, fcx_in_gneq, fcx_in_features; +	struct dasd_device *basedev; +	sector_t first_rec, last_rec; +	sector_t first_trk, last_trk; +	unsigned int first_offs, last_offs; +	unsigned int blk_per_trk, blksize; +	int cdlspecial; +	struct dasd_ccw_req *cqr; + +	basedev = block->base; +	private = (struct dasd_eckd_private *) basedev->private; + +	/* Calculate number of blocks/records per track. */ +	blksize = block->bp_block; +	blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); +	/* Calculate record id of first and last block. */ +	first_rec = first_trk = req->sector >> block->s2b_shift; +	first_offs = sector_div(first_trk, blk_per_trk); +	last_rec = last_trk = +		(req->sector + req->nr_sectors - 1) >> block->s2b_shift; +	last_offs = sector_div(last_trk, blk_per_trk); +	cdlspecial = (private->uses_cdl && first_rec < 2*blk_per_trk); + +	/* is transport mode supported ? */ +	fcx_in_css = css_general_characteristics.fcx; +	fcx_in_gneq = private->gneq->reserved2[7] & 0x04; +	fcx_in_features = private->features.feature[40] & 0x80; +	tpm = fcx_in_css && fcx_in_gneq && fcx_in_features; + +	/* is read track data and write track data in command mode supported? */ +	cmdrtd = private->features.feature[9] & 0x20; +	cmdwtd = private->features.feature[12] & 0x40; +	use_prefix = private->features.feature[8] & 0x01; + +	cqr = NULL; +	if (cdlspecial || dasd_page_cache) { +		/* do nothing, just fall through to the cmd mode single case */ +	} else if (!dasd_nofcx && tpm && (first_trk == last_trk)) { +		cqr = dasd_eckd_build_cp_tpm_track(startdev, block, req, +						    first_rec, last_rec, +						    first_trk, last_trk, +						    first_offs, last_offs, +						    blk_per_trk, blksize); +		if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN) +			cqr = NULL; +	} else if (use_prefix && +		   (((rq_data_dir(req) == READ) && cmdrtd) || +		    ((rq_data_dir(req) == WRITE) && cmdwtd))) { +		cqr = dasd_eckd_build_cp_cmd_track(startdev, block, req, +						   first_rec, last_rec, +						   first_trk, last_trk, +						   first_offs, last_offs, +						   blk_per_trk, blksize); +		if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN) +			cqr = NULL; +	} +	if (!cqr) +		cqr = dasd_eckd_build_cp_cmd_single(startdev, block, req, +						    first_rec, last_rec, +						    first_trk, last_trk, +						    first_offs, last_offs, +						    blk_per_trk, blksize); +	return cqr; +} +  static int  dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)  { @@ -1767,7 +2448,7 @@ out:  }  /* - * Modify ccw chain in cqr so it can be started on a base device. + * Modify ccw/tcw in cqr so it can be started on a base device.   *   * Note that this is not enough to restart the cqr!   * Either reset cqr->startdev as well (summary unit check handling) @@ -1777,13 +2458,24 @@ void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *cqr)  {  	struct ccw1 *ccw;  	struct PFX_eckd_data *pfxdata; - -	ccw = cqr->cpaddr; -	pfxdata = cqr->data; - -	if (ccw->cmd_code == DASD_ECKD_CCW_PFX) { +	struct tcw *tcw; +	struct tccb *tccb; +	struct dcw *dcw; + +	if (cqr->cpmode == 1) { +		tcw = cqr->cpaddr; +		tccb = tcw_get_tccb(tcw); +		dcw = (struct dcw *)&tccb->tca[0]; +		pfxdata = (struct PFX_eckd_data *)&dcw->cd[0];  		pfxdata->validity.verify_base = 0;  		pfxdata->validity.hyper_pav = 0; +	} else { +		ccw = cqr->cpaddr; +		pfxdata = cqr->data; +		if (ccw->cmd_code == DASD_ECKD_CCW_PFX) { +			pfxdata->validity.verify_base = 0; +			pfxdata->validity.hyper_pav = 0; +		}  	}  } @@ -1861,6 +2553,7 @@ dasd_eckd_release(struct dasd_device *device)  {  	struct dasd_ccw_req *cqr;  	int rc; +	struct ccw1 *ccw;  	if (!capable(CAP_SYS_ADMIN))  		return -EACCES; @@ -1868,14 +2561,15 @@ dasd_eckd_release(struct dasd_device *device)  	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,  				   1, 32, device);  	if (IS_ERR(cqr)) { -		DEV_MESSAGE(KERN_WARNING, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "Could not allocate initialization request");  		return PTR_ERR(cqr);  	} -	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE; -        cqr->cpaddr->flags |= CCW_FLAG_SLI; -        cqr->cpaddr->count = 32; -	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; +	ccw = cqr->cpaddr; +	ccw->cmd_code = DASD_ECKD_CCW_RELEASE; +	ccw->flags |= CCW_FLAG_SLI; +	ccw->count = 32; +	ccw->cda = (__u32)(addr_t) cqr->data;  	cqr->startdev = device;  	cqr->memdev = device;  	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); @@ -1902,6 +2596,7 @@ dasd_eckd_reserve(struct dasd_device *device)  {  	struct dasd_ccw_req *cqr;  	int rc; +	struct ccw1 *ccw;  	if (!capable(CAP_SYS_ADMIN))  		return -EACCES; @@ -1909,14 +2604,15 @@ dasd_eckd_reserve(struct dasd_device *device)  	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,  				   1, 32, device);  	if (IS_ERR(cqr)) { -		DEV_MESSAGE(KERN_WARNING, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "Could not allocate initialization request");  		return PTR_ERR(cqr);  	} -	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE; -        cqr->cpaddr->flags |= CCW_FLAG_SLI; -        cqr->cpaddr->count = 32; -	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; +	ccw = cqr->cpaddr; +	ccw->cmd_code = DASD_ECKD_CCW_RESERVE; +	ccw->flags |= CCW_FLAG_SLI; +	ccw->count = 32; +	ccw->cda = (__u32)(addr_t) cqr->data;  	cqr->startdev = device;  	cqr->memdev = device;  	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); @@ -1942,6 +2638,7 @@ dasd_eckd_steal_lock(struct dasd_device *device)  {  	struct dasd_ccw_req *cqr;  	int rc; +	struct ccw1 *ccw;  	if (!capable(CAP_SYS_ADMIN))  		return -EACCES; @@ -1949,14 +2646,15 @@ dasd_eckd_steal_lock(struct dasd_device *device)  	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,  				   1, 32, device);  	if (IS_ERR(cqr)) { -		DEV_MESSAGE(KERN_WARNING, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "Could not allocate initialization request");  		return PTR_ERR(cqr);  	} -	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK; -        cqr->cpaddr->flags |= CCW_FLAG_SLI; -        cqr->cpaddr->count = 32; -	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; +	ccw = cqr->cpaddr; +	ccw->cmd_code = DASD_ECKD_CCW_SLCK; +	ccw->flags |= CCW_FLAG_SLI; +	ccw->count = 32; +	ccw->cda = (__u32)(addr_t) cqr->data;  	cqr->startdev = device;  	cqr->memdev = device;  	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); @@ -1990,7 +2688,7 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp)  				    sizeof(struct dasd_rssd_perf_stats_t)),  				   device);  	if (IS_ERR(cqr)) { -		DEV_MESSAGE(KERN_WARNING, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "Could not allocate initialization request");  		return PTR_ERR(cqr);  	} @@ -2080,9 +2778,9 @@ dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp)  		return -EFAULT;  	private->attrib = attrib; -	DEV_MESSAGE(KERN_INFO, device, -		    "cache operation mode set to %x (%i cylinder prestage)", -		    private->attrib.operation, private->attrib.nr_cyl); +	dev_info(&device->cdev->dev, +		 "The DASD cache mode was set to %x (%i cylinder prestage)\n", +		 private->attrib.operation, private->attrib.nr_cyl);  	return 0;  } @@ -2133,7 +2831,7 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp)  	/* setup CCWs for PSF + RSSD */  	cqr = dasd_smalloc_request("ECKD", 2 , 0, device);  	if (IS_ERR(cqr)) { -		DEV_MESSAGE(KERN_WARNING, device, "%s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			"Could not allocate initialization request");  		rc = PTR_ERR(cqr);  		goto out_free; @@ -2242,11 +2940,54 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)  	return len;  } +static void +dasd_eckd_dump_sense_dbf(struct dasd_device *device, struct dasd_ccw_req *req, +			 struct irb *irb, char *reason) +{ +	u64 *sense; +	int sl; +	struct tsb *tsb; + +	sense = NULL; +	tsb = NULL; +	if (req && scsw_is_tm(&req->irb.scsw)) { +		if (irb->scsw.tm.tcw) +			tsb = tcw_get_tsb( +				(struct tcw *)(unsigned long)irb->scsw.tm.tcw); +		if (tsb && (irb->scsw.tm.fcxs == 0x01)) { +			switch (tsb->flags & 0x07) { +			case 1:	/* tsa_iostat */ +				sense = (u64 *)tsb->tsa.iostat.sense; +			break; +			case 2: /* ts_ddpc */ +				sense = (u64 *)tsb->tsa.ddpc.sense; +			break; +			case 3: /* tsa_intrg */ +			break; +			} +		} +	} else { +		if (irb->esw.esw0.erw.cons) +			sense = (u64 *)irb->ecw; +	} +	if (sense) { +		for (sl = 0; sl < 4; sl++) { +			DBF_DEV_EVENT(DBF_EMERG, device, +				      "%s: %016llx %016llx %016llx %016llx", +				      reason, sense[0], sense[1], sense[2], +				      sense[3]); +		} +	} else { +		DBF_DEV_EVENT(DBF_EMERG, device, "%s", +			      "SORRY - NO VALID SENSE AVAILABLE\n"); +	} +} +  /*   * Print sense data and related channel program.   * Parts are printed because printk buffer is only 1024 bytes.   */ -static void dasd_eckd_dump_sense(struct dasd_device *device, +static void dasd_eckd_dump_sense_ccw(struct dasd_device *device,  				 struct dasd_ccw_req *req, struct irb *irb)  {  	char *page; @@ -2255,8 +2996,8 @@ static void dasd_eckd_dump_sense(struct dasd_device *device,  	page = (char *) get_zeroed_page(GFP_ATOMIC);  	if (page == NULL) { -		DEV_MESSAGE(KERN_ERR, device, " %s", -			    "No memory to dump sense data"); +		DBF_DEV_EVENT(DBF_WARNING, device, "%s", +			      "No memory to dump sense data\n");  		return;  	}  	/* dump the sense data */ @@ -2265,7 +3006,7 @@ static void dasd_eckd_dump_sense(struct dasd_device *device,  		      dev_name(&device->cdev->dev));  	len += sprintf(page + len, KERN_ERR PRINTK_HEADER  		       " in req: %p CS: 0x%02X DS: 0x%02X\n", req, -		       irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); +		       scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw));  	len += sprintf(page + len, KERN_ERR PRINTK_HEADER  		       " device %s: Failing CCW: %p\n",  		       dev_name(&device->cdev->dev), @@ -2341,6 +3082,147 @@ static void dasd_eckd_dump_sense(struct dasd_device *device,  	free_page((unsigned long) page);  } + +/* + * Print sense data from a tcw. + */ +static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, +				 struct dasd_ccw_req *req, struct irb *irb) +{ +	char *page; +	int len, sl, sct, residual; + +	struct tsb *tsb; +	u8 *sense; + + +	page = (char *) get_zeroed_page(GFP_ATOMIC); +	if (page == NULL) { +		DBF_DEV_EVENT(DBF_WARNING, device, " %s", +			    "No memory to dump sense data"); +		return; +	} +	/* dump the sense data */ +	len = sprintf(page,  KERN_ERR PRINTK_HEADER +		      " I/O status report for device %s:\n", +		      dev_name(&device->cdev->dev)); +	len += sprintf(page + len, KERN_ERR PRINTK_HEADER +		       " in req: %p CS: 0x%02X DS: 0x%02X " +		       "fcxs: 0x%02X schxs: 0x%02X\n", req, +		       scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw), +		       irb->scsw.tm.fcxs, irb->scsw.tm.schxs); +	len += sprintf(page + len, KERN_ERR PRINTK_HEADER +		       " device %s: Failing TCW: %p\n", +		       dev_name(&device->cdev->dev), +		       (void *) (addr_t) irb->scsw.tm.tcw); + +	tsb = NULL; +	sense = NULL; +	if (irb->scsw.tm.tcw) +		tsb = tcw_get_tsb( +			(struct tcw *)(unsigned long)irb->scsw.tm.tcw); + +	if (tsb && (irb->scsw.tm.fcxs == 0x01)) { +		len += sprintf(page + len, KERN_ERR PRINTK_HEADER +			       " tsb->length %d\n", tsb->length); +		len += sprintf(page + len, KERN_ERR PRINTK_HEADER +			       " tsb->flags %x\n", tsb->flags); +		len += sprintf(page + len, KERN_ERR PRINTK_HEADER +			       " tsb->dcw_offset %d\n", tsb->dcw_offset); +		len += sprintf(page + len, KERN_ERR PRINTK_HEADER +			       " tsb->count %d\n", tsb->count); +		residual = tsb->count - 28; +		len += sprintf(page + len, KERN_ERR PRINTK_HEADER +			       " residual %d\n", residual); + +		switch (tsb->flags & 0x07) { +		case 1:	/* tsa_iostat */ +			len += sprintf(page + len, KERN_ERR PRINTK_HEADER +			       " tsb->tsa.iostat.dev_time %d\n", +				       tsb->tsa.iostat.dev_time); +			len += sprintf(page + len, KERN_ERR PRINTK_HEADER +			       " tsb->tsa.iostat.def_time %d\n", +				       tsb->tsa.iostat.def_time); +			len += sprintf(page + len, KERN_ERR PRINTK_HEADER +			       " tsb->tsa.iostat.queue_time %d\n", +				       tsb->tsa.iostat.queue_time); +			len += sprintf(page + len, KERN_ERR PRINTK_HEADER +			       " tsb->tsa.iostat.dev_busy_time %d\n", +				       tsb->tsa.iostat.dev_busy_time); +			len += sprintf(page + len, KERN_ERR PRINTK_HEADER +			       " tsb->tsa.iostat.dev_act_time %d\n", +				       tsb->tsa.iostat.dev_act_time); +			sense = tsb->tsa.iostat.sense; +			break; +		case 2: /* ts_ddpc */ +			len += sprintf(page + len, KERN_ERR PRINTK_HEADER +			       " tsb->tsa.ddpc.rc %d\n", tsb->tsa.ddpc.rc); +			len += sprintf(page + len, KERN_ERR PRINTK_HEADER +			       " tsb->tsa.ddpc.rcq:  "); +			for (sl = 0; sl < 16; sl++) { +				for (sct = 0; sct < 8; sct++) { +					len += sprintf(page + len, " %02x", +						       tsb->tsa.ddpc.rcq[sl]); +				} +				len += sprintf(page + len, "\n"); +			} +			sense = tsb->tsa.ddpc.sense; +			break; +		case 3: /* tsa_intrg */ +			len += sprintf(page + len, KERN_ERR PRINTK_HEADER +				      " tsb->tsa.intrg.: not supportet yet \n"); +			break; +		} + +		if (sense) { +			for (sl = 0; sl < 4; sl++) { +				len += sprintf(page + len, +					       KERN_ERR PRINTK_HEADER +					       " Sense(hex) %2d-%2d:", +					       (8 * sl), ((8 * sl) + 7)); +				for (sct = 0; sct < 8; sct++) { +					len += sprintf(page + len, " %02x", +						       sense[8 * sl + sct]); +				} +				len += sprintf(page + len, "\n"); +			} + +			if (sense[27] & DASD_SENSE_BIT_0) { +				/* 24 Byte Sense Data */ +				sprintf(page + len, KERN_ERR PRINTK_HEADER +					" 24 Byte: %x MSG %x, " +					"%s MSGb to SYSOP\n", +					sense[7] >> 4, sense[7] & 0x0f, +					sense[1] & 0x10 ? "" : "no"); +			} else { +				/* 32 Byte Sense Data */ +				sprintf(page + len, KERN_ERR PRINTK_HEADER +					" 32 Byte: Format: %x " +					"Exception class %x\n", +					sense[6] & 0x0f, sense[22] >> 4); +			} +		} else { +			sprintf(page + len, KERN_ERR PRINTK_HEADER +				" SORRY - NO VALID SENSE AVAILABLE\n"); +		} +	} else { +		sprintf(page + len, KERN_ERR PRINTK_HEADER +			" SORRY - NO TSB DATA AVAILABLE\n"); +	} +	printk("%s", page); +	free_page((unsigned long) page); +} + +static void dasd_eckd_dump_sense(struct dasd_device *device, +				 struct dasd_ccw_req *req, struct irb *irb) +{ +	if (req && scsw_is_tm(&req->irb.scsw)) +		dasd_eckd_dump_sense_tcw(device, req, irb); +	else +		dasd_eckd_dump_sense_ccw(device, req, irb); +} + +  /*   * max_blocks is dependent on the amount of storage that is available   * in the static io buffer for each device. Currently each device has @@ -2375,6 +3257,7 @@ static struct dasd_discipline dasd_eckd_discipline = {  	.build_cp = dasd_eckd_build_alias_cp,  	.free_cp = dasd_eckd_free_alias_cp,  	.dump_sense = dasd_eckd_dump_sense, +	.dump_sense_dbf = dasd_eckd_dump_sense_dbf,  	.fill_info = dasd_eckd_fill_info,  	.ioctl = dasd_eckd_ioctl,  }; diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 2476f87d21d0..ad45bcac3ce4 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -38,8 +38,11 @@  #define DASD_ECKD_CCW_RELEASE		 0x94  #define DASD_ECKD_CCW_READ_CKD_MT	 0x9e  #define DASD_ECKD_CCW_WRITE_CKD_MT	 0x9d +#define DASD_ECKD_CCW_WRITE_TRACK_DATA	 0xA5 +#define DASD_ECKD_CCW_READ_TRACK_DATA	 0xA6  #define DASD_ECKD_CCW_RESERVE		 0xB4  #define DASD_ECKD_CCW_PFX		 0xE7 +#define DASD_ECKD_CCW_PFX_READ		 0xEA  #define DASD_ECKD_CCW_RSCK		 0xF9  /* @@ -48,6 +51,11 @@  #define PSF_ORDER_PRSSD 0x18  #define PSF_ORDER_SSC	0x1D +/* + * Size that is reportet for large volumes in the old 16-bit no_cyl field + */ +#define LV_COMPAT_CYL 0xFFFE +  /*****************************************************************************   * SECTION: Type Definitions   ****************************************************************************/ @@ -118,7 +126,9 @@ struct DE_eckd_data {  	unsigned long long ep_sys_time; /* Ext Parameter - System Time Stamp */  	__u8 ep_format;        /* Extended Parameter format byte       */  	__u8 ep_prio;          /* Extended Parameter priority I/O byte */ -	__u8 ep_reserved[6];   /* Extended Parameter Reserved          */ +	__u8 ep_reserved1;     /* Extended Parameter Reserved	       */ +	__u8 ep_rec_per_track; /* Number of records on a track	       */ +	__u8 ep_reserved[4];   /* Extended Parameter Reserved	       */  } __attribute__ ((packed));  struct LO_eckd_data { @@ -139,11 +149,37 @@ struct LO_eckd_data {  	__u16 length;  } __attribute__ ((packed)); +struct LRE_eckd_data { +	struct { +		unsigned char orientation:2; +		unsigned char operation:6; +	} __attribute__ ((packed)) operation; +	struct { +		unsigned char length_valid:1; +		unsigned char length_scope:1; +		unsigned char imbedded_ccw_valid:1; +		unsigned char check_bytes:2; +		unsigned char imbedded_count_valid:1; +		unsigned char reserved:1; +		unsigned char read_count_suffix:1; +	} __attribute__ ((packed)) auxiliary; +	__u8 imbedded_ccw; +	__u8 count; +	struct ch_t seek_addr; +	struct chr_t search_arg; +	__u8 sector; +	__u16 length; +	__u8 imbedded_count; +	__u8 extended_operation; +	__u16 extended_parameter_length; +	__u8 extended_parameter[0]; +} __attribute__ ((packed)); +  /* Prefix data for format 0x00 and 0x01 */  struct PFX_eckd_data {  	unsigned char format;  	struct { -		unsigned char define_extend:1; +		unsigned char define_extent:1;  		unsigned char time_stamp:1;  		unsigned char verify_base:1;  		unsigned char hyper_pav:1; @@ -153,9 +189,8 @@ struct PFX_eckd_data {  	__u8 aux;  	__u8 base_lss;  	__u8 reserved[7]; -	struct DE_eckd_data define_extend; -	struct LO_eckd_data locate_record; -	__u8 LO_extended_data[4]; +	struct DE_eckd_data define_extent; +	struct LRE_eckd_data locate_record;  } __attribute__ ((packed));  struct dasd_eckd_characteristics { @@ -228,7 +263,8 @@ struct dasd_eckd_characteristics {  	__u8 factor7;  	__u8 factor8;  	__u8 reserved2[3]; -	__u8 reserved3[10]; +	__u8 reserved3[6]; +	__u32 long_no_cyl;  } __attribute__ ((packed));  /* elements of the configuration data */ @@ -406,6 +442,7 @@ struct dasd_eckd_private {  	int uses_cdl;  	struct attrib_data_t attrib;	/* e.g. cache operations */  	struct dasd_rssd_features features; +	u32 real_cyl;  	/* alias managemnet */  	struct dasd_uid uid; diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index f8e05ce98621..c24c8c30380d 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -6,6 +6,8 @@   *  Author(s): Stefan Weinhuber <wein@de.ibm.com>   */ +#define KMSG_COMPONENT "dasd" +  #include <linux/init.h>  #include <linux/fs.h>  #include <linux/kernel.h> @@ -297,11 +299,12 @@ static void dasd_eer_write_standard_trigger(struct dasd_device *device,  	struct dasd_eer_header header;  	unsigned long flags;  	struct eerbuffer *eerb; +	char *sense;  	/* go through cqr chain and count the valid sense data sets */  	data_size = 0;  	for (temp_cqr = cqr; temp_cqr; temp_cqr = temp_cqr->refers) -		if (temp_cqr->irb.esw.esw0.erw.cons) +		if (dasd_get_sense(&temp_cqr->irb))  			data_size += 32;  	header.total_size = sizeof(header) + data_size + 4; /* "EOR" */ @@ -316,9 +319,11 @@ static void dasd_eer_write_standard_trigger(struct dasd_device *device,  	list_for_each_entry(eerb, &bufferlist, list) {  		dasd_eer_start_record(eerb, header.total_size);  		dasd_eer_write_buffer(eerb, (char *) &header, sizeof(header)); -		for (temp_cqr = cqr; temp_cqr; temp_cqr = temp_cqr->refers) -			if (temp_cqr->irb.esw.esw0.erw.cons) -				dasd_eer_write_buffer(eerb, cqr->irb.ecw, 32); +		for (temp_cqr = cqr; temp_cqr; temp_cqr = temp_cqr->refers) { +			sense = dasd_get_sense(&temp_cqr->irb); +			if (sense) +				dasd_eer_write_buffer(eerb, sense, 32); +		}  		dasd_eer_write_buffer(eerb, "EOR", 4);  	}  	spin_unlock_irqrestore(&bufferlock, flags); @@ -451,6 +456,7 @@ int dasd_eer_enable(struct dasd_device *device)  {  	struct dasd_ccw_req *cqr;  	unsigned long flags; +	struct ccw1 *ccw;  	if (device->eer_cqr)  		return 0; @@ -468,10 +474,11 @@ int dasd_eer_enable(struct dasd_device *device)  	cqr->expires = 10 * HZ;  	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); -	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SNSS; -	cqr->cpaddr->count = SNSS_DATA_SIZE; -	cqr->cpaddr->flags = 0; -	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; +	ccw = cqr->cpaddr; +	ccw->cmd_code = DASD_ECKD_CCW_SNSS; +	ccw->count = SNSS_DATA_SIZE; +	ccw->flags = 0; +	ccw->cda = (__u32)(addr_t) cqr->data;  	cqr->buildclk = get_clock();  	cqr->status = DASD_CQR_FILLED; @@ -534,7 +541,7 @@ static int dasd_eer_open(struct inode *inp, struct file *filp)  	if (eerb->buffer_page_count < 1 ||  	    eerb->buffer_page_count > INT_MAX / PAGE_SIZE) {  		kfree(eerb); -		MESSAGE(KERN_WARNING, "can't open device since module " +		DBF_EVENT(DBF_WARNING, "can't open device since module "  			"parameter eer_pages is smaller than 1 or"  			" bigger than %d", (int)(INT_MAX / PAGE_SIZE));  		unlock_kernel(); @@ -687,7 +694,7 @@ int __init dasd_eer_init(void)  	if (rc) {  		kfree(dasd_eer_dev);  		dasd_eer_dev = NULL; -		MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not " +		DBF_EVENT(DBF_ERR, "%s", "dasd_eer_init could not "  		       "register misc device");  		return rc;  	} diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index 8f10000851a3..d970ce2814be 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c @@ -9,6 +9,8 @@   *   */ +#define KMSG_COMPONENT "dasd" +  #include <linux/ctype.h>  #include <linux/init.h> @@ -91,14 +93,14 @@ dasd_default_erp_action(struct dasd_ccw_req *cqr)          /* just retry - there is nothing to save ... I got no sense data.... */          if (cqr->retries > 0) { -		DEV_MESSAGE (KERN_DEBUG, device, +		DBF_DEV_EVENT(DBF_DEBUG, device,                               "default ERP called (%i retries left)",                               cqr->retries);  		cqr->lpm    = LPM_ANYPATH;  		cqr->status = DASD_CQR_FILLED;          } else { -                DEV_MESSAGE (KERN_WARNING, device, "%s", -			     "default ERP called (NO retry left)"); +		dev_err(&device->cdev->dev, +			"default ERP has run out of retries and failed\n");  		cqr->status = DASD_CQR_FAILED;  		cqr->stopclk = get_clock();          } @@ -162,8 +164,21 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)  		device->discipline->dump_sense(device, cqr, irb);  } +void +dasd_log_sense_dbf(struct dasd_ccw_req *cqr, struct irb *irb) +{ +	struct dasd_device *device; + +	device = cqr->startdev; +	/* dump sense data to s390 debugfeature*/ +	if (device->discipline && device->discipline->dump_sense_dbf) +		device->discipline->dump_sense_dbf(device, cqr, irb, "log"); +} +EXPORT_SYMBOL(dasd_log_sense_dbf); +  EXPORT_SYMBOL(dasd_default_erp_action);  EXPORT_SYMBOL(dasd_default_erp_postaction);  EXPORT_SYMBOL(dasd_alloc_erp_request);  EXPORT_SYMBOL(dasd_free_erp_request);  EXPORT_SYMBOL(dasd_log_sense); + diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index f1d176021694..a3eb6fd14673 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -6,6 +6,8 @@   *   */ +#define KMSG_COMPONENT "dasd" +  #include <linux/stddef.h>  #include <linux/kernel.h>  #include <asm/debug.h> @@ -128,17 +130,18 @@ dasd_fba_check_characteristics(struct dasd_device *device)  		private = kzalloc(sizeof(struct dasd_fba_private),  				  GFP_KERNEL | GFP_DMA);  		if (private == NULL) { -			DEV_MESSAGE(KERN_WARNING, device, "%s", -				    "memory allocation failed for private " -				    "data"); +			dev_warn(&device->cdev->dev, +				 "Allocating memory for private DASD " +				 "data failed\n");  			return -ENOMEM;  		}  		device->private = (void *) private;  	}  	block = dasd_alloc_block();  	if (IS_ERR(block)) { -		DEV_MESSAGE(KERN_WARNING, device, "%s", -			    "could not allocate dasd block structure"); +		DBF_EVENT(DBF_WARNING, "could not allocate dasd block " +			  "structure for device: %s", +			  dev_name(&device->cdev->dev));  		device->private = NULL;  		kfree(private);  		return PTR_ERR(block); @@ -150,9 +153,9 @@ dasd_fba_check_characteristics(struct dasd_device *device)  	rdc_data = (void *) &(private->rdc_data);  	rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32);  	if (rc) { -		DEV_MESSAGE(KERN_WARNING, device, -			    "Read device characteristics returned error %d", -			    rc); +		DBF_EVENT(DBF_WARNING, "Read device characteristics returned " +			  "error %d for device: %s", +			  rc, dev_name(&device->cdev->dev));  		device->block = NULL;  		dasd_free_block(block);  		device->private = NULL; @@ -160,15 +163,16 @@ dasd_fba_check_characteristics(struct dasd_device *device)  		return rc;  	} -	DEV_MESSAGE(KERN_INFO, device, -		    "%04X/%02X(CU:%04X/%02X) %dMB at(%d B/blk)", -		    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); +	dev_info(&device->cdev->dev, +		 "New FBA DASD %04X/%02X (CU %04X/%02X) with %d MB " +		 "and %d B/blk\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);  	return 0;  } @@ -180,7 +184,7 @@ static int dasd_fba_do_analysis(struct dasd_block *block)  	private = (struct dasd_fba_private *) block->base->private;  	rc = dasd_check_blocksize(private->rdc_data.blk_size);  	if (rc) { -		DEV_MESSAGE(KERN_INFO, block->base, "unknown blocksize %d", +		DBF_DEV_EVENT(DBF_WARNING, block->base, "unknown blocksize %d",  			    private->rdc_data.blk_size);  		return rc;  	} @@ -215,7 +219,7 @@ dasd_fba_erp_postaction(struct dasd_ccw_req * cqr)  	if (cqr->function == dasd_default_erp_action)  		return dasd_default_erp_postaction; -	DEV_MESSAGE(KERN_WARNING, cqr->startdev, "unknown ERP action %p", +	DBF_DEV_EVENT(DBF_WARNING, cqr->startdev, "unknown ERP action %p",  		    cqr->function);  	return NULL;  } @@ -233,9 +237,9 @@ static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device,  	}  	/* check for unsolicited interrupts */ -	DEV_MESSAGE(KERN_DEBUG, device, "%s", +	DBF_DEV_EVENT(DBF_WARNING, device, "%s",  		    "unsolicited interrupt received"); -	device->discipline->dump_sense(device, NULL, irb); +	device->discipline->dump_sense_dbf(device, NULL, irb, "unsolicited");  	dasd_schedule_device_bh(device);  	return;  }; @@ -437,6 +441,25 @@ dasd_fba_fill_info(struct dasd_device * device,  }  static void +dasd_fba_dump_sense_dbf(struct dasd_device *device, struct dasd_ccw_req *req, +			 struct irb *irb, char *reason) +{ +	int sl; +	if (irb->esw.esw0.erw.cons) { +		for (sl = 0; sl < 4; sl++) { +			DBF_DEV_EVENT(DBF_EMERG, device, +				      "%s: %08x %08x %08x %08x", +				      reason, irb->ecw[8 * 0], irb->ecw[8 * 1], +				      irb->ecw[8 * 2], irb->ecw[8 * 3]); +		} +	} else { +		DBF_DEV_EVENT(DBF_EMERG, device, "%s", +			      "SORRY - NO VALID SENSE AVAILABLE\n"); +	} +} + + +static void  dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,  		    struct irb *irb)  { @@ -446,7 +469,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,  	page = (char *) get_zeroed_page(GFP_ATOMIC);  	if (page == NULL) { -		DEV_MESSAGE(KERN_ERR, device, " %s", +		DBF_DEV_EVENT(DBF_WARNING, device, "%s",  			    "No memory to dump sense data");  		return;  	} @@ -476,8 +499,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,  	        len += sprintf(page + len, KERN_ERR PRINTK_HEADER  			       " SORRY - NO VALID SENSE AVAILABLE\n");  	} -	MESSAGE_LOG(KERN_ERR, "%s", -		    page + sizeof(KERN_ERR PRINTK_HEADER)); +	printk(KERN_ERR "%s", page);  	/* dump the Channel Program */  	/* print first CCWs (maximum 8) */ @@ -498,8 +520,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,  		len += sprintf(page + len, "\n");  		act++;  	} -	MESSAGE_LOG(KERN_ERR, "%s", -		    page + sizeof(KERN_ERR PRINTK_HEADER)); +	printk(KERN_ERR "%s", page);  	/* print failing CCW area */ @@ -540,8 +561,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,  		act++;  	}  	if (len > 0) -		MESSAGE_LOG(KERN_ERR, "%s", -			    page + sizeof(KERN_ERR PRINTK_HEADER)); +		printk(KERN_ERR "%s", page);  	free_page((unsigned long) page);  } @@ -576,6 +596,7 @@ static struct dasd_discipline dasd_fba_discipline = {  	.build_cp = dasd_fba_build_cp,  	.free_cp = dasd_fba_free_cp,  	.dump_sense = dasd_fba_dump_sense, +	.dump_sense_dbf = dasd_fba_dump_sense_dbf,  	.fill_info = dasd_fba_fill_info,  }; diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index e99d566b69cc..d3198303b93c 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -11,6 +11,8 @@   *   */ +#define KMSG_COMPONENT "dasd" +  #include <linux/interrupt.h>  #include <linux/fs.h>  #include <linux/blkpg.h> @@ -163,9 +165,8 @@ int dasd_gendisk_init(void)  	/* Register to static dasd major 94 */  	rc = register_blkdev(DASD_MAJOR, "dasd");  	if (rc != 0) { -		MESSAGE(KERN_WARNING, -			"Couldn't register successfully to " -			"major no %d", DASD_MAJOR); +		pr_warning("Registering the device driver with major number " +			   "%d failed\n", DASD_MAJOR);  		return rc;  	}  	return 0; diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 4a39084d9c95..c1e487f774c6 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -112,6 +112,9 @@ do { \  				d_data); \  } while(0) +/* limit size for an errorstring */ +#define ERRORLENGTH 30 +  /* definition of dbf debug levels */  #define	DBF_EMERG	0	/* system is unusable			*/  #define	DBF_ALERT	1	/* action must be taken immediately	*/ @@ -157,7 +160,8 @@ struct dasd_ccw_req {  	struct dasd_block *block;	/* the originating block device */  	struct dasd_device *memdev;	/* the device used to allocate this */  	struct dasd_device *startdev;	/* device the request is started on */ -	struct ccw1 *cpaddr;		/* address of channel program */ +	void *cpaddr;			/* address of ccw or tcw */ +	unsigned char cpmode;		/* 0 = cmd mode, 1 = itcw */  	char status;			/* status of this request */  	short retries;			/* A retry counter */  	unsigned long flags;        	/* flags of this request */ @@ -280,6 +284,8 @@ struct dasd_discipline {  	dasd_erp_fn_t(*erp_postaction) (struct dasd_ccw_req *);  	void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *,  			    struct irb *); +	void (*dump_sense_dbf) (struct dasd_device *, struct dasd_ccw_req *, +			    struct irb *, char *);  	void (*handle_unsolicited_interrupt) (struct dasd_device *,  					      struct irb *); @@ -378,7 +384,7 @@ struct dasd_block {  	struct block_device *bdev;  	atomic_t open_count; -	unsigned long blocks;	   /* size of volume in blocks */ +	unsigned long long blocks; /* size of volume in blocks */  	unsigned int bp_block;	   /* bytes per block */  	unsigned int s2b_shift;	   /* log2 (bp_block/512) */ @@ -573,12 +579,14 @@ int dasd_generic_notify(struct ccw_device *, int);  void dasd_generic_handle_state_change(struct dasd_device *);  int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int); +char *dasd_get_sense(struct irb *);  /* externals in dasd_devmap.c */  extern int dasd_max_devindex;  extern int dasd_probeonly;  extern int dasd_autodetect;  extern int dasd_nopav; +extern int dasd_nofcx;  int dasd_devmap_init(void);  void dasd_devmap_exit(void); @@ -623,6 +631,7 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int,  					    struct dasd_device *);  void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *);  void dasd_log_sense(struct dasd_ccw_req *, struct irb *); +void dasd_log_sense_dbf(struct dasd_ccw_req *cqr, struct irb *irb);  /* externals in dasd_3990_erp.c */  struct dasd_ccw_req *dasd_3990_erp_action(struct dasd_ccw_req *); diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index b82d816d9ef7..4ce3f72ee1c1 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -9,6 +9,9 @@   *   * i/o controls for the dasd driver.   */ + +#define KMSG_COMPONENT "dasd" +  #include <linux/interrupt.h>  #include <linux/major.h>  #include <linux/fs.h> @@ -94,7 +97,8 @@ static int dasd_ioctl_quiesce(struct dasd_block *block)  	if (!capable (CAP_SYS_ADMIN))  		return -EACCES; -	DEV_MESSAGE(KERN_DEBUG, base, "%s", "Quiesce IO on device"); +	dev_info(&base->cdev->dev, "The DASD has been put in the quiesce " +		 "state\n");  	spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);  	base->stopped |= DASD_STOPPED_QUIESCE;  	spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); @@ -103,7 +107,7 @@ static int dasd_ioctl_quiesce(struct dasd_block *block)  /* - * Quiesce device. + * Resume device.   */  static int dasd_ioctl_resume(struct dasd_block *block)  { @@ -114,7 +118,8 @@ static int dasd_ioctl_resume(struct dasd_block *block)  	if (!capable (CAP_SYS_ADMIN))  		return -EACCES; -	DEV_MESSAGE(KERN_DEBUG, base, "%s", "resume IO on device"); +	dev_info(&base->cdev->dev, "I/O operations have been resumed " +		 "on the DASD\n");  	spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);  	base->stopped &= ~DASD_STOPPED_QUIESCE;  	spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); @@ -140,13 +145,13 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)  		return -EPERM;  	if (base->state != DASD_STATE_BASIC) { -		DEV_MESSAGE(KERN_WARNING, base, "%s", -			    "dasd_format: device is not disabled! "); +		dev_warn(&base->cdev->dev, +			 "The DASD cannot be formatted while it is enabled\n");  		return -EBUSY;  	}  	DBF_DEV_EVENT(DBF_NOTICE, base, -		      "formatting units %d to %d (%d B blocks) flags %d", +		      "formatting units %u to %u (%u B blocks) flags %u",  		      fdata->start_unit,  		      fdata->stop_unit, fdata->blksize, fdata->intensity); @@ -169,10 +174,9 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)  		dasd_sfree_request(cqr, cqr->memdev);  		if (rc) {  			if (rc != -ERESTARTSYS) -				DEV_MESSAGE(KERN_ERR, base, -					    " Formatting of unit %d failed " -					    "with rc = %d", -					    fdata->start_unit, rc); +				dev_err(&base->cdev->dev, +					"Formatting unit %d failed with " +					"rc=%d\n", fdata->start_unit, rc);  			return rc;  		}  		fdata->start_unit++; @@ -199,8 +203,9 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp)  	if (copy_from_user(&fdata, argp, sizeof(struct format_data_t)))  		return -EFAULT;  	if (bdev != bdev->bd_contains) { -		DEV_MESSAGE(KERN_WARNING, block->base, "%s", -			    "Cannot low-level format a partition"); +		dev_warn(&block->base->cdev->dev, +			 "The specified DASD is a partition and cannot be " +			 "formatted\n");  		return -EINVAL;  	}  	return dasd_format(block, &fdata); @@ -365,9 +370,9 @@ static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd,  	return ret;  } -int -dasd_ioctl(struct block_device *bdev, fmode_t mode, -	   unsigned int cmd, unsigned long arg) +static int +dasd_do_ioctl(struct block_device *bdev, fmode_t mode, +	      unsigned int cmd, unsigned long arg)  {  	struct dasd_block *block = bdev->bd_disk->private_data;  	void __user *argp = (void __user *)arg; @@ -420,3 +425,14 @@ dasd_ioctl(struct block_device *bdev, fmode_t mode,  		return -EINVAL;  	}  } + +int dasd_ioctl(struct block_device *bdev, fmode_t mode, +	       unsigned int cmd, unsigned long arg) +{ +	int rc; + +	lock_kernel(); +	rc = dasd_do_ioctl(bdev, mode, cmd, arg); +	unlock_kernel(); +	return rc; +} diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index bf6fd348f20e..2080ba6a69b0 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -11,6 +11,8 @@   *   */ +#define KMSG_COMPONENT "dasd" +  #include <linux/ctype.h>  #include <linux/seq_file.h>  #include <linux/vmalloc.h> @@ -112,7 +114,7 @@ dasd_devices_show(struct seq_file *m, void *v)  			seq_printf(m, "n/f	 ");  		else  			seq_printf(m, -				   "at blocksize: %d, %ld blocks, %ld MB", +				   "at blocksize: %d, %lld blocks, %lld MB",  				   block->bp_block, block->blocks,  				   ((block->bp_block >> 9) *  				    block->blocks) >> 11); @@ -267,7 +269,7 @@ dasd_statistics_write(struct file *file, const char __user *user_buf,  	buffer = dasd_get_user_string(user_buf, user_len);  	if (IS_ERR(buffer))  		return PTR_ERR(buffer); -	MESSAGE_LOG(KERN_INFO, "/proc/dasd/statictics: '%s'", buffer); +	DBF_EVENT(DBF_DEBUG, "/proc/dasd/statictics: '%s'\n", buffer);  	/* check for valid verbs */  	for (str = buffer; isspace(*str); str++); @@ -277,33 +279,33 @@ dasd_statistics_write(struct file *file, const char __user *user_buf,  		if (strcmp(str, "on") == 0) {  			/* switch on statistics profiling */  			dasd_profile_level = DASD_PROFILE_ON; -			MESSAGE(KERN_INFO, "%s", "Statistics switched on"); +			pr_info("The statistics feature has been switched " +				"on\n");  		} else if (strcmp(str, "off") == 0) {  			/* switch off and reset statistics profiling */  			memset(&dasd_global_profile,  			       0, sizeof (struct dasd_profile_info_t));  			dasd_profile_level = DASD_PROFILE_OFF; -			MESSAGE(KERN_INFO, "%s", "Statistics switched off"); +			pr_info("The statistics feature has been switched " +				"off\n");  		} else  			goto out_error;  	} else if (strncmp(str, "reset", 5) == 0) {  		/* reset the statistics */  		memset(&dasd_global_profile, 0,  		       sizeof (struct dasd_profile_info_t)); -		MESSAGE(KERN_INFO, "%s", "Statistics reset"); +		pr_info("The statistics have been reset\n");  	} else  		goto out_error;  	kfree(buffer);  	return user_len;  out_error: -	MESSAGE(KERN_WARNING, "%s", -		"/proc/dasd/statistics: only 'set on', 'set off' " -		"and 'reset' are supported verbs"); +	pr_warning("%s is not a supported value for /proc/dasd/statistics\n", +		str);  	kfree(buffer);  	return -EINVAL;  #else -	MESSAGE(KERN_WARNING, "%s", -		"/proc/dasd/statistics: is not activated in this kernel"); +	pr_warning("/proc/dasd/statistics: is not activated in this kernel\n");  	return user_len;  #endif				/* CONFIG_DASD_PROFILE */  } diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h index d0d565a05dfe..c07809c8016a 100644 --- a/drivers/s390/char/tape.h +++ b/drivers/s390/char/tape.h @@ -324,8 +324,6 @@ static inline void tape_proc_cleanup (void) {;}  #endif  /* a function for dumping device sense info */ -extern void tape_dump_sense(struct tape_device *, struct tape_request *, -			    struct irb *);  extern void tape_dump_sense_dbf(struct tape_device *, struct tape_request *,  				struct irb *); diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 22ca34361ed7..807ded5eb049 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -8,6 +8,8 @@   *		 Martin Schwidefsky <schwidefsky@de.ibm.com>   */ +#define KMSG_COMPONENT "tape" +  #include <linux/module.h>  #include <linux/init.h>  #include <linux/bio.h> @@ -18,8 +20,6 @@  #include "tape.h"  #include "tape_std.h" -#define PRINTK_HEADER "TAPE_34XX: " -  /*   * Pointer to debug area.   */ @@ -203,8 +203,7 @@ tape_34xx_unsolicited_irq(struct tape_device *device, struct irb *irb)  		tape_34xx_schedule_work(device, TO_MSEN);  	} else {  		DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id); -		PRINT_WARN("Unsolicited IRQ (Device End) caught.\n"); -		tape_dump_sense(device, NULL, irb); +		tape_dump_sense_dbf(device, NULL, irb);  	}  	return TAPE_IO_SUCCESS;  } @@ -226,9 +225,7 @@ tape_34xx_erp_read_opposite(struct tape_device *device,  		tape_std_read_backward(device, request);  		return tape_34xx_erp_retry(request);  	} -	if (request->op != TO_RBA) -		PRINT_ERR("read_opposite called with state:%s\n", -			  tape_op_verbose[request->op]); +  	/*  	 * We tried to read forward and backward, but hat no  	 * success -> failed. @@ -241,13 +238,9 @@ tape_34xx_erp_bug(struct tape_device *device, struct tape_request *request,  		  struct irb *irb, int no)  {  	if (request->op != TO_ASSIGN) { -		PRINT_WARN("An unexpected condition #%d was caught in " -			   "tape error recovery.\n", no); -		PRINT_WARN("Please report this incident.\n"); -		if (request) -			PRINT_WARN("Operation of tape:%s\n", -				   tape_op_verbose[request->op]); -		tape_dump_sense(device, request, irb); +		dev_err(&device->cdev->dev, "An unexpected condition %d " +			"occurred in tape error recovery\n", no); +		tape_dump_sense_dbf(device, request, irb);  	}  	return tape_34xx_erp_failed(request, -EIO);  } @@ -261,9 +254,8 @@ tape_34xx_erp_overrun(struct tape_device *device, struct tape_request *request,  		      struct irb *irb)  {  	if (irb->ecw[3] == 0x40) { -		PRINT_WARN ("Data overrun error between control-unit " -			    "and drive. Use a faster channel connection, " -			    "if possible! \n"); +		dev_warn (&device->cdev->dev, "A data overrun occurred between" +			" the control unit and tape unit\n");  		return tape_34xx_erp_failed(request, -EIO);  	}  	return tape_34xx_erp_bug(device, request, irb, -1); @@ -280,7 +272,8 @@ tape_34xx_erp_sequence(struct tape_device *device,  		/*  		 * cu detected incorrect block-id sequence on tape.  		 */ -		PRINT_WARN("Illegal block-id sequence found!\n"); +		dev_warn (&device->cdev->dev, "The block ID sequence on the " +			"tape is incorrect\n");  		return tape_34xx_erp_failed(request, -EIO);  	}  	/* @@ -393,8 +386,6 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  			/* Writing at physical end of volume */  			return tape_34xx_erp_failed(request, -ENOSPC);  		default: -			PRINT_ERR("Invalid op in %s:%i\n", -				  __func__, __LINE__);  			return tape_34xx_erp_failed(request, 0);  		}  	} @@ -420,7 +411,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  							 irb, -4);  			/* data check is permanent, CU recovery has failed */ -			PRINT_WARN("Permanent read error\n"); +			dev_warn (&device->cdev->dev, "A read error occurred " +				"that cannot be recovered\n");  			return tape_34xx_erp_failed(request, -EIO);  		case 0x25:  			// a write data check occurred @@ -433,22 +425,26 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  							 irb, -5);  			// data check is permanent, cu-recovery has failed -			PRINT_WARN("Permanent write error\n"); +			dev_warn (&device->cdev->dev, "A write error on the " +				"tape cannot be recovered\n");  			return tape_34xx_erp_failed(request, -EIO);  		case 0x26:  			/* Data Check (read opposite) occurred. */  			return tape_34xx_erp_read_opposite(device, request);  		case 0x28:  			/* ID-Mark at tape start couldn't be written */ -			PRINT_WARN("ID-Mark could not be written.\n"); +			dev_warn (&device->cdev->dev, "Writing the ID-mark " +				"failed\n");  			return tape_34xx_erp_failed(request, -EIO);  		case 0x31:  			/* Tape void. Tried to read beyond end of device. */ -			PRINT_WARN("Read beyond end of recorded area.\n"); +			dev_warn (&device->cdev->dev, "Reading the tape beyond" +				" the end of the recorded area failed\n");  			return tape_34xx_erp_failed(request, -ENOSPC);  		case 0x41:  			/* Record sequence error. */ -			PRINT_WARN("Invalid block-id sequence found.\n"); +			dev_warn (&device->cdev->dev, "The tape contains an " +				"incorrect block ID sequence\n");  			return tape_34xx_erp_failed(request, -EIO);  		default:  			/* all data checks for 3480 should result in one of @@ -470,16 +466,12 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  	switch (sense[3]) {  	case 0x00:  		/* Unit check with erpa code 0. Report and ignore. */ -		PRINT_WARN("Non-error sense was found. " -			   "Unit-check will be ignored.\n");  		return TAPE_IO_SUCCESS;  	case 0x21:  		/*  		 * Data streaming not operational. CU will switch to  		 * interlock mode. Reissue the command.  		 */ -		PRINT_WARN("Data streaming not operational. " -			   "Switching to interlock-mode.\n");  		return tape_34xx_erp_retry(request);  	case 0x22:  		/* @@ -487,11 +479,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  		 * error on the lower interface, internal path not usable,  		 * or error during cartridge load.  		 */ -		PRINT_WARN("A path equipment check occurred. One of the " -			   "following conditions occurred:\n"); -		PRINT_WARN("drive adapter error, buffer error on the lower " -			   "interface, internal path not usable, error " -			   "during cartridge load.\n"); +		dev_warn (&device->cdev->dev, "A path equipment check occurred" +			" for the tape device\n");  		return tape_34xx_erp_failed(request, -EIO);  	case 0x24:  		/* @@ -514,7 +503,6 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  		 * but the hardware isn't capable to do idrc, or a perform  		 * subsystem func is issued and the CU is not on-line.  		 */ -		PRINT_WARN ("Function incompatible. Try to switch off idrc\n");  		return tape_34xx_erp_failed(request, -EIO);  	case 0x2a:  		/* @@ -552,23 +540,26 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  		 * reading the format id mark or that that format specified  		 * is not supported by the drive.  		 */ -		PRINT_WARN("Drive not capable processing the tape format!\n"); +		dev_warn (&device->cdev->dev, "The tape unit cannot process " +			"the tape format\n");  		return tape_34xx_erp_failed(request, -EMEDIUMTYPE);  	case 0x30:  		/* The medium is write protected. */ -		PRINT_WARN("Medium is write protected!\n"); +		dev_warn (&device->cdev->dev, "The tape medium is write-" +			"protected\n");  		return tape_34xx_erp_failed(request, -EACCES);  	case 0x32:  		// Tension loss. We cannot recover this, it's an I/O error. -		PRINT_WARN("The drive lost tape tension.\n"); +		dev_warn (&device->cdev->dev, "The tape does not have the " +			"required tape tension\n");  		return tape_34xx_erp_failed(request, -EIO);  	case 0x33:  		/*  		 * Load Failure. The cartridge was not inserted correctly or  		 * the tape is not threaded correctly.  		 */ -		PRINT_WARN("Cartridge load failure. Reload the cartridge " -			   "and try again.\n"); +		dev_warn (&device->cdev->dev, "The tape unit failed to load" +			" the cartridge\n");  		tape_34xx_delete_sbid_from(device, 0);  		return tape_34xx_erp_failed(request, -EIO);  	case 0x34: @@ -576,8 +567,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  		 * Unload failure. The drive cannot maintain tape tension  		 * and control tape movement during an unload operation.  		 */ -		PRINT_WARN("Failure during cartridge unload. " -			   "Please try manually.\n"); +		dev_warn (&device->cdev->dev, "Automatic unloading of the tape" +			" cartridge failed\n");  		if (request->op == TO_RUN)  			return tape_34xx_erp_failed(request, -EIO);  		return tape_34xx_erp_bug(device, request, irb, sense[3]); @@ -589,8 +580,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  		 * - the cartridge loader does not respond correctly  		 * - a failure occurs during an index, load, or unload cycle  		 */ -		PRINT_WARN("Equipment check! Please check the drive and " -			   "the cartridge loader.\n"); +		dev_warn (&device->cdev->dev, "An equipment check has occurred" +			" on the tape unit\n");  		return tape_34xx_erp_failed(request, -EIO);  	case 0x36:  		if (device->cdev->id.driver_info == tape_3490) @@ -603,7 +594,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  		 * Tape length error. The tape is shorter than reported in  		 * the beginning-of-tape data.  		 */ -		PRINT_WARN("Tape length error.\n"); +		dev_warn (&device->cdev->dev, "The tape information states an" +			" incorrect length\n");  		return tape_34xx_erp_failed(request, -EIO);  	case 0x38:  		/* @@ -620,12 +612,12 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  		return tape_34xx_erp_failed(request, -EIO);  	case 0x3a:  		/* Drive switched to not ready. */ -		PRINT_WARN("Drive not ready. Turn the ready/not ready switch " -			   "to ready position and try again.\n"); +		dev_warn (&device->cdev->dev, "The tape unit is not ready\n");  		return tape_34xx_erp_failed(request, -EIO);  	case 0x3b:  		/* Manual rewind or unload. This causes an I/O error. */ -		PRINT_WARN("Medium was rewound or unloaded manually.\n"); +		dev_warn (&device->cdev->dev, "The tape medium has been " +			"rewound or unloaded manually\n");  		tape_34xx_delete_sbid_from(device, 0);  		return tape_34xx_erp_failed(request, -EIO);  	case 0x42: @@ -633,7 +625,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  		 * Degraded mode. A condition that can cause degraded  		 * performance is detected.  		 */ -		PRINT_WARN("Subsystem is running in degraded mode.\n"); +		dev_warn (&device->cdev->dev, "The tape subsystem is running " +			"in degraded mode\n");  		return tape_34xx_erp_retry(request);  	case 0x43:  		/* Drive not ready. */ @@ -652,7 +645,6 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  					break;  			}  		} -		PRINT_WARN("The drive is not ready.\n");  		return tape_34xx_erp_failed(request, -ENOMEDIUM);  	case 0x44:  		/* Locate Block unsuccessful. */ @@ -663,7 +655,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  		return tape_34xx_erp_failed(request, -EIO);  	case 0x45:  		/* The drive is assigned to a different channel path. */ -		PRINT_WARN("The drive is assigned elsewhere.\n"); +		dev_warn (&device->cdev->dev, "The tape unit is already " +			"assigned\n");  		return tape_34xx_erp_failed(request, -EIO);  	case 0x46:  		/* @@ -671,11 +664,12 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  		 * the power supply may be switched off or  		 * the drive address may not be set correctly.  		 */ -		PRINT_WARN("The drive is not on-line."); +		dev_warn (&device->cdev->dev, "The tape unit is not online\n");  		return tape_34xx_erp_failed(request, -EIO);  	case 0x47:  		/* Volume fenced. CU reports volume integrity is lost. */ -		PRINT_WARN("Volume fenced. The volume integrity is lost.\n"); +		dev_warn (&device->cdev->dev, "The control unit has fenced " +			"access to the tape volume\n");  		tape_34xx_delete_sbid_from(device, 0);  		return tape_34xx_erp_failed(request, -EIO);  	case 0x48: @@ -683,20 +677,21 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  		return tape_34xx_erp_retry(request);  	case 0x49:  		/* Bus out check. A parity check error on the bus was found. */ -		PRINT_WARN("Bus out check. A data transfer over the bus " -			   "has been corrupted.\n"); +		dev_warn (&device->cdev->dev, "A parity error occurred on the " +			"tape bus\n");  		return tape_34xx_erp_failed(request, -EIO);  	case 0x4a:  		/* Control unit erp failed. */ -		PRINT_WARN("The control unit I/O error recovery failed.\n"); +		dev_warn (&device->cdev->dev, "I/O error recovery failed on " +			"the tape control unit\n");  		return tape_34xx_erp_failed(request, -EIO);  	case 0x4b:  		/*  		 * CU and drive incompatible. The drive requests micro-program  		 * patches, which are not available on the CU.  		 */ -		PRINT_WARN("The drive needs microprogram patches from the " -			   "control unit, which are not available.\n"); +		dev_warn (&device->cdev->dev, "The tape unit requires a " +			"firmware update\n");  		return tape_34xx_erp_failed(request, -EIO);  	case 0x4c:  		/* @@ -721,8 +716,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  			 * the block to be written is larger than allowed for  			 * buffered mode.  			 */ -			PRINT_WARN("Maximum block size for buffered " -				   "mode exceeded.\n"); +			dev_warn (&device->cdev->dev, "The maximum block size" +				" for buffered mode is exceeded\n");  			return tape_34xx_erp_failed(request, -ENOBUFS);  		}  		/* This erpa is reserved for 3480. */ @@ -759,22 +754,20 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  		return tape_34xx_erp_retry(request);  	case 0x55:  		/* Channel interface recovery (permanent). */ -		PRINT_WARN("A permanent channel interface error occurred.\n"); +		dev_warn (&device->cdev->dev, "A channel interface error cannot be" +			" recovered\n");  		return tape_34xx_erp_failed(request, -EIO);  	case 0x56:  		/* Channel protocol error. */ -		PRINT_WARN("A channel protocol error occurred.\n"); +		dev_warn (&device->cdev->dev, "A channel protocol error " +			"occurred\n");  		return tape_34xx_erp_failed(request, -EIO);  	case 0x57:  		if (device->cdev->id.driver_info == tape_3480) {  			/* Attention intercept. */ -			PRINT_WARN("An attention intercept occurred, " -				   "which will be recovered.\n");  			return tape_34xx_erp_retry(request);  		} else {  			/* Global status intercept. */ -			PRINT_WARN("An global status intercept was received, " -				   "which will be recovered.\n");  			return tape_34xx_erp_retry(request);  		}  	case 0x5a: @@ -782,42 +775,31 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,  		 * Tape length incompatible. The tape inserted is too long,  		 * which could cause damage to the tape or the drive.  		 */ -		PRINT_WARN("Tape Length Incompatible\n"); -		PRINT_WARN("Tape length exceeds IBM enhanced capacity " -			"cartdridge length or a medium\n"); -		PRINT_WARN("with EC-CST identification mark has been mounted " -			"in a device that writes\n"); -		PRINT_WARN("3480 or 3480 XF format.\n"); +		dev_warn (&device->cdev->dev, "The tape unit does not support " +			"the tape length\n");  		return tape_34xx_erp_failed(request, -EIO);  	case 0x5b:  		/* Format 3480 XF incompatible */  		if (sense[1] & SENSE_BEGINNING_OF_TAPE)  			/* The tape will get overwritten. */  			return tape_34xx_erp_retry(request); -		PRINT_WARN("Format 3480 XF Incompatible\n"); -		PRINT_WARN("Medium has been created in 3480 format. " -			"To change the format writes\n"); -		PRINT_WARN("must be issued at BOT.\n"); +		dev_warn (&device->cdev->dev, "The tape unit does not support" +			" format 3480 XF\n");  		return tape_34xx_erp_failed(request, -EIO);  	case 0x5c:  		/* Format 3480-2 XF incompatible */ -		PRINT_WARN("Format 3480-2 XF Incompatible\n"); -		PRINT_WARN("Device can only read 3480 or 3480 XF format.\n"); +		dev_warn (&device->cdev->dev, "The tape unit does not support tape " +			"format 3480-2 XF\n");  		return tape_34xx_erp_failed(request, -EIO);  	case 0x5d:  		/* Tape length violation. */ -		PRINT_WARN("Tape Length Violation\n"); -		PRINT_WARN("The mounted tape exceeds IBM Enhanced Capacity " -			"Cartdridge System Tape length.\n"); -		PRINT_WARN("This may cause damage to the drive or tape when " -			"processing to the EOV\n"); +		dev_warn (&device->cdev->dev, "The tape unit does not support" +			" the current tape length\n");  		return tape_34xx_erp_failed(request, -EMEDIUMTYPE);  	case 0x5e:  		/* Compaction algorithm incompatible. */ -		PRINT_WARN("Compaction Algorithm Incompatible\n"); -		PRINT_WARN("The volume is recorded using an incompatible " -			"compaction algorithm,\n"); -		PRINT_WARN("which is not supported by the device.\n"); +		dev_warn (&device->cdev->dev, "The tape unit does not support" +			" the compaction algorithm\n");  		return tape_34xx_erp_failed(request, -EMEDIUMTYPE);  		/* The following erpas should have been covered earlier. */ @@ -848,7 +830,6 @@ tape_34xx_irq(struct tape_device *device, struct tape_request *request,  	    (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) &&  	    (request->op == TO_WRI)) {  		/* Write at end of volume */ -		PRINT_INFO("End of volume\n"); /* XXX */  		return tape_34xx_erp_failed(request, -ENOSPC);  	} @@ -869,9 +850,7 @@ tape_34xx_irq(struct tape_device *device, struct tape_request *request,  	}  	DBF_EVENT(6, "xunknownirq\n"); -	PRINT_ERR("Unexpected interrupt.\n"); -	PRINT_ERR("Current op is: %s", tape_op_verbose[request->op]); -	tape_dump_sense(device, request, irb); +	tape_dump_sense_dbf(device, request, irb);  	return TAPE_IO_STOP;  } diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 71605a179d65..fc1d91294143 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -8,12 +8,15 @@   *		 Martin Schwidefsky <schwidefsky@de.ibm.com>   */ +#define KMSG_COMPONENT "tape" +  #include <linux/module.h>  #include <linux/init.h>  #include <linux/bio.h>  #include <asm/ebcdic.h>  #define TAPE_DBF_AREA	tape_3590_dbf +#define BUFSIZE 512	/* size of buffers for dynamic generated messages */  #include "tape.h"  #include "tape_std.h" @@ -36,7 +39,7 @@ EXPORT_SYMBOL(TAPE_DBF_AREA);   * - Read Alternate:		 implemented   *******************************************************************/ -#define PRINTK_HEADER "TAPE_3590: " +#define KMSG_COMPONENT "tape"  static const char *tape_3590_msg[TAPE_3590_MAX_MSG] = {  	[0x00] = "", @@ -661,8 +664,7 @@ tape_3590_bread(struct tape_device *device, struct request *req)  			ccw++;  			dst += TAPEBLOCK_HSEC_SIZE;  		} -		if (off > bv->bv_len) -			BUG(); +		BUG_ON(off > bv->bv_len);  	}  	ccw = tape_ccw_end(ccw, NOP, 0, NULL);  	DBF_EVENT(6, "xBREDccwg\n"); @@ -726,7 +728,7 @@ static void tape_3590_med_state_set(struct tape_device *device,  	}  	c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK;  	if (sense->flags & MSENSE_CRYPT_MASK) { -		PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags); +		DBF_EVENT(6, "Medium is encrypted (%04x)\n", sense->flags);  		c_info->medium_status |= TAPE390_MEDIUM_ENCRYPTED_MASK;  	} else	{  		DBF_EVENT(6, "Medium is not encrypted %04x\n", sense->flags); @@ -847,8 +849,7 @@ tape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb)  		tape_3590_schedule_work(device, TO_READ_ATTMSG);  	} else {  		DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id); -		PRINT_WARN("Unsolicited IRQ (Device End) caught.\n"); -		tape_dump_sense(device, NULL, irb); +		tape_dump_sense_dbf(device, NULL, irb);  	}  	/* check medium state */  	tape_3590_schedule_work(device, TO_MSEN); @@ -876,8 +877,6 @@ tape_3590_erp_basic(struct tape_device *device, struct tape_request *request,  	case SENSE_BRA_DRE:  		return tape_3590_erp_failed(device, request, irb, rc);  	default: -		PRINT_ERR("Unknown BRA %x - This should not happen!\n", -			  sense->bra);  		BUG();  		return TAPE_IO_STOP;  	} @@ -910,7 +909,8 @@ tape_3590_erp_swap(struct tape_device *device, struct tape_request *request,  	 * should proceed with the new tape... this  	 * should probably be done in user space!  	 */ -	PRINT_WARN("(%s): Swap Tape Device!\n", dev_name(&device->cdev->dev)); +	dev_warn (&device->cdev->dev, "The tape medium must be loaded into a " +		"different tape unit\n");  	return tape_3590_erp_basic(device, request, irb, -EIO);  } @@ -985,8 +985,6 @@ tape_3590_erp_read_opposite(struct tape_device *device,  		return tape_3590_erp_failed(device, request, irb, -EIO);  		break;  	default: -		PRINT_WARN("read_opposite_recovery_called_with_op: %s\n", -			   tape_op_verbose[request->op]);  		return tape_3590_erp_failed(device, request, irb, -EIO);  	}  } @@ -998,50 +996,61 @@ static void  tape_3590_print_mim_msg_f0(struct tape_device *device, struct irb *irb)  {  	struct tape_3590_sense *sense; +	char *exception, *service; + +	exception = kmalloc(BUFSIZE, GFP_ATOMIC); +	service = kmalloc(BUFSIZE, GFP_ATOMIC); + +	if (!exception || !service) +		goto out_nomem;  	sense = (struct tape_3590_sense *) irb->ecw;  	/* Exception Message */  	switch (sense->fmt.f70.emc) {  	case 0x02: -		PRINT_WARN("(%s): Data degraded\n", -			   dev_name(&device->cdev->dev)); +		snprintf(exception, BUFSIZE, "Data degraded");  		break;  	case 0x03: -		PRINT_WARN("(%s): Data degraded in partion %i\n", -			   dev_name(&device->cdev->dev), sense->fmt.f70.mp); +		snprintf(exception, BUFSIZE, "Data degraded in partion %i", +			sense->fmt.f70.mp);  		break;  	case 0x04: -		PRINT_WARN("(%s): Medium degraded\n", -			   dev_name(&device->cdev->dev)); +		snprintf(exception, BUFSIZE, "Medium degraded");  		break;  	case 0x05: -		PRINT_WARN("(%s): Medium degraded in partition %i\n", -			   dev_name(&device->cdev->dev), sense->fmt.f70.mp); +		snprintf(exception, BUFSIZE, "Medium degraded in partition %i", +			sense->fmt.f70.mp);  		break;  	case 0x06: -		PRINT_WARN("(%s): Block 0 Error\n", -			   dev_name(&device->cdev->dev)); +		snprintf(exception, BUFSIZE, "Block 0 Error");  		break;  	case 0x07: -		PRINT_WARN("(%s): Medium Exception 0x%02x\n", -			   dev_name(&device->cdev->dev), sense->fmt.f70.md); +		snprintf(exception, BUFSIZE, "Medium Exception 0x%02x", +			sense->fmt.f70.md);  		break;  	default: -		PRINT_WARN("(%s): MIM ExMsg: 0x%02x\n", -			   dev_name(&device->cdev->dev), sense->fmt.f70.emc); +		snprintf(exception, BUFSIZE, "0x%02x", +			sense->fmt.f70.emc);  		break;  	}  	/* Service Message */  	switch (sense->fmt.f70.smc) {  	case 0x02: -		PRINT_WARN("(%s): Reference Media maintenance procedure %i\n", -			   dev_name(&device->cdev->dev), sense->fmt.f70.md); +		snprintf(service, BUFSIZE, "Reference Media maintenance " +			"procedure %i", sense->fmt.f70.md);  		break;  	default: -		PRINT_WARN("(%s): MIM ServiceMsg: 0x%02x\n", -			   dev_name(&device->cdev->dev), sense->fmt.f70.smc); +		snprintf(service, BUFSIZE, "0x%02x", +			sense->fmt.f70.smc);  		break;  	} + +	dev_warn (&device->cdev->dev, "Tape media information: exception %s, " +		"service %s\n", exception, service); + +out_nomem: +	kfree(exception); +	kfree(service);  }  /* @@ -1051,108 +1060,108 @@ static void  tape_3590_print_io_sim_msg_f1(struct tape_device *device, struct irb *irb)  {  	struct tape_3590_sense *sense; +	char *exception, *service; + +	exception = kmalloc(BUFSIZE, GFP_ATOMIC); +	service = kmalloc(BUFSIZE, GFP_ATOMIC); + +	if (!exception || !service) +		goto out_nomem;  	sense = (struct tape_3590_sense *) irb->ecw;  	/* Exception Message */  	switch (sense->fmt.f71.emc) {  	case 0x01: -		PRINT_WARN("(%s): Effect of failure is unknown\n", -			   dev_name(&device->cdev->dev)); +		snprintf(exception, BUFSIZE, "Effect of failure is unknown");  		break;  	case 0x02: -		PRINT_WARN("(%s): CU Exception - no performance impact\n", -			   dev_name(&device->cdev->dev)); +		snprintf(exception, BUFSIZE, "CU Exception - no performance " +			"impact");  		break;  	case 0x03: -		PRINT_WARN("(%s): CU Exception on channel interface 0x%02x\n", -			   dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); +		snprintf(exception, BUFSIZE, "CU Exception on channel " +			"interface 0x%02x", sense->fmt.f71.md[0]);  		break;  	case 0x04: -		PRINT_WARN("(%s): CU Exception on device path 0x%02x\n", -			   dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); +		snprintf(exception, BUFSIZE, "CU Exception on device path " +			"0x%02x", sense->fmt.f71.md[0]);  		break;  	case 0x05: -		PRINT_WARN("(%s): CU Exception on library path 0x%02x\n", -			   dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); +		snprintf(exception, BUFSIZE, "CU Exception on library path " +			"0x%02x", sense->fmt.f71.md[0]);  		break;  	case 0x06: -		PRINT_WARN("(%s): CU Exception on node 0x%02x\n", -			   dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); +		snprintf(exception, BUFSIZE, "CU Exception on node 0x%02x", +			sense->fmt.f71.md[0]);  		break;  	case 0x07: -		PRINT_WARN("(%s): CU Exception on partition 0x%02x\n", -			   dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); +		snprintf(exception, BUFSIZE, "CU Exception on partition " +			"0x%02x", sense->fmt.f71.md[0]);  		break;  	default: -		PRINT_WARN("(%s): SIM ExMsg: 0x%02x\n", -			   dev_name(&device->cdev->dev), sense->fmt.f71.emc); +		snprintf(exception, BUFSIZE, "0x%02x", +			sense->fmt.f71.emc);  	}  	/* Service Message */  	switch (sense->fmt.f71.smc) {  	case 0x01: -		PRINT_WARN("(%s): Repair impact is unknown\n", -			   dev_name(&device->cdev->dev)); +		snprintf(service, BUFSIZE, "Repair impact is unknown");  		break;  	case 0x02: -		PRINT_WARN("(%s): Repair will not impact cu performance\n", -			   dev_name(&device->cdev->dev)); +		snprintf(service, BUFSIZE, "Repair will not impact cu " +			"performance");  		break;  	case 0x03:  		if (sense->fmt.f71.mdf == 0) -			PRINT_WARN("(%s): Repair will disable node " -				   "0x%x on CU\n", -				   dev_name(&device->cdev->dev), -				   sense->fmt.f71.md[1]); +			snprintf(service, BUFSIZE, "Repair will disable node " +				"0x%x on CU", sense->fmt.f71.md[1]);  		else -			PRINT_WARN("(%s): Repair will disable nodes " -				   "(0x%x-0x%x) on CU\n", -				   dev_name(&device->cdev->dev), -				   sense->fmt.f71.md[1], sense->fmt.f71.md[2]); +			snprintf(service, BUFSIZE, "Repair will disable " +				"nodes (0x%x-0x%x) on CU", sense->fmt.f71.md[1], +				sense->fmt.f71.md[2]);  		break;  	case 0x04:  		if (sense->fmt.f71.mdf == 0) -			PRINT_WARN("(%s): Repair will disable cannel path " -				   "0x%x on CU\n", -				   dev_name(&device->cdev->dev), -				   sense->fmt.f71.md[1]); +			snprintf(service, BUFSIZE, "Repair will disable " +				"channel path 0x%x on CU", +				sense->fmt.f71.md[1]);  		else -			PRINT_WARN("(%s): Repair will disable cannel paths " -				   "(0x%x-0x%x) on CU\n", -				   dev_name(&device->cdev->dev), -				   sense->fmt.f71.md[1], sense->fmt.f71.md[2]); +			snprintf(service, BUFSIZE, "Repair will disable cannel" +				" paths (0x%x-0x%x) on CU", +				sense->fmt.f71.md[1], sense->fmt.f71.md[2]);  		break;  	case 0x05:  		if (sense->fmt.f71.mdf == 0) -			PRINT_WARN("(%s): Repair will disable device path " -				   "0x%x on CU\n", -				   dev_name(&device->cdev->dev), -				   sense->fmt.f71.md[1]); +			snprintf(service, BUFSIZE, "Repair will disable device" +				" path 0x%x on CU", sense->fmt.f71.md[1]);  		else -			PRINT_WARN("(%s): Repair will disable device paths " -				   "(0x%x-0x%x) on CU\n", -				   dev_name(&device->cdev->dev), -				   sense->fmt.f71.md[1], sense->fmt.f71.md[2]); +			snprintf(service, BUFSIZE, "Repair will disable device" +				" paths (0x%x-0x%x) on CU", +				sense->fmt.f71.md[1], sense->fmt.f71.md[2]);  		break;  	case 0x06:  		if (sense->fmt.f71.mdf == 0) -			PRINT_WARN("(%s): Repair will disable library path " -				   "0x%x on CU\n", -				   dev_name(&device->cdev->dev), -				   sense->fmt.f71.md[1]); +			snprintf(service, BUFSIZE, "Repair will disable " +				"library path 0x%x on CU", +				sense->fmt.f71.md[1]);  		else -			PRINT_WARN("(%s): Repair will disable library paths " -				   "(0x%x-0x%x) on CU\n", -				   dev_name(&device->cdev->dev), -				   sense->fmt.f71.md[1], sense->fmt.f71.md[2]); +			snprintf(service, BUFSIZE, "Repair will disable " +				"library paths (0x%x-0x%x) on CU", +				sense->fmt.f71.md[1], sense->fmt.f71.md[2]);  		break;  	case 0x07: -		PRINT_WARN("(%s): Repair will disable access to CU\n", -			   dev_name(&device->cdev->dev)); +		snprintf(service, BUFSIZE, "Repair will disable access to CU");  		break;  	default: -		PRINT_WARN("(%s): SIM ServiceMsg: 0x%02x\n", -			   dev_name(&device->cdev->dev), sense->fmt.f71.smc); +		snprintf(service, BUFSIZE, "0x%02x", +			sense->fmt.f71.smc);  	} + +	dev_warn (&device->cdev->dev, "I/O subsystem information: exception" +		" %s, service %s\n", exception, service); +out_nomem: +	kfree(exception); +	kfree(service);  }  /* @@ -1162,111 +1171,109 @@ static void  tape_3590_print_dev_sim_msg_f2(struct tape_device *device, struct irb *irb)  {  	struct tape_3590_sense *sense; +	char *exception, *service; + +	exception = kmalloc(BUFSIZE, GFP_ATOMIC); +	service = kmalloc(BUFSIZE, GFP_ATOMIC); + +	if (!exception || !service) +		goto out_nomem;  	sense = (struct tape_3590_sense *) irb->ecw;  	/* Exception Message */  	switch (sense->fmt.f71.emc) {  	case 0x01: -		PRINT_WARN("(%s): Effect of failure is unknown\n", -			   dev_name(&device->cdev->dev)); +		snprintf(exception, BUFSIZE, "Effect of failure is unknown");  		break;  	case 0x02: -		PRINT_WARN("(%s): DV Exception - no performance impact\n", -			   dev_name(&device->cdev->dev)); +		snprintf(exception, BUFSIZE, "DV Exception - no performance" +			" impact");  		break;  	case 0x03: -		PRINT_WARN("(%s): DV Exception on channel interface 0x%02x\n", -			   dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); +		snprintf(exception, BUFSIZE, "DV Exception on channel " +			"interface 0x%02x", sense->fmt.f71.md[0]);  		break;  	case 0x04: -		PRINT_WARN("(%s): DV Exception on loader 0x%02x\n", -			   dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); +		snprintf(exception, BUFSIZE, "DV Exception on loader 0x%02x", +			sense->fmt.f71.md[0]);  		break;  	case 0x05: -		PRINT_WARN("(%s): DV Exception on message display 0x%02x\n", -			   dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); +		snprintf(exception, BUFSIZE, "DV Exception on message display" +			" 0x%02x", sense->fmt.f71.md[0]);  		break;  	case 0x06: -		PRINT_WARN("(%s): DV Exception in tape path\n", -			   dev_name(&device->cdev->dev)); +		snprintf(exception, BUFSIZE, "DV Exception in tape path");  		break;  	case 0x07: -		PRINT_WARN("(%s): DV Exception in drive\n", -			   dev_name(&device->cdev->dev)); +		snprintf(exception, BUFSIZE, "DV Exception in drive");  		break;  	default: -		PRINT_WARN("(%s): DSIM ExMsg: 0x%02x\n", -			   dev_name(&device->cdev->dev), sense->fmt.f71.emc); +		snprintf(exception, BUFSIZE, "0x%02x", +			sense->fmt.f71.emc);  	}  	/* Service Message */  	switch (sense->fmt.f71.smc) {  	case 0x01: -		PRINT_WARN("(%s): Repair impact is unknown\n", -			   dev_name(&device->cdev->dev)); +		snprintf(service, BUFSIZE, "Repair impact is unknown");  		break;  	case 0x02: -		PRINT_WARN("(%s): Repair will not impact device performance\n", -			   dev_name(&device->cdev->dev)); +		snprintf(service, BUFSIZE, "Repair will not impact device " +			"performance");  		break;  	case 0x03:  		if (sense->fmt.f71.mdf == 0) -			PRINT_WARN("(%s): Repair will disable channel path " -				   "0x%x on DV\n", -				   dev_name(&device->cdev->dev), -				   sense->fmt.f71.md[1]); +			snprintf(service, BUFSIZE, "Repair will disable " +				"channel path 0x%x on DV", +				sense->fmt.f71.md[1]);  		else -			PRINT_WARN("(%s): Repair will disable channel path " -				   "(0x%x-0x%x) on DV\n", -				   dev_name(&device->cdev->dev), -				   sense->fmt.f71.md[1], sense->fmt.f71.md[2]); +			snprintf(service, BUFSIZE, "Repair will disable " +				"channel path (0x%x-0x%x) on DV", +				sense->fmt.f71.md[1], sense->fmt.f71.md[2]);  		break;  	case 0x04:  		if (sense->fmt.f71.mdf == 0) -			PRINT_WARN("(%s): Repair will disable interface 0x%x " -				   "on DV\n", -				   dev_name(&device->cdev->dev), -				   sense->fmt.f71.md[1]); +			snprintf(service, BUFSIZE, "Repair will disable " +				"interface 0x%x on DV", sense->fmt.f71.md[1]);  		else -			PRINT_WARN("(%s): Repair will disable interfaces " -				   "(0x%x-0x%x) on DV\n", -				   dev_name(&device->cdev->dev), -				   sense->fmt.f71.md[1], sense->fmt.f71.md[2]); +			snprintf(service, BUFSIZE, "Repair will disable " +				"interfaces (0x%x-0x%x) on DV", +				sense->fmt.f71.md[1], sense->fmt.f71.md[2]);  		break;  	case 0x05:  		if (sense->fmt.f71.mdf == 0) -			PRINT_WARN("(%s): Repair will disable loader 0x%x " -				   "on DV\n", -				   dev_name(&device->cdev->dev), -				   sense->fmt.f71.md[1]); +			snprintf(service, BUFSIZE, "Repair will disable loader" +				" 0x%x on DV", sense->fmt.f71.md[1]);  		else -			PRINT_WARN("(%s): Repair will disable loader " -				   "(0x%x-0x%x) on DV\n", -				   dev_name(&device->cdev->dev), -				   sense->fmt.f71.md[1], sense->fmt.f71.md[2]); +			snprintf(service, BUFSIZE, "Repair will disable loader" +				" (0x%x-0x%x) on DV", +				sense->fmt.f71.md[1], sense->fmt.f71.md[2]);  		break;  	case 0x07: -		PRINT_WARN("(%s): Repair will disable access to DV\n", -			   dev_name(&device->cdev->dev)); +		snprintf(service, BUFSIZE, "Repair will disable access to DV");  		break;  	case 0x08:  		if (sense->fmt.f71.mdf == 0) -			PRINT_WARN("(%s): Repair will disable message " -				   "display 0x%x on DV\n", -				   dev_name(&device->cdev->dev), -				   sense->fmt.f71.md[1]); +			snprintf(service, BUFSIZE, "Repair will disable " +				"message display 0x%x on DV", +				sense->fmt.f71.md[1]);  		else -			PRINT_WARN("(%s): Repair will disable message " -				   "displays (0x%x-0x%x) on DV\n", -				   dev_name(&device->cdev->dev), -				   sense->fmt.f71.md[1], sense->fmt.f71.md[2]); +			snprintf(service, BUFSIZE, "Repair will disable " +				"message displays (0x%x-0x%x) on DV", +				 sense->fmt.f71.md[1], sense->fmt.f71.md[2]);  		break;  	case 0x09: -		PRINT_WARN("(%s): Clean DV\n", dev_name(&device->cdev->dev)); +		snprintf(service, BUFSIZE, "Clean DV");  		break;  	default: -		PRINT_WARN("(%s): DSIM ServiceMsg: 0x%02x\n", -			   dev_name(&device->cdev->dev), sense->fmt.f71.smc); +		snprintf(service, BUFSIZE, "0x%02x", +			sense->fmt.f71.smc);  	} + +	dev_warn (&device->cdev->dev, "Device subsystem information: exception" +		" %s, service %s\n", exception, service); +out_nomem: +	kfree(exception); +	kfree(service);  }  /* @@ -1282,46 +1289,44 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb)  		return;  	if ((sense->mc > 0) && (sense->mc < TAPE_3590_MAX_MSG)) {  		if (tape_3590_msg[sense->mc] != NULL) -			PRINT_WARN("(%s): %s\n", dev_name(&device->cdev->dev), -				   tape_3590_msg[sense->mc]); -		else { -			PRINT_WARN("(%s): Message Code 0x%x\n", -				   dev_name(&device->cdev->dev), sense->mc); -		} +			dev_warn (&device->cdev->dev, "The tape unit has " +				"issued sense message %s\n", +				tape_3590_msg[sense->mc]); +		else +			dev_warn (&device->cdev->dev, "The tape unit has " +				"issued an unknown sense message code 0x%x\n", +				sense->mc);  		return;  	}  	if (sense->mc == 0xf0) {  		/* Standard Media Information Message */ -		PRINT_WARN("(%s): MIM SEV=%i, MC=%02x, ES=%x/%x, " -			   "RC=%02x-%04x-%02x\n", dev_name(&device->cdev->dev), -			   sense->fmt.f70.sev, sense->mc, -			   sense->fmt.f70.emc, sense->fmt.f70.smc, -			   sense->fmt.f70.refcode, sense->fmt.f70.mid, -			   sense->fmt.f70.fid); +		dev_warn (&device->cdev->dev, "MIM SEV=%i, MC=%02x, ES=%x/%x, " +			"RC=%02x-%04x-%02x\n", sense->fmt.f70.sev, sense->mc, +			sense->fmt.f70.emc, sense->fmt.f70.smc, +			sense->fmt.f70.refcode, sense->fmt.f70.mid, +			sense->fmt.f70.fid);  		tape_3590_print_mim_msg_f0(device, irb);  		return;  	}  	if (sense->mc == 0xf1) {  		/* Standard I/O Subsystem Service Information Message */ -		PRINT_WARN("(%s): IOSIM SEV=%i, DEVTYPE=3590/%02x, " -			   "MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n", -			   dev_name(&device->cdev->dev), sense->fmt.f71.sev, -			   device->cdev->id.dev_model, -			   sense->mc, sense->fmt.f71.emc, -			   sense->fmt.f71.smc, sense->fmt.f71.refcode1, -			   sense->fmt.f71.refcode2, sense->fmt.f71.refcode3); +		dev_warn (&device->cdev->dev, "IOSIM SEV=%i, DEVTYPE=3590/%02x," +			" MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n", +			sense->fmt.f71.sev, device->cdev->id.dev_model, +			sense->mc, sense->fmt.f71.emc, sense->fmt.f71.smc, +			sense->fmt.f71.refcode1, sense->fmt.f71.refcode2, +			sense->fmt.f71.refcode3);  		tape_3590_print_io_sim_msg_f1(device, irb);  		return;  	}  	if (sense->mc == 0xf2) {  		/* Standard Device Service Information Message */ -		PRINT_WARN("(%s): DEVSIM SEV=%i, DEVTYPE=3590/%02x, " -			   "MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n", -			   dev_name(&device->cdev->dev), sense->fmt.f71.sev, -			   device->cdev->id.dev_model, -			   sense->mc, sense->fmt.f71.emc, -			   sense->fmt.f71.smc, sense->fmt.f71.refcode1, -			   sense->fmt.f71.refcode2, sense->fmt.f71.refcode3); +		dev_warn (&device->cdev->dev, "DEVSIM SEV=%i, DEVTYPE=3590/%02x" +			", MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n", +			sense->fmt.f71.sev, device->cdev->id.dev_model, +			sense->mc, sense->fmt.f71.emc, sense->fmt.f71.smc, +			sense->fmt.f71.refcode1, sense->fmt.f71.refcode2, +			sense->fmt.f71.refcode3);  		tape_3590_print_dev_sim_msg_f2(device, irb);  		return;  	} @@ -1329,8 +1334,8 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb)  		/* Standard Library Service Information Message */  		return;  	} -	PRINT_WARN("(%s): Device Message(%x)\n", -		   dev_name(&device->cdev->dev), sense->mc); +	dev_warn (&device->cdev->dev, "The tape unit has issued an unknown " +		"sense message code %x\n", sense->mc);  }  static int tape_3590_crypt_error(struct tape_device *device, @@ -1355,9 +1360,8 @@ static int tape_3590_crypt_error(struct tape_device *device,  		/* No connection to EKM */  		return tape_3590_erp_basic(device, request, irb, -ENOTCONN); -	PRINT_ERR("(%s): Unable to get encryption key from EKM\n", bus_id); -	PRINT_ERR("(%s): CU=%02X DRIVE=%06X EKM=%02X:%04X\n", bus_id, cu_rc, -		drv_rc, ekm_rc1, ekm_rc2); +	dev_err (&device->cdev->dev, "The tape unit failed to obtain the " +		"encryption key from EKM\n");  	return tape_3590_erp_basic(device, request, irb, -ENOKEY);  } @@ -1443,8 +1447,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,  		 * print additional msg since default msg  		 * "device intervention" is not very meaningfull  		 */ -		PRINT_WARN("(%s): Tape operation when medium not loaded\n", -			   dev_name(&device->cdev->dev));  		tape_med_state_set(device, MS_UNLOADED);  		tape_3590_schedule_work(device, TO_CRYPT_OFF);  		return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM); @@ -1490,19 +1492,13 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,  		return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);  	case 0x6020: -		PRINT_WARN("(%s): Cartridge of wrong type ?\n", -			   dev_name(&device->cdev->dev));  		return tape_3590_erp_basic(device, request, irb, -EMEDIUMTYPE);  	case 0x8011: -		PRINT_WARN("(%s): Another host has reserved the tape device\n", -			   dev_name(&device->cdev->dev));  		return tape_3590_erp_basic(device, request, irb, -EPERM);  	case 0x8013: -		PRINT_WARN("(%s): Another host has privileged access to the " -			   "tape device\n", dev_name(&device->cdev->dev)); -		PRINT_WARN("(%s): To solve the problem unload the current " -			   "cartridge!\n", dev_name(&device->cdev->dev)); +		dev_warn (&device->cdev->dev, "A different host has privileged" +			" access to the tape unit\n");  		return tape_3590_erp_basic(device, request, irb, -EPERM);  	default:  		return tape_3590_erp_basic(device, request, irb, -EIO); @@ -1552,9 +1548,7 @@ tape_3590_irq(struct tape_device *device, struct tape_request *request,  	}  	DBF_EVENT(6, "xunknownirq\n"); -	PRINT_ERR("Unexpected interrupt.\n"); -	PRINT_ERR("Current op is: %s", tape_op_verbose[request->op]); -	tape_dump_sense(device, request, irb); +	tape_dump_sense_dbf(device, request, irb);  	return TAPE_IO_STOP;  } @@ -1609,7 +1603,6 @@ tape_3590_setup_device(struct tape_device *device)  	if (rc)  		goto fail_rdc_data;  	if (rdc_data->data[31] == 0x13) { -		PRINT_INFO("Device has crypto support\n");  		data->crypt_info.capability |= TAPE390_CRYPT_SUPPORTED_MASK;  		tape_3592_disable_crypt(device);  	} else { diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index ae18baf59f06..f32e89e7c4f2 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -10,6 +10,8 @@   *		 Stefan Bader <shbader@de.ibm.com>   */ +#define KMSG_COMPONENT "tape" +  #include <linux/fs.h>  #include <linux/module.h>  #include <linux/blkdev.h> @@ -23,8 +25,6 @@  #include "tape.h" -#define PRINTK_HEADER "TAPE_BLOCK: " -  #define TAPEBLOCK_MAX_SEC	100  #define TAPEBLOCK_MIN_REQUEUE	3 @@ -279,8 +279,6 @@ tapeblock_cleanup_device(struct tape_device *device)  	tape_put_device(device);  	if (!device->blk_data.disk) { -		PRINT_ERR("(%s): No gendisk to clean up!\n", -			dev_name(&device->cdev->dev));  		goto cleanup_queue;  	} @@ -314,7 +312,8 @@ tapeblock_revalidate_disk(struct gendisk *disk)  	if (!device->blk_data.medium_changed)  		return 0; -	PRINT_INFO("Detecting media size...\n"); +	dev_info(&device->cdev->dev, "Determining the size of the recorded " +		"area...\n");  	rc = tape_mtop(device, MTFSFM, 1);  	if (rc)  		return rc; @@ -341,7 +340,8 @@ tapeblock_revalidate_disk(struct gendisk *disk)  	device->bof = rc;  	nr_of_blks -= rc; -	PRINT_INFO("Found %i blocks on media\n", nr_of_blks); +	dev_info(&device->cdev->dev, "The size of the recorded area is %i " +		"blocks\n", nr_of_blks);  	set_capacity(device->blk_data.disk,  		nr_of_blks*(TAPEBLOCK_HSEC_SIZE/512)); @@ -376,8 +376,8 @@ tapeblock_open(struct block_device *bdev, fmode_t mode)  	if (device->required_tapemarks) {  		DBF_EVENT(2, "TBLOCK: missing tapemarks\n"); -		PRINT_ERR("TBLOCK: Refusing to open tape with missing" -			" end of file marks.\n"); +		dev_warn(&device->cdev->dev, "Opening the tape failed because" +			" of missing end-of-file marks\n");  		rc = -EPERM;  		goto put_device;  	} @@ -452,7 +452,6 @@ tapeblock_ioctl(  			rc = -EINVAL;  			break;  		default: -			PRINT_WARN("invalid ioctl 0x%x\n", command);  			rc = -EINVAL;  	} @@ -474,7 +473,6 @@ tapeblock_init(void)  	if (tapeblock_major == 0)  		tapeblock_major = rc; -	PRINT_INFO("tape gets major %d for block device\n", tapeblock_major);  	return 0;  } diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c index be0ce2215c8d..31566c55adfe 100644 --- a/drivers/s390/char/tape_char.c +++ b/drivers/s390/char/tape_char.c @@ -24,8 +24,6 @@  #include "tape_std.h"  #include "tape_class.h" -#define PRINTK_HEADER "TAPE_CHAR: " -  #define TAPECHAR_MAJOR		0	/* get dynamic major */  /* @@ -102,8 +100,6 @@ tapechar_check_idalbuffer(struct tape_device *device, size_t block_size)  	if (block_size > MAX_BLOCKSIZE) {  		DBF_EVENT(3, "Invalid blocksize (%zd > %d)\n",  			block_size, MAX_BLOCKSIZE); -		PRINT_ERR("Invalid blocksize (%zd> %d)\n", -			block_size, MAX_BLOCKSIZE);  		return -EINVAL;  	} @@ -485,7 +481,6 @@ tapechar_init (void)  		return -1;  	tapechar_major = MAJOR(dev); -	PRINT_INFO("tape gets major %d for character devices\n", MAJOR(dev));  	return 0;  } @@ -496,7 +491,5 @@ tapechar_init (void)  void  tapechar_exit(void)  { -	PRINT_INFO("tape releases major %d for character devices\n", -		tapechar_major);  	unregister_chrdev_region(MKDEV(tapechar_major, 0), 256);  } diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index f9bb51fa7f5b..08c09d3503cf 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -11,6 +11,7 @@   *		 Stefan Bader <shbader@de.ibm.com>   */ +#define KMSG_COMPONENT "tape"  #include <linux/module.h>  #include <linux/init.h>	     // for kernel parameters  #include <linux/kmod.h>	     // for requesting modules @@ -25,7 +26,6 @@  #include "tape.h"  #include "tape_std.h" -#define PRINTK_HEADER "TAPE_CORE: "  #define LONG_BUSY_TIMEOUT 180 /* seconds */  static void __tape_do_irq (struct ccw_device *, unsigned long, struct irb *); @@ -214,13 +214,13 @@ 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); -		PRINT_INFO("(%s): Tape is unloaded\n", -			   dev_name(&device->cdev->dev)); +		dev_info(&device->cdev->dev, "The tape cartridge has been " +			"successfully unloaded\n");  		break;  	case MS_LOADED:  		device->tape_generic_status &= ~GMT_DR_OPEN(~0); -		PRINT_INFO("(%s): Tape has been mounted\n", -			   dev_name(&device->cdev->dev)); +		dev_info(&device->cdev->dev, "A tape cartridge has been " +			"mounted\n");  		break;  	default:  		// print nothing @@ -333,7 +333,6 @@ tape_generic_online(struct tape_device *device,  	/* Let the discipline have a go at the device. */  	device->discipline = discipline;  	if (!try_module_get(discipline->owner)) { -		PRINT_ERR("Cannot get module. Module gone.\n");  		return -EINVAL;  	} @@ -391,7 +390,6 @@ int  tape_generic_offline(struct tape_device *device)  {  	if (!device) { -		PRINT_ERR("tape_generic_offline: no such device\n");  		return -ENODEV;  	} @@ -413,9 +411,6 @@ tape_generic_offline(struct tape_device *device)  			DBF_EVENT(3, "(%08x): Set offline failed "  				"- drive in use.\n",  				device->cdev_id); -			PRINT_WARN("(%s): Set offline failed " -				"- drive in use.\n", -				dev_name(&device->cdev->dev));  			spin_unlock_irq(get_ccwdev_lock(device->cdev));  			return -EBUSY;  	} @@ -435,14 +430,11 @@ tape_alloc_device(void)  	device = kzalloc(sizeof(struct tape_device), GFP_KERNEL);  	if (device == NULL) {  		DBF_EXCEPTION(2, "ti:no mem\n"); -		PRINT_INFO ("can't allocate memory for " -			    "tape info structure\n");  		return ERR_PTR(-ENOMEM);  	}  	device->modeset_byte = kmalloc(1, GFP_KERNEL | GFP_DMA);  	if (device->modeset_byte == NULL) {  		DBF_EXCEPTION(2, "ti:no mem\n"); -		PRINT_INFO("can't allocate memory for modeset byte\n");  		kfree(device);  		return ERR_PTR(-ENOMEM);  	} @@ -490,7 +482,6 @@ tape_put_device(struct tape_device *device)  	} else {  		if (remain < 0) {  			DBF_EVENT(4, "put device without reference\n"); -			PRINT_ERR("put device without reference\n");  		} else {  			DBF_EVENT(4, "tape_free_device(%p)\n", device);  			kfree(device->modeset_byte); @@ -538,8 +529,6 @@ tape_generic_probe(struct ccw_device *cdev)  	ret = sysfs_create_group(&cdev->dev.kobj, &tape_attr_group);  	if (ret) {  		tape_put_device(device); -		PRINT_ERR("probe failed for tape device %s\n", -			  dev_name(&cdev->dev));  		return ret;  	}  	cdev->dev.driver_data = device; @@ -547,7 +536,6 @@ tape_generic_probe(struct ccw_device *cdev)  	device->cdev = cdev;  	ccw_device_get_id(cdev, &dev_id);  	device->cdev_id = devid_to_int(&dev_id); -	PRINT_INFO("tape device %s found\n", dev_name(&cdev->dev));  	return ret;  } @@ -584,7 +572,6 @@ tape_generic_remove(struct ccw_device *cdev)  	device = cdev->dev.driver_data;  	if (!device) { -		PRINT_ERR("No device pointer in tape_generic_remove!\n");  		return;  	}  	DBF_LH(3, "(%08x): tape_generic_remove(%p)\n", device->cdev_id, cdev); @@ -615,10 +602,8 @@ tape_generic_remove(struct ccw_device *cdev)  			 */  			DBF_EVENT(3, "(%08x): Drive in use vanished!\n",  				device->cdev_id); -			PRINT_WARN("(%s): Drive in use vanished - " -				"expect trouble!\n", -				dev_name(&device->cdev->dev)); -			PRINT_WARN("State was %i\n", device->tape_state); +			dev_warn(&device->cdev->dev, "A tape unit was detached" +				" while in use\n");  			tape_state_set(device, TS_NOT_OPER);  			__tape_discard_requests(device);  			spin_unlock_irq(get_ccwdev_lock(device->cdev)); @@ -639,8 +624,7 @@ tape_alloc_request(int cplength, int datasize)  {  	struct tape_request *request; -	if (datasize > PAGE_SIZE || (cplength*sizeof(struct ccw1)) > PAGE_SIZE) -		BUG(); +	BUG_ON(datasize > PAGE_SIZE || (cplength*sizeof(struct ccw1)) > PAGE_SIZE);  	DBF_LH(6, "tape_alloc_request(%d, %d)\n", cplength, datasize); @@ -797,8 +781,7 @@ static void tape_long_busy_timeout(unsigned long data)  	device = (struct tape_device *) data;  	spin_lock_irq(get_ccwdev_lock(device->cdev));  	request = list_entry(device->req_queue.next, struct tape_request, list); -	if (request->status != TAPE_REQUEST_LONG_BUSY) -		BUG(); +	BUG_ON(request->status != TAPE_REQUEST_LONG_BUSY);  	DBF_LH(6, "%08x: Long busy timeout.\n", device->cdev_id);  	__tape_start_next_request(device);  	device->lb_timeout.data = (unsigned long) tape_put_device(device); @@ -830,30 +813,6 @@ __tape_end_request(  }  /* - * Write sense data to console/dbf - */ -void -tape_dump_sense(struct tape_device* device, struct tape_request *request, -		struct irb *irb) -{ -	unsigned int *sptr; - -	PRINT_INFO("-------------------------------------------------\n"); -	PRINT_INFO("DSTAT : %02x  CSTAT: %02x	CPA: %04x\n", -		   irb->scsw.cmd.dstat, irb->scsw.cmd.cstat, irb->scsw.cmd.cpa); -	PRINT_INFO("DEVICE: %s\n", dev_name(&device->cdev->dev)); -	if (request != NULL) -		PRINT_INFO("OP	  : %s\n", tape_op_verbose[request->op]); - -	sptr = (unsigned int *) irb->ecw; -	PRINT_INFO("Sense data: %08X %08X %08X %08X \n", -		   sptr[0], sptr[1], sptr[2], sptr[3]); -	PRINT_INFO("Sense data: %08X %08X %08X %08X \n", -		   sptr[4], sptr[5], sptr[6], sptr[7]); -	PRINT_INFO("--------------------------------------------------\n"); -} - -/*   * Write sense data to dbf   */  void @@ -1051,8 +1010,6 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)  	device = (struct tape_device *) cdev->dev.driver_data;  	if (device == NULL) { -		PRINT_ERR("could not get device structure for %s " -			  "in interrupt\n", dev_name(&cdev->dev));  		return;  	}  	request = (struct tape_request *) intparm; @@ -1064,13 +1021,13 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)  		/* FIXME: What to do with the request? */  		switch (PTR_ERR(irb)) {  			case -ETIMEDOUT: -				PRINT_WARN("(%s): Request timed out\n", +				DBF_LH(1, "(%s): Request timed out\n",  					dev_name(&cdev->dev));  			case -EIO:  				__tape_end_request(device, request, -EIO);  				break;  			default: -				PRINT_ERR("(%s): Unexpected i/o error %li\n", +				DBF_LH(1, "(%s): Unexpected i/o error %li\n",  					dev_name(&cdev->dev),  					PTR_ERR(irb));  		} @@ -1182,8 +1139,6 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)  		default:  			if (rc > 0) {  				DBF_EVENT(6, "xunknownrc\n"); -				PRINT_ERR("Invalid return code from discipline " -				  	"interrupt function.\n");  				__tape_end_request(device, request, -EIO);  			} else {  				__tape_end_request(device, request, rc); @@ -1323,7 +1278,6 @@ EXPORT_SYMBOL(tape_state_set);  EXPORT_SYMBOL(tape_med_state_set);  EXPORT_SYMBOL(tape_alloc_request);  EXPORT_SYMBOL(tape_free_request); -EXPORT_SYMBOL(tape_dump_sense);  EXPORT_SYMBOL(tape_dump_sense_dbf);  EXPORT_SYMBOL(tape_do_io);  EXPORT_SYMBOL(tape_do_io_async); diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c index 8a376af926a7..202f42132939 100644 --- a/drivers/s390/char/tape_proc.c +++ b/drivers/s390/char/tape_proc.c @@ -20,8 +20,6 @@  #include "tape.h" -#define PRINTK_HEADER "TAPE_PROC: " -  static const char *tape_med_st_verbose[MS_SIZE] =  {  	[MS_UNKNOWN] = "UNKNOWN ", @@ -128,7 +126,6 @@ tape_proc_init(void)  		proc_create("tapedevices", S_IFREG | S_IRUGO | S_IWUSR, NULL,  			    &tape_proc_ops);  	if (tape_proc_devices == NULL) { -		PRINT_WARN("tape: Cannot register procfs entry tapedevices\n");  		return;  	}  } diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index 5bd573d144d6..1a9420ba518d 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c @@ -26,8 +26,6 @@  #include "tape.h"  #include "tape_std.h" -#define PRINTK_HEADER "TAPE_STD: " -  /*   * tape_std_assign   */ @@ -39,16 +37,15 @@ tape_std_assign_timeout(unsigned long data)  	int rc;  	request = (struct tape_request *) data; -	if ((device = request->device) == NULL) -		BUG(); +	device = request->device; +	BUG_ON(!device);  	DBF_EVENT(3, "%08x: Assignment timeout. Device busy.\n",  			device->cdev_id);  	rc = tape_cancel_io(device, request);  	if(rc) -		PRINT_ERR("(%s): Assign timeout: Cancel failed with rc = %i\n", +		DBF_EVENT(3, "(%s): Assign timeout: Cancel failed with rc = %i\n",  			dev_name(&device->cdev->dev), rc); -  }  int @@ -82,8 +79,6 @@ tape_std_assign(struct tape_device *device)  	del_timer(&timeout);  	if (rc != 0) { -		PRINT_WARN("%s: assign failed - device might be busy\n", -			dev_name(&device->cdev->dev));  		DBF_EVENT(3, "%08x: assign failed - device might be busy\n",  			device->cdev_id);  	} else { @@ -105,8 +100,6 @@ tape_std_unassign (struct tape_device *device)  	if (device->tape_state == TS_NOT_OPER) {  		DBF_EVENT(3, "(%08x): Can't unassign device\n",  			device->cdev_id); -		PRINT_WARN("(%s): Can't unassign device - device gone\n", -			dev_name(&device->cdev->dev));  		return -EIO;  	} @@ -120,8 +113,6 @@ tape_std_unassign (struct tape_device *device)  	if ((rc = tape_do_io(device, request)) != 0) {  		DBF_EVENT(3, "%08x: Unassign failed\n", device->cdev_id); -		PRINT_WARN("%s: Unassign failed\n", -			   dev_name(&device->cdev->dev));  	} else {  		DBF_EVENT(3, "%08x: Tape unassigned\n", device->cdev_id);  	} @@ -242,8 +233,6 @@ tape_std_mtsetblk(struct tape_device *device, int count)  	if (count > MAX_BLOCKSIZE) {  		DBF_EVENT(3, "Invalid block size (%d > %d) given.\n",  			count, MAX_BLOCKSIZE); -		PRINT_ERR("Invalid block size (%d > %d) given.\n", -			count, MAX_BLOCKSIZE);  		return -EINVAL;  	} @@ -633,14 +622,6 @@ tape_std_mtcompression(struct tape_device *device, int mt_count)  	if (mt_count < 0 || mt_count > 1) {  		DBF_EXCEPTION(6, "xcom parm\n"); -		if (*device->modeset_byte & 0x08) -			PRINT_INFO("(%s) Compression is currently on\n", -				   dev_name(&device->cdev->dev)); -		else -			PRINT_INFO("(%s) Compression is currently off\n", -				   dev_name(&device->cdev->dev)); -		PRINT_INFO("Use 1 to switch compression on, 0 to " -			   "switch it off\n");  		return -EINVAL;  	}  	request = tape_alloc_request(2, 0); diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index eefc6611412e..1bbae433fbd8 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -5,7 +5,7 @@   *   * For more information please refer to Documentation/s390/zfcpdump.txt   * - * Copyright IBM Corp. 2003,2007 + * Copyright IBM Corp. 2003,2008   * Author(s): Michael Holzheu   */ @@ -24,6 +24,7 @@  #include <asm/debug.h>  #include <asm/processor.h>  #include <asm/irqflags.h> +#include <asm/checksum.h>  #include "sclp.h"  #define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x) @@ -48,12 +49,19 @@ struct sys_info {  	union save_area	lc_mask;  }; +struct ipib_info { +	unsigned long	ipib; +	u32		checksum; +}  __attribute__((packed)); +  static struct sys_info sys_info;  static struct debug_info *zcore_dbf;  static int hsa_available;  static struct dentry *zcore_dir;  static struct dentry *zcore_file;  static struct dentry *zcore_memmap_file; +static struct dentry *zcore_reipl_file; +static struct ipl_parameter_block *ipl_block;  /*   * Copy memory from HSA to kernel or user memory (not reentrant): @@ -527,6 +535,33 @@ static const struct file_operations zcore_memmap_fops = {  	.release	= zcore_memmap_release,  }; +static ssize_t zcore_reipl_write(struct file *filp, const char __user *buf, +				 size_t count, loff_t *ppos) +{ +	if (ipl_block) { +		diag308(DIAG308_SET, ipl_block); +		diag308(DIAG308_IPL, NULL); +	} +	return count; +} + +static int zcore_reipl_open(struct inode *inode, struct file *filp) +{ +	return 0; +} + +static int zcore_reipl_release(struct inode *inode, struct file *filp) +{ +	return 0; +} + +static const struct file_operations zcore_reipl_fops = { +	.owner		= THIS_MODULE, +	.write		= zcore_reipl_write, +	.open		= zcore_reipl_open, +	.release	= zcore_reipl_release, +}; +  static void __init set_s390_lc_mask(union save_area *map)  { @@ -645,6 +680,40 @@ static int __init zcore_header_init(int arch, struct zcore_header *hdr)  	return 0;  } +/* + * Provide IPL parameter information block from either HSA or memory + * for future reipl + */ +static int __init zcore_reipl_init(void) +{ +	struct ipib_info ipib_info; +	int rc; + +	rc = memcpy_hsa_kernel(&ipib_info, __LC_DUMP_REIPL, sizeof(ipib_info)); +	if (rc) +		return rc; +	if (ipib_info.ipib == 0) +		return 0; +	ipl_block = (void *) __get_free_page(GFP_KERNEL); +	if (!ipl_block) +		return -ENOMEM; +	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); +	if (rc) { +		free_page((unsigned long) ipl_block); +		return rc; +	} +	if (csum_partial(ipl_block, ipl_block->hdr.len, 0) != +	    ipib_info.checksum) { +		TRACE("Checksum does not match\n"); +		free_page((unsigned long) ipl_block); +		ipl_block = NULL; +	} +	return 0; +} +  static int __init zcore_init(void)  {  	unsigned char arch; @@ -690,6 +759,10 @@ static int __init zcore_init(void)  	if (rc)  		goto fail; +	rc = zcore_reipl_init(); +	if (rc) +		goto fail; +  	zcore_dir = debugfs_create_dir("zcore" , NULL);  	if (!zcore_dir) {  		rc = -ENOMEM; @@ -707,9 +780,17 @@ static int __init zcore_init(void)  		rc = -ENOMEM;  		goto fail_file;  	} +	zcore_reipl_file = debugfs_create_file("reipl", S_IRUSR, zcore_dir, +						NULL, &zcore_reipl_fops); +	if (!zcore_reipl_file) { +		rc = -ENOMEM; +		goto fail_memmap_file; +	}  	hsa_available = 1;  	return 0; +fail_memmap_file: +	debugfs_remove(zcore_memmap_file);  fail_file:  	debugfs_remove(zcore_file);  fail_dir: @@ -723,10 +804,15 @@ static void __exit zcore_exit(void)  {  	debug_unregister(zcore_dbf);  	sclp_sdias_exit(); +	free_page((unsigned long) ipl_block); +	debugfs_remove(zcore_reipl_file); +	debugfs_remove(zcore_memmap_file); +	debugfs_remove(zcore_file); +	debugfs_remove(zcore_dir);  	diag308(DIAG308_REL_HSA, NULL);  } -MODULE_AUTHOR("Copyright IBM Corp. 2003,2007"); +MODULE_AUTHOR("Copyright IBM Corp. 2003,2008");  MODULE_DESCRIPTION("zcore module for zfcpdump support");  MODULE_LICENSE("GPL"); diff --git a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile index bd79bd165396..adb3dd301528 100644 --- a/drivers/s390/cio/Makefile +++ b/drivers/s390/cio/Makefile @@ -3,7 +3,7 @@  #  obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o scsw.o \ -	fcx.o itcw.o +	fcx.o itcw.o crw.o  ccw_device-objs += device.o device_fsm.o device_ops.o  ccw_device-objs += device_id.o device_pgid.o device_status.o  obj-y += ccw_device.o cmf.o diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index fe6cea15bbaf..65d2e769dfa1 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -34,8 +34,8 @@ struct airq_t {  	void *drv_data;  }; -static union indicator_t indicators[MAX_ISC]; -static struct airq_t *airqs[MAX_ISC][NR_AIRQS]; +static union indicator_t indicators[MAX_ISC+1]; +static struct airq_t *airqs[MAX_ISC+1][NR_AIRQS];  static int register_airq(struct airq_t *airq, u8 isc)  { @@ -133,6 +133,8 @@ void do_adapter_IO(u8 isc)  		while (word) {  			if (word & INDICATOR_MASK) {  				airq = airqs[isc][i]; +				/* Make sure gcc reads from airqs only once. */ +				barrier();  				if (likely(airq))  					airq->handler(&indicators[isc].byte[i],  						      airq->drv_data); diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index fe00be3675cd..6565f027791e 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -336,8 +336,7 @@ cio_ignore_write(struct file *file, const char __user *user_buf,  		 size_t user_len, loff_t *offset)  {  	char *buf; -	size_t i; -	ssize_t rc, ret; +	ssize_t rc, ret, i;  	if (*offset)  		return -EINVAL; diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index b91c1719b075..22ce765d537e 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -315,16 +315,32 @@ error:  }  EXPORT_SYMBOL(ccwgroup_create_from_string); -static int __init -init_ccwgroup (void) +static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, +			     void *data); + +static struct notifier_block ccwgroup_nb = { +	.notifier_call = ccwgroup_notifier +}; + +static int __init init_ccwgroup(void)  { -	return bus_register (&ccwgroup_bus_type); +	int ret; + +	ret = bus_register(&ccwgroup_bus_type); +	if (ret) +		return ret; + +	ret = bus_register_notifier(&ccwgroup_bus_type, &ccwgroup_nb); +	if (ret) +		bus_unregister(&ccwgroup_bus_type); + +	return ret;  } -static void __exit -cleanup_ccwgroup (void) +static void __exit cleanup_ccwgroup(void)  { -	bus_unregister (&ccwgroup_bus_type); +	bus_unregister_notifier(&ccwgroup_bus_type, &ccwgroup_nb); +	bus_unregister(&ccwgroup_bus_type);  }  module_init(init_ccwgroup); @@ -392,27 +408,28 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const  	unsigned long value;  	int ret; -	gdev = to_ccwgroupdev(dev);  	if (!dev->driver) -		return count; +		return -ENODEV; + +	gdev = to_ccwgroupdev(dev); +	gdrv = to_ccwgroupdrv(dev->driver); -	gdrv = to_ccwgroupdrv (gdev->dev.driver);  	if (!try_module_get(gdrv->owner))  		return -EINVAL;  	ret = strict_strtoul(buf, 0, &value);  	if (ret)  		goto out; -	ret = count; +  	if (value == 1) -		ccwgroup_set_online(gdev); +		ret = ccwgroup_set_online(gdev);  	else if (value == 0) -		ccwgroup_set_offline(gdev); +		ret = ccwgroup_set_offline(gdev);  	else  		ret = -EINVAL;  out:  	module_put(gdrv->owner); -	return ret; +	return (ret == 0) ? count : ret;  }  static ssize_t @@ -454,13 +471,18 @@ ccwgroup_remove (struct device *dev)  	struct ccwgroup_device *gdev;  	struct ccwgroup_driver *gdrv; +	device_remove_file(dev, &dev_attr_online); +	device_remove_file(dev, &dev_attr_ungroup); + +	if (!dev->driver) +		return 0; +  	gdev = to_ccwgroupdev(dev);  	gdrv = to_ccwgroupdrv(dev->driver); -	device_remove_file(dev, &dev_attr_online); - -	if (gdrv && gdrv->remove) +	if (gdrv->remove)  		gdrv->remove(gdev); +  	return 0;  } @@ -469,9 +491,13 @@ static void ccwgroup_shutdown(struct device *dev)  	struct ccwgroup_device *gdev;  	struct ccwgroup_driver *gdrv; +	if (!dev->driver) +		return; +  	gdev = to_ccwgroupdev(dev);  	gdrv = to_ccwgroupdrv(dev->driver); -	if (gdrv && gdrv->shutdown) + +	if (gdrv->shutdown)  		gdrv->shutdown(gdev);  } @@ -484,6 +510,19 @@ static struct bus_type ccwgroup_bus_type = {  	.shutdown = ccwgroup_shutdown,  }; + +static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, +			     void *data) +{ +	struct device *dev = data; + +	if (action == BUS_NOTIFY_UNBIND_DRIVER) +		device_schedule_callback(dev, ccwgroup_ungroup_callback); + +	return NOTIFY_OK; +} + +  /**   * ccwgroup_driver_register() - register a ccw group driver   * @cdriver: driver to be registered diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 1246f61a5338..3e5f304ad88f 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -17,8 +17,8 @@  #include <linux/errno.h>  #include <asm/chpid.h>  #include <asm/sclp.h> +#include <asm/crw.h> -#include "../s390mach.h"  #include "cio.h"  #include "css.h"  #include "ioasm.h" @@ -706,12 +706,12 @@ static int __init chp_init(void)  	struct chp_id chpid;  	int ret; -	ret = s390_register_crw_handler(CRW_RSC_CPATH, chp_process_crw); +	ret = crw_register_handler(CRW_RSC_CPATH, chp_process_crw);  	if (ret)  		return ret;  	chp_wq = create_singlethread_workqueue("cio_chp");  	if (!chp_wq) { -		s390_unregister_crw_handler(CRW_RSC_CPATH); +		crw_unregister_handler(CRW_RSC_CPATH);  		return -ENOMEM;  	}  	INIT_WORK(&cfg_work, cfg_func); diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index ebab6ea4659b..883f16f96f22 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -19,8 +19,8 @@  #include <asm/cio.h>  #include <asm/chpid.h>  #include <asm/chsc.h> +#include <asm/crw.h> -#include "../s390mach.h"  #include "css.h"  #include "cio.h"  #include "cio_debug.h" @@ -589,6 +589,7 @@ __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)  	case 0x0102:  	case 0x0103:  		ret = -EINVAL; +		break;  	default:  		ret = chsc_error_from_response(secm_area->response.code);  	} @@ -820,7 +821,7 @@ int __init chsc_alloc_sei_area(void)  			      "chsc machine checks!\n");  		return -ENOMEM;  	} -	ret = s390_register_crw_handler(CRW_RSC_CSS, chsc_process_crw); +	ret = crw_register_handler(CRW_RSC_CSS, chsc_process_crw);  	if (ret)  		kfree(sei_page);  	return ret; @@ -828,7 +829,7 @@ int __init chsc_alloc_sei_area(void)  void __init chsc_free_sei_area(void)  { -	s390_unregister_crw_handler(CRW_RSC_CSS); +	crw_unregister_handler(CRW_RSC_CSS);  	kfree(sei_page);  } diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 659f8a791656..2aebb9823044 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -30,6 +30,8 @@  #include <asm/isc.h>  #include <asm/cpu.h>  #include <asm/fcx.h> +#include <asm/nmi.h> +#include <asm/crw.h>  #include "cio.h"  #include "css.h"  #include "chsc.h" @@ -38,7 +40,6 @@  #include "blacklist.h"  #include "cio_debug.h"  #include "chp.h" -#include "../s390mach.h"  debug_info_t *cio_debug_msg_id;  debug_info_t *cio_debug_trace_id; @@ -471,6 +472,7 @@ EXPORT_SYMBOL_GPL(cio_enable_subchannel);  int cio_disable_subchannel(struct subchannel *sch)  {  	char dbf_txt[15]; +	int retry;  	int ret;  	CIO_TRACE_EVENT (2, "dissch"); @@ -481,16 +483,17 @@ int cio_disable_subchannel(struct subchannel *sch)  	if (cio_update_schib(sch))  		return -ENODEV; -	if (scsw_actl(&sch->schib.scsw) != 0) -		/* -		 * the disable function must not be called while there are -		 *  requests pending for completion ! -		 */ -		return -EBUSY; -  	sch->config.ena = 0; -	ret = cio_commit_config(sch); +	for (retry = 0; retry < 3; retry++) { +		ret = cio_commit_config(sch); +		if (ret == -EBUSY) { +			struct irb irb; +			if (tsch(sch->schid, &irb) != 0) +				break; +		} else +			break; +	}  	sprintf (dbf_txt, "ret:%d", ret);  	CIO_TRACE_EVENT (2, dbf_txt);  	return ret; diff --git a/drivers/s390/cio/crw.c b/drivers/s390/cio/crw.c new file mode 100644 index 000000000000..d157665d0e76 --- /dev/null +++ b/drivers/s390/cio/crw.c @@ -0,0 +1,159 @@ +/* + *   Channel report handling code + * + *    Copyright IBM Corp. 2000,2009 + *    Author(s): Ingo Adlung <adlung@de.ibm.com>, + *		 Martin Schwidefsky <schwidefsky@de.ibm.com>, + *		 Cornelia Huck <cornelia.huck@de.ibm.com>, + *		 Heiko Carstens <heiko.carstens@de.ibm.com>, + */ + +#include <linux/semaphore.h> +#include <linux/mutex.h> +#include <linux/kthread.h> +#include <linux/init.h> +#include <asm/crw.h> + +static struct semaphore crw_semaphore; +static DEFINE_MUTEX(crw_handler_mutex); +static crw_handler_t crw_handlers[NR_RSCS]; + +/** + * crw_register_handler() - register a channel report word handler + * @rsc: reporting source code to handle + * @handler: handler to be registered + * + * Returns %0 on success and a negative error value otherwise. + */ +int crw_register_handler(int rsc, crw_handler_t handler) +{ +	int rc = 0; + +	if ((rsc < 0) || (rsc >= NR_RSCS)) +		return -EINVAL; +	mutex_lock(&crw_handler_mutex); +	if (crw_handlers[rsc]) +		rc = -EBUSY; +	else +		crw_handlers[rsc] = handler; +	mutex_unlock(&crw_handler_mutex); +	return rc; +} + +/** + * crw_unregister_handler() - unregister a channel report word handler + * @rsc: reporting source code to handle + */ +void crw_unregister_handler(int rsc) +{ +	if ((rsc < 0) || (rsc >= NR_RSCS)) +		return; +	mutex_lock(&crw_handler_mutex); +	crw_handlers[rsc] = NULL; +	mutex_unlock(&crw_handler_mutex); +} + +/* + * Retrieve CRWs and call function to handle event. + */ +static int crw_collect_info(void *unused) +{ +	struct crw crw[2]; +	int ccode; +	unsigned int chain; +	int ignore; + +repeat: +	ignore = down_interruptible(&crw_semaphore); +	chain = 0; +	while (1) { +		crw_handler_t handler; + +		if (unlikely(chain > 1)) { +			struct crw tmp_crw; + +			printk(KERN_WARNING"%s: Code does not support more " +			       "than two chained crws; please report to " +			       "linux390@de.ibm.com!\n", __func__); +			ccode = stcrw(&tmp_crw); +			printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, " +			       "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", +			       __func__, tmp_crw.slct, tmp_crw.oflw, +			       tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc, +			       tmp_crw.erc, tmp_crw.rsid); +			printk(KERN_WARNING"%s: This was crw number %x in the " +			       "chain\n", __func__, chain); +			if (ccode != 0) +				break; +			chain = tmp_crw.chn ? chain + 1 : 0; +			continue; +		} +		ccode = stcrw(&crw[chain]); +		if (ccode != 0) +			break; +		printk(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, " +		       "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", +		       crw[chain].slct, crw[chain].oflw, crw[chain].chn, +		       crw[chain].rsc, crw[chain].anc, crw[chain].erc, +		       crw[chain].rsid); +		/* Check for overflows. */ +		if (crw[chain].oflw) { +			int i; + +			pr_debug("%s: crw overflow detected!\n", __func__); +			mutex_lock(&crw_handler_mutex); +			for (i = 0; i < NR_RSCS; i++) { +				if (crw_handlers[i]) +					crw_handlers[i](NULL, NULL, 1); +			} +			mutex_unlock(&crw_handler_mutex); +			chain = 0; +			continue; +		} +		if (crw[0].chn && !chain) { +			chain++; +			continue; +		} +		mutex_lock(&crw_handler_mutex); +		handler = crw_handlers[crw[chain].rsc]; +		if (handler) +			handler(&crw[0], chain ? &crw[1] : NULL, 0); +		mutex_unlock(&crw_handler_mutex); +		/* chain is always 0 or 1 here. */ +		chain = crw[chain].chn ? chain + 1 : 0; +	} +	goto repeat; +	return 0; +} + +void crw_handle_channel_report(void) +{ +	up(&crw_semaphore); +} + +/* + * Separate initcall needed for semaphore initialization since + * crw_handle_channel_report might be called before crw_machine_check_init. + */ +static int __init crw_init_semaphore(void) +{ +	init_MUTEX_LOCKED(&crw_semaphore); +	return 0; +} +pure_initcall(crw_init_semaphore); + +/* + * Machine checks for the channel subsystem must be enabled + * after the channel subsystem is initialized + */ +static int __init crw_machine_check_init(void) +{ +	struct task_struct *task; + +	task = kthread_run(crw_collect_info, NULL, "kmcheck"); +	if (IS_ERR(task)) +		return PTR_ERR(task); +	ctl_set_bit(14, 28);	/* enable channel report MCH */ +	return 0; +} +device_initcall(crw_machine_check_init); diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 427d11d88069..0085d8901792 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -18,8 +18,8 @@  #include <linux/list.h>  #include <linux/reboot.h>  #include <asm/isc.h> +#include <asm/crw.h> -#include "../s390mach.h"  #include "css.h"  #include "cio.h"  #include "cio_debug.h" @@ -83,6 +83,25 @@ static int call_fn_unknown_sch(struct subchannel_id schid, void *data)  	return rc;  } +static int call_fn_all_sch(struct subchannel_id schid, void *data) +{ +	struct cb_data *cb = data; +	struct subchannel *sch; +	int rc = 0; + +	sch = get_subchannel_by_schid(schid); +	if (sch) { +		if (cb->fn_known_sch) +			rc = cb->fn_known_sch(sch, cb->data); +		put_device(&sch->dev); +	} else { +		if (cb->fn_unknown_sch) +			rc = cb->fn_unknown_sch(schid, cb->data); +	} + +	return rc; +} +  int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),  			       int (*fn_unknown)(struct subchannel_id,  			       void *), void *data) @@ -90,13 +109,17 @@ int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),  	struct cb_data cb;  	int rc; -	cb.set = idset_sch_new(); -	if (!cb.set) -		return -ENOMEM; -	idset_fill(cb.set);  	cb.data = data;  	cb.fn_known_sch = fn_known;  	cb.fn_unknown_sch = fn_unknown; + +	cb.set = idset_sch_new(); +	if (!cb.set) +		/* fall back to brute force scanning in case of oom */ +		return for_each_subchannel(call_fn_all_sch, &cb); + +	idset_fill(cb.set); +  	/* Process registered subchannels. */  	rc = bus_for_each_dev(&css_bus_type, NULL, &cb, call_fn_known_sch);  	if (rc) @@ -510,6 +533,17 @@ static int reprobe_subchannel(struct subchannel_id schid, void *data)  	return ret;  } +static void reprobe_after_idle(struct work_struct *unused) +{ +	/* Make sure initial subchannel scan is done. */ +	wait_event(ccw_device_init_wq, +		   atomic_read(&ccw_device_init_count) == 0); +	if (need_reprobe) +		css_schedule_reprobe(); +} + +static DECLARE_WORK(reprobe_idle_work, reprobe_after_idle); +  /* Work function used to reprobe all unregistered subchannels. */  static void reprobe_all(struct work_struct *unused)  { @@ -517,10 +551,12 @@ static void reprobe_all(struct work_struct *unused)  	CIO_MSG_EVENT(4, "reprobe start\n"); -	need_reprobe = 0;  	/* Make sure initial subchannel scan is done. */ -	wait_event(ccw_device_init_wq, -		   atomic_read(&ccw_device_init_count) == 0); +	if (atomic_read(&ccw_device_init_count) != 0) { +		queue_work(ccw_device_work, &reprobe_idle_work); +		return; +	} +	need_reprobe = 0;  	ret = for_each_subchannel_staged(NULL, reprobe_subchannel, NULL);  	CIO_MSG_EVENT(4, "reprobe done (rc=%d, need_reprobe=%d)\n", ret, @@ -619,7 +655,7 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high)  		css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid;  	} else {  #ifdef CONFIG_SMP -		css->global_pgid.pgid_high.cpu_addr = hard_smp_processor_id(); +		css->global_pgid.pgid_high.cpu_addr = stap();  #else  		css->global_pgid.pgid_high.cpu_addr = 0;  #endif @@ -765,7 +801,7 @@ init_channel_subsystem (void)  	if (ret)  		goto out; -	ret = s390_register_crw_handler(CRW_RSC_SCH, css_process_crw); +	ret = crw_register_handler(CRW_RSC_SCH, css_process_crw);  	if (ret)  		goto out; @@ -845,7 +881,7 @@ out_unregister:  out_bus:  	bus_unregister(&css_bus_type);  out: -	s390_unregister_crw_handler(CRW_RSC_CSS); +	crw_unregister_handler(CRW_RSC_CSS);  	chsc_free_sei_area();  	kfree(slow_subchannel_set);  	pr_alert("The CSS device driver initialization failed with " diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index e28f8ae53453..c4d2f667a2f6 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -457,12 +457,13 @@ int ccw_device_set_online(struct ccw_device *cdev)  	return (ret == 0) ? -ENODEV : ret;  } -static void online_store_handle_offline(struct ccw_device *cdev) +static int online_store_handle_offline(struct ccw_device *cdev)  {  	if (cdev->private->state == DEV_STATE_DISCONNECTED)  		ccw_device_remove_disconnected(cdev); -	else if (cdev->drv && cdev->drv->set_offline) -		ccw_device_set_offline(cdev); +	else if (cdev->online && cdev->drv && cdev->drv->set_offline) +		return ccw_device_set_offline(cdev); +	return 0;  }  static int online_store_recog_and_online(struct ccw_device *cdev) @@ -530,13 +531,10 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,  		goto out;  	switch (i) {  	case 0: -		online_store_handle_offline(cdev); -		ret = count; +		ret = online_store_handle_offline(cdev);  		break;  	case 1:  		ret = online_store_handle_online(cdev, force); -		if (!ret) -			ret = count;  		break;  	default:  		ret = -EINVAL; @@ -545,7 +543,7 @@ out:  	if (cdev->drv)  		module_put(cdev->drv->owner);  	atomic_set(&cdev->private->onoff, 0); -	return ret; +	return (ret < 0) ? ret : count;  }  static ssize_t @@ -681,35 +679,22 @@ get_orphaned_ccwdev_by_dev_id(struct channel_subsystem *css,  	return dev ? to_ccwdev(dev) : NULL;  } -static void -ccw_device_add_changed(struct work_struct *work) -{ -	struct ccw_device_private *priv; -	struct ccw_device *cdev; - -	priv = container_of(work, struct ccw_device_private, kick_work); -	cdev = priv->cdev; -	if (device_add(&cdev->dev)) { -		put_device(&cdev->dev); -		return; -	} -	set_bit(1, &cdev->private->registered); -} - -void ccw_device_do_unreg_rereg(struct work_struct *work) +void ccw_device_do_unbind_bind(struct work_struct *work)  {  	struct ccw_device_private *priv;  	struct ccw_device *cdev;  	struct subchannel *sch; +	int ret;  	priv = container_of(work, struct ccw_device_private, kick_work);  	cdev = priv->cdev;  	sch = to_subchannel(cdev->dev.parent); -	ccw_device_unregister(cdev); -	PREPARE_WORK(&cdev->private->kick_work, -		     ccw_device_add_changed); -	queue_work(ccw_device_work, &cdev->private->kick_work); +	if (test_bit(1, &cdev->private->registered)) { +		device_release_driver(&cdev->dev); +		ret = device_attach(&cdev->dev); +		WARN_ON(ret == -ENODEV); +	}  }  static void @@ -1035,8 +1020,6 @@ static void ccw_device_call_sch_unregister(struct work_struct *work)  void  io_subchannel_recog_done(struct ccw_device *cdev)  { -	struct subchannel *sch; -  	if (css_init_done == 0) {  		cdev->private->flags.recog_done = 1;  		return; @@ -1047,7 +1030,6 @@ io_subchannel_recog_done(struct ccw_device *cdev)  		/* Remove device found not operational. */  		if (!get_device(&cdev->dev))  			break; -		sch = to_subchannel(cdev->dev.parent);  		PREPARE_WORK(&cdev->private->kick_work,  			     ccw_device_call_sch_unregister);  		queue_work(slow_path_wq, &cdev->private->kick_work); diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 0f2e63ea48de..85e01846ca65 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -80,7 +80,7 @@ void io_subchannel_init_config(struct subchannel *sch);  int ccw_device_cancel_halt_clear(struct ccw_device *); -void ccw_device_do_unreg_rereg(struct work_struct *); +void ccw_device_do_unbind_bind(struct work_struct *);  void ccw_device_move_to_orphanage(struct work_struct *);  int ccw_device_is_orphan(struct ccw_device *); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 8df5eaafc5ab..87b4bfca080f 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -194,7 +194,7 @@ ccw_device_handle_oper(struct ccw_device *cdev)  	    cdev->id.dev_type != cdev->private->senseid.dev_type ||  	    cdev->id.dev_model != cdev->private->senseid.dev_model) {  		PREPARE_WORK(&cdev->private->kick_work, -			     ccw_device_do_unreg_rereg); +			     ccw_device_do_unbind_bind);  		queue_work(ccw_device_work, &cdev->private->kick_work);  		return 0;  	} @@ -366,7 +366,7 @@ static void ccw_device_oper_notify(struct ccw_device *cdev)  	}  	/* Driver doesn't want device back. */  	ccw_device_set_notoper(cdev); -	PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unreg_rereg); +	PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unbind_bind);  	queue_work(ccw_device_work, &cdev->private->kick_work);  } @@ -728,7 +728,7 @@ static void ccw_device_generic_notoper(struct ccw_device *cdev,  {  	struct subchannel *sch; -	cdev->private->state = DEV_STATE_NOT_OPER; +	ccw_device_set_notoper(cdev);  	sch = to_subchannel(cdev->dev.parent);  	css_schedule_eval(sch->schid);  } @@ -1052,7 +1052,7 @@ ccw_device_offline_irq(struct ccw_device *cdev, enum dev_event dev_event)  	sch = to_subchannel(cdev->dev.parent);  	/*  	 * An interrupt in state offline means a previous disable was not -	 * successful. Try again. +	 * successful - should not happen, but we try to disable again.  	 */  	cio_disable_subchannel(sch);  } diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index eabcc42d63df..151754d54745 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -680,7 +680,7 @@ int ccw_device_tm_intrg(struct ccw_device *cdev)  	if (cdev->private->state != DEV_STATE_ONLINE)  		return -EIO;  	if (!scsw_is_tm(&sch->schib.scsw) || -	    !(scsw_actl(&sch->schib.scsw) | SCSW_ACTL_START_PEND)) +	    !(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_START_PEND))  		return -EINVAL;  	return cio_tm_intrg(sch);  } diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 42f2b09631b6..13bcb8114388 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -186,6 +186,9 @@ struct qdio_input_q {  	/* input buffer acknowledgement flag */  	int polling; +	/* first ACK'ed buffer */ +	int ack_start; +  	/* how much sbals are acknowledged with qebsm */  	int ack_count; @@ -234,7 +237,7 @@ struct qdio_q {  	int first_to_check;  	/* first_to_check of the last time */ -	int last_move_ftc; +	int last_move;  	/* beginning position for calling the program */  	int first_to_kick; @@ -244,7 +247,6 @@ struct qdio_q {  	struct qdio_irq *irq_ptr;  	struct tasklet_struct tasklet; -	spinlock_t lock;  	/* error condition during a data transfer */  	unsigned int qdio_error; @@ -354,7 +356,7 @@ int get_buf_state(struct qdio_q *q, unsigned int bufnr, unsigned char *state,  		  int auto_ack);  void qdio_check_outbound_after_thinint(struct qdio_q *q);  int qdio_inbound_q_moved(struct qdio_q *q); -void qdio_kick_inbound_handler(struct qdio_q *q); +void qdio_kick_handler(struct qdio_q *q);  void qdio_stop_polling(struct qdio_q *q);  int qdio_siga_sync_q(struct qdio_q *q); diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index da7afb04e71f..e3434b34f86c 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -63,8 +63,9 @@ static int qstat_show(struct seq_file *m, void *v)  	seq_printf(m, "device state indicator: %d\n", *(u32 *)q->irq_ptr->dsci);  	seq_printf(m, "nr_used: %d\n", atomic_read(&q->nr_buf_used));  	seq_printf(m, "ftc: %d\n", q->first_to_check); -	seq_printf(m, "last_move_ftc: %d\n", q->last_move_ftc); +	seq_printf(m, "last_move: %d\n", q->last_move);  	seq_printf(m, "polling: %d\n", q->u.in.polling); +	seq_printf(m, "ack start: %d\n", q->u.in.ack_start);  	seq_printf(m, "ack count: %d\n", q->u.in.ack_count);  	seq_printf(m, "slsb buffer states:\n");  	seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n"); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 10cb0f8726e5..9e8a2914259b 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -380,11 +380,11 @@ inline void qdio_stop_polling(struct qdio_q *q)  	/* show the card that we are not polling anymore */  	if (is_qebsm(q)) { -		set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT, +		set_buf_states(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT,  			       q->u.in.ack_count);  		q->u.in.ack_count = 0;  	} else -		set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT); +		set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT);  }  static void announce_buffer_error(struct qdio_q *q, int count) @@ -419,15 +419,15 @@ static inline void inbound_primed(struct qdio_q *q, int count)  		if (!q->u.in.polling) {  			q->u.in.polling = 1;  			q->u.in.ack_count = count; -			q->last_move_ftc = q->first_to_check; +			q->u.in.ack_start = q->first_to_check;  			return;  		}  		/* delete the previous ACK's */ -		set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT, +		set_buf_states(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT,  			       q->u.in.ack_count);  		q->u.in.ack_count = count; -		q->last_move_ftc = q->first_to_check; +		q->u.in.ack_start = q->first_to_check;  		return;  	} @@ -439,14 +439,13 @@ static inline void inbound_primed(struct qdio_q *q, int count)  	if (q->u.in.polling) {  		/* reset the previous ACK but first set the new one */  		set_buf_state(q, new, SLSB_P_INPUT_ACK); -		set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT); -	} -	else { +		set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT); +	} else {  		q->u.in.polling = 1; -		set_buf_state(q, q->first_to_check, SLSB_P_INPUT_ACK); +		set_buf_state(q, new, SLSB_P_INPUT_ACK);  	} -	q->last_move_ftc = new; +	q->u.in.ack_start = new;  	count--;  	if (!count)  		return; @@ -455,7 +454,7 @@ static inline void inbound_primed(struct qdio_q *q, int count)  	 * Need to change all PRIMED buffers to NOT_INIT, otherwise  	 * we're loosing initiative in the thinint code.  	 */ -	set_buf_states(q, next_buf(q->first_to_check), SLSB_P_INPUT_NOT_INIT, +	set_buf_states(q, q->first_to_check, SLSB_P_INPUT_NOT_INIT,  		       count);  } @@ -523,7 +522,8 @@ int qdio_inbound_q_moved(struct qdio_q *q)  	bufnr = get_inbound_buffer_frontier(q); -	if ((bufnr != q->last_move_ftc) || q->qdio_error) { +	if ((bufnr != q->last_move) || q->qdio_error) { +		q->last_move = bufnr;  		if (!need_siga_sync(q) && !pci_out_supported(q))  			q->u.in.timestamp = get_usecs(); @@ -570,29 +570,30 @@ static int qdio_inbound_q_done(struct qdio_q *q)  	}  } -void qdio_kick_inbound_handler(struct qdio_q *q) +void qdio_kick_handler(struct qdio_q *q)  { -	int count, start, end; - -	qdio_perf_stat_inc(&perf_stats.inbound_handler); - -	start = q->first_to_kick; -	end = q->first_to_check; -	if (end >= start) -		count = end - start; -	else -		count = end + QDIO_MAX_BUFFERS_PER_Q - start; - -	DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%3d c:%3d", start, count); +	int start = q->first_to_kick; +	int end = q->first_to_check; +	int count;  	if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE))  		return; -	q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, -		   start, count, q->irq_ptr->int_parm); +	count = sub_buf(end, start); + +	if (q->is_input_q) { +		qdio_perf_stat_inc(&perf_stats.inbound_handler); +		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%3d c:%3d", start, count); +	} else { +		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: nr:%1d", q->nr); +		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "s:%3d c:%3d", start, count); +	} + +	q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count, +		   q->irq_ptr->int_parm);  	/* for the next time */ -	q->first_to_kick = q->first_to_check; +	q->first_to_kick = end;  	q->qdio_error = 0;  } @@ -603,7 +604,7 @@ again:  	if (!qdio_inbound_q_moved(q))  		return; -	qdio_kick_inbound_handler(q); +	qdio_kick_handler(q);  	if (!qdio_inbound_q_done(q))  		/* means poll time is not yet over */ @@ -698,21 +699,21 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q)  	bufnr = get_outbound_buffer_frontier(q); -	if ((bufnr != q->last_move_ftc) || q->qdio_error) { -		q->last_move_ftc = bufnr; +	if ((bufnr != q->last_move) || q->qdio_error) { +		q->last_move = bufnr;  		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr);  		return 1;  	} else  		return 0;  } -static void qdio_kick_outbound_q(struct qdio_q *q) +static int qdio_kick_outbound_q(struct qdio_q *q)  {  	unsigned int busy_bit;  	int cc;  	if (!need_siga_out(q)) -		return; +		return 0;  	DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);  	qdio_perf_stat_inc(&perf_stats.siga_out); @@ -724,75 +725,37 @@ static void qdio_kick_outbound_q(struct qdio_q *q)  	case 2:  		if (busy_bit) {  			DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr); -			q->qdio_error = cc | QDIO_ERROR_SIGA_BUSY; -		} else { -			DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", -				      q->nr); -			q->qdio_error = cc; -		} +			cc |= QDIO_ERROR_SIGA_BUSY; +		} else +			DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr);  		break;  	case 1:  	case 3:  		DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc); -		q->qdio_error = cc;  		break;  	} -} - -static void qdio_kick_outbound_handler(struct qdio_q *q) -{ -	int start, end, count; - -	start = q->first_to_kick; -	end = q->last_move_ftc; -	if (end >= start) -		count = end - start; -	else -		count = end + QDIO_MAX_BUFFERS_PER_Q - start; - -	DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kickouth: %1d", q->nr); -	DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "s:%3d c:%3d", start, count); - -	if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) -		return; - -	q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count, -		   q->irq_ptr->int_parm); - -	/* for the next time: */ -	q->first_to_kick = q->last_move_ftc; -	q->qdio_error = 0; +	return cc;  }  static void __qdio_outbound_processing(struct qdio_q *q)  { -	unsigned long flags; -  	qdio_perf_stat_inc(&perf_stats.tasklet_outbound); -	spin_lock_irqsave(&q->lock, flags); -  	BUG_ON(atomic_read(&q->nr_buf_used) < 0);  	if (qdio_outbound_q_moved(q)) -		qdio_kick_outbound_handler(q); - -	spin_unlock_irqrestore(&q->lock, flags); +		qdio_kick_handler(q); -	if (queue_type(q) == QDIO_ZFCP_QFMT) { +	if (queue_type(q) == QDIO_ZFCP_QFMT)  		if (!pci_out_supported(q) && !qdio_outbound_q_done(q)) -			tasklet_schedule(&q->tasklet); -		return; -	} +			goto sched;  	/* bail out for HiperSockets unicast queues */  	if (queue_type(q) == QDIO_IQDIO_QFMT && !multicast_outbound(q))  		return;  	if ((queue_type(q) == QDIO_IQDIO_QFMT) && -	    (atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL) { -		tasklet_schedule(&q->tasklet); -		return; -	} +	    (atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL) +		goto sched;  	if (q->u.out.pci_out_enabled)  		return; @@ -810,6 +773,12 @@ static void __qdio_outbound_processing(struct qdio_q *q)  			qdio_perf_stat_inc(&perf_stats.debug_tl_out_timer);  		}  	} +	return; + +sched: +	if (unlikely(q->irq_ptr->state == QDIO_IRQ_STATE_STOPPED)) +		return; +	tasklet_schedule(&q->tasklet);  }  /* outbound tasklet */ @@ -822,6 +791,9 @@ void qdio_outbound_processing(unsigned long data)  void qdio_outbound_timer(unsigned long data)  {  	struct qdio_q *q = (struct qdio_q *)data; + +	if (unlikely(q->irq_ptr->state == QDIO_IRQ_STATE_STOPPED)) +		return;  	tasklet_schedule(&q->tasklet);  } @@ -863,6 +835,9 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr)  	int i;  	struct qdio_q *q; +	if (unlikely(irq_ptr->state == QDIO_IRQ_STATE_STOPPED)) +		return; +  	qdio_perf_stat_inc(&perf_stats.pci_int);  	for_each_input_queue(irq_ptr, q, i) @@ -1065,8 +1040,9 @@ EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc);   * @cdev: associated ccw device   * @how: use halt or clear to shutdown   * - * This function calls qdio_shutdown() for @cdev with method @how - * and on success qdio_free() for @cdev. + * This function calls qdio_shutdown() for @cdev with method @how. + * and qdio_free(). The qdio_free() return value is ignored since + * !irq_ptr is already checked.   */  int qdio_cleanup(struct ccw_device *cdev, int how)  { @@ -1077,8 +1053,8 @@ int qdio_cleanup(struct ccw_device *cdev, int how)  		return -ENODEV;  	rc = qdio_shutdown(cdev, how); -	if (rc == 0) -		rc = qdio_free(cdev); + +	qdio_free(cdev);  	return rc;  }  EXPORT_SYMBOL_GPL(qdio_cleanup); @@ -1090,11 +1066,11 @@ static void qdio_shutdown_queues(struct ccw_device *cdev)  	int i;  	for_each_input_queue(irq_ptr, q, i) -		tasklet_disable(&q->tasklet); +		tasklet_kill(&q->tasklet);  	for_each_output_queue(irq_ptr, q, i) { -		tasklet_disable(&q->tasklet);  		del_timer(&q->u.out.timer); +		tasklet_kill(&q->tasklet);  	}  } @@ -1112,6 +1088,7 @@ int qdio_shutdown(struct ccw_device *cdev, int how)  	if (!irq_ptr)  		return -ENODEV; +	BUG_ON(irqs_disabled());  	DBF_EVENT("qshutdown:%4x", cdev->private->schid.sch_no);  	mutex_lock(&irq_ptr->setup_mutex); @@ -1124,6 +1101,12 @@ int qdio_shutdown(struct ccw_device *cdev, int how)  		return 0;  	} +	/* +	 * Indicate that the device is going down. Scheduling the queue +	 * tasklets is forbidden from here on. +	 */ +	qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); +  	tiqdio_remove_input_queues(irq_ptr);  	qdio_shutdown_queues(cdev);  	qdio_shutdown_debug_entries(irq_ptr, cdev); @@ -1403,9 +1386,8 @@ int qdio_activate(struct ccw_device *cdev)  	switch (irq_ptr->state) {  	case QDIO_IRQ_STATE_STOPPED:  	case QDIO_IRQ_STATE_ERR: -		mutex_unlock(&irq_ptr->setup_mutex); -		qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR); -		return -EIO; +		rc = -EIO; +		break;  	default:  		qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ACTIVE);  		rc = 0; @@ -1442,10 +1424,10 @@ static inline int buf_in_between(int bufnr, int start, int count)   * @bufnr: first buffer to process   * @count: how many buffers are emptied   */ -static void handle_inbound(struct qdio_q *q, unsigned int callflags, -			   int bufnr, int count) +static int handle_inbound(struct qdio_q *q, unsigned int callflags, +			  int bufnr, int count)  { -	int used, cc, diff; +	int used, diff;  	if (!q->u.in.polling)  		goto set; @@ -1456,19 +1438,18 @@ static void handle_inbound(struct qdio_q *q, unsigned int callflags,  		q->u.in.polling = 0;  		q->u.in.ack_count = 0;  		goto set; -	} else if (buf_in_between(q->last_move_ftc, bufnr, count)) { +	} else if (buf_in_between(q->u.in.ack_start, bufnr, count)) {  		if (is_qebsm(q)) { -			/* partial overwrite, just update last_move_ftc */ +			/* partial overwrite, just update ack_start */  			diff = add_buf(bufnr, count); -			diff = sub_buf(diff, q->last_move_ftc); +			diff = sub_buf(diff, q->u.in.ack_start);  			q->u.in.ack_count -= diff;  			if (q->u.in.ack_count <= 0) {  				q->u.in.polling = 0;  				q->u.in.ack_count = 0; -				/* TODO: must we set last_move_ftc to something meaningful? */  				goto set;  			} -			q->last_move_ftc = add_buf(q->last_move_ftc, diff); +			q->u.in.ack_start = add_buf(q->u.in.ack_start, diff);  		}  		else  			/* the only ACK will be deleted, so stop polling */ @@ -1483,13 +1464,11 @@ set:  	/* no need to signal as long as the adapter had free buffers */  	if (used) -		return; +		return 0; -	if (need_siga_in(q)) { -		cc = qdio_siga_input(q); -		if (cc) -			q->qdio_error = cc; -	} +	if (need_siga_in(q)) +		return qdio_siga_input(q); +	return 0;  }  /** @@ -1499,11 +1478,11 @@ set:   * @bufnr: first buffer to process   * @count: how many buffers are filled   */ -static void handle_outbound(struct qdio_q *q, unsigned int callflags, -			    int bufnr, int count) +static int handle_outbound(struct qdio_q *q, unsigned int callflags, +			   int bufnr, int count)  {  	unsigned char state; -	int used; +	int used, rc = 0;  	qdio_perf_stat_inc(&perf_stats.outbound_handler); @@ -1518,27 +1497,26 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags,  	if (queue_type(q) == QDIO_IQDIO_QFMT) {  		if (multicast_outbound(q)) -			qdio_kick_outbound_q(q); +			rc = qdio_kick_outbound_q(q);  		else  			if ((q->irq_ptr->ssqd_desc.mmwc > 1) &&  			    (count > 1) &&  			    (count <= q->irq_ptr->ssqd_desc.mmwc)) {  				/* exploit enhanced SIGA */  				q->u.out.use_enh_siga = 1; -				qdio_kick_outbound_q(q); +				rc = qdio_kick_outbound_q(q);  			} else {  				/*  				* One siga-w per buffer required for unicast  				* HiperSockets.  				*/  				q->u.out.use_enh_siga = 0; -				while (count--) -					qdio_kick_outbound_q(q); +				while (count--) { +					rc = qdio_kick_outbound_q(q); +					if (rc) +						goto out; +				}  			} - -		/* report CC=2 conditions synchronously */ -		if (q->qdio_error) -			__qdio_outbound_processing(q);  		goto out;  	} @@ -1550,14 +1528,14 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags,  	/* try to fast requeue buffers */  	get_buf_state(q, prev_buf(bufnr), &state, 0);  	if (state != SLSB_CU_OUTPUT_PRIMED) -		qdio_kick_outbound_q(q); +		rc = qdio_kick_outbound_q(q);  	else {  		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "fast-req");  		qdio_perf_stat_inc(&perf_stats.fast_requeue);  	}  out: -	/* Fixme: could wait forever if called from process context */  	tasklet_schedule(&q->tasklet); +	return rc;  }  /** @@ -1596,14 +1574,12 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags,  		return -EBUSY;  	if (callflags & QDIO_FLAG_SYNC_INPUT) -		handle_inbound(irq_ptr->input_qs[q_nr], callflags, bufnr, -			       count); +		return handle_inbound(irq_ptr->input_qs[q_nr], +				      callflags, bufnr, count);  	else if (callflags & QDIO_FLAG_SYNC_OUTPUT) -		handle_outbound(irq_ptr->output_qs[q_nr], callflags, bufnr, -				count); -	else -		return -EINVAL; -	return 0; +		return handle_outbound(irq_ptr->output_qs[q_nr], +				       callflags, bufnr, count); +	return -EINVAL;  }  EXPORT_SYMBOL_GPL(do_QDIO); diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index c08356b95bf5..18d54fc21ce9 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -117,7 +117,6 @@ static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr,  	q->mask = 1 << (31 - i);  	q->nr = i;  	q->handler = handler; -	spin_lock_init(&q->lock);  }  static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr, diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 8e90e147b746..c655d011a78d 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -31,6 +31,7 @@  /* list of thin interrupt input queues */  static LIST_HEAD(tiq_list); +DEFINE_MUTEX(tiq_list_lock);  /* adapter local summary indicator */  static unsigned char *tiqdio_alsi; @@ -95,12 +96,11 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr)  	if (!css_qdio_omit_svs && irq_ptr->siga_flag.sync)  		css_qdio_omit_svs = 1; -	for_each_input_queue(irq_ptr, q, i) { +	mutex_lock(&tiq_list_lock); +	for_each_input_queue(irq_ptr, q, i)  		list_add_rcu(&q->entry, &tiq_list); -		synchronize_rcu(); -	} +	mutex_unlock(&tiq_list_lock);  	xchg(irq_ptr->dsci, 1); -	tasklet_schedule(&tiqdio_tasklet);  }  /* @@ -118,7 +118,10 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)  		/* if establish triggered an error */  		if (!q || !q->entry.prev || !q->entry.next)  			continue; + +		mutex_lock(&tiq_list_lock);  		list_del_rcu(&q->entry); +		mutex_unlock(&tiq_list_lock);  		synchronize_rcu();  	}  } @@ -155,15 +158,15 @@ static void __tiqdio_inbound_processing(struct qdio_q *q)  	 */  	qdio_check_outbound_after_thinint(q); -again:  	if (!qdio_inbound_q_moved(q))  		return; -	qdio_kick_inbound_handler(q); +	qdio_kick_handler(q);  	if (!tiqdio_inbound_q_done(q)) {  		qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop); -		goto again; +		if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) +			tasklet_schedule(&q->tasklet);  	}  	qdio_stop_polling(q); @@ -173,7 +176,8 @@ again:  	 */  	if (!tiqdio_inbound_q_done(q)) {  		qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop2); -		goto again; +		if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) +			tasklet_schedule(&q->tasklet);  	}  } @@ -366,10 +370,11 @@ void qdio_shutdown_thinint(struct qdio_irq *irq_ptr)  void __exit tiqdio_unregister_thinints(void)  { -	tasklet_disable(&tiqdio_tasklet); +	WARN_ON(!list_empty(&tiq_list));  	if (tiqdio_alsi) {  		s390_unregister_adapter_interrupt(tiqdio_alsi, QDIO_AIRQ_ISC);  		isc_unregister(QDIO_AIRQ_ISC);  	} +	tasklet_kill(&tiqdio_tasklet);  } diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index cb22b97944b8..65b6a96afe6b 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -128,8 +128,7 @@ static void __zcrypt_increase_preference(struct zcrypt_device *zdev)  	if (l == zdev->list.prev)  		return;  	/* Move zdev behind l */ -	list_del(&zdev->list); -	list_add(&zdev->list, l); +	list_move(&zdev->list, l);  }  /** @@ -157,8 +156,7 @@ static void __zcrypt_decrease_preference(struct zcrypt_device *zdev)  	if (l == zdev->list.next)  		return;  	/* Move zdev before l */ -	list_del(&zdev->list); -	list_add_tail(&zdev->list, l); +	list_move_tail(&zdev->list, l);  }  static void zcrypt_device_release(struct kref *kref) diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index e7a1e22e77ac..c20d4790258e 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -781,8 +781,7 @@ static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev,  		/* Signal pending. */  		ap_cancel_message(zdev->ap_dev, &ap_msg);  out_free: -	memset(ap_msg.message, 0x0, ap_msg.length); -	kfree(ap_msg.message); +	kzfree(ap_msg.message);  	return rc;  } diff --git a/drivers/s390/ebcdic.c b/drivers/s390/ebcdic.c deleted file mode 100644 index 99c98da15473..000000000000 --- a/drivers/s390/ebcdic.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - *  arch/s390/kernel/ebcdic.c - *    ECBDIC -> ASCII, ASCII -> ECBDIC conversion tables. - * - *  S390 version - *    Copyright (C) 1998 IBM Corporation - *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> - */ - -#include <asm/types.h> - -/* - * ASCII -> EBCDIC - */ -__u8 _ascebc[256] = -{ - /*00  NL    SH    SX    EX    ET    NQ    AK    BL */ -     0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, - /*08  BS    HT    LF    VT    FF    CR    SO    SI */ -     0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - /*10  DL    D1    D2    D3    D4    NK    SN    EB */ -     0x10, 0x11, 0x12, 0x13, 0x3C, 0x15, 0x32, 0x26, - /*18  CN    EM    SB    EC    FS    GS    RS    US */ -     0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F, - /*20  SP     !     "     #     $     %     &     ' */ -     0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, - /*28   (     )     *     +     ,     -    .      / */ -     0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, - /*30   0     1     2     3     4     5     6     7 */ -     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, - /*38   8     9     :     ;     <     =     >     ? */ -     0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, - /*40   @     A     B     C     D     E     F     G */ -     0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - /*48   H     I     J     K     L     M     N     O */ -     0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, - /*50   P     Q     R     S     T     U     V     W */ -     0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, - /*58   X     Y     Z     [     \     ]     ^     _ */ -     0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D, - /*60   `     a     b     c     d     e     f     g */ -     0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - /*68   h     i     j     k     l     m     n     o */ -     0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, - /*70   p     q     r     s     t     u     v     w */ -     0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - /*78   x     y     z     {     |     }     ~    DL */ -     0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, -     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, -     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, -     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, -     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, -     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, -     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, -     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, -     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, -     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, -     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, -     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, -     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, -     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, -     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, -     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, -     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF -}; - -/* - * EBCDIC -> ASCII - */ -__u8 _ebcasc[256] = -{ - /* 0x00   NUL   SOH   STX   ETX  *SEL    HT  *RNL   DEL */ -          0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, - /* 0x08   -GE  -SPS  -RPT    VT    FF    CR    SO    SI */ -          0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - /* 0x10   DLE   DC1   DC2   DC3  -RES   -NL    BS  -POC -                                  -ENP  ->LF             */ -          0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, - /* 0x18   CAN    EM  -UBS  -CU1  -IFS  -IGS  -IRS  -ITB -                                                    -IUS */ -          0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - /* 0x20   -DS  -SOS    FS  -WUS  -BYP    LF   ETB   ESC -                                  -INP                   */ -          0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, - /* 0x28   -SA  -SFE   -SM  -CSP  -MFA   ENQ   ACK   BEL -                       -SW                               */  -          0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, - /* 0x30  ----  ----   SYN   -IR   -PP  -TRN  -NBS   EOT */ -          0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, - /* 0x38  -SBS   -IT  -RFF  -CU3   DC4   NAK  ----   SUB */ -          0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, - /* 0x40    SP   RSP                         ----       */ -          0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, - /* 0x48                       .     <     (     +     | */ -          0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, - /* 0x50     &                                      ---- */ -          0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, - /* 0x58                !     $     *     )     ;       */ -          0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA, - /* 0x60     -     /  ----       ----  ----  ----       */ -          0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F, - /* 0x68              ----     ,     %     _     >     ? */  -          0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, - /* 0x70  ----        ----  ----  ----  ----  ----  ---- */ -          0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - /* 0x78     *     `     :     #     @     '     =     " */ -          0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, - /* 0x80     *     a     b     c     d     e     f     g */ -          0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - /* 0x88     h     i              ----  ----  ----       */ -          0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, - /* 0x90          j     k     l     m     n     o     p */ -          0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, - /* 0x98     q     r                    ----        ---- */ -          0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, - /* 0xA0           ~     s     t     u     v     w     x */ -          0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - /* 0xA8     y     z              ----  ----  ----  ---- */ -          0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, - /* 0xB0     ^                    ----       ----       */ -          0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, - /* 0xB8        ----     [     ]  ----  ----  ----  ---- */ -          0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07, - /* 0xC0     {     A     B     C     D     E     F     G */ -          0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - /* 0xC8     H     I  ----                         ---- */ -          0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, - /* 0xD0     }     J     K     L     M     N     O     P */ -          0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, - /* 0xD8     Q     R  ----                              */ -          0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, - /* 0xE0     \           S     T     U     V     W     X */ -          0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - /* 0xE8     Y     Z        ----       ----  ----  ---- */ -          0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07, - /* 0xF0     0     1     2     3     4     5     6     7 */ -          0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - /* 0xF8     8     9  ----  ----       ----  ----  ---- */ -          0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07 -}; - -/* - * EBCDIC (capitals) -> ASCII (small case) - */ -__u8 _ebcasc_reduce_case[256] = -{ - /* 0x00   NUL   SOH   STX   ETX  *SEL    HT  *RNL   DEL */ -          0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, - - /* 0x08   -GE  -SPS  -RPT    VT    FF    CR    SO    SI */ -          0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - - /* 0x10   DLE   DC1   DC2   DC3  -RES   -NL    BS  -POC -                                  -ENP  ->LF             */ -          0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, - - /* 0x18   CAN    EM  -UBS  -CU1  -IFS  -IGS  -IRS  -ITB -                                                    -IUS */ -          0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - - /* 0x20   -DS  -SOS    FS  -WUS  -BYP    LF   ETB   ESC -                                  -INP                   */ -          0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, - - /* 0x28   -SA  -SFE   -SM  -CSP  -MFA   ENQ   ACK   BEL -                       -SW                               */  -          0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, - - /* 0x30  ----  ----   SYN   -IR   -PP  -TRN  -NBS   EOT */ -          0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, - - /* 0x38  -SBS   -IT  -RFF  -CU3   DC4   NAK  ----   SUB */ -          0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, - - /* 0x40    SP   RSP                         ----       */ -          0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, - - /* 0x48                       .     <     (     +     | */ -          0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, - - /* 0x50     &                                      ---- */ -          0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, - - /* 0x58                !     $     *     )     ;       */ -          0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA, - - /* 0x60     -     /  ----       ----  ----  ----       */ -          0x2D, 0x2F, 0x07, 0x84, 0x07, 0x07, 0x07, 0x8F, - - /* 0x68              ----     ,     %     _     >     ? */  -          0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, - - /* 0x70  ----        ----  ----  ----  ----  ----  ---- */ -          0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - - /* 0x78     *     `     :     #     @     '     =     " */ -          0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, - - /* 0x80     *     a     b     c     d     e     f     g */ -          0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - - /* 0x88     h     i              ----  ----  ----       */ -          0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, - - /* 0x90          j     k     l     m     n     o     p */ -          0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, - - /* 0x98     q     r                    ----        ---- */ -          0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, - - /* 0xA0           ~     s     t     u     v     w     x */ -          0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - - /* 0xA8     y     z              ----  ----  ----  ---- */ -          0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, - - /* 0xB0     ^                    ----       ----       */ -          0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, - - /* 0xB8        ----     [     ]  ----  ----  ----  ---- */ -          0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07, - - /* 0xC0     {     A     B     C     D     E     F     G */ -          0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - - /* 0xC8     H     I  ----                         ---- */ -          0x68, 0x69, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, - - /* 0xD0     }     J     K     L     M     N     O     P */ -          0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, - - /* 0xD8     Q     R  ----                              */ -          0x71, 0x72, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, - - /* 0xE0     \           S     T     U     V     W     X */ -          0x5C, 0xF6, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - - /* 0xE8     Y     Z        ----       ----  ----  ---- */ -          0x79, 0x7A, 0xFD, 0x07, 0x94, 0x07, 0x07, 0x07, - - /* 0xF0     0     1     2     3     4     5     6     7 */ -          0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - - /* 0xF8     8     9  ----  ----       ----  ----  ---- */ -          0x38, 0x39, 0x07, 0x07, 0x81, 0x07, 0x07, 0x07 -}; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 6fec3cfcf978..c827d69b5a91 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2680,40 +2680,21 @@ static int qeth_handle_send_error(struct qeth_card *card,  		struct qeth_qdio_out_buffer *buffer, unsigned int qdio_err)  {  	int sbalf15 = buffer->buffer->element[15].flags & 0xff; -	int cc = qdio_err & 3;  	QETH_DBF_TEXT(TRACE, 6, "hdsnderr");  	qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr"); -	switch (cc) { -	case 0: -		if (qdio_err) { -			QETH_DBF_TEXT(TRACE, 1, "lnkfail"); -			QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); -			QETH_DBF_TEXT_(TRACE, 1, "%04x %02x", -				       (u16)qdio_err, (u8)sbalf15); -			return QETH_SEND_ERROR_LINK_FAILURE; -		} + +	if (!qdio_err)  		return QETH_SEND_ERROR_NONE; -	case 2: -		if (qdio_err & QDIO_ERROR_SIGA_BUSY) { -			QETH_DBF_TEXT(TRACE, 1, "SIGAcc2B"); -			QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); -			return QETH_SEND_ERROR_KICK_IT; -		} -		if ((sbalf15 >= 15) && (sbalf15 <= 31)) -			return QETH_SEND_ERROR_RETRY; -		return QETH_SEND_ERROR_LINK_FAILURE; -		/* look at qdio_error and sbalf 15 */ -	case 1: -		QETH_DBF_TEXT(TRACE, 1, "SIGAcc1"); -		QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); -		return QETH_SEND_ERROR_LINK_FAILURE; -	case 3: -	default: -		QETH_DBF_TEXT(TRACE, 1, "SIGAcc3"); -		QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); -		return QETH_SEND_ERROR_KICK_IT; -	} + +	if ((sbalf15 >= 15) && (sbalf15 <= 31)) +		return QETH_SEND_ERROR_RETRY; + +	QETH_DBF_TEXT(TRACE, 1, "lnkfail"); +	QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); +	QETH_DBF_TEXT_(TRACE, 1, "%04x %02x", +		       (u16)qdio_err, (u8)sbalf15); +	return QETH_SEND_ERROR_LINK_FAILURE;  }  /* @@ -2849,10 +2830,14 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,  			qeth_get_micros() -  			queue->card->perf_stats.outbound_do_qdio_start_time;  	if (rc) { +		queue->card->stats.tx_errors += count; +		/* ignore temporary SIGA errors without busy condition */ +		if (rc == QDIO_ERROR_SIGA_TARGET) +			return;  		QETH_DBF_TEXT(TRACE, 2, "flushbuf");  		QETH_DBF_TEXT_(TRACE, 2, " err%d", rc);  		QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_DDEV_ID(queue->card)); -		queue->card->stats.tx_errors += count; +  		/* this must not happen under normal circumstances. if it  		 * happens something is really wrong -> recover */  		qeth_schedule_recovery(queue->card); @@ -2927,13 +2912,7 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev,  	}  	for (i = first_element; i < (first_element + count); ++i) {  		buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]; -		/*we only handle the KICK_IT error by doing a recovery */ -		if (qeth_handle_send_error(card, buffer, qdio_error) -				== QETH_SEND_ERROR_KICK_IT){ -			netif_stop_queue(card->dev); -			qeth_schedule_recovery(card); -			return; -		} +		qeth_handle_send_error(card, buffer, qdio_error);  		qeth_clear_output_buffer(queue, buffer);  	}  	atomic_sub(count, &queue->used_buffers); diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h deleted file mode 100644 index d39f8b697d27..000000000000 --- a/drivers/s390/s390mach.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - *  drivers/s390/s390mach.h - *   S/390 data definitions for machine check processing - * - *  S390 version - *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation - *    Author(s): Ingo Adlung (adlung@de.ibm.com) - */ - -#ifndef __s390mach_h -#define __s390mach_h - -#include <asm/types.h> - -struct mci { -	__u32   sd              :  1; /* 00 system damage */ -	__u32   pd              :  1; /* 01 instruction-processing damage */ -	__u32   sr              :  1; /* 02 system recovery */ -	__u32   to_be_defined_1 :  1; /* 03 */ -	__u32   cd              :  1; /* 04 timing-facility damage */ -	__u32   ed              :  1; /* 05 external damage */ -	__u32   to_be_defined_2 :  1; /* 06 */ -	__u32   dg              :  1; /* 07 degradation */ -	__u32   w               :  1; /* 08 warning pending */ -	__u32   cp              :  1; /* 09 channel-report pending */ -	__u32   sp              :  1; /* 10 service-processor damage */ -	__u32   ck              :  1; /* 11 channel-subsystem damage */ -	__u32   to_be_defined_3 :  2; /* 12-13 */ -	__u32   b               :  1; /* 14 backed up */ -	__u32   to_be_defined_4 :  1; /* 15 */ -	__u32   se              :  1; /* 16 storage error uncorrected */ -	__u32   sc              :  1; /* 17 storage error corrected */ -	__u32   ke              :  1; /* 18 storage-key error uncorrected */ -	__u32   ds              :  1; /* 19 storage degradation */ -	__u32   wp              :  1; /* 20 psw mwp validity */ -	__u32   ms              :  1; /* 21 psw mask and key validity */ -	__u32   pm              :  1; /* 22 psw program mask and cc validity */ -	__u32   ia              :  1; /* 23 psw instruction address validity */ -	__u32   fa              :  1; /* 24 failing storage address validity */ -	__u32   to_be_defined_5 :  1; /* 25 */ -	__u32   ec              :  1; /* 26 external damage code validity */ -	__u32   fp              :  1; /* 27 floating point register validity */ -	__u32   gr              :  1; /* 28 general register validity */ -	__u32   cr              :  1; /* 29 control register validity */ -	__u32   to_be_defined_6 :  1; /* 30 */ -	__u32   st              :  1; /* 31 storage logical validity */ -	__u32   ie              :  1; /* 32 indirect storage error */ -	__u32   ar              :  1; /* 33 access register validity */ -	__u32   da              :  1; /* 34 delayed access exception */ -	__u32   to_be_defined_7 :  7; /* 35-41 */ -	__u32   pr              :  1; /* 42 tod programmable register validity */ -	__u32   fc              :  1; /* 43 fp control register validity */ -	__u32   ap              :  1; /* 44 ancillary report */ -	__u32   to_be_defined_8 :  1; /* 45 */ -	__u32   ct              :  1; /* 46 cpu timer validity */ -	__u32   cc              :  1; /* 47 clock comparator validity */ -	__u32	to_be_defined_9 : 16; /* 47-63 */ -}; - -/* - * Channel Report Word - */ -struct crw { -	__u32 res1    :  1;   /* reserved zero */ -	__u32 slct    :  1;   /* solicited */ -	__u32 oflw    :  1;   /* overflow */ -	__u32 chn     :  1;   /* chained */ -	__u32 rsc     :  4;   /* reporting source code */ -	__u32 anc     :  1;   /* ancillary report */ -	__u32 res2    :  1;   /* reserved zero */ -	__u32 erc     :  6;   /* error-recovery code */ -	__u32 rsid    : 16;   /* reporting-source ID */ -} __attribute__ ((packed)); - -typedef void (*crw_handler_t)(struct crw *, struct crw *, int); - -extern int s390_register_crw_handler(int rsc, crw_handler_t handler); -extern void s390_unregister_crw_handler(int rsc); - -#define NR_RSCS 16 - -#define CRW_RSC_MONITOR  0x2  /* monitoring facility */ -#define CRW_RSC_SCH      0x3  /* subchannel */ -#define CRW_RSC_CPATH    0x4  /* channel path */ -#define CRW_RSC_CONFIG   0x9  /* configuration-alert facility */ -#define CRW_RSC_CSS      0xB  /* channel subsystem */ - -#define CRW_ERC_EVENT    0x00 /* event information pending */ -#define CRW_ERC_AVAIL    0x01 /* available */ -#define CRW_ERC_INIT     0x02 /* initialized */ -#define CRW_ERC_TERROR   0x03 /* temporary error */ -#define CRW_ERC_IPARM    0x04 /* installed parm initialized */ -#define CRW_ERC_TERM     0x05 /* terminal */ -#define CRW_ERC_PERRN    0x06 /* perm. error, fac. not init */ -#define CRW_ERC_PERRI    0x07 /* perm. error, facility init */ -#define CRW_ERC_PMOD     0x08 /* installed parameters modified */ - -static inline int stcrw(struct crw *pcrw ) -{ -	int ccode; - -	__asm__ __volatile__( -		"stcrw 0(%2)\n\t" -		"ipm %0\n\t" -		"srl %0,28\n\t" -		: "=d" (ccode), "=m" (*pcrw) -		: "a" (pcrw) -		: "cc" ); -	return ccode; -} - -#define ED_ETR_SYNC	12	/* External damage ETR sync check */ -#define ED_ETR_SWITCH	13	/* External damage ETR switch to local */ - -#define ED_STP_SYNC	7	/* External damage STP sync check */ -#define ED_STP_ISLAND	6	/* External damage STP island check */ - -struct pt_regs; - -void s390_handle_mcck(void); -void s390_do_machine_check(struct pt_regs *regs); -#endif /* __s390mach */ diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c index 1e064c4a4f86..46297683cd34 100644 --- a/fs/partitions/ibm.c +++ b/fs/partitions/ibm.c @@ -21,20 +21,38 @@   * compute the block number from a   * cyl-cyl-head-head structure   */ -static inline int +static sector_t  cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) { -        return ptr->cc * geo->heads * geo->sectors + -	       ptr->hh * geo->sectors; + +	sector_t cyl; +	__u16 head; + +	/*decode cylinder and heads for large volumes */ +	cyl = ptr->hh & 0xFFF0; +	cyl <<= 12; +	cyl |= ptr->cc; +	head = ptr->hh & 0x000F; +	return cyl * geo->heads * geo->sectors + +	       head * geo->sectors;  }  /*   * compute the block number from a   * cyl-cyl-head-head-block structure   */ -static inline int +static sector_t  cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) { -        return ptr->cc * geo->heads * geo->sectors + -		ptr->hh * geo->sectors + + +	sector_t cyl; +	__u16 head; + +	/*decode cylinder and heads for large volumes */ +	cyl = ptr->hh & 0xFFF0; +	cyl <<= 12; +	cyl |= ptr->cc; +	head = ptr->hh & 0x000F; +	return	cyl * geo->heads * geo->sectors + +		head * geo->sectors +  		ptr->b;  } @@ -43,14 +61,15 @@ cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) {  int  ibm_partition(struct parsed_partitions *state, struct block_device *bdev)  { -	int blocksize, offset, size,res; -	loff_t i_size; +	int blocksize, res; +	loff_t i_size, offset, size, fmt_size;  	dasd_information2_t *info;  	struct hd_geometry *geo;  	char type[5] = {0,};  	char name[7] = {0,};  	union label_t { -		struct vtoc_volume_label vol; +		struct vtoc_volume_label_cdl vol; +		struct vtoc_volume_label_ldl lnx;  		struct vtoc_cms_label cms;  	} *label;  	unsigned char *data; @@ -85,14 +104,16 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)  	if (data == NULL)  		goto out_readerr; -	strncpy (type, data, 4); -	if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) -		strncpy(name, data + 8, 6); -	else -		strncpy(name, data + 4, 6);  	memcpy(label, data, sizeof(union label_t));  	put_dev_sector(sect); +	if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) { +		strncpy(type, label->vol.vollbl, 4); +		strncpy(name, label->vol.volid, 6); +	} else { +		strncpy(type, label->lnx.vollbl, 4); +		strncpy(name, label->lnx.volid, 6); +	}  	EBCASC(type, 4);  	EBCASC(name, 6); @@ -110,36 +131,54 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)  			/*  			 * VM style CMS1 labeled disk  			 */ +			blocksize = label->cms.block_size;  			if (label->cms.disk_offset != 0) {  				printk("CMS1/%8s(MDSK):", name);  				/* disk is reserved minidisk */ -				blocksize = label->cms.block_size;  				offset = label->cms.disk_offset;  				size = (label->cms.block_count - 1)  					* (blocksize >> 9);  			} else {  				printk("CMS1/%8s:", name);  				offset = (info->label_block + 1); -				size = i_size >> 9; +				size = label->cms.block_count +					* (blocksize >> 9);  			} +			put_partition(state, 1, offset*(blocksize >> 9), +				      size-offset*(blocksize >> 9));  		} else { -			/* -			 * Old style LNX1 or unlabeled disk -			 */ -			if (strncmp(type, "LNX1", 4) == 0) -				printk ("LNX1/%8s:", name); -			else +			if (strncmp(type, "LNX1", 4) == 0) { +				printk("LNX1/%8s:", name); +				if (label->lnx.ldl_version == 0xf2) { +					fmt_size = label->lnx.formatted_blocks +						* (blocksize >> 9); +				} else if (!strcmp(info->type, "ECKD")) { +					/* formated w/o large volume support */ +					fmt_size = geo->cylinders * geo->heads +					      * geo->sectors * (blocksize >> 9); +				} else { +					/* old label and no usable disk geometry +					 * (e.g. DIAG) */ +					fmt_size = i_size >> 9; +				} +				size = i_size >> 9; +				if (fmt_size < size) +					size = fmt_size; +				offset = (info->label_block + 1); +			} else { +				/* unlabeled disk */  				printk("(nonl)"); -			offset = (info->label_block + 1); -			size = i_size >> 9; -		} -		put_partition(state, 1, offset*(blocksize >> 9), +				size = i_size >> 9; +				offset = (info->label_block + 1); +			} +			put_partition(state, 1, offset*(blocksize >> 9),  				      size-offset*(blocksize >> 9)); +		}  	} else if (info->format == DASD_FORMAT_CDL) {  		/*  		 * New style CDL formatted disk  		 */ -		unsigned int blk; +		sector_t blk;  		int counter;  		/* @@ -166,7 +205,8 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)  				/* skip FMT4 / FMT5 / FMT7 labels */  				if (f1.DS1FMTID == _ascebc['4']  				    || f1.DS1FMTID == _ascebc['5'] -				    || f1.DS1FMTID == _ascebc['7']) { +				    || f1.DS1FMTID == _ascebc['7'] +				    || f1.DS1FMTID == _ascebc['9']) {  					blk++;  					data = read_dev_sector(bdev, blk *  							       (blocksize/512), @@ -174,8 +214,9 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)  					continue;  				} -				/* only FMT1 valid at this point */ -				if (f1.DS1FMTID != _ascebc['1']) +				/* only FMT1 and 8 labels valid at this point */ +				if (f1.DS1FMTID != _ascebc['1'] && +				    f1.DS1FMTID != _ascebc['8'])  					break;  				/* OK, we got valid partition data */ | 
