Skip to content

Commit

Permalink
s390/3270: handle reconnect of a tty with a different size
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Martin Schwidefsky committed May 10, 2016
1 parent 8340ab6 commit 7e36eff
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 4 deletions.
32 changes: 29 additions & 3 deletions drivers/s390/char/raw3270.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ module_param(tubxcorrect, bool, 0);
*/
DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue);

static void __raw3270_disconnect(struct raw3270 *rp);

/*
* Encode array for 12 bit 3270 addresses.
*/
Expand Down Expand Up @@ -336,8 +338,11 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
set_bit(RAW3270_FLAGS_BUSY, &rp->flags);
/* Handle disconnected devices */
if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
(irb->ecw[0] & SNS0_INTERVENTION_REQ))
(irb->ecw[0] & SNS0_INTERVENTION_REQ)) {
set_bit(RAW3270_FLAGS_BUSY, &rp->flags);
if (rp->state > RAW3270_STATE_RESET)
__raw3270_disconnect(rp);
}
/* Call interrupt handler of the view */
if (view)
view->fn->intv(view, rq, irb);
Expand All @@ -347,8 +352,7 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
/* Device busy, do not start I/O */
return;

if (rq) {
BUG_ON(list_empty(&rq->list));
if (rq && !list_empty(&rq->list)) {
/* The request completed, remove from queue and do callback. */
list_del_init(&rq->list);
if (rq->callback)
Expand Down Expand Up @@ -634,6 +638,28 @@ raw3270_reset(struct raw3270_view *view)
return rc;
}

static void
__raw3270_disconnect(struct raw3270 *rp)
{
struct raw3270_request *rq;
struct raw3270_view *view;

rp->state = RAW3270_STATE_INIT;
rp->view = &rp->init_view;
/* Cancel all queued requests */
while (!list_empty(&rp->req_queue)) {
rq = list_entry(rp->req_queue.next,struct raw3270_request,list);
view = rq->view;
rq->rc = -EACCES;
list_del_init(&rq->list);
if (rq->callback)
rq->callback(rq, rq->callback_data);
raw3270_put_view(view);
}
/* Start from scratch */
__raw3270_reset_device(rp);
}

static void
raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
struct irb *irb)
Expand Down
25 changes: 24 additions & 1 deletion drivers/s390/char/tty3270.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,27 @@ tty3270_blank_line(struct tty3270 *tp)
tp->nr_up++;
}

/*
* Create a blank screen and remove all lines from the history.
*/
static void
tty3270_blank_screen(struct tty3270 *tp)
{
struct string *s, *n;
int i;

for (i = 0; i < tp->view.rows - 2; i++)
tp->screen[i].len = 0;
tp->nr_up = 0;
list_for_each_entry_safe(s, n, &tp->lines, list) {
list_del(&s->list);
if (!list_empty(&s->update))
list_del(&s->update);
tp->nr_lines--;
free_string(&tp->freemem, s);
}
}

/*
* Write request completion callback.
*/
Expand Down Expand Up @@ -816,6 +837,7 @@ static void tty3270_resize_work(struct work_struct *work)
return;
/* Switch to new output size */
spin_lock_bh(&tp->view.lock);
tty3270_blank_screen(tp);
oscreen = tp->screen;
orows = tp->view.rows;
tp->view.model = tp->n_model;
Expand All @@ -826,7 +848,6 @@ static void tty3270_resize_work(struct work_struct *work)
free_string(&tp->freemem, tp->status);
tty3270_create_prompt(tp);
tty3270_create_status(tp);
tp->nr_up = 0;
while (tp->nr_lines < tp->view.rows - 2)
tty3270_blank_line(tp);
tp->update_flags = TTY_UPDATE_ALL;
Expand All @@ -848,6 +869,8 @@ tty3270_resize(struct raw3270_view *view, int model, int rows, int cols)
{
struct tty3270 *tp = container_of(view, struct tty3270, view);

if (tp->n_model == model && tp->n_rows == rows && tp->n_cols == cols)
return;
tp->n_model = model;
tp->n_rows = rows;
tp->n_cols = cols;
Expand Down

0 comments on commit 7e36eff

Please sign in to comment.