s390/sclp: avoid merged message output
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Thu, 1 Oct 2015 12:11:35 +0000 (14:11 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 14 Oct 2015 12:32:10 +0000 (14:32 +0200)
The sclp console and tty code currently uses several message text
objects in a single message event to print several lines with one
SCCB. This causes the output of these lines to be fused into a
block which is noticeable when selecting text in the operating system
message panel.

Instead use several message events with a single message text object
each to print every line on its own. This changes the SCCB layout
from

    struct sccb_header
        struct evbuf_header
            struct mdb_header
                struct go
                struct mto
...
struct mto

to

    struct sccb_header
        struct evbuf_header
            struct mdb_header
                struct go
                struct mto
...
        struct evbuf_header
            struct mdb_header
                struct go
                struct mto

Reviewed-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/char/sclp_rw.c
drivers/s390/char/sclp_rw.h
drivers/s390/char/sclp_tty.c

index 35a84af875ee97c046c8f9e9e2b3ddacae16eddc..6010cd347a08700701379ef17f738a12755eb110 100644 (file)
@@ -47,9 +47,9 @@ struct sclp_buffer *
 sclp_make_buffer(void *page, unsigned short columns, unsigned short htab)
 {
        struct sclp_buffer *buffer;
-       struct write_sccb *sccb;
+       struct sccb_header *sccb;
 
-       sccb = (struct write_sccb *) page;
+       sccb = (struct sccb_header *) page;
        /*
         * We keep the struct sclp_buffer structure at the end
         * of the sccb page.
@@ -57,24 +57,16 @@ sclp_make_buffer(void *page, unsigned short columns, unsigned short htab)
        buffer = ((struct sclp_buffer *) ((addr_t) sccb + PAGE_SIZE)) - 1;
        buffer->sccb = sccb;
        buffer->retry_count = 0;
-       buffer->mto_number = 0;
-       buffer->mto_char_sum = 0;
+       buffer->messages = 0;
+       buffer->char_sum = 0;
        buffer->current_line = NULL;
        buffer->current_length = 0;
        buffer->columns = columns;
        buffer->htab = htab;
 
        /* initialize sccb */
-       memset(sccb, 0, sizeof(struct write_sccb));
-       sccb->header.length = sizeof(struct write_sccb);
-       sccb->msg_buf.header.length = sizeof(struct msg_buf);
-       sccb->msg_buf.header.type = EVTYP_MSG;
-       sccb->msg_buf.mdb.header.length = sizeof(struct mdb);
-       sccb->msg_buf.mdb.header.type = 1;
-       sccb->msg_buf.mdb.header.tag = 0xD4C4C240;      /* ebcdic "MDB " */
-       sccb->msg_buf.mdb.header.revision_code = 1;
-       sccb->msg_buf.mdb.go.length = sizeof(struct go);
-       sccb->msg_buf.mdb.go.type = 1;
+       memset(sccb, 0, sizeof(struct sccb_header));
+       sccb->length = sizeof(struct sccb_header);
 
        return buffer;
 }
@@ -90,37 +82,49 @@ sclp_unmake_buffer(struct sclp_buffer *buffer)
 }
 
 /*
- * Initialize a new Message Text Object (MTO) at the end of the provided buffer
- * with enough room for max_len characters. Return 0 on success.
+ * Initialize a new message the end of the provided buffer with
+ * enough room for max_len characters. Return 0 on success.
  */
 static int
 sclp_initialize_mto(struct sclp_buffer *buffer, int max_len)
 {
-       struct write_sccb *sccb;
+       struct sccb_header *sccb;
+       struct msg_buf *msg;
+       struct mdb *mdb;
+       struct go *go;
        struct mto *mto;
-       int mto_size;
+       int msg_size;
 
-       /* max size of new Message Text Object including message text  */
-       mto_size = sizeof(struct mto) + max_len;
+       /* max size of new message including message text  */
+       msg_size = sizeof(struct msg_buf) + max_len;
 
        /* check if current buffer sccb can contain the mto */
        sccb = buffer->sccb;
-       if ((MAX_SCCB_ROOM - sccb->header.length) < mto_size)
+       if ((MAX_SCCB_ROOM - sccb->length) < msg_size)
                return -ENOMEM;
 
-       /* find address of new message text object */
-       mto = (struct mto *)(((addr_t) sccb) + sccb->header.length);
+       msg = (struct msg_buf *)((addr_t) sccb + sccb->length);
+       memset(msg, 0, sizeof(struct msg_buf));
+       msg->header.length = sizeof(struct msg_buf);
+       msg->header.type = EVTYP_MSG;
 
-       /*
-        * fill the new Message-Text Object,
-        * starting behind the former last byte of the SCCB
-        */
-       memset(mto, 0, sizeof(struct mto));
+       mdb = &msg->mdb;
+       mdb->header.length = sizeof(struct mdb);
+       mdb->header.type = 1;
+       mdb->header.tag = 0xD4C4C240;   /* ebcdic "MDB " */
+       mdb->header.revision_code = 1;
+
+       go = &mdb->go;
+       go->length = sizeof(struct go);
+       go->type = 1;
+
+       mto = &mdb->mto;
        mto->length = sizeof(struct mto);
        mto->type = 4;  /* message text object */
        mto->line_type_flags = LNTPFLGS_ENDTEXT; /* end text */
 
        /* set pointer to first byte after struct mto. */
+       buffer->current_msg = msg;
        buffer->current_line = (char *) (mto + 1);
        buffer->current_length = 0;
 
@@ -128,45 +132,37 @@ sclp_initialize_mto(struct sclp_buffer *buffer, int max_len)
 }
 
 /*
- * Finalize MTO initialized by sclp_initialize_mto(), updating the sizes of
- * MTO, enclosing MDB, event buffer and SCCB.
+ * Finalize message initialized by sclp_initialize_mto(),
+ * updating the sizes of MTO, enclosing MDB, event buffer and SCCB.
  */
 static void
 sclp_finalize_mto(struct sclp_buffer *buffer)
 {
-       struct write_sccb *sccb;
-       struct mto *mto;
-       int str_len, mto_size;
-
-       str_len = buffer->current_length;
-       buffer->current_line = NULL;
-       buffer->current_length = 0;
-
-       /* real size of new Message Text Object including message text  */
-       mto_size = sizeof(struct mto) + str_len;
-
-       /* find address of new message text object */
-       sccb = buffer->sccb;
-       mto = (struct mto *)(((addr_t) sccb) + sccb->header.length);
-
-       /* set size of message text object */
-       mto->length = mto_size;
+       struct sccb_header *sccb;
+       struct msg_buf *msg;
 
        /*
         * update values of sizes
         * (SCCB, Event(Message) Buffer, Message Data Block)
         */
-       sccb->header.length += mto_size;
-       sccb->msg_buf.header.length += mto_size;
-       sccb->msg_buf.mdb.header.length += mto_size;
+       sccb = buffer->sccb;
+       msg = buffer->current_msg;
+       msg->header.length += buffer->current_length;
+       msg->mdb.header.length += buffer->current_length;
+       msg->mdb.mto.length += buffer->current_length;
+       sccb->length += msg->header.length;
 
        /*
         * count number of buffered messages (= number of Message Text
         * Objects) and number of buffered characters
         * for the SCCB currently used for buffering and at all
         */
-       buffer->mto_number++;
-       buffer->mto_char_sum += str_len;
+       buffer->messages++;
+       buffer->char_sum += buffer->current_length;
+
+       buffer->current_line = NULL;
+       buffer->current_length = 0;
+       buffer->current_msg = NULL;
 }
 
 /*
@@ -218,7 +214,13 @@ sclp_write(struct sclp_buffer *buffer, const unsigned char *msg, int count)
                        break;
                case '\a':      /* bell, one for several times  */
                        /* set SCLP sound alarm bit in General Object */
-                       buffer->sccb->msg_buf.mdb.go.general_msg_flags |=
+                       if (buffer->current_line == NULL) {
+                               rc = sclp_initialize_mto(buffer,
+                                                        buffer->columns);
+                               if (rc)
+                                       return i_msg;
+                       }
+                       buffer->current_msg->mdb.go.general_msg_flags |=
                                GNRLMSGFLGS_SNDALRM;
                        break;
                case '\t':      /* horizontal tabulator  */
@@ -309,11 +311,13 @@ sclp_write(struct sclp_buffer *buffer, const unsigned char *msg, int count)
 int
 sclp_buffer_space(struct sclp_buffer *buffer)
 {
+       struct sccb_header *sccb;
        int count;
 
-       count = MAX_SCCB_ROOM - buffer->sccb->header.length;
+       sccb = buffer->sccb;
+       count = MAX_SCCB_ROOM - sccb->length;
        if (buffer->current_line != NULL)
-               count -= sizeof(struct mto) + buffer->current_length;
+               count -= sizeof(struct msg_buf) + buffer->current_length;
        return count;
 }
 
@@ -325,7 +329,7 @@ sclp_chars_in_buffer(struct sclp_buffer *buffer)
 {
        int count;
 
-       count = buffer->mto_char_sum;
+       count = buffer->char_sum;
        if (buffer->current_line != NULL)
                count += buffer->current_length;
        return count;
@@ -378,7 +382,7 @@ sclp_writedata_callback(struct sclp_req *request, void *data)
 {
        int rc;
        struct sclp_buffer *buffer;
-       struct write_sccb *sccb;
+       struct sccb_header *sccb;
 
        buffer = (struct sclp_buffer *) data;
        sccb = buffer->sccb;
@@ -389,7 +393,7 @@ sclp_writedata_callback(struct sclp_req *request, void *data)
                return;
        }
        /* check SCLP response code and choose suitable action  */
-       switch (sccb->header.response_code) {
+       switch (sccb->response_code) {
        case 0x0020 :
                /* Normal completion, buffer processed, message(s) sent */
                rc = 0;
@@ -403,7 +407,7 @@ sclp_writedata_callback(struct sclp_req *request, void *data)
                /* remove processed buffers and requeue rest */
                if (sclp_remove_processed((struct sccb_header *) sccb) > 0) {
                        /* not all buffers were processed */
-                       sccb->header.response_code = 0x0000;
+                       sccb->response_code = 0x0000;
                        buffer->request.status = SCLP_REQ_FILLED;
                        rc = sclp_add_request(request);
                        if (rc == 0)
@@ -419,14 +423,14 @@ sclp_writedata_callback(struct sclp_req *request, void *data)
                        break;
                }
                /* retry request */
-               sccb->header.response_code = 0x0000;
+               sccb->response_code = 0x0000;
                buffer->request.status = SCLP_REQ_FILLED;
                rc = sclp_add_request(request);
                if (rc == 0)
                        return;
                break;
        default:
-               if (sccb->header.response_code == 0x71f0)
+               if (sccb->response_code == 0x71f0)
                        rc = -ENOMEM;
                else
                        rc = -EINVAL;
@@ -445,25 +449,19 @@ int
 sclp_emit_buffer(struct sclp_buffer *buffer,
                 void (*callback)(struct sclp_buffer *, int))
 {
-       struct write_sccb *sccb;
-
        /* add current line if there is one */
        if (buffer->current_line != NULL)
                sclp_finalize_mto(buffer);
 
        /* Are there messages in the output buffer ? */
-       if (buffer->mto_number == 0)
+       if (buffer->messages == 0)
                return -EIO;
 
-       sccb = buffer->sccb;
-       /* Use normal write message */
-       sccb->msg_buf.header.type = EVTYP_MSG;
-
        buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
        buffer->request.status = SCLP_REQ_FILLED;
        buffer->request.callback = sclp_writedata_callback;
        buffer->request.callback_data = buffer;
-       buffer->request.sccb = sccb;
+       buffer->request.sccb = buffer->sccb;
        buffer->callback = callback;
        return sclp_add_request(&buffer->request);
 }
index 7a7bfc947d97eb3b502ccb39ee4fd21f751bdb5e..e3b0290995ba67d8c3d5c5374ac2e12023dc6dec 100644 (file)
@@ -45,6 +45,7 @@ struct mdb_header {
 struct mdb {
        struct mdb_header header;
        struct go go;
+       struct mto mto;
 } __attribute__((packed));
 
 struct msg_buf {
@@ -52,14 +53,9 @@ struct msg_buf {
        struct mdb mdb;
 } __attribute__((packed));
 
-struct write_sccb {
-       struct sccb_header header;
-       struct msg_buf msg_buf;
-} __attribute__((packed));
-
 /* The number of empty mto buffers that can be contained in a single sccb. */
-#define NR_EMPTY_MTO_PER_SCCB ((PAGE_SIZE - sizeof(struct sclp_buffer) - \
-                       sizeof(struct write_sccb)) / sizeof(struct mto))
+#define NR_EMPTY_MSG_PER_SCCB ((PAGE_SIZE - sizeof(struct sclp_buffer) - \
+                       sizeof(struct sccb_header)) / sizeof(struct msg_buf))
 
 /*
  * data structure for information about list of SCCBs (only for writing),
@@ -68,7 +64,8 @@ struct write_sccb {
 struct sclp_buffer {
        struct list_head list;          /* list_head for sccb_info chain */
        struct sclp_req request;
-       struct write_sccb *sccb;
+       void *sccb;
+       struct msg_buf *current_msg;
        char *current_line;
        int current_length;
        int retry_count;
@@ -76,8 +73,8 @@ struct sclp_buffer {
        unsigned short columns;
        unsigned short htab;
        /* statistics about this buffer */
-       unsigned int mto_char_sum;      /* # chars in sccb */
-       unsigned int mto_number;        /* # mtos in sccb */
+       unsigned int char_sum;          /* # chars in sccb */
+       unsigned int messages;          /* # messages in sccb */
        /* Callback that is called after reaching final status. */
        void (*callback)(struct sclp_buffer *, int);
 };
index 003663288e29b7f60405fa9bf721dcc6dbe19c0c..3c6e174e19b6faa54a9a828be4c23d707e045df3 100644 (file)
@@ -84,8 +84,8 @@ sclp_tty_close(struct tty_struct *tty, struct file *filp)
  * to change as output buffers get emptied, or if the output flow
  * control is acted. This is not an exact number because not every
  * character needs the same space in the sccb. The worst case is
- * a string of newlines. Every newlines creates a new mto which
- * needs 8 bytes.
+ * a string of newlines. Every newline creates a new message which
+ * needs 82 bytes.
  */
 static int
 sclp_tty_write_room (struct tty_struct *tty)
@@ -97,9 +97,9 @@ sclp_tty_write_room (struct tty_struct *tty)
        spin_lock_irqsave(&sclp_tty_lock, flags);
        count = 0;
        if (sclp_ttybuf != NULL)
-               count = sclp_buffer_space(sclp_ttybuf) / sizeof(struct mto);
+               count = sclp_buffer_space(sclp_ttybuf) / sizeof(struct msg_buf);
        list_for_each(l, &sclp_tty_pages)
-               count += NR_EMPTY_MTO_PER_SCCB;
+               count += NR_EMPTY_MSG_PER_SCCB;
        spin_unlock_irqrestore(&sclp_tty_lock, flags);
        return count;
 }