From ba5c2e2ae4806b4e5810153d9d9581593b65773b Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Thu, 8 Dec 2022 20:58:26 +0100 Subject: [PATCH] s390/con3270: add special output handling when oops_in_progress is set Normally a user can scroll back with PF7/PF8 if printed messages are outside of the visible screen area. This doesn't work when the kernel crashes, because the scrollback handling is done by the kernel, which is no longer alive after the kernel crash. Add code to always print all dirty lines in the screen buffer, so the user can scroll back with the terminal scrollback keys (Page Up/Down). Signed-off-by: Sven Schnelle Acked-by: Heiko Carstens Signed-off-by: Heiko Carstens --- drivers/s390/char/con3270.c | 76 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 15 deletions(-) diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index 2d867f6..9402690 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -91,6 +91,7 @@ struct tty3270 { char *converted_line; /* RAW 3270 data stream */ unsigned int line_view_start; /* Start of visible area */ unsigned int line_write_start; /* current write position */ + unsigned int oops_line; /* line counter used when print oops */ /* Current tty screen. */ unsigned int cx, cy; /* Current output position. */ @@ -129,7 +130,8 @@ struct tty3270 { /* tty3270->update_flags. See tty3270_update for details. */ #define TTY_UPDATE_INPUT 0x1 /* Update input line. */ #define TTY_UPDATE_STATUS 0x2 /* Update status line. */ -#define TTY_UPDATE_ALL 0x3 /* Recreate screen. */ +#define TTY_UPDATE_LINES 0x4 /* Update visible screen lines */ +#define TTY_UPDATE_ALL 0x7 /* Recreate screen. */ #define TTY3270_INPUT_AREA_ROWS 2 @@ -274,7 +276,7 @@ static int tty3270_add_status(struct tty3270 *tp) codepage_convert(tp->view.ascebc, cp, len); cp += len; } else { - cp = tty3270_ebcdic_convert(tp, cp, "Running"); + cp = tty3270_ebcdic_convert(tp, cp, oops_in_progress ? "Crashed" : "Running"); } cp = tty3270_add_sf(tp, cp, TF_LOG); cp = tty3270_add_sa(tp, cp, TAT_FGCOLOR, TAC_RESET); @@ -468,6 +470,55 @@ static unsigned int tty3270_convert_line(struct tty3270 *tp, struct tty3270_line return cp - (char *)tp->converted_line; } +static void tty3270_update_lines_visible(struct tty3270 *tp, struct raw3270_request *rq) +{ + struct tty3270_line *line; + int len, i; + + for (i = 0; i < tty3270_tty_rows(tp); i++) { + line = tty3270_get_view_line(tp, i); + if (!line->dirty) + continue; + len = tty3270_convert_line(tp, line, i); + if (raw3270_request_add_data(rq, tp->converted_line, len)) + break; + line->dirty = 0; + } + if (i == tty3270_tty_rows(tp)) { + for (i = 0; i < tp->allocated_lines; i++) + tp->screen[i].dirty = 0; + tp->update_flags &= ~TTY_UPDATE_LINES; + } +} + +static void tty3270_update_lines_all(struct tty3270 *tp, struct raw3270_request *rq) +{ + struct tty3270_line *line; + char buf[4]; + int len, i; + + for (i = 0; i < tp->allocated_lines; i++) { + line = tty3270_get_write_line(tp, i + tp->cy + 1); + if (!line->dirty) + continue; + len = tty3270_convert_line(tp, line, tp->oops_line); + if (raw3270_request_add_data(rq, tp->converted_line, len)) + break; + line->dirty = 0; + if (++tp->oops_line >= tty3270_tty_rows(tp)) + tp->oops_line = 0; + } + + if (i == tp->allocated_lines) { + if (tp->oops_line < tty3270_tty_rows(tp)) { + tty3270_add_ra(tp, buf, 0, tty3270_tty_rows(tp), 0); + if (raw3270_request_add_data(rq, buf, sizeof(buf))) + return; + } + tp->update_flags &= ~TTY_UPDATE_LINES; + } +} + /* * Update 3270 display. */ @@ -475,9 +526,8 @@ static void tty3270_update(struct timer_list *t) { struct tty3270 *tp = from_timer(tp, t, timer); struct raw3270_request *wrq; - struct tty3270_line *line; u8 cmd = TC_WRITE; - int i, rc, len; + int rc, len; wrq = xchg(&tp->write, 0); if (!wrq) { @@ -511,19 +561,13 @@ static void tty3270_update(struct timer_list *t) tp->update_flags &= ~TTY_UPDATE_INPUT; } - for (i = 0; i < tty3270_tty_rows(tp); i++) { - line = tty3270_get_view_line(tp, i); - if (!line->dirty) - continue; - len = tty3270_convert_line(tp, line, i); - if (raw3270_request_add_data(wrq, tp->converted_line, len)) - break; - line->dirty = 0; + if (tp->update_flags & TTY_UPDATE_LINES) { + if (oops_in_progress) + tty3270_update_lines_all(tp, wrq); + else + tty3270_update_lines_visible(tp, wrq); } - if (i < tty3270_tty_rows(tp) - 1) - tty3270_set_timer(tp, 1); - wrq->callback = tty3270_write_callback; rc = raw3270_start(&tp->view, wrq); if (rc == 0) { @@ -1750,6 +1794,7 @@ static void tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty, } } /* Setup timer to update display after 1/10 second */ + tp->update_flags |= TTY_UPDATE_LINES; if (!timer_pending(&tp->timer)) tty3270_set_timer(tp, msecs_to_jiffies(100)); @@ -2068,6 +2113,7 @@ static int con3270_notify(struct notifier_block *self, return NOTIFY_DONE; con3270_wait_write(tp); tp->nr_up = 0; + tp->update_flags = TTY_UPDATE_ALL; while (tp->update_flags != 0) { spin_unlock_irqrestore(&tp->view.lock, flags); tty3270_update(&tp->timer); -- 2.7.4