public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH][2.5.21] s390 tape fixes.
@ 2002-06-13 23:43 Martin Schwidefsky
  0 siblings, 0 replies; only message in thread
From: Martin Schwidefsky @ 2002-06-13 23:43 UTC (permalink / raw)
  To: linux-kernel; +Cc: torvalds

Hi,
the new tape driver in 2.5.21 is a more or less 1:1 copy of the 2.4 code.
To get it to work some adaptions are needed. Here they are.

blue skies,
  Martin.


diff -urN linux-2.5.21/drivers/s390/char/tape.c linux-2.5.21-s390/drivers/s390/char/tape.c
--- linux-2.5.21/drivers/s390/char/tape.c	Sun Jun  9 07:30:37 2002
+++ linux-2.5.21-s390/drivers/s390/char/tape.c	Tue Jun 11 18:43:32 2002
@@ -47,7 +47,9 @@
 #define TAPE_NO_IO          0
 #define TAPE_DO_IO          1
 
-#define TAPE_CIO_PRIVATE_DATA
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,16))
+	#define TAPE_CIO_PRIVATE_DATA
+#endif
 
 #ifdef CONFIG_KMOD
 #define tape_request_module(a) request_module(a)
@@ -142,9 +144,12 @@
 	"WTM",
 	"MSN",
 	"LOA",
-	"RCF", /* 3590 */
-	"RAT", /* 3590 */
-	"NOT"
+	"RCF",
+	"RAT",
+	"NOT",
+	"DIS",
+	"ASS",
+	"UAS"
 };
 
 /*******************************************************************
@@ -204,12 +209,21 @@
 	release:tape_proc_devices_release,	/* close */
 };
 
+static struct inode_operations tape_proc_devices_inode_ops =
+{
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+	default_file_ops:&tape_proc_devices_file_ops		/* file ops */
+#endif				/* LINUX_IS_24 */
+};
+
+
 /* 
  * Initialize procfs stuff on startup
  */
 
 static inline void
 tape_proc_init (void) {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 	tape_proc_devices = create_proc_entry ("tapedevices",
 						S_IFREG | S_IRUGO | S_IWUSR,
 						&proc_root);
@@ -217,6 +231,24 @@
 	        goto error;
 	tape_proc_devices->proc_fops = &tape_proc_devices_file_ops;
 	tape_proc_devices->proc_iops = &tape_proc_devices_inode_ops;
+#else
+	tape_proc_devices = (struct proc_dir_entry *) kmalloc 
+            (sizeof (struct proc_dir_entry), GFP_ATOMIC);
+	if (tape_proc_devices == NULL) 
+	        goto error;
+	memset (tape_proc_devices, 0, sizeof (struct proc_dir_entry));
+	tape_proc_devices->name = "tapedevices";
+	tape_proc_devices->namelen = strlen ("tapedevices");
+	tape_proc_devices->low_ino = 0;
+	tape_proc_devices->mode = (S_IFREG | S_IRUGO | S_IWUSR);
+	tape_proc_devices->nlink = 1;
+	tape_proc_devices->uid = 0;
+	tape_proc_devices->gid = 0;
+	tape_proc_devices->size = 0;
+	tape_proc_devices->get_info = NULL;
+	tape_proc_devices->ops = &tape_proc_devices_inode_ops;
+	proc_register (&proc_root, tape_proc_devices);
+#endif
 	return;
  error:
 	PRINT_WARN ("tape: Cannot register procfs entry tapedevices\n");
@@ -359,8 +391,14 @@
 static inline void
 tape_proc_cleanup (void)
 {
-        if (tape_proc_devices != NULL)
+        if (tape_proc_devices != NULL){
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 		remove_proc_entry ("tapedevices", &proc_root);
+#else
+		proc_unregister (&proc_root, tape_proc_devices->low_ino);
+		kfree (tape_proc_devices);
+#endif /* LINUX_IS_24 */
+	}
 }
 
 #endif /* CONFIG_PROC_FS */
@@ -384,12 +422,12 @@
         wake_up_interruptible(&treq->wq);
 }
  
-#ifdef CONFIG_S390_TAPE_BLOCK
 static void tape_schedule_tapeblock(tape_ccw_req_t* treq){
         treq->wakeup = NULL;
+#ifdef CONFIG_S390_TAPE_BLOCK
         tapeblock_schedule_exec_io((tape_dev_t*)(treq->tape_dev));;
-}
 #endif
+}
  
 static void tape_wait_event(tape_ccw_req_t* treq){
         wait_event (treq->wq,(treq->wakeup == NULL));
@@ -400,9 +438,9 @@
 	if (signal_pending (current)) {
 		treq->rc = tape_halt_io(treq->tape_dev);
 		if(treq->rc == -ERESTARTSYS)
-		        PRINT_INFO("IO stopped on irq %d\n",treq->tape_dev->devinfo.irq); /* FIXME: only put into dbf */
+		        tape_sprintf_event(tape_dbf_area, 3, "IO stopped on irq %d\n", treq->tape_dev->devinfo.irq);
                 else if(treq->rc == 0)
-		        PRINT_INFO("could not stop IO,irq was faster on irq %d\n",treq->tape_dev->devinfo.irq); /* FIXME: only put into dbf */
+		        tape_sprintf_event(tape_dbf_area, 3, "could not stop IO,irq was faster on irq %d\n", treq->tape_dev->devinfo.irq);
                 else
 			PRINT_WARN("IO error while stopping IO on irq %d\n",treq->tape_dev->devinfo.irq);
 	}
@@ -632,7 +670,9 @@
 	return 1;
 }
 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,99))
 __setup("tape=", tape_parm_call_setup);
+#endif   /* kernel >2.3.99 */
 #endif   /* not defined MODULE */
 
 
@@ -736,9 +776,8 @@
 	}
 		
 	for (frontend=tape_first_front;frontend!=NULL;frontend=frontend->next){
-		if(frontend->mkdevfstree(td) == NULL){
+		if(frontend->setup_device(td) != 0)
 			goto out_undo;
-		}
 	}
 #endif
 #ifdef TAPE_CIO_PRIVATE_DATA
@@ -771,7 +810,7 @@
 	free_irq (td->devinfo.irq, &(td->devstat)); 
 #ifdef CONFIG_DEVFS_FS
         for (frontend=tape_first_front;frontend!=NULL;frontend=frontend->next)
-                frontend->rmdevfstree(td);
+                frontend->cleanup_device(td);
         tape_rmdevfsroot(td);
 #endif
 	tape_state_set(td,TS_NOT_OPER);
@@ -1007,8 +1046,8 @@
 			/* Wrong type - try next one */
 			continue;
 
-		tape_sprintf_event (tape_dbf_area,3,"det irq:  %x\n",irq);
-		tape_sprintf_event (tape_dbf_area,3,"cu     :  %x\n",disc->cu_type);
+		tape_sprintf_event (tape_dbf_area, 4, "det irq:  %x\n", irq);
+		tape_sprintf_event (tape_dbf_area, 4, "cu     :  %x\n", disc->cu_type);
 
 
 		if(!tape_autoprobe) {
@@ -1219,13 +1258,13 @@
 			rc = -ERESTARTSYS;
 			goto out;
 		case -ENODEV:
-		        PRINT_INFO ("device gone, retry\n"); /* FIXME: s390dbf only */
+		        tape_sprintf_exception(tape_dbf_area, 2, "device gone, retry\n");
 			break;
 		case -EIO:
-			PRINT_INFO ("I/O error, retry\n"); /* FIXME: s390dbf only */
+			tape_sprintf_exception(tape_dbf_area, 2, "I/O error, retry\n");
 			break;
 		case -EBUSY:
-			PRINT_INFO ( "device busy, retry later\n"); /* FIXME: s390dbf only */
+			tape_sprintf_exception(tape_dbf_area, 2, "device busy, retry later\n");
 			break;
 		default:
 			PRINT_ERR ( "line %d unknown RC=%d, please report"
@@ -1709,9 +1748,9 @@
 
 	tape_init_devregs();
 #ifdef TAPE_DEBUG
-        tape_dbf_area = debug_register ( "tape", 2, 2, 3*sizeof(long));
+        tape_dbf_area = debug_register ( "tape", 1, 2, 3*sizeof(long));
         debug_register_view(tape_dbf_area,&debug_sprintf_view);
-        tape_sprintf_event (tape_dbf_area,3,"begin init\n");
+        tape_sprintf_event (tape_dbf_area,3,"begin init: ($Revision: 1.87 $)\n");
 #endif /* TAPE_DEBUG */
 	tape_print_banner();
 #ifndef MODULE
@@ -1720,7 +1759,6 @@
 #ifdef CONFIG_DEVFS_FS
         tape_devfs_root_entry=devfs_mk_dir (NULL, "tape", NULL);
 #endif /* CONFIG_DEVFS_FS */
-
         tape_sprintf_event (tape_dbf_area,3,"dev detect\n");
 	/* Allocate the tape structures */
         if (*tape!=NULL) { /* if parameters are present */
@@ -1766,7 +1804,7 @@
 
 #ifdef MODULE
 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");
+MODULE_DESCRIPTION("Linux on zSeries channel attached tape device driver ($Revision: 1.87 $)");
 MODULE_PARM (tape, "1-" __MODULE_STRING (256) "s");
 
 /*
@@ -1820,7 +1858,7 @@
 	tape_cleanup_disciplines();
 #ifdef CONFIG_DEVFS_FS
 	devfs_unregister (tape_devfs_root_entry); /* devfs checks for NULL */
-#endif CONFIG_DEVFS_FS
+#endif /* CONFIG_DEVFS_FS */
 #ifdef CONFIG_PROC_FS
 	tape_proc_cleanup();
 #endif 
@@ -1879,7 +1917,7 @@
 		case MS_LOADED:
 			PRINT_INFO("(%x): Tape has been mounted\n",td->devstat.devno);
 			break;
-		default:
+		default: 
 			// print nothing
 			break;
 	}
diff -urN linux-2.5.21/drivers/s390/char/tape.h linux-2.5.21-s390/drivers/s390/char/tape.h
--- linux-2.5.21/drivers/s390/char/tape.h	Sun Jun  9 07:30:53 2002
+++ linux-2.5.21-s390/drivers/s390/char/tape.h	Tue Jun 11 18:43:32 2002
@@ -94,10 +94,12 @@
 	TO_WTM,
 	TO_MSEN,
 	TO_LOAD,
-	TO_READ_CONFIG, /* 3590 */
-	TO_READ_ATTMSG, /* 3590 */
+	TO_READ_CONFIG,
+	TO_READ_ATTMSG,
 	TO_NOTHING,
 	TO_DIS,
+	TO_ASSIGN,
+	TO_UNASSIGN,
 	TO_SIZE
 } tape_op_t;
 
@@ -142,6 +144,8 @@
 typedef int (*tape_setup_device_t) (struct _tape_dev_t*);
 typedef void (*tape_cleanup_device_t) (struct _tape_dev_t*);
 typedef int (*tape_disc_ioctl_overl_t)(struct _tape_dev_t*, unsigned int,unsigned long);
+typedef tape_ccw_req_t* (*tape_assign_dev_t)(struct _tape_dev_t*);
+typedef tape_ccw_req_t* (*tape_unassign_dev_t)(struct _tape_dev_t*);
 #ifdef CONFIG_DEVFS_FS
 typedef devfs_handle_t (*tape_devfs_constructor_t) (struct _tape_dev_t*);
 typedef void (*tape_devfs_destructor_t) (struct _tape_dev_t*);
@@ -165,17 +169,16 @@
 	tape_reqgen_ioctl_t         ioctl;
 	tape_disc_shutdown_t        shutdown;
 	tape_disc_ioctl_overl_t     discipline_ioctl_overload;
+        tape_assign_dev_t           assign;
+        tape_unassign_dev_t         unassign;
 	void*                       next;
 } tape_discipline_t  __attribute__ ((aligned(8)));
 
 /* Frontend */
 
 typedef struct _tape_frontend_t {
-	tape_setup_device_t device_setup;
-#ifdef CONFIG_DEVFS_FS
-	tape_devfs_constructor_t mkdevfstree;
-	tape_devfs_destructor_t rmdevfstree;
-#endif
+	tape_setup_device_t setup_device;
+	tape_cleanup_device_t cleanup_device;
 	void* next;
 } tape_frontend_t  __attribute__ ((aligned(8)));
 
@@ -194,6 +197,7 @@
 
 typedef struct _tape_blk_front_data_t{
 	request_queue_t request_queue;
+	spinlock_t request_queue_lock;
 	struct request* current_request;
 	int blk_retries;
 	long position;
@@ -215,6 +219,7 @@
 	struct file *filp;             /* backpointer to file structure */
 	int tape_state;                /* State of the device. See tape_stat */
 	int medium_state;              /* loaded, unloaded, unkown etc. */
+        int assigned;                  /* for reserve on open */
 	tape_discipline_t* discipline; /* The used discipline */
 	void* discdata;                /* discipline specific data */
 	tape_ccw_req_t* treq;          /* Active Tape request */
diff -urN linux-2.5.21/drivers/s390/char/tape3480.c linux-2.5.21-s390/drivers/s390/char/tape3480.c
--- linux-2.5.21/drivers/s390/char/tape3480.c	Sun Jun  9 07:27:21 2002
+++ linux-2.5.21-s390/drivers/s390/char/tape3480.c	Tue Jun 11 18:43:32 2002
@@ -18,6 +18,15 @@
 #include "tape34xx.h"
 #include "tape3480.h"
 
+#ifdef  TAPE_DEBUG
+#ifdef  MODULE
+#define TAPE_DBF (tape_dbf_3480)
+        debug_info_t *tape_dbf_3480 = NULL;
+#else
+#define TAPE_DBF (tape_dbf_area)
+#endif  /* MODULE */
+#endif  /* TAPE_DEBUG */
+
 #ifdef CONFIG_S390_TAPE_3480_MODULE
 static tape_discipline_t* disc;
 
@@ -36,14 +45,25 @@
 		tape_unregister_discipline(disc);
 		kfree(disc);
 	}
+#ifdef TAPE_DEBUG
+#ifdef MODULE
+       debug_unregister(tape_dbf_3480);
+#endif /* MODULE */
+#endif /* TAPE_DEBUG */
 }
+
+#ifdef MODULE
+MODULE_AUTHOR("(C) 2001-2002 IBM Deutschland Entwicklung GmbH");
+MODULE_DESCRIPTION("Linux on zSeries channel attached 3480 tape device driver ($Revision: 1.30 $)");
+#endif /* MODULE */
+
 #endif /* CONFIG_S390_TAPE_3480_MODULE */
 
 int
 tape3480_setup_device(tape_dev_t * td)
 {
 	tape3480_disc_data_t *data = NULL;
-	tape_sprintf_event (tape_dbf_area,6,"3480 dsetup:  %x\n",td->first_minor);
+	tape_sprintf_event (TAPE_DBF, 6, "3480 minor1: %x\n", td->first_minor);
 	data = kmalloc (sizeof (tape3480_disc_data_t), GFP_KERNEL | GFP_DMA);
 	if(data == NULL)
 		return -1;
@@ -69,10 +89,16 @@
 tape3480_init (void)
 {
 	tape_discipline_t *disc;
-	tape_sprintf_event (tape_dbf_area,3,"3480 init\n");
+#ifdef TAPE_DEBUG
+#ifdef MODULE
+        tape_dbf_3480 = debug_register("tape3480", 1, 2, 3*sizeof(long));
+        debug_register_view(tape_dbf_3480, &debug_sprintf_view);
+#endif /* MODULE */
+#endif /* TAPE_DEBUG */
+	tape_sprintf_event (TAPE_DBF,3,"3480 init: $Revision: 1.30 $\n");
 	disc = kmalloc (sizeof (tape_discipline_t), GFP_ATOMIC);
 	if (disc == NULL) {
-	        tape_sprintf_exception (tape_dbf_area,3,"disc:nomem\n");
+	        tape_sprintf_exception (TAPE_DBF,3,"disc:nomem\n");
 		return disc;
 	}
 	disc->owner = THIS_MODULE;
@@ -90,7 +116,9 @@
 	disc->bread = tape34xx_bread;
 	disc->free_bread = tape34xx_free_bread;
 	disc->bread_enable_locate = tape34xx_bread_enable_locate;
+	disc->assign = tape34xx_assign;
+	disc->unassign = tape34xx_unassign;
 	disc->next = NULL;
-	tape_sprintf_event (tape_dbf_area,3,"3480 regis\n");
+	tape_sprintf_event (TAPE_DBF,3,"3480 registered\n");
 	return disc;
 }
diff -urN linux-2.5.21/drivers/s390/char/tape3490.c linux-2.5.21-s390/drivers/s390/char/tape3490.c
--- linux-2.5.21/drivers/s390/char/tape3490.c	Sun Jun  9 07:31:25 2002
+++ linux-2.5.21-s390/drivers/s390/char/tape3490.c	Tue Jun 11 18:43:32 2002
@@ -18,6 +18,15 @@
 #include "tape34xx.h"
 #include "tape3490.h"
 
+#ifdef  TAPE_DEBUG
+#ifdef  MODULE
+#define TAPE_DBF (tape_dbf_3490)
+        debug_info_t *tape_dbf_3490 = NULL;
+#else
+#define TAPE_DBF (tape_dbf_area)
+#endif  /* MODULE */
+#endif  /* TAPE_DEBUG */
+
 #ifdef CONFIG_S390_TAPE_3490_MODULE 
 static tape_discipline_t* disc;
 
@@ -36,14 +45,25 @@
 		tape_unregister_discipline(disc);
 		kfree(disc);
 	}
+#ifdef TAPE_DEBUG
+#ifdef MODULE
+       debug_unregister(tape_dbf_3490);
+#endif /* MODULE */
+#endif /* TAPE_DEBUG */
 }
+
+#ifdef MODULE
+MODULE_AUTHOR("(C) 2001-2002 IBM Deutschland Entwicklung GmbH");
+MODULE_DESCRIPTION("Linux on zSeries channel attached 3490 tape device driver ($Revision: 1.34 $)");
+#endif /* MODULE */
+
 #endif /* CONFIG_S390_TAPE_3490_MODULE */
 
 int
 tape3490_setup_device (tape_dev_t * td)
 {
 	tape3490_disc_data_t *data = NULL;
-	tape_sprintf_event (tape_dbf_area,1,"3490 dsetup: %x\n",td->first_minor);
+	tape_sprintf_event (TAPE_DBF, 6, "3490 minor1: %x\n", td->first_minor);
 	data = kmalloc (sizeof (tape3490_disc_data_t), GFP_KERNEL | GFP_DMA);
 	if(data == NULL)
 		return -1;
@@ -70,10 +90,16 @@
 tape3490_init (void)
 {
 	tape_discipline_t *disc;
-	tape_sprintf_event (tape_dbf_area,3,"3490 init\n");
+#ifdef TAPE_DEBUG
+#ifdef MODULE
+        tape_dbf_3490 = debug_register("tape3490", 1, 2, 3*sizeof(long));
+        debug_register_view(tape_dbf_3490, &debug_sprintf_view);
+#endif /* MODULE */
+#endif /* TAPE_DEBUG */
+	tape_sprintf_event (TAPE_DBF,3,"3490 init: $Revision: 1.34 $\n");
 	disc = kmalloc (sizeof (tape_discipline_t), GFP_ATOMIC);
 	if (disc == NULL) {
-	        tape_sprintf_exception (tape_dbf_area,3,"disc:nomem\n");
+	        tape_sprintf_exception (TAPE_DBF,3,"disc:nomem\n");
 		return disc;
 	}
 	disc->owner = THIS_MODULE;
@@ -91,7 +117,9 @@
 	disc->bread = tape34xx_bread;
 	disc->free_bread = tape34xx_free_bread;
 	disc->bread_enable_locate = tape34xx_bread_enable_locate;
+	disc->assign = tape34xx_assign;
+	disc->unassign = tape34xx_unassign;
 	disc->next = NULL;
-	tape_sprintf_event (tape_dbf_area,3,"3490 regis\n");
+	tape_sprintf_event (TAPE_DBF,3,"3490 registered\n");
 	return disc;
 }
diff -urN linux-2.5.21/drivers/s390/char/tape34xx.c linux-2.5.21-s390/drivers/s390/char/tape34xx.c
--- linux-2.5.21/drivers/s390/char/tape34xx.c	Sun Jun  9 07:27:22 2002
+++ linux-2.5.21-s390/drivers/s390/char/tape34xx.c	Wed Jun 12 14:32:25 2002
@@ -21,6 +21,7 @@
 #include <linux/compatmac.h>
 #include "tape.h"
 #include "tape34xx.h"
+#include "tapeblock.h"
 #include <asm/idals.h>
 #include <asm/ebcdic.h>
 #include <asm/tape390.h>
@@ -59,6 +60,8 @@
 			tape_med_state_set(td,MS_LOADED);
 			break;
 		case TO_NOP:
+	        case TO_ASSIGN:
+	        case TO_UNASSIGN:
 			break;
 		case TO_RUN:
 			tape_med_state_set(td,MS_UNLOADED);
@@ -102,6 +105,66 @@
         }
 }
 
+/* 
+ * tape34xx_assign
+ */
+
+tape_ccw_req_t *
+tape34xx_assign (tape_dev_t* td)
+{
+        tape_ccw_req_t *treq = NULL;
+	ccw1_t *ccw = NULL;
+	int ccw_cnt = 2;
+        int ds = 11;
+        int op = TO_ASSIGN;
+
+	treq = tape_alloc_ccw_req(ccw_cnt, ds, 0, op);
+	if (!treq) {
+	        tape_sprintf_event(tape_dbf_area, 3, "T34xx: assign failed\n");
+	        goto error;
+	}
+	ccw = treq->cpaddr;
+	ccw = tape_ccw_cc(ccw, ASSIGN, ds, treq->kernbuf, 1);
+	ccw = tape_ccw_end(ccw, NOP, 0, 0, 1);
+
+	return(treq);
+
+error:
+	if (treq)
+                tape_free_ccw_req(treq);
+	return NULL;
+}
+
+/* 
+ * tape34xx_unassign
+ */
+
+tape_ccw_req_t *
+tape34xx_unassign (tape_dev_t* td)
+{
+        tape_ccw_req_t *treq = NULL;
+	ccw1_t *ccw = NULL;
+	int ccw_cnt = 2;
+        int ds = 11;
+        int op = TO_UNASSIGN;
+
+	treq = tape_alloc_ccw_req(ccw_cnt, ds, 0, op);
+	if (!treq) {
+	        tape_sprintf_event(tape_dbf_area, 3, "T34xx: unassign failed\n");
+	        goto error;
+	}
+	ccw = treq->cpaddr;
+	ccw = tape_ccw_cc(ccw, UNASSIGN, ds, treq->kernbuf, 1);
+	ccw = tape_ccw_end(ccw, NOP, 0, 0, 1);
+
+	return(treq);
+
+error:
+	if (treq)
+                tape_free_ccw_req(treq);
+	return NULL;
+}
+
 
 /*
  * tape34xx_display 
@@ -122,15 +185,15 @@
         if (rc != 0)
                 goto error;
 
-        treq=tape_alloc_ccw_req(ccw_cnt, ds, 0, op);
+        treq = tape_alloc_ccw_req(ccw_cnt, ds, 0, op);
         if (!treq)
 	        goto error;
 
         ((unsigned char *)treq->kernbuf)[0] = d_struct.cntrl;
 
         for (i = 0; i < 8; i++) {
-                ((unsigned char *)treq->kernbuf)[i+1] = d_struct.message1[i];
-                ((unsigned char *)treq->kernbuf)[i+9] = d_struct.message2[i];
+	        ((unsigned char *)treq->kernbuf)[i+1] = d_struct.message1[i];
+	        ((unsigned char *)treq->kernbuf)[i+9] = d_struct.message2[i];
         }
 
         ASCEBC (((unsigned char*)treq->kernbuf) + 1, 16);
@@ -142,7 +205,6 @@
         tape_do_io_and_wait(td,treq,TAPE_WAIT_INTERRUPTIBLE);
     
         tape_free_ccw_req(treq);
-
         return(0);
 
  error:
@@ -363,6 +425,11 @@
 		case MTCOMPRESSION:
 			if((count < 0) || (count > 1)){
 				tape_sprintf_exception (tape_dbf_area,6,"xcom parm\n");
+				if (MOD_BYTE && 0x08)
+					PRINT_INFO("(%x) Compression is currently on\n", td->devstat.devno);
+				else
+					PRINT_INFO("(%x) Compression is currently off\n", td->devstat.devno);
+				PRINT_INFO("Use 1 to switch compression on, 0 to switch it off\n");
 				goto error;
 			}
 			if(count == 0){
@@ -510,19 +577,20 @@
 	tape_ccw_req_t *treq;
 	ccw1_t *ccw;
 	__u8 *data;
-	int s2b = blksize_size[tapeblock_major][td->first_minor]/hardsect_size[tapeblock_major][td->first_minor];
-	int realcount = 0;
-	int size,bhct = 0;
-	struct buffer_head* bh;
-	for (bh = req->bh; bh; bh = bh->b_reqnext) {
-		if (bh->b_size > blksize_size[tapeblock_major][td->first_minor])
-			for (size = 0; size < bh->b_size; size += blksize_size[tapeblock_major][td->first_minor])
-				bhct++;
-		else
-			bhct++;
-	}
+	int count = 0,realcount,i;
+	unsigned off;
+	char* dst;
+	struct bio_vec *bv;
+	struct bio *bio;
+
+        rq_for_each_bio(bio, req) {
+		bio_for_each_segment(bv, bio, i) {
+			count += bv->bv_len >> (S2B + 9);
+                }
+        }
+
 	tape_sprintf_event (tape_dbf_area,6,"xBREDid:");
-	treq = tape_alloc_ccw_req (2+bhct+1, 4,0,TO_BLOCK);
+	treq = tape_alloc_ccw_req (2+count+1, 4,0,TO_BLOCK);
 	if (!treq) {
 		tape_sprintf_exception (tape_dbf_area,6,"xBREDnomem\n");
                 goto error;
@@ -531,7 +599,7 @@
 	data = treq->kernbuf;
 	data[0] = 0x01;
 	data[1] = data[2] = data[3] = 0x00;
-	realcount=req->sector/s2b;
+	realcount=req->sector >> S2B;
 	if (MOD_BYTE & 0x08)	// IDRC on
 		data[1] = data[1] | 0x80;
 	data[3] += realcount % 256;
@@ -545,21 +613,23 @@
 		ccw = tape_ccw_cc(ccw,LOCATE,4,treq->kernbuf,1);
 	else
 		ccw = tape_ccw_cc(ccw,NOP,0,0,1);
-	td->blk_data.position=realcount+req->nr_sectors/s2b;
-	for (bh=req->bh;bh!=NULL;) {
-		if (bh->b_size >= blksize_size[tapeblock_major][td->first_minor]) {
-			for (size = 0; size < bh->b_size; size += blksize_size[tapeblock_major][td->first_minor]){
+
+	td->blk_data.position=realcount + (req->nr_sectors >> S2B);
+
+	rq_for_each_bio(bio, req) {
+                bio_for_each_segment(bv, bio, i) {
+                        dst = kmap(bv->bv_page) + bv->bv_offset;
+                        for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) {
 				ccw->flags = CCW_FLAG_CC;
 				ccw->cmd_code = READ_FORWARD;
-				ccw->count = blksize_size[tapeblock_major][td->first_minor];
-				set_normalized_cda(ccw,__pa(bh->b_data+size));
-				ccw++;
-			}
-			bh = bh->b_reqnext;
-		} else {	/* group N bhs to fit into byt_per_blk */
-		    BUG();
-		}
-	}
+				ccw->count = TAPEBLOCK_HSEC_SIZE;
+				set_normalized_cda(ccw,(void*)__pa(dst));
+                                ccw++;
+                                dst += TAPEBLOCK_HSEC_SIZE;
+                        }
+                }
+        }
+
 	ccw = tape_ccw_end(ccw,NOP,0,0,1);
 	tape_sprintf_event (tape_dbf_area,6,"xBREDccwg\n");
 	return treq;
@@ -603,7 +673,7 @@
 	tape_ccw_req_t* treq = tape_get_active_ccw_req(td);
 	tape_sprintf_event (tape_dbf_area,6,"xdefhandle\n");
 	PRINT_ERR ("TAPE34XX: An unexpected Unit Check occurred.\n");
-	PRINT_ERR ("TAPE34XX: Please read Documentation/s390/TAPE and report it!\n");
+	PRINT_ERR ("TAPE34XX: Please report it to linux390@de.ibm.com.\n");
 	PRINT_ERR ("TAPE34XX: Current op is: %s",tape_op_verbose[treq->op]);
 	tape_dump_sense (td);
 	treq->rc = -EIO;
@@ -633,28 +703,30 @@
 	tape34xx_error_recovery_has_failed(td,EIO);
 	return;
     }
-    if (sense[0]&SENSE_COMMAND_REJECT)
-	switch (treq->op) {
-	case TO_DSE:
-	case TO_EGA:
-	case TO_WRI:
-	case TO_WTM:
-	    if (sense[1]&SENSE_WRITE_PROTECT) {
-		// trying to write, but medium is write protected
-		tape34xx_error_recovery_has_failed(td,EACCES);
-		return;
-	    }
-	default:
-	    tape34xx_error_recovery_HWBUG(td,1);
-	    return;
-	}
+
+    if ((sense[0]&SENSE_COMMAND_REJECT) && (td->assigned == 0))
+	  switch (treq->op) {
+	          case TO_DSE:
+	          case TO_EGA:
+	          case TO_WRI:
+	          case TO_WTM:
+		    if (sense[1]&SENSE_WRITE_PROTECT) {
+		      // trying to write, but medium is write protected
+		      tape34xx_error_recovery_has_failed(td,EACCES);
+		      return;
+		    }
+	          default:
+		    tape34xx_error_recovery_HWBUG(td,1);
+		    return;
+	  }
+
     // special cases for various tape-states when reaching end of recorded area
     if (((sense[0]==0x08) || (sense[0]==0x10) || (sense[0]==0x12)) &&
 	((sense[1]==0x40) || (sense[1]==0x0c)))
 	switch (treq->op) {
 	case TO_FSF:
 	    // Trying to seek beyond end of recorded area
-	    tape34xx_error_recovery_has_failed(td,EIO);
+	    tape34xx_error_recovery_has_failed(td,ENOSPC);
 	    return;
 	case TO_LBL:
 	    // Block could not be located.
@@ -970,7 +1042,7 @@
 	return;
     case 0x45:
 	// The drive is assigned elsewhere [to a different channel path/computer].
-	PRINT_WARN("The drive is assigned elsewhere.\n");
+        PRINT_WARN("The drive is assigned elsewhere.\n");
 	tape34xx_error_recovery_has_failed(td,EIO);
 	return;
     case 0x46:
@@ -1013,7 +1085,7 @@
       	    tape34xx_error_recovery_HWBUG(td,21);
 	    return;
 	case 0x3490:
-	    // Resetting event received. Since the driver does not support resetting event recovery
+	    // Resetting event recieved. Since the driver does not support resetting event recovery
 	    // (which has to be handled by the I/O Layer), we'll report and retry our command.
 	    tape34xx_error_recovery_do_retry(td);
 	    return;
@@ -1080,7 +1152,7 @@
 	    return;
 	case 0x3490:
 	    // Global status intercept. We have to reissue the command.
-	    PRINT_WARN("An global status intercept was received, which will be recovered.\n");
+	    PRINT_WARN("An global status intercept was recieved, which will be recovered.\n");
 	    tape34xx_error_recovery_do_retry(td);
 	    return;
 	}
@@ -1176,12 +1248,14 @@
 void 
 tape34xx_error_recovery_HWBUG (tape_dev_t* td,int condno) {
 	tape_ccw_req_t *treq = tape_get_active_ccw_req(td);
-	PRINT_WARN("An unexpected condition #%d was caught in tape error recovery.\n",condno);
-	PRINT_WARN("Please report this incident.\n");
-	if(treq)
-	PRINT_WARN("Operation of tape:%s\n", tape_op_verbose[treq->op]);
-	tape_dump_sense(td);
-	tape34xx_error_recovery_has_failed(td,EIO);
+	if (treq->op != TO_ASSIGN) {
+	        PRINT_WARN("An unexpected condition #%d was caught in tape error recovery.\n",condno);
+		PRINT_WARN("Please report this incident.\n");
+		if(treq)
+		        PRINT_WARN("Operation of tape:%s\n", tape_op_verbose[treq->op]);
+		tape_dump_sense(td);
+	}
+	  tape34xx_error_recovery_has_failed(td,EIO);
 }
 
 /*
@@ -1251,4 +1325,6 @@
 EXPORT_SYMBOL(tape34xx_free_bread);
 EXPORT_SYMBOL(tape34xx_process_eov);
 EXPORT_SYMBOL(tape34xx_bread_enable_locate);
+EXPORT_SYMBOL(tape34xx_assign);
+EXPORT_SYMBOL(tape34xx_unassign);
 
diff -urN linux-2.5.21/drivers/s390/char/tape34xx.h linux-2.5.21-s390/drivers/s390/char/tape34xx.h
--- linux-2.5.21/drivers/s390/char/tape34xx.h	Sun Jun  9 07:30:37 2002
+++ linux-2.5.21-s390/drivers/s390/char/tape34xx.h	Tue Jun 11 18:43:32 2002
@@ -113,6 +113,8 @@
 tape_ccw_req_t * tape34xx_read_block (const char *data, size_t count, tape_dev_t* td);
 tape_ccw_req_t * tape34xx_ioctl(tape_dev_t* td, int op,int count, int* rc);
 tape_ccw_req_t * tape34xx_bread (struct request *req, tape_dev_t* td,int tapeblock_major);
+tape_ccw_req_t * tape34xx_assign(tape_dev_t* td);
+tape_ccw_req_t * tape34xx_unassign(tape_dev_t* td);
 void tape34xx_free_bread (tape_ccw_req_t* treq);
 void tape34xx_bread_enable_locate (tape_ccw_req_t * treq);
 tape_ccw_req_t * tape34xx_bwrite (struct request *req, tape_dev_t* td,int tapeblock_major);
diff -urN linux-2.5.21/drivers/s390/char/tapeblock.c linux-2.5.21-s390/drivers/s390/char/tapeblock.c
--- linux-2.5.21/drivers/s390/char/tapeblock.c	Sun Jun  9 07:29:15 2002
+++ linux-2.5.21-s390/drivers/s390/char/tapeblock.c	Wed Jun 12 14:32:25 2002
@@ -18,6 +18,7 @@
 #include <linux/blk.h>
 #include <linux/version.h>
 #include <linux/interrupt.h>
+#include <linux/buffer_head.h>
 #include <asm/debug.h>
 #include <asm/s390dyn.h>
 #include <linux/compatmac.h>
@@ -79,15 +80,44 @@
 }
 #endif
 
-void 
-tapeblock_setup(tape_dev_t* td) {
-    blk_size[tapeblock_major][td->first_minor]=0; // this will be detected
-    blk_queue_hardsect_size(&ti->request_queue, 2048);
-    blk_init_queue (&td->blk_data.request_queue, tape_request_fn); 
+static int
+tapeblock_setup_device(tape_dev_t* td) {
+	int rc = 0;	
+	rc = blk_init_queue (&td->blk_data.request_queue, tape_request_fn, &td->blk_data.request_queue_lock);
+	if(rc){
+		PRINT_ERR("blk_init_queue failed\n");
+		goto out;
+	}
+
+	elevator_exit(&td->blk_data.request_queue, &td->blk_data.request_queue.elevator);
+        rc = elevator_init(&td->blk_data.request_queue,
+                           &td->blk_data.request_queue.elevator,
+                           elevator_noop);
+        if (rc) {
+		PRINT_ERR("elevator_init failed\n");
+                blk_cleanup_queue(&td->blk_data.request_queue);
+		goto out;
+        }
+	blk_queue_hardsect_size(&td->blk_data.request_queue,TAPEBLOCK_HSEC_SIZE);
+	blk_queue_max_sectors(&td->blk_data.request_queue, -1L /* 0xffff XXX*/);
+	blk_queue_max_phys_segments(&td->blk_data.request_queue, -1L);
+	blk_queue_max_hw_segments(&td->blk_data.request_queue, -1L);
+	blk_queue_max_segment_size(&td->blk_data.request_queue, -1L);
+	blk_queue_segment_boundary(&td->blk_data.request_queue, -1L);
 #ifdef CONFIG_DEVFS_FS
-    tapeblock_mkdevfstree(td);
+	if(!tapeblock_mkdevfstree(td))
+		rc = -1;
+#endif
+out:
+	set_device_ro (mk_kdev(tapeblock_major, td->first_minor), 1);
+	return rc;
+}
+
+static void
+tapeblock_cleanup_device(tape_dev_t* td) {
+#ifdef CONFIG_DEVFS_FS
+		tapeblock_rmdevfstree(td);
 #endif
-    set_device_ro (MKDEV(tapeblock_major, td->first_minor), 1);
 }
 
 int
@@ -98,34 +128,32 @@
 	tape_init();
 	/* Register the tape major number to the kernel */
 #ifdef CONFIG_DEVFS_FS
-	result = devfs_register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops);
-#else
-	result = register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops);
+	if(tapeblock_major == 0)
+	 	tapeblock_major = devfs_alloc_major (DEVFS_SPECIAL_BLK);
+
+// XXX	result = devfs_register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops);
 #endif
+        result = register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops);
+        if(tapeblock_major == 0) {
+                tapeblock_major = result;
+        }
+
 	if (result < 0) {
 		PRINT_WARN(KERN_ERR "tape: can't get major %d for block device\n", tapeblock_major);
 		result=-ENODEV;
 		goto out;
 	}
-	if (tapeblock_major == 0) tapeblock_major = result;   /* accept dynamic major number*/
 	INIT_BLK_DEV(tapeblock_major,tape_request_fn,tapeblock_getqueue,NULL);
 	PRINT_WARN(KERN_ERR " tape gets major %d for block device\n", tapeblock_major);
 	blk_size[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_KERNEL);
 	if (blk_size[tapeblock_major]==NULL) goto out_undo_bdev;
 	memset(blk_size[tapeblock_major],0,256*sizeof(int));
-	hardsect_size[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_KERNEL);
-	if (hardsect_size[tapeblock_major]==NULL) goto out_undo_blk_size;
-	memset(hardsect_size[tapeblock_major],0,256*sizeof(int));
-	max_sectors[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_KERNEL);
-	if (max_sectors[tapeblock_major]==NULL) goto out_undo_hardsect_size;
-	memset(max_sectors[tapeblock_major],0,256*sizeof(int));
+
 	blkfront = kmalloc(sizeof(tape_frontend_t),GFP_KERNEL);
-	if (blkfront==NULL) goto out_undo_max_sectors;
-	blkfront->device_setup=(tape_setup_device_t)tapeblock_setup;
-#ifdef CONFIG_DEVFS_FS
-	blkfront->mkdevfstree = tapeblock_mkdevfstree;
-	blkfront->rmdevfstree = tapeblock_rmdevfstree;
-#endif
+	if (blkfront==NULL) 
+		goto out_undo_size;
+	blkfront->setup_device=tapeblock_setup_device;
+	blkfront->cleanup_device=tapeblock_cleanup_device;
 	blkfront->next=NULL;
 	if (tape_first_front==NULL) {
 		tape_first_front=blkfront;
@@ -137,16 +165,12 @@
 	}
 	td=tape_first_dev;
 	while (td!=NULL) {
-		tapeblock_setup(td);
+		tapeblock_setup_device(td);
 		td=td->next;
 	}
 	result=0;
 	goto out;
-out_undo_max_sectors:
-	kfree(max_sectors[tapeblock_major]);
-out_undo_hardsect_size:
-	kfree(hardsect_size[tapeblock_major]);
-out_undo_blk_size:
+out_undo_size:
 	kfree(blk_size[tapeblock_major]);
 out_undo_bdev:
 #ifdef CONFIG_DEVFS_FS
@@ -155,9 +179,6 @@
 	unregister_blkdev(tapeblock_major, "tBLK");
 #endif
 	result=-ENOMEM;
-	blk_size[tapeblock_major]=
-	hardsect_size[tapeblock_major]=
-	max_sectors[tapeblock_major]=NULL;
 	tapeblock_major=-1;    
 out:
 	return result;
@@ -168,19 +189,8 @@
 tapeblock_uninit(void) {
 	if (tapeblock_major==-1)
 	        goto out; /* init failed so there is nothing to clean up */
-	if (blk_size[tapeblock_major]!=NULL) {
-		kfree(blk_size[tapeblock_major]);
-		blk_size[tapeblock_major]=NULL;
-	}
-	if (hardsect_size[tapeblock_major]!=NULL) {
-		kfree (hardsect_size[tapeblock_major]);
-		hardsect_size[tapeblock_major]=NULL;
-	}
-	if (max_sectors[tapeblock_major]!=NULL) {
-		kfree (max_sectors[tapeblock_major]);
-		max_sectors[tapeblock_major]=NULL;
-	}
 
+	blk_dev[tapeblock_major].queue = NULL;
 #ifdef CONFIG_DEVFS_FS
 	devfs_unregister_blkdev(tapeblock_major, "tBLK");
 #else
@@ -202,7 +212,7 @@
 
 	inode = filp->f_dentry->d_inode;
 
-	td = tape_get_device_by_minor(MINOR (inode->i_rdev));
+	td = tape_get_device_by_minor(minor (inode->i_rdev));
 	if (td == NULL){
 		rc = -ENODEV;
 		goto error;
@@ -247,11 +257,12 @@
 	long lockflags;
 	tape_dev_t *td = NULL;
 	int rc = 0;
-	if((!inode) || !(inode->i_rdev)) {
+	if((!inode) || kdev_none(inode->i_rdev) /* XXX !(inode->i_rdev) */) {
+		PRINT_ERR("no device in release\n");
 		rc = -EINVAL;
 		goto out;
 	}
-	td = tape_get_device_by_minor(MINOR (inode->i_rdev));
+	td = tape_get_device_by_minor(minor (inode->i_rdev));
 	if (td==NULL) {
 		rc = -ENODEV;
 		goto out;
@@ -261,24 +272,32 @@
 	tape_sprintf_event (tape_dbf_area,6,"b:release: %x\n",td->first_minor);
 	if(tape_state_get(td) == TS_IN_USE)
 		tape_state_set (td, TS_UNUSED);
-	else if (tape_state_get(td) != TS_NOT_OPER) 
+	else if (tape_state_get(td) == TS_UNUSED){
+		PRINT_ERR("Release on tape in unused state.\n");
+		PRINT_ERR("Perhaps tape was detached while it was mounted!\n");
+		PRINT_ERR("Detaching mounted tapes is not allowed!\n");
+		s390irq_spin_unlock_irqrestore (td->devinfo.irq, lockflags);
+		rc = -ENODEV;
+		goto out;
+	} else if (tape_state_get(td) != TS_NOT_OPER) {
 		BUG();
+	}
 	s390irq_spin_unlock_irqrestore (td->devinfo.irq, lockflags);
 	tape_put_device(td);
 	tape_put_device(td); /* 2x ! */
 	if ( td->discipline->owner )
 		__MOD_DEC_USE_COUNT(td->discipline->owner);
-	invalidate_bdev(inode->i_rdev, 0);
+	invalidate_buffers(inode->i_rdev);
 out:
 	return rc;
 }
 
 static void
 tapeblock_end_request(tape_dev_t* td) {
-    struct buffer_head *bh;
     int uptodate;
     tape_ccw_req_t *treq = tape_get_active_ccw_req(td);
     if(treq == NULL){
+	PRINT_ERR("tapeblock_end_request: no request!\n");
 	uptodate = 0;
     }
     else
@@ -288,15 +307,18 @@
     } else {
 	tape_sprintf_event (tape_dbf_area,3,"b:failed: %x\n",(unsigned long)treq);
     }
+#if 0
     // now inform ll_rw_block about a request status
     while ((bh = td->blk_data.current_request->bh) != NULL) {
 	td->blk_data.current_request->bh = bh->b_reqnext;
 	bh->b_reqnext = NULL;
 	bh->b_end_io (bh, uptodate);
     }
-    if (!end_that_request_first (td->blk_data.current_request, uptodate, "tBLK")) {
+#endif
+
+    if (!end_that_request_first (td->blk_data.current_request, uptodate, td->blk_data.current_request->hard_nr_sectors  /* XXX "tBLK" */)) {
 #ifndef DEVICE_NO_RANDOM
-	add_blkdev_randomness (MAJOR (td->blk_data.current_request->rq_dev));
+	add_blkdev_randomness (major (td->blk_data.current_request->rq_dev));
 #endif
 	end_that_request_last (td->blk_data.current_request);
     }
@@ -333,11 +355,15 @@
     if (tape_state_get (td) == TS_NOT_OPER) {
 	return;
     }
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,98))
+	if(blk_queue_empty(&td->blk_data.request_queue)) {
+#else
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 	if (list_empty (&td->blk_data.request_queue.queue_head)) {
 #else
 	if (td->blk_data.request_queue==NULL) {
 #endif
+#endif
 	// nothing more to do or device has dissapeared;)
 	tape_sprintf_event (tape_dbf_area,6,"b:Qempty\n");
 	return;
@@ -347,9 +373,10 @@
     if (req==NULL) {
 	BUG(); // Yo. The queue was not reported empy, but no request found. This is _bad_.
     }
-    if (req->cmd!=READ) { // we only support reading
+    if (rq_data_dir(req) !=READ) { // we only support reading
+	PRINT_ERR("tried to write on readonly tape!\n");
 	tapeblock_end_request (td); // check state, inform user, free mem, dev=idl
-	tapeblock_schedule_exec_io(td);
+	// XXX tapeblock_schedule_exec_io(td);
 	return;
     }
     treq=td->discipline->bread(req,td,tapeblock_major); //build channel program from request
@@ -391,14 +418,12 @@
 static void
 run_tapeblock_exec_IO (tape_dev_t* td) {
     long flags_390irq,flags_ior;
-    request_queue_t *q = &tape->request_queue;
-
-    spin_lock_irqsave (&q->queue_lock, flags_ior);
+    spin_lock_irqsave (&td->blk_data.request_queue_lock, flags_ior);
     s390irq_spin_lock_irqsave(td->devinfo.irq,flags_390irq);
     atomic_set(&td->blk_data.bh_scheduled,0);
     tapeblock_exec_IO(td);
     s390irq_spin_unlock_irqrestore(td->devinfo.irq,flags_390irq);
-    spin_unlock_irqrestore (&q->queue_lock, flags_ior);
+    spin_unlock_irqrestore (&td->blk_data.request_queue_lock, flags_ior);
 }
 
 void
@@ -445,7 +470,7 @@
 #endif
 
 static request_queue_t* tapeblock_getqueue (kdev_t kdev) {
-	tape_dev_t* td=tape_get_device_by_minor(MINOR(kdev));
+	tape_dev_t* td=tape_get_device_by_minor(minor(kdev));
 	if (td!=NULL) return &td->blk_data.request_queue;
 	else return NULL;
 }
@@ -453,6 +478,7 @@
 int tapeblock_mediumdetect(tape_dev_t* td) {
 	tape_ccw_req_t *treq;
 	unsigned int nr_of_blks;
+	unsigned short max;
 	int rc;
 	PRINT_INFO("Detecting media size...\n");
 
@@ -500,5 +526,11 @@
         tape_free_ccw_req (treq);
 	if(rc)	
 		return rc;
+
+	PRINT_INFO("Found %i blocks on media\n",nr_of_blks);
+	max = nr_of_blks << S2B;
+        blk_queue_max_sectors(&td->blk_data.request_queue, max);
+
+	// blk_size[tapeblock_major][td->first_minor]=nr_of_blks*(blksize_size[tapeblock_major][td->first_minor]/1024); */
 	return 0;
 }
diff -urN linux-2.5.21/drivers/s390/char/tapeblock.h linux-2.5.21-s390/drivers/s390/char/tapeblock.h
--- linux-2.5.21/drivers/s390/char/tapeblock.h	Sun Jun  9 07:29:15 2002
+++ linux-2.5.21-s390/drivers/s390/char/tapeblock.h	Wed Jun 12 14:32:25 2002
@@ -17,14 +17,15 @@
 #define TAPEBLOCK_H
 #include <linux/config.h>
 
-#define TAPEBLOCK_READAHEAD 30
 #define TAPEBLOCK_MAJOR 0
 
 #define TAPEBLOCK_DEVFSMODE 0060644 // blkdev, rwx for user, rw for group&others
 
+#define TAPEBLOCK_HSEC_SIZE 2048
+#define S2B 2 /* bits to shift 512 to get a block (2048) */
+
 int tapeblock_open(struct inode *, struct file *);
 int tapeblock_release(struct inode *, struct file *);
-void tapeblock_setup(tape_dev_t* td);
 void tapeblock_schedule_exec_io (tape_dev_t *td);
 int tapeblock_mediumdetect(tape_dev_t* td);
 #ifdef CONFIG_DEVFS_FS
diff -urN linux-2.5.21/drivers/s390/char/tapechar.c linux-2.5.21-s390/drivers/s390/char/tapechar.c
--- linux-2.5.21/drivers/s390/char/tapechar.c	Sun Jun  9 07:29:30 2002
+++ linux-2.5.21-s390/drivers/s390/char/tapechar.c	Tue Jun 11 18:43:32 2002
@@ -106,11 +106,23 @@
  * This function is called for every new tapedevice
  */
 
-void
-tapechar_setup (tape_dev_t * td)
+
+static int
+tapechar_setup_device (tape_dev_t * td)
 {
+	int rc = 0;
+#ifdef CONFIG_DEVFS_FS
+	if(!tapechar_mkdevfstree(td))
+		rc = -1;
+#endif
+	return rc;
+	
+}
+
+static void
+tapechar_cleanup_device(tape_dev_t* td) {
 #ifdef CONFIG_DEVFS_FS
-    tapechar_mkdevfstree(td);
+	tapechar_rmdevfstree(td);
 #endif
 }
 
@@ -129,30 +141,33 @@
 
 	/* Register the tape major number to the kernel */
 #ifdef CONFIG_DEVFS_FS
-	result = devfs_register_chrdev (tapechar_major, "tape", &tape_fops);
-#else
-	result = register_chrdev (tapechar_major, "tape", &tape_fops);
+	if(tapechar_major == 0)
+		tapechar_major = devfs_alloc_major (DEVFS_SPECIAL_CHR);
+// XXX	result = devfs_register_chrdev (tapechar_major, "tape", &tape_fops);
 #endif
+        result = register_chrdev(tapechar_major, "tape", &tape_fops);
+        if(tapechar_major == 0) {
+                tapechar_major = result;
+        }
+
 	if (result < 0) {
-		PRINT_WARN (KERN_ERR "tape: can't get major %d\n", tapechar_major);
-		tape_sprintf_event (tape_dbf_area,3,"c:initfail\n");
+		PRINT_WARN (KERN_ERR "TCHAR: can't get major %d\n", tapechar_major);
+		tape_sprintf_event (tape_dbf_area, 3, "TCHAR:initfail\n");
 		goto out;
 	}
 	if (tapechar_major == 0)
 		tapechar_major = result;	/* accept dynamic major number */
-	PRINT_WARN (KERN_ERR " tape gets major %d for character device\n", result);
+	PRINT_WARN (KERN_ERR "Tape gets major %d for char device\n", tapechar_major);
+	tape_sprintf_event(tape_dbf_area, 3, "Tape gets major %d for char device\n", result);
 	charfront = kmalloc (sizeof (tape_frontend_t), GFP_KERNEL);
 	if (charfront == NULL) {
-	        PRINT_WARN (KERN_ERR "tapechar: cannot alloc memory for the frontend_t structure\n");
-                tape_sprintf_event (tape_dbf_area,3,"c:initfail no mem\n");
+	        PRINT_WARN (KERN_ERR "TCHAR: cannot alloc memory for the frontend_t structure\n");
+                tape_sprintf_event (tape_dbf_area, 3, "TCHAR:initfail no mem\n");
 		goto out;
 	}
-	charfront->device_setup = (tape_setup_device_t)tapechar_setup;
-#ifdef CONFIG_DEVFS_FS
-	charfront->mkdevfstree = tapechar_mkdevfstree;
-	charfront->rmdevfstree = tapechar_rmdevfstree;
-#endif
-        tape_sprintf_event (tape_dbf_area,3,"c:init ok\n");
+	charfront->setup_device = tapechar_setup_device;
+	charfront->cleanup_device = tapechar_cleanup_device;
+        tape_sprintf_event (tape_dbf_area, 3, "TCHAR:init ok\n");
 	charfront->next=NULL;
 	if (tape_first_front==NULL) {
 	    tape_first_front=charfront;
@@ -164,7 +179,7 @@
 	}
 	td=tape_first_dev;
 	while (td!=NULL) {
-	    tapechar_setup(td);
+	    tapechar_setup_device(td);
 	    td=td->next;
 	}
  out:
@@ -247,14 +262,14 @@
 	int rc = 0;
 	size_t cpysize;
 
-        tape_sprintf_event (tape_dbf_area,6,"c:read\n");
+        tape_sprintf_event (tape_dbf_area,6,"TCHAR:read\n");
 	td = (tape_dev_t*)filp->private_data;
 	
 	if (ppos != &filp->f_pos) {
 		/* "A request was outside the capabilities of the device." */
 		/* This check uses internal knowledge about how pread and */
 		/* read work... */
-	        tape_sprintf_event (tape_dbf_area,6,"c:ppos wrong\n");
+	        tape_sprintf_event (tape_dbf_area,6,"TCHAR:ppos wrong\n");
 		rc = -EOVERFLOW;      /* errno=75 Value too large for def. data type */
 		goto out;
 	}
@@ -263,12 +278,12 @@
 	} else {
 	        if (count < td->char_data.block_size) {
 		        rc = -EINVAL; // invalid argument+
-			tape_sprintf_event (tape_dbf_area,3,"tapechar:read smaller than block size was requested\n");
+			tape_sprintf_event (tape_dbf_area,3,"TCHAR:read smaller than block size was requested\n");
 			goto out;
 		}
 		block_size = td->char_data.block_size;
 	}
-	tape_sprintf_event (tape_dbf_area,6,"c:nbytes: %x\n",block_size);
+	tape_sprintf_event (tape_dbf_area,6,"TCHAR:nbytes: %x\n",block_size);
 	treq = td->discipline->read_block (data, block_size, td);
 	if (!treq) {
 		rc = -ENOBUFS;
@@ -284,7 +299,7 @@
 		tape_sprintf_exception (tape_dbf_area,6,"xfrb segf.\n");
 		rc = -EFAULT;
 	}
-	tape_sprintf_event (tape_dbf_area,6,"c:rbytes:  %x\n", cpysize);
+	tape_sprintf_event (tape_dbf_area,6,"TCHAR:rbytes:  %x\n", cpysize);
 	filp->f_pos += cpysize;
 out_free:
 	tape_free_ccw_req(treq);
@@ -304,14 +319,14 @@
 	tape_ccw_req_t *treq;
 	int nblocks, i = 0,rc = 0;
 	size_t written = 0;
-	tape_sprintf_event (tape_dbf_area,6,"c:write\n");
+	tape_sprintf_event (tape_dbf_area,6,"TCHAR:write\n");
 
 	td = (tape_dev_t*)filp->private_data;
 	block_size = count;
         
 	if (ppos != &filp->f_pos) {
 		/* "A request was outside the capabilities of the device." */
-	        tape_sprintf_event (tape_dbf_area,6,"c:ppos wrong\n");
+	        tape_sprintf_event (tape_dbf_area,6,"TCHAR:ppos wrong\n");
 		rc = -EOVERFLOW; /* errno=75 Value too large for def. data type */
 		goto out;
 	}
@@ -326,8 +341,8 @@
 		block_size = td->char_data.block_size;
 		nblocks = count / block_size;
 	}
-	tape_sprintf_event (tape_dbf_area,6,"c:nbytes: %x\n",block_size);
-        tape_sprintf_event (tape_dbf_area,6,"c:nblocks: %x\n",nblocks);
+	tape_sprintf_event (tape_dbf_area,6,"TCHAR:nbytes: %x\n",block_size);
+        tape_sprintf_event (tape_dbf_area,6,"TCHAR:nblocks: %x\n",nblocks);
 	for (i = 0; i < nblocks; i++) {
 		treq = td->discipline->write_block (data + i * block_size, block_size, td);
 		if (!treq) {
@@ -340,14 +355,14 @@
 		tape_free_ccw_req(treq);
 		if(rc < 0)
 			goto out;
-	        tape_sprintf_event (tape_dbf_area,6,"c:wbytes: %x\n",block_size - td->devstat.rescnt); 
+	        tape_sprintf_event (tape_dbf_area,6,"TCHAR:wbytes: %x\n",block_size - td->devstat.rescnt); 
 		filp->f_pos += block_size - td->devstat.rescnt;
 		written += block_size - td->devstat.rescnt;
 		rc = written;
 		if (td->devstat.rescnt > 0)
 			goto out;
 	}
-	tape_sprintf_event (tape_dbf_area,6,"c:wtotal: %x\n",written);
+	tape_sprintf_event (tape_dbf_area,6,"TCHAR:wtotal: %x\n",written);
 
 out:
 	if (rc==-ENOSPC){
@@ -374,9 +389,9 @@
 
 	td = (tape_dev_t*)filp->private_data; 
 
-	tape_sprintf_event (tape_dbf_area,6,"c:mtio\n");
-	tape_sprintf_event (tape_dbf_area,6,"c:ioop: %x\n",mt_op);
-	tape_sprintf_event (tape_dbf_area,6,"c:arg:  %x\n",mt_count);
+	tape_sprintf_event (tape_dbf_area,6,"TCHAR:mtio\n");
+	tape_sprintf_event (tape_dbf_area,6,"TCHAR:ioop: %x\n",mt_op);
+	tape_sprintf_event (tape_dbf_area,6,"TCHAR:arg:  %x\n",mt_count);
 
 	switch (mt_op) {
 		case MTRETEN:		// retension the tape
@@ -399,17 +414,17 @@
 			goto out;
 		case MTSETBLK:
 			td->char_data.block_size = mt_count;
-			tape_sprintf_event (tape_dbf_area,6,"c:setblk:\n");
+			tape_sprintf_event (tape_dbf_area,6,"TCHAR:setblk:\n");
 			goto out;
 		case MTRESET:
 			td->char_data.block_size = 0;
-			tape_sprintf_event (tape_dbf_area,6,"c:devreset:\n");
+			tape_sprintf_event (tape_dbf_area,6,"TCHAR:devreset:\n");
 			goto out;
 		default:
 			treq = td->discipline->ioctl (td, mt_op,mt_count,&rc);
 	}
 	if (treq == NULL) {
-	        tape_sprintf_event (tape_dbf_area,6,"c:ccwg fail\n");
+	        tape_sprintf_event (tape_dbf_area,6,"TCHAR:ccwg fail\n");
 		goto out;
 	}
 
@@ -442,7 +457,7 @@
 	        case MTBSF:		//need to skip forward over the filemark
 			return tapechar_mtioctop (filp, MTFSF, 1);
 	}
-	tape_sprintf_event (tape_dbf_area,6,"c:mtio done\n");
+	tape_sprintf_event (tape_dbf_area,6,"TCHAR:mtio done\n");
 out:
 	return rc;
 }
@@ -462,13 +477,13 @@
 	struct mtget get;
 	int rc;
 
-	tape_sprintf_event (tape_dbf_area,6,"c:ioct\n");
+	tape_sprintf_event (tape_dbf_area,6,"TCHAR:ioct\n");
 
         td = (tape_dev_t*)filp->private_data;
 
 	// check for discipline ioctl overloading
 	if ((rc = td->discipline->discipline_ioctl_overload (td, cmd, arg)) != -EINVAL) {
-		tape_sprintf_event (tape_dbf_area,6,"c:ioverloa\n");
+		tape_sprintf_event (tape_dbf_area,6,"TCHAR:ioverloa\n");
 		goto out;
 	}
 	rc = 0;
@@ -537,7 +552,7 @@
 		tape_free_ccw_req(treq);
 		goto out;
 	default:
-	        tape_sprintf_event (tape_dbf_area,3,"c:ioct inv\n");
+	        tape_sprintf_event (tape_dbf_area,3,"TCHAR:ioct inv\n");
 		rc = -EINVAL;
 		goto out;
 	}
@@ -553,47 +568,82 @@
 tapechar_open (struct inode *inode, struct file *filp)
 {
 	tape_dev_t *td = NULL;
+	tape_ccw_req_t *treq = NULL;
 	int  rc = 0;
+	int  a_rc = 0;
 	long lockflags;
 
 	MOD_INC_USE_COUNT;
 
-	tape_sprintf_event (tape_dbf_area,6,"c:open: %x\n",td->first_minor); 
+	tape_sprintf_event (tape_dbf_area,6,"TCHAR:open: %x\n",td->first_minor); 
 
 	inode = filp->f_dentry->d_inode;
 
 	td = tape_get_device_by_minor(minor (inode->i_rdev));
-	if (td == NULL){
+	if (td == NULL) {
 		rc = -ENODEV;
 		goto error;
 	}
+
+	/* assign device to the specific channel path */
+        treq = td->discipline->assign(td);
+	if (!treq) {
+	        rc = -ENOBUFS;
+		goto error;
+	}
+
+	rc = tape_do_io_and_wait(td,treq,TAPE_WAIT);
+	tape_free_ccw_req(treq);
+	if(rc < 0) {
+	        PRINT_WARN("(%04x): assign failed - device might be busy\n", td->devstat.devno);
+	        tape_sprintf_event(tape_dbf_area, 3, "(%04x): assign failed - device might be busy\n", td->devstat.devno);
+		goto error;
+	}
+	td->assigned = 1;
+	tape_sprintf_event(tape_dbf_area, 3, "(%04x): assign lpum = %02x\n", td->devstat.devno, td->devstat.lpum);
+
 	s390irq_spin_lock_irqsave(td->devinfo.irq,lockflags);
 	if (tape_state_get(td) == TS_NOT_OPER) {
-		tape_sprintf_event (tape_dbf_area,6,"c:nodev\n");
+		tape_sprintf_event (tape_dbf_area,6,"TCHAR:nodev\n");
 		rc = -ENODEV;
 		goto out;
 	}
 
-	if (tape_state_get (td) != TS_UNUSED) {
-		tape_sprintf_event (tape_dbf_area,6,"c:dbusy\n");
+	if (tape_state_get (td) == TS_IN_USE) {
+		tape_sprintf_event (tape_dbf_area,6,"TCHAR:dbusy\n");
 		rc = -EBUSY;
 		goto out;
 	}
 	if ( td->discipline->owner )
 		__MOD_INC_USE_COUNT(td->discipline->owner);
 	tape_state_set (td, TS_IN_USE);
-	td->filp = filp; /* save for later reference     */
+	td->filp = filp;            /* save for later reference */
 	filp->private_data = td;    /* save the dev.info for later reference */
 out:
 	s390irq_spin_unlock_irqrestore(td->devinfo.irq,lockflags);
+	if(rc != 0) {
+	        treq = td->discipline->unassign(td);
+		if (!treq) {
+		        rc = -ENOBUFS;
+			goto error;
+		}
+		a_rc = tape_do_io_and_wait(td,treq,TAPE_WAIT);
+		tape_free_ccw_req(treq);
+		if(a_rc < 0) {
+		        PRINT_WARN("(%04x): unassign failed\n", td->devstat.devno);
+	                tape_sprintf_event(tape_dbf_area, 3, "(%04x): unassign failed\n", td->devstat.devno);
+			goto error;
+		}
+		td->assigned = 0;
+	}
 error:
-	if(rc != 0){
+	if (rc != 0) {
 		MOD_DEC_USE_COUNT;
-		if (td!=NULL)
-			tape_put_device(td);
+	        if (td != NULL)
+		        tape_put_device(td);
+
 	}
 	return rc;
-
 }
 
 /*
@@ -608,7 +658,7 @@
 	int rc = 0;
 	long lockflags;
 
-	tape_sprintf_event (tape_dbf_area,6,"c:release: %x\n",td->first_minor);
+	tape_sprintf_event (tape_dbf_area,6,"TCHAR:release: %x\n",td->first_minor);
 
 	td = (tape_dev_t*)filp->private_data;
 
@@ -618,18 +668,37 @@
 	if (minor (inode->i_rdev) == TAPECHAR_REW_MINOR(td->first_minor)) {
 		treq = td->discipline->ioctl (td, MTREW,1,&rc);
 		if (treq != NULL) {
-		        tape_sprintf_event (tape_dbf_area,6,"c:rewrelea\n");
+		        tape_sprintf_event (tape_dbf_area,6,"TCHAR:rewrelea\n");
 			rc = tape_do_io_and_wait(td, treq, TAPE_WAIT);
 			tape_free_ccw_req (treq);
 		}
 	}
 
+	/* unassign from the channel path on release */
+	treq = td->discipline->unassign(td);
+	if (!treq) {
+	        rc = -ENOBUFS;
+		goto out;
+	}
+	rc = tape_do_io_and_wait(td,treq,TAPE_WAIT);
+	tape_free_ccw_req(treq);
+	if(rc < 0) {
+	        PRINT_WARN("(%04x): unassign failed\n", td->devstat.devno);
+		tape_sprintf_event(tape_dbf_area, 3, "(%04x): unassign failed\n", td->devstat.devno);
+		goto out;
+	}
+	tape_sprintf_event(tape_dbf_area, 3, "(%04x): unassign lpum = %02x\n", td->devstat.devno, td->devstat.lpum);
+ out:
 	s390irq_spin_lock_irqsave(td->devinfo.irq,lockflags);
+	td->assigned = 0;
+
 	if(tape_state_get(td) == TS_IN_USE)
 		tape_state_set (td, TS_UNUSED);
 	else if (tape_state_get(td) != TS_NOT_OPER) 
 		BUG();
+
 	s390irq_spin_unlock_irqrestore(td->devinfo.irq,lockflags);
+
 	if ( td->discipline->owner )
 		__MOD_DEC_USE_COUNT(td->discipline->owner);
 	tape_put_device(td);
diff -urN linux-2.5.21/drivers/s390/char/tapedefs.h linux-2.5.21-s390/drivers/s390/char/tapedefs.h
--- linux-2.5.21/drivers/s390/char/tapedefs.h	Sun Jun  9 07:27:16 2002
+++ linux-2.5.21-s390/drivers/s390/char/tapedefs.h	Tue Jun 11 18:43:32 2002
@@ -33,6 +33,9 @@
 #define CONFIG_S390_TAPE_DYNAMIC // allow devices to be attached or detached on the fly
 #define TAPEBLOCK_RETRIES 20     // number of retries, when a block-dev request fails.
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,98))
+	#define rq_data_dir(req) ((req)->cmd)
+#endif
 
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 #define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \
@@ -40,10 +43,17 @@
         blk_dev[d_major].queue = d_queue_fn; \
 } while(0)
 static inline struct request * 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,99))
+tape_next_request( request_queue_t *queue )
+{
+	return elv_next_request(queue);
+}
+#else
 tape_next_request( request_queue_t *queue ) 
 {
-        return elv_next_request(queue);
+        return blkdev_entry_next_request(&queue->queue_head);
 }
+#endif
 static inline void 
 tape_dequeue_request( request_queue_t * q, struct request *req )
 {

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2002-06-13 21:55 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-06-13 23:43 [PATCH][2.5.21] s390 tape fixes Martin Schwidefsky

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox