include upstream ip1000a driver version 2.09f
[linux-2.4.git] / drivers / s390 / char / tapechar.c
1
2 /***************************************************************************
3  *
4  *  drivers/s390/char/tapechar.c
5  *    character device frontend for tape device driver
6  *
7  *  S390 and zSeries version
8  *    Copyright (C) 2001 IBM Corporation
9  *    Author(s): Carsten Otte <cotte@de.ibm.com>
10  *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
11  *
12  *
13  ****************************************************************************
14  */
15
16 #include "tapedefs.h"
17 #include <linux/config.h>
18 #include <linux/version.h>
19 #include <linux/types.h>
20 #include <linux/proc_fs.h>
21 #include <asm/ccwcache.h>       /* CCW allocations      */
22 #include <asm/s390dyn.h>
23 #include <asm/debug.h>
24 #include <linux/mtio.h>
25 #include <asm/uaccess.h>
26 #include <linux/compatmac.h>
27 #ifdef MODULE
28 #define __NO_VERSION__
29 #include <linux/module.h>
30 #endif
31 #include "tape.h"
32 #include "tapechar.h"
33
34 #define PRINTK_HEADER "TCHAR:"
35
36 /*
37  * file operation structure for tape devices
38  */
39 static struct file_operations tape_fops =
40 {
41     //    owner   : THIS_MODULE,
42         llseek:NULL,            /* lseek - default */
43         read:tape_read,         /* read  */
44         write:tape_write,       /* write */
45         readdir:NULL,           /* readdir - bad */
46         poll:NULL,              /* poll */
47         ioctl:tape_ioctl,       /* ioctl */
48         mmap:NULL,              /* mmap */
49         open:tape_open,         /* open */
50         flush:NULL,             /* flush */
51         release:tape_release,   /* release */
52         fsync:NULL,             /* fsync */
53         fasync:NULL,            /* fasync */
54         lock:NULL,
55 };
56
57 int tape_major = TAPE_MAJOR;
58
59 #ifdef CONFIG_DEVFS_FS
60 void
61 tapechar_mkdevfstree (tape_info_t* ti) {
62     ti->devfs_char_dir=devfs_mk_dir (ti->devfs_dir, "char", ti);
63     ti->devfs_nonrewinding=devfs_register(ti->devfs_char_dir, "nonrewinding",
64                                             DEVFS_FL_DEFAULT,tape_major, 
65                                             ti->nor_minor, TAPECHAR_DEFAULTMODE, 
66                                             &tape_fops, ti);
67     ti->devfs_rewinding=devfs_register(ti->devfs_char_dir, "rewinding",
68                                          DEVFS_FL_DEFAULT, tape_major, ti->rew_minor,
69                                          TAPECHAR_DEFAULTMODE, &tape_fops, ti);
70 }
71
72 void
73 tapechar_rmdevfstree (tape_info_t* ti) {
74     devfs_unregister(ti->devfs_nonrewinding);
75     devfs_unregister(ti->devfs_rewinding);
76     devfs_unregister(ti->devfs_char_dir);
77 }
78 #endif
79
80 void
81 tapechar_setup (tape_info_t * ti)
82 {
83 #ifdef CONFIG_DEVFS_FS
84     tapechar_mkdevfstree(ti);
85 #endif
86 }
87
88 void
89 tapechar_init (void)
90 {
91         int result;
92         tape_frontend_t *charfront,*temp;
93         tape_info_t* ti;
94
95         tape_init();
96
97         /* Register the tape major number to the kernel */
98 #ifdef CONFIG_DEVFS_FS
99         result = devfs_register_chrdev (tape_major, "tape", &tape_fops);
100 #else
101         result = register_chrdev (tape_major, "tape", &tape_fops);
102 #endif
103
104         if (result < 0) {
105                 PRINT_WARN (KERN_ERR "tape: can't get major %d\n", tape_major);
106 #ifdef TAPE_DEBUG
107                 debug_text_event (tape_debug_area,3,"c:initfail");
108                 debug_text_event (tape_debug_area,3,"regchrfail");
109 #endif /* TAPE_DEBUG */
110                 panic ("no major number available for tape char device");
111         }
112         if (tape_major == 0)
113                 tape_major = result;    /* accept dynamic major number */
114         PRINT_WARN (KERN_ERR " tape gets major %d for character device\n", result);
115         charfront = kmalloc (sizeof (tape_frontend_t), GFP_KERNEL);
116         if (charfront == NULL) {
117 #ifdef TAPE_DEBUG
118                 debug_text_event (tape_debug_area,3,"c:initfail");
119                 debug_text_event (tape_debug_area,3,"no mem");
120 #endif /* TAPE_DEBUG */
121                 panic ("no major number available for tape char device");               
122         }
123         charfront->device_setup = tapechar_setup;
124 #ifdef CONFIG_DEVFS_FS
125         charfront->mkdevfstree = tapechar_mkdevfstree;
126         charfront->rmdevfstree = tapechar_rmdevfstree;
127 #endif
128 #ifdef TAPE_DEBUG
129         debug_text_event (tape_debug_area,3,"c:init ok");
130 #endif /* TAPE_DEBUG */
131         charfront->next=NULL;
132         if (first_frontend==NULL) {
133             first_frontend=charfront;
134         } else {
135             temp=first_frontend;
136             while (temp->next!=NULL)
137                 temp=temp->next;
138             temp->next=charfront;
139         }
140         ti=first_tape_info;
141         while (ti!=NULL) {
142             tapechar_setup(ti);
143             ti=ti->next;
144         }
145 }
146
147 void
148 tapechar_uninit (void)
149 {
150         unregister_chrdev (tape_major, "tape");
151 }
152
153 /*
154  * Tape device read function
155  */
156 ssize_t
157 tape_read (struct file *filp, char *data, size_t count, loff_t * ppos)
158 {
159         long lockflags;
160         tape_info_t *ti;
161         size_t block_size;
162         ccw_req_t *cqr;
163         int rc;
164         loff_t pos = *ppos;
165 #ifdef TAPE_DEBUG
166         debug_text_event (tape_debug_area,6,"c:read");
167 #endif /* TAPE_DEBUG */
168         ti = first_tape_info;
169         while ((ti != NULL) && (ti->rew_filp != filp) && (ti->nor_filp != filp))
170                 ti = (tape_info_t *) ti->next;
171         if (ti == NULL) {
172 #ifdef TAPE_DEBUG
173                 debug_text_event (tape_debug_area,6,"c:nodev");
174 #endif /* TAPE_DEBUG */
175                 return -ENODEV;
176         }
177         if (ppos != &filp->f_pos) {
178                 /* "A request was outside the capabilities of the device." */
179 #ifdef TAPE_DEBUG
180                 debug_text_event (tape_debug_area,6,"c:ppos wrong");
181 #endif /* TAPE_DEBUG */
182                 return -EOVERFLOW;      /* errno=75 Value too large for def. data type */
183         }
184         if (ti->block_size == 0) {
185                 block_size = count;
186         } else {
187                 block_size = ti->block_size;
188         }
189 #ifdef TAPE_DEBUG
190         debug_text_event (tape_debug_area,6,"c:nbytes:");
191         debug_int_event (tape_debug_area,6,block_size);
192 #endif
193         cqr = ti->discipline->read_block (data, block_size, ti);
194         if (!cqr) {
195                 return -ENOBUFS;
196         }
197         s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
198         ti->cqr = cqr;
199         ti->wanna_wakeup=0;
200         rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
201         if (rc) {
202             tapestate_set(ti,TS_IDLE);
203             kfree (cqr);
204             s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
205             return rc;
206         }
207         s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
208         wait_event (ti->wq,ti->wanna_wakeup);
209         ti->cqr = NULL;
210         ti->discipline->free_read_block (cqr, ti);
211         s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
212         if (tapestate_get (ti) == TS_FAILED) {
213                 tapestate_set (ti, TS_IDLE);
214                 s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
215                 return ti->rc;
216         }
217         if (tapestate_get (ti) == TS_NOT_OPER) {
218             ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
219             ti->devinfo.irq=-1;
220             s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
221             return -ENODEV;
222         }
223         if (tapestate_get (ti) != TS_DONE) {
224                 tapestate_set (ti, TS_IDLE);
225                 s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
226                 return -EIO;
227         }
228         tapestate_set (ti, TS_IDLE);
229         s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
230 #ifdef TAPE_DEBUG
231         debug_text_event (tape_debug_area,6,"c:rbytes:");
232         debug_int_event (tape_debug_area,6,block_size - ti->devstat.rescnt);
233 #endif  /* TAPE_DEBUG */
234         *ppos = pos + (block_size - ti->devstat.rescnt);
235         return block_size - ti->devstat.rescnt;
236 }
237
238 /*
239  * Tape device write function
240  */
241 ssize_t
242 tape_write (struct file *filp, const char *data, size_t count, loff_t * ppos)
243 {
244         long lockflags;
245         tape_info_t *ti;
246         size_t block_size;
247         ccw_req_t *cqr;
248         int nblocks, i, rc;
249         size_t written = 0;
250         loff_t pos = *ppos;
251
252 #ifdef TAPE_DEBUG
253         debug_text_event (tape_debug_area,6,"c:write");
254 #endif
255         ti = first_tape_info;
256         while ((ti != NULL) && (ti->nor_filp != filp) && (ti->rew_filp != filp))
257                 ti = (tape_info_t *) ti->next;
258         if (ti == NULL)
259                 return -ENODEV;
260         if (ppos != &filp->f_pos) {
261                 /* "A request was outside the capabilities of the device." */
262 #ifdef TAPE_DEBUG
263                 debug_text_event (tape_debug_area,6,"c:ppos wrong");
264 #endif
265                 return -EOVERFLOW;      /* errno=75 Value too large for def. data type */
266         }
267         if ((ti->block_size != 0) && (count % ti->block_size != 0))
268                 return -EIO;
269         if (ti->block_size == 0) {
270                 block_size = count;
271                 nblocks = 1;
272         } else {
273                 block_size = ti->block_size;
274                 nblocks = count / (ti->block_size);
275         }
276 #ifdef TAPE_DEBUG
277                 debug_text_event (tape_debug_area,6,"c:nbytes:");
278                 debug_int_event (tape_debug_area,6,block_size);
279                 debug_text_event (tape_debug_area,6,"c:nblocks:");
280                 debug_int_event (tape_debug_area,6,nblocks);
281 #endif
282         for (i = 0; i < nblocks; i++) {
283                 cqr = ti->discipline->write_block (data + i * block_size, block_size, ti);
284                 if (!cqr) {
285                         return -ENOBUFS;
286                 }
287                 s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
288                 ti->cqr = cqr;
289                 ti->wanna_wakeup=0;
290                 rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
291                 s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
292                 wait_event_interruptible (ti->wq,ti->wanna_wakeup);
293                 ti->cqr = NULL;
294                 ti->discipline->free_write_block (cqr, ti);
295                 if (signal_pending (current)) {
296                         tapestate_set (ti, TS_IDLE);
297                         return -ERESTARTSYS;
298                 }
299                 s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
300                 if (tapestate_get (ti) == TS_FAILED) {
301                         tapestate_set (ti, TS_IDLE);
302                         s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
303                         if ((ti->rc==-ENOSPC) && (i!=0))
304                           return i*block_size;
305                         return ti->rc;
306                 }
307                 if (tapestate_get (ti) == TS_NOT_OPER) {
308                     ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
309                     ti->devinfo.irq=-1;
310                     s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
311                     return -ENODEV;
312                 }
313                 if (tapestate_get (ti) != TS_DONE) {
314                         tapestate_set (ti, TS_IDLE);
315                         s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
316                         return -EIO;
317                 }
318                 tapestate_set (ti, TS_IDLE);
319                 s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
320 #ifdef TAPE_DEBUG
321                 debug_text_event (tape_debug_area,6,"c:wbytes:"); 
322                 debug_int_event (tape_debug_area,6,block_size - ti->devstat.rescnt);
323 #endif
324                 written += block_size - ti->devstat.rescnt;
325                 if (ti->devstat.rescnt > 0) {
326                         *ppos = pos + written;
327                         return written;
328                 }
329         }
330 #ifdef TAPE_DEBUG
331         debug_text_event (tape_debug_area,6,"c:wtotal:");
332         debug_int_event (tape_debug_area,6,written);
333 #endif
334         *ppos = pos + written;
335         return written;
336 }
337
338 static int
339 tape_mtioctop (struct file *filp, short mt_op, int mt_count)
340 {
341         tape_info_t *ti;
342         ccw_req_t *cqr = NULL;
343         int rc;
344         long lockflags;
345 #ifdef TAPE_DEBUG
346         debug_text_event (tape_debug_area,6,"c:mtio");
347         debug_text_event (tape_debug_area,6,"c:ioop:");
348         debug_int_event (tape_debug_area,6,mt_op); 
349         debug_text_event (tape_debug_area,6,"c:arg:");
350         debug_int_event (tape_debug_area,6,mt_count);
351 #endif
352         ti = first_tape_info;
353         while ((ti != NULL) && (ti->rew_filp != filp) && (ti->nor_filp != filp))
354                 ti = (tape_info_t *) ti->next;
355         if (ti == NULL)
356                 return -ENODEV;
357         switch (mt_op) {
358         case MTREW:             // rewind
359
360                 cqr = ti->discipline->mtrew (ti, mt_count);
361                 break;
362         case MTOFFL:            // put drive offline
363
364                 cqr = ti->discipline->mtoffl (ti, mt_count);
365                 break;
366         case MTUNLOAD:          // unload the tape
367
368                 cqr = ti->discipline->mtunload (ti, mt_count);
369                 break;
370         case MTWEOF:            // write tapemark
371
372                 cqr = ti->discipline->mtweof (ti, mt_count);
373                 break;
374         case MTFSF:             // forward space file
375
376                 cqr = ti->discipline->mtfsf (ti, mt_count);
377                 break;
378         case MTBSF:             // backward space file
379
380                 cqr = ti->discipline->mtbsf (ti, mt_count);
381                 break;
382         case MTFSFM:            // forward space file, stop at BOT side
383
384                 cqr = ti->discipline->mtfsfm (ti, mt_count);
385                 break;
386         case MTBSFM:            // backward space file, stop at BOT side
387
388                 cqr = ti->discipline->mtbsfm (ti, mt_count);
389                 break;
390         case MTFSR:             // forward space file
391
392                 cqr = ti->discipline->mtfsr (ti, mt_count);
393                 break;
394         case MTBSR:             // backward space file
395
396                 cqr = ti->discipline->mtbsr (ti, mt_count);
397                 break;
398         case MTNOP:
399                 cqr = ti->discipline->mtnop (ti, mt_count);
400                 break;
401         case MTEOM:             // postion at the end of portion
402
403         case MTRETEN:           // retension the tape
404
405                 cqr = ti->discipline->mteom (ti, mt_count);
406                 break;
407         case MTERASE:
408                 cqr = ti->discipline->mterase (ti, mt_count);
409                 break;
410         case MTSETDENSITY:
411                 cqr = ti->discipline->mtsetdensity (ti, mt_count);
412                 break;
413         case MTSEEK:
414                 cqr = ti->discipline->mtseek (ti, mt_count);
415                 break;
416         case MTSETDRVBUFFER:
417                 cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
418                 break;
419         case MTLOCK:
420                 cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
421                 break;
422         case MTUNLOCK:
423                 cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
424                 break;
425         case MTLOAD:
426                 cqr = ti->discipline->mtload (ti, mt_count);
427                 if (cqr!=NULL) break; // if backend driver has an load function ->use it
428                 // if no medium is in, wait until it gets inserted
429                 if (ti->medium_is_unloaded) {
430                     wait_event_interruptible (ti->wq,ti->medium_is_unloaded==0);
431                 }
432                 return 0;
433         case MTCOMPRESSION:
434                 cqr = ti->discipline->mtcompression (ti, mt_count);
435                 break;
436         case MTSETPART:
437                 cqr = ti->discipline->mtsetpart (ti, mt_count);
438                 break;
439         case MTMKPART:
440                 cqr = ti->discipline->mtmkpart (ti, mt_count);
441                 break;
442         case MTTELL:            // return number of block relative to current file
443
444                 cqr = ti->discipline->mttell (ti, mt_count);
445                 break;
446         case MTSETBLK:
447                 s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
448                 ti->block_size = mt_count;
449                 s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
450 #ifdef TAPE_DEBUG
451                 debug_text_event (tape_debug_area,6,"c:setblk:");
452                 debug_int_event (tape_debug_area,6,mt_count);
453 #endif
454                 return 0;
455         case MTRESET:
456                 s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
457                 ti->kernbuf = ti->userbuf = NULL;
458                 tapestate_set (ti, TS_IDLE);
459                 ti->block_size = 0;
460                 s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
461 #ifdef TAPE_DEBUG
462                 debug_text_event (tape_debug_area,6,"c:devreset:");
463                 debug_int_event (tape_debug_area,6,ti->blk_minor);
464 #endif
465                 return 0;
466         default:
467 #ifdef TAPE_DEBUG
468             debug_text_event (tape_debug_area,6,"c:inv.mtio");
469 #endif
470                 return -EINVAL;
471         }
472         if (cqr == NULL) {
473 #ifdef TAPE_DEBUG
474                 debug_text_event (tape_debug_area,6,"c:ccwg fail");
475 #endif
476                 return -ENOSPC;
477         }
478         s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
479         ti->cqr = cqr;
480         ti->wanna_wakeup=0;
481         rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
482         s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
483         wait_event_interruptible (ti->wq,ti->wanna_wakeup);
484         ti->cqr = NULL;
485         if (ti->kernbuf != NULL) {
486                 kfree (ti->kernbuf);
487                 ti->kernbuf = NULL;
488         }
489         tape_free_request (cqr);
490         // if medium was unloaded, update the corresponding variable.
491         switch (mt_op) {
492         case MTOFFL:
493         case MTUNLOAD:
494             ti->medium_is_unloaded=1;
495         }
496         if (signal_pending (current)) {
497                 tapestate_set (ti, TS_IDLE);
498                 return -ERESTARTSYS;
499         }
500         s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
501         if (((mt_op == MTEOM) || (mt_op == MTRETEN)) && (tapestate_get (ti) == TS_FAILED))
502                 tapestate_set (ti, TS_DONE);
503         if (tapestate_get (ti) == TS_FAILED) {
504                 tapestate_set (ti, TS_IDLE);
505                 s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
506                 return ti->rc;
507         }
508         if (tapestate_get (ti) == TS_NOT_OPER) {
509             ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
510             ti->devinfo.irq=-1;
511             s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
512             return -ENODEV;
513         }
514         if (tapestate_get (ti) != TS_DONE) {
515                 tapestate_set (ti, TS_IDLE);
516                 s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
517                 return -EIO;
518         }
519         tapestate_set (ti, TS_IDLE);
520         s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
521         switch (mt_op) {
522         case MTRETEN:           //need to rewind the tape after moving to eom
523
524                 return tape_mtioctop (filp, MTREW, 1);
525         case MTFSFM:            //need to skip back over the filemark
526
527                 return tape_mtioctop (filp, MTBSFM, 1);
528         case MTBSF:             //need to skip forward over the filemark
529
530                 return tape_mtioctop (filp, MTFSF, 1);
531         }
532 #ifdef TAPE_DEBUG
533         debug_text_event (tape_debug_area,6,"c:mtio done");
534 #endif
535         return 0;
536 }
537
538 /*
539  * Tape device io controls.
540  */
541 int
542 tape_ioctl (struct inode *inode, struct file *filp,
543             unsigned int cmd, unsigned long arg)
544 {
545         long lockflags;
546         tape_info_t *ti;
547         ccw_req_t *cqr;
548         struct mtop op;         /* structure for MTIOCTOP */
549         struct mtpos pos;       /* structure for MTIOCPOS */
550         struct mtget get;
551
552         int rc;
553 #ifdef TAPE_DEBUG
554         debug_text_event (tape_debug_area,6,"c:ioct");
555 #endif
556         ti = first_tape_info;
557         while ((ti != NULL) &&
558                (ti->rew_minor != MINOR (inode->i_rdev)) &&
559                (ti->nor_minor != MINOR (inode->i_rdev)))
560                 ti = (tape_info_t *) ti->next;
561         if (ti == NULL) {
562 #ifdef TAPE_DEBUG
563                 debug_text_event (tape_debug_area,6,"c:nodev");
564 #endif
565                 return -ENODEV;
566         }
567         // check for discipline ioctl overloading
568         if ((rc = ti->discipline->discipline_ioctl_overload (inode, filp, cmd, arg))
569             != -EINVAL) {
570 #ifdef TAPE_DEBUG
571             debug_text_event (tape_debug_area,6,"c:ioverloa");
572 #endif
573             return rc;
574         }
575
576         switch (cmd) {
577         case MTIOCTOP:          /* tape op command */
578                 if (copy_from_user (&op, (char *) arg, sizeof (struct mtop))) {
579                          return -EFAULT;
580                 }
581                 return (tape_mtioctop (filp, op.mt_op, op.mt_count));
582         case MTIOCPOS:          /* query tape position */
583                 cqr = ti->discipline->mttell (ti, 0);
584                 s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
585                 ti->cqr = cqr;
586                 ti->wanna_wakeup=0;
587                 do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
588                 s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
589                 wait_event_interruptible (ti->wq,ti->wanna_wakeup);
590                 pos.mt_blkno = ti->rc;
591                 ti->cqr = NULL;
592                 if (ti->kernbuf != NULL) {
593                         kfree (ti->kernbuf);
594                         ti->kernbuf = NULL;
595                 }
596                 tape_free_request (cqr);
597                 if (signal_pending (current)) {
598                         tapestate_set (ti, TS_IDLE);
599                         return -ERESTARTSYS;
600                 }
601                 s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
602                 tapestate_set (ti, TS_IDLE);
603                 s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
604                 if (copy_to_user ((char *) arg, &pos, sizeof (struct mtpos)))
605                          return -EFAULT;
606                 return 0;
607         case MTIOCGET:
608                 get.mt_erreg = ti->rc;
609                 cqr = ti->discipline->mttell (ti, 0);
610                 s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
611                 ti->cqr = cqr;
612                 ti->wanna_wakeup=0;
613                 do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
614                 s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
615                 wait_event_interruptible (ti->wq,ti->wanna_wakeup);
616                 get.mt_blkno = ti->rc;
617                 get.mt_fileno = 0;
618                 get.mt_type = MT_ISUNKNOWN;
619                 get.mt_resid = ti->devstat.rescnt;
620                 get.mt_dsreg = ti->devstat.ii.sense.data[3];
621                 get.mt_gstat = 0;
622                 if (ti->devstat.ii.sense.data[1] & 0x08)
623                         get.mt_gstat &= GMT_BOT (1);    // BOT
624
625                 if (ti->devstat.ii.sense.data[1] & 0x02)
626                         get.mt_gstat &= GMT_WR_PROT (1);        // write protected
627
628                 if (ti->devstat.ii.sense.data[1] & 0x40)
629                         get.mt_gstat &= GMT_ONLINE (1);         //drive online
630
631                 ti->cqr = NULL;
632                 if (ti->kernbuf != NULL) {
633                         kfree (ti->kernbuf);
634                         ti->kernbuf = NULL;
635                 }
636                 tape_free_request (cqr);
637                 if (signal_pending (current)) {
638                         tapestate_set (ti, TS_IDLE);
639                         return -ERESTARTSYS;
640                 }
641                 s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
642                 tapestate_set (ti, TS_IDLE);
643                 s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
644                 if (copy_to_user ((char *) arg, &get, sizeof (struct mtget)))
645                          return -EFAULT;
646                 return 0;
647         default:
648 #ifdef TAPE_DEBUG
649                 debug_text_event (tape_debug_area,3,"c:ioct inv");
650 #endif      
651                 return -EINVAL;
652         }
653 }
654
655 /*
656  * Tape device open function.
657  */
658 int
659 tape_open (struct inode *inode, struct file *filp)
660 {
661         tape_info_t *ti;
662         kdev_t dev;
663         long lockflags;
664
665         inode = filp->f_dentry->d_inode;
666         ti = first_tape_info;
667         while ((ti != NULL) &&
668                (ti->rew_minor != MINOR (inode->i_rdev)) &&
669                (ti->nor_minor != MINOR (inode->i_rdev)))
670                 ti = (tape_info_t *) ti->next;
671         if (ti == NULL)
672                 return -ENODEV;
673 #ifdef TAPE_DEBUG
674         debug_text_event (tape_debug_area,6,"c:open:");
675         debug_int_event (tape_debug_area,6,ti->blk_minor);
676 #endif
677         s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
678         if (tapestate_get (ti) != TS_UNUSED) {
679                 s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
680 #ifdef TAPE_DEBUG
681                 debug_text_event (tape_debug_area,6,"c:dbusy");
682 #endif
683                 return -EBUSY;
684         }
685         tapestate_set (ti, TS_IDLE);
686         s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
687
688         dev = MKDEV (tape_major, MINOR (inode->i_rdev));        /* Get the device */
689         s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
690         if (ti->rew_minor == MINOR (inode->i_rdev))
691                 ti->rew_filp = filp;    /* save for later reference     */
692         else
693                 ti->nor_filp = filp;
694         filp->private_data = ti;        /* save the dev.info for later reference */
695         s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
696
697 #ifdef MODULE
698         MOD_INC_USE_COUNT;
699 #endif                          /* MODULE */
700         return 0;
701 }
702
703 /*
704  * Tape device release function.
705  */
706 int
707 tape_release (struct inode *inode, struct file *filp)
708 {
709         long lockflags;
710         tape_info_t *ti,*lastti;
711         ccw_req_t *cqr = NULL;
712         int rc = 0;
713
714         ti = first_tape_info;
715         while ((ti != NULL) && (ti->rew_minor != MINOR (inode->i_rdev)) && (ti->nor_minor != MINOR (inode->i_rdev)))
716                 ti = (tape_info_t *) ti->next;
717         if ((ti != NULL) && (tapestate_get (ti) == TS_NOT_OPER)) {
718             if (ti==first_tape_info) {
719                 first_tape_info=ti->next;
720             } else {
721                 lastti=first_tape_info;
722                 while (lastti->next!=ti) lastti=lastti->next;
723                 lastti->next=ti->next;
724             }
725             kfree(ti);    
726             goto out;
727         }
728         if ((ti == NULL) || (tapestate_get (ti) != TS_IDLE)) {
729 #ifdef TAPE_DEBUG
730         debug_text_event (tape_debug_area,6,"c:notidle!");
731 #endif
732                 rc = -ENXIO;    /* error in tape_release */
733                 goto out;
734         }
735 #ifdef TAPE_DEBUG
736         debug_text_event (tape_debug_area,6,"c:release:");
737         debug_int_event (tape_debug_area,6,ti->blk_minor);
738 #endif
739         if (ti->rew_minor == MINOR (inode->i_rdev)) {
740                 cqr = ti->discipline->mtrew (ti, 1);
741                 if (cqr != NULL) {
742 #ifdef TAPE_DEBUG
743                         debug_text_event (tape_debug_area,6,"c:rewrelea");
744 #endif
745                         s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
746                         tapestate_set (ti, TS_REW_RELEASE_INIT);
747                         ti->cqr = cqr;
748                         ti->wanna_wakeup=0;
749                         rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
750                         s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
751                         wait_event (ti->wq,ti->wanna_wakeup);
752                         ti->cqr = NULL;
753                         tape_free_request (cqr);
754                 }
755         }
756         s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
757         tapestate_set (ti, TS_UNUSED);
758         s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
759 out:
760 #ifdef MODULE
761         MOD_DEC_USE_COUNT;
762 #endif                          /* MODULE */
763         return rc;
764 }