diff options
Diffstat (limited to 'drivers/s390/cio/chsc.c')
-rw-r--r-- | drivers/s390/cio/chsc.c | 130 |
1 files changed, 33 insertions, 97 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 02615eb43984..89a130a62654 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -195,12 +195,8 @@ static void terminate_internal_io(struct subchannel *sch) | |||
195 | if (cio_clear(sch)) { | 195 | if (cio_clear(sch)) { |
196 | /* Recheck device in case clear failed. */ | 196 | /* Recheck device in case clear failed. */ |
197 | sch->lpm = 0; | 197 | sch->lpm = 0; |
198 | if (device_trigger_verify(sch) != 0) { | 198 | if (device_trigger_verify(sch) != 0) |
199 | if(css_enqueue_subchannel_slow(sch->schid)) { | 199 | css_schedule_eval(sch->schid); |
200 | css_clear_subchannel_slow_list(); | ||
201 | need_rescan = 1; | ||
202 | } | ||
203 | } | ||
204 | return; | 200 | return; |
205 | } | 201 | } |
206 | /* Request retry of internal operation. */ | 202 | /* Request retry of internal operation. */ |
@@ -262,11 +258,8 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) | |||
262 | 258 | ||
263 | out_unreg: | 259 | out_unreg: |
264 | sch->lpm = 0; | 260 | sch->lpm = 0; |
265 | if (css_enqueue_subchannel_slow(sch->schid)) { | ||
266 | css_clear_subchannel_slow_list(); | ||
267 | need_rescan = 1; | ||
268 | } | ||
269 | spin_unlock_irq(sch->lock); | 261 | spin_unlock_irq(sch->lock); |
262 | css_schedule_eval(sch->schid); | ||
270 | return 0; | 263 | return 0; |
271 | } | 264 | } |
272 | 265 | ||
@@ -281,9 +274,6 @@ void chsc_chp_offline(struct chp_id chpid) | |||
281 | return; | 274 | return; |
282 | bus_for_each_dev(&css_bus_type, NULL, &chpid, | 275 | bus_for_each_dev(&css_bus_type, NULL, &chpid, |
283 | s390_subchannel_remove_chpid); | 276 | s390_subchannel_remove_chpid); |
284 | |||
285 | if (need_rescan || css_slow_subchannels_exist()) | ||
286 | queue_work(slow_path_wq, &slow_path_work); | ||
287 | } | 277 | } |
288 | 278 | ||
289 | struct res_acc_data { | 279 | struct res_acc_data { |
@@ -331,7 +321,6 @@ static int | |||
331 | s390_process_res_acc_new_sch(struct subchannel_id schid) | 321 | s390_process_res_acc_new_sch(struct subchannel_id schid) |
332 | { | 322 | { |
333 | struct schib schib; | 323 | struct schib schib; |
334 | int ret; | ||
335 | /* | 324 | /* |
336 | * We don't know the device yet, but since a path | 325 | * We don't know the device yet, but since a path |
337 | * may be available now to the device we'll have | 326 | * may be available now to the device we'll have |
@@ -342,15 +331,10 @@ s390_process_res_acc_new_sch(struct subchannel_id schid) | |||
342 | */ | 331 | */ |
343 | if (stsch_err(schid, &schib)) | 332 | if (stsch_err(schid, &schib)) |
344 | /* We're through */ | 333 | /* We're through */ |
345 | return need_rescan ? -EAGAIN : -ENXIO; | 334 | return -ENXIO; |
346 | 335 | ||
347 | /* Put it on the slow path. */ | 336 | /* Put it on the slow path. */ |
348 | ret = css_enqueue_subchannel_slow(schid); | 337 | css_schedule_eval(schid); |
349 | if (ret) { | ||
350 | css_clear_subchannel_slow_list(); | ||
351 | need_rescan = 1; | ||
352 | return -EAGAIN; | ||
353 | } | ||
354 | return 0; | 338 | return 0; |
355 | } | 339 | } |
356 | 340 | ||
@@ -392,10 +376,8 @@ __s390_process_res_acc(struct subchannel_id schid, void *data) | |||
392 | } | 376 | } |
393 | 377 | ||
394 | 378 | ||
395 | static int | 379 | static void s390_process_res_acc (struct res_acc_data *res_data) |
396 | s390_process_res_acc (struct res_acc_data *res_data) | ||
397 | { | 380 | { |
398 | int rc; | ||
399 | char dbf_txt[15]; | 381 | char dbf_txt[15]; |
400 | 382 | ||
401 | sprintf(dbf_txt, "accpr%x.%02x", res_data->chpid.cssid, | 383 | sprintf(dbf_txt, "accpr%x.%02x", res_data->chpid.cssid, |
@@ -413,12 +395,7 @@ s390_process_res_acc (struct res_acc_data *res_data) | |||
413 | * The more information we have (info), the less scanning | 395 | * The more information we have (info), the less scanning |
414 | * will we have to do. | 396 | * will we have to do. |
415 | */ | 397 | */ |
416 | rc = for_each_subchannel(__s390_process_res_acc, res_data); | 398 | for_each_subchannel(__s390_process_res_acc, res_data); |
417 | if (css_slow_subchannels_exist()) | ||
418 | rc = -EAGAIN; | ||
419 | else if (rc != -EAGAIN) | ||
420 | rc = 0; | ||
421 | return rc; | ||
422 | } | 399 | } |
423 | 400 | ||
424 | static int | 401 | static int |
@@ -470,7 +447,7 @@ struct chsc_sei_area { | |||
470 | /* ccdf has to be big enough for a link-incident record */ | 447 | /* ccdf has to be big enough for a link-incident record */ |
471 | } __attribute__ ((packed)); | 448 | } __attribute__ ((packed)); |
472 | 449 | ||
473 | static int chsc_process_sei_link_incident(struct chsc_sei_area *sei_area) | 450 | static void chsc_process_sei_link_incident(struct chsc_sei_area *sei_area) |
474 | { | 451 | { |
475 | struct chp_id chpid; | 452 | struct chp_id chpid; |
476 | int id; | 453 | int id; |
@@ -478,7 +455,7 @@ static int chsc_process_sei_link_incident(struct chsc_sei_area *sei_area) | |||
478 | CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x)\n", | 455 | CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x)\n", |
479 | sei_area->rs, sei_area->rsid); | 456 | sei_area->rs, sei_area->rsid); |
480 | if (sei_area->rs != 4) | 457 | if (sei_area->rs != 4) |
481 | return 0; | 458 | return; |
482 | id = __get_chpid_from_lir(sei_area->ccdf); | 459 | id = __get_chpid_from_lir(sei_area->ccdf); |
483 | if (id < 0) | 460 | if (id < 0) |
484 | CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n"); | 461 | CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n"); |
@@ -487,21 +464,18 @@ static int chsc_process_sei_link_incident(struct chsc_sei_area *sei_area) | |||
487 | chpid.id = id; | 464 | chpid.id = id; |
488 | chsc_chp_offline(chpid); | 465 | chsc_chp_offline(chpid); |
489 | } | 466 | } |
490 | |||
491 | return 0; | ||
492 | } | 467 | } |
493 | 468 | ||
494 | static int chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) | 469 | static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) |
495 | { | 470 | { |
496 | struct res_acc_data res_data; | 471 | struct res_acc_data res_data; |
497 | struct chp_id chpid; | 472 | struct chp_id chpid; |
498 | int status; | 473 | int status; |
499 | int rc; | ||
500 | 474 | ||
501 | CIO_CRW_EVENT(4, "chsc: resource accessibility event (rs=%02x, " | 475 | CIO_CRW_EVENT(4, "chsc: resource accessibility event (rs=%02x, " |
502 | "rs_id=%04x)\n", sei_area->rs, sei_area->rsid); | 476 | "rs_id=%04x)\n", sei_area->rs, sei_area->rsid); |
503 | if (sei_area->rs != 4) | 477 | if (sei_area->rs != 4) |
504 | return 0; | 478 | return; |
505 | chp_id_init(&chpid); | 479 | chp_id_init(&chpid); |
506 | chpid.id = sei_area->rsid; | 480 | chpid.id = sei_area->rsid; |
507 | /* allocate a new channel path structure, if needed */ | 481 | /* allocate a new channel path structure, if needed */ |
@@ -509,7 +483,7 @@ static int chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) | |||
509 | if (status < 0) | 483 | if (status < 0) |
510 | chp_new(chpid); | 484 | chp_new(chpid); |
511 | else if (!status) | 485 | else if (!status) |
512 | return 0; | 486 | return; |
513 | memset(&res_data, 0, sizeof(struct res_acc_data)); | 487 | memset(&res_data, 0, sizeof(struct res_acc_data)); |
514 | res_data.chpid = chpid; | 488 | res_data.chpid = chpid; |
515 | if ((sei_area->vf & 0xc0) != 0) { | 489 | if ((sei_area->vf & 0xc0) != 0) { |
@@ -521,9 +495,7 @@ static int chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) | |||
521 | /* link address */ | 495 | /* link address */ |
522 | res_data.fla_mask = 0xff00; | 496 | res_data.fla_mask = 0xff00; |
523 | } | 497 | } |
524 | rc = s390_process_res_acc(&res_data); | 498 | s390_process_res_acc(&res_data); |
525 | |||
526 | return rc; | ||
527 | } | 499 | } |
528 | 500 | ||
529 | struct chp_config_data { | 501 | struct chp_config_data { |
@@ -532,7 +504,7 @@ struct chp_config_data { | |||
532 | u8 pc; | 504 | u8 pc; |
533 | }; | 505 | }; |
534 | 506 | ||
535 | static int chsc_process_sei_chp_config(struct chsc_sei_area *sei_area) | 507 | static void chsc_process_sei_chp_config(struct chsc_sei_area *sei_area) |
536 | { | 508 | { |
537 | struct chp_config_data *data; | 509 | struct chp_config_data *data; |
538 | struct chp_id chpid; | 510 | struct chp_id chpid; |
@@ -540,7 +512,7 @@ static int chsc_process_sei_chp_config(struct chsc_sei_area *sei_area) | |||
540 | 512 | ||
541 | CIO_CRW_EVENT(4, "chsc: channel-path-configuration notification\n"); | 513 | CIO_CRW_EVENT(4, "chsc: channel-path-configuration notification\n"); |
542 | if (sei_area->rs != 0) | 514 | if (sei_area->rs != 0) |
543 | return 0; | 515 | return; |
544 | data = (struct chp_config_data *) &(sei_area->ccdf); | 516 | data = (struct chp_config_data *) &(sei_area->ccdf); |
545 | chp_id_init(&chpid); | 517 | chp_id_init(&chpid); |
546 | for (num = 0; num <= __MAX_CHPID; num++) { | 518 | for (num = 0; num <= __MAX_CHPID; num++) { |
@@ -561,52 +533,44 @@ static int chsc_process_sei_chp_config(struct chsc_sei_area *sei_area) | |||
561 | break; | 533 | break; |
562 | } | 534 | } |
563 | } | 535 | } |
564 | |||
565 | return 0; | ||
566 | } | 536 | } |
567 | 537 | ||
568 | static int chsc_process_sei(struct chsc_sei_area *sei_area) | 538 | static void chsc_process_sei(struct chsc_sei_area *sei_area) |
569 | { | 539 | { |
570 | int rc; | ||
571 | |||
572 | /* Check if we might have lost some information. */ | 540 | /* Check if we might have lost some information. */ |
573 | if (sei_area->flags & 0x40) | 541 | if (sei_area->flags & 0x40) { |
574 | CIO_CRW_EVENT(2, "chsc: event overflow\n"); | 542 | CIO_CRW_EVENT(2, "chsc: event overflow\n"); |
543 | css_schedule_eval_all(); | ||
544 | } | ||
575 | /* which kind of information was stored? */ | 545 | /* which kind of information was stored? */ |
576 | rc = 0; | ||
577 | switch (sei_area->cc) { | 546 | switch (sei_area->cc) { |
578 | case 1: /* link incident*/ | 547 | case 1: /* link incident*/ |
579 | rc = chsc_process_sei_link_incident(sei_area); | 548 | chsc_process_sei_link_incident(sei_area); |
580 | break; | 549 | break; |
581 | case 2: /* i/o resource accessibiliy */ | 550 | case 2: /* i/o resource accessibiliy */ |
582 | rc = chsc_process_sei_res_acc(sei_area); | 551 | chsc_process_sei_res_acc(sei_area); |
583 | break; | 552 | break; |
584 | case 8: /* channel-path-configuration notification */ | 553 | case 8: /* channel-path-configuration notification */ |
585 | rc = chsc_process_sei_chp_config(sei_area); | 554 | chsc_process_sei_chp_config(sei_area); |
586 | break; | 555 | break; |
587 | default: /* other stuff */ | 556 | default: /* other stuff */ |
588 | CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n", | 557 | CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n", |
589 | sei_area->cc); | 558 | sei_area->cc); |
590 | break; | 559 | break; |
591 | } | 560 | } |
592 | |||
593 | return rc; | ||
594 | } | 561 | } |
595 | 562 | ||
596 | int chsc_process_crw(void) | 563 | void chsc_process_crw(void) |
597 | { | 564 | { |
598 | struct chsc_sei_area *sei_area; | 565 | struct chsc_sei_area *sei_area; |
599 | int ret; | ||
600 | int rc; | ||
601 | 566 | ||
602 | if (!sei_page) | 567 | if (!sei_page) |
603 | return 0; | 568 | return; |
604 | /* Access to sei_page is serialized through machine check handler | 569 | /* Access to sei_page is serialized through machine check handler |
605 | * thread, so no need for locking. */ | 570 | * thread, so no need for locking. */ |
606 | sei_area = sei_page; | 571 | sei_area = sei_page; |
607 | 572 | ||
608 | CIO_TRACE_EVENT( 2, "prcss"); | 573 | CIO_TRACE_EVENT( 2, "prcss"); |
609 | ret = 0; | ||
610 | do { | 574 | do { |
611 | memset(sei_area, 0, sizeof(*sei_area)); | 575 | memset(sei_area, 0, sizeof(*sei_area)); |
612 | sei_area->request.length = 0x0010; | 576 | sei_area->request.length = 0x0010; |
@@ -616,37 +580,26 @@ int chsc_process_crw(void) | |||
616 | 580 | ||
617 | if (sei_area->response.code == 0x0001) { | 581 | if (sei_area->response.code == 0x0001) { |
618 | CIO_CRW_EVENT(4, "chsc: sei successful\n"); | 582 | CIO_CRW_EVENT(4, "chsc: sei successful\n"); |
619 | rc = chsc_process_sei(sei_area); | 583 | chsc_process_sei(sei_area); |
620 | if (rc) | ||
621 | ret = rc; | ||
622 | } else { | 584 | } else { |
623 | CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n", | 585 | CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n", |
624 | sei_area->response.code); | 586 | sei_area->response.code); |
625 | ret = 0; | ||
626 | break; | 587 | break; |
627 | } | 588 | } |
628 | } while (sei_area->flags & 0x80); | 589 | } while (sei_area->flags & 0x80); |
629 | |||
630 | return ret; | ||
631 | } | 590 | } |
632 | 591 | ||
633 | static int | 592 | static int |
634 | __chp_add_new_sch(struct subchannel_id schid) | 593 | __chp_add_new_sch(struct subchannel_id schid) |
635 | { | 594 | { |
636 | struct schib schib; | 595 | struct schib schib; |
637 | int ret; | ||
638 | 596 | ||
639 | if (stsch_err(schid, &schib)) | 597 | if (stsch_err(schid, &schib)) |
640 | /* We're through */ | 598 | /* We're through */ |
641 | return need_rescan ? -EAGAIN : -ENXIO; | 599 | return -ENXIO; |
642 | 600 | ||
643 | /* Put it on the slow path. */ | 601 | /* Put it on the slow path. */ |
644 | ret = css_enqueue_subchannel_slow(schid); | 602 | css_schedule_eval(schid); |
645 | if (ret) { | ||
646 | css_clear_subchannel_slow_list(); | ||
647 | need_rescan = 1; | ||
648 | return -EAGAIN; | ||
649 | } | ||
650 | return 0; | 603 | return 0; |
651 | } | 604 | } |
652 | 605 | ||
@@ -693,22 +646,15 @@ __chp_add(struct subchannel_id schid, void *data) | |||
693 | return 0; | 646 | return 0; |
694 | } | 647 | } |
695 | 648 | ||
696 | int chsc_chp_online(struct chp_id chpid) | 649 | void chsc_chp_online(struct chp_id chpid) |
697 | { | 650 | { |
698 | int rc; | ||
699 | char dbf_txt[15]; | 651 | char dbf_txt[15]; |
700 | 652 | ||
701 | sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id); | 653 | sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id); |
702 | CIO_TRACE_EVENT(2, dbf_txt); | 654 | CIO_TRACE_EVENT(2, dbf_txt); |
703 | 655 | ||
704 | if (chp_get_status(chpid) == 0) | 656 | if (chp_get_status(chpid) != 0) |
705 | return 0; | 657 | for_each_subchannel(__chp_add, &chpid); |
706 | rc = for_each_subchannel(__chp_add, &chpid); | ||
707 | if (css_slow_subchannels_exist()) | ||
708 | rc = -EAGAIN; | ||
709 | if (rc != -EAGAIN) | ||
710 | rc = 0; | ||
711 | return rc; | ||
712 | } | 658 | } |
713 | 659 | ||
714 | static void __s390_subchannel_vary_chpid(struct subchannel *sch, | 660 | static void __s390_subchannel_vary_chpid(struct subchannel *sch, |
@@ -749,12 +695,8 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch, | |||
749 | sch->driver->verify(&sch->dev); | 695 | sch->driver->verify(&sch->dev); |
750 | } | 696 | } |
751 | } else if (!sch->lpm) { | 697 | } else if (!sch->lpm) { |
752 | if (device_trigger_verify(sch) != 0) { | 698 | if (device_trigger_verify(sch) != 0) |
753 | if (css_enqueue_subchannel_slow(sch->schid)) { | 699 | css_schedule_eval(sch->schid); |
754 | css_clear_subchannel_slow_list(); | ||
755 | need_rescan = 1; | ||
756 | } | ||
757 | } | ||
758 | } else if (sch->driver && sch->driver->verify) | 700 | } else if (sch->driver && sch->driver->verify) |
759 | sch->driver->verify(&sch->dev); | 701 | sch->driver->verify(&sch->dev); |
760 | break; | 702 | break; |
@@ -801,11 +743,7 @@ __s390_vary_chpid_on(struct subchannel_id schid, void *data) | |||
801 | /* We're through */ | 743 | /* We're through */ |
802 | return -ENXIO; | 744 | return -ENXIO; |
803 | /* Put it on the slow path. */ | 745 | /* Put it on the slow path. */ |
804 | if (css_enqueue_subchannel_slow(schid)) { | 746 | css_schedule_eval(schid); |
805 | css_clear_subchannel_slow_list(); | ||
806 | need_rescan = 1; | ||
807 | return -EAGAIN; | ||
808 | } | ||
809 | return 0; | 747 | return 0; |
810 | } | 748 | } |
811 | 749 | ||
@@ -826,8 +764,6 @@ int chsc_chp_vary(struct chp_id chpid, int on) | |||
826 | if (on) | 764 | if (on) |
827 | /* Scan for new devices on varied on path. */ | 765 | /* Scan for new devices on varied on path. */ |
828 | for_each_subchannel(__s390_vary_chpid_on, NULL); | 766 | for_each_subchannel(__s390_vary_chpid_on, NULL); |
829 | if (need_rescan || css_slow_subchannels_exist()) | ||
830 | queue_work(slow_path_wq, &slow_path_work); | ||
831 | return 0; | 767 | return 0; |
832 | } | 768 | } |
833 | 769 | ||