Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6: (81 commits) [S390] remove duplicated #includes [S390] cpumask: use mm_cpumask() wrapper [S390] cpumask: Use accessors code. [S390] cpumask: prepare for iterators to only go to nr_cpu_ids/nr_cpumask_bits. [S390] cpumask: remove cpu_coregroup_map [S390] fix clock comparator save area usage [S390] Add hwcap flag for the etf3 enhancement facility [S390] Ensure that ipl panic notifier is called late. [S390] fix dfp elf hwcap/facility bit detection [S390] smp: perform initial cpu reset before starting a cpu [S390] smp: fix memory leak on __cpu_up [S390] ipl: Improve checking logic and remove switch defaults. [S390] s390dbf: Remove needless check for NULL pointer. [S390] s390dbf: Remove redundant initilizations. [S390] use kzfree() [S390] BUG to BUG_ON changes [S390] zfcpdump: Prevent zcore from beeing built as a kernel module. [S390] Use csum_partial in checksum.h [S390] cleanup lowcore.h [S390] eliminate ipl_device from lowcore ...
This commit is contained in:
commit
21cdbc1378
99 changed files with 4048 additions and 2906 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -201,8 +201,7 @@ static int __init prng_init(void)
|
|||
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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
68
arch/s390/include/asm/crw.h
Normal file
68
arch/s390/include/asm/crw.h
Normal file
|
@ -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 */
|
|
@ -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;
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 0x0014
|
||||
#define __LC_EXT_PARAMS 0x0080
|
||||
#define __LC_CPU_ADDRESS 0x0084
|
||||
#define __LC_EXT_INT_CODE 0x0086
|
||||
|
||||
#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 0x0088
|
||||
#define __LC_SVC_INT_CODE 0x008a
|
||||
#define __LC_PGM_ILC 0x008c
|
||||
#define __LC_PGM_INT_CODE 0x008e
|
||||
|
||||
#define __LC_SVC_ILC 0x088
|
||||
#define __LC_SVC_INT_CODE 0x08A
|
||||
#define __LC_PGM_ILC 0x08C
|
||||
#define __LC_PGM_INT_CODE 0x08E
|
||||
#define __LC_PER_ATMID 0x0096
|
||||
#define __LC_PER_ADDRESS 0x0098
|
||||
#define __LC_PER_ACCESS_ID 0x00a1
|
||||
#define __LC_AR_MODE_ID 0x00a3
|
||||
|
||||
#define __LC_PER_ATMID 0x096
|
||||
#define __LC_PER_ADDRESS 0x098
|
||||
#define __LC_PER_ACCESS_ID 0x0A1
|
||||
#define __LC_AR_MODE_ID 0x0A3
|
||||
#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_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_LAST_BREAK 0x110
|
||||
|
||||
#define __LC_RETURN_PSW 0x200
|
||||
|
||||
#define __LC_SAVE_AREA 0xC00
|
||||
#define __LC_DUMP_REIPL 0x0e00
|
||||
|
||||
#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
|
||||
#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_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_PASTE 0xE40
|
||||
|
||||
#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
|
||||
#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 */
|
||||
/* 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 */
|
||||
|
||||
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 */
|
||||
/* 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 */
|
||||
|
||||
/* 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 */
|
||||
/* Return psws. */
|
||||
__u32 save_area[16]; /* 0x0200 */
|
||||
psw_t return_psw; /* 0x0240 */
|
||||
psw_t return_mcck_psw; /* 0x0248 */
|
||||
|
||||
/* 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 */
|
||||
/* 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 */
|
||||
|
||||
/* 0xe00 is used as indicator for dump tools */
|
||||
/* whether the kernel died with panic() or not */
|
||||
__u32 panic_magic; /* 0xe00 */
|
||||
/* Current process. */
|
||||
__u32 current_task; /* 0x0290 */
|
||||
__u32 thread_info; /* 0x0294 */
|
||||
__u32 kernel_stack; /* 0x0298 */
|
||||
|
||||
/* Align to the top 1k of prefix area */
|
||||
__u8 pad12[0x1000-0xe04]; /* 0xe04 */
|
||||
/* 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 */
|
||||
/* 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 */
|
||||
|
||||
/* 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 */
|
||||
/* Entry/exit save area & return psws. */
|
||||
__u64 save_area[16]; /* 0x0200 */
|
||||
psw_t return_psw; /* 0x0280 */
|
||||
psw_t return_mcck_psw; /* 0x0290 */
|
||||
|
||||
/* 0xe00 is used as indicator for dump tools */
|
||||
/* whether the kernel died with panic() or not */
|
||||
__u32 panic_magic; /* 0xe00 */
|
||||
/* 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 */
|
||||
__u32 paste[16]; /* 0x03c0 */
|
||||
|
||||
__u8 pad13[0x11b8-0xe80]; /* 0xe80 */
|
||||
__u8 pad_0x0400[0x0e00-0x0400]; /* 0x0400 */
|
||||
|
||||
/* 64 bit extparam used for pfault, diag 250 etc */
|
||||
__u64 ext_params2; /* 0x11B8 */
|
||||
/*
|
||||
* 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 */
|
||||
|
||||
__u8 pad14[0x1200-0x11C0]; /* 0x11C0 */
|
||||
/* 64 bit extparam used for pfault/diag 250: defined by architecture */
|
||||
__u64 ext_params2; /* 0x11B8 */
|
||||
__u8 pad_0x11c0[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 */
|
||||
/* 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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
66
arch/s390/include/asm/nmi.h
Normal file
66
arch/s390/include/asm/nmi.h
Normal file
|
@ -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 */
|
|
@ -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 *);
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
54
arch/s390/kernel/bitmap.c
Normal file
54
arch/s390/kernel/bitmap.c
Normal file
|
@ -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);
|
|
@ -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 {
|
||||
|
|
|
@ -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 @@ debug_open(struct inode *inode, struct file *file)
|
|||
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:
|
||||
|
|
|
@ -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;
|
||||
/* No VM information? Looks like LPAR */
|
||||
if (stsi(&vmms, 3, 2, 2) == -ENOSYS)
|
||||
return;
|
||||
if (!vmms.count)
|
||||
return;
|
||||
|
||||
get_cpu_id(&S390_lowcore.cpu_data.cpu_id);
|
||||
|
||||
/* Running under z/VM ? */
|
||||
if (cpuinfo->cpu_id.version == 0xff)
|
||||
machine_flags |= MACHINE_FLAG_VM;
|
||||
|
||||
/* 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) {
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
#
|
||||
|
|
|
@ -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
|
||||
#
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
|
@ -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;
|
||||
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;
|
||||
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 @@ SYSCALL_DEFINE0(execve)
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 @@ static int __cpuinit smp_alloc_lowcore(int cpu)
|
|||
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;
|
||||
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);
|
||||
|
||||
ccode = signal_processor_p((__u32)(unsigned long)(lowcore_ptr[cpu]),
|
||||
cpu, sigp_set_prefix);
|
||||
if (ccode)
|
||||
return -EIO;
|
||||
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;
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -144,7 +144,6 @@ int vdso_alloc_per_cpu(int cpu, struct _lowcore *lowcore)
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -108,6 +108,8 @@ SECTIONS
|
|||
EXIT_TEXT
|
||||
}
|
||||
|
||||
/* early.c uses stsi, which requires page aligned data. */
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
.init.data : {
|
||||
INIT_DATA
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 @@ void __udelay(unsigned long usecs)
|
|||
local_irq_restore(flags);
|
||||
preempt_enable();
|
||||
}
|
||||
EXPORT_SYMBOL(__udelay);
|
||||
|
||||
/*
|
||||
* Simple udelay variant. To be used on startup and reboot
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int write)
|
|||
goto bad_area;
|
||||
}
|
||||
|
||||
survive:
|
||||
if (is_vm_hugetlb_page(vma))
|
||||
address &= HPAGE_MASK;
|
||||
/*
|
||||
|
@ -378,8 +354,8 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int write)
|
|||
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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
@ -617,6 +624,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)
|
||||
|
@ -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
|
||||
|
@ -876,6 +919,171 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
@ -884,24 +1092,53 @@ static int __init hvc_iucv_init(void)
|
|||
int rc;
|
||||
unsigned int i;
|
||||
|
||||
if (!MACHINE_IS_VM) {
|
||||
pr_info("The z/VM IUCV HVC device driver cannot "
|
||||
"be used without z/VM\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!hvc_iucv_devices)
|
||||
return -ENODEV;
|
||||
|
||||
if (hvc_iucv_devices > MAX_HVC_IUCV_LINES)
|
||||
return -EINVAL;
|
||||
if (!MACHINE_IS_VM) {
|
||||
pr_notice("The z/VM IUCV HVC device driver cannot "
|
||||
"be used without z/VM\n");
|
||||
rc = -ENODEV;
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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 @@ static int __init hvc_iucv_init(void)
|
|||
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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
@ -436,6 +440,25 @@ dasd_fba_fill_info(struct dasd_device * device,
|
|||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -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 *);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
@ -829,30 +812,6 @@ __tape_end_request(
|
|||
__tape_start_next_request(device);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -315,16 +315,32 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
|
|||
}
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
159
drivers/s390/cio/crw.c
Normal file
159
drivers/s390/cio/crw.c
Normal file
|
@ -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);
|
|
@ -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 @@ init_channel_subsystem (void)
|
|||
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 "
|
||||
|
|
|
@ -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 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
|
|||
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);
|
||||
|
|
|
@ -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 *);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 @@ static void __qdio_inbound_processing(struct qdio_q *q)
|
|||
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);
|
||||
qdio_kick_handler(q);
|
||||
|
||||
spin_unlock_irqrestore(&q->lock, flags);
|
||||
|
||||
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 @@ static void handle_inbound(struct qdio_q *q, unsigned int callflags,
|
|||
|
||||
/* 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 @@ static void handle_inbound(struct qdio_q *q, unsigned int callflags,
|
|||
* @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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 @@ static void __tiqdio_inbound_processing(struct qdio_q *q)
|
|||
*/
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 - / ---- <20> ---- ---- ---- */
|
||||
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 <20> 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 ---- <20> ---- ---- ---- */
|
||||
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 - / ---- <20> ---- ---- ---- */
|
||||
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 <20> 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 ---- <20> ---- ---- ---- */
|
||||
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
|
||||
};
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Old style LNX1 or unlabeled disk
|
||||
*/
|
||||
if (strncmp(type, "LNX1", 4) == 0)
|
||||
printk ("LNX1/%8s:", name);
|
||||
else
|
||||
printk("(nonl)");
|
||||
offset = (info->label_block + 1);
|
||||
size = i_size >> 9;
|
||||
}
|
||||
put_partition(state, 1, offset*(blocksize >> 9),
|
||||
put_partition(state, 1, offset*(blocksize >> 9),
|
||||
size-offset*(blocksize >> 9));
|
||||
} 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)");
|
||||
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 */
|
||||
|
|
Loading…
Reference in a new issue