diff options
author | Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 2006-06-29 08:57:03 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2006-06-29 08:57:03 -0400 |
commit | 40154b824331cd9c81c06545761338f3d80a36e2 (patch) | |
tree | da4d06f7b09150e1c34b543d5300c3948e284a70 /drivers | |
parent | 887ab5992925736ab23985c35f8149739e9de354 (diff) |
[S390] cio async subchannel reprobe.
Changes in the DASD driver require an asynchronous implementation of the
subchannel reprobe loop. This loop was so far only used by the blacklisting
mechanism but is now available to all CCW device drivers.
Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/cio/blacklist.c | 35 | ||||
-rw-r--r-- | drivers/s390/cio/css.c | 63 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 4 | ||||
-rw-r--r-- | drivers/s390/cio/device.h | 6 |
4 files changed, 72 insertions, 36 deletions
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 0960bef7b199..15b895496a45 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c | |||
@@ -224,39 +224,6 @@ is_blacklisted (int ssid, int devno) | |||
224 | } | 224 | } |
225 | 225 | ||
226 | #ifdef CONFIG_PROC_FS | 226 | #ifdef CONFIG_PROC_FS |
227 | static int | ||
228 | __s390_redo_validation(struct subchannel_id schid, void *data) | ||
229 | { | ||
230 | int ret; | ||
231 | struct subchannel *sch; | ||
232 | |||
233 | sch = get_subchannel_by_schid(schid); | ||
234 | if (sch) { | ||
235 | /* Already known. */ | ||
236 | put_device(&sch->dev); | ||
237 | return 0; | ||
238 | } | ||
239 | ret = css_probe_device(schid); | ||
240 | if (ret == -ENXIO) | ||
241 | return ret; /* We're through. */ | ||
242 | if (ret == -ENOMEM) | ||
243 | /* Stop validation for now. Bad, but no need for a panic. */ | ||
244 | return ret; | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | /* | ||
249 | * Function: s390_redo_validation | ||
250 | * Look for no longer blacklisted devices | ||
251 | * FIXME: there must be a better way to do this */ | ||
252 | static inline void | ||
253 | s390_redo_validation (void) | ||
254 | { | ||
255 | CIO_TRACE_EVENT (0, "redoval"); | ||
256 | |||
257 | for_each_subchannel(__s390_redo_validation, NULL); | ||
258 | } | ||
259 | |||
260 | /* | 227 | /* |
261 | * Function: blacklist_parse_proc_parameters | 228 | * Function: blacklist_parse_proc_parameters |
262 | * parse the stuff which is piped to /proc/cio_ignore | 229 | * parse the stuff which is piped to /proc/cio_ignore |
@@ -281,7 +248,7 @@ blacklist_parse_proc_parameters (char *buf) | |||
281 | return; | 248 | return; |
282 | } | 249 | } |
283 | 250 | ||
284 | s390_redo_validation (); | 251 | css_schedule_reprobe(); |
285 | } | 252 | } |
286 | 253 | ||
287 | /* Iterator struct for all devices. */ | 254 | /* Iterator struct for all devices. */ |
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 |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 8e3053c2a451..eafde43e8410 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -133,8 +133,8 @@ struct css_driver io_subchannel_driver = { | |||
133 | 133 | ||
134 | struct workqueue_struct *ccw_device_work; | 134 | struct workqueue_struct *ccw_device_work; |
135 | struct workqueue_struct *ccw_device_notify_work; | 135 | struct workqueue_struct *ccw_device_notify_work; |
136 | static wait_queue_head_t ccw_device_init_wq; | 136 | wait_queue_head_t ccw_device_init_wq; |
137 | static atomic_t ccw_device_init_count; | 137 | atomic_t ccw_device_init_count; |
138 | 138 | ||
139 | static int __init | 139 | static int __init |
140 | init_ccw_bus_type (void) | 140 | init_ccw_bus_type (void) |
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 11587ebb7289..8e0d1db3dd4e 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h | |||
@@ -1,6 +1,10 @@ | |||
1 | #ifndef S390_DEVICE_H | 1 | #ifndef S390_DEVICE_H |
2 | #define S390_DEVICE_H | 2 | #define S390_DEVICE_H |
3 | 3 | ||
4 | #include <asm/ccwdev.h> | ||
5 | #include <asm/atomic.h> | ||
6 | #include <linux/wait.h> | ||
7 | |||
4 | /* | 8 | /* |
5 | * states of the device statemachine | 9 | * states of the device statemachine |
6 | */ | 10 | */ |
@@ -67,6 +71,8 @@ dev_fsm_final_state(struct ccw_device *cdev) | |||
67 | 71 | ||
68 | extern struct workqueue_struct *ccw_device_work; | 72 | extern struct workqueue_struct *ccw_device_work; |
69 | extern struct workqueue_struct *ccw_device_notify_work; | 73 | extern struct workqueue_struct *ccw_device_notify_work; |
74 | extern wait_queue_head_t ccw_device_init_wq; | ||
75 | extern atomic_t ccw_device_init_count; | ||
70 | 76 | ||
71 | void io_subchannel_recog_done(struct ccw_device *cdev); | 77 | void io_subchannel_recog_done(struct ccw_device *cdev); |
72 | 78 | ||