diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-22 12:32:07 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-22 12:32:07 -0400 |
commit | c8107ed99ad02d519d4fc1c3017ac7cede47e788 (patch) | |
tree | f5dc1703510b8675f97ee3bd2bf13deeaf70af2a | |
parent | 7a6d0071d821965349ff853041f1c1aab496f2d9 (diff) | |
parent | 51dce3867c6c63c7500332e5448c2ba76808d6b5 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 fixes from Martin Schwidefsky:
- A couple of bug fixes: memory management, perf, cio, dasd and
scm_blk.
- A larger change in regard to the CPU topology to improve performance
for systems running under z/VM or KVM.
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
s390/topology: enable / disable topology dynamically
s390/topology: alternative topology for topology-less machines
s390/mm: fix write access check in gup_huge_pmd()
s390/mm: make pmdp_invalidate() do invalidation only
s390/cio: recover from bad paths
s390/scm_blk: consistently use blk_status_t as error type
s390/dasd: fix race during dasd initialization
s390/perf: fix bug when creating per-thread event
-rw-r--r-- | arch/s390/include/asm/pgtable.h | 4 | ||||
-rw-r--r-- | arch/s390/kernel/early.c | 12 | ||||
-rw-r--r-- | arch/s390/kernel/perf_cpum_sf.c | 9 | ||||
-rw-r--r-- | arch/s390/kernel/topology.c | 148 | ||||
-rw-r--r-- | arch/s390/mm/gup.c | 7 | ||||
-rw-r--r-- | drivers/s390/block/dasd.c | 12 | ||||
-rw-r--r-- | drivers/s390/block/scm_blk.c | 6 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 12 | ||||
-rw-r--r-- | drivers/s390/cio/device.h | 1 | ||||
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 12 | ||||
-rw-r--r-- | drivers/s390/cio/io_sch.h | 2 |
11 files changed, 183 insertions, 42 deletions
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index dce708e061ea..20e75a2ca93a 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
@@ -1507,7 +1507,9 @@ static inline pmd_t pmdp_huge_clear_flush(struct vm_area_struct *vma, | |||
1507 | static inline void pmdp_invalidate(struct vm_area_struct *vma, | 1507 | static inline void pmdp_invalidate(struct vm_area_struct *vma, |
1508 | unsigned long addr, pmd_t *pmdp) | 1508 | unsigned long addr, pmd_t *pmdp) |
1509 | { | 1509 | { |
1510 | pmdp_xchg_direct(vma->vm_mm, addr, pmdp, __pmd(_SEGMENT_ENTRY_EMPTY)); | 1510 | pmd_t pmd = __pmd(pmd_val(*pmdp) | _SEGMENT_ENTRY_INVALID); |
1511 | |||
1512 | pmdp_xchg_direct(vma->vm_mm, addr, pmdp, pmd); | ||
1511 | } | 1513 | } |
1512 | 1514 | ||
1513 | #define __HAVE_ARCH_PMDP_SET_WRPROTECT | 1515 | #define __HAVE_ARCH_PMDP_SET_WRPROTECT |
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index ca8cd80e8feb..60181caf8e8a 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c | |||
@@ -404,18 +404,6 @@ static inline void save_vector_registers(void) | |||
404 | #endif | 404 | #endif |
405 | } | 405 | } |
406 | 406 | ||
407 | static int __init topology_setup(char *str) | ||
408 | { | ||
409 | bool enabled; | ||
410 | int rc; | ||
411 | |||
412 | rc = kstrtobool(str, &enabled); | ||
413 | if (!rc && !enabled) | ||
414 | S390_lowcore.machine_flags &= ~MACHINE_FLAG_TOPOLOGY; | ||
415 | return rc; | ||
416 | } | ||
417 | early_param("topology", topology_setup); | ||
418 | |||
419 | static int __init disable_vector_extension(char *str) | 407 | static int __init disable_vector_extension(char *str) |
420 | { | 408 | { |
421 | S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX; | 409 | S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX; |
diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index c1bf75ffb875..7e1e40323b78 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c | |||
@@ -823,9 +823,12 @@ static int cpumsf_pmu_event_init(struct perf_event *event) | |||
823 | } | 823 | } |
824 | 824 | ||
825 | /* Check online status of the CPU to which the event is pinned */ | 825 | /* Check online status of the CPU to which the event is pinned */ |
826 | if ((unsigned int)event->cpu >= nr_cpumask_bits || | 826 | if (event->cpu >= 0) { |
827 | (event->cpu >= 0 && !cpu_online(event->cpu))) | 827 | if ((unsigned int)event->cpu >= nr_cpumask_bits) |
828 | return -ENODEV; | 828 | return -ENODEV; |
829 | if (!cpu_online(event->cpu)) | ||
830 | return -ENODEV; | ||
831 | } | ||
829 | 832 | ||
830 | /* Force reset of idle/hv excludes regardless of what the | 833 | /* Force reset of idle/hv excludes regardless of what the |
831 | * user requested. | 834 | * user requested. |
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index bb47c92476f0..ed0bdd220e1a 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c | |||
@@ -8,6 +8,8 @@ | |||
8 | 8 | ||
9 | #include <linux/workqueue.h> | 9 | #include <linux/workqueue.h> |
10 | #include <linux/bootmem.h> | 10 | #include <linux/bootmem.h> |
11 | #include <linux/uaccess.h> | ||
12 | #include <linux/sysctl.h> | ||
11 | #include <linux/cpuset.h> | 13 | #include <linux/cpuset.h> |
12 | #include <linux/device.h> | 14 | #include <linux/device.h> |
13 | #include <linux/export.h> | 15 | #include <linux/export.h> |
@@ -29,12 +31,20 @@ | |||
29 | #define PTF_VERTICAL (1UL) | 31 | #define PTF_VERTICAL (1UL) |
30 | #define PTF_CHECK (2UL) | 32 | #define PTF_CHECK (2UL) |
31 | 33 | ||
34 | enum { | ||
35 | TOPOLOGY_MODE_HW, | ||
36 | TOPOLOGY_MODE_SINGLE, | ||
37 | TOPOLOGY_MODE_PACKAGE, | ||
38 | TOPOLOGY_MODE_UNINITIALIZED | ||
39 | }; | ||
40 | |||
32 | struct mask_info { | 41 | struct mask_info { |
33 | struct mask_info *next; | 42 | struct mask_info *next; |
34 | unsigned char id; | 43 | unsigned char id; |
35 | cpumask_t mask; | 44 | cpumask_t mask; |
36 | }; | 45 | }; |
37 | 46 | ||
47 | static int topology_mode = TOPOLOGY_MODE_UNINITIALIZED; | ||
38 | static void set_topology_timer(void); | 48 | static void set_topology_timer(void); |
39 | static void topology_work_fn(struct work_struct *work); | 49 | static void topology_work_fn(struct work_struct *work); |
40 | static struct sysinfo_15_1_x *tl_info; | 50 | static struct sysinfo_15_1_x *tl_info; |
@@ -59,11 +69,26 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) | |||
59 | cpumask_t mask; | 69 | cpumask_t mask; |
60 | 70 | ||
61 | cpumask_copy(&mask, cpumask_of(cpu)); | 71 | cpumask_copy(&mask, cpumask_of(cpu)); |
62 | if (!MACHINE_HAS_TOPOLOGY) | 72 | switch (topology_mode) { |
63 | return mask; | 73 | case TOPOLOGY_MODE_HW: |
64 | for (; info; info = info->next) { | 74 | while (info) { |
65 | if (cpumask_test_cpu(cpu, &info->mask)) | 75 | if (cpumask_test_cpu(cpu, &info->mask)) { |
66 | return info->mask; | 76 | mask = info->mask; |
77 | break; | ||
78 | } | ||
79 | info = info->next; | ||
80 | } | ||
81 | if (cpumask_empty(&mask)) | ||
82 | cpumask_copy(&mask, cpumask_of(cpu)); | ||
83 | break; | ||
84 | case TOPOLOGY_MODE_PACKAGE: | ||
85 | cpumask_copy(&mask, cpu_present_mask); | ||
86 | break; | ||
87 | default: | ||
88 | /* fallthrough */ | ||
89 | case TOPOLOGY_MODE_SINGLE: | ||
90 | cpumask_copy(&mask, cpumask_of(cpu)); | ||
91 | break; | ||
67 | } | 92 | } |
68 | return mask; | 93 | return mask; |
69 | } | 94 | } |
@@ -74,7 +99,7 @@ static cpumask_t cpu_thread_map(unsigned int cpu) | |||
74 | int i; | 99 | int i; |
75 | 100 | ||
76 | cpumask_copy(&mask, cpumask_of(cpu)); | 101 | cpumask_copy(&mask, cpumask_of(cpu)); |
77 | if (!MACHINE_HAS_TOPOLOGY) | 102 | if (topology_mode != TOPOLOGY_MODE_HW) |
78 | return mask; | 103 | return mask; |
79 | cpu -= cpu % (smp_cpu_mtid + 1); | 104 | cpu -= cpu % (smp_cpu_mtid + 1); |
80 | for (i = 0; i <= smp_cpu_mtid; i++) | 105 | for (i = 0; i <= smp_cpu_mtid; i++) |
@@ -184,10 +209,8 @@ static void topology_update_polarization_simple(void) | |||
184 | { | 209 | { |
185 | int cpu; | 210 | int cpu; |
186 | 211 | ||
187 | mutex_lock(&smp_cpu_state_mutex); | ||
188 | for_each_possible_cpu(cpu) | 212 | for_each_possible_cpu(cpu) |
189 | smp_cpu_set_polarization(cpu, POLARIZATION_HRZ); | 213 | smp_cpu_set_polarization(cpu, POLARIZATION_HRZ); |
190 | mutex_unlock(&smp_cpu_state_mutex); | ||
191 | } | 214 | } |
192 | 215 | ||
193 | static int ptf(unsigned long fc) | 216 | static int ptf(unsigned long fc) |
@@ -223,7 +246,7 @@ int topology_set_cpu_management(int fc) | |||
223 | static void update_cpu_masks(void) | 246 | static void update_cpu_masks(void) |
224 | { | 247 | { |
225 | struct cpu_topology_s390 *topo; | 248 | struct cpu_topology_s390 *topo; |
226 | int cpu; | 249 | int cpu, id; |
227 | 250 | ||
228 | for_each_possible_cpu(cpu) { | 251 | for_each_possible_cpu(cpu) { |
229 | topo = &cpu_topology[cpu]; | 252 | topo = &cpu_topology[cpu]; |
@@ -231,12 +254,13 @@ static void update_cpu_masks(void) | |||
231 | topo->core_mask = cpu_group_map(&socket_info, cpu); | 254 | topo->core_mask = cpu_group_map(&socket_info, cpu); |
232 | topo->book_mask = cpu_group_map(&book_info, cpu); | 255 | topo->book_mask = cpu_group_map(&book_info, cpu); |
233 | topo->drawer_mask = cpu_group_map(&drawer_info, cpu); | 256 | topo->drawer_mask = cpu_group_map(&drawer_info, cpu); |
234 | if (!MACHINE_HAS_TOPOLOGY) { | 257 | if (topology_mode != TOPOLOGY_MODE_HW) { |
258 | id = topology_mode == TOPOLOGY_MODE_PACKAGE ? 0 : cpu; | ||
235 | topo->thread_id = cpu; | 259 | topo->thread_id = cpu; |
236 | topo->core_id = cpu; | 260 | topo->core_id = cpu; |
237 | topo->socket_id = cpu; | 261 | topo->socket_id = id; |
238 | topo->book_id = cpu; | 262 | topo->book_id = id; |
239 | topo->drawer_id = cpu; | 263 | topo->drawer_id = id; |
240 | if (cpu_present(cpu)) | 264 | if (cpu_present(cpu)) |
241 | cpumask_set_cpu(cpu, &cpus_with_topology); | 265 | cpumask_set_cpu(cpu, &cpus_with_topology); |
242 | } | 266 | } |
@@ -254,6 +278,7 @@ static int __arch_update_cpu_topology(void) | |||
254 | struct sysinfo_15_1_x *info = tl_info; | 278 | struct sysinfo_15_1_x *info = tl_info; |
255 | int rc = 0; | 279 | int rc = 0; |
256 | 280 | ||
281 | mutex_lock(&smp_cpu_state_mutex); | ||
257 | cpumask_clear(&cpus_with_topology); | 282 | cpumask_clear(&cpus_with_topology); |
258 | if (MACHINE_HAS_TOPOLOGY) { | 283 | if (MACHINE_HAS_TOPOLOGY) { |
259 | rc = 1; | 284 | rc = 1; |
@@ -263,6 +288,7 @@ static int __arch_update_cpu_topology(void) | |||
263 | update_cpu_masks(); | 288 | update_cpu_masks(); |
264 | if (!MACHINE_HAS_TOPOLOGY) | 289 | if (!MACHINE_HAS_TOPOLOGY) |
265 | topology_update_polarization_simple(); | 290 | topology_update_polarization_simple(); |
291 | mutex_unlock(&smp_cpu_state_mutex); | ||
266 | return rc; | 292 | return rc; |
267 | } | 293 | } |
268 | 294 | ||
@@ -289,6 +315,11 @@ void topology_schedule_update(void) | |||
289 | schedule_work(&topology_work); | 315 | schedule_work(&topology_work); |
290 | } | 316 | } |
291 | 317 | ||
318 | static void topology_flush_work(void) | ||
319 | { | ||
320 | flush_work(&topology_work); | ||
321 | } | ||
322 | |||
292 | static void topology_timer_fn(unsigned long ignored) | 323 | static void topology_timer_fn(unsigned long ignored) |
293 | { | 324 | { |
294 | if (ptf(PTF_CHECK)) | 325 | if (ptf(PTF_CHECK)) |
@@ -459,6 +490,12 @@ void __init topology_init_early(void) | |||
459 | struct sysinfo_15_1_x *info; | 490 | struct sysinfo_15_1_x *info; |
460 | 491 | ||
461 | set_sched_topology(s390_topology); | 492 | set_sched_topology(s390_topology); |
493 | if (topology_mode == TOPOLOGY_MODE_UNINITIALIZED) { | ||
494 | if (MACHINE_HAS_TOPOLOGY) | ||
495 | topology_mode = TOPOLOGY_MODE_HW; | ||
496 | else | ||
497 | topology_mode = TOPOLOGY_MODE_SINGLE; | ||
498 | } | ||
462 | if (!MACHINE_HAS_TOPOLOGY) | 499 | if (!MACHINE_HAS_TOPOLOGY) |
463 | goto out; | 500 | goto out; |
464 | tl_info = memblock_virt_alloc(PAGE_SIZE, PAGE_SIZE); | 501 | tl_info = memblock_virt_alloc(PAGE_SIZE, PAGE_SIZE); |
@@ -474,12 +511,97 @@ out: | |||
474 | __arch_update_cpu_topology(); | 511 | __arch_update_cpu_topology(); |
475 | } | 512 | } |
476 | 513 | ||
514 | static inline int topology_get_mode(int enabled) | ||
515 | { | ||
516 | if (!enabled) | ||
517 | return TOPOLOGY_MODE_SINGLE; | ||
518 | return MACHINE_HAS_TOPOLOGY ? TOPOLOGY_MODE_HW : TOPOLOGY_MODE_PACKAGE; | ||
519 | } | ||
520 | |||
521 | static inline int topology_is_enabled(void) | ||
522 | { | ||
523 | return topology_mode != TOPOLOGY_MODE_SINGLE; | ||
524 | } | ||
525 | |||
526 | static int __init topology_setup(char *str) | ||
527 | { | ||
528 | bool enabled; | ||
529 | int rc; | ||
530 | |||
531 | rc = kstrtobool(str, &enabled); | ||
532 | if (rc) | ||
533 | return rc; | ||
534 | topology_mode = topology_get_mode(enabled); | ||
535 | return 0; | ||
536 | } | ||
537 | early_param("topology", topology_setup); | ||
538 | |||
539 | static int topology_ctl_handler(struct ctl_table *ctl, int write, | ||
540 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
541 | { | ||
542 | unsigned int len; | ||
543 | int new_mode; | ||
544 | char buf[2]; | ||
545 | |||
546 | if (!*lenp || *ppos) { | ||
547 | *lenp = 0; | ||
548 | return 0; | ||
549 | } | ||
550 | if (!write) { | ||
551 | strncpy(buf, topology_is_enabled() ? "1\n" : "0\n", | ||
552 | ARRAY_SIZE(buf)); | ||
553 | len = strnlen(buf, ARRAY_SIZE(buf)); | ||
554 | if (len > *lenp) | ||
555 | len = *lenp; | ||
556 | if (copy_to_user(buffer, buf, len)) | ||
557 | return -EFAULT; | ||
558 | goto out; | ||
559 | } | ||
560 | len = *lenp; | ||
561 | if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len)) | ||
562 | return -EFAULT; | ||
563 | if (buf[0] != '0' && buf[0] != '1') | ||
564 | return -EINVAL; | ||
565 | mutex_lock(&smp_cpu_state_mutex); | ||
566 | new_mode = topology_get_mode(buf[0] == '1'); | ||
567 | if (topology_mode != new_mode) { | ||
568 | topology_mode = new_mode; | ||
569 | topology_schedule_update(); | ||
570 | } | ||
571 | mutex_unlock(&smp_cpu_state_mutex); | ||
572 | topology_flush_work(); | ||
573 | out: | ||
574 | *lenp = len; | ||
575 | *ppos += len; | ||
576 | return 0; | ||
577 | } | ||
578 | |||
579 | static struct ctl_table topology_ctl_table[] = { | ||
580 | { | ||
581 | .procname = "topology", | ||
582 | .mode = 0644, | ||
583 | .proc_handler = topology_ctl_handler, | ||
584 | }, | ||
585 | { }, | ||
586 | }; | ||
587 | |||
588 | static struct ctl_table topology_dir_table[] = { | ||
589 | { | ||
590 | .procname = "s390", | ||
591 | .maxlen = 0, | ||
592 | .mode = 0555, | ||
593 | .child = topology_ctl_table, | ||
594 | }, | ||
595 | { }, | ||
596 | }; | ||
597 | |||
477 | static int __init topology_init(void) | 598 | static int __init topology_init(void) |
478 | { | 599 | { |
479 | if (MACHINE_HAS_TOPOLOGY) | 600 | if (MACHINE_HAS_TOPOLOGY) |
480 | set_topology_timer(); | 601 | set_topology_timer(); |
481 | else | 602 | else |
482 | topology_update_polarization_simple(); | 603 | topology_update_polarization_simple(); |
604 | register_sysctl_table(topology_dir_table); | ||
483 | return device_create_file(cpu_subsys.dev_root, &dev_attr_dispatching); | 605 | return device_create_file(cpu_subsys.dev_root, &dev_attr_dispatching); |
484 | } | 606 | } |
485 | device_initcall(topology_init); | 607 | device_initcall(topology_init); |
diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c index 8ecc25e760fa..98ffe3ee9411 100644 --- a/arch/s390/mm/gup.c +++ b/arch/s390/mm/gup.c | |||
@@ -56,13 +56,12 @@ static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr, | |||
56 | static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr, | 56 | static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr, |
57 | unsigned long end, int write, struct page **pages, int *nr) | 57 | unsigned long end, int write, struct page **pages, int *nr) |
58 | { | 58 | { |
59 | unsigned long mask, result; | ||
60 | struct page *head, *page; | 59 | struct page *head, *page; |
60 | unsigned long mask; | ||
61 | int refs; | 61 | int refs; |
62 | 62 | ||
63 | result = write ? 0 : _SEGMENT_ENTRY_PROTECT; | 63 | mask = (write ? _SEGMENT_ENTRY_PROTECT : 0) | _SEGMENT_ENTRY_INVALID; |
64 | mask = result | _SEGMENT_ENTRY_INVALID; | 64 | if ((pmd_val(pmd) & mask) != 0) |
65 | if ((pmd_val(pmd) & mask) != result) | ||
66 | return 0; | 65 | return 0; |
67 | VM_BUG_ON(!pfn_valid(pmd_val(pmd) >> PAGE_SHIFT)); | 66 | VM_BUG_ON(!pfn_valid(pmd_val(pmd) >> PAGE_SHIFT)); |
68 | 67 | ||
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index ea19b4ff87a2..29f35e29d480 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -1644,7 +1644,9 @@ void dasd_generic_handle_state_change(struct dasd_device *device) | |||
1644 | dasd_schedule_device_bh(device); | 1644 | dasd_schedule_device_bh(device); |
1645 | if (device->block) { | 1645 | if (device->block) { |
1646 | dasd_schedule_block_bh(device->block); | 1646 | dasd_schedule_block_bh(device->block); |
1647 | blk_mq_run_hw_queues(device->block->request_queue, true); | 1647 | if (device->block->request_queue) |
1648 | blk_mq_run_hw_queues(device->block->request_queue, | ||
1649 | true); | ||
1648 | } | 1650 | } |
1649 | } | 1651 | } |
1650 | EXPORT_SYMBOL_GPL(dasd_generic_handle_state_change); | 1652 | EXPORT_SYMBOL_GPL(dasd_generic_handle_state_change); |
@@ -3759,7 +3761,9 @@ int dasd_generic_path_operational(struct dasd_device *device) | |||
3759 | dasd_schedule_device_bh(device); | 3761 | dasd_schedule_device_bh(device); |
3760 | if (device->block) { | 3762 | if (device->block) { |
3761 | dasd_schedule_block_bh(device->block); | 3763 | dasd_schedule_block_bh(device->block); |
3762 | blk_mq_run_hw_queues(device->block->request_queue, true); | 3764 | if (device->block->request_queue) |
3765 | blk_mq_run_hw_queues(device->block->request_queue, | ||
3766 | true); | ||
3763 | } | 3767 | } |
3764 | 3768 | ||
3765 | if (!device->stopped) | 3769 | if (!device->stopped) |
@@ -4025,7 +4029,9 @@ int dasd_generic_restore_device(struct ccw_device *cdev) | |||
4025 | 4029 | ||
4026 | if (device->block) { | 4030 | if (device->block) { |
4027 | dasd_schedule_block_bh(device->block); | 4031 | dasd_schedule_block_bh(device->block); |
4028 | blk_mq_run_hw_queues(device->block->request_queue, true); | 4032 | if (device->block->request_queue) |
4033 | blk_mq_run_hw_queues(device->block->request_queue, | ||
4034 | true); | ||
4029 | } | 4035 | } |
4030 | 4036 | ||
4031 | clear_bit(DASD_FLAG_SUSPENDED, &device->flags); | 4037 | clear_bit(DASD_FLAG_SUSPENDED, &device->flags); |
diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c index 2e7fd966c515..eb51893c74a4 100644 --- a/drivers/s390/block/scm_blk.c +++ b/drivers/s390/block/scm_blk.c | |||
@@ -249,7 +249,7 @@ static void scm_request_requeue(struct scm_request *scmrq) | |||
249 | static void scm_request_finish(struct scm_request *scmrq) | 249 | static void scm_request_finish(struct scm_request *scmrq) |
250 | { | 250 | { |
251 | struct scm_blk_dev *bdev = scmrq->bdev; | 251 | struct scm_blk_dev *bdev = scmrq->bdev; |
252 | int *error; | 252 | blk_status_t *error; |
253 | int i; | 253 | int i; |
254 | 254 | ||
255 | for (i = 0; i < nr_requests_per_io && scmrq->request[i]; i++) { | 255 | for (i = 0; i < nr_requests_per_io && scmrq->request[i]; i++) { |
@@ -415,7 +415,7 @@ void scm_blk_irq(struct scm_device *scmdev, void *data, blk_status_t error) | |||
415 | 415 | ||
416 | static void scm_blk_request_done(struct request *req) | 416 | static void scm_blk_request_done(struct request *req) |
417 | { | 417 | { |
418 | int *error = blk_mq_rq_to_pdu(req); | 418 | blk_status_t *error = blk_mq_rq_to_pdu(req); |
419 | 419 | ||
420 | blk_mq_end_request(req, *error); | 420 | blk_mq_end_request(req, *error); |
421 | } | 421 | } |
@@ -450,7 +450,7 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev) | |||
450 | atomic_set(&bdev->queued_reqs, 0); | 450 | atomic_set(&bdev->queued_reqs, 0); |
451 | 451 | ||
452 | bdev->tag_set.ops = &scm_mq_ops; | 452 | bdev->tag_set.ops = &scm_mq_ops; |
453 | bdev->tag_set.cmd_size = sizeof(int); | 453 | bdev->tag_set.cmd_size = sizeof(blk_status_t); |
454 | bdev->tag_set.nr_hw_queues = nr_requests; | 454 | bdev->tag_set.nr_hw_queues = nr_requests; |
455 | bdev->tag_set.queue_depth = nr_requests_per_io * nr_requests; | 455 | bdev->tag_set.queue_depth = nr_requests_per_io * nr_requests; |
456 | bdev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; | 456 | bdev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 489b583f263d..e5c32f4b5287 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -1225,10 +1225,16 @@ static int device_is_disconnected(struct ccw_device *cdev) | |||
1225 | static int recovery_check(struct device *dev, void *data) | 1225 | static int recovery_check(struct device *dev, void *data) |
1226 | { | 1226 | { |
1227 | struct ccw_device *cdev = to_ccwdev(dev); | 1227 | struct ccw_device *cdev = to_ccwdev(dev); |
1228 | struct subchannel *sch; | ||
1228 | int *redo = data; | 1229 | int *redo = data; |
1229 | 1230 | ||
1230 | spin_lock_irq(cdev->ccwlock); | 1231 | spin_lock_irq(cdev->ccwlock); |
1231 | switch (cdev->private->state) { | 1232 | switch (cdev->private->state) { |
1233 | case DEV_STATE_ONLINE: | ||
1234 | sch = to_subchannel(cdev->dev.parent); | ||
1235 | if ((sch->schib.pmcw.pam & sch->opm) == sch->vpm) | ||
1236 | break; | ||
1237 | /* fall through */ | ||
1232 | case DEV_STATE_DISCONNECTED: | 1238 | case DEV_STATE_DISCONNECTED: |
1233 | CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n", | 1239 | CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n", |
1234 | cdev->private->dev_id.ssid, | 1240 | cdev->private->dev_id.ssid, |
@@ -1260,7 +1266,7 @@ static void recovery_work_func(struct work_struct *unused) | |||
1260 | } | 1266 | } |
1261 | spin_unlock_irq(&recovery_lock); | 1267 | spin_unlock_irq(&recovery_lock); |
1262 | } else | 1268 | } else |
1263 | CIO_MSG_EVENT(4, "recovery: end\n"); | 1269 | CIO_MSG_EVENT(3, "recovery: end\n"); |
1264 | } | 1270 | } |
1265 | 1271 | ||
1266 | static DECLARE_WORK(recovery_work, recovery_work_func); | 1272 | static DECLARE_WORK(recovery_work, recovery_work_func); |
@@ -1274,11 +1280,11 @@ static void recovery_func(unsigned long data) | |||
1274 | schedule_work(&recovery_work); | 1280 | schedule_work(&recovery_work); |
1275 | } | 1281 | } |
1276 | 1282 | ||
1277 | static void ccw_device_schedule_recovery(void) | 1283 | void ccw_device_schedule_recovery(void) |
1278 | { | 1284 | { |
1279 | unsigned long flags; | 1285 | unsigned long flags; |
1280 | 1286 | ||
1281 | CIO_MSG_EVENT(4, "recovery: schedule\n"); | 1287 | CIO_MSG_EVENT(3, "recovery: schedule\n"); |
1282 | spin_lock_irqsave(&recovery_lock, flags); | 1288 | spin_lock_irqsave(&recovery_lock, flags); |
1283 | if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) { | 1289 | if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) { |
1284 | recovery_phase = 0; | 1290 | recovery_phase = 0; |
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index ec497af99dd8..69cb70f080a5 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h | |||
@@ -134,6 +134,7 @@ void ccw_device_set_disconnected(struct ccw_device *cdev); | |||
134 | void ccw_device_set_notoper(struct ccw_device *cdev); | 134 | void ccw_device_set_notoper(struct ccw_device *cdev); |
135 | 135 | ||
136 | void ccw_device_set_timeout(struct ccw_device *, int); | 136 | void ccw_device_set_timeout(struct ccw_device *, int); |
137 | void ccw_device_schedule_recovery(void); | ||
137 | 138 | ||
138 | /* Channel measurement facility related */ | 139 | /* Channel measurement facility related */ |
139 | void retry_set_schib(struct ccw_device *cdev); | 140 | void retry_set_schib(struct ccw_device *cdev); |
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 12016e32e519..f98ea674c3d8 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -476,6 +476,17 @@ static void create_fake_irb(struct irb *irb, int type) | |||
476 | } | 476 | } |
477 | } | 477 | } |
478 | 478 | ||
479 | static void ccw_device_handle_broken_paths(struct ccw_device *cdev) | ||
480 | { | ||
481 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | ||
482 | u8 broken_paths = (sch->schib.pmcw.pam & sch->opm) ^ sch->vpm; | ||
483 | |||
484 | if (broken_paths && (cdev->private->path_broken_mask != broken_paths)) | ||
485 | ccw_device_schedule_recovery(); | ||
486 | |||
487 | cdev->private->path_broken_mask = broken_paths; | ||
488 | } | ||
489 | |||
479 | void ccw_device_verify_done(struct ccw_device *cdev, int err) | 490 | void ccw_device_verify_done(struct ccw_device *cdev, int err) |
480 | { | 491 | { |
481 | struct subchannel *sch; | 492 | struct subchannel *sch; |
@@ -508,6 +519,7 @@ callback: | |||
508 | memset(&cdev->private->irb, 0, sizeof(struct irb)); | 519 | memset(&cdev->private->irb, 0, sizeof(struct irb)); |
509 | } | 520 | } |
510 | ccw_device_report_path_events(cdev); | 521 | ccw_device_report_path_events(cdev); |
522 | ccw_device_handle_broken_paths(cdev); | ||
511 | break; | 523 | break; |
512 | case -ETIME: | 524 | case -ETIME: |
513 | case -EUSERS: | 525 | case -EUSERS: |
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index 220f49145b2f..9a1b56b2df3e 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h | |||
@@ -131,6 +131,8 @@ struct ccw_device_private { | |||
131 | not operable */ | 131 | not operable */ |
132 | u8 path_gone_mask; /* mask of paths, that became unavailable */ | 132 | u8 path_gone_mask; /* mask of paths, that became unavailable */ |
133 | u8 path_new_mask; /* mask of paths, that became available */ | 133 | u8 path_new_mask; /* mask of paths, that became available */ |
134 | u8 path_broken_mask; /* mask of paths, which were found to be | ||
135 | unusable */ | ||
134 | struct { | 136 | struct { |
135 | unsigned int fast:1; /* post with "channel end" */ | 137 | unsigned int fast:1; /* post with "channel end" */ |
136 | unsigned int repall:1; /* report every interrupt status */ | 138 | unsigned int repall:1; /* report every interrupt status */ |