tapechar.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:21k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

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