*** 0.2.1.16 1993/03/01 00:06:16 --- kernel/chr_drv/tpqic02.c 1993/03/08 18:52:28 *************** *** 1,6 **** ! /* $Id: tpqic02.c,v 0.2.1.16 1993/03/01 00:06:16 root Exp $ * ! * Driver for tape drive support for Linux-i386 0.99.5 * * Copyright (c) 1992 by H. H. Bergman. All rights reserved. * Current e-mail address: s0356514@let.rug.nl --- 1,6 ---- ! /* $Id: tpqic02.c,v 0.2.1.17 1993/03/08 18:51:59 root Exp root $ * ! * Driver for tape drive support for Linux-i386 0.99.6. * * Copyright (c) 1992 by H. H. Bergman. All rights reserved. * Current e-mail address: s0356514@let.rug.nl *************** *** 27,32 **** --- 27,35 ---- * You are not allowed to change this line nor the text above. * * $Log: tpqic02.c,v $ + * Revision 0.2.1.17 1993/03/08 18:51:59 root + * Tried to `fix' write-once bug in previous release. + * * Revision 0.2.1.16 1993/03/01 00:06:16 root * Use register_chrdev() for 0.99.6. * *************** *** 179,186 **** static volatile struct tpstatus tperror; /* last drive status */ ! static char rcs_revision[] = "$Revision: 0.2.1.16 $"; ! static char rcs_date[] = "$Date: 1993/03/01 00:06:16 $"; /* Flag bits for status and outstanding requests. * (Could all be put in one bit-field-struct.) --- 182,189 ---- static volatile struct tpstatus tperror; /* last drive status */ ! static char rcs_revision[] = "$Revision: 0.2.1.17 $"; ! static char rcs_date[] = "$Date: 1993/03/08 18:51:59 $"; /* Flag bits for status and outstanding requests. * (Could all be put in one bit-field-struct.) *************** *** 210,217 **** static dev_t current_tape_dev = (TAPE_QIC02_MAJOR)<<8; static int extra_blocks_left = BLOCKS_BEYOND_EW; ! static flag return_read_eof = NO; static flag return_write_eof = NO; --- 213,236 ---- static dev_t current_tape_dev = (TAPE_QIC02_MAJOR)<<8; static int extra_blocks_left = BLOCKS_BEYOND_EW; ! ! ! /* return_*_eof: ! * NO: not at EOF, ! * YES: tell app EOF was reached (return 0). ! * ! * return_*_eof==YES && reported_*_eof==NO ==> ! * return current buffer, next time(s) return EOF. ! * ! * return_*_eof==YES && reported_*_eof==YES ==> ! * at EOF and application knows it, so we can ! * move on to the next file. ! * ! */ ! static flag return_read_eof = NO; /* set to signal app EOF was reached */ static flag return_write_eof = NO; + static flag reported_read_eof = NO; /* set when we've done that */ + static flag reported_write_eof = NO; *************** *** 474,479 **** --- 493,501 ---- need_rewind = YES; status_eof_detected = NO; status_eom_detected = NO; + /******* when this happens, the status should be re-read, because + ******* the cartridge may have been changed. + *******/ } else if (exnr==EXC_XFILLER) tpqputs("[Bad block -- filler data transfered.]"); *************** *** 963,968 **** --- 985,994 ---- need_rewind = NO; ioctl_status.mt_fileno = ioctl_status.mt_blkno = 0; extra_blocks_left = BLOCKS_BEYOND_EW; + return_write_eof = NO; + return_read_eof = NO; + reported_read_eof = NO; + reported_write_eof = NO; } /* sense() will set eof/eom as required */ if (stat==TE_EX) { *************** *** 1063,1070 **** tpqputs("Couldn't finish write cycle properly"); (void) tp_sense(0); } ! if (return_write_eof==NO) /* prevent subsequent writes */ ! return_write_eof=YES; } } /* terminate_write */ --- 1089,1099 ---- tpqputs("Couldn't finish write cycle properly"); (void) tp_sense(0); } ! /* If there is an EOF token waiting to be returned to ! * the (writing) application, discard it now. ! * We could be at EOT, so don't reset return_write_eof. ! */ ! reported_write_eof=YES; } } /* terminate_write */ *************** *** 1096,1102 **** tpqputs("Rewinding tape..."); stat = ll_do_qic_cmd(QCMD_REWIND, TIM_R); if (stat != 0) { ! printk(TPQIC_NAME ": rewind failed in do_qic_cmd()"); return stat; } need_rewind = NO; --- 1125,1131 ---- tpqputs("Rewinding tape..."); stat = ll_do_qic_cmd(QCMD_REWIND, TIM_R); if (stat != 0) { ! printk(TPQIC_NAME ": rewind failed in do_qic_cmd(). stat=0x%2x", stat); return stat; } need_rewind = NO; *************** *** 1674,1679 **** --- 1703,1709 ---- static int tape_qic02_lseek(struct inode * inode, struct file * file, off_t offset, int origin) { + printk(TPQIC_NAME ": lseek request: offset=0x%8x, origin=0x%8x\n", offset, origin); return -EINVAL; /* not supported */ } /* tape_qic02_lseek */ *************** *** 1702,1716 **** * than waste time on a context switch, when the kernel buffer fills up. */ ! /********************************************************************************** * Problem: tar(1) doesn't always read the entire file. Sometimes the entire file * has been read, but the EOF token is never returned to tar(1), simply because * tar(1) knows it has already read all of the data it needs. So we must use ! * open/release to reset the `return_read_eof' flag. If we don't, the next read * request would return the EOF flag for the previous file. - * - * Problem: When we are at EOD, - ********************************************************************************** */ static int tape_qic02_read(struct inode * inode, struct file * filp, char * buf, int count) --- 1732,1743 ---- * than waste time on a context switch, when the kernel buffer fills up. */ ! /* * Problem: tar(1) doesn't always read the entire file. Sometimes the entire file * has been read, but the EOF token is never returned to tar(1), simply because * tar(1) knows it has already read all of the data it needs. So we must use ! * open/release to reset the `reported_read_eof' flag. If we don't, the next read * request would return the EOF flag for the previous file. */ static int tape_qic02_read(struct inode * inode, struct file * filp, char * buf, int count) *************** *** 1724,1730 **** printk(TPQIC_NAME ": request READ, minor=%x, buf=%lx, count=%x, pos=%x, flags=%x\n", MINOR(dev), buf, count, filp->f_pos, flags); ! if (count % TAPE_BLKSIZE) { /* only allow mod 512 bytes at a time */ tpqputs("Wrong block size"); return -EINVAL; } --- 1751,1757 ---- printk(TPQIC_NAME ": request READ, minor=%x, buf=%lx, count=%x, pos=%x, flags=%x\n", MINOR(dev), buf, count, filp->f_pos, flags); ! if (count % TAPE_BLKSIZE) { /* Only allow mod 512 bytes at a time. */ tpqputs("Wrong block size"); return -EINVAL; } *************** *** 1731,1784 **** /* Just assume everything is ok. Controller will scream if not. */ ! if (status_bytes_wr) /* once written, no more reads, 'till after WFM */ return -EACCES; ! /********************* CLEAN THIS UP *************************************************/ ! while (count>0) { /* see how much fits in the kernel buffer */ bytes_todo = TPQBUF_SIZE; if (bytes_todo>count) bytes_todo = count; ! /* must ensure that user program sees exactly one EOF token (==0) */ if (return_read_eof==YES) { ! printk("read: return_read_eof==%d, total_bytes_done==%d\n", return_read_eof, total_bytes_done); ! if (total_bytes_done>0) { ! return total_bytes_done; /* next time return EOF */ } else { ! return_read_eof = -YES; /* move on next time */ ! return 0; /* return EOF */ ! } ! } ! if (return_read_eof==-YES) { ! printk("read: return_read_eof==%d, status_eom_detected==%d\n", return_read_eof, status_eom_detected); ! /* application program has already received EOF ! * (above), now continue with next file on tape, ! * if possible. ! * Assume that upon reaching the FM, EXCEPTION is ! * set, causing a sense(), and skipping the FM. ! ***** exact behaviour is not clear to me. ! */ /*********** this should check for (EOD|NDT), not EOM, 'cause we can read past EW: ************/ ! if (status_eom_detected) /* if EOM, nothing left to read, so */ ! return 0; /* return EOF on subsequent reads */ ! else { /* just eof, there may be more files ahead... */ ! return_read_eof = NO; ! status_eof_detected = NO; /* reset this too */ } } ! /* start reading data */ ! verify_area(buf, bytes_todo); /* check buffer is valid */ if (bytes_todo>0) { if (is_exception()) /****************************************/ tpqputs("is_exception() before start_dma()!"); /****************************************************************** ***** if start_dma() fails because the head is positioned 0 bytes ***** before the FM, (causing EXCEPTION to be set) return_read_eof should ! ***** be set to YES, and we should return 0, rather than -ENXIO. ***************************************************************************/ stat = start_dma(READ, bytes_todo); if (stat == TE_OK) { --- 1758,1828 ---- /* Just assume everything is ok. Controller will scream if not. */ ! if (status_bytes_wr) /* Once written, no more reads, 'till after WFM. */ return -EACCES; ! /* This is rather ugly because it has to implement a finite state ! * machine in order to handle the EOF situations properly. ! */ ! while (count>=0) { ! bytes_done = 0; /* see how much fits in the kernel buffer */ bytes_todo = TPQBUF_SIZE; if (bytes_todo>count) bytes_todo = count; ! /* Must ensure that user program sees exactly one EOF token (==0) */ if (return_read_eof==YES) { ! printk("read: return_read_eof==%d, reported_read_eof==%d, total_bytes_done==%d\n", return_read_eof, reported_read_eof, total_bytes_done); ! ! if (reported_read_eof==NO) { ! /* have not yet returned EOF to user program */ ! if (total_bytes_done>0) { ! return total_bytes_done; /* next time return EOF */ ! } else { ! reported_read_eof = YES; /* move on next time */ ! return 0; /* return EOF */ ! } } else { ! /* Application program has already received EOF ! * (above), now continue with next file on tape, ! * if possible. ! * Assume that upon reaching the FM, EXCEPTION is ! * set, causing a sense(), and skipping the FM. ! ***** exact behaviour is not clear to me. ! */ /*********** this should check for (EOD|NDT), not EOM, 'cause we can read past EW: ************/ ! if (status_eom_detected) ! /* If EOM, nothing left to read, so keep returning EOFs. ! *** should probably set some flag to avoid clearing ! *** status_eom_detected through ioctls or something ! */ ! return 0; ! else { ! /* just eof, there may be more files ahead... */ ! return_read_eof = NO; ! reported_read_eof = NO; ! status_eof_detected = NO; /* reset this too */ ! /*fall through*/ ! } } } ! /*****************************/ ! if (bytes_todo==0) ! return total_bytes_done; ! if (bytes_todo>0) { + /* start reading data */ + verify_area(buf, bytes_todo); /* check buffer is valid */ if (is_exception()) /****************************************/ tpqputs("is_exception() before start_dma()!"); /****************************************************************** ***** if start_dma() fails because the head is positioned 0 bytes ***** before the FM, (causing EXCEPTION to be set) return_read_eof should ! ***** be set to YES, and we should return total_bytes_done, rather than -ENXIO. ! ***** The app should recognize this as an EOF condition. ***************************************************************************/ stat = start_dma(READ, bytes_todo); if (stat == TE_OK) { *************** *** 1808,1814 **** memcpy_tofs( (void *) buf, (void *) buffaddr, bytes_done); #if 1 /* Checks Ton's patch below */ ! if ((return_read_eof != YES) && (status_eof_detected == YES)) { printk(TPQIC_NAME ": read(): return_read_eof=%d, status_eof_detected=YES. return_read_eof:=YES\n", return_read_eof); } #endif --- 1852,1858 ---- memcpy_tofs( (void *) buf, (void *) buffaddr, bytes_done); #if 1 /* Checks Ton's patch below */ ! if ((return_read_eof == NO) && (status_eof_detected == YES)) { printk(TPQIC_NAME ": read(): return_read_eof=%d, status_eof_detected=YES. return_read_eof:=YES\n", return_read_eof); } #endif *************** *** 1825,1837 **** count -= bytes_done; } } ! if (total_bytes_done>0) ! return total_bytes_done; ! else { ! if (return_read_eof==YES) ! return_read_eof=-YES; ! return 0; ! } } /* tape_qic02_read */ --- 1869,1876 ---- count -= bytes_done; } } ! tpqputs("read request for <0 bytes"); ! return -EINVAL; } /* tape_qic02_read */ *************** *** 1847,1852 **** --- 1886,1907 ---- * If the user-program wants to use the extra space, it should use the * MTNOP ioctl() to get the generic status register and may then continue * writing (max 1kB). ----------- doesn't work yet............... + * + * EOF behaviour on writes: + * If there is enough room, write all of the data. + * If there is insufficient room, write as much as will fit and + * return the amount written. If the requested amount differs from the + * written amount, the application program should recognize that as the + * end of file. Subsequent writes will return -ENOSPC. + * Unless the minor bits specify a rewind-on-close, the tape will not + * be rewound when it is full. The user-program should do that, if desired. + * If the driver were to do that automatically, a user-program could be + * confused about the EOT/BOT condition after re-opening the tape device. + * + * Multiple volume support: Tar closes the tape device before prompting for + * the next tape. The user may then insert a new tape and tar will open the + * tape device again. The driver will detect an exception status in (No Cartridge) + * and force a rewind. After that tar may continue writing. */ static int tape_qic02_write(struct inode * inode, struct file * filp, char * buf, int count) { *************** *** 1876,1900 **** if (doing_read == YES) /************************** ?????????????? ***********/ terminate_read(0); ! while (count>0) { /* see how much fits in the kernel buffer */ bytes_todo = TPQBUF_SIZE; if (bytes_todo>count) bytes_todo = count; if (return_write_eof == YES) { ! /* EOF on write means EOM. Don't want to break the tape. */ ! if (total_bytes_done>0) { ! return total_bytes_done; /* next time EOM */ } else { ! return_write_eof = -YES; /************* should set flag to allow extra 1kB */ need_rewind = YES; /* at EOT, so need rewind */ ! return 0; /* return EOF */ ! } } - if (return_write_eof == -YES) /********* should check for extra 1kB *********/ - return -ENOSPC; /* copy from user to DMA buffer and initiate transfer. */ if (bytes_todo>0) { --- 1931,1970 ---- if (doing_read == YES) /************************** ?????????????? ***********/ terminate_read(0); ! while (count>=0) { /* see how much fits in the kernel buffer */ + bytes_done = 0; bytes_todo = TPQBUF_SIZE; if (bytes_todo>count) bytes_todo = count; if (return_write_eof == YES) { ! /* return_write_eof should be reset on reverse tape movements. */ ! ! if (reported_write_eof==NO) { ! if (bytes_todo>0) { ! tpqputs("partial write"); ! /* partial write signals EOF to user program */ ! } ! reported_write_eof = YES; ! return total_bytes_done; } else { ! /************* should set flag to allow extra 1kB ********/ ! ! #if 0 ! /******** need_rewind shouldn't be reset here, but user prog should do ! ******** rewind or use auto-rewinding device ! ********/ need_rewind = YES; /* at EOT, so need rewind */ ! #endif ! ! return -ENOSPC; /* return error */ ! } } + /*********** CLEAN THIS UP TOO ********************************/ + if (bytes_todo==0) + return total_bytes_done; /* copy from user to DMA buffer and initiate transfer. */ if (bytes_todo>0) { *************** *** 1902,1910 **** /****************** similar problem with read() at FM could happen here at EOT. ******************/ if (start_dma(WRITE, bytes_todo) != TE_OK) /* should do sense() on error here */ ! return -ENXIO; /* Wait for write to complete, interrupt should wake us. */ while ((status_error == 0) && (dma_mode != 0)) { sleep_on(&tape_qic02_transfer); --- 1972,1984 ---- /****************** similar problem with read() at FM could happen here at EOT. ******************/ + + /***** if at EOT, 0 bytes can be written. start_dma() will + ***** fail and write() will return ENXIO error + *****/ if (start_dma(WRITE, bytes_todo) != TE_OK) /* should do sense() on error here */ ! return -ENXIO; /*********** FIXTHIS **************/ /* Wait for write to complete, interrupt should wake us. */ while ((status_error == 0) && (dma_mode != 0)) { sleep_on(&tape_qic02_transfer); *************** *** 1934,1940 **** count -= bytes_done; } } ! return total_bytes_done; } /* tape_qic02_write */ --- 2008,2016 ---- count -= bytes_done; } } ! tpqputs("write request for <0 bytes"); ! printk(TPQIC_NAME ": status_bytes_wr %x, buf %x, total_bytes_done %x, count %x\n", status_bytes_wr, buf, total_bytes_done, count); ! return -EINVAL; } /* tape_qic02_write */ *************** *** 1974,1979 **** --- 2050,2064 ---- status_bytes_rd = NO; status_bytes_wr = NO; + return_read_eof = NO; /********????????????????*****/ + return_write_eof = (status_eot_detected)? YES : NO; + + /* Clear this in case user app close()d before reading EOF token */ + status_eof_detected = NO; + + reported_read_eof = NO; + reported_write_eof = NO; + switch (flags & O_ACCMODE) { case O_RDONLY: mode_access = READ; *************** *** 2076,2083 **** current_tape_dev = 0xff80; return -EIO; } ! if (return_read_eof==YES) /* EOF token was never returned to app */ ! return_read_eof = -YES; /* Now flush it, if not at EOD. */ return 0; } /* tape_qic02_open */ --- 2161,2167 ---- current_tape_dev = 0xff80; return -EIO; } ! return 0; } /* tape_qic02_open */ *** 0.13 1993/03/01 00:09:11 --- include/linux/tpqic02.h 1993/03/08 18:52:44 *************** *** 1,4 **** ! /* $Id: tpqic02.h,v 0.13 1993/03/01 00:09:11 root Exp $ * * Include file for QIC-02 driver for Linux. * --- 1,4 ---- ! /* $Id: tpqic02.h,v 0.14 1993/03/08 18:51:59 root Exp root $ * * Include file for QIC-02 driver for Linux. * *************** *** 317,324 **** typedef char flag; #define YES 1 /* YES must be != 0 */ - #define NO 0 #ifdef TDEBUG --- 317,324 ---- typedef char flag; + #define NO 0 /* NO must be 0 */ #define YES 1 /* YES must be != 0 */ #ifdef TDEBUG