diff options
65 files changed, 1325 insertions, 569 deletions
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 237acab169dd..2a5f0e14efa3 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt | |||
@@ -72,6 +72,7 @@ Code Seq#(hex) Include File Comments | |||
72 | 0x06 all linux/lp.h | 72 | 0x06 all linux/lp.h |
73 | 0x09 all linux/raid/md_u.h | 73 | 0x09 all linux/raid/md_u.h |
74 | 0x10 00-0F drivers/char/s390/vmcp.h | 74 | 0x10 00-0F drivers/char/s390/vmcp.h |
75 | 0x10 10-1F arch/s390/include/uapi/sclp_ctl.h | ||
75 | 0x12 all linux/fs.h | 76 | 0x12 all linux/fs.h |
76 | linux/blkpg.h | 77 | linux/blkpg.h |
77 | 0x1b all InfiniBand Subsystem <http://infiniband.sourceforge.net/> | 78 | 0x1b all InfiniBand Subsystem <http://infiniband.sourceforge.net/> |
diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c index 7ef60b52d6e0..42be53743133 100644 --- a/arch/s390/appldata/appldata_mem.c +++ b/arch/s390/appldata/appldata_mem.c | |||
@@ -32,7 +32,7 @@ | |||
32 | * book: | 32 | * book: |
33 | * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml | 33 | * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml |
34 | */ | 34 | */ |
35 | static struct appldata_mem_data { | 35 | struct appldata_mem_data { |
36 | u64 timestamp; | 36 | u64 timestamp; |
37 | u32 sync_count_1; /* after VM collected the record data, */ | 37 | u32 sync_count_1; /* after VM collected the record data, */ |
38 | u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the | 38 | u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the |
@@ -63,7 +63,7 @@ static struct appldata_mem_data { | |||
63 | u64 pgmajfault; /* page faults (major only) */ | 63 | u64 pgmajfault; /* page faults (major only) */ |
64 | // <-- New in 2.6 | 64 | // <-- New in 2.6 |
65 | 65 | ||
66 | } __attribute__((packed)) appldata_mem_data; | 66 | } __packed; |
67 | 67 | ||
68 | 68 | ||
69 | /* | 69 | /* |
@@ -118,7 +118,6 @@ static struct appldata_ops ops = { | |||
118 | .record_nr = APPLDATA_RECORD_MEM_ID, | 118 | .record_nr = APPLDATA_RECORD_MEM_ID, |
119 | .size = sizeof(struct appldata_mem_data), | 119 | .size = sizeof(struct appldata_mem_data), |
120 | .callback = &appldata_get_mem_data, | 120 | .callback = &appldata_get_mem_data, |
121 | .data = &appldata_mem_data, | ||
122 | .owner = THIS_MODULE, | 121 | .owner = THIS_MODULE, |
123 | .mod_lvl = {0xF0, 0xF0}, /* EBCDIC "00" */ | 122 | .mod_lvl = {0xF0, 0xF0}, /* EBCDIC "00" */ |
124 | }; | 123 | }; |
@@ -131,7 +130,17 @@ static struct appldata_ops ops = { | |||
131 | */ | 130 | */ |
132 | static int __init appldata_mem_init(void) | 131 | static int __init appldata_mem_init(void) |
133 | { | 132 | { |
134 | return appldata_register_ops(&ops); | 133 | int ret; |
134 | |||
135 | ops.data = kzalloc(sizeof(struct appldata_mem_data), GFP_KERNEL); | ||
136 | if (!ops.data) | ||
137 | return -ENOMEM; | ||
138 | |||
139 | ret = appldata_register_ops(&ops); | ||
140 | if (ret) | ||
141 | kfree(ops.data); | ||
142 | |||
143 | return ret; | ||
135 | } | 144 | } |
136 | 145 | ||
137 | /* | 146 | /* |
@@ -142,6 +151,7 @@ static int __init appldata_mem_init(void) | |||
142 | static void __exit appldata_mem_exit(void) | 151 | static void __exit appldata_mem_exit(void) |
143 | { | 152 | { |
144 | appldata_unregister_ops(&ops); | 153 | appldata_unregister_ops(&ops); |
154 | kfree(ops.data); | ||
145 | } | 155 | } |
146 | 156 | ||
147 | 157 | ||
diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c index 2d224b945355..66037d2622b4 100644 --- a/arch/s390/appldata/appldata_net_sum.c +++ b/arch/s390/appldata/appldata_net_sum.c | |||
@@ -29,7 +29,7 @@ | |||
29 | * book: | 29 | * book: |
30 | * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml | 30 | * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml |
31 | */ | 31 | */ |
32 | static struct appldata_net_sum_data { | 32 | struct appldata_net_sum_data { |
33 | u64 timestamp; | 33 | u64 timestamp; |
34 | u32 sync_count_1; /* after VM collected the record data, */ | 34 | u32 sync_count_1; /* after VM collected the record data, */ |
35 | u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the | 35 | u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the |
@@ -51,7 +51,7 @@ static struct appldata_net_sum_data { | |||
51 | u64 rx_dropped; /* no space in linux buffers */ | 51 | u64 rx_dropped; /* no space in linux buffers */ |
52 | u64 tx_dropped; /* no space available in linux */ | 52 | u64 tx_dropped; /* no space available in linux */ |
53 | u64 collisions; /* collisions while transmitting */ | 53 | u64 collisions; /* collisions while transmitting */ |
54 | } __attribute__((packed)) appldata_net_sum_data; | 54 | } __packed; |
55 | 55 | ||
56 | 56 | ||
57 | /* | 57 | /* |
@@ -121,7 +121,6 @@ static struct appldata_ops ops = { | |||
121 | .record_nr = APPLDATA_RECORD_NET_SUM_ID, | 121 | .record_nr = APPLDATA_RECORD_NET_SUM_ID, |
122 | .size = sizeof(struct appldata_net_sum_data), | 122 | .size = sizeof(struct appldata_net_sum_data), |
123 | .callback = &appldata_get_net_sum_data, | 123 | .callback = &appldata_get_net_sum_data, |
124 | .data = &appldata_net_sum_data, | ||
125 | .owner = THIS_MODULE, | 124 | .owner = THIS_MODULE, |
126 | .mod_lvl = {0xF0, 0xF0}, /* EBCDIC "00" */ | 125 | .mod_lvl = {0xF0, 0xF0}, /* EBCDIC "00" */ |
127 | }; | 126 | }; |
@@ -134,7 +133,17 @@ static struct appldata_ops ops = { | |||
134 | */ | 133 | */ |
135 | static int __init appldata_net_init(void) | 134 | static int __init appldata_net_init(void) |
136 | { | 135 | { |
137 | return appldata_register_ops(&ops); | 136 | int ret; |
137 | |||
138 | ops.data = kzalloc(sizeof(struct appldata_net_sum_data), GFP_KERNEL); | ||
139 | if (!ops.data) | ||
140 | return -ENOMEM; | ||
141 | |||
142 | ret = appldata_register_ops(&ops); | ||
143 | if (ret) | ||
144 | kfree(ops.data); | ||
145 | |||
146 | return ret; | ||
138 | } | 147 | } |
139 | 148 | ||
140 | /* | 149 | /* |
@@ -145,6 +154,7 @@ static int __init appldata_net_init(void) | |||
145 | static void __exit appldata_net_exit(void) | 154 | static void __exit appldata_net_exit(void) |
146 | { | 155 | { |
147 | appldata_unregister_ops(&ops); | 156 | appldata_unregister_ops(&ops); |
157 | kfree(ops.data); | ||
148 | } | 158 | } |
149 | 159 | ||
150 | 160 | ||
diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c index 7fd3690b6760..138893e5f736 100644 --- a/arch/s390/hypfs/hypfs_diag.c +++ b/arch/s390/hypfs/hypfs_diag.c | |||
@@ -651,9 +651,7 @@ static int hypfs_create_cpu_files(struct super_block *sb, | |||
651 | } | 651 | } |
652 | diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer); | 652 | diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer); |
653 | rc = hypfs_create_str(sb, cpu_dir, "type", buffer); | 653 | rc = hypfs_create_str(sb, cpu_dir, "type", buffer); |
654 | if (IS_ERR(rc)) | 654 | return PTR_RET(rc); |
655 | return PTR_ERR(rc); | ||
656 | return 0; | ||
657 | } | 655 | } |
658 | 656 | ||
659 | static void *hypfs_create_lpar_files(struct super_block *sb, | 657 | static void *hypfs_create_lpar_files(struct super_block *sb, |
@@ -702,9 +700,7 @@ static int hypfs_create_phys_cpu_files(struct super_block *sb, | |||
702 | return PTR_ERR(rc); | 700 | return PTR_ERR(rc); |
703 | diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer); | 701 | diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer); |
704 | rc = hypfs_create_str(sb, cpu_dir, "type", buffer); | 702 | rc = hypfs_create_str(sb, cpu_dir, "type", buffer); |
705 | if (IS_ERR(rc)) | 703 | return PTR_RET(rc); |
706 | return PTR_ERR(rc); | ||
707 | return 0; | ||
708 | } | 704 | } |
709 | 705 | ||
710 | static void *hypfs_create_phys_files(struct super_block *sb, | 706 | static void *hypfs_create_phys_files(struct super_block *sb, |
diff --git a/arch/s390/include/asm/airq.h b/arch/s390/include/asm/airq.h index 9819891ed7a2..4066cee0c2d2 100644 --- a/arch/s390/include/asm/airq.h +++ b/arch/s390/include/asm/airq.h | |||
@@ -9,9 +9,18 @@ | |||
9 | #ifndef _ASM_S390_AIRQ_H | 9 | #ifndef _ASM_S390_AIRQ_H |
10 | #define _ASM_S390_AIRQ_H | 10 | #define _ASM_S390_AIRQ_H |
11 | 11 | ||
12 | typedef void (*adapter_int_handler_t)(void *, void *); | 12 | struct airq_struct { |
13 | struct hlist_node list; /* Handler queueing. */ | ||
14 | void (*handler)(struct airq_struct *); /* Thin-interrupt handler */ | ||
15 | u8 *lsi_ptr; /* Local-Summary-Indicator pointer */ | ||
16 | u8 lsi_mask; /* Local-Summary-Indicator mask */ | ||
17 | u8 isc; /* Interrupt-subclass */ | ||
18 | u8 flags; | ||
19 | }; | ||
13 | 20 | ||
14 | void *s390_register_adapter_interrupt(adapter_int_handler_t, void *, u8); | 21 | #define AIRQ_PTR_ALLOCATED 0x01 |
15 | void s390_unregister_adapter_interrupt(void *, u8); | 22 | |
23 | int register_adapter_interrupt(struct airq_struct *airq); | ||
24 | void unregister_adapter_interrupt(struct airq_struct *airq); | ||
16 | 25 | ||
17 | #endif /* _ASM_S390_AIRQ_H */ | 26 | #endif /* _ASM_S390_AIRQ_H */ |
diff --git a/arch/s390/include/asm/dma-mapping.h b/arch/s390/include/asm/dma-mapping.h index 2f8c1abeb086..3fbc67d9e197 100644 --- a/arch/s390/include/asm/dma-mapping.h +++ b/arch/s390/include/asm/dma-mapping.h | |||
@@ -53,7 +53,7 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) | |||
53 | debug_dma_mapping_error(dev, dma_addr); | 53 | debug_dma_mapping_error(dev, dma_addr); |
54 | if (dma_ops->mapping_error) | 54 | if (dma_ops->mapping_error) |
55 | return dma_ops->mapping_error(dev, dma_addr); | 55 | return dma_ops->mapping_error(dev, dma_addr); |
56 | return (dma_addr == DMA_ERROR_CODE); | 56 | return dma_addr == DMA_ERROR_CODE; |
57 | } | 57 | } |
58 | 58 | ||
59 | static inline void *dma_alloc_coherent(struct device *dev, size_t size, | 59 | static inline void *dma_alloc_coherent(struct device *dev, size_t size, |
diff --git a/arch/s390/include/asm/facility.h b/arch/s390/include/asm/facility.h index 2ee66a65f2d4..0aa6a7ed95a3 100644 --- a/arch/s390/include/asm/facility.h +++ b/arch/s390/include/asm/facility.h | |||
@@ -13,6 +13,16 @@ | |||
13 | 13 | ||
14 | #define MAX_FACILITY_BIT (256*8) /* stfle_fac_list has 256 bytes */ | 14 | #define MAX_FACILITY_BIT (256*8) /* stfle_fac_list has 256 bytes */ |
15 | 15 | ||
16 | static inline int __test_facility(unsigned long nr, void *facilities) | ||
17 | { | ||
18 | unsigned char *ptr; | ||
19 | |||
20 | if (nr >= MAX_FACILITY_BIT) | ||
21 | return 0; | ||
22 | ptr = (unsigned char *) facilities + (nr >> 3); | ||
23 | return (*ptr & (0x80 >> (nr & 7))) != 0; | ||
24 | } | ||
25 | |||
16 | /* | 26 | /* |
17 | * The test_facility function uses the bit odering where the MSB is bit 0. | 27 | * The test_facility function uses the bit odering where the MSB is bit 0. |
18 | * That makes it easier to query facility bits with the bit number as | 28 | * That makes it easier to query facility bits with the bit number as |
@@ -20,12 +30,7 @@ | |||
20 | */ | 30 | */ |
21 | static inline int test_facility(unsigned long nr) | 31 | static inline int test_facility(unsigned long nr) |
22 | { | 32 | { |
23 | unsigned char *ptr; | 33 | return __test_facility(nr, &S390_lowcore.stfle_fac_list); |
24 | |||
25 | if (nr >= MAX_FACILITY_BIT) | ||
26 | return 0; | ||
27 | ptr = (unsigned char *) &S390_lowcore.stfle_fac_list + (nr >> 3); | ||
28 | return (*ptr & (0x80 >> (nr & 7))) != 0; | ||
29 | } | 34 | } |
30 | 35 | ||
31 | /** | 36 | /** |
diff --git a/arch/s390/include/asm/io.h b/arch/s390/include/asm/io.h index fd9be010f9b2..cd6b9ee7b69c 100644 --- a/arch/s390/include/asm/io.h +++ b/arch/s390/include/asm/io.h | |||
@@ -13,28 +13,6 @@ | |||
13 | #include <asm/page.h> | 13 | #include <asm/page.h> |
14 | #include <asm/pci_io.h> | 14 | #include <asm/pci_io.h> |
15 | 15 | ||
16 | /* | ||
17 | * Change virtual addresses to physical addresses and vv. | ||
18 | * These are pretty trivial | ||
19 | */ | ||
20 | static inline unsigned long virt_to_phys(volatile void * address) | ||
21 | { | ||
22 | unsigned long real_address; | ||
23 | asm volatile( | ||
24 | " lra %0,0(%1)\n" | ||
25 | " jz 0f\n" | ||
26 | " la %0,0\n" | ||
27 | "0:" | ||
28 | : "=a" (real_address) : "a" (address) : "cc"); | ||
29 | return real_address; | ||
30 | } | ||
31 | #define virt_to_phys virt_to_phys | ||
32 | |||
33 | static inline void * phys_to_virt(unsigned long address) | ||
34 | { | ||
35 | return (void *) address; | ||
36 | } | ||
37 | |||
38 | void *xlate_dev_mem_ptr(unsigned long phys); | 16 | void *xlate_dev_mem_ptr(unsigned long phys); |
39 | #define xlate_dev_mem_ptr xlate_dev_mem_ptr | 17 | #define xlate_dev_mem_ptr xlate_dev_mem_ptr |
40 | void unxlate_dev_mem_ptr(unsigned long phys, void *addr); | 18 | void unxlate_dev_mem_ptr(unsigned long phys, void *addr); |
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index 6c1801235db9..6e577ba0e5da 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h | |||
@@ -120,7 +120,6 @@ struct zpci_dev { | |||
120 | 120 | ||
121 | struct dentry *debugfs_dev; | 121 | struct dentry *debugfs_dev; |
122 | struct dentry *debugfs_perf; | 122 | struct dentry *debugfs_perf; |
123 | struct dentry *debugfs_debug; | ||
124 | }; | 123 | }; |
125 | 124 | ||
126 | struct pci_hp_callback_ops { | 125 | struct pci_hp_callback_ops { |
@@ -143,7 +142,6 @@ int zpci_enable_device(struct zpci_dev *); | |||
143 | int zpci_disable_device(struct zpci_dev *); | 142 | int zpci_disable_device(struct zpci_dev *); |
144 | void zpci_stop_device(struct zpci_dev *); | 143 | void zpci_stop_device(struct zpci_dev *); |
145 | void zpci_free_device(struct zpci_dev *); | 144 | void zpci_free_device(struct zpci_dev *); |
146 | int zpci_scan_device(struct zpci_dev *); | ||
147 | int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64); | 145 | int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64); |
148 | int zpci_unregister_ioat(struct zpci_dev *, u8); | 146 | int zpci_unregister_ioat(struct zpci_dev *, u8); |
149 | 147 | ||
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h index 590c3219c634..e1408ddb94f8 100644 --- a/arch/s390/include/asm/pgalloc.h +++ b/arch/s390/include/asm/pgalloc.h | |||
@@ -22,6 +22,9 @@ unsigned long *page_table_alloc(struct mm_struct *, unsigned long); | |||
22 | void page_table_free(struct mm_struct *, unsigned long *); | 22 | void page_table_free(struct mm_struct *, unsigned long *); |
23 | void page_table_free_rcu(struct mmu_gather *, unsigned long *); | 23 | void page_table_free_rcu(struct mmu_gather *, unsigned long *); |
24 | 24 | ||
25 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, | ||
26 | unsigned long key, bool nq); | ||
27 | |||
25 | static inline void clear_table(unsigned long *s, unsigned long val, size_t n) | 28 | static inline void clear_table(unsigned long *s, unsigned long val, size_t n) |
26 | { | 29 | { |
27 | typedef struct { char _[n]; } addrtype; | 30 | typedef struct { char _[n]; } addrtype; |
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index 559512a455da..52b56533c57c 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h | |||
@@ -24,6 +24,7 @@ struct pt_regs | |||
24 | unsigned long gprs[NUM_GPRS]; | 24 | unsigned long gprs[NUM_GPRS]; |
25 | unsigned long orig_gpr2; | 25 | unsigned long orig_gpr2; |
26 | unsigned int int_code; | 26 | unsigned int int_code; |
27 | unsigned int int_parm; | ||
27 | unsigned long int_parm_long; | 28 | unsigned long int_parm_long; |
28 | }; | 29 | }; |
29 | 30 | ||
diff --git a/arch/s390/include/uapi/asm/Kbuild b/arch/s390/include/uapi/asm/Kbuild index 9ccd1905bdad..6a9a9eb645f5 100644 --- a/arch/s390/include/uapi/asm/Kbuild +++ b/arch/s390/include/uapi/asm/Kbuild | |||
@@ -35,6 +35,7 @@ header-y += siginfo.h | |||
35 | header-y += signal.h | 35 | header-y += signal.h |
36 | header-y += socket.h | 36 | header-y += socket.h |
37 | header-y += sockios.h | 37 | header-y += sockios.h |
38 | header-y += sclp_ctl.h | ||
38 | header-y += stat.h | 39 | header-y += stat.h |
39 | header-y += statfs.h | 40 | header-y += statfs.h |
40 | header-y += swab.h | 41 | header-y += swab.h |
diff --git a/arch/s390/include/uapi/asm/chsc.h b/arch/s390/include/uapi/asm/chsc.h index 1c6a7f85a581..65dc694725a8 100644 --- a/arch/s390/include/uapi/asm/chsc.h +++ b/arch/s390/include/uapi/asm/chsc.h | |||
@@ -29,6 +29,16 @@ struct chsc_async_area { | |||
29 | __u8 data[CHSC_SIZE - sizeof(struct chsc_async_header)]; | 29 | __u8 data[CHSC_SIZE - sizeof(struct chsc_async_header)]; |
30 | } __attribute__ ((packed)); | 30 | } __attribute__ ((packed)); |
31 | 31 | ||
32 | struct chsc_header { | ||
33 | __u16 length; | ||
34 | __u16 code; | ||
35 | } __attribute__ ((packed)); | ||
36 | |||
37 | struct chsc_sync_area { | ||
38 | struct chsc_header header; | ||
39 | __u8 data[CHSC_SIZE - sizeof(struct chsc_header)]; | ||
40 | } __attribute__ ((packed)); | ||
41 | |||
32 | struct chsc_response_struct { | 42 | struct chsc_response_struct { |
33 | __u16 length; | 43 | __u16 length; |
34 | __u16 code; | 44 | __u16 code; |
@@ -126,5 +136,8 @@ struct chsc_cpd_info { | |||
126 | #define CHSC_INFO_CCL _IOWR(CHSC_IOCTL_MAGIC, 0x86, struct chsc_comp_list) | 136 | #define CHSC_INFO_CCL _IOWR(CHSC_IOCTL_MAGIC, 0x86, struct chsc_comp_list) |
127 | #define CHSC_INFO_CPD _IOWR(CHSC_IOCTL_MAGIC, 0x87, struct chsc_cpd_info) | 137 | #define CHSC_INFO_CPD _IOWR(CHSC_IOCTL_MAGIC, 0x87, struct chsc_cpd_info) |
128 | #define CHSC_INFO_DCAL _IOWR(CHSC_IOCTL_MAGIC, 0x88, struct chsc_dcal) | 138 | #define CHSC_INFO_DCAL _IOWR(CHSC_IOCTL_MAGIC, 0x88, struct chsc_dcal) |
139 | #define CHSC_START_SYNC _IOWR(CHSC_IOCTL_MAGIC, 0x89, struct chsc_sync_area) | ||
140 | #define CHSC_ON_CLOSE_SET _IOWR(CHSC_IOCTL_MAGIC, 0x8a, struct chsc_async_area) | ||
141 | #define CHSC_ON_CLOSE_REMOVE _IO(CHSC_IOCTL_MAGIC, 0x8b) | ||
129 | 142 | ||
130 | #endif | 143 | #endif |
diff --git a/arch/s390/include/uapi/asm/dasd.h b/arch/s390/include/uapi/asm/dasd.h index 38eca3ba40e2..5812a3b2df9e 100644 --- a/arch/s390/include/uapi/asm/dasd.h +++ b/arch/s390/include/uapi/asm/dasd.h | |||
@@ -261,6 +261,10 @@ struct dasd_snid_ioctl_data { | |||
261 | #define BIODASDQUIESCE _IO(DASD_IOCTL_LETTER,6) | 261 | #define BIODASDQUIESCE _IO(DASD_IOCTL_LETTER,6) |
262 | /* Resume IO on device */ | 262 | /* Resume IO on device */ |
263 | #define BIODASDRESUME _IO(DASD_IOCTL_LETTER,7) | 263 | #define BIODASDRESUME _IO(DASD_IOCTL_LETTER,7) |
264 | /* Abort all I/O on a device */ | ||
265 | #define BIODASDABORTIO _IO(DASD_IOCTL_LETTER, 240) | ||
266 | /* Allow I/O on a device */ | ||
267 | #define BIODASDALLOWIO _IO(DASD_IOCTL_LETTER, 241) | ||
264 | 268 | ||
265 | 269 | ||
266 | /* retrieve API version number */ | 270 | /* retrieve API version number */ |
diff --git a/arch/s390/include/uapi/asm/sclp_ctl.h b/arch/s390/include/uapi/asm/sclp_ctl.h new file mode 100644 index 000000000000..f2818613ee41 --- /dev/null +++ b/arch/s390/include/uapi/asm/sclp_ctl.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * IOCTL interface for SCLP | ||
3 | * | ||
4 | * Copyright IBM Corp. 2012 | ||
5 | * | ||
6 | * Author: Michael Holzheu <holzheu@linux.vnet.ibm.com> | ||
7 | */ | ||
8 | |||
9 | #ifndef _ASM_SCLP_CTL_H | ||
10 | #define _ASM_SCLP_CTL_H | ||
11 | |||
12 | #include <linux/types.h> | ||
13 | |||
14 | struct sclp_ctl_sccb { | ||
15 | __u32 cmdw; | ||
16 | __u64 sccb; | ||
17 | } __attribute__((packed)); | ||
18 | |||
19 | #define SCLP_CTL_IOCTL_MAGIC 0x10 | ||
20 | |||
21 | #define SCLP_CTL_SCCB \ | ||
22 | _IOWR(SCLP_CTL_IOCTL_MAGIC, 0x10, struct sclp_ctl_sccb) | ||
23 | |||
24 | #endif | ||
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 7a82f9f70100..d6de844bc30a 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c | |||
@@ -47,6 +47,7 @@ int main(void) | |||
47 | DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs)); | 47 | DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs)); |
48 | DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2)); | 48 | DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2)); |
49 | DEFINE(__PT_INT_CODE, offsetof(struct pt_regs, int_code)); | 49 | DEFINE(__PT_INT_CODE, offsetof(struct pt_regs, int_code)); |
50 | DEFINE(__PT_INT_PARM, offsetof(struct pt_regs, int_parm)); | ||
50 | DEFINE(__PT_INT_PARM_LONG, offsetof(struct pt_regs, int_parm_long)); | 51 | DEFINE(__PT_INT_PARM_LONG, offsetof(struct pt_regs, int_parm_long)); |
51 | DEFINE(__PT_SIZE, sizeof(struct pt_regs)); | 52 | DEFINE(__PT_SIZE, sizeof(struct pt_regs)); |
52 | BLANK(); | 53 | BLANK(); |
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 4d5e6f8a7978..be7a408be7a1 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
@@ -429,11 +429,19 @@ io_skip: | |||
429 | stm %r0,%r7,__PT_R0(%r11) | 429 | stm %r0,%r7,__PT_R0(%r11) |
430 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC | 430 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC |
431 | stm %r8,%r9,__PT_PSW(%r11) | 431 | stm %r8,%r9,__PT_PSW(%r11) |
432 | mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID | ||
432 | TRACE_IRQS_OFF | 433 | TRACE_IRQS_OFF |
433 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) | 434 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
435 | io_loop: | ||
434 | l %r1,BASED(.Ldo_IRQ) | 436 | l %r1,BASED(.Ldo_IRQ) |
435 | lr %r2,%r11 # pass pointer to pt_regs | 437 | lr %r2,%r11 # pass pointer to pt_regs |
436 | basr %r14,%r1 # call do_IRQ | 438 | basr %r14,%r1 # call do_IRQ |
439 | tm __LC_MACHINE_FLAGS+2,0x10 # MACHINE_FLAG_LPAR | ||
440 | jz io_return | ||
441 | tpi 0 | ||
442 | jz io_return | ||
443 | mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID | ||
444 | j io_loop | ||
437 | io_return: | 445 | io_return: |
438 | LOCKDEP_SYS_EXIT | 446 | LOCKDEP_SYS_EXIT |
439 | TRACE_IRQS_ON | 447 | TRACE_IRQS_ON |
@@ -573,10 +581,10 @@ ext_skip: | |||
573 | stm %r0,%r7,__PT_R0(%r11) | 581 | stm %r0,%r7,__PT_R0(%r11) |
574 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC | 582 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC |
575 | stm %r8,%r9,__PT_PSW(%r11) | 583 | stm %r8,%r9,__PT_PSW(%r11) |
584 | mvc __PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR | ||
585 | mvc __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS | ||
576 | TRACE_IRQS_OFF | 586 | TRACE_IRQS_OFF |
577 | lr %r2,%r11 # pass pointer to pt_regs | 587 | lr %r2,%r11 # pass pointer to pt_regs |
578 | l %r3,__LC_EXT_CPU_ADDR # get cpu address + interruption code | ||
579 | l %r4,__LC_EXT_PARAMS # get external parameters | ||
580 | l %r1,BASED(.Ldo_extint) | 588 | l %r1,BASED(.Ldo_extint) |
581 | basr %r14,%r1 # call do_extint | 589 | basr %r14,%r1 # call do_extint |
582 | j io_return | 590 | j io_return |
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index aa0ab02e9595..3ddbc26d246e 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h | |||
@@ -54,7 +54,7 @@ void handle_signal32(unsigned long sig, struct k_sigaction *ka, | |||
54 | void do_notify_resume(struct pt_regs *regs); | 54 | void do_notify_resume(struct pt_regs *regs); |
55 | 55 | ||
56 | struct ext_code; | 56 | struct ext_code; |
57 | void do_extint(struct pt_regs *regs, struct ext_code, unsigned int, unsigned long); | 57 | void do_extint(struct pt_regs *regs); |
58 | void do_restart(void); | 58 | void do_restart(void); |
59 | void __init startup_init(void); | 59 | void __init startup_init(void); |
60 | void die(struct pt_regs *regs, const char *str); | 60 | void die(struct pt_regs *regs, const char *str); |
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 4c17eece707e..bc5864c5148b 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
@@ -460,10 +460,18 @@ io_skip: | |||
460 | stmg %r0,%r7,__PT_R0(%r11) | 460 | stmg %r0,%r7,__PT_R0(%r11) |
461 | mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC | 461 | mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC |
462 | stmg %r8,%r9,__PT_PSW(%r11) | 462 | stmg %r8,%r9,__PT_PSW(%r11) |
463 | mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID | ||
463 | TRACE_IRQS_OFF | 464 | TRACE_IRQS_OFF |
464 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | 465 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
466 | io_loop: | ||
465 | lgr %r2,%r11 # pass pointer to pt_regs | 467 | lgr %r2,%r11 # pass pointer to pt_regs |
466 | brasl %r14,do_IRQ | 468 | brasl %r14,do_IRQ |
469 | tm __LC_MACHINE_FLAGS+6,0x10 # MACHINE_FLAG_LPAR | ||
470 | jz io_return | ||
471 | tpi 0 | ||
472 | jz io_return | ||
473 | mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID | ||
474 | j io_loop | ||
467 | io_return: | 475 | io_return: |
468 | LOCKDEP_SYS_EXIT | 476 | LOCKDEP_SYS_EXIT |
469 | TRACE_IRQS_ON | 477 | TRACE_IRQS_ON |
@@ -605,13 +613,13 @@ ext_skip: | |||
605 | stmg %r0,%r7,__PT_R0(%r11) | 613 | stmg %r0,%r7,__PT_R0(%r11) |
606 | mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC | 614 | mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC |
607 | stmg %r8,%r9,__PT_PSW(%r11) | 615 | stmg %r8,%r9,__PT_PSW(%r11) |
616 | lghi %r1,__LC_EXT_PARAMS2 | ||
617 | mvc __PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR | ||
618 | mvc __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS | ||
619 | mvc __PT_INT_PARM_LONG(8,%r11),0(%r1) | ||
608 | TRACE_IRQS_OFF | 620 | TRACE_IRQS_OFF |
609 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | 621 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
610 | lghi %r1,4096 | ||
611 | lgr %r2,%r11 # pass pointer to pt_regs | 622 | lgr %r2,%r11 # pass pointer to pt_regs |
612 | llgf %r3,__LC_EXT_CPU_ADDR # get cpu address + interruption code | ||
613 | llgf %r4,__LC_EXT_PARAMS # get external parameter | ||
614 | lg %r5,__LC_EXT_PARAMS2-4096(%r1) # get 64 bit external parameter | ||
615 | brasl %r14,do_extint | 623 | brasl %r14,do_extint |
616 | j io_return | 624 | j io_return |
617 | 625 | ||
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index dd3c1994b8bd..54b0995514e8 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c | |||
@@ -234,9 +234,9 @@ int unregister_external_interrupt(u16 code, ext_int_handler_t handler) | |||
234 | } | 234 | } |
235 | EXPORT_SYMBOL(unregister_external_interrupt); | 235 | EXPORT_SYMBOL(unregister_external_interrupt); |
236 | 236 | ||
237 | void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code, | 237 | void __irq_entry do_extint(struct pt_regs *regs) |
238 | unsigned int param32, unsigned long param64) | ||
239 | { | 238 | { |
239 | struct ext_code ext_code; | ||
240 | struct pt_regs *old_regs; | 240 | struct pt_regs *old_regs; |
241 | struct ext_int_info *p; | 241 | struct ext_int_info *p; |
242 | int index; | 242 | int index; |
@@ -248,6 +248,7 @@ void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code, | |||
248 | clock_comparator_work(); | 248 | clock_comparator_work(); |
249 | } | 249 | } |
250 | kstat_incr_irqs_this_cpu(EXTERNAL_INTERRUPT, NULL); | 250 | kstat_incr_irqs_this_cpu(EXTERNAL_INTERRUPT, NULL); |
251 | ext_code = *(struct ext_code *) ®s->int_code; | ||
251 | if (ext_code.code != 0x1004) | 252 | if (ext_code.code != 0x1004) |
252 | __get_cpu_var(s390_idle).nohz_delay = 1; | 253 | __get_cpu_var(s390_idle).nohz_delay = 1; |
253 | 254 | ||
@@ -255,7 +256,8 @@ void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code, | |||
255 | rcu_read_lock(); | 256 | rcu_read_lock(); |
256 | list_for_each_entry_rcu(p, &ext_int_hash[index], entry) | 257 | list_for_each_entry_rcu(p, &ext_int_hash[index], entry) |
257 | if (likely(p->code == ext_code.code)) | 258 | if (likely(p->code == ext_code.code)) |
258 | p->handler(ext_code, param32, param64); | 259 | p->handler(ext_code, regs->int_parm, |
260 | regs->int_parm_long); | ||
259 | rcu_read_unlock(); | 261 | rcu_read_unlock(); |
260 | irq_exit(); | 262 | irq_exit(); |
261 | set_irq_regs(old_regs); | 263 | set_irq_regs(old_regs); |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 4f977d0d25c2..15a016c10563 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -49,7 +49,6 @@ | |||
49 | 49 | ||
50 | enum { | 50 | enum { |
51 | ec_schedule = 0, | 51 | ec_schedule = 0, |
52 | ec_call_function, | ||
53 | ec_call_function_single, | 52 | ec_call_function_single, |
54 | ec_stop_cpu, | 53 | ec_stop_cpu, |
55 | }; | 54 | }; |
@@ -438,8 +437,6 @@ static void smp_handle_ext_call(void) | |||
438 | smp_stop_cpu(); | 437 | smp_stop_cpu(); |
439 | if (test_bit(ec_schedule, &bits)) | 438 | if (test_bit(ec_schedule, &bits)) |
440 | scheduler_ipi(); | 439 | scheduler_ipi(); |
441 | if (test_bit(ec_call_function, &bits)) | ||
442 | generic_smp_call_function_interrupt(); | ||
443 | if (test_bit(ec_call_function_single, &bits)) | 440 | if (test_bit(ec_call_function_single, &bits)) |
444 | generic_smp_call_function_single_interrupt(); | 441 | generic_smp_call_function_single_interrupt(); |
445 | } | 442 | } |
@@ -456,7 +453,7 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask) | |||
456 | int cpu; | 453 | int cpu; |
457 | 454 | ||
458 | for_each_cpu(cpu, mask) | 455 | for_each_cpu(cpu, mask) |
459 | pcpu_ec_call(pcpu_devices + cpu, ec_call_function); | 456 | pcpu_ec_call(pcpu_devices + cpu, ec_call_function_single); |
460 | } | 457 | } |
461 | 458 | ||
462 | void arch_send_call_function_single_ipi(int cpu) | 459 | void arch_send_call_function_single_ipi(int cpu) |
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index a938b548f07e..74c29d922458 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
@@ -771,6 +771,54 @@ static inline void page_table_free_pgste(unsigned long *table) | |||
771 | __free_page(page); | 771 | __free_page(page); |
772 | } | 772 | } |
773 | 773 | ||
774 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, | ||
775 | unsigned long key, bool nq) | ||
776 | { | ||
777 | spinlock_t *ptl; | ||
778 | pgste_t old, new; | ||
779 | pte_t *ptep; | ||
780 | |||
781 | down_read(&mm->mmap_sem); | ||
782 | ptep = get_locked_pte(current->mm, addr, &ptl); | ||
783 | if (unlikely(!ptep)) { | ||
784 | up_read(&mm->mmap_sem); | ||
785 | return -EFAULT; | ||
786 | } | ||
787 | |||
788 | new = old = pgste_get_lock(ptep); | ||
789 | pgste_val(new) &= ~(PGSTE_GR_BIT | PGSTE_GC_BIT | | ||
790 | PGSTE_ACC_BITS | PGSTE_FP_BIT); | ||
791 | pgste_val(new) |= (key & (_PAGE_CHANGED | _PAGE_REFERENCED)) << 48; | ||
792 | pgste_val(new) |= (key & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56; | ||
793 | if (!(pte_val(*ptep) & _PAGE_INVALID)) { | ||
794 | unsigned long address, bits; | ||
795 | unsigned char skey; | ||
796 | |||
797 | address = pte_val(*ptep) & PAGE_MASK; | ||
798 | skey = page_get_storage_key(address); | ||
799 | bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED); | ||
800 | /* Set storage key ACC and FP */ | ||
801 | page_set_storage_key(address, | ||
802 | (key & (_PAGE_ACC_BITS | _PAGE_FP_BIT)), | ||
803 | !nq); | ||
804 | |||
805 | /* Merge host changed & referenced into pgste */ | ||
806 | pgste_val(new) |= bits << 52; | ||
807 | /* Transfer skey changed & referenced bit to kvm user bits */ | ||
808 | pgste_val(new) |= bits << 45; /* PGSTE_UR_BIT & PGSTE_UC_BIT */ | ||
809 | } | ||
810 | /* changing the guest storage key is considered a change of the page */ | ||
811 | if ((pgste_val(new) ^ pgste_val(old)) & | ||
812 | (PGSTE_ACC_BITS | PGSTE_FP_BIT | PGSTE_GR_BIT | PGSTE_GC_BIT)) | ||
813 | pgste_val(new) |= PGSTE_UC_BIT; | ||
814 | |||
815 | pgste_set_unlock(ptep, new); | ||
816 | pte_unmap_unlock(*ptep, ptl); | ||
817 | up_read(&mm->mmap_sem); | ||
818 | return 0; | ||
819 | } | ||
820 | EXPORT_SYMBOL(set_guest_storage_key); | ||
821 | |||
774 | #else /* CONFIG_PGSTE */ | 822 | #else /* CONFIG_PGSTE */ |
775 | 823 | ||
776 | static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm, | 824 | static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm, |
diff --git a/arch/s390/oprofile/hwsampler.h b/arch/s390/oprofile/hwsampler.h index 1912f3bb190c..0022e1ebfbde 100644 --- a/arch/s390/oprofile/hwsampler.h +++ b/arch/s390/oprofile/hwsampler.h | |||
@@ -81,8 +81,8 @@ struct hws_data_entry { | |||
81 | unsigned int:16; | 81 | unsigned int:16; |
82 | unsigned int prim_asn:16; /* primary ASN */ | 82 | unsigned int prim_asn:16; /* primary ASN */ |
83 | unsigned long long ia; /* Instruction Address */ | 83 | unsigned long long ia; /* Instruction Address */ |
84 | unsigned long long lpp; /* Logical-Partition Program Param. */ | 84 | unsigned long long gpp; /* Guest Program Parameter */ |
85 | unsigned long long vpp; /* Virtual-Machine Program Param. */ | 85 | unsigned long long hpp; /* Host Program Parameter */ |
86 | }; | 86 | }; |
87 | 87 | ||
88 | struct hws_trailer_entry { | 88 | struct hws_trailer_entry { |
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index f1e5be85d592..e2956ad39a4f 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c | |||
@@ -82,10 +82,13 @@ struct intr_bucket { | |||
82 | 82 | ||
83 | static struct intr_bucket *bucket; | 83 | static struct intr_bucket *bucket; |
84 | 84 | ||
85 | /* Adapter local summary indicator */ | 85 | /* Adapter interrupt definitions */ |
86 | static u8 *zpci_irq_si; | 86 | static void zpci_irq_handler(struct airq_struct *airq); |
87 | 87 | ||
88 | static atomic_t irq_retries = ATOMIC_INIT(0); | 88 | static struct airq_struct zpci_airq = { |
89 | .handler = zpci_irq_handler, | ||
90 | .isc = PCI_ISC, | ||
91 | }; | ||
89 | 92 | ||
90 | /* I/O Map */ | 93 | /* I/O Map */ |
91 | static DEFINE_SPINLOCK(zpci_iomap_lock); | 94 | static DEFINE_SPINLOCK(zpci_iomap_lock); |
@@ -404,7 +407,7 @@ static struct pci_ops pci_root_ops = { | |||
404 | /* store the last handled bit to implement fair scheduling of devices */ | 407 | /* store the last handled bit to implement fair scheduling of devices */ |
405 | static DEFINE_PER_CPU(unsigned long, next_sbit); | 408 | static DEFINE_PER_CPU(unsigned long, next_sbit); |
406 | 409 | ||
407 | static void zpci_irq_handler(void *dont, void *need) | 410 | static void zpci_irq_handler(struct airq_struct *airq) |
408 | { | 411 | { |
409 | unsigned long sbit, mbit, last = 0, start = __get_cpu_var(next_sbit); | 412 | unsigned long sbit, mbit, last = 0, start = __get_cpu_var(next_sbit); |
410 | int rescan = 0, max = aisb_max; | 413 | int rescan = 0, max = aisb_max; |
@@ -452,7 +455,6 @@ scan: | |||
452 | max = aisb_max; | 455 | max = aisb_max; |
453 | sbit = find_first_bit_left(bucket->aisb, max); | 456 | sbit = find_first_bit_left(bucket->aisb, max); |
454 | if (sbit != max) { | 457 | if (sbit != max) { |
455 | atomic_inc(&irq_retries); | ||
456 | rescan++; | 458 | rescan++; |
457 | goto scan; | 459 | goto scan; |
458 | } | 460 | } |
@@ -565,7 +567,21 @@ static void zpci_map_resources(struct zpci_dev *zdev) | |||
565 | pr_debug("BAR%i: -> start: %Lx end: %Lx\n", | 567 | pr_debug("BAR%i: -> start: %Lx end: %Lx\n", |
566 | i, pdev->resource[i].start, pdev->resource[i].end); | 568 | i, pdev->resource[i].start, pdev->resource[i].end); |
567 | } | 569 | } |
568 | }; | 570 | } |
571 | |||
572 | static void zpci_unmap_resources(struct zpci_dev *zdev) | ||
573 | { | ||
574 | struct pci_dev *pdev = zdev->pdev; | ||
575 | resource_size_t len; | ||
576 | int i; | ||
577 | |||
578 | for (i = 0; i < PCI_BAR_COUNT; i++) { | ||
579 | len = pci_resource_len(pdev, i); | ||
580 | if (!len) | ||
581 | continue; | ||
582 | pci_iounmap(pdev, (void *) pdev->resource[i].start); | ||
583 | } | ||
584 | } | ||
569 | 585 | ||
570 | struct zpci_dev *zpci_alloc_device(void) | 586 | struct zpci_dev *zpci_alloc_device(void) |
571 | { | 587 | { |
@@ -701,25 +717,20 @@ static int __init zpci_irq_init(void) | |||
701 | goto out_alloc; | 717 | goto out_alloc; |
702 | } | 718 | } |
703 | 719 | ||
704 | isc_register(PCI_ISC); | 720 | rc = register_adapter_interrupt(&zpci_airq); |
705 | zpci_irq_si = s390_register_adapter_interrupt(&zpci_irq_handler, NULL, PCI_ISC); | 721 | if (rc) |
706 | if (IS_ERR(zpci_irq_si)) { | ||
707 | rc = PTR_ERR(zpci_irq_si); | ||
708 | zpci_irq_si = NULL; | ||
709 | goto out_ai; | 722 | goto out_ai; |
710 | } | 723 | /* Set summary to 1 to be called every time for the ISC. */ |
724 | *zpci_airq.lsi_ptr = 1; | ||
711 | 725 | ||
712 | for_each_online_cpu(cpu) | 726 | for_each_online_cpu(cpu) |
713 | per_cpu(next_sbit, cpu) = 0; | 727 | per_cpu(next_sbit, cpu) = 0; |
714 | 728 | ||
715 | spin_lock_init(&bucket->lock); | 729 | spin_lock_init(&bucket->lock); |
716 | /* set summary to 1 to be called every time for the ISC */ | ||
717 | *zpci_irq_si = 1; | ||
718 | set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC); | 730 | set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC); |
719 | return 0; | 731 | return 0; |
720 | 732 | ||
721 | out_ai: | 733 | out_ai: |
722 | isc_unregister(PCI_ISC); | ||
723 | free_page((unsigned long) bucket->alloc); | 734 | free_page((unsigned long) bucket->alloc); |
724 | out_alloc: | 735 | out_alloc: |
725 | free_page((unsigned long) bucket->aisb); | 736 | free_page((unsigned long) bucket->aisb); |
@@ -732,21 +743,10 @@ static void zpci_irq_exit(void) | |||
732 | { | 743 | { |
733 | free_page((unsigned long) bucket->alloc); | 744 | free_page((unsigned long) bucket->alloc); |
734 | free_page((unsigned long) bucket->aisb); | 745 | free_page((unsigned long) bucket->aisb); |
735 | s390_unregister_adapter_interrupt(zpci_irq_si, PCI_ISC); | 746 | unregister_adapter_interrupt(&zpci_airq); |
736 | isc_unregister(PCI_ISC); | ||
737 | kfree(bucket); | 747 | kfree(bucket); |
738 | } | 748 | } |
739 | 749 | ||
740 | void zpci_debug_info(struct zpci_dev *zdev, struct seq_file *m) | ||
741 | { | ||
742 | if (!zdev) | ||
743 | return; | ||
744 | |||
745 | seq_printf(m, "global irq retries: %u\n", atomic_read(&irq_retries)); | ||
746 | seq_printf(m, "aibv[0]:%016lx aibv[1]:%016lx aisb:%016lx\n", | ||
747 | get_imap(0)->aibv, get_imap(1)->aibv, *bucket->aisb); | ||
748 | } | ||
749 | |||
750 | static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size, | 750 | static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size, |
751 | unsigned long flags, int domain) | 751 | unsigned long flags, int domain) |
752 | { | 752 | { |
@@ -810,6 +810,16 @@ int pcibios_add_device(struct pci_dev *pdev) | |||
810 | return 0; | 810 | return 0; |
811 | } | 811 | } |
812 | 812 | ||
813 | void pcibios_release_device(struct pci_dev *pdev) | ||
814 | { | ||
815 | struct zpci_dev *zdev = get_zdev(pdev); | ||
816 | |||
817 | zpci_unmap_resources(zdev); | ||
818 | zpci_fmb_disable_device(zdev); | ||
819 | zpci_debug_exit_device(zdev); | ||
820 | zdev->pdev = NULL; | ||
821 | } | ||
822 | |||
813 | static int zpci_scan_bus(struct zpci_dev *zdev) | 823 | static int zpci_scan_bus(struct zpci_dev *zdev) |
814 | { | 824 | { |
815 | struct resource *res; | 825 | struct resource *res; |
@@ -950,25 +960,6 @@ void zpci_stop_device(struct zpci_dev *zdev) | |||
950 | } | 960 | } |
951 | EXPORT_SYMBOL_GPL(zpci_stop_device); | 961 | EXPORT_SYMBOL_GPL(zpci_stop_device); |
952 | 962 | ||
953 | int zpci_scan_device(struct zpci_dev *zdev) | ||
954 | { | ||
955 | zdev->pdev = pci_scan_single_device(zdev->bus, ZPCI_DEVFN); | ||
956 | if (!zdev->pdev) { | ||
957 | pr_err("pci_scan_single_device failed for fid: 0x%x\n", | ||
958 | zdev->fid); | ||
959 | goto out; | ||
960 | } | ||
961 | |||
962 | pci_bus_add_devices(zdev->bus); | ||
963 | |||
964 | return 0; | ||
965 | out: | ||
966 | zpci_dma_exit_device(zdev); | ||
967 | clp_disable_fh(zdev); | ||
968 | return -EIO; | ||
969 | } | ||
970 | EXPORT_SYMBOL_GPL(zpci_scan_device); | ||
971 | |||
972 | static inline int barsize(u8 size) | 963 | static inline int barsize(u8 size) |
973 | { | 964 | { |
974 | return (size) ? (1 << size) >> 10 : 0; | 965 | return (size) ? (1 << size) >> 10 : 0; |
diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c index bd34359d1546..2e9539625d93 100644 --- a/arch/s390/pci/pci_clp.c +++ b/arch/s390/pci/pci_clp.c | |||
@@ -236,7 +236,6 @@ int clp_disable_fh(struct zpci_dev *zdev) | |||
236 | if (!zdev_enabled(zdev)) | 236 | if (!zdev_enabled(zdev)) |
237 | return 0; | 237 | return 0; |
238 | 238 | ||
239 | dev_info(&zdev->pdev->dev, "disabling fn handle: 0x%x\n", fh); | ||
240 | rc = clp_set_pci_fn(&fh, 0, CLP_SET_DISABLE_PCI_FN); | 239 | rc = clp_set_pci_fn(&fh, 0, CLP_SET_DISABLE_PCI_FN); |
241 | if (!rc) | 240 | if (!rc) |
242 | /* Success -> store disabled handle in zdev */ | 241 | /* Success -> store disabled handle in zdev */ |
diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c index 771b82359af4..75c69b402e05 100644 --- a/arch/s390/pci/pci_debug.c +++ b/arch/s390/pci/pci_debug.c | |||
@@ -115,27 +115,6 @@ static const struct file_operations debugfs_pci_perf_fops = { | |||
115 | .release = single_release, | 115 | .release = single_release, |
116 | }; | 116 | }; |
117 | 117 | ||
118 | static int pci_debug_show(struct seq_file *m, void *v) | ||
119 | { | ||
120 | struct zpci_dev *zdev = m->private; | ||
121 | |||
122 | zpci_debug_info(zdev, m); | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int pci_debug_seq_open(struct inode *inode, struct file *filp) | ||
127 | { | ||
128 | return single_open(filp, pci_debug_show, | ||
129 | file_inode(filp)->i_private); | ||
130 | } | ||
131 | |||
132 | static const struct file_operations debugfs_pci_debug_fops = { | ||
133 | .open = pci_debug_seq_open, | ||
134 | .read = seq_read, | ||
135 | .llseek = seq_lseek, | ||
136 | .release = single_release, | ||
137 | }; | ||
138 | |||
139 | void zpci_debug_init_device(struct zpci_dev *zdev) | 118 | void zpci_debug_init_device(struct zpci_dev *zdev) |
140 | { | 119 | { |
141 | zdev->debugfs_dev = debugfs_create_dir(dev_name(&zdev->pdev->dev), | 120 | zdev->debugfs_dev = debugfs_create_dir(dev_name(&zdev->pdev->dev), |
@@ -149,19 +128,11 @@ void zpci_debug_init_device(struct zpci_dev *zdev) | |||
149 | &debugfs_pci_perf_fops); | 128 | &debugfs_pci_perf_fops); |
150 | if (IS_ERR(zdev->debugfs_perf)) | 129 | if (IS_ERR(zdev->debugfs_perf)) |
151 | zdev->debugfs_perf = NULL; | 130 | zdev->debugfs_perf = NULL; |
152 | |||
153 | zdev->debugfs_debug = debugfs_create_file("debug", | ||
154 | S_IFREG | S_IRUGO | S_IWUSR, | ||
155 | zdev->debugfs_dev, zdev, | ||
156 | &debugfs_pci_debug_fops); | ||
157 | if (IS_ERR(zdev->debugfs_debug)) | ||
158 | zdev->debugfs_debug = NULL; | ||
159 | } | 131 | } |
160 | 132 | ||
161 | void zpci_debug_exit_device(struct zpci_dev *zdev) | 133 | void zpci_debug_exit_device(struct zpci_dev *zdev) |
162 | { | 134 | { |
163 | debugfs_remove(zdev->debugfs_perf); | 135 | debugfs_remove(zdev->debugfs_perf); |
164 | debugfs_remove(zdev->debugfs_debug); | ||
165 | debugfs_remove(zdev->debugfs_dev); | 136 | debugfs_remove(zdev->debugfs_dev); |
166 | } | 137 | } |
167 | 138 | ||
diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c index f8e69d5bc0a9..a2343c1f6e04 100644 --- a/arch/s390/pci/pci_dma.c +++ b/arch/s390/pci/pci_dma.c | |||
@@ -263,7 +263,7 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page, | |||
263 | enum dma_data_direction direction, | 263 | enum dma_data_direction direction, |
264 | struct dma_attrs *attrs) | 264 | struct dma_attrs *attrs) |
265 | { | 265 | { |
266 | struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev)); | 266 | struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); |
267 | unsigned long nr_pages, iommu_page_index; | 267 | unsigned long nr_pages, iommu_page_index; |
268 | unsigned long pa = page_to_phys(page) + offset; | 268 | unsigned long pa = page_to_phys(page) + offset; |
269 | int flags = ZPCI_PTE_VALID; | 269 | int flags = ZPCI_PTE_VALID; |
@@ -304,7 +304,7 @@ static void s390_dma_unmap_pages(struct device *dev, dma_addr_t dma_addr, | |||
304 | size_t size, enum dma_data_direction direction, | 304 | size_t size, enum dma_data_direction direction, |
305 | struct dma_attrs *attrs) | 305 | struct dma_attrs *attrs) |
306 | { | 306 | { |
307 | struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev)); | 307 | struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); |
308 | unsigned long iommu_page_index; | 308 | unsigned long iommu_page_index; |
309 | int npages; | 309 | int npages; |
310 | 310 | ||
@@ -323,7 +323,7 @@ static void *s390_dma_alloc(struct device *dev, size_t size, | |||
323 | dma_addr_t *dma_handle, gfp_t flag, | 323 | dma_addr_t *dma_handle, gfp_t flag, |
324 | struct dma_attrs *attrs) | 324 | struct dma_attrs *attrs) |
325 | { | 325 | { |
326 | struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev)); | 326 | struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); |
327 | struct page *page; | 327 | struct page *page; |
328 | unsigned long pa; | 328 | unsigned long pa; |
329 | dma_addr_t map; | 329 | dma_addr_t map; |
diff --git a/arch/s390/pci/pci_sysfs.c b/arch/s390/pci/pci_sysfs.c index a42cce69d0a0..e99a2557f186 100644 --- a/arch/s390/pci/pci_sysfs.c +++ b/arch/s390/pci/pci_sysfs.c | |||
@@ -15,40 +15,36 @@ | |||
15 | static ssize_t show_fid(struct device *dev, struct device_attribute *attr, | 15 | static ssize_t show_fid(struct device *dev, struct device_attribute *attr, |
16 | char *buf) | 16 | char *buf) |
17 | { | 17 | { |
18 | struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev)); | 18 | struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); |
19 | 19 | ||
20 | sprintf(buf, "0x%08x\n", zdev->fid); | 20 | return sprintf(buf, "0x%08x\n", zdev->fid); |
21 | return strlen(buf); | ||
22 | } | 21 | } |
23 | static DEVICE_ATTR(function_id, S_IRUGO, show_fid, NULL); | 22 | static DEVICE_ATTR(function_id, S_IRUGO, show_fid, NULL); |
24 | 23 | ||
25 | static ssize_t show_fh(struct device *dev, struct device_attribute *attr, | 24 | static ssize_t show_fh(struct device *dev, struct device_attribute *attr, |
26 | char *buf) | 25 | char *buf) |
27 | { | 26 | { |
28 | struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev)); | 27 | struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); |
29 | 28 | ||
30 | sprintf(buf, "0x%08x\n", zdev->fh); | 29 | return sprintf(buf, "0x%08x\n", zdev->fh); |
31 | return strlen(buf); | ||
32 | } | 30 | } |
33 | static DEVICE_ATTR(function_handle, S_IRUGO, show_fh, NULL); | 31 | static DEVICE_ATTR(function_handle, S_IRUGO, show_fh, NULL); |
34 | 32 | ||
35 | static ssize_t show_pchid(struct device *dev, struct device_attribute *attr, | 33 | static ssize_t show_pchid(struct device *dev, struct device_attribute *attr, |
36 | char *buf) | 34 | char *buf) |
37 | { | 35 | { |
38 | struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev)); | 36 | struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); |
39 | 37 | ||
40 | sprintf(buf, "0x%04x\n", zdev->pchid); | 38 | return sprintf(buf, "0x%04x\n", zdev->pchid); |
41 | return strlen(buf); | ||
42 | } | 39 | } |
43 | static DEVICE_ATTR(pchid, S_IRUGO, show_pchid, NULL); | 40 | static DEVICE_ATTR(pchid, S_IRUGO, show_pchid, NULL); |
44 | 41 | ||
45 | static ssize_t show_pfgid(struct device *dev, struct device_attribute *attr, | 42 | static ssize_t show_pfgid(struct device *dev, struct device_attribute *attr, |
46 | char *buf) | 43 | char *buf) |
47 | { | 44 | { |
48 | struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev)); | 45 | struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); |
49 | 46 | ||
50 | sprintf(buf, "0x%02x\n", zdev->pfgid); | 47 | return sprintf(buf, "0x%02x\n", zdev->pfgid); |
51 | return strlen(buf); | ||
52 | } | 48 | } |
53 | static DEVICE_ATTR(pfgid, S_IRUGO, show_pfgid, NULL); | 49 | static DEVICE_ATTR(pfgid, S_IRUGO, show_pfgid, NULL); |
54 | 50 | ||
diff --git a/block/blk-core.c b/block/blk-core.c index 0852e5d43436..93a18d1d3da8 100644 --- a/block/blk-core.c +++ b/block/blk-core.c | |||
@@ -2315,6 +2315,9 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes) | |||
2315 | case -EBADE: | 2315 | case -EBADE: |
2316 | error_type = "critical nexus"; | 2316 | error_type = "critical nexus"; |
2317 | break; | 2317 | break; |
2318 | case -ETIMEDOUT: | ||
2319 | error_type = "timeout"; | ||
2320 | break; | ||
2318 | case -EIO: | 2321 | case -EIO: |
2319 | default: | 2322 | default: |
2320 | error_type = "I/O"; | 2323 | error_type = "I/O"; |
diff --git a/block/blk-timeout.c b/block/blk-timeout.c index 6e4744cbfb56..65f103563969 100644 --- a/block/blk-timeout.c +++ b/block/blk-timeout.c | |||
@@ -82,9 +82,10 @@ void blk_delete_timer(struct request *req) | |||
82 | static void blk_rq_timed_out(struct request *req) | 82 | static void blk_rq_timed_out(struct request *req) |
83 | { | 83 | { |
84 | struct request_queue *q = req->q; | 84 | struct request_queue *q = req->q; |
85 | enum blk_eh_timer_return ret; | 85 | enum blk_eh_timer_return ret = BLK_EH_RESET_TIMER; |
86 | 86 | ||
87 | ret = q->rq_timed_out_fn(req); | 87 | if (q->rq_timed_out_fn) |
88 | ret = q->rq_timed_out_fn(req); | ||
88 | switch (ret) { | 89 | switch (ret) { |
89 | case BLK_EH_HANDLED: | 90 | case BLK_EH_HANDLED: |
90 | __blk_complete_request(req); | 91 | __blk_complete_request(req); |
diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c index 46a7b738f61f..ea3fa90d020a 100644 --- a/drivers/pci/hotplug/s390_pci_hpc.c +++ b/drivers/pci/hotplug/s390_pci_hpc.c | |||
@@ -41,6 +41,28 @@ struct slot { | |||
41 | struct zpci_dev *zdev; | 41 | struct zpci_dev *zdev; |
42 | }; | 42 | }; |
43 | 43 | ||
44 | static inline int slot_configure(struct slot *slot) | ||
45 | { | ||
46 | int ret = sclp_pci_configure(slot->zdev->fid); | ||
47 | |||
48 | zpci_dbg(3, "conf fid:%x, rc:%d\n", slot->zdev->fid, ret); | ||
49 | if (!ret) | ||
50 | slot->zdev->state = ZPCI_FN_STATE_CONFIGURED; | ||
51 | |||
52 | return ret; | ||
53 | } | ||
54 | |||
55 | static inline int slot_deconfigure(struct slot *slot) | ||
56 | { | ||
57 | int ret = sclp_pci_deconfigure(slot->zdev->fid); | ||
58 | |||
59 | zpci_dbg(3, "deconf fid:%x, rc:%d\n", slot->zdev->fid, ret); | ||
60 | if (!ret) | ||
61 | slot->zdev->state = ZPCI_FN_STATE_STANDBY; | ||
62 | |||
63 | return ret; | ||
64 | } | ||
65 | |||
44 | static int enable_slot(struct hotplug_slot *hotplug_slot) | 66 | static int enable_slot(struct hotplug_slot *hotplug_slot) |
45 | { | 67 | { |
46 | struct slot *slot = hotplug_slot->private; | 68 | struct slot *slot = hotplug_slot->private; |
@@ -49,14 +71,23 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) | |||
49 | if (slot->zdev->state != ZPCI_FN_STATE_STANDBY) | 71 | if (slot->zdev->state != ZPCI_FN_STATE_STANDBY) |
50 | return -EIO; | 72 | return -EIO; |
51 | 73 | ||
52 | rc = sclp_pci_configure(slot->zdev->fid); | 74 | rc = slot_configure(slot); |
53 | zpci_dbg(3, "conf fid:%x, rc:%d\n", slot->zdev->fid, rc); | 75 | if (rc) |
54 | if (!rc) { | 76 | return rc; |
55 | slot->zdev->state = ZPCI_FN_STATE_CONFIGURED; | 77 | |
56 | /* automatically scan the device after is was configured */ | 78 | rc = zpci_enable_device(slot->zdev); |
57 | zpci_enable_device(slot->zdev); | 79 | if (rc) |
58 | zpci_scan_device(slot->zdev); | 80 | goto out_deconfigure; |
59 | } | 81 | |
82 | slot->zdev->state = ZPCI_FN_STATE_ONLINE; | ||
83 | |||
84 | pci_scan_slot(slot->zdev->bus, ZPCI_DEVFN); | ||
85 | pci_bus_add_devices(slot->zdev->bus); | ||
86 | |||
87 | return rc; | ||
88 | |||
89 | out_deconfigure: | ||
90 | slot_deconfigure(slot); | ||
60 | return rc; | 91 | return rc; |
61 | } | 92 | } |
62 | 93 | ||
@@ -68,17 +99,14 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) | |||
68 | if (!zpci_fn_configured(slot->zdev->state)) | 99 | if (!zpci_fn_configured(slot->zdev->state)) |
69 | return -EIO; | 100 | return -EIO; |
70 | 101 | ||
102 | if (slot->zdev->pdev) | ||
103 | pci_stop_and_remove_bus_device(slot->zdev->pdev); | ||
104 | |||
71 | rc = zpci_disable_device(slot->zdev); | 105 | rc = zpci_disable_device(slot->zdev); |
72 | if (rc) | 106 | if (rc) |
73 | return rc; | 107 | return rc; |
74 | /* TODO: we rely on the user to unbind/remove the device, is that plausible | 108 | |
75 | * or do we need to trigger that here? | 109 | return slot_deconfigure(slot); |
76 | */ | ||
77 | rc = sclp_pci_deconfigure(slot->zdev->fid); | ||
78 | zpci_dbg(3, "deconf fid:%x, rc:%d\n", slot->zdev->fid, rc); | ||
79 | if (!rc) | ||
80 | slot->zdev->state = ZPCI_FN_STATE_STANDBY; | ||
81 | return rc; | ||
82 | } | 110 | } |
83 | 111 | ||
84 | static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) | 112 | static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index a899d8bb190d..95057a925d80 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -1335,6 +1335,16 @@ int __weak pcibios_add_device (struct pci_dev *dev) | |||
1335 | } | 1335 | } |
1336 | 1336 | ||
1337 | /** | 1337 | /** |
1338 | * pcibios_release_device - provide arch specific hooks when releasing device dev | ||
1339 | * @dev: the PCI device being released | ||
1340 | * | ||
1341 | * Permits the platform to provide architecture specific functionality when | ||
1342 | * devices are released. This is the default implementation. Architecture | ||
1343 | * implementations can override this. | ||
1344 | */ | ||
1345 | void __weak pcibios_release_device(struct pci_dev *dev) {} | ||
1346 | |||
1347 | /** | ||
1338 | * pcibios_disable_device - disable arch specific PCI resources for device dev | 1348 | * pcibios_disable_device - disable arch specific PCI resources for device dev |
1339 | * @dev: the PCI device to disable | 1349 | * @dev: the PCI device to disable |
1340 | * | 1350 | * |
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 70f10fa3c1b2..58cc0a8a0979 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -1132,6 +1132,7 @@ static void pci_release_dev(struct device *dev) | |||
1132 | pci_dev = to_pci_dev(dev); | 1132 | pci_dev = to_pci_dev(dev); |
1133 | pci_release_capabilities(pci_dev); | 1133 | pci_release_capabilities(pci_dev); |
1134 | pci_release_of_node(pci_dev); | 1134 | pci_release_of_node(pci_dev); |
1135 | pcibios_release_device(pci_dev); | ||
1135 | kfree(pci_dev); | 1136 | kfree(pci_dev); |
1136 | } | 1137 | } |
1137 | 1138 | ||
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index d72a9216ee2e..17150a778984 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -38,9 +38,6 @@ | |||
38 | */ | 38 | */ |
39 | #define DASD_CHANQ_MAX_SIZE 4 | 39 | #define DASD_CHANQ_MAX_SIZE 4 |
40 | 40 | ||
41 | #define DASD_SLEEPON_START_TAG (void *) 1 | ||
42 | #define DASD_SLEEPON_END_TAG (void *) 2 | ||
43 | |||
44 | /* | 41 | /* |
45 | * SECTION: exported variables of dasd.c | 42 | * SECTION: exported variables of dasd.c |
46 | */ | 43 | */ |
@@ -1787,11 +1784,11 @@ static void __dasd_device_process_ccw_queue(struct dasd_device *device, | |||
1787 | list_for_each_safe(l, n, &device->ccw_queue) { | 1784 | list_for_each_safe(l, n, &device->ccw_queue) { |
1788 | cqr = list_entry(l, struct dasd_ccw_req, devlist); | 1785 | cqr = list_entry(l, struct dasd_ccw_req, devlist); |
1789 | 1786 | ||
1790 | /* Stop list processing at the first non-final request. */ | 1787 | /* Skip any non-final request. */ |
1791 | if (cqr->status == DASD_CQR_QUEUED || | 1788 | if (cqr->status == DASD_CQR_QUEUED || |
1792 | cqr->status == DASD_CQR_IN_IO || | 1789 | cqr->status == DASD_CQR_IN_IO || |
1793 | cqr->status == DASD_CQR_CLEAR_PENDING) | 1790 | cqr->status == DASD_CQR_CLEAR_PENDING) |
1794 | break; | 1791 | continue; |
1795 | if (cqr->status == DASD_CQR_ERROR) { | 1792 | if (cqr->status == DASD_CQR_ERROR) { |
1796 | __dasd_device_recovery(device, cqr); | 1793 | __dasd_device_recovery(device, cqr); |
1797 | } | 1794 | } |
@@ -2183,7 +2180,7 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible) | |||
2183 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && | 2180 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && |
2184 | (!dasd_eer_enabled(device))) { | 2181 | (!dasd_eer_enabled(device))) { |
2185 | cqr->status = DASD_CQR_FAILED; | 2182 | cqr->status = DASD_CQR_FAILED; |
2186 | cqr->intrc = -EAGAIN; | 2183 | cqr->intrc = -ENOLINK; |
2187 | continue; | 2184 | continue; |
2188 | } | 2185 | } |
2189 | /* Don't try to start requests if device is stopped */ | 2186 | /* Don't try to start requests if device is stopped */ |
@@ -2402,8 +2399,7 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) | |||
2402 | * Cancels a request that was started with dasd_sleep_on_req. | 2399 | * Cancels a request that was started with dasd_sleep_on_req. |
2403 | * This is useful to timeout requests. The request will be | 2400 | * This is useful to timeout requests. The request will be |
2404 | * terminated if it is currently in i/o. | 2401 | * terminated if it is currently in i/o. |
2405 | * Returns 1 if the request has been terminated. | 2402 | * Returns 0 if request termination was successful |
2406 | * 0 if there was no need to terminate the request (not started yet) | ||
2407 | * negative error code if termination failed | 2403 | * negative error code if termination failed |
2408 | * Cancellation of a request is an asynchronous operation! The calling | 2404 | * Cancellation of a request is an asynchronous operation! The calling |
2409 | * function has to wait until the request is properly returned via callback. | 2405 | * function has to wait until the request is properly returned via callback. |
@@ -2440,7 +2436,6 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr) | |||
2440 | return rc; | 2436 | return rc; |
2441 | } | 2437 | } |
2442 | 2438 | ||
2443 | |||
2444 | /* | 2439 | /* |
2445 | * SECTION: Operations of the dasd_block layer. | 2440 | * SECTION: Operations of the dasd_block layer. |
2446 | */ | 2441 | */ |
@@ -2537,6 +2532,16 @@ static void __dasd_process_request_queue(struct dasd_block *block) | |||
2537 | __blk_end_request_all(req, -EIO); | 2532 | __blk_end_request_all(req, -EIO); |
2538 | continue; | 2533 | continue; |
2539 | } | 2534 | } |
2535 | if (test_bit(DASD_FLAG_ABORTALL, &basedev->flags) && | ||
2536 | (basedev->features & DASD_FEATURE_FAILFAST || | ||
2537 | blk_noretry_request(req))) { | ||
2538 | DBF_DEV_EVENT(DBF_ERR, basedev, | ||
2539 | "Rejecting failfast request %p", | ||
2540 | req); | ||
2541 | blk_start_request(req); | ||
2542 | __blk_end_request_all(req, -ETIMEDOUT); | ||
2543 | continue; | ||
2544 | } | ||
2540 | cqr = basedev->discipline->build_cp(basedev, block, req); | 2545 | cqr = basedev->discipline->build_cp(basedev, block, req); |
2541 | if (IS_ERR(cqr)) { | 2546 | if (IS_ERR(cqr)) { |
2542 | if (PTR_ERR(cqr) == -EBUSY) | 2547 | if (PTR_ERR(cqr) == -EBUSY) |
@@ -2575,8 +2580,10 @@ static void __dasd_process_request_queue(struct dasd_block *block) | |||
2575 | */ | 2580 | */ |
2576 | cqr->callback_data = (void *) req; | 2581 | cqr->callback_data = (void *) req; |
2577 | cqr->status = DASD_CQR_FILLED; | 2582 | cqr->status = DASD_CQR_FILLED; |
2583 | req->completion_data = cqr; | ||
2578 | blk_start_request(req); | 2584 | blk_start_request(req); |
2579 | list_add_tail(&cqr->blocklist, &block->ccw_queue); | 2585 | list_add_tail(&cqr->blocklist, &block->ccw_queue); |
2586 | INIT_LIST_HEAD(&cqr->devlist); | ||
2580 | dasd_profile_start(block, cqr, req); | 2587 | dasd_profile_start(block, cqr, req); |
2581 | } | 2588 | } |
2582 | } | 2589 | } |
@@ -2590,8 +2597,17 @@ static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr) | |||
2590 | req = (struct request *) cqr->callback_data; | 2597 | req = (struct request *) cqr->callback_data; |
2591 | dasd_profile_end(cqr->block, cqr, req); | 2598 | dasd_profile_end(cqr->block, cqr, req); |
2592 | status = cqr->block->base->discipline->free_cp(cqr, req); | 2599 | status = cqr->block->base->discipline->free_cp(cqr, req); |
2593 | if (status <= 0) | 2600 | if (status < 0) |
2594 | error = status ? status : -EIO; | 2601 | error = status; |
2602 | else if (status == 0) { | ||
2603 | if (cqr->intrc == -EPERM) | ||
2604 | error = -EBADE; | ||
2605 | else if (cqr->intrc == -ENOLINK || | ||
2606 | cqr->intrc == -ETIMEDOUT) | ||
2607 | error = cqr->intrc; | ||
2608 | else | ||
2609 | error = -EIO; | ||
2610 | } | ||
2595 | __blk_end_request_all(req, error); | 2611 | __blk_end_request_all(req, error); |
2596 | } | 2612 | } |
2597 | 2613 | ||
@@ -2692,6 +2708,7 @@ static void __dasd_block_start_head(struct dasd_block *block) | |||
2692 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && | 2708 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && |
2693 | (!dasd_eer_enabled(block->base))) { | 2709 | (!dasd_eer_enabled(block->base))) { |
2694 | cqr->status = DASD_CQR_FAILED; | 2710 | cqr->status = DASD_CQR_FAILED; |
2711 | cqr->intrc = -ENOLINK; | ||
2695 | dasd_schedule_block_bh(block); | 2712 | dasd_schedule_block_bh(block); |
2696 | continue; | 2713 | continue; |
2697 | } | 2714 | } |
@@ -2864,6 +2881,82 @@ static void do_dasd_request(struct request_queue *queue) | |||
2864 | } | 2881 | } |
2865 | 2882 | ||
2866 | /* | 2883 | /* |
2884 | * Block timeout callback, called from the block layer | ||
2885 | * | ||
2886 | * request_queue lock is held on entry. | ||
2887 | * | ||
2888 | * Return values: | ||
2889 | * BLK_EH_RESET_TIMER if the request should be left running | ||
2890 | * BLK_EH_NOT_HANDLED if the request is handled or terminated | ||
2891 | * by the driver. | ||
2892 | */ | ||
2893 | enum blk_eh_timer_return dasd_times_out(struct request *req) | ||
2894 | { | ||
2895 | struct dasd_ccw_req *cqr = req->completion_data; | ||
2896 | struct dasd_block *block = req->q->queuedata; | ||
2897 | struct dasd_device *device; | ||
2898 | int rc = 0; | ||
2899 | |||
2900 | if (!cqr) | ||
2901 | return BLK_EH_NOT_HANDLED; | ||
2902 | |||
2903 | device = cqr->startdev ? cqr->startdev : block->base; | ||
2904 | if (!device->blk_timeout) | ||
2905 | return BLK_EH_RESET_TIMER; | ||
2906 | DBF_DEV_EVENT(DBF_WARNING, device, | ||
2907 | " dasd_times_out cqr %p status %x", | ||
2908 | cqr, cqr->status); | ||
2909 | |||
2910 | spin_lock(&block->queue_lock); | ||
2911 | spin_lock(get_ccwdev_lock(device->cdev)); | ||
2912 | cqr->retries = -1; | ||
2913 | cqr->intrc = -ETIMEDOUT; | ||
2914 | if (cqr->status >= DASD_CQR_QUEUED) { | ||
2915 | spin_unlock(get_ccwdev_lock(device->cdev)); | ||
2916 | rc = dasd_cancel_req(cqr); | ||
2917 | } else if (cqr->status == DASD_CQR_FILLED || | ||
2918 | cqr->status == DASD_CQR_NEED_ERP) { | ||
2919 | cqr->status = DASD_CQR_TERMINATED; | ||
2920 | spin_unlock(get_ccwdev_lock(device->cdev)); | ||
2921 | } else if (cqr->status == DASD_CQR_IN_ERP) { | ||
2922 | struct dasd_ccw_req *searchcqr, *nextcqr, *tmpcqr; | ||
2923 | |||
2924 | list_for_each_entry_safe(searchcqr, nextcqr, | ||
2925 | &block->ccw_queue, blocklist) { | ||
2926 | tmpcqr = searchcqr; | ||
2927 | while (tmpcqr->refers) | ||
2928 | tmpcqr = tmpcqr->refers; | ||
2929 | if (tmpcqr != cqr) | ||
2930 | continue; | ||
2931 | /* searchcqr is an ERP request for cqr */ | ||
2932 | searchcqr->retries = -1; | ||
2933 | searchcqr->intrc = -ETIMEDOUT; | ||
2934 | if (searchcqr->status >= DASD_CQR_QUEUED) { | ||
2935 | spin_unlock(get_ccwdev_lock(device->cdev)); | ||
2936 | rc = dasd_cancel_req(searchcqr); | ||
2937 | spin_lock(get_ccwdev_lock(device->cdev)); | ||
2938 | } else if ((searchcqr->status == DASD_CQR_FILLED) || | ||
2939 | (searchcqr->status == DASD_CQR_NEED_ERP)) { | ||
2940 | searchcqr->status = DASD_CQR_TERMINATED; | ||
2941 | rc = 0; | ||
2942 | } else if (searchcqr->status == DASD_CQR_IN_ERP) { | ||
2943 | /* | ||
2944 | * Shouldn't happen; most recent ERP | ||
2945 | * request is at the front of queue | ||
2946 | */ | ||
2947 | continue; | ||
2948 | } | ||
2949 | break; | ||
2950 | } | ||
2951 | spin_unlock(get_ccwdev_lock(device->cdev)); | ||
2952 | } | ||
2953 | dasd_schedule_block_bh(block); | ||
2954 | spin_unlock(&block->queue_lock); | ||
2955 | |||
2956 | return rc ? BLK_EH_RESET_TIMER : BLK_EH_NOT_HANDLED; | ||
2957 | } | ||
2958 | |||
2959 | /* | ||
2867 | * Allocate and initialize request queue and default I/O scheduler. | 2960 | * Allocate and initialize request queue and default I/O scheduler. |
2868 | */ | 2961 | */ |
2869 | static int dasd_alloc_queue(struct dasd_block *block) | 2962 | static int dasd_alloc_queue(struct dasd_block *block) |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index a71bb8aaca1d..58bc6eb49de1 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
@@ -1240,6 +1240,101 @@ dasd_expires_store(struct device *dev, struct device_attribute *attr, | |||
1240 | 1240 | ||
1241 | static DEVICE_ATTR(expires, 0644, dasd_expires_show, dasd_expires_store); | 1241 | static DEVICE_ATTR(expires, 0644, dasd_expires_show, dasd_expires_store); |
1242 | 1242 | ||
1243 | static ssize_t | ||
1244 | dasd_retries_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
1245 | { | ||
1246 | struct dasd_device *device; | ||
1247 | int len; | ||
1248 | |||
1249 | device = dasd_device_from_cdev(to_ccwdev(dev)); | ||
1250 | if (IS_ERR(device)) | ||
1251 | return -ENODEV; | ||
1252 | len = snprintf(buf, PAGE_SIZE, "%lu\n", device->default_retries); | ||
1253 | dasd_put_device(device); | ||
1254 | return len; | ||
1255 | } | ||
1256 | |||
1257 | static ssize_t | ||
1258 | dasd_retries_store(struct device *dev, struct device_attribute *attr, | ||
1259 | const char *buf, size_t count) | ||
1260 | { | ||
1261 | struct dasd_device *device; | ||
1262 | unsigned long val; | ||
1263 | |||
1264 | device = dasd_device_from_cdev(to_ccwdev(dev)); | ||
1265 | if (IS_ERR(device)) | ||
1266 | return -ENODEV; | ||
1267 | |||
1268 | if ((strict_strtoul(buf, 10, &val) != 0) || | ||
1269 | (val > DASD_RETRIES_MAX)) { | ||
1270 | dasd_put_device(device); | ||
1271 | return -EINVAL; | ||
1272 | } | ||
1273 | |||
1274 | if (val) | ||
1275 | device->default_retries = val; | ||
1276 | |||
1277 | dasd_put_device(device); | ||
1278 | return count; | ||
1279 | } | ||
1280 | |||
1281 | static DEVICE_ATTR(retries, 0644, dasd_retries_show, dasd_retries_store); | ||
1282 | |||
1283 | static ssize_t | ||
1284 | dasd_timeout_show(struct device *dev, struct device_attribute *attr, | ||
1285 | char *buf) | ||
1286 | { | ||
1287 | struct dasd_device *device; | ||
1288 | int len; | ||
1289 | |||
1290 | device = dasd_device_from_cdev(to_ccwdev(dev)); | ||
1291 | if (IS_ERR(device)) | ||
1292 | return -ENODEV; | ||
1293 | len = snprintf(buf, PAGE_SIZE, "%lu\n", device->blk_timeout); | ||
1294 | dasd_put_device(device); | ||
1295 | return len; | ||
1296 | } | ||
1297 | |||
1298 | static ssize_t | ||
1299 | dasd_timeout_store(struct device *dev, struct device_attribute *attr, | ||
1300 | const char *buf, size_t count) | ||
1301 | { | ||
1302 | struct dasd_device *device; | ||
1303 | struct request_queue *q; | ||
1304 | unsigned long val, flags; | ||
1305 | |||
1306 | device = dasd_device_from_cdev(to_ccwdev(dev)); | ||
1307 | if (IS_ERR(device) || !device->block) | ||
1308 | return -ENODEV; | ||
1309 | |||
1310 | if ((strict_strtoul(buf, 10, &val) != 0) || | ||
1311 | val > UINT_MAX / HZ) { | ||
1312 | dasd_put_device(device); | ||
1313 | return -EINVAL; | ||
1314 | } | ||
1315 | q = device->block->request_queue; | ||
1316 | if (!q) { | ||
1317 | dasd_put_device(device); | ||
1318 | return -ENODEV; | ||
1319 | } | ||
1320 | spin_lock_irqsave(&device->block->request_queue_lock, flags); | ||
1321 | if (!val) | ||
1322 | blk_queue_rq_timed_out(q, NULL); | ||
1323 | else | ||
1324 | blk_queue_rq_timed_out(q, dasd_times_out); | ||
1325 | |||
1326 | device->blk_timeout = val; | ||
1327 | |||
1328 | blk_queue_rq_timeout(q, device->blk_timeout * HZ); | ||
1329 | spin_unlock_irqrestore(&device->block->request_queue_lock, flags); | ||
1330 | |||
1331 | dasd_put_device(device); | ||
1332 | return count; | ||
1333 | } | ||
1334 | |||
1335 | static DEVICE_ATTR(timeout, 0644, | ||
1336 | dasd_timeout_show, dasd_timeout_store); | ||
1337 | |||
1243 | static ssize_t dasd_reservation_policy_show(struct device *dev, | 1338 | static ssize_t dasd_reservation_policy_show(struct device *dev, |
1244 | struct device_attribute *attr, | 1339 | struct device_attribute *attr, |
1245 | char *buf) | 1340 | char *buf) |
@@ -1350,6 +1445,8 @@ static struct attribute * dasd_attrs[] = { | |||
1350 | &dev_attr_erplog.attr, | 1445 | &dev_attr_erplog.attr, |
1351 | &dev_attr_failfast.attr, | 1446 | &dev_attr_failfast.attr, |
1352 | &dev_attr_expires.attr, | 1447 | &dev_attr_expires.attr, |
1448 | &dev_attr_retries.attr, | ||
1449 | &dev_attr_timeout.attr, | ||
1353 | &dev_attr_reservation_policy.attr, | 1450 | &dev_attr_reservation_policy.attr, |
1354 | &dev_attr_last_known_reservation_state.attr, | 1451 | &dev_attr_last_known_reservation_state.attr, |
1355 | &dev_attr_safe_offline.attr, | 1452 | &dev_attr_safe_offline.attr, |
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index cc0603358522..feca317b33de 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c | |||
@@ -359,6 +359,7 @@ dasd_diag_check_device(struct dasd_device *device) | |||
359 | } | 359 | } |
360 | 360 | ||
361 | device->default_expires = DIAG_TIMEOUT; | 361 | device->default_expires = DIAG_TIMEOUT; |
362 | device->default_retries = DIAG_MAX_RETRIES; | ||
362 | 363 | ||
363 | /* Figure out position of label block */ | 364 | /* Figure out position of label block */ |
364 | switch (private->rdc_data.vdev_class) { | 365 | switch (private->rdc_data.vdev_class) { |
@@ -555,7 +556,7 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev, | |||
555 | recid++; | 556 | recid++; |
556 | } | 557 | } |
557 | } | 558 | } |
558 | cqr->retries = DIAG_MAX_RETRIES; | 559 | cqr->retries = memdev->default_retries; |
559 | cqr->buildclk = get_tod_clock(); | 560 | cqr->buildclk = get_tod_clock(); |
560 | if (blk_noretry_request(req) || | 561 | if (blk_noretry_request(req) || |
561 | block->base->features & DASD_FEATURE_FAILFAST) | 562 | block->base->features & DASD_FEATURE_FAILFAST) |
@@ -582,7 +583,10 @@ dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req) | |||
582 | 583 | ||
583 | static void dasd_diag_handle_terminated_request(struct dasd_ccw_req *cqr) | 584 | static void dasd_diag_handle_terminated_request(struct dasd_ccw_req *cqr) |
584 | { | 585 | { |
585 | cqr->status = DASD_CQR_FILLED; | 586 | if (cqr->retries < 0) |
587 | cqr->status = DASD_CQR_FAILED; | ||
588 | else | ||
589 | cqr->status = DASD_CQR_FILLED; | ||
586 | }; | 590 | }; |
587 | 591 | ||
588 | /* Fill in IOCTL data for device. */ | 592 | /* Fill in IOCTL data for device. */ |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 6a44b27623ed..e61a6deea3c0 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -1682,6 +1682,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
1682 | 1682 | ||
1683 | /* set default timeout */ | 1683 | /* set default timeout */ |
1684 | device->default_expires = DASD_EXPIRES; | 1684 | device->default_expires = DASD_EXPIRES; |
1685 | /* set default retry count */ | ||
1686 | device->default_retries = DASD_RETRIES; | ||
1687 | |||
1685 | if (private->gneq) { | 1688 | if (private->gneq) { |
1686 | value = 1; | 1689 | value = 1; |
1687 | for (i = 0; i < private->gneq->timeout.value; i++) | 1690 | for (i = 0; i < private->gneq->timeout.value; i++) |
@@ -2378,6 +2381,10 @@ sleep: | |||
2378 | 2381 | ||
2379 | static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr) | 2382 | static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr) |
2380 | { | 2383 | { |
2384 | if (cqr->retries < 0) { | ||
2385 | cqr->status = DASD_CQR_FAILED; | ||
2386 | return; | ||
2387 | } | ||
2381 | cqr->status = DASD_CQR_FILLED; | 2388 | cqr->status = DASD_CQR_FILLED; |
2382 | if (cqr->block && (cqr->startdev != cqr->block->base)) { | 2389 | if (cqr->block && (cqr->startdev != cqr->block->base)) { |
2383 | dasd_eckd_reset_ccw_to_base_io(cqr); | 2390 | dasd_eckd_reset_ccw_to_base_io(cqr); |
@@ -2659,7 +2666,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( | |||
2659 | cqr->block = block; | 2666 | cqr->block = block; |
2660 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ | 2667 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ |
2661 | cqr->lpm = startdev->path_data.ppm; | 2668 | cqr->lpm = startdev->path_data.ppm; |
2662 | cqr->retries = 256; | 2669 | cqr->retries = startdev->default_retries; |
2663 | cqr->buildclk = get_tod_clock(); | 2670 | cqr->buildclk = get_tod_clock(); |
2664 | cqr->status = DASD_CQR_FILLED; | 2671 | cqr->status = DASD_CQR_FILLED; |
2665 | return cqr; | 2672 | return cqr; |
@@ -2834,7 +2841,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( | |||
2834 | cqr->block = block; | 2841 | cqr->block = block; |
2835 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ | 2842 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ |
2836 | cqr->lpm = startdev->path_data.ppm; | 2843 | cqr->lpm = startdev->path_data.ppm; |
2837 | cqr->retries = 256; | 2844 | cqr->retries = startdev->default_retries; |
2838 | cqr->buildclk = get_tod_clock(); | 2845 | cqr->buildclk = get_tod_clock(); |
2839 | cqr->status = DASD_CQR_FILLED; | 2846 | cqr->status = DASD_CQR_FILLED; |
2840 | return cqr; | 2847 | return cqr; |
@@ -2968,7 +2975,7 @@ static int prepare_itcw(struct itcw *itcw, | |||
2968 | 2975 | ||
2969 | dcw = itcw_add_dcw(itcw, pfx_cmd, 0, | 2976 | dcw = itcw_add_dcw(itcw, pfx_cmd, 0, |
2970 | &pfxdata, sizeof(pfxdata), total_data_size); | 2977 | &pfxdata, sizeof(pfxdata), total_data_size); |
2971 | return IS_ERR(dcw) ? PTR_ERR(dcw) : 0; | 2978 | return PTR_RET(dcw); |
2972 | } | 2979 | } |
2973 | 2980 | ||
2974 | static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( | 2981 | static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( |
@@ -3127,7 +3134,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( | |||
3127 | cqr->block = block; | 3134 | cqr->block = block; |
3128 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ | 3135 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ |
3129 | cqr->lpm = startdev->path_data.ppm; | 3136 | cqr->lpm = startdev->path_data.ppm; |
3130 | cqr->retries = 256; | 3137 | cqr->retries = startdev->default_retries; |
3131 | cqr->buildclk = get_tod_clock(); | 3138 | cqr->buildclk = get_tod_clock(); |
3132 | cqr->status = DASD_CQR_FILLED; | 3139 | cqr->status = DASD_CQR_FILLED; |
3133 | return cqr; | 3140 | return cqr; |
@@ -3330,7 +3337,7 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev, | |||
3330 | cqr->block = block; | 3337 | cqr->block = block; |
3331 | cqr->expires = startdev->default_expires * HZ; | 3338 | cqr->expires = startdev->default_expires * HZ; |
3332 | cqr->lpm = startdev->path_data.ppm; | 3339 | cqr->lpm = startdev->path_data.ppm; |
3333 | cqr->retries = 256; | 3340 | cqr->retries = startdev->default_retries; |
3334 | cqr->buildclk = get_tod_clock(); | 3341 | cqr->buildclk = get_tod_clock(); |
3335 | cqr->status = DASD_CQR_FILLED; | 3342 | cqr->status = DASD_CQR_FILLED; |
3336 | 3343 | ||
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index 3250cb471f78..8d11f773a752 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c | |||
@@ -159,6 +159,14 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb) | |||
159 | struct dasd_device *device; | 159 | struct dasd_device *device; |
160 | 160 | ||
161 | device = cqr->startdev; | 161 | device = cqr->startdev; |
162 | if (cqr->intrc == -ETIMEDOUT) { | ||
163 | dev_err(&device->cdev->dev, "cqr %p timeout error", cqr); | ||
164 | return; | ||
165 | } | ||
166 | if (cqr->intrc == -ENOLINK) { | ||
167 | dev_err(&device->cdev->dev, "cqr %p transport error", cqr); | ||
168 | return; | ||
169 | } | ||
162 | /* dump sense data */ | 170 | /* dump sense data */ |
163 | if (device->discipline && device->discipline->dump_sense) | 171 | if (device->discipline && device->discipline->dump_sense) |
164 | device->discipline->dump_sense(device, cqr, irb); | 172 | device->discipline->dump_sense(device, cqr, irb); |
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 4dd0e2f6047e..9cbc8c32ba59 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #endif /* PRINTK_HEADER */ | 29 | #endif /* PRINTK_HEADER */ |
30 | #define PRINTK_HEADER "dasd(fba):" | 30 | #define PRINTK_HEADER "dasd(fba):" |
31 | 31 | ||
32 | #define FBA_DEFAULT_RETRIES 32 | ||
33 | |||
32 | #define DASD_FBA_CCW_WRITE 0x41 | 34 | #define DASD_FBA_CCW_WRITE 0x41 |
33 | #define DASD_FBA_CCW_READ 0x42 | 35 | #define DASD_FBA_CCW_READ 0x42 |
34 | #define DASD_FBA_CCW_LOCATE 0x43 | 36 | #define DASD_FBA_CCW_LOCATE 0x43 |
@@ -167,6 +169,7 @@ dasd_fba_check_characteristics(struct dasd_device *device) | |||
167 | } | 169 | } |
168 | 170 | ||
169 | device->default_expires = DASD_EXPIRES; | 171 | device->default_expires = DASD_EXPIRES; |
172 | device->default_retries = FBA_DEFAULT_RETRIES; | ||
170 | device->path_data.opm = LPM_ANYPATH; | 173 | device->path_data.opm = LPM_ANYPATH; |
171 | 174 | ||
172 | readonly = dasd_device_is_ro(device); | 175 | readonly = dasd_device_is_ro(device); |
@@ -369,7 +372,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, | |||
369 | cqr->memdev = memdev; | 372 | cqr->memdev = memdev; |
370 | cqr->block = block; | 373 | cqr->block = block; |
371 | cqr->expires = memdev->default_expires * HZ; /* default 5 minutes */ | 374 | cqr->expires = memdev->default_expires * HZ; /* default 5 minutes */ |
372 | cqr->retries = 32; | 375 | cqr->retries = memdev->default_retries; |
373 | cqr->buildclk = get_tod_clock(); | 376 | cqr->buildclk = get_tod_clock(); |
374 | cqr->status = DASD_CQR_FILLED; | 377 | cqr->status = DASD_CQR_FILLED; |
375 | return cqr; | 378 | return cqr; |
@@ -425,7 +428,10 @@ out: | |||
425 | 428 | ||
426 | static void dasd_fba_handle_terminated_request(struct dasd_ccw_req *cqr) | 429 | static void dasd_fba_handle_terminated_request(struct dasd_ccw_req *cqr) |
427 | { | 430 | { |
428 | cqr->status = DASD_CQR_FILLED; | 431 | if (cqr->retries < 0) |
432 | cqr->status = DASD_CQR_FAILED; | ||
433 | else | ||
434 | cqr->status = DASD_CQR_FILLED; | ||
429 | }; | 435 | }; |
430 | 436 | ||
431 | static int | 437 | static int |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 0785bd9bd5b6..690001af0d09 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
@@ -224,6 +224,8 @@ struct dasd_ccw_req { | |||
224 | /* default expiration time*/ | 224 | /* default expiration time*/ |
225 | #define DASD_EXPIRES 300 | 225 | #define DASD_EXPIRES 300 |
226 | #define DASD_EXPIRES_MAX 40000000 | 226 | #define DASD_EXPIRES_MAX 40000000 |
227 | #define DASD_RETRIES 256 | ||
228 | #define DASD_RETRIES_MAX 32768 | ||
227 | 229 | ||
228 | /* per dasd_ccw_req flags */ | 230 | /* per dasd_ccw_req flags */ |
229 | #define DASD_CQR_FLAGS_USE_ERP 0 /* use ERP for this request */ | 231 | #define DASD_CQR_FLAGS_USE_ERP 0 /* use ERP for this request */ |
@@ -466,6 +468,9 @@ struct dasd_device { | |||
466 | 468 | ||
467 | /* default expiration time in s */ | 469 | /* default expiration time in s */ |
468 | unsigned long default_expires; | 470 | unsigned long default_expires; |
471 | unsigned long default_retries; | ||
472 | |||
473 | unsigned long blk_timeout; | ||
469 | 474 | ||
470 | struct dentry *debugfs_dentry; | 475 | struct dentry *debugfs_dentry; |
471 | struct dasd_profile profile; | 476 | struct dasd_profile profile; |
@@ -519,7 +524,10 @@ struct dasd_block { | |||
519 | #define DASD_FLAG_SUSPENDED 9 /* The device was suspended */ | 524 | #define DASD_FLAG_SUSPENDED 9 /* The device was suspended */ |
520 | #define DASD_FLAG_SAFE_OFFLINE 10 /* safe offline processing requested*/ | 525 | #define DASD_FLAG_SAFE_OFFLINE 10 /* safe offline processing requested*/ |
521 | #define DASD_FLAG_SAFE_OFFLINE_RUNNING 11 /* safe offline running */ | 526 | #define DASD_FLAG_SAFE_OFFLINE_RUNNING 11 /* safe offline running */ |
527 | #define DASD_FLAG_ABORTALL 12 /* Abort all noretry requests */ | ||
522 | 528 | ||
529 | #define DASD_SLEEPON_START_TAG ((void *) 1) | ||
530 | #define DASD_SLEEPON_END_TAG ((void *) 2) | ||
523 | 531 | ||
524 | void dasd_put_device_wake(struct dasd_device *); | 532 | void dasd_put_device_wake(struct dasd_device *); |
525 | 533 | ||
@@ -660,6 +668,8 @@ void dasd_free_device(struct dasd_device *); | |||
660 | struct dasd_block *dasd_alloc_block(void); | 668 | struct dasd_block *dasd_alloc_block(void); |
661 | void dasd_free_block(struct dasd_block *); | 669 | void dasd_free_block(struct dasd_block *); |
662 | 670 | ||
671 | enum blk_eh_timer_return dasd_times_out(struct request *req); | ||
672 | |||
663 | void dasd_enable_device(struct dasd_device *); | 673 | void dasd_enable_device(struct dasd_device *); |
664 | void dasd_set_target_state(struct dasd_device *, int); | 674 | void dasd_set_target_state(struct dasd_device *, int); |
665 | void dasd_kick_device(struct dasd_device *); | 675 | void dasd_kick_device(struct dasd_device *); |
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 8be1b51e9311..25a0f2f8b0b9 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c | |||
@@ -141,6 +141,59 @@ static int dasd_ioctl_resume(struct dasd_block *block) | |||
141 | } | 141 | } |
142 | 142 | ||
143 | /* | 143 | /* |
144 | * Abort all failfast I/O on a device. | ||
145 | */ | ||
146 | static int dasd_ioctl_abortio(struct dasd_block *block) | ||
147 | { | ||
148 | unsigned long flags; | ||
149 | struct dasd_device *base; | ||
150 | struct dasd_ccw_req *cqr, *n; | ||
151 | |||
152 | base = block->base; | ||
153 | if (!capable(CAP_SYS_ADMIN)) | ||
154 | return -EACCES; | ||
155 | |||
156 | if (test_and_set_bit(DASD_FLAG_ABORTALL, &base->flags)) | ||
157 | return 0; | ||
158 | DBF_DEV_EVENT(DBF_NOTICE, base, "%s", "abortall flag set"); | ||
159 | |||
160 | spin_lock_irqsave(&block->request_queue_lock, flags); | ||
161 | spin_lock(&block->queue_lock); | ||
162 | list_for_each_entry_safe(cqr, n, &block->ccw_queue, blocklist) { | ||
163 | if (test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && | ||
164 | cqr->callback_data && | ||
165 | cqr->callback_data != DASD_SLEEPON_START_TAG && | ||
166 | cqr->callback_data != DASD_SLEEPON_END_TAG) { | ||
167 | spin_unlock(&block->queue_lock); | ||
168 | blk_abort_request(cqr->callback_data); | ||
169 | spin_lock(&block->queue_lock); | ||
170 | } | ||
171 | } | ||
172 | spin_unlock(&block->queue_lock); | ||
173 | spin_unlock_irqrestore(&block->request_queue_lock, flags); | ||
174 | |||
175 | dasd_schedule_block_bh(block); | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | /* | ||
180 | * Allow I/O on a device | ||
181 | */ | ||
182 | static int dasd_ioctl_allowio(struct dasd_block *block) | ||
183 | { | ||
184 | struct dasd_device *base; | ||
185 | |||
186 | base = block->base; | ||
187 | if (!capable(CAP_SYS_ADMIN)) | ||
188 | return -EACCES; | ||
189 | |||
190 | if (test_and_clear_bit(DASD_FLAG_ABORTALL, &base->flags)) | ||
191 | DBF_DEV_EVENT(DBF_NOTICE, base, "%s", "abortall flag unset"); | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | /* | ||
144 | * performs formatting of _device_ according to _fdata_ | 197 | * performs formatting of _device_ according to _fdata_ |
145 | * Note: The discipline's format_function is assumed to deliver formatting | 198 | * Note: The discipline's format_function is assumed to deliver formatting |
146 | * commands to format multiple units of the device. In terms of the ECKD | 199 | * commands to format multiple units of the device. In terms of the ECKD |
@@ -458,6 +511,12 @@ int dasd_ioctl(struct block_device *bdev, fmode_t mode, | |||
458 | case BIODASDRESUME: | 511 | case BIODASDRESUME: |
459 | rc = dasd_ioctl_resume(block); | 512 | rc = dasd_ioctl_resume(block); |
460 | break; | 513 | break; |
514 | case BIODASDABORTIO: | ||
515 | rc = dasd_ioctl_abortio(block); | ||
516 | break; | ||
517 | case BIODASDALLOWIO: | ||
518 | rc = dasd_ioctl_allowio(block); | ||
519 | break; | ||
461 | case BIODASDFMT: | 520 | case BIODASDFMT: |
462 | rc = dasd_ioctl_format(bdev, argp); | 521 | rc = dasd_ioctl_format(bdev, argp); |
463 | break; | 522 | break; |
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index f3c325207445..17821a026c9c 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ | 5 | obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ |
6 | sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o | 6 | sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o |
7 | 7 | ||
8 | obj-$(CONFIG_TN3270) += raw3270.o | 8 | obj-$(CONFIG_TN3270) += raw3270.o |
9 | obj-$(CONFIG_TN3270_CONSOLE) += con3270.o | 9 | obj-$(CONFIG_TN3270_CONSOLE) += con3270.o |
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index bd6871bf545a..3e4fb4e858da 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c | |||
@@ -50,11 +50,42 @@ static char sclp_init_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); | |||
50 | /* Suspend request */ | 50 | /* Suspend request */ |
51 | static DECLARE_COMPLETION(sclp_request_queue_flushed); | 51 | static DECLARE_COMPLETION(sclp_request_queue_flushed); |
52 | 52 | ||
53 | /* Number of console pages to allocate, used by sclp_con.c and sclp_vt220.c */ | ||
54 | int sclp_console_pages = SCLP_CONSOLE_PAGES; | ||
55 | /* Flag to indicate if buffer pages are dropped on buffer full condition */ | ||
56 | int sclp_console_drop = 0; | ||
57 | /* Number of times the console dropped buffer pages */ | ||
58 | unsigned long sclp_console_full; | ||
59 | |||
53 | static void sclp_suspend_req_cb(struct sclp_req *req, void *data) | 60 | static void sclp_suspend_req_cb(struct sclp_req *req, void *data) |
54 | { | 61 | { |
55 | complete(&sclp_request_queue_flushed); | 62 | complete(&sclp_request_queue_flushed); |
56 | } | 63 | } |
57 | 64 | ||
65 | static int __init sclp_setup_console_pages(char *str) | ||
66 | { | ||
67 | int pages, rc; | ||
68 | |||
69 | rc = kstrtoint(str, 0, &pages); | ||
70 | if (!rc && pages >= SCLP_CONSOLE_PAGES) | ||
71 | sclp_console_pages = pages; | ||
72 | return 1; | ||
73 | } | ||
74 | |||
75 | __setup("sclp_con_pages=", sclp_setup_console_pages); | ||
76 | |||
77 | static int __init sclp_setup_console_drop(char *str) | ||
78 | { | ||
79 | int drop, rc; | ||
80 | |||
81 | rc = kstrtoint(str, 0, &drop); | ||
82 | if (!rc && drop) | ||
83 | sclp_console_drop = 1; | ||
84 | return 1; | ||
85 | } | ||
86 | |||
87 | __setup("sclp_con_drop=", sclp_setup_console_drop); | ||
88 | |||
58 | static struct sclp_req sclp_suspend_req; | 89 | static struct sclp_req sclp_suspend_req; |
59 | 90 | ||
60 | /* Timer for request retries. */ | 91 | /* Timer for request retries. */ |
@@ -117,14 +148,19 @@ static int sclp_init(void); | |||
117 | int | 148 | int |
118 | sclp_service_call(sclp_cmdw_t command, void *sccb) | 149 | sclp_service_call(sclp_cmdw_t command, void *sccb) |
119 | { | 150 | { |
120 | int cc; | 151 | int cc = 4; /* Initialize for program check handling */ |
121 | 152 | ||
122 | asm volatile( | 153 | asm volatile( |
123 | " .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */ | 154 | "0: .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */ |
124 | " ipm %0\n" | 155 | "1: ipm %0\n" |
125 | " srl %0,28" | 156 | " srl %0,28\n" |
126 | : "=&d" (cc) : "d" (command), "a" (__pa(sccb)) | 157 | "2:\n" |
158 | EX_TABLE(0b, 2b) | ||
159 | EX_TABLE(1b, 2b) | ||
160 | : "+&d" (cc) : "d" (command), "a" (__pa(sccb)) | ||
127 | : "cc", "memory"); | 161 | : "cc", "memory"); |
162 | if (cc == 4) | ||
163 | return -EINVAL; | ||
128 | if (cc == 3) | 164 | if (cc == 3) |
129 | return -EIO; | 165 | return -EIO; |
130 | if (cc == 2) | 166 | if (cc == 2) |
@@ -1013,11 +1049,47 @@ static const struct dev_pm_ops sclp_pm_ops = { | |||
1013 | .restore = sclp_restore, | 1049 | .restore = sclp_restore, |
1014 | }; | 1050 | }; |
1015 | 1051 | ||
1052 | static ssize_t sclp_show_console_pages(struct device_driver *dev, char *buf) | ||
1053 | { | ||
1054 | return sprintf(buf, "%i\n", sclp_console_pages); | ||
1055 | } | ||
1056 | |||
1057 | static DRIVER_ATTR(con_pages, S_IRUSR, sclp_show_console_pages, NULL); | ||
1058 | |||
1059 | static ssize_t sclp_show_con_drop(struct device_driver *dev, char *buf) | ||
1060 | { | ||
1061 | return sprintf(buf, "%i\n", sclp_console_drop); | ||
1062 | } | ||
1063 | |||
1064 | static DRIVER_ATTR(con_drop, S_IRUSR, sclp_show_con_drop, NULL); | ||
1065 | |||
1066 | static ssize_t sclp_show_console_full(struct device_driver *dev, char *buf) | ||
1067 | { | ||
1068 | return sprintf(buf, "%lu\n", sclp_console_full); | ||
1069 | } | ||
1070 | |||
1071 | static DRIVER_ATTR(con_full, S_IRUSR, sclp_show_console_full, NULL); | ||
1072 | |||
1073 | static struct attribute *sclp_drv_attrs[] = { | ||
1074 | &driver_attr_con_pages.attr, | ||
1075 | &driver_attr_con_drop.attr, | ||
1076 | &driver_attr_con_full.attr, | ||
1077 | NULL, | ||
1078 | }; | ||
1079 | static struct attribute_group sclp_drv_attr_group = { | ||
1080 | .attrs = sclp_drv_attrs, | ||
1081 | }; | ||
1082 | static const struct attribute_group *sclp_drv_attr_groups[] = { | ||
1083 | &sclp_drv_attr_group, | ||
1084 | NULL, | ||
1085 | }; | ||
1086 | |||
1016 | static struct platform_driver sclp_pdrv = { | 1087 | static struct platform_driver sclp_pdrv = { |
1017 | .driver = { | 1088 | .driver = { |
1018 | .name = "sclp", | 1089 | .name = "sclp", |
1019 | .owner = THIS_MODULE, | 1090 | .owner = THIS_MODULE, |
1020 | .pm = &sclp_pm_ops, | 1091 | .pm = &sclp_pm_ops, |
1092 | .groups = sclp_drv_attr_groups, | ||
1021 | }, | 1093 | }, |
1022 | }; | 1094 | }; |
1023 | 1095 | ||
@@ -1096,10 +1168,12 @@ static __init int sclp_initcall(void) | |||
1096 | rc = platform_driver_register(&sclp_pdrv); | 1168 | rc = platform_driver_register(&sclp_pdrv); |
1097 | if (rc) | 1169 | if (rc) |
1098 | return rc; | 1170 | return rc; |
1171 | |||
1099 | sclp_pdev = platform_device_register_simple("sclp", -1, NULL, 0); | 1172 | sclp_pdev = platform_device_register_simple("sclp", -1, NULL, 0); |
1100 | rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0; | 1173 | rc = PTR_RET(sclp_pdev); |
1101 | if (rc) | 1174 | if (rc) |
1102 | goto fail_platform_driver_unregister; | 1175 | goto fail_platform_driver_unregister; |
1176 | |||
1103 | rc = atomic_notifier_chain_register(&panic_notifier_list, | 1177 | rc = atomic_notifier_chain_register(&panic_notifier_list, |
1104 | &sclp_on_panic_nb); | 1178 | &sclp_on_panic_nb); |
1105 | if (rc) | 1179 | if (rc) |
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 25bcd4c0ed82..40d1406289ed 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h | |||
@@ -15,7 +15,7 @@ | |||
15 | 15 | ||
16 | /* maximum number of pages concerning our own memory management */ | 16 | /* maximum number of pages concerning our own memory management */ |
17 | #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3) | 17 | #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3) |
18 | #define MAX_CONSOLE_PAGES 6 | 18 | #define SCLP_CONSOLE_PAGES 6 |
19 | 19 | ||
20 | #define EVTYP_OPCMD 0x01 | 20 | #define EVTYP_OPCMD 0x01 |
21 | #define EVTYP_MSG 0x02 | 21 | #define EVTYP_MSG 0x02 |
@@ -171,10 +171,15 @@ int sclp_remove_processed(struct sccb_header *sccb); | |||
171 | int sclp_deactivate(void); | 171 | int sclp_deactivate(void); |
172 | int sclp_reactivate(void); | 172 | int sclp_reactivate(void); |
173 | int sclp_service_call(sclp_cmdw_t command, void *sccb); | 173 | int sclp_service_call(sclp_cmdw_t command, void *sccb); |
174 | int sclp_sync_request(sclp_cmdw_t command, void *sccb); | ||
174 | 175 | ||
175 | int sclp_sdias_init(void); | 176 | int sclp_sdias_init(void); |
176 | void sclp_sdias_exit(void); | 177 | void sclp_sdias_exit(void); |
177 | 178 | ||
179 | extern int sclp_console_pages; | ||
180 | extern int sclp_console_drop; | ||
181 | extern unsigned long sclp_console_full; | ||
182 | |||
178 | /* useful inlines */ | 183 | /* useful inlines */ |
179 | 184 | ||
180 | /* VM uses EBCDIC 037, LPAR+native(SE+HMC) use EBCDIC 500 */ | 185 | /* VM uses EBCDIC 037, LPAR+native(SE+HMC) use EBCDIC 500 */ |
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index bf07c3a188d4..8cd34bf644b3 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c | |||
@@ -195,7 +195,7 @@ static void sclp_sync_callback(struct sclp_req *req, void *data) | |||
195 | complete(completion); | 195 | complete(completion); |
196 | } | 196 | } |
197 | 197 | ||
198 | static int do_sync_request(sclp_cmdw_t cmd, void *sccb) | 198 | int sclp_sync_request(sclp_cmdw_t cmd, void *sccb) |
199 | { | 199 | { |
200 | struct completion completion; | 200 | struct completion completion; |
201 | struct sclp_req *request; | 201 | struct sclp_req *request; |
@@ -270,7 +270,7 @@ int sclp_get_cpu_info(struct sclp_cpu_info *info) | |||
270 | if (!sccb) | 270 | if (!sccb) |
271 | return -ENOMEM; | 271 | return -ENOMEM; |
272 | sccb->header.length = sizeof(*sccb); | 272 | sccb->header.length = sizeof(*sccb); |
273 | rc = do_sync_request(SCLP_CMDW_READ_CPU_INFO, sccb); | 273 | rc = sclp_sync_request(SCLP_CMDW_READ_CPU_INFO, sccb); |
274 | if (rc) | 274 | if (rc) |
275 | goto out; | 275 | goto out; |
276 | if (sccb->header.response_code != 0x0010) { | 276 | if (sccb->header.response_code != 0x0010) { |
@@ -304,7 +304,7 @@ static int do_cpu_configure(sclp_cmdw_t cmd) | |||
304 | if (!sccb) | 304 | if (!sccb) |
305 | return -ENOMEM; | 305 | return -ENOMEM; |
306 | sccb->header.length = sizeof(*sccb); | 306 | sccb->header.length = sizeof(*sccb); |
307 | rc = do_sync_request(cmd, sccb); | 307 | rc = sclp_sync_request(cmd, sccb); |
308 | if (rc) | 308 | if (rc) |
309 | goto out; | 309 | goto out; |
310 | switch (sccb->header.response_code) { | 310 | switch (sccb->header.response_code) { |
@@ -374,7 +374,7 @@ static int do_assign_storage(sclp_cmdw_t cmd, u16 rn) | |||
374 | return -ENOMEM; | 374 | return -ENOMEM; |
375 | sccb->header.length = PAGE_SIZE; | 375 | sccb->header.length = PAGE_SIZE; |
376 | sccb->rn = rn; | 376 | sccb->rn = rn; |
377 | rc = do_sync_request(cmd, sccb); | 377 | rc = sclp_sync_request(cmd, sccb); |
378 | if (rc) | 378 | if (rc) |
379 | goto out; | 379 | goto out; |
380 | switch (sccb->header.response_code) { | 380 | switch (sccb->header.response_code) { |
@@ -429,7 +429,7 @@ static int sclp_attach_storage(u8 id) | |||
429 | if (!sccb) | 429 | if (!sccb) |
430 | return -ENOMEM; | 430 | return -ENOMEM; |
431 | sccb->header.length = PAGE_SIZE; | 431 | sccb->header.length = PAGE_SIZE; |
432 | rc = do_sync_request(0x00080001 | id << 8, sccb); | 432 | rc = sclp_sync_request(0x00080001 | id << 8, sccb); |
433 | if (rc) | 433 | if (rc) |
434 | goto out; | 434 | goto out; |
435 | switch (sccb->header.response_code) { | 435 | switch (sccb->header.response_code) { |
@@ -627,7 +627,7 @@ static int __init sclp_detect_standby_memory(void) | |||
627 | for (id = 0; id <= sclp_max_storage_id; id++) { | 627 | for (id = 0; id <= sclp_max_storage_id; id++) { |
628 | memset(sccb, 0, PAGE_SIZE); | 628 | memset(sccb, 0, PAGE_SIZE); |
629 | sccb->header.length = PAGE_SIZE; | 629 | sccb->header.length = PAGE_SIZE; |
630 | rc = do_sync_request(0x00040001 | id << 8, sccb); | 630 | rc = sclp_sync_request(0x00040001 | id << 8, sccb); |
631 | if (rc) | 631 | if (rc) |
632 | goto out; | 632 | goto out; |
633 | switch (sccb->header.response_code) { | 633 | switch (sccb->header.response_code) { |
@@ -668,7 +668,7 @@ static int __init sclp_detect_standby_memory(void) | |||
668 | if (rc) | 668 | if (rc) |
669 | goto out; | 669 | goto out; |
670 | sclp_pdev = platform_device_register_simple("sclp_mem", -1, NULL, 0); | 670 | sclp_pdev = platform_device_register_simple("sclp_mem", -1, NULL, 0); |
671 | rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0; | 671 | rc = PTR_RET(sclp_pdev); |
672 | if (rc) | 672 | if (rc) |
673 | goto out_driver; | 673 | goto out_driver; |
674 | sclp_add_standby_memory(); | 674 | sclp_add_standby_memory(); |
@@ -714,7 +714,7 @@ static int do_pci_configure(sclp_cmdw_t cmd, u32 fid) | |||
714 | sccb->header.length = PAGE_SIZE; | 714 | sccb->header.length = PAGE_SIZE; |
715 | sccb->atype = SCLP_RECONFIG_PCI_ATPYE; | 715 | sccb->atype = SCLP_RECONFIG_PCI_ATPYE; |
716 | sccb->aid = fid; | 716 | sccb->aid = fid; |
717 | rc = do_sync_request(cmd, sccb); | 717 | rc = sclp_sync_request(cmd, sccb); |
718 | if (rc) | 718 | if (rc) |
719 | goto out; | 719 | goto out; |
720 | switch (sccb->header.response_code) { | 720 | switch (sccb->header.response_code) { |
@@ -771,7 +771,7 @@ static int do_chp_configure(sclp_cmdw_t cmd) | |||
771 | if (!sccb) | 771 | if (!sccb) |
772 | return -ENOMEM; | 772 | return -ENOMEM; |
773 | sccb->header.length = sizeof(*sccb); | 773 | sccb->header.length = sizeof(*sccb); |
774 | rc = do_sync_request(cmd, sccb); | 774 | rc = sclp_sync_request(cmd, sccb); |
775 | if (rc) | 775 | if (rc) |
776 | goto out; | 776 | goto out; |
777 | switch (sccb->header.response_code) { | 777 | switch (sccb->header.response_code) { |
@@ -846,7 +846,7 @@ int sclp_chp_read_info(struct sclp_chp_info *info) | |||
846 | if (!sccb) | 846 | if (!sccb) |
847 | return -ENOMEM; | 847 | return -ENOMEM; |
848 | sccb->header.length = sizeof(*sccb); | 848 | sccb->header.length = sizeof(*sccb); |
849 | rc = do_sync_request(SCLP_CMDW_READ_CHPATH_INFORMATION, sccb); | 849 | rc = sclp_sync_request(SCLP_CMDW_READ_CHPATH_INFORMATION, sccb); |
850 | if (rc) | 850 | if (rc) |
851 | goto out; | 851 | goto out; |
852 | if (sccb->header.response_code != 0x0010) { | 852 | if (sccb->header.response_code != 0x0010) { |
diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c index ecf45c54f8c4..5880def98fc1 100644 --- a/drivers/s390/char/sclp_con.c +++ b/drivers/s390/char/sclp_con.c | |||
@@ -130,6 +130,31 @@ sclp_console_timeout(unsigned long data) | |||
130 | } | 130 | } |
131 | 131 | ||
132 | /* | 132 | /* |
133 | * Drop oldest console buffer if sclp_con_drop is set | ||
134 | */ | ||
135 | static int | ||
136 | sclp_console_drop_buffer(void) | ||
137 | { | ||
138 | struct list_head *list; | ||
139 | struct sclp_buffer *buffer; | ||
140 | void *page; | ||
141 | |||
142 | if (!sclp_console_drop) | ||
143 | return 0; | ||
144 | list = sclp_con_outqueue.next; | ||
145 | if (sclp_con_queue_running) | ||
146 | /* The first element is in I/O */ | ||
147 | list = list->next; | ||
148 | if (list == &sclp_con_outqueue) | ||
149 | return 0; | ||
150 | list_del(list); | ||
151 | buffer = list_entry(list, struct sclp_buffer, list); | ||
152 | page = sclp_unmake_buffer(buffer); | ||
153 | list_add_tail((struct list_head *) page, &sclp_con_pages); | ||
154 | return 1; | ||
155 | } | ||
156 | |||
157 | /* | ||
133 | * Writes the given message to S390 system console | 158 | * Writes the given message to S390 system console |
134 | */ | 159 | */ |
135 | static void | 160 | static void |
@@ -150,9 +175,13 @@ sclp_console_write(struct console *console, const char *message, | |||
150 | do { | 175 | do { |
151 | /* make sure we have a console output buffer */ | 176 | /* make sure we have a console output buffer */ |
152 | if (sclp_conbuf == NULL) { | 177 | if (sclp_conbuf == NULL) { |
178 | if (list_empty(&sclp_con_pages)) | ||
179 | sclp_console_full++; | ||
153 | while (list_empty(&sclp_con_pages)) { | 180 | while (list_empty(&sclp_con_pages)) { |
154 | if (sclp_con_suspended) | 181 | if (sclp_con_suspended) |
155 | goto out; | 182 | goto out; |
183 | if (sclp_console_drop_buffer()) | ||
184 | break; | ||
156 | spin_unlock_irqrestore(&sclp_con_lock, flags); | 185 | spin_unlock_irqrestore(&sclp_con_lock, flags); |
157 | sclp_sync_wait(); | 186 | sclp_sync_wait(); |
158 | spin_lock_irqsave(&sclp_con_lock, flags); | 187 | spin_lock_irqsave(&sclp_con_lock, flags); |
@@ -297,7 +326,7 @@ sclp_console_init(void) | |||
297 | return rc; | 326 | return rc; |
298 | /* Allocate pages for output buffering */ | 327 | /* Allocate pages for output buffering */ |
299 | INIT_LIST_HEAD(&sclp_con_pages); | 328 | INIT_LIST_HEAD(&sclp_con_pages); |
300 | for (i = 0; i < MAX_CONSOLE_PAGES; i++) { | 329 | for (i = 0; i < sclp_console_pages; i++) { |
301 | page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); | 330 | page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); |
302 | list_add_tail(page, &sclp_con_pages); | 331 | list_add_tail(page, &sclp_con_pages); |
303 | } | 332 | } |
diff --git a/drivers/s390/char/sclp_ctl.c b/drivers/s390/char/sclp_ctl.c new file mode 100644 index 000000000000..648cb86afd42 --- /dev/null +++ b/drivers/s390/char/sclp_ctl.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * IOCTL interface for SCLP | ||
3 | * | ||
4 | * Copyright IBM Corp. 2012 | ||
5 | * | ||
6 | * Author: Michael Holzheu <holzheu@linux.vnet.ibm.com> | ||
7 | */ | ||
8 | |||
9 | #include <linux/compat.h> | ||
10 | #include <linux/uaccess.h> | ||
11 | #include <linux/miscdevice.h> | ||
12 | #include <linux/gfp.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/ioctl.h> | ||
15 | #include <linux/fs.h> | ||
16 | #include <asm/compat.h> | ||
17 | #include <asm/sclp_ctl.h> | ||
18 | #include <asm/sclp.h> | ||
19 | |||
20 | #include "sclp.h" | ||
21 | |||
22 | /* | ||
23 | * Supported command words | ||
24 | */ | ||
25 | static unsigned int sclp_ctl_sccb_wlist[] = { | ||
26 | 0x00400002, | ||
27 | 0x00410002, | ||
28 | }; | ||
29 | |||
30 | /* | ||
31 | * Check if command word is supported | ||
32 | */ | ||
33 | static int sclp_ctl_cmdw_supported(unsigned int cmdw) | ||
34 | { | ||
35 | int i; | ||
36 | |||
37 | for (i = 0; i < ARRAY_SIZE(sclp_ctl_sccb_wlist); i++) { | ||
38 | if (cmdw == sclp_ctl_sccb_wlist[i]) | ||
39 | return 1; | ||
40 | } | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | static void __user *u64_to_uptr(u64 value) | ||
45 | { | ||
46 | if (is_compat_task()) | ||
47 | return compat_ptr(value); | ||
48 | else | ||
49 | return (void __user *)(unsigned long)value; | ||
50 | } | ||
51 | |||
52 | /* | ||
53 | * Start SCLP request | ||
54 | */ | ||
55 | static int sclp_ctl_ioctl_sccb(void __user *user_area) | ||
56 | { | ||
57 | struct sclp_ctl_sccb ctl_sccb; | ||
58 | struct sccb_header *sccb; | ||
59 | int rc; | ||
60 | |||
61 | if (copy_from_user(&ctl_sccb, user_area, sizeof(ctl_sccb))) | ||
62 | return -EFAULT; | ||
63 | if (!sclp_ctl_cmdw_supported(ctl_sccb.cmdw)) | ||
64 | return -EOPNOTSUPP; | ||
65 | sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); | ||
66 | if (!sccb) | ||
67 | return -ENOMEM; | ||
68 | if (copy_from_user(sccb, u64_to_uptr(ctl_sccb.sccb), sizeof(*sccb))) { | ||
69 | rc = -EFAULT; | ||
70 | goto out_free; | ||
71 | } | ||
72 | if (sccb->length > PAGE_SIZE || sccb->length < 8) | ||
73 | return -EINVAL; | ||
74 | if (copy_from_user(sccb, u64_to_uptr(ctl_sccb.sccb), sccb->length)) { | ||
75 | rc = -EFAULT; | ||
76 | goto out_free; | ||
77 | } | ||
78 | rc = sclp_sync_request(ctl_sccb.cmdw, sccb); | ||
79 | if (rc) | ||
80 | goto out_free; | ||
81 | if (copy_to_user(u64_to_uptr(ctl_sccb.sccb), sccb, sccb->length)) | ||
82 | rc = -EFAULT; | ||
83 | out_free: | ||
84 | free_page((unsigned long) sccb); | ||
85 | return rc; | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * SCLP SCCB ioctl function | ||
90 | */ | ||
91 | static long sclp_ctl_ioctl(struct file *filp, unsigned int cmd, | ||
92 | unsigned long arg) | ||
93 | { | ||
94 | void __user *argp; | ||
95 | |||
96 | if (is_compat_task()) | ||
97 | argp = compat_ptr(arg); | ||
98 | else | ||
99 | argp = (void __user *) arg; | ||
100 | switch (cmd) { | ||
101 | case SCLP_CTL_SCCB: | ||
102 | return sclp_ctl_ioctl_sccb(argp); | ||
103 | default: /* unknown ioctl number */ | ||
104 | return -ENOTTY; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | /* | ||
109 | * File operations | ||
110 | */ | ||
111 | static const struct file_operations sclp_ctl_fops = { | ||
112 | .owner = THIS_MODULE, | ||
113 | .open = nonseekable_open, | ||
114 | .unlocked_ioctl = sclp_ctl_ioctl, | ||
115 | .compat_ioctl = sclp_ctl_ioctl, | ||
116 | .llseek = no_llseek, | ||
117 | }; | ||
118 | |||
119 | /* | ||
120 | * Misc device definition | ||
121 | */ | ||
122 | static struct miscdevice sclp_ctl_device = { | ||
123 | .minor = MISC_DYNAMIC_MINOR, | ||
124 | .name = "sclp", | ||
125 | .fops = &sclp_ctl_fops, | ||
126 | }; | ||
127 | |||
128 | /* | ||
129 | * Register sclp_ctl misc device | ||
130 | */ | ||
131 | static int __init sclp_ctl_init(void) | ||
132 | { | ||
133 | return misc_register(&sclp_ctl_device); | ||
134 | } | ||
135 | module_init(sclp_ctl_init); | ||
136 | |||
137 | /* | ||
138 | * Deregister sclp_ctl misc device | ||
139 | */ | ||
140 | static void __exit sclp_ctl_exit(void) | ||
141 | { | ||
142 | misc_deregister(&sclp_ctl_device); | ||
143 | } | ||
144 | module_exit(sclp_ctl_exit); | ||
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 5aaaa2ec8df4..4eed38cd0af6 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c | |||
@@ -362,6 +362,31 @@ sclp_vt220_timeout(unsigned long data) | |||
362 | 362 | ||
363 | #define BUFFER_MAX_DELAY HZ/20 | 363 | #define BUFFER_MAX_DELAY HZ/20 |
364 | 364 | ||
365 | /* | ||
366 | * Drop oldest console buffer if sclp_con_drop is set | ||
367 | */ | ||
368 | static int | ||
369 | sclp_vt220_drop_buffer(void) | ||
370 | { | ||
371 | struct list_head *list; | ||
372 | struct sclp_vt220_request *request; | ||
373 | void *page; | ||
374 | |||
375 | if (!sclp_console_drop) | ||
376 | return 0; | ||
377 | list = sclp_vt220_outqueue.next; | ||
378 | if (sclp_vt220_queue_running) | ||
379 | /* The first element is in I/O */ | ||
380 | list = list->next; | ||
381 | if (list == &sclp_vt220_outqueue) | ||
382 | return 0; | ||
383 | list_del(list); | ||
384 | request = list_entry(list, struct sclp_vt220_request, list); | ||
385 | page = request->sclp_req.sccb; | ||
386 | list_add_tail((struct list_head *) page, &sclp_vt220_empty); | ||
387 | return 1; | ||
388 | } | ||
389 | |||
365 | /* | 390 | /* |
366 | * Internal implementation of the write function. Write COUNT bytes of data | 391 | * Internal implementation of the write function. Write COUNT bytes of data |
367 | * from memory at BUF | 392 | * from memory at BUF |
@@ -390,12 +415,16 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, | |||
390 | do { | 415 | do { |
391 | /* Create an sclp output buffer if none exists yet */ | 416 | /* Create an sclp output buffer if none exists yet */ |
392 | if (sclp_vt220_current_request == NULL) { | 417 | if (sclp_vt220_current_request == NULL) { |
418 | if (list_empty(&sclp_vt220_empty)) | ||
419 | sclp_console_full++; | ||
393 | while (list_empty(&sclp_vt220_empty)) { | 420 | while (list_empty(&sclp_vt220_empty)) { |
394 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
395 | if (may_fail || sclp_vt220_suspended) | 421 | if (may_fail || sclp_vt220_suspended) |
396 | goto out; | 422 | goto out; |
397 | else | 423 | if (sclp_vt220_drop_buffer()) |
398 | sclp_sync_wait(); | 424 | break; |
425 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
426 | |||
427 | sclp_sync_wait(); | ||
399 | spin_lock_irqsave(&sclp_vt220_lock, flags); | 428 | spin_lock_irqsave(&sclp_vt220_lock, flags); |
400 | } | 429 | } |
401 | page = (void *) sclp_vt220_empty.next; | 430 | page = (void *) sclp_vt220_empty.next; |
@@ -428,8 +457,8 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, | |||
428 | sclp_vt220_timer.expires = jiffies + BUFFER_MAX_DELAY; | 457 | sclp_vt220_timer.expires = jiffies + BUFFER_MAX_DELAY; |
429 | add_timer(&sclp_vt220_timer); | 458 | add_timer(&sclp_vt220_timer); |
430 | } | 459 | } |
431 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
432 | out: | 460 | out: |
461 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
433 | return overall_written; | 462 | return overall_written; |
434 | } | 463 | } |
435 | 464 | ||
@@ -803,7 +832,7 @@ sclp_vt220_con_init(void) | |||
803 | 832 | ||
804 | if (!CONSOLE_IS_SCLP) | 833 | if (!CONSOLE_IS_SCLP) |
805 | return 0; | 834 | return 0; |
806 | rc = __sclp_vt220_init(MAX_CONSOLE_PAGES); | 835 | rc = __sclp_vt220_init(sclp_console_pages); |
807 | if (rc) | 836 | if (rc) |
808 | return rc; | 837 | return rc; |
809 | /* Attach linux console */ | 838 | /* Attach linux console */ |
diff --git a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c index 54b3c79203f5..91c3c642c76e 100644 --- a/drivers/s390/char/tape_class.c +++ b/drivers/s390/char/tape_class.c | |||
@@ -77,7 +77,7 @@ struct tape_class_device *register_tape_dev( | |||
77 | tcd->class_device = device_create(tape_class, device, | 77 | tcd->class_device = device_create(tape_class, device, |
78 | tcd->char_device->dev, NULL, | 78 | tcd->char_device->dev, NULL, |
79 | "%s", tcd->device_name); | 79 | "%s", tcd->device_name); |
80 | rc = IS_ERR(tcd->class_device) ? PTR_ERR(tcd->class_device) : 0; | 80 | rc = PTR_RET(tcd->class_device); |
81 | if (rc) | 81 | if (rc) |
82 | goto fail_with_cdev; | 82 | goto fail_with_cdev; |
83 | rc = sysfs_create_link( | 83 | rc = sysfs_create_link( |
diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index e9b72311e254..d5eac985976b 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c | |||
@@ -112,7 +112,8 @@ static int vmwdt_keepalive(void) | |||
112 | 112 | ||
113 | static int vmwdt_disable(void) | 113 | static int vmwdt_disable(void) |
114 | { | 114 | { |
115 | int ret = __diag288(wdt_cancel, 0, "", 0); | 115 | char cmd[] = {'\0'}; |
116 | int ret = __diag288(wdt_cancel, 0, cmd, 0); | ||
116 | WARN_ON(ret != 0); | 117 | WARN_ON(ret != 0); |
117 | clear_bit(VMWDT_RUNNING, &vmwdt_is_open); | 118 | clear_bit(VMWDT_RUNNING, &vmwdt_is_open); |
118 | return ret; | 119 | return ret; |
@@ -124,7 +125,7 @@ static int __init vmwdt_probe(void) | |||
124 | * so we try initializing it with a NOP command ("BEGIN") | 125 | * so we try initializing it with a NOP command ("BEGIN") |
125 | * that won't cause any harm even if the following disable | 126 | * that won't cause any harm even if the following disable |
126 | * fails for some reason */ | 127 | * fails for some reason */ |
127 | static char __initdata ebc_begin[] = { | 128 | char ebc_begin[] = { |
128 | 194, 197, 199, 201, 213 | 129 | 194, 197, 199, 201, 213 |
129 | }; | 130 | }; |
130 | if (__diag288(wdt_init, 15, ebc_begin, sizeof(ebc_begin)) != 0) | 131 | if (__diag288(wdt_init, 15, ebc_begin, sizeof(ebc_begin)) != 0) |
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index bc10220f6847..91edbd7ee806 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c | |||
@@ -9,142 +9,87 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/irq.h> | ||
13 | #include <linux/kernel_stat.h> | ||
12 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/mutex.h> | ||
16 | #include <linux/rculist.h> | ||
13 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
14 | #include <linux/rcupdate.h> | ||
15 | 18 | ||
16 | #include <asm/airq.h> | 19 | #include <asm/airq.h> |
17 | #include <asm/isc.h> | 20 | #include <asm/isc.h> |
18 | 21 | ||
19 | #include "cio.h" | 22 | #include "cio.h" |
20 | #include "cio_debug.h" | 23 | #include "cio_debug.h" |
24 | #include "ioasm.h" | ||
21 | 25 | ||
22 | #define NR_AIRQS 32 | 26 | static DEFINE_SPINLOCK(airq_lists_lock); |
23 | #define NR_AIRQS_PER_WORD sizeof(unsigned long) | 27 | static struct hlist_head airq_lists[MAX_ISC+1]; |
24 | #define NR_AIRQ_WORDS (NR_AIRQS / NR_AIRQS_PER_WORD) | ||
25 | |||
26 | union indicator_t { | ||
27 | unsigned long word[NR_AIRQ_WORDS]; | ||
28 | unsigned char byte[NR_AIRQS]; | ||
29 | } __attribute__((packed)); | ||
30 | |||
31 | struct airq_t { | ||
32 | adapter_int_handler_t handler; | ||
33 | void *drv_data; | ||
34 | }; | ||
35 | |||
36 | static union indicator_t indicators[MAX_ISC+1]; | ||
37 | static struct airq_t *airqs[MAX_ISC+1][NR_AIRQS]; | ||
38 | |||
39 | static int register_airq(struct airq_t *airq, u8 isc) | ||
40 | { | ||
41 | int i; | ||
42 | |||
43 | for (i = 0; i < NR_AIRQS; i++) | ||
44 | if (!cmpxchg(&airqs[isc][i], NULL, airq)) | ||
45 | return i; | ||
46 | return -ENOMEM; | ||
47 | } | ||
48 | 28 | ||
49 | /** | 29 | /** |
50 | * s390_register_adapter_interrupt() - register adapter interrupt handler | 30 | * register_adapter_interrupt() - register adapter interrupt handler |
51 | * @handler: adapter handler to be registered | 31 | * @airq: pointer to adapter interrupt descriptor |
52 | * @drv_data: driver data passed with each call to the handler | ||
53 | * @isc: isc for which the handler should be called | ||
54 | * | 32 | * |
55 | * Returns: | 33 | * Returns 0 on success, or -EINVAL. |
56 | * Pointer to the indicator to be used on success | ||
57 | * ERR_PTR() if registration failed | ||
58 | */ | 34 | */ |
59 | void *s390_register_adapter_interrupt(adapter_int_handler_t handler, | 35 | int register_adapter_interrupt(struct airq_struct *airq) |
60 | void *drv_data, u8 isc) | ||
61 | { | 36 | { |
62 | struct airq_t *airq; | 37 | char dbf_txt[32]; |
63 | char dbf_txt[16]; | 38 | |
64 | int ret; | 39 | if (!airq->handler || airq->isc > MAX_ISC) |
65 | 40 | return -EINVAL; | |
66 | if (isc > MAX_ISC) | 41 | if (!airq->lsi_ptr) { |
67 | return ERR_PTR(-EINVAL); | 42 | airq->lsi_ptr = kzalloc(1, GFP_KERNEL); |
68 | airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL); | 43 | if (!airq->lsi_ptr) |
69 | if (!airq) { | 44 | return -ENOMEM; |
70 | ret = -ENOMEM; | 45 | airq->flags |= AIRQ_PTR_ALLOCATED; |
71 | goto out; | ||
72 | } | 46 | } |
73 | airq->handler = handler; | 47 | if (!airq->lsi_mask) |
74 | airq->drv_data = drv_data; | 48 | airq->lsi_mask = 0xff; |
75 | 49 | snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%p", airq); | |
76 | ret = register_airq(airq, isc); | ||
77 | out: | ||
78 | snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret); | ||
79 | CIO_TRACE_EVENT(4, dbf_txt); | 50 | CIO_TRACE_EVENT(4, dbf_txt); |
80 | if (ret < 0) { | 51 | isc_register(airq->isc); |
81 | kfree(airq); | 52 | spin_lock(&airq_lists_lock); |
82 | return ERR_PTR(ret); | 53 | hlist_add_head_rcu(&airq->list, &airq_lists[airq->isc]); |
83 | } else | 54 | spin_unlock(&airq_lists_lock); |
84 | return &indicators[isc].byte[ret]; | 55 | return 0; |
85 | } | 56 | } |
86 | EXPORT_SYMBOL(s390_register_adapter_interrupt); | 57 | EXPORT_SYMBOL(register_adapter_interrupt); |
87 | 58 | ||
88 | /** | 59 | /** |
89 | * s390_unregister_adapter_interrupt - unregister adapter interrupt handler | 60 | * unregister_adapter_interrupt - unregister adapter interrupt handler |
90 | * @ind: indicator for which the handler is to be unregistered | 61 | * @airq: pointer to adapter interrupt descriptor |
91 | * @isc: interruption subclass | ||
92 | */ | 62 | */ |
93 | void s390_unregister_adapter_interrupt(void *ind, u8 isc) | 63 | void unregister_adapter_interrupt(struct airq_struct *airq) |
94 | { | 64 | { |
95 | struct airq_t *airq; | 65 | char dbf_txt[32]; |
96 | char dbf_txt[16]; | ||
97 | int i; | ||
98 | 66 | ||
99 | i = (int) ((addr_t) ind) - ((addr_t) &indicators[isc].byte[0]); | 67 | if (hlist_unhashed(&airq->list)) |
100 | snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i); | 68 | return; |
69 | snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%p", airq); | ||
101 | CIO_TRACE_EVENT(4, dbf_txt); | 70 | CIO_TRACE_EVENT(4, dbf_txt); |
102 | indicators[isc].byte[i] = 0; | 71 | spin_lock(&airq_lists_lock); |
103 | airq = xchg(&airqs[isc][i], NULL); | 72 | hlist_del_rcu(&airq->list); |
104 | /* | 73 | spin_unlock(&airq_lists_lock); |
105 | * Allow interrupts to complete. This will ensure that the airq handle | 74 | synchronize_rcu(); |
106 | * is no longer referenced by any interrupt handler. | 75 | isc_unregister(airq->isc); |
107 | */ | 76 | if (airq->flags & AIRQ_PTR_ALLOCATED) { |
108 | synchronize_sched(); | 77 | kfree(airq->lsi_ptr); |
109 | kfree(airq); | 78 | airq->lsi_ptr = NULL; |
79 | airq->flags &= ~AIRQ_PTR_ALLOCATED; | ||
80 | } | ||
110 | } | 81 | } |
111 | EXPORT_SYMBOL(s390_unregister_adapter_interrupt); | 82 | EXPORT_SYMBOL(unregister_adapter_interrupt); |
112 | |||
113 | #define INDICATOR_MASK (0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8)) | ||
114 | 83 | ||
115 | void do_adapter_IO(u8 isc) | 84 | void do_adapter_IO(u8 isc) |
116 | { | 85 | { |
117 | int w; | 86 | struct airq_struct *airq; |
118 | int i; | 87 | struct hlist_head *head; |
119 | unsigned long word; | 88 | |
120 | struct airq_t *airq; | 89 | head = &airq_lists[isc]; |
121 | 90 | rcu_read_lock(); | |
122 | /* | 91 | hlist_for_each_entry_rcu(airq, head, list) |
123 | * Access indicator array in word-sized chunks to minimize storage | 92 | if ((*airq->lsi_ptr & airq->lsi_mask) != 0) |
124 | * fetch operations. | 93 | airq->handler(airq); |
125 | */ | 94 | rcu_read_unlock(); |
126 | for (w = 0; w < NR_AIRQ_WORDS; w++) { | ||
127 | word = indicators[isc].word[w]; | ||
128 | i = w * NR_AIRQS_PER_WORD; | ||
129 | /* | ||
130 | * Check bytes within word for active indicators. | ||
131 | */ | ||
132 | while (word) { | ||
133 | if (word & INDICATOR_MASK) { | ||
134 | airq = airqs[isc][i]; | ||
135 | /* Make sure gcc reads from airqs only once. */ | ||
136 | barrier(); | ||
137 | if (likely(airq)) | ||
138 | airq->handler(&indicators[isc].byte[i], | ||
139 | airq->drv_data); | ||
140 | else | ||
141 | /* | ||
142 | * Reset ill-behaved indicator. | ||
143 | */ | ||
144 | indicators[isc].byte[i] = 0; | ||
145 | } | ||
146 | word <<= 8; | ||
147 | i++; | ||
148 | } | ||
149 | } | ||
150 | } | 95 | } |
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 8ea7d9b2c671..13299f902676 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <asm/chpid.h> | 20 | #include <asm/chpid.h> |
21 | #include <asm/chsc.h> | 21 | #include <asm/chsc.h> |
22 | #include <asm/crw.h> | 22 | #include <asm/crw.h> |
23 | #include <asm/isc.h> | ||
23 | 24 | ||
24 | #include "css.h" | 25 | #include "css.h" |
25 | #include "cio.h" | 26 | #include "cio.h" |
@@ -144,6 +145,65 @@ out: | |||
144 | return ret; | 145 | return ret; |
145 | } | 146 | } |
146 | 147 | ||
148 | /** | ||
149 | * chsc_ssqd() - store subchannel QDIO data (SSQD) | ||
150 | * @schid: id of the subchannel on which SSQD is performed | ||
151 | * @ssqd: request and response block for SSQD | ||
152 | * | ||
153 | * Returns 0 on success. | ||
154 | */ | ||
155 | int chsc_ssqd(struct subchannel_id schid, struct chsc_ssqd_area *ssqd) | ||
156 | { | ||
157 | memset(ssqd, 0, sizeof(*ssqd)); | ||
158 | ssqd->request.length = 0x0010; | ||
159 | ssqd->request.code = 0x0024; | ||
160 | ssqd->first_sch = schid.sch_no; | ||
161 | ssqd->last_sch = schid.sch_no; | ||
162 | ssqd->ssid = schid.ssid; | ||
163 | |||
164 | if (chsc(ssqd)) | ||
165 | return -EIO; | ||
166 | |||
167 | return chsc_error_from_response(ssqd->response.code); | ||
168 | } | ||
169 | EXPORT_SYMBOL_GPL(chsc_ssqd); | ||
170 | |||
171 | /** | ||
172 | * chsc_sadc() - set adapter device controls (SADC) | ||
173 | * @schid: id of the subchannel on which SADC is performed | ||
174 | * @scssc: request and response block for SADC | ||
175 | * @summary_indicator_addr: summary indicator address | ||
176 | * @subchannel_indicator_addr: subchannel indicator address | ||
177 | * | ||
178 | * Returns 0 on success. | ||
179 | */ | ||
180 | int chsc_sadc(struct subchannel_id schid, struct chsc_scssc_area *scssc, | ||
181 | u64 summary_indicator_addr, u64 subchannel_indicator_addr) | ||
182 | { | ||
183 | memset(scssc, 0, sizeof(*scssc)); | ||
184 | scssc->request.length = 0x0fe0; | ||
185 | scssc->request.code = 0x0021; | ||
186 | scssc->operation_code = 0; | ||
187 | |||
188 | scssc->summary_indicator_addr = summary_indicator_addr; | ||
189 | scssc->subchannel_indicator_addr = subchannel_indicator_addr; | ||
190 | |||
191 | scssc->ks = PAGE_DEFAULT_KEY >> 4; | ||
192 | scssc->kc = PAGE_DEFAULT_KEY >> 4; | ||
193 | scssc->isc = QDIO_AIRQ_ISC; | ||
194 | scssc->schid = schid; | ||
195 | |||
196 | /* enable the time delay disablement facility */ | ||
197 | if (css_general_characteristics.aif_tdd) | ||
198 | scssc->word_with_d_bit = 0x10000000; | ||
199 | |||
200 | if (chsc(scssc)) | ||
201 | return -EIO; | ||
202 | |||
203 | return chsc_error_from_response(scssc->response.code); | ||
204 | } | ||
205 | EXPORT_SYMBOL_GPL(chsc_sadc); | ||
206 | |||
147 | static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data) | 207 | static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data) |
148 | { | 208 | { |
149 | spin_lock_irq(sch->lock); | 209 | spin_lock_irq(sch->lock); |
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index e7ef2a683b8f..23d072e70eb2 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h | |||
@@ -7,14 +7,10 @@ | |||
7 | #include <asm/chpid.h> | 7 | #include <asm/chpid.h> |
8 | #include <asm/chsc.h> | 8 | #include <asm/chsc.h> |
9 | #include <asm/schid.h> | 9 | #include <asm/schid.h> |
10 | #include <asm/qdio.h> | ||
10 | 11 | ||
11 | #define CHSC_SDA_OC_MSS 0x2 | 12 | #define CHSC_SDA_OC_MSS 0x2 |
12 | 13 | ||
13 | struct chsc_header { | ||
14 | u16 length; | ||
15 | u16 code; | ||
16 | } __attribute__ ((packed)); | ||
17 | |||
18 | #define NR_MEASUREMENT_CHARS 5 | 14 | #define NR_MEASUREMENT_CHARS 5 |
19 | struct cmg_chars { | 15 | struct cmg_chars { |
20 | u32 values[NR_MEASUREMENT_CHARS]; | 16 | u32 values[NR_MEASUREMENT_CHARS]; |
@@ -77,6 +73,40 @@ struct chsc_ssd_info { | |||
77 | u16 fla[8]; | 73 | u16 fla[8]; |
78 | }; | 74 | }; |
79 | 75 | ||
76 | struct chsc_ssqd_area { | ||
77 | struct chsc_header request; | ||
78 | u16:10; | ||
79 | u8 ssid:2; | ||
80 | u8 fmt:4; | ||
81 | u16 first_sch; | ||
82 | u16:16; | ||
83 | u16 last_sch; | ||
84 | u32:32; | ||
85 | struct chsc_header response; | ||
86 | u32:32; | ||
87 | struct qdio_ssqd_desc qdio_ssqd; | ||
88 | } __packed; | ||
89 | |||
90 | struct chsc_scssc_area { | ||
91 | struct chsc_header request; | ||
92 | u16 operation_code; | ||
93 | u16:16; | ||
94 | u32:32; | ||
95 | u32:32; | ||
96 | u64 summary_indicator_addr; | ||
97 | u64 subchannel_indicator_addr; | ||
98 | u32 ks:4; | ||
99 | u32 kc:4; | ||
100 | u32:21; | ||
101 | u32 isc:3; | ||
102 | u32 word_with_d_bit; | ||
103 | u32:32; | ||
104 | struct subchannel_id schid; | ||
105 | u32 reserved[1004]; | ||
106 | struct chsc_header response; | ||
107 | u32:32; | ||
108 | } __packed; | ||
109 | |||
80 | struct chsc_scpd { | 110 | struct chsc_scpd { |
81 | struct chsc_header request; | 111 | struct chsc_header request; |
82 | u32:2; | 112 | u32:2; |
@@ -116,7 +146,9 @@ int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid, | |||
116 | void chsc_chp_online(struct chp_id chpid); | 146 | void chsc_chp_online(struct chp_id chpid); |
117 | void chsc_chp_offline(struct chp_id chpid); | 147 | void chsc_chp_offline(struct chp_id chpid); |
118 | int chsc_get_channel_measurement_chars(struct channel_path *chp); | 148 | int chsc_get_channel_measurement_chars(struct channel_path *chp); |
119 | 149 | int chsc_ssqd(struct subchannel_id schid, struct chsc_ssqd_area *ssqd); | |
150 | int chsc_sadc(struct subchannel_id schid, struct chsc_scssc_area *scssc, | ||
151 | u64 summary_indicator_addr, u64 subchannel_indicator_addr); | ||
120 | int chsc_error_from_response(int response); | 152 | int chsc_error_from_response(int response); |
121 | 153 | ||
122 | int chsc_siosl(struct subchannel_id schid); | 154 | int chsc_siosl(struct subchannel_id schid); |
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index facdf809113f..7b29d0be0ca3 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c | |||
@@ -29,6 +29,10 @@ | |||
29 | static debug_info_t *chsc_debug_msg_id; | 29 | static debug_info_t *chsc_debug_msg_id; |
30 | static debug_info_t *chsc_debug_log_id; | 30 | static debug_info_t *chsc_debug_log_id; |
31 | 31 | ||
32 | static struct chsc_request *on_close_request; | ||
33 | static struct chsc_async_area *on_close_chsc_area; | ||
34 | static DEFINE_MUTEX(on_close_mutex); | ||
35 | |||
32 | #define CHSC_MSG(imp, args...) do { \ | 36 | #define CHSC_MSG(imp, args...) do { \ |
33 | debug_sprintf_event(chsc_debug_msg_id, imp , ##args); \ | 37 | debug_sprintf_event(chsc_debug_msg_id, imp , ##args); \ |
34 | } while (0) | 38 | } while (0) |
@@ -258,7 +262,7 @@ static int chsc_async(struct chsc_async_area *chsc_area, | |||
258 | CHSC_LOG(2, "schid"); | 262 | CHSC_LOG(2, "schid"); |
259 | CHSC_LOG_HEX(2, &sch->schid, sizeof(sch->schid)); | 263 | CHSC_LOG_HEX(2, &sch->schid, sizeof(sch->schid)); |
260 | cc = chsc(chsc_area); | 264 | cc = chsc(chsc_area); |
261 | sprintf(dbf, "cc:%d", cc); | 265 | snprintf(dbf, sizeof(dbf), "cc:%d", cc); |
262 | CHSC_LOG(2, dbf); | 266 | CHSC_LOG(2, dbf); |
263 | switch (cc) { | 267 | switch (cc) { |
264 | case 0: | 268 | case 0: |
@@ -287,11 +291,11 @@ static int chsc_async(struct chsc_async_area *chsc_area, | |||
287 | return ret; | 291 | return ret; |
288 | } | 292 | } |
289 | 293 | ||
290 | static void chsc_log_command(struct chsc_async_area *chsc_area) | 294 | static void chsc_log_command(void *chsc_area) |
291 | { | 295 | { |
292 | char dbf[10]; | 296 | char dbf[10]; |
293 | 297 | ||
294 | sprintf(dbf, "CHSC:%x", chsc_area->header.code); | 298 | snprintf(dbf, sizeof(dbf), "CHSC:%x", ((uint16_t *)chsc_area)[1]); |
295 | CHSC_LOG(0, dbf); | 299 | CHSC_LOG(0, dbf); |
296 | CHSC_LOG_HEX(0, chsc_area, 32); | 300 | CHSC_LOG_HEX(0, chsc_area, 32); |
297 | } | 301 | } |
@@ -355,13 +359,106 @@ static int chsc_ioctl_start(void __user *user_area) | |||
355 | if (copy_to_user(user_area, chsc_area, PAGE_SIZE)) | 359 | if (copy_to_user(user_area, chsc_area, PAGE_SIZE)) |
356 | ret = -EFAULT; | 360 | ret = -EFAULT; |
357 | out_free: | 361 | out_free: |
358 | sprintf(dbf, "ret:%d", ret); | 362 | snprintf(dbf, sizeof(dbf), "ret:%d", ret); |
359 | CHSC_LOG(0, dbf); | 363 | CHSC_LOG(0, dbf); |
360 | kfree(request); | 364 | kfree(request); |
361 | free_page((unsigned long)chsc_area); | 365 | free_page((unsigned long)chsc_area); |
362 | return ret; | 366 | return ret; |
363 | } | 367 | } |
364 | 368 | ||
369 | static int chsc_ioctl_on_close_set(void __user *user_area) | ||
370 | { | ||
371 | char dbf[13]; | ||
372 | int ret; | ||
373 | |||
374 | mutex_lock(&on_close_mutex); | ||
375 | if (on_close_chsc_area) { | ||
376 | ret = -EBUSY; | ||
377 | goto out_unlock; | ||
378 | } | ||
379 | on_close_request = kzalloc(sizeof(*on_close_request), GFP_KERNEL); | ||
380 | if (!on_close_request) { | ||
381 | ret = -ENOMEM; | ||
382 | goto out_unlock; | ||
383 | } | ||
384 | on_close_chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL); | ||
385 | if (!on_close_chsc_area) { | ||
386 | ret = -ENOMEM; | ||
387 | goto out_free_request; | ||
388 | } | ||
389 | if (copy_from_user(on_close_chsc_area, user_area, PAGE_SIZE)) { | ||
390 | ret = -EFAULT; | ||
391 | goto out_free_chsc; | ||
392 | } | ||
393 | ret = 0; | ||
394 | goto out_unlock; | ||
395 | |||
396 | out_free_chsc: | ||
397 | free_page((unsigned long)on_close_chsc_area); | ||
398 | on_close_chsc_area = NULL; | ||
399 | out_free_request: | ||
400 | kfree(on_close_request); | ||
401 | on_close_request = NULL; | ||
402 | out_unlock: | ||
403 | mutex_unlock(&on_close_mutex); | ||
404 | snprintf(dbf, sizeof(dbf), "ocsret:%d", ret); | ||
405 | CHSC_LOG(0, dbf); | ||
406 | return ret; | ||
407 | } | ||
408 | |||
409 | static int chsc_ioctl_on_close_remove(void) | ||
410 | { | ||
411 | char dbf[13]; | ||
412 | int ret; | ||
413 | |||
414 | mutex_lock(&on_close_mutex); | ||
415 | if (!on_close_chsc_area) { | ||
416 | ret = -ENOENT; | ||
417 | goto out_unlock; | ||
418 | } | ||
419 | free_page((unsigned long)on_close_chsc_area); | ||
420 | on_close_chsc_area = NULL; | ||
421 | kfree(on_close_request); | ||
422 | on_close_request = NULL; | ||
423 | ret = 0; | ||
424 | out_unlock: | ||
425 | mutex_unlock(&on_close_mutex); | ||
426 | snprintf(dbf, sizeof(dbf), "ocrret:%d", ret); | ||
427 | CHSC_LOG(0, dbf); | ||
428 | return ret; | ||
429 | } | ||
430 | |||
431 | static int chsc_ioctl_start_sync(void __user *user_area) | ||
432 | { | ||
433 | struct chsc_sync_area *chsc_area; | ||
434 | int ret, ccode; | ||
435 | |||
436 | chsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); | ||
437 | if (!chsc_area) | ||
438 | return -ENOMEM; | ||
439 | if (copy_from_user(chsc_area, user_area, PAGE_SIZE)) { | ||
440 | ret = -EFAULT; | ||
441 | goto out_free; | ||
442 | } | ||
443 | if (chsc_area->header.code & 0x4000) { | ||
444 | ret = -EINVAL; | ||
445 | goto out_free; | ||
446 | } | ||
447 | chsc_log_command(chsc_area); | ||
448 | ccode = chsc(chsc_area); | ||
449 | if (ccode != 0) { | ||
450 | ret = -EIO; | ||
451 | goto out_free; | ||
452 | } | ||
453 | if (copy_to_user(user_area, chsc_area, PAGE_SIZE)) | ||
454 | ret = -EFAULT; | ||
455 | else | ||
456 | ret = 0; | ||
457 | out_free: | ||
458 | free_page((unsigned long)chsc_area); | ||
459 | return ret; | ||
460 | } | ||
461 | |||
365 | static int chsc_ioctl_info_channel_path(void __user *user_cd) | 462 | static int chsc_ioctl_info_channel_path(void __user *user_cd) |
366 | { | 463 | { |
367 | struct chsc_chp_cd *cd; | 464 | struct chsc_chp_cd *cd; |
@@ -795,6 +892,8 @@ static long chsc_ioctl(struct file *filp, unsigned int cmd, | |||
795 | switch (cmd) { | 892 | switch (cmd) { |
796 | case CHSC_START: | 893 | case CHSC_START: |
797 | return chsc_ioctl_start(argp); | 894 | return chsc_ioctl_start(argp); |
895 | case CHSC_START_SYNC: | ||
896 | return chsc_ioctl_start_sync(argp); | ||
798 | case CHSC_INFO_CHANNEL_PATH: | 897 | case CHSC_INFO_CHANNEL_PATH: |
799 | return chsc_ioctl_info_channel_path(argp); | 898 | return chsc_ioctl_info_channel_path(argp); |
800 | case CHSC_INFO_CU: | 899 | case CHSC_INFO_CU: |
@@ -809,14 +908,60 @@ static long chsc_ioctl(struct file *filp, unsigned int cmd, | |||
809 | return chsc_ioctl_chpd(argp); | 908 | return chsc_ioctl_chpd(argp); |
810 | case CHSC_INFO_DCAL: | 909 | case CHSC_INFO_DCAL: |
811 | return chsc_ioctl_dcal(argp); | 910 | return chsc_ioctl_dcal(argp); |
911 | case CHSC_ON_CLOSE_SET: | ||
912 | return chsc_ioctl_on_close_set(argp); | ||
913 | case CHSC_ON_CLOSE_REMOVE: | ||
914 | return chsc_ioctl_on_close_remove(); | ||
812 | default: /* unknown ioctl number */ | 915 | default: /* unknown ioctl number */ |
813 | return -ENOIOCTLCMD; | 916 | return -ENOIOCTLCMD; |
814 | } | 917 | } |
815 | } | 918 | } |
816 | 919 | ||
920 | static atomic_t chsc_ready_for_use = ATOMIC_INIT(1); | ||
921 | |||
922 | static int chsc_open(struct inode *inode, struct file *file) | ||
923 | { | ||
924 | if (!atomic_dec_and_test(&chsc_ready_for_use)) { | ||
925 | atomic_inc(&chsc_ready_for_use); | ||
926 | return -EBUSY; | ||
927 | } | ||
928 | return nonseekable_open(inode, file); | ||
929 | } | ||
930 | |||
931 | static int chsc_release(struct inode *inode, struct file *filp) | ||
932 | { | ||
933 | char dbf[13]; | ||
934 | int ret; | ||
935 | |||
936 | mutex_lock(&on_close_mutex); | ||
937 | if (!on_close_chsc_area) | ||
938 | goto out_unlock; | ||
939 | init_completion(&on_close_request->completion); | ||
940 | CHSC_LOG(0, "on_close"); | ||
941 | chsc_log_command(on_close_chsc_area); | ||
942 | spin_lock_irq(&chsc_lock); | ||
943 | ret = chsc_async(on_close_chsc_area, on_close_request); | ||
944 | spin_unlock_irq(&chsc_lock); | ||
945 | if (ret == -EINPROGRESS) { | ||
946 | wait_for_completion(&on_close_request->completion); | ||
947 | ret = chsc_examine_irb(on_close_request); | ||
948 | } | ||
949 | snprintf(dbf, sizeof(dbf), "relret:%d", ret); | ||
950 | CHSC_LOG(0, dbf); | ||
951 | free_page((unsigned long)on_close_chsc_area); | ||
952 | on_close_chsc_area = NULL; | ||
953 | kfree(on_close_request); | ||
954 | on_close_request = NULL; | ||
955 | out_unlock: | ||
956 | mutex_unlock(&on_close_mutex); | ||
957 | atomic_inc(&chsc_ready_for_use); | ||
958 | return 0; | ||
959 | } | ||
960 | |||
817 | static const struct file_operations chsc_fops = { | 961 | static const struct file_operations chsc_fops = { |
818 | .owner = THIS_MODULE, | 962 | .owner = THIS_MODULE, |
819 | .open = nonseekable_open, | 963 | .open = chsc_open, |
964 | .release = chsc_release, | ||
820 | .unlocked_ioctl = chsc_ioctl, | 965 | .unlocked_ioctl = chsc_ioctl, |
821 | .compat_ioctl = chsc_ioctl, | 966 | .compat_ioctl = chsc_ioctl, |
822 | .llseek = no_llseek, | 967 | .llseek = no_llseek, |
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 935d80b4e9ce..4eeb4a6bf207 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -568,7 +568,7 @@ out: | |||
568 | */ | 568 | */ |
569 | void __irq_entry do_IRQ(struct pt_regs *regs) | 569 | void __irq_entry do_IRQ(struct pt_regs *regs) |
570 | { | 570 | { |
571 | struct tpi_info *tpi_info; | 571 | struct tpi_info *tpi_info = (struct tpi_info *) ®s->int_code; |
572 | struct subchannel *sch; | 572 | struct subchannel *sch; |
573 | struct irb *irb; | 573 | struct irb *irb; |
574 | struct pt_regs *old_regs; | 574 | struct pt_regs *old_regs; |
@@ -579,46 +579,34 @@ void __irq_entry do_IRQ(struct pt_regs *regs) | |||
579 | if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) | 579 | if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) |
580 | /* Serve timer interrupts first. */ | 580 | /* Serve timer interrupts first. */ |
581 | clock_comparator_work(); | 581 | clock_comparator_work(); |
582 | /* | 582 | |
583 | * Get interrupt information from lowcore | 583 | kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL); |
584 | */ | 584 | irb = (struct irb *) &S390_lowcore.irb; |
585 | tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id; | 585 | if (tpi_info->adapter_IO) { |
586 | irb = (struct irb *)&S390_lowcore.irb; | 586 | do_adapter_IO(tpi_info->isc); |
587 | do { | 587 | goto out; |
588 | kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL); | 588 | } |
589 | if (tpi_info->adapter_IO) { | 589 | sch = (struct subchannel *)(unsigned long) tpi_info->intparm; |
590 | do_adapter_IO(tpi_info->isc); | 590 | if (!sch) { |
591 | continue; | 591 | /* Clear pending interrupt condition. */ |
592 | } | 592 | inc_irq_stat(IRQIO_CIO); |
593 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; | 593 | tsch(tpi_info->schid, irb); |
594 | if (!sch) { | 594 | goto out; |
595 | /* Clear pending interrupt condition. */ | 595 | } |
596 | inc_irq_stat(IRQIO_CIO); | 596 | spin_lock(sch->lock); |
597 | tsch(tpi_info->schid, irb); | 597 | /* Store interrupt response block to lowcore. */ |
598 | continue; | 598 | if (tsch(tpi_info->schid, irb) == 0) { |
599 | } | 599 | /* Keep subchannel information word up to date. */ |
600 | spin_lock(sch->lock); | 600 | memcpy (&sch->schib.scsw, &irb->scsw, sizeof (irb->scsw)); |
601 | /* Store interrupt response block to lowcore. */ | 601 | /* Call interrupt handler if there is one. */ |
602 | if (tsch(tpi_info->schid, irb) == 0) { | 602 | if (sch->driver && sch->driver->irq) |
603 | /* Keep subchannel information word up to date. */ | 603 | sch->driver->irq(sch); |
604 | memcpy (&sch->schib.scsw, &irb->scsw, | 604 | else |
605 | sizeof (irb->scsw)); | ||
606 | /* Call interrupt handler if there is one. */ | ||
607 | if (sch->driver && sch->driver->irq) | ||
608 | sch->driver->irq(sch); | ||
609 | else | ||
610 | inc_irq_stat(IRQIO_CIO); | ||
611 | } else | ||
612 | inc_irq_stat(IRQIO_CIO); | 605 | inc_irq_stat(IRQIO_CIO); |
613 | spin_unlock(sch->lock); | 606 | } else |
614 | /* | 607 | inc_irq_stat(IRQIO_CIO); |
615 | * Are more interrupts pending? | 608 | spin_unlock(sch->lock); |
616 | * If so, the tpi instruction will update the lowcore | 609 | out: |
617 | * to hold the info for the next interrupt. | ||
618 | * We don't do this for VM because a tpi drops the cpu | ||
619 | * out of the sie which costs more cycles than it saves. | ||
620 | */ | ||
621 | } while (MACHINE_IS_LPAR && tpi(NULL) != 0); | ||
622 | irq_exit(); | 610 | irq_exit(); |
623 | set_irq_regs(old_regs); | 611 | set_irq_regs(old_regs); |
624 | } | 612 | } |
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 5132554d7917..8acaae18bd11 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h | |||
@@ -140,40 +140,6 @@ struct siga_flag { | |||
140 | u8:3; | 140 | u8:3; |
141 | } __attribute__ ((packed)); | 141 | } __attribute__ ((packed)); |
142 | 142 | ||
143 | struct chsc_ssqd_area { | ||
144 | struct chsc_header request; | ||
145 | u16:10; | ||
146 | u8 ssid:2; | ||
147 | u8 fmt:4; | ||
148 | u16 first_sch; | ||
149 | u16:16; | ||
150 | u16 last_sch; | ||
151 | u32:32; | ||
152 | struct chsc_header response; | ||
153 | u32:32; | ||
154 | struct qdio_ssqd_desc qdio_ssqd; | ||
155 | } __attribute__ ((packed)); | ||
156 | |||
157 | struct scssc_area { | ||
158 | struct chsc_header request; | ||
159 | u16 operation_code; | ||
160 | u16:16; | ||
161 | u32:32; | ||
162 | u32:32; | ||
163 | u64 summary_indicator_addr; | ||
164 | u64 subchannel_indicator_addr; | ||
165 | u32 ks:4; | ||
166 | u32 kc:4; | ||
167 | u32:21; | ||
168 | u32 isc:3; | ||
169 | u32 word_with_d_bit; | ||
170 | u32:32; | ||
171 | struct subchannel_id schid; | ||
172 | u32 reserved[1004]; | ||
173 | struct chsc_header response; | ||
174 | u32:32; | ||
175 | } __attribute__ ((packed)); | ||
176 | |||
177 | struct qdio_dev_perf_stat { | 143 | struct qdio_dev_perf_stat { |
178 | unsigned int adapter_int; | 144 | unsigned int adapter_int; |
179 | unsigned int qdio_int; | 145 | unsigned int qdio_int; |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 843051bc20f1..fb1c1e0483ed 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
@@ -608,50 +608,6 @@ static inline int contains_aobs(struct qdio_q *q) | |||
608 | return !q->is_input_q && q->u.out.use_cq; | 608 | return !q->is_input_q && q->u.out.use_cq; |
609 | } | 609 | } |
610 | 610 | ||
611 | static inline void qdio_trace_aob(struct qdio_irq *irq, struct qdio_q *q, | ||
612 | int i, struct qaob *aob) | ||
613 | { | ||
614 | int tmp; | ||
615 | |||
616 | DBF_DEV_EVENT(DBF_INFO, irq, "AOB%d:%lx", i, | ||
617 | (unsigned long) virt_to_phys(aob)); | ||
618 | DBF_DEV_EVENT(DBF_INFO, irq, "RES00:%lx", | ||
619 | (unsigned long) aob->res0[0]); | ||
620 | DBF_DEV_EVENT(DBF_INFO, irq, "RES01:%lx", | ||
621 | (unsigned long) aob->res0[1]); | ||
622 | DBF_DEV_EVENT(DBF_INFO, irq, "RES02:%lx", | ||
623 | (unsigned long) aob->res0[2]); | ||
624 | DBF_DEV_EVENT(DBF_INFO, irq, "RES03:%lx", | ||
625 | (unsigned long) aob->res0[3]); | ||
626 | DBF_DEV_EVENT(DBF_INFO, irq, "RES04:%lx", | ||
627 | (unsigned long) aob->res0[4]); | ||
628 | DBF_DEV_EVENT(DBF_INFO, irq, "RES05:%lx", | ||
629 | (unsigned long) aob->res0[5]); | ||
630 | DBF_DEV_EVENT(DBF_INFO, irq, "RES1:%x", aob->res1); | ||
631 | DBF_DEV_EVENT(DBF_INFO, irq, "RES2:%x", aob->res2); | ||
632 | DBF_DEV_EVENT(DBF_INFO, irq, "RES3:%x", aob->res3); | ||
633 | DBF_DEV_EVENT(DBF_INFO, irq, "AORC:%u", aob->aorc); | ||
634 | DBF_DEV_EVENT(DBF_INFO, irq, "FLAGS:%u", aob->flags); | ||
635 | DBF_DEV_EVENT(DBF_INFO, irq, "CBTBS:%u", aob->cbtbs); | ||
636 | DBF_DEV_EVENT(DBF_INFO, irq, "SBC:%u", aob->sb_count); | ||
637 | for (tmp = 0; tmp < QDIO_MAX_ELEMENTS_PER_BUFFER; ++tmp) { | ||
638 | DBF_DEV_EVENT(DBF_INFO, irq, "SBA%d:%lx", tmp, | ||
639 | (unsigned long) aob->sba[tmp]); | ||
640 | DBF_DEV_EVENT(DBF_INFO, irq, "rSBA%d:%lx", tmp, | ||
641 | (unsigned long) q->sbal[i]->element[tmp].addr); | ||
642 | DBF_DEV_EVENT(DBF_INFO, irq, "DC%d:%u", tmp, aob->dcount[tmp]); | ||
643 | DBF_DEV_EVENT(DBF_INFO, irq, "rDC%d:%u", tmp, | ||
644 | q->sbal[i]->element[tmp].length); | ||
645 | } | ||
646 | DBF_DEV_EVENT(DBF_INFO, irq, "USER0:%lx", (unsigned long) aob->user0); | ||
647 | for (tmp = 0; tmp < 2; ++tmp) { | ||
648 | DBF_DEV_EVENT(DBF_INFO, irq, "RES4%d:%lx", tmp, | ||
649 | (unsigned long) aob->res4[tmp]); | ||
650 | } | ||
651 | DBF_DEV_EVENT(DBF_INFO, irq, "USER1:%lx", (unsigned long) aob->user1); | ||
652 | DBF_DEV_EVENT(DBF_INFO, irq, "USER2:%lx", (unsigned long) aob->user2); | ||
653 | } | ||
654 | |||
655 | static inline void qdio_handle_aobs(struct qdio_q *q, int start, int count) | 611 | static inline void qdio_handle_aobs(struct qdio_q *q, int start, int count) |
656 | { | 612 | { |
657 | unsigned char state = 0; | 613 | unsigned char state = 0; |
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 16ecd35b8e51..f5f4a91fab44 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c | |||
@@ -254,40 +254,31 @@ int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, | |||
254 | int rc; | 254 | int rc; |
255 | 255 | ||
256 | DBF_EVENT("getssqd:%4x", schid->sch_no); | 256 | DBF_EVENT("getssqd:%4x", schid->sch_no); |
257 | if (irq_ptr != NULL) | 257 | if (!irq_ptr) { |
258 | ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; | ||
259 | else | ||
260 | ssqd = (struct chsc_ssqd_area *)__get_free_page(GFP_KERNEL); | 258 | ssqd = (struct chsc_ssqd_area *)__get_free_page(GFP_KERNEL); |
261 | memset(ssqd, 0, PAGE_SIZE); | 259 | if (!ssqd) |
262 | 260 | return -ENOMEM; | |
263 | ssqd->request = (struct chsc_header) { | 261 | } else { |
264 | .length = 0x0010, | 262 | ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; |
265 | .code = 0x0024, | 263 | } |
266 | }; | 264 | |
267 | ssqd->first_sch = schid->sch_no; | 265 | rc = chsc_ssqd(*schid, ssqd); |
268 | ssqd->last_sch = schid->sch_no; | ||
269 | ssqd->ssid = schid->ssid; | ||
270 | |||
271 | if (chsc(ssqd)) | ||
272 | return -EIO; | ||
273 | rc = chsc_error_from_response(ssqd->response.code); | ||
274 | if (rc) | 266 | if (rc) |
275 | return rc; | 267 | goto out; |
276 | 268 | ||
277 | if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) || | 269 | if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) || |
278 | !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) || | 270 | !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) || |
279 | (ssqd->qdio_ssqd.sch != schid->sch_no)) | 271 | (ssqd->qdio_ssqd.sch != schid->sch_no)) |
280 | return -EINVAL; | 272 | rc = -EINVAL; |
281 | 273 | ||
282 | if (irq_ptr != NULL) | 274 | if (!rc) |
283 | memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, | 275 | memcpy(data, &ssqd->qdio_ssqd, sizeof(*data)); |
284 | sizeof(struct qdio_ssqd_desc)); | 276 | |
285 | else { | 277 | out: |
286 | memcpy(data, &ssqd->qdio_ssqd, | 278 | if (!irq_ptr) |
287 | sizeof(struct qdio_ssqd_desc)); | ||
288 | free_page((unsigned long)ssqd); | 279 | free_page((unsigned long)ssqd); |
289 | } | 280 | |
290 | return 0; | 281 | return rc; |
291 | } | 282 | } |
292 | 283 | ||
293 | void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) | 284 | void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) |
@@ -295,7 +286,7 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) | |||
295 | unsigned char qdioac; | 286 | unsigned char qdioac; |
296 | int rc; | 287 | int rc; |
297 | 288 | ||
298 | rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, NULL); | 289 | rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, &irq_ptr->ssqd_desc); |
299 | if (rc) { | 290 | if (rc) { |
300 | DBF_ERROR("%4x ssqd ERR", irq_ptr->schid.sch_no); | 291 | DBF_ERROR("%4x ssqd ERR", irq_ptr->schid.sch_no); |
301 | DBF_ERROR("rc:%x", rc); | 292 | DBF_ERROR("rc:%x", rc); |
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index bde5255200dc..5d06253c2a7a 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c | |||
@@ -36,8 +36,13 @@ struct indicator_t { | |||
36 | static LIST_HEAD(tiq_list); | 36 | static LIST_HEAD(tiq_list); |
37 | static DEFINE_MUTEX(tiq_list_lock); | 37 | static DEFINE_MUTEX(tiq_list_lock); |
38 | 38 | ||
39 | /* adapter local summary indicator */ | 39 | /* Adapter interrupt definitions */ |
40 | static u8 *tiqdio_alsi; | 40 | static void tiqdio_thinint_handler(struct airq_struct *airq); |
41 | |||
42 | static struct airq_struct tiqdio_airq = { | ||
43 | .handler = tiqdio_thinint_handler, | ||
44 | .isc = QDIO_AIRQ_ISC, | ||
45 | }; | ||
41 | 46 | ||
42 | static struct indicator_t *q_indicators; | 47 | static struct indicator_t *q_indicators; |
43 | 48 | ||
@@ -176,7 +181,7 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq) | |||
176 | * @alsi: pointer to adapter local summary indicator | 181 | * @alsi: pointer to adapter local summary indicator |
177 | * @data: NULL | 182 | * @data: NULL |
178 | */ | 183 | */ |
179 | static void tiqdio_thinint_handler(void *alsi, void *data) | 184 | static void tiqdio_thinint_handler(struct airq_struct *airq) |
180 | { | 185 | { |
181 | u32 si_used = clear_shared_ind(); | 186 | u32 si_used = clear_shared_ind(); |
182 | struct qdio_q *q; | 187 | struct qdio_q *q; |
@@ -208,51 +213,31 @@ static void tiqdio_thinint_handler(void *alsi, void *data) | |||
208 | 213 | ||
209 | static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) | 214 | static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) |
210 | { | 215 | { |
211 | struct scssc_area *scssc_area; | 216 | struct chsc_scssc_area *scssc = (void *)irq_ptr->chsc_page; |
217 | u64 summary_indicator_addr, subchannel_indicator_addr; | ||
212 | int rc; | 218 | int rc; |
213 | 219 | ||
214 | scssc_area = (struct scssc_area *)irq_ptr->chsc_page; | ||
215 | memset(scssc_area, 0, PAGE_SIZE); | ||
216 | |||
217 | if (reset) { | 220 | if (reset) { |
218 | scssc_area->summary_indicator_addr = 0; | 221 | summary_indicator_addr = 0; |
219 | scssc_area->subchannel_indicator_addr = 0; | 222 | subchannel_indicator_addr = 0; |
220 | } else { | 223 | } else { |
221 | scssc_area->summary_indicator_addr = virt_to_phys(tiqdio_alsi); | 224 | summary_indicator_addr = virt_to_phys(tiqdio_airq.lsi_ptr); |
222 | scssc_area->subchannel_indicator_addr = | 225 | subchannel_indicator_addr = virt_to_phys(irq_ptr->dsci); |
223 | virt_to_phys(irq_ptr->dsci); | ||
224 | } | 226 | } |
225 | 227 | ||
226 | scssc_area->request = (struct chsc_header) { | 228 | rc = chsc_sadc(irq_ptr->schid, scssc, summary_indicator_addr, |
227 | .length = 0x0fe0, | 229 | subchannel_indicator_addr); |
228 | .code = 0x0021, | ||
229 | }; | ||
230 | scssc_area->operation_code = 0; | ||
231 | scssc_area->ks = PAGE_DEFAULT_KEY >> 4; | ||
232 | scssc_area->kc = PAGE_DEFAULT_KEY >> 4; | ||
233 | scssc_area->isc = QDIO_AIRQ_ISC; | ||
234 | scssc_area->schid = irq_ptr->schid; | ||
235 | |||
236 | /* enable the time delay disablement facility */ | ||
237 | if (css_general_characteristics.aif_tdd) | ||
238 | scssc_area->word_with_d_bit = 0x10000000; | ||
239 | |||
240 | rc = chsc(scssc_area); | ||
241 | if (rc) | ||
242 | return -EIO; | ||
243 | |||
244 | rc = chsc_error_from_response(scssc_area->response.code); | ||
245 | if (rc) { | 230 | if (rc) { |
246 | DBF_ERROR("%4x SSI r:%4x", irq_ptr->schid.sch_no, | 231 | DBF_ERROR("%4x SSI r:%4x", irq_ptr->schid.sch_no, |
247 | scssc_area->response.code); | 232 | scssc->response.code); |
248 | DBF_ERROR_HEX(&scssc_area->response, sizeof(void *)); | 233 | goto out; |
249 | return rc; | ||
250 | } | 234 | } |
251 | 235 | ||
252 | DBF_EVENT("setscind"); | 236 | DBF_EVENT("setscind"); |
253 | DBF_HEX(&scssc_area->summary_indicator_addr, sizeof(unsigned long)); | 237 | DBF_HEX(&summary_indicator_addr, sizeof(summary_indicator_addr)); |
254 | DBF_HEX(&scssc_area->subchannel_indicator_addr, sizeof(unsigned long)); | 238 | DBF_HEX(&subchannel_indicator_addr, sizeof(subchannel_indicator_addr)); |
255 | return 0; | 239 | out: |
240 | return rc; | ||
256 | } | 241 | } |
257 | 242 | ||
258 | /* allocate non-shared indicators and shared indicator */ | 243 | /* allocate non-shared indicators and shared indicator */ |
@@ -272,14 +257,12 @@ void tiqdio_free_memory(void) | |||
272 | 257 | ||
273 | int __init tiqdio_register_thinints(void) | 258 | int __init tiqdio_register_thinints(void) |
274 | { | 259 | { |
275 | isc_register(QDIO_AIRQ_ISC); | 260 | int rc; |
276 | tiqdio_alsi = s390_register_adapter_interrupt(&tiqdio_thinint_handler, | 261 | |
277 | NULL, QDIO_AIRQ_ISC); | 262 | rc = register_adapter_interrupt(&tiqdio_airq); |
278 | if (IS_ERR(tiqdio_alsi)) { | 263 | if (rc) { |
279 | DBF_EVENT("RTI:%lx", PTR_ERR(tiqdio_alsi)); | 264 | DBF_EVENT("RTI:%x", rc); |
280 | tiqdio_alsi = NULL; | 265 | return rc; |
281 | isc_unregister(QDIO_AIRQ_ISC); | ||
282 | return -ENOMEM; | ||
283 | } | 266 | } |
284 | return 0; | 267 | return 0; |
285 | } | 268 | } |
@@ -312,9 +295,5 @@ void qdio_shutdown_thinint(struct qdio_irq *irq_ptr) | |||
312 | void __exit tiqdio_unregister_thinints(void) | 295 | void __exit tiqdio_unregister_thinints(void) |
313 | { | 296 | { |
314 | WARN_ON(!list_empty(&tiq_list)); | 297 | WARN_ON(!list_empty(&tiq_list)); |
315 | 298 | unregister_adapter_interrupt(&tiqdio_airq); | |
316 | if (tiqdio_alsi) { | ||
317 | s390_unregister_adapter_interrupt(tiqdio_alsi, QDIO_AIRQ_ISC); | ||
318 | isc_unregister(QDIO_AIRQ_ISC); | ||
319 | } | ||
320 | } | 299 | } |
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 9de41aa14896..f446a7705c3b 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c | |||
@@ -58,7 +58,7 @@ static inline void ap_schedule_poll_timer(void); | |||
58 | static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags); | 58 | static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags); |
59 | static int ap_device_remove(struct device *dev); | 59 | static int ap_device_remove(struct device *dev); |
60 | static int ap_device_probe(struct device *dev); | 60 | static int ap_device_probe(struct device *dev); |
61 | static void ap_interrupt_handler(void *unused1, void *unused2); | 61 | static void ap_interrupt_handler(struct airq_struct *airq); |
62 | static void ap_reset(struct ap_device *ap_dev); | 62 | static void ap_reset(struct ap_device *ap_dev); |
63 | static void ap_config_timeout(unsigned long ptr); | 63 | static void ap_config_timeout(unsigned long ptr); |
64 | static int ap_select_domain(void); | 64 | static int ap_select_domain(void); |
@@ -106,7 +106,6 @@ static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait); | |||
106 | static struct task_struct *ap_poll_kthread = NULL; | 106 | static struct task_struct *ap_poll_kthread = NULL; |
107 | static DEFINE_MUTEX(ap_poll_thread_mutex); | 107 | static DEFINE_MUTEX(ap_poll_thread_mutex); |
108 | static DEFINE_SPINLOCK(ap_poll_timer_lock); | 108 | static DEFINE_SPINLOCK(ap_poll_timer_lock); |
109 | static void *ap_interrupt_indicator; | ||
110 | static struct hrtimer ap_poll_timer; | 109 | static struct hrtimer ap_poll_timer; |
111 | /* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. | 110 | /* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. |
112 | * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/ | 111 | * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/ |
@@ -120,13 +119,21 @@ static int ap_suspend_flag; | |||
120 | static int user_set_domain = 0; | 119 | static int user_set_domain = 0; |
121 | static struct bus_type ap_bus_type; | 120 | static struct bus_type ap_bus_type; |
122 | 121 | ||
122 | /* Adapter interrupt definitions */ | ||
123 | static int ap_airq_flag; | ||
124 | |||
125 | static struct airq_struct ap_airq = { | ||
126 | .handler = ap_interrupt_handler, | ||
127 | .isc = AP_ISC, | ||
128 | }; | ||
129 | |||
123 | /** | 130 | /** |
124 | * ap_using_interrupts() - Returns non-zero if interrupt support is | 131 | * ap_using_interrupts() - Returns non-zero if interrupt support is |
125 | * available. | 132 | * available. |
126 | */ | 133 | */ |
127 | static inline int ap_using_interrupts(void) | 134 | static inline int ap_using_interrupts(void) |
128 | { | 135 | { |
129 | return ap_interrupt_indicator != NULL; | 136 | return ap_airq_flag; |
130 | } | 137 | } |
131 | 138 | ||
132 | /** | 139 | /** |
@@ -588,7 +595,7 @@ static int ap_init_queue(ap_qid_t qid) | |||
588 | } | 595 | } |
589 | } | 596 | } |
590 | if (rc == 0 && ap_using_interrupts()) { | 597 | if (rc == 0 && ap_using_interrupts()) { |
591 | rc = ap_queue_enable_interruption(qid, ap_interrupt_indicator); | 598 | rc = ap_queue_enable_interruption(qid, ap_airq.lsi_ptr); |
592 | /* If interruption mode is supported by the machine, | 599 | /* If interruption mode is supported by the machine, |
593 | * but an AP can not be enabled for interruption then | 600 | * but an AP can not be enabled for interruption then |
594 | * the AP will be discarded. */ | 601 | * the AP will be discarded. */ |
@@ -821,13 +828,22 @@ static int ap_bus_suspend(struct device *dev, pm_message_t state) | |||
821 | 828 | ||
822 | static int ap_bus_resume(struct device *dev) | 829 | static int ap_bus_resume(struct device *dev) |
823 | { | 830 | { |
824 | int rc = 0; | ||
825 | struct ap_device *ap_dev = to_ap_dev(dev); | 831 | struct ap_device *ap_dev = to_ap_dev(dev); |
832 | int rc; | ||
826 | 833 | ||
827 | if (ap_suspend_flag) { | 834 | if (ap_suspend_flag) { |
828 | ap_suspend_flag = 0; | 835 | ap_suspend_flag = 0; |
829 | if (!ap_interrupts_available()) | 836 | if (ap_interrupts_available()) { |
830 | ap_interrupt_indicator = NULL; | 837 | if (!ap_using_interrupts()) { |
838 | rc = register_adapter_interrupt(&ap_airq); | ||
839 | ap_airq_flag = (rc == 0); | ||
840 | } | ||
841 | } else { | ||
842 | if (ap_using_interrupts()) { | ||
843 | unregister_adapter_interrupt(&ap_airq); | ||
844 | ap_airq_flag = 0; | ||
845 | } | ||
846 | } | ||
831 | ap_query_configuration(); | 847 | ap_query_configuration(); |
832 | if (!user_set_domain) { | 848 | if (!user_set_domain) { |
833 | ap_domain_index = -1; | 849 | ap_domain_index = -1; |
@@ -848,7 +864,10 @@ static int ap_bus_resume(struct device *dev) | |||
848 | tasklet_schedule(&ap_tasklet); | 864 | tasklet_schedule(&ap_tasklet); |
849 | if (ap_thread_flag) | 865 | if (ap_thread_flag) |
850 | rc = ap_poll_thread_start(); | 866 | rc = ap_poll_thread_start(); |
851 | } | 867 | else |
868 | rc = 0; | ||
869 | } else | ||
870 | rc = 0; | ||
852 | if (AP_QID_QUEUE(ap_dev->qid) != ap_domain_index) { | 871 | if (AP_QID_QUEUE(ap_dev->qid) != ap_domain_index) { |
853 | spin_lock_bh(&ap_dev->lock); | 872 | spin_lock_bh(&ap_dev->lock); |
854 | ap_dev->qid = AP_MKQID(AP_QID_DEVICE(ap_dev->qid), | 873 | ap_dev->qid = AP_MKQID(AP_QID_DEVICE(ap_dev->qid), |
@@ -1266,7 +1285,7 @@ out: | |||
1266 | return rc; | 1285 | return rc; |
1267 | } | 1286 | } |
1268 | 1287 | ||
1269 | static void ap_interrupt_handler(void *unused1, void *unused2) | 1288 | static void ap_interrupt_handler(struct airq_struct *airq) |
1270 | { | 1289 | { |
1271 | inc_irq_stat(IRQIO_APB); | 1290 | inc_irq_stat(IRQIO_APB); |
1272 | tasklet_schedule(&ap_tasklet); | 1291 | tasklet_schedule(&ap_tasklet); |
@@ -1722,7 +1741,7 @@ static void ap_poll_all(unsigned long dummy) | |||
1722 | * important that no requests on any AP get lost. | 1741 | * important that no requests on any AP get lost. |
1723 | */ | 1742 | */ |
1724 | if (ap_using_interrupts()) | 1743 | if (ap_using_interrupts()) |
1725 | xchg((u8 *)ap_interrupt_indicator, 0); | 1744 | xchg(ap_airq.lsi_ptr, 0); |
1726 | do { | 1745 | do { |
1727 | flags = 0; | 1746 | flags = 0; |
1728 | spin_lock(&ap_device_list_lock); | 1747 | spin_lock(&ap_device_list_lock); |
@@ -1795,7 +1814,7 @@ static int ap_poll_thread_start(void) | |||
1795 | mutex_lock(&ap_poll_thread_mutex); | 1814 | mutex_lock(&ap_poll_thread_mutex); |
1796 | if (!ap_poll_kthread) { | 1815 | if (!ap_poll_kthread) { |
1797 | ap_poll_kthread = kthread_run(ap_poll_thread, NULL, "appoll"); | 1816 | ap_poll_kthread = kthread_run(ap_poll_thread, NULL, "appoll"); |
1798 | rc = IS_ERR(ap_poll_kthread) ? PTR_ERR(ap_poll_kthread) : 0; | 1817 | rc = PTR_RET(ap_poll_kthread); |
1799 | if (rc) | 1818 | if (rc) |
1800 | ap_poll_kthread = NULL; | 1819 | ap_poll_kthread = NULL; |
1801 | } | 1820 | } |
@@ -1881,13 +1900,8 @@ int __init ap_module_init(void) | |||
1881 | return -ENODEV; | 1900 | return -ENODEV; |
1882 | } | 1901 | } |
1883 | if (ap_interrupts_available()) { | 1902 | if (ap_interrupts_available()) { |
1884 | isc_register(AP_ISC); | 1903 | rc = register_adapter_interrupt(&ap_airq); |
1885 | ap_interrupt_indicator = s390_register_adapter_interrupt( | 1904 | ap_airq_flag = (rc == 0); |
1886 | &ap_interrupt_handler, NULL, AP_ISC); | ||
1887 | if (IS_ERR(ap_interrupt_indicator)) { | ||
1888 | ap_interrupt_indicator = NULL; | ||
1889 | isc_unregister(AP_ISC); | ||
1890 | } | ||
1891 | } | 1905 | } |
1892 | 1906 | ||
1893 | register_reset_call(&ap_reset_call); | 1907 | register_reset_call(&ap_reset_call); |
@@ -1904,7 +1918,7 @@ int __init ap_module_init(void) | |||
1904 | 1918 | ||
1905 | /* Create /sys/devices/ap. */ | 1919 | /* Create /sys/devices/ap. */ |
1906 | ap_root_device = root_device_register("ap"); | 1920 | ap_root_device = root_device_register("ap"); |
1907 | rc = IS_ERR(ap_root_device) ? PTR_ERR(ap_root_device) : 0; | 1921 | rc = PTR_RET(ap_root_device); |
1908 | if (rc) | 1922 | if (rc) |
1909 | goto out_bus; | 1923 | goto out_bus; |
1910 | 1924 | ||
@@ -1955,10 +1969,8 @@ out_bus: | |||
1955 | bus_unregister(&ap_bus_type); | 1969 | bus_unregister(&ap_bus_type); |
1956 | out: | 1970 | out: |
1957 | unregister_reset_call(&ap_reset_call); | 1971 | unregister_reset_call(&ap_reset_call); |
1958 | if (ap_using_interrupts()) { | 1972 | if (ap_using_interrupts()) |
1959 | s390_unregister_adapter_interrupt(ap_interrupt_indicator, AP_ISC); | 1973 | unregister_adapter_interrupt(&ap_airq); |
1960 | isc_unregister(AP_ISC); | ||
1961 | } | ||
1962 | return rc; | 1974 | return rc; |
1963 | } | 1975 | } |
1964 | 1976 | ||
@@ -1994,10 +2006,8 @@ void ap_module_exit(void) | |||
1994 | bus_remove_file(&ap_bus_type, ap_bus_attrs[i]); | 2006 | bus_remove_file(&ap_bus_type, ap_bus_attrs[i]); |
1995 | bus_unregister(&ap_bus_type); | 2007 | bus_unregister(&ap_bus_type); |
1996 | unregister_reset_call(&ap_reset_call); | 2008 | unregister_reset_call(&ap_reset_call); |
1997 | if (ap_using_interrupts()) { | 2009 | if (ap_using_interrupts()) |
1998 | s390_unregister_adapter_interrupt(ap_interrupt_indicator, AP_ISC); | 2010 | unregister_adapter_interrupt(&ap_airq); |
1999 | isc_unregister(AP_ISC); | ||
2000 | } | ||
2001 | } | 2011 | } |
2002 | 2012 | ||
2003 | module_init(ap_module_init); | 2013 | module_init(ap_module_init); |
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 83bc9c5fa0c1..fd7b3bd80789 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c | |||
@@ -3348,7 +3348,7 @@ static int __init claw_init(void) | |||
3348 | } | 3348 | } |
3349 | CLAW_DBF_TEXT(2, setup, "init_mod"); | 3349 | CLAW_DBF_TEXT(2, setup, "init_mod"); |
3350 | claw_root_dev = root_device_register("claw"); | 3350 | claw_root_dev = root_device_register("claw"); |
3351 | ret = IS_ERR(claw_root_dev) ? PTR_ERR(claw_root_dev) : 0; | 3351 | ret = PTR_RET(claw_root_dev); |
3352 | if (ret) | 3352 | if (ret) |
3353 | goto register_err; | 3353 | goto register_err; |
3354 | ret = ccw_driver_register(&claw_ccw_driver); | 3354 | ret = ccw_driver_register(&claw_ccw_driver); |
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 676f12049a36..70b3a023100e 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c | |||
@@ -1837,7 +1837,7 @@ static int __init ctcm_init(void) | |||
1837 | if (ret) | 1837 | if (ret) |
1838 | goto out_err; | 1838 | goto out_err; |
1839 | ctcm_root_dev = root_device_register("ctcm"); | 1839 | ctcm_root_dev = root_device_register("ctcm"); |
1840 | ret = IS_ERR(ctcm_root_dev) ? PTR_ERR(ctcm_root_dev) : 0; | 1840 | ret = PTR_RET(ctcm_root_dev); |
1841 | if (ret) | 1841 | if (ret) |
1842 | goto register_err; | 1842 | goto register_err; |
1843 | ret = ccw_driver_register(&ctcm_ccw_driver); | 1843 | ret = ccw_driver_register(&ctcm_ccw_driver); |
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index c645dc9e98af..f404f55b3191 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c | |||
@@ -2441,7 +2441,7 @@ __init lcs_init_module(void) | |||
2441 | if (rc) | 2441 | if (rc) |
2442 | goto out_err; | 2442 | goto out_err; |
2443 | lcs_root_dev = root_device_register("lcs"); | 2443 | lcs_root_dev = root_device_register("lcs"); |
2444 | rc = IS_ERR(lcs_root_dev) ? PTR_ERR(lcs_root_dev) : 0; | 2444 | rc = PTR_RET(lcs_root_dev); |
2445 | if (rc) | 2445 | if (rc) |
2446 | goto register_err; | 2446 | goto register_err; |
2447 | rc = ccw_driver_register(&lcs_ccw_driver); | 2447 | rc = ccw_driver_register(&lcs_ccw_driver); |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 6cd0fc1b203a..70ce6b6fce3b 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -5705,7 +5705,7 @@ static int __init qeth_core_init(void) | |||
5705 | if (rc) | 5705 | if (rc) |
5706 | goto out_err; | 5706 | goto out_err; |
5707 | qeth_core_root_dev = root_device_register("qeth"); | 5707 | qeth_core_root_dev = root_device_register("qeth"); |
5708 | rc = IS_ERR(qeth_core_root_dev) ? PTR_ERR(qeth_core_root_dev) : 0; | 5708 | rc = PTR_RET(qeth_core_root_dev); |
5709 | if (rc) | 5709 | if (rc) |
5710 | goto register_err; | 5710 | goto register_err; |
5711 | qeth_core_header_cache = kmem_cache_create("qeth_hdr", | 5711 | qeth_core_header_cache = kmem_cache_create("qeth_hdr", |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 3a24e4ff3248..8f170e9073a5 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -1643,6 +1643,7 @@ void pcibios_set_master(struct pci_dev *dev); | |||
1643 | int pcibios_set_pcie_reset_state(struct pci_dev *dev, | 1643 | int pcibios_set_pcie_reset_state(struct pci_dev *dev, |
1644 | enum pcie_reset_state state); | 1644 | enum pcie_reset_state state); |
1645 | int pcibios_add_device(struct pci_dev *dev); | 1645 | int pcibios_add_device(struct pci_dev *dev); |
1646 | void pcibios_release_device(struct pci_dev *dev); | ||
1646 | 1647 | ||
1647 | #ifdef CONFIG_PCI_MMCONFIG | 1648 | #ifdef CONFIG_PCI_MMCONFIG |
1648 | void __init pci_mmcfg_early_init(void); | 1649 | void __init pci_mmcfg_early_init(void); |