]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6
authorLinus Torvalds <torvalds@g5.osdl.org>
Thu, 29 Jun 2006 18:01:17 +0000 (11:01 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Thu, 29 Jun 2006 18:01:17 +0000 (11:01 -0700)
* 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6: (28 commits)
  [S390] rework of channel measurement facility.
  [S390] appldata enhancements.
  [S390] Add vmpanic parameter.
  [S390] add PAV support to the dasd driver.
  [S390] remove export of sys_call_table
  [S390] remove unused macros from binfmt_elf32.c
  [S390] fix duplicate export of overflow{ug}id
  [S390] cio chpid offline.
  [S390] avenrun export in appdata_base.c
  Convert s390_collect_crw_info() in s390mach.c from being started
  [S390] dasd eer data format.
  [S390] preempt_count initialization.
  [S390] head.S code moving.
  [S390] dasd whitespace and other cosmetics.
  [S390] virtual cpu accounting vs. machine checks.
  [S390] add __cpuinit to appldata cpu hotplug notifier.
  [S390] dasd_eckd_dump_sense bug.
  [S390] missing check in dasd_eer_open.
  [S390] modular 3270 driver.
  [S390] console_unblank woes.
  ...

48 files changed:
Documentation/kernel-parameters.txt
arch/s390/appldata/appldata.h
arch/s390/appldata/appldata_base.c
arch/s390/appldata/appldata_mem.c
arch/s390/appldata/appldata_net_sum.c
arch/s390/appldata/appldata_os.c
arch/s390/kernel/binfmt_elf32.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/head.S
arch/s390/kernel/head31.S
arch/s390/kernel/head64.S
arch/s390/kernel/s390_ksyms.c
arch/s390/kernel/setup.c
arch/s390/kernel/traps.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_3370_erp.c
drivers/s390/block/dasd_3990_erp.c
drivers/s390/block/dasd_9336_erp.c
drivers/s390/block/dasd_9343_erp.c
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_diag.h
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_eckd.h
drivers/s390/block/dasd_eer.c
drivers/s390/block/dasd_erp.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_fba.h
drivers/s390/block/dasd_int.h
drivers/s390/block/dasd_ioctl.c
drivers/s390/char/raw3270.c
drivers/s390/cio/blacklist.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chsc.c
drivers/s390/cio/cmf.c
drivers/s390/cio/css.c
drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_ops.c
drivers/s390/s390mach.c
include/asm-s390/bitops.h
include/asm-s390/cio.h
include/asm-s390/cmb.h
include/asm-s390/dasd.h
include/asm-s390/thread_info.h
include/asm-s390/unistd.h

index 0d189c93eeaf94b283d22fd39d4dea8274d2d3cc..25f8d20dac534f07a0bf285feb35de115e2ac514 100644 (file)
@@ -1689,9 +1689,14 @@ running once the system is up.
                        decrease the size and leave more room for directly
                        mapped kernel RAM.
 
-       vmhalt=         [KNL,S390]
+       vmhalt=         [KNL,S390] Perform z/VM CP command after system halt.
+                       Format: <command>
 
-       vmpoff=         [KNL,S390]
+       vmpanic=        [KNL,S390] Perform z/VM CP command after kernel panic.
+                       Format: <command>
+
+       vmpoff=         [KNL,S390] Perform z/VM CP command after power off.
+                       Format: <command>
 
        waveartist=     [HW,OSS]
                        Format: <io>,<irq>,<dma>,<dma2>
index e806a8922bbbe83e180e806fcbdf28efef5af700..71d65eb30650463345a6d02ca7e680b3b3f27240 100644 (file)
@@ -3,9 +3,9 @@
  *
  * Definitions and interface for Linux - z/VM Monitor Stream.
  *
- * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
  *
- * Author: Gerald Schaefer <geraldsc@de.ibm.com>
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 //#define APPLDATA_DEBUG                       /* Debug messages on/off */
 #define CTL_APPLDATA_NET_SUM   2125
 #define CTL_APPLDATA_PROC      2126
 
+#ifndef CONFIG_64BIT
+
+#define APPLDATA_START_INTERVAL_REC 0x00       /* Function codes for */
+#define APPLDATA_STOP_REC          0x01        /* DIAG 0xDC      */
+#define APPLDATA_GEN_EVENT_RECORD   0x02
+#define APPLDATA_START_CONFIG_REC   0x03
+
+#else
+
+#define APPLDATA_START_INTERVAL_REC 0x80
+#define APPLDATA_STOP_REC          0x81
+#define APPLDATA_GEN_EVENT_RECORD   0x82
+#define APPLDATA_START_CONFIG_REC   0x83
+
+#endif /* CONFIG_64BIT */
+
 #define P_INFO(x...)   printk(KERN_INFO MY_PRINT_NAME " info: " x)
 #define P_ERROR(x...)  printk(KERN_ERR MY_PRINT_NAME " error: " x)
 #define P_WARNING(x...)        printk(KERN_WARNING MY_PRINT_NAME " status: " x)
@@ -53,7 +69,11 @@ struct appldata_ops {
        void *data;                             /* record data */
        unsigned int size;                      /* size of record */
        struct module *owner;                   /* THIS_MODULE */
+       char mod_lvl[2];                        /* modification level, EBCDIC */
 };
 
 extern int appldata_register_ops(struct appldata_ops *ops);
 extern void appldata_unregister_ops(struct appldata_ops *ops);
+extern int appldata_diag(char record_nr, u16 function, unsigned long buffer,
+                        u16 length, char *mod_lvl);
+
index 54d35c13090798810a5dfcc931446e07ec0dae8a..61bc44626c043ec2bb41c0e61399b2e1127680ae 100644 (file)
@@ -5,9 +5,9 @@
  * Exports appldata_register_ops() and appldata_unregister_ops() for the
  * data gathering modules.
  *
- * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
  *
- * Author: Gerald Schaefer <geraldsc@de.ibm.com>
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 #include <linux/config.h>
 
 #define TOD_MICRO      0x01000                 /* nr. of TOD clock units
                                                   for 1 microsecond */
-#ifndef CONFIG_64BIT
-
-#define APPLDATA_START_INTERVAL_REC 0x00       /* Function codes for */
-#define APPLDATA_STOP_REC          0x01        /* DIAG 0xDC      */
-#define APPLDATA_GEN_EVENT_RECORD   0x02
-#define APPLDATA_START_CONFIG_REC   0x03
-
-#else
-
-#define APPLDATA_START_INTERVAL_REC 0x80
-#define APPLDATA_STOP_REC          0x81
-#define APPLDATA_GEN_EVENT_RECORD   0x82
-#define APPLDATA_START_CONFIG_REC   0x83
-
-#endif /* CONFIG_64BIT */
-
 
 /*
  * Parameter list for DIAGNOSE X'DC'
@@ -195,8 +179,8 @@ static void appldata_work_fn(void *data)
  *
  * prepare parameter list, issue DIAG 0xDC
  */
-static int appldata_diag(char record_nr, u16 function, unsigned long buffer,
-                       u16 length)
+int appldata_diag(char record_nr, u16 function, unsigned long buffer,
+                       u16 length, char *mod_lvl)
 {
        unsigned long ry;
        struct appldata_product_id {
@@ -214,7 +198,7 @@ static int appldata_diag(char record_nr, u16 function, unsigned long buffer,
                .record_nr  = record_nr,
                .version_nr = {0xF2, 0xF6},             /* "26" */
                .release_nr = {0xF0, 0xF1},             /* "01" */
-               .mod_lvl    = {0xF0, 0xF0},             /* "00" */
+               .mod_lvl    = {mod_lvl[0], mod_lvl[1]},
        };
        struct appldata_parameter_list appldata_parameter_list = {
                                .diag = 0xDC,
@@ -467,24 +451,25 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
                        module_put(ops->owner);
                        return -ENODEV;
                }
-               ops->active = 1;
                ops->callback(ops->data);       // init record
                rc = appldata_diag(ops->record_nr,
                                        APPLDATA_START_INTERVAL_REC,
-                                       (unsigned long) ops->data, ops->size);
+                                       (unsigned long) ops->data, ops->size,
+                                       ops->mod_lvl);
                if (rc != 0) {
                        P_ERROR("START DIAG 0xDC for %s failed, "
                                "return code: %d\n", ops->name, rc);
                        module_put(ops->owner);
-                       ops->active = 0;
                } else {
                        P_INFO("Monitoring %s data enabled, "
                                "DIAG 0xDC started.\n", ops->name);
+                       ops->active = 1;
                }
        } else if ((buf[0] == '0') && (ops->active == 1)) {
                ops->active = 0;
                rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
-                               (unsigned long) ops->data, ops->size);
+                               (unsigned long) ops->data, ops->size,
+                               ops->mod_lvl);
                if (rc != 0) {
                        P_ERROR("STOP DIAG 0xDC for %s failed, "
                                "return code: %d\n", ops->name, rc);
@@ -633,7 +618,7 @@ appldata_offline_cpu(int cpu)
        spin_unlock(&appldata_timer_lock);
 }
 
-static int
+static int __cpuinit
 appldata_cpu_notify(struct notifier_block *self,
                    unsigned long action, void *hcpu)
 {
@@ -710,7 +695,8 @@ static void __exit appldata_exit(void)
        list_for_each(lh, &appldata_ops_list) {
                ops = list_entry(lh, struct appldata_ops, list);
                rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
-                               (unsigned long) ops->data, ops->size);
+                               (unsigned long) ops->data, ops->size,
+                               ops->mod_lvl);
                if (rc != 0) {
                        P_ERROR("STOP DIAG 0xDC for %s failed, "
                                "return code: %d\n", ops->name, rc);
@@ -739,6 +725,7 @@ MODULE_DESCRIPTION("Linux-VM Monitor Stream, base infrastructure");
 
 EXPORT_SYMBOL_GPL(appldata_register_ops);
 EXPORT_SYMBOL_GPL(appldata_unregister_ops);
+EXPORT_SYMBOL_GPL(appldata_diag);
 
 #ifdef MODULE
 /*
@@ -779,7 +766,6 @@ unsigned long nr_iowait(void)
 #endif /* MODULE */
 EXPORT_SYMBOL_GPL(si_swapinfo);
 EXPORT_SYMBOL_GPL(nr_threads);
-EXPORT_SYMBOL_GPL(avenrun);
 EXPORT_SYMBOL_GPL(get_full_page_state);
 EXPORT_SYMBOL_GPL(nr_running);
 EXPORT_SYMBOL_GPL(nr_iowait);
index f0e2fbed3d4cf86a8000ec212e435546098507fc..7915a197d96d227bb2175ada9125be89399fafa5 100644 (file)
@@ -4,9 +4,9 @@
  * Data gathering module for Linux-VM Monitor Stream, Stage 1.
  * Collects data related to memory management.
  *
- * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
  *
- * Author: Gerald Schaefer <geraldsc@de.ibm.com>
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 #include <linux/config.h>
@@ -152,6 +152,7 @@ static struct appldata_ops ops = {
        .callback  = &appldata_get_mem_data,
        .data      = &appldata_mem_data,
        .owner     = THIS_MODULE,
+       .mod_lvl   = {0xF0, 0xF0},              /* EBCDIC "00" */
 };
 
 
index 2a4c7432db4ac2960cde34ee6033671fe171cfc5..39b7bdecbf0563f38046245af32d0258c2054c05 100644 (file)
@@ -5,9 +5,9 @@
  * Collects accumulated network statistics (Packets received/transmitted,
  * dropped, errors, ...).
  *
- * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
  *
- * Author: Gerald Schaefer <geraldsc@de.ibm.com>
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 #include <linux/config.h>
@@ -152,6 +152,7 @@ static struct appldata_ops ops = {
        .callback  = &appldata_get_net_sum_data,
        .data      = &appldata_net_sum_data,
        .owner     = THIS_MODULE,
+       .mod_lvl   = {0xF0, 0xF0},              /* EBCDIC "00" */
 };
 
 
index 99ddd3bf2fbaac6bb2e5ef49fbd43e7c16bac0f2..f2b44a2f1deca958c9f1840d47407b149a730041 100644 (file)
@@ -4,9 +4,9 @@
  * Data gathering module for Linux-VM Monitor Stream, Stage 1.
  * Collects misc. OS related data (CPU utilization, running processes).
  *
- * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
  *
- * Author: Gerald Schaefer <geraldsc@de.ibm.com>
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 #include <linux/config.h>
@@ -44,11 +44,14 @@ struct appldata_os_per_cpu {
        u32 per_cpu_system;     /* ... spent in kernel mode         */
        u32 per_cpu_idle;       /* ... spent in idle mode           */
 
-// New in 2.6 -->
+       /* New in 2.6 */
        u32 per_cpu_irq;        /* ... spent in interrupts          */
        u32 per_cpu_softirq;    /* ... spent in softirqs            */
        u32 per_cpu_iowait;     /* ... spent while waiting for I/O  */
-// <-- New in 2.6
+
+       /* New in modification level 01 */
+       u32 per_cpu_steal;      /* ... stolen by hypervisor         */
+       u32 cpu_id;             /* number of this CPU               */
 } __attribute__((packed));
 
 struct appldata_os_data {
@@ -68,10 +71,9 @@ struct appldata_os_data {
        u32 avenrun[3];         /* average nr. of running processes during */
                                /* the last 1, 5 and 15 minutes */
 
-// New in 2.6 -->
+       /* New in 2.6 */
        u32 nr_iowait;          /* number of blocked threads
                                   (waiting for I/O)               */
-// <-- New in 2.6
 
        /* per cpu data */
        struct appldata_os_per_cpu os_cpu[0];
@@ -79,6 +81,14 @@ struct appldata_os_data {
 
 static struct appldata_os_data *appldata_os_data;
 
+static struct appldata_ops ops = {
+       .ctl_nr    = CTL_APPLDATA_OS,
+       .name      = "os",
+       .record_nr = APPLDATA_RECORD_OS_ID,
+       .owner     = THIS_MODULE,
+       .mod_lvl   = {0xF0, 0xF1},              /* EBCDIC "01" */
+};
+
 
 static inline void appldata_print_debug(struct appldata_os_data *os_data)
 {
@@ -100,15 +110,17 @@ static inline void appldata_print_debug(struct appldata_os_data *os_data)
        P_DEBUG("nr_cpus = %u\n", os_data->nr_cpus);
        for (i = 0; i < os_data->nr_cpus; i++) {
                P_DEBUG("cpu%u : user = %u, nice = %u, system = %u, "
-                       "idle = %u, irq = %u, softirq = %u, iowait = %u\n",
-                               i,
+                       "idle = %u, irq = %u, softirq = %u, iowait = %u, "
+                       "steal = %u\n",
+                               os_data->os_cpu[i].cpu_id,
                                os_data->os_cpu[i].per_cpu_user,
                                os_data->os_cpu[i].per_cpu_nice,
                                os_data->os_cpu[i].per_cpu_system,
                                os_data->os_cpu[i].per_cpu_idle,
                                os_data->os_cpu[i].per_cpu_irq,
                                os_data->os_cpu[i].per_cpu_softirq,
-                               os_data->os_cpu[i].per_cpu_iowait);
+                               os_data->os_cpu[i].per_cpu_iowait,
+                               os_data->os_cpu[i].per_cpu_steal);
        }
 
        P_DEBUG("sync_count_1 = %u\n", os_data->sync_count_1);
@@ -123,14 +135,13 @@ static inline void appldata_print_debug(struct appldata_os_data *os_data)
  */
 static void appldata_get_os_data(void *data)
 {
-       int i, j;
+       int i, j, rc;
        struct appldata_os_data *os_data;
+       unsigned int new_size;
 
        os_data = data;
        os_data->sync_count_1++;
 
-       os_data->nr_cpus = num_online_cpus();
-
        os_data->nr_threads = nr_threads;
        os_data->nr_running = nr_running();
        os_data->nr_iowait  = nr_iowait();
@@ -154,9 +165,44 @@ static void appldata_get_os_data(void *data)
                        cputime_to_jiffies(kstat_cpu(i).cpustat.softirq);
                os_data->os_cpu[j].per_cpu_iowait =
                        cputime_to_jiffies(kstat_cpu(i).cpustat.iowait);
+               os_data->os_cpu[j].per_cpu_steal =
+                       cputime_to_jiffies(kstat_cpu(i).cpustat.steal);
+               os_data->os_cpu[j].cpu_id = i;
                j++;
        }
 
+       os_data->nr_cpus = j;
+
+       new_size = sizeof(struct appldata_os_data) +
+                  (os_data->nr_cpus * sizeof(struct appldata_os_per_cpu));
+       if (ops.size != new_size) {
+               if (ops.active) {
+                       rc = appldata_diag(APPLDATA_RECORD_OS_ID,
+                                          APPLDATA_START_INTERVAL_REC,
+                                          (unsigned long) ops.data, new_size,
+                                          ops.mod_lvl);
+                       if (rc != 0) {
+                               P_ERROR("os: START NEW DIAG 0xDC failed, "
+                                       "return code: %d, new size = %i\n", rc,
+                                       new_size);
+                               P_INFO("os: stopping old record now\n");
+                       } else
+                               P_INFO("os: new record size = %i\n", new_size);
+
+                       rc = appldata_diag(APPLDATA_RECORD_OS_ID,
+                                          APPLDATA_STOP_REC,
+                                          (unsigned long) ops.data, ops.size,
+                                          ops.mod_lvl);
+                       if (rc != 0)
+                               P_ERROR("os: STOP OLD DIAG 0xDC failed, "
+                                       "return code: %d, old size = %i\n", rc,
+                                       ops.size);
+                       else
+                               P_INFO("os: old record size = %i stopped\n",
+                                       ops.size);
+               }
+               ops.size = new_size;
+       }
        os_data->timestamp = get_clock();
        os_data->sync_count_2++;
 #ifdef APPLDATA_DEBUG
@@ -165,15 +211,6 @@ static void appldata_get_os_data(void *data)
 }
 
 
-static struct appldata_ops ops = {
-       .ctl_nr    = CTL_APPLDATA_OS,
-       .name      = "os",
-       .record_nr = APPLDATA_RECORD_OS_ID,
-       .callback  = &appldata_get_os_data,
-       .owner     = THIS_MODULE,
-};
-
-
 /*
  * appldata_os_init()
  *
@@ -181,26 +218,25 @@ static struct appldata_ops ops = {
  */
 static int __init appldata_os_init(void)
 {
-       int rc, size;
+       int rc, max_size;
 
-       size = sizeof(struct appldata_os_data) +
-               (NR_CPUS * sizeof(struct appldata_os_per_cpu));
-       if (size > APPLDATA_MAX_REC_SIZE) {
-               P_ERROR("Size of record = %i, bigger than maximum (%i)!\n",
-                       size, APPLDATA_MAX_REC_SIZE);
+       max_size = sizeof(struct appldata_os_data) +
+                  (NR_CPUS * sizeof(struct appldata_os_per_cpu));
+       if (max_size > APPLDATA_MAX_REC_SIZE) {
+               P_ERROR("Max. size of OS record = %i, bigger than maximum "
+                       "record size (%i)\n", max_size, APPLDATA_MAX_REC_SIZE);
                rc = -ENOMEM;
                goto out;
        }
-       P_DEBUG("sizeof(os) = %i, sizeof(os_cpu) = %lu\n", size,
+       P_DEBUG("max. sizeof(os) = %i, sizeof(os_cpu) = %lu\n", max_size,
                sizeof(struct appldata_os_per_cpu));
 
-       appldata_os_data = kmalloc(size, GFP_DMA);
+       appldata_os_data = kzalloc(max_size, GFP_DMA);
        if (appldata_os_data == NULL) {
                P_ERROR("No memory for %s!\n", ops.name);
                rc = -ENOMEM;
                goto out;
        }
-       memset(appldata_os_data, 0, size);
 
        appldata_os_data->per_cpu_size = sizeof(struct appldata_os_per_cpu);
        appldata_os_data->cpu_offset   = offsetof(struct appldata_os_data,
@@ -208,7 +244,7 @@ static int __init appldata_os_init(void)
        P_DEBUG("cpu offset = %u\n", appldata_os_data->cpu_offset);
 
        ops.data = appldata_os_data;
-       ops.size = size;
+       ops.callback  = &appldata_get_os_data;
        rc = appldata_register_ops(&ops);
        if (rc != 0) {
                P_ERROR("Error registering ops, rc = %i\n", rc);
index 1f451c2cb071896f7032e990ac78256769a74c58..12a6311e9838901ed2ca106a9e34f778bd33be27 100644 (file)
@@ -177,11 +177,6 @@ struct elf_prpsinfo32
 
 #include <linux/highuid.h>
 
-#undef NEW_TO_OLD_UID
-#undef NEW_TO_OLD_GID
-#define NEW_TO_OLD_UID(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)
-#define NEW_TO_OLD_GID(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid) 
-
 #define elf_addr_t     u32
 /*
 #define init_elf_binfmt init_elf32_binfmt
index b2448487854cfbd5a36aae778be1eebec9184211..aa8b52c2140f1e672bed5c4be2715d10140e01f4 100644 (file)
@@ -93,13 +93,22 @@ STACK_SIZE  = 1 << STACK_SHIFT
        l       %r13,__LC_SVC_NEW_PSW+4 # load &system_call to %r13
        .endm
 
-       .macro  SAVE_ALL psworg,savearea,sync
+       .macro  SAVE_ALL_SYNC psworg,savearea
        la      %r12,\psworg
-       .if     \sync
        tm      \psworg+1,0x01          # test problem state bit
        bz      BASED(2f)               # skip stack setup save
        l       %r15,__LC_KERNEL_STACK  # problem state -> load ksp
-       .else
+#ifdef CONFIG_CHECK_STACK
+       b       BASED(3f)
+2:     tml     %r15,STACK_SIZE - CONFIG_STACK_GUARD
+       bz      BASED(stack_overflow)
+3:
+#endif
+2:
+       .endm
+
+       .macro  SAVE_ALL_ASYNC psworg,savearea
+       la      %r12,\psworg
        tm      \psworg+1,0x01          # test problem state bit
        bnz     BASED(1f)               # from user -> load async stack
        clc     \psworg+4(4),BASED(.Lcritical_end)
@@ -115,7 +124,6 @@ STACK_SIZE  = 1 << STACK_SHIFT
        sra     %r14,STACK_SHIFT
        be      BASED(2f)
 1:     l       %r15,__LC_ASYNC_STACK
-       .endif
 #ifdef CONFIG_CHECK_STACK
        b       BASED(3f)
 2:     tml     %r15,STACK_SIZE - CONFIG_STACK_GUARD
@@ -196,7 +204,7 @@ system_call:
        STORE_TIMER __LC_SYNC_ENTER_TIMER
 sysc_saveall:
        SAVE_ALL_BASE __LC_SAVE_AREA
-        SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        lh      %r7,0x8a          # get svc number from lowcore
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -425,7 +433,7 @@ pgm_check_handler:
        SAVE_ALL_BASE __LC_SAVE_AREA
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
         bnz     BASED(pgm_per)           # got per exception -> special case
-       SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -464,7 +472,7 @@ pgm_per:
 # Normal per exception
 #
 pgm_per_std:
-       SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -490,7 +498,7 @@ pgm_no_vtime2:
 # it was a single stepped SVC that is causing all the trouble
 #
 pgm_svcper:
-       SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -519,7 +527,7 @@ io_int_handler:
        STORE_TIMER __LC_ASYNC_ENTER_TIMER
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+16
-        SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+16,0
+       SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+16
        CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+16
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -631,7 +639,7 @@ ext_int_handler:
        STORE_TIMER __LC_ASYNC_ENTER_TIMER
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+16
-        SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16,0
+       SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16
        CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -657,21 +665,31 @@ __critical_end:
         .globl mcck_int_handler
 mcck_int_handler:
        spt     __LC_CPU_TIMER_SAVE_AREA        # revalidate cpu timer
-       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA
        lm      %r0,%r15,__LC_GPREGS_SAVE_AREA  # revalidate gprs
        SAVE_ALL_BASE __LC_SAVE_AREA+32
        la      %r12,__LC_MCK_OLD_PSW
        tm      __LC_MCCK_CODE,0x80     # system damage?
        bo      BASED(mcck_int_main)    # yes -> rest of mcck code invalid
-       tm      __LC_MCCK_CODE+5,0x02   # stored cpu timer value valid?
-       bo      BASED(0f)
-       spt     __LC_LAST_UPDATE_TIMER  # revalidate cpu timer
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
-       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_LAST_UPDATE_TIMER
-       mvc     __LC_SYNC_ENTER_TIMER(8),__LC_LAST_UPDATE_TIMER
-       mvc     __LC_EXIT_TIMER(8),__LC_LAST_UPDATE_TIMER
+       mvc     __LC_SAVE_AREA+52(8),__LC_ASYNC_ENTER_TIMER
+       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA
+       tm      __LC_MCCK_CODE+5,0x02   # stored cpu timer value valid?
+       bo      BASED(1f)
+       la      %r14,__LC_SYNC_ENTER_TIMER
+       clc     0(8,%r14),__LC_ASYNC_ENTER_TIMER
+       bl      BASED(0f)
+       la      %r14,__LC_ASYNC_ENTER_TIMER
+0:     clc     0(8,%r14),__LC_EXIT_TIMER
+       bl      BASED(0f)
+       la      %r14,__LC_EXIT_TIMER
+0:     clc     0(8,%r14),__LC_LAST_UPDATE_TIMER
+       bl      BASED(0f)
+       la      %r14,__LC_LAST_UPDATE_TIMER
+0:     spt     0(%r14)
+       mvc     __LC_ASYNC_ENTER_TIMER(8),0(%r14)
+1:
 #endif
-0:     tm      __LC_MCCK_CODE+2,0x09   # mwp + ia of old psw valid?
+       tm      __LC_MCCK_CODE+2,0x09   # mwp + ia of old psw valid?
        bno     BASED(mcck_int_main)    # no -> skip cleanup critical
        tm      __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
        bnz     BASED(mcck_int_main)    # from user -> load async stack
@@ -691,7 +709,7 @@ mcck_int_main:
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      __LC_MCCK_CODE+2,0x08   # mwp of old psw valid?
        bno     BASED(mcck_no_vtime)    # no -> skip cleanup critical
-       tm      __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ?
+       tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        bz      BASED(mcck_no_vtime)
        UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
        UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
@@ -715,6 +733,20 @@ mcck_no_vtime:
        l       %r1,BASED(.Ls390_handle_mcck)
        basr    %r14,%r1                # call machine check handler
 mcck_return:
+       mvc     __LC_RETURN_MCCK_PSW(8),SP_PSW(%r15) # move return PSW
+       ni      __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+52
+       tm      __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
+       bno     BASED(0f)
+       lm      %r0,%r15,SP_R0(%r15)    # load gprs 0-15
+       stpt    __LC_EXIT_TIMER
+       lpsw    __LC_RETURN_MCCK_PSW    # back to caller
+0:
+#endif
+       lm      %r0,%r15,SP_R0(%r15)    # load gprs 0-15
+       lpsw    __LC_RETURN_MCCK_PSW    # back to caller
+
         RESTORE_ALL __LC_RETURN_MCCK_PSW,0
 
 #ifdef CONFIG_SMP
@@ -781,6 +813,8 @@ cleanup_table_sysc_leave:
        .long   sysc_leave + 0x80000000, sysc_work_loop + 0x80000000
 cleanup_table_sysc_work_loop:
        .long   sysc_work_loop + 0x80000000, sysc_reschedule + 0x80000000
+cleanup_table_io_return:
+       .long   io_return + 0x80000000, io_leave + 0x80000000
 cleanup_table_io_leave:
        .long   io_leave + 0x80000000, io_done + 0x80000000
 cleanup_table_io_work_loop:
@@ -806,6 +840,11 @@ cleanup_critical:
        bl      BASED(0f)
        clc     4(4,%r12),BASED(cleanup_table_sysc_work_loop+4)
        bl      BASED(cleanup_sysc_return)
+0:
+       clc     4(4,%r12),BASED(cleanup_table_io_return)
+       bl      BASED(0f)
+       clc     4(4,%r12),BASED(cleanup_table_io_return+4)
+       bl      BASED(cleanup_io_return)
 0:
        clc     4(4,%r12),BASED(cleanup_table_io_leave)
        bl      BASED(0f)
@@ -839,7 +878,7 @@ cleanup_system_call:
        mvc     __LC_SAVE_AREA(16),0(%r12)
 0:     st      %r13,4(%r12)
        st      %r12,__LC_SAVE_AREA+48  # argh
-       SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        l       %r12,__LC_SAVE_AREA+48  # argh
        st      %r15,12(%r12)
@@ -980,7 +1019,6 @@ cleanup_io_leave_insn:
                .long  cleanup_critical
 
 #define SYSCALL(esa,esame,emu) .long esa
-       .globl  sys_call_table
 sys_call_table:
 #include "syscalls.S"
 #undef SYSCALL
index 2ac095bc0e250373588ba658916d0bdc700577fc..f3222a1b286174b97ed2141f0007a98b8a5af780 100644 (file)
@@ -87,13 +87,22 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
        larl    %r13,system_call
        .endm
 
-        .macro  SAVE_ALL psworg,savearea,sync
+       .macro  SAVE_ALL_SYNC psworg,savearea
        la      %r12,\psworg
-       .if     \sync
        tm      \psworg+1,0x01          # test problem state bit
        jz      2f                      # skip stack setup save
        lg      %r15,__LC_KERNEL_STACK  # problem state -> load ksp
-       .else
+#ifdef CONFIG_CHECK_STACK
+       j       3f
+2:     tml     %r15,STACK_SIZE - CONFIG_STACK_GUARD
+       jz      stack_overflow
+3:
+#endif
+2:
+       .endm
+
+       .macro  SAVE_ALL_ASYNC psworg,savearea
+       la      %r12,\psworg
        tm      \psworg+1,0x01          # test problem state bit
        jnz     1f                      # from user -> load kernel stack
        clc     \psworg+8(8),BASED(.Lcritical_end)
@@ -108,7 +117,6 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
        srag    %r14,%r14,STACK_SHIFT
        jz      2f
 1:     lg      %r15,__LC_ASYNC_STACK   # load async stack
-       .endif
 #ifdef CONFIG_CHECK_STACK
        j       3f
 2:     tml     %r15,STACK_SIZE - CONFIG_STACK_GUARD
@@ -187,7 +195,7 @@ system_call:
        STORE_TIMER __LC_SYNC_ENTER_TIMER
 sysc_saveall:
        SAVE_ALL_BASE __LC_SAVE_AREA
-        SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
         CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        llgh    %r7,__LC_SVC_INT_CODE # get svc number from lowcore
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -446,7 +454,7 @@ pgm_check_handler:
        SAVE_ALL_BASE __LC_SAVE_AREA
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
         jnz     pgm_per                  # got per exception -> special case
-       SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -485,7 +493,7 @@ pgm_per:
 # Normal per exception
 #
 pgm_per_std:
-       SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -511,7 +519,7 @@ pgm_no_vtime2:
 # it was a single stepped SVC that is causing all the trouble
 #
 pgm_svcper:
-       SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -539,7 +547,7 @@ io_int_handler:
        STORE_TIMER __LC_ASYNC_ENTER_TIMER
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+32
-        SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+32,0
+       SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+32
        CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+32
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -647,7 +655,7 @@ ext_int_handler:
        STORE_TIMER __LC_ASYNC_ENTER_TIMER
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+32
-        SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32,0
+       SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32
        CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -672,21 +680,32 @@ __critical_end:
 mcck_int_handler:
        la      %r1,4095                # revalidate r1
        spt     __LC_CPU_TIMER_SAVE_AREA-4095(%r1)      # revalidate cpu timer
-       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA-4095(%r1)
        lmg     %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
        SAVE_ALL_BASE __LC_SAVE_AREA+64
        la      %r12,__LC_MCK_OLD_PSW
        tm      __LC_MCCK_CODE,0x80     # system damage?
        jo      mcck_int_main           # yes -> rest of mcck code invalid
-       tm      __LC_MCCK_CODE+5,0x02   # stored cpu timer value valid?
-       jo      0f
-       spt     __LC_LAST_UPDATE_TIMER
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
-       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_LAST_UPDATE_TIMER
-       mvc     __LC_SYNC_ENTER_TIMER(8),__LC_LAST_UPDATE_TIMER
-       mvc     __LC_EXIT_TIMER(8),__LC_LAST_UPDATE_TIMER
+       la      %r14,4095
+       mvc     __LC_SAVE_AREA+104(8),__LC_ASYNC_ENTER_TIMER
+       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA-4095(%r14)
+       tm      __LC_MCCK_CODE+5,0x02   # stored cpu timer value valid?
+       jo      1f
+       la      %r14,__LC_SYNC_ENTER_TIMER
+       clc     0(8,%r14),__LC_ASYNC_ENTER_TIMER
+       jl      0f
+       la      %r14,__LC_ASYNC_ENTER_TIMER
+0:     clc     0(8,%r14),__LC_EXIT_TIMER
+       jl      0f
+       la      %r14,__LC_EXIT_TIMER
+0:     clc     0(8,%r14),__LC_LAST_UPDATE_TIMER
+       jl      0f
+       la      %r14,__LC_LAST_UPDATE_TIMER
+0:     spt     0(%r14)
+       mvc     __LC_ASYNC_ENTER_TIMER(8),0(%r14)
+1:
 #endif
-0:     tm      __LC_MCCK_CODE+2,0x09   # mwp + ia of old psw valid?
+       tm      __LC_MCCK_CODE+2,0x09   # mwp + ia of old psw valid?
        jno     mcck_int_main           # no -> skip cleanup critical
        tm      __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
        jnz     mcck_int_main           # from user -> load kernel stack
@@ -705,7 +724,7 @@ mcck_int_main:
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      __LC_MCCK_CODE+2,0x08   # mwp of old psw valid?
        jno     mcck_no_vtime           # no -> no timer update
-       tm      __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ?
+       tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        jz      mcck_no_vtime
        UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
        UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
@@ -727,7 +746,17 @@ mcck_no_vtime:
        jno     mcck_return
        brasl   %r14,s390_handle_mcck
 mcck_return:
-        RESTORE_ALL __LC_RETURN_MCCK_PSW,0
+       mvc     __LC_RETURN_MCCK_PSW(16),SP_PSW(%r15) # move return PSW
+       ni      __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit
+       lmg     %r0,%r15,SP_R0(%r15)    # load gprs 0-15
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+104
+       tm      __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
+       jno     0f
+       stpt    __LC_EXIT_TIMER
+0:
+#endif
+       lpswe   __LC_RETURN_MCCK_PSW    # back to caller
 
 #ifdef CONFIG_SMP
 /*
@@ -789,6 +818,8 @@ cleanup_table_sysc_leave:
        .quad   sysc_leave, sysc_work_loop
 cleanup_table_sysc_work_loop:
        .quad   sysc_work_loop, sysc_reschedule
+cleanup_table_io_return:
+       .quad   io_return, io_leave
 cleanup_table_io_leave:
        .quad   io_leave, io_done
 cleanup_table_io_work_loop:
@@ -814,6 +845,11 @@ cleanup_critical:
        jl      0f
        clc     8(8,%r12),BASED(cleanup_table_sysc_work_loop+8)
        jl      cleanup_sysc_return
+0:
+       clc     8(8,%r12),BASED(cleanup_table_io_return)
+       jl      0f
+       clc     8(8,%r12),BASED(cleanup_table_io_return+8)
+       jl      cleanup_io_return
 0:
        clc     8(8,%r12),BASED(cleanup_table_io_leave)
        jl      0f
@@ -847,7 +883,7 @@ cleanup_system_call:
        mvc     __LC_SAVE_AREA(32),0(%r12)
 0:     stg     %r13,8(%r12)
        stg     %r12,__LC_SAVE_AREA+96  # argh
-       SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        lg      %r12,__LC_SAVE_AREA+96  # argh
        stg     %r15,24(%r12)
@@ -957,7 +993,6 @@ cleanup_io_leave_insn:
                .quad  __critical_end
 
 #define SYSCALL(esa,esame,emu) .long esame
-       .globl  sys_call_table
 sys_call_table:
 #include "syscalls.S"
 #undef SYSCALL
@@ -965,7 +1000,6 @@ sys_call_table:
 #ifdef CONFIG_COMPAT
 
 #define SYSCALL(esa,esame,emu) .long emu
-       .globl  sys_call_table_emu
 sys_call_table_emu:
 #include "syscalls.S"
 #undef SYSCALL
index ea88d066bf04138a19bfa31fb7351b8737b2e81d..538c82da49b1b2d614f8aaa1e57b2d864fac2975 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  arch/s390/kernel/head.S
  *
- * (C) Copyright IBM Corp. 1999, 2005
+ * Copyright (C) IBM Corp. 1999,2006
  *
  *    Author(s): Hartmut Penner <hp@de.ibm.com>
  *              Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -482,24 +482,23 @@ start:
 
 .macro GET_IPL_DEVICE
 .Lget_ipl_device:
-       basr  %r12,0
-.LGID: l     %r1,0xb8                  # get sid
+       l     %r1,0xb8                  # get sid
        sll   %r1,15                    # test if subchannel is enabled
        srl   %r1,31
        ltr   %r1,%r1
-       bz    0(%r14)                   # subchannel disabled
+       bz    2f-.LPG1(%r13)            # subchannel disabled
        l     %r1,0xb8
-       la    %r5,.Lipl_schib-.LGID(%r12)
+       la    %r5,.Lipl_schib-.LPG1(%r13)
        stsch 0(%r5)                    # get schib of subchannel
-       bnz   0(%r14)                   # schib not available
+       bnz   2f-.LPG1(%r13)            # schib not available
        tm    5(%r5),0x01               # devno valid?
-       bno   0(%r14)
-       la    %r6,ipl_parameter_flags-.LGID(%r12)
+       bno   2f-.LPG1(%r13)
+       la    %r6,ipl_parameter_flags-.LPG1(%r13)
        oi    3(%r6),0x01               # set flag
-       la    %r2,ipl_devno-.LGID(%r12)
+       la    %r2,ipl_devno-.LPG1(%r13)
        mvc   0(2,%r2),6(%r5)           # store devno
        tm    4(%r5),0x80               # qdio capable device?
-       bno   0(%r14)
+       bno   2f-.LPG1(%r13)
        oi    3(%r6),0x02               # set flag
 
        # copy ipl parameters
@@ -523,7 +522,7 @@ start:
        ar    %r2,%r1
        sr    %r0,%r4
        jne   1b
-       b     0(%r14)
+       b     2f-.LPG1(%r13)
 
        .align 4
 .Lipl_schib:
@@ -537,6 +536,7 @@ ipl_parameter_flags:
        .globl ipl_devno
 ipl_devno:
        .word 0
+2:
 .endm
 
 #ifdef CONFIG_64BIT
index 2d3b089bfb83d37acbc8427889034573ed2d1213..d00de17b3778ef9fde54a971de2175922ab5b03d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/s390/kernel/head31.S
  *
- * (C) Copyright IBM Corp. 2005
+ * Copyright (C) IBM Corp. 2005,2006
  *
  *   Author(s):        Hartmut Penner <hp@de.ibm.com>
  *             Martin Schwidefsky <schwidefsky@de.ibm.com>
 # or linload or SALIPL
 #
        .org    0x10000
-startup:basr   %r13,0                   # get base
-.LPG1: l       %r1, .Lget_ipl_device_addr-.LPG1(%r13)
-       basr    %r14, %r1
+startup:basr   %r13,0                  # get base
+.LPG0: l       %r13,0f-.LPG0(%r13)
+       b       0(%r13)
+0:     .long   startup_continue
+
+#
+# params at 10400 (setup.h)
+#
+       .org    PARMAREA
+       .long   0,0                     # IPL_DEVICE
+       .long   0,RAMDISK_ORIGIN        # INITRD_START
+       .long   0,RAMDISK_SIZE          # INITRD_SIZE
+
+       .org    COMMAND_LINE
+       .byte   "root=/dev/ram0 ro"
+       .byte   0
+
+       .org    0x11000
+
+startup_continue:
+       basr    %r13,0                  # get base
+.LPG1: GET_IPL_DEVICE
        lctl    %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
-       la      %r12,_pstart-.LPG1(%r13) # pointer to parameter area
-                                        # move IPL device to lowcore
+       l       %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area
+                                       # move IPL device to lowcore
        mvc     __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12)
 
 #
@@ -51,8 +70,8 @@ startup:basr  %r13,0                   # get base
        a       %r1,__LC_EXT_NEW_PSW+4  # set handler
        st      %r1,__LC_EXT_NEW_PSW+4
 
-       la      %r4,_pstart-.LPG1(%r13) # %r4 is our index for sccb stuff
-       la      %r1, .Lsccb-PARMAREA(%r4)       # our sccb
+       l       %r4,.Lsccbaddr-.LPG1(%r13) # %r4 is our index for sccb stuff
+       lr      %r1,%r4                 # our sccb
        .insn   rre,0xb2200000,%r2,%r1  # service call
        ipm     %r1
        srl     %r1,28                  # get cc code
@@ -63,7 +82,7 @@ startup:basr  %r13,0                   # get base
        be      .Lservicecall-.LPG1(%r13)
        lpsw    .Lwaitsclp-.LPG1(%r13)
 .Lsclph:
-       lh      %r1,.Lsccbr-PARMAREA(%r4)
+       lh      %r1,.Lsccbr-.Lsccb(%r4)
        chi     %r1,0x10                # 0x0010 is the sucess code
        je      .Lprocsccb              # let's process the sccb
        chi     %r1,0x1f0
@@ -74,7 +93,7 @@ startup:basr  %r13,0                   # get base
        b       .Lservicecall-.LPG1(%r13)
 .Lprocsccb:
        lhi     %r1,0
-       icm     %r1,3,.Lscpincr1-PARMAREA(%r4) # use this one if != 0
+       icm     %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0
        jnz     .Lscnd
        lhi     %r1,0x800               # otherwise report 2GB
 .Lscnd:
@@ -84,10 +103,10 @@ startup:basr       %r13,0                   # get base
        lr      %r1,%r3
 .Lno2gb:
        xr      %r3,%r3                 # same logic
-       ic      %r3,.Lscpa1-PARMAREA(%r4)
+       ic      %r3,.Lscpa1-.Lsccb(%r4)
        chi     %r3,0x00
        jne     .Lcompmem
-       l       %r3,.Lscpa2-PARMAREA(%r13)
+       l       %r3,.Lscpa2-.Lsccb(%r4)
 .Lcompmem:
        mr      %r2,%r1                 # mem in MB on 128-bit
        l       %r1,.Lonemb-.LPG1(%r13)
@@ -95,8 +114,6 @@ startup:basr %r13,0                   # get base
        b       .Lfchunk-.LPG1(%r13)
 
        .align 4
-.Lget_ipl_device_addr:
-       .long   .Lget_ipl_device
 .Lpmask:
        .byte   0
 .align 8
@@ -242,6 +259,8 @@ startup:basr        %r13,0                   # get base
        .long   0                       # cr13: home space segment table
        .long   0xc0000000              # cr14: machine check handling off
        .long   0                       # cr15: linkage stack operations
+.Lduct:        .long   0,0,0,0,0,0,0,0
+       .long   0,0,0,0,0,0,0,0
 .Lpcmem:.long  0x00080000,0x80000000 + .Lchkmem
 .Lpcfpu:.long  0x00080000,0x80000000 + .Lchkfpu
 .Lpccsp:.long  0x00080000,0x80000000 + .Lchkcsp
@@ -252,25 +271,9 @@ startup:basr       %r13,0                   # get base
 .Lmflags:.long machine_flags
 .Lbss_bgn:  .long __bss_start
 .Lbss_end:  .long _end
-
-       .org    PARMAREA-64
-.Lduct:        .long   0,0,0,0,0,0,0,0
-       .long   0,0,0,0,0,0,0,0
-
-#
-# params at 10400 (setup.h)
-#
-       .org    PARMAREA
-       .global _pstart
-_pstart:
-       .long   0,0                     # IPL_DEVICE
-       .long   0,RAMDISK_ORIGIN        # INITRD_START
-       .long   0,RAMDISK_SIZE          # INITRD_SIZE
-
-       .org    COMMAND_LINE
-       .byte   "root=/dev/ram0 ro"
-       .byte   0
-       .org    0x11000
+.Lparmaddr: .long PARMAREA
+.Lsccbaddr: .long .Lsccb
+       .align  4096
 .Lsccb:
        .hword  0x1000                  # length, one page
        .byte   0x00,0x00,0x00
@@ -287,18 +290,14 @@ _pstart:
 .Lscpincr2:
        .quad   0x00
        .fill   3984,1,0
-       .org    0x12000
-       .global _pend
-_pend:
-
-       GET_IPL_DEVICE
+       .align  4096
 
 #ifdef CONFIG_SHARED_KERNEL
        .org    0x100000
 #endif
 
 #
-# startup-code, running in virtual mode
+# startup-code, running in absolute addressing mode
 #
        .globl  _stext
 _stext:        basr    %r13,0                  # get base
index f08c06f45d5ceea01fcb70ab3051037af13fcf70..47744fcca930d92f3e2dad3184a64be84009d3c8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/s390/kernel/head64.S
  *
- * (C) Copyright IBM Corp. 1999,2005
+ * Copyright (C) IBM Corp. 1999,2006
  *
  *   Author(s):        Hartmut Penner <hp@de.ibm.com>
  *             Martin Schwidefsky <schwidefsky@de.ibm.com>
 # this is called either by the ipl loader or directly by PSW restart
 # or linload or SALIPL
 #
-        .org  0x10000
-startup:basr  %r13,0                     # get base
+       .org  0x10000
+startup:basr  %r13,0                    # get base
+.LPG0: l     %r13,0f-.LPG0(%r13)
+       b     0(%r13)
+0:     .long startup_continue
+
+#
+# params at 10400 (setup.h)
+#
+       .org   PARMAREA
+       .quad  0                        # IPL_DEVICE
+       .quad  RAMDISK_ORIGIN           # INITRD_START
+       .quad  RAMDISK_SIZE             # INITRD_SIZE
+
+       .org   COMMAND_LINE
+       .byte  "root=/dev/ram0 ro"
+       .byte  0
+
+       .org   0x11000
+
+startup_continue:
+       basr  %r13,0                     # get base
 .LPG1:  sll   %r13,1                     # remove high order bit
         srl   %r13,1
-       l     %r1,.Lget_ipl_device_addr-.LPG1(%r13)
-       basr  %r14,%r1
+       GET_IPL_DEVICE
         lhi   %r1,1                      # mode 1 = esame
         slr   %r0,%r0                    # set cpuid to zero
         sigp  %r1,%r0,0x12               # switch to esame mode
        sam64                            # switch to 64 bit mode
        lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
-       larl  %r12,_pstart               # pointer to parameter area
+       lg    %r12,.Lparmaddr-.LPG1(%r13)# pointer to parameter area
                                         # move IPL device to lowcore
         mvc   __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12)
 
@@ -55,8 +74,8 @@ startup:basr  %r13,0                     # get base
        larl  %r1,.Lsclph
        stg   %r1,__LC_EXT_NEW_PSW+8    # set handler
 
-       larl  %r4,_pstart               # %r4 is our index for sccb stuff
-       la    %r1,.Lsccb-PARMAREA(%r4)  # our sccb
+       larl  %r4,.Lsccb                # %r4 is our index for sccb stuff
+       lgr   %r1,%r4                   # our sccb
        .insn rre,0xb2200000,%r2,%r1    # service call
        ipm   %r1
        srl   %r1,28                    # get cc code
@@ -67,7 +86,7 @@ startup:basr  %r13,0                     # get base
        be    .Lservicecall-.LPG1(%r13)
        lpswe .Lwaitsclp-.LPG1(%r13)
 .Lsclph:
-       lh    %r1,.Lsccbr-PARMAREA(%r4)
+       lh    %r1,.Lsccbr-.Lsccb(%r4)
        chi   %r1,0x10                  # 0x0010 is the sucess code
        je    .Lprocsccb                # let's process the sccb
        chi   %r1,0x1f0
@@ -78,15 +97,15 @@ startup:basr  %r13,0                     # get base
        b     .Lservicecall-.LPG1(%r13)
 .Lprocsccb:
        lghi  %r1,0
-       icm   %r1,3,.Lscpincr1-PARMAREA(%r4) # use this one if != 0
+       icm   %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0
        jnz   .Lscnd
-       lg    %r1,.Lscpincr2-PARMAREA(%r4) # otherwise use this one
+       lg    %r1,.Lscpincr2-.Lsccb(%r4) # otherwise use this one
 .Lscnd:
        xr    %r3,%r3                   # same logic
-       ic    %r3,.Lscpa1-PARMAREA(%r4)
+       ic    %r3,.Lscpa1-.Lsccb(%r4)
        chi   %r3,0x00
        jne   .Lcompmem
-       l     %r3,.Lscpa2-PARMAREA(%r13)
+       l     %r3,.Lscpa2-.Lsccb(%r4)
 .Lcompmem:
        mlgr  %r2,%r1                   # mem in MB on 128-bit
        l     %r1,.Lonemb-.LPG1(%r13)
@@ -94,8 +113,6 @@ startup:basr  %r13,0                     # get base
        b     .Lfchunk-.LPG1(%r13)
 
        .align 4
-.Lget_ipl_device_addr:
-       .long .Lget_ipl_device
 .Lpmask:
        .byte 0
        .align 8
@@ -242,29 +259,16 @@ startup:basr  %r13,0                     # get base
         .quad  0                        # cr13: home space segment table
         .quad  0xc0000000               # cr14: machine check handling off
         .quad  0                        # cr15: linkage stack operations
+.Lduct: .long 0,0,0,0,0,0,0,0
+       .long 0,0,0,0,0,0,0,0
 .Lpcmsk:.quad  0x0000000180000000
 .L4malign:.quad 0xffffffffffc00000
 .Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
 .Lnop: .long  0x07000700
+.Lparmaddr:
+       .quad   PARMAREA
 
-       .org PARMAREA-64
-.Lduct:        .long 0,0,0,0,0,0,0,0
-       .long 0,0,0,0,0,0,0,0
-
-#
-# params at 10400 (setup.h)
-#
-       .org   PARMAREA
-       .global _pstart
-_pstart:
-       .quad  0                        # IPL_DEVICE
-        .quad  RAMDISK_ORIGIN           # INITRD_START
-        .quad  RAMDISK_SIZE             # INITRD_SIZE
-
-        .org   COMMAND_LINE
-       .byte  "root=/dev/ram0 ro"
-        .byte  0
-       .org   0x11000
+       .align 4096
 .Lsccb:
        .hword 0x1000                   # length, one page
        .byte 0x00,0x00,0x00
@@ -281,18 +285,14 @@ _pstart:
 .Lscpincr2:
        .quad 0x00
        .fill 3984,1,0
-       .org 0x12000
-       .global _pend
-_pend: 
-
-       GET_IPL_DEVICE
+       .align 4096
 
 #ifdef CONFIG_SHARED_KERNEL
        .org   0x100000
 #endif
        
 #
-# startup-code, running in virtual mode
+# startup-code, running in absolute addressing mode
 #
         .globl _stext
 _stext:        basr  %r13,0                    # get base
@@ -326,4 +326,3 @@ _stext:     basr  %r13,0                    # get base
             .align 8
 .Ldw:       .quad  0x0002000180000000,0x0000000000000000
 .Laregs:    .long  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
index 4176c77670c41f222f22311376fc633e48f901d1..0886e739d12269a121b3a0cdf85f02e4b3c0c7fe 100644 (file)
@@ -46,8 +46,6 @@ EXPORT_SYMBOL(__down_interruptible);
  */
 extern int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs);
 EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(overflowuid);
-EXPORT_SYMBOL(overflowgid);
 EXPORT_SYMBOL(empty_zero_page);
 
 /*
index b282034452a4707357dadd5b75d9be0f3bd83206..2b2551e3510b196c30fe5834b2a18a9d151e52a5 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/seq_file.h>
 #include <linux/kernel_stat.h>
 #include <linux/device.h>
+#include <linux/notifier.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -115,6 +116,7 @@ void __devinit cpu_init (void)
  */
 char vmhalt_cmd[128] = "";
 char vmpoff_cmd[128] = "";
+char vmpanic_cmd[128] = "";
 
 static inline void strncpy_skip_quote(char *dst, char *src, int n)
 {
@@ -146,6 +148,38 @@ static int __init vmpoff_setup(char *str)
 
 __setup("vmpoff=", vmpoff_setup);
 
+static int vmpanic_notify(struct notifier_block *self, unsigned long event,
+                         void *data)
+{
+       if (MACHINE_IS_VM && strlen(vmpanic_cmd) > 0)
+               cpcmd(vmpanic_cmd, NULL, 0, NULL);
+
+       return NOTIFY_OK;
+}
+
+#define PANIC_PRI_VMPANIC      0
+
+static struct notifier_block vmpanic_nb = {
+       .notifier_call = vmpanic_notify,
+       .priority = PANIC_PRI_VMPANIC
+};
+
+static int __init vmpanic_setup(char *str)
+{
+       static int register_done __initdata = 0;
+
+       strncpy_skip_quote(vmpanic_cmd, str, 127);
+       vmpanic_cmd[127] = 0;
+       if (!register_done) {
+               register_done = 1;
+               atomic_notifier_chain_register(&panic_notifier_list,
+                                              &vmpanic_nb);
+       }
+       return 1;
+}
+
+__setup("vmpanic=", vmpanic_setup);
+
 /*
  * condev= and conmode= setup parameter.
  */
@@ -289,19 +323,34 @@ void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
 
 void machine_restart(char *command)
 {
-       console_unblank();
+       if (!in_interrupt() || oops_in_progress)
+               /*
+                * Only unblank the console if we are called in enabled
+                * context or a bust_spinlocks cleared the way for us.
+                */
+               console_unblank();
        _machine_restart(command);
 }
 
 void machine_halt(void)
 {
-       console_unblank();
+       if (!in_interrupt() || oops_in_progress)
+               /*
+                * Only unblank the console if we are called in enabled
+                * context or a bust_spinlocks cleared the way for us.
+                */
+               console_unblank();
        _machine_halt();
 }
 
 void machine_power_off(void)
 {
-       console_unblank();
+       if (!in_interrupt() || oops_in_progress)
+               /*
+                * Only unblank the console if we are called in enabled
+                * context or a bust_spinlocks cleared the way for us.
+                */
+               console_unblank();
        _machine_power_off();
 }
 
index a46793beeddda592d70797ed79fc4c462477f1d6..b7630436f693cda60aa7976b8c3a9b43212ab327 100644 (file)
@@ -150,13 +150,11 @@ void show_stack(struct task_struct *task, unsigned long *sp)
        unsigned long *stack;
        int i;
 
-       // debugging aid: "show_stack(NULL);" prints the
-       // back trace for this cpu.
-
        if (!sp)
-               sp = task ? (unsigned long *) task->thread.ksp : __r15;
+               stack = task ? (unsigned long *) task->thread.ksp : __r15;
+       else
+               stack = sp;
 
-       stack = sp;
        for (i = 0; i < kstack_depth_to_print; i++) {
                if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
                        break;
index cfb1fff3787caafd63fe05a2c36587bfdb8f19a5..bafcd2f20ae241071e5fad970684bd4f088df9fa 100644 (file)
@@ -95,7 +95,7 @@ dasd_alloc_device(void)
        spin_lock_init(&device->mem_lock);
        spin_lock_init(&device->request_queue_lock);
        atomic_set (&device->tasklet_scheduled, 0);
-       tasklet_init(&device->tasklet, 
+       tasklet_init(&device->tasklet,
                     (void (*)(unsigned long)) dasd_tasklet,
                     (unsigned long) device);
        INIT_LIST_HEAD(&device->ccw_queue);
@@ -128,7 +128,7 @@ dasd_state_new_to_known(struct dasd_device *device)
        int rc;
 
        /*
-        * As long as the device is not in state DASD_STATE_NEW we want to 
+        * As long as the device is not in state DASD_STATE_NEW we want to
         * keep the reference count > 0.
         */
        dasd_get_device(device);
@@ -336,7 +336,7 @@ dasd_decrease_state(struct dasd_device *device)
        if (device->state == DASD_STATE_ONLINE &&
            device->target <= DASD_STATE_READY)
                dasd_state_online_to_ready(device);
-       
+
        if (device->state == DASD_STATE_READY &&
            device->target <= DASD_STATE_BASIC)
                dasd_state_ready_to_basic(device);
@@ -348,7 +348,7 @@ dasd_decrease_state(struct dasd_device *device)
        if (device->state == DASD_STATE_BASIC &&
            device->target <= DASD_STATE_KNOWN)
                dasd_state_basic_to_known(device);
-       
+
        if (device->state == DASD_STATE_KNOWN &&
            device->target <= DASD_STATE_NEW)
                dasd_state_known_to_new(device);
@@ -994,7 +994,7 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
                      ((irb->scsw.cstat << 8) | irb->scsw.dstat), cqr);
 
        /* Find out the appropriate era_action. */
-       if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) 
+       if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC)
                era = dasd_era_fatal;
        else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
                 irb->scsw.cstat == 0 &&
@@ -1004,7 +1004,7 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
                era = dasd_era_fatal; /* don't recover this request */
        else if (irb->esw.esw0.erw.cons)
                era = device->discipline->examine_error(cqr, irb);
-       else 
+       else
                era = dasd_era_recover;
 
        DBF_DEV_EVENT(DBF_DEBUG, device, "era_code %d", era);
@@ -1287,7 +1287,7 @@ __dasd_start_head(struct dasd_device * device)
 }
 
 /*
- * Remove requests from the ccw queue. 
+ * Remove requests from the ccw queue.
  */
 static void
 dasd_flush_ccw_queue(struct dasd_device * device, int all)
@@ -1450,23 +1450,23 @@ dasd_sleep_on(struct dasd_ccw_req * cqr)
        wait_queue_head_t wait_q;
        struct dasd_device *device;
        int rc;
-       
+
        device = cqr->device;
        spin_lock_irq(get_ccwdev_lock(device->cdev));
-       
+
        init_waitqueue_head (&wait_q);
        cqr->callback = dasd_wakeup_cb;
        cqr->callback_data = (void *) &wait_q;
        cqr->status = DASD_CQR_QUEUED;
        list_add_tail(&cqr->list, &device->ccw_queue);
-       
+
        /* let the bh start the request to keep them in order */
        dasd_schedule_bh(device);
-       
+
        spin_unlock_irq(get_ccwdev_lock(device->cdev));
 
        wait_event(wait_q, _wait_for_wakeup(cqr));
-       
+
        /* Request status is either done or failed. */
        rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
        return rc;
@@ -1568,7 +1568,7 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
        wait_queue_head_t wait_q;
        struct dasd_device *device;
        int rc;
-       
+
        device = cqr->device;
        spin_lock_irq(get_ccwdev_lock(device->cdev));
        rc = _dasd_term_running_cqr(device);
@@ -1576,20 +1576,20 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
                spin_unlock_irq(get_ccwdev_lock(device->cdev));
                return rc;
        }
-       
+
        init_waitqueue_head (&wait_q);
        cqr->callback = dasd_wakeup_cb;
        cqr->callback_data = (void *) &wait_q;
        cqr->status = DASD_CQR_QUEUED;
        list_add(&cqr->list, &device->ccw_queue);
-       
+
        /* let the bh start the request to keep them in order */
        dasd_schedule_bh(device);
-       
+
        spin_unlock_irq(get_ccwdev_lock(device->cdev));
 
        wait_event(wait_q, _wait_for_wakeup(cqr));
-       
+
        /* Request status is either done or failed. */
        rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
        return rc;
@@ -1725,7 +1725,7 @@ dasd_flush_request_queue(struct dasd_device * device)
 
        if (!device->request_queue)
                return;
-       
+
        spin_lock_irq(&device->request_queue_lock);
        while (!list_empty(&device->request_queue->queue_head)) {
                req = elv_next_request(device->request_queue);
@@ -1855,15 +1855,34 @@ dasd_generic_probe (struct ccw_device *cdev,
 {
        int ret;
 
+       ret = ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
+       if (ret) {
+               printk(KERN_WARNING
+                      "dasd_generic_probe: could not set ccw-device options "
+                      "for %s\n", cdev->dev.bus_id);
+               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);
-       } else {
-               cdev->handler = &dasd_int_handler;
+               return ret;
        }
+       cdev->handler = &dasd_int_handler;
 
+       /*
+        * Automatically online either all dasd devices (dasd_autodetect)
+        * or all devices specified with dasd= parameters during
+        * initial probe.
+        */
+       if ((dasd_get_feature(cdev, DASD_FEATURE_INITIAL_ONLINE) > 0 ) ||
+           (dasd_autodetect && dasd_busid_known(cdev->dev.bus_id) != 0))
+               ret = ccw_device_set_online(cdev);
+       if (ret)
+               printk(KERN_WARNING
+                      "dasd_generic_probe: could not initially online "
+                      "ccw-device %s\n", cdev->dev.bus_id);
        return ret;
 }
 
@@ -1911,6 +1930,8 @@ dasd_generic_set_online (struct ccw_device *cdev,
        struct dasd_device *device;
        int rc;
 
+       /* first online clears initial online feature flag */
+       dasd_set_feature(cdev, DASD_FEATURE_INITIAL_ONLINE, 0);
        device = dasd_create_device(cdev);
        if (IS_ERR(device))
                return PTR_ERR(device);
@@ -2065,31 +2086,6 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
        return ret;
 }
 
-/*
- * Automatically online either all dasd devices (dasd_autodetect) or
- * all devices specified with dasd= parameters.
- */
-static int
-__dasd_auto_online(struct device *dev, void *data)
-{
-       struct ccw_device *cdev;
-
-       cdev = to_ccwdev(dev);
-       if (dasd_autodetect || dasd_busid_known(cdev->dev.bus_id) == 0)
-               ccw_device_set_online(cdev);
-       return 0;
-}
-
-void
-dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver)
-{
-       struct device_driver *drv;
-
-       drv = get_driver(&dasd_discipline_driver->driver);
-       driver_for_each_device(drv, NULL, NULL, __dasd_auto_online);
-       put_driver(drv);
-}
-
 
 static int __init
 dasd_init(void)
@@ -2170,23 +2166,4 @@ EXPORT_SYMBOL_GPL(dasd_generic_remove);
 EXPORT_SYMBOL_GPL(dasd_generic_notify);
 EXPORT_SYMBOL_GPL(dasd_generic_set_online);
 EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
-EXPORT_SYMBOL_GPL(dasd_generic_auto_online);
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
index 1d11c2a9525d3d1ab7f158efd6f96df53e541949..1ddab8991d92fe1020c1c8309180d175700f954b 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_3370_erp.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
 
 
 /*
- * DASD_3370_ERP_EXAMINE 
+ * DASD_3370_ERP_EXAMINE
  *
  * DESCRIPTION
- *   Checks only for fatal/no/recover error. 
+ *   Checks only for fatal/no/recover error.
  *   A detailed examination of the sense data is done later outside
  *   the interrupt handler.
  *
@@ -23,7 +23,7 @@
  *   'Chapter 7. 3370 Sense Data'.
  *
  * RETURN VALUES
- *   dasd_era_none     no error 
+ *   dasd_era_none     no error
  *   dasd_era_fatal    for all fatal (unrecoverable errors)
  *   dasd_era_recover  for all others.
  */
@@ -82,22 +82,3 @@ dasd_3370_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
        return dasd_era_recover;
 
 }                              /* END dasd_3370_erp_examine */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
index 2ed51562319eae9541b6f2dda331bb3818aac75b..669805d4402dcdf628424cb0ff49900db9ba50ad 100644 (file)
@@ -1,6 +1,6 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_3990_erp.c
- * Author(s)......: Horst  Hummel    <Horst.Hummel@de.ibm.com> 
+ * Author(s)......: Horst  Hummel    <Horst.Hummel@de.ibm.com>
  *                 Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001
@@ -25,23 +25,23 @@ struct DCTL_data {
 } __attribute__ ((packed));
 
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * SECTION ERP EXAMINATION
- ***************************************************************************** 
+ *****************************************************************************
  */
 
 /*
- * DASD_3990_ERP_EXAMINE_24 
+ * DASD_3990_ERP_EXAMINE_24
  *
  * DESCRIPTION
- *   Checks only for fatal (unrecoverable) error. 
+ *   Checks only for fatal (unrecoverable) error.
  *   A detailed examination of the sense data is done later outside
  *   the interrupt handler.
  *
  *   Each bit configuration leading to an action code 2 (Exit with
  *   programming error or unusual condition indication)
  *   are handled as fatal error´s.
- * 
+ *
  *   All other configurations are handled as recoverable errors.
  *
  * RETURN VALUES
@@ -93,15 +93,15 @@ dasd_3990_erp_examine_24(struct dasd_ccw_req * cqr, char *sense)
 }                              /* END dasd_3990_erp_examine_24 */
 
 /*
- * DASD_3990_ERP_EXAMINE_32 
+ * DASD_3990_ERP_EXAMINE_32
  *
  * DESCRIPTION
- *   Checks only for fatal/no/recoverable error. 
+ *   Checks only for fatal/no/recoverable error.
  *   A detailed examination of the sense data is done later outside
  *   the interrupt handler.
  *
  * RETURN VALUES
- *   dasd_era_none     no error 
+ *   dasd_era_none     no error
  *   dasd_era_fatal    for all fatal (unrecoverable errors)
  *   dasd_era_recover  for recoverable others.
  */
@@ -128,10 +128,10 @@ dasd_3990_erp_examine_32(struct dasd_ccw_req * cqr, char *sense)
 }                              /* end dasd_3990_erp_examine_32 */
 
 /*
- * DASD_3990_ERP_EXAMINE 
+ * DASD_3990_ERP_EXAMINE
  *
  * DESCRIPTION
- *   Checks only for fatal/no/recover error. 
+ *   Checks only for fatal/no/recover error.
  *   A detailed examination of the sense data is done later outside
  *   the interrupt handler.
  *
@@ -139,7 +139,7 @@ dasd_3990_erp_examine_32(struct dasd_ccw_req * cqr, char *sense)
  *   'Chapter 7. Error Recovery Procedures'.
  *
  * RETURN VALUES
- *   dasd_era_none     no error 
+ *   dasd_era_none     no error
  *   dasd_era_fatal    for all fatal (unrecoverable errors)
  *   dasd_era_recover  for all others.
  */
@@ -178,18 +178,18 @@ dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
 }                              /* END dasd_3990_erp_examine */
 
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * SECTION ERP HANDLING
- ***************************************************************************** 
+ *****************************************************************************
  */
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * 24 and 32 byte sense ERP functions
- ***************************************************************************** 
+ *****************************************************************************
  */
 
 /*
- * DASD_3990_ERP_CLEANUP 
+ * DASD_3990_ERP_CLEANUP
  *
  * DESCRIPTION
  *   Removes the already build but not necessary ERP request and sets
@@ -197,10 +197,10 @@ dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
  *
  *  PARAMETER
  *   erp               request to be blocked
- *   final_status      either DASD_CQR_DONE or DASD_CQR_FAILED 
+ *   final_status      either DASD_CQR_DONE or DASD_CQR_FAILED
  *
  * RETURN VALUES
- *   cqr               original cqr               
+ *   cqr               original cqr
  */
 static struct dasd_ccw_req *
 dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status)
@@ -214,7 +214,7 @@ dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status)
 }                              /* end dasd_3990_erp_cleanup */
 
 /*
- * DASD_3990_ERP_BLOCK_QUEUE 
+ * DASD_3990_ERP_BLOCK_QUEUE
  *
  * DESCRIPTION
  *   Block the given device request queue to prevent from further
@@ -237,7 +237,7 @@ dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)
 }
 
 /*
- * DASD_3990_ERP_INT_REQ 
+ * DASD_3990_ERP_INT_REQ
  *
  * DESCRIPTION
  *   Handles 'Intervention Required' error.
@@ -277,7 +277,7 @@ dasd_3990_erp_int_req(struct dasd_ccw_req * erp)
 }                              /* end dasd_3990_erp_int_req */
 
 /*
- * DASD_3990_ERP_ALTERNATE_PATH 
+ * DASD_3990_ERP_ALTERNATE_PATH
  *
  * DESCRIPTION
  *   Repeat the operation on a different channel path.
@@ -330,15 +330,15 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
  * DASD_3990_ERP_DCTL
  *
  * DESCRIPTION
- *   Setup cqr to do the Diagnostic Control (DCTL) command with an 
+ *   Setup cqr to do the Diagnostic Control (DCTL) command with an
  *   Inhibit Write subcommand (0x20) and the given modifier.
  *
  *  PARAMETER
  *   erp               pointer to the current (failed) ERP
  *   modifier          subcommand modifier
- *   
+ *
  * RETURN VALUES
- *   dctl_cqr          pointer to NEW dctl_cqr 
+ *   dctl_cqr          pointer to NEW dctl_cqr
  *
  */
 static struct dasd_ccw_req *
@@ -386,7 +386,7 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
 }                              /* end dasd_3990_erp_DCTL */
 
 /*
- * DASD_3990_ERP_ACTION_1 
+ * DASD_3990_ERP_ACTION_1
  *
  * DESCRIPTION
  *   Setup ERP to do the ERP action 1 (see Reference manual).
@@ -415,7 +415,7 @@ dasd_3990_erp_action_1(struct dasd_ccw_req * erp)
 }                              /* end dasd_3990_erp_action_1 */
 
 /*
- * DASD_3990_ERP_ACTION_4 
+ * DASD_3990_ERP_ACTION_4
  *
  * DESCRIPTION
  *   Setup ERP to do the ERP action 4 (see Reference manual).
@@ -453,11 +453,11 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
 
                if (sense[25] == 0x1D) {        /* state change pending */
 
-                       DEV_MESSAGE(KERN_INFO, device, 
+                       DEV_MESSAGE(KERN_INFO, device,
                                    "waiting for state change pending "
                                    "interrupt, %d retries left",
                                    erp->retries);
-                       
+
                        dasd_3990_erp_block_queue(erp, 30*HZ);
 
                 } else if (sense[25] == 0x1E) {        /* busy */
@@ -469,9 +469,9 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
                } else {
 
                        /* no state change pending - retry */
-                       DEV_MESSAGE (KERN_INFO, device, 
+                       DEV_MESSAGE (KERN_INFO, device,
                                     "redriving request immediately, "
-                                    "%d retries left", 
+                                    "%d retries left",
                                     erp->retries);
                        erp->status = DASD_CQR_QUEUED;
                }
@@ -482,13 +482,13 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_action_4 */
 
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * 24 byte sense ERP functions (only)
- ***************************************************************************** 
+ *****************************************************************************
  */
 
 /*
- * DASD_3990_ERP_ACTION_5 
+ * DASD_3990_ERP_ACTION_5
  *
  * DESCRIPTION
  *   Setup ERP to do the ERP action 5 (see Reference manual).
@@ -523,7 +523,7 @@ dasd_3990_erp_action_5(struct dasd_ccw_req * erp)
  *
  * PARAMETER
  *   sense             current sense data
- *   
+ *
  * RETURN VALUES
  *   void
  */
@@ -1150,9 +1150,9 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)
  * PARAMETER
  *   erp               current erp_head
  *   sense             current sense data
- * 
+ *
  * RETURN VALUES
- *   erp               'new' erp_head - pointer to new ERP 
+ *   erp               'new' erp_head - pointer to new ERP
  */
 static struct dasd_ccw_req *
 dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)
@@ -1185,7 +1185,7 @@ dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_com_rej */
 
 /*
- * DASD_3990_ERP_BUS_OUT 
+ * DASD_3990_ERP_BUS_OUT
  *
  * DESCRIPTION
  *   Handles 24 byte 'Bus Out Parity Check' error.
@@ -1483,7 +1483,7 @@ dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense)
  *
  * PARAMETER
  *   erp               already added default ERP
- *             
+ *
  * RETURN VALUES
  *   erp               new erp_head - pointer to new ERP
  */
@@ -1527,11 +1527,11 @@ dasd_3990_erp_file_prot(struct dasd_ccw_req * erp)
 }                              /* end dasd_3990_erp_file_prot */
 
 /*
- * DASD_3990_ERP_INSPECT_24 
+ * DASD_3990_ERP_INSPECT_24
  *
  * DESCRIPTION
  *   Does a detailed inspection of the 24 byte sense data
- *   and sets up a related error recovery action.  
+ *   and sets up a related error recovery action.
  *
  * PARAMETER
  *   sense             sense data of the actual error
@@ -1602,13 +1602,13 @@ dasd_3990_erp_inspect_24(struct dasd_ccw_req * erp, char *sense)
 }                              /* END dasd_3990_erp_inspect_24 */
 
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * 32 byte sense ERP functions (only)
- ***************************************************************************** 
+ *****************************************************************************
  */
 
 /*
- * DASD_3990_ERPACTION_10_32 
+ * DASD_3990_ERPACTION_10_32
  *
  * DESCRIPTION
  *   Handles 32 byte 'Action 10' of Single Program Action Codes.
@@ -1616,7 +1616,7 @@ dasd_3990_erp_inspect_24(struct dasd_ccw_req * erp, char *sense)
  *
  * PARAMETER
  *   erp               current erp_head
- *   sense             current sense data 
+ *   sense             current sense data
  * RETURN VALUES
  *   erp               modified erp_head
  */
@@ -1640,18 +1640,18 @@ dasd_3990_erp_action_10_32(struct dasd_ccw_req * erp, char *sense)
  *
  * DESCRIPTION
  *   Handles 32 byte 'Action 1B' of Single Program Action Codes.
- *   A write operation could not be finished because of an unexpected 
+ *   A write operation could not be finished because of an unexpected
  *   condition.
- *   The already created 'default erp' is used to get the link to 
- *   the erp chain, but it can not be used for this recovery 
+ *   The already created 'default erp' is used to get the link to
+ *   the erp chain, but it can not be used for this recovery
  *   action because it contains no DE/LO data space.
  *
  * PARAMETER
  *   default_erp       already added default erp.
- *   sense             current sense data 
+ *   sense             current sense data
  *
  * RETURN VALUES
- *   erp               new erp or 
+ *   erp               new erp or
  *                     default_erp in case of imprecise ending or error
  */
 static struct dasd_ccw_req *
@@ -1789,16 +1789,16 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
  * DASD_3990_UPDATE_1B
  *
  * DESCRIPTION
- *   Handles the update to the 32 byte 'Action 1B' of Single Program 
+ *   Handles the update to the 32 byte 'Action 1B' of Single Program
  *   Action Codes in case the first action was not successful.
  *   The already created 'previous_erp' is the currently not successful
- *   ERP. 
+ *   ERP.
  *
  * PARAMETER
  *   previous_erp      already created previous erp.
- *   sense             current sense data 
+ *   sense             current sense data
  * RETURN VALUES
- *   erp               modified erp 
+ *   erp               modified erp
  */
 static struct dasd_ccw_req *
 dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
@@ -1897,7 +1897,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
 }                              /* end dasd_3990_update_1B */
 
 /*
- * DASD_3990_ERP_COMPOUND_RETRY 
+ * DASD_3990_ERP_COMPOUND_RETRY
  *
  * DESCRIPTION
  *   Handles the compound ERP action retry code.
@@ -1943,7 +1943,7 @@ dasd_3990_erp_compound_retry(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_compound_retry */
 
 /*
- * DASD_3990_ERP_COMPOUND_PATH 
+ * DASD_3990_ERP_COMPOUND_PATH
  *
  * DESCRIPTION
  *   Handles the compound ERP action for retry on alternate
@@ -1965,7 +1965,7 @@ dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense)
                dasd_3990_erp_alternate_path(erp);
 
                if (erp->status == DASD_CQR_FAILED) {
-                       /* reset the lpm and the status to be able to 
+                       /* reset the lpm and the status to be able to
                         * try further actions. */
 
                        erp->lpm = 0;
@@ -1980,7 +1980,7 @@ dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_compound_path */
 
 /*
- * DASD_3990_ERP_COMPOUND_CODE 
+ * DASD_3990_ERP_COMPOUND_CODE
  *
  * DESCRIPTION
  *   Handles the compound ERP action for retry code.
@@ -2001,18 +2001,18 @@ dasd_3990_erp_compound_code(struct dasd_ccw_req * erp, char *sense)
 
                switch (sense[28]) {
                case 0x17:
-                       /* issue a Diagnostic Control command with an 
+                       /* issue a Diagnostic Control command with an
                         * Inhibit Write subcommand and controler modifier */
                        erp = dasd_3990_erp_DCTL(erp, 0x20);
                        break;
-                       
+
                case 0x25:
                        /* wait for 5 seconds and retry again */
                        erp->retries = 1;
-                       
+
                        dasd_3990_erp_block_queue (erp, 5*HZ);
                        break;
-                       
+
                default:
                        /* should not happen - continue */
                        break;
@@ -2026,7 +2026,7 @@ dasd_3990_erp_compound_code(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_compound_code */
 
 /*
- * DASD_3990_ERP_COMPOUND_CONFIG 
+ * DASD_3990_ERP_COMPOUND_CONFIG
  *
  * DESCRIPTION
  *   Handles the compound ERP action for configruation
@@ -2063,10 +2063,10 @@ dasd_3990_erp_compound_config(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_compound_config */
 
 /*
- * DASD_3990_ERP_COMPOUND 
+ * DASD_3990_ERP_COMPOUND
  *
  * DESCRIPTION
- *   Does the further compound program action if 
+ *   Does the further compound program action if
  *   compound retry was not successful.
  *
  * PARAMETER
@@ -2110,11 +2110,11 @@ dasd_3990_erp_compound(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_compound */
 
 /*
- * DASD_3990_ERP_INSPECT_32 
+ * DASD_3990_ERP_INSPECT_32
  *
  * DESCRIPTION
  *   Does a detailed inspection of the 32 byte sense data
- *   and sets up a related error recovery action.  
+ *   and sets up a related error recovery action.
  *
  * PARAMETER
  *   sense             sense data of the actual error
@@ -2228,9 +2228,9 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_inspect_32 */
 
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * main ERP control fuctions (24 and 32 byte sense)
- ***************************************************************************** 
+ *****************************************************************************
  */
 
 /*
@@ -2243,7 +2243,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
  * PARAMETER
  *   erp               pointer to the currently created default ERP
  * RETURN VALUES
- *   erp_new           contens was possibly modified 
+ *   erp_new           contens was possibly modified
  */
 static struct dasd_ccw_req *
 dasd_3990_erp_inspect(struct dasd_ccw_req * erp)
@@ -2272,14 +2272,14 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp)
 
 /*
  * DASD_3990_ERP_ADD_ERP
- * 
+ *
  * DESCRIPTION
  *   This funtion adds an additional request block (ERP) to the head of
  *   the given cqr (or erp).
  *   This erp is initialized as an default erp (retry TIC)
  *
  * PARAMETER
- *   cqr               head of the current ERP-chain (or single cqr if 
+ *   cqr               head of the current ERP-chain (or single cqr if
  *                     first error)
  * RETURN VALUES
  *   erp               pointer to new ERP-chain head
@@ -2332,15 +2332,15 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)
 }
 
 /*
- * DASD_3990_ERP_ADDITIONAL_ERP 
- * 
+ * DASD_3990_ERP_ADDITIONAL_ERP
+ *
  * DESCRIPTION
  *   An additional ERP is needed to handle the current error.
  *   Add ERP to the head of the ERP-chain containing the ERP processing
  *   determined based on the sense data.
  *
  * PARAMETER
- *   cqr               head of the current ERP-chain (or single cqr if 
+ *   cqr               head of the current ERP-chain (or single cqr if
  *                     first error)
  *
  * RETURN VALUES
@@ -2376,7 +2376,7 @@ dasd_3990_erp_additional_erp(struct dasd_ccw_req * cqr)
  *   24 byte sense byte 25 and 27 is set as well.
  *
  * PARAMETER
- *   cqr1              first cqr, which will be compared with the 
+ *   cqr1              first cqr, which will be compared with the
  *   cqr2              second cqr.
  *
  * RETURN VALUES
@@ -2415,7 +2415,7 @@ dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2)
  *   cqr               failed cqr (either original cqr or already an erp)
  *
  * RETURN VALUES
- *   erp               erp-pointer to the already defined error 
+ *   erp               erp-pointer to the already defined error
  *                     recovery procedure OR
  *                     NULL if a 'new' error occurred.
  */
@@ -2451,10 +2451,10 @@ dasd_3990_erp_in_erp(struct dasd_ccw_req *cqr)
  * DASD_3990_ERP_FURTHER_ERP (24 & 32 byte sense)
  *
  * DESCRIPTION
- *   No retry is left for the current ERP. Check what has to be done 
+ *   No retry is left for the current ERP. Check what has to be done
  *   with the ERP.
  *     - do further defined ERP action or
- *     - wait for interrupt or 
+ *     - wait for interrupt or
  *     - exit with permanent error
  *
  * PARAMETER
@@ -2485,7 +2485,7 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)
 
                if (!(sense[2] & DASD_SENSE_BIT_0)) {
 
-                       /* issue a Diagnostic Control command with an 
+                       /* issue a Diagnostic Control command with an
                         * Inhibit Write subcommand */
 
                        switch (sense[25]) {
@@ -2535,14 +2535,14 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)
 }                              /* end dasd_3990_erp_further_erp */
 
 /*
- * DASD_3990_ERP_HANDLE_MATCH_ERP 
+ * DASD_3990_ERP_HANDLE_MATCH_ERP
  *
  * DESCRIPTION
  *   An error occurred again and an ERP has been detected which is already
- *   used to handle this error (e.g. retries). 
+ *   used to handle this error (e.g. retries).
  *   All prior ERP's are asumed to be successful and therefore removed
  *   from queue.
- *   If retry counter of matching erp is already 0, it is checked if further 
+ *   If retry counter of matching erp is already 0, it is checked if further
  *   action is needed (besides retry) or if the ERP has failed.
  *
  * PARAMETER
@@ -2631,7 +2631,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
  *   erp               erp-pointer to the head of the ERP action chain.
  *                     This means:
  *                      - either a ptr to an additional ERP cqr or
- *                      - the original given cqr (which's status might 
+ *                      - the original given cqr (which's status might
  *                        be modified)
  */
 struct dasd_ccw_req *
@@ -2723,22 +2723,3 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
        return erp;
 
 }                              /* end dasd_3990_erp_action */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
index dc861446d0562b991427433df7605111429a818e..6e082688475a8f31352cefeebc46aff0ed3ba63e 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_9336_erp.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
 
 
 /*
- * DASD_9336_ERP_EXAMINE 
+ * DASD_9336_ERP_EXAMINE
  *
  * DESCRIPTION
- *   Checks only for fatal/no/recover error. 
+ *   Checks only for fatal/no/recover error.
  *   A detailed examination of the sense data is done later outside
  *   the interrupt handler.
  *
@@ -23,7 +23,7 @@
  *   'Chapter 7. 9336 Sense Data'.
  *
  * RETURN VALUES
- *   dasd_era_none     no error 
+ *   dasd_era_none     no error
  *   dasd_era_fatal    for all fatal (unrecoverable errors)
  *   dasd_era_recover  for all others.
  */
@@ -39,22 +39,3 @@ dasd_9336_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
        return dasd_era_recover;
 
 }                              /* END dasd_9336_erp_examine */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
index 4a5b79569aaaa463461f55a25dffc09f0d9b3b32..ddecb9808ed4b1c08e22399b8bb7151fc0cd636e 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_9345_erp.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
index 216bc4fba19998c2c5a92a8455d92f32d0dce4ab..9e9ae71796028162b94d45316776ec2b2f7f0d6b 100644 (file)
@@ -27,7 +27,7 @@
 #include "dasd_int.h"
 
 kmem_cache_t *dasd_page_cache;
-EXPORT_SYMBOL(dasd_page_cache);
+EXPORT_SYMBOL_GPL(dasd_page_cache);
 
 /*
  * dasd_devmap_t is used to store the features and the relation
@@ -48,6 +48,20 @@ struct dasd_devmap {
        struct dasd_uid uid;
 };
 
+/*
+ * dasd_servermap is used to store the server_id of all storage servers
+ * accessed by DASD device driver.
+ */
+struct dasd_servermap {
+       struct list_head list;
+       struct server_id {
+               char vendor[4];
+               char serial[15];
+       } sid;
+};
+
+static struct list_head dasd_serverlist;
+
 /*
  * Parameter parsing functions for dasd= parameter. The syntax is:
  *   <devno>           : (0x)?[0-9a-fA-F]+
@@ -64,6 +78,8 @@ struct dasd_devmap {
 
 int dasd_probeonly =  0;       /* is true, when probeonly mode is active */
 int dasd_autodetect = 0;       /* is true, when autodetection is active */
+int dasd_nopav = 0;            /* is true, when PAV is disabled */
+EXPORT_SYMBOL_GPL(dasd_nopav);
 
 /*
  * char *dasd[] is intended to hold the ranges supplied by the dasd= statement
@@ -123,7 +139,7 @@ static inline int
 dasd_busid(char **str, int *id0, int *id1, int *devno)
 {
        int val, old_style;
+
        /* check for leading '0x' */
        old_style = 0;
        if ((*str)[0] == '0' && (*str)[1] == 'x') {
@@ -179,7 +195,7 @@ dasd_feature_list(char *str, char **endp)
        features = 0;
 
        while (1) {
-               for (len = 0; 
+               for (len = 0;
                     str[len] && str[len] != ':' && str[len] != ')'; len++);
                if (len == 2 && !strncmp(str, "ro", 2))
                        features |= DASD_FEATURE_READONLY;
@@ -228,19 +244,24 @@ dasd_parse_keyword( char *parsestring ) {
                length = strlen(parsestring);
                residual_str = parsestring + length;
         }
-       if (strncmp ("autodetect", parsestring, length) == 0) {
+       if (strncmp("autodetect", parsestring, length) == 0) {
                dasd_autodetect = 1;
                MESSAGE (KERN_INFO, "%s",
                         "turning to autodetection mode");
                 return residual_str;
         }
-        if (strncmp ("probeonly", parsestring, length) == 0) {
+       if (strncmp("probeonly", parsestring, length) == 0) {
                dasd_probeonly = 1;
                MESSAGE(KERN_INFO, "%s",
                        "turning to probeonly mode");
                 return residual_str;
         }
-        if (strncmp ("fixedbuffers", parsestring, length) == 0) {
+       if (strncmp("nopav", parsestring, length) == 0) {
+               dasd_nopav = 1;
+               MESSAGE(KERN_INFO, "%s", "disable PAV mode");
+               return residual_str;
+       }
+       if (strncmp("fixedbuffers", parsestring, length) == 0) {
                if (dasd_page_cache)
                        return residual_str;
                dasd_page_cache =
@@ -294,6 +315,8 @@ dasd_parse_range( char *parsestring ) {
        features = dasd_feature_list(str, &str);
        if (features < 0)
                return ERR_PTR(-EINVAL);
+       /* each device in dasd= parameter should be set initially online */
+       features |= DASD_FEATURE_INITIAL_ONLINE;
        while (from <= to) {
                sprintf(bus_id, "%01x.%01x.%04x",
                        from_id0, from_id1, from++);
@@ -359,7 +382,7 @@ dasd_parse(void)
  * Add a devmap for the device specified by busid. It is possible that
  * the devmap already exists (dasd= parameter). The order of the devices
  * added through this function will define the kdevs for the individual
- * devices. 
+ * devices.
  */
 static struct dasd_devmap *
 dasd_add_busid(char *bus_id, int features)
@@ -368,7 +391,7 @@ dasd_add_busid(char *bus_id, int features)
        int hash;
 
        new = (struct dasd_devmap *)
-               kmalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
+               kzalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
        if (!new)
                return ERR_PTR(-ENOMEM);
        spin_lock(&dasd_devmap_lock);
@@ -630,7 +653,8 @@ dasd_ro_show(struct device *dev, struct device_attribute *attr, char *buf)
 }
 
 static ssize_t
-dasd_ro_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+dasd_ro_store(struct device *dev, struct device_attribute *attr,
+             const char *buf, size_t count)
 {
        struct dasd_devmap *devmap;
        int ro_flag;
@@ -658,7 +682,7 @@ static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store);
  * use_diag controls whether the driver should use diag rather than ssch
  * to talk to the device
  */
-static ssize_t 
+static ssize_t
 dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct dasd_devmap *devmap;
@@ -673,7 +697,8 @@ dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf)
 }
 
 static ssize_t
-dasd_use_diag_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+dasd_use_diag_store(struct device *dev, struct device_attribute *attr,
+                   const char *buf, size_t count)
 {
        struct dasd_devmap *devmap;
        ssize_t rc;
@@ -697,11 +722,11 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr, const cha
        return rc;
 }
 
-static
-DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
+static DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
 
 static ssize_t
-dasd_discipline_show(struct device *dev, struct device_attribute *attr, char *buf)
+dasd_discipline_show(struct device *dev, struct device_attribute *attr,
+                    char *buf)
 {
        struct dasd_devmap *devmap;
        char *dname;
@@ -834,6 +859,38 @@ static struct attribute_group dasd_attr_group = {
        .attrs = dasd_attrs,
 };
 
+/*
+ * Check if the related storage server is already contained in the
+ * dasd_serverlist. If server is not contained, create new entry.
+ * Return 0 if server was already in serverlist,
+ *       1 if the server was added successfully
+ *      <0 in case of error.
+ */
+static int
+dasd_add_server(struct dasd_uid *uid)
+{
+       struct dasd_servermap *new, *tmp;
+
+       /* check if server is already contained */
+       list_for_each_entry(tmp, &dasd_serverlist, list)
+         // normale cmp?
+               if (strncmp(tmp->sid.vendor, uid->vendor,
+                           sizeof(tmp->sid.vendor)) == 0
+                   && strncmp(tmp->sid.serial, uid->serial,
+                              sizeof(tmp->sid.serial)) == 0)
+                       return 0;
+
+       new = (struct dasd_servermap *)
+               kzalloc(sizeof(struct dasd_servermap), GFP_KERNEL);
+       if (!new)
+               return -ENOMEM;
+
+       strncpy(new->sid.vendor, uid->vendor, sizeof(new->sid.vendor));
+       strncpy(new->sid.serial, uid->serial, sizeof(new->sid.serial));
+       list_add(&new->list, &dasd_serverlist);
+       return 1;
+}
+
 
 /*
  * Return copy of the device unique identifier.
@@ -854,21 +911,26 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid)
 
 /*
  * Register the given device unique identifier into devmap struct.
+ * Return 0 if server was already in serverlist,
+ *       1 if the server was added successful
+ *      <0 in case of error.
  */
 int
 dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid)
 {
        struct dasd_devmap *devmap;
+       int rc;
 
        devmap = dasd_find_busid(cdev->dev.bus_id);
        if (IS_ERR(devmap))
                return PTR_ERR(devmap);
        spin_lock(&dasd_devmap_lock);
        devmap->uid = *uid;
+       rc = dasd_add_server(uid);
        spin_unlock(&dasd_devmap_lock);
-       return 0;
+       return rc;
 }
-EXPORT_SYMBOL(dasd_set_uid);
+EXPORT_SYMBOL_GPL(dasd_set_uid);
 
 /*
  * Return value of the specified feature.
@@ -880,7 +942,7 @@ dasd_get_feature(struct ccw_device *cdev, int feature)
 
        devmap = dasd_find_busid(cdev->dev.bus_id);
        if (IS_ERR(devmap))
-               return (int) PTR_ERR(devmap);
+               return PTR_ERR(devmap);
 
        return ((devmap->features & feature) != 0);
 }
@@ -896,7 +958,7 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
 
        devmap = dasd_find_busid(cdev->dev.bus_id);
        if (IS_ERR(devmap))
-               return (int) PTR_ERR(devmap);
+               return PTR_ERR(devmap);
 
        spin_lock(&dasd_devmap_lock);
        if (flag)
@@ -932,8 +994,10 @@ dasd_devmap_init(void)
        dasd_max_devindex = 0;
        for (i = 0; i < 256; i++)
                INIT_LIST_HEAD(&dasd_hashlists[i]);
-       return 0;
 
+       /* Initialize servermap structure. */
+       INIT_LIST_HEAD(&dasd_serverlist);
+       return 0;
 }
 
 void
index 3f9d704d2657483f739dcced896a212413665882..4002f6c1c1b3222a01b1fa2ced3b8df3da0fe043 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_diag.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Based on.......: linux/drivers/s390/block/mdisk.c
@@ -336,7 +336,7 @@ dasd_diag_check_device(struct dasd_device *device)
 
        private = (struct dasd_diag_private *) device->private;
        if (private == NULL) {
-               private = kmalloc(sizeof(struct dasd_diag_private),GFP_KERNEL);
+               private = kzalloc(sizeof(struct dasd_diag_private),GFP_KERNEL);
                if (private == NULL) {
                        DEV_MESSAGE(KERN_WARNING, device, "%s",
                                "memory allocation failed for private data");
@@ -527,7 +527,7 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
                                   datasize, device);
        if (IS_ERR(cqr))
                return cqr;
-       
+
        dreq = (struct dasd_diag_req *) cqr->data;
        dreq->block_count = count;
        dbio = dreq->bio;
index 38a4e55f89539b90f514ea9f80b77d4f4d139475..b8c78267ff3ef01ef0e60a1e211784629f2f094e 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_diag.h
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Based on.......: linux/drivers/s390/block/mdisk.h
index 7d5a6cee4bd8ff075c4c48ed6edccdb30cefb283..0dfab30e8089814ca75b1320ce4114a0942dcb8a 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_eckd.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                 Horst Hummel <Horst.Hummel@de.ibm.com> 
+ *                 Horst Hummel <Horst.Hummel@de.ibm.com>
  *                 Carsten Otte <Cotte@de.ibm.com>
  *                 Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
@@ -24,6 +24,7 @@
 #include <asm/io.h>
 #include <asm/todclk.h>
 #include <asm/uaccess.h>
+#include <asm/cio.h>
 #include <asm/ccwdev.h>
 
 #include "dasd_int.h"
@@ -89,17 +90,22 @@ dasd_eckd_probe (struct ccw_device *cdev)
 {
        int ret;
 
-       ret = dasd_generic_probe (cdev, &dasd_eckd_discipline);
-       if (ret)
+       /* set ECKD specific ccw-device options */
+       ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE);
+       if (ret) {
+               printk(KERN_WARNING
+                      "dasd_eckd_probe: could not set ccw-device options "
+                      "for %s\n", cdev->dev.bus_id);
                return ret;
-       ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP | CCWDEV_ALLOW_FORCE);
-       return 0;
+       }
+       ret = dasd_generic_probe(cdev, &dasd_eckd_discipline);
+       return ret;
 }
 
 static int
 dasd_eckd_set_online(struct ccw_device *cdev)
 {
-       return dasd_generic_set_online (cdev, &dasd_eckd_discipline);
+       return dasd_generic_set_online(cdev, &dasd_eckd_discipline);
 }
 
 static struct ccw_driver dasd_eckd_driver = {
@@ -210,14 +216,14 @@ check_XRC (struct ccw1         *de_ccw,
 
         /* switch on System Time Stamp - needed for XRC Support */
         if (private->rdc_data.facilities.XRC_supported) {
-                
+
                 data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid'   */
                 data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
-                
+
                 data->ep_sys_time = get_clock ();
-                
+
                 de_ccw->count = sizeof (struct DE_eckd_data);
-                de_ccw->flags |= CCW_FLAG_SLI;  
+               de_ccw->flags |= CCW_FLAG_SLI;
         }
 
         return;
@@ -296,8 +302,8 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
        /* check for sequential prestage - enhance cylinder range */
        if (data->attributes.operation == DASD_SEQ_PRESTAGE ||
            data->attributes.operation == DASD_SEQ_ACCESS) {
-               
-               if (end.cyl + private->attrib.nr_cyl < geo.cyl) 
+
+               if (end.cyl + private->attrib.nr_cyl < geo.cyl)
                        end.cyl += private->attrib.nr_cyl;
                else
                        end.cyl = (geo.cyl - 1);
@@ -317,7 +323,7 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
        struct dasd_eckd_private *private;
        int sector;
        int dn, d;
-                               
+
        private = (struct dasd_eckd_private *) device->private;
 
        DBF_DEV_EVENT(DBF_INFO, device,
@@ -540,6 +546,86 @@ dasd_eckd_read_conf(struct dasd_device *device)
        return 0;
 }
 
+/*
+ * Build CP for Perform Subsystem Function - SSC.
+ */
+struct dasd_ccw_req *
+dasd_eckd_build_psf_ssc(struct dasd_device *device)
+{
+       struct dasd_ccw_req *cqr;
+       struct dasd_psf_ssc_data *psf_ssc_data;
+       struct ccw1 *ccw;
+
+       cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ ,
+                                 sizeof(struct dasd_psf_ssc_data),
+                                 device);
+
+       if (IS_ERR(cqr)) {
+              DEV_MESSAGE(KERN_WARNING, device, "%s",
+                          "Could not allocate PSF-SSC request");
+              return cqr;
+       }
+       psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
+       psf_ssc_data->order = PSF_ORDER_SSC;
+       psf_ssc_data->suborder = 0x08;
+
+       ccw = cqr->cpaddr;
+       ccw->cmd_code = DASD_ECKD_CCW_PSF;
+       ccw->cda = (__u32)(addr_t)psf_ssc_data;
+       ccw->count = 66;
+
+       cqr->device = device;
+       cqr->expires = 10*HZ;
+       cqr->buildclk = get_clock();
+       cqr->status = DASD_CQR_FILLED;
+       return cqr;
+}
+
+/*
+ * Perform Subsystem Function.
+ * It is necessary to trigger CIO for channel revalidation since this
+ * call might change behaviour of DASD devices.
+ */
+static int
+dasd_eckd_psf_ssc(struct dasd_device *device)
+{
+       struct dasd_ccw_req *cqr;
+       int rc;
+
+       cqr = dasd_eckd_build_psf_ssc(device);
+       if (IS_ERR(cqr))
+              return PTR_ERR(cqr);
+
+       rc = dasd_sleep_on(cqr);
+       if (!rc)
+              /* trigger CIO to reprobe devices */
+              css_schedule_reprobe();
+       dasd_sfree_request(cqr, cqr->device);
+       return rc;
+}
+
+/*
+ * Valide storage server of current device.
+ */
+static int
+dasd_eckd_validate_server(struct dasd_device *device)
+{
+       int rc;
+
+       /* Currently PAV is the only reason to 'validate' server on LPAR */
+       if (dasd_nopav || MACHINE_IS_VM)
+               return 0;
+
+       rc = dasd_eckd_psf_ssc(device);
+       if (rc)
+               /* may be requested feature is not available on server,
+                * therefore just report error and go ahead */
+               DEV_MESSAGE(KERN_INFO, device,
+                           "Perform Subsystem Function returned rc=%d", rc);
+       /* RE-Read Configuration Data */
+       return dasd_eckd_read_conf(device);
+}
+
 /*
  * Check device characteristics.
  * If the device is accessible using ECKD discipline, the device is enabled.
@@ -554,7 +640,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
 
        private = (struct dasd_eckd_private *) device->private;
        if (private == NULL) {
-               private = kmalloc(sizeof(struct dasd_eckd_private),
+               private = kzalloc(sizeof(struct dasd_eckd_private),
                                  GFP_KERNEL | GFP_DMA);
                if (private == NULL) {
                        DEV_MESSAGE(KERN_WARNING, device, "%s",
@@ -562,7 +648,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
                                    "data");
                        return -ENOMEM;
                }
-               memset(private, 0, sizeof(struct dasd_eckd_private));
                device->private = (void *) private;
        }
        /* Invalidate status of initial analysis. */
@@ -571,16 +656,29 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
        private->attrib.operation = DASD_NORMAL_CACHE;
        private->attrib.nr_cyl = 0;
 
+       /* Read Configuration Data */
+       rc = dasd_eckd_read_conf(device);
+       if (rc)
+               return rc;
+
+       /* Generate device unique id and register in devmap */
+       rc = dasd_eckd_generate_uid(device, &uid);
+       if (rc)
+               return rc;
+       rc = dasd_set_uid(device->cdev, &uid);
+       if (rc == 1)    /* new server found */
+               rc = dasd_eckd_validate_server(device);
+       if (rc)
+               return rc;
+
        /* Read Device Characteristics */
        rdc_data = (void *) &(private->rdc_data);
        memset(rdc_data, 0, sizeof(rdc_data));
        rc = read_dev_chars(device->cdev, &rdc_data, 64);
-       if (rc) {
+       if (rc)
                DEV_MESSAGE(KERN_WARNING, device,
-                           "Read device characteristics returned error %d",
-                           rc);
-               return rc;
-       }
+                           "Read device characteristics returned "
+                           "rc=%d", rc);
 
        DEV_MESSAGE(KERN_INFO, device,
                    "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d",
@@ -591,19 +689,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
                    private->rdc_data.no_cyl,
                    private->rdc_data.trk_per_cyl,
                    private->rdc_data.sec_per_trk);
-
-       /* Read Configuration Data */
-       rc = dasd_eckd_read_conf (device);
-       if (rc)
-               return rc;
-
-       /* Generate device unique id and register in devmap */
-       rc = dasd_eckd_generate_uid(device, &uid);
-       if (rc)
-               return rc;
-
-       rc = dasd_set_uid(device->cdev, &uid);
-
        return rc;
 }
 
@@ -773,7 +858,7 @@ dasd_eckd_end_analysis(struct dasd_device *device)
                    ((private->rdc_data.no_cyl *
                      private->rdc_data.trk_per_cyl *
                      blk_per_trk * (device->bp_block >> 9)) >> 1),
-                   ((blk_per_trk * device->bp_block) >> 10), 
+                   ((blk_per_trk * device->bp_block) >> 10),
                    private->uses_cdl ?
                    "compatible disk layout" : "linux disk layout");
 
@@ -970,7 +1055,7 @@ dasd_eckd_format_device(struct dasd_device * device,
                                if (i < 3) {
                                        ect->kl = 4;
                                        ect->dl = sizes_trk0[i] - 4;
-                               } 
+                               }
                        }
                        if ((fdata->intensity & 0x08) &&
                            fdata->start_unit == 1) {
@@ -1270,7 +1355,7 @@ dasd_eckd_fill_info(struct dasd_device * device,
 
 /*
  * Release device ioctl.
- * Buils a channel programm to releases a prior reserved 
+ * Buils a channel programm to releases a prior reserved
  * (see dasd_eckd_reserve) device.
  */
 static int
@@ -1310,8 +1395,8 @@ dasd_eckd_release(struct dasd_device *device)
 /*
  * Reserve device ioctl.
  * Options are set to 'synchronous wait for interrupt' and
- * 'timeout the request'. This leads to a terminate IO if 
- * the interrupt is outstanding for a certain time. 
+ * 'timeout the request'. This leads to a terminate IO if
+ * the interrupt is outstanding for a certain time.
  */
 static int
 dasd_eckd_reserve(struct dasd_device *device)
@@ -1349,7 +1434,7 @@ dasd_eckd_reserve(struct dasd_device *device)
 
 /*
  * Steal lock ioctl - unconditional reserve device.
- * Buils a channel programm to break a device's reservation. 
+ * Buils a channel programm to break a device's reservation.
  * (unconditional reserve)
  */
 static int
@@ -1521,6 +1606,40 @@ dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp)
        }
 }
 
+/*
+ * Dump the range of CCWs into 'page' buffer
+ * and return number of printed chars.
+ */
+static inline int
+dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
+{
+       int len, count;
+       char *datap;
+
+       len = 0;
+       while (from <= to) {
+               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
+                              " CCW %p: %08X %08X DAT:",
+                              from, ((int *) from)[0], ((int *) from)[1]);
+
+               /* get pointer to data (consider IDALs) */
+               if (from->flags & CCW_FLAG_IDA)
+                       datap = (char *) *((addr_t *) (addr_t) from->cda);
+               else
+                       datap = (char *) ((addr_t) from->cda);
+
+               /* dump data (max 32 bytes) */
+               for (count = 0; count < from->count && count < 32; count++) {
+                       if (count % 8 == 0) len += sprintf(page + len, " ");
+                       if (count % 4 == 0) len += sprintf(page + len, " ");
+                       len += sprintf(page + len, "%02x", datap[count]);
+               }
+               len += sprintf(page + len, "\n");
+               from++;
+       }
+       return len;
+}
+
 /*
  * Print sense data and related channel program.
  * Parts are printed because printk buffer is only 1024 bytes.
@@ -1530,8 +1649,8 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                     struct irb *irb)
 {
        char *page;
-       struct ccw1 *act, *end, *last;
-       int len, sl, sct, count;
+       struct ccw1 *first, *last, *fail, *from, *to;
+       int len, sl, sct;
 
        page = (char *) get_zeroed_page(GFP_ATOMIC);
        if (page == NULL) {
@@ -1539,7 +1658,8 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                            "No memory to dump sense data");
                return;
        }
-       len = sprintf(page, KERN_ERR PRINTK_HEADER
+       /* dump the sense data */
+       len = sprintf(page,  KERN_ERR PRINTK_HEADER
                      " I/O status report for device %s:\n",
                      device->cdev->dev.bus_id);
        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
@@ -1564,87 +1684,55 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
 
                if (irb->ecw[27] & DASD_SENSE_BIT_0) {
                        /* 24 Byte Sense Data */
-                       len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                                      " 24 Byte: %x MSG %x, "
-                                      "%s MSGb to SYSOP\n",
-                                      irb->ecw[7] >> 4, irb->ecw[7] & 0x0f,
-                                      irb->ecw[1] & 0x10 ? "" : "no");
+                       sprintf(page + len, KERN_ERR PRINTK_HEADER
+                               " 24 Byte: %x MSG %x, "
+                               "%s MSGb to SYSOP\n",
+                               irb->ecw[7] >> 4, irb->ecw[7] & 0x0f,
+                               irb->ecw[1] & 0x10 ? "" : "no");
                } else {
                        /* 32 Byte Sense Data */
-                       len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                                      " 32 Byte: Format: %x "
-                                      "Exception class %x\n",
-                                      irb->ecw[6] & 0x0f, irb->ecw[22] >> 4);
+                       sprintf(page + len, KERN_ERR PRINTK_HEADER
+                               " 32 Byte: Format: %x "
+                               "Exception class %x\n",
+                               irb->ecw[6] & 0x0f, irb->ecw[22] >> 4);
                }
        } else {
-               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                              " SORRY - NO VALID SENSE AVAILABLE\n");
+               sprintf(page + len, KERN_ERR PRINTK_HEADER
+                       " SORRY - NO VALID SENSE AVAILABLE\n");
        }
-       MESSAGE_LOG(KERN_ERR, "%s",
-                   page + sizeof(KERN_ERR PRINTK_HEADER));
-
-       /* dump the Channel Program */
-       /* print first CCWs (maximum 8) */
-       act = req->cpaddr;
-        for (last = act; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
-       end = min(act + 8, last);
-       len = sprintf(page, KERN_ERR PRINTK_HEADER
+       printk("%s", page);
+
+       /* dump the Channel Program (max 140 Bytes per line) */
+       /* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
+       first = req->cpaddr;
+       for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
+       to = min(first + 6, last);
+       len = sprintf(page,  KERN_ERR PRINTK_HEADER
                      " Related CP in req: %p\n", req);
-       while (act <= end) {
-               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                              " CCW %p: %08X %08X DAT:",
-                              act, ((int *) act)[0], ((int *) act)[1]);
-               for (count = 0; count < 32 && count < act->count;
-                    count += sizeof(int))
-                       len += sprintf(page + len, " %08X",
-                                      ((int *) (addr_t) act->cda)
-                                      [(count>>2)]);
-               len += sprintf(page + len, "\n");
-               act++;
-       }
-       MESSAGE_LOG(KERN_ERR, "%s",
-                   page + sizeof(KERN_ERR PRINTK_HEADER));
+       dasd_eckd_dump_ccw_range(first, to, page + len);
+       printk("%s", page);
 
-       /* print failing CCW area */
+       /* print failing CCW area (maximum 4) */
+       /* scsw->cda is either valid or zero  */
        len = 0;
-       if (act <  ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2) {
-               act = ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2;
-               len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
-       }
-       end = min((struct ccw1 *)(addr_t) irb->scsw.cpa + 2, last);
-       while (act <= end) {
-               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                              " CCW %p: %08X %08X DAT:",
-                              act, ((int *) act)[0], ((int *) act)[1]);
-               for (count = 0; count < 32 && count < act->count;
-                    count += sizeof(int))
-                       len += sprintf(page + len, " %08X",
-                                      ((int *) (addr_t) act->cda)
-                                      [(count>>2)]);
-               len += sprintf(page + len, "\n");
-               act++;
+       from = ++to;
+       fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */
+       if (from <  fail - 2) {
+               from = fail - 2;     /* there is a gap - print header */
+               len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n");
        }
+       to = min(fail + 1, last);
+       len += dasd_eckd_dump_ccw_range(from, to, page + len);
 
-       /* print last CCWs */
-       if (act <  last - 2) {
-               act = last - 2;
+       /* print last CCWs (maximum 2) */
+       from = max(from, ++to);
+       if (from < last - 1) {
+               from = last - 1;     /* there is a gap - print header */
                len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
        }
-       while (act <= last) {
-               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                              " CCW %p: %08X %08X DAT:",
-                              act, ((int *) act)[0], ((int *) act)[1]);
-               for (count = 0; count < 32 && count < act->count;
-                    count += sizeof(int))
-                       len += sprintf(page + len, " %08X",
-                                      ((int *) (addr_t) act->cda)
-                                      [(count>>2)]);
-               len += sprintf(page + len, "\n");
-               act++;
-       }
+       len += dasd_eckd_dump_ccw_range(from, last, page + len);
        if (len > 0)
-               MESSAGE_LOG(KERN_ERR, "%s",
-                           page + sizeof(KERN_ERR PRINTK_HEADER));
+               printk("%s", page);
        free_page((unsigned long) page);
 }
 
@@ -1685,14 +1773,8 @@ static struct dasd_discipline dasd_eckd_discipline = {
 static int __init
 dasd_eckd_init(void)
 {
-       int ret;
-
        ASCEBC(dasd_eckd_discipline.ebcname, 4);
-
-       ret = ccw_driver_register(&dasd_eckd_driver);
-       if (!ret)
-               dasd_generic_auto_online(&dasd_eckd_driver);
-       return ret;
+       return ccw_driver_register(&dasd_eckd_driver);
 }
 
 static void __exit
@@ -1703,22 +1785,3 @@ dasd_eckd_cleanup(void)
 
 module_init(dasd_eckd_init);
 module_exit(dasd_eckd_cleanup);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
index d5734e976e1c7da5fd599c52f83ba75a0f6e6e18..712ff1650134c5e1b60953758c922440231bd66d 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_eckd.h
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                  Horst Hummel <Horst.Hummel@de.ibm.com> 
+ *                 Horst Hummel <Horst.Hummel@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
 #define DASD_ECKD_CCW_RESERVE           0xB4
 
 /*
- *Perform Subsystem Function / Sub-Orders
+ * Perform Subsystem Function / Sub-Orders
  */
-#define PSF_ORDER_PRSSD                         0x18
+#define PSF_ORDER_PRSSD 0x18
+#define PSF_ORDER_SSC  0x1D
 
 /*****************************************************************************
  * SECTION: Type Definitions
@@ -155,7 +156,7 @@ struct dasd_eckd_characteristics {
                unsigned char reserved2:4;
                unsigned char reserved3:8;
                unsigned char defect_wr:1;
-               unsigned char XRC_supported:1; 
+               unsigned char XRC_supported:1;
                unsigned char reserved4:1;
                unsigned char striping:1;
                unsigned char reserved5:4;
@@ -343,7 +344,7 @@ struct dasd_eckd_path {
 };
 
 /*
- * Perform Subsystem Function - Prepare for Read Subsystem Data         
+ * Perform Subsystem Function - Prepare for Read Subsystem Data
  */
 struct dasd_psf_prssd_data {
        unsigned char order;
@@ -353,4 +354,15 @@ struct dasd_psf_prssd_data {
        unsigned char varies[9];
 } __attribute__ ((packed));
 
+/*
+ * Perform Subsystem Function - Set Subsystem Characteristics
+ */
+struct dasd_psf_ssc_data {
+       unsigned char order;
+       unsigned char flags;
+       unsigned char cu_type[4];
+       unsigned char suborder;
+       unsigned char reserved[59];
+} __attribute__((packed));
+
 #endif                         /* DASD_ECKD_H */
index 2d8af709947fb09fefdb32c2bb8b195845f11d69..da65f1b032f5ad59748e356342afd1793eb0878e 100644 (file)
@@ -276,7 +276,7 @@ struct dasd_eer_header {
        __u64 tv_sec;
        __u64 tv_usec;
        char busid[DASD_EER_BUSID_SIZE];
-};
+} __attribute__ ((packed));
 
 /*
  * The following function can be used for those triggers that have
@@ -521,6 +521,8 @@ static int dasd_eer_open(struct inode *inp, struct file *filp)
        unsigned long flags;
 
        eerb = kzalloc(sizeof(struct eerbuffer), GFP_KERNEL);
+       if (!eerb)
+               return -ENOMEM;
        eerb->buffer_page_count = eer_pages;
        if (eerb->buffer_page_count < 1 ||
            eerb->buffer_page_count > INT_MAX / PAGE_SIZE) {
index b842377cb0c6c51fa562ba364d4bcab4b2a0d07e..4108d96f6a5a8b9ae5622c79efc09f16adf38b04 100644 (file)
@@ -90,7 +90,7 @@ dasd_default_erp_action(struct dasd_ccw_req * cqr)
 
         /* just retry - there is nothing to save ... I got no sense data.... */
         if (cqr->retries > 0) {
-                DEV_MESSAGE (KERN_DEBUG, device, 
+               DEV_MESSAGE (KERN_DEBUG, device,
                              "default ERP called (%i retries left)",
                              cqr->retries);
                cqr->lpm    = LPM_ANYPATH;
@@ -155,7 +155,7 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
 
 /*
  * Print the hex dump of the memory used by a request. This includes
- * all error recovery ccws that have been chained in from of the 
+ * all error recovery ccws that have been chained in from of the
  * real request.
  */
 static inline void
@@ -227,12 +227,12 @@ dasd_log_ccw(struct dasd_ccw_req * cqr, int caller, __u32 cpa)
                /*
                 * Log bytes arround failed CCW but only if we did
                 * not log the whole CP of the CCW is outside the
-                * logged CP. 
+                * logged CP.
                 */
                if (cplength > 40 ||
                    ((addr_t) cpa < (addr_t) lcqr->cpaddr &&
                     (addr_t) cpa > (addr_t) (lcqr->cpaddr + cplength + 4))) {
-                       
+
                        DEV_MESSAGE(KERN_ERR, device,
                                    "Failed CCW (%p) (area):",
                                    (void *) (long) cpa);
index 91145698f8e926c7265e3d1581abf61479d62b9b..bb7755b9b19d7dfa408a9d79c959ff40f858468e 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_fba.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
@@ -56,19 +56,13 @@ static struct ccw_driver dasd_fba_driver; /* see below */
 static int
 dasd_fba_probe(struct ccw_device *cdev)
 {
-       int ret;
-
-       ret = dasd_generic_probe (cdev, &dasd_fba_discipline);
-       if (ret)
-               return ret;
-       ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
-       return 0;
+       return dasd_generic_probe(cdev, &dasd_fba_discipline);
 }
 
 static int
 dasd_fba_set_online(struct ccw_device *cdev)
 {
-       return dasd_generic_set_online (cdev, &dasd_fba_discipline);
+       return dasd_generic_set_online(cdev, &dasd_fba_discipline);
 }
 
 static struct ccw_driver dasd_fba_driver = {
@@ -125,13 +119,13 @@ static int
 dasd_fba_check_characteristics(struct dasd_device *device)
 {
        struct dasd_fba_private *private;
-       struct ccw_device *cdev = device->cdev; 
+       struct ccw_device *cdev = device->cdev;
        void *rdc_data;
        int rc;
 
        private = (struct dasd_fba_private *) device->private;
        if (private == NULL) {
-               private = kmalloc(sizeof(struct dasd_fba_private), GFP_KERNEL);
+               private = kzalloc(sizeof(struct dasd_fba_private), GFP_KERNEL);
                if (private == NULL) {
                        DEV_MESSAGE(KERN_WARNING, device, "%s",
                                    "memory allocation failed for private "
@@ -204,7 +198,7 @@ dasd_fba_examine_error(struct dasd_ccw_req * cqr, struct irb * irb)
        if (irb->scsw.cstat == 0x00 &&
            irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
                return dasd_era_none;
-       
+
        cdev = device->cdev;
        switch (cdev->id.dev_type) {
        case 0x3370:
@@ -539,7 +533,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
  * 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has
  * 24 bytes, the struct dasd_ccw_req has 136 bytes and each block can use
  * up to 16 bytes (8 for the ccw and 8 for the idal pointer). In
- * addition we have one define extent ccw + 16 bytes of data and a 
+ * addition we have one define extent ccw + 16 bytes of data and a
  * locate record ccw for each block (stupid devices!) + 16 bytes of data.
  * That makes:
  * (8192 - 24 - 136 - 8 - 16) / 40 = 200.2 blocks at maximum.
@@ -569,16 +563,8 @@ static struct dasd_discipline dasd_fba_discipline = {
 static int __init
 dasd_fba_init(void)
 {
-       int ret;
-
        ASCEBC(dasd_fba_discipline.ebcname, 4);
-
-       ret = ccw_driver_register(&dasd_fba_driver);
-       if (ret)
-               return ret;
-
-       dasd_generic_auto_online(&dasd_fba_driver);
-       return 0;
+       return ccw_driver_register(&dasd_fba_driver);
 }
 
 static void __exit
@@ -589,22 +575,3 @@ dasd_fba_cleanup(void)
 
 module_init(dasd_fba_init);
 module_exit(dasd_fba_cleanup);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
index da1fa91fc01dd42a94cffe047459c9ffc6a00136..14c910baa5fe6160192b7c548d8921b829707eda 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_fba.h
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
index d4b13e300a76db523ad2f263ce2f55023c108e6e..03a83efc34c4f71db19f4403c2170554fa4f9f91 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_int.h
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                  Horst Hummel <Horst.Hummel@de.ibm.com> 
+ *                 Horst Hummel <Horst.Hummel@de.ibm.com>
  *                 Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
@@ -186,7 +186,7 @@ struct dasd_ccw_req {
         void *callback_data;
 };
 
-/* 
+/*
  * dasd_ccw_req -> status can be:
  */
 #define DASD_CQR_FILLED   0x00 /* request is ready to be processed */
@@ -248,7 +248,7 @@ struct dasd_discipline {
         /*
          * Error recovery functions. examine_error() returns a value that
          * indicates what to do for an error condition. If examine_error()
-         * returns 'dasd_era_recover' erp_action() is called to create a 
+        * returns 'dasd_era_recover' erp_action() is called to create a
          * special error recovery ccw. erp_postaction() is called after
          * an error recovery ccw has finished its execution. dump_sense
          * is called for every error condition to print the sense data
@@ -302,11 +302,11 @@ struct dasd_device {
        spinlock_t request_queue_lock;
        struct block_device *bdev;
         unsigned int devindex;
-       unsigned long blocks;           /* size of volume in blocks */
-       unsigned int bp_block;          /* bytes per block */
-       unsigned int s2b_shift;         /* log2 (bp_block/512) */
-       unsigned long flags;            /* per device flags */
-       unsigned short features;        /* copy of devmap-features (read-only!) */
+       unsigned long blocks;      /* size of volume in blocks */
+       unsigned int bp_block;     /* bytes per block */
+       unsigned int s2b_shift;    /* log2 (bp_block/512) */
+       unsigned long flags;       /* per device flags */
+       unsigned short features;   /* copy of devmap-features (read-only!) */
 
        /* extended error reporting stuff (eer) */
        struct dasd_ccw_req *eer_cqr;
@@ -513,12 +513,12 @@ void dasd_generic_remove (struct ccw_device *cdev);
 int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
 int dasd_generic_set_offline (struct ccw_device *cdev);
 int dasd_generic_notify(struct ccw_device *, int);
-void dasd_generic_auto_online (struct ccw_driver *);
 
 /* externals in dasd_devmap.c */
 extern int dasd_max_devindex;
 extern int dasd_probeonly;
 extern int dasd_autodetect;
+extern int dasd_nopav;
 
 int dasd_devmap_init(void);
 void dasd_devmap_exit(void);
@@ -606,22 +606,3 @@ static inline int dasd_eer_enabled(struct dasd_device *device)
 #endif                         /* __KERNEL__ */
 
 #endif                         /* DASD_H */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
index b8c80d28df41dba762d8827608fd22e5c5c93e2f..302bcd0f28be4c4532862915417ba2a5add9ea2d 100644 (file)
@@ -90,10 +90,10 @@ static int
 dasd_ioctl_quiesce(struct dasd_device *device)
 {
        unsigned long flags;
-       
+
        if (!capable (CAP_SYS_ADMIN))
                return -EACCES;
-       
+
        DEV_MESSAGE (KERN_DEBUG, device, "%s",
                     "Quiesce IO on device");
        spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
@@ -110,13 +110,13 @@ static int
 dasd_ioctl_resume(struct dasd_device *device)
 {
        unsigned long flags;
-       
-       if (!capable (CAP_SYS_ADMIN)) 
+
+       if (!capable (CAP_SYS_ADMIN))
                return -EACCES;
 
        DEV_MESSAGE (KERN_DEBUG, device, "%s",
                     "resume IO on device");
-       
+
        spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
        device->stopped &= ~DASD_STOPPED_QUIESCE;
        spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
@@ -287,7 +287,7 @@ dasd_ioctl_information(struct dasd_device *device,
        dasd_info->open_count = atomic_read(&device->open_count);
        if (!device->bdev)
                dasd_info->open_count++;
-       
+
        /*
         * check if device is really formatted
         * LDL / CDL was returned by 'fill_info'
index eecb2afad5c25ce460acdeba66041b7d5f291838..3c1314b7391b0fe5141982210c366dfb902875e0 100644 (file)
@@ -50,6 +50,9 @@ struct raw3270 {
        unsigned char *ascebc;          /* ascii -> ebcdic table */
        struct class_device *clttydev;  /* 3270-class tty device ptr */
        struct class_device *cltubdev;  /* 3270-class tub device ptr */
+
+       struct raw3270_request init_request;
+       unsigned char init_data[256];
 };
 
 /* raw3270->flags */
@@ -484,8 +487,6 @@ struct raw3270_ua { /* Query Reply structure for Usable Area */
        } __attribute__ ((packed)) aua;
 } __attribute__ ((packed));
 
-static unsigned char raw3270_init_data[256];
-static struct raw3270_request raw3270_init_request;
 static struct diag210 raw3270_init_diag210;
 static DECLARE_MUTEX(raw3270_init_sem);
 
@@ -644,17 +645,17 @@ __raw3270_size_device(struct raw3270 *rp)
         * required (3270 device switched to 'stand-by') and command
         * rejects (old devices that can't do 'read partition').
         */
-       memset(&raw3270_init_request, 0, sizeof(raw3270_init_request));
-       memset(raw3270_init_data, 0, sizeof(raw3270_init_data));
-       /* Store 'read partition' data stream to raw3270_init_data */
-       memcpy(raw3270_init_data, wbuf, sizeof(wbuf));
-       INIT_LIST_HEAD(&raw3270_init_request.list);
-       raw3270_init_request.ccw.cmd_code = TC_WRITESF;
-       raw3270_init_request.ccw.flags = CCW_FLAG_SLI;
-       raw3270_init_request.ccw.count = sizeof(wbuf);
-       raw3270_init_request.ccw.cda = (__u32) __pa(raw3270_init_data);
-
-       rc = raw3270_start_init(rp, &raw3270_init_view, &raw3270_init_request);
+       memset(&rp->init_request, 0, sizeof(rp->init_request));
+       memset(&rp->init_data, 0, 256);
+       /* Store 'read partition' data stream to init_data */
+       memcpy(&rp->init_data, wbuf, sizeof(wbuf));
+       INIT_LIST_HEAD(&rp->init_request.list);
+       rp->init_request.ccw.cmd_code = TC_WRITESF;
+       rp->init_request.ccw.flags = CCW_FLAG_SLI;
+       rp->init_request.ccw.count = sizeof(wbuf);
+       rp->init_request.ccw.cda = (__u32) __pa(&rp->init_data);
+
+       rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
        if (rc)
                /* Check error cases: -ERESTARTSYS, -EIO and -EOPNOTSUPP */
                return rc;
@@ -679,18 +680,18 @@ __raw3270_size_device(struct raw3270 *rp)
         * The device accepted the 'read partition' command. Now
         * set up a read ccw and issue it.
         */
-       raw3270_init_request.ccw.cmd_code = TC_READMOD;
-       raw3270_init_request.ccw.flags = CCW_FLAG_SLI;
-       raw3270_init_request.ccw.count = sizeof(raw3270_init_data);
-       raw3270_init_request.ccw.cda = (__u32) __pa(raw3270_init_data);
-       rc = raw3270_start_init(rp, &raw3270_init_view, &raw3270_init_request);
+       rp->init_request.ccw.cmd_code = TC_READMOD;
+       rp->init_request.ccw.flags = CCW_FLAG_SLI;
+       rp->init_request.ccw.count = sizeof(rp->init_data);
+       rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
+       rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
        if (rc)
                return rc;
        /* Got a Query Reply */
-       count = sizeof(raw3270_init_data) - raw3270_init_request.rescnt;
-       uap = (struct raw3270_ua *) (raw3270_init_data + 1);
+       count = sizeof(rp->init_data) - rp->init_request.rescnt;
+       uap = (struct raw3270_ua *) (rp->init_data + 1);
        /* Paranoia check. */
-       if (raw3270_init_data[0] != 0x88 || uap->uab.qcode != 0x81)
+       if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81)
                return -EOPNOTSUPP;
        /* Copy rows/columns of default Usable Area */
        rp->rows = uap->uab.h;
@@ -749,18 +750,18 @@ raw3270_reset_device(struct raw3270 *rp)
        int rc;
 
        down(&raw3270_init_sem);
-       memset(&raw3270_init_request, 0, sizeof(raw3270_init_request));
-       memset(raw3270_init_data, 0, sizeof(raw3270_init_data));
-       /* Store reset data stream to raw3270_init_data/raw3270_init_request */
-       raw3270_init_data[0] = TW_KR;
-       INIT_LIST_HEAD(&raw3270_init_request.list);
-       raw3270_init_request.ccw.cmd_code = TC_EWRITEA;
-       raw3270_init_request.ccw.flags = CCW_FLAG_SLI;
-       raw3270_init_request.ccw.count = 1;
-       raw3270_init_request.ccw.cda = (__u32) __pa(raw3270_init_data);
+       memset(&rp->init_request, 0, sizeof(rp->init_request));
+       memset(&rp->init_data, 0, sizeof(rp->init_data));
+       /* Store reset data stream to init_data/init_request */
+       rp->init_data[0] = TW_KR;
+       INIT_LIST_HEAD(&rp->init_request.list);
+       rp->init_request.ccw.cmd_code = TC_EWRITEA;
+       rp->init_request.ccw.flags = CCW_FLAG_SLI;
+       rp->init_request.ccw.count = 1;
+       rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
        rp->view = &raw3270_init_view;
        raw3270_init_view.dev = rp;
-       rc = raw3270_start_init(rp, &raw3270_init_view, &raw3270_init_request);
+       rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
        raw3270_init_view.dev = 0;
        rp->view = 0;
        up(&raw3270_init_sem);
@@ -854,7 +855,7 @@ raw3270_setup_console(struct ccw_device *cdev)
        char *ascebc;
        int rc;
 
-       rp = (struct raw3270 *) alloc_bootmem(sizeof(struct raw3270));
+       rp = (struct raw3270 *) alloc_bootmem_low(sizeof(struct raw3270));
        ascebc = (char *) alloc_bootmem(256);
        rc = raw3270_setup_device(cdev, rp, ascebc);
        if (rc)
@@ -895,7 +896,7 @@ raw3270_create_device(struct ccw_device *cdev)
        char *ascebc;
        int rc;
 
-       rp = kmalloc(sizeof(struct raw3270), GFP_KERNEL);
+       rp = kmalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
        if (!rp)
                return ERR_PTR(-ENOMEM);
        ascebc = kmalloc(256, GFP_KERNEL);
index 0960bef7b199ca6c45868f6e746dee1a862550ac..15b895496a45025038559b18eb874d1b6b6cfc50 100644 (file)
@@ -224,39 +224,6 @@ is_blacklisted (int ssid, int devno)
 }
 
 #ifdef CONFIG_PROC_FS
-static int
-__s390_redo_validation(struct subchannel_id schid, void *data)
-{
-       int ret;
-       struct subchannel *sch;
-
-       sch = get_subchannel_by_schid(schid);
-       if (sch) {
-               /* Already known. */
-               put_device(&sch->dev);
-               return 0;
-       }
-       ret = css_probe_device(schid);
-       if (ret == -ENXIO)
-               return ret; /* We're through. */
-       if (ret == -ENOMEM)
-               /* Stop validation for now. Bad, but no need for a panic. */
-               return ret;
-       return 0;
-}
-
-/*
- * Function: s390_redo_validation
- * Look for no longer blacklisted devices
- * FIXME: there must be a better way to do this */
-static inline void
-s390_redo_validation (void)
-{
-       CIO_TRACE_EVENT (0, "redoval");
-
-       for_each_subchannel(__s390_redo_validation, NULL);
-}
-
 /*
  * Function: blacklist_parse_proc_parameters
  * parse the stuff which is piped to /proc/cio_ignore
@@ -281,7 +248,7 @@ blacklist_parse_proc_parameters (char *buf)
                return;
        }
 
-       s390_redo_validation ();
+       css_schedule_reprobe();
 }
 
 /* Iterator struct for all devices. */
index bdfee7fbaa2ea1f4f9af9e6c964ef04c52f6cd09..c7319a07ba35161fde79dac21de10332d0387736 100644 (file)
@@ -404,21 +404,24 @@ ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
 }
 
 static int
-__ccwgroup_driver_unregister_device(struct device *dev, void *data)
+__ccwgroup_match_all(struct device *dev, void *data)
 {
-       __ccwgroup_remove_symlinks(to_ccwgroupdev(dev));
-       device_unregister(dev);
-       put_device(dev);
-       return 0;
+       return 1;
 }
 
 void
 ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
 {
+       struct device *dev;
+
        /* We don't want ccwgroup devices to live longer than their driver. */
        get_driver(&cdriver->driver);
-       driver_for_each_device(&cdriver->driver, NULL, NULL,
-                              __ccwgroup_driver_unregister_device);
+       while ((dev = driver_find_device(&cdriver->driver, NULL, NULL,
+                                        __ccwgroup_match_all))) {
+               __ccwgroup_remove_symlinks(to_ccwgroupdev(dev));
+               device_unregister(dev);
+               put_device(dev);
+       }
        put_driver(&cdriver->driver);
        driver_unregister(&cdriver->driver);
 }
index 72187e54dcac79353107616bac3fb1aec3f1b4d0..b00f3ed051a094bf259d90b62026959ad139143c 100644 (file)
@@ -244,8 +244,7 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
 
        if ((sch->schib.scsw.actl & SCSW_ACTL_DEVACT) &&
            (sch->schib.scsw.actl & SCSW_ACTL_SCHACT) &&
-           (sch->schib.pmcw.lpum == mask) &&
-           (sch->vpm == 0)) {
+           (sch->schib.pmcw.lpum == mask)) {
                int cc;
 
                cc = cio_clear(sch);
@@ -918,12 +917,13 @@ chp_measurement_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
        chp = to_channelpath(container_of(kobj, struct device, kobj));
        css = to_css(chp->dev.parent);
 
-       size = sizeof(struct cmg_chars);
+       size = sizeof(struct cmg_entry);
 
        /* Only allow single reads. */
        if (off || count < size)
                return 0;
        chp_measurement_copy_block((struct cmg_entry *)buf, css, chp->id);
+       count = size;
        return count;
 }
 
index 07ef3f640f4aa73ec17460a93ab020f21a9bfb2e..1c3e8e9012b08c3553c1b5b7de806a87598f2fc0 100644 (file)
@@ -3,9 +3,10 @@
  *
  * Linux on zSeries Channel Measurement Facility support
  *
- * Copyright 2000,2003 IBM Corporation
+ * Copyright 2000,2006 IBM Corporation
  *
- * Author: Arnd Bergmann <arndb@de.ibm.com>
+ * Authors: Arnd Bergmann <arndb@de.ibm.com>
+ *         Cornelia Huck <cornelia.huck@de.ibm.com>
  *
  * original idea from Natarajan Krishnaswami <nkrishna@us.ibm.com>
  *
@@ -96,9 +97,9 @@ module_param(format, bool, 0444);
 /**
  * struct cmb_operations - functions to use depending on cmb_format
  *
- * all these functions operate on a struct cmf_device. There is only
- * one instance of struct cmb_operations because all cmf_device
- * objects are guaranteed to be of the same type.
+ * Most of these functions operate on a struct ccw_device. There is only
+ * one instance of struct cmb_operations because the format of the measurement
+ * data is guaranteed to be the same for every ccw_device.
  *
  * @alloc:     allocate memory for a channel measurement block,
  *             either with the help of a special pool or with kmalloc
@@ -107,6 +108,7 @@ module_param(format, bool, 0444);
  * @readall:   read a measurement block in a common format
  * @reset:     clear the data in the associated measurement block and
  *             reset its time stamp
+ * @align:     align an allocated block so that the hardware can use it
  */
 struct cmb_operations {
        int (*alloc)  (struct ccw_device*);
@@ -115,11 +117,19 @@ struct cmb_operations {
        u64 (*read)   (struct ccw_device*, int);
        int (*readall)(struct ccw_device*, struct cmbdata *);
        void (*reset) (struct ccw_device*);
+       void * (*align) (void *);
 
        struct attribute_group *attr_group;
 };
 static struct cmb_operations *cmbops;
 
+struct cmb_data {
+       void *hw_block;   /* Pointer to block updated by hardware */
+       void *last_block; /* Last changed block copied from hardware block */
+       int size;         /* Size of hw_block and last_block */
+       unsigned long long last_update;  /* when last_block was updated */
+};
+
 /* our user interface is designed in terms of nanoseconds,
  * while the hardware measures total times in its own
  * unit.*/
@@ -226,63 +236,229 @@ struct set_schib_struct {
        unsigned long address;
        wait_queue_head_t wait;
        int ret;
+       struct kref kref;
 };
 
+static void cmf_set_schib_release(struct kref *kref)
+{
+       struct set_schib_struct *set_data;
+
+       set_data = container_of(kref, struct set_schib_struct, kref);
+       kfree(set_data);
+}
+
+#define CMF_PENDING 1
+
 static int set_schib_wait(struct ccw_device *cdev, u32 mme,
                                int mbfc, unsigned long address)
 {
-       struct set_schib_struct s = {
-               .mme = mme,
-               .mbfc = mbfc,
-               .address = address,
-               .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s.wait),
-       };
+       struct set_schib_struct *set_data;
+       int ret;
 
        spin_lock_irq(cdev->ccwlock);
-       s.ret = set_schib(cdev, mme, mbfc, address);
-       if (s.ret != -EBUSY) {
-               goto out_nowait;
+       if (!cdev->private->cmb) {
+               ret = -ENODEV;
+               goto out;
        }
+       set_data = kzalloc(sizeof(struct set_schib_struct), GFP_ATOMIC);
+       if (!set_data) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       init_waitqueue_head(&set_data->wait);
+       kref_init(&set_data->kref);
+       set_data->mme = mme;
+       set_data->mbfc = mbfc;
+       set_data->address = address;
+
+       ret = set_schib(cdev, mme, mbfc, address);
+       if (ret != -EBUSY)
+               goto out_put;
 
        if (cdev->private->state != DEV_STATE_ONLINE) {
-               s.ret = -EBUSY;
                /* if the device is not online, don't even try again */
-               goto out_nowait;
+               ret = -EBUSY;
+               goto out_put;
        }
+
        cdev->private->state = DEV_STATE_CMFCHANGE;
-       cdev->private->cmb_wait = &s;
-       s.ret = 1;
+       set_data->ret = CMF_PENDING;
+       cdev->private->cmb_wait = set_data;
 
        spin_unlock_irq(cdev->ccwlock);
-       if (wait_event_interruptible(s.wait, s.ret != 1)) {
+       if (wait_event_interruptible(set_data->wait,
+                                    set_data->ret != CMF_PENDING)) {
                spin_lock_irq(cdev->ccwlock);
-               if (s.ret == 1) {
-                       s.ret = -ERESTARTSYS;
-                       cdev->private->cmb_wait = 0;
+               if (set_data->ret == CMF_PENDING) {
+                       set_data->ret = -ERESTARTSYS;
                        if (cdev->private->state == DEV_STATE_CMFCHANGE)
                                cdev->private->state = DEV_STATE_ONLINE;
                }
                spin_unlock_irq(cdev->ccwlock);
        }
-       return s.ret;
-
-out_nowait:
+       spin_lock_irq(cdev->ccwlock);
+       cdev->private->cmb_wait = NULL;
+       ret = set_data->ret;
+out_put:
+       kref_put(&set_data->kref, cmf_set_schib_release);
+out:
        spin_unlock_irq(cdev->ccwlock);
-       return s.ret;
+       return ret;
 }
 
 void retry_set_schib(struct ccw_device *cdev)
 {
-       struct set_schib_struct *s;
+       struct set_schib_struct *set_data;
+
+       set_data = cdev->private->cmb_wait;
+       if (!set_data) {
+               WARN_ON(1);
+               return;
+       }
+       kref_get(&set_data->kref);
+       set_data->ret = set_schib(cdev, set_data->mme, set_data->mbfc,
+                                 set_data->address);
+       wake_up(&set_data->wait);
+       kref_put(&set_data->kref, cmf_set_schib_release);
+}
+
+static int cmf_copy_block(struct ccw_device *cdev)
+{
+       struct subchannel *sch;
+       void *reference_buf;
+       void *hw_block;
+       struct cmb_data *cmb_data;
+
+       sch = to_subchannel(cdev->dev.parent);
+
+       if (stsch(sch->schid, &sch->schib))
+               return -ENODEV;
+
+       if (sch->schib.scsw.fctl & SCSW_FCTL_START_FUNC) {
+               /* Don't copy if a start function is in progress. */
+               if ((!sch->schib.scsw.actl & SCSW_ACTL_SUSPENDED) &&
+                   (sch->schib.scsw.actl &
+                    (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) &&
+                   (!sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS))
+                       return -EBUSY;
+       }
+       cmb_data = cdev->private->cmb;
+       hw_block = cmbops->align(cmb_data->hw_block);
+       if (!memcmp(cmb_data->last_block, hw_block, cmb_data->size))
+               /* No need to copy. */
+               return 0;
+       reference_buf = kzalloc(cmb_data->size, GFP_ATOMIC);
+       if (!reference_buf)
+               return -ENOMEM;
+       /* Ensure consistency of block copied from hardware. */
+       do {
+               memcpy(cmb_data->last_block, hw_block, cmb_data->size);
+               memcpy(reference_buf, hw_block, cmb_data->size);
+       } while (memcmp(cmb_data->last_block, reference_buf, cmb_data->size));
+       cmb_data->last_update = get_clock();
+       kfree(reference_buf);
+       return 0;
+}
+
+struct copy_block_struct {
+       wait_queue_head_t wait;
+       int ret;
+       struct kref kref;
+};
+
+static void cmf_copy_block_release(struct kref *kref)
+{
+       struct copy_block_struct *copy_block;
+
+       copy_block = container_of(kref, struct copy_block_struct, kref);
+       kfree(copy_block);
+}
+
+static int cmf_cmb_copy_wait(struct ccw_device *cdev)
+{
+       struct copy_block_struct *copy_block;
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(cdev->ccwlock, flags);
+       if (!cdev->private->cmb) {
+               ret = -ENODEV;
+               goto out;
+       }
+       copy_block = kzalloc(sizeof(struct copy_block_struct), GFP_ATOMIC);
+       if (!copy_block) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       init_waitqueue_head(&copy_block->wait);
+       kref_init(&copy_block->kref);
+
+       ret = cmf_copy_block(cdev);
+       if (ret != -EBUSY)
+               goto out_put;
+
+       if (cdev->private->state != DEV_STATE_ONLINE) {
+               ret = -EBUSY;
+               goto out_put;
+       }
+
+       cdev->private->state = DEV_STATE_CMFUPDATE;
+       copy_block->ret = CMF_PENDING;
+       cdev->private->cmb_wait = copy_block;
+
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       if (wait_event_interruptible(copy_block->wait,
+                                    copy_block->ret != CMF_PENDING)) {
+               spin_lock_irqsave(cdev->ccwlock, flags);
+               if (copy_block->ret == CMF_PENDING) {
+                       copy_block->ret = -ERESTARTSYS;
+                       if (cdev->private->state == DEV_STATE_CMFUPDATE)
+                               cdev->private->state = DEV_STATE_ONLINE;
+               }
+               spin_unlock_irqrestore(cdev->ccwlock, flags);
+       }
+       spin_lock_irqsave(cdev->ccwlock, flags);
+       cdev->private->cmb_wait = NULL;
+       ret = copy_block->ret;
+out_put:
+       kref_put(&copy_block->kref, cmf_copy_block_release);
+out:
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       return ret;
+}
+
+void cmf_retry_copy_block(struct ccw_device *cdev)
+{
+       struct copy_block_struct *copy_block;
 
-       s = cdev->private->cmb_wait;
-       cdev->private->cmb_wait = 0;
-       if (!s) {
+       copy_block = cdev->private->cmb_wait;
+       if (!copy_block) {
                WARN_ON(1);
                return;
        }
-       s->ret = set_schib(cdev, s->mme, s->mbfc, s->address);
-       wake_up(&s->wait);
+       kref_get(&copy_block->kref);
+       copy_block->ret = cmf_copy_block(cdev);
+       wake_up(&copy_block->wait);
+       kref_put(&copy_block->kref, cmf_copy_block_release);
+}
+
+static void cmf_generic_reset(struct ccw_device *cdev)
+{
+       struct cmb_data *cmb_data;
+
+       spin_lock_irq(cdev->ccwlock);
+       cmb_data = cdev->private->cmb;
+       if (cmb_data) {
+               memset(cmb_data->last_block, 0, cmb_data->size);
+               /*
+                * Need to reset hw block as well to make the hardware start
+                * from 0 again.
+                */
+               memset(cmbops->align(cmb_data->hw_block), 0, cmb_data->size);
+               cmb_data->last_update = 0;
+       }
+       cdev->private->cmb_start_time = get_clock();
+       spin_unlock_irq(cdev->ccwlock);
 }
 
 /**
@@ -343,8 +519,8 @@ struct cmb {
 /* insert a single device into the cmb_area list
  * called with cmb_area.lock held from alloc_cmb
  */
-static inline int
-alloc_cmb_single (struct ccw_device *cdev)
+static inline int alloc_cmb_single (struct ccw_device *cdev,
+                                   struct cmb_data *cmb_data)
 {
        struct cmb *cmb;
        struct ccw_device_private *node;
@@ -358,10 +534,12 @@ alloc_cmb_single (struct ccw_device *cdev)
 
        /* find first unused cmb in cmb_area.mem.
         * this is a little tricky: cmb_area.list
-        * remains sorted by ->cmb pointers */
+        * remains sorted by ->cmb->hw_data pointers */
        cmb = cmb_area.mem;
        list_for_each_entry(node, &cmb_area.list, cmb_list) {
-               if ((struct cmb*)node->cmb > cmb)
+               struct cmb_data *data;
+               data = node->cmb;
+               if ((struct cmb*)data->hw_block > cmb)
                        break;
                cmb++;
        }
@@ -372,7 +550,8 @@ alloc_cmb_single (struct ccw_device *cdev)
 
        /* insert new cmb */
        list_add_tail(&cdev->private->cmb_list, &node->cmb_list);
-       cdev->private->cmb = cmb;
+       cmb_data->hw_block = cmb;
+       cdev->private->cmb = cmb_data;
        ret = 0;
 out:
        spin_unlock_irq(cdev->ccwlock);
@@ -385,7 +564,19 @@ alloc_cmb (struct ccw_device *cdev)
        int ret;
        struct cmb *mem;
        ssize_t size;
+       struct cmb_data *cmb_data;
+
+       /* Allocate private cmb_data. */
+       cmb_data = kzalloc(sizeof(struct cmb_data), GFP_KERNEL);
+       if (!cmb_data)
+               return -ENOMEM;
 
+       cmb_data->last_block = kzalloc(sizeof(struct cmb), GFP_KERNEL);
+       if (!cmb_data->last_block) {
+               kfree(cmb_data);
+               return -ENOMEM;
+       }
+       cmb_data->size = sizeof(struct cmb);
        spin_lock(&cmb_area.lock);
 
        if (!cmb_area.mem) {
@@ -414,29 +605,36 @@ alloc_cmb (struct ccw_device *cdev)
        }
 
        /* do the actual allocation */
-       ret = alloc_cmb_single(cdev);
+       ret = alloc_cmb_single(cdev, cmb_data);
 out:
        spin_unlock(&cmb_area.lock);
-
+       if (ret) {
+               kfree(cmb_data->last_block);
+               kfree(cmb_data);
+       }
        return ret;
 }
 
-static void
-free_cmb(struct ccw_device *cdev)
+static void free_cmb(struct ccw_device *cdev)
 {
        struct ccw_device_private *priv;
-
-       priv = cdev->private;
+       struct cmb_data *cmb_data;
 
        spin_lock(&cmb_area.lock);
        spin_lock_irq(cdev->ccwlock);
 
+       priv = cdev->private;
+
        if (list_empty(&priv->cmb_list)) {
                /* already freed */
                goto out;
        }
 
+       cmb_data = priv->cmb;
        priv->cmb = NULL;
+       if (cmb_data)
+               kfree(cmb_data->last_block);
+       kfree(cmb_data);
        list_del_init(&priv->cmb_list);
 
        if (list_empty(&cmb_area.list)) {
@@ -451,83 +649,97 @@ out:
        spin_unlock(&cmb_area.lock);
 }
 
-static int
-set_cmb(struct ccw_device *cdev, u32 mme)
+static int set_cmb(struct ccw_device *cdev, u32 mme)
 {
        u16 offset;
+       struct cmb_data *cmb_data;
+       unsigned long flags;
 
-       if (!cdev->private->cmb)
+       spin_lock_irqsave(cdev->ccwlock, flags);
+       if (!cdev->private->cmb) {
+               spin_unlock_irqrestore(cdev->ccwlock, flags);
                return -EINVAL;
-
-       offset = mme ? (struct cmb *)cdev->private->cmb - cmb_area.mem : 0;
+       }
+       cmb_data = cdev->private->cmb;
+       offset = mme ? (struct cmb *)cmb_data->hw_block - cmb_area.mem : 0;
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
 
        return set_schib_wait(cdev, mme, 0, offset);
 }
 
-static u64
-read_cmb (struct ccw_device *cdev, int index)
+static u64 read_cmb (struct ccw_device *cdev, int index)
 {
-       /* yes, we have to put it on the stack
-        * because the cmb must only be accessed
-        * atomically, e.g. with mvc */
-       struct cmb cmb;
-       unsigned long flags;
+       struct cmb *cmb;
        u32 val;
+       int ret;
+       unsigned long flags;
+
+       ret = cmf_cmb_copy_wait(cdev);
+       if (ret < 0)
+               return 0;
 
        spin_lock_irqsave(cdev->ccwlock, flags);
        if (!cdev->private->cmb) {
-               spin_unlock_irqrestore(cdev->ccwlock, flags);
-               return 0;
+               ret = 0;
+               goto out;
        }
-
-       cmb = *(struct cmb*)cdev->private->cmb;
-       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       cmb = ((struct cmb_data *)cdev->private->cmb)->last_block;
 
        switch (index) {
        case cmb_ssch_rsch_count:
-               return cmb.ssch_rsch_count;
+               ret = cmb->ssch_rsch_count;
+               goto out;
        case cmb_sample_count:
-               return cmb.sample_count;
+               ret = cmb->sample_count;
+               goto out;
        case cmb_device_connect_time:
-               val = cmb.device_connect_time;
+               val = cmb->device_connect_time;
                break;
        case cmb_function_pending_time:
-               val = cmb.function_pending_time;
+               val = cmb->function_pending_time;
                break;
        case cmb_device_disconnect_time:
-               val = cmb.device_disconnect_time;
+               val = cmb->device_disconnect_time;
                break;
        case cmb_control_unit_queuing_time:
-               val = cmb.control_unit_queuing_time;
+               val = cmb->control_unit_queuing_time;
                break;
        case cmb_device_active_only_time:
-               val = cmb.device_active_only_time;
+               val = cmb->device_active_only_time;
                break;
        default:
-               return 0;
+               ret = 0;
+               goto out;
        }
-       return time_to_avg_nsec(val, cmb.sample_count);
+       ret = time_to_avg_nsec(val, cmb->sample_count);
+out:
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       return ret;
 }
 
-static int
-readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
 {
-       /* yes, we have to put it on the stack
-        * because the cmb must only be accessed
-        * atomically, e.g. with mvc */
-       struct cmb cmb;
-       unsigned long flags;
+       struct cmb *cmb;
+       struct cmb_data *cmb_data;
        u64 time;
+       unsigned long flags;
+       int ret;
 
+       ret = cmf_cmb_copy_wait(cdev);
+       if (ret < 0)
+               return ret;
        spin_lock_irqsave(cdev->ccwlock, flags);
-       if (!cdev->private->cmb) {
-               spin_unlock_irqrestore(cdev->ccwlock, flags);
-               return -ENODEV;
+       cmb_data = cdev->private->cmb;
+       if (!cmb_data) {
+               ret = -ENODEV;
+               goto out;
        }
-
-       cmb = *(struct cmb*)cdev->private->cmb;
-       time = get_clock() - cdev->private->cmb_start_time;
-       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       if (cmb_data->last_update == 0) {
+               ret = -EAGAIN;
+               goto out;
+       }
+       cmb = cmb_data->last_block;
+       time = cmb_data->last_update - cdev->private->cmb_start_time;
 
        memset(data, 0, sizeof(struct cmbdata));
 
@@ -538,31 +750,32 @@ readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
        data->elapsed_time = (time * 1000) >> 12;
 
        /* copy data to new structure */
-       data->ssch_rsch_count = cmb.ssch_rsch_count;
-       data->sample_count = cmb.sample_count;
+       data->ssch_rsch_count = cmb->ssch_rsch_count;
+       data->sample_count = cmb->sample_count;
 
        /* time fields are converted to nanoseconds while copying */
-       data->device_connect_time = time_to_nsec(cmb.device_connect_time);
-       data->function_pending_time = time_to_nsec(cmb.function_pending_time);
-       data->device_disconnect_time = time_to_nsec(cmb.device_disconnect_time);
+       data->device_connect_time = time_to_nsec(cmb->device_connect_time);
+       data->function_pending_time = time_to_nsec(cmb->function_pending_time);
+       data->device_disconnect_time =
+               time_to_nsec(cmb->device_disconnect_time);
        data->control_unit_queuing_time
-               = time_to_nsec(cmb.control_unit_queuing_time);
+               = time_to_nsec(cmb->control_unit_queuing_time);
        data->device_active_only_time
-               = time_to_nsec(cmb.device_active_only_time);
+               = time_to_nsec(cmb->device_active_only_time);
+       ret = 0;
+out:
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       return ret;
+}
 
-       return 0;
+static void reset_cmb(struct ccw_device *cdev)
+{
+       cmf_generic_reset(cdev);
 }
 
-static void
-reset_cmb(struct ccw_device *cdev)
+static void * align_cmb(void *area)
 {
-       struct cmb *cmb;
-       spin_lock_irq(cdev->ccwlock);
-       cmb = cdev->private->cmb;
-       if (cmb)
-               memset (cmb, 0, sizeof (*cmb));
-       cdev->private->cmb_start_time = get_clock();
-       spin_unlock_irq(cdev->ccwlock);
+       return area;
 }
 
 static struct attribute_group cmf_attr_group;
@@ -574,6 +787,7 @@ static struct cmb_operations cmbops_basic = {
        .read   = read_cmb,
        .readall    = readall_cmb,
        .reset      = reset_cmb,
+       .align      = align_cmb,
        .attr_group = &cmf_attr_group,
 };
 \f
@@ -610,22 +824,34 @@ static inline struct cmbe* cmbe_align(struct cmbe *c)
        return (struct cmbe*)addr;
 }
 
-static int
-alloc_cmbe (struct ccw_device *cdev)
+static int alloc_cmbe (struct ccw_device *cdev)
 {
        struct cmbe *cmbe;
-       cmbe = kmalloc (sizeof (*cmbe) * 2, GFP_KERNEL);
+       struct cmb_data *cmb_data;
+       int ret;
+
+       cmbe = kzalloc (sizeof (*cmbe) * 2, GFP_KERNEL);
        if (!cmbe)
                return -ENOMEM;
-
+       cmb_data = kzalloc(sizeof(struct cmb_data), GFP_KERNEL);
+       if (!cmb_data) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+       cmb_data->last_block = kzalloc(sizeof(struct cmbe), GFP_KERNEL);
+       if (!cmb_data->last_block) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+       cmb_data->size = sizeof(struct cmbe);
        spin_lock_irq(cdev->ccwlock);
        if (cdev->private->cmb) {
-               kfree(cmbe);
                spin_unlock_irq(cdev->ccwlock);
-               return -EBUSY;
+               ret = -EBUSY;
+               goto out_free;
        }
-
-       cdev->private->cmb = cmbe;
+       cmb_data->hw_block = cmbe;
+       cdev->private->cmb = cmb_data;
        spin_unlock_irq(cdev->ccwlock);
 
        /* activate global measurement if this is the first channel */
@@ -636,14 +862,24 @@ alloc_cmbe (struct ccw_device *cdev)
        spin_unlock(&cmb_area.lock);
 
        return 0;
+out_free:
+       if (cmb_data)
+               kfree(cmb_data->last_block);
+       kfree(cmb_data);
+       kfree(cmbe);
+       return ret;
 }
 
-static void
-free_cmbe (struct ccw_device *cdev)
+static void free_cmbe (struct ccw_device *cdev)
 {
+       struct cmb_data *cmb_data;
+
        spin_lock_irq(cdev->ccwlock);
-       kfree(cdev->private->cmb);
+       cmb_data = cdev->private->cmb;
        cdev->private->cmb = NULL;
+       if (cmb_data)
+               kfree(cmb_data->last_block);
+       kfree(cmb_data);
        spin_unlock_irq(cdev->ccwlock);
 
        /* deactivate global measurement if this is the last channel */
@@ -654,89 +890,105 @@ free_cmbe (struct ccw_device *cdev)
        spin_unlock(&cmb_area.lock);
 }
 
-static int
-set_cmbe(struct ccw_device *cdev, u32 mme)
+static int set_cmbe(struct ccw_device *cdev, u32 mme)
 {
        unsigned long mba;
+       struct cmb_data *cmb_data;
+       unsigned long flags;
 
-       if (!cdev->private->cmb)
+       spin_lock_irqsave(cdev->ccwlock, flags);
+       if (!cdev->private->cmb) {
+               spin_unlock_irqrestore(cdev->ccwlock, flags);
                return -EINVAL;
-       mba = mme ? (unsigned long) cmbe_align(cdev->private->cmb) : 0;
+       }
+       cmb_data = cdev->private->cmb;
+       mba = mme ? (unsigned long) cmbe_align(cmb_data->hw_block) : 0;
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
 
        return set_schib_wait(cdev, mme, 1, mba);
 }
 
 
-u64
-read_cmbe (struct ccw_device *cdev, int index)
+static u64 read_cmbe (struct ccw_device *cdev, int index)
 {
-       /* yes, we have to put it on the stack
-        * because the cmb must only be accessed
-        * atomically, e.g. with mvc */
-       struct cmbe cmb;
-       unsigned long flags;
+       struct cmbe *cmb;
+       struct cmb_data *cmb_data;
        u32 val;
+       int ret;
+       unsigned long flags;
 
-       spin_lock_irqsave(cdev->ccwlock, flags);
-       if (!cdev->private->cmb) {
-               spin_unlock_irqrestore(cdev->ccwlock, flags);
+       ret = cmf_cmb_copy_wait(cdev);
+       if (ret < 0)
                return 0;
-       }
 
-       cmb = *cmbe_align(cdev->private->cmb);
-       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       spin_lock_irqsave(cdev->ccwlock, flags);
+       cmb_data = cdev->private->cmb;
+       if (!cmb_data) {
+               ret = 0;
+               goto out;
+       }
+       cmb = cmb_data->last_block;
 
        switch (index) {
        case cmb_ssch_rsch_count:
-               return cmb.ssch_rsch_count;
+               ret = cmb->ssch_rsch_count;
+               goto out;
        case cmb_sample_count:
-               return cmb.sample_count;
+               ret = cmb->sample_count;
+               goto out;
        case cmb_device_connect_time:
-               val = cmb.device_connect_time;
+               val = cmb->device_connect_time;
                break;
        case cmb_function_pending_time:
-               val = cmb.function_pending_time;
+               val = cmb->function_pending_time;
                break;
        case cmb_device_disconnect_time:
-               val = cmb.device_disconnect_time;
+               val = cmb->device_disconnect_time;
                break;
        case cmb_control_unit_queuing_time:
-               val = cmb.control_unit_queuing_time;
+               val = cmb->control_unit_queuing_time;
                break;
        case cmb_device_active_only_time:
-               val = cmb.device_active_only_time;
+               val = cmb->device_active_only_time;
                break;
        case cmb_device_busy_time:
-               val = cmb.device_busy_time;
+               val = cmb->device_busy_time;
                break;
        case cmb_initial_command_response_time:
-               val = cmb.initial_command_response_time;
+               val = cmb->initial_command_response_time;
                break;
        default:
-               return 0;
+               ret = 0;
+               goto out;
        }
-       return time_to_avg_nsec(val, cmb.sample_count);
+       ret = time_to_avg_nsec(val, cmb->sample_count);
+out:
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       return ret;
 }
 
-static int
-readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
 {
-       /* yes, we have to put it on the stack
-        * because the cmb must only be accessed
-        * atomically, e.g. with mvc */
-       struct cmbe cmb;
-       unsigned long flags;
+       struct cmbe *cmb;
+       struct cmb_data *cmb_data;
        u64 time;
+       unsigned long flags;
+       int ret;
 
+       ret = cmf_cmb_copy_wait(cdev);
+       if (ret < 0)
+               return ret;
        spin_lock_irqsave(cdev->ccwlock, flags);
-       if (!cdev->private->cmb) {
-               spin_unlock_irqrestore(cdev->ccwlock, flags);
-               return -ENODEV;
+       cmb_data = cdev->private->cmb;
+       if (!cmb_data) {
+               ret = -ENODEV;
+               goto out;
        }
-
-       cmb = *cmbe_align(cdev->private->cmb);
-       time = get_clock() - cdev->private->cmb_start_time;
-       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       if (cmb_data->last_update == 0) {
+               ret = -EAGAIN;
+               goto out;
+       }
+       time = cmb_data->last_update - cdev->private->cmb_start_time;
 
        memset (data, 0, sizeof(struct cmbdata));
 
@@ -746,35 +998,38 @@ readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
        /* conver to nanoseconds */
        data->elapsed_time = (time * 1000) >> 12;
 
+       cmb = cmb_data->last_block;
        /* copy data to new structure */
-       data->ssch_rsch_count = cmb.ssch_rsch_count;
-       data->sample_count = cmb.sample_count;
+       data->ssch_rsch_count = cmb->ssch_rsch_count;
+       data->sample_count = cmb->sample_count;
 
        /* time fields are converted to nanoseconds while copying */
-       data->device_connect_time = time_to_nsec(cmb.device_connect_time);
-       data->function_pending_time = time_to_nsec(cmb.function_pending_time);
-       data->device_disconnect_time = time_to_nsec(cmb.device_disconnect_time);
+       data->device_connect_time = time_to_nsec(cmb->device_connect_time);
+       data->function_pending_time = time_to_nsec(cmb->function_pending_time);
+       data->device_disconnect_time =
+               time_to_nsec(cmb->device_disconnect_time);
        data->control_unit_queuing_time
-               = time_to_nsec(cmb.control_unit_queuing_time);
+               = time_to_nsec(cmb->control_unit_queuing_time);
        data->device_active_only_time
-               = time_to_nsec(cmb.device_active_only_time);
-       data->device_busy_time = time_to_nsec(cmb.device_busy_time);
+               = time_to_nsec(cmb->device_active_only_time);
+       data->device_busy_time = time_to_nsec(cmb->device_busy_time);
        data->initial_command_response_time
-               = time_to_nsec(cmb.initial_command_response_time);
+               = time_to_nsec(cmb->initial_command_response_time);
 
-       return 0;
+       ret = 0;
+out:
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       return ret;
 }
 
-static void
-reset_cmbe(struct ccw_device *cdev)
+static void reset_cmbe(struct ccw_device *cdev)
 {
-       struct cmbe *cmb;
-       spin_lock_irq(cdev->ccwlock);
-       cmb = cmbe_align(cdev->private->cmb);
-       if (cmb)
-               memset (cmb, 0, sizeof (*cmb));
-       cdev->private->cmb_start_time = get_clock();
-       spin_unlock_irq(cdev->ccwlock);
+       cmf_generic_reset(cdev);
+}
+
+static void * align_cmbe(void *area)
+{
+       return cmbe_align(area);
 }
 
 static struct attribute_group cmf_attr_group_ext;
@@ -786,6 +1041,7 @@ static struct cmb_operations cmbops_extended = {
        .read       = read_cmbe,
        .readall    = readall_cmbe,
        .reset      = reset_cmbe,
+       .align      = align_cmbe,
        .attr_group = &cmf_attr_group_ext,
 };
 \f
@@ -803,14 +1059,19 @@ cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr,
        struct ccw_device *cdev;
        long interval;
        unsigned long count;
+       struct cmb_data *cmb_data;
 
        cdev = to_ccwdev(dev);
-       interval  = get_clock() - cdev->private->cmb_start_time;
        count = cmf_read(cdev, cmb_sample_count);
-       if (count)
+       spin_lock_irq(cdev->ccwlock);
+       cmb_data = cdev->private->cmb;
+       if (count) {
+               interval = cmb_data->last_update -
+                       cdev->private->cmb_start_time;
                interval /= count;
-       else
+       else
                interval = -1;
+       spin_unlock_irq(cdev->ccwlock);
        return sprintf(buf, "%ld\n", interval);
 }
 
@@ -823,7 +1084,10 @@ cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char
        int ret;
 
        ret = cmf_readall(to_ccwdev(dev), &data);
-       if (ret)
+       if (ret == -EAGAIN || ret == -ENODEV)
+               /* No data (yet/currently) available to use for calculation. */
+               return sprintf(buf, "n/a\n");
+       else if (ret)
                return ret;
 
        utilization = data.device_connect_time +
@@ -982,6 +1246,13 @@ cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
        return cmbops->readall(cdev, data);
 }
 
+/* Reenable cmf when a disconnected device becomes available again. */
+int cmf_reenable(struct ccw_device *cdev)
+{
+       cmbops->reset(cdev);
+       return cmbops->set(cdev, 2);
+}
+
 static int __init
 init_cmf(void)
 {
index 74ea8aac4b7d9683c37ce79e79a41edf673b9d07..1d3be80797f81e1ed119a08394f872cc20700236 100644 (file)
 #include "cio_debug.h"
 #include "ioasm.h"
 #include "chsc.h"
+#include "device.h"
 
 int need_rescan = 0;
 int css_init_done = 0;
+static int need_reprobe = 0;
 static int max_ssid = 0;
 
 struct channel_subsystem *css[__MAX_CSSID + 1];
@@ -339,6 +341,67 @@ typedef void (*workfunc)(void *);
 DECLARE_WORK(slow_path_work, (workfunc)css_trigger_slow_path, NULL);
 struct workqueue_struct *slow_path_wq;
 
+/* Reprobe subchannel if unregistered. */
+static int reprobe_subchannel(struct subchannel_id schid, void *data)
+{
+       struct subchannel *sch;
+       int ret;
+
+       CIO_DEBUG(KERN_INFO, 6, "cio: reprobe 0.%x.%04x\n",
+                 schid.ssid, schid.sch_no);
+       if (need_reprobe)
+               return -EAGAIN;
+
+       sch = get_subchannel_by_schid(schid);
+       if (sch) {
+               /* Already known. */
+               put_device(&sch->dev);
+               return 0;
+       }
+
+       ret = css_probe_device(schid);
+       switch (ret) {
+       case 0:
+               break;
+       case -ENXIO:
+       case -ENOMEM:
+               /* These should abort looping */
+               break;
+       default:
+               ret = 0;
+       }
+
+       return ret;
+}
+
+/* Work function used to reprobe all unregistered subchannels. */
+static void reprobe_all(void *data)
+{
+       int ret;
+
+       CIO_MSG_EVENT(2, "reprobe start\n");
+
+       need_reprobe = 0;
+       /* Make sure initial subchannel scan is done. */
+       wait_event(ccw_device_init_wq,
+                  atomic_read(&ccw_device_init_count) == 0);
+       ret = for_each_subchannel(reprobe_subchannel, NULL);
+
+       CIO_MSG_EVENT(2, "reprobe done (rc=%d, need_reprobe=%d)\n", ret,
+                     need_reprobe);
+}
+
+DECLARE_WORK(css_reprobe_work, reprobe_all, NULL);
+
+/* Schedule reprobing of all unregistered subchannels. */
+void css_schedule_reprobe(void)
+{
+       need_reprobe = 1;
+       queue_work(ccw_device_work, &css_reprobe_work);
+}
+
+EXPORT_SYMBOL_GPL(css_schedule_reprobe);
+
 /*
  * Rescan for new devices. FIXME: This is slow.
  * This function is called when we have lost CRWs due to overflows and we have
index 8e3053c2a451b4f5dc84d5b7fb77df52119d124c..eafde43e8410cd3e1f041343f86dad2bd543d8c6 100644 (file)
@@ -133,8 +133,8 @@ struct css_driver io_subchannel_driver = {
 
 struct workqueue_struct *ccw_device_work;
 struct workqueue_struct *ccw_device_notify_work;
-static wait_queue_head_t ccw_device_init_wq;
-static atomic_t ccw_device_init_count;
+wait_queue_head_t ccw_device_init_wq;
+atomic_t ccw_device_init_count;
 
 static int __init
 init_ccw_bus_type (void)
index 11587ebb72897dcd68d04dc8d26df767e01af52f..00be9a5b4acde18141a76d7aef38ad4b90b2347c 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef S390_DEVICE_H
 #define S390_DEVICE_H
 
+#include <asm/ccwdev.h>
+#include <asm/atomic.h>
+#include <linux/wait.h>
+
 /*
  * states of the device statemachine
  */
@@ -23,6 +27,7 @@ enum dev_state {
        DEV_STATE_DISCONNECTED,
        DEV_STATE_DISCONNECTED_SENSE_ID,
        DEV_STATE_CMFCHANGE,
+       DEV_STATE_CMFUPDATE,
        /* last element! */
        NR_DEV_STATES
 };
@@ -67,6 +72,8 @@ dev_fsm_final_state(struct ccw_device *cdev)
 
 extern struct workqueue_struct *ccw_device_work;
 extern struct workqueue_struct *ccw_device_notify_work;
+extern wait_queue_head_t ccw_device_init_wq;
+extern atomic_t ccw_device_init_count;
 
 void io_subchannel_recog_done(struct ccw_device *cdev);
 
@@ -112,5 +119,8 @@ int ccw_device_stlck(struct ccw_device *);
 void ccw_device_set_timeout(struct ccw_device *, int);
 extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *);
 
+/* Channel measurement facility related */
 void retry_set_schib(struct ccw_device *cdev);
+void cmf_retry_copy_block(struct ccw_device *);
+int cmf_reenable(struct ccw_device *);
 #endif
index 49ec562d7f60b7d9d5d3c7658851394c11020d8d..7d0dd72635ebde671ce882d13cab17ad6094019f 100644 (file)
@@ -336,8 +336,11 @@ ccw_device_oper_notify(void *data)
        if (!ret)
                /* Driver doesn't want device back. */
                ccw_device_do_unreg_rereg((void *)cdev);
-       else
+       else {
+               /* Reenable channel measurements, if needed. */
+               cmf_reenable(cdev);
                wake_up(&cdev->private->wait_q);
+       }
 }
 
 /*
@@ -861,6 +864,8 @@ ccw_device_clear_verify(struct ccw_device *cdev, enum dev_event dev_event)
        irb = (struct irb *) __LC_IRB;
        /* Accumulate status. We don't do basic sense. */
        ccw_device_accumulate_irb(cdev, irb);
+       /* Remember to clear irb to avoid residuals. */
+       memset(&cdev->private->irb, 0, sizeof(struct irb));
        /* Try to start delayed device verification. */
        ccw_device_online_verify(cdev, 0);
        /* Note: Don't call handler for cio initiated clear! */
@@ -1093,6 +1098,13 @@ ccw_device_change_cmfstate(struct ccw_device *cdev, enum dev_event dev_event)
        dev_fsm_event(cdev, dev_event);
 }
 
+static void ccw_device_update_cmfblock(struct ccw_device *cdev,
+                                      enum dev_event dev_event)
+{
+       cmf_retry_copy_block(cdev);
+       cdev->private->state = DEV_STATE_ONLINE;
+       dev_fsm_event(cdev, dev_event);
+}
 
 static void
 ccw_device_quiesce_done(struct ccw_device *cdev, enum dev_event dev_event)
@@ -1247,6 +1259,12 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
                [DEV_EVENT_TIMEOUT]     = ccw_device_change_cmfstate,
                [DEV_EVENT_VERIFY]      = ccw_device_change_cmfstate,
        },
+       [DEV_STATE_CMFUPDATE] = {
+               [DEV_EVENT_NOTOPER]     = ccw_device_update_cmfblock,
+               [DEV_EVENT_INTERRUPT]   = ccw_device_update_cmfblock,
+               [DEV_EVENT_TIMEOUT]     = ccw_device_update_cmfblock,
+               [DEV_EVENT_VERIFY]      = ccw_device_update_cmfblock,
+       },
 };
 
 /*
index 795abb5a65ba122620517ff44b7164deceec0a50..b266ad8e14ff2623fc6e5cea70e04d9a4160435b 100644 (file)
@@ -78,7 +78,8 @@ ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
                return -ENODEV;
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return -ENODEV;
-       if (cdev->private->state == DEV_STATE_VERIFY) {
+       if (cdev->private->state == DEV_STATE_VERIFY ||
+           cdev->private->state == DEV_STATE_CLEAR_VERIFY) {
                /* Remember to fake irb when finished. */
                if (!cdev->private->flags.fake_irb) {
                        cdev->private->flags.fake_irb = 1;
@@ -270,7 +271,8 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
                 * We didn't get channel end / device end. Check if path
                 * verification has been started; we can retry after it has
                 * finished. We also retry unit checks except for command reject
-                * or intervention required.
+                * or intervention required. Also check for long busy
+                * conditions.
                 */
                 if (cdev->private->flags.doverify ||
                         cdev->private->state == DEV_STATE_VERIFY)
@@ -279,6 +281,10 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
                     !(irb->ecw[0] &
                       (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)))
                         cdev->private->intparm = -EAGAIN;
+               else if ((irb->scsw.dstat & DEV_STAT_ATTENTION) &&
+                        (irb->scsw.dstat & DEV_STAT_DEV_END) &&
+                        (irb->scsw.dstat & DEV_STAT_UNIT_EXCEP))
+                       cdev->private->intparm = -EAGAIN;
                 else
                         cdev->private->intparm = -EIO;
                         
index f99e55308b32df8625658de3f63c1fddf5010236..8dc75002acbea71b1788ed35d314b42dc0e70207 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/errno.h>
 #include <linux/workqueue.h>
 #include <linux/time.h>
+#include <linux/kthread.h>
 
 #include <asm/lowcore.h>
 
@@ -56,8 +57,6 @@ s390_collect_crw_info(void *param)
        unsigned int chain;
 
        sem = (struct semaphore *)param;
-       /* Set a nice name. */
-       daemonize("kmcheck");
 repeat:
        down_interruptible(sem);
        slow = 0;
@@ -516,7 +515,7 @@ arch_initcall(machine_check_init);
 static int __init
 machine_check_crw_init (void)
 {
-       kernel_thread(s390_collect_crw_info, &m_sem, CLONE_FS|CLONE_FILES);
+       kthread_run(s390_collect_crw_info, &m_sem, "kmcheck");
        ctl_set_bit(14, 28);    /* enable channel report MCH */
        return 0;
 }
index 4d2b126ba15961a6b7f7ee8b83d0e751d02b9a8c..0ddcdba79e4a91b6b04b140810994f31bd5636a8 100644 (file)
@@ -12,6 +12,9 @@
  *    Copyright (C) 1992, Linus Torvalds
  *
  */
+
+#ifdef __KERNEL__
+
 #include <linux/compiler.h>
 
 /*
  * with operation of the form "set_bit(bitnr, flags)".
  */
 
-/* set ALIGN_CS to 1 if the SMP safe bit operations should
- * align the address to 4 byte boundary. It seems to work
- * without the alignment. 
- */
-#ifdef __KERNEL__
-#define ALIGN_CS 0
-#else
-#define ALIGN_CS 1
-#ifndef CONFIG_SMP
-#error "bitops won't work without CONFIG_SMP"
-#endif
-#endif
-
 /* bitmap tables from arch/S390/kernel/bitmap.S */
 extern const char _oi_bitmap[];
 extern const char _ni_bitmap[];
@@ -121,10 +111,6 @@ static inline void set_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;    /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;         /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make OR mask */
@@ -141,10 +127,6 @@ static inline void clear_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;    /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;         /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make AND mask */
@@ -161,10 +143,6 @@ static inline void change_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;    /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;         /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make XOR mask */
@@ -182,10 +160,6 @@ test_and_set_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;    /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;         /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make OR/test mask */
@@ -205,10 +179,6 @@ test_and_clear_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;    /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;         /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make AND/test mask */
@@ -228,10 +198,6 @@ test_and_change_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;  /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;       /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make XOR/test mask */
@@ -834,8 +800,6 @@ static inline int sched_find_first_bit(unsigned long *b)
 
 #include <asm-generic/bitops/hweight.h>
 
-#ifdef __KERNEL__
-
 /*
  * ATTENTION: intel byte ordering convention for ext2 and minix !!
  * bit 0 is the LSB of addr; bit 31 is the MSB of addr;
index 089cf567c317b48f09501a377e73b320a59192d0..2b16193063513003e49e7327e8e5add0690f48a9 100644 (file)
@@ -276,6 +276,8 @@ extern void wait_cons_dev(void);
 
 extern void clear_all_subchannels(void);
 
+extern void css_schedule_reprobe(void);
+
 #endif
 
 #endif
index 2d09950a9c11207d43daaa593860256bc52438b1..241756f80df35260a06641d523f42a519170f513 100644 (file)
@@ -44,10 +44,6 @@ struct cmbdata {
 #define BIODASDCMFENABLE       _IO(DASD_IOCTL_LETTER,32)
 /* enable channel measurement */
 #define BIODASDCMFDISABLE      _IO(DASD_IOCTL_LETTER,33)
-/* reset channel measurement block */
-#define BIODASDRESETCMB                _IO(DASD_IOCTL_LETTER,34)
-/* read channel measurement data */
-#define BIODASDREADCMB         _IOWR(DASD_IOCTL_LETTER,32,__u64)
 /* read channel measurement data */
 #define BIODASDREADALLCMB      _IOWR(DASD_IOCTL_LETTER,33,struct cmbdata)
 
index 1630c26e8f45a5c27eef949454fb4702747fc7f0..c042f9578081a4ece5e06afb1b996bd558ed3416 100644 (file)
@@ -68,10 +68,12 @@ typedef struct dasd_information2_t {
  * 0x00: default features
  * 0x01: readonly (ro)
  * 0x02: use diag discipline (diag)
+ * 0x04: set the device initially online (internal use only)
  */
-#define DASD_FEATURE_DEFAULT  0
-#define DASD_FEATURE_READONLY 1
-#define DASD_FEATURE_USEDIAG  2
+#define DASD_FEATURE_DEFAULT        0x00
+#define DASD_FEATURE_READONLY       0x01
+#define DASD_FEATURE_USEDIAG        0x02
+#define DASD_FEATURE_INITIAL_ONLINE  0x04
 
 #define DASD_PARTN_BITS 2
 
index 8e0c7ed73d0312a811c5a3f887527747a6c669c3..0a518915bf90f1087466444caf0809a8b9b3a02b 100644 (file)
@@ -63,6 +63,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
+       .preempt_count  = 1,                    \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall,    \
        },                                      \
index e21443d3ea1df4532562d613571f611c1b464a63..aa7a243862e1b714afbc0803de501b1ab2b13e69 100644 (file)
 
 #ifdef __KERNEL__
 
-/* user-visible error numbers are in the range -1 - -122: see <asm-s390/errno.h> */
-
 #define __syscall_return(type, res)                         \
 do {                                                        \
-       if ((unsigned long)(res) >= (unsigned long)(-125)) { \
+       if ((unsigned long)(res) >= (unsigned long)(-4095)) {\
                errno = -(res);                              \
                res = -1;                                    \
        }                                                    \