From: Greg Howard <ghoward@sgi.com>

The Altix system controller communication driver currently exits the read
and write routines with semaphores still held in some error conditions; fix
this.  Also remove an unnecessary typecast, and use wake_up() instead of
wake_up_all() for waking up processes waiting to send or receive data. 
Update drivers/char/Kconfig to enable this driver for IA64_GENERIC kernels,
and update the generic_defconfig to include it in kernel builds.

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/ia64/configs/generic_defconfig |    1 +
 25-akpm/drivers/char/Kconfig                |    2 +-
 25-akpm/drivers/char/snsc.c                 |   14 ++++++++++----
 3 files changed, 12 insertions(+), 5 deletions(-)

diff -puN arch/ia64/configs/generic_defconfig~altix-system-controller-fixes arch/ia64/configs/generic_defconfig
--- 25/arch/ia64/configs/generic_defconfig~altix-system-controller-fixes	2004-08-15 15:34:28.719040160 -0700
+++ 25-akpm/arch/ia64/configs/generic_defconfig	2004-08-15 15:34:28.726039096 -0700
@@ -575,6 +575,7 @@ CONFIG_SERIAL_NONSTANDARD=y
 # CONFIG_SYNCLINKMP is not set
 # CONFIG_N_HDLC is not set
 # CONFIG_STALDRV is not set
+CONFIG_SGI_SNSC=y
 
 #
 # Serial drivers
diff -puN drivers/char/Kconfig~altix-system-controller-fixes drivers/char/Kconfig
--- 25/drivers/char/Kconfig~altix-system-controller-fixes	2004-08-15 15:34:28.720040008 -0700
+++ 25-akpm/drivers/char/Kconfig	2004-08-15 15:34:28.727038944 -0700
@@ -426,7 +426,7 @@ config A2232
 
 config SGI_SNSC
 	bool "SGI Altix system controller communication support"
-	depends on IA64_SGI_SN2
+	depends on (IA64_SGI_SN2 || IA64_GENERIC)
 	help
 	  If you have an SGI Altix and you want to enable system
 	  controller communication from user space (you want this!),
diff -puN drivers/char/snsc.c~altix-system-controller-fixes drivers/char/snsc.c
--- 25/drivers/char/snsc.c~altix-system-controller-fixes	2004-08-15 15:34:28.722039704 -0700
+++ 25-akpm/drivers/char/snsc.c	2004-08-15 15:34:28.728038792 -0700
@@ -33,7 +33,7 @@
 static irqreturn_t
 scdrv_interrupt(int irq, void *subch_data, struct pt_regs *regs)
 {
-	struct subch_data_s *sd = (struct subch_data_s *) subch_data;
+	struct subch_data_s *sd = subch_data;
 	unsigned long flags;
 	int status;
 
@@ -43,13 +43,13 @@ scdrv_interrupt(int irq, void *subch_dat
 
 	if (status > 0) {
 		if (status & SAL_IROUTER_INTR_RECV) {
-			wake_up_all(&sd->sd_rq);
+			wake_up(&sd->sd_rq);
 		}
 		if (status & SAL_IROUTER_INTR_XMIT) {
 			ia64_sn_irtr_intr_disable
 			    (sd->sd_nasid, sd->sd_subch,
 			     SAL_IROUTER_INTR_XMIT);
-			wake_up_all(&sd->sd_wq);
+			wake_up(&sd->sd_wq);
 		}
 	}
 	spin_unlock(&sd->sd_wlock);
@@ -184,6 +184,7 @@ scdrv_read(struct file *file, char __use
 
 		if (file->f_flags & O_NONBLOCK) {
 			spin_unlock_irqrestore(&sd->sd_rlock, flags);
+			up(&sd->sd_rbs);
 			return -EAGAIN;
 		}
 
@@ -197,6 +198,7 @@ scdrv_read(struct file *file, char __use
 		remove_wait_queue(&sd->sd_rq, &wait);
 		if (signal_pending(current)) {
 			/* wait was interrupted */
+			up(&sd->sd_rbs);
 			return -ERESTARTSYS;
 		}
 
@@ -264,8 +266,10 @@ scdrv_write(struct file *file, const cha
 	}
 
 	count = min((int) count, CHUNKSIZE);
-	if (copy_from_user(sd->sd_wb, buf, count))
+	if (copy_from_user(sd->sd_wb, buf, count)) {
+		up(&sd->sd_wbs);
 		return -EFAULT;
+	}
 
 	/* try to send the buffer */
 	spin_lock_irqsave(&sd->sd_wlock, flags);
@@ -277,6 +281,7 @@ scdrv_write(struct file *file, const cha
 
 		if (file->f_flags & O_NONBLOCK) {
 			spin_unlock(&sd->sd_wlock);
+			up(&sd->sd_wbs);
 			return -EAGAIN;
 		}
 
@@ -289,6 +294,7 @@ scdrv_write(struct file *file, const cha
 		remove_wait_queue(&sd->sd_wq, &wait);
 		if (signal_pending(current)) {
 			/* wait was interrupted */
+			up(&sd->sd_wbs);
 			return -ERESTARTSYS;
 		}
 
_