diff options
Diffstat (limited to 'drivers/s390/cio/css.c')
-rw-r--r-- | drivers/s390/cio/css.c | 110 |
1 files changed, 58 insertions, 52 deletions
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 5137dafd1e8d..dba632a5f71f 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include "ioasm.h" | 21 | #include "ioasm.h" |
22 | #include "chsc.h" | 22 | #include "chsc.h" |
23 | 23 | ||
24 | unsigned int highest_subchannel; | ||
25 | int need_rescan = 0; | 24 | int need_rescan = 0; |
26 | int css_init_done = 0; | 25 | int css_init_done = 0; |
27 | 26 | ||
@@ -32,6 +31,22 @@ struct device css_bus_device = { | |||
32 | .bus_id = "css0", | 31 | .bus_id = "css0", |
33 | }; | 32 | }; |
34 | 33 | ||
34 | inline int | ||
35 | for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data) | ||
36 | { | ||
37 | struct subchannel_id schid; | ||
38 | int ret; | ||
39 | |||
40 | init_subchannel_id(&schid); | ||
41 | ret = -ENODEV; | ||
42 | do { | ||
43 | ret = fn(schid, data); | ||
44 | if (ret) | ||
45 | break; | ||
46 | } while (schid.sch_no++ < __MAX_SUBCHANNEL); | ||
47 | return ret; | ||
48 | } | ||
49 | |||
35 | static struct subchannel * | 50 | static struct subchannel * |
36 | css_alloc_subchannel(struct subchannel_id schid) | 51 | css_alloc_subchannel(struct subchannel_id schid) |
37 | { | 52 | { |
@@ -280,25 +295,10 @@ css_evaluate_subchannel(struct subchannel_id schid, int slow) | |||
280 | return ret; | 295 | return ret; |
281 | } | 296 | } |
282 | 297 | ||
283 | static void | 298 | static int |
284 | css_rescan_devices(void) | 299 | css_rescan_devices(struct subchannel_id schid, void *data) |
285 | { | 300 | { |
286 | int ret; | 301 | return css_evaluate_subchannel(schid, 1); |
287 | struct subchannel_id schid; | ||
288 | |||
289 | init_subchannel_id(&schid); | ||
290 | do { | ||
291 | ret = css_evaluate_subchannel(schid, 1); | ||
292 | /* No more memory. It doesn't make sense to continue. No | ||
293 | * panic because this can happen in midflight and just | ||
294 | * because we can't use a new device is no reason to crash | ||
295 | * the system. */ | ||
296 | if (ret == -ENOMEM) | ||
297 | break; | ||
298 | /* -ENXIO indicates that there are no more subchannels. */ | ||
299 | if (ret == -ENXIO) | ||
300 | break; | ||
301 | } while (schid.sch_no++ < __MAX_SUBCHANNEL); | ||
302 | } | 302 | } |
303 | 303 | ||
304 | struct slow_subchannel { | 304 | struct slow_subchannel { |
@@ -316,7 +316,7 @@ css_trigger_slow_path(void) | |||
316 | 316 | ||
317 | if (need_rescan) { | 317 | if (need_rescan) { |
318 | need_rescan = 0; | 318 | need_rescan = 0; |
319 | css_rescan_devices(); | 319 | for_each_subchannel(css_rescan_devices, NULL); |
320 | return; | 320 | return; |
321 | } | 321 | } |
322 | 322 | ||
@@ -383,6 +383,43 @@ css_process_crw(int irq) | |||
383 | return ret; | 383 | return ret; |
384 | } | 384 | } |
385 | 385 | ||
386 | static int __init | ||
387 | __init_channel_subsystem(struct subchannel_id schid, void *data) | ||
388 | { | ||
389 | struct subchannel *sch; | ||
390 | int ret; | ||
391 | |||
392 | if (cio_is_console(schid)) | ||
393 | sch = cio_get_console_subchannel(); | ||
394 | else { | ||
395 | sch = css_alloc_subchannel(schid); | ||
396 | if (IS_ERR(sch)) | ||
397 | ret = PTR_ERR(sch); | ||
398 | else | ||
399 | ret = 0; | ||
400 | switch (ret) { | ||
401 | case 0: | ||
402 | break; | ||
403 | case -ENOMEM: | ||
404 | panic("Out of memory in init_channel_subsystem\n"); | ||
405 | /* -ENXIO: no more subchannels. */ | ||
406 | case -ENXIO: | ||
407 | return ret; | ||
408 | default: | ||
409 | return 0; | ||
410 | } | ||
411 | } | ||
412 | /* | ||
413 | * We register ALL valid subchannels in ioinfo, even those | ||
414 | * that have been present before init_channel_subsystem. | ||
415 | * These subchannels can't have been registered yet (kmalloc | ||
416 | * not working) so we do it now. This is true e.g. for the | ||
417 | * console subchannel. | ||
418 | */ | ||
419 | css_register_subchannel(sch); | ||
420 | return 0; | ||
421 | } | ||
422 | |||
386 | static void __init | 423 | static void __init |
387 | css_generate_pgid(void) | 424 | css_generate_pgid(void) |
388 | { | 425 | { |
@@ -410,7 +447,6 @@ static int __init | |||
410 | init_channel_subsystem (void) | 447 | init_channel_subsystem (void) |
411 | { | 448 | { |
412 | int ret; | 449 | int ret; |
413 | struct subchannel_id schid; | ||
414 | 450 | ||
415 | if (chsc_determine_css_characteristics() == 0) | 451 | if (chsc_determine_css_characteristics() == 0) |
416 | css_characteristics_avail = 1; | 452 | css_characteristics_avail = 1; |
@@ -426,38 +462,8 @@ init_channel_subsystem (void) | |||
426 | 462 | ||
427 | ctl_set_bit(6, 28); | 463 | ctl_set_bit(6, 28); |
428 | 464 | ||
429 | init_subchannel_id(&schid); | 465 | for_each_subchannel(__init_channel_subsystem, NULL); |
430 | do { | ||
431 | struct subchannel *sch; | ||
432 | |||
433 | if (cio_is_console(schid)) | ||
434 | sch = cio_get_console_subchannel(); | ||
435 | else { | ||
436 | sch = css_alloc_subchannel(schid); | ||
437 | if (IS_ERR(sch)) | ||
438 | ret = PTR_ERR(sch); | ||
439 | else | ||
440 | ret = 0; | ||
441 | if (ret == -ENOMEM) | ||
442 | panic("Out of memory in " | ||
443 | "init_channel_subsystem\n"); | ||
444 | /* -ENXIO: no more subchannels. */ | ||
445 | if (ret == -ENXIO) | ||
446 | break; | ||
447 | if (ret) | ||
448 | continue; | ||
449 | } | ||
450 | /* | ||
451 | * We register ALL valid subchannels in ioinfo, even those | ||
452 | * that have been present before init_channel_subsystem. | ||
453 | * These subchannels can't have been registered yet (kmalloc | ||
454 | * not working) so we do it now. This is true e.g. for the | ||
455 | * console subchannel. | ||
456 | */ | ||
457 | css_register_subchannel(sch); | ||
458 | } while (schid.sch_no++ < __MAX_SUBCHANNEL); | ||
459 | return 0; | 466 | return 0; |
460 | |||
461 | out_bus: | 467 | out_bus: |
462 | bus_unregister(&css_bus_type); | 468 | bus_unregister(&css_bus_type); |
463 | out: | 469 | out: |