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); */ DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue); +static void __raw3270_disconnect(struct raw3270 *rp); + /* * Encode array for 12 bit 3270 addresses. */ @@ -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); @@ -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) @@ -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) 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 @@ -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. */ @@ -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; @@ -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; @@ -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;