diff options
author | Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 2007-04-27 10:01:35 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-04-27 10:01:40 -0400 |
commit | 7ad6a24970325294a22a08446d473384c15b928e (patch) | |
tree | c8f1e25035b207e2a45a29138309acaee20d6cb6 /drivers/s390 | |
parent | 83b3370c79b91b9be3f6540c3c914e689134b45f (diff) |
[S390] cio: fix subchannel channel-path data usage
Ensure that channel-path related subchannel data is only retrieved and
used when it is valid and that it is updated when it may have changed.
Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/cio/chsc.c | 303 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.h | 10 | ||||
-rw-r--r-- | drivers/s390/cio/cio.h | 16 | ||||
-rw-r--r-- | drivers/s390/cio/css.c | 53 | ||||
-rw-r--r-- | drivers/s390/cio/css.h | 1 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 12 | ||||
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 1 |
7 files changed, 179 insertions, 217 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 89a130a62654..0841e16b6a82 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -26,155 +26,84 @@ | |||
26 | 26 | ||
27 | static void *sei_page; | 27 | static void *sei_page; |
28 | 28 | ||
29 | /* FIXME: this is _always_ called for every subchannel. shouldn't we | 29 | struct chsc_ssd_area { |
30 | * process more than one at a time? */ | 30 | struct chsc_header request; |
31 | static int | 31 | u16 :10; |
32 | chsc_get_sch_desc_irq(struct subchannel *sch, void *page) | 32 | u16 ssid:2; |
33 | { | 33 | u16 :4; |
34 | int ccode, j; | 34 | u16 f_sch; /* first subchannel */ |
35 | u16 :16; | ||
36 | u16 l_sch; /* last subchannel */ | ||
37 | u32 :32; | ||
38 | struct chsc_header response; | ||
39 | u32 :32; | ||
40 | u8 sch_valid : 1; | ||
41 | u8 dev_valid : 1; | ||
42 | u8 st : 3; /* subchannel type */ | ||
43 | u8 zeroes : 3; | ||
44 | u8 unit_addr; /* unit address */ | ||
45 | u16 devno; /* device number */ | ||
46 | u8 path_mask; | ||
47 | u8 fla_valid_mask; | ||
48 | u16 sch; /* subchannel */ | ||
49 | u8 chpid[8]; /* chpids 0-7 */ | ||
50 | u16 fla[8]; /* full link addresses 0-7 */ | ||
51 | } __attribute__ ((packed)); | ||
35 | 52 | ||
36 | struct { | 53 | int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd) |
37 | struct chsc_header request; | 54 | { |
38 | u16 reserved1a:10; | 55 | unsigned long page; |
39 | u16 ssid:2; | 56 | struct chsc_ssd_area *ssd_area; |
40 | u16 reserved1b:4; | 57 | int ccode; |
41 | u16 f_sch; /* first subchannel */ | 58 | int ret; |
42 | u16 reserved2; | 59 | int i; |
43 | u16 l_sch; /* last subchannel */ | 60 | int mask; |
44 | u32 reserved3; | ||
45 | struct chsc_header response; | ||
46 | u32 reserved4; | ||
47 | u8 sch_valid : 1; | ||
48 | u8 dev_valid : 1; | ||
49 | u8 st : 3; /* subchannel type */ | ||
50 | u8 zeroes : 3; | ||
51 | u8 unit_addr; /* unit address */ | ||
52 | u16 devno; /* device number */ | ||
53 | u8 path_mask; | ||
54 | u8 fla_valid_mask; | ||
55 | u16 sch; /* subchannel */ | ||
56 | u8 chpid[8]; /* chpids 0-7 */ | ||
57 | u16 fla[8]; /* full link addresses 0-7 */ | ||
58 | } __attribute__ ((packed)) *ssd_area; | ||
59 | |||
60 | ssd_area = page; | ||
61 | 61 | ||
62 | page = get_zeroed_page(GFP_KERNEL | GFP_DMA); | ||
63 | if (!page) | ||
64 | return -ENOMEM; | ||
65 | ssd_area = (struct chsc_ssd_area *) page; | ||
62 | ssd_area->request.length = 0x0010; | 66 | ssd_area->request.length = 0x0010; |
63 | ssd_area->request.code = 0x0004; | 67 | ssd_area->request.code = 0x0004; |
64 | 68 | ssd_area->ssid = schid.ssid; | |
65 | ssd_area->ssid = sch->schid.ssid; | 69 | ssd_area->f_sch = schid.sch_no; |
66 | ssd_area->f_sch = sch->schid.sch_no; | 70 | ssd_area->l_sch = schid.sch_no; |
67 | ssd_area->l_sch = sch->schid.sch_no; | ||
68 | 71 | ||
69 | ccode = chsc(ssd_area); | 72 | ccode = chsc(ssd_area); |
73 | /* Check response. */ | ||
70 | if (ccode > 0) { | 74 | if (ccode > 0) { |
71 | pr_debug("chsc returned with ccode = %d\n", ccode); | 75 | ret = (ccode == 3) ? -ENODEV : -EBUSY; |
72 | return (ccode == 3) ? -ENODEV : -EBUSY; | 76 | goto out_free; |
73 | } | 77 | } |
74 | 78 | if (ssd_area->response.code != 0x0001) { | |
75 | switch (ssd_area->response.code) { | 79 | CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n", |
76 | case 0x0001: /* everything ok */ | 80 | schid.ssid, schid.sch_no, |
77 | break; | ||
78 | case 0x0002: | ||
79 | CIO_CRW_EVENT(2, "Invalid command!\n"); | ||
80 | return -EINVAL; | ||
81 | case 0x0003: | ||
82 | CIO_CRW_EVENT(2, "Error in chsc request block!\n"); | ||
83 | return -EINVAL; | ||
84 | case 0x0004: | ||
85 | CIO_CRW_EVENT(2, "Model does not provide ssd\n"); | ||
86 | return -EOPNOTSUPP; | ||
87 | default: | ||
88 | CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", | ||
89 | ssd_area->response.code); | 81 | ssd_area->response.code); |
90 | return -EIO; | 82 | ret = -EIO; |
91 | } | 83 | goto out_free; |
92 | |||
93 | /* | ||
94 | * ssd_area->st stores the type of the detected | ||
95 | * subchannel, with the following definitions: | ||
96 | * | ||
97 | * 0: I/O subchannel: All fields have meaning | ||
98 | * 1: CHSC subchannel: Only sch_val, st and sch | ||
99 | * have meaning | ||
100 | * 2: Message subchannel: All fields except unit_addr | ||
101 | * have meaning | ||
102 | * 3: ADM subchannel: Only sch_val, st and sch | ||
103 | * have meaning | ||
104 | * | ||
105 | * Other types are currently undefined. | ||
106 | */ | ||
107 | if (ssd_area->st > 3) { /* uhm, that looks strange... */ | ||
108 | CIO_CRW_EVENT(0, "Strange subchannel type %d" | ||
109 | " for sch 0.%x.%04x\n", ssd_area->st, | ||
110 | sch->schid.ssid, sch->schid.sch_no); | ||
111 | /* | ||
112 | * There may have been a new subchannel type defined in the | ||
113 | * time since this code was written; since we don't know which | ||
114 | * fields have meaning and what to do with it we just jump out | ||
115 | */ | ||
116 | return 0; | ||
117 | } else { | ||
118 | const char *type[4] = {"I/O", "chsc", "message", "ADM"}; | ||
119 | CIO_CRW_EVENT(6, "ssd: sch 0.%x.%04x is %s subchannel\n", | ||
120 | sch->schid.ssid, sch->schid.sch_no, | ||
121 | type[ssd_area->st]); | ||
122 | |||
123 | sch->ssd_info.valid = 1; | ||
124 | sch->ssd_info.type = ssd_area->st; | ||
125 | } | 84 | } |
126 | 85 | if (!ssd_area->sch_valid) { | |
127 | if (ssd_area->st == 0 || ssd_area->st == 2) { | 86 | ret = -ENODEV; |
128 | for (j = 0; j < 8; j++) { | 87 | goto out_free; |
129 | if (!((0x80 >> j) & ssd_area->path_mask & | ||
130 | ssd_area->fla_valid_mask)) | ||
131 | continue; | ||
132 | sch->ssd_info.chpid[j] = ssd_area->chpid[j]; | ||
133 | sch->ssd_info.fla[j] = ssd_area->fla[j]; | ||
134 | } | ||
135 | } | 88 | } |
136 | return 0; | 89 | /* Copy data */ |
137 | } | 90 | ret = 0; |
138 | 91 | memset(ssd, 0, sizeof(struct chsc_ssd_info)); | |
139 | int | 92 | if ((ssd_area->st != 0) && (ssd_area->st != 2)) |
140 | css_get_ssd_info(struct subchannel *sch) | 93 | goto out_free; |
141 | { | 94 | ssd->path_mask = ssd_area->path_mask; |
142 | int ret; | 95 | ssd->fla_valid_mask = ssd_area->fla_valid_mask; |
143 | void *page; | 96 | for (i = 0; i < 8; i++) { |
144 | 97 | mask = 0x80 >> i; | |
145 | page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); | 98 | if (ssd_area->path_mask & mask) { |
146 | if (!page) | 99 | chp_id_init(&ssd->chpid[i]); |
147 | return -ENOMEM; | 100 | ssd->chpid[i].id = ssd_area->chpid[i]; |
148 | spin_lock_irq(sch->lock); | ||
149 | ret = chsc_get_sch_desc_irq(sch, page); | ||
150 | if (ret) { | ||
151 | static int cio_chsc_err_msg; | ||
152 | |||
153 | if (!cio_chsc_err_msg) { | ||
154 | printk(KERN_ERR | ||
155 | "chsc_get_sch_descriptions:" | ||
156 | " Error %d while doing chsc; " | ||
157 | "processing some machine checks may " | ||
158 | "not work\n", ret); | ||
159 | cio_chsc_err_msg = 1; | ||
160 | } | ||
161 | } | ||
162 | spin_unlock_irq(sch->lock); | ||
163 | free_page((unsigned long)page); | ||
164 | if (!ret) { | ||
165 | int j, mask; | ||
166 | struct chp_id chpid; | ||
167 | |||
168 | chp_id_init(&chpid); | ||
169 | /* Allocate channel path structures, if needed. */ | ||
170 | for (j = 0; j < 8; j++) { | ||
171 | mask = 0x80 >> j; | ||
172 | chpid.id = sch->ssd_info.chpid[j]; | ||
173 | if ((sch->schib.pmcw.pim & mask) && | ||
174 | !chp_is_registered(chpid)) | ||
175 | chp_new(chpid); | ||
176 | } | 101 | } |
102 | if (ssd_area->fla_valid_mask & mask) | ||
103 | ssd->fla[i] = ssd_area->fla[i]; | ||
177 | } | 104 | } |
105 | out_free: | ||
106 | free_page(page); | ||
178 | return ret; | 107 | return ret; |
179 | } | 108 | } |
180 | 109 | ||
@@ -276,47 +205,6 @@ void chsc_chp_offline(struct chp_id chpid) | |||
276 | s390_subchannel_remove_chpid); | 205 | s390_subchannel_remove_chpid); |
277 | } | 206 | } |
278 | 207 | ||
279 | struct res_acc_data { | ||
280 | struct chp_id chpid; | ||
281 | u32 fla_mask; | ||
282 | u16 fla; | ||
283 | }; | ||
284 | |||
285 | static int s390_process_res_acc_sch(struct res_acc_data *res_data, | ||
286 | struct subchannel *sch) | ||
287 | { | ||
288 | int found; | ||
289 | int chp; | ||
290 | int ccode; | ||
291 | |||
292 | found = 0; | ||
293 | for (chp = 0; chp <= 7; chp++) | ||
294 | /* | ||
295 | * check if chpid is in information updated by ssd | ||
296 | */ | ||
297 | if (sch->ssd_info.valid && | ||
298 | sch->ssd_info.chpid[chp] == res_data->chpid.id && | ||
299 | (sch->ssd_info.fla[chp] & res_data->fla_mask) | ||
300 | == res_data->fla) { | ||
301 | found = 1; | ||
302 | break; | ||
303 | } | ||
304 | |||
305 | if (found == 0) | ||
306 | return 0; | ||
307 | |||
308 | /* | ||
309 | * Do a stsch to update our subchannel structure with the | ||
310 | * new path information and eventually check for logically | ||
311 | * offline chpids. | ||
312 | */ | ||
313 | ccode = stsch(sch->schid, &sch->schib); | ||
314 | if (ccode > 0) | ||
315 | return 0; | ||
316 | |||
317 | return 0x80 >> chp; | ||
318 | } | ||
319 | |||
320 | static int | 208 | static int |
321 | s390_process_res_acc_new_sch(struct subchannel_id schid) | 209 | s390_process_res_acc_new_sch(struct subchannel_id schid) |
322 | { | 210 | { |
@@ -338,6 +226,32 @@ s390_process_res_acc_new_sch(struct subchannel_id schid) | |||
338 | return 0; | 226 | return 0; |
339 | } | 227 | } |
340 | 228 | ||
229 | struct res_acc_data { | ||
230 | struct chp_id chpid; | ||
231 | u32 fla_mask; | ||
232 | u16 fla; | ||
233 | }; | ||
234 | |||
235 | static int get_res_chpid_mask(struct chsc_ssd_info *ssd, | ||
236 | struct res_acc_data *data) | ||
237 | { | ||
238 | int i; | ||
239 | int mask; | ||
240 | |||
241 | for (i = 0; i < 8; i++) { | ||
242 | mask = 0x80 >> i; | ||
243 | if (!(ssd->path_mask & mask)) | ||
244 | continue; | ||
245 | if (!chp_id_is_equal(&ssd->chpid[i], &data->chpid)) | ||
246 | continue; | ||
247 | if ((ssd->fla_valid_mask & mask) && | ||
248 | ((ssd->fla[i] & data->fla_mask) != data->fla)) | ||
249 | continue; | ||
250 | return mask; | ||
251 | } | ||
252 | return 0; | ||
253 | } | ||
254 | |||
341 | static int | 255 | static int |
342 | __s390_process_res_acc(struct subchannel_id schid, void *data) | 256 | __s390_process_res_acc(struct subchannel_id schid, void *data) |
343 | { | 257 | { |
@@ -352,14 +266,11 @@ __s390_process_res_acc(struct subchannel_id schid, void *data) | |||
352 | return s390_process_res_acc_new_sch(schid); | 266 | return s390_process_res_acc_new_sch(schid); |
353 | 267 | ||
354 | spin_lock_irq(sch->lock); | 268 | spin_lock_irq(sch->lock); |
355 | 269 | chp_mask = get_res_chpid_mask(&sch->ssd_info, res_data); | |
356 | chp_mask = s390_process_res_acc_sch(res_data, sch); | 270 | if (chp_mask == 0) |
357 | 271 | goto out; | |
358 | if (chp_mask == 0) { | 272 | if (stsch(sch->schid, &sch->schib)) |
359 | spin_unlock_irq(sch->lock); | 273 | goto out; |
360 | put_device(&sch->dev); | ||
361 | return 0; | ||
362 | } | ||
363 | old_lpm = sch->lpm; | 274 | old_lpm = sch->lpm; |
364 | sch->lpm = ((sch->schib.pmcw.pim & | 275 | sch->lpm = ((sch->schib.pmcw.pim & |
365 | sch->schib.pmcw.pam & | 276 | sch->schib.pmcw.pam & |
@@ -369,13 +280,12 @@ __s390_process_res_acc(struct subchannel_id schid, void *data) | |||
369 | device_trigger_reprobe(sch); | 280 | device_trigger_reprobe(sch); |
370 | else if (sch->driver && sch->driver->verify) | 281 | else if (sch->driver && sch->driver->verify) |
371 | sch->driver->verify(&sch->dev); | 282 | sch->driver->verify(&sch->dev); |
372 | 283 | out: | |
373 | spin_unlock_irq(sch->lock); | 284 | spin_unlock_irq(sch->lock); |
374 | put_device(&sch->dev); | 285 | put_device(&sch->dev); |
375 | return 0; | 286 | return 0; |
376 | } | 287 | } |
377 | 288 | ||
378 | |||
379 | static void s390_process_res_acc (struct res_acc_data *res_data) | 289 | static void s390_process_res_acc (struct res_acc_data *res_data) |
380 | { | 290 | { |
381 | char dbf_txt[15]; | 291 | char dbf_txt[15]; |
@@ -661,29 +571,30 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch, | |||
661 | struct chp_id chpid, int on) | 571 | struct chp_id chpid, int on) |
662 | { | 572 | { |
663 | int chp, old_lpm; | 573 | int chp, old_lpm; |
574 | int mask; | ||
664 | unsigned long flags; | 575 | unsigned long flags; |
665 | 576 | ||
666 | if (!sch->ssd_info.valid) | ||
667 | return; | ||
668 | |||
669 | spin_lock_irqsave(sch->lock, flags); | 577 | spin_lock_irqsave(sch->lock, flags); |
670 | old_lpm = sch->lpm; | 578 | old_lpm = sch->lpm; |
671 | for (chp = 0; chp < 8; chp++) { | 579 | for (chp = 0; chp < 8; chp++) { |
672 | if (sch->ssd_info.chpid[chp] != chpid.id) | 580 | mask = 0x80 >> chp; |
581 | if (!(sch->ssd_info.path_mask & mask)) | ||
582 | continue; | ||
583 | if (!chp_id_is_equal(&sch->ssd_info.chpid[chp], &chpid)) | ||
673 | continue; | 584 | continue; |
674 | 585 | ||
675 | if (on) { | 586 | if (on) { |
676 | sch->opm |= (0x80 >> chp); | 587 | sch->opm |= mask; |
677 | sch->lpm |= (0x80 >> chp); | 588 | sch->lpm |= mask; |
678 | if (!old_lpm) | 589 | if (!old_lpm) |
679 | device_trigger_reprobe(sch); | 590 | device_trigger_reprobe(sch); |
680 | else if (sch->driver && sch->driver->verify) | 591 | else if (sch->driver && sch->driver->verify) |
681 | sch->driver->verify(&sch->dev); | 592 | sch->driver->verify(&sch->dev); |
682 | break; | 593 | break; |
683 | } | 594 | } |
684 | sch->opm &= ~(0x80 >> chp); | 595 | sch->opm &= ~mask; |
685 | sch->lpm &= ~(0x80 >> chp); | 596 | sch->lpm &= ~mask; |
686 | if (check_for_io_on_path(sch, (0x80 >> chp))) { | 597 | if (check_for_io_on_path(sch, mask)) { |
687 | if (device_is_online(sch)) | 598 | if (device_is_online(sch)) |
688 | /* Path verification is done after killing. */ | 599 | /* Path verification is done after killing. */ |
689 | device_kill_io(sch); | 600 | device_kill_io(sch); |
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 742ef57d2c58..2ad81d11cf7b 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include <linux/device.h> | 5 | #include <linux/device.h> |
6 | #include <asm/chpid.h> | 6 | #include <asm/chpid.h> |
7 | #include "schid.h" | ||
7 | 8 | ||
8 | #define CHSC_SDA_OC_MSS 0x2 | 9 | #define CHSC_SDA_OC_MSS 0x2 |
9 | 10 | ||
@@ -35,7 +36,6 @@ struct channel_path_desc { | |||
35 | 36 | ||
36 | struct channel_path; | 37 | struct channel_path; |
37 | 38 | ||
38 | extern int css_get_ssd_info(struct subchannel *); | ||
39 | extern void chsc_process_crw(void); | 39 | extern void chsc_process_crw(void); |
40 | 40 | ||
41 | struct css_general_char { | 41 | struct css_general_char { |
@@ -69,6 +69,14 @@ struct css_chsc_char { | |||
69 | extern struct css_general_char css_general_characteristics; | 69 | extern struct css_general_char css_general_characteristics; |
70 | extern struct css_chsc_char css_chsc_characteristics; | 70 | extern struct css_chsc_char css_chsc_characteristics; |
71 | 71 | ||
72 | struct chsc_ssd_info { | ||
73 | u8 path_mask; | ||
74 | u8 fla_valid_mask; | ||
75 | struct chp_id chpid[8]; | ||
76 | u16 fla[8]; | ||
77 | }; | ||
78 | extern int chsc_get_ssd_info(struct subchannel_id schid, | ||
79 | struct chsc_ssd_info *ssd); | ||
72 | extern int chsc_determine_css_characteristics(void); | 80 | extern int chsc_determine_css_characteristics(void); |
73 | extern int css_characteristics_avail; | 81 | extern int css_characteristics_avail; |
74 | 82 | ||
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index e62ab5c52863..7446c39951a7 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h | |||
@@ -1,19 +1,11 @@ | |||
1 | #ifndef S390_CIO_H | 1 | #ifndef S390_CIO_H |
2 | #define S390_CIO_H | 2 | #define S390_CIO_H |
3 | 3 | ||
4 | #include "schid.h" | ||
5 | #include <linux/mutex.h> | 4 | #include <linux/mutex.h> |
6 | #include <linux/device.h> | 5 | #include <linux/device.h> |
7 | 6 | #include <asm/chpid.h> | |
8 | /* | 7 | #include "chsc.h" |
9 | * where we put the ssd info | 8 | #include "schid.h" |
10 | */ | ||
11 | struct ssd_info { | ||
12 | __u8 valid:1; | ||
13 | __u8 type:7; /* subchannel type */ | ||
14 | __u8 chpid[8]; /* chpids */ | ||
15 | __u16 fla[8]; /* full link addresses */ | ||
16 | } __attribute__ ((packed)); | ||
17 | 9 | ||
18 | /* | 10 | /* |
19 | * path management control word | 11 | * path management control word |
@@ -109,7 +101,7 @@ struct subchannel { | |||
109 | struct schib schib; /* subchannel information block */ | 101 | struct schib schib; /* subchannel information block */ |
110 | struct orb orb; /* operation request block */ | 102 | struct orb orb; /* operation request block */ |
111 | struct ccw1 sense_ccw; /* static ccw for sense command */ | 103 | struct ccw1 sense_ccw; /* static ccw for sense command */ |
112 | struct ssd_info ssd_info; /* subchannel description */ | 104 | struct chsc_ssd_info ssd_info; /* subchannel description */ |
113 | struct device dev; /* entry in device tree */ | 105 | struct device dev; /* entry in device tree */ |
114 | struct css_driver *driver; | 106 | struct css_driver *driver; |
115 | } __attribute__ ((aligned(8))); | 107 | } __attribute__ ((aligned(8))); |
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index fcc641e578f4..27c6d9e55b23 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include "chsc.h" | 21 | #include "chsc.h" |
22 | #include "device.h" | 22 | #include "device.h" |
23 | #include "idset.h" | 23 | #include "idset.h" |
24 | #include "chp.h" | ||
24 | 25 | ||
25 | int css_init_done = 0; | 26 | int css_init_done = 0; |
26 | static int need_reprobe = 0; | 27 | static int need_reprobe = 0; |
@@ -125,8 +126,52 @@ void css_sch_device_unregister(struct subchannel *sch) | |||
125 | mutex_unlock(&sch->reg_mutex); | 126 | mutex_unlock(&sch->reg_mutex); |
126 | } | 127 | } |
127 | 128 | ||
128 | static int | 129 | static void ssd_from_pmcw(struct chsc_ssd_info *ssd, struct pmcw *pmcw) |
129 | css_register_subchannel(struct subchannel *sch) | 130 | { |
131 | int i; | ||
132 | int mask; | ||
133 | |||
134 | memset(ssd, 0, sizeof(struct chsc_ssd_info)); | ||
135 | ssd->path_mask = pmcw->pim; | ||
136 | for (i = 0; i < 8; i++) { | ||
137 | mask = 0x80 >> i; | ||
138 | if (pmcw->pim & mask) { | ||
139 | chp_id_init(&ssd->chpid[i]); | ||
140 | ssd->chpid[i].id = pmcw->chpid[i]; | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | static void ssd_register_chpids(struct chsc_ssd_info *ssd) | ||
146 | { | ||
147 | int i; | ||
148 | int mask; | ||
149 | |||
150 | for (i = 0; i < 8; i++) { | ||
151 | mask = 0x80 >> i; | ||
152 | if (ssd->path_mask & mask) | ||
153 | if (!chp_is_registered(ssd->chpid[i])) | ||
154 | chp_new(ssd->chpid[i]); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | void css_update_ssd_info(struct subchannel *sch) | ||
159 | { | ||
160 | int ret; | ||
161 | |||
162 | if (cio_is_console(sch->schid)) { | ||
163 | /* Console is initialized too early for functions requiring | ||
164 | * memory allocation. */ | ||
165 | ssd_from_pmcw(&sch->ssd_info, &sch->schib.pmcw); | ||
166 | } else { | ||
167 | ret = chsc_get_ssd_info(sch->schid, &sch->ssd_info); | ||
168 | if (ret) | ||
169 | ssd_from_pmcw(&sch->ssd_info, &sch->schib.pmcw); | ||
170 | ssd_register_chpids(&sch->ssd_info); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | static int css_register_subchannel(struct subchannel *sch) | ||
130 | { | 175 | { |
131 | int ret; | 176 | int ret; |
132 | 177 | ||
@@ -135,9 +180,7 @@ css_register_subchannel(struct subchannel *sch) | |||
135 | sch->dev.bus = &css_bus_type; | 180 | sch->dev.bus = &css_bus_type; |
136 | sch->dev.release = &css_subchannel_release; | 181 | sch->dev.release = &css_subchannel_release; |
137 | sch->dev.groups = subch_attr_groups; | 182 | sch->dev.groups = subch_attr_groups; |
138 | 183 | css_update_ssd_info(sch); | |
139 | css_get_ssd_info(sch); | ||
140 | |||
141 | /* make it known to the system */ | 184 | /* make it known to the system */ |
142 | ret = css_sch_device_register(sch); | 185 | ret = css_sch_device_register(sch); |
143 | if (ret) { | 186 | if (ret) { |
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 4b3133a7bae1..71fcfdc42800 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h | |||
@@ -148,6 +148,7 @@ extern int css_init_done; | |||
148 | extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); | 148 | extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); |
149 | extern void css_process_crw(int, int); | 149 | extern void css_process_crw(int, int); |
150 | extern void css_reiterate_subchannels(void); | 150 | extern void css_reiterate_subchannels(void); |
151 | void css_update_ssd_info(struct subchannel *sch); | ||
151 | 152 | ||
152 | #define __MAX_SUBCHANNEL 65535 | 153 | #define __MAX_SUBCHANNEL 65535 |
153 | #define __MAX_SSID 3 | 154 | #define __MAX_SSID 3 |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 34e7d77b997d..7bb44e73ea9d 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -216,12 +216,18 @@ static ssize_t | |||
216 | chpids_show (struct device * dev, struct device_attribute *attr, char * buf) | 216 | chpids_show (struct device * dev, struct device_attribute *attr, char * buf) |
217 | { | 217 | { |
218 | struct subchannel *sch = to_subchannel(dev); | 218 | struct subchannel *sch = to_subchannel(dev); |
219 | struct ssd_info *ssd = &sch->ssd_info; | 219 | struct chsc_ssd_info *ssd = &sch->ssd_info; |
220 | ssize_t ret = 0; | 220 | ssize_t ret = 0; |
221 | int chp; | 221 | int chp; |
222 | int mask; | ||
222 | 223 | ||
223 | for (chp = 0; chp < 8; chp++) | 224 | for (chp = 0; chp < 8; chp++) { |
224 | ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]); | 225 | mask = 0x80 >> chp; |
226 | if (ssd->path_mask & mask) | ||
227 | ret += sprintf(buf + ret, "%02x ", ssd->chpid[chp].id); | ||
228 | else | ||
229 | ret += sprintf(buf + ret, "00 "); | ||
230 | } | ||
225 | ret += sprintf (buf+ret, "\n"); | 231 | ret += sprintf (buf+ret, "\n"); |
226 | return min((ssize_t)PAGE_SIZE, ret); | 232 | return min((ssize_t)PAGE_SIZE, ret); |
227 | } | 233 | } |
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 898ec3b2bebb..aadd2fd4a86c 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -246,6 +246,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) | |||
246 | */ | 246 | */ |
247 | old_lpm = sch->lpm; | 247 | old_lpm = sch->lpm; |
248 | stsch(sch->schid, &sch->schib); | 248 | stsch(sch->schid, &sch->schib); |
249 | css_update_ssd_info(sch); | ||
249 | sch->lpm = sch->schib.pmcw.pam & sch->opm; | 250 | sch->lpm = sch->schib.pmcw.pam & sch->opm; |
250 | /* Check since device may again have become not operational. */ | 251 | /* Check since device may again have become not operational. */ |
251 | if (!sch->schib.pmcw.dnv) | 252 | if (!sch->schib.pmcw.dnv) |