diff options
Diffstat (limited to 'drivers/char/hvc_iucv.c')
-rw-r--r-- | drivers/char/hvc_iucv.c | 40 |
1 files changed, 28 insertions, 12 deletions
diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c index 7b627368caac..a53496828b76 100644 --- a/drivers/char/hvc_iucv.c +++ b/drivers/char/hvc_iucv.c | |||
@@ -60,6 +60,7 @@ enum tty_state_t { | |||
60 | struct hvc_iucv_private { | 60 | struct hvc_iucv_private { |
61 | struct hvc_struct *hvc; /* HVC struct reference */ | 61 | struct hvc_struct *hvc; /* HVC struct reference */ |
62 | u8 srv_name[8]; /* IUCV service name (ebcdic) */ | 62 | u8 srv_name[8]; /* IUCV service name (ebcdic) */ |
63 | unsigned char is_console; /* Linux console usage flag */ | ||
63 | enum iucv_state_t iucv_state; /* IUCV connection status */ | 64 | enum iucv_state_t iucv_state; /* IUCV connection status */ |
64 | enum tty_state_t tty_state; /* TTY status */ | 65 | enum tty_state_t tty_state; /* TTY status */ |
65 | struct iucv_path *path; /* IUCV path pointer */ | 66 | struct iucv_path *path; /* IUCV path pointer */ |
@@ -93,6 +94,7 @@ static unsigned long hvc_iucv_devices = 1; | |||
93 | 94 | ||
94 | /* Array of allocated hvc iucv tty lines... */ | 95 | /* Array of allocated hvc iucv tty lines... */ |
95 | static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES]; | 96 | static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES]; |
97 | #define IUCV_HVC_CON_IDX (0) | ||
96 | 98 | ||
97 | /* Kmem cache and mempool for iucv_tty_buffer elements */ | 99 | /* Kmem cache and mempool for iucv_tty_buffer elements */ |
98 | static struct kmem_cache *hvc_iucv_buffer_cache; | 100 | static struct kmem_cache *hvc_iucv_buffer_cache; |
@@ -139,7 +141,7 @@ static struct iucv_tty_buffer *alloc_tty_buffer(size_t size, gfp_t flags) | |||
139 | bufp = mempool_alloc(hvc_iucv_mempool, flags); | 141 | bufp = mempool_alloc(hvc_iucv_mempool, flags); |
140 | if (!bufp) | 142 | if (!bufp) |
141 | return NULL; | 143 | return NULL; |
142 | memset(bufp, 0, sizeof(struct iucv_tty_buffer)); | 144 | memset(bufp, 0, sizeof(*bufp)); |
143 | 145 | ||
144 | if (size > 0) { | 146 | if (size > 0) { |
145 | bufp->msg.length = MSG_SIZE(size); | 147 | bufp->msg.length = MSG_SIZE(size); |
@@ -463,7 +465,7 @@ static int hvc_iucv_put_chars(uint32_t vtermno, const char *buf, int count) | |||
463 | * @id: Additional data (originally passed to hvc_alloc): the index of an struct | 465 | * @id: Additional data (originally passed to hvc_alloc): the index of an struct |
464 | * hvc_iucv_private instance. | 466 | * hvc_iucv_private instance. |
465 | * | 467 | * |
466 | * The function sets the tty state to TTY_OPEN for the struct hvc_iucv_private | 468 | * The function sets the tty state to TTY_OPENED for the struct hvc_iucv_private |
467 | * instance that is derived from @id. Always returns 0. | 469 | * instance that is derived from @id. Always returns 0. |
468 | * | 470 | * |
469 | * Locking: struct hvc_iucv_private->lock, spin_lock_bh | 471 | * Locking: struct hvc_iucv_private->lock, spin_lock_bh |
@@ -707,6 +709,9 @@ static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) | |||
707 | 709 | ||
708 | /* If the tty has not yet been opened, clean up the hvc_iucv_private | 710 | /* If the tty has not yet been opened, clean up the hvc_iucv_private |
709 | * structure to allow re-connects. | 711 | * structure to allow re-connects. |
712 | * This is also done for our console device because console hangups | ||
713 | * are handled specially and no notifier is called by HVC. | ||
714 | * The tty session is active (TTY_OPEN) and ready for re-connects... | ||
710 | * | 715 | * |
711 | * If it has been opened, let get_chars() return -EPIPE to signal the | 716 | * If it has been opened, let get_chars() return -EPIPE to signal the |
712 | * HVC layer to hang up the tty. | 717 | * HVC layer to hang up the tty. |
@@ -716,7 +721,11 @@ static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) | |||
716 | if (priv->tty_state == TTY_CLOSED) | 721 | if (priv->tty_state == TTY_CLOSED) |
717 | hvc_iucv_cleanup(priv); | 722 | hvc_iucv_cleanup(priv); |
718 | else | 723 | else |
719 | hvc_kick(); | 724 | if (priv->is_console) { |
725 | hvc_iucv_cleanup(priv); | ||
726 | priv->tty_state = TTY_OPENED; | ||
727 | } else | ||
728 | hvc_kick(); | ||
720 | spin_unlock(&priv->lock); | 729 | spin_unlock(&priv->lock); |
721 | 730 | ||
722 | /* finally sever path (outside of priv->lock due to lock ordering) */ | 731 | /* finally sever path (outside of priv->lock due to lock ordering) */ |
@@ -747,7 +756,6 @@ static void hvc_iucv_msg_pending(struct iucv_path *path, | |||
747 | return; | 756 | return; |
748 | } | 757 | } |
749 | 758 | ||
750 | |||
751 | spin_lock(&priv->lock); | 759 | spin_lock(&priv->lock); |
752 | 760 | ||
753 | /* reject messages if tty has not yet been opened */ | 761 | /* reject messages if tty has not yet been opened */ |
@@ -814,13 +822,14 @@ static struct hv_ops hvc_iucv_ops = { | |||
814 | 822 | ||
815 | /** | 823 | /** |
816 | * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance | 824 | * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance |
817 | * @id: hvc_iucv_table index | 825 | * @id: hvc_iucv_table index |
826 | * @is_console: Flag if the instance is used as Linux console | ||
818 | * | 827 | * |
819 | * This function allocates a new hvc_iucv_private structure and stores | 828 | * This function allocates a new hvc_iucv_private structure and stores |
820 | * the instance in hvc_iucv_table at index @id. | 829 | * the instance in hvc_iucv_table at index @id. |
821 | * Returns 0 on success; otherwise non-zero. | 830 | * Returns 0 on success; otherwise non-zero. |
822 | */ | 831 | */ |
823 | static int __init hvc_iucv_alloc(int id) | 832 | static int __init hvc_iucv_alloc(int id, unsigned int is_console) |
824 | { | 833 | { |
825 | struct hvc_iucv_private *priv; | 834 | struct hvc_iucv_private *priv; |
826 | char name[9]; | 835 | char name[9]; |
@@ -842,6 +851,9 @@ static int __init hvc_iucv_alloc(int id) | |||
842 | return -ENOMEM; | 851 | return -ENOMEM; |
843 | } | 852 | } |
844 | 853 | ||
854 | /* set console flag */ | ||
855 | priv->is_console = is_console; | ||
856 | |||
845 | /* finally allocate hvc */ | 857 | /* finally allocate hvc */ |
846 | priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /* PAGE_SIZE */ | 858 | priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /* PAGE_SIZE */ |
847 | HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256); | 859 | HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256); |
@@ -869,7 +881,8 @@ static int __init hvc_iucv_alloc(int id) | |||
869 | */ | 881 | */ |
870 | static int __init hvc_iucv_init(void) | 882 | static int __init hvc_iucv_init(void) |
871 | { | 883 | { |
872 | int rc, i; | 884 | int rc; |
885 | unsigned int i; | ||
873 | 886 | ||
874 | if (!MACHINE_IS_VM) { | 887 | if (!MACHINE_IS_VM) { |
875 | pr_info("The z/VM IUCV HVC device driver cannot " | 888 | pr_info("The z/VM IUCV HVC device driver cannot " |
@@ -901,14 +914,16 @@ static int __init hvc_iucv_init(void) | |||
901 | 914 | ||
902 | /* register the first terminal device as console | 915 | /* register the first terminal device as console |
903 | * (must be done before allocating hvc terminal devices) */ | 916 | * (must be done before allocating hvc terminal devices) */ |
904 | rc = hvc_instantiate(HVC_IUCV_MAGIC, 0, &hvc_iucv_ops); | 917 | rc = hvc_instantiate(HVC_IUCV_MAGIC, IUCV_HVC_CON_IDX, &hvc_iucv_ops); |
905 | if (rc) | 918 | if (rc) { |
906 | pr_warning("Registering HVC terminal device as " | 919 | pr_err("Registering HVC terminal device as " |
907 | "Linux console failed\n"); | 920 | "Linux console failed\n"); |
921 | goto out_error_memory; | ||
922 | } | ||
908 | 923 | ||
909 | /* allocate hvc_iucv_private structs */ | 924 | /* allocate hvc_iucv_private structs */ |
910 | for (i = 0; i < hvc_iucv_devices; i++) { | 925 | for (i = 0; i < hvc_iucv_devices; i++) { |
911 | rc = hvc_iucv_alloc(i); | 926 | rc = hvc_iucv_alloc(i, (i == IUCV_HVC_CON_IDX) ? 1 : 0); |
912 | if (rc) { | 927 | if (rc) { |
913 | pr_err("Creating a new HVC terminal device " | 928 | pr_err("Creating a new HVC terminal device " |
914 | "failed with error code=%d\n", rc); | 929 | "failed with error code=%d\n", rc); |
@@ -935,6 +950,7 @@ out_error_hvc: | |||
935 | hvc_remove(hvc_iucv_table[i]->hvc); | 950 | hvc_remove(hvc_iucv_table[i]->hvc); |
936 | kfree(hvc_iucv_table[i]); | 951 | kfree(hvc_iucv_table[i]); |
937 | } | 952 | } |
953 | out_error_memory: | ||
938 | mempool_destroy(hvc_iucv_mempool); | 954 | mempool_destroy(hvc_iucv_mempool); |
939 | kmem_cache_destroy(hvc_iucv_buffer_cache); | 955 | kmem_cache_destroy(hvc_iucv_buffer_cache); |
940 | return rc; | 956 | return rc; |