diff --git a/Documentation/s390/CommonIO b/Documentation/s390/CommonIO index bf0baa19ec24e875716e09490a2afeaecb86b5e2..339207d11d951a99e54257df96100ab0713e11a9 100644 --- a/Documentation/s390/CommonIO +++ b/Documentation/s390/CommonIO @@ -70,13 +70,19 @@ Command line parameters Note: While already known devices can be added to the list of devices to be ignored, there will be no effect on then. However, if such a device - disappears and then reappears, it will then be ignored. + disappears and then reappears, it will then be ignored. To make + known devices go away, you need the "purge" command (see below). For example, "echo add 0.0.a000-0.0.accc, 0.0.af00-0.0.afff > /proc/cio_ignore" will add 0.0.a000-0.0.accc and 0.0.af00-0.0.afff to the list of ignored devices. + You can remove already known but now ignored devices via + "echo purge > /proc/cio_ignore" + All devices ignored but still registered and not online (= not in use) + will be deregistered and thus removed from the system. + The devices can be specified either by bus id (0.x.abcd) or, for 2.4 backward compatibility, by the device number in hexadecimal (0xabcd or abcd). Device numbers given as 0xabcd will be interpreted as 0.0.abcd. @@ -98,8 +104,7 @@ debugfs entries handling). - /sys/kernel/debug/s390dbf/cio_msg/sprintf - Various debug messages from the common I/O-layer, including messages - printed when cio_msg=yes. + Various debug messages from the common I/O-layer. - /sys/kernel/debug/s390dbf/cio_trace/hex_ascii Logs the calling of functions in the common I/O-layer and, if applicable, diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 8d41908e251375ea3c5a96cbd8000a7b4a29df12..4c03049e7db9195586fe00b07a22c067dcc3f30a 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -74,6 +74,7 @@ config S390 select HAVE_KPROBES select HAVE_KRETPROBES select HAVE_KVM if 64BIT + select HAVE_ARCH_TRACEHOOK source "init/Kconfig" diff --git a/arch/s390/include/asm/dasd.h b/arch/s390/include/asm/dasd.h index 3f002e13d024ee5bf4481ffb4c63698fdcd2ee60..55b2b80cdf6e0926da9663a52292fafb0ca27762 100644 --- a/arch/s390/include/asm/dasd.h +++ b/arch/s390/include/asm/dasd.h @@ -3,6 +3,8 @@ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 + * EMC Symmetrix ioctl Copyright EMC Corporation, 2008 + * Author.........: Nigel Hislop <hislop_nigel@emc.com> * * This file is the interface of the DASD device driver, which is exported to user space * any future changes wrt the API will result in a change of the APIVERSION reported @@ -202,6 +204,16 @@ typedef struct attrib_data_t { #define DASD_SEQ_PRESTAGE 0x4 #define DASD_REC_ACCESS 0x5 +/* + * Perform EMC Symmetrix I/O + */ +typedef struct dasd_symmio_parms { + unsigned char reserved[8]; /* compat with older releases */ + unsigned long long psf_data; /* char * cast to u64 */ + unsigned long long rssd_result; /* char * cast to u64 */ + int psf_data_len; + int rssd_result_len; +} __attribute__ ((packed)) dasd_symmio_parms_t; /******************************************************************************** * SECTION: Definition of IOCTLs @@ -247,6 +259,7 @@ typedef struct attrib_data_t { /* Set Attributes (cache operations) */ #define BIODASDSATTR _IOW(DASD_IOCTL_LETTER,2,attrib_data_t) +#define BIODASDSYMMIO _IOWR(DASD_IOCTL_LETTER, 240, dasd_symmio_parms_t) #endif /* DASD_H */ diff --git a/arch/s390/include/asm/delay.h b/arch/s390/include/asm/delay.h index 78357314c4503f939b0946510aaafd16da32a467..a356c958e2609d4d91ebf5b42bca2c79307bfaba 100644 --- a/arch/s390/include/asm/delay.h +++ b/arch/s390/include/asm/delay.h @@ -15,6 +15,7 @@ #define _S390_DELAY_H extern void __udelay(unsigned long usecs); +extern void udelay_simple(unsigned long usecs); extern void __delay(unsigned long loops); #define udelay(n) __udelay(n) diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 0bdb704ae051f2bf1d83371702aa52bb7994d286..1a928f84afd609bbb989bb1fa9925fa615a7ecf3 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -281,6 +281,9 @@ extern char empty_zero_page[PAGE_SIZE]; #define RCP_GR_BIT 50 #define RCP_GC_BIT 49 +/* User dirty bit for KVM's migration feature */ +#define KVM_UD_BIT 47 + #ifndef __s390x__ /* Bits in the segment table address-space-control-element */ @@ -575,12 +578,16 @@ static inline void ptep_rcp_copy(pte_t *ptep) unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE); skey = page_get_storage_key(page_to_phys(page)); - if (skey & _PAGE_CHANGED) + if (skey & _PAGE_CHANGED) { set_bit_simple(RCP_GC_BIT, pgste); + set_bit_simple(KVM_UD_BIT, pgste); + } if (skey & _PAGE_REFERENCED) set_bit_simple(RCP_GR_BIT, pgste); - if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) + if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) { SetPageDirty(page); + set_bit_simple(KVM_UD_BIT, pgste); + } if (test_and_clear_bit_simple(RCP_HR_BIT, pgste)) SetPageReferenced(page); #endif @@ -744,6 +751,40 @@ static inline pte_t pte_mkspecial(pte_t pte) return pte; } +#ifdef CONFIG_PGSTE +/* + * Get (and clear) the user dirty bit for a PTE. + */ +static inline int kvm_s390_test_and_clear_page_dirty(struct mm_struct *mm, + pte_t *ptep) +{ + int dirty; + unsigned long *pgste; + struct page *page; + unsigned int skey; + + if (!mm->context.pgstes) + return -EINVAL; + rcp_lock(ptep); + pgste = (unsigned long *) (ptep + PTRS_PER_PTE); + page = virt_to_page(pte_val(*ptep)); + skey = page_get_storage_key(page_to_phys(page)); + if (skey & _PAGE_CHANGED) { + set_bit_simple(RCP_GC_BIT, pgste); + set_bit_simple(KVM_UD_BIT, pgste); + } + if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) { + SetPageDirty(page); + set_bit_simple(KVM_UD_BIT, pgste); + } + dirty = test_and_clear_bit_simple(KVM_UD_BIT, pgste); + if (skey & _PAGE_CHANGED) + page_clear_dirty(page); + rcp_unlock(ptep); + return dirty; +} +#endif + #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index af2c9ac28a07945eee89ddc0e7fc2e3d592fd25b..a7226f8143fb9d34df06456f1759d0c2fa085e94 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h @@ -490,6 +490,7 @@ extern void user_disable_single_step(struct task_struct *); #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0) #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN) +#define user_stack_pointer(regs)((regs)->gprs[15]) #define regs_return_value(regs)((regs)->gprs[2]) #define profile_pc(regs) instruction_pointer(regs) extern void show_regs(struct pt_regs * regs); diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index 6813772171f2d7b49826fb49d3f1333edbb88082..4734c3f053546fe3b68f1d3987fbd4e96d0f96f3 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h @@ -299,7 +299,13 @@ struct qdio_ssqd_desc { u8 mbccnt; u16 qdioac2; u64 sch_token; - u64:64; + u8 mro; + u8 mri; + u8:8; + u8 sbalic; + u16:16; + u8:8; + u8 mmwc; } __attribute__ ((packed)); /* params are: ccw_device, qdio_error, queue_number, diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h new file mode 100644 index 0000000000000000000000000000000000000000..6e623971fbb9ae234ad80c450b6da43fa2a68fc4 --- /dev/null +++ b/arch/s390/include/asm/syscall.h @@ -0,0 +1,80 @@ +/* + * Access to user system call parameters and results + * + * Copyright IBM Corp. 2008 + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * as published by the Free Software Foundation. + */ + +#ifndef _ASM_SYSCALL_H +#define _ASM_SYSCALL_H 1 + +#include <asm/ptrace.h> + +static inline long syscall_get_nr(struct task_struct *task, + struct pt_regs *regs) +{ + if (regs->trap != __LC_SVC_OLD_PSW) + return -1; + return regs->gprs[2]; +} + +static inline void syscall_rollback(struct task_struct *task, + struct pt_regs *regs) +{ + regs->gprs[2] = regs->orig_gpr2; +} + +static inline long syscall_get_error(struct task_struct *task, + struct pt_regs *regs) +{ + return (regs->gprs[2] >= -4096UL) ? -regs->gprs[2] : 0; +} + +static inline long syscall_get_return_value(struct task_struct *task, + struct pt_regs *regs) +{ + return regs->gprs[2]; +} + +static inline void syscall_set_return_value(struct task_struct *task, + struct pt_regs *regs, + int error, long val) +{ + regs->gprs[2] = error ? -error : val; +} + +static inline void syscall_get_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned int i, unsigned int n, + unsigned long *args) +{ + BUG_ON(i + n > 6); +#ifdef CONFIG_COMPAT + if (test_tsk_thread_flag(task, TIF_31BIT)) { + if (i + n == 6) + args[--n] = (u32) regs->args[0]; + while (n-- > 0) + args[n] = (u32) regs->gprs[2 + i + n]; + } +#endif + if (i + n == 6) + args[--n] = regs->args[0]; + memcpy(args, ®s->gprs[2 + i], n * sizeof(args[0])); +} + +static inline void syscall_set_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned int i, unsigned int n, + const unsigned long *args) +{ + BUG_ON(i + n > 6); + if (i + n == 6) + regs->args[0] = args[--n]; + memcpy(®s->gprs[2 + i], args, n * sizeof(args[0])); +} + +#endif /* _ASM_SYSCALL_H */ diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h index 91a8f93ad355fcfd2e69a710bbc9efb2bba685f0..ea40a9d690fcc19407d8fd8a610d1af5b25a7a7d 100644 --- a/arch/s390/include/asm/thread_info.h +++ b/arch/s390/include/asm/thread_info.h @@ -86,6 +86,7 @@ static inline struct thread_info *current_thread_info(void) * thread information flags bit numbers */ #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ +#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ #define TIF_SIGPENDING 2 /* signal pending */ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_RESTART_SVC 4 /* restart svc with new svc number */ @@ -100,6 +101,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_RESTORE_SIGMASK 20 /* restore signal mask in do_signal() */ #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) +#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) #define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index d7f22226fc4ec61a569f258c2e0903bbd0c121f3..98e246dc02338bef90d6cd9f27d39069b4cac414 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -608,14 +608,6 @@ asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv, struct time return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); } -/* These are here just in case some old sparc32 binary calls it. */ -asmlinkage long sys32_pause(void) -{ - current->state = TASK_INTERRUPTIBLE; - schedule(); - return -ERESTARTNOHAND; -} - asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf, size_t count, u32 poshi, u32 poslo) { diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h index 20723a06201736c5c67a0a89aa75c65e3b909b33..05f8516366ab0df450c12a53723a53fe94ef841e 100644 --- a/arch/s390/kernel/compat_linux.h +++ b/arch/s390/kernel/compat_linux.h @@ -206,7 +206,6 @@ long sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz); long sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz); -long sys32_pause(void); long sys32_pread64(unsigned int fd, char __user *ubuf, size_t count, u32 poshi, u32 poslo); long sys32_pwrite64(unsigned int fd, const char __user *ubuf, diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 328a20e880b53525f41385fafba3fdf2cac18e1b..ee51ca9e23b56e1ba0380323f4cac8193d63c627 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -128,8 +128,6 @@ sys32_alarm_wrapper: llgfr %r2,%r2 # unsigned int jg sys_alarm # branch to system call -#sys32_pause_wrapper # void - .globl compat_sys_utime_wrapper compat_sys_utime_wrapper: llgtr %r2,%r2 # char * diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 708cf9cf9a355e175d5b1cf4fbdc2b96732e7084..ed500ef799b795a21f322ae0d8e818b8bd926a36 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -49,9 +49,9 @@ SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE -_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ +_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) -_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ +_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ _TIF_MCCK_PENDING) STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER @@ -318,6 +318,8 @@ sysc_work: bo BASED(sysc_reschedule) tm __TI_flags+3(%r9),_TIF_SIGPENDING bnz BASED(sysc_sigpending) + tm __TI_flags+3(%r9),_TIF_NOTIFY_RESUME + bnz BASED(sysc_notify_resume) tm __TI_flags+3(%r9),_TIF_RESTART_SVC bo BASED(sysc_restart) tm __TI_flags+3(%r9),_TIF_SINGLE_STEP @@ -355,6 +357,16 @@ sysc_sigpending: bo BASED(sysc_singlestep) b BASED(sysc_work_loop) +# +# _TIF_NOTIFY_RESUME is set, call do_notify_resume +# +sysc_notify_resume: + la %r2,SP_PTREGS(%r15) # load pt_regs + l %r1,BASED(.Ldo_notify_resume) + la %r14,BASED(sysc_work_loop) + br %r1 # call do_notify_resume + + # # _TIF_RESTART_SVC is set, set up registers and restart svc # @@ -378,20 +390,21 @@ sysc_singlestep: br %r1 # branch to do_single_step # -# call trace before and after sys_call +# call tracehook_report_syscall_entry/tracehook_report_syscall_exit before +# and after the system call # sysc_tracesys: - l %r1,BASED(.Ltrace) + l %r1,BASED(.Ltrace_entry) la %r2,SP_PTREGS(%r15) # load pt_regs la %r3,0 srl %r7,2 st %r7,SP_R2(%r15) basr %r14,%r1 - clc SP_R2(4,%r15),BASED(.Lnr_syscalls) + cl %r2,BASED(.Lnr_syscalls) bnl BASED(sysc_tracenogo) l %r8,BASED(.Lsysc_table) - l %r7,SP_R2(%r15) # strace might have changed the - sll %r7,2 # system call + lr %r7,%r2 + sll %r7,2 # *4 l %r8,0(%r7,%r8) sysc_tracego: lm %r3,%r6,SP_R3(%r15) @@ -401,9 +414,8 @@ sysc_tracego: sysc_tracenogo: tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) bz BASED(sysc_return) - l %r1,BASED(.Ltrace) + l %r1,BASED(.Ltrace_exit) la %r2,SP_PTREGS(%r15) # load pt_regs - la %r3,1 la %r14,BASED(sysc_return) br %r1 @@ -666,6 +678,8 @@ io_work_loop: bo BASED(io_reschedule) tm __TI_flags+3(%r9),_TIF_SIGPENDING bnz BASED(io_sigpending) + tm __TI_flags+3(%r9),_TIF_NOTIFY_RESUME + bnz BASED(io_notify_resume) b BASED(io_restore) io_work_done: @@ -704,6 +718,19 @@ io_sigpending: TRACE_IRQS_OFF b BASED(io_work_loop) +# +# _TIF_SIGPENDING is set, call do_signal +# +io_notify_resume: + TRACE_IRQS_ON + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts + la %r2,SP_PTREGS(%r15) # load pt_regs + l %r1,BASED(.Ldo_notify_resume) + basr %r14,%r1 # call do_signal + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts + TRACE_IRQS_OFF + b BASED(io_work_loop) + /* * External interrupt handler routine */ @@ -1070,6 +1097,8 @@ cleanup_io_leave_insn: .Ldo_IRQ: .long do_IRQ .Ldo_extint: .long do_extint .Ldo_signal: .long do_signal +.Ldo_notify_resume: + .long do_notify_resume .Lhandle_per: .long do_single_step .Ldo_execve: .long do_execve .Lexecve_tail: .long execve_tail @@ -1079,7 +1108,8 @@ cleanup_io_leave_insn: .Lpreempt_schedule_irq: .long preempt_schedule_irq #endif -.Ltrace: .long syscall_trace +.Ltrace_entry: .long do_syscall_trace_enter +.Ltrace_exit: .long do_syscall_trace_exit .Lschedtail: .long schedule_tail .Lsysc_table: .long sys_call_table #ifdef CONFIG_TRACE_IRQFLAGS diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index fee10177dbfcf67a175c7d82f1839886ef509ff4..d7ce150453f2865bfa4c9e99f53c03cda198442d 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -52,9 +52,9 @@ SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER STACK_SIZE = 1 << STACK_SHIFT -_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ +_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) -_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ +_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ _TIF_MCCK_PENDING) #define BASED(name) name-system_call(%r13) @@ -310,6 +310,8 @@ sysc_work: jo sysc_reschedule tm __TI_flags+7(%r9),_TIF_SIGPENDING jnz sysc_sigpending + tm __TI_flags+7(%r9),_TIF_NOTIFY_RESUME + jnz sysc_notify_resume tm __TI_flags+7(%r9),_TIF_RESTART_SVC jo sysc_restart tm __TI_flags+7(%r9),_TIF_SINGLE_STEP @@ -344,6 +346,14 @@ sysc_sigpending: jo sysc_singlestep j sysc_work_loop +# +# _TIF_NOTIFY_RESUME is set, call do_notify_resume +# +sysc_notify_resume: + la %r2,SP_PTREGS(%r15) # load pt_regs + larl %r14,sysc_work_loop + jg do_notify_resume # call do_notify_resume + # # _TIF_RESTART_SVC is set, set up registers and restart svc # @@ -367,20 +377,19 @@ sysc_singlestep: jg do_single_step # branch to do_sigtrap # -# call syscall_trace before and after system call -# special linkage: %r12 contains the return address for trace_svc +# call tracehook_report_syscall_entry/tracehook_report_syscall_exit before +# and after the system call # sysc_tracesys: la %r2,SP_PTREGS(%r15) # load pt_regs la %r3,0 srl %r7,2 stg %r7,SP_R2(%r15) - brasl %r14,syscall_trace + brasl %r14,do_syscall_trace_enter lghi %r0,NR_syscalls - clg %r0,SP_R2(%r15) + clgr %r0,%r2 jnh sysc_tracenogo - lg %r7,SP_R2(%r15) # strace might have changed the - sll %r7,2 # system call + slag %r7,%r2,2 # *4 lgf %r8,0(%r7,%r10) sysc_tracego: lmg %r3,%r6,SP_R3(%r15) @@ -391,9 +400,8 @@ sysc_tracenogo: tm __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) jz sysc_return la %r2,SP_PTREGS(%r15) # load pt_regs - la %r3,1 larl %r14,sysc_return # return point is sysc_return - jg syscall_trace + jg do_syscall_trace_exit # # a new process exits the kernel with ret_from_fork @@ -672,6 +680,8 @@ io_work_loop: jo io_reschedule tm __TI_flags+7(%r9),_TIF_SIGPENDING jnz io_sigpending + tm __TI_flags+7(%r9),_TIF_NOTIFY_RESUME + jnz io_notify_resume j io_restore io_work_done: @@ -712,6 +722,18 @@ io_sigpending: TRACE_IRQS_OFF j io_work_loop +# +# _TIF_NOTIFY_RESUME or is set, call do_notify_resume +# +io_notify_resume: + TRACE_IRQS_ON + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts + la %r2,SP_PTREGS(%r15) # load pt_regs + brasl %r14,do_notify_resume # call do_notify_resume + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts + TRACE_IRQS_OFF + j io_work_loop + /* * External interrupt handler routine */ diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index c8b08289eb87e1d78c9c92996fe7bbfe30c16645..1f31be1ecc4bd57bd3af99ef004f00df4f24987b 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -35,6 +35,7 @@ #include <linux/signal.h> #include <linux/elf.h> #include <linux/regset.h> +#include <linux/tracehook.h> #include <asm/segment.h> #include <asm/page.h> @@ -639,40 +640,44 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, } #endif -asmlinkage void -syscall_trace(struct pt_regs *regs, int entryexit) +asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) { - if (unlikely(current->audit_context) && entryexit) - audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]); - - if (!test_thread_flag(TIF_SYSCALL_TRACE)) - goto out; - if (!(current->ptrace & PT_PTRACED)) - goto out; - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0)); + long ret; /* - * If the debuffer has set an invalid system call number, - * we prepare to skip the system call restart handling. + * The sysc_tracesys code in entry.S stored the system + * call number to gprs[2]. */ - if (!entryexit && regs->gprs[2] >= NR_syscalls) + ret = regs->gprs[2]; + if (test_thread_flag(TIF_SYSCALL_TRACE) && + (tracehook_report_syscall_entry(regs) || + regs->gprs[2] >= NR_syscalls)) { + /* + * Tracing decided this syscall should not happen or the + * debugger stored an invalid system call number. Skip + * the system call and the system call restart handling. + */ regs->trap = -1; - - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; + ret = -1; } - out: - if (unlikely(current->audit_context) && !entryexit) - audit_syscall_entry(test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X, - regs->gprs[2], regs->orig_gpr2, regs->gprs[3], - regs->gprs[4], regs->gprs[5]); + + if (unlikely(current->audit_context)) + audit_syscall_entry(test_thread_flag(TIF_31BIT) ? + AUDIT_ARCH_S390 : AUDIT_ARCH_S390X, + regs->gprs[2], regs->orig_gpr2, + regs->gprs[3], regs->gprs[4], + regs->gprs[5]); + return ret; +} + +asmlinkage void do_syscall_trace_exit(struct pt_regs *regs) +{ + if (unlikely(current->audit_context)) + audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), + regs->gprs[2]); + + if (test_thread_flag(TIF_SYSCALL_TRACE)) + tracehook_report_syscall_exit(regs, 0); } /* diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index b976820402154a49b3792e7f8c07d7c803416358..4f7fc3059a8e8a1e1e937d976d1c962febcdbd7e 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -24,6 +24,7 @@ #include <linux/tty.h> #include <linux/personality.h> #include <linux/binfmts.h> +#include <linux/tracehook.h> #include <asm/ucontext.h> #include <asm/uaccess.h> #include <asm/lowcore.h> @@ -507,6 +508,12 @@ void do_signal(struct pt_regs *regs) */ if (current->thread.per_info.single_step) set_thread_flag(TIF_SINGLE_STEP); + + /* + * Let tracing know that we've done the handler setup. + */ + tracehook_signal_handler(signr, &info, &ka, regs, + test_thread_flag(TIF_SINGLE_STEP)); } return; } @@ -526,3 +533,9 @@ void do_signal(struct pt_regs *regs) set_thread_flag(TIF_RESTART_SVC); } } + +void do_notify_resume(struct pt_regs *regs) +{ + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); +} diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index c66d35e55142b0923d08fa4c675b8b320c78f686..3ae303914b4201f63dc83c09ca74744e2e3ec283 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -37,7 +37,7 @@ SYSCALL(sys_stime,sys_ni_syscall,sys32_stime_wrapper) /* 25 old stime syscall * SYSCALL(sys_ptrace,sys_ptrace,sys32_ptrace_wrapper) SYSCALL(sys_alarm,sys_alarm,sys32_alarm_wrapper) NI_SYSCALL /* old fstat syscall */ -SYSCALL(sys_pause,sys_pause,sys32_pause) +SYSCALL(sys_pause,sys_pause,sys_pause) SYSCALL(sys_utime,sys_utime,compat_sys_utime_wrapper) /* 30 */ NI_SYSCALL /* old stty syscall */ NI_SYSCALL /* old gtty syscall */ diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 06acb1a18bbcb44458a8f04da85f00f54345ca1b..b94e9e3b694a2bd738cfc58d8fdcc9bbc5baa412 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -1356,7 +1356,7 @@ static void __init stp_reset(void) stp_page = alloc_bootmem_pages(PAGE_SIZE); rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); - if (rc == 1) + if (rc == 0) set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags); else if (stp_online) { printk(KERN_WARNING "Running on non STP capable machine.\n"); diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index 0953cee05efc2d40cefcf8819c650de563462f6b..6ccb9fab055a5b08abb129bbd8752d11f1a0dd8c 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c @@ -92,3 +92,16 @@ out: local_irq_restore(flags); preempt_enable(); } + +/* + * Simple udelay variant. To be used on startup and reboot + * when the interrupt handler isn't working. + */ +void udelay_simple(unsigned long usecs) +{ + u64 end; + + end = get_clock() + ((u64) usecs << 12); + while (get_clock() < end) + cpu_relax(); +} diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index f231f5ec74b633555decc0827a8d14d3ceba3d6d..580fc64cc735f343f2576baaba0bebb8eef2b3e9 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -43,20 +43,40 @@ #define DCSS_FINDSEG 0x0c #define DCSS_LOADNOLY 0x10 #define DCSS_SEGEXT 0x18 +#define DCSS_LOADSHRX 0x20 +#define DCSS_LOADNSRX 0x24 +#define DCSS_FINDSEGX 0x2c +#define DCSS_SEGEXTX 0x38 #define DCSS_FINDSEGA 0x0c struct qrange { - unsigned int start; // 3byte start address, 1 byte type - unsigned int end; // 3byte end address, 1 byte reserved + unsigned long start; /* last byte type */ + unsigned long end; /* last byte reserved */ }; struct qout64 { + unsigned long segstart; + unsigned long segend; + int segcnt; + int segrcnt; + struct qrange range[6]; +}; + +#ifdef CONFIG_64BIT +struct qrange_old { + unsigned int start; /* last byte type */ + unsigned int end; /* last byte reserved */ +}; + +/* output area format for the Diag x'64' old subcode x'18' */ +struct qout64_old { int segstart; int segend; int segcnt; int segrcnt; - struct qrange range[6]; + struct qrange_old range[6]; }; +#endif struct qin64 { char qopcode; @@ -86,6 +106,55 @@ static DEFINE_MUTEX(dcss_lock); static LIST_HEAD(dcss_list); static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC", "EW/EN-MIXED" }; +static int loadshr_scode, loadnsr_scode, findseg_scode; +static int segext_scode, purgeseg_scode; +static int scode_set; + +/* set correct Diag x'64' subcodes. */ +static int +dcss_set_subcodes(void) +{ +#ifdef CONFIG_64BIT + char *name = kmalloc(8 * sizeof(char), GFP_DMA); + unsigned long rx, ry; + int rc; + + if (name == NULL) + return -ENOMEM; + + rx = (unsigned long) name; + ry = DCSS_FINDSEGX; + + strcpy(name, "dummy"); + asm volatile( + " diag %0,%1,0x64\n" + "0: ipm %2\n" + " srl %2,28\n" + " j 2f\n" + "1: la %2,3\n" + "2:\n" + EX_TABLE(0b, 1b) + : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); + + kfree(name); + /* Diag x'64' new subcodes are supported, set to new subcodes */ + if (rc != 3) { + loadshr_scode = DCSS_LOADSHRX; + loadnsr_scode = DCSS_LOADNSRX; + purgeseg_scode = DCSS_PURGESEG; + findseg_scode = DCSS_FINDSEGX; + segext_scode = DCSS_SEGEXTX; + return 0; + } +#endif + /* Diag x'64' new subcodes are not supported, set to old subcodes */ + loadshr_scode = DCSS_LOADNOLY; + loadnsr_scode = DCSS_LOADNSR; + purgeseg_scode = DCSS_PURGESEG; + findseg_scode = DCSS_FINDSEG; + segext_scode = DCSS_SEGEXT; + return 0; +} /* * Create the 8 bytes, ebcdic VM segment name from @@ -135,25 +204,45 @@ segment_by_name (char *name) * Perform a function on a dcss segment. */ static inline int -dcss_diag (__u8 func, void *parameter, +dcss_diag(int *func, void *parameter, unsigned long *ret1, unsigned long *ret2) { unsigned long rx, ry; int rc; + if (scode_set == 0) { + rc = dcss_set_subcodes(); + if (rc < 0) + return rc; + scode_set = 1; + } rx = (unsigned long) parameter; - ry = (unsigned long) func; - asm volatile( + ry = (unsigned long) *func; + #ifdef CONFIG_64BIT - " sam31\n" - " diag %0,%1,0x64\n" - " sam64\n" + /* 64-bit Diag x'64' new subcode, keep in 64-bit addressing mode */ + if (*func > DCSS_SEGEXT) + asm volatile( + " diag %0,%1,0x64\n" + " ipm %2\n" + " srl %2,28\n" + : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); + /* 31-bit Diag x'64' old subcode, switch to 31-bit addressing mode */ + else + asm volatile( + " sam31\n" + " diag %0,%1,0x64\n" + " sam64\n" + " ipm %2\n" + " srl %2,28\n" + : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); #else + asm volatile( " diag %0,%1,0x64\n" -#endif " ipm %2\n" " srl %2,28\n" : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); +#endif *ret1 = rx; *ret2 = ry; return rc; @@ -190,14 +279,45 @@ query_segment_type (struct dcss_segment *seg) qin->qoutlen = sizeof(struct qout64); memcpy (qin->qname, seg->dcss_name, 8); - diag_cc = dcss_diag (DCSS_SEGEXT, qin, &dummy, &vmrc); + diag_cc = dcss_diag(&segext_scode, qin, &dummy, &vmrc); + if (diag_cc < 0) { + rc = diag_cc; + goto out_free; + } if (diag_cc > 1) { PRINT_WARN ("segment_type: diag returned error %ld\n", vmrc); rc = dcss_diag_translate_rc (vmrc); goto out_free; } +#ifdef CONFIG_64BIT + /* Only old format of output area of Diagnose x'64' is supported, + copy data for the new format. */ + if (segext_scode == DCSS_SEGEXT) { + struct qout64_old *qout_old; + qout_old = kzalloc(sizeof(struct qout64_old), GFP_DMA); + if (qout_old == NULL) { + rc = -ENOMEM; + goto out_free; + } + memcpy(qout_old, qout, sizeof(struct qout64_old)); + qout->segstart = (unsigned long) qout_old->segstart; + qout->segend = (unsigned long) qout_old->segend; + qout->segcnt = qout_old->segcnt; + qout->segrcnt = qout_old->segrcnt; + + if (qout->segcnt > 6) + qout->segrcnt = 6; + for (i = 0; i < qout->segrcnt; i++) { + qout->range[i].start = + (unsigned long) qout_old->range[i].start; + qout->range[i].end = + (unsigned long) qout_old->range[i].end; + } + kfree(qout_old); + } +#endif if (qout->segcnt > 6) { rc = -ENOTSUPP; goto out_free; @@ -268,6 +388,30 @@ segment_type (char* name) return seg.vm_segtype; } +/* + * check if segment collides with other segments that are currently loaded + * returns 1 if this is the case, 0 if no collision was found + */ +static int +segment_overlaps_others (struct dcss_segment *seg) +{ + struct list_head *l; + struct dcss_segment *tmp; + + BUG_ON(!mutex_is_locked(&dcss_lock)); + list_for_each(l, &dcss_list) { + tmp = list_entry(l, struct dcss_segment, list); + if ((tmp->start_addr >> 20) > (seg->end >> 20)) + continue; + if ((tmp->end >> 20) < (seg->start_addr >> 20)) + continue; + if (seg == tmp) + continue; + return 1; + } + return 0; +} + /* * real segment loading function, called from segment_load */ @@ -276,7 +420,8 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long { struct dcss_segment *seg = kmalloc(sizeof(struct dcss_segment), GFP_DMA); - int dcss_command, rc, diag_cc; + int rc, diag_cc; + unsigned long start_addr, end_addr, dummy; if (seg == NULL) { rc = -ENOMEM; @@ -287,6 +432,13 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long if (rc < 0) goto out_free; + if (loadshr_scode == DCSS_LOADSHRX) { + if (segment_overlaps_others(seg)) { + rc = -EBUSY; + goto out_free; + } + } + rc = vmem_add_mapping(seg->start_addr, seg->end - seg->start_addr + 1); if (rc) @@ -316,20 +468,28 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long } if (do_nonshared) - dcss_command = DCSS_LOADNSR; + diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name, + &start_addr, &end_addr); else - dcss_command = DCSS_LOADNOLY; - - diag_cc = dcss_diag(dcss_command, seg->dcss_name, - &seg->start_addr, &seg->end); + diag_cc = dcss_diag(&loadshr_scode, seg->dcss_name, + &start_addr, &end_addr); + if (diag_cc < 0) { + dcss_diag(&purgeseg_scode, seg->dcss_name, + &dummy, &dummy); + rc = diag_cc; + goto out_resource; + } if (diag_cc > 1) { PRINT_WARN ("segment_load: could not load segment %s - " - "diag returned error (%ld)\n",name,seg->end); - rc = dcss_diag_translate_rc (seg->end); - dcss_diag(DCSS_PURGESEG, seg->dcss_name, - &seg->start_addr, &seg->end); + "diag returned error (%ld)\n", + name, end_addr); + rc = dcss_diag_translate_rc(end_addr); + dcss_diag(&purgeseg_scode, seg->dcss_name, + &dummy, &dummy); goto out_resource; } + seg->start_addr = start_addr; + seg->end = end_addr; seg->do_nonshared = do_nonshared; atomic_set(&seg->ref_count, 1); list_add(&seg->list, &dcss_list); @@ -423,8 +583,8 @@ int segment_modify_shared (char *name, int do_nonshared) { struct dcss_segment *seg; - unsigned long dummy; - int dcss_command, rc, diag_cc; + unsigned long start_addr, end_addr, dummy; + int rc, diag_cc; mutex_lock(&dcss_lock); seg = segment_by_name (name); @@ -445,38 +605,51 @@ segment_modify_shared (char *name, int do_nonshared) goto out_unlock; } release_resource(seg->res); - if (do_nonshared) { - dcss_command = DCSS_LOADNSR; + if (do_nonshared) seg->res->flags &= ~IORESOURCE_READONLY; - } else { - dcss_command = DCSS_LOADNOLY; + else if (seg->vm_segtype == SEG_TYPE_SR || seg->vm_segtype == SEG_TYPE_ER) seg->res->flags |= IORESOURCE_READONLY; - } + if (request_resource(&iomem_resource, seg->res)) { PRINT_WARN("segment_modify_shared: could not reload segment %s" " - overlapping resources\n", name); rc = -EBUSY; kfree(seg->res); - goto out_del; + goto out_del_mem; + } + + dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy); + if (do_nonshared) + diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name, + &start_addr, &end_addr); + else + diag_cc = dcss_diag(&loadshr_scode, seg->dcss_name, + &start_addr, &end_addr); + if (diag_cc < 0) { + rc = diag_cc; + goto out_del_res; } - dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); - diag_cc = dcss_diag(dcss_command, seg->dcss_name, - &seg->start_addr, &seg->end); if (diag_cc > 1) { PRINT_WARN ("segment_modify_shared: could not reload segment %s" - " - diag returned error (%ld)\n",name,seg->end); - rc = dcss_diag_translate_rc (seg->end); - goto out_del; + " - diag returned error (%ld)\n", + name, end_addr); + rc = dcss_diag_translate_rc(end_addr); + goto out_del_res; } + seg->start_addr = start_addr; + seg->end = end_addr; seg->do_nonshared = do_nonshared; rc = 0; goto out_unlock; - out_del: + out_del_res: + release_resource(seg->res); + kfree(seg->res); + out_del_mem: vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1); list_del(&seg->list); - dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); + dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy); kfree(seg); out_unlock: mutex_unlock(&dcss_lock); @@ -510,7 +683,7 @@ segment_unload(char *name) kfree(seg->res); vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1); list_del(&seg->list); - dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); + dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy); kfree(seg); out_unlock: mutex_unlock(&dcss_lock); @@ -545,7 +718,7 @@ segment_save(char *name) endpfn = (seg->end) >> PAGE_SHIFT; sprintf(cmd1, "DEFSEG %s", name); for (i=0; i<seg->segcnt; i++) { - sprintf(cmd1+strlen(cmd1), " %X-%X %s", + sprintf(cmd1+strlen(cmd1), " %lX-%lX %s", seg->range[i].start >> PAGE_SHIFT, seg->range[i].end >> PAGE_SHIFT, segtype_string[seg->range[i].start & 0xff]); diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index acb78017e7d0fd2e2988bfed85ec484e527bfcc6..0a225ccda026017773e1a619fc07c651c7223aef 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -215,7 +215,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(device->cdev->dev.bus_id, 1, 1, + device->debug_area = debug_register(dev_name(&device->cdev->dev), 1, 1, 8 * sizeof(long)); debug_register_view(device->debug_area, &debug_sprintf_view); debug_set_level(device->debug_area, DBF_WARNING); @@ -933,7 +933,7 @@ static void dasd_handle_killed_request(struct ccw_device *cdev, MESSAGE(KERN_DEBUG, "invalid status in handle_killed_request: " "bus_id %s, status %02x", - cdev->dev.bus_id, cqr->status); + dev_name(&cdev->dev), cqr->status); return; } @@ -942,7 +942,7 @@ static void dasd_handle_killed_request(struct ccw_device *cdev, 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", - cdev->dev.bus_id); + dev_name(&cdev->dev)); return; } @@ -982,11 +982,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, break; case -ETIMEDOUT: printk(KERN_WARNING"%s(%s): request timed out\n", - __func__, cdev->dev.bus_id); + __func__, dev_name(&cdev->dev)); break; default: printk(KERN_WARNING"%s(%s): unknown error %ld\n", - __func__, cdev->dev.bus_id, PTR_ERR(irb)); + __func__, dev_name(&cdev->dev), PTR_ERR(irb)); } dasd_handle_killed_request(cdev, intparm); return; @@ -995,7 +995,7 @@ 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", - cdev->dev.bus_id, ((irb->scsw.cmd.cstat << 8) | + dev_name(&cdev->dev), ((irb->scsw.cmd.cstat << 8) | irb->scsw.cmd.dstat), (unsigned int) intparm); /* check for unsolicited interrupts */ @@ -1019,7 +1019,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, if (!device || strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s", - cdev->dev.bus_id); + dev_name(&cdev->dev)); return; } @@ -1037,7 +1037,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, if (cqr->status != DASD_CQR_IN_IO) { MESSAGE(KERN_DEBUG, "invalid status: bus_id %s, status %02x", - cdev->dev.bus_id, cqr->status); + dev_name(&cdev->dev), cqr->status); return; } DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p", @@ -2134,14 +2134,14 @@ int dasd_generic_probe(struct ccw_device *cdev, if (ret) { printk(KERN_WARNING "dasd_generic_probe: could not set ccw-device options " - "for %s\n", cdev->dev.bus_id); + "for %s\n", dev_name(&cdev->dev)); return ret; } ret = dasd_add_sysfs_files(cdev); if (ret) { printk(KERN_WARNING "dasd_generic_probe: could not add sysfs entries " - "for %s\n", cdev->dev.bus_id); + "for %s\n", dev_name(&cdev->dev)); return ret; } cdev->handler = &dasd_int_handler; @@ -2152,13 +2152,13 @@ int dasd_generic_probe(struct ccw_device *cdev, * initial probe. */ if ((dasd_get_feature(cdev, DASD_FEATURE_INITIAL_ONLINE) > 0 ) || - (dasd_autodetect && dasd_busid_known(cdev->dev.bus_id) != 0)) + (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", - cdev->dev.bus_id, ret); + dev_name(&cdev->dev), ret); return 0; } @@ -2224,7 +2224,7 @@ int dasd_generic_set_online(struct ccw_device *cdev, printk (KERN_WARNING "dasd_generic couldn't online device %s " "- discipline DIAG not available\n", - cdev->dev.bus_id); + dev_name(&cdev->dev)); dasd_delete_device(device); return -ENODEV; } @@ -2248,7 +2248,7 @@ int dasd_generic_set_online(struct ccw_device *cdev, printk (KERN_WARNING "dasd_generic couldn't online device %s " "with discipline %s rc=%i\n", - cdev->dev.bus_id, discipline->name, rc); + dev_name(&cdev->dev), discipline->name, rc); module_put(discipline->owner); module_put(base_discipline->owner); dasd_delete_device(device); @@ -2259,7 +2259,7 @@ int dasd_generic_set_online(struct ccw_device *cdev, if (device->state <= DASD_STATE_KNOWN) { printk (KERN_WARNING "dasd_generic discipline not found for %s\n", - cdev->dev.bus_id); + dev_name(&cdev->dev)); rc = -ENODEV; dasd_set_target_state(device, DASD_STATE_NEW); if (device->block) @@ -2267,7 +2267,7 @@ int dasd_generic_set_online(struct ccw_device *cdev, dasd_delete_device(device); } else pr_debug("dasd_generic device %s found\n", - cdev->dev.bus_id); + dev_name(&cdev->dev)); /* FIXME: we have to wait for the root device but we don't want * to wait for each single device but for all at once. */ diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 5c6e6f331cb0691e097f55321eb5fe37007adbb3..b8f9c00633f3adfb6885daedbb04031c1b925877 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -1397,7 +1397,7 @@ static struct dasd_ccw_req *dasd_3990_erp_inspect_alias( DEV_MESSAGE(KERN_ERR, cqr->startdev, "ERP on alias device for request %p," " recover on base device %s", cqr, - cqr->block->base->cdev->dev.bus_id); + dev_name(&cqr->block->base->cdev->dev)); } dasd_eckd_reset_ccw_to_base_io(cqr); erp->startdev = cqr->block->base; diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index cd3335c1c307e1b642c87fbb0873c76a8fdac820..921443b01d163165bcf20b50e81d9baceb785f34 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -515,9 +515,9 @@ dasd_devmap_from_cdev(struct ccw_device *cdev) { struct dasd_devmap *devmap; - devmap = dasd_find_busid(cdev->dev.bus_id); + devmap = dasd_find_busid(dev_name(&cdev->dev)); if (IS_ERR(devmap)) - devmap = dasd_add_busid(cdev->dev.bus_id, + devmap = dasd_add_busid(dev_name(&cdev->dev), DASD_FEATURE_DEFAULT); return devmap; } @@ -584,7 +584,7 @@ dasd_delete_device(struct dasd_device *device) unsigned long flags; /* First remove device pointer from devmap. */ - devmap = dasd_find_busid(device->cdev->dev.bus_id); + devmap = dasd_find_busid(dev_name(&device->cdev->dev)); BUG_ON(IS_ERR(devmap)); spin_lock(&dasd_devmap_lock); if (devmap->device != device) { @@ -674,7 +674,7 @@ dasd_ro_show(struct device *dev, struct device_attribute *attr, char *buf) struct dasd_devmap *devmap; int ro_flag; - devmap = dasd_find_busid(dev->bus_id); + devmap = dasd_find_busid(dev_name(dev)); if (!IS_ERR(devmap)) ro_flag = (devmap->features & DASD_FEATURE_READONLY) != 0; else @@ -723,7 +723,7 @@ dasd_erplog_show(struct device *dev, struct device_attribute *attr, char *buf) struct dasd_devmap *devmap; int erplog; - devmap = dasd_find_busid(dev->bus_id); + devmap = dasd_find_busid(dev_name(dev)); if (!IS_ERR(devmap)) erplog = (devmap->features & DASD_FEATURE_ERPLOG) != 0; else @@ -770,7 +770,7 @@ dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf) struct dasd_devmap *devmap; int use_diag; - devmap = dasd_find_busid(dev->bus_id); + devmap = dasd_find_busid(dev_name(dev)); if (!IS_ERR(devmap)) use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0; else @@ -876,7 +876,7 @@ dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf) struct dasd_devmap *devmap; int alias; - devmap = dasd_find_busid(dev->bus_id); + devmap = dasd_find_busid(dev_name(dev)); spin_lock(&dasd_devmap_lock); if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) { spin_unlock(&dasd_devmap_lock); @@ -899,7 +899,7 @@ dasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) struct dasd_devmap *devmap; char *vendor; - devmap = dasd_find_busid(dev->bus_id); + devmap = dasd_find_busid(dev_name(dev)); spin_lock(&dasd_devmap_lock); if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0) vendor = devmap->uid.vendor; @@ -924,7 +924,7 @@ dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) char ua_string[3]; struct dasd_uid *uid; - devmap = dasd_find_busid(dev->bus_id); + devmap = dasd_find_busid(dev_name(dev)); spin_lock(&dasd_devmap_lock); if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) { spin_unlock(&dasd_devmap_lock); @@ -972,7 +972,7 @@ dasd_eer_show(struct device *dev, struct device_attribute *attr, char *buf) struct dasd_devmap *devmap; int eer_flag; - devmap = dasd_find_busid(dev->bus_id); + devmap = dasd_find_busid(dev_name(dev)); if (!IS_ERR(devmap) && devmap->device) eer_flag = dasd_eer_enabled(devmap->device); else @@ -1034,7 +1034,7 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid) { struct dasd_devmap *devmap; - devmap = dasd_find_busid(cdev->dev.bus_id); + devmap = dasd_find_busid(dev_name(&cdev->dev)); if (IS_ERR(devmap)) return PTR_ERR(devmap); spin_lock(&dasd_devmap_lock); @@ -1057,7 +1057,7 @@ dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) { struct dasd_devmap *devmap; - devmap = dasd_find_busid(cdev->dev.bus_id); + devmap = dasd_find_busid(dev_name(&cdev->dev)); if (IS_ERR(devmap)) return PTR_ERR(devmap); @@ -1077,7 +1077,7 @@ dasd_get_feature(struct ccw_device *cdev, int feature) { struct dasd_devmap *devmap; - devmap = dasd_find_busid(cdev->dev.bus_id); + devmap = dasd_find_busid(dev_name(&cdev->dev)); if (IS_ERR(devmap)) return PTR_ERR(devmap); @@ -1093,7 +1093,7 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag) { struct dasd_devmap *devmap; - devmap = dasd_find_busid(cdev->dev.bus_id); + devmap = dasd_find_busid(dev_name(&cdev->dev)); if (IS_ERR(devmap)) return PTR_ERR(devmap); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 773b3fe275b239b08968c6a7e72e1356bf06674e..49f9d221e23d4de9dd0deda5867565d29330f3a7 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -6,6 +6,8 @@ * Martin Schwidefsky <schwidefsky@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 + * EMC Symmetrix ioctl Copyright EMC Corporation, 2008 + * Author.........: Nigel Hislop <hislop_nigel@emc.com> * */ @@ -84,7 +86,7 @@ dasd_eckd_probe (struct ccw_device *cdev) if (ret) { printk(KERN_WARNING "dasd_eckd_probe: could not set ccw-device options " - "for %s\n", cdev->dev.bus_id); + "for %s\n", dev_name(&cdev->dev)); return ret; } ret = dasd_generic_probe(cdev, &dasd_eckd_discipline); @@ -1501,12 +1503,27 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, return; } - /* just report other unsolicited interrupts */ - DEV_MESSAGE(KERN_DEBUG, device, "%s", - "unsolicited interrupt received"); - device->discipline->dump_sense(device, NULL, irb); - dasd_schedule_device_bh(device); + if ((irb->scsw.cmd.cc == 1) && + (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) && + (irb->scsw.cmd.actl & SCSW_ACTL_START_PEND) && + (irb->scsw.cmd.stctl & SCSW_STCTL_STATUS_PEND)) { + /* fake irb do nothing, they are handled elsewhere */ + dasd_schedule_device_bh(device); + return; + } + + if (!(irb->esw.esw0.erw.cons)) { + /* just report other unsolicited interrupts */ + DEV_MESSAGE(KERN_ERR, device, "%s", + "unsolicited interrupt received"); + } else { + DEV_MESSAGE(KERN_ERR, device, "%s", + "unsolicited interrupt received " + "(sense available)"); + device->discipline->dump_sense(device, NULL, irb); + } + dasd_schedule_device_bh(device); return; }; @@ -2068,6 +2085,103 @@ dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp) return 0; } +/* + * Issue syscall I/O to EMC Symmetrix array. + * CCWs are PSF and RSSD + */ +static int dasd_symm_io(struct dasd_device *device, void __user *argp) +{ + struct dasd_symmio_parms usrparm; + char *psf_data, *rssd_result; + struct dasd_ccw_req *cqr; + struct ccw1 *ccw; + int rc; + + /* Copy parms from caller */ + rc = -EFAULT; + if (copy_from_user(&usrparm, argp, sizeof(usrparm))) + goto out; +#ifndef CONFIG_64BIT + /* Make sure pointers are sane even on 31 bit. */ + if ((usrparm.psf_data >> 32) != 0 || (usrparm.rssd_result >> 32) != 0) { + rc = -EINVAL; + goto out; + } +#endif + /* alloc I/O data area */ + psf_data = kzalloc(usrparm.psf_data_len, GFP_KERNEL | GFP_DMA); + rssd_result = kzalloc(usrparm.rssd_result_len, GFP_KERNEL | GFP_DMA); + if (!psf_data || !rssd_result) { + rc = -ENOMEM; + goto out_free; + } + + /* get syscall header from user space */ + rc = -EFAULT; + if (copy_from_user(psf_data, + (void __user *)(unsigned long) usrparm.psf_data, + usrparm.psf_data_len)) + goto out_free; + + /* sanity check on syscall header */ + if (psf_data[0] != 0x17 && psf_data[1] != 0xce) { + rc = -EINVAL; + goto out_free; + } + + /* setup CCWs for PSF + RSSD */ + cqr = dasd_smalloc_request("ECKD", 2 , 0, device); + if (IS_ERR(cqr)) { + DEV_MESSAGE(KERN_WARNING, device, "%s", + "Could not allocate initialization request"); + rc = PTR_ERR(cqr); + goto out_free; + } + + cqr->startdev = device; + cqr->memdev = device; + cqr->retries = 3; + cqr->expires = 10 * HZ; + cqr->buildclk = get_clock(); + cqr->status = DASD_CQR_FILLED; + + /* Build the ccws */ + ccw = cqr->cpaddr; + + /* PSF ccw */ + ccw->cmd_code = DASD_ECKD_CCW_PSF; + ccw->count = usrparm.psf_data_len; + ccw->flags |= CCW_FLAG_CC; + ccw->cda = (__u32)(addr_t) psf_data; + + ccw++; + + /* RSSD ccw */ + ccw->cmd_code = DASD_ECKD_CCW_RSSD; + ccw->count = usrparm.rssd_result_len; + ccw->flags = CCW_FLAG_SLI ; + ccw->cda = (__u32)(addr_t) rssd_result; + + rc = dasd_sleep_on(cqr); + if (rc) + goto out_sfree; + + rc = -EFAULT; + if (copy_to_user((void __user *)(unsigned long) usrparm.rssd_result, + rssd_result, usrparm.rssd_result_len)) + goto out_sfree; + rc = 0; + +out_sfree: + dasd_sfree_request(cqr, cqr->memdev); +out_free: + kfree(rssd_result); + kfree(psf_data); +out: + DBF_DEV_EVENT(DBF_WARNING, device, "Symmetrix ioctl: rc=%d", rc); + return rc; +} + static int dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp) { @@ -2086,6 +2200,8 @@ dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp) return dasd_eckd_reserve(device); case BIODASDSLCK: return dasd_eckd_steal_lock(device); + case BIODASDSYMMIO: + return dasd_symm_io(device, argp); default: return -ENOIOCTLCMD; } @@ -2145,13 +2261,13 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, /* dump the sense data */ len = sprintf(page, KERN_ERR PRINTK_HEADER " I/O status report for device %s:\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " in req: %p CS: 0x%02X DS: 0x%02X\n", req, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " device %s: Failing CCW: %p\n", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), (void *) (addr_t) irb->scsw.cmd.cpa); if (irb->esw.esw0.erw.cons) { for (sl = 0; sl < 4; sl++) { diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index bf512ac75b9e640f058cf1d1b8ddbd2d9490134a..892e2878d61b94a41ad036a750077a43c158db10 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -309,7 +309,8 @@ static void dasd_eer_write_standard_trigger(struct dasd_device *device, do_gettimeofday(&tv); header.tv_sec = tv.tv_sec; header.tv_usec = tv.tv_usec; - strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE); + strncpy(header.busid, dev_name(&device->cdev->dev), + DASD_EER_BUSID_SIZE); spin_lock_irqsave(&bufferlock, flags); list_for_each_entry(eerb, &bufferlist, list) { @@ -349,7 +350,8 @@ static void dasd_eer_write_snss_trigger(struct dasd_device *device, do_gettimeofday(&tv); header.tv_sec = tv.tv_sec; header.tv_usec = tv.tv_usec; - strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE); + strncpy(header.busid, dev_name(&device->cdev->dev), + DASD_EER_BUSID_SIZE); spin_lock_irqsave(&bufferlock, flags); list_for_each_entry(eerb, &bufferlist, list) { diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index aa0c533423a5f040d96e9d5c6f275787a7a9f21c..93d9b6452a94b5fb2e6606ed9efe92fffce72888 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -451,13 +451,13 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, } len = sprintf(page, KERN_ERR PRINTK_HEADER " I/O status report for device %s:\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " in req: %p CS: 0x%02X DS: 0x%02X\n", req, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " device %s: Failing CCW: %p\n", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), (void *) (addr_t) irb->scsw.cmd.cpa); if (irb->esw.esw0.erw.cons) { for (sl = 0; sl < 4; sl++) { diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 31ecaa4a40e42498661397e7459dad2dd75897f5..489d5fe488fb7d60616caebf36e78360ec4cfdd8 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -126,7 +126,7 @@ do { \ #define DEV_MESSAGE(d_loglevel,d_device,d_string,d_args...)\ do { \ printk(d_loglevel PRINTK_HEADER " %s: " d_string "\n", \ - d_device->cdev->dev.bus_id, d_args); \ + dev_name(&d_device->cdev->dev), d_args); \ DBF_DEV_EVENT(DBF_ALERT, d_device, d_string, d_args); \ } while(0) @@ -140,7 +140,7 @@ do { \ #define DEV_MESSAGE_LOG(d_loglevel,d_device,d_string,d_args...)\ do { \ printk(d_loglevel PRINTK_HEADER " %s: " d_string "\n", \ - d_device->cdev->dev.bus_id, d_args); \ + dev_name(&d_device->cdev->dev), d_args); \ } while(0) #define MESSAGE_LOG(d_loglevel,d_string,d_args...)\ diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index e3b5c4d3036e693ec0f5b7601bbf681c06f9aaea..9088de84b45de867fd845478ac97b3b5c18bf543 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -67,7 +67,7 @@ dasd_devices_show(struct seq_file *m, void *v) return 0; } /* Print device number. */ - seq_printf(m, "%s", device->cdev->dev.bus_id); + seq_printf(m, "%s", dev_name(&device->cdev->dev)); /* Print discipline string. */ if (device != NULL && device->discipline != NULL) seq_printf(m, "(%s)", device->discipline->name); diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 9481e4a3f76ee39cdf2aa9a0f543a831792b6cbd..a7ff167d5b81089c781a3f3c9aa9e736cc8da48e 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -31,7 +31,6 @@ #define PRINT_WARN(x...) printk(KERN_WARNING DCSSBLK_NAME " warning: " x) #define PRINT_ERR(x...) printk(KERN_ERR DCSSBLK_NAME " error: " x) - static int dcssblk_open(struct inode *inode, struct file *filp); static int dcssblk_release(struct inode *inode, struct file *filp); static int dcssblk_make_request(struct request_queue *q, struct bio *bio); @@ -48,6 +47,30 @@ static struct block_device_operations dcssblk_devops = { .direct_access = dcssblk_direct_access, }; +struct dcssblk_dev_info { + struct list_head lh; + struct device dev; + char segment_name[BUS_ID_SIZE]; + atomic_t use_count; + struct gendisk *gd; + unsigned long start; + unsigned long end; + int segment_type; + unsigned char save_pending; + unsigned char is_shared; + struct request_queue *dcssblk_queue; + int num_of_segments; + struct list_head seg_list; +}; + +struct segment_info { + struct list_head lh; + char segment_name[BUS_ID_SIZE]; + unsigned long start; + unsigned long end; + int segment_type; +}; + static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count); static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf, @@ -58,30 +81,20 @@ static ssize_t dcssblk_save_show(struct device *dev, struct device_attribute *at static ssize_t dcssblk_shared_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count); static ssize_t dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t dcssblk_seglist_show(struct device *dev, + struct device_attribute *attr, + char *buf); static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store); static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store); -static DEVICE_ATTR(save, S_IWUSR | S_IRUGO, dcssblk_save_show, +static DEVICE_ATTR(save, S_IWUSR | S_IRUSR, dcssblk_save_show, dcssblk_save_store); -static DEVICE_ATTR(shared, S_IWUSR | S_IRUGO, dcssblk_shared_show, +static DEVICE_ATTR(shared, S_IWUSR | S_IRUSR, dcssblk_shared_show, dcssblk_shared_store); +static DEVICE_ATTR(seglist, S_IRUSR, dcssblk_seglist_show, NULL); static struct device *dcssblk_root_dev; -struct dcssblk_dev_info { - struct list_head lh; - struct device dev; - char segment_name[BUS_ID_SIZE]; - atomic_t use_count; - struct gendisk *gd; - unsigned long start; - unsigned long end; - int segment_type; - unsigned char save_pending; - unsigned char is_shared; - struct request_queue *dcssblk_queue; -}; - static LIST_HEAD(dcssblk_devices); static struct rw_semaphore dcssblk_devices_sem; @@ -91,8 +104,15 @@ static struct rw_semaphore dcssblk_devices_sem; static void dcssblk_release_segment(struct device *dev) { - PRINT_DEBUG("segment release fn called for %s\n", dev->bus_id); - kfree(container_of(dev, struct dcssblk_dev_info, dev)); + struct dcssblk_dev_info *dev_info; + struct segment_info *entry, *temp; + + dev_info = container_of(dev, struct dcssblk_dev_info, dev); + list_for_each_entry_safe(entry, temp, &dev_info->seg_list, lh) { + list_del(&entry->lh); + kfree(entry); + } + kfree(dev_info); module_put(THIS_MODULE); } @@ -142,6 +162,169 @@ dcssblk_get_device_by_name(char *name) return NULL; } +/* + * get the struct segment_info from seg_list + * for the given name. + * down_read(&dcssblk_devices_sem) must be held. + */ +static struct segment_info * +dcssblk_get_segment_by_name(char *name) +{ + struct dcssblk_dev_info *dev_info; + struct segment_info *entry; + + list_for_each_entry(dev_info, &dcssblk_devices, lh) { + list_for_each_entry(entry, &dev_info->seg_list, lh) { + if (!strcmp(name, entry->segment_name)) + return entry; + } + } + return NULL; +} + +/* + * get the highest address of the multi-segment block. + */ +static unsigned long +dcssblk_find_highest_addr(struct dcssblk_dev_info *dev_info) +{ + unsigned long highest_addr; + struct segment_info *entry; + + highest_addr = 0; + list_for_each_entry(entry, &dev_info->seg_list, lh) { + if (highest_addr < entry->end) + highest_addr = entry->end; + } + return highest_addr; +} + +/* + * get the lowest address of the multi-segment block. + */ +static unsigned long +dcssblk_find_lowest_addr(struct dcssblk_dev_info *dev_info) +{ + int set_first; + unsigned long lowest_addr; + struct segment_info *entry; + + set_first = 0; + lowest_addr = 0; + list_for_each_entry(entry, &dev_info->seg_list, lh) { + if (set_first == 0) { + lowest_addr = entry->start; + set_first = 1; + } else { + if (lowest_addr > entry->start) + lowest_addr = entry->start; + } + } + return lowest_addr; +} + +/* + * Check continuity of segments. + */ +static int +dcssblk_is_continuous(struct dcssblk_dev_info *dev_info) +{ + int i, j, rc; + struct segment_info *sort_list, *entry, temp; + + if (dev_info->num_of_segments <= 1) + return 0; + + sort_list = kzalloc( + sizeof(struct segment_info) * dev_info->num_of_segments, + GFP_KERNEL); + if (sort_list == NULL) + return -ENOMEM; + i = 0; + list_for_each_entry(entry, &dev_info->seg_list, lh) { + memcpy(&sort_list[i], entry, sizeof(struct segment_info)); + i++; + } + + /* sort segments */ + for (i = 0; i < dev_info->num_of_segments; i++) + for (j = 0; j < dev_info->num_of_segments; j++) + if (sort_list[j].start > sort_list[i].start) { + memcpy(&temp, &sort_list[i], + sizeof(struct segment_info)); + memcpy(&sort_list[i], &sort_list[j], + sizeof(struct segment_info)); + memcpy(&sort_list[j], &temp, + sizeof(struct segment_info)); + } + + /* check continuity */ + for (i = 0; i < dev_info->num_of_segments - 1; i++) { + if ((sort_list[i].end + 1) != sort_list[i+1].start) { + PRINT_ERR("Segment %s is not contiguous with " + "segment %s\n", + sort_list[i].segment_name, + sort_list[i+1].segment_name); + rc = -EINVAL; + goto out; + } + /* EN and EW are allowed in a block device */ + if (sort_list[i].segment_type != sort_list[i+1].segment_type) { + if (!(sort_list[i].segment_type & SEGMENT_EXCLUSIVE) || + (sort_list[i].segment_type == SEG_TYPE_ER) || + !(sort_list[i+1].segment_type & + SEGMENT_EXCLUSIVE) || + (sort_list[i+1].segment_type == SEG_TYPE_ER)) { + PRINT_ERR("Segment %s has different type from " + "segment %s\n", + sort_list[i].segment_name, + sort_list[i+1].segment_name); + rc = -EINVAL; + goto out; + } + } + } + rc = 0; +out: + kfree(sort_list); + return rc; +} + +/* + * Load a segment + */ +static int +dcssblk_load_segment(char *name, struct segment_info **seg_info) +{ + int rc; + + /* already loaded? */ + down_read(&dcssblk_devices_sem); + *seg_info = dcssblk_get_segment_by_name(name); + up_read(&dcssblk_devices_sem); + if (*seg_info != NULL) + return -EEXIST; + + /* get a struct segment_info */ + *seg_info = kzalloc(sizeof(struct segment_info), GFP_KERNEL); + if (*seg_info == NULL) + return -ENOMEM; + + strcpy((*seg_info)->segment_name, name); + + /* load the segment */ + rc = segment_load(name, SEGMENT_SHARED, + &(*seg_info)->start, &(*seg_info)->end); + if (rc < 0) { + segment_warning(rc, (*seg_info)->segment_name); + kfree(*seg_info); + } else { + INIT_LIST_HEAD(&(*seg_info)->lh); + (*seg_info)->segment_type = rc; + } + return rc; +} + static void dcssblk_unregister_callback(struct device *dev) { device_unregister(dev); @@ -165,6 +348,7 @@ static ssize_t dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count) { struct dcssblk_dev_info *dev_info; + struct segment_info *entry, *temp; int rc; if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) @@ -172,46 +356,46 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch down_write(&dcssblk_devices_sem); dev_info = container_of(dev, struct dcssblk_dev_info, dev); if (atomic_read(&dev_info->use_count)) { - PRINT_ERR("share: segment %s is busy!\n", - dev_info->segment_name); rc = -EBUSY; goto out; } if (inbuf[0] == '1') { - // reload segment in shared mode - rc = segment_modify_shared(dev_info->segment_name, - SEGMENT_SHARED); - if (rc < 0) { - BUG_ON(rc == -EINVAL); - if (rc != -EAGAIN) - goto removeseg; - } else { - dev_info->is_shared = 1; - switch (dev_info->segment_type) { - case SEG_TYPE_SR: - case SEG_TYPE_ER: - case SEG_TYPE_SC: - set_disk_ro(dev_info->gd,1); + /* reload segments in shared mode */ + list_for_each_entry(entry, &dev_info->seg_list, lh) { + rc = segment_modify_shared(entry->segment_name, + SEGMENT_SHARED); + if (rc < 0) { + BUG_ON(rc == -EINVAL); + if (rc != -EAGAIN) + goto removeseg; } } + dev_info->is_shared = 1; + switch (dev_info->segment_type) { + case SEG_TYPE_SR: + case SEG_TYPE_ER: + case SEG_TYPE_SC: + set_disk_ro(dev_info->gd, 1); + } } else if (inbuf[0] == '0') { - // reload segment in exclusive mode + /* reload segments in exclusive mode */ if (dev_info->segment_type == SEG_TYPE_SC) { PRINT_ERR("Segment type SC (%s) cannot be loaded in " - "non-shared mode\n", dev_info->segment_name); + "non-shared mode\n", dev_info->segment_name); rc = -EINVAL; goto out; } - rc = segment_modify_shared(dev_info->segment_name, - SEGMENT_EXCLUSIVE); - if (rc < 0) { - BUG_ON(rc == -EINVAL); - if (rc != -EAGAIN) - goto removeseg; - } else { - dev_info->is_shared = 0; - set_disk_ro(dev_info->gd, 0); + list_for_each_entry(entry, &dev_info->seg_list, lh) { + rc = segment_modify_shared(entry->segment_name, + SEGMENT_EXCLUSIVE); + if (rc < 0) { + BUG_ON(rc == -EINVAL); + if (rc != -EAGAIN) + goto removeseg; + } } + dev_info->is_shared = 0; + set_disk_ro(dev_info->gd, 0); } else { rc = -EINVAL; goto out; @@ -220,8 +404,14 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch goto out; removeseg: - PRINT_ERR("Could not reload segment %s, removing it now!\n", - dev_info->segment_name); + PRINT_ERR("Could not reload segment(s) of the device %s, removing " + "segment(s) now!\n", + dev_info->segment_name); + temp = entry; + list_for_each_entry(entry, &dev_info->seg_list, lh) { + if (entry != temp) + segment_unload(entry->segment_name); + } list_del(&dev_info->lh); del_gendisk(dev_info->gd); @@ -254,6 +444,7 @@ static ssize_t dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count) { struct dcssblk_dev_info *dev_info; + struct segment_info *entry; if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) return -EINVAL; @@ -263,14 +454,16 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char if (inbuf[0] == '1') { if (atomic_read(&dev_info->use_count) == 0) { // device is idle => we save immediately - PRINT_INFO("Saving segment %s\n", + PRINT_INFO("Saving segment(s) of the device %s\n", dev_info->segment_name); - segment_save(dev_info->segment_name); + list_for_each_entry(entry, &dev_info->seg_list, lh) { + segment_save(entry->segment_name); + } } else { // device is busy => we save it when it becomes // idle in dcssblk_release - PRINT_INFO("Segment %s is currently busy, it will " - "be saved when it becomes idle...\n", + PRINT_INFO("Device %s is currently busy, segment(s) " + "will be saved when it becomes idle...\n", dev_info->segment_name); dev_info->save_pending = 1; } @@ -279,7 +472,8 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char // device is busy & the user wants to undo his save // request dev_info->save_pending = 0; - PRINT_INFO("Pending save for segment %s deactivated\n", + PRINT_INFO("Pending save for segment(s) of the device " + "%s deactivated\n", dev_info->segment_name); } } else { @@ -290,67 +484,124 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char return count; } +/* + * device attribute for showing all segments in a device + */ +static ssize_t +dcssblk_seglist_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int i; + + struct dcssblk_dev_info *dev_info; + struct segment_info *entry; + + down_read(&dcssblk_devices_sem); + dev_info = container_of(dev, struct dcssblk_dev_info, dev); + i = 0; + buf[0] = '\0'; + list_for_each_entry(entry, &dev_info->seg_list, lh) { + strcpy(&buf[i], entry->segment_name); + i += strlen(entry->segment_name); + buf[i] = '\n'; + i++; + } + up_read(&dcssblk_devices_sem); + return i; +} + /* * device attribute for adding devices */ static ssize_t dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int rc, i; + int rc, i, j, num_of_segments; struct dcssblk_dev_info *dev_info; + struct segment_info *seg_info, *temp; char *local_buf; unsigned long seg_byte_size; dev_info = NULL; + seg_info = NULL; if (dev != dcssblk_root_dev) { rc = -EINVAL; goto out_nobuf; } + if ((count < 1) || (buf[0] == '\0') || (buf[0] == '\n')) { + rc = -ENAMETOOLONG; + goto out_nobuf; + } + local_buf = kmalloc(count + 1, GFP_KERNEL); if (local_buf == NULL) { rc = -ENOMEM; goto out_nobuf; } + /* * parse input */ + num_of_segments = 0; for (i = 0; ((buf[i] != '\0') && (buf[i] != '\n') && i < count); i++) { - local_buf[i] = toupper(buf[i]); + for (j = i; (buf[j] != ':') && + (buf[j] != '\0') && + (buf[j] != '\n') && + j < count; j++) { + local_buf[j-i] = toupper(buf[j]); + } + local_buf[j-i] = '\0'; + if (((j - i) == 0) || ((j - i) > 8)) { + rc = -ENAMETOOLONG; + goto seg_list_del; + } + + rc = dcssblk_load_segment(local_buf, &seg_info); + if (rc < 0) + goto seg_list_del; + /* + * get a struct dcssblk_dev_info + */ + if (num_of_segments == 0) { + dev_info = kzalloc(sizeof(struct dcssblk_dev_info), + GFP_KERNEL); + if (dev_info == NULL) { + rc = -ENOMEM; + goto out; + } + strcpy(dev_info->segment_name, local_buf); + dev_info->segment_type = seg_info->segment_type; + INIT_LIST_HEAD(&dev_info->seg_list); + } + list_add_tail(&seg_info->lh, &dev_info->seg_list); + num_of_segments++; + i = j; + + if ((buf[j] == '\0') || (buf[j] == '\n')) + break; } - local_buf[i] = '\0'; - if ((i == 0) || (i > 8)) { + + /* no trailing colon at the end of the input */ + if ((i > 0) && (buf[i-1] == ':')) { rc = -ENAMETOOLONG; - goto out; - } - /* - * already loaded? - */ - down_read(&dcssblk_devices_sem); - dev_info = dcssblk_get_device_by_name(local_buf); - up_read(&dcssblk_devices_sem); - if (dev_info != NULL) { - PRINT_WARN("Segment %s already loaded!\n", local_buf); - rc = -EEXIST; - goto out; - } - /* - * get a struct dcssblk_dev_info - */ - dev_info = kzalloc(sizeof(struct dcssblk_dev_info), GFP_KERNEL); - if (dev_info == NULL) { - rc = -ENOMEM; - goto out; + goto seg_list_del; } + strlcpy(local_buf, buf, i + 1); + dev_info->num_of_segments = num_of_segments; + rc = dcssblk_is_continuous(dev_info); + if (rc < 0) + goto seg_list_del; + + dev_info->start = dcssblk_find_lowest_addr(dev_info); + dev_info->end = dcssblk_find_highest_addr(dev_info); - strcpy(dev_info->segment_name, local_buf); - strlcpy(dev_info->dev.bus_id, local_buf, BUS_ID_SIZE); + dev_set_name(&dev_info->dev, dev_info->segment_name); dev_info->dev.release = dcssblk_release_segment; INIT_LIST_HEAD(&dev_info->lh); - dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK); if (dev_info->gd == NULL) { rc = -ENOMEM; - goto free_dev_info; + goto seg_list_del; } dev_info->gd->major = dcssblk_major; dev_info->gd->fops = &dcssblk_devops; @@ -360,65 +611,52 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char dev_info->gd->driverfs_dev = &dev_info->dev; blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096); - /* - * load the segment - */ - rc = segment_load(local_buf, SEGMENT_SHARED, - &dev_info->start, &dev_info->end); - if (rc < 0) { - segment_warning(rc, dev_info->segment_name); - goto dealloc_gendisk; - } + seg_byte_size = (dev_info->end - dev_info->start + 1); set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors - PRINT_INFO("Loaded segment %s, size = %lu Byte, " + PRINT_INFO("Loaded segment(s) %s, size = %lu Byte, " "capacity = %lu (512 Byte) sectors\n", local_buf, seg_byte_size, seg_byte_size >> 9); - dev_info->segment_type = rc; dev_info->save_pending = 0; dev_info->is_shared = 1; dev_info->dev.parent = dcssblk_root_dev; /* - * get minor, add to list + *get minor, add to list */ down_write(&dcssblk_devices_sem); - if (dcssblk_get_device_by_name(local_buf)) { - up_write(&dcssblk_devices_sem); + if (dcssblk_get_segment_by_name(local_buf)) { rc = -EEXIST; - goto unload_seg; + goto release_gd; } rc = dcssblk_assign_free_minor(dev_info); - if (rc) { - up_write(&dcssblk_devices_sem); - PRINT_ERR("No free minor number available! " - "Unloading segment...\n"); - goto unload_seg; - } + if (rc) + goto release_gd; sprintf(dev_info->gd->disk_name, "dcssblk%d", MINOR(disk_devt(dev_info->gd))); list_add_tail(&dev_info->lh, &dcssblk_devices); if (!try_module_get(THIS_MODULE)) { rc = -ENODEV; - goto list_del; + goto dev_list_del; } /* * register the device */ rc = device_register(&dev_info->dev); if (rc) { - PRINT_ERR("Segment %s could not be registered RC=%d\n", - local_buf, rc); module_put(THIS_MODULE); - goto list_del; + goto dev_list_del; } get_device(&dev_info->dev); rc = device_create_file(&dev_info->dev, &dev_attr_shared); if (rc) goto unregister_dev; rc = device_create_file(&dev_info->dev, &dev_attr_save); + if (rc) + goto unregister_dev; + rc = device_create_file(&dev_info->dev, &dev_attr_seglist); if (rc) goto unregister_dev; @@ -434,7 +672,6 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char set_disk_ro(dev_info->gd,0); break; } - PRINT_DEBUG("Segment %s loaded successfully\n", local_buf); up_write(&dcssblk_devices_sem); rc = count; goto out; @@ -445,20 +682,27 @@ unregister_dev: dev_info->gd->queue = NULL; put_disk(dev_info->gd); device_unregister(&dev_info->dev); - segment_unload(dev_info->segment_name); + list_for_each_entry(seg_info, &dev_info->seg_list, lh) { + segment_unload(seg_info->segment_name); + } put_device(&dev_info->dev); up_write(&dcssblk_devices_sem); goto out; -list_del: +dev_list_del: list_del(&dev_info->lh); - up_write(&dcssblk_devices_sem); -unload_seg: - segment_unload(local_buf); -dealloc_gendisk: +release_gd: blk_cleanup_queue(dev_info->dcssblk_queue); dev_info->gd->queue = NULL; put_disk(dev_info->gd); -free_dev_info: + up_write(&dcssblk_devices_sem); +seg_list_del: + if (dev_info == NULL) + goto out; + list_for_each_entry_safe(seg_info, temp, &dev_info->seg_list, lh) { + list_del(&seg_info->lh); + segment_unload(seg_info->segment_name); + kfree(seg_info); + } kfree(dev_info); out: kfree(local_buf); @@ -473,6 +717,7 @@ static ssize_t dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct dcssblk_dev_info *dev_info; + struct segment_info *entry; int rc, i; char *local_buf; @@ -499,26 +744,28 @@ dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const ch dev_info = dcssblk_get_device_by_name(local_buf); if (dev_info == NULL) { up_write(&dcssblk_devices_sem); - PRINT_WARN("Segment %s is not loaded!\n", local_buf); + PRINT_WARN("Device %s is not loaded!\n", local_buf); rc = -ENODEV; goto out_buf; } if (atomic_read(&dev_info->use_count) != 0) { up_write(&dcssblk_devices_sem); - PRINT_WARN("Segment %s is in use!\n", local_buf); + PRINT_WARN("Device %s is in use!\n", local_buf); rc = -EBUSY; goto out_buf; } - list_del(&dev_info->lh); + list_del(&dev_info->lh); del_gendisk(dev_info->gd); blk_cleanup_queue(dev_info->dcssblk_queue); dev_info->gd->queue = NULL; put_disk(dev_info->gd); device_unregister(&dev_info->dev); - segment_unload(dev_info->segment_name); - PRINT_DEBUG("Segment %s unloaded successfully\n", - dev_info->segment_name); + + /* unload all related segments */ + list_for_each_entry(entry, &dev_info->seg_list, lh) + segment_unload(entry->segment_name); + put_device(&dev_info->dev); up_write(&dcssblk_devices_sem); @@ -550,6 +797,7 @@ static int dcssblk_release(struct inode *inode, struct file *filp) { struct dcssblk_dev_info *dev_info; + struct segment_info *entry; int rc; dev_info = inode->i_bdev->bd_disk->private_data; @@ -560,9 +808,11 @@ dcssblk_release(struct inode *inode, struct file *filp) down_write(&dcssblk_devices_sem); if (atomic_dec_and_test(&dev_info->use_count) && (dev_info->save_pending)) { - PRINT_INFO("Segment %s became idle and is being saved now\n", + PRINT_INFO("Device %s became idle and is being saved now\n", dev_info->segment_name); - segment_save(dev_info->segment_name); + list_for_each_entry(entry, &dev_info->seg_list, lh) { + segment_save(entry->segment_name); + } dev_info->save_pending = 0; } up_write(&dcssblk_devices_sem); @@ -602,7 +852,8 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) case SEG_TYPE_SC: /* cannot write to these segments */ if (bio_data_dir(bio) == WRITE) { - PRINT_WARN("rejecting write to ro segment %s\n", dev_info->dev.bus_id); + PRINT_WARN("rejecting write to ro device %s\n", + dev_name(&dev_info->dev)); goto fail; } } @@ -657,7 +908,7 @@ static void dcssblk_check_params(void) { int rc, i, j, k; - char buf[9]; + char buf[DCSSBLK_PARM_LEN + 1]; struct dcssblk_dev_info *dev_info; for (i = 0; (i < DCSSBLK_PARM_LEN) && (dcssblk_segments[i] != '\0'); @@ -665,15 +916,16 @@ dcssblk_check_params(void) for (j = i; (dcssblk_segments[j] != ',') && (dcssblk_segments[j] != '\0') && (dcssblk_segments[j] != '(') && - (j - i) < 8; j++) + (j < DCSSBLK_PARM_LEN); j++) { buf[j-i] = dcssblk_segments[j]; } buf[j-i] = '\0'; rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i); if ((rc >= 0) && (dcssblk_segments[j] == '(')) { - for (k = 0; buf[k] != '\0'; k++) + for (k = 0; (buf[k] != ':') && (buf[k] != '\0'); k++) buf[k] = toupper(buf[k]); + buf[k] = '\0'; if (!strncmp(&dcssblk_segments[j], "(local)", 7)) { down_read(&dcssblk_devices_sem); dev_info = dcssblk_get_device_by_name(buf); @@ -740,10 +992,12 @@ module_exit(dcssblk_exit); module_param_string(segments, dcssblk_segments, DCSSBLK_PARM_LEN, 0444); MODULE_PARM_DESC(segments, "Name of DCSS segment(s) to be loaded, " - "comma-separated list, each name max. 8 chars.\n" - "Adding \"(local)\" to segment name equals echoing 0 to " - "/sys/devices/dcssblk/<segment name>/shared after loading " - "the segment - \n" - "e.g. segments=\"mydcss1,mydcss2,mydcss3(local)\""); + "comma-separated list, names in each set separated " + "by commas are separated by colons, each set contains " + "names of contiguous segments and each name max. 8 chars.\n" + "Adding \"(local)\" to the end of each set equals echoing 0 " + "to /sys/devices/dcssblk/<device name>/shared after loading " + "the contiguous segments - \n" + "e.g. segments=\"mydcss1,mydcss2:mydcss3,mydcss4(local)\""); MODULE_LICENSE("GPL"); diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index dd9b986389a2bf4a2d38a71a64c01dfe25718ef3..03916989ed2d63ec7a45966353c8350e260640ad 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -56,6 +56,7 @@ typedef struct { static xpram_device_t xpram_devices[XPRAM_MAX_DEVS]; static unsigned int xpram_sizes[XPRAM_MAX_DEVS]; static struct gendisk *xpram_disks[XPRAM_MAX_DEVS]; +static struct request_queue *xpram_queues[XPRAM_MAX_DEVS]; static unsigned int xpram_pages; static int xpram_devs; @@ -330,18 +331,22 @@ static int __init xpram_setup_sizes(unsigned long pages) return 0; } -static struct request_queue *xpram_queue; - static int __init xpram_setup_blkdev(void) { unsigned long offset; int i, rc = -ENOMEM; for (i = 0; i < xpram_devs; i++) { - struct gendisk *disk = alloc_disk(1); - if (!disk) + xpram_disks[i] = alloc_disk(1); + if (!xpram_disks[i]) + goto out; + xpram_queues[i] = blk_alloc_queue(GFP_KERNEL); + if (!xpram_queues[i]) { + put_disk(xpram_disks[i]); goto out; - xpram_disks[i] = disk; + } + blk_queue_make_request(xpram_queues[i], xpram_make_request); + blk_queue_hardsect_size(xpram_queues[i], 4096); } /* @@ -351,18 +356,6 @@ static int __init xpram_setup_blkdev(void) if (rc < 0) goto out; - /* - * Assign the other needed values: make request function, sizes and - * hardsect size. All the minor devices feature the same value. - */ - xpram_queue = blk_alloc_queue(GFP_KERNEL); - if (!xpram_queue) { - rc = -ENOMEM; - goto out_unreg; - } - blk_queue_make_request(xpram_queue, xpram_make_request); - blk_queue_hardsect_size(xpram_queue, 4096); - /* * Setup device structures. */ @@ -377,18 +370,18 @@ static int __init xpram_setup_blkdev(void) disk->first_minor = i; disk->fops = &xpram_devops; disk->private_data = &xpram_devices[i]; - disk->queue = xpram_queue; + disk->queue = xpram_queues[i]; sprintf(disk->disk_name, "slram%d", i); set_capacity(disk, xpram_sizes[i] << 1); add_disk(disk); } return 0; -out_unreg: - unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); out: - while (i--) + while (i--) { + blk_cleanup_queue(xpram_queues[i]); put_disk(xpram_disks[i]); + } return rc; } @@ -400,10 +393,10 @@ static void __exit xpram_exit(void) int i; for (i = 0; i < xpram_devs; i++) { del_gendisk(xpram_disks[i]); + blk_cleanup_queue(xpram_queues[i]); put_disk(xpram_disks[i]); } unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); - blk_cleanup_queue(xpram_queue); } static int __init xpram_init(void) diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index d3ec9b55ab351c665016c0c1fd139a6cf841fa9f..9ab06e0dad408abdc2b5f66b33b559ec8ec23000 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -21,6 +21,7 @@ #include <linux/console.h> #include <linux/interrupt.h> #include <linux/err.h> +#include <linux/reboot.h> #include <linux/slab.h> #include <linux/bootmem.h> @@ -88,7 +89,6 @@ struct raw3215_info { int count; /* number of bytes in output buffer */ int written; /* number of bytes in write requests */ struct tty_struct *tty; /* pointer to tty structure if present */ - struct tasklet_struct tasklet; struct raw3215_req *queued_read; /* pointer to queued read requests */ struct raw3215_req *queued_write;/* pointer to queued write requests */ wait_queue_head_t empty_wait; /* wait queue for flushing */ @@ -341,21 +341,14 @@ raw3215_try_io(struct raw3215_info *raw) } /* - * The bottom half handler routine for 3215 devices. It tries to start - * the next IO and wakes up processes waiting on the tty. + * Try to start the next IO and wake up processes waiting on the tty. */ -static void -raw3215_tasklet(void *data) +static void raw3215_next_io(struct raw3215_info *raw) { - struct raw3215_info *raw; struct tty_struct *tty; - unsigned long flags; - raw = (struct raw3215_info *) data; - spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw3215_mk_write_req(raw); raw3215_try_io(raw); - spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); tty = raw->tty; if (tty != NULL && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) { @@ -380,7 +373,7 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) cstat = irb->scsw.cmd.cstat; dstat = irb->scsw.cmd.dstat; if (cstat != 0) - tasklet_schedule(&raw->tasklet); + raw3215_next_io(raw); if (dstat & 0x01) { /* we got a unit exception */ dstat &= ~0x01; /* we can ignore it */ } @@ -390,7 +383,7 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) break; /* Attention interrupt, someone hit the enter key */ raw3215_mk_read_req(raw); - tasklet_schedule(&raw->tasklet); + raw3215_next_io(raw); break; case 0x08: case 0x0C: @@ -448,7 +441,7 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) raw->queued_read == NULL) { wake_up_interruptible(&raw->empty_wait); } - tasklet_schedule(&raw->tasklet); + raw3215_next_io(raw); break; default: /* Strange interrupt, I'll do my best to clean up */ @@ -460,7 +453,7 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) raw->flags &= ~RAW3215_WORKING; raw3215_free_req(req); } - tasklet_schedule(&raw->tasklet); + raw3215_next_io(raw); } return; } @@ -674,9 +667,6 @@ raw3215_probe (struct ccw_device *cdev) kfree(raw); return -ENOMEM; } - tasklet_init(&raw->tasklet, - (void (*)(unsigned long)) raw3215_tasklet, - (unsigned long) raw); init_waitqueue_head(&raw->empty_wait); cdev->dev.driver_data = raw; @@ -775,11 +765,11 @@ static struct tty_driver *con3215_device(struct console *c, int *index) } /* - * panic() calls console_unblank before the system enters a - * disabled, endless loop. + * panic() calls con3215_flush through a panic_notifier + * before the system enters a disabled, endless loop. */ static void -con3215_unblank(void) +con3215_flush(void) { struct raw3215_info *raw; unsigned long flags; @@ -790,6 +780,23 @@ con3215_unblank(void) spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } +static int con3215_notify(struct notifier_block *self, + unsigned long event, void *data) +{ + con3215_flush(); + return NOTIFY_OK; +} + +static struct notifier_block on_panic_nb = { + .notifier_call = con3215_notify, + .priority = 0, +}; + +static struct notifier_block on_reboot_nb = { + .notifier_call = con3215_notify, + .priority = 0, +}; + /* * The console structure for the 3215 console */ @@ -797,7 +804,6 @@ static struct console con3215 = { .name = "ttyS", .write = con3215_write, .device = con3215_device, - .unblank = con3215_unblank, .flags = CON_PRINTBUFFER, }; @@ -846,9 +852,6 @@ con3215_init(void) cdev->handler = raw3215_irq; raw->flags |= RAW3215_FIXED; - tasklet_init(&raw->tasklet, - (void (*)(unsigned long)) raw3215_tasklet, - (unsigned long) raw); init_waitqueue_head(&raw->empty_wait); /* Request the console irq */ @@ -859,6 +862,8 @@ con3215_init(void) raw3215[0] = NULL; return -ENODEV; } + atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb); + register_reboot_notifier(&on_reboot_nb); register_console(&con3215); return 0; } diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index 3c07974886ed2aa1f8fa23dea19fd7e3b77860c0..d028d2ee83dd36a3dff91061fbfc8d830eca3470 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -15,6 +15,7 @@ #include <linux/list.h> #include <linux/types.h> #include <linux/err.h> +#include <linux/reboot.h> #include <asm/ccwdev.h> #include <asm/cio.h> @@ -528,11 +529,11 @@ con3270_wait_write(struct con3270 *cp) } /* - * panic() calls console_unblank before the system enters a - * disabled, endless loop. + * panic() calls con3270_flush through a panic_notifier + * before the system enters a disabled, endless loop. */ static void -con3270_unblank(void) +con3270_flush(void) { struct con3270 *cp; unsigned long flags; @@ -554,6 +555,23 @@ con3270_unblank(void) spin_unlock_irqrestore(&cp->view.lock, flags); } +static int con3270_notify(struct notifier_block *self, + unsigned long event, void *data) +{ + con3270_flush(); + return NOTIFY_OK; +} + +static struct notifier_block on_panic_nb = { + .notifier_call = con3270_notify, + .priority = 0, +}; + +static struct notifier_block on_reboot_nb = { + .notifier_call = con3270_notify, + .priority = 0, +}; + /* * The console structure for the 3270 console */ @@ -561,7 +579,6 @@ static struct console con3270 = { .name = "tty3270", .write = con3270_write, .device = con3270_device, - .unblank = con3270_unblank, .flags = CON_PRINTBUFFER, }; @@ -623,6 +640,8 @@ con3270_init(void) condev->cline->len = 0; con3270_create_status(condev); condev->input = alloc_string(&condev->freemem, 80); + atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb); + register_reboot_notifier(&on_reboot_nb); register_console(&con3270); return 0; } diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index c3dee900a5c8b84608ef868ab73d4d0df0206cf3..1792b2c0130e2c3948ddab8e4798790a7af7b99c 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -1171,7 +1171,7 @@ static int raw3270_create_attributes(struct raw3270 *rp) rp->clttydev = device_create_drvdata(class3270, &rp->cdev->dev, MKDEV(IBM_TTY3270_MAJOR, rp->minor), NULL, - "tty%s", rp->cdev->dev.bus_id); + "tty%s", dev_name(&rp->cdev->dev)); if (IS_ERR(rp->clttydev)) { rc = PTR_ERR(rp->clttydev); goto out_ttydev; @@ -1180,7 +1180,7 @@ static int raw3270_create_attributes(struct raw3270 *rp) rp->cltubdev = device_create_drvdata(class3270, &rp->cdev->dev, MKDEV(IBM_FS3270_MAJOR, rp->minor), NULL, - "tub%s", rp->cdev->dev.bus_id); + "tub%s", dev_name(&rp->cdev->dev)); if (!IS_ERR(rp->cltubdev)) goto out; diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c index 7e619c534bf46ed7e3078dfcd3a0c44738e427bd..9a25c4bd14210ded21fffa666b53f653febced08 100644 --- a/drivers/s390/char/sclp_con.c +++ b/drivers/s390/char/sclp_con.c @@ -16,6 +16,7 @@ #include <linux/bootmem.h> #include <linux/termios.h> #include <linux/err.h> +#include <linux/reboot.h> #include "sclp.h" #include "sclp_rw.h" @@ -172,7 +173,7 @@ sclp_console_device(struct console *c, int *index) * will be flushed to the SCLP. */ static void -sclp_console_unblank(void) +sclp_console_flush(void) { unsigned long flags; @@ -188,6 +189,24 @@ sclp_console_unblank(void) spin_unlock_irqrestore(&sclp_con_lock, flags); } +static int +sclp_console_notify(struct notifier_block *self, + unsigned long event, void *data) +{ + sclp_console_flush(); + return NOTIFY_OK; +} + +static struct notifier_block on_panic_nb = { + .notifier_call = sclp_console_notify, + .priority = 1, +}; + +static struct notifier_block on_reboot_nb = { + .notifier_call = sclp_console_notify, + .priority = 1, +}; + /* * used to register the SCLP console to the kernel and to * give printk necessary information @@ -197,7 +216,6 @@ static struct console sclp_console = .name = sclp_console_name, .write = sclp_console_write, .device = sclp_console_device, - .unblank = sclp_console_unblank, .flags = CON_PRINTBUFFER, .index = 0 /* ttyS0 */ }; @@ -241,6 +259,8 @@ sclp_console_init(void) sclp_con_width_htab = 8; /* enable printk-access to this driver */ + atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb); + register_reboot_notifier(&on_reboot_nb); register_console(&sclp_console); return 0; } diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index ad51738c4261973a7f4fb8b74296dc5dcc17bb85..9854f19f5e624532a754d7b7654c286d9601f75e 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -24,6 +24,8 @@ #include <linux/bootmem.h> #include <linux/interrupt.h> #include <linux/init.h> +#include <linux/reboot.h> + #include <asm/uaccess.h> #include "sclp.h" @@ -743,24 +745,30 @@ sclp_vt220_con_device(struct console *c, int *index) return sclp_vt220_driver; } -/* - * This routine is called from panic when the kernel is going to give up. - * We have to make sure that all buffers will be flushed to the SCLP. - * Note that this function may be called from within an interrupt context. - */ -static void -sclp_vt220_con_unblank(void) +static int +sclp_vt220_notify(struct notifier_block *self, + unsigned long event, void *data) { __sclp_vt220_flush_buffer(); + return NOTIFY_OK; } +static struct notifier_block on_panic_nb = { + .notifier_call = sclp_vt220_notify, + .priority = 1, +}; + +static struct notifier_block on_reboot_nb = { + .notifier_call = sclp_vt220_notify, + .priority = 1, +}; + /* Structure needed to register with printk */ static struct console sclp_vt220_console = { .name = SCLP_VT220_CONSOLE_NAME, .write = sclp_vt220_con_write, .device = sclp_vt220_con_device, - .unblank = sclp_vt220_con_unblank, .flags = CON_PRINTBUFFER, .index = SCLP_VT220_CONSOLE_INDEX }; @@ -776,6 +784,8 @@ sclp_vt220_con_init(void) if (rc) return rc; /* Attach linux console */ + atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb); + register_reboot_notifier(&on_reboot_nb); register_console(&sclp_vt220_console); return 0; } diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 839987618ffd8d545538626733b4c0ca1205c8ce..4005c44a404c47efbb33d8e177389ca4a0b01a28 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -910,7 +910,7 @@ 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", device->cdev->dev.bus_id); + PRINT_WARN("(%s): Swap Tape Device!\n", dev_name(&device->cdev->dev)); return tape_3590_erp_basic(device, request, irb, -EIO); } @@ -1003,40 +1003,43 @@ tape_3590_print_mim_msg_f0(struct tape_device *device, struct irb *irb) /* Exception Message */ switch (sense->fmt.f70.emc) { case 0x02: - PRINT_WARN("(%s): Data degraded\n", device->cdev->dev.bus_id); + PRINT_WARN("(%s): Data degraded\n", + dev_name(&device->cdev->dev)); break; case 0x03: PRINT_WARN("(%s): Data degraded in partion %i\n", - device->cdev->dev.bus_id, sense->fmt.f70.mp); + dev_name(&device->cdev->dev), sense->fmt.f70.mp); break; case 0x04: - PRINT_WARN("(%s): Medium degraded\n", device->cdev->dev.bus_id); + PRINT_WARN("(%s): Medium degraded\n", + dev_name(&device->cdev->dev)); break; case 0x05: PRINT_WARN("(%s): Medium degraded in partition %i\n", - device->cdev->dev.bus_id, sense->fmt.f70.mp); + dev_name(&device->cdev->dev), sense->fmt.f70.mp); break; case 0x06: - PRINT_WARN("(%s): Block 0 Error\n", device->cdev->dev.bus_id); + PRINT_WARN("(%s): Block 0 Error\n", + dev_name(&device->cdev->dev)); break; case 0x07: PRINT_WARN("(%s): Medium Exception 0x%02x\n", - device->cdev->dev.bus_id, sense->fmt.f70.md); + dev_name(&device->cdev->dev), sense->fmt.f70.md); break; default: PRINT_WARN("(%s): MIM ExMsg: 0x%02x\n", - device->cdev->dev.bus_id, sense->fmt.f70.emc); + dev_name(&device->cdev->dev), sense->fmt.f70.emc); break; } /* Service Message */ switch (sense->fmt.f70.smc) { case 0x02: PRINT_WARN("(%s): Reference Media maintenance procedure %i\n", - device->cdev->dev.bus_id, sense->fmt.f70.md); + dev_name(&device->cdev->dev), sense->fmt.f70.md); break; default: PRINT_WARN("(%s): MIM ServiceMsg: 0x%02x\n", - device->cdev->dev.bus_id, sense->fmt.f70.smc); + dev_name(&device->cdev->dev), sense->fmt.f70.smc); break; } } @@ -1054,101 +1057,101 @@ tape_3590_print_io_sim_msg_f1(struct tape_device *device, struct irb *irb) switch (sense->fmt.f71.emc) { case 0x01: PRINT_WARN("(%s): Effect of failure is unknown\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); break; case 0x02: PRINT_WARN("(%s): CU Exception - no performance impact\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); break; case 0x03: PRINT_WARN("(%s): CU Exception on channel interface 0x%02x\n", - device->cdev->dev.bus_id, sense->fmt.f71.md[0]); + dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); break; case 0x04: PRINT_WARN("(%s): CU Exception on device path 0x%02x\n", - device->cdev->dev.bus_id, sense->fmt.f71.md[0]); + dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); break; case 0x05: PRINT_WARN("(%s): CU Exception on library path 0x%02x\n", - device->cdev->dev.bus_id, sense->fmt.f71.md[0]); + dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); break; case 0x06: PRINT_WARN("(%s): CU Exception on node 0x%02x\n", - device->cdev->dev.bus_id, sense->fmt.f71.md[0]); + dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); break; case 0x07: PRINT_WARN("(%s): CU Exception on partition 0x%02x\n", - device->cdev->dev.bus_id, sense->fmt.f71.md[0]); + dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); break; default: PRINT_WARN("(%s): SIM ExMsg: 0x%02x\n", - device->cdev->dev.bus_id, sense->fmt.f71.emc); + dev_name(&device->cdev->dev), sense->fmt.f71.emc); } /* Service Message */ switch (sense->fmt.f71.smc) { case 0x01: PRINT_WARN("(%s): Repair impact is unknown\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); break; case 0x02: PRINT_WARN("(%s): Repair will not impact cu performance\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); break; case 0x03: if (sense->fmt.f71.mdf == 0) PRINT_WARN("(%s): Repair will disable node " "0x%x on CU\n", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), sense->fmt.f71.md[1]); else PRINT_WARN("(%s): Repair will disable nodes " "(0x%x-0x%x) on CU\n", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), 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", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), sense->fmt.f71.md[1]); else PRINT_WARN("(%s): Repair will disable cannel paths " "(0x%x-0x%x) on CU\n", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), 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", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), sense->fmt.f71.md[1]); else PRINT_WARN("(%s): Repair will disable device paths " "(0x%x-0x%x) on CU\n", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), 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", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), sense->fmt.f71.md[1]); else PRINT_WARN("(%s): Repair will disable library paths " "(0x%x-0x%x) on CU\n", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), sense->fmt.f71.md[1], sense->fmt.f71.md[2]); break; case 0x07: PRINT_WARN("(%s): Repair will disable access to CU\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); break; default: PRINT_WARN("(%s): SIM ServiceMsg: 0x%02x\n", - device->cdev->dev.bus_id, sense->fmt.f71.smc); + dev_name(&device->cdev->dev), sense->fmt.f71.smc); } } @@ -1165,104 +1168,104 @@ tape_3590_print_dev_sim_msg_f2(struct tape_device *device, struct irb *irb) switch (sense->fmt.f71.emc) { case 0x01: PRINT_WARN("(%s): Effect of failure is unknown\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); break; case 0x02: PRINT_WARN("(%s): DV Exception - no performance impact\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); break; case 0x03: PRINT_WARN("(%s): DV Exception on channel interface 0x%02x\n", - device->cdev->dev.bus_id, sense->fmt.f71.md[0]); + dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); break; case 0x04: PRINT_WARN("(%s): DV Exception on loader 0x%02x\n", - device->cdev->dev.bus_id, sense->fmt.f71.md[0]); + dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); break; case 0x05: PRINT_WARN("(%s): DV Exception on message display 0x%02x\n", - device->cdev->dev.bus_id, sense->fmt.f71.md[0]); + dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); break; case 0x06: PRINT_WARN("(%s): DV Exception in tape path\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); break; case 0x07: PRINT_WARN("(%s): DV Exception in drive\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); break; default: PRINT_WARN("(%s): DSIM ExMsg: 0x%02x\n", - device->cdev->dev.bus_id, sense->fmt.f71.emc); + dev_name(&device->cdev->dev), sense->fmt.f71.emc); } /* Service Message */ switch (sense->fmt.f71.smc) { case 0x01: PRINT_WARN("(%s): Repair impact is unknown\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); break; case 0x02: PRINT_WARN("(%s): Repair will not impact device performance\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); break; case 0x03: if (sense->fmt.f71.mdf == 0) PRINT_WARN("(%s): Repair will disable channel path " "0x%x on DV\n", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), sense->fmt.f71.md[1]); else PRINT_WARN("(%s): Repair will disable channel path " "(0x%x-0x%x) on DV\n", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), 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", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), sense->fmt.f71.md[1]); else PRINT_WARN("(%s): Repair will disable interfaces " "(0x%x-0x%x) on DV\n", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), 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", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), sense->fmt.f71.md[1]); else PRINT_WARN("(%s): Repair will disable loader " "(0x%x-0x%x) on DV\n", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), sense->fmt.f71.md[1], sense->fmt.f71.md[2]); break; case 0x07: PRINT_WARN("(%s): Repair will disable access to DV\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); break; case 0x08: if (sense->fmt.f71.mdf == 0) PRINT_WARN("(%s): Repair will disable message " "display 0x%x on DV\n", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), sense->fmt.f71.md[1]); else PRINT_WARN("(%s): Repair will disable message " "displays (0x%x-0x%x) on DV\n", - device->cdev->dev.bus_id, + dev_name(&device->cdev->dev), sense->fmt.f71.md[1], sense->fmt.f71.md[2]); break; case 0x09: - PRINT_WARN("(%s): Clean DV\n", device->cdev->dev.bus_id); + PRINT_WARN("(%s): Clean DV\n", dev_name(&device->cdev->dev)); break; default: PRINT_WARN("(%s): DSIM ServiceMsg: 0x%02x\n", - device->cdev->dev.bus_id, sense->fmt.f71.smc); + dev_name(&device->cdev->dev), sense->fmt.f71.smc); } } @@ -1279,18 +1282,18 @@ 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", device->cdev->dev.bus_id, + PRINT_WARN("(%s): %s\n", dev_name(&device->cdev->dev), tape_3590_msg[sense->mc]); else { PRINT_WARN("(%s): Message Code 0x%x\n", - device->cdev->dev.bus_id, sense->mc); + dev_name(&device->cdev->dev), 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", device->cdev->dev.bus_id, + "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, @@ -1302,7 +1305,7 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb) /* 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", - device->cdev->dev.bus_id, sense->fmt.f71.sev, + 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, @@ -1314,7 +1317,7 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb) /* 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", - device->cdev->dev.bus_id, sense->fmt.f71.sev, + 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, @@ -1327,7 +1330,7 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb) return; } PRINT_WARN("(%s): Device Message(%x)\n", - device->cdev->dev.bus_id, sense->mc); + dev_name(&device->cdev->dev), sense->mc); } static int tape_3590_crypt_error(struct tape_device *device, @@ -1336,10 +1339,11 @@ static int tape_3590_crypt_error(struct tape_device *device, u8 cu_rc, ekm_rc1; u16 ekm_rc2; u32 drv_rc; - char *bus_id, *sense; + const char *bus_id; + char *sense; sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data; - bus_id = device->cdev->dev.bus_id; + bus_id = dev_name(&device->cdev->dev); cu_rc = sense[0]; drv_rc = *((u32*) &sense[5]) & 0xffffff; ekm_rc1 = sense[9]; @@ -1440,7 +1444,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, * "device intervention" is not very meaningfull */ PRINT_WARN("(%s): Tape operation when medium not loaded\n", - device->cdev->dev.bus_id); + 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); @@ -1487,18 +1491,18 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, case 0x6020: PRINT_WARN("(%s): Cartridge of wrong type ?\n", - device->cdev->dev.bus_id); + 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", - device->cdev->dev.bus_id); + 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", device->cdev->dev.bus_id); + "tape device\n", dev_name(&device->cdev->dev)); PRINT_WARN("(%s): To solve the problem unload the current " - "cartridge!\n", device->cdev->dev.bus_id); + "cartridge!\n", dev_name(&device->cdev->dev)); return tape_3590_erp_basic(device, request, irb, -EPERM); default: return tape_3590_erp_basic(device, request, irb, -EIO); diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 95da72bc17e8d7e3b218bfe0c4f46a1a9d306900..a25b8bf54f418103ef4dca4da08dd13e1e9d6513 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -278,7 +278,7 @@ tapeblock_cleanup_device(struct tape_device *device) if (!device->blk_data.disk) { PRINT_ERR("(%s): No gendisk to clean up!\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); goto cleanup_queue; } diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 181a5441af16f92dad8b1c0bba954ca5bbefca51..d7073dbf825c4148a58195ff3a204371b9881547 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -215,12 +215,12 @@ tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate) case MS_UNLOADED: device->tape_generic_status |= GMT_DR_OPEN(~0); PRINT_INFO("(%s): Tape is unloaded\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); break; case MS_LOADED: device->tape_generic_status &= ~GMT_DR_OPEN(~0); PRINT_INFO("(%s): Tape has been mounted\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); break; default: // print nothing @@ -415,7 +415,7 @@ tape_generic_offline(struct tape_device *device) device->cdev_id); PRINT_WARN("(%s): Set offline failed " "- drive in use.\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); spin_unlock_irq(get_ccwdev_lock(device->cdev)); return -EBUSY; } @@ -538,7 +538,8 @@ 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", cdev->dev.bus_id); + PRINT_ERR("probe failed for tape device %s\n", + dev_name(&cdev->dev)); return ret; } cdev->dev.driver_data = device; @@ -546,7 +547,7 @@ 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", cdev->dev.bus_id); + PRINT_INFO("tape device %s found\n", dev_name(&cdev->dev)); return ret; } @@ -616,7 +617,7 @@ tape_generic_remove(struct ccw_device *cdev) device->cdev_id); PRINT_WARN("(%s): Drive in use vanished - " "expect trouble!\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); PRINT_WARN("State was %i\n", device->tape_state); tape_state_set(device, TS_NOT_OPER); __tape_discard_requests(device); @@ -840,7 +841,7 @@ tape_dump_sense(struct tape_device* device, struct tape_request *request, 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", device->cdev->dev.bus_id); + PRINT_INFO("DEVICE: %s\n", dev_name(&device->cdev->dev)); if (request != NULL) PRINT_INFO("OP : %s\n", tape_op_verbose[request->op]); @@ -1051,7 +1052,7 @@ __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", cdev->dev.bus_id); + "in interrupt\n", dev_name(&cdev->dev)); return; } request = (struct tape_request *) intparm; @@ -1064,13 +1065,13 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) switch (PTR_ERR(irb)) { case -ETIMEDOUT: PRINT_WARN("(%s): Request timed out\n", - cdev->dev.bus_id); + dev_name(&cdev->dev)); case -EIO: __tape_end_request(device, request, -EIO); break; default: PRINT_ERR("(%s): Unexpected i/o error %li\n", - cdev->dev.bus_id, + dev_name(&cdev->dev), PTR_ERR(irb)); } return; diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c index e7c888c14e71f847b6ba8aa05e2797c700a2ca6a..8a376af926a7407389d1643350afdf42814e726a 100644 --- a/drivers/s390/char/tape_proc.c +++ b/drivers/s390/char/tape_proc.c @@ -52,7 +52,7 @@ static int tape_proc_show(struct seq_file *m, void *v) return 0; spin_lock_irq(get_ccwdev_lock(device->cdev)); seq_printf(m, "%d\t", (int) n); - seq_printf(m, "%-10.10s ", device->cdev->dev.bus_id); + seq_printf(m, "%-10.10s ", dev_name(&device->cdev->dev)); seq_printf(m, "%04X/", device->cdev->id.cu_type); seq_printf(m, "%02X\t", device->cdev->id.cu_model); seq_printf(m, "%04X/", device->cdev->id.dev_type); diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index cc8fd781ee227ce6e8f1ae38956b2fb002fe5ad6..5bd573d144d6d880a4e130469e6e937b163e5ffa 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c @@ -47,7 +47,7 @@ tape_std_assign_timeout(unsigned long data) rc = tape_cancel_io(device, request); if(rc) PRINT_ERR("(%s): Assign timeout: Cancel failed with rc = %i\n", - device->cdev->dev.bus_id, rc); + dev_name(&device->cdev->dev), rc); } @@ -83,7 +83,7 @@ tape_std_assign(struct tape_device *device) if (rc != 0) { PRINT_WARN("%s: assign failed - device might be busy\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); DBF_EVENT(3, "%08x: assign failed - device might be busy\n", device->cdev_id); } else { @@ -106,7 +106,7 @@ tape_std_unassign (struct tape_device *device) DBF_EVENT(3, "(%08x): Can't unassign device\n", device->cdev_id); PRINT_WARN("(%s): Can't unassign device - device gone\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); return -EIO; } @@ -120,7 +120,8 @@ 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", device->cdev->dev.bus_id); + PRINT_WARN("%s: Unassign failed\n", + dev_name(&device->cdev->dev)); } else { DBF_EVENT(3, "%08x: Tape unassigned\n", device->cdev_id); } @@ -634,10 +635,10 @@ tape_std_mtcompression(struct tape_device *device, int mt_count) DBF_EXCEPTION(6, "xcom parm\n"); if (*device->modeset_byte & 0x08) PRINT_INFO("(%s) Compression is currently on\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); else PRINT_INFO("(%s) Compression is currently off\n", - device->cdev->dev.bus_id); + dev_name(&device->cdev->dev)); PRINT_INFO("Use 1 to switch compression on, 0 to " "switch it off\n"); return -EINVAL; diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index c31faefa2b3b40dfcfe93e84249c50f821a10e4a..42173cc34610f41417b877387dd052517638b6b8 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -724,8 +724,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) dev = kzalloc(sizeof(struct device), GFP_KERNEL); if (dev) { - snprintf(dev->bus_id, BUS_ID_SIZE, "%s", - priv->internal_name); + dev_set_name(dev, priv->internal_name); dev->bus = &iucv_bus; dev->parent = iucv_root; dev->driver = &vmlogrdr_driver; @@ -751,7 +750,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) priv->class_device = device_create_drvdata(vmlogrdr_class, dev, MKDEV(vmlogrdr_major, priv->minor_num), - priv, "%s", dev->bus_id); + priv, "%s", dev_name(dev)); if (IS_ERR(priv->class_device)) { ret = PTR_ERR(priv->class_device); priv->class_device=NULL; diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index c1f352b84868c16affd93a7ff7af1f162527eb2b..6fdfa5ddeca8f686938f0b52d4bb28b504bfcddc 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -886,11 +886,11 @@ static int ur_set_online(struct ccw_device *cdev) goto fail_free_cdev; if (urd->cdev->id.cu_type == READER_PUNCH_DEVTYPE) { if (urd->class == DEV_CLASS_UR_I) - sprintf(node_id, "vmrdr-%s", cdev->dev.bus_id); + sprintf(node_id, "vmrdr-%s", dev_name(&cdev->dev)); if (urd->class == DEV_CLASS_UR_O) - sprintf(node_id, "vmpun-%s", cdev->dev.bus_id); + sprintf(node_id, "vmpun-%s", dev_name(&cdev->dev)); } else if (urd->cdev->id.cu_type == PRINTER_DEVTYPE) { - sprintf(node_id, "vmprt-%s", cdev->dev.bus_id); + sprintf(node_id, "vmprt-%s", dev_name(&cdev->dev)); } else { rc = -EOPNOTSUPP; goto fail_free_cdev; diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 0bfcbbe375c4b4640f50bf14e61ce1f6beae3062..2f547b840ef011f70fef2e559bd571d5b66d616e 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -24,6 +24,7 @@ #include "cio.h" #include "cio_debug.h" #include "css.h" +#include "device.h" /* * "Blacklisting" of certain devices: @@ -191,9 +192,9 @@ static int blacklist_parse_parameters(char *str, range_action action, rc = blacklist_range(ra, from_ssid, to_ssid, from, to, msgtrigger); if (rc) - totalrc = 1; + totalrc = -EINVAL; } else - totalrc = 1; + totalrc = -EINVAL; } return totalrc; @@ -240,8 +241,10 @@ static int blacklist_parse_proc_parameters(char *buf) rc = blacklist_parse_parameters(buf, free, 0); else if (strcmp("add", parm) == 0) rc = blacklist_parse_parameters(buf, add, 0); + else if (strcmp("purge", parm) == 0) + return ccw_purge_blacklisted(); else - return 1; + return -EINVAL; css_schedule_reprobe(); @@ -353,7 +356,7 @@ cio_ignore_write(struct file *file, const char __user *user_buf, } ret = blacklist_parse_proc_parameters(buf); if (ret) - rc = -EINVAL; + rc = ret; else rc = user_len; diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 9a50f245774b0491e1c31532d059049cab945c7b..3ac2c2019f5e28ffae89e7c0d07f965be297f500 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -269,8 +269,7 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, goto error; } - snprintf (gdev->dev.bus_id, BUS_ID_SIZE, "%s", - gdev->cdev[0]->dev.bus_id); + dev_set_name(&gdev->dev, "%s", dev_name(&gdev->cdev[0]->dev)); rc = device_add(&gdev->dev); if (rc) diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index f1216cf6fa8fdd098cc3bc9c145d352fb907059d..1246f61a5338afadca17a9debd0ce4217f8af336 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -393,8 +393,7 @@ int chp_new(struct chp_id chpid) chp->state = 1; chp->dev.parent = &channel_subsystems[chpid.cssid]->device; chp->dev.release = chp_release; - snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid, - chpid.id); + dev_set_name(&chp->dev, "chp%x.%02x", chpid.cssid, chpid.id); /* Obtain channel path description and fill it in. */ ret = chsc_determine_base_channel_path_desc(chpid, &chp->desc); diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 91ca87aa9f973902cbe148338709ddf53974c3fc..f49f0e502b8dfb7f144801db8aa57d975a2dc7b7 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -261,7 +261,7 @@ static int chsc_examine_irb(struct chsc_request *request) { int backed_up; - if (!scsw_stctl(&request->irb.scsw) & SCSW_STCTL_STATUS_PEND) + if (!(scsw_stctl(&request->irb.scsw) & SCSW_STCTL_STATUS_PEND)) return -EIO; backed_up = scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHAIN_CHECK; request->irb.scsw.cmd.cstat &= ~SCHN_STAT_CHAIN_CHECK; diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 326f4cc7f92c932578870443f1421488501c25c0..3db2c386546f13733f122b6e0d6ef7410416548c 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -114,6 +114,7 @@ cio_tpi(void) struct tpi_info *tpi_info; struct subchannel *sch; struct irb *irb; + int irq_context; tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID; if (tpi (NULL) != 1) @@ -126,7 +127,9 @@ cio_tpi(void) sch = (struct subchannel *)(unsigned long)tpi_info->intparm; if (!sch) return 1; - local_bh_disable(); + irq_context = in_interrupt(); + if (!irq_context) + local_bh_disable(); irq_enter (); spin_lock(sch->lock); memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); @@ -134,7 +137,8 @@ cio_tpi(void) sch->driver->irq(sch); spin_unlock(sch->lock); irq_exit (); - _local_bh_enable(); + if (!irq_context) + _local_bh_enable(); return 1; } @@ -153,7 +157,7 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 lpm) CIO_MSG_EVENT(2, "cio_start: 'not oper' status for " "subchannel 0.%x.%04x!\n", sch->schid.ssid, sch->schid.sch_no); - sprintf(dbf_text, "no%s", sch->dev.bus_id); + sprintf(dbf_text, "no%s", dev_name(&sch->dev)); CIO_TRACE_EVENT(0, dbf_text); CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib)); @@ -171,7 +175,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ union orb *orb; CIO_TRACE_EVENT(4, "stIO"); - CIO_TRACE_EVENT(4, sch->dev.bus_id); + CIO_TRACE_EVENT(4, dev_name(&sch->dev)); orb = &to_io_private(sch)->orb; memset(orb, 0, sizeof(union orb)); @@ -232,7 +236,7 @@ cio_resume (struct subchannel *sch) int ccode; CIO_TRACE_EVENT (4, "resIO"); - CIO_TRACE_EVENT (4, sch->dev.bus_id); + CIO_TRACE_EVENT(4, dev_name(&sch->dev)); ccode = rsch (sch->schid); @@ -269,7 +273,7 @@ cio_halt(struct subchannel *sch) return -ENODEV; CIO_TRACE_EVENT (2, "haltIO"); - CIO_TRACE_EVENT (2, sch->dev.bus_id); + CIO_TRACE_EVENT(2, dev_name(&sch->dev)); /* * Issue "Halt subchannel" and process condition code @@ -304,7 +308,7 @@ cio_clear(struct subchannel *sch) return -ENODEV; CIO_TRACE_EVENT (2, "clearIO"); - CIO_TRACE_EVENT (2, sch->dev.bus_id); + CIO_TRACE_EVENT(2, dev_name(&sch->dev)); /* * Issue "Clear subchannel" and process condition code @@ -340,7 +344,7 @@ cio_cancel (struct subchannel *sch) return -ENODEV; CIO_TRACE_EVENT (2, "cancelIO"); - CIO_TRACE_EVENT (2, sch->dev.bus_id); + CIO_TRACE_EVENT(2, dev_name(&sch->dev)); ccode = xsch (sch->schid); @@ -404,7 +408,7 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm) int ret; CIO_TRACE_EVENT (2, "ensch"); - CIO_TRACE_EVENT (2, sch->dev.bus_id); + CIO_TRACE_EVENT(2, dev_name(&sch->dev)); if (sch_is_pseudo_sch(sch)) return -EINVAL; @@ -454,7 +458,7 @@ int cio_disable_subchannel(struct subchannel *sch) int ret; CIO_TRACE_EVENT (2, "dissch"); - CIO_TRACE_EVENT (2, sch->dev.bus_id); + CIO_TRACE_EVENT(2, dev_name(&sch->dev)); if (sch_is_pseudo_sch(sch)) return 0; @@ -571,8 +575,10 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid) } mutex_init(&sch->reg_mutex); /* Set a name for the subchannel */ - snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", schid.ssid, - schid.sch_no); + if (cio_is_console(schid)) + sch->dev.init_name = cio_get_console_sch_name(schid); + else + dev_set_name(&sch->dev, "0.%x.%04x", schid.ssid, schid.sch_no); /* * The first subchannel that is not-operational (ccode==3) @@ -677,6 +683,7 @@ do_IRQ (struct pt_regs *regs) #ifdef CONFIG_CCW_CONSOLE static struct subchannel console_subchannel; +static char console_sch_name[10] = "0.x.xxxx"; static struct io_subchannel_private console_priv; static int console_subchannel_in_use; @@ -827,6 +834,12 @@ cio_get_console_subchannel(void) return &console_subchannel; } +const char *cio_get_console_sch_name(struct subchannel_id schid) +{ + snprintf(console_sch_name, 10, "0.%x.%04x", schid.ssid, schid.sch_no); + return (const char *)console_sch_name; +} + #endif static int __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) @@ -846,19 +859,6 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) return -EBUSY; /* uhm... */ } -/* we can't use the normal udelay here, since it enables external interrupts */ - -static void udelay_reset(unsigned long usecs) -{ - uint64_t start_cc, end_cc; - - asm volatile ("STCK %0" : "=m" (start_cc)); - do { - cpu_relax(); - asm volatile ("STCK %0" : "=m" (end_cc)); - } while (((end_cc - start_cc)/4096) < usecs); -} - static int __clear_io_subchannel_easy(struct subchannel_id schid) { @@ -874,7 +874,7 @@ __clear_io_subchannel_easy(struct subchannel_id schid) if (schid_equal(&ti.schid, &schid)) return 0; } - udelay_reset(100); + udelay_simple(100); } return -EBUSY; } @@ -882,7 +882,7 @@ __clear_io_subchannel_easy(struct subchannel_id schid) static void __clear_chsc_subchannel_easy(void) { /* It seems we can only wait for a bit here :/ */ - udelay_reset(100); + udelay_simple(100); } static int pgm_check_occured; @@ -892,7 +892,7 @@ static void cio_reset_pgm_check_handler(void) pgm_check_occured = 1; } -static int stsch_reset(struct subchannel_id schid, volatile struct schib *addr) +static int stsch_reset(struct subchannel_id schid, struct schib *addr) { int rc; diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index 3b236d20e83543ec127a279d132ec7f51df63958..0fb24784e9254fb00641974b1f67b0a95f0861f1 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -117,11 +117,15 @@ extern int cio_is_console(struct subchannel_id); extern struct subchannel *cio_get_console_subchannel(void); extern spinlock_t * cio_get_console_lock(void); extern void *cio_get_console_priv(void); +extern const char *cio_get_console_sch_name(struct subchannel_id schid); +extern const char *cio_get_console_cdev_name(struct subchannel *sch); #else #define cio_is_console(schid) 0 #define cio_get_console_subchannel() NULL #define cio_get_console_lock() NULL #define cio_get_console_priv() NULL +#define cio_get_console_sch_name(schid) NULL +#define cio_get_console_cdev_name(sch) NULL #endif #endif diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 1261e1a9e8cd518f78aa44754a00318182de2ad8..76bbb1e74c2988c025d695c3927fc690ca067ba6 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -698,7 +698,7 @@ static int __init setup_css(int nr) return -ENOMEM; css->pseudo_subchannel->dev.parent = &css->device; css->pseudo_subchannel->dev.release = css_subchannel_release; - sprintf(css->pseudo_subchannel->dev.bus_id, "defunct"); + dev_set_name(&css->pseudo_subchannel->dev, "defunct"); ret = cio_create_sch_lock(css->pseudo_subchannel); if (ret) { kfree(css->pseudo_subchannel); @@ -707,7 +707,7 @@ static int __init setup_css(int nr) mutex_init(&css->mutex); css->valid = 1; css->cssid = nr; - sprintf(css->device.bus_id, "css%x", nr); + dev_set_name(&css->device, "css%x", nr); css->device.release = channel_subsystem_release; tod_high = (u32) (get_clock() >> 32); css_generate_pgid(css, tod_high); diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 28221030b886cfa5ae8d794fdf176bdbfe401845..4e78c82194b47520c271be8617ac5202644d395c 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -31,6 +31,7 @@ #include "device.h" #include "ioasm.h" #include "io_sch.h" +#include "blacklist.h" static struct timer_list recovery_timer; static DEFINE_SPINLOCK(recovery_lock); @@ -296,36 +297,33 @@ static void ccw_device_unregister(struct ccw_device *cdev) device_del(&cdev->dev); } -static void ccw_device_remove_orphan_cb(struct device *dev) +static void ccw_device_remove_orphan_cb(struct work_struct *work) { - struct ccw_device *cdev = to_ccwdev(dev); + struct ccw_device_private *priv; + struct ccw_device *cdev; + priv = container_of(work, struct ccw_device_private, kick_work); + cdev = priv->cdev; ccw_device_unregister(cdev); put_device(&cdev->dev); + /* Release cdev reference for workqueue processing. */ + put_device(&cdev->dev); } -static void ccw_device_remove_sch_cb(struct device *dev) -{ - struct subchannel *sch; - - sch = to_subchannel(dev); - css_sch_device_unregister(sch); - /* Reset intparm to zeroes. */ - sch->schib.pmcw.intparm = 0; - cio_modify(sch); - put_device(&sch->dev); -} +static void ccw_device_call_sch_unregister(struct work_struct *work); static void ccw_device_remove_disconnected(struct ccw_device *cdev) { unsigned long flags; - int rc; /* * Forced offline in disconnected state means * 'throw away device'. */ + /* Get cdev reference for workqueue processing. */ + if (!get_device(&cdev->dev)) + return; if (ccw_device_is_orphan(cdev)) { /* * Deregister ccw device. @@ -335,23 +333,13 @@ ccw_device_remove_disconnected(struct ccw_device *cdev) spin_lock_irqsave(cdev->ccwlock, flags); cdev->private->state = DEV_STATE_NOT_OPER; spin_unlock_irqrestore(cdev->ccwlock, flags); - rc = device_schedule_callback(&cdev->dev, - ccw_device_remove_orphan_cb); - if (rc) - CIO_MSG_EVENT(0, "Couldn't unregister orphan " - "0.%x.%04x\n", - cdev->private->dev_id.ssid, - cdev->private->dev_id.devno); - return; - } - /* Deregister subchannel, which will kill the ccw device. */ - rc = device_schedule_callback(cdev->dev.parent, - ccw_device_remove_sch_cb); - if (rc) - CIO_MSG_EVENT(0, "Couldn't unregister disconnected device " - "0.%x.%04x\n", - cdev->private->dev_id.ssid, - cdev->private->dev_id.devno); + PREPARE_WORK(&cdev->private->kick_work, + ccw_device_remove_orphan_cb); + } else + /* Deregister subchannel, which will kill the ccw device. */ + PREPARE_WORK(&cdev->private->kick_work, + ccw_device_call_sch_unregister); + queue_work(slow_path_wq, &cdev->private->kick_work); } /** @@ -970,12 +958,17 @@ static void ccw_device_call_sch_unregister(struct work_struct *work) priv = container_of(work, struct ccw_device_private, kick_work); cdev = priv->cdev; + /* Get subchannel reference for local processing. */ + if (!get_device(cdev->dev.parent)) + return; sch = to_subchannel(cdev->dev.parent); css_sch_device_unregister(sch); /* Reset intparm to zeroes. */ sch->schib.pmcw.intparm = 0; cio_modify(sch); + /* Release cdev reference for workqueue processing.*/ put_device(&cdev->dev); + /* Release subchannel reference for local processing. */ put_device(&sch->dev); } @@ -1001,6 +994,8 @@ io_subchannel_recog_done(struct ccw_device *cdev) PREPARE_WORK(&cdev->private->kick_work, ccw_device_call_sch_unregister); queue_work(slow_path_wq, &cdev->private->kick_work); + /* Release subchannel reference for asynchronous recognition. */ + put_device(&sch->dev); if (atomic_dec_and_test(&ccw_device_init_count)) wake_up(&ccw_device_init_wq); break; @@ -1040,8 +1035,11 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) init_timer(&priv->timer); /* Set an initial name for the device. */ - snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", - sch->schid.ssid, sch->schib.pmcw.dev); + if (cio_is_console(sch->schid)) + cdev->dev.init_name = cio_get_console_cdev_name(sch); + else + dev_set_name(&cdev->dev, "0.%x.%04x", + sch->schid.ssid, sch->schib.pmcw.dev); /* Increase counter of devices currently in recognition. */ atomic_inc(&ccw_device_init_count); @@ -1106,7 +1104,7 @@ static void io_subchannel_irq(struct subchannel *sch) cdev = sch_get_cdev(sch); CIO_TRACE_EVENT(3, "IRQ"); - CIO_TRACE_EVENT(3, sch->dev.bus_id); + CIO_TRACE_EVENT(3, dev_name(&sch->dev)); if (cdev) dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); } @@ -1476,6 +1474,45 @@ static void ccw_device_schedule_recovery(void) spin_unlock_irqrestore(&recovery_lock, flags); } +static int purge_fn(struct device *dev, void *data) +{ + struct ccw_device *cdev = to_ccwdev(dev); + struct ccw_device_private *priv = cdev->private; + int unreg; + + spin_lock_irq(cdev->ccwlock); + unreg = is_blacklisted(priv->dev_id.ssid, priv->dev_id.devno) && + (priv->state == DEV_STATE_OFFLINE); + spin_unlock_irq(cdev->ccwlock); + if (!unreg) + goto out; + if (!get_device(&cdev->dev)) + goto out; + CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", priv->dev_id.ssid, + priv->dev_id.devno); + PREPARE_WORK(&cdev->private->kick_work, ccw_device_call_sch_unregister); + queue_work(slow_path_wq, &cdev->private->kick_work); + +out: + /* Abort loop in case of pending signal. */ + if (signal_pending(current)) + return -EINTR; + + return 0; +} + +/** + * ccw_purge_blacklisted - purge unused, blacklisted devices + * + * Unregister all ccw devices that are offline and on the blacklist. + */ +int ccw_purge_blacklisted(void) +{ + CIO_MSG_EVENT(2, "ccw: purging blacklisted devices\n"); + bus_for_each_dev(&ccw_bus_type, NULL, NULL, purge_fn); + return 0; +} + static void device_set_disconnected(struct ccw_device *cdev) { if (!cdev) @@ -1492,7 +1529,7 @@ void ccw_device_set_notoper(struct ccw_device *cdev) struct subchannel *sch = to_subchannel(cdev->dev.parent); CIO_TRACE_EVENT(2, "notoper"); - CIO_TRACE_EVENT(2, sch->dev.bus_id); + CIO_TRACE_EVENT(2, dev_name(&sch->dev)); ccw_device_set_timeout(cdev, 0); cio_disable_subchannel(sch); cdev->private->state = DEV_STATE_NOT_OPER; @@ -1591,6 +1628,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int slow) #ifdef CONFIG_CCW_CONSOLE static struct ccw_device console_cdev; +static char console_cdev_name[10] = "0.x.xxxx"; static struct ccw_device_private console_private; static int console_cdev_in_use; @@ -1661,6 +1699,14 @@ ccw_device_probe_console(void) console_cdev.online = 1; return &console_cdev; } + + +const char *cio_get_console_cdev_name(struct subchannel *sch) +{ + snprintf(console_cdev_name, 10, "0.%x.%04x", + sch->schid.ssid, sch->schib.pmcw.dev); + return (const char *)console_cdev_name; +} #endif /* @@ -1673,7 +1719,7 @@ __ccwdev_check_busid(struct device *dev, void *id) bus_id = id; - return (strncmp(bus_id, dev->bus_id, BUS_ID_SIZE) == 0); + return (strncmp(bus_id, dev_name(dev), BUS_ID_SIZE) == 0); } diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 6f5c3f2b3587d8f72d98aa781f9f2cbd6dfd50d3..104ed669db43946a0656fe5adaac51a8374cc4f1 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -86,6 +86,7 @@ int ccw_device_is_orphan(struct ccw_device *); int ccw_device_recognition(struct ccw_device *); int ccw_device_online(struct ccw_device *); int ccw_device_offline(struct ccw_device *); +int ccw_purge_blacklisted(void); /* Function prototypes for device status and basic sense stuff. */ void ccw_device_accumulate_irb(struct ccw_device *, struct irb *); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 84cc9ea346dbc264639d892a19e591ef7535ef8f..10bc03940fb3144fd412e1625eaaa003fd64459d 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -52,8 +52,10 @@ static void ccw_timeout_log(struct ccw_device *cdev) printk(KERN_WARNING "cio: orb:\n"); print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, orb, sizeof(*orb), 0); - printk(KERN_WARNING "cio: ccw device bus id: %s\n", cdev->dev.bus_id); - printk(KERN_WARNING "cio: subchannel bus id: %s\n", sch->dev.bus_id); + printk(KERN_WARNING "cio: ccw device bus id: %s\n", + dev_name(&cdev->dev)); + printk(KERN_WARNING "cio: subchannel bus id: %s\n", + dev_name(&sch->dev)); printk(KERN_WARNING "cio: subchannel lpm: %02x, opm: %02x, " "vpm: %02x\n", sch->lpm, sch->opm, sch->vpm); diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index ee1a28310fbb11945c07714fc9dfef94b4a20752..eabcc42d63df17ca5bfc9afd89a1b6211b92f61a 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -498,7 +498,7 @@ ccw_device_stlck(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); CIO_TRACE_EVENT(2, "stl lock"); - CIO_TRACE_EVENT(2, cdev->dev.bus_id); + CIO_TRACE_EVENT(2, dev_name(&cdev->dev)); buf = kmalloc(32*sizeof(char), GFP_DMA|GFP_KERNEL); if (!buf) diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index 3f8f1cf69c76d9082d3bad69d37d2a1dc0f5d123..c4f3e7c9a85482996dbd41b4249651d108be2e4f 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h @@ -123,7 +123,7 @@ struct ccw_device_private { void *cmb_wait; /* deferred cmb enable/disable */ }; -static inline int ssch(struct subchannel_id schid, volatile union orb *addr) +static inline int ssch(struct subchannel_id schid, union orb *addr) { register struct subchannel_id reg1 asm("1") = schid; int ccode = -EIO; @@ -134,7 +134,9 @@ static inline int ssch(struct subchannel_id schid, volatile union orb *addr) " srl %0,28\n" "1:\n" EX_TABLE(0b, 1b) - : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); + : "+d" (ccode) + : "d" (reg1), "a" (addr), "m" (*addr) + : "cc", "memory"); return ccode; } @@ -147,7 +149,9 @@ static inline int rsch(struct subchannel_id schid) " rsch\n" " ipm %0\n" " srl %0,28" - : "=d" (ccode) : "d" (reg1) : "cc"); + : "=d" (ccode) + : "d" (reg1) + : "cc", "memory"); return ccode; } @@ -160,7 +164,9 @@ static inline int csch(struct subchannel_id schid) " csch\n" " ipm %0\n" " srl %0,28" - : "=d" (ccode) : "d" (reg1) : "cc"); + : "=d" (ccode) + : "d" (reg1) + : "cc"); return ccode; } @@ -173,7 +179,9 @@ static inline int hsch(struct subchannel_id schid) " hsch\n" " ipm %0\n" " srl %0,28" - : "=d" (ccode) : "d" (reg1) : "cc"); + : "=d" (ccode) + : "d" (reg1) + : "cc"); return ccode; } @@ -186,7 +194,9 @@ static inline int xsch(struct subchannel_id schid) " .insn rre,0xb2760000,%1,0\n" " ipm %0\n" " srl %0,28" - : "=d" (ccode) : "d" (reg1) : "cc"); + : "=d" (ccode) + : "d" (reg1) + : "cc"); return ccode; } diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h index 9fa2ac13ac85cc94faf822f88f69d85072d57930..759262792633e0ec5fd4ad0d3f43f80d47ad5225 100644 --- a/drivers/s390/cio/ioasm.h +++ b/drivers/s390/cio/ioasm.h @@ -23,38 +23,39 @@ struct tpi_info { * Some S390 specific IO instructions as inline */ -static inline int stsch(struct subchannel_id schid, - volatile struct schib *addr) +static inline int stsch(struct subchannel_id schid, struct schib *addr) { register struct subchannel_id reg1 asm ("1") = schid; int ccode; asm volatile( - " stsch 0(%2)\n" + " stsch 0(%3)\n" " ipm %0\n" " srl %0,28" - : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); + : "=d" (ccode), "=m" (*addr) + : "d" (reg1), "a" (addr) + : "cc"); return ccode; } -static inline int stsch_err(struct subchannel_id schid, - volatile struct schib *addr) +static inline int stsch_err(struct subchannel_id schid, struct schib *addr) { register struct subchannel_id reg1 asm ("1") = schid; int ccode = -EIO; asm volatile( - " stsch 0(%2)\n" + " stsch 0(%3)\n" "0: ipm %0\n" " srl %0,28\n" "1:\n" EX_TABLE(0b,1b) - : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); + : "+d" (ccode), "=m" (*addr) + : "d" (reg1), "a" (addr) + : "cc"); return ccode; } -static inline int msch(struct subchannel_id schid, - volatile struct schib *addr) +static inline int msch(struct subchannel_id schid, struct schib *addr) { register struct subchannel_id reg1 asm ("1") = schid; int ccode; @@ -63,12 +64,13 @@ static inline int msch(struct subchannel_id schid, " msch 0(%2)\n" " ipm %0\n" " srl %0,28" - : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); + : "=d" (ccode) + : "d" (reg1), "a" (addr), "m" (*addr) + : "cc"); return ccode; } -static inline int msch_err(struct subchannel_id schid, - volatile struct schib *addr) +static inline int msch_err(struct subchannel_id schid, struct schib *addr) { register struct subchannel_id reg1 asm ("1") = schid; int ccode = -EIO; @@ -79,33 +81,38 @@ static inline int msch_err(struct subchannel_id schid, " srl %0,28\n" "1:\n" EX_TABLE(0b,1b) - : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); + : "+d" (ccode) + : "d" (reg1), "a" (addr), "m" (*addr) + : "cc"); return ccode; } -static inline int tsch(struct subchannel_id schid, - volatile struct irb *addr) +static inline int tsch(struct subchannel_id schid, struct irb *addr) { register struct subchannel_id reg1 asm ("1") = schid; int ccode; asm volatile( - " tsch 0(%2)\n" + " tsch 0(%3)\n" " ipm %0\n" " srl %0,28" - : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); + : "=d" (ccode), "=m" (*addr) + : "d" (reg1), "a" (addr) + : "cc"); return ccode; } -static inline int tpi( volatile struct tpi_info *addr) +static inline int tpi(struct tpi_info *addr) { int ccode; asm volatile( - " tpi 0(%1)\n" + " tpi 0(%2)\n" " ipm %0\n" " srl %0,28" - : "=d" (ccode) : "a" (addr), "m" (*addr) : "cc"); + : "=d" (ccode), "=m" (*addr) + : "a" (addr) + : "cc"); return ccode; } diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index c1a70985abfaf7d877fa60d4d6f72a78640cf5e9..e3ea1d5f2810bae11a9b0918f547339b5c88e314 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -16,6 +16,14 @@ #define QDIO_BUSY_BIT_GIVE_UP 2000000 /* 2 seconds = eternity */ #define QDIO_INPUT_THRESHOLD 500 /* 500 microseconds */ +/* + * if an asynchronous HiperSockets queue runs full, the 10 seconds timer wait + * till next initiative to give transmitted skbs back to the stack is too long. + * Therefore polling is started in case of multicast queue is filled more + * than 50 percent. + */ +#define QDIO_IQDIO_POLL_LVL 65 /* HS multicast queue */ + enum qdio_irq_states { QDIO_IRQ_STATE_INACTIVE, QDIO_IRQ_STATE_ESTABLISHED, @@ -195,6 +203,9 @@ struct qdio_output_q { /* PCIs are enabled for the queue */ int pci_out_enabled; + /* IQDIO: output multiple buffers (enhanced SIGA) */ + int use_enh_siga; + /* timer to check for more outbound work */ struct timer_list timer; }; diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index 337aa3087a78712fa78a4c26f7165e1ba8a03c17..b5390821434f066376b35f7a749cf1331eff8a18 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -155,7 +155,7 @@ static int qstat_seq_open(struct inode *inode, struct file *filp) static void get_queue_name(struct qdio_q *q, struct ccw_device *cdev, char *name) { memset(name, 0, sizeof(name)); - sprintf(name, "%s", cdev->dev.bus_id); + sprintf(name, "%s", dev_name(&cdev->dev)); if (q->is_input_q) sprintf(name + strlen(name), "_input"); else diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index e6eabc853422cc9320c7925099471ec04e48f44b..a50682d2a0fa5ebae84dec275ae634febd52c4b5 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -316,6 +316,9 @@ static inline int qdio_do_siga_output(struct qdio_q *q, unsigned int *busy_bit) unsigned int fc = 0; unsigned long schid; + if (q->u.out.use_enh_siga) { + fc = 3; + } if (!is_qebsm(q)) schid = *((u32 *)&q->irq_ptr->schid); else { @@ -851,6 +854,12 @@ static void __qdio_outbound_processing(struct qdio_q *q) 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; + } + if (q->u.out.pci_out_enabled) return; @@ -956,7 +965,7 @@ static void qdio_handle_activate_check(struct ccw_device *cdev, char dbf_text[15]; QDIO_DBF_TEXT2(1, trace, "ick2"); - sprintf(dbf_text, "%s", cdev->dev.bus_id); + sprintf(dbf_text, "%s", dev_name(&cdev->dev)); QDIO_DBF_TEXT2(1, trace, dbf_text); QDIO_DBF_HEX2(0, trace, &intparm, sizeof(int)); QDIO_DBF_HEX2(0, trace, &dstat, sizeof(int)); @@ -1443,6 +1452,8 @@ int qdio_establish(struct qdio_initialize *init_data) } qdio_setup_ssqd_info(irq_ptr); + sprintf(dbf_text, "qDmmwc%2x", irq_ptr->ssqd_desc.mmwc); + QDIO_DBF_TEXT2(0, setup, dbf_text); sprintf(dbf_text, "qib ac%2x", irq_ptr->qib.ac); QDIO_DBF_TEXT2(0, setup, dbf_text); @@ -1615,12 +1626,21 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags, if (multicast_outbound(q)) qdio_kick_outbound_q(q); else - /* - * One siga-w per buffer required for unicast - * HiperSockets. - */ - while (count--) + 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); + } else { + /* + * One siga-w per buffer required for unicast + * HiperSockets. + */ + q->u.out.use_enh_siga = 0; + while (count--) + qdio_kick_outbound_q(q); + } goto out; } diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 62b6b55230d0d4e509910df984de16364b8c99f9..326db1e827c4dbe41f70419a9af53b1a997a7e7a 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -892,8 +892,8 @@ static void ap_scan_bus(struct work_struct *unused) ap_dev->device.bus = &ap_bus_type; ap_dev->device.parent = ap_root_device; - snprintf(ap_dev->device.bus_id, BUS_ID_SIZE, "card%02x", - AP_QID_DEVICE(ap_dev->qid)); + dev_set_name(&ap_dev->device, "card%02x", + AP_QID_DEVICE(ap_dev->qid)); ap_dev->device.release = ap_device_release; rc = device_register(&ap_dev->device); if (rc) { diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 292b60da6dc763e83c34ee2fa49b9a8361908205..ff4a6931bb8e680b4f429577fc81e481df4cd786 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -24,6 +24,7 @@ #include <asm/kvm_virtio.h> #include <asm/setup.h> #include <asm/s390_ext.h> +#include <asm/s390_rdev.h> #define VIRTIO_SUBCODE_64 0x0D00 @@ -241,10 +242,7 @@ static struct virtio_config_ops kvm_vq_configspace_ops = { * The root device for the kvm virtio devices. * This makes them appear as /sys/devices/kvm_s390/0,1,2 not /sys/devices/0,1,2. */ -static struct device kvm_root = { - .parent = NULL, - .bus_id = "kvm_s390", -}; +static struct device *kvm_root; /* * adds a new device and register it with virtio @@ -261,7 +259,7 @@ static void add_kvm_device(struct kvm_device_desc *d, unsigned int offset) return; } - kdev->vdev.dev.parent = &kvm_root; + kdev->vdev.dev.parent = kvm_root; kdev->vdev.id.device = d->type; kdev->vdev.config = &kvm_vq_configspace_ops; kdev->desc = d; @@ -317,15 +315,16 @@ static int __init kvm_devices_init(void) if (!MACHINE_IS_KVM) return -ENODEV; - rc = device_register(&kvm_root); - if (rc) { + kvm_root = s390_root_dev_register("kvm_s390"); + if (IS_ERR(kvm_root)) { + rc = PTR_ERR(kvm_root); printk(KERN_ERR "Could not register kvm_s390 root device"); return rc; } rc = vmem_add_mapping(PFN_PHYS(max_pfn), PAGE_SIZE); if (rc) { - device_unregister(&kvm_root); + s390_root_dev_unregister(kvm_root); return rc; } diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index e10ac9ab2d4477cbfda1d4ada3fd841ac56bb4f4..8f83fc994f508ef6069a1a9cc67eb30b196e945d 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -299,7 +299,7 @@ claw_probe(struct ccwgroup_device *cgdev) probe_error(cgdev); put_device(&cgdev->dev); printk(KERN_WARNING "add_files failed %s %s Exit Line %d \n", - cgdev->cdev[0]->dev.bus_id,__func__,__LINE__); + dev_name(&cgdev->cdev[0]->dev), __func__, __LINE__); CLAW_DBF_TEXT_(2, setup, "probex%d", rc); return rc; } @@ -584,7 +584,7 @@ claw_irq_handler(struct ccw_device *cdev, if (!cdev->dev.driver_data) { printk(KERN_WARNING "claw: unsolicited interrupt for device:" "%s received c-%02x d-%02x\n", - cdev->dev.bus_id, irb->scsw.cmd.cstat, + dev_name(&cdev->dev), irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); CLAW_DBF_TEXT(2, trace, "badirq"); return; @@ -598,7 +598,7 @@ claw_irq_handler(struct ccw_device *cdev, p_ch = &privptr->channel[WRITE]; else { printk(KERN_WARNING "claw: Can't determine channel for " - "interrupt, device %s\n", cdev->dev.bus_id); + "interrupt, device %s\n", dev_name(&cdev->dev)); CLAW_DBF_TEXT(2, trace, "badchan"); return; } @@ -662,7 +662,7 @@ claw_irq_handler(struct ccw_device *cdev, printk(KERN_WARNING "claw: unsolicited " "interrupt for device:" "%s received c-%02x d-%02x\n", - cdev->dev.bus_id, + dev_name(&cdev->dev), irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); return; @@ -1136,19 +1136,20 @@ ccw_check_return_code(struct ccw_device *cdev, int return_code) break; case -ENODEV: printk(KERN_EMERG "%s: Missing device called " - "for IO ENODEV\n", cdev->dev.bus_id); + "for IO ENODEV\n", dev_name(&cdev->dev)); break; case -EIO: printk(KERN_EMERG "%s: Status pending... EIO \n", - cdev->dev.bus_id); + dev_name(&cdev->dev)); break; case -EINVAL: printk(KERN_EMERG "%s: Invalid Dev State EINVAL \n", - cdev->dev.bus_id); + dev_name(&cdev->dev)); break; default: printk(KERN_EMERG "%s: Unknown error in " - "Do_IO %d\n",cdev->dev.bus_id, return_code); + "Do_IO %d\n", dev_name(&cdev->dev), + return_code); } } CLAW_DBF_TEXT(4, trace, "ccwret"); @@ -2848,11 +2849,11 @@ add_channel(struct ccw_device *cdev,int i,struct claw_privbk *privptr) struct chbk *p_ch; struct ccw_dev_id dev_id; - CLAW_DBF_TEXT_(2, setup, "%s", cdev->dev.bus_id); + CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cdev->dev)); privptr->channel[i].flag = i+1; /* Read is 1 Write is 2 */ p_ch = &privptr->channel[i]; p_ch->cdev = cdev; - snprintf(p_ch->id, CLAW_ID_SIZE, "cl-%s", cdev->dev.bus_id); + snprintf(p_ch->id, CLAW_ID_SIZE, "cl-%s", dev_name(&cdev->dev)); ccw_device_get_id(cdev, &dev_id); p_ch->devno = dev_id.devno; if ((p_ch->irb = kzalloc(sizeof (struct irb),GFP_KERNEL)) == NULL) { @@ -2879,7 +2880,8 @@ claw_new_device(struct ccwgroup_device *cgdev) int ret; struct ccw_dev_id dev_id; - printk(KERN_INFO "claw: add for %s\n",cgdev->cdev[READ]->dev.bus_id); + printk(KERN_INFO "claw: add for %s\n", + dev_name(&cgdev->cdev[READ]->dev)); CLAW_DBF_TEXT(2, setup, "new_dev"); privptr = cgdev->dev.driver_data; cgdev->cdev[READ]->dev.driver_data = privptr; @@ -2903,14 +2905,16 @@ claw_new_device(struct ccwgroup_device *cgdev) if (ret != 0) { printk(KERN_WARNING "claw: ccw_device_set_online %s READ failed " - "with ret = %d\n",cgdev->cdev[READ]->dev.bus_id,ret); + "with ret = %d\n", dev_name(&cgdev->cdev[READ]->dev), + ret); goto out; } ret = ccw_device_set_online(cgdev->cdev[WRITE]); if (ret != 0) { printk(KERN_WARNING "claw: ccw_device_set_online %s WRITE failed " - "with ret = %d\n",cgdev->cdev[WRITE]->dev.bus_id, ret); + "with ret = %d\n", dev_name(&cgdev->cdev[WRITE]->dev) + ret); goto out; } dev = alloc_netdev(0,"claw%d",claw_init_netdevice); @@ -2986,7 +2990,7 @@ claw_shutdown_device(struct ccwgroup_device *cgdev) struct net_device *ndev; int ret; - CLAW_DBF_TEXT_(2, setup, "%s", cgdev->dev.bus_id); + CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev)); priv = cgdev->dev.driver_data; if (!priv) return -ENODEV; @@ -3016,11 +3020,11 @@ claw_remove_device(struct ccwgroup_device *cgdev) struct claw_privbk *priv; BUG_ON(!cgdev); - CLAW_DBF_TEXT_(2, setup, "%s", cgdev->dev.bus_id); + CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev)); priv = cgdev->dev.driver_data; BUG_ON(!priv); printk(KERN_INFO "claw: %s() called %s will be removed.\n", - __func__,cgdev->cdev[0]->dev.bus_id); + __func__, dev_name(&cgdev->cdev[0]->dev)); if (cgdev->state == CCWGROUP_ONLINE) claw_shutdown_device(cgdev); claw_remove_files(&cgdev->dev); diff --git a/drivers/s390/net/claw.h b/drivers/s390/net/claw.h index 1a89d989f34811651d61dccd735fdf53f9701555..005072c420d30deeb304874054cb6142a7411fe5 100644 --- a/drivers/s390/net/claw.h +++ b/drivers/s390/net/claw.h @@ -85,7 +85,7 @@ #define CLAW_MAX_DEV 256 /* max claw devices */ #define MAX_NAME_LEN 8 /* host name, adapter name length */ #define CLAW_FRAME_SIZE 4096 -#define CLAW_ID_SIZE BUS_ID_SIZE+3 +#define CLAW_ID_SIZE 20+3 /* state machine codes used in claw_irq_handler */ diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index b11fec24c7d270f1311fd87c342189fd6878d3a6..a4e29836a2aae6ffd15ab35c09c4d48f07b2eb3a 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -277,18 +277,18 @@ static long ctcm_check_irb_error(struct ccw_device *cdev, struct irb *irb) CTCM_DBF_TEXT_(ERROR, CTC_DBF_WARN, "irb error %ld on device %s\n", - PTR_ERR(irb), cdev->dev.bus_id); + PTR_ERR(irb), dev_name(&cdev->dev)); switch (PTR_ERR(irb)) { case -EIO: - ctcm_pr_warn("i/o-error on device %s\n", cdev->dev.bus_id); + ctcm_pr_warn("i/o-error on device %s\n", dev_name(&cdev->dev)); break; case -ETIMEDOUT: - ctcm_pr_warn("timeout on device %s\n", cdev->dev.bus_id); + ctcm_pr_warn("timeout on device %s\n", dev_name(&cdev->dev)); break; default: ctcm_pr_warn("unknown error %ld on device %s\n", - PTR_ERR(irb), cdev->dev.bus_id); + PTR_ERR(irb), dev_name(&cdev->dev)); } return PTR_ERR(irb); } @@ -1182,7 +1182,7 @@ static void ctcm_irq_handler(struct ccw_device *cdev, int dstat; CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG, - "Enter %s(%s)", CTCM_FUNTAIL, &cdev->dev.bus_id); + "Enter %s(%s)", CTCM_FUNTAIL, dev_name(&cdev->dev)); if (ctcm_check_irb_error(cdev, irb)) return; @@ -1208,14 +1208,14 @@ static void ctcm_irq_handler(struct ccw_device *cdev, ch = priv->channel[WRITE]; else { ctcm_pr_err("ctcm: Can't determine channel for interrupt, " - "device %s\n", cdev->dev.bus_id); + "device %s\n", dev_name(&cdev->dev)); return; } dev = ch->netdev; if (dev == NULL) { ctcm_pr_crit("ctcm: %s dev=NULL bus_id=%s, ch=0x%p\n", - __func__, cdev->dev.bus_id, ch); + __func__, dev_name(&cdev->dev), ch); return; } @@ -1329,7 +1329,7 @@ static int add_channel(struct ccw_device *cdev, enum channel_types type, CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, "%s(%s), type %d, proto %d", - __func__, cdev->dev.bus_id, type, priv->protocol); + __func__, dev_name(&cdev->dev), type, priv->protocol); ch = kzalloc(sizeof(struct channel), GFP_KERNEL); if (ch == NULL) @@ -1358,7 +1358,7 @@ static int add_channel(struct ccw_device *cdev, enum channel_types type, goto nomem_return; ch->cdev = cdev; - snprintf(ch->id, CTCM_ID_SIZE, "ch-%s", cdev->dev.bus_id); + snprintf(ch->id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev->dev)); ch->type = type; /** @@ -1518,8 +1518,8 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev) type = get_channel_type(&cdev0->id); - snprintf(read_id, CTCM_ID_SIZE, "ch-%s", cdev0->dev.bus_id); - snprintf(write_id, CTCM_ID_SIZE, "ch-%s", cdev1->dev.bus_id); + snprintf(read_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev0->dev)); + snprintf(write_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev1->dev)); ret = add_channel(cdev0, type, priv); if (ret) diff --git a/drivers/s390/net/ctcm_main.h b/drivers/s390/net/ctcm_main.h index 8e10ee86a5eedc141ab52c391b85f537e8d8148b..d77cce3fe4d48a8bbc6cc97b5346299873f9eeb3 100644 --- a/drivers/s390/net/ctcm_main.h +++ b/drivers/s390/net/ctcm_main.h @@ -104,7 +104,7 @@ #define READ 0 #define WRITE 1 -#define CTCM_ID_SIZE BUS_ID_SIZE+3 +#define CTCM_ID_SIZE 20+3 struct ctcm_profile { unsigned long maxmulti; diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 9bcfa04d863b315df94c2f01e087d071f125679a..0825be87e5a00d47812cfef79eee1d784599993c 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -492,7 +492,7 @@ lcs_start_channel(struct lcs_channel *channel) unsigned long flags; int rc; - LCS_DBF_TEXT_(4,trace,"ssch%s", channel->ccwdev->dev.bus_id); + LCS_DBF_TEXT_(4, trace,"ssch%s", dev_name(&channel->ccwdev->dev)); spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); rc = ccw_device_start(channel->ccwdev, channel->ccws + channel->io_idx, 0, 0, @@ -501,7 +501,8 @@ lcs_start_channel(struct lcs_channel *channel) channel->state = LCS_CH_STATE_RUNNING; spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); if (rc) { - LCS_DBF_TEXT_(4,trace,"essh%s", channel->ccwdev->dev.bus_id); + LCS_DBF_TEXT_(4,trace,"essh%s", + dev_name(&channel->ccwdev->dev)); PRINT_ERR("Error in starting channel, rc=%d!\n", rc); } return rc; @@ -514,12 +515,13 @@ lcs_clear_channel(struct lcs_channel *channel) int rc; LCS_DBF_TEXT(4,trace,"clearch"); - LCS_DBF_TEXT_(4,trace,"%s", channel->ccwdev->dev.bus_id); + LCS_DBF_TEXT_(4, trace, "%s", dev_name(&channel->ccwdev->dev)); spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); rc = ccw_device_clear(channel->ccwdev, (addr_t) channel); spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); if (rc) { - LCS_DBF_TEXT_(4,trace,"ecsc%s", channel->ccwdev->dev.bus_id); + LCS_DBF_TEXT_(4, trace, "ecsc%s", + dev_name(&channel->ccwdev->dev)); return rc; } wait_event(channel->wait_q, (channel->state == LCS_CH_STATE_CLEARED)); @@ -540,13 +542,14 @@ lcs_stop_channel(struct lcs_channel *channel) if (channel->state == LCS_CH_STATE_STOPPED) return 0; LCS_DBF_TEXT(4,trace,"haltsch"); - LCS_DBF_TEXT_(4,trace,"%s", channel->ccwdev->dev.bus_id); + LCS_DBF_TEXT_(4, trace, "%s", dev_name(&channel->ccwdev->dev)); channel->state = LCS_CH_STATE_INIT; spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); rc = ccw_device_halt(channel->ccwdev, (addr_t) channel); spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); if (rc) { - LCS_DBF_TEXT_(4,trace,"ehsc%s", channel->ccwdev->dev.bus_id); + LCS_DBF_TEXT_(4, trace, "ehsc%s", + dev_name(&channel->ccwdev->dev)); return rc; } /* Asynchronous halt initialted. Wait for its completion. */ @@ -632,10 +635,11 @@ __lcs_resume_channel(struct lcs_channel *channel) return 0; if (channel->ccws[channel->io_idx].flags & CCW_FLAG_SUSPEND) return 0; - LCS_DBF_TEXT_(5, trace, "rsch%s", channel->ccwdev->dev.bus_id); + LCS_DBF_TEXT_(5, trace, "rsch%s", dev_name(&channel->ccwdev->dev)); rc = ccw_device_resume(channel->ccwdev); if (rc) { - LCS_DBF_TEXT_(4, trace, "ersc%s", channel->ccwdev->dev.bus_id); + LCS_DBF_TEXT_(4, trace, "ersc%s", + dev_name(&channel->ccwdev->dev)); PRINT_ERR("Error in lcs_resume_channel: rc=%d\n",rc); } else channel->state = LCS_CH_STATE_RUNNING; @@ -1302,18 +1306,18 @@ lcs_check_irb_error(struct ccw_device *cdev, struct irb *irb) switch (PTR_ERR(irb)) { case -EIO: - PRINT_WARN("i/o-error on device %s\n", cdev->dev.bus_id); + PRINT_WARN("i/o-error on device %s\n", dev_name(&cdev->dev)); LCS_DBF_TEXT(2, trace, "ckirberr"); LCS_DBF_TEXT_(2, trace, " rc%d", -EIO); break; case -ETIMEDOUT: - PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id); + PRINT_WARN("timeout on device %s\n", dev_name(&cdev->dev)); LCS_DBF_TEXT(2, trace, "ckirberr"); LCS_DBF_TEXT_(2, trace, " rc%d", -ETIMEDOUT); break; default: PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb), - cdev->dev.bus_id); + dev_name(&cdev->dev)); LCS_DBF_TEXT(2, trace, "ckirberr"); LCS_DBF_TEXT(2, trace, " rc???"); } @@ -1390,7 +1394,7 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) cstat = irb->scsw.cmd.cstat; dstat = irb->scsw.cmd.dstat; - LCS_DBF_TEXT_(5, trace, "Rint%s",cdev->dev.bus_id); + LCS_DBF_TEXT_(5, trace, "Rint%s", dev_name(&cdev->dev)); LCS_DBF_TEXT_(5, trace, "%4x%4x", irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); LCS_DBF_TEXT_(5, trace, "%4x%4x", irb->scsw.cmd.fctl, @@ -1400,7 +1404,7 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) rc = lcs_get_problem(cdev, irb); if (rc || (dstat & DEV_STAT_UNIT_EXCEP)) { PRINT_WARN("check on device %s, dstat=0x%X, cstat=0x%X \n", - cdev->dev.bus_id, dstat, cstat); + dev_name(&cdev->dev), dstat, cstat); if (rc) { channel->state = LCS_CH_STATE_ERROR; } @@ -1463,7 +1467,7 @@ lcs_tasklet(unsigned long data) int rc; channel = (struct lcs_channel *) data; - LCS_DBF_TEXT_(5, trace, "tlet%s",channel->ccwdev->dev.bus_id); + LCS_DBF_TEXT_(5, trace, "tlet%s", dev_name(&channel->ccwdev->dev)); /* Check for processed buffers. */ iob = channel->iob; @@ -2244,7 +2248,7 @@ lcs_recovery(void *ptr) return 0; LCS_DBF_TEXT(4, trace, "recover2"); gdev = card->gdev; - PRINT_WARN("Recovery of device %s started...\n", gdev->dev.bus_id); + PRINT_WARN("Recovery of device %s started...\n", dev_name(&gdev->dev)); rc = __lcs_shutdown_device(gdev, 1); rc = lcs_new_device(gdev); if (!rc) diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 9242b5acc66ba8f63e0344569a8e9cf5e6c478e5..0fea51e34b5751b06f2ddc728c2116c8d6d3f3b7 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1724,7 +1724,7 @@ static int netiucv_register_device(struct net_device *ndev) IUCV_DBF_TEXT(trace, 3, __func__); if (dev) { - snprintf(dev->bus_id, BUS_ID_SIZE, "net%s", ndev->name); + dev_set_name(dev, "net%s", ndev->name); dev->bus = &iucv_bus; dev->parent = iucv_root; /* diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index bf8a75c92f2896d48290683ea2cb032e38d01ba4..af6d6045851394f94d9234af65ac115b4c37a9ef 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -90,11 +90,11 @@ struct qeth_dbf_info { #define CARD_RDEV(card) card->read.ccwdev #define CARD_WDEV(card) card->write.ccwdev #define CARD_DDEV(card) card->data.ccwdev -#define CARD_BUS_ID(card) card->gdev->dev.bus_id -#define CARD_RDEV_ID(card) card->read.ccwdev->dev.bus_id -#define CARD_WDEV_ID(card) card->write.ccwdev->dev.bus_id -#define CARD_DDEV_ID(card) card->data.ccwdev->dev.bus_id -#define CHANNEL_ID(channel) channel->ccwdev->dev.bus_id +#define CARD_BUS_ID(card) dev_name(&card->gdev->dev) +#define CARD_RDEV_ID(card) dev_name(&card->read.ccwdev->dev) +#define CARD_WDEV_ID(card) dev_name(&card->write.ccwdev->dev) +#define CARD_DDEV_ID(card) dev_name(&card->data.ccwdev->dev) +#define CHANNEL_ID(channel) dev_name(&channel->ccwdev->dev) /** * card stuff diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index c7ab1b864516694e97eb3438a70b26f7a20fb952..141b2bb7b3cf44513f6674e9f9d72ec9e9a1b14c 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -745,7 +745,7 @@ static int qeth_get_problem(struct ccw_device *cdev, struct irb *irb) SCHN_STAT_PROT_CHECK | SCHN_STAT_PROG_CHECK)) { QETH_DBF_TEXT(TRACE, 2, "CGENCHK"); PRINT_WARN("check on device %s, dstat=x%x, cstat=x%x ", - cdev->dev.bus_id, dstat, cstat); + dev_name(&cdev->dev), dstat, cstat); print_hex_dump(KERN_WARNING, "qeth: irb ", DUMP_PREFIX_OFFSET, 16, 1, irb, 64, 1); return 1; @@ -784,12 +784,12 @@ static long __qeth_check_irb_error(struct ccw_device *cdev, switch (PTR_ERR(irb)) { case -EIO: - PRINT_WARN("i/o-error on device %s\n", cdev->dev.bus_id); + PRINT_WARN("i/o-error on device %s\n", dev_name(&cdev->dev)); QETH_DBF_TEXT(TRACE, 2, "ckirberr"); QETH_DBF_TEXT_(TRACE, 2, " rc%d", -EIO); break; case -ETIMEDOUT: - PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id); + PRINT_WARN("timeout on device %s\n", dev_name(&cdev->dev)); QETH_DBF_TEXT(TRACE, 2, "ckirberr"); QETH_DBF_TEXT_(TRACE, 2, " rc%d", -ETIMEDOUT); if (intparm == QETH_RCD_PARM) { @@ -803,7 +803,7 @@ static long __qeth_check_irb_error(struct ccw_device *cdev, break; default: PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb), - cdev->dev.bus_id); + dev_name(&cdev->dev)); QETH_DBF_TEXT(TRACE, 2, "ckirberr"); QETH_DBF_TEXT(TRACE, 2, " rc???"); } @@ -4081,7 +4081,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) if (!get_device(dev)) return -ENODEV; - QETH_DBF_TEXT_(SETUP, 2, "%s", gdev->dev.bus_id); + QETH_DBF_TEXT_(SETUP, 2, "%s", dev_name(&gdev->dev)); card = qeth_alloc_card(); if (!card) { diff --git a/drivers/s390/s390_rdev.c b/drivers/s390/s390_rdev.c index 3c7145d9f9a1f74189b655b54afbae05c8d22202..64371c05a3b37a1cac8ca1df37bb4b93389953d1 100644 --- a/drivers/s390/s390_rdev.c +++ b/drivers/s390/s390_rdev.c @@ -30,7 +30,7 @@ s390_root_dev_register(const char *name) dev = kzalloc(sizeof(struct device), GFP_KERNEL); if (!dev) return ERR_PTR(-ENOMEM); - strncpy(dev->bus_id, name, min(strlen(name), (size_t)BUS_ID_SIZE)); + dev_set_name(dev, name); dev->release = s390_root_dev_release; ret = device_register(dev); if (ret) { diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 24255e42dc30bbb4aa6283c31ac1ea170a62b661..3b56220fb900291df60b56284191b6e66119a02d 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -283,8 +283,8 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) unit->port = port; unit->fcp_lun = fcp_lun; - snprintf(unit->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", - (unsigned long long) fcp_lun); + dev_set_name(&unit->sysfs_device, "0x%016llx", + (unsigned long long) fcp_lun); unit->sysfs_device.parent = &port->sysfs_device; unit->sysfs_device.release = zfcp_sysfs_unit_release; dev_set_drvdata(&unit->sysfs_device, unit); @@ -610,8 +610,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); atomic_set(&port->refcount, 0); - snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", - (unsigned long long) wwpn); + dev_set_name(&port->sysfs_device, "0x%016llx", wwpn); port->sysfs_device.parent = &adapter->ccw_device->dev; port->sysfs_device.release = zfcp_sysfs_port_release; diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 73eb41580f25c40fe3dc41861703de5c9f9f2bb8..8a13071c444cab500dfe4318ef4d50bd16243aad 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -596,7 +596,7 @@ struct zfcp_data { struct semaphore config_sema; /* serialises configuration changes */ atomic_t loglevel; /* current loglevel */ - char init_busid[BUS_ID_SIZE]; + char init_busid[20]; u64 init_wwpn; u64 init_fcp_lun; struct kmem_cache *fsf_req_qtcb_cache; @@ -619,7 +619,7 @@ struct zfcp_fsf_req_qtcb { #define ZFCP_SET 0x00000100 #define ZFCP_CLEAR 0x00000200 -#define zfcp_get_busid_by_adapter(adapter) (adapter->ccw_device->dev.bus_id) +#define zfcp_get_busid_by_adapter(adapter) (dev_name(&adapter->ccw_device->dev)) /* * Helper functions for request ID management. diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 782313131870ad928bc9a9a4072a5d3e5503ec02..9040f738ff333f47fd243486c311380f0ea00ebe 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -1376,7 +1376,7 @@ static int zfcp_erp_thread(void *data) struct zfcp_erp_action *act; unsigned long flags; - daemonize("zfcperp%s", adapter->ccw_device->dev.bus_id); + daemonize("zfcperp%s", dev_name(&adapter->ccw_device->dev)); /* Block all signals */ siginitsetinv(¤t->blocked, 0); atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 2809d789b55cbbed03e3425d607302a61a1569e7..ca9293ba1766681c7bcc24721a29b4ac37a4f5bc 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -381,7 +381,7 @@ static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, \ static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL); ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n", - unit->port->adapter->ccw_device->dev.bus_id); + dev_name(&unit->port->adapter->ccw_device->dev)); ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n", (unsigned long long) unit->port->wwpn); ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n", diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index 3eca62566d6b4468412c9ff2afdbb3b5675dc7b6..f7e8e93ff30d32266c5faf4aa0688ce75b2a651e 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -81,7 +81,10 @@ my (@stack, $re, $dre, $x, $xs); $re = qr/.*st[dw]u.*r1,-($x{1,8})\(r1\)/o; } elsif ($arch =~ /^s390x?$/) { # 11160: a7 fb ff 60 aghi %r15,-160 - $re = qr/.*ag?hi.*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})/o; + # or + # 100092: e3 f0 ff c8 ff 71 lay %r15,-56(%r15) + $re = qr/.*(?:lay|ag?hi).*\%r15,-(([0-9]{2}|[3-9])[0-9]{2}) + (?:\(\%r15\))?$/ox; } elsif ($arch =~ /^sh64$/) { #XXX: we only check for the immediate case presently, # though we will want to check for the movi/sub