aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2016-05-02 08:53:29 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2016-05-04 10:29:53 -0400
commit8340ab60b3624386eaa24fa21bdb4e6775066ccf (patch)
treed0e7952f4a44d6733e448006f8a8fc442f1c08c5
parent2e63a3a66655d5fe5d85c090b009979870436c00 (diff)
s390/3270: avoid endless I/O loop with disconnected 3270 terminals
If a 3270 terminal is disconnected while the tty view is active the 3270 driver goes into an endless loop of failed I/O requests until the terminal is connected again. Add code to the raw3270 interrupt handler to check for unit checks due to failed I/O requests and put the device to sleep with the RAW3270_FLAGS_BUSY flag until a unsolicited device end interrupt indicates that the device can be used again. while we are at it simplify the 3270 irq handling and remove unnecessary code. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--drivers/s390/char/con3270.c3
-rw-r--r--drivers/s390/char/fs3270.c3
-rw-r--r--drivers/s390/char/raw3270.c101
-rw-r--r--drivers/s390/char/raw3270.h8
-rw-r--r--drivers/s390/char/tty3270.c3
5 files changed, 23 insertions, 95 deletions
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index 4d7a9badfede..6b1577c73fe7 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -400,7 +400,7 @@ con3270_deactivate(struct raw3270_view *view)
400 del_timer(&cp->timer); 400 del_timer(&cp->timer);
401} 401}
402 402
403static int 403static void
404con3270_irq(struct con3270 *cp, struct raw3270_request *rq, struct irb *irb) 404con3270_irq(struct con3270 *cp, struct raw3270_request *rq, struct irb *irb)
405{ 405{
406 /* Handle ATTN. Schedule tasklet to read aid. */ 406 /* Handle ATTN. Schedule tasklet to read aid. */
@@ -418,7 +418,6 @@ con3270_irq(struct con3270 *cp, struct raw3270_request *rq, struct irb *irb)
418 cp->update_flags = CON_UPDATE_ALL; 418 cp->update_flags = CON_UPDATE_ALL;
419 con3270_set_timer(cp, 1); 419 con3270_set_timer(cp, 1);
420 } 420 }
421 return RAW3270_IO_DONE;
422} 421}
423 422
424/* Console view to a 3270 device. */ 423/* Console view to a 3270 device. */
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index 71e974738014..85eca1cef063 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -217,7 +217,7 @@ fs3270_deactivate(struct raw3270_view *view)
217 fp->init->callback(fp->init, NULL); 217 fp->init->callback(fp->init, NULL);
218} 218}
219 219
220static int 220static void
221fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb) 221fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb)
222{ 222{
223 /* Handle ATTN. Set indication and wake waiters for attention. */ 223 /* Handle ATTN. Set indication and wake waiters for attention. */
@@ -233,7 +233,6 @@ fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb)
233 /* Normal end. Copy residual count. */ 233 /* Normal end. Copy residual count. */
234 rq->rescnt = irb->scsw.cmd.count; 234 rq->rescnt = irb->scsw.cmd.count;
235 } 235 }
236 return RAW3270_IO_DONE;
237} 236}
238 237
239/* 238/*
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 220acb4cbee5..0743f13101ee 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -229,29 +229,6 @@ raw3270_request_set_idal(struct raw3270_request *rq, struct idal_buffer *ib)
229} 229}
230 230
231/* 231/*
232 * Stop running ccw.
233 */
234static int
235__raw3270_halt_io(struct raw3270 *rp, struct raw3270_request *rq)
236{
237 int retries;
238 int rc;
239
240 if (raw3270_request_final(rq))
241 return 0;
242 /* Check if interrupt has already been processed */
243 for (retries = 0; retries < 5; retries++) {
244 if (retries < 2)
245 rc = ccw_device_halt(rp->cdev, (long) rq);
246 else
247 rc = ccw_device_clear(rp->cdev, (long) rq);
248 if (rc == 0)
249 break; /* termination successful */
250 }
251 return rc;
252}
253
254/*
255 * Add the request to the request queue, try to start it if the 232 * Add the request to the request queue, try to start it if the
256 * 3270 device is idle. Return without waiting for end of i/o. 233 * 3270 device is idle. Return without waiting for end of i/o.
257 */ 234 */
@@ -342,7 +319,6 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
342 struct raw3270 *rp; 319 struct raw3270 *rp;
343 struct raw3270_view *view; 320 struct raw3270_view *view;
344 struct raw3270_request *rq; 321 struct raw3270_request *rq;
345 int rc;
346 322
347 rp = dev_get_drvdata(&cdev->dev); 323 rp = dev_get_drvdata(&cdev->dev);
348 if (!rp) 324 if (!rp)
@@ -350,55 +326,27 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
350 rq = (struct raw3270_request *) intparm; 326 rq = (struct raw3270_request *) intparm;
351 view = rq ? rq->view : rp->view; 327 view = rq ? rq->view : rp->view;
352 328
353 if (IS_ERR(irb)) 329 if (!IS_ERR(irb)) {
354 rc = RAW3270_IO_RETRY;
355 else if (irb->scsw.cmd.fctl & SCSW_FCTL_HALT_FUNC) {
356 rq->rc = -EIO;
357 rc = RAW3270_IO_DONE;
358 } else if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END |
359 DEV_STAT_UNIT_EXCEP)) {
360 /* Handle CE-DE-UE and subsequent UDE */ 330 /* Handle CE-DE-UE and subsequent UDE */
361 set_bit(RAW3270_FLAGS_BUSY, &rp->flags); 331 if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END)
362 rc = RAW3270_IO_BUSY;
363 } else if (test_bit(RAW3270_FLAGS_BUSY, &rp->flags)) {
364 /* Wait for UDE if busy flag is set. */
365 if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) {
366 clear_bit(RAW3270_FLAGS_BUSY, &rp->flags); 332 clear_bit(RAW3270_FLAGS_BUSY, &rp->flags);
367 /* Got it, now retry. */ 333 if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END |
368 rc = RAW3270_IO_RETRY; 334 DEV_STAT_DEV_END |
369 } else 335 DEV_STAT_UNIT_EXCEP))
370 rc = RAW3270_IO_BUSY; 336 set_bit(RAW3270_FLAGS_BUSY, &rp->flags);
371 } else if (view) 337 /* Handle disconnected devices */
372 rc = view->fn->intv(view, rq, irb); 338 if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
373 else 339 (irb->ecw[0] & SNS0_INTERVENTION_REQ))
374 rc = RAW3270_IO_DONE; 340 set_bit(RAW3270_FLAGS_BUSY, &rp->flags);
341 /* Call interrupt handler of the view */
342 if (view)
343 view->fn->intv(view, rq, irb);
344 }
375 345
376 switch (rc) { 346 if (test_bit(RAW3270_FLAGS_BUSY, &rp->flags))
377 case RAW3270_IO_DONE: 347 /* Device busy, do not start I/O */
378 break;
379 case RAW3270_IO_BUSY:
380 /*
381 * Intervention required by the operator. We have to wait
382 * for unsolicited device end.
383 */
384 return; 348 return;
385 case RAW3270_IO_RETRY: 349
386 if (!rq)
387 break;
388 rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
389 (unsigned long) rq, 0, 0);
390 if (rq->rc == 0)
391 return; /* Successfully restarted. */
392 break;
393 case RAW3270_IO_STOP:
394 if (!rq)
395 break;
396 __raw3270_halt_io(rp, rq);
397 rq->rc = -EIO;
398 break;
399 default:
400 BUG();
401 }
402 if (rq) { 350 if (rq) {
403 BUG_ON(list_empty(&rq->list)); 351 BUG_ON(list_empty(&rq->list));
404 /* The request completed, remove from queue and do callback. */ 352 /* The request completed, remove from queue and do callback. */
@@ -408,6 +356,7 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
408 /* Do put_device for get_device in raw3270_start. */ 356 /* Do put_device for get_device in raw3270_start. */
409 raw3270_put_view(view); 357 raw3270_put_view(view);
410 } 358 }
359
411 /* 360 /*
412 * Try to start each request on request queue until one is 361 * Try to start each request on request queue until one is
413 * started successful. 362 * started successful.
@@ -685,23 +634,12 @@ raw3270_reset(struct raw3270_view *view)
685 return rc; 634 return rc;
686} 635}
687 636
688static int 637static void
689raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq, 638raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
690 struct irb *irb) 639 struct irb *irb)
691{ 640{
692 struct raw3270 *rp; 641 struct raw3270 *rp;
693 642
694 /*
695 * Unit-Check Processing:
696 * Expect Command Reject or Intervention Required.
697 */
698 if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
699 /* Request finished abnormally. */
700 if (irb->ecw[0] & SNS0_INTERVENTION_REQ) {
701 set_bit(RAW3270_FLAGS_BUSY, &view->dev->flags);
702 return RAW3270_IO_BUSY;
703 }
704 }
705 if (rq) { 643 if (rq) {
706 if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { 644 if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
707 if (irb->ecw[0] & SNS0_CMD_REJECT) 645 if (irb->ecw[0] & SNS0_CMD_REJECT)
@@ -715,7 +653,6 @@ raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
715 rp = view->dev; 653 rp = view->dev;
716 raw3270_read_modified(rp); 654 raw3270_read_modified(rp);
717 } 655 }
718 return RAW3270_IO_DONE;
719} 656}
720 657
721static struct raw3270_fn raw3270_init_fn = { 658static struct raw3270_fn raw3270_init_fn = {
diff --git a/drivers/s390/char/raw3270.h b/drivers/s390/char/raw3270.h
index e1e41c2861fb..56519cbb165c 100644
--- a/drivers/s390/char/raw3270.h
+++ b/drivers/s390/char/raw3270.h
@@ -125,19 +125,13 @@ raw3270_request_final(struct raw3270_request *rq)
125 125
126void raw3270_buffer_address(struct raw3270 *, char *, unsigned short); 126void raw3270_buffer_address(struct raw3270 *, char *, unsigned short);
127 127
128/* Return value of *intv (see raw3270_fn below) can be one of the following: */
129#define RAW3270_IO_DONE 0 /* request finished */
130#define RAW3270_IO_BUSY 1 /* request still active */
131#define RAW3270_IO_RETRY 2 /* retry current request */
132#define RAW3270_IO_STOP 3 /* kill current request */
133
134/* 128/*
135 * Functions of a 3270 view. 129 * Functions of a 3270 view.
136 */ 130 */
137struct raw3270_fn { 131struct raw3270_fn {
138 int (*activate)(struct raw3270_view *); 132 int (*activate)(struct raw3270_view *);
139 void (*deactivate)(struct raw3270_view *); 133 void (*deactivate)(struct raw3270_view *);
140 int (*intv)(struct raw3270_view *, 134 void (*intv)(struct raw3270_view *,
141 struct raw3270_request *, struct irb *); 135 struct raw3270_request *, struct irb *);
142 void (*release)(struct raw3270_view *); 136 void (*release)(struct raw3270_view *);
143 void (*free)(struct raw3270_view *); 137 void (*free)(struct raw3270_view *);
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 54ea5a01e30d..d6da18612ba8 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -645,7 +645,7 @@ tty3270_deactivate(struct raw3270_view *view)
645 del_timer(&tp->timer); 645 del_timer(&tp->timer);
646} 646}
647 647
648static int 648static void
649tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb) 649tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb)
650{ 650{
651 /* Handle ATTN. Schedule tasklet to read aid. */ 651 /* Handle ATTN. Schedule tasklet to read aid. */
@@ -667,7 +667,6 @@ tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb)
667 tp->update_flags = TTY_UPDATE_ALL; 667 tp->update_flags = TTY_UPDATE_ALL;
668 tty3270_set_timer(tp, 1); 668 tty3270_set_timer(tp, 1);
669 } 669 }
670 return RAW3270_IO_DONE;
671} 670}
672 671
673/* 672/*