aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorHendrik Brueckner <brueckner@linux.vnet.ibm.com>2009-01-09 06:15:01 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2009-01-09 06:15:09 -0500
commit6c089fd3502c4655ad7dd9b0f83ab9cb98c98ba3 (patch)
tree4bef449ab25eb1d24a06ca72c4dbb4237de0e41f /drivers/char
parent68c6b3d2c6e49671f6974c9c5ea31c5f190cc8a5 (diff)
[S390] hvc_iucv: Special handling of IUCV HVC devices
This patch introduces special handling of the IUCV HVC console device. If the first IUCV HVC terminal is used as (preferred) Linux console, and needs some special handling for hangup. The hvc_iucv_private structure contains a flag to indicate whether a IUCV HVC device is used as a console. A terminal acting as "console" behaves different if a tty hangup occurs: If the iucv communication path is severed, a tty hangup is not triggered (because the HVC layer does not notify its back-end in that case). Instead, the console session is left unchanged and the IUCV HVC device is reset to allow re-connects. Note: Any output between the disconnect and a re-connect is discarded. Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/hvc_iucv.c40
1 files changed, 28 insertions, 12 deletions
diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c
index 7b627368caa..a53496828b7 100644
--- a/drivers/char/hvc_iucv.c
+++ b/drivers/char/hvc_iucv.c
@@ -60,6 +60,7 @@ enum tty_state_t {
60struct hvc_iucv_private { 60struct 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... */
95static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES]; 96static 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 */
98static struct kmem_cache *hvc_iucv_buffer_cache; 100static 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 */
823static int __init hvc_iucv_alloc(int id) 832static 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 */
870static int __init hvc_iucv_init(void) 882static 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 }
953out_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;