[PATCH][2.5.21] s390 tape fixes.

From: Martin Schwidefsky (martin.schwidefsky@debitel.net)
Date: Thu Jun 13 2002 - 18:43:00 EST


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 )
 {
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sat Jun 15 2002 - 22:00:29 EST