forked from Minki/linux
s390/sclp: avoid merged message output
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>
This commit is contained in:
parent
83abeffbd5
commit
18d1a7f675
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user