From: Martin Schwidefsky <schwidefsky@de.ibm.com>

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

sclp console driver changes:
 - Correct handling of busy and not operational states.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/drivers/s390/char/sclp.c |   69 ++++++++++++++++++++++++++-------------
 1 files changed, 46 insertions(+), 23 deletions(-)

diff -puN drivers/s390/char/sclp.c~s390-sclp-console-driver drivers/s390/char/sclp.c
--- 25/drivers/s390/char/sclp.c~s390-sclp-console-driver	2004-06-30 10:16:42.624279960 -0700
+++ 25-akpm/drivers/s390/char/sclp.c	2004-06-30 10:16:42.628279352 -0700
@@ -52,6 +52,9 @@ static char sclp_init_sccb[PAGE_SIZE] __
 /* Timer for init mask retries. */
 static struct timer_list retry_timer;
 
+/* Timer for busy retries. */
+static struct timer_list sclp_busy_timer;
+
 static volatile unsigned long sclp_status = 0;
 /* some status flags */
 #define SCLP_INIT		0
@@ -59,6 +62,7 @@ static volatile unsigned long sclp_statu
 #define SCLP_READING		2
 
 #define SCLP_INIT_POLL_INTERVAL	1
+#define SCLP_BUSY_POLL_INTERVAL	1
 
 #define SCLP_COMMAND_INITIATED	0
 #define SCLP_BUSY		2
@@ -93,45 +97,61 @@ __service_call(sclp_cmdw_t command, void
 	 */
 	if (cc == SCLP_NOT_OPERATIONAL)
 		return -EIO;
-	/*
-	 * We set the SCLP_RUNNING bit for cc 2 as well because if
-	 * service_call returns cc 2 some old request is running
-	 * that has to complete first
-	 */
-	set_bit(SCLP_RUNNING, &sclp_status);
 	if (cc == SCLP_BUSY)
 		return -EBUSY;
 	return 0;
 }
 
-static int
+static void
 sclp_start_request(void)
 {
 	struct sclp_req *req;
 	int rc;
 	unsigned long flags;
 
-	/* quick exit if sclp is already in use */
-	if (test_bit(SCLP_RUNNING, &sclp_status))
-		return -EBUSY;
 	spin_lock_irqsave(&sclp_lock, flags);
-	/* Get first request on queue if available */
-	req = NULL;
-	if (!list_empty(&sclp_req_queue))
+	/* quick exit if sclp is already in use */
+	if (test_bit(SCLP_RUNNING, &sclp_status)) {
+		spin_unlock_irqrestore(&sclp_lock, flags);
+		return;
+	}
+	/* Try to start requests from the request queue. */
+	while (!list_empty(&sclp_req_queue)) {
 		req = list_entry(sclp_req_queue.next, struct sclp_req, list);
-	if (req) {
 		rc = __service_call(req->command, req->sccb);
-		if (rc) {
-			req->status = SCLP_REQ_FAILED;
-			list_del(&req->list);
-		} else
+		if (rc == 0) {
+			/* Sucessfully started request. */
 			req->status = SCLP_REQ_RUNNING;
-	} else
-		rc = -EINVAL;
+			/* Request active. Set running indication. */
+			set_bit(SCLP_RUNNING, &sclp_status);
+			break;
+		}
+		if (rc == -EBUSY) {
+			/**
+			 * SCLP is busy but no request is running.
+			 * Try again later.
+			 */
+			if (!timer_pending(&sclp_busy_timer) ||
+			    !mod_timer(&sclp_busy_timer,
+				       jiffies + SCLP_BUSY_POLL_INTERVAL*HZ)) {
+				sclp_busy_timer.function =
+					(void *) sclp_start_request;
+				sclp_busy_timer.expires =
+					jiffies + SCLP_BUSY_POLL_INTERVAL*HZ;
+				add_timer(&sclp_busy_timer);
+			}
+			break;
+		}
+		/* Request failed. */
+		req->status = SCLP_REQ_FAILED;
+		list_del(&req->list);
+		if (req->callback) {
+			spin_unlock_irqrestore(&sclp_lock, flags);
+			req->callback(req, req->callback_data);
+			spin_lock_irqsave(&sclp_lock, flags);
+		}
+	}
 	spin_unlock_irqrestore(&sclp_lock, flags);
-	if (rc == -EIO && req->callback != NULL)
-		req->callback(req, req->callback_data);
-	return rc;
 }
 
 static int
@@ -613,6 +633,8 @@ sclp_init_mask(void)
 		 */
 		do {
 			rc = __service_call(req->command, req->sccb);
+			if (rc == 0)
+				set_bit(SCLP_RUNNING, &sclp_status);
 			spin_unlock_irqrestore(&sclp_lock, flags);
 			if (rc == -EIO)
 				return -ENOSYS;
@@ -685,6 +707,7 @@ sclp_init(void)
 	ctl_set_bit(0, 9);
 
 	init_timer(&retry_timer);
+	init_timer(&sclp_busy_timer);
 	/* do the initial write event mask */
 	rc = sclp_init_mask();
 	if (rc == 0) {
_