GIT d9b7058be6557e5e559824eb3eb96f72ee030ce8 git://git390.osdl.marist.edu/pub/scm/s390-features.git commit c6c6e122b12ed0d02fa3b051c327f23323312060 Author: Serge E. Hallyn Date: Wed Jun 14 15:28:55 2006 +0200 [S390] kthread conversion. Convert s390_collect_crw_info() in s390mach.c from being started as a deprecated kernel_thread to a kthread. Signed-off-by: Serge E. Hallyn Signed-off-by: Martin Schwidefsky commit 39ffca4eb7eca944dbb263b27463918e2bb77792 Author: Cornelia Huck Date: Wed Jun 14 15:28:46 2006 +0200 [S390] rework of channel measurement facility. Fixes for several channel measurement facility bugs: * Blocks copied from the hardware might not be consistent. Solve this by moving the copying into idle state and repeating the copying. * avg_sample_interval changed with every read, even though no new block was available. Solve this by storing a timestamp when the last new block was received. * Several locking issues. * Measurements were not reenabled after a disconnected device became available again. * Remove #defines for ioctls that were never implemented. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky commit 61835aeb01aca38f9f2357ef1d5848735b48bc36 Author: Stefan Weinhuber Date: Wed Jun 14 15:28:40 2006 +0200 [S390] dasd eer data format. The struct dasd_eer_header needs the packed attribute, or there will be 6 additional bytes of random data between the fixed header and the variable length part of the eer data. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky commit d356c5035e6ea99750afb488005a64736c27fdc7 Author: Cedric Le Goater Date: Tue Jun 13 19:46:42 2006 +0200 [S390] fix dasd_set_uid EXPORT_SYMBOL dasd_set_uid is exported twice which breaks the compile of the dasd driver. The first EXPORT_SYMBOL is wrong, remove it. Signed-off-by: Cedric Le Goater Signed-off-by: Martin Schwidefsky commit 9a64bb742c6a8bee6a55307fda0eac24b9109075 Author: Heiko Carstens Date: Tue Jun 13 19:46:38 2006 +0200 [S390] preempt_count initialization. The preempt_count in the thread_info structure must be initialized to 1. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit dcfc38a0f1ffdf87d1b2c785175cc4247b18adad Author: Eric Rossman Date: Tue Jun 13 19:46:00 2006 +0200 [S390] move z90crypt.h to include/asm part 2. Really add the new header file.. Signed-off-by: Eric Rossman Signed-off-by: Martin Schwidefsky commit a90b71787746de397a6ef5e4c29b6b95047fd720 Author: Peter Oberparleiter Date: Tue Jun 13 19:44:26 2006 +0200 [S390] Add vmpanic parameter. Implementation of new kernel parameter vmpanic that provides a means to perform a z/VM CP command after a kernel panic occurred. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky commit 878443e72cded9c79603cb829ac59621b0193c93 Author: Horst Hummel Date: Tue Jun 13 19:44:21 2006 +0200 [S390] add PAV support to the dasd driver. Add support for parallel-access-volumes to the dasd driver. This allows concurrent access to dasd devices with multiple channel programs. Signed-off-by: Horst Hummel Signed-off-by: Martin Schwidefsky commit 5d62779b9fb235cbfc4b6031004fbf2c5b58b798 Author: Gerald Schaefer Date: Tue Jun 13 19:44:09 2006 +0200 [S390] appldata enhancements. Add CPU ID and steal time, and make OS record size variable. Signed-off-by: Gerald Schaefer Signed-off-by: Martin Schwidefsky commit 6a5e95e63e241ee81c7e9e4bd8959bda6cb37e2b Author: Eric Rossman Date: Tue Jun 13 19:44:01 2006 +0200 [S390] move z90crypt.h to include/asm. Signed-off-by: Eric Rossman Signed-off-by: Martin Schwidefsky commit 65029a7908fb6eaad3fbf9d13c7f7a3475f80f99 Author: Heiko Carstens Date: Tue Jun 13 19:43:44 2006 +0200 [S390] head.S code moving. There is almost no room left for any new code between 0x10000 and 0x10480. Move the code from 0x10000 to 0x11000. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit ac208c6e87cb7bd4df7c6393cbd5d9e70e4e310e Author: Horst Hummel Date: Tue Jun 13 19:43:38 2006 +0200 [S390] dasd whitespace and other cosmetics. Dasd code cleanup: 1) remove white space, 2) remove the emacs override sections, and 3) use kzalloc instead of kmalloc. Signed-off-by: Horst Hummel Signed-off-by: Martin Schwidefsky commit 03e9d8272b35ea9d0b1d6d90f2ef85622af91649 Author: Martin Schwidefsky Date: Tue Jun 13 19:43:32 2006 +0200 [S390] virtual cpu accounting vs. machine checks. If a machine checks interrupts the external or the i/o interrupt handler before they have completed the cpu time calculations, the accounting goes wrong. After the cpu returned from the machine check handler to the interrupted interrupt handler, a negative cpu time delta can occur. If the accumulated cpu time in lowcore is small enough this value can get negative as well. The next jiffy interrupt will pick up that negative value, shift it by 12 and add the now huge positive value to the cpu time of the process. To solve this the machine check handler is modified not to change any of the timestamps in the lowcore if the machine check interrupted kernel context. Signed-off-by: Martin Schwidefsky commit dd8d696322241965bf17b518817491825f72a823 Author: Gerald Schaefer Date: Tue Jun 13 19:43:29 2006 +0200 [S390] add __cpuinit to appldata cpu hotplug notifier. Signed-off-by: Gerald Schaefer Signed-off-by: Martin Schwidefsky commit bfc4cf91c377bbc633dba6cf512e96a978254520 Author: Horst Hummel Date: Tue Jun 13 19:43:22 2006 +0200 [S390] dasd_eckd_dump_sense bug. The ccw dump function dasd_eckd_dump_ccw_range can crash because it does not take care about the IDAL flag in the ccw. Check for IDALs flag set in CCW and follow the indirect list to print the data that is refered by the ccw. Signed-off-by: Horst Hummel Signed-off-by: Martin Schwidefsky commit e9ee6f062d8e27f8698b57c964ec04c19266629e Author: Stefan Weinhuber Date: Tue Jun 13 19:43:18 2006 +0200 [S390] missing check in dasd_eer_open. Check the return value of kzalloc in dasd_eer_open. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky commit b1c2bfb7e1740d64ba58d5a7225494a70c2cfd3f Author: Martin Schwidefsky Date: Tue Jun 13 19:43:15 2006 +0200 [S390] modular 3270 driver. The initial i/o to a 3270 device is done using the static module variables raw3270_init_data and raw3270_init_request. If the 3270 device driver is built as a module and gets loaded above 2GB, the initial i/o will fail because these variables will get addresses > 2GB. To make it work the two variables are moved to struct raw3270 and the data structure is allocated with GFP_DMA. Signed-off-by: Martin Schwidefsky commit 99f184abc8dfff1a9561ca32e392a91c669ac6a0 Author: Martin Schwidefsky Date: Tue Jun 13 19:41:20 2006 +0200 [S390] console_unblank woes. The software watchdog calls machine_restart from a timer function. The s390 machine_restart calls console_unblank to flush the console output. This is needed for panic to get the panic message printed. If console_unblank is called in interrupt a BUG is triggered in acquire_console_sem. That makes the software watchdog panic instead of restarting the machine. To get around this problem the call to console_unblank is made conditionally on !in_interrupt() || oops_in_progress. Signed-off-by: Martin Schwidefsky commit 6207b74f07749b986ee5ede0c4275e28dea65a5c Author: Heiko Carstens Date: Tue Jun 13 19:41:16 2006 +0200 [S390] __syscall_return error check. Fix __syscall_return macro: valid error numbers are in the range of -1..-4095. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit 1cc83d5cd7dad812db4ef16a8a36207b0059b285 Author: Peter Oberparleiter Date: Tue Jun 13 19:41:12 2006 +0200 [S390] cio async subchannel reprobe. Changes in the DASD driver require an asynchronous implementation of the subchannel reprobe loop. This loop was so far only used by the blacklisting mechanism but is now available to all CCW device drivers. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky commit c38623d1a202c47e8ec8c58bfb0fc507b7754446 Author: Cornelia Huck Date: Tue Jun 13 19:41:08 2006 +0200 [S390] ccwgroup device unregister. Work around the problem that a device cannot be unregistered from driver_for_each_device() because of klist node refcounting: Get device after device owned by the driver to be unregistered with driver_find_device() and then unregister it. This works because driver_get_device() gets us out of the region of the elevated klist node refcount. driver_find_device() will always get the next device in the list after the found one has been unregistered. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky commit fe79c970a09183ffc3795eb94fd22661e8eacb53 Author: Cornelia Huck Date: Tue Jun 13 19:41:05 2006 +0200 [S390] channel measurement fix. Specify correct sizeof() in chp_measurement_read() and return correct amount of read data. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky commit 2ac5c0c4f4c9afedc4ef96efcd34639033186c22 Author: Peter Oberparleiter Date: Tue Jun 13 19:41:01 2006 +0200 [S390] cio long busy in read configuration data. Trying to set a DASD root device online can fail under some circumstances with the message "Read configuration data returned error -5". The cause is that read configuration data incorrectly aborts with -EIO when it encounters a temporary busy condition at a storage server. Perform retry when encountering temporary busy conditions. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky commit d657a4f023c5b7afc7f13d7573b61d3f8aec8d08 Author: Heiko Carstens Date: Tue Jun 13 19:40:58 2006 +0200 [S390] memory detection. The wrong base register is used to read a value from the sclp data structure. The value is used to calculate the memory size. Use correct register %r4. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit 3989ef6cb7415bc2158bd6eb7104418dff45b746 Author: Heiko Carstens Date: Tue Jun 13 19:40:54 2006 +0200 [S390] incomplete stack traces. show_stack() passes a pointer to the current stack frame to show_trace(). Because of tail call optimization the pointer doesn't point to the original stack frame anymory and therefore traces are wrong. Don't pass the pointer of the current stack frame to show_trace(). Instead let show_trace() calculate the pointer on its own. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit 90d00f14cf256eca8c7282363ff68e27aae9d109 Author: Heiko Carstens Date: Tue Jun 13 19:40:30 2006 +0200 [S390] cleanup bitops.h. Encapsulate complete bitops.h with #ifdef __KERNEL__ and remove the now superfluous ALIGN_CS define and its users. This patch is needed for compiling klibc. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a9d3a17..e40d0a2 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1671,9 +1671,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: - vmpoff= [KNL,S390] + vmpanic= [KNL,S390] Perform z/VM CP command after kernel panic. + Format: + + vmpoff= [KNL,S390] Perform z/VM CP command after power off. + Format: waveartist= [HW,OSS] Format: ,,, diff --git a/arch/s390/appldata/appldata.h b/arch/s390/appldata/appldata.h index e806a89..71d65eb 100644 --- a/arch/s390/appldata/appldata.h +++ b/arch/s390/appldata/appldata.h @@ -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 + * Author: Gerald Schaefer */ //#define APPLDATA_DEBUG /* Debug messages on/off */ @@ -29,6 +29,22 @@ #define CTL_APPLDATA_OS 2124 #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); + diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index 9a22434..c2b482d 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -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 + * Author: Gerald Schaefer */ #include @@ -40,22 +40,6 @@ #define APPLDATA_CPU_INTERVAL 10000 /* #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, .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, 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 Str EXPORT_SYMBOL_GPL(appldata_register_ops); EXPORT_SYMBOL_GPL(appldata_unregister_ops); +EXPORT_SYMBOL_GPL(appldata_diag); #ifdef MODULE /* diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c index f0e2fbe..7915a19 100644 --- a/arch/s390/appldata/appldata_mem.c +++ b/arch/s390/appldata/appldata_mem.c @@ -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 + * Author: Gerald Schaefer */ #include @@ -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" */ }; diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c index 2a4c743..39b7bde 100644 --- a/arch/s390/appldata/appldata_net_sum.c +++ b/arch/s390/appldata/appldata_net_sum.c @@ -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 + * Author: Gerald Schaefer */ #include @@ -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" */ }; diff --git a/arch/s390/appldata/appldata_os.c b/arch/s390/appldata/appldata_os.c index 99ddd3b..f2b44a2 100644 --- a/arch/s390/appldata/appldata_os.c +++ b/arch/s390/appldata/appldata_os.c @@ -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 + * Author: Gerald Schaefer */ #include @@ -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( 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( */ 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 *d 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 @@ #endif } -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); diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index b244848..74d80c3 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -93,13 +93,22 @@ #endif 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 @@ #endif 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 @@ # # 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 @@ # # 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 @@ #endif 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: @@ -807,6 +841,11 @@ cleanup_critical: 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) clc 4(4,%r12),BASED(cleanup_table_io_leave+4) @@ -839,7 +878,7 @@ #endif 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) diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 2ac095b..21e601d 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -87,13 +87,22 @@ #endif 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 @@ #endif 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 @@ # # 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 @@ # # 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 @@ #endif 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: @@ -815,6 +846,11 @@ cleanup_critical: 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 clc 8(8,%r12),BASED(cleanup_table_io_leave+8) @@ -847,7 +883,7 @@ #endif 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) diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index ea88d06..538c82d 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -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 * Martin Schwidefsky @@ -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 diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S index 2d3b089..d00de17 100644 --- a/arch/s390/kernel/head31.S +++ b/arch/s390/kernel/head31.S @@ -1,7 +1,7 @@ /* * arch/s390/kernel/head31.S * - * (C) Copyright IBM Corp. 2005 + * Copyright (C) IBM Corp. 2005,2006 * * Author(s): Hartmut Penner * Martin Schwidefsky @@ -16,12 +16,31 @@ # this is called either by the ipl loade # 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 @@ # 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 @@ # 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 @@ # 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 @@ # 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 @@ # b .Lfchunk-.LPG1(%r13) .align 4 -.Lget_ipl_device_addr: - .long .Lget_ipl_device .Lpmask: .byte 0 .align 8 @@ -242,6 +259,8 @@ # .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 @@ # .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 diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index f08c06f..47744fc 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -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 * Martin Schwidefsky @@ -15,18 +15,37 @@ # startup-code at 0x10000, running in ab # 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 @@ # 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 @@ # 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 @@ # 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 @@ # b .Lfchunk-.LPG1(%r13) .align 4 -.Lget_ipl_device_addr: - .long .Lget_ipl_device .Lpmask: .byte 0 .align 8 @@ -242,29 +259,16 @@ # .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 @@ # .align 8 .Ldw: .quad 0x0002000180000000,0x0000000000000000 .Laregs: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 0a04e4a..67566ed 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -37,6 +37,7 @@ #include #include #include #include +#include #include #include @@ -123,6 +124,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) { @@ -154,6 +156,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. */ @@ -297,19 +331,34 @@ #endif 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(); } diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index a46793b..b763043 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -150,13 +150,11 @@ void show_stack(struct task_struct *task 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; diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index cfb1fff..bafcd2f 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -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_devi 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 * 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 * 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 ((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 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 * d } /* - * 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 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 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_dev 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 *c { 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_devi 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 *c 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: - */ diff --git a/drivers/s390/block/dasd_3370_erp.c b/drivers/s390/block/dasd_3370_erp.c index 1d11c2a..1ddab89 100644 --- a/drivers/s390/block/dasd_3370_erp.c +++ b/drivers/s390/block/dasd_3370_erp.c @@ -1,4 +1,4 @@ -/* +/* * File...........: linux/drivers/s390/block/dasd_3370_erp.c * Author(s)......: Holger Smolinski * Bugreports.to..: @@ -12,10 +12,10 @@ #include "dasd_int.h" /* - * 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 @@ #include "dasd_int.h" * '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_re 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: - */ diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 2ed5156..669805d 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -1,6 +1,6 @@ -/* +/* * File...........: linux/drivers/s390/block/dasd_3990_erp.c - * Author(s)......: Horst Hummel + * Author(s)......: Horst Hummel * Holger Smolinski * Bugreports.to..: * (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 } /* 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 } /* 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 * '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_re } /* 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_re * * 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_re } /* 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_cc } /* - * 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_re } /* 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 * 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 * } /* 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_r } /* 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_r 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_r } 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_r } /* 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_r * * PARAMETER * sense current sense data - * + * * RETURN VALUES * void */ @@ -1150,9 +1150,9 @@ dasd_3990_handle_env_data(struct dasd_cc * 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_re } /* 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_r * * 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_ } /* 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 } /* 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 * * 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_c * * 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_c * 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 } /* 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 } /* 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_ 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_ } /* 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_ 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_ } /* 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 das } /* 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_r } /* 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 } /* 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 * 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_re /* * 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_re } /* - * 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 * 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_cc * 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 * 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_cc 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_cc } /* 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 da * 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 @@ #endif /* ERP_DEBUG */ 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: - */ diff --git a/drivers/s390/block/dasd_9336_erp.c b/drivers/s390/block/dasd_9336_erp.c index dc86144..6e08268 100644 --- a/drivers/s390/block/dasd_9336_erp.c +++ b/drivers/s390/block/dasd_9336_erp.c @@ -1,4 +1,4 @@ -/* +/* * File...........: linux/drivers/s390/block/dasd_9336_erp.c * Author(s)......: Holger Smolinski * Bugreports.to..: @@ -12,10 +12,10 @@ #include "dasd_int.h" /* - * 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 @@ #include "dasd_int.h" * '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_re 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: - */ diff --git a/drivers/s390/block/dasd_9343_erp.c b/drivers/s390/block/dasd_9343_erp.c index 4a5b795..ddecb98 100644 --- a/drivers/s390/block/dasd_9343_erp.c +++ b/drivers/s390/block/dasd_9343_erp.c @@ -1,4 +1,4 @@ -/* +/* * File...........: linux/drivers/s390/block/dasd_9345_erp.c * Author(s)......: Holger Smolinski * Bugreports.to..: diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 216bc4f..9e9ae71 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -27,7 +27,7 @@ #define PRINTK_HEADER "dasd_devmap:" #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 @@ -49,6 +49,20 @@ struct dasd_devmap { }; /* + * 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: * : (0x)?[0-9a-fA-F]+ * : [0-0a-f]\.[0-9a-f]\.(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 feature 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 } 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_ * 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, s } 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, 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_ .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, st /* * 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 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 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 diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 3f9d704..4002f6c 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -1,4 +1,4 @@ -/* +/* * File...........: linux/drivers/s390/block/dasd_diag.c * Author(s)......: Holger Smolinski * Based on.......: linux/drivers/s390/block/mdisk.c @@ -336,7 +336,7 @@ dasd_diag_check_device(struct dasd_devic 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 * datasize, device); if (IS_ERR(cqr)) return cqr; - + dreq = (struct dasd_diag_req *) cqr->data; dreq->block_count = count; dbio = dreq->bio; diff --git a/drivers/s390/block/dasd_diag.h b/drivers/s390/block/dasd_diag.h index 38a4e55..b8c7826 100644 --- a/drivers/s390/block/dasd_diag.h +++ b/drivers/s390/block/dasd_diag.h @@ -1,4 +1,4 @@ -/* +/* * File...........: linux/drivers/s390/block/dasd_diag.h * Author(s)......: Holger Smolinski * Based on.......: linux/drivers/s390/block/mdisk.h diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 7d5a6ce..0dfab30 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1,7 +1,7 @@ -/* +/* * File...........: linux/drivers/s390/block/dasd_eckd.c * Author(s)......: Holger Smolinski - * Horst Hummel + * Horst Hummel * Carsten Otte * Martin Schwidefsky * Bugreports.to..: @@ -24,6 +24,7 @@ #include #include #include #include +#include #include #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 /* 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 L struct dasd_eckd_private *private; int sector; int dn, d; - + private = (struct dasd_eckd_private *) device->private; DBF_DEV_EVENT(DBF_INFO, device, @@ -541,6 +547,86 @@ dasd_eckd_read_conf(struct dasd_device * } /* + * 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 d 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 d "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 d 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 d 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_devic ((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_devi 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 * /* * 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 *de /* * 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 *de /* * 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 @@ -1522,6 +1607,40 @@ dasd_eckd_ioctl(struct dasd_device *devi } /* + * 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 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 "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 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_ 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: - */ diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index d5734e9..712ff16 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -1,7 +1,7 @@ -/* +/* * File...........: linux/drivers/s390/block/dasd_eckd.h * Author(s)......: Holger Smolinski - * Horst Hummel + * Horst Hummel * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * @@ -41,9 +41,10 @@ #define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d #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 */ diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index 2d946b6..60ae9a3 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -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 *i 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) { diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index b842377..4108d96 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c @@ -90,7 +90,7 @@ dasd_default_erp_action(struct dasd_ccw_ /* 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_ /* * 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, /* * 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); diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 9114569..bb7755b 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -1,4 +1,4 @@ -/* +/* * File...........: linux/drivers/s390/block/dasd_fba.c * Author(s)......: Holger Smolinski * Bugreports.to..: @@ -56,19 +56,13 @@ static struct ccw_driver dasd_fba_driver 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_r 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 * * 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_d 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: - */ diff --git a/drivers/s390/block/dasd_fba.h b/drivers/s390/block/dasd_fba.h index da1fa91..14c910b 100644 --- a/drivers/s390/block/dasd_fba.h +++ b/drivers/s390/block/dasd_fba.h @@ -1,4 +1,4 @@ -/* +/* * File...........: linux/drivers/s390/block/dasd_fba.h * Author(s)......: Holger Smolinski * Bugreports.to..: diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index d4b13e3..03a83ef 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -1,7 +1,7 @@ -/* +/* * File...........: linux/drivers/s390/block/dasd_int.h * Author(s)......: Holger Smolinski - * Horst Hummel + * Horst Hummel * Martin Schwidefsky * Bugreports.to..: * (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_dev 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 @@ #endif /* CONFIG_DASD_ERR */ #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: - */ diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index b8c80d2..302bcd0 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -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_devic 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' diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index eecb2af..3c1314b 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -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 struc } __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 @@ #endif * 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 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 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); diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 0960bef..15b8954 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -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 *b return; } - s390_redo_validation (); + css_schedule_reprobe(); } /* Iterator struct for all devices. */ diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index bdfee7f..c7319a0 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -404,21 +404,24 @@ ccwgroup_driver_register (struct ccwgrou } 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); } diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 72187e5..4a9da5b 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -918,12 +918,13 @@ chp_measurement_read(struct kobject *kob 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; } diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 07ef3f6..1c3e8e9 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -3,9 +3,10 @@ * * Linux on zSeries Channel Measurement Facility support * - * Copyright 2000,2003 IBM Corporation + * Copyright 2000,2006 IBM Corporation * - * Author: Arnd Bergmann + * Authors: Arnd Bergmann + * Cornelia Huck * * original idea from Natarajan Krishnaswami * @@ -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(©_block->wait); + kref_init(©_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(©_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(©_block->kref); + copy_block->ret = cmf_copy_block(cdev); + wake_up(©_block->wait); + kref_put(©_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 *cde /* 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 *cde /* 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, st 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_basi .read = read_cmb, .readall = readall_cmb, .reset = reset_cmb, + .align = align_cmb, .attr_group = &cmf_attr_group, }; @@ -610,22 +824,34 @@ static inline struct cmbe* cmbe_align(st 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, s /* 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_exte .read = read_cmbe, .readall = readall_cmbe, .reset = reset_cmbe, + .align = align_cmbe, .attr_group = &cmf_attr_group_ext, }; @@ -803,14 +1059,19 @@ cmb_show_avg_sample_interval(struct devi 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 * 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, str 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) { diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 74ea8aa..1d3be80 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -19,9 +19,11 @@ #include "cio.h" #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 diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 8e3053c..eafde43 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -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) diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 11587eb..00be9a5 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -1,6 +1,10 @@ #ifndef S390_DEVICE_H #define S390_DEVICE_H +#include +#include +#include + /* * 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 *c 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 diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 49ec562..e1e566a 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -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); + } } /* @@ -1093,6 +1096,13 @@ ccw_device_change_cmfstate(struct ccw_de 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 +1257,12 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES] [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, + }, }; /* diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 795abb5..5c9904b 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -270,7 +270,8 @@ ccw_device_wake_up(struct ccw_device *cd * 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 +280,10 @@ ccw_device_wake_up(struct ccw_device *cd !(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; diff --git a/drivers/s390/crypto/z90crypt.h b/drivers/s390/crypto/z90crypt.h deleted file mode 100644 index 0ca1d12..0000000 --- a/drivers/s390/crypto/z90crypt.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * linux/drivers/s390/crypto/z90crypt.h - * - * z90crypt 1.3.3 (kernel-private header) - * - * Copyright (C) 2001, 2005 IBM Corporation - * Author(s): Robert Burroughs (burrough@us.ibm.com) - * Eric Rossman (edrossma@us.ibm.com) - * - * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _Z90CRYPT_H_ -#define _Z90CRYPT_H_ - -#include - -/** - * local errno definitions - */ -#define ENOBUFF 129 // filp->private_data->...>work_elem_p->buffer is NULL -#define EWORKPEND 130 // user issues ioctl while another pending -#define ERELEASED 131 // user released while ioctl pending -#define EQUIESCE 132 // z90crypt quiescing (no more work allowed) -#define ETIMEOUT 133 // request timed out -#define EUNKNOWN 134 // some unrecognized error occured (retry may succeed) -#define EGETBUFF 135 // Error getting buffer or hardware lacks capability - // (retry in software) - -/** - * DEPRECATED STRUCTURES - */ - -/** - * This structure is DEPRECATED and the corresponding ioctl() has been - * replaced with individual ioctl()s for each piece of data! - * This structure will NOT survive past version 1.3.1, so switch to the - * new ioctl()s. - */ -#define MASK_LENGTH 64 // mask length -struct ica_z90_status { - int totalcount; - int leedslitecount; // PCICA - int leeds2count; // PCICC - // int PCIXCCCount; is not in struct for backward compatibility - int requestqWaitCount; - int pendingqWaitCount; - int totalOpenCount; - int cryptoDomain; - // status: 0=not there, 1=PCICA, 2=PCICC, 3=PCIXCC_MCL2, 4=PCIXCC_MCL3, - // 5=CEX2C - unsigned char status[MASK_LENGTH]; - // qdepth: # work elements waiting for each device - unsigned char qdepth[MASK_LENGTH]; -}; - -#endif /* _Z90CRYPT_H_ */ diff --git a/drivers/s390/crypto/z90hardware.c b/drivers/s390/crypto/z90hardware.c index be60795..5ba20b9 100644 --- a/drivers/s390/crypto/z90hardware.c +++ b/drivers/s390/crypto/z90hardware.c @@ -29,7 +29,7 @@ #include #include #include #include -#include "z90crypt.h" +#include #include "z90common.h" struct cca_token_hdr { @@ -1688,7 +1688,7 @@ ICAMEX_msg_to_type6MEX_en_msg(struct ica temp_exp = kmalloc(256, GFP_KERNEL); if (!temp_exp) - return EGETBUFF; + return ENOMEM; mod_len = icaMsg_p->inputdatalength; if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len)) { kfree(temp_exp); @@ -1918,7 +1918,7 @@ ICAMEX_msg_to_type6MEX_msgX(struct ica_r temp_exp = kmalloc(256, GFP_KERNEL); if (!temp_exp) - return EGETBUFF; + return ENOMEM; mod_len = icaMsg_p->inputdatalength; if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len)) { kfree(temp_exp); diff --git a/drivers/s390/crypto/z90main.c b/drivers/s390/crypto/z90main.c index 982acc7..a49b3e5 100644 --- a/drivers/s390/crypto/z90main.c +++ b/drivers/s390/crypto/z90main.c @@ -35,7 +35,7 @@ #include #include #include #include -#include "z90crypt.h" +#include #include "z90common.h" /** @@ -381,7 +381,6 @@ static int z90crypt_status_write(struct */ static int domain = DOMAIN_INDEX; static struct z90crypt z90crypt; -static int quiesce_z90crypt; static spinlock_t queuespinlock; static struct list_head request_list; static int requestq_count; @@ -600,8 +599,6 @@ z90crypt_init_module(void) INIT_LIST_HEAD(&request_list); requestq_count = 0; - quiesce_z90crypt = 0; - atomic_set(&total_open, 0); atomic_set(&z90crypt_step, 0); @@ -704,9 +701,6 @@ z90crypt_open(struct inode *inode, struc { struct priv_data *private_data_p; - if (quiesce_z90crypt) - return -EQUIESCE; - private_data_p = kzalloc(sizeof(struct priv_data), GFP_KERNEL); if (!private_data_p) { PRINTK("Memory allocate failed\n"); @@ -767,8 +761,6 @@ z90crypt_read(struct file *filp, char __ PDEBUG("filp %p (PID %d)\n", filp, PID()); - if (quiesce_z90crypt) - return -EQUIESCE; if (count < 0) { PRINTK("Requested random byte count negative: %ld\n", count); return -EINVAL; @@ -1227,7 +1219,7 @@ z90crypt_send(struct work_element *we_p, if (CHK_RDWRMASK(we_p->status[0]) != STAT_NOWORK) { PDEBUG("PID %d tried to send more work but has outstanding " "work.\n", PID()); - return -EWORKPEND; + return -EBUSY; } we_p->devindex = -1; // Reset device number spin_lock_irq(&queuespinlock); @@ -1294,7 +1286,7 @@ z90crypt_process_results(struct work_ele if (!we_p->buffer) { PRINTK("we_p %p PID %d in STAT_READPEND: buffer NULL.\n", we_p, PID()); - rv = -ENOBUFF; + rv = -ENOMEM; } if (!rv) @@ -1607,12 +1599,12 @@ z90crypt_prepare(struct work_element *we rv = -ENODEV; break; case SEN_NOT_AVAIL: - case EGETBUFF: - rv = -EGETBUFF; + case ENOMEM: + rv = -ENODEV; break; default: PRINTK("rv = %d\n", rv); - rv = -EGETBUFF; + rv = -ENODEV; break; } if (CHK_RDWRMASK(we_p->status[0]) == STAT_WRITTEN) @@ -1676,22 +1668,21 @@ z90crypt_rsa(struct priv_data *private_d /** * EINVAL *after* receive is almost always a padding error or * length error issued by a coprocessor (not an accelerator). - * We convert this return value to -EGETBUFF which should + * We convert this return value to -ENODEV which should * trigger a fallback to software. */ case -EINVAL: if ((we_p->devtype != PCICA) && (we_p->devtype != CEX2A)) - rv = -EGETBUFF; + rv = -ENODEV; break; - case -ETIMEOUT: + case -EIO: if (z90crypt.mask.st_count > 0) rv = -ERESTARTSYS; // retry with another else rv = -ENODEV; // no cards left /* fall through to clean up request queue */ case -ERESTARTSYS: - case -ERELEASED: switch (CHK_RDWRMASK(we_p->status[0])) { case STAT_WRITTEN: purge_work_element(we_p); @@ -1745,10 +1736,6 @@ z90crypt_unlocked_ioctl(struct file *fil switch (cmd) { case ICARSAMODEXPO: case ICARSACRT: - if (quiesce_z90crypt) { - ret = -EQUIESCE; - break; - } ret = -ENODEV; // Default if no devices loopLim = z90crypt.hdware_info->hdware_mask.st_count - (z90crypt.hdware_info->hdware_mask.disabled_count + @@ -1917,17 +1904,6 @@ z90crypt_unlocked_ioctl(struct file *fil ret = -EFAULT; break; - case Z90QUIESCE: - if (current->euid != 0) { - PRINTK("QUIESCE fails: euid %d\n", - current->euid); - ret = -EACCES; - } else { - PRINTK("QUIESCE device from PID %d\n", PID()); - quiesce_z90crypt = 1; - } - break; - default: /* user passed an invalid IOCTL number */ PDEBUG("cmd 0x%08X contains invalid ioctl code\n", cmd); @@ -2456,7 +2432,7 @@ helper_handle_work_element(int index, un pq_p->status[0] |= STAT_FAILED; break; } - if ((pq_p->status[0] != STAT_FAILED) || (pq_p->retcode != -ERELEASED)) { + if (pq_p->status[0] != STAT_FAILED) { pq_p->audit[1] |= FP_AWAKENING; atomic_set(&pq_p->alarmrung, 1); wake_up(&pq_p->waitq); @@ -2647,7 +2623,7 @@ helper_timeout_requests(void) ((struct caller *)pq_p->requestptr)->caller_id[5], ((struct caller *)pq_p->requestptr)->caller_id[6], ((struct caller *)pq_p->requestptr)->caller_id[7]); - pq_p->retcode = -ETIMEOUT; + pq_p->retcode = -EIO; pq_p->status[0] |= STAT_FAILED; /* get this off any caller queue it may be on */ unbuild_caller(LONG2DEVPTR(pq_p->devindex), @@ -2679,7 +2655,7 @@ helper_timeout_requests(void) ((struct caller *)pq_p->requestptr)->caller_id[5], ((struct caller *)pq_p->requestptr)->caller_id[6], ((struct caller *)pq_p->requestptr)->caller_id[7]); - pq_p->retcode = -ETIMEOUT; + pq_p->retcode = -EIO; pq_p->status[0] |= STAT_FAILED; list_del_init(lptr); requestq_count--; diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index f99e553..8dc7500 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c @@ -14,6 +14,7 @@ #include #include #include #include +#include #include @@ -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; } diff --git a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h index 4d2b126..657b724 100644 --- a/include/asm-s390/bitops.h +++ b/include/asm-s390/bitops.h @@ -12,6 +12,10 @@ #define _S390_BITOPS_H * Copyright (C) 1992, Linus Torvalds * */ + +#ifdef __KERNEL__ + +#include #include /* @@ -50,19 +54,6 @@ #include * 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 +112,6 @@ static inline void set_bit_cs(unsigned l 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 +128,6 @@ static inline void clear_bit_cs(unsigned 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 +144,6 @@ static inline void change_bit_cs(unsigne 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 +161,6 @@ test_and_set_bit_cs(unsigned long nr, vo 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 +180,6 @@ test_and_clear_bit_cs(unsigned long nr, 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 +199,6 @@ test_and_change_bit_cs(unsigned long nr, 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 +801,6 @@ #include #include -#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; diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h index 089cf56..2b16193 100644 --- a/include/asm-s390/cio.h +++ b/include/asm-s390/cio.h @@ -276,6 +276,8 @@ extern void wait_cons_dev(void); extern void clear_all_subchannels(void); +extern void css_schedule_reprobe(void); + #endif #endif diff --git a/include/asm-s390/cmb.h b/include/asm-s390/cmb.h index 2d09950..241756f 100644 --- a/include/asm-s390/cmb.h +++ b/include/asm-s390/cmb.h @@ -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) diff --git a/include/asm-s390/dasd.h b/include/asm-s390/dasd.h index 1630c26..c042f95 100644 --- a/include/asm-s390/dasd.h +++ b/include/asm-s390/dasd.h @@ -68,10 +68,12 @@ #define DASD_FORMAT_CDL 2 * 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 diff --git a/include/asm-s390/thread_info.h b/include/asm-s390/thread_info.h index 8e0c7ed..0a51891 100644 --- a/include/asm-s390/thread_info.h +++ b/include/asm-s390/thread_info.h @@ -63,6 +63,7 @@ #define INIT_THREAD_INFO(tsk) \ .exec_domain = &default_exec_domain, \ .flags = 0, \ .cpu = 0, \ + .preempt_count = 1, \ .restart_block = { \ .fn = do_no_restart_syscall, \ }, \ diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h index e21443d..0918632 100644 --- a/include/asm-s390/unistd.h +++ b/include/asm-s390/unistd.h @@ -392,13 +392,9 @@ #define __NR_newfstatat 293 #endif -#ifdef __KERNEL__ - -/* user-visible error numbers are in the range -1 - -122: see */ - #define __syscall_return(type, res) \ do { \ - if ((unsigned long)(res) >= (unsigned long)(-125)) { \ + if ((unsigned long)(res) >= (unsigned long)(-4095)) {\ errno = -(res); \ res = -1; \ } \ @@ -548,6 +544,7 @@ type name(type1 arg1, type2 arg2, type3 __syscall_return(type,__res); \ } +#ifdef __KERNEL__ #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_SYS_ALARM @@ -574,9 +571,11 @@ # ifdef CONFIG_COMPAT # define __ARCH_WANT_COMPAT_SYS_TIME # define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND # endif +#endif #ifdef __KERNEL_SYSCALLS__ +#include #include #include #include @@ -624,7 +623,7 @@ asmlinkage long sys_rt_sigaction(int sig struct sigaction __user *oact, size_t sigsetsize); -#endif /* __KERNEL_SYSCALLS__ */ +#endif /* * "Conditional" syscalls @@ -634,5 +633,4 @@ #endif /* __KERNEL_SYSCALLS__ */ */ #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") -#endif /* __KERNEL__ */ #endif /* _ASM_S390_UNISTD_H_ */ diff --git a/include/asm-s390/z90crypt.h b/include/asm-s390/z90crypt.h index 31a2439..9ff0a32 100644 --- a/include/asm-s390/z90crypt.h +++ b/include/asm-s390/z90crypt.h @@ -30,7 +30,7 @@ #include #define z90crypt_VERSION 1 #define z90crypt_RELEASE 3 // 2 = PCIXCC, 3 = rewrite for coding standards -#define z90crypt_VARIANT 3 // 3 = CEX2A support +#define z90crypt_VARIANT 3 // 3 = CEX2A support, cleanup, sysfs interface /** * struct ica_rsa_modexpo @@ -209,4 +209,31 @@ #define Z90STAT_STATUS_MASK _IOR(Z90_IOC #define Z90STAT_QDEPTH_MASK _IOR(Z90_IOCTL_MAGIC, 0x49, char[64]) #define Z90STAT_PERDEV_REQCNT _IOR(Z90_IOCTL_MAGIC, 0x4a, int[64]) +/** + * DEPRECATED STRUCTURES + */ + +/** + * This structure is DEPRECATED and the corresponding ioctl() has been + * replaced with individual ioctl()s for each piece of data! + * This structure will NOT survive past version 1.3.1, so switch to the + * new ioctl()s. + */ +#define MASK_LENGTH 64 // mask length +struct ica_z90_status { + int totalcount; + int leedslitecount; // PCICA + int leeds2count; // PCICC + // int PCIXCCCount; is not in struct for backward compatibility + int requestqWaitCount; + int pendingqWaitCount; + int totalOpenCount; + int cryptoDomain; + // status: 0=not there, 1=PCICA, 2=PCICC, 3=PCIXCC_MCL2, 4=PCIXCC_MCL3, + // 5=CEX2C + unsigned char status[MASK_LENGTH]; + // qdepth: # work elements waiting for each device + unsigned char qdepth[MASK_LENGTH]; +}; + #endif /* __ASM_S390_Z90CRYPT_H */