aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/chsc.c
diff options
context:
space:
mode:
authorPeter Oberparleiter <peter.oberparleiter@de.ibm.com>2007-04-27 10:01:34 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2007-04-27 10:01:40 -0400
commit83b3370c79b91b9be3f6540c3c914e689134b45f (patch)
treead7c062b260c0259c74e45ff869208c1ad139629 /drivers/s390/cio/chsc.c
parent387b734fc2b55f776b192c7afdfd892ba42347d4 (diff)
[S390] cio: replace subchannel evaluation queue with bitmap
Use a bitmap for indicating which subchannels require evaluation instead of allocating memory for each evaluation request. This approach reduces memory consumption during recovery in case of massive evaluation request occurrence and removes the need for memory allocation failure handling. Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/chsc.c')
-rw-r--r--drivers/s390/cio/chsc.c130
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
263out_unreg: 259out_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
289struct res_acc_data { 279struct res_acc_data {
@@ -331,7 +321,6 @@ static int
331s390_process_res_acc_new_sch(struct subchannel_id schid) 321s390_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
395static int 379static void s390_process_res_acc (struct res_acc_data *res_data)
396s390_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
424static int 401static 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
473static int chsc_process_sei_link_incident(struct chsc_sei_area *sei_area) 450static 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
494static int chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) 469static 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
529struct chp_config_data { 501struct chp_config_data {
@@ -532,7 +504,7 @@ struct chp_config_data {
532 u8 pc; 504 u8 pc;
533}; 505};
534 506
535static int chsc_process_sei_chp_config(struct chsc_sei_area *sei_area) 507static 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
568static int chsc_process_sei(struct chsc_sei_area *sei_area) 538static 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
596int chsc_process_crw(void) 563void 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
633static int 592static 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
696int chsc_chp_online(struct chp_id chpid) 649void 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
714static void __s390_subchannel_vary_chpid(struct subchannel *sch, 660static 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