File: /usr/src/linux/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     #ifdef TAPE_DEBUG
165             debug_text_event (tape_debug_area,6,"c:read");
166     #endif /* TAPE_DEBUG */
167     	ti = first_tape_info;
168     	while ((ti != NULL) && (ti->rew_filp != filp) && (ti->nor_filp != filp))
169     		ti = (tape_info_t *) ti->next;
170     	if (ti == NULL) {
171     #ifdef TAPE_DEBUG
172     	        debug_text_event (tape_debug_area,6,"c:nodev");
173     #endif /* TAPE_DEBUG */
174     		return -ENODEV;
175     	}
176     	if (ppos != &filp->f_pos) {
177     		/* "A request was outside the capabilities of the device." */
178     #ifdef TAPE_DEBUG
179     	        debug_text_event (tape_debug_area,6,"c:ppos wrong");
180     #endif /* TAPE_DEBUG */
181     		return -EOVERFLOW;	/* errno=75 Value too large for def. data type */
182     	}
183     	if (ti->block_size == 0) {
184     		block_size = count;
185     	} else {
186     		block_size = ti->block_size;
187     	}
188     #ifdef TAPE_DEBUG
189     	debug_text_event (tape_debug_area,6,"c:nbytes:");
190     	debug_int_event (tape_debug_area,6,block_size);
191     #endif
192     	cqr = ti->discipline->read_block (data, block_size, ti);
193     	if (!cqr) {
194     		return -ENOBUFS;
195     	}
196     	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
197     	ti->cqr = cqr;
198     	ti->wanna_wakeup=0;
199     	rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
200     	if (rc) {
201     	    tapestate_set(ti,TS_IDLE);
202     	    kfree (cqr);
203     	    s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
204     	    return rc;
205     	}
206     	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
207     	wait_event_interruptible (ti->wq,ti->wanna_wakeup);
208     	ti->cqr = NULL;
209     	ti->discipline->free_read_block (cqr, ti);
210     	if (signal_pending (current)) {
211     		tapestate_set (ti, TS_IDLE);
212     		return -ERESTARTSYS;
213     	}
214     	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
215     	if (tapestate_get (ti) == TS_FAILED) {
216     		tapestate_set (ti, TS_IDLE);
217     		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
218     		return ti->rc;
219     	}
220     	if (tapestate_get (ti) == TS_NOT_OPER) {
221     	    ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
222     	    ti->devinfo.irq=-1;
223     	    s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
224     	    return -ENODEV;
225     	}
226     	if (tapestate_get (ti) != TS_DONE) {
227     		tapestate_set (ti, TS_IDLE);
228     		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
229     		return -EIO;
230     	}
231     	tapestate_set (ti, TS_IDLE);
232     	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
233     #ifdef TAPE_DEBUG
234     	debug_text_event (tape_debug_area,6,"c:rbytes:");
235     	debug_int_event (tape_debug_area,6,block_size - ti->devstat.rescnt);
236     #endif	/* TAPE_DEBUG */
237     	filp->f_pos += block_size - ti->devstat.rescnt;
238     	return block_size - ti->devstat.rescnt;
239     }
240     
241     /*
242      * Tape device write function
243      */
244     ssize_t
245     tape_write (struct file *filp, const char *data, size_t count, loff_t * ppos)
246     {
247     	long lockflags;
248     	tape_info_t *ti;
249     	size_t block_size;
250     	ccw_req_t *cqr;
251     	int nblocks, i, rc;
252     	size_t written = 0;
253     #ifdef TAPE_DEBUG
254     	debug_text_event (tape_debug_area,6,"c:write");
255     #endif
256     	ti = first_tape_info;
257     	while ((ti != NULL) && (ti->nor_filp != filp) && (ti->rew_filp != filp))
258     		ti = (tape_info_t *) ti->next;
259     	if (ti == NULL)
260     		return -ENODEV;
261     	if (ppos != &filp->f_pos) {
262     		/* "A request was outside the capabilities of the device." */
263     #ifdef TAPE_DEBUG
264     	        debug_text_event (tape_debug_area,6,"c:ppos wrong");
265     #endif
266     		return -EOVERFLOW;	/* errno=75 Value too large for def. data type */
267     	}
268     	if ((ti->block_size != 0) && (count % ti->block_size != 0))
269     		return -EIO;
270     	if (ti->block_size == 0) {
271     		block_size = count;
272     		nblocks = 1;
273     	} else {
274     		block_size = ti->block_size;
275     		nblocks = count / (ti->block_size);
276     	}
277     #ifdef TAPE_DEBUG
278     	        debug_text_event (tape_debug_area,6,"c:nbytes:");
279     		debug_int_event (tape_debug_area,6,block_size);
280     	        debug_text_event (tape_debug_area,6,"c:nblocks:");
281     	        debug_int_event (tape_debug_area,6,nblocks);
282     #endif
283     	for (i = 0; i < nblocks; i++) {
284     		cqr = ti->discipline->write_block (data + i * block_size, block_size, ti);
285     		if (!cqr) {
286     			return -ENOBUFS;
287     		}
288     		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
289     		ti->cqr = cqr;
290     		ti->wanna_wakeup=0;
291     		rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
292     		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
293     		wait_event_interruptible (ti->wq,ti->wanna_wakeup);
294     		ti->cqr = NULL;
295     		ti->discipline->free_write_block (cqr, ti);
296     		if (signal_pending (current)) {
297     			tapestate_set (ti, TS_IDLE);
298     			return -ERESTARTSYS;
299     		}
300     		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
301     		if (tapestate_get (ti) == TS_FAILED) {
302     			tapestate_set (ti, TS_IDLE);
303     			s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
304                             if ((ti->rc==-ENOSPC) && (i!=0))
305     			  return i*block_size;
306     			return ti->rc;
307     		}
308     		if (tapestate_get (ti) == TS_NOT_OPER) {
309     		    ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
310     		    ti->devinfo.irq=-1;
311     		    s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
312     		    return -ENODEV;
313     		}
314     		if (tapestate_get (ti) != TS_DONE) {
315     			tapestate_set (ti, TS_IDLE);
316     			s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
317     			return -EIO;
318     		}
319     		tapestate_set (ti, TS_IDLE);
320     		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
321     #ifdef TAPE_DEBUG
322     	        debug_text_event (tape_debug_area,6,"c:wbytes:"); 
323     		debug_int_event (tape_debug_area,6,block_size - ti->devstat.rescnt);
324     #endif
325     		filp->f_pos += block_size - ti->devstat.rescnt;
326     		written += block_size - ti->devstat.rescnt;
327     		if (ti->devstat.rescnt > 0)
328     			return written;
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     	return written;
335     }
336     
337     static int
338     tape_mtioctop (struct file *filp, short mt_op, int mt_count)
339     {
340     	tape_info_t *ti;
341     	ccw_req_t *cqr = NULL;
342     	int rc;
343     	long lockflags;
344     #ifdef TAPE_DEBUG
345     	debug_text_event (tape_debug_area,6,"c:mtio");
346     	debug_text_event (tape_debug_area,6,"c:ioop:");
347     	debug_int_event (tape_debug_area,6,mt_op); 
348     	debug_text_event (tape_debug_area,6,"c:arg:");
349     	debug_int_event (tape_debug_area,6,mt_count);
350     #endif
351     	ti = first_tape_info;
352     	while ((ti != NULL) && (ti->rew_filp != filp) && (ti->nor_filp != filp))
353     		ti = (tape_info_t *) ti->next;
354     	if (ti == NULL)
355     		return -ENODEV;
356     	switch (mt_op) {
357     	case MTREW:		// rewind
358     
359     		cqr = ti->discipline->mtrew (ti, mt_count);
360     		break;
361     	case MTOFFL:		// put drive offline
362     
363     		cqr = ti->discipline->mtoffl (ti, mt_count);
364     		break;
365     	case MTUNLOAD:		// unload the tape
366     
367     		cqr = ti->discipline->mtunload (ti, mt_count);
368     		break;
369     	case MTWEOF:		// write tapemark
370     
371     		cqr = ti->discipline->mtweof (ti, mt_count);
372     		break;
373     	case MTFSF:		// forward space file
374     
375     		cqr = ti->discipline->mtfsf (ti, mt_count);
376     		break;
377     	case MTBSF:		// backward space file
378     
379     		cqr = ti->discipline->mtbsf (ti, mt_count);
380     		break;
381     	case MTFSFM:		// forward space file, stop at BOT side
382     
383     		cqr = ti->discipline->mtfsfm (ti, mt_count);
384     		break;
385     	case MTBSFM:		// backward space file, stop at BOT side
386     
387     		cqr = ti->discipline->mtbsfm (ti, mt_count);
388     		break;
389     	case MTFSR:		// forward space file
390     
391     		cqr = ti->discipline->mtfsr (ti, mt_count);
392     		break;
393     	case MTBSR:		// backward space file
394     
395     		cqr = ti->discipline->mtbsr (ti, mt_count);
396     		break;
397     	case MTNOP:
398     		cqr = ti->discipline->mtnop (ti, mt_count);
399     		break;
400     	case MTEOM:		// postion at the end of portion
401     
402     	case MTRETEN:		// retension the tape
403     
404     		cqr = ti->discipline->mteom (ti, mt_count);
405     		break;
406     	case MTERASE:
407     		cqr = ti->discipline->mterase (ti, mt_count);
408     		break;
409     	case MTSETDENSITY:
410     		cqr = ti->discipline->mtsetdensity (ti, mt_count);
411     		break;
412     	case MTSEEK:
413     		cqr = ti->discipline->mtseek (ti, mt_count);
414     		break;
415     	case MTSETDRVBUFFER:
416     		cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
417     		break;
418     	case MTLOCK:
419     		cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
420     		break;
421     	case MTUNLOCK:
422     		cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
423     		break;
424     	case MTLOAD:
425     		cqr = ti->discipline->mtload (ti, mt_count);
426     		if (cqr!=NULL) break; // if backend driver has an load function ->use it
427     		// if no medium is in, wait until it gets inserted
428     		if (ti->medium_is_unloaded) {
429     		    wait_event_interruptible (ti->wq,ti->medium_is_unloaded==0);
430     		}
431     		return 0;
432     	case MTCOMPRESSION:
433     		cqr = ti->discipline->mtcompression (ti, mt_count);
434     		break;
435     	case MTSETPART:
436     		cqr = ti->discipline->mtsetpart (ti, mt_count);
437     		break;
438     	case MTMKPART:
439     		cqr = ti->discipline->mtmkpart (ti, mt_count);
440     		break;
441     	case MTTELL:		// return number of block relative to current file
442     
443     		cqr = ti->discipline->mttell (ti, mt_count);
444     		break;
445     	case MTSETBLK:
446     		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
447     		ti->block_size = mt_count;
448     		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
449     #ifdef TAPE_DEBUG
450     		debug_text_event (tape_debug_area,6,"c:setblk:");
451     	        debug_int_event (tape_debug_area,6,mt_count);
452     #endif
453     		return 0;
454     	case MTRESET:
455     		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
456     		ti->kernbuf = ti->userbuf = NULL;
457     		tapestate_set (ti, TS_IDLE);
458     		ti->block_size = 0;
459     		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
460     #ifdef TAPE_DEBUG
461     		debug_text_event (tape_debug_area,6,"c:devreset:");
462     		debug_int_event (tape_debug_area,6,ti->blk_minor);
463     #endif
464     		return 0;
465     	default:
466     #ifdef TAPE_DEBUG
467     	    debug_text_event (tape_debug_area,6,"c:inv.mtio");
468     #endif
469     		return -EINVAL;
470     	}
471     	if (cqr == NULL) {
472     #ifdef TAPE_DEBUG
473     	        debug_text_event (tape_debug_area,6,"c:ccwg fail");
474     #endif
475     		return -ENOSPC;
476     	}
477     	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
478     	ti->cqr = cqr;
479     	ti->wanna_wakeup=0;
480     	rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
481     	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
482     	wait_event_interruptible (ti->wq,ti->wanna_wakeup);
483     	ti->cqr = NULL;
484     	if (ti->kernbuf != NULL) {
485     		kfree (ti->kernbuf);
486     		ti->kernbuf = NULL;
487     	}
488     	tape_free_request (cqr);
489     	// if medium was unloaded, update the corresponding variable.
490     	switch (mt_op) {
491     	case MTOFFL:
492     	case MTUNLOAD:
493     	    ti->medium_is_unloaded=1;
494     	}
495     	if (signal_pending (current)) {
496     		tapestate_set (ti, TS_IDLE);
497     		return -ERESTARTSYS;
498     	}
499     	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
500     	if (((mt_op == MTEOM) || (mt_op == MTRETEN)) && (tapestate_get (ti) == TS_FAILED))
501     		tapestate_set (ti, TS_DONE);
502     	if (tapestate_get (ti) == TS_FAILED) {
503     		tapestate_set (ti, TS_IDLE);
504     		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
505     		return ti->rc;
506     	}
507     	if (tapestate_get (ti) == TS_NOT_OPER) {
508     	    ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
509     	    ti->devinfo.irq=-1;
510     	    s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
511     	    return -ENODEV;
512     	}
513     	if (tapestate_get (ti) != TS_DONE) {
514     		tapestate_set (ti, TS_IDLE);
515     		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
516     		return -EIO;
517     	}
518     	tapestate_set (ti, TS_IDLE);
519     	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
520     	switch (mt_op) {
521     	case MTRETEN:		//need to rewind the tape after moving to eom
522     
523     		return tape_mtioctop (filp, MTREW, 1);
524     	case MTFSFM:		//need to skip back over the filemark
525     
526     		return tape_mtioctop (filp, MTBSFM, 1);
527     	case MTBSF:		//need to skip forward over the filemark
528     
529     		return tape_mtioctop (filp, MTFSF, 1);
530     	}
531     #ifdef TAPE_DEBUG
532     	debug_text_event (tape_debug_area,6,"c:mtio done");
533     #endif
534     	return 0;
535     }
536     
537     /*
538      * Tape device io controls.
539      */
540     int
541     tape_ioctl (struct inode *inode, struct file *filp,
542     	    unsigned int cmd, unsigned long arg)
543     {
544     	long lockflags;
545     	tape_info_t *ti;
546     	ccw_req_t *cqr;
547     	struct mtop op;		/* structure for MTIOCTOP */
548     	struct mtpos pos;	/* structure for MTIOCPOS */
549     	struct mtget get;
550     
551     	int rc;
552     #ifdef TAPE_DEBUG
553     	debug_text_event (tape_debug_area,6,"c:ioct");
554     #endif
555     	ti = first_tape_info;
556     	while ((ti != NULL) &&
557     	       (ti->rew_minor != MINOR (inode->i_rdev)) &&
558     	       (ti->nor_minor != MINOR (inode->i_rdev)))
559     		ti = (tape_info_t *) ti->next;
560     	if (ti == NULL) {
561     #ifdef TAPE_DEBUG
562     	        debug_text_event (tape_debug_area,6,"c:nodev");
563     #endif
564     		return -ENODEV;
565     	}
566     	// check for discipline ioctl overloading
567     	if ((rc = ti->discipline->discipline_ioctl_overload (inode, filp, cmd, arg))
568     	    != -EINVAL) {
569     #ifdef TAPE_DEBUG
570     	    debug_text_event (tape_debug_area,6,"c:ioverloa");
571     #endif
572     	    return rc;
573     	}
574     
575     	switch (cmd) {
576     	case MTIOCTOP:		/* tape op command */
577     		if (copy_from_user (&op, (char *) arg, sizeof (struct mtop))) {
578     			 return -EFAULT;
579     		}
580     		return (tape_mtioctop (filp, op.mt_op, op.mt_count));
581     	case MTIOCPOS:		/* query tape position */
582     		cqr = ti->discipline->mttell (ti, 0);
583     		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
584     		ti->cqr = cqr;
585     		ti->wanna_wakeup=0;
586     		do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
587     		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
588     		wait_event_interruptible (ti->wq,ti->wanna_wakeup);
589     		pos.mt_blkno = ti->rc;
590     		ti->cqr = NULL;
591     		if (ti->kernbuf != NULL) {
592     			kfree (ti->kernbuf);
593     			ti->kernbuf = NULL;
594     		}
595     		tape_free_request (cqr);
596     		if (signal_pending (current)) {
597     			tapestate_set (ti, TS_IDLE);
598     			return -ERESTARTSYS;
599     		}
600     		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
601     		tapestate_set (ti, TS_IDLE);
602     		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
603     		if (copy_to_user ((char *) arg, &pos, sizeof (struct mtpos)))
604     			 return -EFAULT;
605     		return 0;
606     	case MTIOCGET:
607     		get.mt_erreg = ti->rc;
608     		cqr = ti->discipline->mttell (ti, 0);
609     		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
610     		ti->cqr = cqr;
611     		ti->wanna_wakeup=0;
612     		do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
613     		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
614     		wait_event_interruptible (ti->wq,ti->wanna_wakeup);
615     		get.mt_blkno = ti->rc;
616     		get.mt_fileno = 0;
617     		get.mt_type = MT_ISUNKNOWN;
618     		get.mt_resid = ti->devstat.rescnt;
619     		get.mt_dsreg = ti->devstat.ii.sense.data[3];
620     		get.mt_gstat = 0;
621     		if (ti->devstat.ii.sense.data[1] & 0x08)
622     			get.mt_gstat &= GMT_BOT (1);	// BOT
623     
624     		if (ti->devstat.ii.sense.data[1] & 0x02)
625     			get.mt_gstat &= GMT_WR_PROT (1);	// write protected
626     
627     		if (ti->devstat.ii.sense.data[1] & 0x40)
628     			get.mt_gstat &= GMT_ONLINE (1);		//drive online
629     
630     		ti->cqr = NULL;
631     		if (ti->kernbuf != NULL) {
632     			kfree (ti->kernbuf);
633     			ti->kernbuf = NULL;
634     		}
635     		tape_free_request (cqr);
636     		if (signal_pending (current)) {
637     			tapestate_set (ti, TS_IDLE);
638     			return -ERESTARTSYS;
639     		}
640     		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
641     		tapestate_set (ti, TS_IDLE);
642     		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
643     		if (copy_to_user ((char *) arg, &get, sizeof (struct mtget)))
644     			 return -EFAULT;
645     		return 0;
646     	default:
647     #ifdef TAPE_DEBUG
648     	        debug_text_event (tape_debug_area,3,"c:ioct inv");
649     #endif	    
650     		return -EINVAL;
651     	}
652     }
653     
654     /*
655      * Tape device open function.
656      */
657     int
658     tape_open (struct inode *inode, struct file *filp)
659     {
660     	tape_info_t *ti;
661     	kdev_t dev;
662     	long lockflags;
663     
664     	inode = filp->f_dentry->d_inode;
665     	ti = first_tape_info;
666     	while ((ti != NULL) &&
667     	       (ti->rew_minor != MINOR (inode->i_rdev)) &&
668     	       (ti->nor_minor != MINOR (inode->i_rdev)))
669     		ti = (tape_info_t *) ti->next;
670     	if (ti == NULL)
671     		return -ENODEV;
672     #ifdef TAPE_DEBUG
673     	debug_text_event (tape_debug_area,6,"c:open:");
674     	debug_int_event (tape_debug_area,6,ti->blk_minor);
675     #endif
676     	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
677     	if (tapestate_get (ti) != TS_UNUSED) {
678     		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
679     #ifdef TAPE_DEBUG
680     		debug_text_event (tape_debug_area,6,"c:dbusy");
681     #endif
682     		return -EBUSY;
683     	}
684     	tapestate_set (ti, TS_IDLE);
685     	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
686     
687     	dev = MKDEV (tape_major, MINOR (inode->i_rdev));	/* Get the device */
688     	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
689     	if (ti->rew_minor == MINOR (inode->i_rdev))
690     		ti->rew_filp = filp;	/* save for later reference     */
691     	else
692     		ti->nor_filp = filp;
693     	filp->private_data = ti;	/* save the dev.info for later reference */
694     	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
695     
696     #ifdef MODULE
697     	MOD_INC_USE_COUNT;
698     #endif				/* MODULE */
699     	return 0;
700     }
701     
702     /*
703      * Tape device release function.
704      */
705     int
706     tape_release (struct inode *inode, struct file *filp)
707     {
708     	long lockflags;
709     	tape_info_t *ti,*lastti;
710     	ccw_req_t *cqr = NULL;
711     	int rc;
712     
713     	ti = first_tape_info;
714     	while ((ti != NULL) && (ti->rew_minor != MINOR (inode->i_rdev)) && (ti->nor_minor != MINOR (inode->i_rdev)))
715     		ti = (tape_info_t *) ti->next;
716     	if ((ti != NULL) && (tapestate_get (ti) == TS_NOT_OPER)) {
717     	    if (ti==first_tape_info) {
718     		first_tape_info=ti->next;
719     	    } else {
720     		lastti=first_tape_info;
721     		while (lastti->next!=ti) lastti=lastti->next;
722     		lastti->next=ti->next;
723     	    }
724     	    kfree(ti);    
725     	    return 0;
726     	}
727     	if ((ti == NULL) || (tapestate_get (ti) != TS_IDLE)) {
728     #ifdef TAPE_DEBUG
729     	debug_text_event (tape_debug_area,6,"c:notidle!");
730     #endif
731     		return -ENXIO;	/* error in tape_release */
732     	}
733     #ifdef TAPE_DEBUG
734     	debug_text_event (tape_debug_area,6,"c:release:");
735     	debug_int_event (tape_debug_area,6,ti->blk_minor);
736     #endif
737     	if (ti->rew_minor == MINOR (inode->i_rdev)) {
738     		cqr = ti->discipline->mtrew (ti, 1);
739     		if (cqr != NULL) {
740     #ifdef TAPE_DEBUG
741     		        debug_text_event (tape_debug_area,6,"c:rewrelea");
742     #endif
743     			s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
744     			tapestate_set (ti, TS_REW_RELEASE_INIT);
745     			ti->cqr = cqr;
746     			ti->wanna_wakeup=0;
747     			rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
748     			s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
749     			wait_event (ti->wq,ti->wanna_wakeup);
750     			ti->cqr = NULL;
751     			tape_free_request (cqr);
752     		}
753     	}
754     	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
755     	tapestate_set (ti, TS_UNUSED);
756     	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
757     #ifdef MODULE
758     	MOD_DEC_USE_COUNT;
759     #endif				/* MODULE */
760     	return 0;
761     }
762