aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2013-01-04 08:55:13 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2013-02-14 09:55:03 -0500
commit4d334fd155b53adfe78393e66850ff4bb0aa8406 (patch)
tree72ac8f4d428545eb402c73e5b002b2a70e2cef69 /drivers
parentc95571e68086d36e8e3369597b03ec29c63abec9 (diff)
s390/3270: asynchronous size sensing
Convert the synchronous size sense code to an interrupt driven approach. This allows to set the device online even if the terminal is not connected. With the new code views can be registered without a connected terminal, the tty can be opened as soon as the device is online. After the terminal has been connected and the size has been determined the tty is resized to match the device characteristics.. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/s390/char/raw3270.c535
-rw-r--r--drivers/s390/char/raw3270.h1
-rw-r--r--drivers/s390/char/tty3270.c109
-rw-r--r--drivers/tty/tty_io.c1
4 files changed, 332 insertions, 314 deletions
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 72f69fda9d01..4c9030a5b9f2 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -37,6 +37,7 @@ struct raw3270 {
37 int minor; 37 int minor;
38 38
39 short model, rows, cols; 39 short model, rows, cols;
40 unsigned int state;
40 unsigned long flags; 41 unsigned long flags;
41 42
42 struct list_head req_queue; /* Request queue. */ 43 struct list_head req_queue; /* Request queue. */
@@ -47,17 +48,25 @@ struct raw3270 {
47 48
48 unsigned char *ascebc; /* ascii -> ebcdic table */ 49 unsigned char *ascebc; /* ascii -> ebcdic table */
49 50
50 struct raw3270_request init_request; 51 struct raw3270_view init_view;
52 struct raw3270_request init_reset;
53 struct raw3270_request init_readpart;
54 struct raw3270_request init_readmod;
51 unsigned char init_data[256]; 55 unsigned char init_data[256];
52}; 56};
53 57
58/* raw3270->state */
59#define RAW3270_STATE_INIT 0 /* Initial state */
60#define RAW3270_STATE_RESET 1 /* Reset command is pending */
61#define RAW3270_STATE_W4ATTN 2 /* Wait for attention interrupt */
62#define RAW3270_STATE_READMOD 3 /* Read partition is pending */
63#define RAW3270_STATE_READY 4 /* Device is usable by views */
64
54/* raw3270->flags */ 65/* raw3270->flags */
55#define RAW3270_FLAGS_14BITADDR 0 /* 14-bit buffer addresses */ 66#define RAW3270_FLAGS_14BITADDR 0 /* 14-bit buffer addresses */
56#define RAW3270_FLAGS_BUSY 1 /* Device busy, leave it alone */ 67#define RAW3270_FLAGS_BUSY 1 /* Device busy, leave it alone */
57#define RAW3270_FLAGS_ATTN 2 /* Device sent an ATTN interrupt */ 68#define RAW3270_FLAGS_CONSOLE 2 /* Device is the console. */
58#define RAW3270_FLAGS_READY 4 /* Device is useable by views */ 69#define RAW3270_FLAGS_FROZEN 3 /* set if 3270 is frozen for suspend */
59#define RAW3270_FLAGS_CONSOLE 8 /* Device is the console. */
60#define RAW3270_FLAGS_FROZEN 16 /* set if 3270 is frozen for suspend */
61 70
62/* Semaphore to protect global data of raw3270 (devices, views, etc). */ 71/* Semaphore to protect global data of raw3270 (devices, views, etc). */
63static DEFINE_MUTEX(raw3270_mutex); 72static DEFINE_MUTEX(raw3270_mutex);
@@ -95,6 +104,17 @@ static unsigned char raw3270_ebcgraf[64] = {
95 0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f 104 0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
96}; 105};
97 106
107static inline int raw3270_state_ready(struct raw3270 *rp)
108{
109 return rp->state == RAW3270_STATE_READY;
110}
111
112static inline int raw3270_state_final(struct raw3270 *rp)
113{
114 return rp->state == RAW3270_STATE_INIT ||
115 rp->state == RAW3270_STATE_READY;
116}
117
98void 118void
99raw3270_buffer_address(struct raw3270 *rp, char *cp, unsigned short addr) 119raw3270_buffer_address(struct raw3270 *rp, char *cp, unsigned short addr)
100{ 120{
@@ -212,7 +232,7 @@ raw3270_request_set_idal(struct raw3270_request *rq, struct idal_buffer *ib)
212 * Stop running ccw. 232 * Stop running ccw.
213 */ 233 */
214static int 234static int
215raw3270_halt_io_nolock(struct raw3270 *rp, struct raw3270_request *rq) 235__raw3270_halt_io(struct raw3270 *rp, struct raw3270_request *rq)
216{ 236{
217 int retries; 237 int retries;
218 int rc; 238 int rc;
@@ -231,18 +251,6 @@ raw3270_halt_io_nolock(struct raw3270 *rp, struct raw3270_request *rq)
231 return rc; 251 return rc;
232} 252}
233 253
234static int
235raw3270_halt_io(struct raw3270 *rp, struct raw3270_request *rq)
236{
237 unsigned long flags;
238 int rc;
239
240 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
241 rc = raw3270_halt_io_nolock(rp, rq);
242 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
243 return rc;
244}
245
246/* 254/*
247 * Add the request to the request queue, try to start it if the 255 * Add the request to the request queue, try to start it if the
248 * 3270 device is idle. Return without waiting for end of i/o. 256 * 3270 device is idle. Return without waiting for end of i/o.
@@ -279,8 +287,8 @@ raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
279 if (!rp || rp->view != view || 287 if (!rp || rp->view != view ||
280 test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) 288 test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
281 rc = -EACCES; 289 rc = -EACCES;
282 else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) 290 else if (!raw3270_state_ready(rp))
283 rc = -ENODEV; 291 rc = -EBUSY;
284 else 292 else
285 rc = __raw3270_start(rp, view, rq); 293 rc = __raw3270_start(rp, view, rq);
286 spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags); 294 spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
@@ -297,8 +305,8 @@ raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq)
297 if (!rp || rp->view != view || 305 if (!rp || rp->view != view ||
298 test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) 306 test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
299 rc = -EACCES; 307 rc = -EACCES;
300 else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) 308 else if (!raw3270_state_ready(rp))
301 rc = -ENODEV; 309 rc = -EBUSY;
302 else 310 else
303 rc = __raw3270_start(rp, view, rq); 311 rc = __raw3270_start(rp, view, rq);
304 return rc; 312 return rc;
@@ -376,7 +384,7 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
376 case RAW3270_IO_STOP: 384 case RAW3270_IO_STOP:
377 if (!rq) 385 if (!rq)
378 break; 386 break;
379 raw3270_halt_io_nolock(rp, rq); 387 __raw3270_halt_io(rp, rq);
380 rq->rc = -EIO; 388 rq->rc = -EIO;
381 break; 389 break;
382 default: 390 default:
@@ -411,9 +419,14 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
411} 419}
412 420
413/* 421/*
414 * Size sensing. 422 * To determine the size of the 3270 device we need to do:
423 * 1) send a 'read partition' data stream to the device
424 * 2) wait for the attn interrupt that precedes the query reply
425 * 3) do a read modified to get the query reply
426 * To make things worse we have to cope with intervention
427 * required (3270 device switched to 'stand-by') and command
428 * rejects (old devices that can't do 'read partition').
415 */ 429 */
416
417struct raw3270_ua { /* Query Reply structure for Usable Area */ 430struct raw3270_ua { /* Query Reply structure for Usable Area */
418 struct { /* Usable Area Query Reply Base */ 431 struct { /* Usable Area Query Reply Base */
419 short l; /* Length of this structured field */ 432 short l; /* Length of this structured field */
@@ -449,117 +462,21 @@ struct raw3270_ua { /* Query Reply structure for Usable Area */
449 } __attribute__ ((packed)) aua; 462 } __attribute__ ((packed)) aua;
450} __attribute__ ((packed)); 463} __attribute__ ((packed));
451 464
452static struct diag210 raw3270_init_diag210;
453static DEFINE_MUTEX(raw3270_init_mutex);
454
455static int
456raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
457 struct irb *irb)
458{
459 /*
460 * Unit-Check Processing:
461 * Expect Command Reject or Intervention Required.
462 */
463 if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
464 /* Request finished abnormally. */
465 if (irb->ecw[0] & SNS0_INTERVENTION_REQ) {
466 set_bit(RAW3270_FLAGS_BUSY, &view->dev->flags);
467 return RAW3270_IO_BUSY;
468 }
469 }
470 if (rq) {
471 if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
472 if (irb->ecw[0] & SNS0_CMD_REJECT)
473 rq->rc = -EOPNOTSUPP;
474 else
475 rq->rc = -EIO;
476 } else
477 /* Request finished normally. Copy residual count. */
478 rq->rescnt = irb->scsw.cmd.count;
479 }
480 if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
481 set_bit(RAW3270_FLAGS_ATTN, &view->dev->flags);
482 wake_up(&raw3270_wait_queue);
483 }
484 return RAW3270_IO_DONE;
485}
486
487static struct raw3270_fn raw3270_init_fn = {
488 .intv = raw3270_init_irq
489};
490
491static struct raw3270_view raw3270_init_view = {
492 .fn = &raw3270_init_fn
493};
494
495/*
496 * raw3270_wait/raw3270_wait_interruptible/__raw3270_wakeup
497 * Wait for end of request. The request must have been started
498 * with raw3270_start, rc = 0. The device lock may NOT have been
499 * released between calling raw3270_start and raw3270_wait.
500 */
501static void 465static void
502raw3270_wake_init(struct raw3270_request *rq, void *data) 466raw3270_size_device_vm(struct raw3270 *rp)
503{
504 wake_up((wait_queue_head_t *) data);
505}
506
507/*
508 * Special wait function that can cope with console initialization.
509 */
510static int
511raw3270_start_init(struct raw3270 *rp, struct raw3270_view *view,
512 struct raw3270_request *rq)
513{
514 unsigned long flags;
515 int rc;
516
517#ifdef CONFIG_TN3270_CONSOLE
518 if (raw3270_registered == 0) {
519 spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
520 rq->callback = NULL;
521 rc = __raw3270_start(rp, view, rq);
522 if (rc == 0)
523 while (!raw3270_request_final(rq)) {
524 wait_cons_dev();
525 barrier();
526 }
527 spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
528 return rq->rc;
529 }
530#endif
531 rq->callback = raw3270_wake_init;
532 rq->callback_data = &raw3270_wait_queue;
533 spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
534 rc = __raw3270_start(rp, view, rq);
535 spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
536 if (rc)
537 return rc;
538 /* Now wait for the completion. */
539 rc = wait_event_interruptible(raw3270_wait_queue,
540 raw3270_request_final(rq));
541 if (rc == -ERESTARTSYS) { /* Interrupted by a signal. */
542 raw3270_halt_io(view->dev, rq);
543 /* No wait for the halt to complete. */
544 wait_event(raw3270_wait_queue, raw3270_request_final(rq));
545 return -ERESTARTSYS;
546 }
547 return rq->rc;
548}
549
550static int
551__raw3270_size_device_vm(struct raw3270 *rp)
552{ 467{
553 int rc, model; 468 int rc, model;
554 struct ccw_dev_id dev_id; 469 struct ccw_dev_id dev_id;
470 struct diag210 diag_data;
555 471
556 ccw_device_get_id(rp->cdev, &dev_id); 472 ccw_device_get_id(rp->cdev, &dev_id);
557 raw3270_init_diag210.vrdcdvno = dev_id.devno; 473 diag_data.vrdcdvno = dev_id.devno;
558 raw3270_init_diag210.vrdclen = sizeof(struct diag210); 474 diag_data.vrdclen = sizeof(struct diag210);
559 rc = diag210(&raw3270_init_diag210); 475 rc = diag210(&diag_data);
560 if (rc) 476 model = diag_data.vrdccrmd;
561 return rc; 477 /* Use default model 2 if the size could not be detected */
562 model = raw3270_init_diag210.vrdccrmd; 478 if (rc || model < 2 || model > 5)
479 model = 2;
563 switch (model) { 480 switch (model) {
564 case 2: 481 case 2:
565 rp->model = model; 482 rp->model = model;
@@ -581,77 +498,25 @@ __raw3270_size_device_vm(struct raw3270 *rp)
581 rp->rows = 27; 498 rp->rows = 27;
582 rp->cols = 132; 499 rp->cols = 132;
583 break; 500 break;
584 default:
585 rc = -EOPNOTSUPP;
586 break;
587 } 501 }
588 return rc;
589} 502}
590 503
591static int 504static void
592__raw3270_size_device(struct raw3270 *rp) 505raw3270_size_device(struct raw3270 *rp)
593{ 506{
594 static const unsigned char wbuf[] =
595 { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
596 struct raw3270_ua *uap; 507 struct raw3270_ua *uap;
597 int rc;
598 508
599 /*
600 * To determine the size of the 3270 device we need to do:
601 * 1) send a 'read partition' data stream to the device
602 * 2) wait for the attn interrupt that precedes the query reply
603 * 3) do a read modified to get the query reply
604 * To make things worse we have to cope with intervention
605 * required (3270 device switched to 'stand-by') and command
606 * rejects (old devices that can't do 'read partition').
607 */
608 memset(&rp->init_request, 0, sizeof(rp->init_request));
609 memset(&rp->init_data, 0, 256);
610 /* Store 'read partition' data stream to init_data */
611 memcpy(&rp->init_data, wbuf, sizeof(wbuf));
612 INIT_LIST_HEAD(&rp->init_request.list);
613 rp->init_request.ccw.cmd_code = TC_WRITESF;
614 rp->init_request.ccw.flags = CCW_FLAG_SLI;
615 rp->init_request.ccw.count = sizeof(wbuf);
616 rp->init_request.ccw.cda = (__u32) __pa(&rp->init_data);
617
618 rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
619 if (rc)
620 /* Check error cases: -ERESTARTSYS, -EIO and -EOPNOTSUPP */
621 return rc;
622
623 /* Wait for attention interrupt. */
624#ifdef CONFIG_TN3270_CONSOLE
625 if (raw3270_registered == 0) {
626 unsigned long flags;
627
628 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
629 while (!test_and_clear_bit(RAW3270_FLAGS_ATTN, &rp->flags))
630 wait_cons_dev();
631 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
632 } else
633#endif
634 rc = wait_event_interruptible(raw3270_wait_queue,
635 test_and_clear_bit(RAW3270_FLAGS_ATTN, &rp->flags));
636 if (rc)
637 return rc;
638
639 /*
640 * The device accepted the 'read partition' command. Now
641 * set up a read ccw and issue it.
642 */
643 rp->init_request.ccw.cmd_code = TC_READMOD;
644 rp->init_request.ccw.flags = CCW_FLAG_SLI;
645 rp->init_request.ccw.count = sizeof(rp->init_data);
646 rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
647 rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
648 if (rc)
649 return rc;
650 /* Got a Query Reply */ 509 /* Got a Query Reply */
651 uap = (struct raw3270_ua *) (rp->init_data + 1); 510 uap = (struct raw3270_ua *) (rp->init_data + 1);
652 /* Paranoia check. */ 511 /* Paranoia check. */
653 if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81) 512 if (rp->init_readmod.rc || rp->init_data[0] != 0x88 ||
654 return -EOPNOTSUPP; 513 uap->uab.qcode != 0x81) {
514 /* Couldn't detect size. Use default model 2. */
515 rp->model = 2;
516 rp->rows = 24;
517 rp->cols = 80;
518 return;
519 }
655 /* Copy rows/columns of default Usable Area */ 520 /* Copy rows/columns of default Usable Area */
656 rp->rows = uap->uab.h; 521 rp->rows = uap->uab.h;
657 rp->cols = uap->uab.w; 522 rp->cols = uap->uab.w;
@@ -664,66 +529,131 @@ __raw3270_size_device(struct raw3270 *rp)
664 rp->rows = uap->aua.hauai; 529 rp->rows = uap->aua.hauai;
665 rp->cols = uap->aua.wauai; 530 rp->cols = uap->aua.wauai;
666 } 531 }
667 return 0; 532 /* Try to find a model. */
533 rp->model = 0;
534 if (rp->rows == 24 && rp->cols == 80)
535 rp->model = 2;
536 if (rp->rows == 32 && rp->cols == 80)
537 rp->model = 3;
538 if (rp->rows == 43 && rp->cols == 80)
539 rp->model = 4;
540 if (rp->rows == 27 && rp->cols == 132)
541 rp->model = 5;
668} 542}
669 543
670static int 544static void
671raw3270_size_device(struct raw3270 *rp) 545raw3270_size_device_done(struct raw3270 *rp)
672{ 546{
673 int rc; 547 struct raw3270_view *view;
674 548
675 mutex_lock(&raw3270_init_mutex);
676 rp->view = &raw3270_init_view;
677 raw3270_init_view.dev = rp;
678 if (MACHINE_IS_VM)
679 rc = __raw3270_size_device_vm(rp);
680 else
681 rc = __raw3270_size_device(rp);
682 raw3270_init_view.dev = NULL;
683 rp->view = NULL; 549 rp->view = NULL;
684 mutex_unlock(&raw3270_init_mutex); 550 rp->state = RAW3270_STATE_READY;
685 if (rc == 0) { /* Found something. */ 551 /* Notify views about new size */
686 /* Try to find a model. */ 552 list_for_each_entry(view, &rp->view_list, list)
687 rp->model = 0; 553 if (view->fn->resize)
688 if (rp->rows == 24 && rp->cols == 80) 554 view->fn->resize(view, rp->model, rp->rows, rp->cols);
689 rp->model = 2; 555 /* Setup processing done, now activate a view */
690 if (rp->rows == 32 && rp->cols == 80) 556 list_for_each_entry(view, &rp->view_list, list) {
691 rp->model = 3; 557 rp->view = view;
692 if (rp->rows == 43 && rp->cols == 80) 558 if (view->fn->activate(view) == 0)
693 rp->model = 4; 559 break;
694 if (rp->rows == 27 && rp->cols == 132) 560 rp->view = NULL;
695 rp->model = 5;
696 } else {
697 /* Couldn't detect size. Use default model 2. */
698 rp->model = 2;
699 rp->rows = 24;
700 rp->cols = 80;
701 return 0;
702 } 561 }
703 return rc; 562}
563
564static void
565raw3270_read_modified_cb(struct raw3270_request *rq, void *data)
566{
567 struct raw3270 *rp = rq->view->dev;
568
569 raw3270_size_device(rp);
570 raw3270_size_device_done(rp);
571}
572
573static void
574raw3270_read_modified(struct raw3270 *rp)
575{
576 if (rp->state != RAW3270_STATE_W4ATTN)
577 return;
578 /* Use 'read modified' to get the result of a read partition. */
579 memset(&rp->init_readmod, 0, sizeof(rp->init_readmod));
580 memset(&rp->init_data, 0, sizeof(rp->init_data));
581 rp->init_readmod.ccw.cmd_code = TC_READMOD;
582 rp->init_readmod.ccw.flags = CCW_FLAG_SLI;
583 rp->init_readmod.ccw.count = sizeof(rp->init_data);
584 rp->init_readmod.ccw.cda = (__u32) __pa(rp->init_data);
585 rp->init_readmod.callback = raw3270_read_modified_cb;
586 rp->state = RAW3270_STATE_READMOD;
587 raw3270_start_irq(&rp->init_view, &rp->init_readmod);
588}
589
590static void
591raw3270_writesf_readpart(struct raw3270 *rp)
592{
593 static const unsigned char wbuf[] =
594 { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
595
596 /* Store 'read partition' data stream to init_data */
597 memset(&rp->init_readpart, 0, sizeof(rp->init_readpart));
598 memset(&rp->init_data, 0, sizeof(rp->init_data));
599 memcpy(&rp->init_data, wbuf, sizeof(wbuf));
600 rp->init_readpart.ccw.cmd_code = TC_WRITESF;
601 rp->init_readpart.ccw.flags = CCW_FLAG_SLI;
602 rp->init_readpart.ccw.count = sizeof(wbuf);
603 rp->init_readpart.ccw.cda = (__u32) __pa(&rp->init_data);
604 rp->state = RAW3270_STATE_W4ATTN;
605 raw3270_start_irq(&rp->init_view, &rp->init_readpart);
606}
607
608/*
609 * Device reset
610 */
611static void
612raw3270_reset_device_cb(struct raw3270_request *rq, void *data)
613{
614 struct raw3270 *rp = rq->view->dev;
615
616 if (rp->state != RAW3270_STATE_RESET)
617 return;
618 if (rq && rq->rc) {
619 /* Reset command failed. */
620 rp->state = RAW3270_STATE_INIT;
621 } else if (0 && MACHINE_IS_VM) {
622 raw3270_size_device_vm(rp);
623 raw3270_size_device_done(rp);
624 } else
625 raw3270_writesf_readpart(rp);
704} 626}
705 627
706static int 628static int
707raw3270_reset_device(struct raw3270 *rp) 629__raw3270_reset_device(struct raw3270 *rp)
708{ 630{
709 int rc; 631 int rc;
710 632
711 mutex_lock(&raw3270_init_mutex); 633 /* Store reset data stream to init_data/init_reset */
712 memset(&rp->init_request, 0, sizeof(rp->init_request)); 634 memset(&rp->init_reset, 0, sizeof(rp->init_reset));
713 memset(&rp->init_data, 0, sizeof(rp->init_data)); 635 memset(&rp->init_data, 0, sizeof(rp->init_data));
714 /* Store reset data stream to init_data/init_request */
715 rp->init_data[0] = TW_KR; 636 rp->init_data[0] = TW_KR;
716 INIT_LIST_HEAD(&rp->init_request.list); 637 rp->init_reset.ccw.cmd_code = TC_EWRITEA;
717 rp->init_request.ccw.cmd_code = TC_EWRITEA; 638 rp->init_reset.ccw.flags = CCW_FLAG_SLI;
718 rp->init_request.ccw.flags = CCW_FLAG_SLI; 639 rp->init_reset.ccw.count = 1;
719 rp->init_request.ccw.count = 1; 640 rp->init_reset.ccw.cda = (__u32) __pa(rp->init_data);
720 rp->init_request.ccw.cda = (__u32) __pa(rp->init_data); 641 rp->init_reset.callback = raw3270_reset_device_cb;
721 rp->view = &raw3270_init_view; 642 rc = __raw3270_start(rp, &rp->init_view, &rp->init_reset);
722 raw3270_init_view.dev = rp; 643 if (rc == 0 && rp->state == RAW3270_STATE_INIT)
723 rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request); 644 rp->state = RAW3270_STATE_RESET;
724 raw3270_init_view.dev = NULL; 645 return rc;
725 rp->view = NULL; 646}
726 mutex_unlock(&raw3270_init_mutex); 647
648static int
649raw3270_reset_device(struct raw3270 *rp)
650{
651 unsigned long flags;
652 int rc;
653
654 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
655 rc = __raw3270_reset_device(rp);
656 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
727 return rc; 657 return rc;
728} 658}
729 659
@@ -737,13 +667,50 @@ raw3270_reset(struct raw3270_view *view)
737 if (!rp || rp->view != view || 667 if (!rp || rp->view != view ||
738 test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) 668 test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
739 rc = -EACCES; 669 rc = -EACCES;
740 else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) 670 else if (!raw3270_state_ready(rp))
741 rc = -ENODEV; 671 rc = -EBUSY;
742 else 672 else
743 rc = raw3270_reset_device(view->dev); 673 rc = raw3270_reset_device(view->dev);
744 return rc; 674 return rc;
745} 675}
746 676
677static int
678raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
679 struct irb *irb)
680{
681 struct raw3270 *rp;
682
683 /*
684 * Unit-Check Processing:
685 * Expect Command Reject or Intervention Required.
686 */
687 if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
688 /* Request finished abnormally. */
689 if (irb->ecw[0] & SNS0_INTERVENTION_REQ) {
690 set_bit(RAW3270_FLAGS_BUSY, &view->dev->flags);
691 return RAW3270_IO_BUSY;
692 }
693 }
694 if (rq) {
695 if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
696 if (irb->ecw[0] & SNS0_CMD_REJECT)
697 rq->rc = -EOPNOTSUPP;
698 else
699 rq->rc = -EIO;
700 }
701 }
702 if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
703 /* Queue read modified after attention interrupt */
704 rp = view->dev;
705 raw3270_read_modified(rp);
706 }
707 return RAW3270_IO_DONE;
708}
709
710static struct raw3270_fn raw3270_init_fn = {
711 .intv = raw3270_init_irq
712};
713
747/* 714/*
748 * Setup new 3270 device. 715 * Setup new 3270 device.
749 */ 716 */
@@ -772,6 +739,10 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
772 INIT_LIST_HEAD(&rp->req_queue); 739 INIT_LIST_HEAD(&rp->req_queue);
773 INIT_LIST_HEAD(&rp->view_list); 740 INIT_LIST_HEAD(&rp->view_list);
774 741
742 rp->init_view.dev = rp;
743 rp->init_view.fn = &raw3270_init_fn;
744 rp->view = &rp->init_view;
745
775 /* 746 /*
776 * Add device to list and find the smallest unused minor 747 * Add device to list and find the smallest unused minor
777 * number for it. Note: there is no device with minor 0, 748 * number for it. Note: there is no device with minor 0,
@@ -810,6 +781,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
810 */ 781 */
811struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev) 782struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
812{ 783{
784 unsigned long flags;
813 struct raw3270 *rp; 785 struct raw3270 *rp;
814 char *ascebc; 786 char *ascebc;
815 int rc; 787 int rc;
@@ -820,16 +792,15 @@ struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
820 if (rc) 792 if (rc)
821 return ERR_PTR(rc); 793 return ERR_PTR(rc);
822 set_bit(RAW3270_FLAGS_CONSOLE, &rp->flags); 794 set_bit(RAW3270_FLAGS_CONSOLE, &rp->flags);
823 rc = raw3270_reset_device(rp); 795 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
824 if (rc) 796 do {
825 return ERR_PTR(rc); 797 __raw3270_reset_device(rp);
826 rc = raw3270_size_device(rp); 798 while (!raw3270_state_final(rp)) {
827 if (rc) 799 wait_cons_dev();
828 return ERR_PTR(rc); 800 barrier();
829 rc = raw3270_reset_device(rp); 801 }
830 if (rc) 802 } while (rp->state != RAW3270_STATE_READY);
831 return ERR_PTR(rc); 803 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
832 set_bit(RAW3270_FLAGS_READY, &rp->flags);
833 return rp; 804 return rp;
834} 805}
835 806
@@ -891,13 +862,13 @@ raw3270_activate_view(struct raw3270_view *view)
891 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); 862 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
892 if (rp->view == view) 863 if (rp->view == view)
893 rc = 0; 864 rc = 0;
894 else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) 865 else if (!raw3270_state_ready(rp))
895 rc = -ENODEV; 866 rc = -EBUSY;
896 else if (test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) 867 else if (test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
897 rc = -EACCES; 868 rc = -EACCES;
898 else { 869 else {
899 oldview = NULL; 870 oldview = NULL;
900 if (rp->view) { 871 if (rp->view && rp->view->fn->deactivate) {
901 oldview = rp->view; 872 oldview = rp->view;
902 oldview->fn->deactivate(oldview); 873 oldview->fn->deactivate(oldview);
903 } 874 }
@@ -942,7 +913,7 @@ raw3270_deactivate_view(struct raw3270_view *view)
942 list_del_init(&view->list); 913 list_del_init(&view->list);
943 list_add_tail(&view->list, &rp->view_list); 914 list_add_tail(&view->list, &rp->view_list);
944 /* Try to activate another view. */ 915 /* Try to activate another view. */
945 if (test_bit(RAW3270_FLAGS_READY, &rp->flags) && 916 if (raw3270_state_ready(rp) &&
946 !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) { 917 !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
947 list_for_each_entry(view, &rp->view_list, list) { 918 list_for_each_entry(view, &rp->view_list, list) {
948 rp->view = view; 919 rp->view = view;
@@ -973,18 +944,16 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor)
973 if (rp->minor != minor) 944 if (rp->minor != minor)
974 continue; 945 continue;
975 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); 946 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
976 if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) { 947 atomic_set(&view->ref_count, 2);
977 atomic_set(&view->ref_count, 2); 948 view->dev = rp;
978 view->dev = rp; 949 view->fn = fn;
979 view->fn = fn; 950 view->model = rp->model;
980 view->model = rp->model; 951 view->rows = rp->rows;
981 view->rows = rp->rows; 952 view->cols = rp->cols;
982 view->cols = rp->cols; 953 view->ascebc = rp->ascebc;
983 view->ascebc = rp->ascebc; 954 spin_lock_init(&view->lock);
984 spin_lock_init(&view->lock); 955 list_add(&view->list, &rp->view_list);
985 list_add(&view->list, &rp->view_list); 956 rc = 0;
986 rc = 0;
987 }
988 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); 957 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
989 break; 958 break;
990 } 959 }
@@ -1008,14 +977,11 @@ raw3270_find_view(struct raw3270_fn *fn, int minor)
1008 if (rp->minor != minor) 977 if (rp->minor != minor)
1009 continue; 978 continue;
1010 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); 979 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
1011 if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) { 980 list_for_each_entry(tmp, &rp->view_list, list) {
1012 view = ERR_PTR(-ENOENT); 981 if (tmp->fn == fn) {
1013 list_for_each_entry(tmp, &rp->view_list, list) { 982 raw3270_get_view(tmp);
1014 if (tmp->fn == fn) { 983 view = tmp;
1015 raw3270_get_view(tmp); 984 break;
1016 view = tmp;
1017 break;
1018 }
1019 } 985 }
1020 } 986 }
1021 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); 987 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
@@ -1042,7 +1008,7 @@ raw3270_del_view(struct raw3270_view *view)
1042 rp->view = NULL; 1008 rp->view = NULL;
1043 } 1009 }
1044 list_del_init(&view->list); 1010 list_del_init(&view->list);
1045 if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags) && 1011 if (!rp->view && raw3270_state_ready(rp) &&
1046 !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) { 1012 !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
1047 /* Try to activate another view. */ 1013 /* Try to activate another view. */
1048 list_for_each_entry(nv, &rp->view_list, list) { 1014 list_for_each_entry(nv, &rp->view_list, list) {
@@ -1177,19 +1143,10 @@ raw3270_set_online (struct ccw_device *cdev)
1177 rp = raw3270_create_device(cdev); 1143 rp = raw3270_create_device(cdev);
1178 if (IS_ERR(rp)) 1144 if (IS_ERR(rp))
1179 return PTR_ERR(rp); 1145 return PTR_ERR(rp);
1180 rc = raw3270_reset_device(rp);
1181 if (rc)
1182 goto failure;
1183 rc = raw3270_size_device(rp);
1184 if (rc)
1185 goto failure;
1186 rc = raw3270_reset_device(rp);
1187 if (rc)
1188 goto failure;
1189 rc = raw3270_create_attributes(rp); 1146 rc = raw3270_create_attributes(rp);
1190 if (rc) 1147 if (rc)
1191 goto failure; 1148 goto failure;
1192 set_bit(RAW3270_FLAGS_READY, &rp->flags); 1149 raw3270_reset_device(rp);
1193 mutex_lock(&raw3270_mutex); 1150 mutex_lock(&raw3270_mutex);
1194 list_for_each_entry(np, &raw3270_notifier, list) 1151 list_for_each_entry(np, &raw3270_notifier, list)
1195 np->create(rp->minor); 1152 np->create(rp->minor);
@@ -1221,14 +1178,14 @@ raw3270_remove (struct ccw_device *cdev)
1221 */ 1178 */
1222 if (rp == NULL) 1179 if (rp == NULL)
1223 return; 1180 return;
1224 clear_bit(RAW3270_FLAGS_READY, &rp->flags);
1225 1181
1226 sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group); 1182 sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group);
1227 1183
1228 /* Deactivate current view and remove all views. */ 1184 /* Deactivate current view and remove all views. */
1229 spin_lock_irqsave(get_ccwdev_lock(cdev), flags); 1185 spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
1230 if (rp->view) { 1186 if (rp->view) {
1231 rp->view->fn->deactivate(rp->view); 1187 if (rp->view->fn->deactivate)
1188 rp->view->fn->deactivate(rp->view);
1232 rp->view = NULL; 1189 rp->view = NULL;
1233 } 1190 }
1234 while (!list_empty(&rp->view_list)) { 1191 while (!list_empty(&rp->view_list)) {
@@ -1277,7 +1234,7 @@ static int raw3270_pm_stop(struct ccw_device *cdev)
1277 if (!rp) 1234 if (!rp)
1278 return 0; 1235 return 0;
1279 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); 1236 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
1280 if (rp->view) 1237 if (rp->view && rp->view->fn->deactivate)
1281 rp->view->fn->deactivate(rp->view); 1238 rp->view->fn->deactivate(rp->view);
1282 if (!test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) { 1239 if (!test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) {
1283 /* 1240 /*
@@ -1304,7 +1261,7 @@ static int raw3270_pm_start(struct ccw_device *cdev)
1304 return 0; 1261 return 0;
1305 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); 1262 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
1306 clear_bit(RAW3270_FLAGS_FROZEN, &rp->flags); 1263 clear_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
1307 if (rp->view) 1264 if (rp->view && rp->view->fn->activate)
1308 rp->view->fn->activate(rp->view); 1265 rp->view->fn->activate(rp->view);
1309 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); 1266 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
1310 return 0; 1267 return 0;
diff --git a/drivers/s390/char/raw3270.h b/drivers/s390/char/raw3270.h
index a4c79d043cd3..7b73ff8c1bd7 100644
--- a/drivers/s390/char/raw3270.h
+++ b/drivers/s390/char/raw3270.h
@@ -141,6 +141,7 @@ struct raw3270_fn {
141 struct raw3270_request *, struct irb *); 141 struct raw3270_request *, struct irb *);
142 void (*release)(struct raw3270_view *); 142 void (*release)(struct raw3270_view *);
143 void (*free)(struct raw3270_view *); 143 void (*free)(struct raw3270_view *);
144 void (*resize)(struct raw3270_view *, int, int, int);
144}; 145};
145 146
146/* 147/*
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 48767e6bab9d..8f1e02543ada 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -15,6 +15,7 @@
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/console.h> 16#include <linux/console.h>
17#include <linux/interrupt.h> 17#include <linux/interrupt.h>
18#include <linux/workqueue.h>
18 19
19#include <linux/slab.h> 20#include <linux/slab.h>
20#include <linux/bootmem.h> 21#include <linux/bootmem.h>
@@ -80,6 +81,8 @@ struct tty3270 {
80 unsigned int highlight; /* Blink/reverse/underscore */ 81 unsigned int highlight; /* Blink/reverse/underscore */
81 unsigned int f_color; /* Foreground color */ 82 unsigned int f_color; /* Foreground color */
82 struct tty3270_line *screen; 83 struct tty3270_line *screen;
84 unsigned int n_model, n_cols, n_rows; /* New model & size */
85 struct work_struct resize_work;
83 86
84 /* Input stuff. */ 87 /* Input stuff. */
85 struct string *prompt; /* Output string for input area. */ 88 struct string *prompt; /* Output string for input area. */
@@ -115,6 +118,7 @@ struct tty3270 {
115#define TTY_UPDATE_ALL 16 /* Recreate screen. */ 118#define TTY_UPDATE_ALL 16 /* Recreate screen. */
116 119
117static void tty3270_update(struct tty3270 *); 120static void tty3270_update(struct tty3270 *);
121static void tty3270_resize_work(struct work_struct *work);
118 122
119/* 123/*
120 * Setup timeout for a device. On timeout trigger an update. 124 * Setup timeout for a device. On timeout trigger an update.
@@ -711,6 +715,7 @@ tty3270_alloc_view(void)
711 tasklet_init(&tp->readlet, 715 tasklet_init(&tp->readlet,
712 (void (*)(unsigned long)) tty3270_read_tasklet, 716 (void (*)(unsigned long)) tty3270_read_tasklet,
713 (unsigned long) tp->read); 717 (unsigned long) tp->read);
718 INIT_WORK(&tp->resize_work, tty3270_resize_work);
714 719
715 return tp; 720 return tp;
716 721
@@ -754,42 +759,96 @@ tty3270_free_view(struct tty3270 *tp)
754/* 759/*
755 * Allocate tty3270 screen. 760 * Allocate tty3270 screen.
756 */ 761 */
757static int 762static struct tty3270_line *
758tty3270_alloc_screen(struct tty3270 *tp) 763tty3270_alloc_screen(unsigned int rows, unsigned int cols)
759{ 764{
765 struct tty3270_line *screen;
760 unsigned long size; 766 unsigned long size;
761 int lines; 767 int lines;
762 768
763 size = sizeof(struct tty3270_line) * (tp->view.rows - 2); 769 size = sizeof(struct tty3270_line) * (rows - 2);
764 tp->screen = kzalloc(size, GFP_KERNEL); 770 screen = kzalloc(size, GFP_KERNEL);
765 if (!tp->screen) 771 if (!screen)
766 goto out_err; 772 goto out_err;
767 for (lines = 0; lines < tp->view.rows - 2; lines++) { 773 for (lines = 0; lines < rows - 2; lines++) {
768 size = sizeof(struct tty3270_cell) * tp->view.cols; 774 size = sizeof(struct tty3270_cell) * cols;
769 tp->screen[lines].cells = kzalloc(size, GFP_KERNEL); 775 screen[lines].cells = kzalloc(size, GFP_KERNEL);
770 if (!tp->screen[lines].cells) 776 if (!screen[lines].cells)
771 goto out_screen; 777 goto out_screen;
772 } 778 }
773 return 0; 779 return screen;
774out_screen: 780out_screen:
775 while (lines--) 781 while (lines--)
776 kfree(tp->screen[lines].cells); 782 kfree(screen[lines].cells);
777 kfree(tp->screen); 783 kfree(screen);
778out_err: 784out_err:
779 return -ENOMEM; 785 return ERR_PTR(-ENOMEM);
780} 786}
781 787
782/* 788/*
783 * Free tty3270 screen. 789 * Free tty3270 screen.
784 */ 790 */
785static void 791static void
786tty3270_free_screen(struct tty3270 *tp) 792tty3270_free_screen(struct tty3270_line *screen, unsigned int rows)
787{ 793{
788 int lines; 794 int lines;
789 795
790 for (lines = 0; lines < tp->view.rows - 2; lines++) 796 for (lines = 0; lines < rows - 2; lines++)
791 kfree(tp->screen[lines].cells); 797 kfree(screen[lines].cells);
792 kfree(tp->screen); 798 kfree(screen);
799}
800
801/*
802 * Resize tty3270 screen
803 */
804static void tty3270_resize_work(struct work_struct *work)
805{
806 struct tty3270 *tp = container_of(work, struct tty3270, resize_work);
807 struct tty3270_line *screen, *oscreen;
808 struct tty_struct *tty;
809 unsigned int orows;
810 struct winsize ws;
811
812 screen = tty3270_alloc_screen(tp->n_rows, tp->n_cols);
813 if (!screen)
814 return;
815 /* Switch to new output size */
816 spin_lock_bh(&tp->view.lock);
817 oscreen = tp->screen;
818 orows = tp->view.rows;
819 tp->view.model = tp->n_model;
820 tp->view.rows = tp->n_rows;
821 tp->view.cols = tp->n_cols;
822 tp->screen = screen;
823 free_string(&tp->freemem, tp->prompt);
824 free_string(&tp->freemem, tp->status);
825 tty3270_create_prompt(tp);
826 tty3270_create_status(tp);
827 tp->nr_up = 0;
828 while (tp->nr_lines < tp->view.rows - 2)
829 tty3270_blank_line(tp);
830 tp->update_flags = TTY_UPDATE_ALL;
831 spin_unlock_bh(&tp->view.lock);
832 tty3270_free_screen(oscreen, orows);
833 tty3270_set_timer(tp, 1);
834 /* Informat tty layer about new size */
835 tty = tty_port_tty_get(&tp->port);
836 if (!tty)
837 return;
838 ws.ws_row = tp->view.rows - 2;
839 ws.ws_col = tp->view.cols;
840 tty_do_resize(tty, &ws);
841}
842
843static void
844tty3270_resize(struct raw3270_view *view, int model, int rows, int cols)
845{
846 struct tty3270 *tp = container_of(view, struct tty3270, view);
847
848 tp->n_model = model;
849 tp->n_rows = rows;
850 tp->n_cols = cols;
851 schedule_work(&tp->resize_work);
793} 852}
794 853
795/* 854/*
@@ -817,7 +876,8 @@ static void
817tty3270_free(struct raw3270_view *view) 876tty3270_free(struct raw3270_view *view)
818{ 877{
819 struct tty3270 *tp = container_of(view, struct tty3270, view); 878 struct tty3270 *tp = container_of(view, struct tty3270, view);
820 tty3270_free_screen(tp); 879
880 tty3270_free_screen(tp->screen, tp->view.rows);
821 tty3270_free_view(tp); 881 tty3270_free_view(tp);
822} 882}
823 883
@@ -841,7 +901,8 @@ static struct raw3270_fn tty3270_fn = {
841 .deactivate = tty3270_deactivate, 901 .deactivate = tty3270_deactivate,
842 .intv = (void *) tty3270_irq, 902 .intv = (void *) tty3270_irq,
843 .release = tty3270_release, 903 .release = tty3270_release,
844 .free = tty3270_free 904 .free = tty3270_free,
905 .resize = tty3270_resize
845}; 906};
846 907
847/* 908/*
@@ -869,10 +930,6 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
869 if (tty3270_max_index < tty->index) 930 if (tty3270_max_index < tty->index)
870 tty3270_max_index = tty->index; 931 tty3270_max_index = tty->index;
871 932
872 /* Quick exit if there is no device for tty->index. */
873 if (PTR_ERR(view) == -ENODEV)
874 return -ENODEV;
875
876 /* Allocate tty3270 structure on first open. */ 933 /* Allocate tty3270 structure on first open. */
877 tp = tty3270_alloc_view(); 934 tp = tty3270_alloc_view();
878 if (IS_ERR(tp)) 935 if (IS_ERR(tp))
@@ -884,10 +941,12 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
884 return rc; 941 return rc;
885 } 942 }
886 943
887 rc = tty3270_alloc_screen(tp); 944 tp->screen = tty3270_alloc_screen(tp->view.cols, tp->view.rows);
888 if (rc) { 945 if (IS_ERR(tp->screen)) {
946 rc = PTR_ERR(tp->screen);
889 raw3270_put_view(&tp->view); 947 raw3270_put_view(&tp->view);
890 raw3270_del_view(&tp->view); 948 raw3270_del_view(&tp->view);
949 tty3270_free_view(tp);
891 return rc; 950 return rc;
892 } 951 }
893 952
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index da9fde850754..3f00f9e8daf2 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -2203,6 +2203,7 @@ done:
2203 mutex_unlock(&tty->termios_mutex); 2203 mutex_unlock(&tty->termios_mutex);
2204 return 0; 2204 return 0;
2205} 2205}
2206EXPORT_SYMBOL(tty_do_resize);
2206 2207
2207/** 2208/**
2208 * tiocswinsz - implement window size set ioctl 2209 * tiocswinsz - implement window size set ioctl