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