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 |
