aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/css.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/cio/css.c')
-rw-r--r--drivers/s390/cio/css.c69
1 files changed, 38 insertions, 31 deletions
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 7e4d57b4266f..5137dafd1e8d 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -33,7 +33,7 @@ struct device css_bus_device = {
33}; 33};
34 34
35static struct subchannel * 35static struct subchannel *
36css_alloc_subchannel(int irq) 36css_alloc_subchannel(struct subchannel_id schid)
37{ 37{
38 struct subchannel *sch; 38 struct subchannel *sch;
39 int ret; 39 int ret;
@@ -41,13 +41,11 @@ css_alloc_subchannel(int irq)
41 sch = kmalloc (sizeof (*sch), GFP_KERNEL | GFP_DMA); 41 sch = kmalloc (sizeof (*sch), GFP_KERNEL | GFP_DMA);
42 if (sch == NULL) 42 if (sch == NULL)
43 return ERR_PTR(-ENOMEM); 43 return ERR_PTR(-ENOMEM);
44 ret = cio_validate_subchannel (sch, irq); 44 ret = cio_validate_subchannel (sch, schid);
45 if (ret < 0) { 45 if (ret < 0) {
46 kfree(sch); 46 kfree(sch);
47 return ERR_PTR(ret); 47 return ERR_PTR(ret);
48 } 48 }
49 if (irq > highest_subchannel)
50 highest_subchannel = irq;
51 49
52 if (sch->st != SUBCHANNEL_TYPE_IO) { 50 if (sch->st != SUBCHANNEL_TYPE_IO) {
53 /* For now we ignore all non-io subchannels. */ 51 /* For now we ignore all non-io subchannels. */
@@ -87,7 +85,7 @@ css_subchannel_release(struct device *dev)
87 struct subchannel *sch; 85 struct subchannel *sch;
88 86
89 sch = to_subchannel(dev); 87 sch = to_subchannel(dev);
90 if (!cio_is_console(sch->irq)) 88 if (!cio_is_console(sch->schid))
91 kfree(sch); 89 kfree(sch);
92} 90}
93 91
@@ -114,12 +112,12 @@ css_register_subchannel(struct subchannel *sch)
114} 112}
115 113
116int 114int
117css_probe_device(int irq) 115css_probe_device(struct subchannel_id schid)
118{ 116{
119 int ret; 117 int ret;
120 struct subchannel *sch; 118 struct subchannel *sch;
121 119
122 sch = css_alloc_subchannel(irq); 120 sch = css_alloc_subchannel(schid);
123 if (IS_ERR(sch)) 121 if (IS_ERR(sch))
124 return PTR_ERR(sch); 122 return PTR_ERR(sch);
125 ret = css_register_subchannel(sch); 123 ret = css_register_subchannel(sch);
@@ -132,26 +130,26 @@ static int
132check_subchannel(struct device * dev, void * data) 130check_subchannel(struct device * dev, void * data)
133{ 131{
134 struct subchannel *sch; 132 struct subchannel *sch;
135 int irq = (unsigned long)data; 133 struct subchannel_id *schid = data;
136 134
137 sch = to_subchannel(dev); 135 sch = to_subchannel(dev);
138 return (sch->irq == irq); 136 return schid_equal(&sch->schid, schid);
139} 137}
140 138
141struct subchannel * 139struct subchannel *
142get_subchannel_by_schid(int irq) 140get_subchannel_by_schid(struct subchannel_id schid)
143{ 141{
144 struct device *dev; 142 struct device *dev;
145 143
146 dev = bus_find_device(&css_bus_type, NULL, 144 dev = bus_find_device(&css_bus_type, NULL,
147 (void *)(unsigned long)irq, check_subchannel); 145 (void *)&schid, check_subchannel);
148 146
149 return dev ? to_subchannel(dev) : NULL; 147 return dev ? to_subchannel(dev) : NULL;
150} 148}
151 149
152 150
153static inline int 151static inline int
154css_get_subchannel_status(struct subchannel *sch, int schid) 152css_get_subchannel_status(struct subchannel *sch, struct subchannel_id schid)
155{ 153{
156 struct schib schib; 154 struct schib schib;
157 int cc; 155 int cc;
@@ -170,13 +168,13 @@ css_get_subchannel_status(struct subchannel *sch, int schid)
170} 168}
171 169
172static int 170static int
173css_evaluate_subchannel(int irq, int slow) 171css_evaluate_subchannel(struct subchannel_id schid, int slow)
174{ 172{
175 int event, ret, disc; 173 int event, ret, disc;
176 struct subchannel *sch; 174 struct subchannel *sch;
177 unsigned long flags; 175 unsigned long flags;
178 176
179 sch = get_subchannel_by_schid(irq); 177 sch = get_subchannel_by_schid(schid);
180 disc = sch ? device_is_disconnected(sch) : 0; 178 disc = sch ? device_is_disconnected(sch) : 0;
181 if (disc && slow) { 179 if (disc && slow) {
182 if (sch) 180 if (sch)
@@ -194,9 +192,10 @@ css_evaluate_subchannel(int irq, int slow)
194 put_device(&sch->dev); 192 put_device(&sch->dev);
195 return -EAGAIN; /* Will be done on the slow path. */ 193 return -EAGAIN; /* Will be done on the slow path. */
196 } 194 }
197 event = css_get_subchannel_status(sch, irq); 195 event = css_get_subchannel_status(sch, schid);
198 CIO_MSG_EVENT(4, "Evaluating schid %04x, event %d, %s, %s path.\n", 196 CIO_MSG_EVENT(4, "Evaluating schid %04x, event %d, %s, %s path.\n",
199 irq, event, sch?(disc?"disconnected":"normal"):"unknown", 197 schid.sch_no, event,
198 sch?(disc?"disconnected":"normal"):"unknown",
200 slow?"slow":"fast"); 199 slow?"slow":"fast");
201 switch (event) { 200 switch (event) {
202 case CIO_NO_PATH: 201 case CIO_NO_PATH:
@@ -253,7 +252,7 @@ css_evaluate_subchannel(int irq, int slow)
253 sch->schib.pmcw.intparm = 0; 252 sch->schib.pmcw.intparm = 0;
254 cio_modify(sch); 253 cio_modify(sch);
255 put_device(&sch->dev); 254 put_device(&sch->dev);
256 ret = css_probe_device(irq); 255 ret = css_probe_device(schid);
257 } else { 256 } else {
258 /* 257 /*
259 * We can't immediately deregister the disconnected 258 * We can't immediately deregister the disconnected
@@ -272,7 +271,7 @@ css_evaluate_subchannel(int irq, int slow)
272 device_trigger_reprobe(sch); 271 device_trigger_reprobe(sch);
273 spin_unlock_irqrestore(&sch->lock, flags); 272 spin_unlock_irqrestore(&sch->lock, flags);
274 } 273 }
275 ret = sch ? 0 : css_probe_device(irq); 274 ret = sch ? 0 : css_probe_device(schid);
276 break; 275 break;
277 default: 276 default:
278 BUG(); 277 BUG();
@@ -284,10 +283,12 @@ css_evaluate_subchannel(int irq, int slow)
284static void 283static void
285css_rescan_devices(void) 284css_rescan_devices(void)
286{ 285{
287 int irq, ret; 286 int ret;
287 struct subchannel_id schid;
288 288
289 for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { 289 init_subchannel_id(&schid);
290 ret = css_evaluate_subchannel(irq, 1); 290 do {
291 ret = css_evaluate_subchannel(schid, 1);
291 /* No more memory. It doesn't make sense to continue. No 292 /* No more memory. It doesn't make sense to continue. No
292 * panic because this can happen in midflight and just 293 * panic because this can happen in midflight and just
293 * because we can't use a new device is no reason to crash 294 * because we can't use a new device is no reason to crash
@@ -297,12 +298,12 @@ css_rescan_devices(void)
297 /* -ENXIO indicates that there are no more subchannels. */ 298 /* -ENXIO indicates that there are no more subchannels. */
298 if (ret == -ENXIO) 299 if (ret == -ENXIO)
299 break; 300 break;
300 } 301 } while (schid.sch_no++ < __MAX_SUBCHANNEL);
301} 302}
302 303
303struct slow_subchannel { 304struct slow_subchannel {
304 struct list_head slow_list; 305 struct list_head slow_list;
305 unsigned long schid; 306 struct subchannel_id schid;
306}; 307};
307 308
308static LIST_HEAD(slow_subchannels_head); 309static LIST_HEAD(slow_subchannels_head);
@@ -357,20 +358,24 @@ int
357css_process_crw(int irq) 358css_process_crw(int irq)
358{ 359{
359 int ret; 360 int ret;
361 struct subchannel_id mchk_schid;
360 362
361 CIO_CRW_EVENT(2, "source is subchannel %04X\n", irq); 363 CIO_CRW_EVENT(2, "source is subchannel %04X\n", irq);
362 364
363 if (need_rescan) 365 if (need_rescan)
364 /* We need to iterate all subchannels anyway. */ 366 /* We need to iterate all subchannels anyway. */
365 return -EAGAIN; 367 return -EAGAIN;
368
369 init_subchannel_id(&mchk_schid);
370 mchk_schid.sch_no = irq;
366 /* 371 /*
367 * Since we are always presented with IPI in the CRW, we have to 372 * Since we are always presented with IPI in the CRW, we have to
368 * use stsch() to find out if the subchannel in question has come 373 * use stsch() to find out if the subchannel in question has come
369 * or gone. 374 * or gone.
370 */ 375 */
371 ret = css_evaluate_subchannel(irq, 0); 376 ret = css_evaluate_subchannel(mchk_schid, 0);
372 if (ret == -EAGAIN) { 377 if (ret == -EAGAIN) {
373 if (css_enqueue_subchannel_slow(irq)) { 378 if (css_enqueue_subchannel_slow(mchk_schid)) {
374 css_clear_subchannel_slow_list(); 379 css_clear_subchannel_slow_list();
375 need_rescan = 1; 380 need_rescan = 1;
376 } 381 }
@@ -404,7 +409,8 @@ css_generate_pgid(void)
404static int __init 409static int __init
405init_channel_subsystem (void) 410init_channel_subsystem (void)
406{ 411{
407 int ret, irq; 412 int ret;
413 struct subchannel_id schid;
408 414
409 if (chsc_determine_css_characteristics() == 0) 415 if (chsc_determine_css_characteristics() == 0)
410 css_characteristics_avail = 1; 416 css_characteristics_avail = 1;
@@ -420,13 +426,14 @@ init_channel_subsystem (void)
420 426
421 ctl_set_bit(6, 28); 427 ctl_set_bit(6, 28);
422 428
423 for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { 429 init_subchannel_id(&schid);
430 do {
424 struct subchannel *sch; 431 struct subchannel *sch;
425 432
426 if (cio_is_console(irq)) 433 if (cio_is_console(schid))
427 sch = cio_get_console_subchannel(); 434 sch = cio_get_console_subchannel();
428 else { 435 else {
429 sch = css_alloc_subchannel(irq); 436 sch = css_alloc_subchannel(schid);
430 if (IS_ERR(sch)) 437 if (IS_ERR(sch))
431 ret = PTR_ERR(sch); 438 ret = PTR_ERR(sch);
432 else 439 else
@@ -448,7 +455,7 @@ init_channel_subsystem (void)
448 * console subchannel. 455 * console subchannel.
449 */ 456 */
450 css_register_subchannel(sch); 457 css_register_subchannel(sch);
451 } 458 } while (schid.sch_no++ < __MAX_SUBCHANNEL);
452 return 0; 459 return 0;
453 460
454out_bus: 461out_bus:
@@ -482,7 +489,7 @@ struct bus_type css_bus_type = {
482subsys_initcall(init_channel_subsystem); 489subsys_initcall(init_channel_subsystem);
483 490
484int 491int
485css_enqueue_subchannel_slow(unsigned long schid) 492css_enqueue_subchannel_slow(struct subchannel_id schid)
486{ 493{
487 struct slow_subchannel *new_slow_sch; 494 struct slow_subchannel *new_slow_sch;
488 unsigned long flags; 495 unsigned long flags;