diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2008-07-14 03:58:46 -0400 |
---|---|---|
committer | Heiko Carstens <heiko.carstens@de.ibm.com> | 2008-07-14 04:02:06 -0400 |
commit | c11561897ab57a3c11e0a284ba17795d580589ab (patch) | |
tree | 53224c4e8062a85b1794a3cabe81a86317538dfa /drivers/s390/cio | |
parent | c820de39bd083222f5be2563181c87493e436f7c (diff) |
[S390] cio: Cleanup crw interface.
Eliminate the need for the machine check handler to call into
the common I/O layer directly by introducing an interface to
register handlers for crws per rsc.
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')
-rw-r--r-- | drivers/s390/cio/chp.c | 49 | ||||
-rw-r--r-- | drivers/s390/cio/chp.h | 1 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.c | 25 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.h | 2 | ||||
-rw-r--r-- | drivers/s390/cio/css.c | 31 | ||||
-rw-r--r-- | drivers/s390/cio/css.h | 1 |
6 files changed, 87 insertions, 22 deletions
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 297f1653b52b..672d9731c525 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <asm/chpid.h> | 18 | #include <asm/chpid.h> |
19 | #include <asm/sclp.h> | 19 | #include <asm/sclp.h> |
20 | 20 | ||
21 | #include "../s390mach.h" | ||
21 | #include "cio.h" | 22 | #include "cio.h" |
22 | #include "css.h" | 23 | #include "css.h" |
23 | #include "ioasm.h" | 24 | #include "ioasm.h" |
@@ -476,24 +477,52 @@ void *chp_get_chp_desc(struct chp_id chpid) | |||
476 | 477 | ||
477 | /** | 478 | /** |
478 | * chp_process_crw - process channel-path status change | 479 | * chp_process_crw - process channel-path status change |
479 | * @id: channel-path ID number | 480 | * @crw0: channel report-word to handler |
480 | * @status: non-zero if channel-path has become available, zero otherwise | 481 | * @crw1: second channel-report word (always NULL) |
482 | * @overflow: crw overflow indication | ||
481 | * | 483 | * |
482 | * Handle channel-report-words indicating that the status of a channel-path | 484 | * Handle channel-report-words indicating that the status of a channel-path |
483 | * has changed. | 485 | * has changed. |
484 | */ | 486 | */ |
485 | void chp_process_crw(int id, int status) | 487 | static void chp_process_crw(struct crw *crw0, struct crw *crw1, |
488 | int overflow) | ||
486 | { | 489 | { |
487 | struct chp_id chpid; | 490 | struct chp_id chpid; |
488 | 491 | ||
492 | if (overflow) { | ||
493 | css_schedule_eval_all(); | ||
494 | return; | ||
495 | } | ||
496 | CIO_CRW_EVENT(2, "CRW reports slct=%d, oflw=%d, " | ||
497 | "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", | ||
498 | crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc, | ||
499 | crw0->erc, crw0->rsid); | ||
500 | /* | ||
501 | * Check for solicited machine checks. These are | ||
502 | * created by reset channel path and need not be | ||
503 | * handled here. | ||
504 | */ | ||
505 | if (crw0->slct) { | ||
506 | CIO_CRW_EVENT(2, "solicited machine check for " | ||
507 | "channel path %02X\n", crw0->rsid); | ||
508 | return; | ||
509 | } | ||
489 | chp_id_init(&chpid); | 510 | chp_id_init(&chpid); |
490 | chpid.id = id; | 511 | chpid.id = crw0->rsid; |
491 | if (status) { | 512 | switch (crw0->erc) { |
513 | case CRW_ERC_IPARM: /* Path has come. */ | ||
492 | if (!chp_is_registered(chpid)) | 514 | if (!chp_is_registered(chpid)) |
493 | chp_new(chpid); | 515 | chp_new(chpid); |
494 | chsc_chp_online(chpid); | 516 | chsc_chp_online(chpid); |
495 | } else | 517 | break; |
518 | case CRW_ERC_PERRI: /* Path has gone. */ | ||
519 | case CRW_ERC_PERRN: | ||
496 | chsc_chp_offline(chpid); | 520 | chsc_chp_offline(chpid); |
521 | break; | ||
522 | default: | ||
523 | CIO_CRW_EVENT(2, "Don't know how to handle erc=%x\n", | ||
524 | crw0->erc); | ||
525 | } | ||
497 | } | 526 | } |
498 | 527 | ||
499 | int chp_ssd_get_mask(struct chsc_ssd_info *ssd, struct res_acc_data *data) | 528 | int chp_ssd_get_mask(struct chsc_ssd_info *ssd, struct res_acc_data *data) |
@@ -674,10 +703,16 @@ static int cfg_wait_idle(void) | |||
674 | static int __init chp_init(void) | 703 | static int __init chp_init(void) |
675 | { | 704 | { |
676 | struct chp_id chpid; | 705 | struct chp_id chpid; |
706 | int ret; | ||
677 | 707 | ||
708 | ret = s390_register_crw_handler(CRW_RSC_CPATH, chp_process_crw); | ||
709 | if (ret) | ||
710 | return ret; | ||
678 | chp_wq = create_singlethread_workqueue("cio_chp"); | 711 | chp_wq = create_singlethread_workqueue("cio_chp"); |
679 | if (!chp_wq) | 712 | if (!chp_wq) { |
713 | s390_unregister_crw_handler(CRW_RSC_CPATH); | ||
680 | return -ENOMEM; | 714 | return -ENOMEM; |
715 | } | ||
681 | INIT_WORK(&cfg_work, cfg_func); | 716 | INIT_WORK(&cfg_work, cfg_func); |
682 | init_waitqueue_head(&cfg_wait_queue); | 717 | init_waitqueue_head(&cfg_wait_queue); |
683 | if (info_update()) | 718 | if (info_update()) |
diff --git a/drivers/s390/cio/chp.h b/drivers/s390/cio/chp.h index f03b0d2cdc09..dffe2771ddac 100644 --- a/drivers/s390/cio/chp.h +++ b/drivers/s390/cio/chp.h | |||
@@ -54,7 +54,6 @@ int chp_get_status(struct chp_id chpid); | |||
54 | u8 chp_get_sch_opm(struct subchannel *sch); | 54 | u8 chp_get_sch_opm(struct subchannel *sch); |
55 | int chp_is_registered(struct chp_id chpid); | 55 | int chp_is_registered(struct chp_id chpid); |
56 | void *chp_get_chp_desc(struct chp_id chpid); | 56 | void *chp_get_chp_desc(struct chp_id chpid); |
57 | void chp_process_crw(int id, int available); | ||
58 | void chp_remove_cmg_attr(struct channel_path *chp); | 57 | void chp_remove_cmg_attr(struct channel_path *chp); |
59 | int chp_add_cmg_attr(struct channel_path *chp); | 58 | int chp_add_cmg_attr(struct channel_path *chp); |
60 | int chp_new(struct chp_id chpid); | 59 | int chp_new(struct chp_id chpid); |
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 1c0f5db94c7b..cb36f7929786 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <asm/cio.h> | 16 | #include <asm/cio.h> |
17 | #include <asm/chpid.h> | 17 | #include <asm/chpid.h> |
18 | 18 | ||
19 | #include "../s390mach.h" | ||
19 | #include "css.h" | 20 | #include "css.h" |
20 | #include "cio.h" | 21 | #include "cio.h" |
21 | #include "cio_debug.h" | 22 | #include "cio_debug.h" |
@@ -372,17 +373,25 @@ static void chsc_process_sei(struct chsc_sei_area *sei_area) | |||
372 | } | 373 | } |
373 | } | 374 | } |
374 | 375 | ||
375 | void chsc_process_crw(void) | 376 | static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow) |
376 | { | 377 | { |
377 | struct chsc_sei_area *sei_area; | 378 | struct chsc_sei_area *sei_area; |
378 | 379 | ||
380 | if (overflow) { | ||
381 | css_schedule_eval_all(); | ||
382 | return; | ||
383 | } | ||
384 | CIO_CRW_EVENT(2, "CRW reports slct=%d, oflw=%d, " | ||
385 | "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", | ||
386 | crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc, | ||
387 | crw0->erc, crw0->rsid); | ||
379 | if (!sei_page) | 388 | if (!sei_page) |
380 | return; | 389 | return; |
381 | /* Access to sei_page is serialized through machine check handler | 390 | /* Access to sei_page is serialized through machine check handler |
382 | * thread, so no need for locking. */ | 391 | * thread, so no need for locking. */ |
383 | sei_area = sei_page; | 392 | sei_area = sei_page; |
384 | 393 | ||
385 | CIO_TRACE_EVENT( 2, "prcss"); | 394 | CIO_TRACE_EVENT(2, "prcss"); |
386 | do { | 395 | do { |
387 | memset(sei_area, 0, sizeof(*sei_area)); | 396 | memset(sei_area, 0, sizeof(*sei_area)); |
388 | sei_area->request.length = 0x0010; | 397 | sei_area->request.length = 0x0010; |
@@ -751,15 +760,23 @@ out: | |||
751 | 760 | ||
752 | int __init chsc_alloc_sei_area(void) | 761 | int __init chsc_alloc_sei_area(void) |
753 | { | 762 | { |
763 | int ret; | ||
764 | |||
754 | sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); | 765 | sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); |
755 | if (!sei_page) | 766 | if (!sei_page) { |
756 | CIO_MSG_EVENT(0, "Can't allocate page for processing of " | 767 | CIO_MSG_EVENT(0, "Can't allocate page for processing of " |
757 | "chsc machine checks!\n"); | 768 | "chsc machine checks!\n"); |
758 | return (sei_page ? 0 : -ENOMEM); | 769 | return -ENOMEM; |
770 | } | ||
771 | ret = s390_register_crw_handler(CRW_RSC_CSS, chsc_process_crw); | ||
772 | if (ret) | ||
773 | kfree(sei_page); | ||
774 | return ret; | ||
759 | } | 775 | } |
760 | 776 | ||
761 | void __init chsc_free_sei_area(void) | 777 | void __init chsc_free_sei_area(void) |
762 | { | 778 | { |
779 | s390_unregister_crw_handler(CRW_RSC_CSS); | ||
763 | kfree(sei_page); | 780 | kfree(sei_page); |
764 | } | 781 | } |
765 | 782 | ||
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index d1f5db1e69b9..3b7c044d8453 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h | |||
@@ -36,8 +36,6 @@ struct channel_path_desc { | |||
36 | 36 | ||
37 | struct channel_path; | 37 | struct channel_path; |
38 | 38 | ||
39 | extern void chsc_process_crw(void); | ||
40 | |||
41 | struct css_general_char { | 39 | struct css_general_char { |
42 | u64 : 41; | 40 | u64 : 41; |
43 | u32 aif : 1; /* bit 41 */ | 41 | u32 aif : 1; /* bit 41 */ |
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 020566571e07..cf9d27c6f444 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/list.h> | 14 | #include <linux/list.h> |
15 | #include <linux/reboot.h> | 15 | #include <linux/reboot.h> |
16 | 16 | ||
17 | #include "../s390mach.h" | ||
17 | #include "css.h" | 18 | #include "css.h" |
18 | #include "cio.h" | 19 | #include "cio.h" |
19 | #include "cio_debug.h" | 20 | #include "cio_debug.h" |
@@ -530,18 +531,29 @@ EXPORT_SYMBOL_GPL(css_schedule_reprobe); | |||
530 | /* | 531 | /* |
531 | * Called from the machine check handler for subchannel report words. | 532 | * Called from the machine check handler for subchannel report words. |
532 | */ | 533 | */ |
533 | void css_process_crw(int rsid1, int rsid2) | 534 | static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow) |
534 | { | 535 | { |
535 | struct subchannel_id mchk_schid; | 536 | struct subchannel_id mchk_schid; |
536 | 537 | ||
537 | CIO_CRW_EVENT(2, "source is subchannel %04X, subsystem id %x\n", | 538 | if (overflow) { |
538 | rsid1, rsid2); | 539 | css_schedule_eval_all(); |
540 | return; | ||
541 | } | ||
542 | CIO_CRW_EVENT(2, "CRW0 reports slct=%d, oflw=%d, " | ||
543 | "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", | ||
544 | crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc, | ||
545 | crw0->erc, crw0->rsid); | ||
546 | if (crw1) | ||
547 | CIO_CRW_EVENT(2, "CRW1 reports slct=%d, oflw=%d, " | ||
548 | "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", | ||
549 | crw1->slct, crw1->oflw, crw1->chn, crw1->rsc, | ||
550 | crw1->anc, crw1->erc, crw1->rsid); | ||
539 | init_subchannel_id(&mchk_schid); | 551 | init_subchannel_id(&mchk_schid); |
540 | mchk_schid.sch_no = rsid1; | 552 | mchk_schid.sch_no = crw0->rsid; |
541 | if (rsid2 != 0) | 553 | if (crw1) |
542 | mchk_schid.ssid = (rsid2 >> 8) & 3; | 554 | mchk_schid.ssid = (crw1->rsid >> 8) & 3; |
543 | 555 | ||
544 | /* | 556 | /* |
545 | * Since we are always presented with IPI in the CRW, we have to | 557 | * Since we are always presented with IPI in the CRW, we have to |
546 | * use stsch() to find out if the subchannel in question has come | 558 | * use stsch() to find out if the subchannel in question has come |
547 | * or gone. | 559 | * or gone. |
@@ -740,6 +752,10 @@ init_channel_subsystem (void) | |||
740 | if (ret) | 752 | if (ret) |
741 | goto out; | 753 | goto out; |
742 | 754 | ||
755 | ret = s390_register_crw_handler(CRW_RSC_SCH, css_process_crw); | ||
756 | if (ret) | ||
757 | goto out; | ||
758 | |||
743 | if ((ret = bus_register(&css_bus_type))) | 759 | if ((ret = bus_register(&css_bus_type))) |
744 | goto out; | 760 | goto out; |
745 | 761 | ||
@@ -817,6 +833,7 @@ out_unregister: | |||
817 | out_bus: | 833 | out_bus: |
818 | bus_unregister(&css_bus_type); | 834 | bus_unregister(&css_bus_type); |
819 | out: | 835 | out: |
836 | s390_unregister_crw_handler(CRW_RSC_CSS); | ||
820 | chsc_free_sei_area(); | 837 | chsc_free_sei_area(); |
821 | kfree(slow_subchannel_set); | 838 | kfree(slow_subchannel_set); |
822 | printk(KERN_WARNING"cio: failed to initialize css driver (%d)!\n", | 839 | printk(KERN_WARNING"cio: failed to initialize css driver (%d)!\n", |
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 4cdc132c86bb..3ec3dc5a1e5e 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h | |||
@@ -103,7 +103,6 @@ int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *), | |||
103 | int (*fn_unknown)(struct subchannel_id, | 103 | int (*fn_unknown)(struct subchannel_id, |
104 | void *), void *data); | 104 | void *), void *data); |
105 | extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); | 105 | extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); |
106 | extern void css_process_crw(int, int); | ||
107 | extern void css_reiterate_subchannels(void); | 106 | extern void css_reiterate_subchannels(void); |
108 | void css_update_ssd_info(struct subchannel *sch); | 107 | void css_update_ssd_info(struct subchannel *sch); |
109 | 108 | ||