diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2008-07-14 03:59:05 -0400 |
---|---|---|
committer | Heiko Carstens <heiko.carstens@de.ibm.com> | 2008-07-14 04:02:12 -0400 |
commit | 9d92a7e1b0d095c8be96ce5e592c6c5541684631 (patch) | |
tree | 22cfca810de07a7d7f87f17a89de0ae10d462038 /drivers/s390/cio/chsc.c | |
parent | 683c5418e6ac9f40f925dab6f547a5b0a4ad43c6 (diff) |
[S390] cio: Add chsc subchannel driver.
This patch adds a driver for subchannels of type chsc.
A device /dev/chsc is created which may be used to issue ioctls to:
- obtain information about the machine's I/O configuration
- dynamically change the machine's I/O configuration via
asynchronous chsc commands
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/chsc.c')
-rw-r--r-- | drivers/s390/cio/chsc.c | 48 |
1 files changed, 41 insertions, 7 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index e23c3806972a..65264a38057d 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -15,6 +15,7 @@ | |||
15 | 15 | ||
16 | #include <asm/cio.h> | 16 | #include <asm/cio.h> |
17 | #include <asm/chpid.h> | 17 | #include <asm/chpid.h> |
18 | #include <asm/chsc.h> | ||
18 | 19 | ||
19 | #include "../s390mach.h" | 20 | #include "../s390mach.h" |
20 | #include "css.h" | 21 | #include "css.h" |
@@ -627,23 +628,33 @@ chsc_secm(struct channel_subsystem *css, int enable) | |||
627 | return ret; | 628 | return ret; |
628 | } | 629 | } |
629 | 630 | ||
630 | int chsc_determine_channel_path_description(struct chp_id chpid, | 631 | int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, |
631 | struct channel_path_desc *desc) | 632 | int c, int m, |
633 | struct chsc_response_struct *resp) | ||
632 | { | 634 | { |
633 | int ccode, ret; | 635 | int ccode, ret; |
634 | 636 | ||
635 | struct { | 637 | struct { |
636 | struct chsc_header request; | 638 | struct chsc_header request; |
637 | u32 : 24; | 639 | u32 : 2; |
640 | u32 m : 1; | ||
641 | u32 c : 1; | ||
642 | u32 fmt : 4; | ||
643 | u32 cssid : 8; | ||
644 | u32 : 4; | ||
645 | u32 rfmt : 4; | ||
638 | u32 first_chpid : 8; | 646 | u32 first_chpid : 8; |
639 | u32 : 24; | 647 | u32 : 24; |
640 | u32 last_chpid : 8; | 648 | u32 last_chpid : 8; |
641 | u32 zeroes1; | 649 | u32 zeroes1; |
642 | struct chsc_header response; | 650 | struct chsc_header response; |
643 | u32 zeroes2; | 651 | u8 data[PAGE_SIZE - 20]; |
644 | struct channel_path_desc desc; | ||
645 | } __attribute__ ((packed)) *scpd_area; | 652 | } __attribute__ ((packed)) *scpd_area; |
646 | 653 | ||
654 | if ((rfmt == 1) && !css_general_characteristics.fcs) | ||
655 | return -EINVAL; | ||
656 | if ((rfmt == 2) && !css_general_characteristics.cib) | ||
657 | return -EINVAL; | ||
647 | scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); | 658 | scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); |
648 | if (!scpd_area) | 659 | if (!scpd_area) |
649 | return -ENOMEM; | 660 | return -ENOMEM; |
@@ -651,8 +662,13 @@ int chsc_determine_channel_path_description(struct chp_id chpid, | |||
651 | scpd_area->request.length = 0x0010; | 662 | scpd_area->request.length = 0x0010; |
652 | scpd_area->request.code = 0x0002; | 663 | scpd_area->request.code = 0x0002; |
653 | 664 | ||
665 | scpd_area->cssid = chpid.cssid; | ||
654 | scpd_area->first_chpid = chpid.id; | 666 | scpd_area->first_chpid = chpid.id; |
655 | scpd_area->last_chpid = chpid.id; | 667 | scpd_area->last_chpid = chpid.id; |
668 | scpd_area->m = m; | ||
669 | scpd_area->c = c; | ||
670 | scpd_area->fmt = fmt; | ||
671 | scpd_area->rfmt = rfmt; | ||
656 | 672 | ||
657 | ccode = chsc(scpd_area); | 673 | ccode = chsc(scpd_area); |
658 | if (ccode > 0) { | 674 | if (ccode > 0) { |
@@ -663,8 +679,7 @@ int chsc_determine_channel_path_description(struct chp_id chpid, | |||
663 | ret = chsc_error_from_response(scpd_area->response.code); | 679 | ret = chsc_error_from_response(scpd_area->response.code); |
664 | if (ret == 0) | 680 | if (ret == 0) |
665 | /* Success. */ | 681 | /* Success. */ |
666 | memcpy(desc, &scpd_area->desc, | 682 | memcpy(resp, &scpd_area->response, scpd_area->response.length); |
667 | sizeof(struct channel_path_desc)); | ||
668 | else | 683 | else |
669 | CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n", | 684 | CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n", |
670 | scpd_area->response.code); | 685 | scpd_area->response.code); |
@@ -672,6 +687,25 @@ out: | |||
672 | free_page((unsigned long)scpd_area); | 687 | free_page((unsigned long)scpd_area); |
673 | return ret; | 688 | return ret; |
674 | } | 689 | } |
690 | EXPORT_SYMBOL_GPL(chsc_determine_channel_path_desc); | ||
691 | |||
692 | int chsc_determine_base_channel_path_desc(struct chp_id chpid, | ||
693 | struct channel_path_desc *desc) | ||
694 | { | ||
695 | struct chsc_response_struct *chsc_resp; | ||
696 | int ret; | ||
697 | |||
698 | chsc_resp = kzalloc(sizeof(*chsc_resp), GFP_KERNEL); | ||
699 | if (!chsc_resp) | ||
700 | return -ENOMEM; | ||
701 | ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, chsc_resp); | ||
702 | if (ret) | ||
703 | goto out_free; | ||
704 | memcpy(desc, &chsc_resp->data, chsc_resp->length); | ||
705 | out_free: | ||
706 | kfree(chsc_resp); | ||
707 | return ret; | ||
708 | } | ||
675 | 709 | ||
676 | static void | 710 | static void |
677 | chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv, | 711 | chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv, |