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