Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6: [S390] fill out file list in s390 MAINTAINERS entry [S390] Add support for LZO-compressed kernels. [S390] cmm: get rid of CMM_PROC config option [S390] cmm: remove superfluous EXPORT_SYMBOLs plus cleanups [S390] dasd: unit check handling during internal cio I/O [S390] cio: unit check handling during internal I/O [S390] ccwgroup: add locking around drvdata access [S390] cio: remove stsch [S390] spp: remove KVM_AWARE_CMF config option [S390] kprobes: forbid probing of stnsm/stosm/epsw [S390] spp: fix compilation for CONFIG_32BIT [S390] atomic: implement atomic64_dec_if_positive [S390] cmm: fix crash on module unload
This commit is contained in:
Коммит
cc106eb35e
|
@ -4836,6 +4836,9 @@ W: http://www.ibm.com/developerworks/linux/linux390/
|
|||
S: Supported
|
||||
F: arch/s390/
|
||||
F: drivers/s390/
|
||||
F: fs/partitions/ibm.c
|
||||
F: Documentation/s390/
|
||||
F: Documentation/DocBook/s390*
|
||||
|
||||
S390 NETWORK DRIVERS
|
||||
M: Ursula Braun <ursula.braun@de.ibm.com>
|
||||
|
|
|
@ -102,6 +102,7 @@ config S390
|
|||
select HAVE_KERNEL_GZIP
|
||||
select HAVE_KERNEL_BZIP2
|
||||
select HAVE_KERNEL_LZMA
|
||||
select HAVE_KERNEL_LZO
|
||||
select ARCH_INLINE_SPIN_TRYLOCK
|
||||
select ARCH_INLINE_SPIN_TRYLOCK_BH
|
||||
select ARCH_INLINE_SPIN_LOCK
|
||||
|
@ -479,13 +480,6 @@ config CMM
|
|||
Everybody who wants to run Linux under VM should select this
|
||||
option.
|
||||
|
||||
config CMM_PROC
|
||||
bool "/proc interface to cooperative memory management"
|
||||
depends on CMM
|
||||
help
|
||||
Select this option to enable the /proc interface to the
|
||||
cooperative memory management.
|
||||
|
||||
config CMM_IUCV
|
||||
bool "IUCV special message interface to cooperative memory management"
|
||||
depends on CMM && (SMSGIUCV=y || CMM=SMSGIUCV)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
BITS := $(if $(CONFIG_64BIT),64,31)
|
||||
|
||||
targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 \
|
||||
vmlinux.bin.lzma misc.o piggy.o sizes.h head$(BITS).o
|
||||
vmlinux.bin.lzma vmlinux.bin.lzo misc.o piggy.o sizes.h head$(BITS).o
|
||||
|
||||
KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2
|
||||
KBUILD_CFLAGS += $(cflags-y)
|
||||
|
@ -47,6 +47,7 @@ vmlinux.bin.all-y := $(obj)/vmlinux.bin
|
|||
suffix-$(CONFIG_KERNEL_GZIP) := gz
|
||||
suffix-$(CONFIG_KERNEL_BZIP2) := bz2
|
||||
suffix-$(CONFIG_KERNEL_LZMA) := lzma
|
||||
suffix-$(CONFIG_KERNEL_LZO) := lzo
|
||||
|
||||
$(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y)
|
||||
$(call if_changed,gzip)
|
||||
|
@ -54,6 +55,8 @@ $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y)
|
|||
$(call if_changed,bzip2)
|
||||
$(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y)
|
||||
$(call if_changed,lzma)
|
||||
$(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y)
|
||||
$(call if_changed,lzo)
|
||||
|
||||
LDFLAGS_piggy.o := -r --format binary --oformat $(LD_BFD) -T
|
||||
$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix-y)
|
||||
|
|
|
@ -50,6 +50,10 @@ static unsigned long free_mem_end_ptr;
|
|||
#include "../../../../lib/decompress_unlzma.c"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KERNEL_LZO
|
||||
#include "../../../../lib/decompress_unlzo.c"
|
||||
#endif
|
||||
|
||||
extern _sclp_print_early(const char *);
|
||||
|
||||
int puts(const char *s)
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#define ATOMIC_INIT(i) { (i) }
|
||||
|
||||
|
@ -274,6 +275,7 @@ static inline void atomic64_clear_mask(unsigned long long mask, atomic64_t *v)
|
|||
static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u)
|
||||
{
|
||||
long long c, old;
|
||||
|
||||
c = atomic64_read(v);
|
||||
for (;;) {
|
||||
if (unlikely(c == u))
|
||||
|
@ -286,6 +288,23 @@ static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u)
|
|||
return c != u;
|
||||
}
|
||||
|
||||
static inline long long atomic64_dec_if_positive(atomic64_t *v)
|
||||
{
|
||||
long long c, old, dec;
|
||||
|
||||
c = atomic64_read(v);
|
||||
for (;;) {
|
||||
dec = c - 1;
|
||||
if (unlikely(dec < 0))
|
||||
break;
|
||||
old = atomic64_cmpxchg((v), c, dec);
|
||||
if (likely(old == c))
|
||||
break;
|
||||
c = old;
|
||||
}
|
||||
return dec;
|
||||
}
|
||||
|
||||
#define atomic64_add(_i, _v) atomic64_add_return(_i, _v)
|
||||
#define atomic64_add_negative(_i, _v) (atomic64_add_return(_i, _v) < 0)
|
||||
#define atomic64_inc(_v) atomic64_add_return(1, _v)
|
||||
|
|
|
@ -91,6 +91,14 @@ struct ccw_device {
|
|||
void (*handler) (struct ccw_device *, unsigned long, struct irb *);
|
||||
};
|
||||
|
||||
/*
|
||||
* Possible CIO actions triggered by the unit check handler.
|
||||
*/
|
||||
enum uc_todo {
|
||||
UC_TODO_RETRY,
|
||||
UC_TODO_RETRY_ON_NEW_PATH,
|
||||
UC_TODO_STOP
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ccw driver - device driver for channel attached devices
|
||||
|
@ -107,6 +115,7 @@ struct ccw_device {
|
|||
* @freeze: callback for freezing during hibernation snapshotting
|
||||
* @thaw: undo work done in @freeze
|
||||
* @restore: callback for restoring after hibernation
|
||||
* @uc_handler: callback for unit check handler
|
||||
* @driver: embedded device driver structure
|
||||
* @name: device driver name
|
||||
*/
|
||||
|
@ -124,6 +133,7 @@ struct ccw_driver {
|
|||
int (*freeze)(struct ccw_device *);
|
||||
int (*thaw) (struct ccw_device *);
|
||||
int (*restore)(struct ccw_device *);
|
||||
enum uc_todo (*uc_handler) (struct ccw_device *, struct irb *);
|
||||
struct device_driver driver;
|
||||
char *name;
|
||||
};
|
||||
|
|
|
@ -132,8 +132,6 @@ int main(void)
|
|||
DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));
|
||||
DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags));
|
||||
DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func));
|
||||
DEFINE(__LC_SIE_HOOK, offsetof(struct _lowcore, sie_hook));
|
||||
DEFINE(__LC_CMF_HPP, offsetof(struct _lowcore, cmf_hpp));
|
||||
DEFINE(__LC_IRB, offsetof(struct _lowcore, irb));
|
||||
DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area));
|
||||
DEFINE(__LC_CLOCK_COMP_SAVE_AREA, offsetof(struct _lowcore, clock_comp_save_area));
|
||||
|
@ -154,6 +152,8 @@ int main(void)
|
|||
DEFINE(__LC_FP_CREG_SAVE_AREA, offsetof(struct _lowcore, fpt_creg_save_area));
|
||||
DEFINE(__LC_LAST_BREAK, offsetof(struct _lowcore, breaking_event_addr));
|
||||
DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data));
|
||||
DEFINE(__LC_SIE_HOOK, offsetof(struct _lowcore, sie_hook));
|
||||
DEFINE(__LC_CMF_HPP, offsetof(struct _lowcore, cmf_hpp));
|
||||
#endif /* CONFIG_32BIT */
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
|
|||
ltgr %r3,%r3
|
||||
jz 0f
|
||||
basr %r14,%r3
|
||||
0:
|
||||
0:
|
||||
#endif
|
||||
.endm
|
||||
|
||||
|
|
|
@ -63,6 +63,8 @@ int __kprobes is_prohibited_opcode(kprobe_opcode_t *instruction)
|
|||
case 0x0b: /* bsm */
|
||||
case 0x83: /* diag */
|
||||
case 0x44: /* ex */
|
||||
case 0xac: /* stnsm */
|
||||
case 0xad: /* stosm */
|
||||
return -EINVAL;
|
||||
}
|
||||
switch (*(__u16 *) instruction) {
|
||||
|
@ -72,6 +74,7 @@ int __kprobes is_prohibited_opcode(kprobe_opcode_t *instruction)
|
|||
case 0xb258: /* bsg */
|
||||
case 0xb218: /* pc */
|
||||
case 0xb228: /* pt */
|
||||
case 0xb98d: /* epsw */
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -401,7 +401,6 @@ setup_lowcore(void)
|
|||
lc->io_new_psw.mask = psw_kernel_bits;
|
||||
lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
|
||||
lc->clock_comparator = -1ULL;
|
||||
lc->cmf_hpp = -1ULL;
|
||||
lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
|
||||
lc->async_stack = (unsigned long)
|
||||
__alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
|
||||
|
@ -418,6 +417,7 @@ setup_lowcore(void)
|
|||
__ctl_set_bit(14, 29);
|
||||
}
|
||||
#else
|
||||
lc->cmf_hpp = -1ULL;
|
||||
lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0];
|
||||
#endif
|
||||
lc->sync_enter_timer = S390_lowcore.sync_enter_timer;
|
||||
|
|
|
@ -33,17 +33,6 @@ config KVM
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
config KVM_AWARE_CMF
|
||||
depends on KVM
|
||||
bool "KVM aware sampling"
|
||||
---help---
|
||||
This option enhances the sampling data from the CPU Measurement
|
||||
Facility with additional information, that allows to distinguish
|
||||
guest(s) and host when using the kernel based virtual machine
|
||||
functionality.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
# OK, it's a little counter-intuitive to do this, but it puts it neatly under
|
||||
# the virtualization menu.
|
||||
source drivers/vhost/Kconfig
|
||||
|
|
|
@ -32,12 +32,10 @@ SPI_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
|
|||
|
||||
|
||||
.macro SPP newpp
|
||||
#ifdef CONFIG_KVM_AWARE_CMF
|
||||
tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_SPP
|
||||
jz 0f
|
||||
.insn s,0xb2800000,\newpp
|
||||
0:
|
||||
#endif
|
||||
0:
|
||||
.endm
|
||||
|
||||
sie_irq_handler:
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
/*
|
||||
* arch/s390/mm/cmm.c
|
||||
*
|
||||
* S390 version
|
||||
* Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
|
||||
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
|
||||
*
|
||||
* Collaborative memory management interface.
|
||||
*
|
||||
* Copyright IBM Corp 2003,2010
|
||||
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
|
@ -20,9 +18,9 @@
|
|||
#include <linux/kthread.h>
|
||||
#include <linux/oom.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/diag.h>
|
||||
|
||||
static char *sender = "VMRMSVM";
|
||||
|
@ -53,14 +51,14 @@ static struct cmm_page_array *cmm_timed_page_list;
|
|||
static DEFINE_SPINLOCK(cmm_lock);
|
||||
|
||||
static struct task_struct *cmm_thread_ptr;
|
||||
static wait_queue_head_t cmm_thread_wait;
|
||||
static struct timer_list cmm_timer;
|
||||
static DECLARE_WAIT_QUEUE_HEAD(cmm_thread_wait);
|
||||
static DEFINE_TIMER(cmm_timer, NULL, 0, 0);
|
||||
|
||||
static void cmm_timer_fn(unsigned long);
|
||||
static void cmm_set_timer(void);
|
||||
|
||||
static long
|
||||
cmm_alloc_pages(long nr, long *counter, struct cmm_page_array **list)
|
||||
static long cmm_alloc_pages(long nr, long *counter,
|
||||
struct cmm_page_array **list)
|
||||
{
|
||||
struct cmm_page_array *pa, *npa;
|
||||
unsigned long addr;
|
||||
|
@ -99,8 +97,7 @@ cmm_alloc_pages(long nr, long *counter, struct cmm_page_array **list)
|
|||
return nr;
|
||||
}
|
||||
|
||||
static long
|
||||
cmm_free_pages(long nr, long *counter, struct cmm_page_array **list)
|
||||
static long cmm_free_pages(long nr, long *counter, struct cmm_page_array **list)
|
||||
{
|
||||
struct cmm_page_array *pa;
|
||||
unsigned long addr;
|
||||
|
@ -140,11 +137,10 @@ static int cmm_oom_notify(struct notifier_block *self,
|
|||
}
|
||||
|
||||
static struct notifier_block cmm_oom_nb = {
|
||||
.notifier_call = cmm_oom_notify
|
||||
.notifier_call = cmm_oom_notify,
|
||||
};
|
||||
|
||||
static int
|
||||
cmm_thread(void *dummy)
|
||||
static int cmm_thread(void *dummy)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
@ -170,7 +166,7 @@ cmm_thread(void *dummy)
|
|||
cmm_timed_pages_target = cmm_timed_pages;
|
||||
} else if (cmm_timed_pages_target < cmm_timed_pages) {
|
||||
cmm_free_pages(1, &cmm_timed_pages,
|
||||
&cmm_timed_page_list);
|
||||
&cmm_timed_page_list);
|
||||
}
|
||||
if (cmm_timed_pages > 0 && !timer_pending(&cmm_timer))
|
||||
cmm_set_timer();
|
||||
|
@ -178,14 +174,12 @@ cmm_thread(void *dummy)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
cmm_kick_thread(void)
|
||||
static void cmm_kick_thread(void)
|
||||
{
|
||||
wake_up(&cmm_thread_wait);
|
||||
}
|
||||
|
||||
static void
|
||||
cmm_set_timer(void)
|
||||
static void cmm_set_timer(void)
|
||||
{
|
||||
if (cmm_timed_pages_target <= 0 || cmm_timeout_seconds <= 0) {
|
||||
if (timer_pending(&cmm_timer))
|
||||
|
@ -202,8 +196,7 @@ cmm_set_timer(void)
|
|||
add_timer(&cmm_timer);
|
||||
}
|
||||
|
||||
static void
|
||||
cmm_timer_fn(unsigned long ignored)
|
||||
static void cmm_timer_fn(unsigned long ignored)
|
||||
{
|
||||
long nr;
|
||||
|
||||
|
@ -216,57 +209,49 @@ cmm_timer_fn(unsigned long ignored)
|
|||
cmm_set_timer();
|
||||
}
|
||||
|
||||
void
|
||||
cmm_set_pages(long nr)
|
||||
static void cmm_set_pages(long nr)
|
||||
{
|
||||
cmm_pages_target = nr;
|
||||
cmm_kick_thread();
|
||||
}
|
||||
|
||||
long
|
||||
cmm_get_pages(void)
|
||||
static long cmm_get_pages(void)
|
||||
{
|
||||
return cmm_pages;
|
||||
}
|
||||
|
||||
void
|
||||
cmm_add_timed_pages(long nr)
|
||||
static void cmm_add_timed_pages(long nr)
|
||||
{
|
||||
cmm_timed_pages_target += nr;
|
||||
cmm_kick_thread();
|
||||
}
|
||||
|
||||
long
|
||||
cmm_get_timed_pages(void)
|
||||
static long cmm_get_timed_pages(void)
|
||||
{
|
||||
return cmm_timed_pages;
|
||||
}
|
||||
|
||||
void
|
||||
cmm_set_timeout(long nr, long seconds)
|
||||
static void cmm_set_timeout(long nr, long seconds)
|
||||
{
|
||||
cmm_timeout_pages = nr;
|
||||
cmm_timeout_seconds = seconds;
|
||||
cmm_set_timer();
|
||||
}
|
||||
|
||||
static int
|
||||
cmm_skip_blanks(char *cp, char **endp)
|
||||
static int cmm_skip_blanks(char *cp, char **endp)
|
||||
{
|
||||
char *str;
|
||||
|
||||
for (str = cp; *str == ' ' || *str == '\t'; str++);
|
||||
for (str = cp; *str == ' ' || *str == '\t'; str++)
|
||||
;
|
||||
*endp = str;
|
||||
return str != cp;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMM_PROC
|
||||
|
||||
static struct ctl_table cmm_table[];
|
||||
|
||||
static int
|
||||
cmm_pages_handler(ctl_table *ctl, int write,
|
||||
void __user *buffer, size_t *lenp, loff_t *ppos)
|
||||
static int cmm_pages_handler(ctl_table *ctl, int write, void __user *buffer,
|
||||
size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
char buf[16], *p;
|
||||
long nr;
|
||||
|
@ -305,9 +290,8 @@ cmm_pages_handler(ctl_table *ctl, int write,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
cmm_timeout_handler(ctl_table *ctl, int write,
|
||||
void __user *buffer, size_t *lenp, loff_t *ppos)
|
||||
static int cmm_timeout_handler(ctl_table *ctl, int write, void __user *buffer,
|
||||
size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
char buf[64], *p;
|
||||
long nr, seconds;
|
||||
|
@ -370,12 +354,10 @@ static struct ctl_table cmm_dir_table[] = {
|
|||
},
|
||||
{ }
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CMM_IUCV
|
||||
#define SMSG_PREFIX "CMM"
|
||||
static void
|
||||
cmm_smsg_target(const char *from, char *msg)
|
||||
static void cmm_smsg_target(const char *from, char *msg)
|
||||
{
|
||||
long nr, seconds;
|
||||
|
||||
|
@ -445,16 +427,13 @@ static struct notifier_block cmm_power_notifier = {
|
|||
.notifier_call = cmm_power_event,
|
||||
};
|
||||
|
||||
static int
|
||||
cmm_init (void)
|
||||
static int cmm_init(void)
|
||||
{
|
||||
int rc = -ENOMEM;
|
||||
|
||||
#ifdef CONFIG_CMM_PROC
|
||||
cmm_sysctl_header = register_sysctl_table(cmm_dir_table);
|
||||
if (!cmm_sysctl_header)
|
||||
goto out_sysctl;
|
||||
#endif
|
||||
#ifdef CONFIG_CMM_IUCV
|
||||
rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
|
||||
if (rc < 0)
|
||||
|
@ -466,8 +445,6 @@ cmm_init (void)
|
|||
rc = register_pm_notifier(&cmm_power_notifier);
|
||||
if (rc)
|
||||
goto out_pm;
|
||||
init_waitqueue_head(&cmm_thread_wait);
|
||||
init_timer(&cmm_timer);
|
||||
cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread");
|
||||
rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0;
|
||||
if (rc)
|
||||
|
@ -483,36 +460,26 @@ out_oom_notify:
|
|||
smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target);
|
||||
out_smsg:
|
||||
#endif
|
||||
#ifdef CONFIG_CMM_PROC
|
||||
unregister_sysctl_table(cmm_sysctl_header);
|
||||
out_sysctl:
|
||||
#endif
|
||||
del_timer_sync(&cmm_timer);
|
||||
return rc;
|
||||
}
|
||||
module_init(cmm_init);
|
||||
|
||||
static void
|
||||
cmm_exit(void)
|
||||
static void cmm_exit(void)
|
||||
{
|
||||
kthread_stop(cmm_thread_ptr);
|
||||
unregister_pm_notifier(&cmm_power_notifier);
|
||||
unregister_oom_notifier(&cmm_oom_nb);
|
||||
cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
|
||||
cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
|
||||
#ifdef CONFIG_CMM_PROC
|
||||
unregister_sysctl_table(cmm_sysctl_header);
|
||||
#endif
|
||||
#ifdef CONFIG_CMM_IUCV
|
||||
smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target);
|
||||
#endif
|
||||
unregister_pm_notifier(&cmm_power_notifier);
|
||||
unregister_oom_notifier(&cmm_oom_nb);
|
||||
kthread_stop(cmm_thread_ptr);
|
||||
del_timer_sync(&cmm_timer);
|
||||
cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
|
||||
cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
|
||||
}
|
||||
|
||||
module_init(cmm_init);
|
||||
module_exit(cmm_exit);
|
||||
|
||||
EXPORT_SYMBOL(cmm_set_pages);
|
||||
EXPORT_SYMBOL(cmm_get_pages);
|
||||
EXPORT_SYMBOL(cmm_add_timed_pages);
|
||||
EXPORT_SYMBOL(cmm_get_timed_pages);
|
||||
EXPORT_SYMBOL(cmm_set_timeout);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -1186,6 +1186,29 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
|
|||
dasd_schedule_device_bh(device);
|
||||
}
|
||||
|
||||
enum uc_todo dasd_generic_uc_handler(struct ccw_device *cdev, struct irb *irb)
|
||||
{
|
||||
struct dasd_device *device;
|
||||
|
||||
device = dasd_device_from_cdev_locked(cdev);
|
||||
|
||||
if (IS_ERR(device))
|
||||
goto out;
|
||||
if (test_bit(DASD_FLAG_OFFLINE, &device->flags) ||
|
||||
device->state != device->target ||
|
||||
!device->discipline->handle_unsolicited_interrupt){
|
||||
dasd_put_device(device);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dasd_device_clear_timer(device);
|
||||
device->discipline->handle_unsolicited_interrupt(device, irb);
|
||||
dasd_put_device(device);
|
||||
out:
|
||||
return UC_TODO_RETRY;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dasd_generic_uc_handler);
|
||||
|
||||
/*
|
||||
* If we have an error on a dasd_block layer request then we cancel
|
||||
* and return all further requests from the same dasd_block as well.
|
||||
|
|
|
@ -3436,6 +3436,7 @@ static struct ccw_driver dasd_eckd_driver = {
|
|||
.freeze = dasd_generic_pm_freeze,
|
||||
.thaw = dasd_generic_restore_device,
|
||||
.restore = dasd_generic_restore_device,
|
||||
.uc_handler = dasd_generic_uc_handler,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -617,6 +617,7 @@ int dasd_generic_notify(struct ccw_device *, int);
|
|||
void dasd_generic_handle_state_change(struct dasd_device *);
|
||||
int dasd_generic_pm_freeze(struct ccw_device *);
|
||||
int dasd_generic_restore_device(struct ccw_device *);
|
||||
enum uc_todo dasd_generic_uc_handler(struct ccw_device *, struct irb *);
|
||||
|
||||
int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int);
|
||||
char *dasd_get_sense(struct irb *);
|
||||
|
|
|
@ -123,8 +123,10 @@ ccwgroup_release (struct device *dev)
|
|||
|
||||
for (i = 0; i < gdev->count; i++) {
|
||||
if (gdev->cdev[i]) {
|
||||
spin_lock_irq(gdev->cdev[i]->ccwlock);
|
||||
if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
|
||||
dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
|
||||
spin_unlock_irq(gdev->cdev[i]->ccwlock);
|
||||
put_device(&gdev->cdev[i]->dev);
|
||||
}
|
||||
}
|
||||
|
@ -262,11 +264,14 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
|
|||
goto error;
|
||||
}
|
||||
/* Don't allow a device to belong to more than one group. */
|
||||
spin_lock_irq(gdev->cdev[i]->ccwlock);
|
||||
if (dev_get_drvdata(&gdev->cdev[i]->dev)) {
|
||||
spin_unlock_irq(gdev->cdev[i]->ccwlock);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
|
||||
spin_unlock_irq(gdev->cdev[i]->ccwlock);
|
||||
}
|
||||
/* Check for sufficient number of bus ids. */
|
||||
if (i < num_devices && !curr_buf) {
|
||||
|
@ -303,8 +308,10 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
|
|||
error:
|
||||
for (i = 0; i < num_devices; i++)
|
||||
if (gdev->cdev[i]) {
|
||||
spin_lock_irq(gdev->cdev[i]->ccwlock);
|
||||
if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
|
||||
dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
|
||||
spin_unlock_irq(gdev->cdev[i]->ccwlock);
|
||||
put_device(&gdev->cdev[i]->dev);
|
||||
gdev->cdev[i] = NULL;
|
||||
}
|
||||
|
|
|
@ -159,6 +159,7 @@ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb)
|
|||
{
|
||||
struct irb *irb = &cdev->private->irb;
|
||||
struct cmd_scsw *scsw = &irb->scsw.cmd;
|
||||
enum uc_todo todo;
|
||||
|
||||
/* Perform BASIC SENSE if needed. */
|
||||
if (ccw_device_accumulate_and_sense(cdev, lcirb))
|
||||
|
@ -178,6 +179,20 @@ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb)
|
|||
/* Check for command reject. */
|
||||
if (irb->ecw[0] & SNS0_CMD_REJECT)
|
||||
return IO_REJECTED;
|
||||
/* Ask the driver what to do */
|
||||
if (cdev->drv && cdev->drv->uc_handler) {
|
||||
todo = cdev->drv->uc_handler(cdev, lcirb);
|
||||
switch (todo) {
|
||||
case UC_TODO_RETRY:
|
||||
return IO_STATUS_ERROR;
|
||||
case UC_TODO_RETRY_ON_NEW_PATH:
|
||||
return IO_PATH_ERROR;
|
||||
case UC_TODO_STOP:
|
||||
return IO_REJECTED;
|
||||
default:
|
||||
return IO_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
/* Assume that unexpected SENSE data implies an error. */
|
||||
return IO_STATUS_ERROR;
|
||||
}
|
||||
|
|
|
@ -23,21 +23,6 @@ struct tpi_info {
|
|||
* Some S390 specific IO instructions as inline
|
||||
*/
|
||||
|
||||
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(%3)\n"
|
||||
" ipm %0\n"
|
||||
" srl %0,28"
|
||||
: "=d" (ccode), "=m" (*addr)
|
||||
: "d" (reg1), "a" (addr)
|
||||
: "cc");
|
||||
return ccode;
|
||||
}
|
||||
|
||||
static inline int stsch_err(struct subchannel_id schid, struct schib *addr)
|
||||
{
|
||||
register struct subchannel_id reg1 asm ("1") = schid;
|
||||
|
|
Загрузка…
Ссылка в новой задаче