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

- 3215: Adapt to notify api change in cio.
- 3215/sclp: move copy_from_user out of locked code.



---

 25-akpm/drivers/s390/char/con3215.c  |   92 ++++++++++++++---------------------
 25-akpm/drivers/s390/char/sclp_con.c |    4 -
 25-akpm/drivers/s390/char/sclp_rw.c  |   16 +-----
 25-akpm/drivers/s390/char/sclp_rw.h  |    2 
 25-akpm/drivers/s390/char/sclp_tty.c |   38 +++++++++++---
 5 files changed, 75 insertions(+), 77 deletions(-)

diff -puN drivers/s390/char/con3215.c~s390-03-console-driver drivers/s390/char/con3215.c
--- 25/drivers/s390/char/con3215.c~s390-03-console-driver	Thu Jan  8 14:11:29 2004
+++ 25-akpm/drivers/s390/char/con3215.c	Thu Jan  8 14:11:29 2004
@@ -96,6 +96,7 @@ struct raw3215_info {
 	int msg_dstat;		      /* dstat for pending message */
 	int msg_cstat;		      /* cstat for pending message */
 	int line_pos;		      /* position on the line (for tabs) */
+	char ubuffer[80];	      /* copy_from_user buffer */
 };
 
 /* array of 3215 devices structures */
@@ -532,15 +533,12 @@ raw3215_make_room(struct raw3215_info *r
 /*
  * String write routine for 3215 devices
  */
-static int
-raw3215_write(struct raw3215_info *raw, const char *str,
-	      int from_user, unsigned int length)
+static void
+raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length)
 {
 	unsigned long flags;
-	int ret, c;
-	int count;
+	int c, count;
 
-	ret = 0;
 	while (length > 0) {
 		spin_lock_irqsave(raw->lock, flags);
 		count = (length > RAW3215_BUFFER_SIZE) ?
@@ -550,46 +548,19 @@ raw3215_write(struct raw3215_info *raw, 
 		raw3215_make_room(raw, count);
 
 		/* copy string to output buffer and convert it to EBCDIC */
-		if (from_user) {
-			while (1) {
-				c = min_t(int, count,
-					min(RAW3215_BUFFER_SIZE - raw->count,
-					    RAW3215_BUFFER_SIZE - raw->head));
-				if (c <= 0)
-					break;
-				c -= copy_from_user(raw->buffer + raw->head,
-						    str, c);
-				if (c == 0) {
-					if (!ret)
-						ret = -EFAULT;
-					break;
-				}
-				ASCEBC(raw->buffer + raw->head, c);
-				raw->head = (raw->head + c) &
-					    (RAW3215_BUFFER_SIZE - 1);
-				raw->count += c;
-				raw->line_pos += c;
-				str += c;
-				count -= c;
-				ret += c;
-			}
-		} else {
-			while (1) {
-				c = min_t(int, count,
-					min(RAW3215_BUFFER_SIZE - raw->count,
-					    RAW3215_BUFFER_SIZE - raw->head));
-				if (c <= 0)
-					break;
-				memcpy(raw->buffer + raw->head, str, c);
-				ASCEBC(raw->buffer + raw->head, c);
-				raw->head = (raw->head + c) &
-					    (RAW3215_BUFFER_SIZE - 1);
-				raw->count += c;
-				raw->line_pos += c;
-				str += c;
-				count -= c;
-				ret += c;
-			}
+		while (1) {
+			c = min_t(int, count,
+				  min(RAW3215_BUFFER_SIZE - raw->count,
+				      RAW3215_BUFFER_SIZE - raw->head));
+			if (c <= 0)
+				break;
+			memcpy(raw->buffer + raw->head, str, c);
+			ASCEBC(raw->buffer + raw->head, c);
+			raw->head = (raw->head + c) & (RAW3215_BUFFER_SIZE - 1);
+			raw->count += c;
+			raw->line_pos += c;
+			str += c;
+			count -= c;
 		}
 		if (!(raw->flags & RAW3215_WORKING)) {
 			raw3215_mk_write_req(raw);
@@ -598,8 +569,6 @@ raw3215_write(struct raw3215_info *raw, 
 		}
 		spin_unlock_irqrestore(raw->lock, flags);
 	}
-
-	return ret;
 }
 
 /*
@@ -752,11 +721,12 @@ raw3215_probe (struct ccw_device *cdev)
 	return 0;
 }
 
-static int
+static void
 raw3215_remove (struct ccw_device *cdev)
 {
 	struct raw3215_info *raw;
 
+	ccw_device_set_offline(cdev);
 	raw = cdev->dev.driver_data;
 	if (raw) {
 		cdev->dev.driver_data = NULL;
@@ -764,7 +734,6 @@ raw3215_remove (struct ccw_device *cdev)
 			kfree(raw->buffer);
 		kfree(raw);
 	}
-	return 0;
 }
 
 static int
@@ -825,7 +794,7 @@ con3215_write(struct console *co, const 
 		for (i = 0; i < count; i++)
 			if (str[i] == '\t' || str[i] == '\n')
 				break;
-		raw3215_write(raw, str, 0, i);
+		raw3215_write(raw, str, i);
 		count -= i;
 		str += i;
 		if (count > 0) {
@@ -1021,12 +990,29 @@ tty3215_write(struct tty_struct * tty, i
 	      const unsigned char *buf, int count)
 {
 	struct raw3215_info *raw;
-	int ret = 0;
+	int length, ret;
 
 	if (!tty)
 		return 0;
 	raw = (struct raw3215_info *) tty->driver_data;
-	ret = raw3215_write(raw, buf, from_user, count);
+	if (!from_user) {
+		raw3215_write(raw, buf, count);
+		return count;
+	}
+	ret = 0;
+	while (count > 0) {
+		length = count < 80 ? count : 80;
+		length -= copy_from_user(raw->ubuffer, buf, length);
+		if (length == 0) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
+		raw3215_write(raw, raw->ubuffer, count);
+		buf += length;
+		count -= length;
+		ret += length;
+	}
 	return ret;
 }
 
diff -puN drivers/s390/char/sclp_con.c~s390-03-console-driver drivers/s390/char/sclp_con.c
--- 25/drivers/s390/char/sclp_con.c~s390-03-console-driver	Thu Jan  8 14:11:29 2004
+++ 25-akpm/drivers/s390/char/sclp_con.c	Thu Jan  8 14:11:29 2004
@@ -134,8 +134,8 @@ sclp_console_write(struct console *conso
 		}
 		/* try to write the string to the current output buffer */
 		written = sclp_write(sclp_conbuf, (const unsigned char *)
-				     message, count, 0);
-		if (written == -EFAULT || written == count)
+				     message, count);
+		if (written == count)
 			break;
 		/*
 		 * Not all characters could be written to the current
diff -puN drivers/s390/char/sclp_rw.c~s390-03-console-driver drivers/s390/char/sclp_rw.c
--- 25/drivers/s390/char/sclp_rw.c~s390-03-console-driver	Thu Jan  8 14:11:29 2004
+++ 25-akpm/drivers/s390/char/sclp_rw.c	Thu Jan  8 14:11:29 2004
@@ -175,11 +175,9 @@ sclp_finalize_mto(struct sclp_buffer *bu
  *  is not busy)
  */
 int
-sclp_write(struct sclp_buffer *buffer,
-	   const unsigned char *msg, int count, int from_user)
+sclp_write(struct sclp_buffer *buffer, const unsigned char *msg, int count)
 {
 	int spaces, i_msg;
-	char ch;
 	int rc;
 
 	/*
@@ -206,13 +204,7 @@ sclp_write(struct sclp_buffer *buffer,
 	 * This is in order to a slim and quick implementation.
 	 */
 	for (i_msg = 0; i_msg < count; i_msg++) {
-		if (from_user) {
-			if (get_user(ch, msg + i_msg) != 0)
-				return -EFAULT;
-		} else
-			ch = msg[i_msg];
-
-		switch (ch) {
+		switch (msg[i_msg]) {
 		case '\n':	/* new line, line feed (ASCII)	*/
 			/* check if new mto needs to be created */
 			if (buffer->current_line == NULL) {
@@ -286,7 +278,7 @@ sclp_write(struct sclp_buffer *buffer,
 			break;
 		default:	/* no escape character	*/
 			/* do not output unprintable characters */
-			if (!isprint(ch))
+			if (!isprint(msg[i_msg]))
 				break;
 			/* check if new mto needs to be created */
 			if (buffer->current_line == NULL) {
@@ -295,7 +287,7 @@ sclp_write(struct sclp_buffer *buffer,
 				if (rc)
 					return i_msg;
 			}
-			*buffer->current_line++ = sclp_ascebc(ch);
+			*buffer->current_line++ = sclp_ascebc(msg[i_msg]);
 			buffer->current_length++;
 			break;
 		}
diff -puN drivers/s390/char/sclp_rw.h~s390-03-console-driver drivers/s390/char/sclp_rw.h
--- 25/drivers/s390/char/sclp_rw.h~s390-03-console-driver	Thu Jan  8 14:11:29 2004
+++ 25-akpm/drivers/s390/char/sclp_rw.h	Thu Jan  8 14:11:29 2004
@@ -89,7 +89,7 @@ int sclp_rw_init(void);
 struct sclp_buffer *sclp_make_buffer(void *, unsigned short, unsigned short);
 void *sclp_unmake_buffer(struct sclp_buffer *);
 int sclp_buffer_space(struct sclp_buffer *);
-int sclp_write(struct sclp_buffer *buffer, const unsigned char *, int, int);
+int sclp_write(struct sclp_buffer *buffer, const unsigned char *, int);
 void sclp_emit_buffer(struct sclp_buffer *,void (*)(struct sclp_buffer *,int));
 void sclp_set_columns(struct sclp_buffer *, unsigned short);
 void sclp_set_htab(struct sclp_buffer *, unsigned short);
diff -puN drivers/s390/char/sclp_tty.c~s390-03-console-driver drivers/s390/char/sclp_tty.c
--- 25/drivers/s390/char/sclp_tty.c~s390-03-console-driver	Thu Jan  8 14:11:29 2004
+++ 25-akpm/drivers/s390/char/sclp_tty.c	Thu Jan  8 14:11:29 2004
@@ -322,7 +322,7 @@ sclp_tty_timeout(unsigned long data)
  * Write a string to the sclp tty.
  */
 static void
-sclp_tty_write_string(const unsigned char *str, int count, int from_user)
+sclp_tty_write_string(const unsigned char *str, int count)
 {
 	unsigned long flags;
 	void *page;
@@ -348,8 +348,8 @@ sclp_tty_write_string(const unsigned cha
 						       sclp_ioctls.htab);
 		}
 		/* try to write the string to the current output buffer */
-		written = sclp_write(sclp_ttybuf, str, count, from_user);
-		if (written == -EFAULT || written == count)
+		written = sclp_write(sclp_ttybuf, str, count);
+		if (written == count)
 			break;
 		/*
 		 * Not all characters could be written to the current
@@ -389,12 +389,32 @@ static int
 sclp_tty_write(struct tty_struct *tty, int from_user,
 	       const unsigned char *buf, int count)
 {
+	int length, ret;
+
 	if (sclp_tty_chars_count > 0) {
-		sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0);
+		sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);
 		sclp_tty_chars_count = 0;
 	}
-	sclp_tty_write_string(buf, count, from_user);
-	return count;
+	if (!from_user) {
+		sclp_tty_write_string(buf, count);
+		return count;
+	}
+	ret = 0;
+	while (count > 0) {
+		length = count < SCLP_TTY_BUF_SIZE ?
+			count : SCLP_TTY_BUF_SIZE;
+		length -= copy_from_user(sclp_tty_chars, buf, length);
+		if (length == 0) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
+		sclp_tty_write_string(sclp_tty_chars, length);
+		buf += length;
+		count -= length;
+		ret += length;
+	}
+	return ret;
 }
 
 /*
@@ -412,7 +432,7 @@ sclp_tty_put_char(struct tty_struct *tty
 {
 	sclp_tty_chars[sclp_tty_chars_count++] = ch;
 	if (ch == '\n' || sclp_tty_chars_count >= SCLP_TTY_BUF_SIZE) {
-		sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0);
+		sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);
 		sclp_tty_chars_count = 0;
 	}
 }
@@ -425,7 +445,7 @@ static void
 sclp_tty_flush_chars(struct tty_struct *tty)
 {
 	if (sclp_tty_chars_count > 0) {
-		sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0);
+		sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);
 		sclp_tty_chars_count = 0;
 	}
 }
@@ -464,7 +484,7 @@ static void
 sclp_tty_flush_buffer(struct tty_struct *tty)
 {
 	if (sclp_tty_chars_count > 0) {
-		sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0);
+		sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);
 		sclp_tty_chars_count = 0;
 	}
 }

_