aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/css.c
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2008-07-14 03:58:45 -0400
committerHeiko Carstens <heiko.carstens@de.ibm.com>2008-07-14 04:02:05 -0400
commitc820de39bd083222f5be2563181c87493e436f7c (patch)
tree4861db1aeca00d55d76b5844ad209d81a2795105 /drivers/s390/cio/css.c
parent7e9db9eaefdb8798730790214ff1b7746006ec98 (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.c123
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
286static int css_probe_device(struct subchannel_id schid) 286int 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}
331EXPORT_SYMBOL_GPL(css_sch_is_valid); 331EXPORT_SYMBOL_GPL(css_sch_is_valid);
332 332
333static 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
348static 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
439static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow) 333static 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
351static 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
457static void css_evaluate_subchannel(struct subchannel_id schid, int slow) 366static void css_evaluate_subchannel(struct subchannel_id schid, int slow)
458{ 367{
459 struct subchannel *sch; 368 struct subchannel *sch;