diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-18 12:17:16 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-18 12:17:16 -0700 |
commit | f61a657fdf221403d99e6f0d4c6d24762920d4a9 (patch) | |
tree | 54c5413977be2acdffcb31ee058af333ba3679a3 /drivers/s390/char/raw3270.c | |
parent | 0e034f5c4bc408c943f9c4a06244415d75d7108c (diff) | |
parent | c53db5222b92d1df384a89ceba7808f8e4c535dd (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Martin Schwidefsky:
"The s390 patches for the 4.7 merge window have the usual bug fixes and
cleanups, and the following new features:
- An interface for dasd driver to query if a volume is online to
another operating system
- A new ioctl for the dasd driver to verify the format for a range of
tracks
- Following the example of x86 the struct fpu is now allocated with
the task_struct
- The 'report_error' interface for the PCI bus to send an
adapter-error notification from user space to the service element
of the machine"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (29 commits)
s390/vmem: remove unused function parameter
s390/vmem: fix identity mapping
s390: add missing include statements
s390: add missing declarations
s390: make couple of variables and functions static
s390/cache: remove superfluous locking
s390/cpuinfo: simplify locking and skip offline cpus early
s390/3270: hangup the 3270 tty after a disconnect
s390/3270: handle reconnect of a tty with a different size
s390/3270: avoid endless I/O loop with disconnected 3270 terminals
s390/3270: fix garbled output on 3270 tty view
s390/3270: fix view reference counting
s390/3270: add missing tty_kref_put
s390/dumpstack: implement and use return_address()
s390/cpum_sf: Remove superfluous SMP function call
s390/cpum_cf: Remove superfluous SMP function call
s390/Kconfig: make z196 the default processor type
s390/sclp: avoid compile warning in sclp_pci_report
s390/fpu: allocate 'struct fpu' with the task_struct
s390/crypto: cleanup and move the header with the cpacf definitions
...
Diffstat (limited to 'drivers/s390/char/raw3270.c')
-rw-r--r-- | drivers/s390/char/raw3270.c | 131 |
1 files changed, 47 insertions, 84 deletions
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 220acb4cbee5..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. */ @@ -229,29 +231,6 @@ raw3270_request_set_idal(struct raw3270_request *rq, struct idal_buffer *ib) } /* - * Stop running ccw. - */ -static int -__raw3270_halt_io(struct raw3270 *rp, struct raw3270_request *rq) -{ - int retries; - int rc; - - if (raw3270_request_final(rq)) - return 0; - /* Check if interrupt has already been processed */ - for (retries = 0; retries < 5; retries++) { - if (retries < 2) - rc = ccw_device_halt(rp->cdev, (long) rq); - else - rc = ccw_device_clear(rp->cdev, (long) rq); - if (rc == 0) - break; /* termination successful */ - } - return rc; -} - -/* * Add the request to the request queue, try to start it if the * 3270 device is idle. Return without waiting for end of i/o. */ @@ -342,7 +321,6 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) struct raw3270 *rp; struct raw3270_view *view; struct raw3270_request *rq; - int rc; rp = dev_get_drvdata(&cdev->dev); if (!rp) @@ -350,57 +328,31 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) rq = (struct raw3270_request *) intparm; view = rq ? rq->view : rp->view; - if (IS_ERR(irb)) - rc = RAW3270_IO_RETRY; - else if (irb->scsw.cmd.fctl & SCSW_FCTL_HALT_FUNC) { - rq->rc = -EIO; - rc = RAW3270_IO_DONE; - } else if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END | - DEV_STAT_UNIT_EXCEP)) { + if (!IS_ERR(irb)) { /* Handle CE-DE-UE and subsequent UDE */ - set_bit(RAW3270_FLAGS_BUSY, &rp->flags); - rc = RAW3270_IO_BUSY; - } else if (test_bit(RAW3270_FLAGS_BUSY, &rp->flags)) { - /* Wait for UDE if busy flag is set. */ - if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) { + if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) clear_bit(RAW3270_FLAGS_BUSY, &rp->flags); - /* Got it, now retry. */ - rc = RAW3270_IO_RETRY; - } else - rc = RAW3270_IO_BUSY; - } else if (view) - rc = view->fn->intv(view, rq, irb); - else - rc = RAW3270_IO_DONE; + if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | + DEV_STAT_DEV_END | + DEV_STAT_UNIT_EXCEP)) + 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)) { + 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); + } - switch (rc) { - case RAW3270_IO_DONE: - break; - case RAW3270_IO_BUSY: - /* - * Intervention required by the operator. We have to wait - * for unsolicited device end. - */ + if (test_bit(RAW3270_FLAGS_BUSY, &rp->flags)) + /* Device busy, do not start I/O */ return; - case RAW3270_IO_RETRY: - if (!rq) - break; - rq->rc = ccw_device_start(rp->cdev, &rq->ccw, - (unsigned long) rq, 0, 0); - if (rq->rc == 0) - return; /* Successfully restarted. */ - break; - case RAW3270_IO_STOP: - if (!rq) - break; - __raw3270_halt_io(rp, rq); - rq->rc = -EIO; - break; - default: - BUG(); - } - 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) @@ -408,6 +360,7 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) /* Do put_device for get_device in raw3270_start. */ raw3270_put_view(view); } + /* * Try to start each request on request queue until one is * started successful. @@ -685,23 +638,34 @@ raw3270_reset(struct raw3270_view *view) return rc; } -static int +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) { struct raw3270 *rp; - /* - * Unit-Check Processing: - * Expect Command Reject or Intervention Required. - */ - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { - /* Request finished abnormally. */ - if (irb->ecw[0] & SNS0_INTERVENTION_REQ) { - set_bit(RAW3270_FLAGS_BUSY, &view->dev->flags); - return RAW3270_IO_BUSY; - } - } if (rq) { if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { if (irb->ecw[0] & SNS0_CMD_REJECT) @@ -715,7 +679,6 @@ raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq, rp = view->dev; raw3270_read_modified(rp); } - return RAW3270_IO_DONE; } static struct raw3270_fn raw3270_init_fn = { |