diff options
Diffstat (limited to 'drivers/s390/cio/css.c')
-rw-r--r-- | drivers/s390/cio/css.c | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 74ea8aac4b7d..1d3be80797f8 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -19,9 +19,11 @@ | |||
19 | #include "cio_debug.h" | 19 | #include "cio_debug.h" |
20 | #include "ioasm.h" | 20 | #include "ioasm.h" |
21 | #include "chsc.h" | 21 | #include "chsc.h" |
22 | #include "device.h" | ||
22 | 23 | ||
23 | int need_rescan = 0; | 24 | int need_rescan = 0; |
24 | int css_init_done = 0; | 25 | int css_init_done = 0; |
26 | static int need_reprobe = 0; | ||
25 | static int max_ssid = 0; | 27 | static int max_ssid = 0; |
26 | 28 | ||
27 | struct channel_subsystem *css[__MAX_CSSID + 1]; | 29 | struct channel_subsystem *css[__MAX_CSSID + 1]; |
@@ -339,6 +341,67 @@ typedef void (*workfunc)(void *); | |||
339 | DECLARE_WORK(slow_path_work, (workfunc)css_trigger_slow_path, NULL); | 341 | DECLARE_WORK(slow_path_work, (workfunc)css_trigger_slow_path, NULL); |
340 | struct workqueue_struct *slow_path_wq; | 342 | struct workqueue_struct *slow_path_wq; |
341 | 343 | ||
344 | /* Reprobe subchannel if unregistered. */ | ||
345 | static int reprobe_subchannel(struct subchannel_id schid, void *data) | ||
346 | { | ||
347 | struct subchannel *sch; | ||
348 | int ret; | ||
349 | |||
350 | CIO_DEBUG(KERN_INFO, 6, "cio: reprobe 0.%x.%04x\n", | ||
351 | schid.ssid, schid.sch_no); | ||
352 | if (need_reprobe) | ||
353 | return -EAGAIN; | ||
354 | |||
355 | sch = get_subchannel_by_schid(schid); | ||
356 | if (sch) { | ||
357 | /* Already known. */ | ||
358 | put_device(&sch->dev); | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | ret = css_probe_device(schid); | ||
363 | switch (ret) { | ||
364 | case 0: | ||
365 | break; | ||
366 | case -ENXIO: | ||
367 | case -ENOMEM: | ||
368 | /* These should abort looping */ | ||
369 | break; | ||
370 | default: | ||
371 | ret = 0; | ||
372 | } | ||
373 | |||
374 | return ret; | ||
375 | } | ||
376 | |||
377 | /* Work function used to reprobe all unregistered subchannels. */ | ||
378 | static void reprobe_all(void *data) | ||
379 | { | ||
380 | int ret; | ||
381 | |||
382 | CIO_MSG_EVENT(2, "reprobe start\n"); | ||
383 | |||
384 | need_reprobe = 0; | ||
385 | /* Make sure initial subchannel scan is done. */ | ||
386 | wait_event(ccw_device_init_wq, | ||
387 | atomic_read(&ccw_device_init_count) == 0); | ||
388 | ret = for_each_subchannel(reprobe_subchannel, NULL); | ||
389 | |||
390 | CIO_MSG_EVENT(2, "reprobe done (rc=%d, need_reprobe=%d)\n", ret, | ||
391 | need_reprobe); | ||
392 | } | ||
393 | |||
394 | DECLARE_WORK(css_reprobe_work, reprobe_all, NULL); | ||
395 | |||
396 | /* Schedule reprobing of all unregistered subchannels. */ | ||
397 | void css_schedule_reprobe(void) | ||
398 | { | ||
399 | need_reprobe = 1; | ||
400 | queue_work(ccw_device_work, &css_reprobe_work); | ||
401 | } | ||
402 | |||
403 | EXPORT_SYMBOL_GPL(css_schedule_reprobe); | ||
404 | |||
342 | /* | 405 | /* |
343 | * Rescan for new devices. FIXME: This is slow. | 406 | * Rescan for new devices. FIXME: This is slow. |
344 | * This function is called when we have lost CRWs due to overflows and we have | 407 | * This function is called when we have lost CRWs due to overflows and we have |