diff options
Diffstat (limited to 'drivers/s390/s390mach.c')
-rw-r--r-- | drivers/s390/s390mach.c | 56 |
1 files changed, 42 insertions, 14 deletions
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index 4191fd9d4d11..7dad597ff86e 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c | |||
@@ -23,7 +23,7 @@ | |||
23 | 23 | ||
24 | static struct semaphore m_sem; | 24 | static struct semaphore m_sem; |
25 | 25 | ||
26 | extern int css_process_crw(int); | 26 | extern int css_process_crw(int, int); |
27 | extern int chsc_process_crw(void); | 27 | extern int chsc_process_crw(void); |
28 | extern int chp_process_crw(int, int); | 28 | extern int chp_process_crw(int, int); |
29 | extern void css_reiterate_subchannels(void); | 29 | extern void css_reiterate_subchannels(void); |
@@ -49,9 +49,10 @@ s390_handle_damage(char *msg) | |||
49 | static int | 49 | static int |
50 | s390_collect_crw_info(void *param) | 50 | s390_collect_crw_info(void *param) |
51 | { | 51 | { |
52 | struct crw crw; | 52 | struct crw crw[2]; |
53 | int ccode, ret, slow; | 53 | int ccode, ret, slow; |
54 | struct semaphore *sem; | 54 | struct semaphore *sem; |
55 | unsigned int chain; | ||
55 | 56 | ||
56 | sem = (struct semaphore *)param; | 57 | sem = (struct semaphore *)param; |
57 | /* Set a nice name. */ | 58 | /* Set a nice name. */ |
@@ -59,25 +60,50 @@ s390_collect_crw_info(void *param) | |||
59 | repeat: | 60 | repeat: |
60 | down_interruptible(sem); | 61 | down_interruptible(sem); |
61 | slow = 0; | 62 | slow = 0; |
63 | chain = 0; | ||
62 | while (1) { | 64 | while (1) { |
63 | ccode = stcrw(&crw); | 65 | if (unlikely(chain > 1)) { |
66 | struct crw tmp_crw; | ||
67 | |||
68 | printk(KERN_WARNING"%s: Code does not support more " | ||
69 | "than two chained crws; please report to " | ||
70 | "linux390@de.ibm.com!\n", __FUNCTION__); | ||
71 | ccode = stcrw(&tmp_crw); | ||
72 | printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, " | ||
73 | "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", | ||
74 | __FUNCTION__, tmp_crw.slct, tmp_crw.oflw, | ||
75 | tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc, | ||
76 | tmp_crw.erc, tmp_crw.rsid); | ||
77 | printk(KERN_WARNING"%s: This was crw number %x in the " | ||
78 | "chain\n", __FUNCTION__, chain); | ||
79 | if (ccode != 0) | ||
80 | break; | ||
81 | chain = tmp_crw.chn ? chain + 1 : 0; | ||
82 | continue; | ||
83 | } | ||
84 | ccode = stcrw(&crw[chain]); | ||
64 | if (ccode != 0) | 85 | if (ccode != 0) |
65 | break; | 86 | break; |
66 | DBG(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, " | 87 | DBG(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, " |
67 | "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", | 88 | "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", |
68 | crw.slct, crw.oflw, crw.chn, crw.rsc, crw.anc, | 89 | crw[chain].slct, crw[chain].oflw, crw[chain].chn, |
69 | crw.erc, crw.rsid); | 90 | crw[chain].rsc, crw[chain].anc, crw[chain].erc, |
91 | crw[chain].rsid); | ||
70 | /* Check for overflows. */ | 92 | /* Check for overflows. */ |
71 | if (crw.oflw) { | 93 | if (crw[chain].oflw) { |
72 | pr_debug("%s: crw overflow detected!\n", __FUNCTION__); | 94 | pr_debug("%s: crw overflow detected!\n", __FUNCTION__); |
73 | css_reiterate_subchannels(); | 95 | css_reiterate_subchannels(); |
96 | chain = 0; | ||
74 | slow = 1; | 97 | slow = 1; |
75 | continue; | 98 | continue; |
76 | } | 99 | } |
77 | switch (crw.rsc) { | 100 | switch (crw[chain].rsc) { |
78 | case CRW_RSC_SCH: | 101 | case CRW_RSC_SCH: |
79 | pr_debug("source is subchannel %04X\n", crw.rsid); | 102 | if (crw[0].chn && !chain) |
80 | ret = css_process_crw (crw.rsid); | 103 | break; |
104 | pr_debug("source is subchannel %04X\n", crw[0].rsid); | ||
105 | ret = css_process_crw (crw[0].rsid, | ||
106 | chain ? crw[1].rsid : 0); | ||
81 | if (ret == -EAGAIN) | 107 | if (ret == -EAGAIN) |
82 | slow = 1; | 108 | slow = 1; |
83 | break; | 109 | break; |
@@ -85,18 +111,18 @@ repeat: | |||
85 | pr_debug("source is monitoring facility\n"); | 111 | pr_debug("source is monitoring facility\n"); |
86 | break; | 112 | break; |
87 | case CRW_RSC_CPATH: | 113 | case CRW_RSC_CPATH: |
88 | pr_debug("source is channel path %02X\n", crw.rsid); | 114 | pr_debug("source is channel path %02X\n", crw[0].rsid); |
89 | switch (crw.erc) { | 115 | switch (crw[0].erc) { |
90 | case CRW_ERC_IPARM: /* Path has come. */ | 116 | case CRW_ERC_IPARM: /* Path has come. */ |
91 | ret = chp_process_crw(crw.rsid, 1); | 117 | ret = chp_process_crw(crw[0].rsid, 1); |
92 | break; | 118 | break; |
93 | case CRW_ERC_PERRI: /* Path has gone. */ | 119 | case CRW_ERC_PERRI: /* Path has gone. */ |
94 | case CRW_ERC_PERRN: | 120 | case CRW_ERC_PERRN: |
95 | ret = chp_process_crw(crw.rsid, 0); | 121 | ret = chp_process_crw(crw[0].rsid, 0); |
96 | break; | 122 | break; |
97 | default: | 123 | default: |
98 | pr_debug("Don't know how to handle erc=%x\n", | 124 | pr_debug("Don't know how to handle erc=%x\n", |
99 | crw.erc); | 125 | crw[0].erc); |
100 | ret = 0; | 126 | ret = 0; |
101 | } | 127 | } |
102 | if (ret == -EAGAIN) | 128 | if (ret == -EAGAIN) |
@@ -115,6 +141,8 @@ repeat: | |||
115 | pr_debug("unknown source\n"); | 141 | pr_debug("unknown source\n"); |
116 | break; | 142 | break; |
117 | } | 143 | } |
144 | /* chain is always 0 or 1 here. */ | ||
145 | chain = crw[chain].chn ? chain + 1 : 0; | ||
118 | } | 146 | } |
119 | if (slow) | 147 | if (slow) |
120 | queue_work(slow_path_wq, &slow_path_work); | 148 | queue_work(slow_path_wq, &slow_path_work); |