[S390] subchannel lock conversion.

Convert the subchannel lock to a pointer to a lock.  Needed for the dynamic
subchannel mapping patch.

Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index dbfb77b..cbab8d2 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -183,7 +183,7 @@
 	page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 	if (!page)
 		return -ENOMEM;
-	spin_lock_irq(&sch->lock);
+	spin_lock_irq(sch->lock);
 	ret = chsc_get_sch_desc_irq(sch, page);
 	if (ret) {
 		static int cio_chsc_err_msg;
@@ -197,7 +197,7 @@
 			cio_chsc_err_msg = 1;
 		}
 	}
-	spin_unlock_irq(&sch->lock);
+	spin_unlock_irq(sch->lock);
 	free_page((unsigned long)page);
 	if (!ret) {
 		int j, chpid, mask;
@@ -233,7 +233,7 @@
 	if (j >= 8)
 		return 0;
 
-	spin_lock_irq(&sch->lock);
+	spin_lock_irq(sch->lock);
 
 	stsch(sch->schid, &schib);
 	if (!schib.pmcw.dnv)
@@ -265,10 +265,10 @@
 	else if (sch->lpm == mask)
 		goto out_unreg;
 out_unlock:
-	spin_unlock_irq(&sch->lock);
+	spin_unlock_irq(sch->lock);
 	return 0;
 out_unreg:
-	spin_unlock_irq(&sch->lock);
+	spin_unlock_irq(sch->lock);
 	sch->lpm = 0;
 	if (css_enqueue_subchannel_slow(sch->schid)) {
 		css_clear_subchannel_slow_list();
@@ -378,12 +378,12 @@
 		/* Check if a subchannel is newly available. */
 		return s390_process_res_acc_new_sch(schid);
 
-	spin_lock_irq(&sch->lock);
+	spin_lock_irq(sch->lock);
 
 	chp_mask = s390_process_res_acc_sch(res_data, sch);
 
 	if (chp_mask == 0) {
-		spin_unlock_irq(&sch->lock);
+		spin_unlock_irq(sch->lock);
 		put_device(&sch->dev);
 		return 0;
 	}
@@ -397,7 +397,7 @@
 	else if (sch->driver && sch->driver->verify)
 		sch->driver->verify(&sch->dev);
 
-	spin_unlock_irq(&sch->lock);
+	spin_unlock_irq(sch->lock);
 	put_device(&sch->dev);
 	return 0;
 }
@@ -635,21 +635,21 @@
 	if (!sch)
 		/* Check if the subchannel is now available. */
 		return __chp_add_new_sch(schid);
-	spin_lock_irq(&sch->lock);
+	spin_lock_irq(sch->lock);
 	for (i=0; i<8; i++) {
 		mask = 0x80 >> i;
 		if ((sch->schib.pmcw.pim & mask) &&
 		    (sch->schib.pmcw.chpid[i] == chp->id)) {
 			if (stsch(sch->schid, &sch->schib) != 0) {
 				/* Endgame. */
-				spin_unlock_irq(&sch->lock);
+				spin_unlock_irq(sch->lock);
 				return -ENXIO;
 			}
 			break;
 		}
 	}
 	if (i==8) {
-		spin_unlock_irq(&sch->lock);
+		spin_unlock_irq(sch->lock);
 		return 0;
 	}
 	sch->lpm = ((sch->schib.pmcw.pim &
@@ -660,7 +660,7 @@
 	if (sch->driver && sch->driver->verify)
 		sch->driver->verify(&sch->dev);
 
-	spin_unlock_irq(&sch->lock);
+	spin_unlock_irq(sch->lock);
 	put_device(&sch->dev);
 	return 0;
 }
@@ -750,7 +750,7 @@
 	if (!sch->ssd_info.valid)
 		return;
 	
-	spin_lock_irqsave(&sch->lock, flags);
+	spin_lock_irqsave(sch->lock, flags);
 	old_lpm = sch->lpm;
 	for (chp = 0; chp < 8; chp++) {
 		if (sch->ssd_info.chpid[chp] != chpid)
@@ -785,7 +785,7 @@
 			sch->driver->verify(&sch->dev);
 		break;
 	}
-	spin_unlock_irqrestore(&sch->lock, flags);
+	spin_unlock_irqrestore(sch->lock, flags);
 }
 
 static int
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 20aee27..e8d3314 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -143,11 +143,11 @@
 		return 1;
 	local_bh_disable();
 	irq_enter ();
-	spin_lock(&sch->lock);
+	spin_lock(sch->lock);
 	memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw));
 	if (sch->driver && sch->driver->irq)
 		sch->driver->irq(&sch->dev);
-	spin_unlock(&sch->lock);
+	spin_unlock(sch->lock);
 	irq_exit ();
 	_local_bh_enable();
 	return 1;
@@ -496,6 +496,15 @@
 	return ret;
 }
 
+static int cio_create_sch_lock(struct subchannel *sch)
+{
+	sch->lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
+	if (!sch->lock)
+		return -ENOMEM;
+	spin_lock_init(sch->lock);
+	return 0;
+}
+
 /*
  * cio_validate_subchannel()
  *
@@ -513,6 +522,7 @@
 {
 	char dbf_txt[15];
 	int ccode;
+	int err;
 
 	sprintf (dbf_txt, "valsch%x", schid.sch_no);
 	CIO_TRACE_EVENT (4, dbf_txt);
@@ -520,9 +530,15 @@
 	/* Nuke all fields. */
 	memset(sch, 0, sizeof(struct subchannel));
 
-	spin_lock_init(&sch->lock);
+	sch->schid = schid;
+	if (cio_is_console(schid)) {
+		sch->lock = cio_get_console_lock();
+	} else {
+		err = cio_create_sch_lock(sch);
+		if (err)
+			goto out;
+	}
 	mutex_init(&sch->reg_mutex);
-
 	/* Set a name for the subchannel */
 	snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", schid.ssid,
 		  schid.sch_no);
@@ -534,10 +550,10 @@
 	 *  is not valid.
 	 */
 	ccode = stsch_err (schid, &sch->schib);
-	if (ccode)
-		return (ccode == 3) ? -ENXIO : ccode;
-
-	sch->schid = schid;
+	if (ccode) {
+		err = (ccode == 3) ? -ENXIO : ccode;
+		goto out;
+	}
 	/* Copy subchannel type from path management control word. */
 	sch->st = sch->schib.pmcw.st;
 
@@ -550,14 +566,16 @@
 			  "non-I/O subchannel type %04X\n",
 			  sch->schid.ssid, sch->schid.sch_no, sch->st);
 		/* We stop here for non-io subchannels. */
-		return sch->st;
+		err = sch->st;
+		goto out;
 	}
 
 	/* Initialization for io subchannels. */
-	if (!sch->schib.pmcw.dnv)
+	if (!sch->schib.pmcw.dnv) {
 		/* io subchannel but device number is invalid. */
-		return -ENODEV;
-
+		err = -ENODEV;
+		goto out;
+	}
 	/* Devno is valid. */
 	if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) {
 		/*
@@ -567,7 +585,8 @@
 		CIO_MSG_EVENT(0, "Blacklisted device detected "
 			      "at devno %04X, subchannel set %x\n",
 			      sch->schib.pmcw.dev, sch->schid.ssid);
-		return -ENODEV;
+		err = -ENODEV;
+		goto out;
 	}
 	sch->opm = 0xff;
 	if (!cio_is_console(sch->schid))
@@ -595,6 +614,11 @@
 	if ((sch->lpm & (sch->lpm - 1)) != 0)
 		sch->schib.pmcw.mp = 1;	/* multipath mode */
 	return 0;
+out:
+	if (!cio_is_console(schid))
+		kfree(sch->lock);
+	sch->lock = NULL;
+	return err;
 }
 
 /*
@@ -637,7 +661,7 @@
 		}
 		sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
 		if (sch)
-			spin_lock(&sch->lock);
+			spin_lock(sch->lock);
 		/* Store interrupt response block to lowcore. */
 		if (tsch (tpi_info->schid, irb) == 0 && sch) {
 			/* Keep subchannel information word up to date. */
@@ -648,7 +672,7 @@
 				sch->driver->irq(&sch->dev);
 		}
 		if (sch)
-			spin_unlock(&sch->lock);
+			spin_unlock(sch->lock);
 		/*
 		 * Are more interrupts pending?
 		 * If so, the tpi instruction will update the lowcore
@@ -687,10 +711,10 @@
 	__ctl_load (cr6, 6, 6);
 
 	do {
-		spin_unlock(&console_subchannel.lock);
+		spin_unlock(console_subchannel.lock);
 		if (!cio_tpi())
 			cpu_relax();
-		spin_lock(&console_subchannel.lock);
+		spin_lock(console_subchannel.lock);
 	} while (console_subchannel.schib.scsw.actl != 0);
 	/*
 	 * restore previous isc value
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 4541c1a..7e7369b 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -87,7 +87,7 @@
 /* subchannel data structure used by I/O subroutines */
 struct subchannel {
 	struct subchannel_id schid;
-	spinlock_t lock;	/* subchannel lock */
+	spinlock_t *lock;	/* subchannel lock */
 	struct mutex reg_mutex;
 	enum {
 		SUBCHANNEL_TYPE_IO = 0,
@@ -137,9 +137,11 @@
 extern void cio_release_console(void);
 extern int cio_is_console(struct subchannel_id);
 extern struct subchannel *cio_get_console_subchannel(void);
+extern spinlock_t * cio_get_console_lock(void);
 #else
 #define cio_is_console(schid) 0
 #define cio_get_console_subchannel() NULL
+#define cio_get_console_lock() NULL;
 #endif
 
 extern int cio_show_msg;
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 55895c8..65939e2 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -91,9 +91,9 @@
 		/* Reset intparm to zeroes. */
 		sch->schib.pmcw.intparm = 0;
 		cio_modify(sch);
+		kfree(sch->lock);
 		kfree(sch);
 	}
-	
 }
 
 static void
@@ -102,8 +102,10 @@
 	struct subchannel *sch;
 
 	sch = to_subchannel(dev);
-	if (!cio_is_console(sch->schid))
+	if (!cio_is_console(sch->schid)) {
+		kfree(sch->lock);
 		kfree(sch);
+	}
 }
 
 extern int css_get_ssd_info(struct subchannel *sch);
@@ -206,18 +208,18 @@
 	unsigned long flags;
 	enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE } action;
 
-	spin_lock_irqsave(&sch->lock, flags);
+	spin_lock_irqsave(sch->lock, flags);
 	disc = device_is_disconnected(sch);
 	if (disc && slow) {
 		/* Disconnected devices are evaluated directly only.*/
-		spin_unlock_irqrestore(&sch->lock, flags);
+		spin_unlock_irqrestore(sch->lock, flags);
 		return 0;
 	}
 	/* No interrupt after machine check - kill pending timers. */
 	device_kill_pending_timer(sch);
 	if (!disc && !slow) {
 		/* Non-disconnected devices are evaluated on the slow path. */
-		spin_unlock_irqrestore(&sch->lock, flags);
+		spin_unlock_irqrestore(sch->lock, flags);
 		return -EAGAIN;
 	}
 	event = css_get_subchannel_status(sch);
@@ -242,9 +244,9 @@
 		/* Ask driver what to do with device. */
 		action = UNREGISTER;
 		if (sch->driver && sch->driver->notify) {
-			spin_unlock_irqrestore(&sch->lock, flags);
+			spin_unlock_irqrestore(sch->lock, flags);
 			ret = sch->driver->notify(&sch->dev, event);
-			spin_lock_irqsave(&sch->lock, flags);
+			spin_lock_irqsave(sch->lock, flags);
 			if (ret)
 				action = NONE;
 		}
@@ -269,9 +271,9 @@
 	case UNREGISTER:
 	case UNREGISTER_PROBE:
 		/* Unregister device (will use subchannel lock). */
-		spin_unlock_irqrestore(&sch->lock, flags);
+		spin_unlock_irqrestore(sch->lock, flags);
 		css_sch_device_unregister(sch);
-		spin_lock_irqsave(&sch->lock, flags);
+		spin_lock_irqsave(sch->lock, flags);
 
 		/* Reset intparm to zeroes. */
 		sch->schib.pmcw.intparm = 0;
@@ -283,7 +285,7 @@
 	default:
 		break;
 	}
-	spin_unlock_irqrestore(&sch->lock, flags);
+	spin_unlock_irqrestore(sch->lock, flags);
 	/* Probe if necessary. */
 	if (action == UNREGISTER_PROBE)
 		ret = css_probe_device(sch->schid);
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index e644fd6..9a31239 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -774,9 +774,9 @@
 		printk (KERN_WARNING "%s: could not register %s\n",
 			__func__, cdev->dev.bus_id);
 		put_device(&cdev->dev);
-		spin_lock_irqsave(&sch->lock, flags);
+		spin_lock_irqsave(sch->lock, flags);
 		sch->dev.driver_data = NULL;
-		spin_unlock_irqrestore(&sch->lock, flags);
+		spin_unlock_irqrestore(sch->lock, flags);
 		kfree (cdev->private);
 		kfree (cdev);
 		put_device(&sch->dev);
@@ -860,7 +860,7 @@
 
 	sch->dev.driver_data = cdev;
 	sch->driver = &io_subchannel_driver;
-	cdev->ccwlock = &sch->lock;
+	cdev->ccwlock = sch->lock;
 
 	/* Init private data. */
 	priv = cdev->private;
@@ -880,9 +880,9 @@
 	atomic_inc(&ccw_device_init_count);
 
 	/* Start async. device sensing. */
-	spin_lock_irq(&sch->lock);
+	spin_lock_irq(sch->lock);
 	rc = ccw_device_recognition(cdev);
-	spin_unlock_irq(&sch->lock);
+	spin_unlock_irq(sch->lock);
 	if (rc) {
 		if (atomic_dec_and_test(&ccw_device_init_count))
 			wake_up(&ccw_device_init_wq);
@@ -924,9 +924,9 @@
 
 	rc = io_subchannel_recog(cdev, sch);
 	if (rc) {
-		spin_lock_irqsave(&sch->lock, flags);
+		spin_lock_irqsave(sch->lock, flags);
 		sch->dev.driver_data = NULL;
-		spin_unlock_irqrestore(&sch->lock, flags);
+		spin_unlock_irqrestore(sch->lock, flags);
 		if (cdev->dev.release)
 			cdev->dev.release(&cdev->dev);
 	}
@@ -1036,6 +1036,13 @@
 static struct ccw_device_private console_private;
 static int console_cdev_in_use;
 
+static DEFINE_SPINLOCK(ccw_console_lock);
+
+spinlock_t * cio_get_console_lock(void)
+{
+	return &ccw_console_lock;
+}
+
 static int
 ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch)
 {
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index b39c1fa..d269607 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -316,9 +316,9 @@
 			ccw_device_set_timeout(cdev, 0);
 		if (ret == -EBUSY) {
 			/* Try again later. */
-			spin_unlock_irq(&sch->lock);
+			spin_unlock_irq(sch->lock);
 			msleep(10);
-			spin_lock_irq(&sch->lock);
+			spin_lock_irq(sch->lock);
 			continue;
 		}
 		if (ret != 0)
@@ -326,12 +326,12 @@
 			break;
 		/* Wait for end of request. */
 		cdev->private->intparm = magic;
-		spin_unlock_irq(&sch->lock);
+		spin_unlock_irq(sch->lock);
 		wait_event(cdev->private->wait_q,
 			   (cdev->private->intparm == -EIO) ||
 			   (cdev->private->intparm == -EAGAIN) ||
 			   (cdev->private->intparm == 0));
-		spin_lock_irq(&sch->lock);
+		spin_lock_irq(sch->lock);
 		/* Check at least for channel end / device end */
 		if (cdev->private->intparm == -EIO) {
 			/* Non-retryable error. */
@@ -342,9 +342,9 @@
 			/* Success. */
 			break;
 		/* Try again later. */
-		spin_unlock_irq(&sch->lock);
+		spin_unlock_irq(sch->lock);
 		msleep(10);
-		spin_lock_irq(&sch->lock);
+		spin_lock_irq(sch->lock);
 	} while (1);
 
 	return ret;
@@ -389,7 +389,7 @@
 		return ret;
 	}
 
-	spin_lock_irq(&sch->lock);
+	spin_lock_irq(sch->lock);
 	/* Save interrupt handler. */
 	handler = cdev->handler;
 	/* Temporarily install own handler. */
@@ -406,7 +406,7 @@
 
 	/* Restore interrupt handler. */
 	cdev->handler = handler;
-	spin_unlock_irq(&sch->lock);
+	spin_unlock_irq(sch->lock);
 
 	clear_normalized_cda (rdc_ccw);
 	kfree(rdc_ccw);
@@ -463,7 +463,7 @@
 	rcd_ccw->count = ciw->count;
 	rcd_ccw->flags = CCW_FLAG_SLI;
 
-	spin_lock_irq(&sch->lock);
+	spin_lock_irq(sch->lock);
 	/* Save interrupt handler. */
 	handler = cdev->handler;
 	/* Temporarily install own handler. */
@@ -480,7 +480,7 @@
 
 	/* Restore interrupt handler. */
 	cdev->handler = handler;
-	spin_unlock_irq(&sch->lock);
+	spin_unlock_irq(sch->lock);
 
  	/*
  	 * on success we update the user input parms
@@ -537,7 +537,7 @@
 		kfree(buf);
 		return -ENOMEM;
 	}
-	spin_lock_irqsave(&sch->lock, flags);
+	spin_lock_irqsave(sch->lock, flags);
 	ret = cio_enable_subchannel(sch, 3);
 	if (ret)
 		goto out_unlock;
@@ -559,9 +559,9 @@
 		goto out_unlock;
 	}
 	cdev->private->irb.scsw.actl |= SCSW_ACTL_START_PEND;
-	spin_unlock_irqrestore(&sch->lock, flags);
+	spin_unlock_irqrestore(sch->lock, flags);
 	wait_event(cdev->private->wait_q, cdev->private->irb.scsw.actl == 0);
-	spin_lock_irqsave(&sch->lock, flags);
+	spin_lock_irqsave(sch->lock, flags);
 	cio_disable_subchannel(sch); //FIXME: return code?
 	if ((cdev->private->irb.scsw.dstat !=
 	     (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
@@ -572,7 +572,7 @@
 out_unlock:
 	kfree(buf);
 	kfree(buf2);
-	spin_unlock_irqrestore(&sch->lock, flags);
+	spin_unlock_irqrestore(sch->lock, flags);
 	return ret;
 }