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:
Linus Torvalds 2009-03-26 16:04:22 -07:00
commit 21cdbc1378
99 changed files with 4048 additions and 2906 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -201,8 +201,7 @@ out_free:
static void __exit prng_exit(void)
{
/* wipe me */
memset(p->buf, 0, prng_chunk_size);
kfree(p->buf);
kzfree(p->buf);
kfree(p);
misc_deregister(&prng_dev);

View file

@ -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;
}

View 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 */

View file

@ -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;
/*

View file

@ -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;
}

View file

@ -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

View file

@ -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);
}

View 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 */

View file

@ -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 *);
/*

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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__ */

View file

@ -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)

View file

@ -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

View file

@ -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];

View file

@ -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

View file

@ -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)

View file

@ -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
View 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);

View file

@ -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 {

View file

@ -603,7 +603,7 @@ debug_input(struct file *file, const char __user *user_buf, size_t length,
static int
debug_open(struct inode *inode, struct file *file)
{
int i = 0, rc = 0;
int i, rc = 0;
file_private_info_t *p_info;
debug_info_t *debug_info, *debug_info_snapshot;
@ -642,8 +642,7 @@ found:
p_info = kmalloc(sizeof(file_private_info_t),
GFP_KERNEL);
if(!p_info){
if(debug_info_snapshot)
debug_info_free(debug_info_snapshot);
debug_info_free(debug_info_snapshot);
rc = -ENOMEM;
goto out;
}
@ -698,8 +697,7 @@ debug_info_t *debug_register_mode(const char *name, int pages_per_area,
if ((uid != 0) || (gid != 0))
pr_warning("Root becomes the owner of all s390dbf files "
"in sysfs\n");
if (!initialized)
BUG();
BUG_ON(!initialized);
mutex_lock(&debug_mutex);
/* create new debug_info */
@ -1156,7 +1154,6 @@ debug_unregister_view(debug_info_t * id, struct debug_view *view)
else {
debugfs_remove(id->debugfs_entries[i]);
id->views[i] = NULL;
rc = 0;
}
spin_unlock_irqrestore(&id->lock, flags);
out:

View file

@ -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) {

View file

@ -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}

View file

@ -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
#

View file

@ -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
#

View file

@ -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;
}

View file

@ -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)

View file

@ -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);

View file

@ -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, &regs, 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 @@ out:
int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs)
{
#ifndef CONFIG_64BIT
/*
/*
* save fprs to current->thread.fp_regs to merge them with
* the emulated registers and then copy the result to the dump.
*/
@ -322,6 +319,7 @@ int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs)
#endif /* CONFIG_64BIT */
return 1;
}
EXPORT_SYMBOL(dump_fpu);
unsigned long get_wchan(struct task_struct *p)
{
@ -346,4 +344,3 @@ unsigned long get_wchan(struct task_struct *p)
}
return 0;
}

View file

@ -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)

View file

@ -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)

View file

@ -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);

View file

@ -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();
/*

View file

@ -32,6 +32,7 @@
#include <linux/delay.h>
#include <linux/cache.h>
#include <linux/interrupt.h>
#include <linux/irqflags.h>
#include <linux/cpu.h>
#include <linux/timex.h>
#include <linux/bootmem.h>
@ -50,12 +51,6 @@
#include <asm/vdso.h>
#include "entry.h"
/*
* An array with a pointer the lowcore of every CPU.
*/
struct _lowcore *lowcore_ptr[NR_CPUS];
EXPORT_SYMBOL(lowcore_ptr);
static struct task_struct *current_set[NR_CPUS];
static u8 smp_cpu_type;
@ -81,9 +76,7 @@ void smp_send_stop(void)
/* Disable all interrupts/machine checks */
__load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
/* write magic number to zero page (absolute 0) */
lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC;
trace_hardirqs_off();
/* stop all processors */
for_each_online_cpu(cpu) {
@ -233,7 +226,7 @@ EXPORT_SYMBOL(smp_ctl_clear_bit);
*/
#define CPU_INIT_NO 1
#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
#ifdef CONFIG_ZFCPDUMP
/*
* zfcpdump_prefix_array holds prefix registers for the following scenario:
@ -274,7 +267,7 @@ EXPORT_SYMBOL_GPL(zfcpdump_save_areas);
static inline void smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) { }
#endif /* CONFIG_ZFCPDUMP || CONFIG_ZFCPDUMP_MODULE */
#endif /* CONFIG_ZFCPDUMP */
static int cpu_stopped(int cpu)
{
@ -304,8 +297,8 @@ static int smp_rescan_cpus_sigp(cpumask_t avail)
{
int cpu_id, logical_cpu;
logical_cpu = first_cpu(avail);
if (logical_cpu == NR_CPUS)
logical_cpu = cpumask_first(&avail);
if (logical_cpu >= nr_cpu_ids)
return 0;
for (cpu_id = 0; cpu_id <= 65535; cpu_id++) {
if (cpu_known(cpu_id))
@ -316,8 +309,8 @@ static int smp_rescan_cpus_sigp(cpumask_t avail)
continue;
cpu_set(logical_cpu, cpu_present_map);
smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED;
logical_cpu = next_cpu(logical_cpu, avail);
if (logical_cpu == NR_CPUS)
logical_cpu = cpumask_next(logical_cpu, &avail);
if (logical_cpu >= nr_cpu_ids)
break;
}
return 0;
@ -329,8 +322,8 @@ static int smp_rescan_cpus_sclp(cpumask_t avail)
int cpu_id, logical_cpu, cpu;
int rc;
logical_cpu = first_cpu(avail);
if (logical_cpu == NR_CPUS)
logical_cpu = cpumask_first(&avail);
if (logical_cpu >= nr_cpu_ids)
return 0;
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info)
@ -351,8 +344,8 @@ static int smp_rescan_cpus_sclp(cpumask_t avail)
smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY;
else
smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED;
logical_cpu = next_cpu(logical_cpu, avail);
if (logical_cpu == NR_CPUS)
logical_cpu = cpumask_next(logical_cpu, &avail);
if (logical_cpu >= nr_cpu_ids)
break;
}
out:
@ -379,7 +372,7 @@ static void __init smp_detect_cpus(void)
c_cpus = 1;
s_cpus = 0;
boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
boot_cpu_addr = __cpu_logical_map[0];
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info)
panic("smp_detect_cpus failed to allocate memory\n");
@ -453,7 +446,7 @@ int __cpuinit start_secondary(void *cpuvoid)
/* Switch on interrupts */
local_irq_enable();
/* Print info about this processor */
print_cpu_info(&S390_lowcore.cpu_data);
print_cpu_info();
/* cpu_idle will call schedule for us */
cpu_idle();
return 0;
@ -515,7 +508,6 @@ out:
return -ENOMEM;
}
#ifdef CONFIG_HOTPLUG_CPU
static void smp_free_lowcore(int cpu)
{
struct _lowcore *lowcore;
@ -534,7 +526,6 @@ static void smp_free_lowcore(int cpu)
free_pages((unsigned long) lowcore, lc_order);
lowcore_ptr[cpu] = NULL;
}
#endif /* CONFIG_HOTPLUG_CPU */
/* Upping and downing of CPUs */
int __cpuinit __cpu_up(unsigned int cpu)
@ -543,16 +534,23 @@ int __cpuinit __cpu_up(unsigned int cpu)
struct _lowcore *cpu_lowcore;
struct stack_frame *sf;
sigp_ccode ccode;
u32 lowcore;
if (smp_cpu_state[cpu] != CPU_STATE_CONFIGURED)
return -EIO;
if (smp_alloc_lowcore(cpu))
return -ENOMEM;
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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -144,7 +144,6 @@ out:
return -ENOMEM;
}
#ifdef CONFIG_HOTPLUG_CPU
void vdso_free_per_cpu(int cpu, struct _lowcore *lowcore)
{
unsigned long segment_table, page_table, page_frame;
@ -163,7 +162,6 @@ void vdso_free_per_cpu(int cpu, struct _lowcore *lowcore)
free_page(page_table);
free_pages(segment_table, SEGMENT_ORDER);
}
#endif /* CONFIG_HOTPLUG_CPU */
static void __vdso_init_cr5(void *dummy)
{

View file

@ -108,6 +108,8 @@ SECTIONS
EXIT_TEXT
}
/* early.c uses stsi, which requires page aligned data. */
. = ALIGN(PAGE_SIZE);
.init.data : {
INIT_DATA
}

View file

@ -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);

View file

@ -9,6 +9,7 @@
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/timex.h>
#include <linux/module.h>
#include <linux/irqflags.h>
#include <linux/interrupt.h>
@ -92,6 +93,7 @@ out:
local_irq_restore(flags);
preempt_enable();
}
EXPORT_SYMBOL(__udelay);
/*
* Simple udelay variant. To be used on startup and reboot

View file

@ -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);

View file

@ -200,29 +200,6 @@ static void do_low_address(struct pt_regs *regs, unsigned long error_code)
do_no_context(regs, error_code, 0);
}
/*
* We ran out of memory, or some other thing happened to us that made
* us unable to handle the page fault gracefully.
*/
static int do_out_of_memory(struct pt_regs *regs, unsigned long error_code,
unsigned long address)
{
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm;
up_read(&mm->mmap_sem);
if (is_global_init(tsk)) {
yield();
down_read(&mm->mmap_sem);
return 1;
}
printk("VM: killing process %s\n", tsk->comm);
if (regs->psw.mask & PSW_MASK_PSTATE)
do_group_exit(SIGKILL);
do_no_context(regs, error_code, address);
return 0;
}
static void do_sigbus(struct pt_regs *regs, unsigned long error_code,
unsigned long address)
{
@ -367,7 +344,6 @@ good_area:
goto bad_area;
}
survive:
if (is_vm_hugetlb_page(vma))
address &= HPAGE_MASK;
/*
@ -378,8 +354,8 @@ survive:
fault = handle_mm_fault(mm, vma, address, write);
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM) {
if (do_out_of_memory(regs, error_code, address))
goto survive;
up_read(&mm->mmap_sem);
pagefault_out_of_memory();
return;
} else if (fault & VM_FAULT_SIGBUS) {
do_sigbus(regs, error_code, address);

View file

@ -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

View file

@ -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);

View file

@ -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 @@ out_error_hvc:
out_error_memory:
mempool_destroy(hvc_iucv_mempool);
kmem_cache_destroy(hvc_iucv_buffer_cache);
out_error:
hvc_iucv_devices = 0; /* ensure that we do not provide any device */
return rc;
}
@ -968,3 +1208,4 @@ static int __init hvc_iucv_config(char *val)
device_initcall(hvc_iucv_init);
__setup("hvc_iucv=", hvc_iucv_config);
core_param(hvc_iucv_allow, hvc_iucv_filter, vmidfilter, 0640);

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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);
}

View file

@ -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

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -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,
};

View file

@ -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;

View file

@ -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 *);

View file

@ -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;
}

View file

@ -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 */
}

View file

@ -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 *);

View file

@ -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;
}

View file

@ -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 {

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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");

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -315,16 +315,32 @@ error:
}
EXPORT_SYMBOL(ccwgroup_create_from_string);
static int __init
init_ccwgroup (void)
static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action,
void *data);
static struct notifier_block ccwgroup_nb = {
.notifier_call = ccwgroup_notifier
};
static int __init init_ccwgroup(void)
{
return bus_register (&ccwgroup_bus_type);
int ret;
ret = bus_register(&ccwgroup_bus_type);
if (ret)
return ret;
ret = bus_register_notifier(&ccwgroup_bus_type, &ccwgroup_nb);
if (ret)
bus_unregister(&ccwgroup_bus_type);
return ret;
}
static void __exit
cleanup_ccwgroup (void)
static void __exit cleanup_ccwgroup(void)
{
bus_unregister (&ccwgroup_bus_type);
bus_unregister_notifier(&ccwgroup_bus_type, &ccwgroup_nb);
bus_unregister(&ccwgroup_bus_type);
}
module_init(init_ccwgroup);
@ -392,27 +408,28 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const
unsigned long value;
int ret;
gdev = to_ccwgroupdev(dev);
if (!dev->driver)
return count;
return -ENODEV;
gdev = to_ccwgroupdev(dev);
gdrv = to_ccwgroupdrv(dev->driver);
gdrv = to_ccwgroupdrv (gdev->dev.driver);
if (!try_module_get(gdrv->owner))
return -EINVAL;
ret = strict_strtoul(buf, 0, &value);
if (ret)
goto out;
ret = count;
if (value == 1)
ccwgroup_set_online(gdev);
ret = ccwgroup_set_online(gdev);
else if (value == 0)
ccwgroup_set_offline(gdev);
ret = ccwgroup_set_offline(gdev);
else
ret = -EINVAL;
out:
module_put(gdrv->owner);
return ret;
return (ret == 0) ? count : ret;
}
static ssize_t
@ -454,13 +471,18 @@ ccwgroup_remove (struct device *dev)
struct ccwgroup_device *gdev;
struct ccwgroup_driver *gdrv;
device_remove_file(dev, &dev_attr_online);
device_remove_file(dev, &dev_attr_ungroup);
if (!dev->driver)
return 0;
gdev = to_ccwgroupdev(dev);
gdrv = to_ccwgroupdrv(dev->driver);
device_remove_file(dev, &dev_attr_online);
if (gdrv && gdrv->remove)
if (gdrv->remove)
gdrv->remove(gdev);
return 0;
}
@ -469,9 +491,13 @@ static void ccwgroup_shutdown(struct device *dev)
struct ccwgroup_device *gdev;
struct ccwgroup_driver *gdrv;
if (!dev->driver)
return;
gdev = to_ccwgroupdev(dev);
gdrv = to_ccwgroupdrv(dev->driver);
if (gdrv && gdrv->shutdown)
if (gdrv->shutdown)
gdrv->shutdown(gdev);
}
@ -484,6 +510,19 @@ static struct bus_type ccwgroup_bus_type = {
.shutdown = ccwgroup_shutdown,
};
static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action,
void *data)
{
struct device *dev = data;
if (action == BUS_NOTIFY_UNBIND_DRIVER)
device_schedule_callback(dev, ccwgroup_ungroup_callback);
return NOTIFY_OK;
}
/**
* ccwgroup_driver_register() - register a ccw group driver
* @cdriver: driver to be registered

View file

@ -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);

View file

@ -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);
}

View file

@ -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
View 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);

View file

@ -18,8 +18,8 @@
#include <linux/list.h>
#include <linux/reboot.h>
#include <asm/isc.h>
#include <asm/crw.h>
#include "../s390mach.h"
#include "css.h"
#include "cio.h"
#include "cio_debug.h"
@ -83,6 +83,25 @@ static int call_fn_unknown_sch(struct subchannel_id schid, void *data)
return rc;
}
static int call_fn_all_sch(struct subchannel_id schid, void *data)
{
struct cb_data *cb = data;
struct subchannel *sch;
int rc = 0;
sch = get_subchannel_by_schid(schid);
if (sch) {
if (cb->fn_known_sch)
rc = cb->fn_known_sch(sch, cb->data);
put_device(&sch->dev);
} else {
if (cb->fn_unknown_sch)
rc = cb->fn_unknown_sch(schid, cb->data);
}
return rc;
}
int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
int (*fn_unknown)(struct subchannel_id,
void *), void *data)
@ -90,13 +109,17 @@ int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
struct cb_data cb;
int rc;
cb.set = idset_sch_new();
if (!cb.set)
return -ENOMEM;
idset_fill(cb.set);
cb.data = data;
cb.fn_known_sch = fn_known;
cb.fn_unknown_sch = fn_unknown;
cb.set = idset_sch_new();
if (!cb.set)
/* fall back to brute force scanning in case of oom */
return for_each_subchannel(call_fn_all_sch, &cb);
idset_fill(cb.set);
/* Process registered subchannels. */
rc = bus_for_each_dev(&css_bus_type, NULL, &cb, call_fn_known_sch);
if (rc)
@ -510,6 +533,17 @@ static int reprobe_subchannel(struct subchannel_id schid, void *data)
return ret;
}
static void reprobe_after_idle(struct work_struct *unused)
{
/* Make sure initial subchannel scan is done. */
wait_event(ccw_device_init_wq,
atomic_read(&ccw_device_init_count) == 0);
if (need_reprobe)
css_schedule_reprobe();
}
static DECLARE_WORK(reprobe_idle_work, reprobe_after_idle);
/* Work function used to reprobe all unregistered subchannels. */
static void reprobe_all(struct work_struct *unused)
{
@ -517,10 +551,12 @@ static void reprobe_all(struct work_struct *unused)
CIO_MSG_EVENT(4, "reprobe start\n");
need_reprobe = 0;
/* Make sure initial subchannel scan is done. */
wait_event(ccw_device_init_wq,
atomic_read(&ccw_device_init_count) == 0);
if (atomic_read(&ccw_device_init_count) != 0) {
queue_work(ccw_device_work, &reprobe_idle_work);
return;
}
need_reprobe = 0;
ret = for_each_subchannel_staged(NULL, reprobe_subchannel, NULL);
CIO_MSG_EVENT(4, "reprobe done (rc=%d, need_reprobe=%d)\n", ret,
@ -619,7 +655,7 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high)
css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid;
} else {
#ifdef CONFIG_SMP
css->global_pgid.pgid_high.cpu_addr = hard_smp_processor_id();
css->global_pgid.pgid_high.cpu_addr = stap();
#else
css->global_pgid.pgid_high.cpu_addr = 0;
#endif
@ -765,7 +801,7 @@ init_channel_subsystem (void)
if (ret)
goto out;
ret = s390_register_crw_handler(CRW_RSC_SCH, css_process_crw);
ret = crw_register_handler(CRW_RSC_SCH, css_process_crw);
if (ret)
goto out;
@ -845,7 +881,7 @@ out_unregister:
out_bus:
bus_unregister(&css_bus_type);
out:
s390_unregister_crw_handler(CRW_RSC_CSS);
crw_unregister_handler(CRW_RSC_CSS);
chsc_free_sei_area();
kfree(slow_subchannel_set);
pr_alert("The CSS device driver initialization failed with "

View file

@ -457,12 +457,13 @@ int ccw_device_set_online(struct ccw_device *cdev)
return (ret == 0) ? -ENODEV : ret;
}
static void online_store_handle_offline(struct ccw_device *cdev)
static int online_store_handle_offline(struct ccw_device *cdev)
{
if (cdev->private->state == DEV_STATE_DISCONNECTED)
ccw_device_remove_disconnected(cdev);
else if (cdev->drv && cdev->drv->set_offline)
ccw_device_set_offline(cdev);
else if (cdev->online && cdev->drv && cdev->drv->set_offline)
return ccw_device_set_offline(cdev);
return 0;
}
static int online_store_recog_and_online(struct ccw_device *cdev)
@ -530,13 +531,10 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
goto out;
switch (i) {
case 0:
online_store_handle_offline(cdev);
ret = count;
ret = online_store_handle_offline(cdev);
break;
case 1:
ret = online_store_handle_online(cdev, force);
if (!ret)
ret = count;
break;
default:
ret = -EINVAL;
@ -545,7 +543,7 @@ out:
if (cdev->drv)
module_put(cdev->drv->owner);
atomic_set(&cdev->private->onoff, 0);
return ret;
return (ret < 0) ? ret : count;
}
static ssize_t
@ -681,35 +679,22 @@ get_orphaned_ccwdev_by_dev_id(struct channel_subsystem *css,
return dev ? to_ccwdev(dev) : NULL;
}
static void
ccw_device_add_changed(struct work_struct *work)
{
struct ccw_device_private *priv;
struct ccw_device *cdev;
priv = container_of(work, struct ccw_device_private, kick_work);
cdev = priv->cdev;
if (device_add(&cdev->dev)) {
put_device(&cdev->dev);
return;
}
set_bit(1, &cdev->private->registered);
}
void ccw_device_do_unreg_rereg(struct work_struct *work)
void ccw_device_do_unbind_bind(struct work_struct *work)
{
struct ccw_device_private *priv;
struct ccw_device *cdev;
struct subchannel *sch;
int ret;
priv = container_of(work, struct ccw_device_private, kick_work);
cdev = priv->cdev;
sch = to_subchannel(cdev->dev.parent);
ccw_device_unregister(cdev);
PREPARE_WORK(&cdev->private->kick_work,
ccw_device_add_changed);
queue_work(ccw_device_work, &cdev->private->kick_work);
if (test_bit(1, &cdev->private->registered)) {
device_release_driver(&cdev->dev);
ret = device_attach(&cdev->dev);
WARN_ON(ret == -ENODEV);
}
}
static void
@ -1035,8 +1020,6 @@ static void ccw_device_call_sch_unregister(struct work_struct *work)
void
io_subchannel_recog_done(struct ccw_device *cdev)
{
struct subchannel *sch;
if (css_init_done == 0) {
cdev->private->flags.recog_done = 1;
return;
@ -1047,7 +1030,6 @@ io_subchannel_recog_done(struct ccw_device *cdev)
/* Remove device found not operational. */
if (!get_device(&cdev->dev))
break;
sch = to_subchannel(cdev->dev.parent);
PREPARE_WORK(&cdev->private->kick_work,
ccw_device_call_sch_unregister);
queue_work(slow_path_wq, &cdev->private->kick_work);

View file

@ -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 *);

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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");

View file

@ -380,11 +380,11 @@ inline void qdio_stop_polling(struct qdio_q *q)
/* show the card that we are not polling anymore */
if (is_qebsm(q)) {
set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT,
set_buf_states(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT,
q->u.in.ack_count);
q->u.in.ack_count = 0;
} else
set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT);
set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT);
}
static void announce_buffer_error(struct qdio_q *q, int count)
@ -419,15 +419,15 @@ static inline void inbound_primed(struct qdio_q *q, int count)
if (!q->u.in.polling) {
q->u.in.polling = 1;
q->u.in.ack_count = count;
q->last_move_ftc = q->first_to_check;
q->u.in.ack_start = q->first_to_check;
return;
}
/* delete the previous ACK's */
set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT,
set_buf_states(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT,
q->u.in.ack_count);
q->u.in.ack_count = count;
q->last_move_ftc = q->first_to_check;
q->u.in.ack_start = q->first_to_check;
return;
}
@ -439,14 +439,13 @@ static inline void inbound_primed(struct qdio_q *q, int count)
if (q->u.in.polling) {
/* reset the previous ACK but first set the new one */
set_buf_state(q, new, SLSB_P_INPUT_ACK);
set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT);
}
else {
set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT);
} else {
q->u.in.polling = 1;
set_buf_state(q, q->first_to_check, SLSB_P_INPUT_ACK);
set_buf_state(q, new, SLSB_P_INPUT_ACK);
}
q->last_move_ftc = new;
q->u.in.ack_start = new;
count--;
if (!count)
return;
@ -455,7 +454,7 @@ static inline void inbound_primed(struct qdio_q *q, int count)
* Need to change all PRIMED buffers to NOT_INIT, otherwise
* we're loosing initiative in the thinint code.
*/
set_buf_states(q, next_buf(q->first_to_check), SLSB_P_INPUT_NOT_INIT,
set_buf_states(q, q->first_to_check, SLSB_P_INPUT_NOT_INIT,
count);
}
@ -523,7 +522,8 @@ int qdio_inbound_q_moved(struct qdio_q *q)
bufnr = get_inbound_buffer_frontier(q);
if ((bufnr != q->last_move_ftc) || q->qdio_error) {
if ((bufnr != q->last_move) || q->qdio_error) {
q->last_move = bufnr;
if (!need_siga_sync(q) && !pci_out_supported(q))
q->u.in.timestamp = get_usecs();
@ -570,29 +570,30 @@ static int qdio_inbound_q_done(struct qdio_q *q)
}
}
void qdio_kick_inbound_handler(struct qdio_q *q)
void qdio_kick_handler(struct qdio_q *q)
{
int count, start, end;
qdio_perf_stat_inc(&perf_stats.inbound_handler);
start = q->first_to_kick;
end = q->first_to_check;
if (end >= start)
count = end - start;
else
count = end + QDIO_MAX_BUFFERS_PER_Q - start;
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%3d c:%3d", start, count);
int start = q->first_to_kick;
int end = q->first_to_check;
int count;
if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE))
return;
q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr,
start, count, q->irq_ptr->int_parm);
count = sub_buf(end, start);
if (q->is_input_q) {
qdio_perf_stat_inc(&perf_stats.inbound_handler);
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%3d c:%3d", start, count);
} else {
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: nr:%1d", q->nr);
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "s:%3d c:%3d", start, count);
}
q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count,
q->irq_ptr->int_parm);
/* for the next time */
q->first_to_kick = q->first_to_check;
q->first_to_kick = end;
q->qdio_error = 0;
}
@ -603,7 +604,7 @@ again:
if (!qdio_inbound_q_moved(q))
return;
qdio_kick_inbound_handler(q);
qdio_kick_handler(q);
if (!qdio_inbound_q_done(q))
/* means poll time is not yet over */
@ -698,21 +699,21 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q)
bufnr = get_outbound_buffer_frontier(q);
if ((bufnr != q->last_move_ftc) || q->qdio_error) {
q->last_move_ftc = bufnr;
if ((bufnr != q->last_move) || q->qdio_error) {
q->last_move = bufnr;
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr);
return 1;
} else
return 0;
}
static void qdio_kick_outbound_q(struct qdio_q *q)
static int qdio_kick_outbound_q(struct qdio_q *q)
{
unsigned int busy_bit;
int cc;
if (!need_siga_out(q))
return;
return 0;
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
qdio_perf_stat_inc(&perf_stats.siga_out);
@ -724,75 +725,37 @@ static void qdio_kick_outbound_q(struct qdio_q *q)
case 2:
if (busy_bit) {
DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr);
q->qdio_error = cc | QDIO_ERROR_SIGA_BUSY;
} else {
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d",
q->nr);
q->qdio_error = cc;
}
cc |= QDIO_ERROR_SIGA_BUSY;
} else
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr);
break;
case 1:
case 3:
DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc);
q->qdio_error = cc;
break;
}
}
static void qdio_kick_outbound_handler(struct qdio_q *q)
{
int start, end, count;
start = q->first_to_kick;
end = q->last_move_ftc;
if (end >= start)
count = end - start;
else
count = end + QDIO_MAX_BUFFERS_PER_Q - start;
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kickouth: %1d", q->nr);
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "s:%3d c:%3d", start, count);
if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE))
return;
q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count,
q->irq_ptr->int_parm);
/* for the next time: */
q->first_to_kick = q->last_move_ftc;
q->qdio_error = 0;
return cc;
}
static void __qdio_outbound_processing(struct qdio_q *q)
{
unsigned long flags;
qdio_perf_stat_inc(&perf_stats.tasklet_outbound);
spin_lock_irqsave(&q->lock, flags);
BUG_ON(atomic_read(&q->nr_buf_used) < 0);
if (qdio_outbound_q_moved(q))
qdio_kick_outbound_handler(q);
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 @@ set:
/* no need to signal as long as the adapter had free buffers */
if (used)
return;
return 0;
if (need_siga_in(q)) {
cc = qdio_siga_input(q);
if (cc)
q->qdio_error = cc;
}
if (need_siga_in(q))
return qdio_siga_input(q);
return 0;
}
/**
@ -1499,11 +1478,11 @@ set:
* @bufnr: first buffer to process
* @count: how many buffers are filled
*/
static void handle_outbound(struct qdio_q *q, unsigned int callflags,
int bufnr, int count)
static int handle_outbound(struct qdio_q *q, unsigned int callflags,
int bufnr, int count)
{
unsigned char state;
int used;
int used, rc = 0;
qdio_perf_stat_inc(&perf_stats.outbound_handler);
@ -1518,27 +1497,26 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags,
if (queue_type(q) == QDIO_IQDIO_QFMT) {
if (multicast_outbound(q))
qdio_kick_outbound_q(q);
rc = qdio_kick_outbound_q(q);
else
if ((q->irq_ptr->ssqd_desc.mmwc > 1) &&
(count > 1) &&
(count <= q->irq_ptr->ssqd_desc.mmwc)) {
/* exploit enhanced SIGA */
q->u.out.use_enh_siga = 1;
qdio_kick_outbound_q(q);
rc = qdio_kick_outbound_q(q);
} else {
/*
* One siga-w per buffer required for unicast
* HiperSockets.
*/
q->u.out.use_enh_siga = 0;
while (count--)
qdio_kick_outbound_q(q);
while (count--) {
rc = qdio_kick_outbound_q(q);
if (rc)
goto out;
}
}
/* report CC=2 conditions synchronously */
if (q->qdio_error)
__qdio_outbound_processing(q);
goto out;
}
@ -1550,14 +1528,14 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags,
/* try to fast requeue buffers */
get_buf_state(q, prev_buf(bufnr), &state, 0);
if (state != SLSB_CU_OUTPUT_PRIMED)
qdio_kick_outbound_q(q);
rc = qdio_kick_outbound_q(q);
else {
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "fast-req");
qdio_perf_stat_inc(&perf_stats.fast_requeue);
}
out:
/* Fixme: could wait forever if called from process context */
tasklet_schedule(&q->tasklet);
return rc;
}
/**
@ -1596,14 +1574,12 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
return -EBUSY;
if (callflags & QDIO_FLAG_SYNC_INPUT)
handle_inbound(irq_ptr->input_qs[q_nr], callflags, bufnr,
count);
return handle_inbound(irq_ptr->input_qs[q_nr],
callflags, bufnr, count);
else if (callflags & QDIO_FLAG_SYNC_OUTPUT)
handle_outbound(irq_ptr->output_qs[q_nr], callflags, bufnr,
count);
else
return -EINVAL;
return 0;
return handle_outbound(irq_ptr->output_qs[q_nr],
callflags, bufnr, count);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(do_QDIO);

View file

@ -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,

View file

@ -31,6 +31,7 @@
/* list of thin interrupt input queues */
static LIST_HEAD(tiq_list);
DEFINE_MUTEX(tiq_list_lock);
/* adapter local summary indicator */
static unsigned char *tiqdio_alsi;
@ -95,12 +96,11 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr)
if (!css_qdio_omit_svs && irq_ptr->siga_flag.sync)
css_qdio_omit_svs = 1;
for_each_input_queue(irq_ptr, q, i) {
mutex_lock(&tiq_list_lock);
for_each_input_queue(irq_ptr, q, i)
list_add_rcu(&q->entry, &tiq_list);
synchronize_rcu();
}
mutex_unlock(&tiq_list_lock);
xchg(irq_ptr->dsci, 1);
tasklet_schedule(&tiqdio_tasklet);
}
/*
@ -118,7 +118,10 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
/* if establish triggered an error */
if (!q || !q->entry.prev || !q->entry.next)
continue;
mutex_lock(&tiq_list_lock);
list_del_rcu(&q->entry);
mutex_unlock(&tiq_list_lock);
synchronize_rcu();
}
}
@ -155,15 +158,15 @@ static void __tiqdio_inbound_processing(struct qdio_q *q)
*/
qdio_check_outbound_after_thinint(q);
again:
if (!qdio_inbound_q_moved(q))
return;
qdio_kick_inbound_handler(q);
qdio_kick_handler(q);
if (!tiqdio_inbound_q_done(q)) {
qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop);
goto again;
if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED))
tasklet_schedule(&q->tasklet);
}
qdio_stop_polling(q);
@ -173,7 +176,8 @@ again:
*/
if (!tiqdio_inbound_q_done(q)) {
qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop2);
goto again;
if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED))
tasklet_schedule(&q->tasklet);
}
}
@ -366,10 +370,11 @@ void qdio_shutdown_thinint(struct qdio_irq *irq_ptr)
void __exit tiqdio_unregister_thinints(void)
{
tasklet_disable(&tiqdio_tasklet);
WARN_ON(!list_empty(&tiq_list));
if (tiqdio_alsi) {
s390_unregister_adapter_interrupt(tiqdio_alsi, QDIO_AIRQ_ISC);
isc_unregister(QDIO_AIRQ_ISC);
}
tasklet_kill(&tiqdio_tasklet);
}

View file

@ -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)

View file

@ -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;
}

View file

@ -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
};

View file

@ -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);

View file

@ -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 */

View file

@ -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 */