Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 27 May 2010 17:48:46 +0000 (10:48 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 27 May 2010 17:48:46 +0000 (10:48 -0700)
* '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

19 files changed:
MAINTAINERS
arch/s390/Kconfig
arch/s390/boot/compressed/Makefile
arch/s390/boot/compressed/misc.c
arch/s390/include/asm/atomic.h
arch/s390/include/asm/ccwdev.h
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/entry64.S
arch/s390/kernel/kprobes.c
arch/s390/kernel/setup.c
arch/s390/kvm/Kconfig
arch/s390/kvm/sie64a.S
arch/s390/mm/cmm.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_int.h
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/ccwreq.c
drivers/s390/cio/ioasm.h

index 8b7eba2..33047a6 100644 (file)
@@ -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>
index 79d0ca0..bee1c0f 100644 (file)
@@ -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)
index 6e4a67a..1c999f7 100644 (file)
@@ -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)
index 14e0479..0851eb1 100644 (file)
@@ -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)
index 451bfbb..76daea1 100644 (file)
@@ -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)
index f4bd346..1c0030f 100644 (file)
@@ -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;
 };
index d9b490a..5232278 100644 (file)
@@ -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;
 }
index 178d925..e7192e1 100644 (file)
@@ -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
 
index 3d34eef..2a3d2bf 100644 (file)
@@ -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;
index 7d89324..c8e8e13 100644 (file)
@@ -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;
index 2f4b687..a725158 100644 (file)
@@ -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
index 31646bd..7e9d30d 100644 (file)
@@ -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:
index f87b347..eb6a2ef 100644 (file)
@@ -1,11 +1,9 @@
 /*
- *  arch/s390/mm/cmm.c
+ *  Collaborative memory management interface.
  *
- *  S390 version
- *    Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *    Copyright IBM Corp 2003,2010
+ *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
  *
- *  Collaborative memory management interface.
  */
 
 #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");
index 0e86247..33975e9 100644 (file)
@@ -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.
index 5b1cd8d..ab84da5 100644 (file)
@@ -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,
 };
 
 /*
index 32fac18..49b431d 100644 (file)
@@ -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 *);
index 5f97ea2..97b25d6 100644 (file)
@@ -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;
                }
index 37df42a..7f206ed 100644 (file)
@@ -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;
        }
index 7592627..fac0615 100644 (file)
@@ -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;