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

Tape driver changes:
 - Add missing break in tape_34xx_work_handler to avoid misleading message.
 - Cleanup offline/remove code.


---

 25-akpm/drivers/s390/char/tape_34xx.c  |    5 -
 25-akpm/drivers/s390/char/tape_class.c |    6 -
 25-akpm/drivers/s390/char/tape_core.c  |  112 +++++++++++++++++++++------------
 3 files changed, 78 insertions(+), 45 deletions(-)

diff -puN drivers/s390/char/tape_34xx.c~s390-3-12-tape-driver-fixes drivers/s390/char/tape_34xx.c
--- 25/drivers/s390/char/tape_34xx.c~s390-3-12-tape-driver-fixes	2004-04-08 13:55:03.125549016 -0700
+++ 25-akpm/drivers/s390/char/tape_34xx.c	2004-04-08 13:55:03.133547800 -0700
@@ -113,6 +113,7 @@ tape_34xx_work_handler(void *data)
 	switch(p->op) {
 		case TO_MSEN:
 			tape_34xx_medium_sense(p->device);
+			break;
 		default:
 			DBF_EVENT(3, "T34XX: internal error: unknown work\n");
 	}
@@ -1342,7 +1343,7 @@ tape_34xx_init (void)
 {
 	int rc;
 
-	DBF_EVENT(3, "34xx init: $Revision: 1.19 $\n");
+	DBF_EVENT(3, "34xx init: $Revision: 1.20 $\n");
 	/* Register driver for 3480/3490 tapes. */
 	rc = ccw_driver_register(&tape_34xx_driver);
 	if (rc)
@@ -1361,7 +1362,7 @@ tape_34xx_exit(void)
 MODULE_DEVICE_TABLE(ccw, tape_34xx_ids);
 MODULE_AUTHOR("(C) 2001-2002 IBM Deutschland Entwicklung GmbH");
 MODULE_DESCRIPTION("Linux on zSeries channel attached 3480 tape "
-		   "device driver ($Revision: 1.19 $)");
+		   "device driver ($Revision: 1.20 $)");
 MODULE_LICENSE("GPL");
 
 module_init(tape_34xx_init);
diff -puN drivers/s390/char/tape_class.c~s390-3-12-tape-driver-fixes drivers/s390/char/tape_class.c
--- 25/drivers/s390/char/tape_class.c~s390-3-12-tape-driver-fixes	2004-04-08 13:55:03.127548712 -0700
+++ 25-akpm/drivers/s390/char/tape_class.c	2004-04-08 13:55:03.133547800 -0700
@@ -1,6 +1,6 @@
 /*
  * (C) Copyright IBM Corp. 2004
- * tape_class.c ($Revision: 1.6 $)
+ * tape_class.c ($Revision: 1.8 $)
  *
  * Tape class device support
  *
@@ -12,7 +12,7 @@
 MODULE_AUTHOR("Stefan Bader <shbader@de.ibm.com>");
 MODULE_DESCRIPTION(
 	"(C) Copyright IBM Corp. 2004   All Rights Reserved.\n"
-	"tape_class.c ($Revision: 1.6 $)"
+	"tape_class.c ($Revision: 1.8 $)"
 );
 MODULE_LICENSE("GPL");
 
@@ -85,7 +85,7 @@ struct tape_class_device *register_tape_
 	return tcd;
 
 fail_with_cdev:
-	cdev_del(&tcd->char_device);
+	cdev_del(tcd->char_device);
 
 fail_with_tcd:
 	kfree(tcd);
diff -puN drivers/s390/char/tape_core.c~s390-3-12-tape-driver-fixes drivers/s390/char/tape_core.c
--- 25/drivers/s390/char/tape_core.c~s390-3-12-tape-driver-fixes	2004-04-08 13:55:03.128548560 -0700
+++ 25-akpm/drivers/s390/char/tape_core.c	2004-04-08 13:55:03.135547496 -0700
@@ -377,6 +377,16 @@ out:
 	return rc;
 }
 
+static inline void
+tape_cleanup_device(struct tape_device *device)
+{
+	tapeblock_cleanup_device(device);
+	tapechar_cleanup_device(device);
+	device->discipline->cleanup_device(device);
+	tape_remove_minor(device);
+	tape_med_state_set(device, MS_UNKNOWN);
+}
+
 /*
  * Set device offline.
  *
@@ -399,12 +409,13 @@ tape_generic_offline(struct tape_device 
 	switch (device->tape_state) {
 		case TS_INIT:
 		case TS_NOT_OPER:
+			spin_unlock_irq(get_ccwdev_lock(device->cdev));
 			break;
 		case TS_UNUSED:
-			tapeblock_cleanup_device(device);
-			tapechar_cleanup_device(device);
-			device->discipline->cleanup_device(device);
-			tape_remove_minor(device);
+			tape_state_set(device, TS_INIT);
+			spin_unlock_irq(get_ccwdev_lock(device->cdev));
+			tape_cleanup_device(device);
+			break;
 		default:
 			DBF_EVENT(3, "(%08x): Set offline failed "
 				"- drive in use.\n",
@@ -415,9 +426,6 @@ tape_generic_offline(struct tape_device 
 			spin_unlock_irq(get_ccwdev_lock(device->cdev));
 			return -EBUSY;
 	}
-	spin_unlock_irq(get_ccwdev_lock(device->cdev));
-
-	tape_med_state_set(device, MS_UNKNOWN);
 
 	DBF_LH(3, "(%08x): Drive set offline.\n", device->cdev_id);
 	return 0;
@@ -543,26 +551,12 @@ tape_generic_probe(struct ccw_device *cd
 	return 0;
 }
 
-/*
- * Driverfs tape remove function.
- *
- * This function is called whenever the common I/O layer detects the device
- * gone. This can happen at any time and we cannot refuse.
- */
-void
-tape_generic_remove(struct ccw_device *cdev)
+static inline void
+__tape_discard_requests(struct tape_device *device)
 {
-	struct tape_device *	device;
 	struct tape_request *	request;
 	struct list_head *	l, *n;
 
-	device = cdev->dev.driver_data;
-	DBF_LH(3, "(%08x): tape_generic_remove(%p)\n", device->cdev_id, cdev);
-
-	/*
-	 * No more requests may be processed. So just post them as i/o errors.
-	 */
-	spin_lock_irq(get_ccwdev_lock(device->cdev));
 	list_for_each_safe(l, n, &device->req_queue) {
 		request = list_entry(l, struct tape_request, list);
 		if (request->status == TAPE_REQUEST_IN_IO)
@@ -575,28 +569,66 @@ tape_generic_remove(struct ccw_device *c
 		if (request->callback != NULL)
 			request->callback(request, request->callback_data);
 	}
+}
 
-	if (device->tape_state != TS_UNUSED && device->tape_state != TS_INIT) {
-		DBF_EVENT(3, "(%08x): Drive in use vanished!\n",
-			device->cdev_id);
-		PRINT_WARN("(%s): Drive in use vanished - expect trouble!\n",
-			device->cdev->dev.bus_id);
-		PRINT_WARN("State was %i\n", device->tape_state);
-		device->tape_state = TS_NOT_OPER;
-		tapeblock_cleanup_device(device);
-		tapechar_cleanup_device(device);
-		device->discipline->cleanup_device(device);
-		tape_remove_minor(device);
+/*
+ * Driverfs tape remove function.
+ *
+ * This function is called whenever the common I/O layer detects the device
+ * gone. This can happen at any time and we cannot refuse.
+ */
+void
+tape_generic_remove(struct ccw_device *cdev)
+{
+	struct tape_device *	device;
+
+	device = cdev->dev.driver_data;
+	if (!device) {
+		PRINT_ERR("No device pointer in tape_generic_remove!\n");
+		return;
+	}
+	DBF_LH(3, "(%08x): tape_generic_remove(%p)\n", device->cdev_id, cdev);
+
+	spin_lock_irq(get_ccwdev_lock(device->cdev));
+	switch (device->tape_state) {
+		case TS_INIT:
+			tape_state_set(device, TS_NOT_OPER);
+		case TS_NOT_OPER:
+			/*
+			 * Nothing to do.
+			 */
+			spin_unlock_irq(get_ccwdev_lock(device->cdev));
+			break;
+		case TS_UNUSED:
+			/*
+			 * Need only to release the device.
+			 */
+			tape_state_set(device, TS_NOT_OPER);
+			spin_unlock_irq(get_ccwdev_lock(device->cdev));
+			tape_cleanup_device(device);
+			break;
+		default:
+			/*
+			 * There may be requests on the queue. We will not get
+			 * an interrupt for a request that was running. So we
+			 * just post them all as I/O errors.
+			 */
+			DBF_EVENT(3, "(%08x): Drive in use vanished!\n",
+				device->cdev_id);
+			PRINT_WARN("(%s): Drive in use vanished - "
+				"expect trouble!\n",
+				device->cdev->dev.bus_id);
+			PRINT_WARN("State was %i\n", device->tape_state);
+			tape_state_set(device, TS_NOT_OPER);
+			__tape_discard_requests(device);
+			spin_unlock_irq(get_ccwdev_lock(device->cdev));
+			tape_cleanup_device(device);
 	}
-	device->tape_state = TS_NOT_OPER;
-	tape_med_state_set(device, MS_UNKNOWN);
-	spin_unlock_irq(get_ccwdev_lock(device->cdev));
 
 	if (cdev->dev.driver_data != NULL) {
 		sysfs_remove_group(&cdev->dev.kobj, &tape_attr_group);
 		cdev->dev.driver_data = tape_put_device(cdev->dev.driver_data);
 	}
-
 }
 
 /*
@@ -1149,7 +1181,7 @@ tape_init (void)
 #ifdef DBF_LIKE_HELL
 	debug_set_level(tape_dbf_area, 6);
 #endif
-	DBF_EVENT(3, "tape init: ($Revision: 1.48 $)\n");
+	DBF_EVENT(3, "tape init: ($Revision: 1.49 $)\n");
 	tape_proc_init();
 	tapechar_init ();
 	tapeblock_init ();
@@ -1174,7 +1206,7 @@ tape_exit(void)
 MODULE_AUTHOR("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte and "
 	      "Michael Holzheu (cotte@de.ibm.com,holzheu@de.ibm.com)");
 MODULE_DESCRIPTION("Linux on zSeries channel attached "
-		   "tape device driver ($Revision: 1.48 $)");
+		   "tape device driver ($Revision: 1.49 $)");
 MODULE_LICENSE("GPL");
 
 module_init(tape_init);

_