diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2008-07-14 03:58:45 -0400 |
---|---|---|
committer | Heiko Carstens <heiko.carstens@de.ibm.com> | 2008-07-14 04:02:05 -0400 |
commit | c820de39bd083222f5be2563181c87493e436f7c (patch) | |
tree | 4861db1aeca00d55d76b5844ad209d81a2795105 /drivers/s390/cio/css.c | |
parent | 7e9db9eaefdb8798730790214ff1b7746006ec98 (diff) |
[S390] cio: Rework css driver.
Rework the css driver methods to provide sane callbacks for
subchannels of all types.
As a bonus, this cleans up and simplyfies the machine check
handling for I/O subchannels a lot.
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/css.c')
-rw-r--r-- | drivers/s390/cio/css.c | 123 |
1 files changed, 16 insertions, 107 deletions
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 53e7496dc90c..020566571e07 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -283,7 +283,7 @@ static int css_register_subchannel(struct subchannel *sch) | |||
283 | return ret; | 283 | return ret; |
284 | } | 284 | } |
285 | 285 | ||
286 | static int css_probe_device(struct subchannel_id schid) | 286 | int css_probe_device(struct subchannel_id schid) |
287 | { | 287 | { |
288 | int ret; | 288 | int ret; |
289 | struct subchannel *sch; | 289 | struct subchannel *sch; |
@@ -330,112 +330,6 @@ int css_sch_is_valid(struct schib *schib) | |||
330 | } | 330 | } |
331 | EXPORT_SYMBOL_GPL(css_sch_is_valid); | 331 | EXPORT_SYMBOL_GPL(css_sch_is_valid); |
332 | 332 | ||
333 | static int css_get_subchannel_status(struct subchannel *sch) | ||
334 | { | ||
335 | struct schib schib; | ||
336 | |||
337 | if (stsch(sch->schid, &schib)) | ||
338 | return CIO_GONE; | ||
339 | if (!css_sch_is_valid(&schib)) | ||
340 | return CIO_GONE; | ||
341 | if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev)) | ||
342 | return CIO_REVALIDATE; | ||
343 | if (!sch->lpm) | ||
344 | return CIO_NO_PATH; | ||
345 | return CIO_OPER; | ||
346 | } | ||
347 | |||
348 | static int css_evaluate_known_subchannel(struct subchannel *sch, int slow) | ||
349 | { | ||
350 | int event, ret, disc; | ||
351 | unsigned long flags; | ||
352 | enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE } action; | ||
353 | |||
354 | spin_lock_irqsave(sch->lock, flags); | ||
355 | disc = device_is_disconnected(sch); | ||
356 | if (disc && slow) { | ||
357 | /* Disconnected devices are evaluated directly only.*/ | ||
358 | spin_unlock_irqrestore(sch->lock, flags); | ||
359 | return 0; | ||
360 | } | ||
361 | /* No interrupt after machine check - kill pending timers. */ | ||
362 | device_kill_pending_timer(sch); | ||
363 | if (!disc && !slow) { | ||
364 | /* Non-disconnected devices are evaluated on the slow path. */ | ||
365 | spin_unlock_irqrestore(sch->lock, flags); | ||
366 | return -EAGAIN; | ||
367 | } | ||
368 | event = css_get_subchannel_status(sch); | ||
369 | CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, %s, %s path.\n", | ||
370 | sch->schid.ssid, sch->schid.sch_no, event, | ||
371 | disc ? "disconnected" : "normal", | ||
372 | slow ? "slow" : "fast"); | ||
373 | /* Analyze subchannel status. */ | ||
374 | action = NONE; | ||
375 | switch (event) { | ||
376 | case CIO_NO_PATH: | ||
377 | if (disc) { | ||
378 | /* Check if paths have become available. */ | ||
379 | action = REPROBE; | ||
380 | break; | ||
381 | } | ||
382 | /* fall through */ | ||
383 | case CIO_GONE: | ||
384 | /* Prevent unwanted effects when opening lock. */ | ||
385 | cio_disable_subchannel(sch); | ||
386 | device_set_disconnected(sch); | ||
387 | /* Ask driver what to do with device. */ | ||
388 | action = UNREGISTER; | ||
389 | if (sch->driver && sch->driver->notify) { | ||
390 | spin_unlock_irqrestore(sch->lock, flags); | ||
391 | ret = sch->driver->notify(sch, event); | ||
392 | spin_lock_irqsave(sch->lock, flags); | ||
393 | if (ret) | ||
394 | action = NONE; | ||
395 | } | ||
396 | break; | ||
397 | case CIO_REVALIDATE: | ||
398 | /* Device will be removed, so no notify necessary. */ | ||
399 | if (disc) | ||
400 | /* Reprobe because immediate unregister might block. */ | ||
401 | action = REPROBE; | ||
402 | else | ||
403 | action = UNREGISTER_PROBE; | ||
404 | break; | ||
405 | case CIO_OPER: | ||
406 | if (disc) | ||
407 | /* Get device operational again. */ | ||
408 | action = REPROBE; | ||
409 | break; | ||
410 | } | ||
411 | /* Perform action. */ | ||
412 | ret = 0; | ||
413 | switch (action) { | ||
414 | case UNREGISTER: | ||
415 | case UNREGISTER_PROBE: | ||
416 | /* Unregister device (will use subchannel lock). */ | ||
417 | spin_unlock_irqrestore(sch->lock, flags); | ||
418 | css_sch_device_unregister(sch); | ||
419 | spin_lock_irqsave(sch->lock, flags); | ||
420 | |||
421 | /* Reset intparm to zeroes. */ | ||
422 | sch->schib.pmcw.intparm = 0; | ||
423 | cio_modify(sch); | ||
424 | break; | ||
425 | case REPROBE: | ||
426 | device_trigger_reprobe(sch); | ||
427 | break; | ||
428 | default: | ||
429 | break; | ||
430 | } | ||
431 | spin_unlock_irqrestore(sch->lock, flags); | ||
432 | /* Probe if necessary. */ | ||
433 | if (action == UNREGISTER_PROBE) | ||
434 | ret = css_probe_device(sch->schid); | ||
435 | |||
436 | return ret; | ||
437 | } | ||
438 | |||
439 | static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow) | 333 | static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow) |
440 | { | 334 | { |
441 | struct schib schib; | 335 | struct schib schib; |
@@ -454,6 +348,21 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow) | |||
454 | return css_probe_device(schid); | 348 | return css_probe_device(schid); |
455 | } | 349 | } |
456 | 350 | ||
351 | static int css_evaluate_known_subchannel(struct subchannel *sch, int slow) | ||
352 | { | ||
353 | int ret = 0; | ||
354 | |||
355 | if (sch->driver) { | ||
356 | if (sch->driver->sch_event) | ||
357 | ret = sch->driver->sch_event(sch, slow); | ||
358 | else | ||
359 | dev_dbg(&sch->dev, | ||
360 | "Got subchannel machine check but " | ||
361 | "no sch_event handler provided.\n"); | ||
362 | } | ||
363 | return ret; | ||
364 | } | ||
365 | |||
457 | static void css_evaluate_subchannel(struct subchannel_id schid, int slow) | 366 | static void css_evaluate_subchannel(struct subchannel_id schid, int slow) |
458 | { | 367 | { |
459 | struct subchannel *sch; | 368 | struct subchannel *sch; |