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

嵌入式Linux

开发平台:

Unix_Linux

  1. /***************************************************************************
  2.  *
  3.  *  drivers/s390/char/tapeblock.c
  4.  *    block 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/blkdev.h>
  17. #include <linux/blk.h>
  18. #include <linux/version.h>
  19. #include <linux/interrupt.h>
  20. #include <asm/ccwcache.h> /* CCW allocations      */
  21. #include <asm/debug.h>
  22. #include <asm/s390dyn.h>
  23. #include <linux/compatmac.h>
  24. #ifdef MODULE
  25. #define __NO_VERSION__
  26. #include <linux/module.h>
  27. #endif
  28. #include "tape.h"
  29. #include "tapeblock.h"
  30. #define PRINTK_HEADER "TBLOCK:"
  31. /*
  32.  * file operation structure for tape devices
  33.  */
  34. #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
  35. static struct block_device_operations tapeblock_fops = {
  36. #else
  37. static struct file_operations tapeblock_fops = {
  38. #endif
  39.     owner   : THIS_MODULE,
  40.     open    : tapeblock_open,      /* open */
  41.     release : tapeblock_release,   /* release */
  42.         };
  43. int    tapeblock_major = 0;
  44. #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
  45. static void tape_request_fn (request_queue_t * queue);
  46. #else
  47. static void tape_request_fn (void);
  48. #endif
  49. static request_queue_t* tapeblock_getqueue (kdev_t kdev);
  50. #ifdef CONFIG_DEVFS_FS
  51. void
  52. tapeblock_mkdevfstree (tape_info_t* ti) {
  53.     ti->devfs_block_dir=devfs_mk_dir (ti->devfs_dir, "block", ti);
  54.     ti->devfs_disc=devfs_register(ti->devfs_block_dir, "disc",DEVFS_FL_DEFAULT,
  55.     tapeblock_major, ti->blk_minor,
  56.     TAPEBLOCK_DEFAULTMODE, &tapeblock_fops, ti);
  57. }
  58. void
  59. tapeblock_rmdevfstree (tape_info_t* ti) {
  60.     devfs_unregister(ti->devfs_disc);
  61.     devfs_unregister(ti->devfs_block_dir);
  62. }
  63. #endif
  64. void 
  65. tapeblock_setup(tape_info_t* ti) {
  66.     blk_size[tapeblock_major][ti->blk_minor]=0; // this will be detected
  67.     blksize_size[tapeblock_major][ti->blk_minor]=2048; // blocks are 2k by default.
  68.     hardsect_size[tapeblock_major][ti->blk_minor]=512;
  69.     blk_init_queue (&ti->request_queue, tape_request_fn); 
  70.     blk_queue_headactive (&ti->request_queue, 0); 
  71. #ifdef CONFIG_DEVFS_FS
  72.     tapeblock_mkdevfstree(ti);
  73. #endif
  74. }
  75. int
  76. tapeblock_init(void) {
  77.     int result;
  78.     tape_frontend_t* blkfront,*temp;
  79.     tape_info_t* ti;
  80.     tape_init();
  81.     /* Register the tape major number to the kernel */
  82. #ifdef CONFIG_DEVFS_FS
  83.     result = devfs_register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops);
  84. #else
  85.     result = register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops);
  86. #endif
  87.     if (result < 0) {
  88.         PRINT_WARN(KERN_ERR "tape: can't get major %d for block devicen", tapeblock_major);
  89.         panic ("cannot get major number for tape block device");
  90.     }
  91.     if (tapeblock_major == 0) tapeblock_major = result;   /* accept dynamic major number*/
  92.     INIT_BLK_DEV(tapeblock_major,tape_request_fn,tapeblock_getqueue,NULL);
  93.     read_ahead[tapeblock_major]=TAPEBLOCK_READAHEAD;
  94.     PRINT_WARN(KERN_ERR " tape gets major %d for block devicen", result);
  95.     blk_size[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_ATOMIC);
  96.     memset(blk_size[tapeblock_major],0,256*sizeof(int));
  97.     blksize_size[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_ATOMIC);
  98.     memset(blksize_size[tapeblock_major],0,256*sizeof(int));
  99.     hardsect_size[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_ATOMIC);
  100.     memset(hardsect_size[tapeblock_major],0,256*sizeof(int));
  101.     max_sectors[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_ATOMIC);
  102.     memset(max_sectors[tapeblock_major],0,256*sizeof(int));
  103.     blkfront = kmalloc(sizeof(tape_frontend_t),GFP_KERNEL);
  104.     if (blkfront==NULL) panic ("no mem for tape block device structure");
  105.     blkfront->device_setup=tapeblock_setup;
  106. #ifdef CONFIG_DEVFS_FS
  107.     blkfront->mkdevfstree = tapeblock_mkdevfstree;
  108.     blkfront->rmdevfstree = tapeblock_rmdevfstree;
  109. #endif
  110.     blkfront->next=NULL;
  111.     if (first_frontend==NULL) {
  112. first_frontend=blkfront;
  113.     } else {
  114. temp=first_frontend;
  115. while (temp->next!=NULL)
  116. temp=temp->next;
  117. temp->next=blkfront;
  118.     }
  119.     ti=first_tape_info;
  120.     while (ti!=NULL) {
  121. tapeblock_setup(ti);
  122. ti=ti->next;
  123.     }
  124.     return 0;
  125. }
  126. void 
  127. tapeblock_uninit(void) {
  128.     unregister_blkdev(tapeblock_major, "tBLK");
  129. }
  130. int
  131. tapeblock_open(struct inode *inode, struct file *filp) {
  132.     tape_info_t *ti;
  133.     kdev_t dev;
  134.     int rc;
  135.     long lockflags;
  136.     inode = filp->f_dentry->d_inode;
  137.     ti = first_tape_info;
  138.     while ((ti != NULL) && (ti->blk_minor != MINOR (inode->i_rdev)))
  139. ti = (tape_info_t *) ti->next;
  140. if (ti == NULL)
  141. return -ENODEV;
  142. #ifdef TAPE_DEBUG
  143. debug_text_event (tape_debug_area,6,"b:open:");
  144. debug_int_event (tape_debug_area,6,ti->blk_minor);
  145. #endif
  146. s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
  147. if (tapestate_get (ti) != TS_UNUSED) {
  148. s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  149. #ifdef TAPE_DEBUG
  150. debug_text_event (tape_debug_area,6,"b:dbusy");
  151. #endif
  152. return -EBUSY;
  153. }
  154. tapestate_set (ti, TS_IDLE);
  155.         ti->position=-1;
  156.         
  157. s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  158.         rc=tapeblock_mediumdetect(ti);
  159.         if (rc) {
  160.     s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
  161.     tapestate_set (ti, TS_UNUSED);
  162.     s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  163.     return rc; // in case of errors, we don't have a size of the medium
  164. }
  165. dev = MKDEV (tapeblock_major, MINOR (inode->i_rdev)); /* Get the device */
  166. s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
  167. ti->blk_filp = filp;
  168. filp->private_data = ti; /* save the dev.info for later reference */
  169.         ti->cqr=NULL;
  170. s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  171.     
  172. return 0;
  173. }
  174. int
  175. tapeblock_release(struct inode *inode, struct file *filp) {
  176. long lockflags;
  177. tape_info_t *ti,*lastti;
  178. ti = first_tape_info;
  179. while ((ti != NULL) && (ti->blk_minor != MINOR (inode->i_rdev)))
  180. ti = (tape_info_t *) ti->next;
  181. if ((ti != NULL) && (tapestate_get (ti) == TS_NOT_OPER)) {
  182.     if (ti==first_tape_info) {
  183. first_tape_info=ti->next;
  184.     } else {
  185. lastti=first_tape_info;
  186. while (lastti->next!=ti) lastti=lastti->next;
  187. lastti->next=ti->next;
  188.     }
  189.     kfree(ti);    
  190.     return 0;
  191. }
  192. if ((ti == NULL) || (tapestate_get (ti) != TS_IDLE)) {
  193. #ifdef TAPE_DEBUG
  194. debug_text_event (tape_debug_area,3,"b:notidle!");
  195. #endif
  196. return -ENXIO; /* error in tape_release */
  197. }
  198. #ifdef TAPE_DEBUG
  199. debug_text_event (tape_debug_area,6,"b:release:");
  200. debug_int_event (tape_debug_area,6,ti->blk_minor);
  201. #endif
  202. s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
  203. tapestate_set (ti, TS_UNUSED);
  204. s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  205. invalidate_buffers(inode->i_rdev);
  206. return 0;
  207. }
  208. static void
  209. tapeblock_end_request(tape_info_t* ti) {
  210.     struct buffer_head *bh;
  211.     int uptodate;
  212.     if ((tapestate_get(ti)!=TS_FAILED) &&
  213. (tapestate_get(ti)!=TS_DONE))
  214.        BUG(); // A request has to be completed to end it
  215.     uptodate=(tapestate_get(ti)==TS_DONE); // is the buffer up to date?
  216. #ifdef TAPE_DEBUG
  217.     if (uptodate) {
  218. debug_text_event (tape_debug_area,6,"b:done:");
  219. debug_int_event (tape_debug_area,6,(long)ti->cqr);
  220.     } else {
  221. debug_text_event (tape_debug_area,3,"b:failed:");
  222. debug_int_event (tape_debug_area,3,(long)ti->cqr);
  223.     }
  224. #endif
  225.     // now inform ll_rw_block about a request status
  226.     while ((bh = ti->current_request->bh) != NULL) {
  227. ti->current_request->bh = bh->b_reqnext;
  228. bh->b_reqnext = NULL;
  229. bh->b_end_io (bh, uptodate);
  230.     }
  231.     if (!end_that_request_first (ti->current_request, uptodate, "tBLK")) {
  232. #ifndef DEVICE_NO_RANDOM
  233. add_blkdev_randomness (MAJOR (ti->current_request->rq_dev));
  234. #endif
  235. end_that_request_last (ti->current_request);
  236.     }
  237.     ti->discipline->free_bread(ti->cqr,ti);
  238.     ti->cqr=NULL;
  239.     ti->current_request=NULL;
  240.     if (tapestate_get(ti)!=TS_NOT_OPER) tapestate_set(ti,TS_IDLE);
  241.     return;
  242. }
  243. static void
  244. tapeblock_exec_IO (tape_info_t* ti) {
  245.     int rc;
  246.     struct request* req;
  247.     if (ti->cqr) { // process done/failed request
  248. while ((tapestate_get(ti)==TS_FAILED) &&
  249.     ti->blk_retries>0) {
  250.     ti->blk_retries--;
  251.     ti->position=-1;
  252.     tapestate_set(ti,TS_BLOCK_INIT);
  253. #ifdef TAPE_DEBUG
  254.     debug_text_event (tape_debug_area,3,"b:retryreq:");
  255.     debug_int_event (tape_debug_area,3,(long)ti->cqr);
  256. #endif
  257.     rc = do_IO (ti->devinfo.irq, ti->cqr->cpaddr, (unsigned long) ti->cqr, 
  258. 0x00, ti->cqr->options);
  259.     if (rc) {
  260. #ifdef TAPE_DEBUG
  261. debug_text_event (tape_debug_area,3,"b:doIOfail:");
  262. debug_int_event (tape_debug_area,3,(long)ti->cqr);
  263. #endif 
  264. continue; // one retry lost 'cause doIO failed
  265.     }
  266.     return;
  267. }
  268. tapeblock_end_request (ti); // check state, inform user, free mem, dev=idl
  269.     }
  270.     if (ti->cqr!=NULL) BUG(); // tape should be idle now, request should be freed!
  271.     if (tapestate_get (ti) == TS_NOT_OPER) {
  272. ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
  273. ti->devinfo.irq=-1;
  274. return;
  275.     }
  276. #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
  277. if (list_empty (&ti->request_queue.queue_head)) {
  278. #else
  279. if (ti->request_queue==NULL) {
  280. #endif
  281. // nothing more to do or device has dissapeared;)
  282. #ifdef TAPE_DEBUG
  283. debug_text_event (tape_debug_area,6,"b:Qempty");
  284. #endif
  285. tapestate_set(ti,TS_IDLE);
  286. return;
  287.     }
  288.     // queue is not empty, fetch a request and start IO!
  289.     req=ti->current_request=tape_next_request(&ti->request_queue);
  290.     if (req==NULL) {
  291. BUG(); // Yo. The queue was not reported empy, but no request found. This is _bad_.
  292.     }
  293.     if (req->cmd!=READ) { // we only support reading
  294. tapestate_set(ti,TS_FAILED);
  295. tapeblock_end_request (ti); // check state, inform user, free mem, dev=idl
  296. tapestate_set(ti,TS_BLOCK_INIT);
  297. schedule_tapeblock_exec_IO(ti);
  298. return;
  299.     }
  300.     ti->cqr=ti->discipline->bread(req,ti,tapeblock_major); //build channel program from request
  301.     if (!ti->cqr) {
  302. // ccw generation failed. we try again later.
  303. #ifdef TAPE_DEBUG
  304. debug_text_event (tape_debug_area,3,"b:cqrNULL");
  305. #endif
  306. schedule_tapeblock_exec_IO(ti);
  307. ti->current_request=NULL;
  308. return;
  309.     }
  310.     ti->blk_retries = TAPEBLOCK_RETRIES;
  311.     rc= do_IO (ti->devinfo.irq, ti->cqr->cpaddr, 
  312.        (unsigned long) ti->cqr, 0x00, ti->cqr->options);
  313.     if (rc) {
  314. // okay. ssch failed. we try later.
  315. #ifdef TAPE_DEBUG
  316. debug_text_event (tape_debug_area,3,"b:doIOfail");
  317. #endif
  318. ti->discipline->free_bread(ti->cqr,ti);
  319. ti->cqr=NULL;
  320. ti->current_request=NULL;
  321. schedule_tapeblock_exec_IO(ti);
  322. return;
  323.     }
  324.     // our request is in IO. we remove it from the queue and exit
  325.     tape_dequeue_request (&ti->request_queue,req);
  326. }
  327. static void 
  328. do_tape_request (request_queue_t * queue) {
  329.     tape_info_t* ti;
  330.     long lockflags;
  331.     for (ti=first_tape_info;
  332.  ((ti!=NULL) && ((&ti->request_queue)!=queue));
  333.  ti=ti->next);
  334.     if (ti==NULL) BUG();
  335.     s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
  336.     if (tapestate_get(ti)!=TS_IDLE) {
  337. s390irq_spin_unlock_irqrestore(ti->devinfo.irq,lockflags);
  338. return;
  339.     }
  340.     if (tapestate_get(ti)!=TS_IDLE) BUG();
  341.     tapestate_set(ti,TS_BLOCK_INIT);
  342.     tapeblock_exec_IO(ti);
  343.     s390irq_spin_unlock_irqrestore(ti->devinfo.irq,lockflags);
  344. }
  345. static void
  346. run_tapeblock_exec_IO (tape_info_t* ti) {
  347.     long flags_390irq,flags_ior;
  348.     spin_lock_irqsave (&io_request_lock, flags_ior);
  349.     s390irq_spin_lock_irqsave(ti->devinfo.irq,flags_390irq);
  350.     atomic_set(&ti->bh_scheduled,0);
  351.     tapeblock_exec_IO(ti);
  352.     s390irq_spin_unlock_irqrestore(ti->devinfo.irq,flags_390irq);
  353.     spin_unlock_irqrestore (&io_request_lock, flags_ior);
  354. }
  355. void
  356. schedule_tapeblock_exec_IO (tape_info_t *ti)
  357. {
  358. /* Protect against rescheduling, when already running */
  359.         if (atomic_compare_and_swap(0,1,&ti->bh_scheduled)) {
  360.                 return;
  361.         }
  362. #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
  363. INIT_LIST_HEAD(&ti->bh_tq.list);
  364. #endif
  365. ti->bh_tq.sync = 0;
  366. ti->bh_tq.routine = (void *) (void *) run_tapeblock_exec_IO;
  367. ti->bh_tq.data = ti;
  368. queue_task (&ti->bh_tq, &tq_immediate);
  369. mark_bh (IMMEDIATE_BH);
  370. return;
  371. }
  372. /* wrappers around do_tape_request for different kernel versions */
  373. #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
  374. static void tape_request_fn (void) {
  375.     tape_info_t* ti=first_tape_info;
  376.     while (ti!=NULL) {
  377. do_tape_request(&ti->request_queue);
  378. ti=ti->next;
  379.     }
  380. }
  381. #else
  382. static void  tape_request_fn (request_queue_t* queue) {
  383.     do_tape_request(queue);
  384. }
  385. #endif
  386. static request_queue_t* tapeblock_getqueue (kdev_t kdev) {
  387.     tape_info_t* ti=first_tape_info;
  388.     while ((ti!=NULL) && (MINOR(kdev)!=ti->blk_minor)) 
  389.         ti=ti->next;
  390.     if (ti!=NULL) return &ti->request_queue;
  391.     return NULL;
  392. }
  393. int tapeblock_mediumdetect(tape_info_t* ti) {
  394.         ccw_req_t* cqr;
  395.     int losize=1,hisize=1,rc;
  396.     long lockflags;
  397. #ifdef TAPE_DEBUG
  398.     debug_text_event (tape_debug_area,3,"b:medDet");
  399. #endif
  400.     PRINT_WARN("Detecting media size. This will take _long_, so get yourself a coffee...n");
  401.     while (1) { //is interruped by break
  402. hisize=hisize << 1; // try twice the size tested before 
  403. cqr=ti->discipline->mtseek (ti, hisize);
  404. if (cqr == NULL) {
  405. #ifdef TAPE_DEBUG
  406.     debug_text_event (tape_debug_area,6,"b:ccwg fail");
  407. #endif
  408.     return -ENOSPC;
  409. }
  410. s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
  411. ti->cqr = cqr;
  412. ti->wanna_wakeup=0;
  413. rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
  414. s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  415. if (rc) return -EIO;
  416. wait_event_interruptible (ti->wq,ti->wanna_wakeup);
  417. ti->cqr = NULL;
  418. tape_free_request (cqr);
  419. if (ti->kernbuf) {
  420.     kfree (ti->kernbuf);
  421.     ti->kernbuf=NULL;
  422. }
  423. if (signal_pending (current)) {
  424. tapestate_set (ti, TS_IDLE);
  425. return -ERESTARTSYS;
  426. }
  427. s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
  428. if (tapestate_get (ti) == TS_FAILED) {
  429. tapestate_set (ti, TS_IDLE);
  430. s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  431. break;
  432. }
  433. if (tapestate_get (ti) == TS_NOT_OPER) {
  434.     ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
  435.     ti->devinfo.irq=-1;
  436.     s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
  437.     return -ENODEV;
  438. }
  439. if (tapestate_get (ti) != TS_DONE) {
  440. tapestate_set (ti, TS_IDLE);
  441. s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  442. return -EIO;
  443. }
  444. tapestate_set (ti, TS_IDLE);
  445. s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  446. losize=hisize;
  447.     }
  448.     cqr = ti->discipline->mtrew (ti, 1);
  449.     if (cqr == NULL) {
  450. #ifdef TAPE_DEBUG
  451. debug_text_event (tape_debug_area,6,"b:ccwg fail");
  452. #endif
  453. return -ENOSPC;
  454.     }
  455.     s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
  456.     ti->cqr = cqr;
  457.     ti->wanna_wakeup=0;
  458.     rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
  459.     s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  460.     wait_event_interruptible (ti->wq,ti->wanna_wakeup);
  461.     ti->cqr = NULL;
  462.     tape_free_request (cqr);
  463.     if (signal_pending (current)) {
  464. tapestate_set (ti, TS_IDLE);
  465. return -ERESTARTSYS;
  466.     }
  467.     s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
  468.     if (tapestate_get (ti) == TS_FAILED) {
  469. tapestate_set (ti, TS_IDLE);
  470. s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  471. return -EIO;
  472.     }
  473.     if (tapestate_get (ti) == TS_NOT_OPER) {
  474. ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
  475. ti->devinfo.irq=-1;
  476. s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
  477. return -ENODEV;
  478.     }
  479.     if (tapestate_get (ti) != TS_DONE) {
  480. tapestate_set (ti, TS_IDLE);
  481. s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  482. return -EIO;
  483.     }
  484.     tapestate_set (ti, TS_IDLE);
  485.     s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  486.     while (losize!=hisize) {
  487. cqr=ti->discipline->mtseek (ti, (hisize+losize)/2+1);
  488. if (cqr == NULL) {
  489. #ifdef TAPE_DEBUG
  490.     debug_text_event (tape_debug_area,6,"b:ccwg fail");
  491. #endif
  492.     return -ENOSPC;
  493. }
  494. s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
  495. ti->cqr = cqr;
  496. ti->wanna_wakeup=0;
  497. rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
  498. s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  499. if (rc) return -EIO;
  500. wait_event_interruptible (ti->wq,ti->wanna_wakeup);
  501. ti->cqr = NULL;
  502. tape_free_request (cqr);
  503. if (ti->kernbuf) {
  504.     kfree (ti->kernbuf);
  505.     ti->kernbuf=NULL;
  506. }
  507. if (signal_pending (current)) {
  508. tapestate_set (ti, TS_IDLE);
  509. return -ERESTARTSYS;
  510. }
  511. s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
  512. if (tapestate_get (ti) == TS_NOT_OPER) {
  513.     ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
  514.     ti->devinfo.irq=-1;
  515.     s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
  516.     return -ENODEV;
  517. }
  518. if (tapestate_get (ti) == TS_FAILED) {
  519. tapestate_set (ti, TS_IDLE);
  520. s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  521. hisize=(hisize+losize)/2;
  522. cqr = ti->discipline->mtrew (ti, 1);
  523. if (cqr == NULL) {
  524. #ifdef TAPE_DEBUG
  525.     debug_text_event (tape_debug_area,6,"b:ccwg fail");
  526. #endif
  527.     return -ENOSPC;
  528. }
  529. s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
  530. ti->cqr = cqr;
  531. ti->wanna_wakeup=0;
  532. rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
  533. s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  534. wait_event_interruptible (ti->wq,ti->wanna_wakeup);
  535. ti->cqr = NULL;
  536. tape_free_request (cqr);
  537. if (signal_pending (current)) {
  538.     tapestate_set (ti, TS_IDLE);
  539.     return -ERESTARTSYS;
  540. }
  541. s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
  542. if (tapestate_get (ti) == TS_FAILED) {
  543.     tapestate_set (ti, TS_IDLE);
  544.     s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  545.     return -EIO;
  546. }
  547. if (tapestate_get (ti) != TS_DONE) {
  548.     tapestate_set (ti, TS_IDLE);
  549.     s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  550.     return -EIO;
  551. }
  552. tapestate_set (ti, TS_IDLE);
  553. s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  554. continue;
  555. }
  556. if (tapestate_get (ti) != TS_DONE) {
  557. tapestate_set (ti, TS_IDLE);
  558. s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  559. return -EIO;
  560. }
  561. tapestate_set (ti, TS_IDLE);
  562. s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
  563. losize=(hisize+losize)/2+1;
  564.     }
  565.     blk_size[tapeblock_major][ti->blk_minor]=(losize)*(blksize_size[tapeblock_major][ti->blk_minor]/1024);
  566.     return 0;
  567. }