aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2016-05-02 09:07:00 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2016-05-10 07:24:46 -0400
commit7e36eff1eece29eaa37501806ded0e0fb88e61ee (patch)
tree699b58fdaa61cfbc76d8c8482a4cdc395efe8ffd
parent8340ab60b3624386eaa24fa21bdb4e6775066ccf (diff)
s390/3270: handle reconnect of a tty with a different size
If an existing 3270 terminal disconnects and reconnects with a different size, the 3270 driver still works with the old size. If the new dimensions are larger the output merely looks funny, if the new dimensions are smaller the terminal is unusable. To fix this restart the size detection after a unit check has been received. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--drivers/s390/char/raw3270.c32
-rw-r--r--drivers/s390/char/tty3270.c25
2 files changed, 53 insertions, 4 deletions
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 0743f13101ee..a2da898ce90f 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -90,6 +90,8 @@ module_param(tubxcorrect, bool, 0);
90 */ 90 */
91DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue); 91DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue);
92 92
93static void __raw3270_disconnect(struct raw3270 *rp);
94
93/* 95/*
94 * Encode array for 12 bit 3270 addresses. 96 * Encode array for 12 bit 3270 addresses.
95 */ 97 */
@@ -336,8 +338,11 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
336 set_bit(RAW3270_FLAGS_BUSY, &rp->flags); 338 set_bit(RAW3270_FLAGS_BUSY, &rp->flags);
337 /* Handle disconnected devices */ 339 /* Handle disconnected devices */
338 if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) && 340 if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
339 (irb->ecw[0] & SNS0_INTERVENTION_REQ)) 341 (irb->ecw[0] & SNS0_INTERVENTION_REQ)) {
340 set_bit(RAW3270_FLAGS_BUSY, &rp->flags); 342 set_bit(RAW3270_FLAGS_BUSY, &rp->flags);
343 if (rp->state > RAW3270_STATE_RESET)
344 __raw3270_disconnect(rp);
345 }
341 /* Call interrupt handler of the view */ 346 /* Call interrupt handler of the view */
342 if (view) 347 if (view)
343 view->fn->intv(view, rq, irb); 348 view->fn->intv(view, rq, irb);
@@ -347,8 +352,7 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
347 /* Device busy, do not start I/O */ 352 /* Device busy, do not start I/O */
348 return; 353 return;
349 354
350 if (rq) { 355 if (rq && !list_empty(&rq->list)) {
351 BUG_ON(list_empty(&rq->list));
352 /* The request completed, remove from queue and do callback. */ 356 /* The request completed, remove from queue and do callback. */
353 list_del_init(&rq->list); 357 list_del_init(&rq->list);
354 if (rq->callback) 358 if (rq->callback)
@@ -635,6 +639,28 @@ raw3270_reset(struct raw3270_view *view)
635} 639}
636 640
637static void 641static void
642__raw3270_disconnect(struct raw3270 *rp)
643{
644 struct raw3270_request *rq;
645 struct raw3270_view *view;
646
647 rp->state = RAW3270_STATE_INIT;
648 rp->view = &rp->init_view;
649 /* Cancel all queued requests */
650 while (!list_empty(&rp->req_queue)) {
651 rq = list_entry(rp->req_queue.next,struct raw3270_request,list);
652 view = rq->view;
653 rq->rc = -EACCES;
654 list_del_init(&rq->list);
655 if (rq->callback)
656 rq->callback(rq, rq->callback_data);
657 raw3270_put_view(view);
658 }
659 /* Start from scratch */
660 __raw3270_reset_device(rp);
661}
662
663static void
638raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq, 664raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
639 struct irb *irb) 665 struct irb *irb)
640{ 666{
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index d6da18612ba8..402eff3c1634 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -319,6 +319,27 @@ tty3270_blank_line(struct tty3270 *tp)
319} 319}
320 320
321/* 321/*
322 * Create a blank screen and remove all lines from the history.
323 */
324static void
325tty3270_blank_screen(struct tty3270 *tp)
326{
327 struct string *s, *n;
328 int i;
329
330 for (i = 0; i < tp->view.rows - 2; i++)
331 tp->screen[i].len = 0;
332 tp->nr_up = 0;
333 list_for_each_entry_safe(s, n, &tp->lines, list) {
334 list_del(&s->list);
335 if (!list_empty(&s->update))
336 list_del(&s->update);
337 tp->nr_lines--;
338 free_string(&tp->freemem, s);
339 }
340}
341
342/*
322 * Write request completion callback. 343 * Write request completion callback.
323 */ 344 */
324static void 345static void
@@ -816,6 +837,7 @@ static void tty3270_resize_work(struct work_struct *work)
816 return; 837 return;
817 /* Switch to new output size */ 838 /* Switch to new output size */
818 spin_lock_bh(&tp->view.lock); 839 spin_lock_bh(&tp->view.lock);
840 tty3270_blank_screen(tp);
819 oscreen = tp->screen; 841 oscreen = tp->screen;
820 orows = tp->view.rows; 842 orows = tp->view.rows;
821 tp->view.model = tp->n_model; 843 tp->view.model = tp->n_model;
@@ -826,7 +848,6 @@ static void tty3270_resize_work(struct work_struct *work)
826 free_string(&tp->freemem, tp->status); 848 free_string(&tp->freemem, tp->status);
827 tty3270_create_prompt(tp); 849 tty3270_create_prompt(tp);
828 tty3270_create_status(tp); 850 tty3270_create_status(tp);
829 tp->nr_up = 0;
830 while (tp->nr_lines < tp->view.rows - 2) 851 while (tp->nr_lines < tp->view.rows - 2)
831 tty3270_blank_line(tp); 852 tty3270_blank_line(tp);
832 tp->update_flags = TTY_UPDATE_ALL; 853 tp->update_flags = TTY_UPDATE_ALL;
@@ -848,6 +869,8 @@ tty3270_resize(struct raw3270_view *view, int model, int rows, int cols)
848{ 869{
849 struct tty3270 *tp = container_of(view, struct tty3270, view); 870 struct tty3270 *tp = container_of(view, struct tty3270, view);
850 871
872 if (tp->n_model == model && tp->n_rows == rows && tp->n_cols == cols)
873 return;
851 tp->n_model = model; 874 tp->n_model = model;
852 tp->n_rows = rows; 875 tp->n_rows = rows;
853 tp->n_cols = cols; 876 tp->n_cols = cols;