aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/cio/chp.c49
-rw-r--r--drivers/s390/cio/chp.h1
-rw-r--r--drivers/s390/cio/chsc.c25
-rw-r--r--drivers/s390/cio/chsc.h2
-rw-r--r--drivers/s390/cio/css.c31
-rw-r--r--drivers/s390/cio/css.h1
-rw-r--r--drivers/s390/s390mach.c102
-rw-r--r--drivers/s390/s390mach.h7
8 files changed, 140 insertions, 78 deletions
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index 297f1653b52b..672d9731c525 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -18,6 +18,7 @@
18#include <asm/chpid.h> 18#include <asm/chpid.h>
19#include <asm/sclp.h> 19#include <asm/sclp.h>
20 20
21#include "../s390mach.h"
21#include "cio.h" 22#include "cio.h"
22#include "css.h" 23#include "css.h"
23#include "ioasm.h" 24#include "ioasm.h"
@@ -476,24 +477,52 @@ void *chp_get_chp_desc(struct chp_id chpid)
476 477
477/** 478/**
478 * chp_process_crw - process channel-path status change 479 * chp_process_crw - process channel-path status change
479 * @id: channel-path ID number 480 * @crw0: channel report-word to handler
480 * @status: non-zero if channel-path has become available, zero otherwise 481 * @crw1: second channel-report word (always NULL)
482 * @overflow: crw overflow indication
481 * 483 *
482 * Handle channel-report-words indicating that the status of a channel-path 484 * Handle channel-report-words indicating that the status of a channel-path
483 * has changed. 485 * has changed.
484 */ 486 */
485void chp_process_crw(int id, int status) 487static void chp_process_crw(struct crw *crw0, struct crw *crw1,
488 int overflow)
486{ 489{
487 struct chp_id chpid; 490 struct chp_id chpid;
488 491
492 if (overflow) {
493 css_schedule_eval_all();
494 return;
495 }
496 CIO_CRW_EVENT(2, "CRW reports slct=%d, oflw=%d, "
497 "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
498 crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc,
499 crw0->erc, crw0->rsid);
500 /*
501 * Check for solicited machine checks. These are
502 * created by reset channel path and need not be
503 * handled here.
504 */
505 if (crw0->slct) {
506 CIO_CRW_EVENT(2, "solicited machine check for "
507 "channel path %02X\n", crw0->rsid);
508 return;
509 }
489 chp_id_init(&chpid); 510 chp_id_init(&chpid);
490 chpid.id = id; 511 chpid.id = crw0->rsid;
491 if (status) { 512 switch (crw0->erc) {
513 case CRW_ERC_IPARM: /* Path has come. */
492 if (!chp_is_registered(chpid)) 514 if (!chp_is_registered(chpid))
493 chp_new(chpid); 515 chp_new(chpid);
494 chsc_chp_online(chpid); 516 chsc_chp_online(chpid);
495 } else 517 break;
518 case CRW_ERC_PERRI: /* Path has gone. */
519 case CRW_ERC_PERRN:
496 chsc_chp_offline(chpid); 520 chsc_chp_offline(chpid);
521 break;
522 default:
523 CIO_CRW_EVENT(2, "Don't know how to handle erc=%x\n",
524 crw0->erc);
525 }
497} 526}
498 527
499int chp_ssd_get_mask(struct chsc_ssd_info *ssd, struct res_acc_data *data) 528int chp_ssd_get_mask(struct chsc_ssd_info *ssd, struct res_acc_data *data)
@@ -674,10 +703,16 @@ static int cfg_wait_idle(void)
674static int __init chp_init(void) 703static int __init chp_init(void)
675{ 704{
676 struct chp_id chpid; 705 struct chp_id chpid;
706 int ret;
677 707
708 ret = s390_register_crw_handler(CRW_RSC_CPATH, chp_process_crw);
709 if (ret)
710 return ret;
678 chp_wq = create_singlethread_workqueue("cio_chp"); 711 chp_wq = create_singlethread_workqueue("cio_chp");
679 if (!chp_wq) 712 if (!chp_wq) {
713 s390_unregister_crw_handler(CRW_RSC_CPATH);
680 return -ENOMEM; 714 return -ENOMEM;
715 }
681 INIT_WORK(&cfg_work, cfg_func); 716 INIT_WORK(&cfg_work, cfg_func);
682 init_waitqueue_head(&cfg_wait_queue); 717 init_waitqueue_head(&cfg_wait_queue);
683 if (info_update()) 718 if (info_update())
diff --git a/drivers/s390/cio/chp.h b/drivers/s390/cio/chp.h
index f03b0d2cdc09..dffe2771ddac 100644
--- a/drivers/s390/cio/chp.h
+++ b/drivers/s390/cio/chp.h
@@ -54,7 +54,6 @@ int chp_get_status(struct chp_id chpid);
54u8 chp_get_sch_opm(struct subchannel *sch); 54u8 chp_get_sch_opm(struct subchannel *sch);
55int chp_is_registered(struct chp_id chpid); 55int chp_is_registered(struct chp_id chpid);
56void *chp_get_chp_desc(struct chp_id chpid); 56void *chp_get_chp_desc(struct chp_id chpid);
57void chp_process_crw(int id, int available);
58void chp_remove_cmg_attr(struct channel_path *chp); 57void chp_remove_cmg_attr(struct channel_path *chp);
59int chp_add_cmg_attr(struct channel_path *chp); 58int chp_add_cmg_attr(struct channel_path *chp);
60int chp_new(struct chp_id chpid); 59int chp_new(struct chp_id chpid);
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 1c0f5db94c7b..cb36f7929786 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -16,6 +16,7 @@
16#include <asm/cio.h> 16#include <asm/cio.h>
17#include <asm/chpid.h> 17#include <asm/chpid.h>
18 18
19#include "../s390mach.h"
19#include "css.h" 20#include "css.h"
20#include "cio.h" 21#include "cio.h"
21#include "cio_debug.h" 22#include "cio_debug.h"
@@ -372,17 +373,25 @@ static void chsc_process_sei(struct chsc_sei_area *sei_area)
372 } 373 }
373} 374}
374 375
375void chsc_process_crw(void) 376static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
376{ 377{
377 struct chsc_sei_area *sei_area; 378 struct chsc_sei_area *sei_area;
378 379
380 if (overflow) {
381 css_schedule_eval_all();
382 return;
383 }
384 CIO_CRW_EVENT(2, "CRW reports slct=%d, oflw=%d, "
385 "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
386 crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc,
387 crw0->erc, crw0->rsid);
379 if (!sei_page) 388 if (!sei_page)
380 return; 389 return;
381 /* Access to sei_page is serialized through machine check handler 390 /* Access to sei_page is serialized through machine check handler
382 * thread, so no need for locking. */ 391 * thread, so no need for locking. */
383 sei_area = sei_page; 392 sei_area = sei_page;
384 393
385 CIO_TRACE_EVENT( 2, "prcss"); 394 CIO_TRACE_EVENT(2, "prcss");
386 do { 395 do {
387 memset(sei_area, 0, sizeof(*sei_area)); 396 memset(sei_area, 0, sizeof(*sei_area));
388 sei_area->request.length = 0x0010; 397 sei_area->request.length = 0x0010;
@@ -751,15 +760,23 @@ out:
751 760
752int __init chsc_alloc_sei_area(void) 761int __init chsc_alloc_sei_area(void)
753{ 762{
763 int ret;
764
754 sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); 765 sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
755 if (!sei_page) 766 if (!sei_page) {
756 CIO_MSG_EVENT(0, "Can't allocate page for processing of " 767 CIO_MSG_EVENT(0, "Can't allocate page for processing of "
757 "chsc machine checks!\n"); 768 "chsc machine checks!\n");
758 return (sei_page ? 0 : -ENOMEM); 769 return -ENOMEM;
770 }
771 ret = s390_register_crw_handler(CRW_RSC_CSS, chsc_process_crw);
772 if (ret)
773 kfree(sei_page);
774 return ret;
759} 775}
760 776
761void __init chsc_free_sei_area(void) 777void __init chsc_free_sei_area(void)
762{ 778{
779 s390_unregister_crw_handler(CRW_RSC_CSS);
763 kfree(sei_page); 780 kfree(sei_page);
764} 781}
765 782
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index d1f5db1e69b9..3b7c044d8453 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -36,8 +36,6 @@ struct channel_path_desc {
36 36
37struct channel_path; 37struct channel_path;
38 38
39extern void chsc_process_crw(void);
40
41struct css_general_char { 39struct css_general_char {
42 u64 : 41; 40 u64 : 41;
43 u32 aif : 1; /* bit 41 */ 41 u32 aif : 1; /* bit 41 */
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 020566571e07..cf9d27c6f444 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -14,6 +14,7 @@
14#include <linux/list.h> 14#include <linux/list.h>
15#include <linux/reboot.h> 15#include <linux/reboot.h>
16 16
17#include "../s390mach.h"
17#include "css.h" 18#include "css.h"
18#include "cio.h" 19#include "cio.h"
19#include "cio_debug.h" 20#include "cio_debug.h"
@@ -530,18 +531,29 @@ EXPORT_SYMBOL_GPL(css_schedule_reprobe);
530/* 531/*
531 * Called from the machine check handler for subchannel report words. 532 * Called from the machine check handler for subchannel report words.
532 */ 533 */
533void css_process_crw(int rsid1, int rsid2) 534static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
534{ 535{
535 struct subchannel_id mchk_schid; 536 struct subchannel_id mchk_schid;
536 537
537 CIO_CRW_EVENT(2, "source is subchannel %04X, subsystem id %x\n", 538 if (overflow) {
538 rsid1, rsid2); 539 css_schedule_eval_all();
540 return;
541 }
542 CIO_CRW_EVENT(2, "CRW0 reports slct=%d, oflw=%d, "
543 "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
544 crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc,
545 crw0->erc, crw0->rsid);
546 if (crw1)
547 CIO_CRW_EVENT(2, "CRW1 reports slct=%d, oflw=%d, "
548 "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
549 crw1->slct, crw1->oflw, crw1->chn, crw1->rsc,
550 crw1->anc, crw1->erc, crw1->rsid);
539 init_subchannel_id(&mchk_schid); 551 init_subchannel_id(&mchk_schid);
540 mchk_schid.sch_no = rsid1; 552 mchk_schid.sch_no = crw0->rsid;
541 if (rsid2 != 0) 553 if (crw1)
542 mchk_schid.ssid = (rsid2 >> 8) & 3; 554 mchk_schid.ssid = (crw1->rsid >> 8) & 3;
543 555
544 /* 556 /*
545 * Since we are always presented with IPI in the CRW, we have to 557 * Since we are always presented with IPI in the CRW, we have to
546 * use stsch() to find out if the subchannel in question has come 558 * use stsch() to find out if the subchannel in question has come
547 * or gone. 559 * or gone.
@@ -740,6 +752,10 @@ init_channel_subsystem (void)
740 if (ret) 752 if (ret)
741 goto out; 753 goto out;
742 754
755 ret = s390_register_crw_handler(CRW_RSC_SCH, css_process_crw);
756 if (ret)
757 goto out;
758
743 if ((ret = bus_register(&css_bus_type))) 759 if ((ret = bus_register(&css_bus_type)))
744 goto out; 760 goto out;
745 761
@@ -817,6 +833,7 @@ out_unregister:
817out_bus: 833out_bus:
818 bus_unregister(&css_bus_type); 834 bus_unregister(&css_bus_type);
819out: 835out:
836 s390_unregister_crw_handler(CRW_RSC_CSS);
820 chsc_free_sei_area(); 837 chsc_free_sei_area();
821 kfree(slow_subchannel_set); 838 kfree(slow_subchannel_set);
822 printk(KERN_WARNING"cio: failed to initialize css driver (%d)!\n", 839 printk(KERN_WARNING"cio: failed to initialize css driver (%d)!\n",
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 4cdc132c86bb..3ec3dc5a1e5e 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -103,7 +103,6 @@ int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
103 int (*fn_unknown)(struct subchannel_id, 103 int (*fn_unknown)(struct subchannel_id,
104 void *), void *data); 104 void *), void *data);
105extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); 105extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
106extern void css_process_crw(int, int);
107extern void css_reiterate_subchannels(void); 106extern void css_reiterate_subchannels(void);
108void css_update_ssd_info(struct subchannel *sch); 107void css_update_ssd_info(struct subchannel *sch);
109 108
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index 5bfbe7659830..fe75152a5084 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -2,10 +2,10 @@
2 * drivers/s390/s390mach.c 2 * drivers/s390/s390mach.c
3 * S/390 machine check handler 3 * S/390 machine check handler
4 * 4 *
5 * S390 version 5 * Copyright IBM Corp. 2000,2008
6 * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Author(s): Ingo Adlung (adlung@de.ibm.com) 6 * Author(s): Ingo Adlung (adlung@de.ibm.com)
8 * Martin Schwidefsky (schwidefsky@de.ibm.com) 7 * Martin Schwidefsky (schwidefsky@de.ibm.com)
8 * Cornelia Huck <cornelia.huck@de.ibm.com>
9 */ 9 */
10 10
11#include <linux/init.h> 11#include <linux/init.h>
@@ -18,10 +18,6 @@
18#include <asm/etr.h> 18#include <asm/etr.h>
19#include <asm/lowcore.h> 19#include <asm/lowcore.h>
20#include <asm/cio.h> 20#include <asm/cio.h>
21#include "cio/cio.h"
22#include "cio/chsc.h"
23#include "cio/css.h"
24#include "cio/chp.h"
25#include "s390mach.h" 21#include "s390mach.h"
26 22
27static struct semaphore m_sem; 23static struct semaphore m_sem;
@@ -36,13 +32,40 @@ s390_handle_damage(char *msg)
36 for(;;); 32 for(;;);
37} 33}
38 34
35static crw_handler_t crw_handlers[NR_RSCS];
36
37/**
38 * s390_register_crw_handler() - register a channel report word handler
39 * @rsc: reporting source code to handle
40 * @handler: handler to be registered
41 *
42 * Returns %0 on success and a negative error value otherwise.
43 */
44int s390_register_crw_handler(int rsc, crw_handler_t handler)
45{
46 if ((rsc < 0) || (rsc >= NR_RSCS))
47 return -EINVAL;
48 if (!cmpxchg(&crw_handlers[rsc], NULL, handler))
49 return 0;
50 return -EBUSY;
51}
52
53/**
54 * s390_unregister_crw_handler() - unregister a channel report word handler
55 * @rsc: reporting source code to handle
56 */
57void s390_unregister_crw_handler(int rsc)
58{
59 if ((rsc < 0) || (rsc >= NR_RSCS))
60 return;
61 xchg(&crw_handlers[rsc], NULL);
62 synchronize_sched();
63}
64
39/* 65/*
40 * Retrieve CRWs and call function to handle event. 66 * Retrieve CRWs and call function to handle event.
41 *
42 * Note : we currently process CRWs for io and chsc subchannels only
43 */ 67 */
44static int 68static int s390_collect_crw_info(void *param)
45s390_collect_crw_info(void *param)
46{ 69{
47 struct crw crw[2]; 70 struct crw crw[2];
48 int ccode; 71 int ccode;
@@ -84,57 +107,24 @@ repeat:
84 crw[chain].rsid); 107 crw[chain].rsid);
85 /* Check for overflows. */ 108 /* Check for overflows. */
86 if (crw[chain].oflw) { 109 if (crw[chain].oflw) {
110 int i;
111
87 pr_debug("%s: crw overflow detected!\n", __func__); 112 pr_debug("%s: crw overflow detected!\n", __func__);
88 css_schedule_eval_all(); 113 for (i = 0; i < NR_RSCS; i++) {
114 if (crw_handlers[i])
115 crw_handlers[i](NULL, NULL, 1);
116 }
89 chain = 0; 117 chain = 0;
90 continue; 118 continue;
91 } 119 }
92 switch (crw[chain].rsc) { 120 if (crw[0].chn && !chain) {
93 case CRW_RSC_SCH: 121 chain++;
94 if (crw[0].chn && !chain) 122 continue;
95 break;
96 pr_debug("source is subchannel %04X\n", crw[0].rsid);
97 css_process_crw(crw[0].rsid, chain ? crw[1].rsid : 0);
98 break;
99 case CRW_RSC_MONITOR:
100 pr_debug("source is monitoring facility\n");
101 break;
102 case CRW_RSC_CPATH:
103 pr_debug("source is channel path %02X\n", crw[0].rsid);
104 /*
105 * Check for solicited machine checks. These are
106 * created by reset channel path and need not be
107 * reported to the common I/O layer.
108 */
109 if (crw[chain].slct) {
110 pr_debug("solicited machine check for "
111 "channel path %02X\n", crw[0].rsid);
112 break;
113 }
114 switch (crw[0].erc) {
115 case CRW_ERC_IPARM: /* Path has come. */
116 chp_process_crw(crw[0].rsid, 1);
117 break;
118 case CRW_ERC_PERRI: /* Path has gone. */
119 case CRW_ERC_PERRN:
120 chp_process_crw(crw[0].rsid, 0);
121 break;
122 default:
123 pr_debug("Don't know how to handle erc=%x\n",
124 crw[0].erc);
125 }
126 break;
127 case CRW_RSC_CONFIG:
128 pr_debug("source is configuration-alert facility\n");
129 break;
130 case CRW_RSC_CSS:
131 pr_debug("source is channel subsystem\n");
132 chsc_process_crw();
133 break;
134 default:
135 pr_debug("unknown source\n");
136 break;
137 } 123 }
124 if (crw_handlers[crw[chain].rsc])
125 crw_handlers[crw[chain].rsc](&crw[0],
126 chain ? &crw[1] : NULL,
127 0);
138 /* chain is always 0 or 1 here. */ 128 /* chain is always 0 or 1 here. */
139 chain = crw[chain].chn ? chain + 1 : 0; 129 chain = crw[chain].chn ? chain + 1 : 0;
140 } 130 }
diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h
index ca681f9b67fc..f11e574076d8 100644
--- a/drivers/s390/s390mach.h
+++ b/drivers/s390/s390mach.h
@@ -72,6 +72,13 @@ struct crw {
72 __u32 rsid : 16; /* reporting-source ID */ 72 __u32 rsid : 16; /* reporting-source ID */
73} __attribute__ ((packed)); 73} __attribute__ ((packed));
74 74
75typedef void (*crw_handler_t)(struct crw *, struct crw *, int);
76
77extern int s390_register_crw_handler(int rsc, crw_handler_t handler);
78extern void s390_unregister_crw_handler(int rsc);
79
80#define NR_RSCS 16
81
75#define CRW_RSC_MONITOR 0x2 /* monitoring facility */ 82#define CRW_RSC_MONITOR 0x2 /* monitoring facility */
76#define CRW_RSC_SCH 0x3 /* subchannel */ 83#define CRW_RSC_SCH 0x3 /* subchannel */
77#define CRW_RSC_CPATH 0x4 /* channel path */ 84#define CRW_RSC_CPATH 0x4 /* channel path */